summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/video
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2007-12-17 15:19:59 +0000
committer Aaron Giles <aaron@aarongiles.com>2007-12-17 15:19:59 +0000
commit7b77f1218624ea26dbb2efd85a19f795f5d4e02e (patch)
tree19209304095572b4fd61c2a2d6a5aa75c4e471ad /src/mame/video
parent3da7f476068b3ffef713218ba2fc1bd5030f2c38 (diff)
Initial checkin of MAME 0.121.mame0121
Diffstat (limited to 'src/mame/video')
-rw-r--r--src/mame/video/1942.c248
-rw-r--r--src/mame/video/1943.c249
-rw-r--r--src/mame/video/20pacgal.c203
-rw-r--r--src/mame/video/40love.c350
-rw-r--r--src/mame/video/4enraya.c40
-rw-r--r--src/mame/video/8080bw.c478
-rw-r--r--src/mame/video/88games.c100
-rw-r--r--src/mame/video/actfancr.c311
-rw-r--r--src/mame/video/aeroboto.c210
-rw-r--r--src/mame/video/aerofgt.c745
-rw-r--r--src/mame/video/afega.c381
-rw-r--r--src/mame/video/airbustr.c151
-rw-r--r--src/mame/video/ajax.c115
-rw-r--r--src/mame/video/aliens.c86
-rw-r--r--src/mame/video/alpha68k.c560
-rw-r--r--src/mame/video/ambush.c173
-rw-r--r--src/mame/video/amiga.c971
-rw-r--r--src/mame/video/ampoker.c120
-rw-r--r--src/mame/video/amspdwy.c150
-rw-r--r--src/mame/video/angelkds.c302
-rw-r--r--src/mame/video/antic.c592
-rw-r--r--src/mame/video/appoooh.c339
-rw-r--r--src/mame/video/aquarium.c183
-rw-r--r--src/mame/video/arabian.c394
-rw-r--r--src/mame/video/arcadecl.c123
-rw-r--r--src/mame/video/argus.c1625
-rw-r--r--src/mame/video/arkanoid.c120
-rw-r--r--src/mame/video/armedf.c355
-rw-r--r--src/mame/video/artmagic.c359
-rw-r--r--src/mame/video/ashnojoe.c222
-rw-r--r--src/mame/video/asterix.c119
-rw-r--r--src/mame/video/astinvad.c148
-rw-r--r--src/mame/video/astrocde.c1106
-rw-r--r--src/mame/video/asuka.c93
-rw-r--r--src/mame/video/atari.c1568
-rw-r--r--src/mame/video/atarifb.c190
-rw-r--r--src/mame/video/atarig1.c221
-rw-r--r--src/mame/video/atarig42.c266
-rw-r--r--src/mame/video/atarigt.c681
-rw-r--r--src/mame/video/atarigx2.c259
-rw-r--r--src/mame/video/atarimo.c1092
-rw-r--r--src/mame/video/atarimo.h133
-rw-r--r--src/mame/video/atarirle.c1760
-rw-r--r--src/mame/video/atarirle.h97
-rw-r--r--src/mame/video/atarisy1.c664
-rw-r--r--src/mame/video/atarisy2.c371
-rw-r--r--src/mame/video/atetris.c67
-rw-r--r--src/mame/video/attckufo.c171
-rw-r--r--src/mame/video/avgdvg.c1523
-rw-r--r--src/mame/video/avgdvg.h29
-rw-r--r--src/mame/video/aztarac.c95
-rw-r--r--src/mame/video/badlands.c147
-rw-r--r--src/mame/video/bagman.c153
-rw-r--r--src/mame/video/balsente.c239
-rw-r--r--src/mame/video/bankp.c205
-rw-r--r--src/mame/video/baraduke.c350
-rw-r--r--src/mame/video/batman.c311
-rw-r--r--src/mame/video/battlane.c250
-rw-r--r--src/mame/video/battlera.c413
-rw-r--r--src/mame/video/battlex.c120
-rw-r--r--src/mame/video/battlnts.c67
-rw-r--r--src/mame/video/bbusters.c299
-rw-r--r--src/mame/video/beathead.c232
-rw-r--r--src/mame/video/beezer.c70
-rw-r--r--src/mame/video/bfm_adr2.c510
-rw-r--r--src/mame/video/bfm_adr2.h24
-rw-r--r--src/mame/video/bigevglf.c95
-rw-r--r--src/mame/video/bigstrkb.c145
-rw-r--r--src/mame/video/bionicc.c232
-rw-r--r--src/mame/video/bishi.c96
-rw-r--r--src/mame/video/bking2.c364
-rw-r--r--src/mame/video/bladestl.c75
-rw-r--r--src/mame/video/blktiger.c248
-rw-r--r--src/mame/video/blmbycar.c259
-rw-r--r--src/mame/video/blockade.c35
-rw-r--r--src/mame/video/blockhl.c67
-rw-r--r--src/mame/video/blockout.c138
-rw-r--r--src/mame/video/bloodbro.c278
-rw-r--r--src/mame/video/blstroid.c180
-rw-r--r--src/mame/video/blueprnt.c133
-rw-r--r--src/mame/video/bogeyman.c155
-rw-r--r--src/mame/video/bombjack.c140
-rw-r--r--src/mame/video/boogwing.c203
-rw-r--r--src/mame/video/bosco.c338
-rw-r--r--src/mame/video/bottom9.c97
-rw-r--r--src/mame/video/boxer.c89
-rw-r--r--src/mame/video/brkthru.c283
-rw-r--r--src/mame/video/bsktball.c63
-rw-r--r--src/mame/video/btime.c659
-rw-r--r--src/mame/video/btoads.c487
-rw-r--r--src/mame/video/bublbobl.c98
-rw-r--r--src/mame/video/buggychl.c275
-rw-r--r--src/mame/video/bwing.c304
-rw-r--r--src/mame/video/cabal.c149
-rw-r--r--src/mame/video/canyon.c97
-rw-r--r--src/mame/video/capbowl.c197
-rw-r--r--src/mame/video/carjmbre.c148
-rw-r--r--src/mame/video/carpolo.c833
-rw-r--r--src/mame/video/cave.c1544
-rw-r--r--src/mame/video/cbasebal.c187
-rw-r--r--src/mame/video/cbuster.c161
-rw-r--r--src/mame/video/ccastles.c366
-rw-r--r--src/mame/video/cchasm.c136
-rw-r--r--src/mame/video/cclimber.c935
-rw-r--r--src/mame/video/centiped.c520
-rw-r--r--src/mame/video/chaknpop.c286
-rw-r--r--src/mame/video/champbas.c151
-rw-r--r--src/mame/video/changela.c836
-rw-r--r--src/mame/video/cheekyms.c180
-rw-r--r--src/mame/video/chqflag.c87
-rw-r--r--src/mame/video/cinemat.c254
-rw-r--r--src/mame/video/circus.c272
-rw-r--r--src/mame/video/circusc.c199
-rw-r--r--src/mame/video/cischeat.c1375
-rw-r--r--src/mame/video/citycon.c170
-rw-r--r--src/mame/video/cloak.c231
-rw-r--r--src/mame/video/cloud9.c332
-rw-r--r--src/mame/video/clshroad.c359
-rw-r--r--src/mame/video/cninja.c526
-rw-r--r--src/mame/video/combatsc.c640
-rw-r--r--src/mame/video/commando.c140
-rw-r--r--src/mame/video/compgolf.c132
-rw-r--r--src/mame/video/contra.c281
-rw-r--r--src/mame/video/cop01.c226
-rw-r--r--src/mame/video/copsnrob.c159
-rw-r--r--src/mame/video/cosmic.c667
-rw-r--r--src/mame/video/cps1.c1955
-rw-r--r--src/mame/video/crbaloon.c167
-rw-r--r--src/mame/video/crgolf.c236
-rw-r--r--src/mame/video/crimfght.c86
-rw-r--r--src/mame/video/crospang.c210
-rw-r--r--src/mame/video/crshrace.c220
-rw-r--r--src/mame/video/csk.c273
-rw-r--r--src/mame/video/cvs.c639
-rw-r--r--src/mame/video/cyberbal.c411
-rw-r--r--src/mame/video/darius.c155
-rw-r--r--src/mame/video/darkmist.c225
-rw-r--r--src/mame/video/darkseal.c311
-rw-r--r--src/mame/video/dassault.c196
-rw-r--r--src/mame/video/dbz.c194
-rw-r--r--src/mame/video/dc.c48
-rw-r--r--src/mame/video/dcheese.c331
-rw-r--r--src/mame/video/dcon.c329
-rw-r--r--src/mame/video/dday.c379
-rw-r--r--src/mame/video/ddragon.c247
-rw-r--r--src/mame/video/ddragon3.c224
-rw-r--r--src/mame/video/ddrible.c247
-rw-r--r--src/mame/video/deadang.c158
-rw-r--r--src/mame/video/dec0.c720
-rw-r--r--src/mame/video/dec8.c823
-rw-r--r--src/mame/video/deco16ic.c1050
-rw-r--r--src/mame/video/deco32.c1633
-rw-r--r--src/mame/video/deco_mlc.c532
-rw-r--r--src/mame/video/decocass.c714
-rw-r--r--src/mame/video/deniam.c401
-rw-r--r--src/mame/video/destroyr.c90
-rw-r--r--src/mame/video/dietgo.c93
-rw-r--r--src/mame/video/digdug.c322
-rw-r--r--src/mame/video/diverboy.c53
-rw-r--r--src/mame/video/djboy.c83
-rw-r--r--src/mame/video/djmain.c194
-rw-r--r--src/mame/video/dkong.c891
-rw-r--r--src/mame/video/docastle.c225
-rw-r--r--src/mame/video/dogfgt.c243
-rw-r--r--src/mame/video/dooyong.c875
-rw-r--r--src/mame/video/dotrikun.c56
-rw-r--r--src/mame/video/dragrace.c81
-rw-r--r--src/mame/video/drgnmst.c209
-rw-r--r--src/mame/video/dribling.c85
-rw-r--r--src/mame/video/drmicro.c166
-rw-r--r--src/mame/video/dynax.c1341
-rw-r--r--src/mame/video/dynduke.c248
-rw-r--r--src/mame/video/eolith.c74
-rw-r--r--src/mame/video/epos.c95
-rw-r--r--src/mame/video/eprom.c270
-rw-r--r--src/mame/video/equites.c681
-rw-r--r--src/mame/video/esd16.c380
-rw-r--r--src/mame/video/espial.c243
-rw-r--r--src/mame/video/exctsccr.c247
-rw-r--r--src/mame/video/exedexes.c254
-rw-r--r--src/mame/video/exerion.c408
-rw-r--r--src/mame/video/exidy.c502
-rw-r--r--src/mame/video/exidy440.c463
-rw-r--r--src/mame/video/exprraid.c143
-rw-r--r--src/mame/video/exterm.c114
-rw-r--r--src/mame/video/exzisus.c229
-rw-r--r--src/mame/video/f1gp.c562
-rw-r--r--src/mame/video/fantland.c133
-rw-r--r--src/mame/video/fastfred.c407
-rw-r--r--src/mame/video/fastlane.c144
-rw-r--r--src/mame/video/fcombat.c236
-rw-r--r--src/mame/video/fgoal.c131
-rw-r--r--src/mame/video/finalizr.c266
-rw-r--r--src/mame/video/firetrap.c296
-rw-r--r--src/mame/video/firetrk.c468
-rw-r--r--src/mame/video/fitfight.c167
-rw-r--r--src/mame/video/flkatck.c163
-rw-r--r--src/mame/video/flower.c204
-rw-r--r--src/mame/video/flstory.c252
-rw-r--r--src/mame/video/flyball.c95
-rw-r--r--src/mame/video/foodf.c155
-rw-r--r--src/mame/video/freekick.c157
-rw-r--r--src/mame/video/fromanc2.c487
-rw-r--r--src/mame/video/fromance.c471
-rw-r--r--src/mame/video/funkybee.c175
-rw-r--r--src/mame/video/funkyjet.c90
-rw-r--r--src/mame/video/funworld.c128
-rw-r--r--src/mame/video/funybubl.c116
-rw-r--r--src/mame/video/fuukifg2.c353
-rw-r--r--src/mame/video/fuukifg3.c388
-rw-r--r--src/mame/video/gaelco.c254
-rw-r--r--src/mame/video/gaelco2.c510
-rw-r--r--src/mame/video/gaelco3d.c535
-rw-r--r--src/mame/video/gaiden.c577
-rw-r--r--src/mame/video/galaga.c610
-rw-r--r--src/mame/video/galaxian.c2243
-rw-r--r--src/mame/video/galivan.c443
-rw-r--r--src/mame/video/galpani2.c204
-rw-r--r--src/mame/video/galpanic.c136
-rw-r--r--src/mame/video/galspnbl.c144
-rw-r--r--src/mame/video/gaplus.c415
-rw-r--r--src/mame/video/gauntlet.c230
-rw-r--r--src/mame/video/gberet.c212
-rw-r--r--src/mame/video/gbusters.c77
-rw-r--r--src/mame/video/gcpinbal.c356
-rw-r--r--src/mame/video/gdrawpkr.c90
-rw-r--r--src/mame/video/genesis.c1382
-rw-r--r--src/mame/video/gijoe.c156
-rw-r--r--src/mame/video/ginganin.c290
-rw-r--r--src/mame/video/gladiatr.c309
-rw-r--r--src/mame/video/glass.c211
-rw-r--r--src/mame/video/gng.c160
-rw-r--r--src/mame/video/goal92.c187
-rw-r--r--src/mame/video/goindol.c143
-rw-r--r--src/mame/video/goldstar.c200
-rw-r--r--src/mame/video/gomoku.c235
-rw-r--r--src/mame/video/goodejan.c104
-rw-r--r--src/mame/video/gotcha.c135
-rw-r--r--src/mame/video/gottlieb.c221
-rw-r--r--src/mame/video/gotya.c192
-rw-r--r--src/mame/video/gradius3.c190
-rw-r--r--src/mame/video/grchamp.c552
-rw-r--r--src/mame/video/gridlee.c212
-rw-r--r--src/mame/video/groundfx.c283
-rw-r--r--src/mame/video/gstriker.c609
-rw-r--r--src/mame/video/gsword.c220
-rw-r--r--src/mame/video/gtia.c1135
-rw-r--r--src/mame/video/gtia.h156
-rw-r--r--src/mame/video/gticlub.c1033
-rw-r--r--src/mame/video/gticlub.h12
-rw-r--r--src/mame/video/gumbo.c51
-rw-r--r--src/mame/video/gunbustr.c254
-rw-r--r--src/mame/video/gundealr.c143
-rw-r--r--src/mame/video/gunsmoke.c216
-rw-r--r--src/mame/video/gyruss.c218
-rw-r--r--src/mame/video/hanaawas.c118
-rw-r--r--src/mame/video/harddriv.c489
-rw-r--r--src/mame/video/hcastle.c231
-rw-r--r--src/mame/video/hexa.c75
-rw-r--r--src/mame/video/hexion.c168
-rw-r--r--src/mame/video/higemaru.c140
-rw-r--r--src/mame/video/hnayayoi.c274
-rw-r--r--src/mame/video/hng64.c2083
-rw-r--r--src/mame/video/holeland.c196
-rw-r--r--src/mame/video/homedata.c882
-rw-r--r--src/mame/video/homerun.c114
-rw-r--r--src/mame/video/hyhoo.c247
-rw-r--r--src/mame/video/hyperspt.c189
-rw-r--r--src/mame/video/hyprduel.c680
-rw-r--r--src/mame/video/ikki.c201
-rw-r--r--src/mame/video/inufuku.c263
-rw-r--r--src/mame/video/iqblock.c103
-rw-r--r--src/mame/video/irobot.c390
-rw-r--r--src/mame/video/ironhors.c262
-rw-r--r--src/mame/video/itech32.c1486
-rw-r--r--src/mame/video/itech8.c670
-rw-r--r--src/mame/video/jack.c179
-rw-r--r--src/mame/video/jackal.c217
-rw-r--r--src/mame/video/jagblit.c480
-rw-r--r--src/mame/video/jagblit.h139
-rw-r--r--src/mame/video/jagobj.c986
-rw-r--r--src/mame/video/jaguar.c881
-rw-r--r--src/mame/video/jailbrek.c136
-rw-r--r--src/mame/video/jalblend.c180
-rw-r--r--src/mame/video/jcross.c194
-rw-r--r--src/mame/video/jedi.c394
-rw-r--r--src/mame/video/jpmimpct.c151
-rw-r--r--src/mame/video/kan_panb.c275
-rw-r--r--src/mame/video/kan_panb.h4
-rw-r--r--src/mame/video/kan_pand.c258
-rw-r--r--src/mame/video/kan_pand.h11
-rw-r--r--src/mame/video/kaneko16.c1057
-rw-r--r--src/mame/video/kangaroo.c308
-rw-r--r--src/mame/video/karnov.c261
-rw-r--r--src/mame/video/kchamp.c139
-rw-r--r--src/mame/video/kickgoal.c257
-rw-r--r--src/mame/video/kingobox.c297
-rw-r--r--src/mame/video/klax.c133
-rw-r--r--src/mame/video/kncljoe.c260
-rw-r--r--src/mame/video/konamigx.c498
-rw-r--r--src/mame/video/konamiic.c8340
-rw-r--r--src/mame/video/konamiic.h454
-rw-r--r--src/mame/video/kopunch.c124
-rw-r--r--src/mame/video/ksayakyu.c116
-rw-r--r--src/mame/video/kyugo.c232
-rw-r--r--src/mame/video/labyrunr.c242
-rw-r--r--src/mame/video/ladybug.c475
-rw-r--r--src/mame/video/ladyfrog.c155
-rw-r--r--src/mame/video/lasso.c403
-rw-r--r--src/mame/video/lastduel.c253
-rw-r--r--src/mame/video/lazercmd.c85
-rw-r--r--src/mame/video/legionna.c450
-rw-r--r--src/mame/video/leland.c573
-rw-r--r--src/mame/video/lemmings.c199
-rw-r--r--src/mame/video/lethal.c146
-rw-r--r--src/mame/video/lethalj.c200
-rw-r--r--src/mame/video/liberate.c419
-rw-r--r--src/mame/video/liberatr.c377
-rw-r--r--src/mame/video/lkage.c210
-rw-r--r--src/mame/video/lordgun.c305
-rw-r--r--src/mame/video/lsasquad.c221
-rw-r--r--src/mame/video/lvcards.c115
-rw-r--r--src/mame/video/lwings.c293
-rw-r--r--src/mame/video/m107.c320
-rw-r--r--src/mame/video/m3raster.c283
-rw-r--r--src/mame/video/m62.c893
-rw-r--r--src/mame/video/m72.c597
-rw-r--r--src/mame/video/m79amb.c42
-rw-r--r--src/mame/video/m90.c261
-rw-r--r--src/mame/video/m92.c471
-rw-r--r--src/mame/video/macrossp.c414
-rw-r--r--src/mame/video/madmotor.c297
-rw-r--r--src/mame/video/magmax.c373
-rw-r--r--src/mame/video/mainevt.c115
-rw-r--r--src/mame/video/mainsnk.c205
-rw-r--r--src/mame/video/malzak.c230
-rw-r--r--src/mame/video/mappy.c590
-rw-r--r--src/mame/video/marineb.c472
-rw-r--r--src/mame/video/mario.c157
-rw-r--r--src/mame/video/markham.c139
-rw-r--r--src/mame/video/marvins.c434
-rw-r--r--src/mame/video/matmania.c358
-rw-r--r--src/mame/video/mayumi.c47
-rw-r--r--src/mame/video/mcatadv.c273
-rw-r--r--src/mame/video/mcr.c417
-rw-r--r--src/mame/video/mcr3.c292
-rw-r--r--src/mame/video/mcr68.c335
-rw-r--r--src/mame/video/meadows.c113
-rw-r--r--src/mame/video/megasys1.c1022
-rw-r--r--src/mame/video/megazone.c222
-rw-r--r--src/mame/video/mermaid.c197
-rw-r--r--src/mame/video/metlclsh.c256
-rw-r--r--src/mame/video/metro.c934
-rw-r--r--src/mame/video/mexico86.c249
-rw-r--r--src/mame/video/midtunit.c842
-rw-r--r--src/mame/video/midvunit.c573
-rw-r--r--src/mame/video/midyunit.c623
-rw-r--r--src/mame/video/midzeus.c1157
-rw-r--r--src/mame/video/mikie.c171
-rw-r--r--src/mame/video/mitchell.c288
-rw-r--r--src/mame/video/mjkjidai.c141
-rw-r--r--src/mame/video/mjsister.c111
-rw-r--r--src/mame/video/mnight.c206
-rw-r--r--src/mame/video/model1.c1535
-rw-r--r--src/mame/video/model2.c2773
-rw-r--r--src/mame/video/model2rd.c191
-rw-r--r--src/mame/video/model3.c1512
-rw-r--r--src/mame/video/mole.c59
-rw-r--r--src/mame/video/momoko.c324
-rw-r--r--src/mame/video/moo.c169
-rw-r--r--src/mame/video/mosaic.c87
-rw-r--r--src/mame/video/mouser.c190
-rw-r--r--src/mame/video/mpatrol.c391
-rw-r--r--src/mame/video/mrdo.c240
-rw-r--r--src/mame/video/mrflea.c97
-rw-r--r--src/mame/video/mrjong.c139
-rw-r--r--src/mame/video/ms32.c510
-rw-r--r--src/mame/video/msisaac.c251
-rw-r--r--src/mame/video/mugsmash.c155
-rw-r--r--src/mame/video/munchmo.c197
-rw-r--r--src/mame/video/mustache.c143
-rw-r--r--src/mame/video/mw8080bw.c391
-rw-r--r--src/mame/video/mystston.c172
-rw-r--r--src/mame/video/mystwarr.c555
-rw-r--r--src/mame/video/n64.c3479
-rw-r--r--src/mame/video/n8080.c405
-rw-r--r--src/mame/video/namcofl.c184
-rw-r--r--src/mame/video/namcona1.c667
-rw-r--r--src/mame/video/namconb1.c289
-rw-r--r--src/mame/video/namcos1.c420
-rw-r--r--src/mame/video/namcos2.c496
-rw-r--r--src/mame/video/namcos21.c489
-rw-r--r--src/mame/video/namcos22.c2485
-rw-r--r--src/mame/video/namcos86.c400
-rw-r--r--src/mame/video/naughtyb.c332
-rw-r--r--src/mame/video/nbmj8688.c747
-rw-r--r--src/mame/video/nbmj8891.c569
-rw-r--r--src/mame/video/nbmj8991.c385
-rw-r--r--src/mame/video/nbmj9195.c526
-rw-r--r--src/mame/video/nemesis.c459
-rw-r--r--src/mame/video/neogeo.c931
-rw-r--r--src/mame/video/news.c103
-rw-r--r--src/mame/video/ninjakd2.c158
-rw-r--r--src/mame/video/ninjakid.c302
-rw-r--r--src/mame/video/ninjaw.c169
-rw-r--r--src/mame/video/nitedrvr.c81
-rw-r--r--src/mame/video/niyanpai.c454
-rw-r--r--src/mame/video/nmk16.c884
-rw-r--r--src/mame/video/nova2001.c194
-rw-r--r--src/mame/video/nycaptor.c309
-rw-r--r--src/mame/video/offtwall.c118
-rw-r--r--src/mame/video/ohmygod.c114
-rw-r--r--src/mame/video/ojankohs.c333
-rw-r--r--src/mame/video/omegaf.c615
-rw-r--r--src/mame/video/oneshot.c198
-rw-r--r--src/mame/video/orbit.c109
-rw-r--r--src/mame/video/othldrby.c224
-rw-r--r--src/mame/video/othunder.c346
-rw-r--r--src/mame/video/overdriv.c87
-rw-r--r--src/mame/video/pacland.c407
-rw-r--r--src/mame/video/pacman.c603
-rw-r--r--src/mame/video/pandoras.c167
-rw-r--r--src/mame/video/paradise.c324
-rw-r--r--src/mame/video/parodius.c98
-rw-r--r--src/mame/video/pass.c66
-rw-r--r--src/mame/video/pastelg.c303
-rw-r--r--src/mame/video/pbaction.c134
-rw-r--r--src/mame/video/pcktgal.c100
-rw-r--r--src/mame/video/pgm.c352
-rw-r--r--src/mame/video/phoenix.c338
-rw-r--r--src/mame/video/pingpong.c156
-rw-r--r--src/mame/video/pirates.c117
-rw-r--r--src/mame/video/pitnrun.c291
-rw-r--r--src/mame/video/pktgaldx.c158
-rw-r--r--src/mame/video/pkunwar.c117
-rw-r--r--src/mame/video/playch10.c174
-rw-r--r--src/mame/video/playmark.c477
-rw-r--r--src/mame/video/plygonet.c93
-rw-r--r--src/mame/video/pokechmp.c74
-rw-r--r--src/mame/video/polepos.c532
-rw-r--r--src/mame/video/policetr.c370
-rw-r--r--src/mame/video/polyplay.c71
-rw-r--r--src/mame/video/poolshrk.c55
-rw-r--r--src/mame/video/pooyan.c134
-rw-r--r--src/mame/video/popeye.c388
-rw-r--r--src/mame/video/popper.c244
-rw-r--r--src/mame/video/portrait.c171
-rw-r--r--src/mame/video/powerins.c373
-rw-r--r--src/mame/video/ppu2c0x.c1578
-rw-r--r--src/mame/video/ppu2c0x.h129
-rw-r--r--src/mame/video/prehisle.c154
-rw-r--r--src/mame/video/psikyo.c599
-rw-r--r--src/mame/video/psikyo4.c144
-rw-r--r--src/mame/video/psikyosh.c1158
-rw-r--r--src/mame/video/psx.c3925
-rw-r--r--src/mame/video/psychic5.c467
-rw-r--r--src/mame/video/punchout.c438
-rw-r--r--src/mame/video/pushman.c119
-rw-r--r--src/mame/video/qdrmfgp.c69
-rw-r--r--src/mame/video/qix.c334
-rw-r--r--src/mame/video/quasar.c283
-rw-r--r--src/mame/video/quizdna.c202
-rw-r--r--src/mame/video/quizpani.c91
-rw-r--r--src/mame/video/raiden.c164
-rw-r--r--src/mame/video/raiders5.c233
-rw-r--r--src/mame/video/rallyx.c581
-rw-r--r--src/mame/video/rampart.c212
-rw-r--r--src/mame/video/rastan.c222
-rw-r--r--src/mame/video/realbrk.c638
-rw-r--r--src/mame/video/redalert.c304
-rw-r--r--src/mame/video/redclash.c417
-rw-r--r--src/mame/video/relief.c173
-rw-r--r--src/mame/video/renegade.c143
-rw-r--r--src/mame/video/retofinv.c247
-rw-r--r--src/mame/video/rockola.c310
-rw-r--r--src/mame/video/rockrage.c95
-rw-r--r--src/mame/video/rocnrope.c130
-rw-r--r--src/mame/video/rohga.c545
-rw-r--r--src/mame/video/rollerg.c76
-rw-r--r--src/mame/video/rollrace.c170
-rw-r--r--src/mame/video/route16.c195
-rw-r--r--src/mame/video/rpunch.c291
-rw-r--r--src/mame/video/runaway.c159
-rw-r--r--src/mame/video/rungun.c130
-rw-r--r--src/mame/video/sauro.c217
-rw-r--r--src/mame/video/sbasketb.c173
-rw-r--r--src/mame/video/sbrkout.c58
-rw-r--r--src/mame/video/sbugger.c60
-rw-r--r--src/mame/video/scotrsht.c169
-rw-r--r--src/mame/video/sderby.c142
-rw-r--r--src/mame/video/segag80r.c865
-rw-r--r--src/mame/video/segag80v.c343
-rw-r--r--src/mame/video/segahang.c93
-rw-r--r--src/mame/video/segaic16.c3588
-rw-r--r--src/mame/video/segaic16.h89
-rw-r--r--src/mame/video/segaic24.c895
-rw-r--r--src/mame/video/segaic24.h45
-rw-r--r--src/mame/video/segaorun.c122
-rw-r--r--src/mame/video/segas16a.c70
-rw-r--r--src/mame/video/segas16b.c82
-rw-r--r--src/mame/video/segas18.c257
-rw-r--r--src/mame/video/segas32.c2847
-rw-r--r--src/mame/video/segasyse.c563
-rw-r--r--src/mame/video/segaxbd.c102
-rw-r--r--src/mame/video/segaybd.c75
-rw-r--r--src/mame/video/seibuspi.c665
-rw-r--r--src/mame/video/seicross.c149
-rw-r--r--src/mame/video/sengokmj.c129
-rw-r--r--src/mame/video/senjyo.c411
-rw-r--r--src/mame/video/seta.c965
-rw-r--r--src/mame/video/seta2.c390
-rw-r--r--src/mame/video/sf.c240
-rw-r--r--src/mame/video/shadfrce.c180
-rw-r--r--src/mame/video/shangha3.c268
-rw-r--r--src/mame/video/shangkid.c298
-rw-r--r--src/mame/video/shaolins.c195
-rw-r--r--src/mame/video/shisen.c65
-rw-r--r--src/mame/video/shootout.c175
-rw-r--r--src/mame/video/shuuz.c140
-rw-r--r--src/mame/video/sidearms.c363
-rw-r--r--src/mame/video/sidepckt.c149
-rw-r--r--src/mame/video/silkroad.c189
-rw-r--r--src/mame/video/simpl156.c156
-rw-r--r--src/mame/video/simpsons.c181
-rw-r--r--src/mame/video/skullxbo.c309
-rw-r--r--src/mame/video/skychut.c138
-rw-r--r--src/mame/video/skydiver.c212
-rw-r--r--src/mame/video/skyfox.c294
-rw-r--r--src/mame/video/skykid.c273
-rw-r--r--src/mame/video/skyraid.c159
-rw-r--r--src/mame/video/slapfght.c254
-rw-r--r--src/mame/video/slapshot.c633
-rw-r--r--src/mame/video/snes.c2208
-rw-r--r--src/mame/video/snk.c631
-rw-r--r--src/mame/video/snk68.c299
-rw-r--r--src/mame/video/solomon.c107
-rw-r--r--src/mame/video/sonson.c171
-rw-r--r--src/mame/video/spacefb.c471
-rw-r--r--src/mame/video/spbactn.c281
-rw-r--r--src/mame/video/spcforce.c55
-rw-r--r--src/mame/video/spdodgeb.c221
-rw-r--r--src/mame/video/speedatk.c109
-rw-r--r--src/mame/video/speedbal.c135
-rw-r--r--src/mame/video/speedspn.c113
-rw-r--r--src/mame/video/splash.c292
-rw-r--r--src/mame/video/sprcros2.c169
-rw-r--r--src/mame/video/sprint2.c196
-rw-r--r--src/mame/video/sprint4.c163
-rw-r--r--src/mame/video/sprint8.c157
-rw-r--r--src/mame/video/spy.c84
-rw-r--r--src/mame/video/srmp2.c462
-rw-r--r--src/mame/video/srumbler.c174
-rw-r--r--src/mame/video/sshangha.c258
-rw-r--r--src/mame/video/sslam.c216
-rw-r--r--src/mame/video/ssozumo.c181
-rw-r--r--src/mame/video/sspeedr.c274
-rw-r--r--src/mame/video/ssrj.c292
-rw-r--r--src/mame/video/ssv.c1169
-rw-r--r--src/mame/video/st0016.c685
-rw-r--r--src/mame/video/stactics.c878
-rw-r--r--src/mame/video/stadhero.c169
-rw-r--r--src/mame/video/starcrus.c572
-rw-r--r--src/mame/video/starfire.c276
-rw-r--r--src/mame/video/starshp1.c432
-rw-r--r--src/mame/video/stfight.c300
-rw-r--r--src/mame/video/stlforce.c196
-rw-r--r--src/mame/video/strnskil.c148
-rw-r--r--src/mame/video/stvvdp1.c2147
-rw-r--r--src/mame/video/stvvdp2.c6291
-rw-r--r--src/mame/video/subs.c163
-rw-r--r--src/mame/video/suna16.c245
-rw-r--r--src/mame/video/suna8.c449
-rw-r--r--src/mame/video/supbtime.c103
-rw-r--r--src/mame/video/superchs.c251
-rw-r--r--src/mame/video/superqix.c260
-rw-r--r--src/mame/video/suprloco.c277
-rw-r--r--src/mame/video/suprnova.c973
-rw-r--r--src/mame/video/suprridr.c212
-rw-r--r--src/mame/video/suprslam.c174
-rw-r--r--src/mame/video/surpratk.c99
-rw-r--r--src/mame/video/sys16spr.c188
-rw-r--r--src/mame/video/system1.c904
-rw-r--r--src/mame/video/system1.h50
-rw-r--r--src/mame/video/system16.c1147
-rw-r--r--src/mame/video/system24.c54
-rw-r--r--src/mame/video/tagteam.c187
-rw-r--r--src/mame/video/tail2nos.c214
-rw-r--r--src/mame/video/taito_b.c635
-rw-r--r--src/mame/video/taito_f2.c1442
-rw-r--r--src/mame/video/taito_f3.c3321
-rw-r--r--src/mame/video/taito_h.c502
-rw-r--r--src/mame/video/taito_l.c352
-rw-r--r--src/mame/video/taito_z.c1032
-rw-r--r--src/mame/video/taitoair.c420
-rw-r--r--src/mame/video/taitoic.c5263
-rw-r--r--src/mame/video/taitoic.h234
-rw-r--r--src/mame/video/taitojc.c644
-rw-r--r--src/mame/video/taitosj.c934
-rw-r--r--src/mame/video/tank8.c275
-rw-r--r--src/mame/video/tankbatt.c110
-rw-r--r--src/mame/video/tankbust.c253
-rw-r--r--src/mame/video/taotaido.c241
-rw-r--r--src/mame/video/targeth.c150
-rw-r--r--src/mame/video/tatsumi.c997
-rw-r--r--src/mame/video/taxidrvr.c157
-rw-r--r--src/mame/video/tbowl.c250
-rw-r--r--src/mame/video/tceptor.c597
-rw-r--r--src/mame/video/tecmo.c252
-rw-r--r--src/mame/video/tecmo16.c507
-rw-r--r--src/mame/video/tehkanwc.c200
-rw-r--r--src/mame/video/terracre.c224
-rw-r--r--src/mame/video/tetrisp2.c797
-rw-r--r--src/mame/video/thedeep.c236
-rw-r--r--src/mame/video/thepit.c312
-rw-r--r--src/mame/video/thief.c314
-rw-r--r--src/mame/video/thoop2.c242
-rw-r--r--src/mame/video/thunderj.c296
-rw-r--r--src/mame/video/thunderx.c91
-rw-r--r--src/mame/video/tia.c2004
-rw-r--r--src/mame/video/tia.h26
-rw-r--r--src/mame/video/tiamc1.c210
-rw-r--r--src/mame/video/tickee.c121
-rw-r--r--src/mame/video/tigeroad.c170
-rw-r--r--src/mame/video/timelimt.c152
-rw-r--r--src/mame/video/timeplt.c224
-rw-r--r--src/mame/video/tmnt.c815
-rw-r--r--src/mame/video/tnzs.c236
-rw-r--r--src/mame/video/toaplan1.c1246
-rw-r--r--src/mame/video/toaplan2.c1619
-rw-r--r--src/mame/video/toki.c321
-rw-r--r--src/mame/video/toobin.c270
-rw-r--r--src/mame/video/topspeed.c199
-rw-r--r--src/mame/video/toypop.c236
-rw-r--r--src/mame/video/tp84.c289
-rw-r--r--src/mame/video/trackfld.c230
-rw-r--r--src/mame/video/travrusa.c332
-rw-r--r--src/mame/video/triplhnt.c148
-rw-r--r--src/mame/video/troangel.c239
-rw-r--r--src/mame/video/truco.c54
-rw-r--r--src/mame/video/trucocl.c82
-rw-r--r--src/mame/video/tryout.c263
-rw-r--r--src/mame/video/tsamurai.c277
-rw-r--r--src/mame/video/tubep.c926
-rw-r--r--src/mame/video/tumbleb.c840
-rw-r--r--src/mame/video/tumblep.c100
-rw-r--r--src/mame/video/tunhunt.c412
-rw-r--r--src/mame/video/turbo.c1094
-rw-r--r--src/mame/video/tutankhm.c164
-rw-r--r--src/mame/video/twin16.c463
-rw-r--r--src/mame/video/twincobr.c521
-rw-r--r--src/mame/video/tx1.c406
-rw-r--r--src/mame/video/ultraman.c135
-rw-r--r--src/mame/video/ultratnk.c164
-rw-r--r--src/mame/video/undrfire.c371
-rw-r--r--src/mame/video/unico.c412
-rw-r--r--src/mame/video/usgames.c74
-rw-r--r--src/mame/video/vaportra.c187
-rw-r--r--src/mame/video/vastar.c229
-rw-r--r--src/mame/video/vball.c191
-rw-r--r--src/mame/video/vendetta.c124
-rw-r--r--src/mame/video/vertigo.c656
-rw-r--r--src/mame/video/vicdual.c151
-rw-r--r--src/mame/video/victory.c1231
-rw-r--r--src/mame/video/videopin.c116
-rw-r--r--src/mame/video/vigilant.c342
-rw-r--r--src/mame/video/vindictr.c303
-rw-r--r--src/mame/video/volfied.c139
-rw-r--r--src/mame/video/vrender0.c522
-rw-r--r--src/mame/video/vrender0.h2
-rw-r--r--src/mame/video/vsnes.c76
-rw-r--r--src/mame/video/vulgus.c229
-rw-r--r--src/mame/video/warpwarp.c269
-rw-r--r--src/mame/video/warriorb.c138
-rw-r--r--src/mame/video/wc90.c386
-rw-r--r--src/mame/video/wc90b.c151
-rw-r--r--src/mame/video/wecleman.c1132
-rw-r--r--src/mame/video/welltris.c250
-rw-r--r--src/mame/video/wgp.c774
-rw-r--r--src/mame/video/williams.c777
-rw-r--r--src/mame/video/wiping.c219
-rw-r--r--src/mame/video/wiz.c301
-rw-r--r--src/mame/video/wolfpack.c327
-rw-r--r--src/mame/video/wrally.c172
-rw-r--r--src/mame/video/wwfsstar.c225
-rw-r--r--src/mame/video/wwfwfest.c284
-rw-r--r--src/mame/video/xain.c275
-rw-r--r--src/mame/video/xevious.c518
-rw-r--r--src/mame/video/xexex.c143
-rw-r--r--src/mame/video/xmen.c258
-rw-r--r--src/mame/video/xorworld.c115
-rw-r--r--src/mame/video/xxmissio.c201
-rw-r--r--src/mame/video/xybots.c166
-rw-r--r--src/mame/video/xyonix.c63
-rw-r--r--src/mame/video/yard.c281
-rw-r--r--src/mame/video/ygv608.c1801
-rw-r--r--src/mame/video/ygv608.h342
-rw-r--r--src/mame/video/yiear.c150
-rw-r--r--src/mame/video/yunsun16.c237
-rw-r--r--src/mame/video/yunsung8.c206
-rw-r--r--src/mame/video/zac2650.c242
-rw-r--r--src/mame/video/zaccaria.c291
-rw-r--r--src/mame/video/zaxxon.c487
-rw-r--r--src/mame/video/zerozone.c50
-rw-r--r--src/mame/video/zodiack.c219
704 files changed, 282428 insertions, 0 deletions
diff --git a/src/mame/video/1942.c b/src/mame/video/1942.c
new file mode 100644
index 00000000000..71b8bb5461b
--- /dev/null
+++ b/src/mame/video/1942.c
@@ -0,0 +1,248 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *c1942_fgvideoram;
+UINT8 *c1942_bgvideoram;
+
+static int c1942_palette_bank;
+static tilemap *fg_tilemap, *bg_tilemap;
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ 1942 has three 256x4 palette PROMs (one per gun) and three 256x4 lookup
+ table PROMs (one for characters, one for sprites, one for background tiles).
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+PALETTE_INIT( 1942 )
+{
+ rgb_t palette[256];
+ int i, colorbase;
+
+ for (i = 0; i < 256; i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i + 0*256] >> 0) & 0x01;
+ bit1 = (color_prom[i + 0*256] >> 1) & 0x01;
+ bit2 = (color_prom[i + 0*256] >> 2) & 0x01;
+ bit3 = (color_prom[i + 0*256] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* green component */
+ bit0 = (color_prom[i + 1*256] >> 0) & 0x01;
+ bit1 = (color_prom[i + 1*256] >> 1) & 0x01;
+ bit2 = (color_prom[i + 1*256] >> 2) & 0x01;
+ bit3 = (color_prom[i + 1*256] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* blue component */
+ bit0 = (color_prom[i + 2*256] >> 0) & 0x01;
+ bit1 = (color_prom[i + 2*256] >> 1) & 0x01;
+ bit2 = (color_prom[i + 2*256] >> 2) & 0x01;
+ bit3 = (color_prom[i + 2*256] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette[i] = MAKE_RGB(r,g,b);
+ }
+
+ color_prom += 3*256;
+ /* color_prom now points to the beginning of the lookup table */
+
+
+ /* characters use palette entries 128-143 */
+ colorbase = 0;
+ for (i = 0; i < 64*4; i++)
+ palette_set_color(machine, colorbase + i, palette[0x80 | *color_prom++]);
+ colorbase += 64*4;
+
+ /* background tiles use palette entries 0-63 in four banks */
+ for (i = 0; i < 32*8; i++)
+ {
+ palette_set_color(machine, colorbase + 0*32*8 + i, palette[0x00 | *color_prom]);
+ palette_set_color(machine, colorbase + 1*32*8 + i, palette[0x10 | *color_prom]);
+ palette_set_color(machine, colorbase + 2*32*8 + i, palette[0x20 | *color_prom]);
+ palette_set_color(machine, colorbase + 3*32*8 + i, palette[0x30 | *color_prom]);
+ color_prom++;
+ }
+ colorbase += 4*32*8;
+
+ /* sprites use palette entries 64-79 */
+ for (i = 0; i < 16*16; i++)
+ palette_set_color(machine, colorbase + i, palette[0x40 | *color_prom++]);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code, color;
+
+ code = c1942_fgvideoram[tile_index];
+ color = c1942_fgvideoram[tile_index + 0x400];
+ SET_TILE_INFO(
+ 0,
+ code + ((color & 0x80) << 1),
+ color & 0x3f,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code, color;
+
+ tile_index = (tile_index & 0x0f) | ((tile_index & 0x01f0) << 1);
+
+ code = c1942_bgvideoram[tile_index];
+ color = c1942_bgvideoram[tile_index + 0x10];
+ SET_TILE_INFO(
+ 1,
+ code + ((color & 0x80) << 1),
+ (color & 0x1f) + (0x20 * c1942_palette_bank),
+ TILE_FLIPYX((color & 0x60) >> 5));
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+VIDEO_START( 1942 )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 16,16,32,16);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ state_save_register_global(c1942_palette_bank);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( c1942_fgvideoram_w )
+{
+ c1942_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( c1942_bgvideoram_w )
+{
+ c1942_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,(offset & 0x0f) | ((offset >> 1) & 0x01f0));
+}
+
+
+WRITE8_HANDLER( c1942_palette_bank_w )
+{
+ if (c1942_palette_bank != data)
+ {
+ c1942_palette_bank = data;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+WRITE8_HANDLER( c1942_scroll_w )
+{
+ static UINT8 scroll[2];
+
+ scroll[offset] = data;
+ tilemap_set_scrollx(bg_tilemap,0,scroll[0] | (scroll[1] << 8));
+}
+
+
+WRITE8_HANDLER( c1942_c804_w )
+{
+ /* bit 7: flip screen
+ bit 4: cpu B reset
+ bit 0: coin counter */
+
+ coin_counter_w(0,data & 0x01);
+
+ cpunum_set_input_line(1, INPUT_LINE_RESET, (data & 0x10) ? ASSERT_LINE : CLEAR_LINE);
+
+ flip_screen_set(data & 0x80);
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int i,code,col,sx,sy,dir;
+
+
+ code = (spriteram[offs] & 0x7f) + 4*(spriteram[offs + 1] & 0x20)
+ + 2*(spriteram[offs] & 0x80);
+ col = spriteram[offs + 1] & 0x0f;
+ sx = spriteram[offs + 3] - 0x10 * (spriteram[offs + 1] & 0x10);
+ sy = spriteram[offs + 2];
+ dir = 1;
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ dir = -1;
+ }
+
+ /* handle double / quadruple height */
+ i = (spriteram[offs + 1] & 0xc0) >> 6;
+ if (i == 2) i = 3;
+
+ do
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ code + i,col,
+ flip_screen,flip_screen,
+ sx,sy + 16 * i * dir,
+ cliprect,TRANSPARENCY_PEN,15);
+
+ i--;
+ } while (i >= 0);
+ }
+
+
+}
+
+VIDEO_UPDATE( 1942 )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/1943.c b/src/mame/video/1943.c
new file mode 100644
index 00000000000..7f336789196
--- /dev/null
+++ b/src/mame/video/1943.c
@@ -0,0 +1,249 @@
+#include "driver.h"
+
+#define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+#define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+UINT8 *c1943_scrollx;
+UINT8 *c1943_scrolly;
+UINT8 *c1943_bgscrollx;
+
+static int chon, objon, sc1on, sc2on;
+
+static tilemap *bg2_tilemap, *bg_tilemap, *fg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ 1943 has three 256x4 palette PROMs (one per gun) and a lot ;-) of 256x4
+ lookup table PROMs.
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+PALETTE_INIT( 1943 )
+{
+ int i;
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int bit0, bit1, bit2, bit3, r, g, b;
+
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ bit3 = (color_prom[i] >> 3) & 0x01;
+
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[i + machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[i + machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[i + machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[i + machine->drv->total_colors] >> 3) & 0x01;
+
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[i + 2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[i + 2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[i + 2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[i + 2*machine->drv->total_colors] >> 3) & 0x01;
+
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ }
+
+ color_prom += 3*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* characters use colors 64-79 */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = *(color_prom++) + 64;
+ color_prom += 128; /* skip the bottom half of the PROM - not used */
+
+ /* foreground tiles use colors 0-63 */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ {
+ /* color 0 MUST map to pen 0 in order for transparency to work */
+ if (i % machine->gfx[1]->color_granularity == 0)
+ COLOR(1,i) = 0;
+ else
+ COLOR(1,i) = color_prom[0] + 16 * (color_prom[256] & 0x03);
+ color_prom++;
+ }
+ color_prom += TOTAL_COLORS(1);
+
+ /* background tiles use colors 0-63 */
+ for (i = 0;i < TOTAL_COLORS(2);i++)
+ {
+ COLOR(2,i) = color_prom[0] + 16 * (color_prom[256] & 0x03);
+ color_prom++;
+ }
+ color_prom += TOTAL_COLORS(2);
+
+ /* sprites use colors 128-255 */
+ /* bit 3 of BMPROM.07 selects priority over the background, but we handle */
+ /* it differently for speed reasons */
+ for (i = 0;i < TOTAL_COLORS(3);i++)
+ {
+ COLOR(3,i) = color_prom[0] + 16 * (color_prom[256] & 0x07) + 128;
+ color_prom++;
+ }
+ color_prom += TOTAL_COLORS(3);
+}
+
+WRITE8_HANDLER( c1943_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( c1943_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( c1943_c804_w )
+{
+ int bankaddress;
+ UINT8 *RAM = memory_region(REGION_CPU1);
+
+ /* bits 0 and 1 are coin counters */
+ coin_counter_w(0, data & 0x01);
+ coin_counter_w(1, data & 0x02);
+
+ /* bits 2, 3 and 4 select the ROM bank */
+ bankaddress = 0x10000 + (data & 0x1c) * 0x1000;
+ memory_set_bankptr(1, &RAM[bankaddress]);
+
+ /* bit 5 resets the sound CPU - we ignore it */
+
+ /* bit 6 flips screen */
+ flip_screen_set(data & 0x40);
+
+ /* bit 7 enables characters */
+ chon = data & 0x80;
+}
+
+WRITE8_HANDLER( c1943_d806_w )
+{
+ /* bit 4 enables bg 1 */
+ sc1on = data & 0x10;
+
+ /* bit 5 enables bg 2 */
+ sc2on = data & 0x20;
+
+ /* bit 6 enables sprites */
+ objon = data & 0x40;
+}
+
+static TILE_GET_INFO( c1943_get_bg2_tile_info )
+{
+ UINT8 *tilerom = memory_region(REGION_GFX5) + 0x8000;
+
+ int offs = tile_index * 2;
+ int attr = tilerom[offs + 1];
+ int code = tilerom[offs];
+ int color = (attr & 0x3c) >> 2;
+ int flags = TILE_FLIPYX((attr & 0xc0) >> 6);
+
+ SET_TILE_INFO(2, code, color, flags);
+}
+
+static TILE_GET_INFO( c1943_get_bg_tile_info )
+{
+ UINT8 *tilerom = memory_region(REGION_GFX5);
+
+ int offs = tile_index * 2;
+ int attr = tilerom[offs + 1];
+ int code = tilerom[offs] + ((attr & 0x01) << 8);
+ int color = (attr & 0x3c) >> 2;
+ int flags = TILE_FLIPYX((attr & 0xc0) >> 6);
+
+ SET_TILE_INFO(1, code, color, flags);
+}
+
+static TILE_GET_INFO( c1943_get_fg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + ((attr & 0xe0) << 3);
+ int color = attr & 0x1f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( 1943 )
+{
+ bg2_tilemap = tilemap_create(c1943_get_bg2_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 2048, 8);
+
+ bg_tilemap = tilemap_create(c1943_get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 2048, 8);
+
+ fg_tilemap = tilemap_create(c1943_get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(bg_tilemap, 0);
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int offs;
+
+ for (offs = spriteram_size - 32; offs >= 0; offs -= 32)
+ {
+ int attr = spriteram[offs + 1];
+ int code = spriteram[offs] + ((attr & 0xe0) << 3);
+ int color = attr & 0x0f;
+ int sx = spriteram[offs + 3] - ((attr & 0x10) << 4);
+ int sy = spriteram[offs + 2];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ }
+
+ // the priority is actually selected by bit 3 of BMPROM.07
+ if (priority)
+ {
+ if (color != 0x0a && color != 0x0b)
+ {
+ drawgfx(bitmap, machine->gfx[3], code, color, flip_screen, flip_screen,
+ sx, sy, cliprect, TRANSPARENCY_PEN, 0);
+ }
+ }
+ else
+ {
+ if (color == 0x0a || color == 0x0b)
+ {
+ drawgfx(bitmap, machine->gfx[3], code, color, flip_screen, flip_screen,
+ sx, sy, cliprect, TRANSPARENCY_PEN, 0);
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( 1943 )
+{
+ tilemap_set_scrollx(bg2_tilemap, 0, c1943_bgscrollx[0] + 256 * c1943_bgscrollx[1]);
+ tilemap_set_scrollx(bg_tilemap, 0, c1943_scrollx[0] + 256 * c1943_scrollx[1]);
+ tilemap_set_scrolly(bg_tilemap, 0, c1943_scrolly[0]);
+
+ if (sc2on)
+ tilemap_draw(bitmap, cliprect, bg2_tilemap, 0, 0);
+ else
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ if (objon) draw_sprites(machine, bitmap, cliprect, 0);
+ if (sc1on) tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ if (objon) draw_sprites(machine, bitmap, cliprect, 1);
+ if (chon) tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/20pacgal.c b/src/mame/video/20pacgal.c
new file mode 100644
index 00000000000..230762173a9
--- /dev/null
+++ b/src/mame/video/20pacgal.c
@@ -0,0 +1,203 @@
+#include "driver.h"
+
+
+
+UINT8 *pacgal_charram,*pacgal_sprram;
+UINT8 *pacgal_videoram,*pacgal_videoram2;
+
+static mame_bitmap *chr_bitmap;
+static int palbank;
+static int active_game;
+
+
+
+static void switch_palette(running_machine *machine)
+{
+ int i;
+ UINT8 *color_prom = memory_region(REGION_PROMS) + 0x1000 * palbank;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+PALETTE_INIT( 20pacgal )
+{
+ palbank = 0;
+ switch_palette(machine);
+}
+
+
+
+VIDEO_START( 20pacgal )
+{
+ chr_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+}
+
+
+
+WRITE8_HANDLER( pacgal_lookup_w )
+{
+ /* palette hacks! */
+ ((UINT16 *)Machine->game_colortable)[offset] = data & 0x0f;
+ ((pen_t *)Machine->remapped_colortable)[offset] = Machine->pens[data & 0x0f];
+}
+
+WRITE8_HANDLER( pacgal_active_game_w )
+{
+ active_game = data & 1;
+
+ if (!active_game)
+ memcpy(pacgal_videoram2,memory_region(REGION_CPU1)+0x8000,0x2000);
+
+ if (palbank != active_game)
+ {
+ palbank = active_game;
+ switch_palette(Machine);
+ }
+}
+
+WRITE8_HANDLER( pacgal_videoram2_w )
+{
+ if (active_game)
+ pacgal_videoram2[offset] = data;
+}
+
+WRITE8_HANDLER( pacgal_charram_w )
+{
+ pacgal_charram[offset] = data;
+
+ decodechar(Machine->gfx[0],offset/16,pacgal_charram,Machine->drv->gfxdecodeinfo[0].gfxlayout);
+}
+
+WRITE8_HANDLER( pacgal_sprram_w )
+{
+ offset = (offset & 0x1f83) | ((offset & 0x078) >> 1) | ((offset & 0x004) << 4);
+ pacgal_sprram[offset] = data;
+
+ decodechar(Machine->gfx[1],offset/64,pacgal_sprram,Machine->drv->gfxdecodeinfo[1].gfxlayout);
+}
+
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+
+ for (offs = 0x80-2;offs >= 0;offs-=2)
+ {
+ static int gfx_offs[2][2] =
+ {
+ { 0, 1 },
+ { 2, 3 }
+ };
+ int sprite = spriteram[offs + 0x000] & 0x7f;
+ int color = spriteram[offs + 0x001] & 0x3f;
+ int sx = spriteram[offs + 0x081] - 41 + 0x100*(spriteram[offs + 0x101] & 3);
+ int sy = 256 - spriteram[offs + 0x080] + 1;
+ int flipx = (spriteram[offs + 0x100] & 0x01);
+ int flipy = (spriteram[offs + 0x100] & 0x02) >> 1;
+ int sizex = (spriteram[offs + 0x100] & 0x04) >> 2;
+ int sizey = (spriteram[offs + 0x100] & 0x08) >> 3;
+ int x,y;
+
+ if (flip_screen)
+ {
+ flipx ^= 1;
+ flipy ^= 1;
+ }
+
+ sy -= 16 * sizey;
+ sy = (sy & 0xff) - 32; // fix wraparound
+
+ for (y = 0;y <= sizey;y++)
+ {
+ for (x = 0;x <= sizex;x++)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ sprite + gfx_offs[y ^ (sizey * flipy)][x ^ (sizex * flipx)],
+ color,
+ flipx,flipy,
+ sx + 16*x, sy + 16*y,
+ cliprect,TRANSPARENCY_COLOR,0);
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( 20pacgal )
+{
+ int x,y;
+
+ for (y = 0;y < 32;y++)
+ {
+ for (x = 0;x < 32;x++)
+ {
+ int sx,sy;
+ if (y < 2)
+ {
+ sy = x-2;
+ sx = 34+y;
+ }
+ else if (y >= 30)
+ {
+ sy = x-2;
+ sx = y-30;
+ }
+ else
+ {
+ sy = y-2;
+ sx = x+2;
+ }
+
+ if (active_game)
+ {
+ drawgfx(chr_bitmap,machine->gfx[0],
+ pacgal_videoram2[y*32 + x] + 0xa00,
+ (pacgal_videoram2[0x400 + y*32 + x] & 0x3f) * 4,
+ 0,0,
+ 8*sx,8*sy,
+ cliprect,TRANSPARENCY_NONE_RAW,0);
+ }
+ else
+ {
+ drawgfx(chr_bitmap,machine->gfx[0],
+ pacgal_videoram[y*32 + x] + 0xa00,
+ (pacgal_videoram[0x400 + y*32 + x] & 0x3f) * 4,
+ 0,0,
+ 8*sx,8*sy,
+ cliprect,TRANSPARENCY_NONE_RAW,0);
+ }
+ }
+ }
+
+ fillbitmap(bitmap,0,NULL);
+
+ draw_sprites(machine,bitmap,cliprect);
+
+ copybitmap(bitmap, chr_bitmap, flip_screen, flip_screen, 0, 0, cliprect, TRANSPARENCY_BLEND_RAW, 4);
+
+ return 0;
+}
diff --git a/src/mame/video/40love.c b/src/mame/video/40love.c
new file mode 100644
index 00000000000..7fccbcd97d9
--- /dev/null
+++ b/src/mame/video/40love.c
@@ -0,0 +1,350 @@
+/*
+* Video Driver for Forty-Love
+*/
+
+#include "driver.h"
+
+/*
+* variables
+*/
+
+UINT8 *fortyl_video_ctrl;
+
+static UINT8 fortyl_flipscreen,fortyl_pix_redraw;
+static UINT8 fortyl_xoffset = 128;
+
+static UINT8 *fortyl_pixram1;
+static UINT8 *fortyl_pixram2;
+
+static mame_bitmap *pixel_bitmap1;
+static mame_bitmap *pixel_bitmap2;
+
+static tilemap *background;
+
+int fortyl_pix_color[4];
+
+/*
+* color prom decoding
+*/
+
+PALETTE_INIT( fortyl )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ /* green component */
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ /* blue component */
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+}
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/*
+colorram format (2 bytes per one tilemap character line, 8 pixels height):
+
+ offset 0 x... .... x scroll (1 MSB bit)
+ offset 0 .xxx x... tile bank (see code below for banking formula)
+ offset 0 .... .xxx tiles color (one color code per whole tilemap line)
+
+ offset 1 xxxx xxxx x scroll (8 LSB bits)
+*/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int tile_number = videoram[tile_index];
+ int tile_attrib = colorram[(tile_index/64)*2];
+ int tile_h_bank = (tile_attrib&0x40)<<3; /* 0x40->0x200 */
+ int tile_l_bank = (tile_attrib&0x18)<<3; /* 0x10->0x80, 0x08->0x40 */
+
+ int code = tile_number;
+ if ((tile_attrib & 0x20) && (code >= 0xc0))
+ code = (code & 0x3f) | tile_l_bank | 0x100;
+ code |= tile_h_bank;
+
+ SET_TILE_INFO( 0,
+ code,
+ tile_attrib & 0x07,
+ 0);
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( fortyl )
+{
+ fortyl_pixram1 = auto_malloc(0x4000);
+ fortyl_pixram2 = auto_malloc(0x4000);
+
+ pixel_bitmap1 = auto_bitmap_alloc(256,256,machine->screen[0].format);
+ pixel_bitmap2 = auto_bitmap_alloc(256,256,machine->screen[0].format);
+
+ background = tilemap_create(get_bg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,32);
+
+ tilemap_set_scroll_rows(background,32);
+ tilemap_set_transparent_pen(background,0);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+static int pixram_sel;
+
+static void fortyl_set_scroll_x(int offset)
+{
+ int i = offset & ~1;
+ int x = ((colorram[i] & 0x80) << 1) | colorram[i+1]; /* 9 bits signed */
+
+ if (fortyl_flipscreen)
+ x += 0x51;
+ else
+ x -= 0x50;
+
+ x &= 0x1ff;
+ if (x&0x100) x -= 0x200; /* sign extend */
+
+ tilemap_set_scrollx(background, offset/2, x);
+}
+
+WRITE8_HANDLER( fortyl_pixram_sel_w )
+{
+ int offs;
+ int f = data & 0x01;
+
+ pixram_sel = (data & 0x04) >> 2;
+
+ if (fortyl_flipscreen != f)
+ {
+ fortyl_flipscreen = f;
+ flip_screen_set(fortyl_flipscreen);
+ fortyl_pix_redraw = 1;
+
+ for (offs=0;offs<32;offs++)
+ fortyl_set_scroll_x(offs*2);
+ }
+}
+
+READ8_HANDLER( fortyl_pixram_r )
+{
+ if (pixram_sel)
+ return fortyl_pixram2[offset];
+ else
+ return fortyl_pixram1[offset];
+}
+
+static void fortyl_plot_pix(int offset)
+{
+ int x,y,i,c,d1,d2;
+
+
+ x = (offset & 0x1f)*8;
+ y = (offset >> 5) & 0xff;
+
+ if (pixram_sel)
+ {
+ d1 = fortyl_pixram2[offset];
+ d2 = fortyl_pixram2[offset + 0x2000];
+ }
+ else
+ {
+ d1 = fortyl_pixram1[offset];
+ d2 = fortyl_pixram1[offset + 0x2000];
+ }
+
+ for (i=0;i<8;i++)
+ {
+ c = ((d2>>i)&1) + ((d1>>i)&1)*2;
+ if (pixram_sel)
+ *BITMAP_ADDR16(pixel_bitmap2, y, x+i) = fortyl_pix_color[c];
+ else
+ *BITMAP_ADDR16(pixel_bitmap1, y, x+i) = fortyl_pix_color[c];
+ }
+}
+
+WRITE8_HANDLER( fortyl_pixram_w )
+{
+ if (pixram_sel)
+ fortyl_pixram2[offset] = data;
+ else
+ fortyl_pixram1[offset] = data;
+
+ fortyl_plot_pix(offset & 0x1fff);
+}
+
+
+WRITE8_HANDLER( fortyl_bg_videoram_w )
+{
+ videoram[offset]=data;
+ tilemap_mark_tile_dirty(background,offset);
+}
+READ8_HANDLER( fortyl_bg_videoram_r )
+{
+ return videoram[offset];
+}
+
+WRITE8_HANDLER( fortyl_bg_colorram_w )
+{
+ if( colorram[offset]!=data )
+ {
+ int i;
+
+ colorram[offset] = data;
+ for (i=(offset/2)*64; i<(offset/2)*64+64; i++)
+ tilemap_mark_tile_dirty(background,i);
+
+ fortyl_set_scroll_x(offset);
+ }
+}
+READ8_HANDLER( fortyl_bg_colorram_r )
+{
+ return colorram[offset];
+}
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+/*
+spriteram format (4 bytes per sprite):
+
+ offset 0 xxxxxxxx y position
+
+ offset 1 x....... flip Y
+ offset 1 .x...... flip X
+ offset 1 ..xxxxxx gfx code (6 LSB bits)
+
+ offset 2 ...xx... gfx code (2 MSB bits)
+ offset 2 .....xxx color code
+ offset 2 ???..... ??? (not used, always 0)
+
+ offset 3 xxxxxxxx x position
+*/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ /* spriteram #1 */
+ for (offs = 0; offs < spriteram_size; offs += 4)
+ {
+ int code,color,sx,sy,flipx,flipy;
+
+ sx = spriteram[offs+3];
+ sy = spriteram[offs+0] +1;
+
+ if (fortyl_flipscreen)
+ sx = 240 - sx;
+ else
+ sy = 242 - sy;
+
+ code = (spriteram[offs+1] & 0x3f) + ((spriteram[offs+2] & 0x18) << 3);
+ flipx = ((spriteram[offs+1] & 0x40) >> 6) ^ fortyl_flipscreen;
+ flipy = ((spriteram[offs+1] & 0x80) >> 7) ^ fortyl_flipscreen;
+ color = (spriteram[offs+2] & 0x07) + 0x08;
+
+ if (spriteram[offs+2] & 0xe0)
+ color = mame_rand(machine)&0xf;
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx+fortyl_xoffset,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ /* spriteram #2 */
+ for (offs = 0; offs < spriteram_2_size; offs += 4)
+ {
+ int code,color,sx,sy,flipx,flipy;
+
+ sx = spriteram_2[offs+3];
+ sy = spriteram_2[offs+0] +1;
+
+ if (fortyl_flipscreen)
+ sx = 240 - sx;
+ else
+ sy = 242 - sy;
+
+ code = (spriteram_2[offs+1] & 0x3f) + ((spriteram_2[offs+2] & 0x18) << 3);
+ flipx = ((spriteram_2[offs+1] & 0x40) >> 6) ^ fortyl_flipscreen;
+ flipy = ((spriteram_2[offs+1] & 0x80) >> 7) ^ fortyl_flipscreen;
+ color = (spriteram_2[offs+2] & 0x07) + 0x08;
+
+ if (spriteram_2[offs+2] & 0xe0)
+ color = mame_rand(machine)&0xf;
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx+fortyl_xoffset,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+static void draw_pixram( mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+ int f = fortyl_flipscreen ^ 1;
+
+ if (fortyl_pix_redraw)
+ {
+ fortyl_pix_redraw = 0;
+
+ for (offs=0; offs<0x2000; offs++)
+ fortyl_plot_pix(offs);
+ }
+
+ if (pixram_sel)
+ copybitmap(bitmap,pixel_bitmap1,f,f,fortyl_xoffset,0,cliprect,TRANSPARENCY_NONE,0);
+ else
+ copybitmap(bitmap,pixel_bitmap2,f,f,fortyl_xoffset,0,cliprect,TRANSPARENCY_NONE,0);
+}
+
+VIDEO_UPDATE( fortyl )
+{
+ draw_pixram(bitmap,cliprect);
+
+ tilemap_set_scrolldy(background,-fortyl_video_ctrl[1]+1,-fortyl_video_ctrl[1]-1 );
+ tilemap_draw(bitmap,cliprect,background,0,0);
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/4enraya.c b/src/mame/video/4enraya.c
new file mode 100644
index 00000000000..6d1a4c58a68
--- /dev/null
+++ b/src/mame/video/4enraya.c
@@ -0,0 +1,40 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+WRITE8_HANDLER( fenraya_videoram_w )
+{
+ videoram[(offset&0x3ff)*2]=data;
+ videoram[(offset&0x3ff)*2+1]=(offset&0xc00)>>10;
+ tilemap_mark_tile_dirty(bg_tilemap,offset&0x3ff);
+}
+
+static TILE_GET_INFO( get_tile_info )
+{
+ int code = videoram[tile_index*2]+(videoram[tile_index*2+1]<<8);
+ SET_TILE_INFO(
+ 0,
+ code,
+ 0,
+ 0);
+}
+
+VIDEO_START( 4enraya )
+{
+ bg_tilemap = tilemap_create( get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+ video_start_generic(machine);
+}
+
+VIDEO_UPDATE( 4enraya)
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap, 0,0);
+ return 0;
+}
diff --git a/src/mame/video/8080bw.c b/src/mame/video/8080bw.c
new file mode 100644
index 00000000000..54b7dc78056
--- /dev/null
+++ b/src/mame/video/8080bw.c
@@ -0,0 +1,478 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "8080bw.h"
+#include "mw8080bw.h"
+
+
+#define NUM_PENS (8)
+
+
+UINT8 *c8080bw_colorram;
+
+static UINT8 c8080bw_flip_screen;
+static UINT8 color_map;
+static UINT8 screen_red;
+static UINT8 schaser_background_disable;
+static UINT8 schaser_background_select;
+
+
+
+void c8080bw_flip_screen_w(int data)
+{
+ color_map = data;
+ c8080bw_flip_screen = data && (readinputportbytag(CABINET_PORT_TAG) & 0x01);
+}
+
+
+void c8080bw_screen_red_w(int data)
+{
+ screen_red = data;
+}
+
+
+void schaser_background_control_w(int data)
+{
+ schaser_background_disable = (data >> 3) & 0x01;
+ schaser_background_select = (data >> 4) & 0x01;
+}
+
+
+static void invadpt2_get_pens(pen_t *pens)
+{
+ offs_t i;
+
+ for (i = 0; i < NUM_PENS; i++)
+ {
+ pens[i] = MAKE_RGB(pal1bit(i >> 0), pal1bit(i >> 2), pal1bit(i >> 1));
+ }
+}
+
+
+static void sflush_get_pens(pen_t *pens)
+{
+ offs_t i;
+
+ pens[0] = MAKE_RGB(0x80, 0x80, 0xff);
+
+ for (i = 1; i < NUM_PENS; i++)
+ {
+ pens[i] = MAKE_RGB(pal1bit(i >> 0), pal1bit(i >> 2), pal1bit(i >> 1));
+ }
+}
+
+
+static void cosmo_get_pens(pen_t *pens)
+{
+ offs_t i;
+
+ for (i = 0; i < NUM_PENS; i++)
+ {
+ pens[i] = MAKE_RGB(pal1bit(i >> 0), pal1bit(i >> 1), pal1bit(i >> 2));
+ }
+}
+
+
+INLINE void set_pixel(mame_bitmap *bitmap, UINT8 y, UINT8 x, pen_t *pens, UINT8 color)
+{
+ if (y >= MW8080BW_VCOUNTER_START_NO_VBLANK)
+ {
+ if (c8080bw_flip_screen)
+ *BITMAP_ADDR32(bitmap, MW8080BW_VBSTART - 1 - (y - MW8080BW_VCOUNTER_START_NO_VBLANK), MW8080BW_HPIXCOUNT - 1 - x) = pens[color];
+ else
+ *BITMAP_ADDR32(bitmap, y - MW8080BW_VCOUNTER_START_NO_VBLANK, x) = pens[color];
+ }
+}
+
+
+INLINE void set_8_pixels(mame_bitmap *bitmap, UINT8 y, UINT8 x, UINT8 data,
+ pen_t *pens, UINT8 fore_color, UINT8 back_color)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ {
+ set_pixel(bitmap, y, x, pens, (data & 0x01) ? fore_color : back_color);
+
+ x = x + 1;
+ data = data >> 1;
+ }
+}
+
+
+/* this is needed as this driver doesn't emulate the shift register like mw8080bw does */
+static void clear_extra_columns(mame_bitmap *bitmap, pen_t *pens, UINT8 color)
+{
+ UINT8 x;
+
+ for (x = 0; x < 4; x++)
+ {
+ UINT8 y;
+
+ for (y = MW8080BW_VCOUNTER_START_NO_VBLANK; y != 0; y++)
+ {
+ if (c8080bw_flip_screen)
+ *BITMAP_ADDR32(bitmap, MW8080BW_VBSTART - 1 - (y - MW8080BW_VCOUNTER_START_NO_VBLANK), MW8080BW_HPIXCOUNT - 1 - (256 + x)) = pens[color];
+ else
+ *BITMAP_ADDR32(bitmap, y - MW8080BW_VCOUNTER_START_NO_VBLANK, 256 + x) = pens[color];
+ }
+ }
+}
+
+
+VIDEO_UPDATE( invadpt2 )
+{
+ pen_t pens[NUM_PENS];
+ offs_t offs;
+ UINT8 *color_map_base;
+
+ invadpt2_get_pens(pens);
+
+ color_map_base = color_map ? &memory_region(REGION_PROMS)[0x0400] : memory_region(REGION_PROMS);
+
+ for (offs = 0; offs < mw8080bw_ram_size; offs++)
+ {
+ UINT8 y = offs >> 5;
+ UINT8 x = offs << 3;
+
+ offs_t color_address = (offs >> 8 << 5) | (offs & 0x1f);
+
+ UINT8 data = mw8080bw_ram[offs];
+ UINT8 fore_color = screen_red ? 1 : color_map_base[color_address] & 0x07;
+
+ set_8_pixels(bitmap, y, x, data, pens, fore_color, 0);
+ }
+
+ clear_extra_columns(bitmap, pens, 0);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( ballbomb )
+{
+ pen_t pens[NUM_PENS];
+ offs_t offs;
+ UINT8 *color_map_base;
+
+ invadpt2_get_pens(pens);
+
+ color_map_base = color_map ? &memory_region(REGION_PROMS)[0x0400] : memory_region(REGION_PROMS);
+
+ for (offs = 0; offs < mw8080bw_ram_size; offs++)
+ {
+ UINT8 y = offs >> 5;
+ UINT8 x = offs << 3;
+
+ offs_t color_address = (offs >> 8 << 5) | (offs & 0x1f);
+
+ UINT8 data = mw8080bw_ram[offs];
+ UINT8 fore_color = screen_red ? 1 : color_map_base[color_address] & 0x07;
+
+ /* blue background */
+ set_8_pixels(bitmap, y, x, data, pens, fore_color, 2);
+ }
+
+ clear_extra_columns(bitmap, pens, 2);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( schaser )
+{
+ pen_t pens[NUM_PENS];
+ offs_t offs;
+ UINT8 *background_map_base;
+
+ invadpt2_get_pens(pens);
+
+ background_map_base = memory_region(REGION_PROMS);
+
+ for (offs = 0; offs < mw8080bw_ram_size; offs++)
+ {
+ UINT8 back_color = 0;
+
+ UINT8 y = offs >> 5;
+ UINT8 x = offs << 3;
+
+ UINT8 data = mw8080bw_ram[offs];
+ UINT8 fore_color = c8080bw_colorram[offs & 0x1f1f] & 0x07;
+
+ if (!schaser_background_disable)
+ {
+ offs_t back_address = (offs >> 8 << 5) | (offs & 0x1f);
+
+ UINT8 back_data = background_map_base[back_address];
+
+ /* the equations derived from the schematics don't appear to produce
+ the right colors, but this one does, at least for this PROM */
+ back_color = (((back_data & 0x0c) == 0x0c) && schaser_background_select) ? 4 : 2;
+ }
+
+ set_8_pixels(bitmap, y, x, data, pens, fore_color, back_color);
+ }
+
+ clear_extra_columns(bitmap, pens, schaser_background_disable ? 0 : 2);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( schasrcv )
+{
+ pen_t pens[NUM_PENS];
+ offs_t offs;
+
+ invadpt2_get_pens(pens);
+
+ for (offs = 0; offs < mw8080bw_ram_size; offs++)
+ {
+ UINT8 y = offs >> 5;
+ UINT8 x = offs << 3;
+
+ UINT8 data = mw8080bw_ram[offs];
+ UINT8 fore_color = c8080bw_colorram[offs & 0x1f1f] & 0x07;
+
+ /* blue background */
+ set_8_pixels(bitmap, y, x, data, pens, fore_color, 2);
+ }
+
+ clear_extra_columns(bitmap, pens, 2);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( rollingc )
+{
+ pen_t pens[NUM_PENS];
+ offs_t offs;
+
+ invadpt2_get_pens(pens);
+
+ for (offs = 0; offs < mw8080bw_ram_size; offs++)
+ {
+ UINT8 y = offs >> 5;
+ UINT8 x = offs << 3;
+
+ UINT8 data = mw8080bw_ram[offs];
+ UINT8 fore_color = c8080bw_colorram[offs & 0x1f1f] & 0x07;
+
+ set_8_pixels(bitmap, y, x, data, pens, fore_color, 0);
+ }
+
+ clear_extra_columns(bitmap, pens, 0);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( polaris )
+{
+ pen_t pens[NUM_PENS];
+ offs_t offs;
+ UINT8 *color_map_base;
+ UINT8 *cloud_gfx;
+
+ invadpt2_get_pens(pens);
+
+ color_map_base = memory_region(REGION_PROMS);
+ cloud_gfx = memory_region(REGION_USER1);
+
+ for (offs = 0; offs < mw8080bw_ram_size; offs++)
+ {
+ UINT8 y = offs >> 5;
+ UINT8 x = offs << 3;
+
+ UINT8 data = mw8080bw_ram[offs];
+
+ offs_t color_address = (offs >> 8 << 5) | (offs & 0x1f);
+
+ /* for the background color, bit 0 of the map PROM is connected to green gun.
+ red is 0 and blue is 1, giving cyan and blue for the background. This
+ is different from what the schematics shows, but it's supported
+ by screenshots. Bit 3 is connected to cloud enable, while
+ bits 1 and 2 are marked 'not use' (sic) */
+
+ UINT8 back_color = (color_map_base[color_address] & 0x01) ? 6 : 2;
+ UINT8 fore_color = ~c8080bw_colorram[offs & 0x1f1f] & 0x07;
+
+ UINT8 cloud_y = y - polaris_get_cloud_pos();
+
+ if ((color_map_base[color_address] & 0x08) || (cloud_y >= 64))
+ {
+ set_8_pixels(bitmap, y, x, data, pens, fore_color, back_color);
+ }
+ else
+ {
+ /* cloud appears in this part of the screen */
+ int i;
+
+ for (i = 0; i < 8; i++)
+ {
+ UINT8 color;
+
+ if (data & 0x01)
+ {
+ color = fore_color;
+ }
+ else
+ {
+ int bit = 1 << (~x & 0x03);
+ offs_t cloud_gfx_offs = ((x >> 2) & 0x03) | ((~cloud_y & 0x3f) << 2);
+
+ color = (cloud_gfx[cloud_gfx_offs] & bit) ? 7 : back_color;
+ }
+
+ set_pixel(bitmap, y, x, pens, color);
+
+ x = x + 1;
+ data = data >> 1;
+ }
+ }
+ }
+
+ clear_extra_columns(bitmap, pens, 6);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( lupin3 )
+{
+ pen_t pens[NUM_PENS];
+ offs_t offs;
+
+ invadpt2_get_pens(pens);
+
+ for (offs = 0; offs < mw8080bw_ram_size; offs++)
+ {
+ UINT8 y = offs >> 5;
+ UINT8 x = offs << 3;
+
+ UINT8 data = mw8080bw_ram[offs];
+ UINT8 fore_color = ~c8080bw_colorram[offs & 0x1f1f] & 0x07;
+
+ set_8_pixels(bitmap, y, x, data, pens, fore_color, 0);
+ }
+
+ clear_extra_columns(bitmap, pens, 0);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( cosmo )
+{
+ pen_t pens[NUM_PENS];
+ offs_t offs;
+
+ cosmo_get_pens(pens);
+
+ for (offs = 0; offs < mw8080bw_ram_size; offs++)
+ {
+ UINT8 y = offs >> 5;
+ UINT8 x = offs << 3;
+
+ offs_t color_address = (offs >> 8 << 5) | (offs & 0x1f);
+
+ UINT8 data = mw8080bw_ram[offs];
+ UINT8 fore_color = c8080bw_colorram[color_address] & 0x07;
+
+ set_8_pixels(bitmap, y, x, data, pens, fore_color, 0);
+ }
+
+ clear_extra_columns(bitmap, pens, 0);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( indianbt )
+{
+ pen_t pens[NUM_PENS];
+ offs_t offs;
+ UINT8 *color_map_base;
+
+ cosmo_get_pens(pens);
+
+ color_map_base = color_map ? &memory_region(REGION_PROMS)[0x0400] : memory_region(REGION_PROMS);
+
+ for (offs = 0; offs < mw8080bw_ram_size; offs++)
+ {
+ UINT8 y = offs >> 5;
+ UINT8 x = offs << 3;
+
+ offs_t color_address = (offs >> 8 << 5) | (offs & 0x1f);
+
+ UINT8 data = mw8080bw_ram[offs];
+ UINT8 fore_color = color_map_base[color_address] & 0x07;
+
+ set_8_pixels(bitmap, y, x, data, pens, fore_color, 0);
+ }
+
+ clear_extra_columns(bitmap, pens, 0);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( shuttlei )
+{
+ pen_t pens[2] = { RGB_BLACK, RGB_WHITE };
+ offs_t offs;
+
+ for (offs = 0; offs < mw8080bw_ram_size; offs++)
+ {
+ int i;
+
+ UINT8 y = offs >> 5;
+ UINT8 x = offs << 3;
+
+ UINT8 data = mw8080bw_ram[offs];
+
+ for (i = 0; i < 8; i++)
+ {
+ pen_t pen = (data & 0x80) ? RGB_WHITE : RGB_BLACK;
+ *BITMAP_ADDR32(bitmap, y, x) = pen;
+
+ x = x + 1;
+ data = data << 1;
+ }
+ }
+
+ clear_extra_columns(bitmap, pens, 0);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( sflush )
+{
+ pen_t pens[NUM_PENS];
+ offs_t offs;
+
+ sflush_get_pens(pens);
+
+ for (offs = 0; offs < mw8080bw_ram_size; offs++)
+ {
+ UINT8 y = offs >> 5;
+ UINT8 x = offs << 3;
+
+ UINT8 data = mw8080bw_ram[offs];
+ UINT8 fore_color = c8080bw_colorram[offs & 0x1f1f] & 0x07;
+
+ set_8_pixels(bitmap, y, x, data, pens, fore_color, 0);
+ }
+
+ clear_extra_columns(bitmap, pens, 0);
+
+ return 0;
+}
diff --git a/src/mame/video/88games.c b/src/mame/video/88games.c
new file mode 100644
index 00000000000..3dceda4659d
--- /dev/null
+++ b/src/mame/video/88games.c
@@ -0,0 +1,100 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+int k88games_priority;
+
+static int layer_colorbase[3],sprite_colorbase,zoom_colorbase;
+
+
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ *code |= ((*color & 0x0f) << 8) | (bank << 12);
+ *color = layer_colorbase[layer] + ((*color & 0xf0) >> 4);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051960
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority,int *shadow)
+{
+ *priority = (*color & 0x20) >> 5; /* ??? */
+ *color = sprite_colorbase + (*color & 0x0f);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051316
+
+***************************************************************************/
+
+static void zoom_callback(int *code,int *color,int *flags)
+{
+ *flags = (*color & 0x40) ? TILE_FLIPX : 0;
+ *code |= ((*color & 0x07) << 8);
+ *color = zoom_colorbase + ((*color & 0x38) >> 3) + ((*color & 0x80) >> 4);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( 88games )
+{
+ layer_colorbase[0] = 64;
+ layer_colorbase[1] = 0;
+ layer_colorbase[2] = 16;
+ sprite_colorbase = 32;
+ zoom_colorbase = 48;
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,NORMAL_PLANE_ORDER,sprite_callback);
+ K051316_vh_start_0(machine,REGION_GFX3,4,FALSE,0,zoom_callback);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( 88games )
+{
+ K052109_tilemap_update();
+
+ if (k88games_priority)
+ {
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],TILEMAP_DRAW_OPAQUE,0);
+ K051960_sprites_draw(bitmap,cliprect,1,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],0,0);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],0,0);
+ K051960_sprites_draw(bitmap,cliprect,0,0);
+ K051316_zoom_draw_0(bitmap,cliprect,0,0);
+ }
+ else
+ {
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],TILEMAP_DRAW_OPAQUE,0);
+ K051316_zoom_draw_0(bitmap,cliprect,0,0);
+ K051960_sprites_draw(bitmap,cliprect,0,0);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],0,0);
+ K051960_sprites_draw(bitmap,cliprect,1,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],0,0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/actfancr.c b/src/mame/video/actfancr.c
new file mode 100644
index 00000000000..6582081d231
--- /dev/null
+++ b/src/mame/video/actfancr.c
@@ -0,0 +1,311 @@
+/*******************************************************************************
+
+ actfancr - Bryan McPhail, mish@tendril.co.uk
+
+*******************************************************************************/
+
+#include "driver.h"
+
+
+static UINT8 actfancr_control_1[0x20],actfancr_control_2[0x20];
+UINT8 *actfancr_pf1_data,*actfancr_pf2_data,*actfancr_pf1_rowscroll_data;
+static tilemap *pf1_tilemap,*pf1_alt_tilemap,*pf2_tilemap;
+static int flipscreen;
+
+static TILEMAP_MAPPER( actfancr_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x0f) + ((row & 0x0f) << 4) + ((col & 0xf0) << 4);
+}
+
+static TILEMAP_MAPPER( actfancr_scan2 )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x0f) + ((row & 0x0f) << 4) + ((row & 0x10) << 4) + ((col & 0x70) << 5);
+}
+
+static TILE_GET_INFO( get_tile_info )
+{
+ int tile,color;
+
+ tile=actfancr_pf1_data[2*tile_index]+(actfancr_pf1_data[2*tile_index+1]<<8);
+ color=tile >> 12;
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 2,
+ tile,
+ color,
+ 0);
+}
+
+static TILEMAP_MAPPER( triothep_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x0f) + ((row & 0x0f) << 4) + ((row & 0x10) << 4) + ((col & 0x10) << 5);
+}
+
+static TILE_GET_INFO( get_trio_tile_info )
+{
+ int tile,color;
+
+ tile=actfancr_pf1_data[2*tile_index]+(actfancr_pf1_data[2*tile_index+1]<<8);
+ color=tile >> 12;
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 2,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_pf2_tile_info )
+{
+ int tile,color;
+
+ tile=actfancr_pf2_data[2*tile_index]+(actfancr_pf2_data[2*tile_index+1]<<8);
+ color=tile>>12;
+
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+/******************************************************************************/
+
+static void register_savestate(void)
+{
+ state_save_register_global_array(actfancr_control_1);
+ state_save_register_global_array(actfancr_control_2);
+}
+
+VIDEO_START( actfancr )
+{
+ pf1_tilemap = tilemap_create(get_tile_info,actfancr_scan,TILEMAP_TYPE_PEN,16,16,256,16);
+ pf1_alt_tilemap = tilemap_create(get_tile_info,actfancr_scan2,TILEMAP_TYPE_PEN,16,16,128,32);
+ pf2_tilemap = tilemap_create(get_pf2_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(pf2_tilemap,0);
+
+ register_savestate();
+}
+
+VIDEO_START( triothep )
+{
+ pf1_tilemap = tilemap_create(get_trio_tile_info,triothep_scan,TILEMAP_TYPE_PEN,16,16,32,32);
+ pf2_tilemap = tilemap_create(get_pf2_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(pf2_tilemap,0);
+
+ pf1_alt_tilemap=NULL;
+
+ register_savestate();
+}
+
+/******************************************************************************/
+
+WRITE8_HANDLER( actfancr_pf1_control_w )
+{
+ actfancr_control_1[offset]=data;
+}
+
+WRITE8_HANDLER( actfancr_pf2_control_w )
+{
+ actfancr_control_2[offset]=data;
+}
+
+WRITE8_HANDLER( actfancr_pf1_data_w )
+{
+ actfancr_pf1_data[offset]=data;
+ tilemap_mark_tile_dirty(pf1_tilemap,offset/2);
+ if (pf1_alt_tilemap) tilemap_mark_tile_dirty(pf1_alt_tilemap,offset/2);
+}
+
+READ8_HANDLER( actfancr_pf1_data_r )
+{
+ return actfancr_pf1_data[offset];
+}
+
+WRITE8_HANDLER( actfancr_pf2_data_w )
+{
+ actfancr_pf2_data[offset]=data;
+ tilemap_mark_tile_dirty(pf2_tilemap,offset/2);
+}
+
+READ8_HANDLER( actfancr_pf2_data_r )
+{
+ return actfancr_pf2_data[offset];
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( actfancr )
+{
+ int offs,mult;
+ int scrollx=(actfancr_control_1[0x10]+(actfancr_control_1[0x11]<<8));
+ int scrolly=(actfancr_control_1[0x12]+(actfancr_control_1[0x13]<<8));
+
+ /* Draw playfield */
+ flipscreen=actfancr_control_2[0]&0x80;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ tilemap_set_scrollx( pf1_tilemap,0, scrollx );
+ tilemap_set_scrolly( pf1_tilemap,0, scrolly );
+ tilemap_set_scrollx( pf1_alt_tilemap,0, scrollx );
+ tilemap_set_scrolly( pf1_alt_tilemap,0, scrolly );
+
+ if (actfancr_control_1[6]==1)
+ tilemap_draw(bitmap,cliprect,pf1_alt_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+
+ /* Sprites */
+ for (offs = 0;offs < 0x800;offs += 8)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash;
+
+ y=buffered_spriteram[offs]+(buffered_spriteram[offs+1]<<8);
+ if ((y&0x8000) == 0) continue;
+ x = buffered_spriteram[offs+4]+(buffered_spriteram[offs+5]<<8);
+ colour = ((x & 0xf000) >> 12);
+ flash=x&0x800;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x1800) >> 11)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ /* multi = 0 1 3 7 */
+ sprite = buffered_spriteram[offs+2]+(buffered_spriteram[offs+3]<<8);
+ sprite &= 0x0fff;
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 256) x -= 512;
+ if (y >= 256) y -= 512;
+ x = 240 - x;
+ y = 240 - y;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flipscreen) {
+ y=240-y;
+ x=240-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+ multi--;
+ }
+ }
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( triothep )
+{
+ int offs,i,mult;
+ int scrollx=(actfancr_control_1[0x10]+(actfancr_control_1[0x11]<<8));
+ int scrolly=(actfancr_control_1[0x12]+(actfancr_control_1[0x13]<<8));
+
+ /* Draw playfield */
+ flipscreen=actfancr_control_2[0]&0x80;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ if (actfancr_control_2[0]&0x4) {
+ tilemap_set_scroll_rows(pf1_tilemap,32);
+ tilemap_set_scrolly( pf1_tilemap,0, scrolly );
+ for (i=0; i<32; i++)
+ tilemap_set_scrollx( pf1_tilemap,i, scrollx+(actfancr_pf1_rowscroll_data[i*2] | actfancr_pf1_rowscroll_data[i*2+1]<<8) );
+ }
+ else {
+ tilemap_set_scroll_rows(pf1_tilemap,1);
+ tilemap_set_scrollx( pf1_tilemap,0, scrollx );
+ tilemap_set_scrolly( pf1_tilemap,0, scrolly );
+ }
+
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+
+ /* Sprites */
+ for (offs = 0;offs < 0x800;offs += 8)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash;
+
+ y=buffered_spriteram[offs]+(buffered_spriteram[offs+1]<<8);
+ if ((y&0x8000) == 0) continue;
+ x = buffered_spriteram[offs+4]+(buffered_spriteram[offs+5]<<8);
+ colour = ((x & 0xf000) >> 12);
+ flash=x&0x800;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x1800) >> 11)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ /* multi = 0 1 3 7 */
+ sprite = buffered_spriteram[offs+2]+(buffered_spriteram[offs+3]<<8);
+ sprite &= 0x0fff;
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 256) x -= 512;
+ if (y >= 256) y -= 512;
+ x = 240 - x;
+ y = 240 - y;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flipscreen) {
+ y=240-y;
+ x=240-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+ multi--;
+ }
+ }
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/aeroboto.c b/src/mame/video/aeroboto.c
new file mode 100644
index 00000000000..cbc8801c491
--- /dev/null
+++ b/src/mame/video/aeroboto.c
@@ -0,0 +1,210 @@
+#include "driver.h"
+
+
+// how the starfield ROM is interpreted: 0=256x256x1 linear bitmap, 1=8x8x1x1024 tilemap
+#define STARS_LAYOUT 1
+
+// scroll speed of the stars: 1=normal, 2=half, 3=one-third...etc.(possitive integers only)
+#define SCROLL_SPEED 1
+
+
+UINT8 *aeroboto_videoram;
+UINT8 *aeroboto_hscroll, *aeroboto_vscroll, *aeroboto_tilecolor;
+UINT8 *aeroboto_starx, *aeroboto_stary, *aeroboto_bgcolor;
+
+static int aeroboto_charbank, aeroboto_starsoff;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 code = aeroboto_videoram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ code + (aeroboto_charbank << 8),
+ aeroboto_tilecolor[code],
+ (aeroboto_tilecolor[code] >= 0x33) ? 0 : TILE_FORCE_LAYER0);
+}
+// transparency should only affect tiles with color 0x33 or higher
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( aeroboto )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,64);
+
+ tilemap_set_transparent_pen(bg_tilemap,0);
+
+ tilemap_set_scroll_rows(bg_tilemap,64);
+
+ #if STARS_LAYOUT
+ {
+ UINT8 *rom, *temp;
+ int i, length;
+
+ rom = memory_region(REGION_GFX2);
+ length = memory_region_length(REGION_GFX2);
+ temp = malloc_or_die(length);
+ memcpy(temp, rom, length);
+
+ for (i=0; i<length; i++) rom[(i&~0xff)+(i<<5&0xe0)+(i>>3&0x1f)] = temp[i];
+
+ free(temp);
+ }
+ #endif
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ8_HANDLER( aeroboto_in0_r )
+{
+ return readinputport(flip_screen ? 1 : 0);
+}
+
+WRITE8_HANDLER( aeroboto_3000_w )
+{
+ /* bit 0 selects both flip screen and player1/player2 controls */
+ flip_screen_set(data & 0x01);
+
+ /* bit 1 = char bank select */
+ if (aeroboto_charbank != ((data & 0x02) >> 1))
+ {
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ aeroboto_charbank = (data & 0x02) >> 1;
+ }
+
+ /* bit 2 = disable star field? */
+ aeroboto_starsoff = data & 0x4;
+}
+
+WRITE8_HANDLER( aeroboto_videoram_w )
+{
+ aeroboto_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( aeroboto_tilecolor_w )
+{
+ if (aeroboto_tilecolor[offset] != data)
+ {
+ aeroboto_tilecolor[offset] = data;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int x = spriteram[offs+3];
+ int y = 240 - spriteram[offs];
+
+ if (flip_screen)
+ {
+ x = 248 - x;
+ y = 240 - y;
+ }
+
+ drawgfx(bitmap, machine->gfx[1],
+ spriteram[offs+1],
+ spriteram[offs+2] & 0x07,
+ flip_screen, flip_screen,
+ ((x + 8) & 0xff) - 8, y,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+
+VIDEO_UPDATE( aeroboto )
+{
+ static rectangle splitrect1 = { 0, 255, 0, 39 };
+ static rectangle splitrect2 = { 0, 255, 40, 255 };
+ static int sx=0, sy=0;
+ static UINT8 ox=0, oy=0;
+ UINT8 *src_base, *src_colptr, *src_rowptr;
+ int src_offsx, src_colmask, sky_color, star_color, x, y, i, j, pen;
+
+ sky_color = star_color = *aeroboto_bgcolor << 2;
+
+ // the star field is supposed to be seen through tile pen 0 when active
+ if (!aeroboto_starsoff)
+ {
+ if (star_color < 0xd0) { star_color = 0xd0; sky_color = 0; }
+ star_color += 2;
+
+ fillbitmap(bitmap, sky_color, cliprect);
+
+ // actual scroll speed is unknown but it can be adjusted by changing the SCROLL_SPEED constant
+ sx += (char)(*aeroboto_starx - ox);
+ ox = *aeroboto_starx;
+ x = sx / SCROLL_SPEED;
+
+ if (*aeroboto_vscroll != 0xff) sy += (char)(*aeroboto_stary - oy);
+ oy = *aeroboto_stary;
+ y = sy / SCROLL_SPEED;
+
+ src_base = memory_region(REGION_GFX2);
+
+ for (i=0; i<256; i++)
+ {
+ src_offsx = (x + i) & 0xff;
+ src_colmask = 1 << (src_offsx & 7);
+ src_offsx >>= 3;
+ src_colptr = src_base + src_offsx;
+ pen = star_color + ((i + 8) >> 4 & 1);
+
+ for (j=0; j<256; j++)
+ {
+ src_rowptr = src_colptr + (((y + j) & 0xff) << 5 );
+ if (!((unsigned)*src_rowptr & src_colmask)) *BITMAP_ADDR16(bitmap, j, i) = pen;
+ }
+ }
+ }
+ else
+ {
+ sx = ox = *aeroboto_starx;
+ sy = oy = *aeroboto_stary;
+ fillbitmap(bitmap, sky_color, cliprect);
+ }
+
+ for (y = 0;y < 64; y++)
+ tilemap_set_scrollx(bg_tilemap,y,aeroboto_hscroll[y]);
+
+ // the playfield is part of a splitscreen and should not overlap with status display
+ tilemap_set_scrolly(bg_tilemap,0,*aeroboto_vscroll);
+ tilemap_draw(bitmap,&splitrect2,bg_tilemap,0,0);
+
+ draw_sprites(machine,bitmap,cliprect);
+
+ // the status display behaves more closely to a 40-line splitscreen than an overlay
+ tilemap_set_scrolly(bg_tilemap,0,0);
+ tilemap_draw(bitmap,&splitrect1,bg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/aerofgt.c b/src/mame/video/aerofgt.c
new file mode 100644
index 00000000000..bd0ba6b8f46
--- /dev/null
+++ b/src/mame/video/aerofgt.c
@@ -0,0 +1,745 @@
+#include "driver.h"
+
+
+UINT16 *aerofgt_rasterram;
+UINT16 *aerofgt_bg1videoram,*aerofgt_bg2videoram;
+UINT16 *aerofgt_spriteram1,*aerofgt_spriteram2,*aerofgt_spriteram3;
+UINT16 *wbbc97_bitmapram;
+size_t aerofgt_spriteram1_size,aerofgt_spriteram2_size,aerofgt_spriteram3_size;
+
+static UINT8 gfxbank[8];
+static UINT16 bg1scrollx,bg1scrolly,bg2scrollx,bg2scrolly,wbbc97_bitmap_enable;
+
+static int charpalettebank,spritepalettebank;
+
+static tilemap *bg1_tilemap,*bg2_tilemap;
+static int sprite_gfx;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_pspikes_tile_info )
+{
+ UINT16 code = aerofgt_bg1videoram[tile_index];
+ int bank = (code & 0x1000) >> 12;
+ SET_TILE_INFO(
+ 0,
+ (code & 0x0fff) + (gfxbank[bank] << 12),
+ ((code & 0xe000) >> 13) + 8 * charpalettebank,
+ 0);
+}
+
+static TILE_GET_INFO( karatblz_bg1_tile_info )
+{
+ UINT16 code = aerofgt_bg1videoram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ (code & 0x1fff) + (gfxbank[0] << 13),
+ (code & 0xe000) >> 13,
+ 0);
+}
+
+/* also spinlbrk */
+static TILE_GET_INFO( karatblz_bg2_tile_info )
+{
+ UINT16 code = aerofgt_bg2videoram[tile_index];
+ SET_TILE_INFO(
+ 1,
+ (code & 0x1fff) + (gfxbank[1] << 13),
+ (code & 0xe000) >> 13,
+ 0);
+}
+
+static TILE_GET_INFO( spinlbrk_bg1_tile_info )
+{
+ UINT16 code = aerofgt_bg1videoram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ (code & 0x0fff) + (gfxbank[0] << 12),
+ (code & 0xf000) >> 12,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg1_tile_info )
+{
+ UINT16 code = aerofgt_bg1videoram[tile_index];
+ int bank = (code & 0x1800) >> 11;
+ SET_TILE_INFO(
+ 0,
+ (code & 0x07ff) + (gfxbank[bank] << 11),
+ (code & 0xe000) >> 13,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg2_tile_info )
+{
+ UINT16 code = aerofgt_bg2videoram[tile_index];
+ int bank = 4 + ((code & 0x1800) >> 11);
+ SET_TILE_INFO(
+ 1,
+ (code & 0x07ff) + (gfxbank[bank] << 11),
+ (code & 0xe000) >> 13,
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( pspikes )
+{
+ bg1_tilemap = tilemap_create(get_pspikes_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ /* no bg2 in this game */
+
+ sprite_gfx = 1;
+}
+
+
+VIDEO_START( karatblz )
+{
+ bg1_tilemap = tilemap_create(karatblz_bg1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,64);
+ bg2_tilemap = tilemap_create(karatblz_bg2_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ tilemap_set_transparent_pen(bg2_tilemap,15);
+
+ spritepalettebank = 0;
+
+ sprite_gfx = 2;
+}
+
+VIDEO_START( spinlbrk )
+{
+ int i;
+
+ bg1_tilemap = tilemap_create(spinlbrk_bg1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,64);
+ bg2_tilemap = tilemap_create(karatblz_bg2_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ tilemap_set_transparent_pen(bg2_tilemap,15);
+
+ spritepalettebank = 0;
+
+ sprite_gfx = 2;
+
+
+ /* sprite maps are hardcoded in this game */
+
+ /* enemy sprites use ROM instead of RAM */
+ aerofgt_spriteram2 = (UINT16 *)memory_region(REGION_GFX5);
+ aerofgt_spriteram2_size = 0x20000;
+
+ /* front sprites are direct maps */
+ aerofgt_spriteram1 = aerofgt_spriteram2 + aerofgt_spriteram2_size/2;
+ aerofgt_spriteram1_size = 0x4000;
+ for (i = 0;i < aerofgt_spriteram1_size/2;i++)
+ aerofgt_spriteram1[i] = i;
+}
+
+VIDEO_START( turbofrc )
+{
+ bg1_tilemap = tilemap_create(get_bg1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,64);
+ bg2_tilemap = tilemap_create(get_bg2_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ tilemap_set_transparent_pen(bg2_tilemap,15);
+
+ spritepalettebank = 0;
+
+ sprite_gfx = 2;
+}
+
+VIDEO_START( wbbc97 )
+{
+ bg1_tilemap = tilemap_create(get_pspikes_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ /* no bg2 in this game */
+
+ tilemap_set_transparent_pen(bg1_tilemap,15);
+
+ sprite_gfx = 1;
+}
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( aerofgt_bg1videoram_w )
+{
+ COMBINE_DATA(&aerofgt_bg1videoram[offset]);
+ tilemap_mark_tile_dirty(bg1_tilemap,offset);
+}
+
+WRITE16_HANDLER( aerofgt_bg2videoram_w )
+{
+ COMBINE_DATA(&aerofgt_bg2videoram[offset]);
+ tilemap_mark_tile_dirty(bg2_tilemap,offset);
+}
+
+
+static void setbank(tilemap *tmap,int num,int bank)
+{
+ if (gfxbank[num] != bank)
+ {
+ gfxbank[num] = bank;
+ tilemap_mark_all_tiles_dirty(tmap);
+ }
+}
+
+WRITE16_HANDLER( pspikes_gfxbank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ setbank(bg1_tilemap,0,(data & 0xf0) >> 4);
+ setbank(bg1_tilemap,1,data & 0x0f);
+ }
+}
+
+WRITE16_HANDLER( pspikesb_gfxbank_w )
+{
+ COMBINE_DATA(&aerofgt_rasterram[0x200/2]);
+
+ setbank(bg1_tilemap,0,(data & 0xf000) >> 12);
+ setbank(bg1_tilemap,1,(data & 0x0f00) >> 8);
+}
+
+WRITE16_HANDLER( karatblz_gfxbank_w )
+{
+ if (ACCESSING_MSB)
+ {
+ setbank(bg1_tilemap,0,(data & 0x0100) >> 8);
+ setbank(bg2_tilemap,1,(data & 0x0800) >> 11);
+ }
+}
+
+WRITE16_HANDLER( spinlbrk_gfxbank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ setbank(bg1_tilemap,0,(data & 0x07));
+ setbank(bg2_tilemap,1,(data & 0x38) >> 3);
+ }
+}
+
+WRITE16_HANDLER( turbofrc_gfxbank_w )
+{
+ static UINT16 bank[2];
+ tilemap *tmap = (offset == 0) ? bg1_tilemap : bg2_tilemap;
+
+ data = COMBINE_DATA(&bank[offset]);
+
+ setbank(tmap,4*offset + 0,(data >> 0) & 0x0f);
+ setbank(tmap,4*offset + 1,(data >> 4) & 0x0f);
+ setbank(tmap,4*offset + 2,(data >> 8) & 0x0f);
+ setbank(tmap,4*offset + 3,(data >> 12) & 0x0f);
+}
+
+WRITE16_HANDLER( aerofgt_gfxbank_w )
+{
+ static UINT16 bank[4];
+ tilemap *tmap = (offset < 2) ? bg1_tilemap : bg2_tilemap;
+
+ data = COMBINE_DATA(&bank[offset]);
+
+ setbank(tmap,2*offset + 0,(data >> 8) & 0xff);
+ setbank(tmap,2*offset + 1,(data >> 0) & 0xff);
+}
+
+WRITE16_HANDLER( aerofgt_bg1scrollx_w )
+{
+ COMBINE_DATA(&bg1scrollx);
+}
+
+WRITE16_HANDLER( aerofgt_bg1scrolly_w )
+{
+ COMBINE_DATA(&bg1scrolly);
+}
+
+WRITE16_HANDLER( aerofgt_bg2scrollx_w )
+{
+ COMBINE_DATA(&bg2scrollx);
+}
+
+WRITE16_HANDLER( aerofgt_bg2scrolly_w )
+{
+ COMBINE_DATA(&bg2scrolly);
+}
+
+WRITE16_HANDLER( pspikes_palette_bank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ spritepalettebank = data & 0x03;
+ if (charpalettebank != (data & 0x1c) >> 2)
+ {
+ charpalettebank = (data & 0x1c) >> 2;
+ tilemap_mark_all_tiles_dirty(bg1_tilemap);
+ }
+ }
+}
+
+WRITE16_HANDLER( wbbc97_bitmap_enable_w )
+{
+ COMBINE_DATA(&wbbc97_bitmap_enable);
+}
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void aerofgt_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int priority)
+{
+ int offs;
+
+
+ priority <<= 12;
+
+ offs = 0;
+ while (offs < 0x0400 && (aerofgt_spriteram3[offs] & 0x8000) == 0)
+ {
+ int attr_start;
+
+ attr_start = 4 * (aerofgt_spriteram3[offs] & 0x03ff);
+
+ /* is the way I handle priority correct? Or should I just check bit 13? */
+ if ((aerofgt_spriteram3[attr_start + 2] & 0x3000) == priority)
+ {
+ int map_start;
+ int ox,oy,x,y,xsize,ysize,zoomx,zoomy,flipx,flipy,color;
+
+ ox = aerofgt_spriteram3[attr_start + 1] & 0x01ff;
+ xsize = (aerofgt_spriteram3[attr_start + 1] & 0x0e00) >> 9;
+ zoomx = (aerofgt_spriteram3[attr_start + 1] & 0xf000) >> 12;
+ oy = aerofgt_spriteram3[attr_start + 0] & 0x01ff;
+ ysize = (aerofgt_spriteram3[attr_start + 0] & 0x0e00) >> 9;
+ zoomy = (aerofgt_spriteram3[attr_start + 0] & 0xf000) >> 12;
+ flipx = aerofgt_spriteram3[attr_start + 2] & 0x4000;
+ flipy = aerofgt_spriteram3[attr_start + 2] & 0x8000;
+ color = (aerofgt_spriteram3[attr_start + 2] & 0x0f00) >> 8;
+ map_start = aerofgt_spriteram3[attr_start + 3] & 0x3fff;
+
+ ox += (xsize*zoomx+2)/4;
+ oy += (ysize*zoomy+2)/4;
+
+ zoomx = 32 - zoomx;
+ zoomy = 32 - zoomy;
+
+ for (y = 0;y <= ysize;y++)
+ {
+ int sx,sy;
+
+ if (flipy) sy = ((oy + zoomy * (ysize - y)/2 + 16) & 0x1ff) - 16;
+ else sy = ((oy + zoomy * y / 2 + 16) & 0x1ff) - 16;
+
+ for (x = 0;x <= xsize;x++)
+ {
+ int code;
+
+ if (flipx) sx = ((ox + zoomx * (xsize - x) / 2 + 16) & 0x1ff) - 16;
+ else sx = ((ox + zoomx * x / 2 + 16) & 0x1ff) - 16;
+
+ if (map_start < 0x2000)
+ code = aerofgt_spriteram1[map_start & 0x1fff] & 0x1fff;
+ else
+ code = aerofgt_spriteram2[map_start & 0x1fff] & 0x1fff;
+
+ drawgfxzoom(bitmap,machine->gfx[sprite_gfx + (map_start >= 0x2000 ? 1 : 0)],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15,
+ zoomx << 11, zoomy << 11);
+ map_start++;
+ }
+ }
+ }
+
+ offs++;
+ }
+}
+
+static void turbofrc_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int chip,int chip_disabled_pri)
+{
+ int attr_start,base,first;
+
+ base = chip * 0x0200;
+ first = 4 * aerofgt_spriteram3[0x1fe + base];
+
+ for (attr_start = base + 0x0200-8;attr_start >= first + base;attr_start -= 4)
+ {
+ int map_start;
+ int ox,oy,x,y,xsize,ysize,zoomx,zoomy,flipx,flipy,color,pri;
+// some other drivers still use this wrong table, they have to be upgraded
+// int zoomtable[16] = { 0,7,14,20,25,30,34,38,42,46,49,52,54,57,59,61 };
+
+ if (!(aerofgt_spriteram3[attr_start + 2] & 0x0080)) continue;
+ pri = aerofgt_spriteram3[attr_start + 2] & 0x0010;
+ if ( chip_disabled_pri & !pri) continue;
+ if (!chip_disabled_pri & (pri>>4)) continue;
+ ox = aerofgt_spriteram3[attr_start + 1] & 0x01ff;
+ xsize = (aerofgt_spriteram3[attr_start + 2] & 0x0700) >> 8;
+ zoomx = (aerofgt_spriteram3[attr_start + 1] & 0xf000) >> 12;
+ oy = aerofgt_spriteram3[attr_start + 0] & 0x01ff;
+ ysize = (aerofgt_spriteram3[attr_start + 2] & 0x7000) >> 12;
+ zoomy = (aerofgt_spriteram3[attr_start + 0] & 0xf000) >> 12;
+ flipx = aerofgt_spriteram3[attr_start + 2] & 0x0800;
+ flipy = aerofgt_spriteram3[attr_start + 2] & 0x8000;
+ color = (aerofgt_spriteram3[attr_start + 2] & 0x000f) + 16 * spritepalettebank;
+
+ map_start = aerofgt_spriteram3[attr_start + 3];
+
+// aerofgt has this adjustment, but doing it here would break turbo force title screen
+// ox += (xsize*zoomx+2)/4;
+// oy += (ysize*zoomy+2)/4;
+
+ zoomx = 32 - zoomx;
+ zoomy = 32 - zoomy;
+
+ for (y = 0;y <= ysize;y++)
+ {
+ int sx,sy;
+
+ if (flipy) sy = ((oy + zoomy * (ysize - y)/2 + 16) & 0x1ff) - 16;
+ else sy = ((oy + zoomy * y / 2 + 16) & 0x1ff) - 16;
+
+ for (x = 0;x <= xsize;x++)
+ {
+ int code;
+
+ if (flipx) sx = ((ox + zoomx * (xsize - x) / 2 + 16) & 0x1ff) - 16;
+ else sx = ((ox + zoomx * x / 2 + 16) & 0x1ff) - 16;
+
+ if (chip == 0)
+ code = aerofgt_spriteram1[map_start % (aerofgt_spriteram1_size/2)];
+ else
+ code = aerofgt_spriteram2[map_start % (aerofgt_spriteram2_size/2)];
+
+ pdrawgfxzoom(bitmap,machine->gfx[sprite_gfx + chip],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15,
+ zoomx << 11, zoomy << 11,
+ pri ? 0 : 2);
+ map_start++;
+ }
+
+ if (xsize == 2) map_start += 1;
+ if (xsize == 4) map_start += 3;
+ if (xsize == 5) map_start += 2;
+ if (xsize == 6) map_start += 1;
+ }
+ }
+}
+
+static void pspikesb_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int i;
+
+ for (i = 4;i < aerofgt_spriteram3_size/2;i += 4)
+ {
+ int xpos,ypos,color,flipx,flipy,code;
+
+ if (aerofgt_spriteram3[i + 3 - 4] & 0x8000) break;
+
+ xpos = (aerofgt_spriteram3[i + 2] & 0x1ff) - 34;
+ ypos = 256 - (aerofgt_spriteram3[i + 3 - 4] & 0x1ff) - 33;
+ code = aerofgt_spriteram3[i + 0] & 0x1fff;
+ flipy = 0;
+ flipx = aerofgt_spriteram3[i + 1] & 0x0800;
+ color = aerofgt_spriteram3[i + 1] & 0x000f;
+
+ drawgfx(bitmap,machine->gfx[sprite_gfx],
+ code,
+ color,
+ flipx,flipy,
+ xpos,ypos,
+ cliprect,TRANSPARENCY_PEN,15);
+
+ /* wrap around y */
+ drawgfx(bitmap,machine->gfx[sprite_gfx],
+ code,
+ color,
+ flipx,flipy,
+ xpos,ypos + 512,
+ cliprect,TRANSPARENCY_PEN,15);
+
+ }
+}
+
+static void aerfboot_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int attr_start;//,base,first;
+
+
+// base = chip * 0x0200;
+// first = 4 * aerofgt_spriteram3[0x1fe + base];
+
+ for (attr_start = aerofgt_spriteram3_size/2 - 4;attr_start >= 0;attr_start -= 4)
+ {
+ int code;
+ int ox,oy,x,y,xsize,ysize,zoomx,zoomy,flipx,flipy,color,pri;
+// some other drivers still use this wrong table, they have to be upgraded
+// int zoomtable[16] = { 0,7,14,20,25,30,34,38,42,46,49,52,54,57,59,61 };
+
+ ox = aerofgt_spriteram3[attr_start + 1] & 0x01ff;
+ oy = aerofgt_spriteram3[attr_start + 0] & 0x01ff;
+ flipx = aerofgt_spriteram3[attr_start + 2] & 0x0800;
+ flipy = aerofgt_spriteram3[attr_start + 2] & 0x8000;
+ color = aerofgt_spriteram3[attr_start + 2] & 0x000f;
+
+// xsize = (aerofgt_spriteram3[attr_start + 2] & 0x0700) >> 8;
+ xsize = (aerofgt_spriteram3[attr_start + 1] & 0x0e00) >> 9;
+ zoomx = (aerofgt_spriteram3[attr_start + 1] & 0xf000) >> 12;
+// ysize = (aerofgt_spriteram3[attr_start + 2] & 0x7000) >> 12;
+ ysize = (aerofgt_spriteram3[attr_start + 0] & 0x0e00) >> 9;
+ zoomy = (aerofgt_spriteram3[attr_start + 0] & 0xf000) >> 12;
+
+ pri = aerofgt_spriteram3[attr_start + 2] & 0x0010;
+ code = aerofgt_spriteram3[attr_start + 3] & 0x3fff;
+
+
+// aerofgt has this adjustment, but doing it here would break turbo force title screen
+// ox += (xsize*zoomx+2)/4;
+// oy += (ysize*zoomy+2)/4;
+
+ zoomx = 32 - zoomx;
+ zoomy = 32 - zoomy;
+
+ for (y = 0;y <= ysize;y++)
+ {
+ int sx,sy;
+
+ if (flipy) sy = ((oy + zoomy * (ysize - y)/2 + 16) & 0x1ff) - 16;
+ else sy = ((oy + zoomy * y / 2 + 16) & 0x1ff) - 16;
+
+ for (x = 0;x <= xsize;x++)
+ {
+ if (flipx) sx = ((ox + zoomx * (xsize - x) / 2 + 16) & 0x1ff) - 16;
+ else sx = ((ox + zoomx * x / 2 + 16) & 0x1ff) - 16;
+
+ pdrawgfxzoom(bitmap,machine->gfx[sprite_gfx + (code >= 0x1000 ? 0 : 1)],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15,
+ zoomx << 11,zoomy << 11,
+ pri ? 0 : 0x2);
+ code++;
+ }
+
+// if (xsize == 2) code += 1;
+// if (xsize == 4) code += 3;
+// if (xsize == 5) code += 2;
+// if (xsize == 6) code += 1;
+ }
+ }
+}
+
+static void wbbc97_draw_bitmap(mame_bitmap *bitmap)
+{
+ int x,y,count;
+ int color;
+
+ count = 16; // weird, the bitmap doesn't start at 0?
+ for (y=0;y<256;y++)
+ {
+ for (x=0;x<512;x++)
+ {
+ color = wbbc97_bitmapram[count] >> 1;
+
+ /* data is GRB; convert to RGB */
+ color = (color & 0x1f) | ((color & 0x3e0) << 5) | ((color & 0x7c00) >> 5);
+ *BITMAP_ADDR16(bitmap, y, (10+x-aerofgt_rasterram[(y & 0x7f)])&0x1ff) = color;
+
+ count++;
+ count &= 0x1ffff;
+ }
+ }
+}
+
+
+VIDEO_UPDATE( pspikes )
+{
+ int i,scrolly;
+
+ tilemap_set_scroll_rows(bg1_tilemap,256);
+ scrolly = bg1scrolly;
+ for (i = 0;i < 256;i++)
+ tilemap_set_scrollx(bg1_tilemap,(i + scrolly) & 0xff,aerofgt_rasterram[i]);
+ tilemap_set_scrolly(bg1_tilemap,0,scrolly);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,0,0);
+ turbofrc_draw_sprites(machine,bitmap,cliprect,0,-1);
+ turbofrc_draw_sprites(machine,bitmap,cliprect,0, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( pspikesb )
+{
+ int i,scrolly;
+
+ tilemap_set_scroll_rows(bg1_tilemap,256);
+ scrolly = bg1scrolly;
+ for (i = 0;i < 256;i++)
+ tilemap_set_scrollx(bg1_tilemap,(i + scrolly) & 0xff,aerofgt_rasterram[i]+22);
+ tilemap_set_scrolly(bg1_tilemap,0,scrolly);
+
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,0,0);
+ pspikesb_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( karatblz )
+{
+ tilemap_set_scrollx(bg1_tilemap,0,bg1scrollx-8);
+ tilemap_set_scrolly(bg1_tilemap,0,bg1scrolly);
+ tilemap_set_scrollx(bg2_tilemap,0,bg2scrollx-4);
+ tilemap_set_scrolly(bg2_tilemap,0,bg2scrolly);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,bg2_tilemap,0,0);
+
+ /* we use the priority buffer so sprites are drawn front to back */
+ turbofrc_draw_sprites(machine,bitmap,cliprect,1,-1);
+ turbofrc_draw_sprites(machine,bitmap,cliprect,1, 0);
+ turbofrc_draw_sprites(machine,bitmap,cliprect,0,-1);
+ turbofrc_draw_sprites(machine,bitmap,cliprect,0, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( spinlbrk )
+{
+ int i,scrolly;
+
+ tilemap_set_scroll_rows(bg1_tilemap,512);
+ scrolly = 0;
+ for (i = 0;i < 256;i++)
+ tilemap_set_scrollx(bg1_tilemap,(i + scrolly) & 0x1ff,aerofgt_rasterram[i]-8);
+// tilemap_set_scrolly(bg1_tilemap,0,bg1scrolly);
+ tilemap_set_scrollx(bg2_tilemap,0,bg2scrollx-4);
+// tilemap_set_scrolly(bg2_tilemap,0,bg2scrolly);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,bg2_tilemap,0,0);
+
+ /* we use the priority buffer so sprites are drawn front to back */
+ turbofrc_draw_sprites(machine,bitmap,cliprect,0,-1);
+ turbofrc_draw_sprites(machine,bitmap,cliprect,0, 0);
+ turbofrc_draw_sprites(machine,bitmap,cliprect,1,-1);
+ turbofrc_draw_sprites(machine,bitmap,cliprect,1, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( turbofrc )
+{
+ int i,scrolly;
+
+ tilemap_set_scroll_rows(bg1_tilemap,512);
+ scrolly = bg1scrolly+2;
+ for (i = 0;i < 256;i++)
+// tilemap_set_scrollx(bg1_tilemap,(i + scrolly) & 0x1ff,aerofgt_rasterram[i]-11);
+ tilemap_set_scrollx(bg1_tilemap,(i + scrolly) & 0x1ff,aerofgt_rasterram[7]-11);
+ tilemap_set_scrolly(bg1_tilemap,0,scrolly);
+ tilemap_set_scrollx(bg2_tilemap,0,bg2scrollx-7);
+ tilemap_set_scrolly(bg2_tilemap,0,bg2scrolly+2);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,bg2_tilemap,0,1);
+
+ /* we use the priority buffer so sprites are drawn front to back */
+ turbofrc_draw_sprites(machine,bitmap,cliprect,1,-1); //ship
+ turbofrc_draw_sprites(machine,bitmap,cliprect,1, 0); //intro
+ turbofrc_draw_sprites(machine,bitmap,cliprect,0,-1); //enemy
+ turbofrc_draw_sprites(machine,bitmap,cliprect,0, 0); //enemy
+ return 0;
+}
+
+VIDEO_UPDATE( aerofgt )
+{
+ tilemap_set_scrollx(bg1_tilemap,0,aerofgt_rasterram[0x0000]-18);
+ tilemap_set_scrolly(bg1_tilemap,0,bg1scrolly);
+ tilemap_set_scrollx(bg2_tilemap,0,aerofgt_rasterram[0x0200]-20);
+ tilemap_set_scrolly(bg2_tilemap,0,bg2scrolly);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,0,0);
+
+ aerofgt_draw_sprites(machine,bitmap,cliprect,0);
+ aerofgt_draw_sprites(machine,bitmap,cliprect,1);
+
+ tilemap_draw(bitmap,cliprect,bg2_tilemap,0,0);
+
+ aerofgt_draw_sprites(machine,bitmap,cliprect,2);
+ aerofgt_draw_sprites(machine,bitmap,cliprect,3);
+ return 0;
+}
+
+
+VIDEO_UPDATE( aerfboot )
+{
+ int i,scrolly;
+
+ tilemap_set_scroll_rows(bg1_tilemap,512);
+ scrolly = bg1scrolly+2;
+ for (i = 0;i < 256;i++)
+ tilemap_set_scrollx(bg1_tilemap,(i + scrolly) & 0x1ff,aerofgt_rasterram[7]+174);
+ tilemap_set_scrolly(bg1_tilemap,0,scrolly);
+ tilemap_set_scrollx(bg2_tilemap,0,bg2scrollx+172);
+ tilemap_set_scrolly(bg2_tilemap,0,bg2scrolly+2);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,bg2_tilemap,0,1);
+
+ /* we use the priority buffer so sprites are drawn front to back */
+ aerfboot_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( wbbc97 )
+{
+ int i,scrolly;
+
+ tilemap_set_scroll_rows(bg1_tilemap,256);
+ scrolly = bg1scrolly;
+ for (i = 0;i < 256;i++)
+ tilemap_set_scrollx(bg1_tilemap,(i + scrolly) & 0xff,aerofgt_rasterram[i]);
+ tilemap_set_scrolly(bg1_tilemap,0,scrolly);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ if(wbbc97_bitmap_enable)
+ {
+ wbbc97_draw_bitmap(bitmap);
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,0,0);
+ }
+ else
+ {
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ }
+
+ turbofrc_draw_sprites(machine,bitmap,cliprect,0,-1);
+ turbofrc_draw_sprites(machine,bitmap,cliprect,0, 0);
+ return 0;
+}
diff --git a/src/mame/video/afega.c b/src/mame/video/afega.c
new file mode 100644
index 00000000000..d4962550984
--- /dev/null
+++ b/src/mame/video/afega.c
@@ -0,0 +1,381 @@
+/***************************************************************************
+
+ -= Afega Games =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z with:
+
+ Q / W Shows Layer 0 / 1
+ A Shows Sprites
+
+ Keys can be used together!
+
+ [ 2 Layers ]
+ [ Layer 0 ] [ Layer 1 ]
+
+ Tile Size: 16 x 16 x 4/8 8 x 8 x 4
+ Layer Size (pixels): 1024 x 1024 256 x 256
+ Layer Size (tiles): 64 x 64 32 x 32
+ Scrolling: Yes No
+
+ The layout is a bit weird. 16 consecutive tile codes define a
+ vertical column. 16 columns form a page (256 x 256).
+ Layer 0 is made of 4 x 4 pages. Layer 1 of just 1 page.
+
+ [ 256 Sprites ]
+
+ Sprites are made of 16 x 16 x 4 tiles. Size can vary from 1 to 16
+ tiles both horizontally and vertically.
+ Is there zooming ?
+
+ [ Priorities ]
+
+ The game only uses this scheme:
+
+ Back -> Front: Layer 0, Sprites, Layer 1
+
+***************************************************************************/
+
+#include "driver.h"
+#ifdef MAME_DEBUG
+#include "ui.h"
+#endif
+
+/* Variables needed by drivers: */
+
+UINT16 *afega_vram_0, *afega_scroll_0;
+UINT16 *afega_vram_1, *afega_scroll_1;
+
+
+/***************************************************************************
+
+
+ Palette - RRRRGGGGBBBB????
+
+
+***************************************************************************/
+
+WRITE16_HANDLER( afega_palette_w )
+{
+ int r,g,b;
+ data = COMBINE_DATA(&paletteram16[offset]);
+ b = ((data & 0x00F0) >> 3 ) + ((data & 0x0002) >> 1);
+ g = ((data & 0x0F00) >> 7 ) + ((data & 0x0004) >> 2);
+ r = ((data & 0xF000) >> 11) + ((data & 0x0008) >> 3);
+ palette_set_color_rgb( Machine, offset, pal5bit(r) , pal5bit(g) , pal5bit(b) );
+}
+
+/* This game uses 8 bit tiles, so it ignores the color codes and just
+ uses the same 256 colors for every tile */
+PALETTE_INIT( grdnstrm )
+{
+ int color, pen;
+ for( color = 0; color < 16; color++ )
+ for( pen = 0; pen < 256; pen++ )
+ colortable[color * 256 + pen + 256*3] = 256*0 + pen;
+}
+
+
+/***************************************************************************
+
+ Tilemaps
+
+ Offset: Bits: Value:
+
+ 2.w fedc ---- ---- ---- Color
+ ---- ba98 7654 3210 Code
+
+***************************************************************************/
+
+#define TILES_PER_PAGE_X (0x10)
+#define TILES_PER_PAGE_Y (0x10)
+#define PAGES_PER_TMAP_X (0x4)
+#define PAGES_PER_TMAP_Y (0x4)
+#define FIREHAWK_PAGES_PER_TMAP_X (0x1)
+#define FIREHAWK_PAGES_PER_TMAP_Y (0x1)
+#define TWINACTN_TILES_PER_PAGE_X (0x100)
+#define TWINACTN_TILES_PER_PAGE_Y (0x10)
+#define TWINACTN_PAGES_PER_TMAP_X (0x1)
+#define TWINACTN_PAGES_PER_TMAP_Y (0x1)
+
+
+static TILEMAP_MAPPER( afega_tilemap_scan_pages )
+{
+ return (row / TILES_PER_PAGE_Y) * TILES_PER_PAGE_X * TILES_PER_PAGE_Y * PAGES_PER_TMAP_X +
+ (row % TILES_PER_PAGE_Y) +
+
+ (col / TILES_PER_PAGE_X) * TILES_PER_PAGE_X * TILES_PER_PAGE_Y +
+ (col % TILES_PER_PAGE_X) * TILES_PER_PAGE_Y;
+}
+
+static TILEMAP_MAPPER( twinactn_tilemap_scan_pages )
+{
+ return (row / TWINACTN_TILES_PER_PAGE_Y) * TWINACTN_TILES_PER_PAGE_X * TWINACTN_TILES_PER_PAGE_Y * TWINACTN_PAGES_PER_TMAP_X +
+ (row % TWINACTN_TILES_PER_PAGE_Y) +
+
+ (col / TWINACTN_TILES_PER_PAGE_X) * TWINACTN_TILES_PER_PAGE_X * TWINACTN_TILES_PER_PAGE_Y +
+ (col % TWINACTN_TILES_PER_PAGE_X) * TWINACTN_TILES_PER_PAGE_Y;
+}
+
+static TILEMAP_MAPPER( firehawk_tilemap_scan_pages )
+{
+ return (row / TILES_PER_PAGE_Y) * TILES_PER_PAGE_X * TILES_PER_PAGE_Y * FIREHAWK_PAGES_PER_TMAP_X +
+ (row % TILES_PER_PAGE_Y) +
+
+ (col / TILES_PER_PAGE_X) * TILES_PER_PAGE_X * TILES_PER_PAGE_Y +
+ (col % TILES_PER_PAGE_X) * TILES_PER_PAGE_Y;
+}
+
+static tilemap *tilemap_0, *tilemap_1;
+
+static TILE_GET_INFO( get_tile_info_0 )
+{
+ UINT16 code = afega_vram_0[tile_index];
+ SET_TILE_INFO(
+ 1,
+ code,
+ (code & 0xf000) >> 12,
+ 0);
+}
+static TILE_GET_INFO( get_tile_info_1 )
+{
+ UINT16 code = afega_vram_1[tile_index];
+ SET_TILE_INFO(
+ 2,
+ code,
+ (code & 0xf000) >> 12,
+ 0);
+}
+
+WRITE16_HANDLER( afega_vram_0_w )
+{
+ COMBINE_DATA(&afega_vram_0[offset]);
+ tilemap_mark_tile_dirty(tilemap_0,offset);
+}
+WRITE16_HANDLER( afega_vram_1_w )
+{
+ COMBINE_DATA(&afega_vram_1[offset]);
+ tilemap_mark_tile_dirty(tilemap_1,offset);
+}
+
+
+/***************************************************************************
+
+
+ Video Hardware Init
+
+
+***************************************************************************/
+
+VIDEO_START( afega )
+{
+ tilemap_0 = tilemap_create( get_tile_info_0, afega_tilemap_scan_pages,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ TILES_PER_PAGE_X*PAGES_PER_TMAP_X,TILES_PER_PAGE_Y*PAGES_PER_TMAP_Y);
+
+ tilemap_1 = tilemap_create( get_tile_info_1, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN,
+ 8,8,
+ 32,32);
+
+ tilemap_set_transparent_pen(tilemap_1,0xf);
+}
+
+VIDEO_START( twinactn )
+{
+ tilemap_0 = tilemap_create( get_tile_info_0, twinactn_tilemap_scan_pages,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ TWINACTN_TILES_PER_PAGE_X*TWINACTN_PAGES_PER_TMAP_X,TWINACTN_TILES_PER_PAGE_Y*TWINACTN_PAGES_PER_TMAP_Y);
+
+ tilemap_1 = tilemap_create( get_tile_info_1, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN,
+ 8,8,
+ 32,32);
+
+ tilemap_set_transparent_pen(tilemap_1,0xf);
+}
+
+VIDEO_START( firehawk )
+{
+ tilemap_0 = tilemap_create( get_tile_info_0, firehawk_tilemap_scan_pages,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ TILES_PER_PAGE_X*FIREHAWK_PAGES_PER_TMAP_X,TILES_PER_PAGE_Y*FIREHAWK_PAGES_PER_TMAP_Y);
+
+ tilemap_1 = tilemap_create( get_tile_info_1, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN,
+ 8,8,
+ 32,32);
+
+ tilemap_set_transparent_pen(tilemap_1,0xf);
+}
+
+
+/***************************************************************************
+
+ Sprites Drawing
+
+ Offset: Bits: Value:
+
+ 0.w fedc ba-- ---- ----
+ ---- --9- ---- ---- Flip Y?
+ ---- ---8 7654 3---
+ ---- --------- -21- Priority?
+ ---- ---- ---- ---0 1 = Draw This Sprite
+
+ 2.w fedc ba98 ---- ----
+ ---- ---- 7654 ---- Number Of Tiles Along Y - 1
+ ---- ---- ---- 3210 Number Of Tiles Along X - 1
+
+ 4.w
+
+ 6.w Code
+
+ 8.w fedc ba98 ---- ----
+ ---- ---- 7654 3210 X (Signed)
+
+ A.w
+
+ C.w fedc ba98 ---- ----
+ ---- ---- 7654 3210 Y (Signed)
+
+ E.w fedc ba98 7654 ----
+ ---- ---- ---- 3210 Color
+
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect, UINT16 attr_mask)
+{
+ int offs;
+
+ int max_x = machine->screen[0].width;
+ int max_y = machine->screen[0].height;
+
+ for ( offs = 0; offs < spriteram_size/2; offs += 16/2 )
+ {
+ int attr, dim, code, sx, sy, color, flipx, flipy;
+
+ int x, xnum, xstart, xend, xinc;
+ int y, ynum, ystart, yend, yinc;
+
+ attr = spriteram16[offs + 0x0/2];
+ if (!(attr & attr_mask)) continue;
+ dim = spriteram16[offs + 0x2/2];
+ code = spriteram16[offs + 0x6/2];
+ sx = spriteram16[offs + 0x8/2];
+ sy = spriteram16[offs + 0xc/2];
+ color = spriteram16[offs + 0xe/2];
+
+ flipx = attr & 0x000; // ?
+ flipy = attr & 0x000; // ?
+
+ xnum = ((dim >> 0) & 0xf) + 1;
+ ynum = ((dim >> 4) & 0xf) + 1;
+
+ sx = (sx & 0xff) - (sx & 0x100);
+ sy = (sy & 0xff) - (sy & 0x100);
+
+ if (flip_screen_x) { flipx = !flipx; sx = max_x - sx - xnum * 16; }
+ if (flip_screen_y) { flipy = !flipy; sy = max_y - sy - ynum * 16; }
+
+ if (flipx) { xstart = xnum-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = xnum; xinc = +1; }
+
+ if (flipy) { ystart = ynum-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = ynum; yinc = +1; }
+
+ for (y = ystart; y != yend; y += yinc)
+ {
+ for (x = xstart; x != xend; x += xinc)
+ {
+ drawgfx( bitmap,machine->gfx[0],
+ code++,
+ color,
+ flipx, flipy,
+ sx + x * 16, sy + y * 16,
+ cliprect,TRANSPARENCY_PEN,15 );
+ }
+ }
+
+#ifdef MAME_DEBUG
+#if 1
+if (input_code_pressed(KEYCODE_X))
+{ /* Display some info on each sprite */
+ char buf[10];
+ sprintf(buf, "%X",(spriteram16[offs + 0x0/2]&6)/2);
+ ui_draw_text(buf, sy, sx);
+}
+#endif
+#endif
+ }
+}
+
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+static void video_update(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect,
+ int dsw_flipscreen, // 1 = Horizontal and vertical screen flip are hardwired to 2 dip switches
+ int xoffset, int yoffset, // tilemap_0 offsets
+ int attr_mask // "sprite active" mask
+ )
+{
+ int layers_ctrl = -1;
+
+ if (dsw_flipscreen)
+ {
+
+ flip_screen_x_set(~readinputport(2) & 0x0100);
+ flip_screen_y_set(~readinputport(2) & 0x0200);
+ }
+
+ tilemap_set_scrollx(tilemap_0, 0, afega_scroll_0[1] + xoffset);
+ tilemap_set_scrolly(tilemap_0, 0, afega_scroll_0[0] + yoffset);
+
+ tilemap_set_scrollx(tilemap_1, 0, afega_scroll_1[1]);
+ tilemap_set_scrolly(tilemap_1, 0, afega_scroll_1[0]);
+
+#ifdef MAME_DEBUG
+if ( input_code_pressed(KEYCODE_Z) )
+{ int msk = 0;
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+ if (input_code_pressed(KEYCODE_A)) msk |= 4;
+ if (msk != 0) layers_ctrl &= msk; }
+#endif
+
+ if (layers_ctrl & 1) tilemap_draw(bitmap,cliprect,tilemap_0,0,0);
+ else fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ if (layers_ctrl & 4) draw_sprites(machine,bitmap,cliprect, attr_mask);
+
+ if (layers_ctrl & 2) tilemap_draw(bitmap,cliprect,tilemap_1,0,0);
+}
+
+VIDEO_UPDATE( afega ) { video_update(machine,bitmap,cliprect, 1, -0x100,+0x000, 0x0001); return 0; }
+VIDEO_UPDATE( bubl2000 ) { video_update(machine,bitmap,cliprect, 0, -0x100,+0x000, 0x0001); return 0; } // no flipscreen support, I really would confirmation from the schematics
+VIDEO_UPDATE( redhawkb ) { video_update(machine,bitmap,cliprect, 0, +0x000,+0x100, 0x0001); return 0; }
+VIDEO_UPDATE( twinactn ) { video_update(machine,bitmap,cliprect, 0, +0x000,+0x000, 0x0100); return 0; }
+
+VIDEO_UPDATE( firehawk )
+{
+ tilemap_set_scrolly(tilemap_0, 0, afega_scroll_1[1] + 0x100);
+ tilemap_set_scrollx(tilemap_0, 0, afega_scroll_1[0]);
+
+ tilemap_draw(bitmap,cliprect,tilemap_0,0,0);
+ draw_sprites(machine,bitmap,cliprect,1);
+
+ tilemap_draw(bitmap,cliprect,tilemap_1,0,0);
+ return 0;
+}
diff --git a/src/mame/video/airbustr.c b/src/mame/video/airbustr.c
new file mode 100644
index 00000000000..735aab07c28
--- /dev/null
+++ b/src/mame/video/airbustr.c
@@ -0,0 +1,151 @@
+/**************************************************************************
+
+ Air Buster
+ (C) 1990 Kaneko
+
+ driver by Luca Elia (l.elia@tin.it)
+
+[Screen]
+ Size: 256 x 256
+ Colors: 256 x 3
+ Color Space: 32R x 32G x 32B
+
+[Scrolling layers]
+ Number: 2
+ Size: 512 x 512
+ Scrolling: X,Y
+ Tiles Size: 16 x 16
+ Tiles Number: 0x1000
+ Colors: 256 x 2 (0-511)
+ Format:
+ Offset: 0x400 0x000
+ Bit: fedc---- -------- Color
+ ----ba98 76543210 Code
+
+[Sprites]
+ On Screen: 256 x 2
+ In ROM: 0x2000
+ Colors: 256 (512-767)
+ Format: See Below
+
+
+**************************************************************************/
+#include "driver.h"
+#include "kan_pand.h"
+
+UINT8 *airbustr_videoram2, *airbustr_colorram2;
+//int airbustr_clear_sprites;
+static tilemap *bg_tilemap, *fg_tilemap;
+static mame_bitmap *sprites_bitmap;
+
+WRITE8_HANDLER( airbustr_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( airbustr_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( airbustr_videoram2_w )
+{
+ airbustr_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( airbustr_colorram2_w )
+{
+ airbustr_colorram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+/* Scroll Registers
+
+ Port:
+ 4 Bg Y scroll, low 8 bits
+ 6 Bg X scroll, low 8 bits
+ 8 Fg Y scroll, low 8 bits
+ A Fg X scroll, low 8 bits
+
+ C 3 2 1 0 <-Bit
+ Bg Y Bg X Fg Y Fg X <-Scroll High Bits (complemented!)
+*/
+
+WRITE8_HANDLER( airbustr_scrollregs_w )
+{
+ static int bg_scrollx, bg_scrolly, fg_scrollx, fg_scrolly, highbits;
+
+ switch (offset) // offset 0 <-> port 4
+ {
+ case 0x00: fg_scrolly = data; break; // low 8 bits
+ case 0x02: fg_scrollx = data; break;
+ case 0x04: bg_scrolly = data; break;
+ case 0x06: bg_scrollx = data; break;
+ case 0x08: highbits = ~data; break; // complemented high bits
+
+ default: logerror("CPU #2 - port %02X written with %02X - PC = %04X\n", offset, data, activecpu_get_pc());
+ }
+
+ tilemap_set_scrolly(bg_tilemap, 0, ((highbits << 5) & 0x100) + bg_scrolly);
+ tilemap_set_scrollx(bg_tilemap, 0, ((highbits << 6) & 0x100) + bg_scrollx);
+ tilemap_set_scrolly(fg_tilemap, 0, ((highbits << 7) & 0x100) + fg_scrolly);
+ tilemap_set_scrollx(fg_tilemap, 0, ((highbits << 8) & 0x100) + fg_scrollx);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = airbustr_colorram2[tile_index];
+ int code = airbustr_videoram2[tile_index] + ((attr & 0x0f) << 8);
+ int color = attr >> 4;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + ((attr & 0x0f) << 8);
+ int color = (attr >> 4) + 16;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( airbustr )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+
+ sprites_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+ pandora_start(1,0,0);
+
+ tilemap_set_scrolldx(bg_tilemap, 0x094, 0x06a);
+ tilemap_set_scrolldy(bg_tilemap, 0x100, 0x1ff);
+ tilemap_set_scrolldx(fg_tilemap, 0x094, 0x06a);
+ tilemap_set_scrolldy(fg_tilemap, 0x100, 0x1ff);
+}
+
+
+VIDEO_UPDATE( airbustr )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+
+ // copy the sprite bitmap to the screen
+ pandora_update(machine, bitmap, cliprect);
+
+ return 0;
+}
+
+VIDEO_EOF( airbustr )
+{
+ // update the sprite bitmap
+ pandora_eof(machine);
+}
+
diff --git a/src/mame/video/ajax.c b/src/mame/video/ajax.c
new file mode 100644
index 00000000000..360c9dc62ef
--- /dev/null
+++ b/src/mame/video/ajax.c
@@ -0,0 +1,115 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+UINT8 ajax_priority;
+static int layer_colorbase[3],sprite_colorbase,zoom_colorbase;
+
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ *code |= ((*color & 0x0f) << 8) | (bank << 12);
+ *color = layer_colorbase[layer] + ((*color & 0xf0) >> 4);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051960
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority,int *shadow)
+{
+ /* priority bits:
+ 4 over zoom (0 = have priority)
+ 5 over B (0 = have priority)
+ 6 over A (1 = have priority)
+ never over F
+ */
+ *priority = 0xff00; /* F = 8 */
+ if ( *color & 0x10) *priority |= 0xf0f0; /* Z = 4 */
+ if (~*color & 0x40) *priority |= 0xcccc; /* A = 2 */
+ if ( *color & 0x20) *priority |= 0xaaaa; /* B = 1 */
+ *color = sprite_colorbase + (*color & 0x0f);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051316
+
+***************************************************************************/
+
+static void zoom_callback(int *code,int *color,int *flags)
+{
+ *code |= ((*color & 0x07) << 8);
+ *color = zoom_colorbase + ((*color & 0x08) >> 3);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( ajax )
+{
+ layer_colorbase[0] = 64;
+ layer_colorbase[1] = 0;
+ layer_colorbase[2] = 32;
+ sprite_colorbase = 16;
+ zoom_colorbase = 6; /* == 48 since it's 7-bit graphics */
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,NORMAL_PLANE_ORDER,sprite_callback);
+ K051316_vh_start_0(machine,REGION_GFX3,7,FALSE,0,zoom_callback);
+}
+
+
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( ajax )
+{
+ K052109_tilemap_update();
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],0,1);
+ if (ajax_priority)
+ {
+ /* basic layer order is B, zoom, A, F */
+ K051316_zoom_draw_0(bitmap,cliprect,0,4);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],0,2);
+ }
+ else
+ {
+ /* basic layer order is B, A, zoom, F */
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],0,2);
+ K051316_zoom_draw_0(bitmap,cliprect,0,4);
+ }
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],0,8);
+
+ K051960_sprites_draw(bitmap,cliprect,-1,-1);
+ return 0;
+}
diff --git a/src/mame/video/aliens.c b/src/mame/video/aliens.c
new file mode 100644
index 00000000000..f6719868488
--- /dev/null
+++ b/src/mame/video/aliens.c
@@ -0,0 +1,86 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+static int layer_colorbase[3],sprite_colorbase;
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void tile_callback(int layer,int bank,int *code,int *color, int *flags, int *priority)
+{
+ *code |= ((*color & 0x3f) << 8) | (bank << 14);
+ *color = layer_colorbase[layer] + ((*color & 0xc0) >> 6);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051960
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority_mask,int *shadow)
+{
+ /* The PROM allows for mixed priorities, where sprites would have */
+ /* priority over text but not on one or both of the other two planes. */
+ switch (*color & 0x70)
+ {
+ case 0x10: *priority_mask = 0x00; break; /* over ABF */
+ case 0x00: *priority_mask = 0xf0 ; break; /* over AB, not F */
+ case 0x40: *priority_mask = 0xf0|0xcc ; break; /* over A, not BF */
+ case 0x20:
+ case 0x60: *priority_mask = 0xf0|0xcc|0xaa; break; /* over -, not ABF */
+ case 0x50: *priority_mask = 0xcc ; break; /* over AF, not B */
+ case 0x30:
+ case 0x70: *priority_mask = 0xcc|0xaa; break; /* over F, not AB */
+ }
+ *code |= (*color & 0x80) << 6;
+ *color = sprite_colorbase + (*color & 0x0f);
+ *shadow = 0; /* shadows are not used by this game */
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( aliens )
+{
+ paletteram = auto_malloc(0x400);
+
+ layer_colorbase[0] = 0;
+ layer_colorbase[1] = 4;
+ layer_colorbase[2] = 8;
+ sprite_colorbase = 16;
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,NORMAL_PLANE_ORDER,sprite_callback);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( aliens )
+{
+ K052109_tilemap_update();
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[layer_colorbase[1] * 16],cliprect);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],0,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],0,2);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],0,4);
+
+ K051960_sprites_draw(bitmap,cliprect,-1,-1);
+ return 0;
+}
diff --git a/src/mame/video/alpha68k.c b/src/mame/video/alpha68k.c
new file mode 100644
index 00000000000..7c013e80cc1
--- /dev/null
+++ b/src/mame/video/alpha68k.c
@@ -0,0 +1,560 @@
+/***************************************************************************
+
+ Alpha 68k video emulation - Bryan McPhail, mish@tendril.co.uk
+
+****************************************************************************/
+
+#include "driver.h"
+
+static tilemap *fix_tilemap;
+static int bank_base,flipscreen;
+
+extern void (*alpha68k_video_banking)(int *bank, int data);
+
+extern int alpha68k_microcontroller_id;
+
+/******************************************************************************/
+
+void alpha68k_flipscreen_w(int flip)
+{
+ flipscreen = flip;
+}
+
+void alpha68k_V_video_bank_w(int bank)
+{
+ bank_base = bank&0xf;
+}
+
+WRITE16_HANDLER( alpha68k_paletteram_w )
+{
+ int newword;
+ int r,g,b;
+
+ COMBINE_DATA(paletteram16 + offset);
+ newword = paletteram16[offset];
+
+ r = ((newword >> 7) & 0x1e) | ((newword >> 14) & 0x01);
+ g = ((newword >> 3) & 0x1e) | ((newword >> 13) & 0x01);
+ b = ((newword << 1) & 0x1e) | ((newword >> 12) & 0x01);
+
+ palette_set_color_rgb(Machine,offset,pal5bit(r),pal5bit(g),pal5bit(b));
+}
+
+/******************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ int tile = videoram16[2*tile_index] &0xff;
+ int color = videoram16[2*tile_index+1] &0x0f;
+
+ tile=tile | (bank_base<<8);
+
+ SET_TILE_INFO(0, tile, color, 0);
+}
+
+WRITE16_HANDLER( alpha68k_videoram_w )
+{
+ /* Doh. */
+ if(ACCESSING_LSB)
+ if(ACCESSING_MSB)
+ videoram16[offset] = data;
+ else
+ videoram16[offset] = data & 0xff;
+ else
+ videoram16[offset] = (data >> 8) & 0xff;
+
+ tilemap_mark_tile_dirty(fix_tilemap,offset/2);
+}
+
+VIDEO_START( alpha68k )
+{
+ fix_tilemap = tilemap_create(get_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(fix_tilemap,0);
+}
+
+/******************************************************************************/
+//AT
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int j, int s, int e)
+{
+ int offs,mx,my,color,tile,fx,fy,i;
+
+ for (offs = s; offs < e; offs += 0x40 )
+ {
+ my = spriteram16[offs+3+(j<<1)];
+ mx = spriteram16[offs+2+(j<<1)]<<1 | my>>15;
+ my = -my & 0x1ff;
+ mx = ((mx + 0x100) & 0x1ff) - 0x100;
+ if (j==0 && s==0x7c0) my++;
+//ZT
+ if (flipscreen) {
+ mx=240-mx;
+ my=240-my;
+ }
+
+ for (i=0; i<0x40; i+=2) {
+ tile = spriteram16[offs+1+i+(0x800*j)+0x800];
+ color = spriteram16[offs +i+(0x800*j)+0x800]&0x7f;
+
+ fy=tile&0x8000;
+ fx=tile&0x4000;
+ tile&=0x3fff;
+
+ if (flipscreen) {
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ }
+
+ if (color)
+ drawgfx(bitmap,machine->gfx[1],
+ tile,
+ color,
+ fx,fy,
+ mx,my,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ if (flipscreen)
+ my=(my-16)&0x1ff;
+ else
+ my=(my+16)&0x1ff;
+ }
+ }
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( alpha68k_II )
+{
+ static int last_bank=0;
+
+ if (last_bank!=bank_base)
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ last_bank=bank_base;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ fillbitmap(bitmap,machine->pens[2047],cliprect);
+//AT
+ draw_sprites(machine, bitmap,cliprect,0,0x07c0,0x0800);
+ draw_sprites(machine, bitmap,cliprect,1,0x0000,0x0800);
+ draw_sprites(machine, bitmap,cliprect,2,0x0000,0x0800);
+ draw_sprites(machine, bitmap,cliprect,0,0x0000,0x07c0);
+//ZT
+ tilemap_draw(bitmap,cliprect,fix_tilemap,0,0);
+ return 0;
+}
+
+/******************************************************************************/
+
+/*
+ Video banking:
+
+ Write to these locations in this order for correct bank:
+
+ 20 28 30 for Bank 0
+ 60 28 30 for Bank 1
+ 20 68 30 etc
+ 60 68 30
+ 20 28 70
+ 60 28 70
+ 20 68 70
+ 60 68 70 for Bank 7
+
+ Actual data values written don't matter!
+
+*/
+
+WRITE16_HANDLER( alpha68k_II_video_bank_w )
+{
+ static int buffer_28,buffer_60,buffer_68;
+
+ switch (offset) {
+ case 0x10: /* Reset */
+ bank_base=buffer_28=buffer_60=buffer_68=0;
+ return;
+ case 0x14:
+ if (buffer_60) bank_base=1; else bank_base=0;
+ buffer_28=1;
+ return;
+ case 0x18:
+ if (buffer_68) {if (buffer_60) bank_base=3; else bank_base=2; }
+ if (buffer_28) {if (buffer_60) bank_base=1; else bank_base=0; }
+ return;
+ case 0x30:
+ buffer_28=buffer_68=0; bank_base=1;
+ buffer_60=1;
+ return;
+ case 0x34:
+ if (buffer_60) bank_base=3; else bank_base=2;
+ buffer_68=1;
+ return;
+ case 0x38:
+ if (buffer_68) {if (buffer_60) bank_base=7; else bank_base=6; }
+ if (buffer_28) {if (buffer_60) bank_base=5; else bank_base=4; }
+ return;
+ case 0x08: /* Graphics flags? Not related to fix chars anyway */
+ case 0x0c:
+ case 0x28:
+ case 0x2c:
+ return;
+ }
+
+ logerror("%04x \n",offset);
+}
+
+/******************************************************************************/
+
+WRITE16_HANDLER( alpha68k_V_video_control_w )
+{
+ switch (offset) {
+ case 0x08: /* Graphics flags? Not related to fix chars anyway */
+ case 0x0c:
+ case 0x28:
+ case 0x2c:
+ return;
+ }
+}
+
+static void draw_sprites_V(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int j, int s, int e, int fx_mask, int fy_mask, int sprite_mask)
+{
+ int offs,mx,my,color,tile,fx,fy,i;
+
+ for (offs = s; offs < e; offs += 0x40 )
+ {
+//AT
+ my = spriteram16[offs+3+(j<<1)];
+ mx = spriteram16[offs+2+(j<<1)]<<1 | my>>15;
+ my = -my & 0x1ff;
+ mx = ((mx + 0x100) & 0x1ff) - 0x100;
+ if (j==0 && s==0x7c0) my++;
+//ZT
+ if (flipscreen) {
+ mx=240-mx;
+ my=240-my;
+ }
+
+ for (i=0; i<0x40; i+=2) {
+ tile = spriteram16[offs+1+i+(0x800*j)+0x800];
+ color = spriteram16[offs +i+(0x800*j)+0x800]&0xff;
+
+ fx=tile&fx_mask;
+ fy=tile&fy_mask;
+ tile=tile&sprite_mask;
+ if (tile>0x4fff) continue;
+
+ if (flipscreen) {
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ }
+
+ if (color)
+ drawgfx(bitmap,machine->gfx[1],
+ tile,
+ color,
+ fx,fy,
+ mx,my,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ if (flipscreen)
+ my=(my-16)&0x1ff;
+ else
+ my=(my+16)&0x1ff;
+ }
+ }
+}
+
+VIDEO_UPDATE( alpha68k_V )
+{
+ static int last_bank=0;
+
+ if (last_bank!=bank_base)
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ last_bank=bank_base;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ fillbitmap(bitmap,machine->pens[4095],cliprect);
+
+ /* This appears to be correct priority */
+ if (alpha68k_microcontroller_id == 0x8814) /* Sky Adventure */
+ {
+ draw_sprites_V(machine, bitmap,cliprect,0,0x07c0,0x0800,0,0x8000,0x7fff);
+ draw_sprites_V(machine, bitmap,cliprect,1,0x0000,0x0800,0,0x8000,0x7fff);
+ //AT: *KLUDGE* fixes priest priority in level 1(could be a game bug)
+ if (spriteram16[0x1bde]==0x24 && (spriteram16[0x1bdf]>>8)==0x3b) {
+ draw_sprites_V(machine, bitmap,cliprect,2,0x03c0,0x0800,0,0x8000,0x7fff);
+ draw_sprites_V(machine, bitmap,cliprect,2,0x0000,0x03c0,0,0x8000,0x7fff);
+ } else
+ draw_sprites_V(machine, bitmap,cliprect,2,0x0000,0x0800,0,0x8000,0x7fff);
+ draw_sprites_V(machine, bitmap,cliprect,0,0x0000,0x07c0,0,0x8000,0x7fff);
+ }
+ else /* gangwars */
+ {
+ draw_sprites_V(machine, bitmap,cliprect,0,0x07c0,0x0800,0x8000,0,0x7fff);
+ draw_sprites_V(machine, bitmap,cliprect,1,0x0000,0x0800,0x8000,0,0x7fff);
+ draw_sprites_V(machine, bitmap,cliprect,2,0x0000,0x0800,0x8000,0,0x7fff);
+ draw_sprites_V(machine, bitmap,cliprect,0,0x0000,0x07c0,0x8000,0,0x7fff);
+ }
+
+ tilemap_draw(bitmap,cliprect,fix_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( alpha68k_V_sb )
+{
+ static int last_bank=0;
+
+ if (last_bank!=bank_base)
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ last_bank=bank_base;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ fillbitmap(bitmap,machine->pens[4095],cliprect);
+
+ /* This appears to be correct priority */
+ draw_sprites_V(machine,bitmap,cliprect,0,0x07c0,0x0800,0x4000,0x8000,0x3fff);
+ draw_sprites_V(machine,bitmap,cliprect,1,0x0000,0x0800,0x4000,0x8000,0x3fff);
+ draw_sprites_V(machine,bitmap,cliprect,2,0x0000,0x0800,0x4000,0x8000,0x3fff);
+ draw_sprites_V(machine,bitmap,cliprect,0,0x0000,0x07c0,0x4000,0x8000,0x3fff);
+
+ tilemap_draw(bitmap,cliprect,fix_tilemap,0,0);
+ return 0;
+}
+
+/******************************************************************************/
+//AT
+static void draw_sprites_I(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int c, int d, int yshift)
+{
+ int data, offs, mx, my, tile, color, fy, i;
+ UINT8 *color_prom = memory_region(REGION_USER1);
+ gfx_element *gfx = machine->gfx[0];
+
+ for (offs=0; offs<0x400; offs+=0x20)
+ {
+ mx = spriteram16[offs+c];
+ my = (yshift-(mx>>8)) & 0xff;
+ mx &= 0xff;
+
+ for (i=0; i<0x20; i++)
+ {
+ data = spriteram16[offs+d+i];
+ tile = data & 0x3fff;
+ fy = data & 0x4000;
+ color = color_prom[tile<<1|data>>15];
+
+ drawgfx(bitmap, gfx, tile, color, 0, fy, mx, my,
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ my = (my + 8) & 0xff;
+ }
+ }
+}
+
+VIDEO_UPDATE( alpha68k_I )
+{
+ int yshift = (alpha68k_microcontroller_id == 0x890a) ? 1 : 0; // The Next Space is 1 pixel off
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ /* This appears to be correct priority */
+ draw_sprites_I(machine, bitmap,cliprect,2,0x0800,yshift);
+ draw_sprites_I(machine, bitmap,cliprect,3,0x0c00,yshift);
+ draw_sprites_I(machine, bitmap,cliprect,1,0x0400,yshift);
+ return 0;
+}
+//ZT
+/******************************************************************************/
+
+PALETTE_INIT( kyros )
+{
+ int i,bit0,bit1,bit2,bit3,r,g,b;
+
+ for (i = 0;i < 256;i++)
+ {
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[0x100] >> 0) & 0x01;
+ bit1 = (color_prom[0x100] >> 1) & 0x01;
+ bit2 = (color_prom[0x100] >> 2) & 0x01;
+ bit3 = (color_prom[0x100] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[0x200] >> 0) & 0x01;
+ bit1 = (color_prom[0x200] >> 1) & 0x01;
+ bit2 = (color_prom[0x200] >> 2) & 0x01;
+ bit3 = (color_prom[0x200] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 0x200;
+
+ for (i = 0;i < 256;i++)
+ {
+ *colortable++ = ((color_prom[0] & 0x0f) << 4) | (color_prom[0x100] & 0x0f);
+ color_prom++;
+ }
+}
+
+PALETTE_INIT( paddlem )
+{
+ int i,bit0,bit1,bit2,bit3,r,g,b;
+
+ for (i = 0;i < 256;i++)
+ {
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[0x100] >> 0) & 0x01;
+ bit1 = (color_prom[0x100] >> 1) & 0x01;
+ bit2 = (color_prom[0x100] >> 2) & 0x01;
+ bit3 = (color_prom[0x100] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[0x200] >> 0) & 0x01;
+ bit1 = (color_prom[0x200] >> 1) & 0x01;
+ bit2 = (color_prom[0x200] >> 2) & 0x01;
+ bit3 = (color_prom[0x200] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* Fill in clut */
+ color_prom += 0x200;
+ for (i=0; i<1024; i++) colortable[i] = color_prom[i]|(color_prom[i+0x400]<<4);
+}
+
+void kyros_video_banking(int *bank, int data)
+{
+ *bank = (data>>13 & 4) | (data>>10 & 3);
+}
+
+void jongbou_video_banking(int *bank, int data)
+{
+ *bank = (data>>11 & 4) | (data>>10 & 3);
+}
+
+static void kyros_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int c,int d)
+{
+ int offs,mx,my,color,tile,i,bank,fy,fx;
+ int data;
+ UINT8 *color_prom = memory_region(REGION_USER1);
+
+//AT
+ for (offs=0; offs<0x400; offs+=0x20)
+ {
+ mx = spriteram16[offs+c];
+ my = -(mx>>8) & 0xff;
+ mx &= 0xff;
+
+ if (flipscreen) {
+ my=249-my;
+ }
+
+ for (i=0; i<0x20; i++)
+ {
+ data = spriteram16[offs+d+i];
+ if (data!=0x20)
+ {
+ color = color_prom[(data>>1&0x1000)|(data&0xffc)|(data>>14&3)];
+ if (color!=0xff)
+ {
+ fy = data & 0x1000;
+ fx = 0;
+
+ if(flipscreen)
+ {
+ if (fy) fy=0; else fy=1;
+ fx = 1;
+ }
+
+ tile = (data>>3 & 0x400) | (data & 0x3ff);
+ alpha68k_video_banking(&bank, data);
+ drawgfx(bitmap, machine->gfx[bank], tile, color, fx, fy, mx, my,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+ }
+//ZT
+ if(flipscreen)
+ my=(my-8)&0xff;
+ else
+ my=(my+8)&0xff;
+ }
+ }
+}
+
+VIDEO_UPDATE( kyros )
+{
+ fillbitmap(bitmap,*videoram16 & 0xff,cliprect); //AT
+
+ kyros_draw_sprites(machine, bitmap,cliprect,2,0x0800);
+ kyros_draw_sprites(machine, bitmap,cliprect,3,0x0c00);
+ kyros_draw_sprites(machine, bitmap,cliprect,1,0x0400);
+ return 0;
+}
+
+/******************************************************************************/
+
+static void sstingry_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int c,int d)
+{
+//AT
+ int data,offs,mx,my,color,tile,i,bank,fy,fx;
+
+ for (offs=0; offs<0x400; offs+=0x20)
+ {
+ mx = spriteram16[offs+c];
+ my = -(mx>>8) & 0xff;
+ mx &= 0xff;
+ if (mx > 0xf8) mx -= 0x100;
+
+ if (flipscreen) {
+ my=249-my;
+ }
+
+ for (i=0; i<0x20; i++)
+ {
+ data = spriteram16[offs+d+i];
+ if (data!=0x40)
+ {
+ fy = data & 0x1000;
+ fx = 0;
+
+ if(flipscreen)
+ {
+ if (fy) fy=0; else fy=1;
+ fx = 1;
+ }
+
+ color = (data>>7 & 0x18) | (data>>13 & 7);
+ tile = data & 0x3ff;
+ bank = data>>10 & 3;
+ drawgfx(bitmap, machine->gfx[bank], tile, color, fx, fy, mx, my,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+//ZT
+ if(flipscreen)
+ my=(my-8)&0xff;
+ else
+ my=(my+8)&0xff;
+ }
+ }
+}
+
+VIDEO_UPDATE( sstingry )
+{
+ fillbitmap(bitmap,*videoram16 & 0xff,cliprect); //AT
+
+ sstingry_draw_sprites(machine, bitmap,cliprect,2,0x0800);
+ sstingry_draw_sprites(machine, bitmap,cliprect,3,0x0c00);
+ sstingry_draw_sprites(machine, bitmap,cliprect,1,0x0400);
+ return 0;
+}
diff --git a/src/mame/video/ambush.c b/src/mame/video/ambush.c
new file mode 100644
index 00000000000..60f6273b2a0
--- /dev/null
+++ b/src/mame/video/ambush.c
@@ -0,0 +1,173 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *ambush_scrollram;
+UINT8 *ambush_colorbank;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ I'm not sure about the resistor value, I'm using the Galaxian ones.
+
+***************************************************************************/
+PALETTE_INIT( ambush )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors; i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+
+static void draw_chars(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int offs, transparency;
+
+
+ transparency = (priority == 0) ? TRANSPARENCY_NONE : TRANSPARENCY_PEN;
+
+ for (offs = 0; offs < videoram_size; offs++)
+ {
+ int code,sx,sy,col;
+ UINT8 scroll;
+
+
+ sy = (offs / 32);
+ sx = (offs % 32);
+
+ col = colorram[((sy & 0x1c) << 3) + sx];
+
+ if ((col & 0x10) != priority) continue;
+
+ scroll = ~ambush_scrollram[sx];
+
+ code = videoram[offs] | ((col & 0x60) << 3);
+
+ if (flip_screen)
+ {
+ sx = 31 - sx;
+ sy = 31 - sy;
+ scroll = ~scroll - 1;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ (col & 0x0f) | ((*ambush_colorbank & 0x03) << 4),
+ flip_screen,flip_screen,
+ 8*sx, (8*sy + scroll) & 0xff,
+ cliprect,transparency,0);
+ }
+}
+
+
+VIDEO_UPDATE( ambush )
+{
+ int offs;
+
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+
+ /* Draw the background priority characters */
+ draw_chars(machine, bitmap, cliprect, 0x00);
+
+
+ /* Draw the sprites. */
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int code,col,sx,sy,flipx,flipy,gfx;
+
+
+ sy = spriteram[offs + 0];
+ sx = spriteram[offs + 3];
+
+ if ( (sy == 0) ||
+ (sy == 0xff) ||
+ ((sx < 0x40) && ( spriteram[offs + 2] & 0x10)) ||
+ ((sx >= 0xc0) && (!(spriteram[offs + 2] & 0x10)))) continue; /* prevent wraparound */
+
+
+ code = (spriteram[offs + 1] & 0x3f) | ((spriteram[offs + 2] & 0x60) << 1);
+
+ if (spriteram[offs + 2] & 0x80)
+ {
+ /* 16x16 sprites */
+ gfx = 1;
+
+ if (!flip_screen)
+ {
+ sy = 240 - sy;
+ }
+ else
+ {
+ sx = 240 - sx;
+ }
+ }
+ else
+ {
+ /* 8x8 sprites */
+ gfx = 0;
+ code <<= 2;
+
+ if (!flip_screen)
+ {
+ sy = 248 - sy;
+ }
+ else
+ {
+ sx = 248 - sx;
+ }
+ }
+
+ col = spriteram[offs + 2] & 0x0f;
+ flipx = spriteram[offs + 1] & 0x40;
+ flipy = spriteram[offs + 1] & 0x80;
+
+ if (flip_screen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[gfx],
+ code, col | ((*ambush_colorbank & 0x03) << 4),
+ flipx, flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+
+ /* Draw the foreground priority characters */
+ draw_chars(machine, bitmap, cliprect, 0x10);
+ return 0;
+}
diff --git a/src/mame/video/amiga.c b/src/mame/video/amiga.c
new file mode 100644
index 00000000000..93c3a2df0cc
--- /dev/null
+++ b/src/mame/video/amiga.c
@@ -0,0 +1,971 @@
+/***************************************************************************
+
+ Amiga hardware
+
+ Driver by: Ernesto Corvi, Mariusz Wojcieszek, Aaron Giles
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/amiga.h"
+
+
+
+/*************************************
+ *
+ * Debugging
+ *
+ *************************************/
+
+#define LOG_COPPER 0
+#define GUESS_COPPER_OFFSET 0
+#define LOG_SPRITE_DMA 0
+
+
+
+/*************************************
+ *
+ * Macros
+ *
+ *************************************/
+
+#define COPPER_CYCLES_TO_PIXELS(x) (4 * (x))
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+/* sprite states */
+static UINT8 sprite_comparitor_enable_mask;
+static UINT8 sprite_dma_reload_mask;
+static UINT8 sprite_dma_live_mask;
+static UINT32 sprite_shiftreg[8];
+static UINT8 sprite_remain[8];
+
+/* playfield states */
+static int last_scanline;
+static UINT16 ham_color;
+
+/* copper states */
+static UINT32 copper_pc;
+static UINT8 copper_waiting;
+static UINT8 copper_waitblit;
+static UINT16 copper_waitval;
+static UINT16 copper_waitmask;
+static UINT16 copper_pending_offset;
+static UINT16 copper_pending_data;
+
+/* misc states */
+static UINT16 genlock_color;
+
+#if GUESS_COPPER_OFFSET
+static int wait_offset = 3;
+#endif
+
+
+
+/*************************************
+ *
+ * Tables
+ *
+ *************************************/
+
+/* expand an 8-bit bit pattern into 16 bits, every other bit */
+static const UINT16 expand_byte[256] =
+{
+ 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
+ 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
+ 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
+ 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
+ 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
+ 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
+ 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
+ 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
+ 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
+ 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
+ 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
+ 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
+ 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
+ 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
+ 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
+ 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
+
+ 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
+ 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
+ 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
+ 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
+ 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
+ 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
+ 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
+ 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
+ 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
+ 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
+ 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
+ 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
+ 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
+ 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
+ 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
+ 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
+};
+
+/* separate 6 in-order bitplanes into 2 x 3-bit bitplanes in two nibbles */
+static UINT8 separate_bitplanes[2][64];
+
+
+
+/*************************************
+ *
+ * 4-4-4 palette init
+ *
+ *************************************/
+
+PALETTE_INIT( amiga )
+{
+ int i;
+
+ for (i = 0; i < 0x1000; i++)
+ palette_set_color_rgb(machine, i, pal4bit(i >> 8), pal4bit(i >> 4), pal4bit(i));
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( amiga )
+{
+ int j;
+
+ /* generate tables that produce the correct playfield color for dual playfield mode */
+ for (j = 0; j < 64; j++)
+ {
+ int pf1pix = ((j >> 0) & 1) | ((j >> 1) & 2) | ((j >> 2) & 4);
+ int pf2pix = ((j >> 1) & 1) | ((j >> 2) & 2) | ((j >> 3) & 4);
+
+ separate_bitplanes[0][j] = (pf1pix || !pf2pix) ? pf1pix : (pf2pix + 8);
+ separate_bitplanes[1][j] = pf2pix ? (pf2pix + 8) : pf1pix;
+ }
+
+ /* reset the genlock color */
+ genlock_color = 0xffff;
+
+ video_start_generic_bitmapped(machine);
+}
+
+
+
+/*************************************
+ *
+ * Beam position
+ *
+ *************************************/
+
+UINT32 amiga_gethvpos(void)
+{
+ UINT32 hvpos = (last_scanline << 8) | (video_screen_get_hpos(0) >> 2);
+ UINT32 latchedpos = readinputportbytag_safe("HVPOS", 0);
+
+ /* if there's no latched position, or if we are in the active display area */
+ /* but before the latching point, return the live HV position */
+ if ((CUSTOM_REG(REG_BPLCON0) & 0x0008) == 0 || latchedpos == 0 || (last_scanline >= 20 && hvpos < latchedpos))
+ return hvpos;
+
+ /* otherwise, return the latched position */
+ return latchedpos;
+}
+
+
+
+/*************************************
+ *
+ * Genlock interaction
+ *
+ *************************************/
+
+void amiga_set_genlock_color(UINT16 color)
+{
+ genlock_color = color;
+}
+
+
+
+/*************************************
+ *
+ * Copper emulation
+ *
+ *************************************/
+
+void copper_setpc(UINT32 pc)
+{
+ if (LOG_COPPER)
+ logerror("copper_setpc(%06x)\n", pc);
+
+ copper_pc = pc;
+ copper_waiting = FALSE;
+}
+
+
+static int copper_execute_next(int xpos)
+{
+ int word0, word1;
+
+ /* bail if not enabled */
+ if ((CUSTOM_REG(REG_DMACON) & (DMACON_COPEN | DMACON_DMAEN)) != (DMACON_COPEN | DMACON_DMAEN))
+ return 511;
+
+ /* flush any pending writes */
+ if (copper_pending_offset)
+ {
+ if (LOG_COPPER)
+ logerror("%02X.%02X: Write to %s = %04x\n", last_scanline, xpos / 2, amiga_custom_names[copper_pending_offset & 0xff], copper_pending_data);
+
+ amiga_custom_w(copper_pending_offset, copper_pending_data, 0);
+ copper_pending_offset = 0;
+ }
+
+ /* if we're waiting, check for a breakthrough */
+ if (copper_waiting)
+ {
+ int curpos = (last_scanline << 8) | (xpos >> 1);
+
+ /* if we're past the wait time, stop it and hold up 2 cycles */
+ if ((curpos & copper_waitmask) >= (copper_waitval & copper_waitmask) &&
+ (!copper_waitblit || !(CUSTOM_REG(REG_DMACON) & DMACON_BBUSY)))
+ {
+ copper_waiting = FALSE;
+#if GUESS_COPPER_OFFSET
+ return xpos + COPPER_CYCLES_TO_PIXELS(1 + wait_offset);
+#else
+ return xpos + COPPER_CYCLES_TO_PIXELS(1 + 3);
+#endif
+ }
+
+ /* otherwise, see if this line is even a possibility; if not, punt */
+ if (((curpos | 0xff) & copper_waitmask) < (copper_waitval & copper_waitmask))
+ return 511;
+
+ /* else just advance another pixel */
+ xpos += COPPER_CYCLES_TO_PIXELS(1);
+ return xpos;
+ }
+
+ /* fetch the first data word */
+ word0 = amiga_chip_ram_r(copper_pc);
+ copper_pc += 2;
+ xpos += COPPER_CYCLES_TO_PIXELS(1);
+
+ /* fetch the second data word */
+ word1 = amiga_chip_ram_r(copper_pc);
+ copper_pc += 2;
+ xpos += COPPER_CYCLES_TO_PIXELS(1);
+
+ if (LOG_COPPER)
+ logerror("%02X.%02X: Copper inst @ %06x = %04x %04x\n", last_scanline, xpos / 2, copper_pc, word0, word1);
+
+ /* handle a move */
+ if ((word0 & 1) == 0)
+ {
+ int min = (CUSTOM_REG(REG_COPCON) & 2) ? 0x20 : 0x40;
+
+ /* do the write if we're allowed */
+ word0 = (word0 >> 1) & 0xff;
+ if (word0 >= min)
+ {
+ /* write it at the *end* of this instruction's cycles */
+ /* needed for Arcadia's Fast Break */
+ copper_pending_offset = word0;
+ copper_pending_data = word1;
+ }
+
+ /* illegal writes suspend until next frame */
+ else
+ {
+ if (LOG_COPPER)
+ logerror("%02X.%02X: Aborting copper on illegal write\n", last_scanline, xpos / 2);
+
+ copper_waitval = 0xffff;
+ copper_waitmask = 0xffff;
+ copper_waitblit = FALSE;
+ copper_waiting = TRUE;
+ return 511;
+ }
+ }
+ else
+ {
+ /* extract common wait/skip values */
+ copper_waitval = word0 & 0xfffe;
+ copper_waitmask = word1 | 0x8001;
+ copper_waitblit = (~word1 >> 15) & 1;
+
+ /* handle a wait */
+ if ((word1 & 1) == 0)
+ {
+ if (LOG_COPPER)
+ logerror(" Waiting for %04x & %04x (currently %04x)\n", copper_waitval, copper_waitmask, (last_scanline << 8) | (xpos >> 1));
+
+ copper_waiting = TRUE;
+ }
+
+ /* handle a skip */
+ else
+ {
+ int curpos = (last_scanline << 8) | (xpos >> 1);
+
+ if (LOG_COPPER)
+ logerror(" Skipping if %04x & %04x (currently %04x)\n", copper_waitval, copper_waitmask, (last_scanline << 8) | (xpos >> 1));
+
+ /* if we're past the wait time, stop it and hold up 2 cycles */
+ if ((curpos & copper_waitmask) >= (copper_waitval & copper_waitmask) &&
+ (!copper_waitblit || !(CUSTOM_REG(REG_DMACON) & DMACON_BBUSY)))
+ {
+ if (LOG_COPPER)
+ logerror(" Skipped\n");
+
+ /* count the cycles it out have taken to fetch the next instruction */
+ copper_pc += 4;
+ xpos += COPPER_CYCLES_TO_PIXELS(2);
+ }
+ }
+ }
+
+ /* advance and consume 8 cycles */
+ return xpos;
+}
+
+
+
+/*************************************
+ *
+ * External sprite controls
+ *
+ *************************************/
+
+void amiga_sprite_dma_reset(int which)
+{
+ sprite_dma_reload_mask |= 1 << which;
+ sprite_dma_live_mask |= 1 << which;
+}
+
+
+void amiga_sprite_enable_comparitor(int which, int enable)
+{
+ if (enable)
+ {
+ sprite_comparitor_enable_mask |= 1 << which;
+ sprite_dma_live_mask &= ~(1 << which);
+ }
+ else
+ sprite_comparitor_enable_mask &= ~(1 << which);
+}
+
+
+
+/*************************************
+ *
+ * Per-scanline sprite fetcher
+ *
+ *************************************/
+
+static void update_sprite_dma(int scanline)
+{
+ int dmaenable = (CUSTOM_REG(REG_DMACON) & (DMACON_SPREN | DMACON_DMAEN)) == (DMACON_SPREN | DMACON_DMAEN);
+ int num, maxdma;
+
+ /* channels are limited by DDFSTART */
+ maxdma = (CUSTOM_REG(REG_DDFSTRT) - 0x14) / 4;
+ if (maxdma > 8)
+ maxdma = 8;
+
+ /* loop over sprite channels */
+ for (num = 0; num < maxdma; num++)
+ {
+ int bitmask = 1 << num;
+ int vstart, vstop;
+
+ /* if we are == VSTOP, fetch new control words */
+ if (dmaenable && (sprite_dma_live_mask & bitmask) && (sprite_dma_reload_mask & bitmask))
+ {
+ /* disable the sprite */
+ sprite_comparitor_enable_mask &= ~bitmask;
+ sprite_dma_reload_mask &= ~bitmask;
+
+ /* fetch data into the control words */
+ CUSTOM_REG(REG_SPR0POS + 4 * num) = amiga_chip_ram_r(CUSTOM_REG_LONG(REG_SPR0PTH + 2 * num) + 0);
+ CUSTOM_REG(REG_SPR0CTL + 4 * num) = amiga_chip_ram_r(CUSTOM_REG_LONG(REG_SPR0PTH + 2 * num) + 2);
+ CUSTOM_REG_LONG(REG_SPR0PTH + 2 * num) += 4;
+ if (LOG_SPRITE_DMA) logerror("%3d:sprite %d fetch: pos=%04X ctl=%04X\n", scanline, num, CUSTOM_REG(REG_SPR0POS + 4 * num), CUSTOM_REG(REG_SPR0CTL + 4 * num));
+ }
+
+ /* compute vstart/vstop */
+ vstart = (CUSTOM_REG(REG_SPR0POS + 4 * num) >> 8) | ((CUSTOM_REG(REG_SPR0CTL + 4 * num) << 6) & 0x100);
+ vstop = (CUSTOM_REG(REG_SPR0CTL + 4 * num) >> 8) | ((CUSTOM_REG(REG_SPR0CTL + 4 * num) << 7) & 0x100);
+
+ /* if we hit vstart, enable the comparitor */
+ if (scanline == vstart)
+ {
+ sprite_comparitor_enable_mask |= 1 << num;
+ if (LOG_SPRITE_DMA) logerror("%3d:sprite %d comparitor enable\n", scanline, num);
+ }
+
+ /* if we hit vstop, disable the comparitor and trigger a reload for the next scanline */
+ if (scanline == vstop)
+ {
+ sprite_comparitor_enable_mask &= ~bitmask;
+ sprite_dma_reload_mask |= 1 << num;
+ CUSTOM_REG(REG_SPR0DATA + 4 * num) = 0; /* just a guess */
+ CUSTOM_REG(REG_SPR0DATB + 4 * num) = 0;
+ if (LOG_SPRITE_DMA) logerror("%3d:sprite %d comparitor disable, prepare for reload\n", scanline, num);
+ }
+
+ /* fetch data if this sprite is enabled */
+ if (dmaenable && (sprite_dma_live_mask & bitmask) && (sprite_comparitor_enable_mask & bitmask))
+ {
+ CUSTOM_REG(REG_SPR0DATA + 4 * num) = amiga_chip_ram_r(CUSTOM_REG_LONG(REG_SPR0PTH + 2 * num) + 0);
+ CUSTOM_REG(REG_SPR0DATB + 4 * num) = amiga_chip_ram_r(CUSTOM_REG_LONG(REG_SPR0PTH + 2 * num) + 2);
+ CUSTOM_REG_LONG(REG_SPR0PTH + 2 * num) += 4;
+ if (LOG_SPRITE_DMA) logerror("%3d:sprite %d fetch: data=%04X-%04X\n", scanline, num, CUSTOM_REG(REG_SPR0DATA + 4 * num), CUSTOM_REG(REG_SPR0DATB + 4 * num));
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Per-pixel sprite computations
+ *
+ *************************************/
+
+INLINE UINT32 interleave_sprite_data(UINT16 lobits, UINT16 hibits)
+{
+ return (expand_byte[lobits & 0xff] << 0) | (expand_byte[lobits >> 8] << 16) |
+ (expand_byte[hibits & 0xff] << 1) | (expand_byte[hibits >> 8] << 17);
+}
+
+
+static int get_sprite_pixel(int x)
+{
+ int pixels = 0;
+ int num, pair;
+
+ /* loop over sprite channels */
+ for (num = 0; num < 8; num++)
+ if (sprite_comparitor_enable_mask & (1 << num))
+ {
+ /* if we're not currently clocking, check against hstart */
+ if (sprite_remain[num] == 0)
+ {
+ int hstart = ((CUSTOM_REG(REG_SPR0POS + 4 * num) & 0xff) << 1) | (CUSTOM_REG(REG_SPR0CTL + 4 * num) & 1);
+ if (hstart == x)
+ {
+ sprite_remain[num] = 16;
+ sprite_shiftreg[num] = interleave_sprite_data(CUSTOM_REG(REG_SPR0DATA + 4 * num), CUSTOM_REG(REG_SPR0DATB + 4 * num));
+ }
+ }
+
+ /* clock the next pixel if we're doing it */
+ if (sprite_remain[num] != 0)
+ {
+ sprite_remain[num]--;
+ pixels |= (sprite_shiftreg[num] & 0xc0000000) >> (16 + 2 * (7 - num));
+ sprite_shiftreg[num] <<= 2;
+ }
+ }
+
+ /* if we have pixels, determine the actual color and get out */
+ if (pixels)
+ {
+ static const UINT16 ormask[16] =
+ {
+ 0x0000, 0x000c, 0x00c0, 0x00cc, 0x0c00, 0x0c0c, 0x0cc0, 0x0ccc,
+ 0xc000, 0xc00c, 0xc0c0, 0xc0cc, 0xcc00, 0xcc0c, 0xccc0, 0xcccc
+ };
+ static const UINT16 spritecollide[16] =
+ {
+ 0x0000, 0x0000, 0x0000, 0x0200, 0x0000, 0x0400, 0x1000, 0x1600,
+ 0x0000, 0x0800, 0x2000, 0x2a00, 0x4000, 0x4c00, 0x7000, 0x7e00
+ };
+ int collide;
+
+ /* OR the two sprite bits together so we only have 1 bit per sprite */
+ collide = pixels | (pixels >> 1);
+
+ /* based on the CLXCON, merge even/odd sprite results */
+ collide |= (collide & ormask[CUSTOM_REG(REG_CLXCON) >> 12]) >> 2;
+
+ /* collapse down to a 4-bit final "sprite present" mask */
+ collide = (collide & 1) | ((collide >> 3) & 2) | ((collide >> 6) & 4) | ((collide >> 9) & 8);
+
+ /* compute sprite-sprite collisions */
+ CUSTOM_REG(REG_CLXDAT) |= spritecollide[collide];
+
+ /* now determine the actual color */
+ for (pair = 0; pixels; pair++, pixels >>= 4)
+ if (pixels & 0x0f)
+ {
+ /* final result is:
+ topmost sprite color in bits 0-5
+ sprite present bitmask in bits 6-9
+ topmost sprite pair index in bits 10-11
+ */
+
+ /* attached case */
+ if (CUSTOM_REG(REG_SPR1CTL + 8 * pair) & 0x0080)
+ return (pixels & 0xf) | 0x10 | (collide << 6) | (pair << 10);
+
+ /* lower-numbered sprite of pair */
+ else if (pixels & 3)
+ return (pixels & 3) | 0x10 | (pair << 2) | (collide << 6) | (pair << 10);
+
+ /* higher-numbered sprite of pair */
+ else
+ return ((pixels >> 2) & 3) | 0x10 | (pair << 2) | (collide << 6) | (pair << 10);
+ }
+ }
+
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Bitplane assembly
+ *
+ *************************************/
+
+INLINE UINT8 assemble_odd_bitplanes(int planes, int obitoffs)
+{
+ UINT8 pix = (CUSTOM_REG(REG_BPL1DAT) >> obitoffs) & 1;
+ if (planes >= 3)
+ {
+ pix |= ((CUSTOM_REG(REG_BPL3DAT) >> obitoffs) & 1) << 2;
+ if (planes >= 5)
+ pix |= ((CUSTOM_REG(REG_BPL5DAT) >> obitoffs) & 1) << 4;
+ }
+ return pix;
+}
+
+
+INLINE UINT8 assemble_even_bitplanes(int planes, int ebitoffs)
+{
+ UINT8 pix = 0;
+ if (planes >= 2)
+ {
+ pix |= ((CUSTOM_REG(REG_BPL2DAT) >> ebitoffs) & 1) << 1;
+ if (planes >= 4)
+ {
+ pix |= ((CUSTOM_REG(REG_BPL4DAT) >> ebitoffs) & 1) << 3;
+ if (planes >= 6)
+ pix |= ((CUSTOM_REG(REG_BPL6DAT) >> ebitoffs) & 1) << 5;
+ }
+ }
+ return pix;
+}
+
+
+
+/*************************************
+ *
+ * Hold and modify pixel computations
+ *
+ *************************************/
+
+INLINE int update_ham(int newpix)
+{
+ switch (newpix >> 4)
+ {
+ case 0:
+ ham_color = CUSTOM_REG(REG_COLOR00 + (newpix & 0xf));
+ break;
+
+ case 1:
+ ham_color = (ham_color & 0xff0) | ((newpix & 0xf) << 0);
+ break;
+
+ case 2:
+ ham_color = (ham_color & 0x0ff) | ((newpix & 0xf) << 8);
+ break;
+
+ case 3:
+ ham_color = (ham_color & 0xf0f) | ((newpix & 0xf) << 4);
+ break;
+ }
+ return ham_color;
+}
+
+
+
+/*************************************
+ *
+ * Single scanline rasterizer
+ *
+ *************************************/
+
+void amiga_render_scanline(int scanline)
+{
+ UINT16 save_color0 = CUSTOM_REG(REG_COLOR00);
+ int ddf_start_pixel = 0, ddf_stop_pixel = 0;
+ int hires = 0, dualpf = 0, lace = 0, ham = 0;
+ int hstart = 0, hstop = 0;
+ int vstart = 0, vstop = 0;
+ int pf1pri = 0, pf2pri = 0;
+ int planes = 0;
+
+ int x;
+ UINT16 *dst;
+ int ebitoffs = 0, obitoffs = 0;
+ int ecolmask = 0, ocolmask = 0;
+ int edelay = 0, odelay = 0;
+ int next_copper_x;
+ int p;
+
+ last_scanline = scanline;
+
+ /* on the first scanline, reset the COPPER and HAM color */
+ if (scanline == 0)
+ {
+ copper_setpc(CUSTOM_REG_LONG(REG_COP1LCH));
+ ham_color = CUSTOM_REG(REG_COLOR00);
+ }
+
+ /* update sprite data fetching */
+ update_sprite_dma(scanline);
+
+ /* start of a new line, signal we're not done with it and fill up vars */
+ dst = BITMAP_ADDR16(tmpbitmap, scanline, 0);
+
+ /* all sprites off at the start of the line */
+ memset(sprite_remain, 0, sizeof(sprite_remain));
+
+ /* temporary set color 0 to the genlock color */
+ if (genlock_color != 0xffff)
+ CUSTOM_REG(REG_COLOR00) = genlock_color;
+
+ /* loop over the line */
+ next_copper_x = 2; /* copper runs on odd timeslots */
+ for (x = 0; x < 0xe4*2; x++)
+ {
+ int sprpix;
+
+ /* time to execute the copper? */
+ if (x == next_copper_x)
+ {
+ /* execute the next batch, restoring and re-saving color 0 around it */
+ CUSTOM_REG(REG_COLOR00) = save_color0;
+ next_copper_x = copper_execute_next(x);
+ save_color0 = CUSTOM_REG(REG_COLOR00);
+ if (genlock_color != 0xffff)
+ CUSTOM_REG(REG_COLOR00) = genlock_color;
+
+ /* compute update-related register values */
+ planes = (CUSTOM_REG(REG_BPLCON0) & (BPLCON0_BPU0 | BPLCON0_BPU1 | BPLCON0_BPU2)) >> 12;
+ hires = CUSTOM_REG(REG_BPLCON0) & BPLCON0_HIRES;
+ ham = CUSTOM_REG(REG_BPLCON0) & BPLCON0_HOMOD;
+ dualpf = CUSTOM_REG(REG_BPLCON0) & BPLCON0_DBLPF;
+ lace = CUSTOM_REG(REG_BPLCON0) & BPLCON0_LACE;
+
+ /* compute the pixel fetch parameters */
+ ddf_start_pixel = ( CUSTOM_REG(REG_DDFSTRT) & 0xfc ) * 2 + (hires ? 9 : 17);
+ ddf_stop_pixel = ( CUSTOM_REG(REG_DDFSTOP) & 0xfc ) * 2 + (hires ? (9 + 15) : (17 + 15));
+
+ if ( ( CUSTOM_REG(REG_DDFSTRT) ^ CUSTOM_REG(REG_DDFSTOP) ) & 0x04 )
+ ddf_stop_pixel += 8;
+
+ /* compute the horizontal start/stop */
+ hstart = CUSTOM_REG(REG_DIWSTRT) & 0xff;
+ hstop = 0x100 + (CUSTOM_REG(REG_DIWSTOP) & 0xff);
+
+ /* compute the vertical start/stop */
+ vstart = CUSTOM_REG(REG_DIWSTRT) >> 8;
+ vstop = (CUSTOM_REG(REG_DIWSTOP) >> 8) | ((~CUSTOM_REG(REG_DIWSTOP) >> 7) & 0x100);
+
+ /* extract playfield priorities */
+ pf1pri = CUSTOM_REG(REG_BPLCON2) & 7;
+ pf2pri = (CUSTOM_REG(REG_BPLCON2) >> 3) & 7;
+
+ /* extract collision masks */
+ ocolmask = (CUSTOM_REG(REG_CLXCON) >> 6) & 0x15;
+ ecolmask = (CUSTOM_REG(REG_CLXCON) >> 6) & 0x2a;
+ }
+
+ /* clear the target pixels to the background color as a starting point */
+ dst[x*2+0] =
+ dst[x*2+1] = CUSTOM_REG(REG_COLOR00);
+
+ /* if we hit the first fetch pixel, reset the counters and latch the delays */
+ if (x == ddf_start_pixel)
+ {
+ odelay = CUSTOM_REG(REG_BPLCON1) & 0xf;
+ edelay = ( CUSTOM_REG(REG_BPLCON1) >> 4 ) & 0x0f;
+
+ if ( hires )
+ {
+ obitoffs = 15 + ( odelay << 1 );
+ ebitoffs = 15 + ( edelay << 1 );
+ }
+ else
+ {
+ if ( CUSTOM_REG(REG_DDFSTRT) & 0x04 )
+ {
+ odelay = ( odelay + 8 ) & 0x0f;
+ edelay = ( edelay + 8 ) & 0x0f;
+ }
+
+ obitoffs = 15 + odelay;
+ ebitoffs = 15 + edelay;
+ }
+
+ for (p = 0; p < 6; p++)
+ CUSTOM_REG(REG_BPL1DAT + p) = 0;
+ }
+
+ /* need to run the sprite engine every pixel to ensure display */
+ sprpix = get_sprite_pixel(x);
+
+ /* to render, we must have bitplane DMA enabled, at least 1 plane, and be within the */
+ /* vertical display window */
+ if ((CUSTOM_REG(REG_DMACON) & (DMACON_BPLEN | DMACON_DMAEN)) == (DMACON_BPLEN | DMACON_DMAEN) &&
+ planes > 0 && scanline >= vstart && scanline < vstop)
+ {
+ int pfpix0 = 0, pfpix1 = 0, collide;
+
+ /* fetch the odd bits if we are within the fetching region */
+ if (x >= ddf_start_pixel && x <= ddf_stop_pixel + odelay)
+ {
+ /* if we need to fetch more data, do it now */
+ if (obitoffs == 15)
+ for (p = 0; p < planes; p += 2)
+ {
+ CUSTOM_REG(REG_BPL1DAT + p) = amiga_chip_ram_r(CUSTOM_REG_LONG(REG_BPL1PTH + p * 2));
+ CUSTOM_REG_LONG(REG_BPL1PTH + p * 2) += 2;
+ }
+
+ /* now assemble the bits */
+ pfpix0 |= assemble_odd_bitplanes(planes, obitoffs);
+ obitoffs--;
+
+ /* for high res, assemble a second set of bits */
+ if (hires)
+ {
+ /* reset bit offsets and fetch more data if needed */
+ if (obitoffs < 0)
+ {
+ obitoffs = 15;
+
+ for (p = 0; p < planes; p += 2)
+ {
+ CUSTOM_REG(REG_BPL1DAT + p) = amiga_chip_ram_r(CUSTOM_REG_LONG(REG_BPL1PTH + p * 2));
+ CUSTOM_REG_LONG(REG_BPL1PTH + p * 2) += 2;
+ }
+ }
+
+ pfpix1 |= assemble_odd_bitplanes(planes, obitoffs);
+ obitoffs--;
+ }
+ else
+ pfpix1 |= pfpix0 & 0x15;
+
+ /* reset bit offsets if needed */
+ if (obitoffs < 0)
+ obitoffs = 15;
+ }
+
+ /* fetch the even bits if we are within the fetching region */
+ if (x >= ddf_start_pixel && x <= ddf_stop_pixel + edelay)
+ {
+ /* if we need to fetch more data, do it now */
+ if (ebitoffs == 15)
+ for (p = 1; p < planes; p += 2)
+ {
+ CUSTOM_REG(REG_BPL1DAT + p) = amiga_chip_ram_r(CUSTOM_REG_LONG(REG_BPL1PTH + p * 2));
+ CUSTOM_REG_LONG(REG_BPL1PTH + p * 2) += 2;
+ }
+
+ /* now assemble the bits */
+ pfpix0 |= assemble_even_bitplanes(planes, ebitoffs);
+ ebitoffs--;
+
+ /* for high res, assemble a second set of bits */
+ if (hires)
+ {
+ /* reset bit offsets and fetch more data if needed */
+ if (ebitoffs < 0)
+ {
+ ebitoffs = 15;
+
+ for (p = 1; p < planes; p += 2)
+ {
+ CUSTOM_REG(REG_BPL1DAT + p) = amiga_chip_ram_r(CUSTOM_REG_LONG(REG_BPL1PTH + p * 2));
+ CUSTOM_REG_LONG(REG_BPL1PTH + p * 2) += 2;
+ }
+ }
+
+ pfpix1 |= assemble_even_bitplanes(planes, ebitoffs);
+ ebitoffs--;
+ }
+ else
+ pfpix1 |= pfpix0 & 0x2a;
+
+ /* reset bit offsets if needed */
+ if (ebitoffs < 0)
+ ebitoffs = 15;
+ }
+
+ /* compute playfield/sprite collisions for first pixel */
+ collide = pfpix0 ^ CUSTOM_REG(REG_CLXCON);
+ if ((collide & ocolmask) == 0)
+ CUSTOM_REG(REG_CLXDAT) |= (sprpix >> 5) & 0x01e;
+ if ((collide & ecolmask) == 0)
+ CUSTOM_REG(REG_CLXDAT) |= (sprpix >> 1) & 0x1e0;
+ if ((collide & (ecolmask | ocolmask)) == 0)
+ CUSTOM_REG(REG_CLXDAT) |= 0x001;
+
+ /* compute playfield/sprite collisions for second pixel */
+ collide = pfpix1 ^ CUSTOM_REG(REG_CLXCON);
+ if ((collide & ocolmask) == 0)
+ CUSTOM_REG(REG_CLXDAT) |= (sprpix >> 5) & 0x01e;
+ if ((collide & ecolmask) == 0)
+ CUSTOM_REG(REG_CLXDAT) |= (sprpix >> 1) & 0x1e0;
+ if ((collide & (ecolmask | ocolmask)) == 0)
+ CUSTOM_REG(REG_CLXDAT) |= 0x001;
+
+ /* if we are within the display region, render */
+ if (x >= hstart && x < hstop)
+ {
+ /* hold-and-modify mode -- assume low-res (hi-res not supported by the hardware) */
+ if (ham)
+ {
+ /* update the HAM color */
+ pfpix0 = update_ham(pfpix0);
+
+ /* sprite has priority */
+ if (sprpix && pf1pri > (sprpix >> 10))
+ {
+ dst[x*2+0] =
+ dst[x*2+1] = CUSTOM_REG(REG_COLOR00 + (sprpix & 0x1f));
+ }
+
+ /* playfield has priority */
+ else
+ {
+ dst[x*2+0] =
+ dst[x*2+1] = pfpix0;
+ }
+ }
+
+ /* dual playfield mode */
+ else if (dualpf)
+ {
+ int pix;
+
+ /* mask out the sprite if it doesn't have priority */
+ pix = sprpix & 0x1f;
+ if (pix)
+ {
+ if ((pfpix0 & 0x15) && pf1pri <= (sprpix >> 10))
+ pix = 0;
+ if ((pfpix0 & 0x2a) && pf2pri <= (sprpix >> 10))
+ pix = 0;
+ }
+
+ /* write out the left pixel */
+ if (pix)
+ dst[x*2+0] = CUSTOM_REG(REG_COLOR00 + pix);
+ else
+ dst[x*2+0] = CUSTOM_REG(REG_COLOR00 + separate_bitplanes[(CUSTOM_REG(REG_BPLCON2) >> 6) & 1][pfpix0]);
+
+ /* mask out the sprite if it doesn't have priority */
+ pix = sprpix & 0x1f;
+ if (pix)
+ {
+ if ((pfpix1 & 0x15) && pf1pri <= (sprpix >> 10))
+ pix = 0;
+ if ((pfpix1 & 0x2a) && pf2pri <= (sprpix >> 10))
+ pix = 0;
+ }
+
+ /* write out the right pixel */
+ if (pix)
+ dst[x*2+1] = CUSTOM_REG(REG_COLOR00 + pix);
+ else
+ dst[x*2+1] = CUSTOM_REG(REG_COLOR00 + separate_bitplanes[(CUSTOM_REG(REG_BPLCON2) >> 6) & 1][pfpix1]);
+ }
+
+ /* single playfield mode */
+ else
+ {
+ /* sprite has priority */
+ if (sprpix && pf1pri > (sprpix >> 10))
+ {
+ dst[x*2+0] =
+ dst[x*2+1] = CUSTOM_REG(REG_COLOR00 + (sprpix & 0x1f));
+ }
+
+ /* playfield has priority */
+ else
+ {
+ dst[x*2+0] = CUSTOM_REG(REG_COLOR00 + pfpix0);
+ dst[x*2+1] = CUSTOM_REG(REG_COLOR00 + pfpix1);
+ }
+ }
+ }
+ }
+ }
+
+#if 0
+ if ( cpu_getcurrentframe() % 64 == 0 && scanline == 100 )
+ {
+ const char *m_lores = "LORES";
+ const char *m_hires = "HIRES";
+ const char *m_ham = "HAM";
+ const char *m_dualpf = "DUALPF";
+ const char *m_lace = "LACE";
+ const char *m_hilace = "HI-LACE";
+ const char *p = m_lores;
+
+ if ( hires ) p = m_hires;
+ if ( ham ) p = m_ham;
+ if ( dualpf ) p = m_dualpf;
+ if ( lace ) p = m_lace;
+
+ if ( hires && lace ) p = m_hilace;
+
+ popmessage("%s(%d pl od=%04x ed=%04x start=%04x stop=%04x)", p, planes, odelay, edelay, CUSTOM_REG(REG_DDFSTRT), CUSTOM_REG(REG_DDFSTOP) );
+ }
+#endif
+
+ /* end of the line: time to add the modulos */
+ if (scanline >= vstart && scanline < vstop)
+ {
+ int p;
+
+ /* update odd planes */
+ for (p = 0; p < planes; p += 2)
+ CUSTOM_REG_LONG(REG_BPL1PTH + p * 2) += CUSTOM_REG_SIGNED(REG_BPL1MOD);
+
+ /* update even planes */
+ for (p = 1; p < planes; p += 2)
+ CUSTOM_REG_LONG(REG_BPL1PTH + p * 2) += CUSTOM_REG_SIGNED(REG_BPL2MOD);
+ }
+
+ /* restore color00 */
+ CUSTOM_REG(REG_COLOR00) = save_color0;
+
+#if GUESS_COPPER_OFFSET
+ if (cpu_getcurrentframe() % 64 == 0 && scanline == 0)
+ {
+ if (input_code_pressed(KEYCODE_Q))
+ popmessage("%d", wait_offset -= 1);
+ if (input_code_pressed(KEYCODE_W))
+ popmessage("%d", wait_offset += 1);
+ }
+#endif
+}
diff --git a/src/mame/video/ampoker.c b/src/mame/video/ampoker.c
new file mode 100644
index 00000000000..f0ae3e9bc0c
--- /dev/null
+++ b/src/mame/video/ampoker.c
@@ -0,0 +1,120 @@
+/********************************************************************************
+
+
+ AMERICAN POKER 2 - VIDEO HARDWARE
+ ---------------------------------
+
+ Company: Novomatic.
+ Year: 1990.
+
+ Original preliminary driver: Curt Coder.
+ Rewrite and additional work: Roberto Fresca, with a lot of help of Grull Osgo.
+
+
+ --- Supported Sets ---
+
+ Old name | New name | Relation | Description
+ --------------------------------------------
+ ampokr2b ampoker2 parent American Poker II.
+ ---- ampkr2b1 clone American Poker II (bootleg, set 1).
+ ampokr2a ampkr2b2 clone American Poker II (bootleg, set 2).
+ ampoker2 ampkr2b3 clone American Poker II (bootleg, set 3).
+ ampokr2c pkrdewin clone Poker De Win.
+ ---- ampkr95 clone American Poker 95.
+ ---- sigmapkr parent Sigma Poker.
+ ---- sigma2k parent Sigma Poker 2000.
+
+
+********************************************************************************/
+
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+
+PALETTE_INIT( ampoker2 )
+{
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ int i;
+
+/* - bits -
+ 76543210
+ RRRGGGBB
+*/
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 0) & 0x01;
+ bit2 = (*color_prom >> 1) & 0x01;
+ b = ( 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2);
+
+ /* green component */
+ bit0 = (*color_prom >> 2) & 0x01;
+ bit1 = (*color_prom >> 3) & 0x01;
+ bit2 = (*color_prom >> 4) & 0x01;
+ g = ( 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2);
+
+ /* red component */
+ bit0 = (*color_prom >> 5) & 0x01;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ r = ( 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2);
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( ampoker2_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int offs = tile_index * 2;
+ int attr = videoram[offs + 1];
+ int code = videoram[offs];
+ int color = attr;
+ code=code+(256*(color & 0x03)); /* code = color.bit1 + color.bit0 + code */
+ color= color >> 1; /* color = color - bit0 (bit1..bit7) */
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static TILE_GET_INFO( s2k_get_bg_tile_info )
+{
+ int offs = tile_index * 2;
+ int attr = videoram[offs + 1];
+ int code = videoram[offs];
+ int color = attr;
+ code=code+(256*(color & 0x0f)); /* the game use 2 extra bits */
+ color= color >> 1;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START(ampoker2)
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+}
+
+VIDEO_START(sigma2k)
+{
+ bg_tilemap = tilemap_create(s2k_get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+}
+
+VIDEO_UPDATE(ampoker2)
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/amspdwy.c b/src/mame/video/amspdwy.c
new file mode 100644
index 00000000000..0ad15f89dc9
--- /dev/null
+++ b/src/mame/video/amspdwy.c
@@ -0,0 +1,150 @@
+/***************************************************************************
+
+ -= American Speedway =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+- 8x8 4 Color Tiles (with 8 palettes) used for both:
+
+ - 1 256x256 non scrolling layer
+ - 64 (32?) Sprites
+
+***************************************************************************/
+#include "driver.h"
+
+/* Variables only used here: */
+
+static tilemap *bg_tilemap;
+
+
+WRITE8_HANDLER( amspdwy_paletteram_w )
+{
+ data ^= 0xff;
+ paletteram_BBGGGRRR_w(offset,data);
+// paletteram_RRRGGGBB_w(offset,data);
+}
+
+WRITE8_HANDLER( amspdwy_flipscreen_w )
+{
+ static int flip = 0;
+ flip ^= 1;
+ flip_screen_set( flip );
+}
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+ [ Tiles Format ]
+
+ Videoram: 76543210 Code Low Bits
+ Colorram: 765-----
+ ---43--- Code High Bits
+ -----210 Color
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 code = videoram[ tile_index ];
+ UINT8 color = colorram[ tile_index ];
+ SET_TILE_INFO(
+ 0,
+ code + ((color & 0x18)<<5),
+ color & 0x07,
+ 0);
+}
+
+WRITE8_HANDLER( amspdwy_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( amspdwy_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+/* logical (col,row) -> memory offset */
+static TILEMAP_MAPPER( tilemap_scan_cols_back )
+{
+ return col*num_rows + (num_rows - row - 1);
+}
+
+
+VIDEO_START( amspdwy )
+{
+ bg_tilemap = tilemap_create( get_tile_info, tilemap_scan_cols_back,
+ TILEMAP_TYPE_PEN, 8,8, 0x20, 0x20 );
+}
+
+
+
+/***************************************************************************
+
+ Sprites Drawing
+
+Offset: Format: Value:
+
+0 Y
+1 X
+2 Code Low Bits
+3 7------- Flip X
+ -6------ Flip Y
+ --5-----
+ ---4---- ?
+ ----3--- Code High Bit?
+ -----210 Color
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int i;
+ int max_x = machine->screen[0].width - 1;
+ int max_y = machine->screen[0].height - 1;
+
+ for (i = 0; i < spriteram_size ; i += 4)
+ {
+ int y = spriteram[i+0];
+ int x = spriteram[i+1];
+ int code = spriteram[i+2];
+ int attr = spriteram[i+3];
+ int flipx = attr & 0x80;
+ int flipy = attr & 0x40;
+
+ if (flip_screen)
+ {
+ x = max_x - x - 8; y = max_y - y - 8;
+ flipx = !flipx; flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+// code + ((attr & 0x18)<<5),
+ code + ((attr & 0x08)<<5),
+ attr,
+ flipx, flipy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,0 );
+ }
+}
+
+
+
+
+/***************************************************************************
+
+ Screen Drawing
+
+***************************************************************************/
+
+VIDEO_UPDATE( amspdwy )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/angelkds.c b/src/mame/video/angelkds.c
new file mode 100644
index 00000000000..d44ba331954
--- /dev/null
+++ b/src/mame/video/angelkds.c
@@ -0,0 +1,302 @@
+/* video/angelkds.c - see drivers/angelkds.c for more info */
+
+/* graphical issues
+
+enable / disable tilemap bits might be wrong
+
+*/
+
+#include "driver.h"
+
+
+static tilemap *tx_tilemap,*bgbot_tilemap ,*bgtop_tilemap;
+
+UINT8 *angelkds_txvideoram, *angelkds_bgbotvideoram, *angelkds_bgtopvideoram;
+
+/*** Text Layer Tilemap
+
+*/
+
+static int angelkds_txbank;
+
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int tileno;
+
+ tileno = angelkds_txvideoram[tile_index] + (angelkds_txbank * 0x100);
+
+ SET_TILE_INFO(0,tileno,0,0);
+}
+
+WRITE8_HANDLER( angelkds_txvideoram_w )
+{
+ angelkds_txvideoram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+WRITE8_HANDLER( angelkds_txbank_write )
+{
+
+if (angelkds_txbank != data)
+ {
+ angelkds_txbank = data;
+ tilemap_mark_all_tiles_dirty (tx_tilemap);
+ };
+
+}
+
+/*** Top Half Background Tilemap
+
+*/
+
+static int angelkds_bgtopbank;
+
+
+static TILE_GET_INFO( get_bgtop_tile_info )
+{
+ int tileno;
+
+ tileno = angelkds_bgtopvideoram[tile_index];
+
+ tileno += angelkds_bgtopbank*0x100 ;
+ SET_TILE_INFO(1,tileno,0,0);
+}
+
+WRITE8_HANDLER( angelkds_bgtopvideoram_w )
+{
+ angelkds_bgtopvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bgtop_tilemap,offset);
+}
+
+WRITE8_HANDLER( angelkds_bgtopbank_write )
+{
+
+if (angelkds_bgtopbank != data)
+ {
+ angelkds_bgtopbank = data;
+ tilemap_mark_all_tiles_dirty (bgtop_tilemap);
+ };
+
+}
+
+WRITE8_HANDLER( angelkds_bgtopscroll_write )
+{
+ tilemap_set_scrollx(bgtop_tilemap, 0, data );
+}
+
+/*** Bottom Half Background Tilemap
+
+*/
+
+static int angelkds_bgbotbank;
+
+static TILE_GET_INFO( get_bgbot_tile_info )
+{
+ int tileno;
+
+ tileno = angelkds_bgbotvideoram[tile_index];
+
+ tileno += angelkds_bgbotbank * 0x100 ;
+ SET_TILE_INFO(2,tileno,1,0);
+}
+
+WRITE8_HANDLER( angelkds_bgbotvideoram_w )
+{
+ angelkds_bgbotvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bgbot_tilemap,offset);
+}
+
+
+WRITE8_HANDLER( angelkds_bgbotbank_write )
+{
+
+if (angelkds_bgbotbank != data)
+ {
+ angelkds_bgbotbank = data;
+ tilemap_mark_all_tiles_dirty (bgbot_tilemap);
+ };
+
+}
+
+WRITE8_HANDLER( angelkds_bgbotscroll_write )
+{
+ tilemap_set_scrollx(bgbot_tilemap, 0, data );
+}
+
+static UINT8 angelkds_layer_ctrl;
+
+WRITE8_HANDLER( angelkds_layer_ctrl_write )
+{
+ angelkds_layer_ctrl = data;
+}
+
+/*** Sprites
+
+the sprites are similar to the tilemaps in the sense that there is
+a split down the middle of the screen
+
+*/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int enable_n)
+{
+ const UINT8 *source = spriteram+0x100-4;
+ const UINT8 *finish = spriteram;
+ const gfx_element *gfx = machine->gfx[3];
+
+ while( source>=finish )
+ {
+ /*
+
+ nnnn nnnn - EeFf B?cc - yyyy yyyy - xxxx xxxx
+
+ n = sprite number
+ E = Sprite Enabled in Top Half of Screen
+ e = Sprite Enabled in Bottom Half of Screen
+ F = Flip Y
+ f = Flip X
+ B = Tile Bank
+ ? = unknown, nothing / unused? recheck
+ c = color
+ y = Y position
+ x = X position
+
+ */
+
+
+ UINT16 tile_no = source[0];
+ UINT8 attr = source[1];
+ UINT8 ypos = source[2];
+ UINT8 xpos = source[3];
+
+ UINT8 enable = attr & 0xc0;
+ UINT8 flipx = (attr & 0x10) >> 4;
+ UINT8 flipy = (attr & 0x20) >> 5;
+ UINT8 bank = attr & 0x08;
+ UINT8 color = attr & 0x03;
+
+ if (bank) tile_no +=0x100;
+
+ ypos= 0xff-ypos;
+
+ if (enable & enable_n)
+ {
+ drawgfx(
+ bitmap,
+ gfx,
+ tile_no,
+ color*4,
+ flipx,flipy,
+ xpos,ypos,
+ cliprect,
+ TRANSPARENCY_PEN,15
+ );
+ /* wraparound */
+ if (xpos > 240)
+ drawgfx(
+ bitmap,
+ gfx,
+ tile_no,
+ color*4,
+ flipx,flipy,
+ xpos-256,ypos,
+ cliprect,
+ TRANSPARENCY_PEN,15
+ );
+ /* wraparound */
+ if (ypos > 240)
+ {
+ drawgfx(
+ bitmap,
+ gfx,
+ tile_no,
+ color*4,
+ flipx,flipy,
+ xpos,ypos-256,
+ cliprect,
+ TRANSPARENCY_PEN,15
+ );
+ /* wraparound */
+ if (xpos > 240)
+ drawgfx(
+ bitmap,
+ gfx,
+ tile_no,
+ color*4,
+ flipx,flipy,
+ xpos-256,ypos-256,
+ cliprect,
+ TRANSPARENCY_PEN,15
+ );
+ }
+
+ }
+
+ source-=0x04;
+
+ }
+
+}
+
+
+/*** Palette Handling
+
+ 4 bits of Red, 4 bits of Green, 4 bits of Blue
+
+*/
+
+WRITE8_HANDLER( angelkds_paletteram_w )
+{
+ int no;
+
+
+ paletteram[offset] = data;
+
+ no=offset & 0xff;
+ palette_set_color_rgb(Machine,no,pal4bit(paletteram[no]),pal4bit(paletteram[no]>>4),pal4bit(paletteram[no+0x100]));
+}
+
+/*** Video Start & Update
+
+*/
+
+VIDEO_START( angelkds )
+{
+
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+ tilemap_set_transparent_pen(tx_tilemap,0);
+
+ bgbot_tilemap = tilemap_create(get_bgbot_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+ tilemap_set_transparent_pen(bgbot_tilemap,15);
+
+ bgtop_tilemap = tilemap_create(get_bgtop_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+ tilemap_set_transparent_pen(bgtop_tilemap,15);
+}
+
+/* enable bits are uncertain */
+
+VIDEO_UPDATE( angelkds )
+{
+ rectangle clip;
+
+ fillbitmap(bitmap,0x3f,cliprect); /* is there a register controling the colour?, we currently use the last colour of the tx palette */
+
+ /* draw top of screen */
+ clip.min_x = 8*0;
+ clip.max_x = 8*16-1;
+ clip.min_y = machine->screen[0].visarea.min_y;
+ clip.max_y = machine->screen[0].visarea.max_y;
+ if ((angelkds_layer_ctrl & 0x80) == 0x00) tilemap_draw(bitmap,&clip,bgtop_tilemap,0,0);
+ draw_sprites(machine, bitmap,&clip, 0x80);
+ if ((angelkds_layer_ctrl & 0x20) == 0x00) tilemap_draw(bitmap,&clip,tx_tilemap,0,0);
+
+ /* draw bottom of screen */
+ clip.min_x = 8*16;
+ clip.max_x = 8*32-1;
+ clip.min_y = machine->screen[0].visarea.min_y;
+ clip.max_y = machine->screen[0].visarea.max_y;
+ if ((angelkds_layer_ctrl & 0x40) == 0x00) tilemap_draw(bitmap,&clip,bgbot_tilemap,0,0);
+ draw_sprites(machine, bitmap,&clip, 0x40);
+ if ((angelkds_layer_ctrl & 0x20) == 0x00) tilemap_draw(bitmap,&clip,tx_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/antic.c b/src/mame/video/antic.c
new file mode 100644
index 00000000000..516c8b2a011
--- /dev/null
+++ b/src/mame/video/antic.c
@@ -0,0 +1,592 @@
+/******************************************************************************
+ Atari 400/800
+
+ ANTIC video controller
+
+ Juergen Buchmueller, June 1998
+******************************************************************************/
+
+#include "driver.h"
+#include "cpu/m6502/m6502.h"
+#include "includes/atari.h"
+
+#ifdef MAME_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x) /* x */
+#endif
+
+ANTIC antic;
+
+/**************************************************************
+ *
+ * Reset ANTIC
+ *
+ **************************************************************/
+
+void antic_reset(void)
+{
+ /* reset the ANTIC read / write registers */
+ memset(&antic.r, 0, sizeof(antic.r));
+ memset(&antic.w, 0, sizeof(antic.w));
+ antic.r.antic00 = 0xff;
+ antic.r.antic01 = 0xff;
+ antic.r.antic02 = 0xff;
+ antic.r.antic03 = 0xff;
+ antic.r.antic04 = 0xff;
+ antic.r.antic05 = 0xff;
+ antic.r.antic06 = 0xff;
+ antic.r.antic07 = 0xff;
+ antic.r.antic08 = 0xff;
+ antic.r.antic09 = 0xff;
+ antic.r.antic0a = 0xff;
+ antic.r.penh = 0x00;
+ antic.r.penv = 0x00;
+ antic.r.antic0e = 0xff;
+ antic.r.nmist = 0x1f;
+}
+
+/**************************************************************
+ *
+ * Read ANTIC hardware registers
+ *
+ **************************************************************/
+READ8_HANDLER ( atari_antic_r )
+{
+ UINT8 data = 0xff;
+
+ switch (offset & 15)
+ {
+ case 0: /* nothing */
+ data = antic.r.antic00;
+ break;
+ case 1: /* nothing */
+ data = antic.r.antic01;
+ break;
+ case 2: /* nothing */
+ data = antic.r.antic02;
+ break;
+ case 3: /* nothing */
+ data = antic.r.antic03;
+ break;
+ case 4: /* nothing */
+ data = antic.r.antic04;
+ break;
+ case 5: /* nothing */
+ data = antic.r.antic05;
+ break;
+ case 6: /* nothing */
+ data = antic.r.antic06;
+ break;
+ case 7: /* nothing */
+ data = antic.r.antic07;
+ break;
+ case 8: /* nothing */
+ data = antic.r.antic08;
+ break;
+ case 9: /* nothing */
+ data = antic.r.antic09;
+ break;
+ case 10: /* WSYNC read */
+ cpunum_spinuntil_trigger(0, TRIGGER_HSYNC);
+ antic.w.wsync = 1;
+ data = antic.r.antic0a;
+ break;
+ case 11: /* vert counter (scanline / 2) */
+ data = antic.r.vcount = antic.scanline >> 1;
+ break;
+ case 12: /* light pen horz pos */
+ data = antic.r.penh;
+ break;
+ case 13: /* light pen vert pos */
+ data = antic.r.penv;
+ break;
+ case 14: /* NMI enable */
+ data = antic.r.antic0e;
+ break;
+ case 15: /* NMI status */
+ data = antic.r.nmist;
+ break;
+ }
+ return data;
+}
+
+/**************************************************************
+ *
+ * Write ANTIC hardware registers
+ *
+ **************************************************************/
+
+WRITE8_HANDLER ( atari_antic_w )
+{
+ int temp;
+
+ switch (offset & 15)
+ {
+ case 0:
+ if( data == antic.w.dmactl )
+ break;
+ LOG(("ANTIC 00 write DMACTL $%02X\n", data));
+ antic.w.dmactl = data;
+ switch (data & 3)
+ {
+ case 0: antic.pfwidth = 0; break;
+ case 1: antic.pfwidth = 32; break;
+ case 2: antic.pfwidth = 40; break;
+ case 3: antic.pfwidth = 48; break;
+ }
+ break;
+ case 1:
+ if( data == antic.w.chactl )
+ break;
+ LOG(("ANTIC 01 write CHACTL $%02X\n", data));
+ antic.w.chactl = data;
+ antic.chand = (data & 1) ? 0x00 : 0xff;
+ antic.chxor = (data & 2) ? 0xff : 0x00;
+ break;
+ case 2:
+ LOG(("ANTIC 02 write DLISTL $%02X\n", data));
+ antic.w.dlistl = data;
+ temp = (antic.w.dlisth << 8) + antic.w.dlistl;
+ antic.dpage = temp & DPAGE;
+ antic.doffs = temp & DOFFS;
+ break;
+ case 3:
+ LOG(("ANTIC 03 write DLISTH $%02X\n", data));
+ antic.w.dlisth = data;
+ temp = (antic.w.dlisth << 8) + antic.w.dlistl;
+ antic.dpage = temp & DPAGE;
+ antic.doffs = temp & DOFFS;
+ break;
+ case 4:
+ if( data == antic.w.hscrol )
+ break;
+ LOG(("ANTIC 04 write HSCROL $%02X\n", data));
+ antic.w.hscrol = data & 15;
+ break;
+ case 5:
+ if( data == antic.w.vscrol )
+ break;
+ LOG(("ANTIC 05 write VSCROL $%02X\n", data));
+ antic.w.vscrol = data & 15;
+ break;
+ case 6:
+ if( data == antic.w.pmbasl )
+ break;
+ LOG(("ANTIC 06 write PMBASL $%02X\n", data));
+ /* antic.w.pmbasl = data; */
+ break;
+ case 7:
+ if( data == antic.w.pmbash )
+ break;
+ LOG(("ANTIC 07 write PMBASH $%02X\n", data));
+ antic.w.pmbash = data;
+ antic.pmbase_s = (data & 0xfc) << 8;
+ antic.pmbase_d = (data & 0xf8) << 8;
+ break;
+ case 8:
+ if( data == antic.w.chbasl )
+ break;
+ LOG(("ANTIC 08 write CHBASL $%02X\n", data));
+ /* antic.w.chbasl = data; */
+ break;
+ case 9:
+ if( data == antic.w.chbash )
+ break;
+ LOG(("ANTIC 09 write CHBASH $%02X\n", data));
+ antic.w.chbash = data;
+ break;
+ case 10: /* WSYNC write */
+ LOG(("ANTIC 0A write WSYNC $%02X\n", data));
+ cpunum_spinuntil_trigger(0, TRIGGER_HSYNC);
+ antic.w.wsync = 1;
+ break;
+ case 11:
+ if( data == antic.w.antic0b )
+ break;
+ LOG(("ANTIC 0B write ?????? $%02X\n", data));
+ antic.w.antic0b = data;
+ break;
+ case 12:
+ if( data == antic.w.antic0c )
+ break;
+ LOG(("ANTIC 0C write ?????? $%02X\n", data));
+ antic.w.antic0c = data;
+ break;
+ case 13:
+ if( data == antic.w.antic0d )
+ break;
+ LOG(("ANTIC 0D write ?????? $%02X\n", data));
+ antic.w.antic0d = data;
+ break;
+ case 14:
+ if( data == antic.w.nmien )
+ break;
+ LOG(("ANTIC 0E write NMIEN $%02X\n", data));
+ antic.w.nmien = data;
+ break;
+ case 15:
+ LOG(("ANTIC 0F write NMIRES $%02X\n", data));
+ antic.r.nmist = 0x1f;
+ antic.w.nmires = data;
+ break;
+ }
+}
+
+/************* ANTIC mode 00: *********************************
+ * generate 1-8 empty scanlines
+ ***************************************************************/
+void antic_mode_0_xx(VIDEO *video)
+{
+ PREPARE();
+ memset(dst, PBK, HWIDTH*4);
+ POST();
+}
+
+/************* ANTIC mode 01: *********************************
+ * display list jump, eventually wait for vsync
+ ***************************************************************/
+
+
+/************* ANTIC mode 02: *********************************
+ * character mode 8x8:2 (32/40/48 byte per line)
+ ***************************************************************/
+#define MODE2(s) COPY4(dst, antic.pf_21[video->data[s]])
+
+void antic_mode_2_32(VIDEO *video)
+{
+ PREPARE_TXT2(32);
+ REP32(MODE2);
+ POST_TXT(32);
+}
+void antic_mode_2_40(VIDEO *video)
+{
+ PREPARE_TXT2(40);
+ REP40(MODE2);
+ POST_TXT(40);
+}
+void antic_mode_2_48(VIDEO *video)
+{
+ PREPARE_TXT2(48);
+ REP48(MODE2);
+ POST_TXT(48);
+}
+
+/************* ANTIC mode 03: *********************************
+ * character mode 8x10:2 (32/40/48 byte per line)
+ ***************************************************************/
+#define MODE3(s) COPY4(dst, antic.pf_21[video->data[s]])
+
+void antic_mode_3_32(VIDEO *video)
+{
+ PREPARE_TXT3(32);
+ REP32(MODE3);
+ POST_TXT(32);
+}
+void antic_mode_3_40(VIDEO *video)
+{
+ PREPARE_TXT3(40);
+ REP40(MODE3);
+ POST_TXT(40);
+}
+void antic_mode_3_48(VIDEO *video)
+{
+ PREPARE_TXT3(48);
+ REP48(MODE3);
+ POST_TXT(48);
+}
+
+/************* ANTIC mode 04: *********************************
+ * character mode 8x8:4 multi color (32/40/48 byte per line)
+ ***************************************************************/
+#define MODE4(s) COPY4(dst, antic.pf_x10b[video->data[s]])
+
+void antic_mode_4_32(VIDEO *video)
+{
+ PREPARE_TXT45(32,0);
+ REP32(MODE4);
+ POST_TXT(32);
+}
+void antic_mode_4_40(VIDEO *video)
+{
+ PREPARE_TXT45(40,0);
+ REP40(MODE4);
+ POST_TXT(40);
+}
+void antic_mode_4_48(VIDEO *video)
+{
+ PREPARE_TXT45(48,0);
+ REP48(MODE4);
+ POST_TXT(48);
+}
+
+/************* ANTIC mode 05: *********************************
+ * character mode 8x16:4 multi color (32/40/48 byte per line)
+ ***************************************************************/
+#define MODE5(s) COPY4(dst, antic.pf_x10b[video->data[s]])
+
+void antic_mode_5_32(VIDEO *video)
+{
+ PREPARE_TXT45(32,1);
+ REP32(MODE5);
+ POST_TXT(32);
+}
+void antic_mode_5_40(VIDEO *video)
+{
+ PREPARE_TXT45(40,1);
+ REP40(MODE5);
+ POST_TXT(40);
+}
+void antic_mode_5_48(VIDEO *video)
+{
+ PREPARE_TXT45(48,1);
+ REP48(MODE5);
+ POST_TXT(48);
+}
+
+/************* ANTIC mode 06: *********************************
+ * character mode 16x8:5 single color (16/20/24 byte per line)
+ ***************************************************************/
+#define MODE6(s) COPY8(dst, antic.pf_3210b2[video->data[s]], antic.pf_3210b2[video->data[s]+1])
+
+void antic_mode_6_32(VIDEO *video)
+{
+ PREPARE_TXT67(16,0);
+ REP16(MODE6);
+ POST_TXT(16);
+}
+void antic_mode_6_40(VIDEO *video)
+{
+ PREPARE_TXT67(20,0);
+ REP20(MODE6);
+ POST_TXT(20);
+}
+void antic_mode_6_48(VIDEO *video)
+{
+ PREPARE_TXT67(24,0);
+ REP24(MODE6);
+ POST_TXT(24);
+}
+
+/************* ANTIC mode 07: *********************************
+ * character mode 16x16:5 single color (16/20/24 byte per line)
+ ***************************************************************/
+#define MODE7(s) COPY8(dst, antic.pf_3210b2[video->data[s]], antic.pf_3210b2[video->data[s]+1])
+
+void antic_mode_7_32(VIDEO *video)
+{
+ PREPARE_TXT67(16,1);
+ REP16(MODE7);
+ POST_TXT(16);
+}
+void antic_mode_7_40(VIDEO *video)
+{
+ PREPARE_TXT67(20,1);
+ REP20(MODE7);
+ POST_TXT(20);
+}
+void antic_mode_7_48(VIDEO *video)
+{
+ PREPARE_TXT67(24,1);
+ REP24(MODE7);
+ POST_TXT(24);
+}
+
+/************* ANTIC mode 08: *********************************
+ * graphics mode 8x8:4 (8/10/12 byte per line)
+ ***************************************************************/
+#define MODE8(s) COPY16(dst, antic.pf_210b4[video->data[s]],antic.pf_210b4[video->data[s]+1],antic.pf_210b4[video->data[s]+2],antic.pf_210b4[video->data[s]+3])
+
+void antic_mode_8_32(VIDEO *video)
+{
+ PREPARE_GFX8(8);
+ REP08(MODE8);
+ POST_GFX(8);
+}
+void antic_mode_8_40(VIDEO *video)
+{
+ PREPARE_GFX8(10);
+ REP10(MODE8);
+ POST_GFX(10);
+}
+void antic_mode_8_48(VIDEO *video)
+{
+ PREPARE_GFX8(12);
+ REP12(MODE8);
+ POST_GFX(12);
+}
+
+/************* ANTIC mode 09: *********************************
+ * graphics mode 4x4:2 (8/10/12 byte per line)
+ ***************************************************************/
+#define MODE9(s) COPY8(dst, antic.pf_3210b2[video->data[s]], antic.pf_3210b2[video->data[s]+1])
+
+void antic_mode_9_32(VIDEO *video)
+{
+ PREPARE_GFX9BC(16);
+ REP16(MODE9);
+ POST_GFX(16);
+}
+void antic_mode_9_40(VIDEO *video)
+{
+ PREPARE_GFX9BC(20);
+ REP20(MODE9);
+ POST_GFX(20);
+}
+void antic_mode_9_48(VIDEO *video)
+{
+ PREPARE_GFX9BC(24);
+ REP24(MODE9);
+ POST_GFX(24);
+}
+
+/************* ANTIC mode 0A: *********************************
+ * graphics mode 4x4:4 (16/20/24 byte per line)
+ ***************************************************************/
+#define MODEA(s) COPY8(dst, antic.pf_210b2[video->data[s]], antic.pf_210b2[video->data[s]+1])
+
+void antic_mode_a_32(VIDEO *video)
+{
+ PREPARE_GFXA(16);
+ REP16(MODEA);
+ POST_GFX(16);
+}
+void antic_mode_a_40(VIDEO *video)
+{
+ PREPARE_GFXA(20);
+ REP20(MODEA);
+ POST_GFX(20);
+}
+void antic_mode_a_48(VIDEO *video)
+{
+ PREPARE_GFXA(24);
+ REP24(MODEA);
+ POST_GFX(24);
+}
+
+/************* ANTIC mode 0B: *********************************
+ * graphics mode 2x2:2 (16/20/24 byte per line)
+ ***************************************************************/
+#define MODEB(s) COPY8(dst, antic.pf_3210b2[video->data[s]], antic.pf_3210b2[video->data[s]+1])
+
+void antic_mode_b_32(VIDEO *video)
+{
+ PREPARE_GFX9BC(16);
+ REP16(MODEB);
+ POST_GFX(16);
+}
+void antic_mode_b_40(VIDEO *video)
+{
+ PREPARE_GFX9BC(20);
+ REP20(MODEB);
+ POST_GFX(20);
+}
+void antic_mode_b_48(VIDEO *video)
+{
+ PREPARE_GFX9BC(24);
+ REP24(MODEB);
+ POST_GFX(24);
+}
+
+/************* ANTIC mode 0C: *********************************
+ * graphics mode 2x1:2 (16/20/24 byte per line)
+ ***************************************************************/
+#define MODEC(s) COPY8(dst, antic.pf_3210b2[video->data[s]], antic.pf_3210b2[video->data[s]+1])
+
+void antic_mode_c_32(VIDEO *video)
+{
+ PREPARE_GFX9BC(16);
+ REP16(MODEC);
+ POST_GFX(16);
+}
+void antic_mode_c_40(VIDEO *video)
+{
+ PREPARE_GFX9BC(20);
+ REP20(MODEC);
+ POST_GFX(20);
+}
+void antic_mode_c_48(VIDEO *video)
+{
+ PREPARE_GFX9BC(24);
+ REP24(MODEC);
+ POST_GFX(24);
+}
+
+/************* ANTIC mode 0D: *********************************
+ * graphics mode 2x2:4 (32/40/48 byte per line)
+ ***************************************************************/
+#define MODED(s) COPY4(dst, antic.pf_x10b[video->data[s]])
+
+void antic_mode_d_32(VIDEO *video)
+{
+ PREPARE_GFXDE(32);
+ REP32(MODED);
+ POST_GFX(32);
+}
+void antic_mode_d_40(VIDEO *video)
+{
+ PREPARE_GFXDE(40);
+ REP40(MODED);
+ POST_GFX(40);
+}
+void antic_mode_d_48(VIDEO *video)
+{
+ PREPARE_GFXDE(48);
+ REP48(MODED);
+ POST_GFX(48);
+}
+
+/************* ANTIC mode 0E: *********************************
+ * graphics mode 2x1:4 (32/40/48 byte per line)
+ ***************************************************************/
+#define MODEE(s) COPY4(dst, antic.pf_x10b[video->data[s]])
+
+void antic_mode_e_32(VIDEO *video)
+{
+ PREPARE_GFXDE(32);
+ REP32(MODEE);
+ POST_GFX(32);
+}
+void antic_mode_e_40(VIDEO *video)
+{
+ PREPARE_GFXDE(40);
+ REP40(MODEE);
+ POST_GFX(40);
+}
+void antic_mode_e_48(VIDEO *video)
+{
+ PREPARE_GFXDE(48);
+ REP48(MODEE);
+ POST_GFX(48);
+}
+
+/************* ANTIC mode 0F: *********************************
+ * graphics mode 1x1:2 (32/40/48 byte per line)
+ ***************************************************************/
+#define MODEF(s) COPY4(dst, antic.pf_1b[video->data[s]])
+
+void antic_mode_f_32(VIDEO *video)
+{
+ PREPARE_GFXF(32);
+ REP32(MODEF);
+ POST_GFX(32);
+}
+void antic_mode_f_40(VIDEO *video)
+{
+ PREPARE_GFXF(40);
+ REP40(MODEF);
+ POST_GFX(40);
+}
+void antic_mode_f_48(VIDEO *video)
+{
+ PREPARE_GFXF(48);
+ REP48(MODEF);
+ POST_GFX(48);
+}
+
diff --git a/src/mame/video/appoooh.c b/src/mame/video/appoooh.c
new file mode 100644
index 00000000000..e1c56bf6a3f
--- /dev/null
+++ b/src/mame/video/appoooh.c
@@ -0,0 +1,339 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "appoooh.h"
+
+UINT8 *appoooh_fg_videoram,*appoooh_fg_colorram;
+UINT8 *appoooh_bg_videoram,*appoooh_bg_colorram;
+
+#define CHR1_OFST 0x00 /* palette page of char set #1 */
+#define CHR2_OFST 0x10 /* palette page of char set #2 */
+
+static tilemap *fg_tilemap,*bg_tilemap;
+
+static int scroll_x;
+static int priority;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Palette information of appoooh is not known.
+
+ The palette decoder of Bank Panic was used for this driver.
+ Because these hardware is similar.
+
+***************************************************************************/
+PALETTE_INIT( appoooh )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* charset #1 lookup table */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = (*(color_prom++) & 0x0f)|CHR1_OFST;
+
+ /* charset #2 lookup table */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = (*(color_prom++) & 0x0f)|CHR2_OFST;
+
+ /* TODO: the driver currently uses only 16 of the 32 color codes. */
+ /* 16-31 might be unused, but there might be a palette bank selector */
+ /* to use them somewhere in the game. */
+}
+
+PALETTE_INIT( robowres )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ for (i = 0;i < 32*8;i++)
+ colortable[i]=(*(color_prom++) & 0x0f);
+
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = appoooh_fg_videoram[tile_index] + 256 * ((appoooh_fg_colorram[tile_index]>>5) & 7);
+
+ SET_TILE_INFO(
+ 0,
+ code,
+ appoooh_fg_colorram[tile_index]&0x0f,
+ (appoooh_fg_colorram[tile_index] & 0x10 ) ? TILEMAP_FLIPX : 0
+ );
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = appoooh_bg_videoram[tile_index] + 256 * ((appoooh_bg_colorram[tile_index]>>5) & 7);
+
+ SET_TILE_INFO(
+ 1,
+ code,
+ appoooh_bg_colorram[tile_index]&0x0f,
+ (appoooh_bg_colorram[tile_index] & 0x10 ) ? TILEMAP_FLIPX : 0
+ );
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+VIDEO_START( appoooh )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,32,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_scrolldy(fg_tilemap,8,8);
+ tilemap_set_scrolldy(bg_tilemap,8,8);
+}
+
+WRITE8_HANDLER( appoooh_scroll_w )
+{
+ scroll_x = data;
+}
+
+
+WRITE8_HANDLER( appoooh_fg_videoram_w )
+{
+ appoooh_fg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE8_HANDLER( appoooh_fg_colorram_w )
+{
+ appoooh_fg_colorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE8_HANDLER( appoooh_bg_videoram_w )
+{
+ appoooh_bg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( appoooh_bg_colorram_w )
+{
+ appoooh_bg_colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( appoooh_out_w )
+{
+ /* bit 0 controls NMI */
+ interrupt_enable_w(0,data & 0x01);
+
+ /* bit 1 flip screen */
+ flip_screen_set(data & 0x02);
+
+ /* bits 2-3 unknown */
+
+ /* bits 4-5 are playfield/sprite priority */
+ /* TODO: understand how this works, currently the only thing I do is draw */
+ /* the front layer behind sprites when priority == 0, and invert the sprite */
+ /* order when priority == 1 */
+ priority = (data & 0x30) >> 4;
+
+ /* bit 6 ROM bank select */
+ {
+ UINT8 *RAM = memory_region(REGION_CPU1);
+
+ memory_set_bankptr(1,&RAM[data&0x40 ? 0x10000 : 0x0a000]);
+ }
+
+ /* bit 7 unknown (used) */
+}
+
+static void appoooh_draw_sprites(mame_bitmap *dest_bmp,
+ const rectangle *cliprect,
+ const gfx_element *gfx,
+ UINT8 *sprite)
+{
+ int offs;
+
+ for (offs = 0x20 - 4;offs >= 0;offs -= 4)
+ {
+ int sy = 240 - sprite[offs+0];
+ int code = (sprite[offs+1]>>2) + ((sprite[offs+2]>>5) & 0x07)*0x40;
+ int color = sprite[offs+2]&0x0f; /* TODO: bit 4 toggles continuously, what is it? */
+ int sx = sprite[offs+3];
+ int flipx = sprite[offs+1]&0x01;
+
+ if(sx>=248) sx -= 256;
+
+ if (flip_screen)
+ {
+ sx = 239 - sx;
+ sy = 239 - sy;
+ flipx = !flipx;
+ }
+ drawgfx( dest_bmp, gfx,
+ code,
+ color,
+ flipx,flip_screen,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN , 0);
+ }
+}
+
+static void robowres_draw_sprites(mame_bitmap *dest_bmp,
+ const rectangle *cliprect,
+ const gfx_element *gfx,
+ UINT8 *sprite)
+{
+ int offs;
+
+ for (offs = 0x20 - 4;offs >= 0;offs -= 4)
+ {
+ int sy = 240 - sprite[offs+0];
+ int code = 0x200 + (sprite[offs+1]>>2) + ((sprite[offs+2]>>5) & 0x07)*0x40;
+ int color = sprite[offs+2]&0x0f; /* TODO: bit 4 toggles continuously, what is it? */
+ int sx = sprite[offs+3];
+ int flipx = sprite[offs+1]&0x01;
+
+ if(sx>=248) sx -= 256;
+
+ if (flip_screen)
+ {
+ sx = 239 - sx;
+ sy = 239 - sy;
+ flipx = !flipx;
+ }
+ drawgfx( dest_bmp, gfx,
+ code,
+ color,
+ flipx,flip_screen,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN , 0);
+ }
+}
+
+
+VIDEO_UPDATE( appoooh )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ if (priority == 0) /* fg behind sprites */
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+
+ /* draw sprites */
+ if (priority == 1)
+ {
+ /* sprite set #1 */
+ appoooh_draw_sprites( bitmap, cliprect, machine->gfx[2],spriteram);
+ /* sprite set #2 */
+ appoooh_draw_sprites( bitmap, cliprect, machine->gfx[3],spriteram_2);
+ }
+ else
+ {
+ /* sprite set #2 */
+ appoooh_draw_sprites( bitmap, cliprect, machine->gfx[3],spriteram_2);
+ /* sprite set #1 */
+ appoooh_draw_sprites( bitmap, cliprect, machine->gfx[2],spriteram);
+ }
+
+ if (priority != 0) /* fg in front of sprites */
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( robowres )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ if (priority == 0) /* fg behind sprites */
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+
+ /* draw sprites */
+ if (priority == 1)
+ {
+ /* sprite set #1 */
+ robowres_draw_sprites( bitmap, cliprect, machine->gfx[2],spriteram);
+ /* sprite set #2 */
+ robowres_draw_sprites( bitmap, cliprect, machine->gfx[3],spriteram_2);
+ }
+ else
+ {
+ /* sprite set #2 */
+ robowres_draw_sprites( bitmap, cliprect, machine->gfx[3],spriteram_2);
+ /* sprite set #1 */
+ robowres_draw_sprites( bitmap, cliprect, machine->gfx[2],spriteram);
+ }
+
+ if (priority != 0) /* fg in front of sprites */
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/aquarium.c b/src/mame/video/aquarium.c
new file mode 100644
index 00000000000..2648119d48d
--- /dev/null
+++ b/src/mame/video/aquarium.c
@@ -0,0 +1,183 @@
+/* Aquarium */
+
+#include "driver.h"
+
+extern UINT16 *aquarium_scroll;
+
+static tilemap *aquarium_txt_tilemap;
+extern UINT16 *aquarium_txt_videoram;
+
+static tilemap *aquarium_mid_tilemap;
+extern UINT16 *aquarium_mid_videoram;
+
+static tilemap *aquarium_bak_tilemap;
+extern UINT16 *aquarium_bak_videoram;
+
+/* gcpinbal.c modified */
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int y_offs)
+{
+ int offs,chain_pos;
+ int x,y,curx,cury;
+ UINT8 col,flipx,flipy,chain;
+ UINT16 code;
+
+ for (offs = 0;offs < spriteram_size/2;offs += 8)
+ {
+ code = ((spriteram16[offs+5])&0xff) + (((spriteram16[offs+6]) &0xff) << 8);
+ code &= 0x3fff;
+
+ if (!(spriteram16[offs+4] &0x80)) /* active sprite ? */
+ {
+ x = ((spriteram16[offs+0]) &0xff) + (((spriteram16[offs+1]) &0xff) << 8);
+ y = ((spriteram16[offs+2]) &0xff) + (((spriteram16[offs+3]) &0xff) << 8);
+
+ /* Treat coords as signed */
+ if (x & 0x8000) x -= 0x10000;
+ if (y & 0x8000) y -= 0x10000;
+
+ col = ((spriteram16[offs+7]) &0x0f);
+ chain = (spriteram16[offs+4]) &0x07;
+ flipy = (spriteram16[offs+4]) &0x10;
+ flipx = (spriteram16[offs+4]) &0x20;
+
+ curx = x;
+ cury = y;
+
+ if (((spriteram16[offs+4]) &0x08) && flipy)
+ cury += (chain * 16);
+
+ if (!(((spriteram16[offs+4]) &0x08)) && flipx)
+ curx += (chain * 16);
+
+
+ for (chain_pos = chain;chain_pos >= 0;chain_pos--)
+ {
+ drawgfx(bitmap, machine->gfx[0],
+ code,
+ col,
+ flipx, flipy,
+ curx,cury,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ /* wrap around y */
+ drawgfx(bitmap, machine->gfx[0],
+ code,
+ col,
+ flipx, flipy,
+ curx,cury+256,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ code++;
+
+ if ((spriteram16[offs+4]) &0x08) /* Y chain */
+ {
+ if (flipy) cury -= 16;
+ else cury += 16;
+ }
+ else /* X chain */
+ {
+ if (flipx) curx -= 16;
+ else curx += 16;
+ }
+ }
+ }
+ }
+#if 0
+ if (rotate)
+ {
+ char buf[80];
+ sprintf(buf,"sprite rotate offs %04x ?",rotate);
+ popmessage(buf);
+ }
+#endif
+}
+
+/* TXT Layer */
+
+static TILE_GET_INFO( get_aquarium_txt_tile_info )
+{
+ int tileno,colour;
+
+ tileno = (aquarium_txt_videoram[tile_index] & 0x0fff);
+ colour = (aquarium_txt_videoram[tile_index] & 0xf000) >> 12;
+ SET_TILE_INFO(2,tileno,colour,0);
+}
+
+WRITE16_HANDLER( aquarium_txt_videoram_w )
+{
+ aquarium_txt_videoram[offset] = data;
+ tilemap_mark_tile_dirty(aquarium_txt_tilemap,offset);
+}
+
+/* MID Layer */
+
+static TILE_GET_INFO( get_aquarium_mid_tile_info )
+{
+ int tileno,colour,flag;
+
+ tileno = (aquarium_mid_videoram[tile_index*2] & 0x0fff);
+ colour = (aquarium_mid_videoram[tile_index*2+1] & 0x001f);
+ flag = TILE_FLIPYX((aquarium_mid_videoram[tile_index*2+1] & 0x300) >> 8);
+
+ SET_TILE_INFO(1,tileno,colour,flag);
+
+ tileinfo->category = (aquarium_mid_videoram[tile_index*2+1] & 0x20) >> 5;
+}
+
+WRITE16_HANDLER( aquarium_mid_videoram_w )
+{
+ aquarium_mid_videoram[offset] = data;
+ tilemap_mark_tile_dirty(aquarium_mid_tilemap,offset/2);
+}
+
+/* BAK Layer */
+static TILE_GET_INFO( get_aquarium_bak_tile_info )
+
+{
+ int tileno,colour,flag;
+
+ tileno = (aquarium_bak_videoram[tile_index*2] & 0x0fff);
+ colour = (aquarium_bak_videoram[tile_index*2+1] & 0x001f);
+ flag = TILE_FLIPYX((aquarium_bak_videoram[tile_index*2+1] & 0x300) >> 8);
+
+ SET_TILE_INFO(3,tileno,colour,flag);
+
+ tileinfo->category = (aquarium_bak_videoram[tile_index*2+1] & 0x20) >> 5;
+}
+
+WRITE16_HANDLER( aquarium_bak_videoram_w )
+{
+ aquarium_bak_videoram[offset] = data;
+ tilemap_mark_tile_dirty(aquarium_bak_tilemap,offset/2);
+}
+
+VIDEO_START(aquarium)
+{
+ aquarium_txt_tilemap = tilemap_create(get_aquarium_txt_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,64);
+ tilemap_set_transparent_pen(aquarium_txt_tilemap,0);
+
+ aquarium_bak_tilemap = tilemap_create(get_aquarium_bak_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+ aquarium_mid_tilemap = tilemap_create(get_aquarium_mid_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+ tilemap_set_transparent_pen(aquarium_mid_tilemap,0);
+}
+
+VIDEO_UPDATE(aquarium)
+{
+ tilemap_set_scrollx(aquarium_mid_tilemap, 0, aquarium_scroll[0]);
+ tilemap_set_scrolly(aquarium_mid_tilemap, 0, aquarium_scroll[1]);
+ tilemap_set_scrollx(aquarium_bak_tilemap, 0, aquarium_scroll[2]);
+ tilemap_set_scrolly(aquarium_bak_tilemap, 0, aquarium_scroll[3]);
+ tilemap_set_scrollx(aquarium_txt_tilemap, 0, aquarium_scroll[4]);
+ tilemap_set_scrolly(aquarium_txt_tilemap, 0, aquarium_scroll[5]);
+
+ tilemap_draw(bitmap,cliprect,aquarium_bak_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,aquarium_mid_tilemap,0,0);
+
+ draw_sprites(machine, bitmap,cliprect,16);
+
+ tilemap_draw(bitmap,cliprect,aquarium_bak_tilemap,1,0);
+ tilemap_draw(bitmap,cliprect,aquarium_mid_tilemap,1,0);
+
+ tilemap_draw(bitmap,cliprect,aquarium_txt_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/arabian.c b/src/mame/video/arabian.c
new file mode 100644
index 00000000000..c0197fa672d
--- /dev/null
+++ b/src/mame/video/arabian.c
@@ -0,0 +1,394 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "arabian.h"
+
+
+/* Constants */
+#define BITMAP_WIDTH 256
+#define BITMAP_HEIGHT 256
+
+
+/* Local variables */
+static UINT8 *main_bitmap;
+static UINT8 *converted_gfx;
+
+
+/* Globals */
+UINT8 arabian_video_control;
+UINT8 arabian_flip_screen;
+
+
+
+/*************************************
+ *
+ * Color PROM conversion
+ *
+ *************************************/
+
+PALETTE_INIT( arabian )
+{
+ int i;
+
+ /* there are effectively 6 bits of color: 2 red, 2 green, 2 blue */
+ for (i = 0; i < 64; i++)
+ {
+ palette_set_color_rgb(machine, i,
+ ((i >> 5) & 1) * (153*192/255) + ((i >> 4) & 1) * (102*192/255) + ((i & 0x30) ? 63 : 0),
+ ((i >> 3) & 1) * (156*192/255) + ((i >> 2) & 1) * (99*192/255) + ((i & 0x0c) ? 63 : 0),
+ ((i >> 1) & 1) * 192 + ((i >> 0) & 1) * 63);
+ }
+
+ /* there are 13 color table bits */
+ for (i = 0; i < (1 << 13); i++)
+ {
+ int ena = (i >> 12) & 1;
+ int enb = (i >> 11) & 1;
+ int abhf = (~i >> 10) & 1;
+ int aghf = (~i >> 9) & 1;
+ int arhf = (~i >> 8) & 1;
+ int az = (i >> 7) & 1;
+ int ar = (i >> 6) & 1;
+ int ag = (i >> 5) & 1;
+ int ab = (i >> 4) & 1;
+ int bz = (i >> 3) & 1;
+ int br = (i >> 2) & 1;
+ int bg = (i >> 1) & 1;
+ int bb = (i >> 0) & 1;
+
+ int planea = (az | ar | ag | ab) & ena;
+
+ /*-------------------------------------------------------------------------
+ red derivation:
+
+ ROUT.1200 = !IC192.11
+ = !(!(!IC117.11 | !IC118.12))
+ = !IC117.11 | !IC118.12
+ = !(IC99.8 ^ IC119.6) | !(!(!BLNK & IC119.11 & BR))
+ = !((!ARHF & !BLNK & AR & AZ) ^ !(AR & !BLNK)) | (!BLNK & IC119.11 & BR)
+ = !BLNK & (!((!ARHF & AR & AZ) ^ !AR) | (IC119.11 & BR))
+ = !BLNK & ((!(!ARHF & AR & AZ) ^ AR) | (BR & !(AZ | AR | AG | AB)))
+
+ ROUT.1800 = !IC192.3
+ = !(!(!IC119.6 | !IC118.12))
+ = !IC119.6 | !IC118.12
+ = !(!(AR & !BLNK) | !(!(!BLNK & IC119.11 & BZ)))
+ = (AR & !BLNK) | (!BLNK & IC119.11 & BZ)
+ = !BLNK & (AR | (BZ & !(AZ | AR | AG | AB)))
+
+ RENA = IC116.6
+ = !IC192.11 | !IC192.3
+ = ROUT.1200 | ROUT.1800
+
+ red.hi = planea ? ar : bz;
+ red.lo = planea ? ((!arhf & az) ? 0 : ar) : br;
+ red.base = (red.hi | red.lo)
+ -------------------------------------------------------------------------*/
+
+ int rhi = planea ? ar : enb ? bz : 0;
+ int rlo = planea ? ((!arhf & az) ? 0 : ar) : enb ? br : 0;
+
+ /*-------------------------------------------------------------------------
+ green derivation:
+
+ GOUT.750 = !IC192.8
+ = !(!(!IC119.8 | !IC120.8))
+ = !IC119.8 | !IC120.8
+ = !(!(AG & !BLNK)) | !(!(!BLNK & IC119.11 & BB))
+ = (AG & !BLNK) | (!BLNK & IC119.11 & BB)
+ = !BLNK & (AG | (IC119.11 & BB))
+ = !BLNK & (AG | (BB & !(AZ | AR | AG | AB)))
+
+ GOUT.1200 = !IC192.6
+ = !(!(!IC117.3 | !IC118.6))
+ = !IC117.3 | !IC118.6
+ = !(IC99.6 ^ IC119.8) | !(!(!BLNK & IC119.11 & BG))
+ = !((!AGHF & !BLNK & AG & AZ) ^ !(AG & !BLNK)) | (!BLNK & IC119.11 & BG)
+ = !BLNK & (!((!AGHF & AG & AZ) ^ !AG) | (IC119.11 & BG))
+ = !BLNK & ((!(!AGHF & AG & AZ) ^ AG) | (BG & !(AZ | AR | AG | AB)))
+
+ GENA = IC116.8
+ = !IC192.8 | !IC192.6
+ = GOUT.750 | GOUT.1200
+
+ grn.hi = planea ? ag : bb;
+ grn.lo = planea ? ((!aghf & az) ? 0 : ag) : bg;
+ grn.base = (grn.hi | grn.lo)
+ -------------------------------------------------------------------------*/
+
+ int ghi = planea ? ag : enb ? bb : 0;
+ int glo = planea ? ((!aghf & az) ? 0 : ag) : enb ? bg : 0;
+
+ /*-------------------------------------------------------------------------
+ blue derivation:
+
+ BOUT.1200 = !IC117.6
+ = !IC119.3
+ = !(!(AB & !BLNK))
+ = !BLNK & AB
+
+ BENA = !IC117.8
+ = !(IC189.6 ^ IC119.3)
+ = !((!ABHF & !BLNK & AB & AZ) ^ !(AB & !BLNK))
+ = (!(!ABHF & !BLNK & AB & AZ) ^ (AB & !BLNK))
+ = !BLNK & (!(!ABHF & AB & AZ) ^ AB)
+
+ blu.hi = ab;
+ blu.base = ((!abhf & az) ? 0 : ab);
+ -------------------------------------------------------------------------*/
+
+ int bhi = ab;
+ int bbase = (!abhf & az) ? 0 : ab;
+
+ *colortable++ = (rhi << 5) | (rlo << 4) |
+ (ghi << 3) | (glo << 2) |
+ (bhi << 1) | bbase;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( arabian )
+{
+ UINT8 *gfxbase = memory_region(REGION_GFX1);
+ int offs;
+
+ /* allocate a common bitmap to use for both planes */
+ /* plane A (top plane with motion objects) is in the upper 4 bits */
+ /* plane B (bottom plane with playfield) is in the lower 4 bits */
+ main_bitmap = auto_malloc(BITMAP_WIDTH * BITMAP_HEIGHT);
+
+ /* allocate memory for the converted graphics data */
+ converted_gfx = auto_malloc(0x8000 * 2);
+
+ /*--------------------------------------------------
+ transform graphics data into more usable format
+ which is coded like this:
+
+ byte adr+0x4000 byte adr
+ DCBA DCBA DCBA DCBA
+
+ D-bits of pixel 4
+ C-bits of pixel 3
+ B-bits of pixel 2
+ A-bits of pixel 1
+
+ after conversion :
+
+ byte adr+0x4000 byte adr
+ DDDD CCCC BBBB AAAA
+ --------------------------------------------------*/
+
+ for (offs = 0; offs < 0x4000; offs++)
+ {
+ int v1 = gfxbase[offs + 0x0000];
+ int v2 = gfxbase[offs + 0x4000];
+ int p1, p2, p3, p4;
+
+ p1 = (v1 & 0x01) | ((v1 & 0x10) >> 3) | ((v2 & 0x01) << 2) | ((v2 & 0x10) >> 1);
+ v1 >>= 1;
+ v2 >>= 1;
+ p2 = (v1 & 0x01) | ((v1 & 0x10) >> 3) | ((v2 & 0x01) << 2) | ((v2 & 0x10) >> 1);
+ v1 >>= 1;
+ v2 >>= 1;
+ p3 = (v1 & 0x01) | ((v1 & 0x10) >> 3) | ((v2 & 0x01) << 2) | ((v2 & 0x10) >> 1);
+ v1 >>= 1;
+ v2 >>= 1;
+ p4 = (v1 & 0x01) | ((v1 & 0x10) >> 3) | ((v2 & 0x01) << 2) | ((v2 & 0x10) >> 1);
+
+ converted_gfx[offs * 4 + 3] = p1;
+ converted_gfx[offs * 4 + 2] = p2;
+ converted_gfx[offs * 4 + 1] = p3;
+ converted_gfx[offs * 4 + 0] = p4;
+ }
+}
+
+
+
+/*************************************
+ *
+ * DMA blitter simulation
+ *
+ *************************************/
+
+static void blit_area(UINT8 plane, UINT16 src, UINT8 x, UINT8 y, UINT8 sx, UINT8 sy)
+{
+ UINT8 *srcdata = &converted_gfx[src * 4];
+ int i,j;
+
+ /* loop over X, then Y */
+ for (i = 0; i <= sx; i++, x += 4)
+ for (j = 0; j <= sy; j++)
+ {
+ UINT8 p1 = *srcdata++;
+ UINT8 p2 = *srcdata++;
+ UINT8 p3 = *srcdata++;
+ UINT8 p4 = *srcdata++;
+ UINT8 *base;
+
+ /* get a pointer to the bitmap */
+ base = &main_bitmap[((y + j) & 0xff) * BITMAP_WIDTH + (x & 0xff)];
+
+ /* bit 0 means write to upper plane (upper 4 bits of our bitmap) */
+ if (plane & 0x01)
+ {
+ if (p4 != 8) base[0] = (base[0] & ~0xf0) | (p4 << 4);
+ if (p3 != 8) base[1] = (base[1] & ~0xf0) | (p3 << 4);
+ if (p2 != 8) base[2] = (base[2] & ~0xf0) | (p2 << 4);
+ if (p1 != 8) base[3] = (base[3] & ~0xf0) | (p1 << 4);
+ }
+
+ /* bit 2 means write to lower plane (lower 4 bits of our bitmap) */
+ if (plane & 0x04)
+ {
+ if (p4 != 8) base[0] = (base[0] & ~0x0f) | p4;
+ if (p3 != 8) base[1] = (base[1] & ~0x0f) | p3;
+ if (p2 != 8) base[2] = (base[2] & ~0x0f) | p2;
+ if (p1 != 8) base[3] = (base[3] & ~0x0f) | p1;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * DMA blitter parameters
+ *
+ *************************************/
+
+WRITE8_HANDLER( arabian_blitter_w )
+{
+ /* write the data */
+ offset &= 7;
+ spriteram[offset] = data;
+
+ /* watch for a write to offset 6 -- that triggers the blit */
+ if ((offset & 0x07) == 6)
+ {
+ /* extract the data */
+ int plane = spriteram[offset - 6];
+ int src = spriteram[offset - 5] | (spriteram[offset - 4] << 8);
+ int x = spriteram[offset - 2] << 2;
+ int y = spriteram[offset - 3];
+ int sx = spriteram[offset - 0];
+ int sy = spriteram[offset - 1];
+
+ /* blit it */
+ blit_area(plane, src, x, y, sx, sy);
+ }
+}
+
+
+
+/*************************************
+ *
+ * VRAM direct I/O
+ *
+ *************************************/
+
+WRITE8_HANDLER( arabian_videoram_w )
+{
+ UINT8 *base;
+ UINT8 x, y;
+
+ /* determine X/Y and mark the area dirty */
+ x = (offset >> 8) << 2;
+ y = offset & 0xff;
+
+ /* get a pointer to the pixels */
+ base = &main_bitmap[y * BITMAP_WIDTH + x];
+
+ /* the data is written as 4 2-bit values, as follows:
+
+ bit 7 = pixel 3, upper bit
+ bit 6 = pixel 2, upper bit
+ bit 5 = pixel 1, upper bit
+ bit 4 = pixel 0, upper bit
+ bit 3 = pixel 3, lower bit
+ bit 2 = pixel 2, lower bit
+ bit 1 = pixel 1, lower bit
+ bit 0 = pixel 0, lower bit
+ */
+
+ /* enable writes to AZ/AR */
+ if (spriteram[0] & 0x08)
+ {
+ base[0] = (base[0] & ~0x03) | ((data & 0x10) >> 3) | ((data & 0x01) >> 0);
+ base[1] = (base[1] & ~0x03) | ((data & 0x20) >> 4) | ((data & 0x02) >> 1);
+ base[2] = (base[2] & ~0x03) | ((data & 0x40) >> 5) | ((data & 0x04) >> 2);
+ base[3] = (base[3] & ~0x03) | ((data & 0x80) >> 6) | ((data & 0x08) >> 3);
+ }
+
+ /* enable writes to AG/AB */
+ if (spriteram[0] & 0x04)
+ {
+ base[0] = (base[0] & ~0x0c) | ((data & 0x10) >> 1) | ((data & 0x01) << 2);
+ base[1] = (base[1] & ~0x0c) | ((data & 0x20) >> 2) | ((data & 0x02) << 1);
+ base[2] = (base[2] & ~0x0c) | ((data & 0x40) >> 3) | ((data & 0x04) << 0);
+ base[3] = (base[3] & ~0x0c) | ((data & 0x80) >> 4) | ((data & 0x08) >> 1);
+ }
+
+ /* enable writes to BZ/BR */
+ if (spriteram[0] & 0x02)
+ {
+ base[0] = (base[0] & ~0x30) | ((data & 0x10) << 1) | ((data & 0x01) << 4);
+ base[1] = (base[1] & ~0x30) | ((data & 0x20) << 0) | ((data & 0x02) << 3);
+ base[2] = (base[2] & ~0x30) | ((data & 0x40) >> 1) | ((data & 0x04) << 2);
+ base[3] = (base[3] & ~0x30) | ((data & 0x80) >> 2) | ((data & 0x08) << 1);
+ }
+
+ /* enable writes to BG/BB */
+ if (spriteram[0] & 0x01)
+ {
+ base[0] = (base[0] & ~0xc0) | ((data & 0x10) << 3) | ((data & 0x01) << 6);
+ base[1] = (base[1] & ~0xc0) | ((data & 0x20) << 2) | ((data & 0x02) << 5);
+ base[2] = (base[2] & ~0xc0) | ((data & 0x40) << 1) | ((data & 0x04) << 4);
+ base[3] = (base[3] & ~0xc0) | ((data & 0x80) << 0) | ((data & 0x08) << 3);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Core video refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( arabian )
+{
+ const pen_t *colortable = &machine->remapped_colortable[(arabian_video_control >> 3) << 8];
+ int y;
+
+ /* render the screen from the bitmap */
+ for (y = 0; y < BITMAP_HEIGHT; y++)
+ {
+ /* non-flipped case */
+ if (!arabian_flip_screen)
+ draw_scanline8(bitmap, 0, y, BITMAP_WIDTH, &main_bitmap[y * BITMAP_WIDTH], colortable, -1);
+
+ /* flipped case */
+ else
+ {
+ UINT8 scanline[BITMAP_WIDTH];
+ int x;
+ for (x = 0; x < BITMAP_WIDTH; x++)
+ scanline[BITMAP_WIDTH - 1 - x] = main_bitmap[y * BITMAP_WIDTH + x];
+ draw_scanline8(bitmap, 0, BITMAP_HEIGHT - 1 - y, BITMAP_WIDTH, scanline, colortable, -1);
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/arcadecl.c b/src/mame/video/arcadecl.c
new file mode 100644
index 00000000000..2ddd17f0842
--- /dev/null
+++ b/src/mame/video/arcadecl.c
@@ -0,0 +1,123 @@
+/***************************************************************************
+
+ Atari Arcade Classics hardware (prototypes)
+
+ Note: this video hardware has some similarities to Shuuz & company
+ The sprite offset registers are stored to 3EFF80
+
+****************************************************************************/
+
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "arcadecl.h"
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static UINT8 has_mo;
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( arcadecl )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 0, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 0, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x100, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0x00ff,0,0,0 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0,0x7fff,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0x000f,0 }}, /* mask for the color */
+ {{ 0,0,0xff80,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xff80 }}, /* mask for the Y position */
+ {{ 0,0,0,0x0070 }}, /* mask for the width, in tiles*/
+ {{ 0,0,0,0x0007 }}, /* mask for the height, in tiles */
+ {{ 0,0x8000,0,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0, /* callback routine for special entries */
+ };
+
+ /* initialize the playfield */
+ rampart_bitmap_init(machine, 43*8, 30*8);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+
+ /* set the intial scroll offset */
+ atarimo_set_xscroll(0, -4);
+ atarimo_set_yscroll(0, 0x110);
+ has_mo = (machine->gfx[0]->total_elements > 10);
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( arcadecl )
+{
+ /* draw the playfield */
+ rampart_bitmap_render(machine, bitmap, cliprect);
+
+ /* draw and merge the MO */
+ if (has_mo)
+ {
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* not yet verified
+ */
+ pf[x] = mo[x];
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/argus.c b/src/mame/video/argus.c
new file mode 100644
index 00000000000..ed78ccc01ef
--- /dev/null
+++ b/src/mame/video/argus.c
@@ -0,0 +1,1625 @@
+/***************************************************************************
+
+Functions to emulate the video hardware of the machine.
+
+
+BG RAM format [Argus and Butasan]
+-----------------------------------------------------------------------------
+ +0 +1
+ xxxx xxxx ---- ---- = 1st - 8th bits of tile number
+ ---- ---- xx-- ---- = 9th and 10th bit of tile number
+ ---- ---- --x- ---- = flip y
+ ---- ---- ---x ---- = flip x
+ ---- ---- ---- xxxx = color
+
+BG RAM format [Valtric]
+-----------------------------------------------------------------------------
+ +0 +1
+ xxxx xxxx ---- ---- = 1st - 8th bits of tile number
+ ---- ---- xx-- ---- = 9th and 10th bit of tile number
+ ---- ---- --x- ---- = 11th bit of tile number
+ ---- ---- ---- xxxx = color
+
+
+Text RAM format [Argus, Valtric and Butasan]
+-----------------------------------------------------------------------------
+ +0 +1
+ xxxx xxxx ---- ---- = low bits of tile number
+ ---- ---- xx-- ---- = high bits of tile number
+ ---- ---- --x- ---- = flip y
+ ---- ---- ---x ---- = flip x
+ ---- ---- ---- xxxx = color
+
+
+Sprite RAM format [Argus]
+-----------------------------------------------------------------------------
+ +11 +12 +13 +14 +15
+ xxxx xxxx ---- ---- ---- ---- ---- ---- ---- ---- = sprite y
+ ---- ---- xxxx xxxx ---- ---- ---- ---- ---- ---- = low bits of sprite x
+ ---- ---- ---- ---- xx-- ---- ---- ---- ---- ---- = high bits of tile number
+ ---- ---- ---- ---- --x- ---- ---- ---- ---- ---- = flip y
+ ---- ---- ---- ---- ---x ---- ---- ---- ---- ---- = flip x
+ ---- ---- ---- ---- ---- --x- ---- ---- ---- ---- = high bit of sprite y
+ ---- ---- ---- ---- ---- ---x ---- ---- ---- ---- = high bit of sprite x
+ ---- ---- ---- ---- ---- ---- xxxx xxxx ---- ---- = low bits of tile number
+ ---- ---- ---- ---- ---- ---- ---- ---- ---- x--- = BG1 / sprite priority (Argus only)
+ ---- ---- ---- ---- ---- ---- ---- ---- ---- -xxx = color
+
+Sprite RAM format [Valtric]
+-----------------------------------------------------------------------------
+ +11 +12 +13 +14 +15
+ xxxx xxxx ---- ---- ---- ---- ---- ---- ---- ---- = sprite y
+ ---- ---- xxxx xxxx ---- ---- ---- ---- ---- ---- = low bits of sprite x
+ ---- ---- ---- ---- xx-- ---- ---- ---- ---- ---- = high bits of tile number
+ ---- ---- ---- ---- --x- ---- ---- ---- ---- ---- = flip y
+ ---- ---- ---- ---- ---x ---- ---- ---- ---- ---- = flip x
+ ---- ---- ---- ---- ---- --x- ---- ---- ---- ---- = high bit of sprite y
+ ---- ---- ---- ---- ---- ---x ---- ---- ---- ---- = high bit of sprite x
+ ---- ---- ---- ---- ---- ---- xxxx xxxx ---- ---- = low bits of tile number
+ ---- ---- ---- ---- ---- ---- ---- ---- ---- xxxx = color
+
+Sprite RAM format [Butasan]
+-----------------------------------------------------------------------------
+ +8 +9 +10 +11 +12
+ ---- -x-- ---- ---- ---- ---- ---- ---- ---- ---- = flip y
+ ---- ---x ---- ---- ---- ---- ---- ---- ---- ---- = flip x
+ ---- ---- ---- xxxx ---- ---- ---- ---- ---- ---- = color ($00 - $0B)
+ ---- ---- ---- ---- xxxx xxxx ---- ---- ---- ---- = low bits of sprite x
+ ---- ---- ---- ---- ---- ---- ---- ---x ---- ---- = top bit of sprite x
+ ---- ---- ---- ---- ---- ---- ---- ---- xxxx xxxx = low bits of sprite y
+ +13 +14 +15
+ ---- ---x ---- ---- ---- ---- = top bit of sprite y
+ ---- ---- xxxx xxxx ---- ---- = low bits of tile number
+ ---- ---- ---- ---- ---- xxxx = top bits of tile number
+
+(*) Sprite size is defined by its offset.
+ $F000 - $F0FF : 16x32 $F100 - $F2FF : 16x16
+ $F300 - $F3FF : 16x32 $F400 - $F57F : 16x16
+ $F580 - $F61F : 32x32 $F620 - $F67F : 64x64
+
+
+Scroll RAM of X and Y coordinates [Argus, Valtric and Butasan]
+-----------------------------------------------------------------------------
+ +0 +1
+ xxxx xxxx ---- ---- = scroll value
+ ---- ---- ---- ---x = top bit of scroll value
+
+
+Video effect RAM ( $C30C )
+-----------------------------------------------------------------------------
+ +0
+ ---- ---x = BG enable bit
+ ---- --x- = gray scale effect or tile bank select.
+
+
+Flip screen controller
+-----------------------------------------------------------------------------
+ +0
+ x--- ---- = flip screen
+
+
+BG0 palette intensity ( $C47F, $C4FF )
+-----------------------------------------------------------------------------
+ +0 (c47f) +1 (c4ff)
+ xxxx ---- ---- ---- = red intensity
+ ---- xxxx ---- ---- = green intensity
+ ---- ---- xxxx ---- = blue intensity
+
+
+(*) Things which are not emulated.
+ - Color $000 - 00f, $01e, $02e ... are half transparent color.
+ - Sprite priority bit may be present in Butasan. But I don't know
+ what is happened when it is set.
+
+***************************************************************************/
+
+#include "driver.h"
+
+#include "jalblend.c"
+
+#define BUTASAN_TEXT_RAMSIZE 0x0800
+#define BUTASAN_BG0_RAMSIZE 0x0800
+#define BUTASAN_TXBACK_RAMSIZE 0x0800
+#define BUTASAN_BG0BACK_RAMSIZE 0x0800
+
+
+UINT8 *argus_paletteram;
+UINT8 *argus_txram;
+UINT8 *argus_bg0_scrollx;
+UINT8 *argus_bg0_scrolly;
+UINT8 *argus_bg1ram;
+UINT8 *argus_bg1_scrollx;
+UINT8 *argus_bg1_scrolly;
+UINT8 *butasan_bg1ram;
+
+static UINT8 *argus_dummy_bg0ram;
+static UINT8 *butasan_txram;
+static UINT8 *butasan_bg0ram;
+static UINT8 *butasan_bg0backram;
+static UINT8 *butasan_txbackram;
+
+static tilemap *tx_tilemap = NULL;
+static tilemap *bg0_tilemap = NULL;
+static tilemap *bg1_tilemap = NULL;
+static tilemap *bombsa_bg_tilemap = NULL;
+
+static UINT8 argus_bg_status = 0x01;
+static UINT8 butasan_bg1_status = 0x01;
+static UINT8 argus_bg_purple = 0;
+static UINT8 argus_flipscreen = 0;
+
+static int argus_palette_intensity = 0;
+
+/* VROM scroll related for Argus */
+static int lowbitscroll = 0;
+static int prvscrollx = 0;
+
+static UINT8 bombsa_ram_page;
+static UINT8* bomba_otherram;
+
+static int valtric_mosaic=0;
+static mame_bitmap *mosaicbitmap;
+
+
+/***************************************************************************
+ Callbacks for the tilemap code
+***************************************************************************/
+
+static TILE_GET_INFO( argus_get_tx_tile_info )
+{
+ int hi, lo;
+
+ lo = argus_txram[ tile_index << 1 ];
+ hi = argus_txram[ (tile_index << 1) + 1 ];
+
+ SET_TILE_INFO(
+ 3,
+ ((hi & 0xc0) << 2) | lo,
+ hi & 0x0f,
+ TILE_FLIPYX((hi & 0x30) >> 4));
+}
+
+static TILE_GET_INFO( argus_get_bg0_tile_info )
+{
+ int hi, lo;
+
+ lo = argus_dummy_bg0ram[ tile_index << 1 ];
+ hi = argus_dummy_bg0ram[ (tile_index << 1) + 1 ];
+
+ SET_TILE_INFO(
+ 1,
+ ((hi & 0xc0) << 2) | lo,
+ hi & 0x0f,
+ TILE_FLIPYX((hi & 0x30) >> 4));
+}
+
+static TILE_GET_INFO( argus_get_bg1_tile_info )
+{
+ int hi, lo;
+
+ lo = argus_bg1ram[ tile_index << 1 ];
+ hi = argus_bg1ram[ (tile_index << 1) + 1 ];
+
+ SET_TILE_INFO(
+ 2,
+ lo,
+ hi & 0x0f,
+ TILE_FLIPYX((hi & 0x30) >> 4));
+}
+
+static TILE_GET_INFO( valtric_get_tx_tile_info )
+{
+ int hi, lo;
+
+ lo = argus_txram[ tile_index << 1 ];
+ hi = argus_txram[ (tile_index << 1) + 1 ];
+
+ SET_TILE_INFO(
+ 2,
+ ((hi & 0xc0) << 2) | lo,
+ hi & 0x0f,
+ TILE_FLIPYX((hi & 0x30) >> 4));
+}
+
+static TILE_GET_INFO( valtric_get_bg_tile_info )
+{
+ int hi, lo, color, tile;
+
+ lo = argus_bg1ram[ tile_index << 1 ];
+ hi = argus_bg1ram[ (tile_index << 1) + 1 ];
+
+ tile = ((hi & 0xc0) << 2) | ((hi & 0x20) << 5) | lo;
+ color = hi & 0x0f;
+
+ SET_TILE_INFO(
+ 1,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( butasan_get_tx_tile_info )
+{
+ int hi, lo;
+
+ tile_index ^= 0x3e0;
+
+ lo = butasan_txram[ tile_index << 1 ];
+ hi = butasan_txram[ (tile_index << 1) + 1 ];
+
+ SET_TILE_INFO(
+ 3,
+ ((hi & 0xc0) << 2) | lo,
+ hi & 0x0f,
+ TILE_FLIPYX((hi & 0x30) >> 4));
+}
+
+static TILE_GET_INFO( butasan_get_bg0_tile_info )
+{
+ int hi, lo;
+ int attrib;
+
+ attrib = (tile_index & 0x00f) | ((tile_index & 0x1e0) >> 1);
+ attrib |= ((tile_index & 0x200) >> 1) | ((tile_index & 0x010) << 5);
+ attrib ^= 0x0f0;
+
+ lo = butasan_bg0ram[ attrib << 1 ];
+ hi = butasan_bg0ram[ (attrib << 1) + 1 ];
+
+ SET_TILE_INFO(
+ 1,
+ ((hi & 0xc0) << 2) | lo,
+ hi & 0x0f,
+ TILE_FLIPYX((hi & 0x30) >> 4));
+}
+
+
+
+
+
+
+static TILE_GET_INFO( butasan_get_bg1_tile_info )
+{
+ int bank, tile, attrib, color;
+
+ attrib = (tile_index & 0x00f) | ((tile_index & 0x3e0) >> 1)
+ | ((tile_index & 0x010) << 5);
+ attrib ^= 0x0f0;
+
+ bank = (butasan_bg1_status & 0x02) << 7;
+ tile = butasan_bg1ram[ attrib ] | bank;
+ color = (tile & 0x80) >> 7;
+
+ SET_TILE_INFO(
+ 2,
+ tile,
+ color,
+ 0);
+}
+
+
+/***************************************************************************
+ Initialize and destroy video hardware emulation
+***************************************************************************/
+
+VIDEO_START( argus )
+{
+ lowbitscroll = 0;
+ /* info offset type w h col row */
+ bg0_tilemap = tilemap_create(argus_get_bg0_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+ bg1_tilemap = tilemap_create(argus_get_bg1_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+ tx_tilemap = tilemap_create(argus_get_tx_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ /* dummy RAM for back ground */
+ argus_dummy_bg0ram = auto_malloc( 0x800 );
+ memset( argus_dummy_bg0ram, 0, 0x800 );
+
+ memset( argus_bg0_scrollx, 0x00, 2 );
+
+ tilemap_set_transparent_pen( bg0_tilemap, 15 );
+ tilemap_set_transparent_pen( bg1_tilemap, 15 );
+ tilemap_set_transparent_pen( tx_tilemap, 15 );
+
+ jal_blend_table = auto_malloc(0xc00);
+ memset(jal_blend_table,0,0xc00) ;
+}
+
+VIDEO_START( valtric )
+{
+ /* info offset type w h col row */
+ bg1_tilemap = tilemap_create(valtric_get_bg_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+ tx_tilemap = tilemap_create(valtric_get_tx_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen( bg1_tilemap, 15 );
+ tilemap_set_transparent_pen( tx_tilemap, 15 );
+ mosaicbitmap=auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ jal_blend_table = auto_malloc(0xc00);
+ memset(jal_blend_table,0,0xc00) ;
+}
+
+VIDEO_START( butasan )
+{
+ /* info offset type w h col row */
+ bg0_tilemap = tilemap_create(butasan_get_bg0_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+ bg1_tilemap = tilemap_create(butasan_get_bg1_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+ tx_tilemap = tilemap_create(butasan_get_tx_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ butasan_txram = auto_malloc( BUTASAN_TEXT_RAMSIZE );
+ butasan_bg0ram = auto_malloc( BUTASAN_BG0_RAMSIZE );
+ butasan_txbackram = auto_malloc( BUTASAN_TXBACK_RAMSIZE );
+ butasan_bg0backram = auto_malloc( BUTASAN_BG0BACK_RAMSIZE );
+
+ memset( butasan_txram, 0x00, BUTASAN_TEXT_RAMSIZE );
+ memset( butasan_bg0ram, 0x00, BUTASAN_BG0_RAMSIZE );
+ memset( butasan_txbackram, 0x00, BUTASAN_TXBACK_RAMSIZE );
+ memset( butasan_bg0backram, 0x00, BUTASAN_BG0BACK_RAMSIZE );
+
+ tilemap_set_transparent_pen( tx_tilemap, 15 );
+
+ jal_blend_table = auto_malloc(0xc00);
+ memset(jal_blend_table,0,0xc00) ;
+}
+
+#if 0
+static TILE_GET_INFO( bombsa_get_tx_alt_tile_info )
+{
+ int hi, lo;
+
+ lo = bombsa_tx_alt_ram[ tile_index << 1 ];
+ hi = bombsa_tx_alt_ram[ (tile_index << 1) + 1 ];
+
+ SET_TILE_INFO(
+ 2,
+ ((hi & 0xc0) << 2) | lo,
+ hi & 0x0f,
+ TILE_FLIPYX((hi & 0x30) >> 4));
+}
+#endif
+
+static TILE_GET_INFO( bombsa_get_bg_tile_info )
+{
+ int tileno;
+ int col;
+
+ tileno = bomba_otherram[tile_index*2] | ( bomba_otherram[tile_index*2+1]<<8);
+ col = 0;
+
+ SET_TILE_INFO(
+ 1,
+ tileno,
+ col,
+ 0);
+}
+
+
+VIDEO_START( bombsa )
+{
+ /* info offset type w h col row */
+// bg1_tilemap = tilemap_create(valtric_get_bg_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+ tx_tilemap = tilemap_create(valtric_get_tx_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+#if 0
+ /* this might be wrong.. but it looks like there may be a tilemap here that can change between 8x8 and 16x16 mode.. */
+ /* when you start the game it gets 'corrupted' with data for another layer.. */
+ tx_alt_tilemap = tilemap_create(bombsa_get_tx_alt_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+#endif
+
+ bombsa_bg_tilemap = tilemap_create(bombsa_get_bg_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 16, 16, 64, 32);
+
+#if 0
+ bombsa_tx_alt_ram = auto_malloc(0x800);
+#endif
+
+// tilemap_set_transparent_pen( bg1_tilemap, 15 );
+ tilemap_set_transparent_pen( tx_tilemap, 15 );
+#if 0
+ tilemap_set_transparent_pen( tx_alt_tilemap, 15 );
+#endif
+// jal_blend_table = auto_malloc(0xc00);
+// memset(jal_blend_table,0,0xc00) ;
+
+ bomba_otherram = auto_malloc(0x1000);
+}
+
+/***************************************************************************
+ Functions for handler of MAP roms in Argus and palette color
+***************************************************************************/
+
+/* Write bg0 pattern data to dummy bg0 ram */
+static void argus_write_dummy_rams( int dramoffs, int vromoffs )
+{
+ int i;
+ int voffs;
+ int offs;
+
+ UINT8 *VROM1 = memory_region( REGION_USER1 ); /* "ag_15.bin" */
+ UINT8 *VROM2 = memory_region( REGION_USER2 ); /* "ag_16.bin" */
+
+ /* offset in pattern data */
+ offs = VROM1[ vromoffs ] | ( VROM1[ vromoffs + 1 ] << 8 );
+ offs &= 0x7ff;
+
+ voffs = offs * 16;
+ for (i = 0 ; i < 8 ; i ++)
+ {
+ argus_dummy_bg0ram[ dramoffs ] = VROM2[ voffs ];
+ argus_dummy_bg0ram[ dramoffs + 1 ] = VROM2[ voffs + 1 ];
+ tilemap_mark_tile_dirty( bg0_tilemap, dramoffs >> 1 );
+ dramoffs += 2;
+ voffs += 2;
+ }
+}
+
+
+static void bombsa_change_palette(int color, int data)
+{
+ palette_set_color_rgb(Machine, color, pal4bit(data >> 12), pal4bit(data >> 8), pal4bit(data >> 4));
+}
+
+
+static void argus_change_palette(int color, int data)
+{
+ jal_blend_table[color] = data & 0x0f ;
+
+ palette_set_color_rgb(Machine, color, pal4bit(data >> 12), pal4bit(data >> 8), pal4bit(data >> 4));
+}
+
+static void argus_change_bg_palette(int color, int data)
+{
+ int r, g, b;
+ int ir, ig, ib;
+
+ r = (data >> 12) & 0x0f;
+ g = (data >> 8) & 0x0f;
+ b = (data >> 4) & 0x0f;
+
+ ir = (argus_palette_intensity >> 12) & 0x0f;
+ ig = (argus_palette_intensity >> 8) & 0x0f;
+ ib = (argus_palette_intensity >> 4) & 0x0f;
+
+ r = (r - ir > 0) ? r - ir : 0;
+ g = (g - ig > 0) ? g - ig : 0;
+ b = (b - ib > 0) ? b - ib : 0;
+
+ if (argus_bg_status & 2) /* Gray / purple scale */
+ {
+ r = (r + g + b) / 3;
+ g = b = r;
+ if (argus_bg_purple == 2) /* Purple */
+ g = 0;
+ }
+
+ palette_set_color_rgb(Machine, color, pal4bit(r), pal4bit(g), pal4bit(b));
+}
+
+
+/***************************************************************************
+ Memory handler
+***************************************************************************/
+
+WRITE8_HANDLER(valtric_mosaic_w)
+{
+ if(data!=0x80)
+ {
+ valtric_mosaic=0x0f-(data&0x0f);
+
+ if(valtric_mosaic!=0)
+ {
+ valtric_mosaic++;
+ }
+
+ if(data&0x80)
+ {
+ valtric_mosaic*=-1;
+ }
+ }
+}
+
+
+WRITE8_HANDLER( bombsa_pageselect_w )
+{
+ bombsa_ram_page = data;
+}
+
+READ8_HANDLER( argus_txram_r )
+{
+ return argus_txram[ offset ];
+}
+
+WRITE8_HANDLER( argus_txram_w )
+{
+ argus_txram[ offset ] = data;
+ tilemap_mark_tile_dirty(tx_tilemap, offset >> 1);
+}
+
+READ8_HANDLER( bombsa_txram_r )
+{
+#if 0
+ if (bombsa_ram_page == 1)
+ {
+ return argus_txram[ offset ];
+ }
+ else
+ {
+ return bombsa_tx_alt_ram[ offset ];
+ }
+#endif
+
+ return argus_txram[ offset ];
+
+}
+
+WRITE8_HANDLER( bombsa_txram_w )
+{
+#if 0
+ if (bombsa_ram_page == 1)
+ {
+ argus_txram[ offset ] = data;
+ tilemap_mark_tile_dirty(tx_tilemap, offset >> 1);
+ }
+ else
+ {
+ /* 8x8 .. */
+ bombsa_tx_alt_ram[ offset ] = data;
+ tilemap_mark_tile_dirty(tx_alt_tilemap, offset >> 1);
+ /* also 16x16 ..? */
+ }
+#endif
+ argus_txram[ offset ] = data;
+ tilemap_mark_tile_dirty(tx_tilemap, offset >> 1);
+}
+
+READ8_HANDLER( butasan_txram_r )
+{
+ return butasan_txram[ offset ];
+}
+
+WRITE8_HANDLER( butasan_txram_w )
+{
+ butasan_txram[ offset ] = data;
+ tilemap_mark_tile_dirty(tx_tilemap, (offset ^ 0x7c0) >> 1);
+}
+
+READ8_HANDLER( argus_bg1ram_r )
+{
+ return argus_bg1ram[ offset ];
+}
+
+WRITE8_HANDLER( argus_bg1ram_w )
+{
+ argus_bg1ram[ offset ] = data;
+ tilemap_mark_tile_dirty(bg1_tilemap, offset >> 1);
+}
+
+READ8_HANDLER( butasan_bg0ram_r )
+{
+ return butasan_bg0ram[ offset ];
+}
+
+WRITE8_HANDLER( butasan_bg0ram_w )
+{
+ int idx;
+
+ butasan_bg0ram[ offset ] = data;
+
+ idx = ((offset & 0x01f) >> 1) | ((offset & 0x400) >> 6);
+ idx |= (offset & 0x3e0) ^ 0x1e0;
+
+ tilemap_mark_tile_dirty(bg0_tilemap, idx);
+}
+
+READ8_HANDLER( butasan_bg1ram_r )
+{
+ return butasan_bg1ram[ offset ];
+}
+
+WRITE8_HANDLER( butasan_bg1ram_w )
+{
+ int idx;
+
+ butasan_bg1ram[ offset ] = data;
+
+ idx = (offset & 0x00f) | ((offset & 0x200) >> 5) | ((offset & 0x1f0) << 1);
+ idx ^= 0x0f0;
+
+ tilemap_mark_tile_dirty(bg1_tilemap, idx);
+}
+
+WRITE8_HANDLER ( argus_bg0_scrollx_w )
+{
+ if (argus_bg0_scrollx[ offset ] != data)
+ {
+ argus_bg0_scrollx[ offset ] = data;
+ }
+}
+
+WRITE8_HANDLER( argus_bg0_scrolly_w )
+{
+ if (argus_bg0_scrolly[ offset ] != data)
+ {
+ int scrolly;
+ argus_bg0_scrolly[ offset ] = data;
+ scrolly = argus_bg0_scrolly[0] | ( (argus_bg0_scrolly[1] & 0x01) << 8);
+ if (!argus_flipscreen)
+ tilemap_set_scrolly( bg0_tilemap, 0, scrolly );
+ else
+ tilemap_set_scrolly( bg0_tilemap, 0, (scrolly + 256) & 0x1ff );
+ }
+}
+
+WRITE8_HANDLER( butasan_bg0_scrollx_w )
+{
+ if (argus_bg0_scrollx[ offset ] != data)
+ {
+ int scrollx;
+ argus_bg0_scrollx[ offset ] = data;
+ scrollx = argus_bg0_scrollx[0] | ( (argus_bg0_scrollx[1] & 0x01) << 8);
+ if (!argus_flipscreen)
+ tilemap_set_scrollx( bg0_tilemap, 0, scrollx );
+ else
+ tilemap_set_scrollx( bg0_tilemap, 0, (scrollx + 256) & 0x1ff );
+ }
+}
+
+WRITE8_HANDLER( argus_bg1_scrollx_w )
+{
+ if (argus_bg1_scrollx[ offset ] != data)
+ {
+ int scrollx;
+ argus_bg1_scrollx[ offset ] = data;
+ scrollx = argus_bg1_scrollx[0] | ( (argus_bg1_scrollx[1] & 0x01) << 8);
+ if (!argus_flipscreen)
+ tilemap_set_scrollx( bg1_tilemap, 0, scrollx );
+ else
+ tilemap_set_scrollx( bg1_tilemap, 0, (scrollx + 256) & 0x1ff );
+ }
+}
+
+WRITE8_HANDLER( argus_bg1_scrolly_w )
+{
+ if (argus_bg1_scrolly[ offset ] != data)
+ {
+ int scrolly;
+ argus_bg1_scrolly[ offset ] = data;
+ scrolly = argus_bg1_scrolly[0] | ( (argus_bg1_scrolly[1] & 0x01) << 8);
+ if (!argus_flipscreen)
+ tilemap_set_scrolly( bg1_tilemap, 0, scrolly );
+ else
+ tilemap_set_scrolly( bg1_tilemap, 0, (scrolly + 256) & 0x1ff );
+ }
+}
+
+WRITE8_HANDLER( argus_bg_status_w )
+{
+ if (argus_bg_status != data)
+ {
+ argus_bg_status = data;
+
+ /* Backgound enable */
+ tilemap_set_enable(bg1_tilemap, argus_bg_status & 1);
+
+ /* Gray / purple scale */
+ if (argus_bg_status & 2)
+ {
+ int offs;
+
+ for (offs = 0x400 ; offs < 0x500 ; offs ++)
+ {
+ argus_change_bg_palette( (offs - 0x0400) + 128,
+ (argus_paletteram[offs] << 8) | argus_paletteram[offs + 0x0400] );
+ }
+ }
+ }
+}
+
+WRITE8_HANDLER( valtric_bg_status_w )
+{
+ if (argus_bg_status != data)
+ {
+ argus_bg_status = data;
+
+ /* Backgound enable */
+ tilemap_set_enable(bg1_tilemap, argus_bg_status & 1);
+
+ /* Gray / purple scale */
+ if (argus_bg_status & 2)
+ {
+ int offs;
+
+ for (offs = 0x400 ; offs < 0x600 ; offs += 2)
+ {
+ argus_change_bg_palette( ((offs - 0x0400) >> 1) + 256,
+ argus_paletteram[offs | 1] | (argus_paletteram[offs & ~1] << 8));
+ }
+ }
+ }
+}
+
+WRITE8_HANDLER( butasan_bg0_status_w )
+{
+ if (argus_bg_status != data)
+ {
+ argus_bg_status = data;
+
+ /* Backgound enable */
+ tilemap_set_enable(bg0_tilemap, argus_bg_status & 1);
+ }
+}
+
+WRITE8_HANDLER( argus_flipscreen_w )
+{
+ if (argus_flipscreen != (data >> 7))
+ {
+ argus_flipscreen = data >> 7;
+ tilemap_set_flip( ALL_TILEMAPS, (argus_flipscreen) ? TILEMAP_FLIPY | TILEMAP_FLIPX : 0);
+ if (!argus_flipscreen)
+ {
+ int scrollx, scrolly;
+
+ if (bg0_tilemap != NULL)
+ {
+ scrollx = argus_bg0_scrollx[0] | ( (argus_bg0_scrollx[1] & 0x01) << 8);
+ tilemap_set_scrollx(bg0_tilemap, 0, scrollx & 0x1ff);
+
+ scrolly = argus_bg0_scrolly[0] | ( (argus_bg0_scrolly[1] & 0x01) << 8);
+ tilemap_set_scrolly(bg0_tilemap, 0, scrolly);
+ }
+ scrollx = argus_bg1_scrollx[0] | ( (argus_bg1_scrollx[1] & 0x01) << 8);
+ tilemap_set_scrollx(bg1_tilemap, 0, scrollx);
+
+ scrolly = argus_bg1_scrolly[0] | ( (argus_bg1_scrolly[1] & 0x01) << 8);
+ tilemap_set_scrolly(bg1_tilemap, 0, scrolly);
+ }
+ else
+ {
+ int scrollx, scrolly;
+
+ if (bg0_tilemap != NULL)
+ {
+ scrollx = argus_bg0_scrollx[0] | ( (argus_bg0_scrollx[1] & 0x01) << 8);
+ tilemap_set_scrollx(bg0_tilemap, 0, (scrollx + 256) & 0x1ff);
+
+ scrolly = argus_bg0_scrolly[0] | ( (argus_bg0_scrolly[1] & 0x01) << 8);
+ tilemap_set_scrolly(bg0_tilemap, 0, (scrolly + 256) & 0x1ff);
+ }
+ scrollx = argus_bg1_scrollx[0] | ( (argus_bg1_scrollx[1] & 0x01) << 8);
+ tilemap_set_scrollx(bg1_tilemap, 0, (scrollx + 256) & 0x1ff);
+
+ scrolly = argus_bg1_scrolly[0] | ( (argus_bg1_scrolly[1] & 0x01) << 8);
+ tilemap_set_scrolly(bg1_tilemap, 0, (scrolly + 256) & 0x1ff);
+ }
+ }
+}
+
+READ8_HANDLER( argus_paletteram_r )
+{
+ return argus_paletteram[ offset ];
+}
+
+WRITE8_HANDLER( argus_paletteram_w )
+{
+ int offs;
+
+ argus_paletteram[ offset ] = data;
+
+ if (offset != 0x007f && offset != 0x00ff)
+ {
+ if (offset >= 0x0000 && offset <= 0x00ff) /* sprite color */
+ {
+ if (offset & 0x80)
+ offset -= 0x80;
+
+ argus_change_palette( offset,
+ (argus_paletteram[offset] << 8) | argus_paletteram[offset + 0x80] );
+ }
+
+ else if ( (offset >= 0x0400 && offset <= 0x04ff) ||
+ (offset >= 0x0800 && offset <= 0x08ff) ) /* BG0 color */
+ {
+ if (offset >= 0x0800)
+ offset -= 0x0400;
+
+ argus_change_bg_palette( (offset - 0x0400) + 128,
+ (argus_paletteram[offset] << 8) | argus_paletteram[offset + 0x0400] );
+ }
+
+ else if ( (offset >= 0x0500 && offset <= 0x05ff) ||
+ (offset >= 0x0900 && offset <= 0x09ff) ) /* BG1 color */
+ {
+ if (offset >= 0x0900)
+ offset -= 0x0400;
+
+ argus_change_palette( (offset - 0x0500) + 384,
+ (argus_paletteram[offset] << 8) | argus_paletteram[offset + 0x0400] );
+ }
+
+ else if ( (offset >= 0x0700 && offset <= 0x07ff) ||
+ (offset >= 0x0b00 && offset <= 0x0bff) ) /* text color */
+ {
+ if (offset >= 0x0b00)
+ offset -= 0x0400;
+
+ argus_change_palette( (offset - 0x0700) + 640,
+ (argus_paletteram[offset] << 8) | argus_paletteram[offset + 0x0400] );
+ }
+ }
+ else
+ {
+ argus_palette_intensity = (argus_paletteram[0x007f] << 8) | argus_paletteram[0x00ff];
+
+ for (offs = 0x400 ; offs < 0x500 ; offs ++)
+ {
+ argus_change_bg_palette( (offs - 0x0400) + 128,
+ (argus_paletteram[offs] << 8) | argus_paletteram[offs + 0x0400] );
+ }
+
+ argus_bg_purple = argus_paletteram[0x0ff] & 0x0f;
+ }
+}
+
+WRITE8_HANDLER( valtric_paletteram_w )
+{
+ int offs;
+
+ argus_paletteram[ offset ] = data;
+
+ if (offset != 0x01fe && offset != 0x01ff)
+ {
+ if (offset >= 0x0000 && offset <= 0x01ff)
+ {
+ argus_change_palette( offset >> 1,
+ argus_paletteram[offset | 1] | (argus_paletteram[offset & ~1] << 8));
+ }
+ else if (offset >= 0x0400 && offset <= 0x05ff )
+ {
+ argus_change_bg_palette( ((offset - 0x0400) >> 1) + 256,
+ argus_paletteram[offset | 1] | (argus_paletteram[offset & ~1] << 8));
+ }
+ else if (offset >= 0x0600 && offset <= 0x07ff )
+ {
+ argus_change_palette( ((offset - 0x0600) >> 1) + 512,
+ argus_paletteram[offset | 1] | (argus_paletteram[offset & ~1] << 8));
+ }
+ }
+ else
+ {
+ argus_palette_intensity = (argus_paletteram[0x01fe] << 8) | argus_paletteram[0x01ff];
+
+ for (offs = 0x400 ; offs < 0x600 ; offs += 2)
+ {
+ argus_change_bg_palette( ((offs - 0x0400) >> 1) + 256,
+ argus_paletteram[offs | 1] | (argus_paletteram[offs & ~1] << 8));
+ }
+
+ argus_bg_purple = argus_paletteram[0x01ff] & 0x0f;
+ }
+}
+
+WRITE8_HANDLER( butasan_paletteram_w )
+{
+ argus_paletteram[ offset ] = data;
+
+ if (offset < 0x0200 ) /* BG1 color */
+ {
+ argus_change_palette( ((offset - 0x0000) >> 1) + 256,
+ argus_paletteram[offset | 1] | (argus_paletteram[offset & ~1] << 8));
+ }
+ else if (offset < 0x0240 ) /* BG0 color */
+ {
+ argus_change_palette( ((offset - 0x0200) >> 1) + 192,
+ argus_paletteram[offset | 1] | (argus_paletteram[offset & ~1] << 8));
+ }
+ else if (offset >= 0x0400 && offset <= 0x04ff ) /* Sprite color */
+ {
+ if (offset < 0x0480) /* 16 colors */
+ argus_change_palette( ((offset - 0x0400) >> 1) + 0,
+ argus_paletteram[offset | 1] | (argus_paletteram[offset & ~1] << 8));
+ else /* 8 colors */
+ {
+ argus_change_palette( (offset & 0x70) + ((offset & 0x00f) >> 1) + 64,
+ argus_paletteram[offset | 1] | (argus_paletteram[offset & ~1] << 8));
+ argus_change_palette( (offset & 0x70) + ((offset & 0x00f) >> 1) + 72,
+ argus_paletteram[offset | 1] | (argus_paletteram[offset & ~1] << 8));
+ }
+ }
+ else if (offset >= 0x0600 && offset <= 0x07ff ) /* Text color */
+ {
+ argus_change_palette( ((offset - 0x0600) >> 1) + 512,
+ argus_paletteram[offset | 1] | (argus_paletteram[offset & ~1] << 8));
+ }
+}
+
+READ8_HANDLER( bombsa_paletteram_r )
+{
+ if (bombsa_ram_page==1)
+ {
+ return argus_paletteram[ offset ];
+ }
+ else if (bombsa_ram_page==0)
+ {
+ return bomba_otherram[ offset ];
+ }
+ else
+ {
+ mame_printf_debug("unknown bombsa_paletteram_r %02x %04x\n",bombsa_ram_page,offset);
+ return 0x00;
+ }
+}
+
+WRITE8_HANDLER( bombsa_paletteram_w )
+{
+ if (bombsa_ram_page==1)
+ {
+ argus_paletteram[ offset ] = data;
+ bombsa_change_palette( offset>>1, argus_paletteram[offset | 1] | (argus_paletteram[offset & ~1] << 8));
+ }
+ else if (bombsa_ram_page==0)
+ {
+ bomba_otherram[offset] = data;
+
+ tilemap_mark_tile_dirty(bombsa_bg_tilemap, offset/2);
+ }
+ else
+ {
+ mame_printf_debug("unknown bombsa_paletteram_w %02x %04x %02x\n",bombsa_ram_page,offset, data);
+ }
+}
+
+READ8_HANDLER( butasan_txbackram_r )
+{
+ return butasan_txbackram[ offset ];
+}
+
+WRITE8_HANDLER( butasan_txbackram_w )
+{
+ if (butasan_txbackram[ offset ] != data)
+ {
+ butasan_txbackram[ offset ] = data;
+ }
+}
+
+READ8_HANDLER( butasan_bg0backram_r )
+{
+ return butasan_bg0backram[ offset ];
+}
+
+WRITE8_HANDLER( butasan_bg0backram_w )
+{
+ if (butasan_bg0backram[ offset ] != data)
+ {
+ butasan_bg0backram[ offset ] = data;
+ }
+}
+
+WRITE8_HANDLER( butasan_bg1_status_w )
+{
+ if (butasan_bg1_status != data)
+ {
+ butasan_bg1_status = data;
+
+ tilemap_set_enable(bg1_tilemap, butasan_bg1_status & 0x01); /* Set enable flag */
+ tilemap_mark_all_tiles_dirty( bg1_tilemap ); /* Bank changed */
+ }
+}
+
+
+/***************************************************************************
+ Screen refresh
+***************************************************************************/
+
+static void argus_bg0_scroll_handle( void )
+{
+ int delta;
+ int scrollx;
+ int dcolumn;
+
+ /* Deficit between previous and current scroll value */
+ scrollx = argus_bg0_scrollx[0] | (argus_bg0_scrollx[1] << 8);
+ delta = scrollx - prvscrollx;
+ prvscrollx = scrollx;
+
+ if ( delta == 0 )
+ return;
+
+ if (delta > 0)
+ {
+ lowbitscroll += delta % 16;
+ dcolumn = delta / 16;
+
+ if (lowbitscroll >= 16)
+ {
+ dcolumn ++;
+ lowbitscroll -= 16;
+ }
+
+ if (dcolumn != 0)
+ {
+ int i, j;
+ int col, woffs, roffs;
+
+ col = ( (scrollx / 16) + 16 ) % 32;
+ woffs = 32 * 2 * col;
+ roffs = ( ( (scrollx / 16) + 16 ) * 8 ) % 0x8000;
+
+ if ( dcolumn >= 18 )
+ dcolumn = 18;
+
+ for ( i = 0 ; i < dcolumn ; i ++ )
+ {
+ for ( j = 0 ; j < 4 ; j ++ )
+ {
+ argus_write_dummy_rams( woffs, roffs );
+ woffs += 16;
+ roffs += 2;
+ }
+ woffs -= 128;
+ roffs -= 16;
+ if (woffs < 0)
+ woffs += 0x800;
+ if (roffs < 0)
+ roffs += 0x8000;
+ }
+ }
+ }
+ else
+ {
+ lowbitscroll += (delta % 16);
+ dcolumn = -(delta / 16);
+
+ if (lowbitscroll <= 0)
+ {
+ dcolumn ++;
+ lowbitscroll += 16;
+ }
+
+ if (dcolumn != 0)
+ {
+ int i, j;
+ int col, woffs, roffs;
+
+ col = ( (scrollx / 16) + 31 ) % 32;
+ woffs = 32 * 2 * col;
+ roffs = ( (scrollx / 16) - 1 ) * 8;
+ if (roffs < 0)
+ roffs += 0x08000;
+
+ if (dcolumn >= 18)
+ dcolumn = 18;
+
+ for ( i = 0 ; i < dcolumn ; i ++ )
+ {
+ for ( j = 0 ; j < 4 ; j ++ )
+ {
+ argus_write_dummy_rams( woffs, roffs );
+ woffs += 16;
+ roffs += 2;
+ }
+ if (woffs >= 0x800)
+ woffs -= 0x800;
+ if (roffs >= 0x8000)
+ roffs -= 0x8000;
+ }
+ }
+ }
+
+ if (!argus_flipscreen)
+ tilemap_set_scrollx(bg0_tilemap, 0, scrollx & 0x1ff);
+ else
+ tilemap_set_scrollx(bg0_tilemap, 0, (scrollx + 256) & 0x1ff);
+
+}
+
+static void argus_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int offs;
+
+ /* Draw the sprites */
+ for (offs = 11 ; offs < spriteram_size ; offs += 16)
+ {
+ if ( !(spriteram[offs+4] == 0 && spriteram[offs] == 0xf0) )
+ {
+ int sx, sy, tile, flipx, flipy, color, pri;
+
+ sx = spriteram[offs + 1];
+ sy = spriteram[offs];
+
+ if (argus_flipscreen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ }
+
+ if (!argus_flipscreen)
+ {
+ if ( spriteram[offs+2] & 0x01) sx -= 256;
+ if (!(spriteram[offs+2] & 0x02)) sy -= 256;
+ }
+ else
+ {
+ if ( spriteram[offs+2] & 0x01) sx += 256;
+ if (!(spriteram[offs+2] & 0x02)) sy += 256;
+ }
+
+ tile = spriteram[offs+3] + ((spriteram[offs+2] & 0xc0) << 2);
+ flipx = spriteram[offs+2] & 0x10;
+ flipy = spriteram[offs+2] & 0x20;
+ color = spriteram[offs+4] & 0x07;
+ pri = (spriteram[offs+4] & 0x08) >> 3;
+
+ if (argus_flipscreen)
+ {
+ flipx ^= 0x10;
+ flipy ^= 0x20;
+ }
+
+ if (priority != pri)
+ jal_blend_drawgfx(bitmap,machine->gfx[0],
+ tile,
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 15
+ );
+ }
+ }
+}
+
+static void valtric_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ /* Draw the sprites */
+ for (offs = 11 ; offs < spriteram_size ; offs += 16)
+ {
+ if ( !(spriteram[offs+4] == 0 && spriteram[offs] == 0xf0) )
+ {
+ int sx, sy, tile, flipx, flipy, color;
+
+ sx = spriteram[offs + 1];
+ sy = spriteram[offs];
+
+ if (argus_flipscreen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ }
+
+ if (!argus_flipscreen)
+ {
+ if ( spriteram[offs+2] & 0x01) sx -= 256;
+ if (!(spriteram[offs+2] & 0x02)) sy -= 256;
+ }
+ else
+ {
+ if ( spriteram[offs+2] & 0x01) sx += 256;
+ if (!(spriteram[offs+2] & 0x02)) sy += 256;
+ }
+
+ tile = spriteram[offs+3] + ((spriteram[offs+2] & 0xc0) << 2);
+ flipx = spriteram[offs+2] & 0x10;
+ flipy = spriteram[offs+2] & 0x20;
+ color = spriteram[offs+4] & 0x0f;
+
+ if (argus_flipscreen)
+ {
+ flipx ^= 0x10;
+ flipy ^= 0x20;
+ }
+
+ jal_blend_drawgfx(bitmap,machine->gfx[0],
+ tile,
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 15);
+ }
+ }
+}
+
+static void butasan_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ /* Draw the sprites */
+ for (offs = 8 ; offs < spriteram_size ; offs += 16)
+ {
+ int sx, sy, tile, flipx, flipy, color;
+
+ sx = spriteram[offs + 2];
+ sy = 240 - spriteram[offs + 4];
+
+ if (spriteram[offs + 3] & 0x01) sx -= 256;
+ if (spriteram[offs + 5] & 0x01) sy += 256;
+
+ tile = spriteram[offs + 6] + ((spriteram[offs + 7] & 0x0f) << 8);
+ flipx = spriteram[offs + 0] & 0x01;
+ flipy = spriteram[offs + 0] & 0x04;
+ color = spriteram[offs + 1] & 0x0f;
+
+ if (!argus_flipscreen)
+ {
+ if ( (offs >= 0x100 && offs < 0x300) || (offs >= 0x400 && offs < 0x580) )
+ {
+ jal_blend_drawgfx(bitmap,machine->gfx[0],
+ tile,
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 7);
+ }
+ else if ( (offs >= 0x000 && offs < 0x100) || (offs >= 0x300 && offs < 0x400) )
+ {
+ int i;
+
+ for ( i = 0 ; i <= 1 ; i ++ )
+ {
+ int td;
+
+ td = (flipx) ? (1 - i) : i;
+
+ jal_blend_drawgfx(bitmap,machine->gfx[0],
+ tile + td,
+ color,
+ flipx, flipy,
+ sx + i * 16, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 7);
+ }
+ }
+ else if ( offs >= 0x580 && offs < 0x620 )
+ {
+ int i, j;
+
+ for ( i = 0 ; i <= 1 ; i ++ )
+ {
+ for ( j = 0 ; j <= 1 ; j ++ )
+ {
+ int td;
+
+ if ( !flipy )
+ td = (flipx) ? (i * 2) + 1 - j : i * 2 + j;
+ else
+ td = (flipx) ? ( (1 - i) * 2 ) + 1 - j : (1 - i) * 2 + j;
+
+ jal_blend_drawgfx(bitmap,machine->gfx[0],
+ tile + td,
+ color,
+ flipx, flipy,
+ sx + j * 16, sy - i * 16,
+ cliprect,
+ TRANSPARENCY_PEN, 7);
+ }
+ }
+ }
+ else if ( offs >= 0x620 && offs < 0x680 )
+ {
+ int i, j;
+
+ for ( i = 0 ; i <= 3 ; i ++ )
+ {
+ for ( j = 0 ; j <= 3 ; j ++ )
+ {
+ int td;
+
+ if ( !flipy )
+ td = (flipx) ? (i * 4) + 3 - j : i * 4 + j;
+ else
+ td = (flipx) ? ( (3 - i) * 4 ) + 3 - j : (3 - i) * 4 + j;
+
+ jal_blend_drawgfx(bitmap,machine->gfx[0],
+ tile + td,
+ color,
+ flipx, flipy,
+ sx + j * 16, sy - i * 16,
+ cliprect,
+ TRANSPARENCY_PEN, 7);
+ }
+ }
+ }
+ }
+ else
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx ^= 0x01;
+ flipy ^= 0x04;
+
+ if ( (offs >= 0x100 && offs < 0x300) || (offs >= 0x400 && offs < 0x580) )
+ {
+ jal_blend_drawgfx(bitmap,machine->gfx[0],
+ tile,
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 7);
+ }
+ else if ( (offs >= 0x000 && offs < 0x100) || (offs >= 0x300 && offs < 0x400) )
+ {
+ int i;
+
+ for ( i = 0 ; i <= 1 ; i ++ )
+ {
+ int td;
+
+ td = (flipx) ? i : (1 - i);
+
+ jal_blend_drawgfx(bitmap,machine->gfx[0],
+ tile + td,
+ color,
+ flipx, flipy,
+ sx - i * 16, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 7);
+ }
+ }
+ else if ( offs >= 0x580 && offs < 0x620 )
+ {
+ int i, j;
+
+ for ( i = 0 ; i <= 1 ; i ++ )
+ {
+ for ( j = 0 ; j <= 1 ; j ++ )
+ {
+ int td;
+
+ if ( !flipy )
+ td = (flipx) ? (1 - i) * 2 + j : ( (1 - i) * 2 ) + 1 - j;
+ else
+ td = (flipx) ? i * 2 + j : (i * 2) + 1 - j;
+
+ jal_blend_drawgfx(bitmap,machine->gfx[0],
+ tile + td,
+ color,
+ flipx, flipy,
+ sx - j * 16, sy + i * 16,
+ cliprect,
+ TRANSPARENCY_PEN, 7);
+ }
+ }
+ }
+ else if ( offs >= 0x620 && offs < 0x680 )
+ {
+ int i, j;
+
+ for ( i = 0 ; i <= 3 ; i ++ )
+ {
+ for ( j = 0 ; j <= 3 ; j ++ )
+ {
+ int td;
+
+ if ( !flipy )
+ td = (flipx) ? (3 - i) * 4 + j : ( (3 - i) * 4 ) + 3 - j;
+ else
+ td = (flipx) ? i * 4 + j : (i * 4) + 3 - j;
+
+ jal_blend_drawgfx(bitmap,machine->gfx[0],
+ tile + td,
+ color,
+ flipx, flipy,
+ sx - j * 16, sy + i * 16,
+ cliprect,
+ TRANSPARENCY_PEN, 7);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+#ifdef MAME_DEBUG
+static void butasan_log_vram(void)
+{
+ int offs;
+
+ if ( input_code_pressed(KEYCODE_M) )
+ {
+ int i;
+ logerror("\nSprite RAM\n");
+ logerror("---------------------------------------\n");
+ logerror(" +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f\n");
+ for (offs = 0 ; offs < spriteram_size ; offs += 16)
+ {
+ for (i = 0 ; i < 16 ; i ++)
+ {
+ if (i == 0)
+ {
+ logerror("%04x : ", offs + 0xf000);
+ logerror("%02x ", spriteram[offs]);
+ }
+ else if (i == 7)
+ logerror("%02x ", spriteram[offs + 7]);
+ else if (i == 15)
+ logerror("%02x\n", spriteram[offs + 15]);
+ else
+ logerror("%02x ", spriteram[offs + i]);
+ }
+ }
+ logerror("\nColor RAM\n");
+ logerror("---------------------------------------\n");
+ logerror(" +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f\n");
+ for (offs = 0 ; offs < 0xbf0 ; offs += 16)
+ {
+ for (i = 0 ; i < 16 ; i ++)
+ {
+ if (i == 0)
+ {
+ logerror("%04x : ", offs + 0xc400);
+ logerror("%02x ", argus_paletteram[offs]);
+ }
+ else if (i == 7)
+ logerror("%02x ", argus_paletteram[offs + 7]);
+ else if (i == 15)
+ logerror("%02x\n", argus_paletteram[offs + 15]);
+ else
+ logerror("%02x ", argus_paletteram[offs + i]);
+ }
+ }
+ }
+}
+#endif
+
+static void bombsa_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ /* Draw the sprites */
+ for (offs = 11 ; offs < spriteram_size ; offs += 16)
+ {
+ if ( !(spriteram[offs+4] == 0 && spriteram[offs] == 0xf0) )
+ {
+ int sx, sy, tile, flipx, flipy, color, size;
+
+ sx = spriteram[offs + 1];
+ sy = spriteram[offs];
+
+ if (spriteram[offs+2] & 0x01) sx += 256;
+ if (spriteram[offs+2] & 0x02) sy += 256;
+
+
+ tile = spriteram[offs+3] + ((spriteram[offs+2] & 0xc0) << 2);
+ flipx = spriteram[offs+2] & 0x10;
+ flipy = spriteram[offs+2] & 0x20;
+ color = spriteram[offs+4] & 0x0f;
+ size = spriteram[offs+2] & 0x08;
+
+ if(!size)
+ {
+ drawgfx(bitmap,machine->gfx[0],tile,color,flipx,flipy,sx,sy,cliprect,TRANSPARENCY_PEN,15);
+ }
+ else
+ {
+ if (!flipy && !flipx)
+ {
+ drawgfx(bitmap,machine->gfx[0],tile+0,color,flipx,flipy,sx,sy,cliprect,TRANSPARENCY_PEN,15);
+ drawgfx(bitmap,machine->gfx[0],tile+1,color,flipx,flipy,sx,sy+16,cliprect,TRANSPARENCY_PEN,15);
+ drawgfx(bitmap,machine->gfx[0],tile+2,color,flipx,flipy,sx+16,sy,cliprect,TRANSPARENCY_PEN,15);
+ drawgfx(bitmap,machine->gfx[0],tile+3,color,flipx,flipy,sx+16,sy+16,cliprect,TRANSPARENCY_PEN,15);
+ }
+ else if (!flipy && flipx)
+ {
+ drawgfx(bitmap,machine->gfx[0],tile+0,color,flipx,flipy,sx+16,sy,cliprect,TRANSPARENCY_PEN,15);
+ drawgfx(bitmap,machine->gfx[0],tile+1,color,flipx,flipy,sx+16,sy+16,cliprect,TRANSPARENCY_PEN,15);
+ drawgfx(bitmap,machine->gfx[0],tile+2,color,flipx,flipy,sx,sy,cliprect,TRANSPARENCY_PEN,15);
+ drawgfx(bitmap,machine->gfx[0],tile+3,color,flipx,flipy,sx,sy+16,cliprect,TRANSPARENCY_PEN,15);
+ }
+ else if (flipy && !flipx)
+ {
+ drawgfx(bitmap,machine->gfx[0],tile+0,color,flipx,flipy,sx,sy+16,cliprect,TRANSPARENCY_PEN,15);
+ drawgfx(bitmap,machine->gfx[0],tile+1,color,flipx,flipy,sx,sy,cliprect,TRANSPARENCY_PEN,15);
+ drawgfx(bitmap,machine->gfx[0],tile+2,color,flipx,flipy,sx+16,sy+16,cliprect,TRANSPARENCY_PEN,15);
+ drawgfx(bitmap,machine->gfx[0],tile+3,color,flipx,flipy,sx+16,sy,cliprect,TRANSPARENCY_PEN,15);
+ }
+ else if (flipy && flipx)
+ {
+ drawgfx(bitmap,machine->gfx[0],tile+0,color,flipx,flipy,sx+16,sy+16,cliprect,TRANSPARENCY_PEN,15);
+ drawgfx(bitmap,machine->gfx[0],tile+1,color,flipx,flipy,sx+16,sy,cliprect,TRANSPARENCY_PEN,15);
+ drawgfx(bitmap,machine->gfx[0],tile+2,color,flipx,flipy,sx,sy+16,cliprect,TRANSPARENCY_PEN,15);
+ drawgfx(bitmap,machine->gfx[0],tile+3,color,flipx,flipy,sx,sy,cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( argus )
+{
+ /* scroll BG0 and render tile at proper position */
+ argus_bg0_scroll_handle();
+
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ tilemap_draw(bitmap, cliprect, bg0_tilemap, 0, 0);
+ argus_draw_sprites(machine, bitmap, cliprect, 0);
+ tilemap_draw(bitmap, cliprect, bg1_tilemap, 0, 0);
+ argus_draw_sprites(machine, bitmap, cliprect, 1);
+ tilemap_draw(bitmap, cliprect, tx_tilemap, 0, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( valtric )
+{
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ if(valtric_mosaic==0)
+ {
+ tilemap_draw(bitmap, cliprect, bg1_tilemap, 0, 0);
+ }
+ else
+ {
+ tilemap_draw(mosaicbitmap, cliprect, bg1_tilemap, 0, 0);
+ {
+ int step=valtric_mosaic;
+ UINT32 *dest;
+ int x,y,xx,yy;
+ if(valtric_mosaic<0)step*=-1;
+ for(y=0;y<machine->screen[0].width+step;y+=step)
+ for(x=0;x<machine->screen[0].height+step;x+=step)
+ {
+ static int c=0;
+
+ if(y<machine->screen[0].height && x< machine->screen[0].width)
+ {
+ c=*BITMAP_ADDR32(mosaicbitmap, y, x);
+ }
+
+ if(valtric_mosaic<0)
+ {
+ if(y+step-1<machine->screen[0].height && x+step-1< machine->screen[0].width)
+ {
+ c = *BITMAP_ADDR32(mosaicbitmap, y+step-1, x+step-1);
+ }
+ }
+ for(yy=0;yy<step;yy++)
+ for(xx=0;xx<step;xx++)
+ {
+ if(xx+x < machine->screen[0].width && yy+y<machine->screen[0].height)
+ {
+ dest=BITMAP_ADDR32(bitmap, y+yy, x+xx);
+ *dest=c;
+ }
+ }
+ }
+ }
+ }
+
+ valtric_draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, tx_tilemap, 0, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( butasan )
+{
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ tilemap_draw(bitmap, cliprect, bg1_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, bg0_tilemap, 0, 0);
+ butasan_draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, tx_tilemap, 0, 0);
+
+#ifdef MAME_DEBUG
+ butasan_log_vram();
+#endif
+ return 0;
+}
+
+
+VIDEO_UPDATE( bombsa )
+{
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+// tilemap_draw(bitmap, cliprect, bg1_tilemap, 0, 0);
+// valtric_draw_sprites(bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, bombsa_bg_tilemap, 0, 0);
+
+#if 0
+ tilemap_draw(bitmap, cliprect, tx_alt_tilemap, 0, 0);
+#endif
+ tilemap_draw(bitmap, cliprect, tx_tilemap, 0, 0);
+ bombsa_draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/arkanoid.c b/src/mame/video/arkanoid.c
new file mode 100644
index 00000000000..826efe6953a
--- /dev/null
+++ b/src/mame/video/arkanoid.c
@@ -0,0 +1,120 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/arkanoid.h"
+
+static UINT8 gfxbank, palettebank;
+extern UINT8 arkanoid_paddle_select;
+
+static tilemap *bg_tilemap;
+
+WRITE8_HANDLER( arkanoid_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+WRITE8_HANDLER( arkanoid_d008_w )
+{
+ int bank;
+
+ /* bits 0 and 1 flip X and Y, I don't know which is which */
+ if (flip_screen_x != (data & 0x01)) {
+ flip_screen_x_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ if (flip_screen_y != (data & 0x02)) {
+ flip_screen_y_set(data & 0x02);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ /* bit 2 selects the input paddle */
+ arkanoid_paddle_select = data & 0x04;
+
+ /* bit 3 is coin lockout (but not the service coin) */
+ coin_lockout_w(0, !(data & 0x08));
+ coin_lockout_w(1, !(data & 0x08));
+
+ /* bit 4 is unknown */
+
+ /* bits 5 and 6 control gfx bank and palette bank. They are used together */
+ /* so I don't know which is which. */
+ bank = (data & 0x20) >> 5;
+
+ if (gfxbank != bank) {
+ gfxbank = bank;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ bank = (data & 0x40) >> 6;
+
+ if (palettebank != bank) {
+ palettebank = bank;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ /* bit 7 is unknown */
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int offs = tile_index * 2;
+ int code = videoram[offs + 1] + ((videoram[offs] & 0x07) << 8) + 2048 * gfxbank;
+ int color = ((videoram[offs] & 0xf8) >> 3) + 32 * palettebank;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( arkanoid )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ state_save_register_global(gfxbank);
+ state_save_register_global(palettebank);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int sx,sy,code;
+
+ sx = spriteram[offs];
+ sy = 248 - spriteram[offs + 1];
+ if (flip_screen_x) sx = 248 - sx;
+ if (flip_screen_y) sy = 248 - sy;
+
+ code = spriteram[offs + 3] + ((spriteram[offs + 2] & 0x03) << 8) + 1024 * gfxbank;
+
+ drawgfx(bitmap,machine->gfx[0],
+ 2 * code,
+ ((spriteram[offs + 2] & 0xf8) >> 3) + 32 * palettebank,
+ flip_screen_x,flip_screen_y,
+ sx,sy + (flip_screen_y ? 8 : -8),
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[0],
+ 2 * code + 1,
+ ((spriteram[offs + 2] & 0xf8) >> 3) + 32 * palettebank,
+ flip_screen_x,flip_screen_y,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+VIDEO_UPDATE( arkanoid )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/armedf.c b/src/mame/video/armedf.c
new file mode 100644
index 00000000000..c654ac55f8a
--- /dev/null
+++ b/src/mame/video/armedf.c
@@ -0,0 +1,355 @@
+#include "driver.h"
+
+
+UINT16 armedf_vreg;
+
+UINT16 *terraf_text_videoram;
+UINT16 *armedf_bg_videoram;
+UINT16 *armedf_fg_videoram;
+UINT16 *legion_cmd;
+static UINT16 armedf_fg_scrollx,armedf_fg_scrolly;
+
+static UINT16 terraf_scroll_msb;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+tilemap *armedf_tx_tilemap;
+
+static int scroll_type,sprite_offy, mcu_mode, old_mcu_mode;
+
+void armedf_setgfxtype( int type )
+{
+ scroll_type = type;
+ mcu_mode = 0;
+ old_mcu_mode = 0;
+}
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( armedf_scan )
+{ /* col: 0..63; row: 0..31 */
+ switch( scroll_type )
+ {
+ case 1: /* armed formation */
+ return col*32+row;
+
+ case 3: /* legion */
+ case 6: /* legiono */
+ return (col&0x1f)*32+row+0x800*(col/32);
+
+ default:
+ return 32*(31-row)+(col&0x1f)+0x800*(col/32);
+ }
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int tile_number = terraf_text_videoram[tile_index]&0xff;
+ int attributes;
+
+ if( scroll_type == 1 )
+ {
+ attributes = terraf_text_videoram[tile_index+0x800]&0xff;
+ }
+ else
+ {
+ attributes = terraf_text_videoram[tile_index+0x400]&0xff;
+ }
+ SET_TILE_INFO(
+ 0,
+ tile_number + 256 * (attributes & 0x3),
+ attributes >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int data = armedf_fg_videoram[tile_index];
+ SET_TILE_INFO(
+ 1,
+ data&0x7ff,
+ data>>11,
+ 0);
+}
+
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int data = armedf_bg_videoram[tile_index];
+ SET_TILE_INFO(
+ 2,
+ data&0x3ff,
+ data>>11,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( armedf )
+{
+ if( scroll_type == 4 || /* cclimbr2 */
+ scroll_type == 3 || /* legion */
+ scroll_type == 6 ) /* legiono */
+ {
+ sprite_offy = 0;
+ }
+ else
+ {
+ sprite_offy = 128;
+ }
+
+ //bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,64,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,64,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,64,32);
+ armedf_tx_tilemap = tilemap_create(get_tx_tile_info,armedf_scan,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0xf);
+ tilemap_set_transparent_pen(armedf_tx_tilemap,0xf);
+ tilemap_set_transparent_pen(bg_tilemap,0xf);
+
+ if( scroll_type!=1 )
+ {
+ tilemap_set_scrollx(armedf_tx_tilemap,0,-128);
+ }
+}
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( armedf_text_videoram_w )
+{
+ COMBINE_DATA(&terraf_text_videoram[offset]);
+ if( scroll_type == 1 )
+ {
+ tilemap_mark_tile_dirty(armedf_tx_tilemap,offset & 0x7ff);
+ }
+ else
+ {
+ tilemap_mark_tile_dirty(armedf_tx_tilemap,offset & 0xbff);
+ }
+
+/* if (offset<0x10)
+ logerror("%04x %04x %04x %04x %04x %04x %04x %04x-%04x %04x %04x %04x %04x %04x %04x %04x (%04x)\n",
+ terraf_text_videoram[0], terraf_text_videoram[1], terraf_text_videoram[2],
+ terraf_text_videoram[3], terraf_text_videoram[4], terraf_text_videoram[5],
+ terraf_text_videoram[6], terraf_text_videoram[7], terraf_text_videoram[8],
+ terraf_text_videoram[9], terraf_text_videoram[10], terraf_text_videoram[11],
+ terraf_text_videoram[12], terraf_text_videoram[13], terraf_text_videoram[14],
+ terraf_text_videoram[15], offset);*/
+}
+
+
+WRITE16_HANDLER( armedf_fg_videoram_w )
+{
+ COMBINE_DATA(&armedf_fg_videoram[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE16_HANDLER( armedf_bg_videoram_w )
+{
+ COMBINE_DATA(&armedf_bg_videoram[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+static int waiting_msb;
+
+WRITE16_HANDLER( terraf_fg_scrollx_w )
+{
+ if (ACCESSING_MSB)
+ {
+ armedf_fg_scrollx = data >> 8;
+ waiting_msb = 1;
+ }
+}
+
+WRITE16_HANDLER( terraf_fg_scrolly_w )
+{
+ if (ACCESSING_MSB)
+ {
+ if (waiting_msb)
+ terraf_scroll_msb = data >> 8;
+ else
+ armedf_fg_scrolly = data >> 8;
+ }
+}
+
+WRITE16_HANDLER( terraf_fg_scroll_msb_arm_w )
+{
+ if (ACCESSING_MSB)
+ waiting_msb = 0;
+}
+
+WRITE16_HANDLER( armedf_fg_scrollx_w )
+{
+ COMBINE_DATA(&armedf_fg_scrollx);
+}
+
+WRITE16_HANDLER( armedf_fg_scrolly_w )
+{
+ COMBINE_DATA(&armedf_fg_scrolly);
+}
+
+WRITE16_HANDLER( armedf_bg_scrollx_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrollx(bg_tilemap,0,scroll);
+}
+
+WRITE16_HANDLER( armedf_bg_scrolly_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrolly(bg_tilemap,0,scroll);
+}
+
+WRITE16_HANDLER( armedf_mcu_cmd )
+{
+ COMBINE_DATA(&mcu_mode);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority )
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size/2;offs += 4)
+ {
+ int code = buffered_spriteram16[offs+1]; /* ??YX?TTTTTTTTTTT */
+ int flipx = code & 0x2000;
+ int flipy = code & 0x1000;
+ int color = (buffered_spriteram16[offs+2]>>8)&0x1f;
+ int sx = buffered_spriteram16[offs+3];
+ int sy = sprite_offy+240-(buffered_spriteram16[offs+0]&0x1ff);
+
+ if (flip_screen) {
+ sx = 320 - sx + 176; /* don't ask where 176 comes from, just tried it out */
+ sy = 240 - sy + 1; /* don't ask where 1 comes from, just tried it out */
+ flipx = !flipx; /* the values seem to result in pixel-correct placement */
+ flipy = !flipy; /* in all the games supported by this driver */
+ }
+
+ if (((buffered_spriteram16[offs+0] & 0x3000) >> 12) == priority)
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ code & 0xfff,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+}
+
+
+
+VIDEO_UPDATE( armedf )
+{
+ int sprite_enable = armedf_vreg & 0x200;
+
+ tilemap_set_enable( bg_tilemap, armedf_vreg&0x800 );
+ tilemap_set_enable( fg_tilemap, armedf_vreg&0x400 );
+ tilemap_set_enable( armedf_tx_tilemap, armedf_vreg&0x100 );
+
+ if ((scroll_type == 0)||(scroll_type == 5 )) {
+ if (old_mcu_mode!=mcu_mode) {
+ if ((mcu_mode&0x000f)==0x0004) { // transparent tx
+ tilemap_set_transparent_pen(armedf_tx_tilemap, 0x0f);
+ tilemap_mark_all_tiles_dirty( armedf_tx_tilemap );
+ //logerror("? Transparent TX 0x0f\n");
+ }
+ if ((mcu_mode&0x000f)==0x000f) { // opaque tx
+ tilemap_set_transparent_pen(armedf_tx_tilemap, 0x10);
+ tilemap_mark_all_tiles_dirty( armedf_tx_tilemap );
+ //logerror("? Opaque TX\n");
+ }
+
+ old_mcu_mode = mcu_mode;
+ //logerror("MCU Change => %04x\n",mcu_mode);
+ }
+ }
+
+ switch (scroll_type)
+ {
+ case 0: /* terra force */
+ tilemap_set_scrollx( fg_tilemap, 0, armedf_fg_scrolly + ((terraf_scroll_msb>>4)&3)*256 );
+ tilemap_set_scrolly( fg_tilemap, 0, armedf_fg_scrollx + ((terraf_scroll_msb)&3)*256 );
+ break;
+
+ case 1: /* armed formation */
+ tilemap_set_scrollx( fg_tilemap, 0, armedf_fg_scrollx );
+ tilemap_set_scrolly( fg_tilemap, 0, armedf_fg_scrolly );
+ break;
+
+ case 6: /* legiono */
+ tilemap_set_scrollx( fg_tilemap, 0, (legion_cmd[13] & 0xff) | ((legion_cmd[14] & 0x3)<<8) );
+ tilemap_set_scrolly( fg_tilemap, 0, (legion_cmd[11] & 0xff) | ((legion_cmd[12] & 0x3)<<8) );
+ break;
+ case 2: /* kodure ookami */
+ case 3:
+ case 4: /* crazy climber 2 */
+ {
+ int scrollx,scrolly;
+
+ /* scrolling is handled by the protection mcu */
+ scrollx = (terraf_text_videoram[13] & 0xff) | (terraf_text_videoram[14] << 8);
+ scrolly = (terraf_text_videoram[11] & 0xff) | (terraf_text_videoram[12] << 8);
+ tilemap_set_scrollx( fg_tilemap, 0, scrollx);
+ tilemap_set_scrolly( fg_tilemap, 0, scrolly);
+
+ }
+ break;
+ case 5: /* terra force (US) */
+ tilemap_set_scrollx( fg_tilemap, 0, (terraf_text_videoram[13] & 0xff) | ((terraf_text_videoram[14] & 0x3)<<8) );
+ tilemap_set_scrolly( fg_tilemap, 0, (terraf_text_videoram[11] & 0xff) | ((terraf_text_videoram[12] & 0x3)<<8) );
+ break;
+
+ }
+
+
+ fillbitmap( bitmap, 0xff, cliprect );
+ if (armedf_vreg & 0x0800) tilemap_draw( bitmap, cliprect, bg_tilemap, 0, 0);
+ /*if( armedf_vreg & 0x0800 )
+ {
+ tilemap_draw( bitmap, cliprect, bg_tilemap, 0, 0);
+ }
+ else
+ {
+ fillbitmap( bitmap, get_black_pen(machine)&0x0f, cliprect );
+ }*/
+
+ if ((mcu_mode&0x0030)==0x0030) tilemap_draw( bitmap, cliprect, armedf_tx_tilemap, 0, 0);
+ if( sprite_enable ) draw_sprites(machine, bitmap, cliprect, 2 );
+ if ((mcu_mode&0x0030)==0x0020) tilemap_draw( bitmap, cliprect, armedf_tx_tilemap, 0, 0);
+ tilemap_draw( bitmap, cliprect, fg_tilemap, 0, 0);
+ if ((mcu_mode&0x0030)==0x0010) tilemap_draw( bitmap, cliprect, armedf_tx_tilemap, 0, 0);
+ if( sprite_enable ) draw_sprites(machine, bitmap, cliprect, 1 );
+ if ((mcu_mode&0x0030)==0x0000) tilemap_draw( bitmap, cliprect, armedf_tx_tilemap, 0, 0);
+ if( sprite_enable ) draw_sprites(machine, bitmap, cliprect, 0 );
+
+ return 0;
+}
+
+VIDEO_EOF( armedf )
+{
+ buffer_spriteram16_w(0,0,0);
+}
diff --git a/src/mame/video/artmagic.c b/src/mame/video/artmagic.c
new file mode 100644
index 00000000000..0dab8c9a630
--- /dev/null
+++ b/src/mame/video/artmagic.c
@@ -0,0 +1,359 @@
+/***************************************************************************
+
+ Art & Magic hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "profiler.h"
+#include "cpu/tms34010/tms34010.h"
+#include "cpu/tms34010/34010ops.h"
+#include "artmagic.h"
+
+
+#define INSTANT_BLIT 1
+
+
+UINT16 *artmagic_vram0;
+UINT16 *artmagic_vram1;
+
+/* decryption parameters */
+int artmagic_xor[16], artmagic_is_stoneball;
+
+static UINT16 *blitter_base;
+static UINT32 blitter_mask;
+static UINT16 blitter_data[8];
+static UINT8 blitter_page;
+
+#if (!INSTANT_BLIT)
+static attotime blitter_busy_until;
+#endif
+
+
+
+/*************************************
+ *
+ * Inlines
+ *
+ *************************************/
+
+INLINE UINT16 *address_to_vram(offs_t *address)
+{
+ offs_t original = *address;
+ *address = TOWORD(original & 0x001fffff);
+ if (original >= 0x00000000 && original < 0x001fffff)
+ return artmagic_vram0;
+ else if (original >= 0x00400000 && original < 0x005fffff)
+ return artmagic_vram1;
+ return NULL;
+}
+
+
+
+/*************************************
+ *
+ * Video start
+ *
+ *************************************/
+
+VIDEO_START( artmagic )
+{
+ blitter_base = (UINT16 *)memory_region(REGION_GFX1);
+ blitter_mask = memory_region_length(REGION_GFX1)/2 - 1;
+}
+
+
+
+/*************************************
+ *
+ * Shift register transfers
+ *
+ *************************************/
+
+void artmagic_to_shiftreg(offs_t address, UINT16 *data)
+{
+ UINT16 *vram = address_to_vram(&address);
+ if (vram)
+ memcpy(data, &vram[address], TOBYTE(0x2000));
+}
+
+
+void artmagic_from_shiftreg(offs_t address, UINT16 *data)
+{
+ UINT16 *vram = address_to_vram(&address);
+ if (vram)
+ memcpy(&vram[address], data, TOBYTE(0x2000));
+}
+
+
+
+/*************************************
+ *
+ * Custom blitter
+ *
+ *************************************/
+
+static void execute_blit(void)
+{
+ UINT16 *dest = blitter_page ? artmagic_vram0 : artmagic_vram1;
+ int offset = ((blitter_data[1] & 0xff) << 16) | blitter_data[0];
+ int color = (blitter_data[1] >> 4) & 0xf0;
+ int x = (INT16)blitter_data[2];
+ int y = (INT16)blitter_data[3];
+ int maskx = blitter_data[6] & 0xff;
+ int masky = blitter_data[6] >> 8;
+ int w = ((blitter_data[7] & 0xff) + 1) * 4;
+ int h = (blitter_data[7] >> 8) + 1;
+ int i, j, sx, sy, last;
+
+#if 0
+{
+ static UINT32 hit_list[50000];
+ static int hit_index;
+ static FILE *f;
+
+ logerror("%08X:Blit from %06X to (%d,%d) %dx%d -- %04X %04X %04X %04X %04X %04X %04X %04X\n",
+ activecpu_get_pc(), offset, x, y, w, h,
+ blitter_data[0], blitter_data[1],
+ blitter_data[2], blitter_data[3],
+ blitter_data[4], blitter_data[5],
+ blitter_data[6], blitter_data[7]);
+
+ if (!f) f = fopen("artmagic.log", "w");
+
+ for (i = 0; i < hit_index; i++)
+ if (hit_list[i] == offset)
+ break;
+ if (i == hit_index)
+ {
+ int tempoffs = offset;
+ hit_list[hit_index++] = offset;
+
+ fprintf(f, "----------------------\n"
+ "%08X:Blit from %06X to (%d,%d) %dx%d -- %04X %04X %04X %04X %04X %04X %04X %04X\n",
+ activecpu_get_pc(), offset, x, y, w, h,
+ blitter_data[0], blitter_data[1],
+ blitter_data[2], blitter_data[3],
+ blitter_data[4], blitter_data[5],
+ blitter_data[6], blitter_data[7]);
+
+ fprintf(f, "\t");
+ for (i = 0; i < h; i++)
+ {
+ for (j = 0; j < w; j += 4)
+ fprintf(f, "%04X ", blitter_base[tempoffs++]);
+ fprintf(f, "\n\t");
+ }
+ fprintf(f, "\n\t");
+ tempoffs = offset;
+ for (i = 0; i < h; i++)
+ {
+ last = 0;
+ if (i == 0) /* first line */
+ {
+ /* ultennis, stonebal */
+ last ^= (blitter_data[7] & 0x0001);
+ if (artmagic_is_stoneball)
+ last ^= ((blitter_data[0] & 0x0020) >> 3);
+ else /* ultennis */
+ last ^= ((blitter_data[0] & 0x0040) >> 4);
+
+ /* cheesech */
+ last ^= ((blitter_data[7] & 0x0400) >> 9);
+ last ^= ((blitter_data[0] & 0x2000) >> 10);
+ }
+ else /* following lines */
+ {
+ int val = blitter_base[tempoffs];
+
+ /* ultennis, stonebal */
+ last ^= 4;
+ last ^= ((val & 0x0400) >> 8);
+ last ^= ((val & 0x5000) >> 12);
+
+ /* cheesech */
+ last ^= 8;
+ last ^= ((val & 0x0800) >> 8);
+ last ^= ((val & 0xa000) >> 12);
+ }
+
+ for (j = 0; j < w; j += 4)
+ {
+ static const char hex[] = ".123456789ABCDEF";
+ int val = blitter_base[tempoffs++];
+ int p1, p2, p3, p4;
+ p1 = last = ((val ^ artmagic_xor[last]) >> 0) & 0xf;
+ p2 = last = ((val ^ artmagic_xor[last]) >> 4) & 0xf;
+ p3 = last = ((val ^ artmagic_xor[last]) >> 8) & 0xf;
+ p4 = last = ((val ^ artmagic_xor[last]) >> 12) & 0xf;
+ fprintf(f, "%c%c%c%c ", hex[p1], hex[p2], hex[p3], hex[p4]);
+ }
+ fprintf(f, "\n\t");
+ }
+ fprintf(f, "\n");
+ }
+}
+#endif
+
+ profiler_mark(PROFILER_VIDEO);
+
+ last = 0;
+ sy = y;
+ for (i = 0; i < h; i++)
+ {
+ if ((i & 1) || !((masky << ((i/2) & 7)) & 0x80))
+ {
+ if (sy >= 0 && sy < 256)
+ {
+ int tsy = sy * TOWORD(0x2000);
+ sx = x;
+
+ /* The first pixel of every line doesn't have a previous pixel
+ to depend on, so it takes the "feed" from other bits.
+ The very first pixel blitted is also treated differently.
+
+ ultennis/stonebal use a different encryption from cheesech,
+ however the former only need to set bits 0 and 2 of the
+ feed (the others are irrelevant), while the latter only
+ bits 1 and 3, so I can handle both at the same time.
+ */
+ last = 0;
+ if (i == 0) /* first line */
+ {
+ /* ultennis, stonebal */
+ last ^= (blitter_data[7] & 0x0001);
+ if (artmagic_is_stoneball)
+ last ^= ((blitter_data[0] & 0x0020) >> 3);
+ else /* ultennis */
+ last ^= (((blitter_data[0] + 1) & 0x0040) >> 4);
+
+ /* cheesech */
+ last ^= ((blitter_data[7] & 0x0400) >> 9);
+ last ^= ((blitter_data[0] & 0x2000) >> 10);
+ }
+ else /* following lines */
+ {
+ int val = blitter_base[offset & blitter_mask];
+
+ /* ultennis, stonebal */
+ last ^= 4;
+ last ^= ((val & 0x0400) >> 8);
+ last ^= ((val & 0x5000) >> 12);
+
+ /* cheesech */
+ last ^= 8;
+ last ^= ((val & 0x0800) >> 8);
+ last ^= ((val & 0xa000) >> 12);
+ }
+
+ for (j = 0; j < w; j += 4)
+ {
+ UINT16 val = blitter_base[(offset + j/4) & blitter_mask];
+ if (sx < 508)
+ {
+ if (h == 1 && artmagic_is_stoneball)
+ last = ((val) >> 0) & 0xf;
+ else
+ last = ((val ^ artmagic_xor[last]) >> 0) & 0xf;
+ if (!((maskx << ((j/2) & 7)) & 0x80))
+ {
+ if (last && sx >= 0 && sx < 512)
+ dest[tsy + sx] = color | (last);
+ sx++;
+ }
+
+ if (h == 1 && artmagic_is_stoneball)
+ last = ((val) >> 4) & 0xf;
+ else
+ last = ((val ^ artmagic_xor[last]) >> 4) & 0xf;
+ {
+ if (last && sx >= 0 && sx < 512)
+ dest[tsy + sx] = color | (last);
+ sx++;
+ }
+
+ if (h == 1 && artmagic_is_stoneball)
+ last = ((val) >> 8) & 0xf;
+ else
+ last = ((val ^ artmagic_xor[last]) >> 8) & 0xf;
+ if (!((maskx << ((j/2) & 7)) & 0x40))
+ {
+ if (last && sx >= 0 && sx < 512)
+ dest[tsy + sx] = color | (last);
+ sx++;
+ }
+
+ if (h == 1 && artmagic_is_stoneball)
+ last = ((val) >> 12) & 0xf;
+ else
+ last = ((val ^ artmagic_xor[last]) >> 12) & 0xf;
+ {
+ if (last && sx >= 0 && sx < 512)
+ dest[tsy + sx] = color | (last);
+ sx++;
+ }
+ }
+ }
+ }
+ sy++;
+ }
+ offset += w/4;
+ }
+
+ profiler_mark(PROFILER_END);
+
+#if (!INSTANT_BLIT)
+ blitter_busy_until = attotime_add(timer_get_time(), ATTOTIME_IN_NSEC(w*h*20));
+#endif
+}
+
+
+READ16_HANDLER( artmagic_blitter_r )
+{
+ /*
+ bit 1 is a busy flag; loops tightly if clear
+ bit 2 is tested in a similar fashion
+ bit 4 reflects the page
+ */
+ UINT16 result = 0xffef | (blitter_page << 4);
+#if (!INSTANT_BLIT)
+ if (attotime_compare(timer_get_time(), blitter_busy_until) < 0)
+ result ^= 6;
+#endif
+ return result;
+}
+
+
+WRITE16_HANDLER( artmagic_blitter_w )
+{
+ COMBINE_DATA(&blitter_data[offset]);
+
+ /* offset 3 triggers the blit */
+ if (offset == 3)
+ execute_blit();
+
+ /* offset 4 contains the target page */
+ else if (offset == 4)
+ blitter_page = (data >> 1) & 1;
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+void artmagic_scanline(running_machine *machine, int screen, mame_bitmap *bitmap, int scanline, const tms34010_display_params *params)
+{
+ offs_t offset = (params->rowaddr << 12) & 0x7ff000;
+ UINT16 *vram = address_to_vram(&offset);
+ UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0);
+ int coladdr = params->coladdr << 1;
+ int x;
+
+ vram += offset;
+ for (x = params->heblnk; x < params->hsblnk; x++)
+ dest[x] = vram[coladdr++ & 0x1ff] & 0xff;
+}
diff --git a/src/mame/video/ashnojoe.c b/src/mame/video/ashnojoe.c
new file mode 100644
index 00000000000..d2764acb01e
--- /dev/null
+++ b/src/mame/video/ashnojoe.c
@@ -0,0 +1,222 @@
+/********************************************************************
+
+ Ashita no Joe (Success Joe) [Wave]
+ video hardware emulation
+
+*********************************************************************/
+
+#include "driver.h"
+
+UINT16 *ashnojoetileram16, *ashnojoetileram16_2, *ashnojoetileram16_3, *ashnojoetileram16_4, *ashnojoetileram16_5, *ashnojoetileram16_6, *ashnojoetileram16_7;
+static tilemap *joetilemap, *joetilemap2, *joetilemap3, *joetilemap4, *joetilemap5, *joetilemap6, *joetilemap7;
+
+UINT16 *ashnojoe_tilemap_reg;
+
+static TILE_GET_INFO( get_joe_tile_info )
+{
+ int code = ashnojoetileram16 [tile_index];
+
+ SET_TILE_INFO(
+ 2,
+ code & 0xfff,
+ ((code >> 12) & 0x0f),
+ 0);
+}
+
+static TILE_GET_INFO( get_joe_tile_info_2 )
+{
+ int code = ashnojoetileram16_2 [tile_index*2];
+ int attr = ashnojoetileram16_2 [tile_index*2+1];
+
+ SET_TILE_INFO(
+ 4,
+ (code & 0x7fff),
+ ((attr >> 8) & 0x1f) + 0x40,
+ 0);
+}
+
+static TILE_GET_INFO( get_joe_tile_info_3 )
+{
+ int code = ashnojoetileram16_3 [tile_index];
+
+ SET_TILE_INFO(
+ 0,
+ code & 0xfff,
+ ((code >> 12) & 0x0f) + 0x10,
+ 0);
+}
+
+static TILE_GET_INFO( get_joe_tile_info_4 )
+{
+ int code = ashnojoetileram16_4 [tile_index];
+
+ SET_TILE_INFO(
+ 1,
+ code & 0xfff,
+ ((code >> 12) & 0x0f) + 0x60,
+ 0);
+}
+
+static TILE_GET_INFO( get_joe_tile_info_5 )
+{
+ int code = ashnojoetileram16_5 [tile_index*2];
+ int attr = ashnojoetileram16_5 [tile_index*2+1];
+
+ SET_TILE_INFO(
+ 4,
+ (code & 0x7fff),
+ ((attr >> 8) & 0x1f) + 0x20,
+ 0);
+}
+
+static TILE_GET_INFO( get_joe_tile_info_6 )
+{
+ int code = ashnojoetileram16_6 [tile_index*2];
+ int attr = ashnojoetileram16_6 [tile_index*2+1];
+
+ SET_TILE_INFO(
+ 3,
+ (code & 0x1fff),
+ ((attr >> 8) & 0x1f) + 0x70,
+ 0);
+}
+
+
+static TILE_GET_INFO( get_joe_tile_info_7 )
+{
+ int code = ashnojoetileram16_7 [tile_index*2];
+ int attr = ashnojoetileram16_7 [tile_index*2+1];
+
+ SET_TILE_INFO(
+ 3,
+ (code & 0x1fff),
+ ((attr >> 8) & 0x1f) + 0x70,
+ 0);
+}
+
+WRITE16_HANDLER( ashnojoe_tileram_w )
+{
+ ashnojoetileram16[offset] = data;
+ tilemap_mark_tile_dirty(joetilemap,offset);
+}
+
+
+WRITE16_HANDLER( ashnojoe_tileram2_w )
+{
+ ashnojoetileram16_2[offset] = data;
+ tilemap_mark_tile_dirty(joetilemap2,offset/2);
+}
+
+WRITE16_HANDLER( ashnojoe_tileram3_w )
+{
+ ashnojoetileram16_3[offset] = data;
+ tilemap_mark_tile_dirty(joetilemap3,offset);
+}
+
+WRITE16_HANDLER( ashnojoe_tileram4_w )
+{
+ ashnojoetileram16_4[offset] = data;
+ tilemap_mark_tile_dirty(joetilemap4,offset);
+}
+
+WRITE16_HANDLER( ashnojoe_tileram5_w )
+{
+ ashnojoetileram16_5[offset] = data;
+ tilemap_mark_tile_dirty(joetilemap5,offset/2);
+}
+
+WRITE16_HANDLER( ashnojoe_tileram6_w )
+{
+ ashnojoetileram16_6[offset] = data;
+ tilemap_mark_tile_dirty(joetilemap6,offset/2);
+}
+
+WRITE16_HANDLER( ashnojoe_tileram7_w )
+{
+ ashnojoetileram16_7[offset] = data;
+ tilemap_mark_tile_dirty(joetilemap7,offset/2);
+}
+
+WRITE16_HANDLER( joe_tilemaps_xscroll_w )
+{
+ switch( offset )
+ {
+ case 0:
+ tilemap_set_scrollx(joetilemap3,0,data);
+ break;
+ case 1:
+ tilemap_set_scrollx(joetilemap5,0,data);
+ break;
+ case 2:
+ tilemap_set_scrollx(joetilemap2,0,data);
+ break;
+ case 3:
+ tilemap_set_scrollx(joetilemap4,0,data);
+ break;
+ case 4:
+ tilemap_set_scrollx(joetilemap6,0,data);
+ tilemap_set_scrollx(joetilemap7,0,data);
+ break;
+ }
+}
+
+WRITE16_HANDLER( joe_tilemaps_yscroll_w )
+{
+ switch( offset )
+ {
+ case 0:
+ tilemap_set_scrolly(joetilemap3,0,data);
+ break;
+ case 1:
+ tilemap_set_scrolly(joetilemap5,0,data);
+ break;
+ case 2:
+ tilemap_set_scrolly(joetilemap2,0,data);
+ break;
+ case 3:
+ tilemap_set_scrolly(joetilemap4,0,data);
+ break;
+ case 4:
+ tilemap_set_scrolly(joetilemap6,0,data);
+ tilemap_set_scrolly(joetilemap7,0,data);
+ break;
+ }
+}
+
+VIDEO_START( ashnojoe )
+{
+ joetilemap = tilemap_create(get_joe_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ joetilemap2 = tilemap_create(get_joe_tile_info_2,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ joetilemap3 = tilemap_create(get_joe_tile_info_3,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,64);
+ joetilemap4 = tilemap_create(get_joe_tile_info_4,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,64);
+ joetilemap5 = tilemap_create(get_joe_tile_info_5,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ joetilemap6 = tilemap_create(get_joe_tile_info_6,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,32,32);
+ joetilemap7 = tilemap_create(get_joe_tile_info_7,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,32,32);
+
+ tilemap_set_transparent_pen(joetilemap, 15);
+ tilemap_set_transparent_pen(joetilemap2,15);
+ tilemap_set_transparent_pen(joetilemap3,15);
+ tilemap_set_transparent_pen(joetilemap4,15);
+ tilemap_set_transparent_pen(joetilemap5,15);
+}
+
+VIDEO_UPDATE( ashnojoe )
+{
+
+// ashnojoe_tilemap_reg[0] & 0x10 // ?? on coin insertion
+
+ flip_screen_set(ashnojoe_tilemap_reg[0] & 1);
+
+ if(ashnojoe_tilemap_reg[0] & 0x02)
+ tilemap_draw(bitmap,cliprect,joetilemap7,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,joetilemap6,0,0);
+
+ tilemap_draw(bitmap,cliprect,joetilemap4,0,0);
+ tilemap_draw(bitmap,cliprect,joetilemap2,0,0);
+ tilemap_draw(bitmap,cliprect,joetilemap5,0,0);
+ tilemap_draw(bitmap,cliprect,joetilemap3,0,0);
+ tilemap_draw(bitmap,cliprect,joetilemap, 0,0);
+
+ return 0;
+}
diff --git a/src/mame/video/asterix.c b/src/mame/video/asterix.c
new file mode 100644
index 00000000000..96d662b9967
--- /dev/null
+++ b/src/mame/video/asterix.c
@@ -0,0 +1,119 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+static int sprite_colorbase;
+static int layer_colorbase[4], layerpri[3];
+static UINT16 spritebank;
+static int tilebanks[4];
+static int spritebanks[4];
+
+static void reset_spritebank(void)
+{
+ K053244_bankselect(0, spritebank & 7);
+ spritebanks[0] = (spritebank << 12) & 0x7000;
+ spritebanks[1] = (spritebank << 9) & 0x7000;
+ spritebanks[2] = (spritebank << 6) & 0x7000;
+ spritebanks[3] = (spritebank << 3) & 0x7000;
+}
+
+WRITE16_HANDLER( asterix_spritebank_w )
+{
+ COMBINE_DATA(&spritebank);
+ reset_spritebank();
+}
+
+static void asterix_sprite_callback(int *code, int *color, int *priority_mask)
+{
+ int pri = (*color & 0x00e0) >> 2;
+ if (pri <= layerpri[2]) *priority_mask = 0;
+ else if (pri > layerpri[2] && pri <= layerpri[1]) *priority_mask = 0xf0;
+ else if (pri > layerpri[1] && pri <= layerpri[0]) *priority_mask = 0xf0|0xcc;
+ else *priority_mask = 0xf0|0xcc|0xaa;
+ *color = sprite_colorbase | (*color & 0x001f);
+ *code = (*code & 0xfff) | spritebanks[(*code >> 12) & 3];
+}
+
+
+static void asterix_tile_callback(int layer, int *code, int *color, int *flags)
+{
+ *flags = *code & 0x1000 ? TILE_FLIPX : 0;
+ *color = (layer_colorbase[layer] + ((*code & 0xe000) >> 13)) & 0x7f;
+ *code = (*code & 0x03ff) | tilebanks[(*code >> 10) & 3];
+}
+
+VIDEO_START( asterix )
+{
+ K053251_vh_start();
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_4, 1, NULL, asterix_tile_callback, 1);
+ K053245_vh_start(machine,0, REGION_GFX2,NORMAL_PLANE_ORDER, asterix_sprite_callback);
+
+ K056832_set_LayerOffset(0, 89, 0);
+ K056832_set_LayerOffset(1, 91, 0);
+ K056832_set_LayerOffset(2, 89, 0);
+ K056832_set_LayerOffset(3, 95, 0);
+
+ K053245_set_SpriteOffset(0,-3,-1);
+}
+
+/* useful function to sort the three tile layers by priority order */
+static void sortlayers(int *layer,int *pri)
+{
+#define SWAP(a,b) \
+ if (pri[a] < pri[b]) \
+ { \
+ int t; \
+ t = pri[a]; pri[a] = pri[b]; pri[b] = t; \
+ t = layer[a]; layer[a] = layer[b]; layer[b] = t; \
+ }
+
+ SWAP(0,1)
+ SWAP(0,2)
+ SWAP(1,2)
+}
+
+VIDEO_UPDATE( asterix )
+{
+ static const int K053251_CI[4] = { K053251_CI0, K053251_CI2, K053251_CI3, K053251_CI4 };
+ int layer[3], plane, new_colorbase;
+
+ tilebanks[0] = (K056832_get_lookup(0) << 10);
+ tilebanks[1] = (K056832_get_lookup(1) << 10);
+ tilebanks[2] = (K056832_get_lookup(2) << 10);
+ tilebanks[3] = (K056832_get_lookup(3) << 10);
+
+ // update color info and refresh tilemaps
+ sprite_colorbase = K053251_get_palette_index(K053251_CI1);
+
+ for (plane=0; plane<4; plane++)
+ {
+ new_colorbase = K053251_get_palette_index(K053251_CI[plane]);
+ if (layer_colorbase[plane] != new_colorbase)
+ {
+ layer_colorbase[plane] = new_colorbase;
+ K056832_mark_plane_dirty(plane);
+ }
+ }
+
+ layer[0] = 0;
+ layerpri[0] = K053251_get_priority(K053251_CI0);
+ layer[1] = 1;
+ layerpri[1] = K053251_get_priority(K053251_CI2);
+ layer[2] = 3;
+ layerpri[2] = K053251_get_priority(K053251_CI4);
+
+ sortlayers(layer, layerpri);
+
+ fillbitmap(priority_bitmap, 0, cliprect);
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ K056832_tilemap_draw(machine, bitmap, cliprect, layer[0], 0, 1);
+ K056832_tilemap_draw(machine, bitmap, cliprect, layer[1], 0, 2);
+ K056832_tilemap_draw(machine, bitmap, cliprect, layer[2], 0, 4);
+
+ pdrawgfx_shadow_lowpri = 1; /* fix shadows in front of feet */
+ K053245_sprites_draw(0, bitmap, cliprect);
+
+ K056832_tilemap_draw(machine, bitmap, cliprect, 2, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/astinvad.c b/src/mame/video/astinvad.c
new file mode 100644
index 00000000000..031fdbeda11
--- /dev/null
+++ b/src/mame/video/astinvad.c
@@ -0,0 +1,148 @@
+/***************************************************************************
+
+ Video emulation for Astro Invader, Space Intruder et al
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/astinvad.h"
+
+
+static UINT8 spaceint_color;
+static UINT8 screen_red;
+
+
+void astinvad_set_screen_red(int data)
+{
+ screen_red = data;
+}
+
+
+WRITE8_HANDLER( spaceint_color_w )
+{
+ spaceint_color = data & 0x0f;
+}
+
+
+WRITE8_HANDLER( spaceint_videoram_w )
+{
+ videoram[offset] = data;
+ colorram[offset] = spaceint_color;
+}
+
+
+VIDEO_START( spaceint )
+{
+ colorram = auto_malloc(videoram_size);
+}
+
+
+
+static void plot_byte(mame_bitmap *bitmap, UINT8 y, UINT8 x, UINT8 data, UINT8 color)
+{
+ int i;
+
+ pen_t fore_pen = MAKE_RGB(pal1bit(color >> 0), pal1bit(color >> 2), pal1bit(color >> 1));
+
+ for (i = 0; i < 8; i++)
+ {
+ pen_t pen = (data & 0x01) ? fore_pen : RGB_BLACK;
+
+ if (flip_screen)
+ *BITMAP_ADDR32(bitmap, 255 - y, 255 - x) = pen;
+ else
+ *BITMAP_ADDR32(bitmap, y, x) = pen;
+
+ x = x + 1;
+ data = data >> 1;
+ }
+}
+
+
+VIDEO_UPDATE( astinvad )
+{
+ if (screen_red)
+ {
+ fillbitmap(bitmap, MAKE_RGB(pal1bit(1), pal1bit(0), pal1bit(0)), cliprect);
+ }
+ else
+ {
+ offs_t offs;
+
+ for (offs = 0; offs < videoram_size; offs++)
+ {
+ UINT8 color;
+ UINT8 data = videoram[offs];
+
+ UINT8 y = offs >> 5;
+ UINT8 x = offs << 3;
+
+ offs_t n = ((offs >> 3) & ~0x1f) | (offs & 0x1f);
+
+ if (flip_screen)
+ color = (memory_region(REGION_PROMS)[n] >> 4) & 0x07;
+ else
+ color = (memory_region(REGION_PROMS)[(~n + 0x80) & 0x3ff]) & 0x07;
+
+ plot_byte(bitmap, y, x, data, color);
+ }
+ }
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( spcking2 )
+{
+ if (screen_red)
+ {
+ fillbitmap(bitmap, MAKE_RGB(pal1bit(1), pal1bit(0), pal1bit(0)), cliprect);
+ }
+ else
+ {
+ offs_t offs;
+
+ for (offs = 0; offs < videoram_size; offs++)
+ {
+ UINT8 color;
+ UINT8 data = videoram[offs];
+
+ UINT8 y = offs >> 5;
+ UINT8 x = offs << 3;
+
+ offs_t n = ((offs >> 3) & ~0x1f) | (offs & 0x1f);
+
+ if (flip_screen)
+ color = (memory_region(REGION_PROMS)[n] >> 4) & 0x07;
+ else
+ color = (memory_region(REGION_PROMS)[n ^ 0x03ff]) & 0x07;
+
+ plot_byte(bitmap, y, x, data, color);
+ }
+ }
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( spaceint )
+{
+ offs_t offs;
+
+ for (offs = 0; offs < videoram_size; offs++)
+ {
+ UINT8 data = videoram[offs];
+ UINT8 color = colorram[offs];
+
+ UINT8 y = ~offs;
+ UINT8 x = offs >> 8 << 3;
+
+ /* this is almost certainly wrong */
+ offs_t n = ((offs >> 5) & 0xf0) | color;
+ color = memory_region(REGION_PROMS)[n] & 0x07;
+
+ plot_byte(bitmap, y, x, data, color);
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/astrocde.c b/src/mame/video/astrocde.c
new file mode 100644
index 00000000000..e6c094784ee
--- /dev/null
+++ b/src/mame/video/astrocde.c
@@ -0,0 +1,1106 @@
+/***************************************************************************
+
+ Bally Astrocade-based hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "cpu/z80/z80.h"
+#include "includes/astrocde.h"
+#include "sound/astrocde.h"
+#include <math.h> /* for sin() and cos() */
+#include "osd_cpu.h"
+#include "video/resnet.h"
+
+
+
+/*************************************
+ *
+ * Constants
+ *
+ *************************************/
+
+#define RNG_PERIOD ((1 << 17) - 1)
+#define VERT_OFFSET (22) /* pixels from top of screen to top of game area */
+#define HORZ_OFFSET (16) /* pixels from left of screen to left of game area */
+
+
+
+/*************************************
+ *
+ * Global variables
+ *
+ *************************************/
+
+/* video configuration */
+UINT8 astrocade_video_config;
+UINT8 astrocade_sparkle[4];
+
+/* palette/sparkle/star */
+static UINT8 *sparklestar;
+
+/* Astrocade interrupts */
+static UINT8 interrupt_enable;
+static UINT8 interrupt_vector;
+static UINT8 interrupt_scanline;
+static UINT8 vertical_feedback;
+static UINT8 horizontal_feedback;
+
+/* Astrocade video parameters */
+static emu_timer *scanline_timer;
+static UINT8 colors[8];
+static UINT8 colorsplit;
+static UINT8 bgdata;
+static UINT8 vblank;
+static UINT8 video_mode;
+
+/* Astrocade function generator */
+static UINT8 funcgen_expand_color[2];
+static UINT8 funcgen_control;
+static UINT8 funcgen_expand_count;
+static UINT8 funcgen_rotate_count;
+static UINT8 funcgen_rotate_data[4];
+static UINT8 funcgen_shift_prev_data;
+static UINT8 funcgen_intercept;
+
+/* pattern board registers */
+static UINT16 pattern_source;
+static UINT8 pattern_mode;
+static UINT16 pattern_dest;
+static UINT8 pattern_skip;
+static UINT8 pattern_width;
+static UINT8 pattern_height;
+
+/* 16-color board registers and video RAM */
+static UINT16 *profpac_videoram;
+static UINT16 profpac_palette[16];
+static UINT8 profpac_colormap[4];
+static UINT8 profpac_intercept;
+static UINT8 profpac_vispage;
+static UINT8 profpac_readpage;
+static UINT8 profpac_readshift;
+static UINT8 profpac_writepage;
+static UINT8 profpac_writemode;
+static UINT16 profpac_writemask;
+static UINT8 profpac_vw;
+
+
+
+/*************************************
+ *
+ * Function prototypes
+ *
+ *************************************/
+
+static void init_savestate(void);
+static TIMER_CALLBACK( scanline_callback );
+static void init_sparklestar(void);
+
+
+
+/*************************************
+ *
+ * Scanline conversion
+ *
+ *************************************/
+
+INLINE int mame_vpos_to_astrocade_vpos(int scanline)
+{
+ scanline -= VERT_OFFSET;
+ if (scanline < 0)
+ scanline += 262;
+ return scanline;
+}
+
+
+
+/*************************************
+ *
+ * Palette initialization
+ *
+ *************************************/
+
+PALETTE_INIT( astrocde )
+{
+ /*
+ The Astrocade has a 256 color palette: 32 colors with 8 luminance
+ values for each color. The 32 colors circle around the YUV color
+ space, with the exception of the first 8 which are grayscale.
+
+ We actually build a 512 entry palette with an extra bit of
+ luminance informaton. This is because the sparkle/star circuitry
+ on Wizard of War and Gorf replaces the luminance with a value
+ that has a 4-bit resolution.
+ */
+
+ int color, luma;
+
+ /* loop over color values */
+ for (color = 0; color < 32; color++)
+ {
+ float ry = 0.75 * sin((color / 32.0) * (2.0 * M_PI));
+ float by = 1.15 * cos((color / 32.0) * (2.0 * M_PI));
+
+ /* color 0 maps to ry = by = 0 */
+ if (color == 0)
+ ry = by = 0;
+
+ /* iterate over luminence values */
+ for (luma = 0; luma < 16; luma++)
+ {
+ float y = luma / 15.0;
+ int r, g, b;
+
+ /* transform to RGB */
+ r = (ry + y) * 255;
+ g = ((y - 0.299 * (ry + y) - 0.114 * (by + y)) / 0.587) * 255;
+ b = (by + y) * 255;
+
+ /* clamp and store */
+ r = MAX(r, 0);
+ r = MIN(r, 255);
+ g = MAX(g, 0);
+ g = MIN(g, 255);
+ b = MAX(b, 0);
+ b = MIN(b, 255);
+ palette_set_color(machine, color * 16 + luma, MAKE_RGB(r, g, b));
+ }
+ }
+}
+
+
+PALETTE_INIT( profpac )
+{
+ /* Professor Pac-Man uses a more standard 12-bit RGB palette layout */
+ static const int resistances[4] = { 6200, 3000, 1500, 750 };
+ double weights[4];
+ int i;
+
+ /* compute the color output resistor weights */
+ compute_resistor_weights(0, 255, -1.0,
+ 4, resistances, weights, 1500, 0,
+ 4, resistances, weights, 1500, 0,
+ 4, resistances, weights, 1500, 0);
+
+ /* initialize the palette with these colors */
+ for (i = 0; i < 4096; i++)
+ {
+ int bit0, bit1, bit2, bit3;
+ int r, g, b;
+
+ /* blue component */
+ bit0 = (i >> 0) & 0x01;
+ bit1 = (i >> 1) & 0x01;
+ bit2 = (i >> 2) & 0x01;
+ bit3 = (i >> 3) & 0x01;
+ b = combine_4_weights(weights, bit0, bit1, bit2, bit3);
+
+ /* green component */
+ bit0 = (i >> 4) & 0x01;
+ bit1 = (i >> 5) & 0x01;
+ bit2 = (i >> 6) & 0x01;
+ bit3 = (i >> 7) & 0x01;
+ g = combine_4_weights(weights, bit0, bit1, bit2, bit3);
+
+ /* red component */
+ bit0 = (i >> 8) & 0x01;
+ bit1 = (i >> 9) & 0x01;
+ bit2 = (i >> 10) & 0x01;
+ bit3 = (i >> 11) & 0x01;
+ r = combine_4_weights(weights, bit0, bit1, bit2, bit3);
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( astrocde )
+{
+ /* allocate a per-scanline timer */
+ scanline_timer = timer_alloc(scanline_callback);
+ timer_adjust(scanline_timer, video_screen_get_time_until_pos(0, 1, 0), 1, attotime_zero);
+
+ /* register for save states */
+ init_savestate();
+
+ /* initialize the sparkle and stars */
+ if (astrocade_video_config & AC_STARS)
+ init_sparklestar();
+}
+
+
+VIDEO_START( profpac )
+{
+ /* allocate a per-scanline timer */
+ scanline_timer = timer_alloc(scanline_callback);
+ timer_adjust(scanline_timer, video_screen_get_time_until_pos(0, 1, 0), 1, attotime_zero);
+
+ /* allocate videoram */
+ profpac_videoram = auto_malloc(0x4000 * 4 * sizeof(*profpac_videoram));
+
+ /* register for save states */
+ init_savestate();
+
+ /* register our specific save state data */
+ state_save_register_global_pointer(profpac_videoram, 0x4000 * 4);
+ state_save_register_global_array(profpac_palette);
+ state_save_register_global_array(profpac_colormap);
+ state_save_register_global(profpac_intercept);
+ state_save_register_global(profpac_vispage);
+ state_save_register_global(profpac_readpage);
+ state_save_register_global(profpac_readshift);
+ state_save_register_global(profpac_writepage);
+ state_save_register_global(profpac_writemode);
+ state_save_register_global(profpac_writemask);
+ state_save_register_global(profpac_vw);
+}
+
+
+static void init_savestate(void)
+{
+ state_save_register_global_array(astrocade_sparkle);
+
+ state_save_register_global(interrupt_enable);
+ state_save_register_global(interrupt_vector);
+ state_save_register_global(interrupt_scanline);
+ state_save_register_global(vertical_feedback);
+ state_save_register_global(horizontal_feedback);
+
+ state_save_register_global_array(colors);
+ state_save_register_global(colorsplit);
+ state_save_register_global(bgdata);
+ state_save_register_global(vblank);
+ state_save_register_global(video_mode);
+
+ state_save_register_global_array(funcgen_expand_color);
+ state_save_register_global(funcgen_control);
+ state_save_register_global(funcgen_expand_count);
+ state_save_register_global(funcgen_rotate_count);
+ state_save_register_global_array(funcgen_rotate_data);
+ state_save_register_global(funcgen_shift_prev_data);
+ state_save_register_global(funcgen_intercept);
+
+ state_save_register_global(pattern_source);
+ state_save_register_global(pattern_mode);
+ state_save_register_global(pattern_dest);
+ state_save_register_global(pattern_skip);
+ state_save_register_global(pattern_width);
+ state_save_register_global(pattern_height);
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( astrocde )
+{
+ int xystep = 2 - video_mode;
+ UINT32 sparklebase = 0;
+ int y;
+
+ /* compute the starting point of sparkle for the current frame */
+ if (astrocade_video_config & AC_STARS)
+ sparklebase = ((UINT64)cpu_getcurrentframe() * (UINT64)(machine->screen[0].width * machine->screen[0].height)) % RNG_PERIOD;
+
+ /* iterate over scanlines */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ int effy = mame_vpos_to_astrocade_vpos(y);
+ UINT16 offset = (effy / xystep) * (80 / xystep);
+ UINT32 sparkleoffs = 0, staroffs = 0;
+ int x;
+
+ /* compute the star and sparkle offset at the start of this line */
+ if (astrocade_video_config & AC_STARS)
+ {
+ staroffs = ((effy < 0) ? (effy + 262) : effy) * machine->screen[0].width;
+ sparkleoffs = sparklebase + y * machine->screen[0].width;
+ if (sparkleoffs >= RNG_PERIOD)
+ sparkleoffs -= RNG_PERIOD;
+ }
+
+ /* iterate over groups of 4 pixels */
+ for (x = 0; x < 456/4; x += xystep)
+ {
+ int effx = x - HORZ_OFFSET/4;
+ const UINT8 *colorbase = &colors[(effx < colorsplit) ? 4 : 0];
+ UINT8 data;
+ int xx;
+
+ /* select either video data or background data */
+ data = (effx >= 0 && effx < 80 && effy >= 0 && effy < vblank) ? videoram[offset++] : bgdata;
+
+ /* iterate over the 4 pixels */
+ for (xx = 0; xx < 4; xx++)
+ {
+ UINT8 pixdata = (data >> 6) & 3;
+ int coldata = colorbase[pixdata] << 1;
+ int luma = coldata & 0x0f;
+ rgb_t color;
+
+ /* handle stars/sparkle */
+ if (astrocade_video_config & AC_STARS)
+ {
+ /* if sparkle is enabled for this pixel index and either it is non-zero or a star */
+ /* then adjust the intensity */
+ if (astrocade_sparkle[pixdata] == 0)
+ {
+ if (pixdata != 0 || (sparklestar[staroffs] & 0x10))
+ luma = sparklestar[sparkleoffs] & 0x0f;
+ else if (pixdata == 0)
+ coldata = luma = 0;
+ }
+
+ /* update sparkle/star offsets */
+ staroffs++;
+ if (++sparkleoffs >= RNG_PERIOD)
+ sparkleoffs = 0;
+ }
+ color = (coldata & 0x1f0) | luma;
+
+ /* store the final color to the destination and shift */
+ *dest++ = color;
+ if (xystep == 2)
+ *dest++ = color;
+ data <<= 2;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( profpac )
+{
+ int y;
+
+ /* iterate over scanlines */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ int effy = mame_vpos_to_astrocade_vpos(y);
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ UINT16 offset = profpac_vispage * 0x4000 + effy * 80;
+ int x;
+
+ /* star with black */
+
+ /* iterate over groups of 4 pixels */
+ for (x = 0; x < 456/4; x++)
+ {
+ int effx = x - HORZ_OFFSET/4;
+
+ /* select either video data or background data */
+ UINT16 data = (effx >= 0 && effx < 80 && effy >= 0 && effy < vblank) ? profpac_videoram[offset++] : 0;
+
+ /* iterate over the 4 pixels */
+ *dest++ = profpac_palette[(data >> 12) & 0x0f];
+ *dest++ = profpac_palette[(data >> 8) & 0x0f];
+ *dest++ = profpac_palette[(data >> 4) & 0x0f];
+ *dest++ = profpac_palette[(data >> 0) & 0x0f];
+ }
+ }
+
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Interrupt generation
+ *
+ *************************************/
+
+static TIMER_CALLBACK( interrupt_off )
+{
+ cpunum_set_input_line(0, 0, CLEAR_LINE);
+}
+
+
+void astrocade_trigger_lightpen(UINT8 vfeedback, UINT8 hfeedback)
+{
+ /* both bits 1 and 4 enable lightpen interrupts; bit 4 enables them even in horizontal */
+ /* blanking regions; we treat them both the same here */
+ if ((interrupt_enable & 0x12) != 0)
+ {
+ /* bit 0 controls the interrupt mode: mode 0 means assert until acknowledged */
+ if ((interrupt_enable & 0x01) == 0)
+ cpunum_set_input_line_and_vector(0, 0, HOLD_LINE, interrupt_vector & 0xf0);
+
+ /* mode 1 means assert for 1 instruction */
+ else
+ {
+ cpunum_set_input_line_and_vector(0, 0, ASSERT_LINE, interrupt_vector & 0xf0);
+ timer_set(ATTOTIME_IN_CYCLES(1, 0), 0, interrupt_off);
+ }
+
+ /* latch the feedback registers */
+ vertical_feedback = vfeedback;
+ horizontal_feedback = hfeedback;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Per-scanline callback
+ *
+ *************************************/
+
+static TIMER_CALLBACK( scanline_callback )
+{
+ int scanline = param;
+ int astrocade_scanline = mame_vpos_to_astrocade_vpos(scanline);
+
+ /* force an update against the current scanline */
+ video_screen_update_partial(0, scanline - 1);
+
+ /* generate a scanline interrupt if it's time */
+ if (astrocade_scanline == interrupt_scanline && (interrupt_enable & 0x08) != 0)
+ {
+ /* bit 2 controls the interrupt mode: mode 0 means assert until acknowledged */
+ if ((interrupt_enable & 0x04) == 0)
+ cpunum_set_input_line_and_vector(0, 0, HOLD_LINE, interrupt_vector);
+
+ /* mode 1 means assert for 1 instruction */
+ else
+ {
+ cpunum_set_input_line_and_vector(0, 0, ASSERT_LINE, interrupt_vector);
+ timer_set(ATTOTIME_IN_CYCLES(1, 0), 0, interrupt_off);
+ }
+ }
+
+ /* on some games, the horizontal drive line is conected to the lightpen interrupt */
+ else if (astrocade_video_config & AC_LIGHTPEN_INTS)
+ astrocade_trigger_lightpen(astrocade_scanline, 8);
+
+ /* advance to the next scanline */
+ scanline++;
+ if (scanline >= machine->screen[0].height)
+ scanline = 0;
+ timer_adjust(scanline_timer, video_screen_get_time_until_pos(0, scanline, 0), scanline, attotime_zero);
+}
+
+
+
+/*************************************
+ *
+ * Data chip registers
+ *
+ *************************************/
+
+READ8_HANDLER( astrocade_data_chip_register_r )
+{
+ UINT8 result = 0xff;
+
+ /* these are the core registers */
+ switch (offset & 0xff)
+ {
+ case 0x08: /* intercept feedback */
+ result = funcgen_intercept;
+ funcgen_intercept = 0;
+ break;
+
+ case 0x0e: /* vertical feedback (from lightpen interrupt) */
+ result = vertical_feedback;
+ break;
+
+ case 0x0f: /* horizontal feedback (from lightpen interrupt) */
+ result = horizontal_feedback;
+ break;
+
+ case 0x10: /* player 1 handle */
+ result = readinputportbytag_safe("P1HANDLE", 0xff);
+ break;
+
+ case 0x11: /* player 2 handle */
+ result = readinputportbytag_safe("P2HANDLE", 0xff);
+ break;
+
+ case 0x12: /* player 3 handle */
+ result = readinputportbytag_safe("P3HANDLE", 0xff);
+ break;
+
+ case 0x13: /* player 4 handle */
+ result = readinputportbytag_safe("P4HANDLE", 0xff);
+ break;
+
+ case 0x14: /* keypad column 0 */
+ result = readinputportbytag_safe("KEYPAD0", 0xff);
+ break;
+
+ case 0x15: /* keypad column 1 */
+ result = readinputportbytag_safe("KEYPAD1", 0xff);
+ break;
+
+ case 0x16: /* keypad column 2 */
+ result = readinputportbytag_safe("KEYPAD2", 0xff);
+ break;
+
+ case 0x17: /* keypad column 3 */
+ result = readinputportbytag_safe("KEYPAD3", 0xff);
+ break;
+ }
+
+ return result;
+}
+
+
+WRITE8_HANDLER( astrocade_data_chip_register_w )
+{
+ /* these are the core registers */
+ switch (offset & 0xff)
+ {
+ case 0x00: /* color table is in registers 0-7 */
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ colors[offset & 7] = data;
+ break;
+
+ case 0x08: /* mode register */
+ video_mode = data & 1;
+ break;
+
+ case 0x09: /* color split pixel */
+ colorsplit = 2 * (data & 0x3f);
+ bgdata = ((data & 0xc0) >> 6) * 0x55;
+ break;
+
+ case 0x0a: /* vertical blank register */
+ vblank = data;
+ break;
+
+ case 0x0b: /* color block transfer */
+ colors[(offset >> 8) & 7] = data;
+ break;
+
+ case 0x0c: /* function generator */
+ funcgen_control = data;
+ funcgen_expand_count = 0; /* reset flip-flop for expand mode on write to this register */
+ funcgen_rotate_count = 0; /* reset counter for rotate mode on write to this register */
+ funcgen_shift_prev_data = 0; /* reset shift buffer on write to this register */
+ break;
+
+ case 0x0d: /* interrupt feedback */
+ interrupt_vector = data;
+ break;
+
+ case 0x0e: /* interrupt enable and mode */
+ interrupt_enable = data;
+ break;
+
+ case 0x0f: /* interrupt line */
+ interrupt_scanline = data;
+ break;
+
+ case 0x10: /* master oscillator register */
+ case 0x11: /* tone A frequency register */
+ case 0x12: /* tone B frequency register */
+ case 0x13: /* tone C frequency register */
+ case 0x14: /* vibrato register */
+ case 0x15: /* tone C volume, noise modulation and MUX register */
+ case 0x16: /* tone A volume and tone B volume register */
+ case 0x17: /* noise volume register */
+ case 0x18: /* sound block transfer */
+ if (astrocade_video_config & AC_SOUND_PRESENT)
+ astrocade_sound1_w(offset, data);
+ break;
+
+ case 0x19: /* expand register */
+ funcgen_expand_color[0] = data & 0x03;
+ funcgen_expand_color[1] = (data >> 2) & 0x03;
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Function generator
+ *
+ *************************************/
+
+WRITE8_HANDLER( astrocade_funcgen_w )
+{
+ UINT8 prev_data;
+
+ /* control register:
+ bit 0 = shift amount LSB
+ bit 1 = shift amount MSB
+ bit 2 = rotate
+ bit 3 = expand
+ bit 4 = OR
+ bit 5 = XOR
+ bit 6 = flop
+ */
+
+ /* expansion */
+ if (funcgen_control & 0x08)
+ {
+ funcgen_expand_count ^= 1;
+ data >>= 4 * funcgen_expand_count;
+ data = (funcgen_expand_color[(data >> 3) & 1] << 6) |
+ (funcgen_expand_color[(data >> 2) & 1] << 4) |
+ (funcgen_expand_color[(data >> 1) & 1] << 2) |
+ (funcgen_expand_color[(data >> 0) & 1] << 0);
+ }
+ prev_data = funcgen_shift_prev_data;
+ funcgen_shift_prev_data = data;
+
+ /* rotate or shift */
+ if (funcgen_control & 0x04)
+ {
+ /* rotate */
+
+ /* first 4 writes accumulate data for the rotate */
+ if ((funcgen_rotate_count & 4) == 0)
+ {
+ funcgen_rotate_data[funcgen_rotate_count++ & 3] = data;
+ return;
+ }
+
+ /* second 4 writes actually write it */
+ else
+ {
+ UINT8 shift = 2 * (~funcgen_rotate_count++ & 3);
+ data = (((funcgen_rotate_data[3] >> shift) & 3) << 6) |
+ (((funcgen_rotate_data[2] >> shift) & 3) << 4) |
+ (((funcgen_rotate_data[1] >> shift) & 3) << 2) |
+ (((funcgen_rotate_data[0] >> shift) & 3) << 0);
+ }
+ }
+ else
+ {
+ /* shift */
+ UINT8 shift = 2 * (funcgen_control & 0x03);
+ data = (data >> shift) | (prev_data << (8 - shift));
+ }
+
+ /* flopping */
+ if (funcgen_control & 0x40)
+ data = (data >> 6) | ((data >> 2) & 0x0c) | ((data << 2) & 0x30) | (data << 6);
+
+ /* OR/XOR */
+ if (funcgen_control & 0x30)
+ {
+ UINT8 olddata = program_read_byte_8(0x4000 + offset);
+
+ /* compute any intercepts */
+ funcgen_intercept &= 0x0f;
+ if ((olddata & 0xc0) && (data & 0xc0))
+ funcgen_intercept |= 0x11;
+ if ((olddata & 0x30) && (data & 0x30))
+ funcgen_intercept |= 0x22;
+ if ((olddata & 0x0c) && (data & 0x0c))
+ funcgen_intercept |= 0x44;
+ if ((olddata & 0x03) && (data & 0x03))
+ funcgen_intercept |= 0x88;
+
+ /* apply the operation */
+ if (funcgen_control & 0x10)
+ data |= olddata;
+ else if (funcgen_control & 0x20)
+ data ^= olddata;
+ }
+
+ /* write the result */
+ program_write_byte_8(0x4000 + offset, data);
+}
+
+
+
+/*************************************
+ *
+ * Pattern board
+ *
+ *************************************/
+
+INLINE void increment_source(UINT8 curwidth, UINT8 *u13ff)
+{
+ /* if the flip-flop at U13 is high and mode.d2 is 1 we can increment */
+ /* however, if mode.d3 is set and we're on the last byte of a row, the increment is suppressed */
+ if (*u13ff && (pattern_mode & 0x04) != 0 && (curwidth != 0 || (pattern_mode & 0x08) == 0))
+ pattern_source++;
+
+ /* if mode.d1 is 1, toggle the flip-flop; otherwise leave it preset */
+ if ((pattern_mode & 0x02) != 0)
+ *u13ff ^= 1;
+}
+
+
+INLINE void increment_dest(UINT8 curwidth)
+{
+ /* increment is suppressed for the last byte in a row */
+ if (curwidth != 0)
+ {
+ /* if mode.d5 is 1, we increment */
+ if ((pattern_mode & 0x20) != 0)
+ pattern_dest++;
+
+ /* otherwise, we decrement */
+ else
+ pattern_dest--;
+ }
+}
+
+
+static void execute_blit(void)
+{
+ /*
+ pattern_source = counter set U7/U16/U25/U34
+ pattern_dest = counter set U9/U18/U30/U39
+ pattern_mode = latch U21
+ pattern_skip = latch set U30/U39
+ pattern_width = latch set U32/U41
+ pattern_height = counter set U31/U40
+
+ pattern_mode bits:
+ d0 = direction (0 = read from src, write to dest, 1 = read from dest, write to src)
+ d1 = expand (0 = increment src each pixel, 1 = increment src every other pixel)
+ d2 = constant (0 = never increment src, 1 = normal src increment)
+ d3 = flush (0 = copy all data, 1 = copy a 0 in place of last byte of each row)
+ d4 = dest increment direction (0 = decrement dest on carry, 1 = increment dest on carry)
+ d5 = dest direction (0 = increment dest, 1 = decrement dest)
+ */
+
+ UINT8 curwidth; /* = counter set U33/U42 */
+ UINT8 u13ff; /* = flip-flop at U13 */
+ int cycles = 0;
+
+/* logerror("Blit: src=%04X mode=%02X dest=%04X skip=%02X width=%02X height=%02X\n",
+ pattern_source, pattern_mode, pattern_dest, pattern_skip, pattern_width, pattern_height);*/
+
+ /* flip-flop at U13 is cleared at the beginning */
+ u13ff = 0;
+
+ /* it is also forced preset if mode.d1 == 0 */
+ if ((pattern_mode & 0x02) == 0)
+ u13ff = 1;
+
+ /* loop over height */
+ do
+ {
+ UINT16 carry;
+
+ /* loop over width */
+ curwidth = pattern_width;
+ do
+ {
+ UINT16 busaddr;
+ UINT8 busdata;
+
+ /* ----- read phase ----- */
+
+ /* address is selected between source/dest based on mode.d0 */
+ busaddr = ((pattern_mode & 0x01) == 0) ? pattern_source : pattern_dest;
+
+ /* if mode.d3 is set, then the last byte fetched per row is forced to 0 */
+ if (curwidth == 0 && (pattern_mode & 0x08) != 0)
+ busdata = 0;
+ else
+ busdata = program_read_byte_8(busaddr);
+
+ /* increment the appropriate address */
+ if ((pattern_mode & 0x01) == 0)
+ increment_source(curwidth, &u13ff);
+ else
+ increment_dest(curwidth);
+
+ /* ----- write phase ----- */
+
+ /* address is selected between source/dest based on mode.d0 */
+ busaddr = ((pattern_mode & 0x01) != 0) ? pattern_source : pattern_dest;
+ program_write_byte_8(busaddr, busdata);
+
+ /* increment the appropriate address */
+ if ((pattern_mode & 0x01) == 0)
+ increment_dest(curwidth);
+ else
+ increment_source(curwidth, &u13ff);
+
+ /* count 4 cycles (two read, two write) */
+ cycles += 4;
+
+ } while (curwidth-- != 0);
+
+ /* at the end of each row, the skip value is added to the dest value */
+ carry = ((pattern_dest & 0xff) + pattern_skip) & 0x100;
+ pattern_dest = (pattern_dest & 0xff00) | ((pattern_dest + pattern_skip) & 0xff);
+
+ /* carry behavior into the top byte is controlled by mode.d4 */
+ if ((pattern_mode & 0x10) == 0)
+ pattern_dest += carry;
+ else
+ pattern_dest -= carry ^ 0x100;
+
+ } while (pattern_height-- != 0);
+
+ /* count cycles we ran the bus */
+ activecpu_adjust_icount(-cycles);
+}
+
+
+WRITE8_HANDLER( astrocade_pattern_board_w )
+{
+ switch (offset)
+ {
+ case 0: /* source offset low 8 bits */
+ pattern_source = (pattern_source & 0xff00) | (data << 0);
+ break;
+
+ case 1: /* source offset upper 8 bits */
+ pattern_source = (pattern_source & 0x00ff) | (data << 8);
+ break;
+
+ case 2: /* mode control; also clears low byte of dest */
+ pattern_mode = data & 0x3f;
+ pattern_dest &= 0xff00;
+ break;
+
+ case 3: /* skip value */
+ pattern_skip = data;
+ break;
+
+ case 4: /* dest offset upper 8 bits; also adds skip to low 8 bits */
+ pattern_dest = ((pattern_dest + pattern_skip) & 0xff) | (data << 8);
+ break;
+
+ case 5: /* width of blit */
+ pattern_width = data;
+ break;
+
+ case 6: /* height of blit and initiator */
+ pattern_height = data;
+ execute_blit();
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Sparkle/star circuit
+ *
+ *************************************/
+
+/*
+ Counters at U15/U16:
+ On VERTDR, load 0x33 into counters at U15/U16
+ On HORZDR, clock counters, stopping at overflow to 0x00 (prevents sparkle in VBLANK)
+
+ Shift registers at U17/U12/U11:
+ cleared on vertdr
+ clocked at 7M (pixel clock)
+ taps from bit 4, 8, 12, 16 control sparkle intensity
+
+ Shift registers at U17/U19/U18:
+ cleared on reset
+ clocked at 7M (pixel clock)
+ if bits 0-7 == 0xfe, a star is generated
+
+ Both shift registers are the same with identical feedback.
+ We use one array to hold both shift registers. Bits 0-3
+ bits hold the intensity, and bit 4 holds whether or not
+ a star is present.
+
+ We must use independent lookups for each case. For the star
+ lookup, we need to compute the pixel index relative to the
+ end of VBLANK and use that (which at 455*262 is guaranteed
+ to be less than RNG_PERIOD).
+
+ For the sparkle lookup, we need to compute the pixel index
+ relative to the beginning of time and use that, mod RNG_PERIOD.
+*/
+
+static void init_sparklestar(void)
+{
+ UINT32 shiftreg;
+ int i;
+
+ /* reset global sparkle state */
+ astrocade_sparkle[0] = astrocade_sparkle[1] = astrocade_sparkle[2] = astrocade_sparkle[3] = 0;
+
+ /* allocate memory for the sparkle/star array */
+ sparklestar = auto_malloc(RNG_PERIOD);
+
+ /* generate the data for the sparkle/star array */
+ for (shiftreg = i = 0; i < RNG_PERIOD; i++)
+ {
+ UINT8 newbit;
+
+ /* clock the shift register */
+ newbit = ((shiftreg >> 12) ^ ~shiftreg) & 1;
+ shiftreg = (shiftreg >> 1) | (newbit << 16);
+
+ /* extract the sparkle/star intensity here */
+ /* this is controlled by the shift register at U17/U19/U18 */
+ sparklestar[i] = (((shiftreg >> 4) & 1) << 3) |
+ (((shiftreg >> 12) & 1) << 2) |
+ (((shiftreg >> 16) & 1) << 1) |
+ (((shiftreg >> 8) & 1) << 0);
+
+ /* determine the star enable here */
+ /* this is controlled by the shift register at U17/U12/U11 */
+ if ((shiftreg & 0xff) == 0xfe)
+ sparklestar[i] |= 0x10;
+ }
+}
+
+
+
+/*************************************
+ *
+ * 16-color video board registers
+ *
+ *************************************/
+
+WRITE8_HANDLER( profpac_page_select_w )
+{
+ profpac_readpage = data & 3;
+ profpac_writepage = (data >> 2) & 3;
+ profpac_vispage = (data >> 4) & 3;
+}
+
+
+READ8_HANDLER( profpac_intercept_r )
+{
+ return profpac_intercept;
+}
+
+
+WRITE8_HANDLER( profpac_screenram_ctrl_w )
+{
+ switch (offset)
+ {
+ case 0: /* port 0xC0 - red component */
+ profpac_palette[data >> 4] = (profpac_palette[data >> 4] & ~0xf00) | ((data & 0x0f) << 8);
+ break;
+
+ case 1: /* port 0xC1 - green component */
+ profpac_palette[data >> 4] = (profpac_palette[data >> 4] & ~0x0f0) | ((data & 0x0f) << 4);
+ break;
+
+ case 2: /* port 0xC2 - blue component */
+ profpac_palette[data >> 4] = (profpac_palette[data >> 4] & ~0x00f) | ((data & 0x0f) << 0);
+ break;
+
+ case 3: /* port 0xC3 - set 2bpp to 4bpp mapping and clear intercepts */
+ profpac_colormap[(data >> 4) & 3] = data & 0x0f;
+ profpac_intercept = 0x00;
+ break;
+
+ case 4: /* port 0xC4 - which half to read on a memory access */
+ profpac_vw = data & 0x0f; /* refresh write enable lines TBD */
+ profpac_readshift = 2 * ((data >> 4) & 1);
+ break;
+
+ case 5: /* port 0xC5 - write enable and write mode */
+ profpac_writemask = ((data & 0x0f) << 12) | ((data & 0x0f) << 8) | ((data & 0x0f) << 4) | ((data & 0x0f) << 0);
+ profpac_writemode = (data >> 4) & 0x03;
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * 16-color video board VRAM access
+ *
+ *************************************/
+
+READ8_HANDLER( profpac_videoram_r )
+{
+ UINT16 temp = profpac_videoram[profpac_readpage * 0x4000 + offset] >> profpac_readshift;
+ return ((temp >> 6) & 0xc0) | ((temp >> 4) & 0x30) | ((temp >> 2) & 0x0c) | ((temp >> 0) & 0x03);
+}
+
+
+/* All this information comes from decoding the PLA at U39 on the screen ram board */
+WRITE8_HANDLER( profpac_videoram_w )
+{
+ UINT16 oldbits = profpac_videoram[profpac_writepage * 0x4000 + offset];
+ UINT16 newbits, result = 0;
+
+ /* apply the 2->4 bit expansion first */
+ newbits = (profpac_colormap[(data >> 6) & 3] << 12) |
+ (profpac_colormap[(data >> 4) & 3] << 8) |
+ (profpac_colormap[(data >> 2) & 3] << 4) |
+ (profpac_colormap[(data >> 0) & 3] << 0);
+
+ /* there are 4 write modes: overwrite, xor, overlay, or underlay */
+ switch (profpac_writemode)
+ {
+ case 0: /* normal write */
+ result = newbits;
+ break;
+
+ case 1: /* xor write */
+ result = newbits ^ oldbits;
+ break;
+
+ case 2: /* overlay write */
+ result = ((newbits & 0xf000) == 0) ? (oldbits & 0xf000) : (newbits & 0xf000);
+ result |= ((newbits & 0x0f00) == 0) ? (oldbits & 0x0f00) : (newbits & 0x0f00);
+ result |= ((newbits & 0x00f0) == 0) ? (oldbits & 0x00f0) : (newbits & 0x00f0);
+ result |= ((newbits & 0x000f) == 0) ? (oldbits & 0x000f) : (newbits & 0x000f);
+ break;
+
+ case 3: /* underlay write */
+ result = ((oldbits & 0xf000) != 0) ? (oldbits & 0xf000) : (newbits & 0xf000);
+ result |= ((oldbits & 0x0f00) != 0) ? (oldbits & 0x0f00) : (newbits & 0x0f00);
+ result |= ((oldbits & 0x00f0) != 0) ? (oldbits & 0x00f0) : (newbits & 0x00f0);
+ result |= ((oldbits & 0x000f) != 0) ? (oldbits & 0x000f) : (newbits & 0x000f);
+ break;
+ }
+
+ /* apply the write mask and store */
+ result = (result & profpac_writemask) | (oldbits & ~profpac_writemask);
+ profpac_videoram[profpac_writepage * 0x4000 + offset] = result;
+
+ /* Intercept (collision) stuff */
+
+ /* There are 3 bits on the register, which are set by various combinations of writes */
+ if (((oldbits & 0xf000) == 0x2000 && (newbits & 0x8000) == 0x8000) ||
+ ((oldbits & 0xf000) == 0x3000 && (newbits & 0xc000) == 0x4000) ||
+ ((oldbits & 0x0f00) == 0x0200 && (newbits & 0x0800) == 0x0800) ||
+ ((oldbits & 0x0f00) == 0x0300 && (newbits & 0x0c00) == 0x0400) ||
+ ((oldbits & 0x00f0) == 0x0020 && (newbits & 0x0080) == 0x0080) ||
+ ((oldbits & 0x00f0) == 0x0030 && (newbits & 0x00c0) == 0x0040) ||
+ ((oldbits & 0x000f) == 0x0002 && (newbits & 0x0008) == 0x0008) ||
+ ((oldbits & 0x000f) == 0x0003 && (newbits & 0x000c) == 0x0004))
+ profpac_intercept |= 0x01;
+
+ if (((newbits & 0xf000) != 0x0000 && (oldbits & 0xc000) == 0x4000) ||
+ ((newbits & 0x0f00) != 0x0000 && (oldbits & 0x0c00) == 0x0400) ||
+ ((newbits & 0x00f0) != 0x0000 && (oldbits & 0x00c0) == 0x0040) ||
+ ((newbits & 0x000f) != 0x0000 && (oldbits & 0x000c) == 0x0004))
+ profpac_intercept |= 0x02;
+
+ if (((newbits & 0xf000) != 0x0000 && (oldbits & 0x8000) == 0x8000) ||
+ ((newbits & 0x0f00) != 0x0000 && (oldbits & 0x0800) == 0x0800) ||
+ ((newbits & 0x00f0) != 0x0000 && (oldbits & 0x0080) == 0x0080) ||
+ ((newbits & 0x000f) != 0x0000 && (oldbits & 0x0008) == 0x0008))
+ profpac_intercept |= 0x04;
+}
diff --git a/src/mame/video/asuka.c b/src/mame/video/asuka.c
new file mode 100644
index 00000000000..dff8d0a7d70
--- /dev/null
+++ b/src/mame/video/asuka.c
@@ -0,0 +1,93 @@
+#include "driver.h"
+#include "video/taitoic.h"
+
+#define TC0100SCN_GFX_NUM 1
+
+
+/**********************************************************/
+
+static void asuka_core_video_start(running_machine *machine, int x_offs,int buffering)
+{
+ PC090OJ_vh_start(0,0,8,buffering); /* gfxset, x offset, y offset, buffering */
+ TC0100SCN_vh_start(machine,1,TC0100SCN_GFX_NUM,x_offs,0,0,0,0,0,0);
+ TC0110PCR_vh_start();
+}
+
+VIDEO_START( asuka )
+{
+ asuka_core_video_start(machine, 0,0);
+}
+
+VIDEO_START( galmedes )
+{
+ asuka_core_video_start(machine, 1,0);
+}
+
+VIDEO_START( cadash )
+{
+ asuka_core_video_start(machine, 1,1);
+}
+
+/**************************************************************
+ SPRITE READ AND WRITE HANDLERS
+**************************************************************/
+
+WRITE16_HANDLER( asuka_spritectrl_w )
+{
+ /* Bits 2-5 are color bank; in asuka games bit 0 is global priority */
+ PC090OJ_sprite_ctrl = ((data & 0x3c) >> 2) | ((data & 0x1) << 15);
+}
+
+
+/**************************************************************
+ SCREEN REFRESH
+**************************************************************/
+
+VIDEO_UPDATE( asuka )
+{
+ UINT8 layer[3];
+
+ TC0100SCN_tilemap_update(machine);
+
+ layer[0] = TC0100SCN_bottomlayer(0);
+ layer[1] = layer[0]^1;
+ layer[2] = 2;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* Ensure screen blanked even when bottom layer not drawn due to disable bit */
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0],TILEMAP_DRAW_OPAQUE,1);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[1],0,2);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[2],0,4);
+
+ /* Sprites may be over or under top bg layer */
+ PC090OJ_draw_sprites(machine,bitmap,cliprect,2);
+ return 0;
+}
+
+
+VIDEO_UPDATE( bonzeadv )
+{
+ UINT8 layer[3];
+
+ TC0100SCN_tilemap_update(machine);
+
+ layer[0] = TC0100SCN_bottomlayer(0);
+ layer[1] = layer[0]^1;
+ layer[2] = 2;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* Ensure screen blanked even when bottom layer not drawn due to disable bit */
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0],TILEMAP_DRAW_OPAQUE,1);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[1],0,2);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[2],0,4);
+
+ /* Sprites are always over both bg layers */
+ PC090OJ_draw_sprites(machine,bitmap,cliprect,0);
+ return 0;
+}
diff --git a/src/mame/video/atari.c b/src/mame/video/atari.c
new file mode 100644
index 00000000000..ca1166b42a0
--- /dev/null
+++ b/src/mame/video/atari.c
@@ -0,0 +1,1568 @@
+/******************************************************************************
+ Atari 400/800
+
+ Video handler
+
+ Juergen Buchmueller, June 1998
+******************************************************************************/
+
+#include "driver.h"
+#include "includes/atari.h"
+#include "video/gtia.h"
+
+#ifdef LSB_FIRST
+#define BYTE_XOR(n) (n)
+#else
+#define BYTE_XOR(n) ((n)^1)
+#endif
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x) /* x */
+#endif
+
+char atari_frame_message[64+1];
+int atari_frame_counter;
+
+/* flag for displaying television artifacts in ANTIC mode F (15) */
+static UINT32 tv_artifacts = 0;
+
+/*************************************************************************
+ * The priority tables tell which playfield, player or missile colors
+ * have precedence about the others, depending on the contents of the
+ * "prior" register. There are 64 possible priority selections.
+ * The table is here to make it easier to build the 'illegal' priority
+ * combinations that produce black or 'ILL' color.
+ *************************************************************************/
+
+/*************************************************************************
+ * calculate player/missile priorities (GTIA prior at $D00D)
+ * prior color priorities in descending order
+ * ------------------------------------------------------------------
+ * bit 0 PL0 PL1 PL2 PL3 PF0 PF1 PF2 PF3/P4 BK
+ * all players in front of all playfield colors
+ * bit 1 PL0 PL1 PF0 PF1 PF2 PF3/P4 PL2 PL3 BK
+ * pl 0+1 in front of pf 0-3 in front of pl 2+3
+ * bit 2 PF0 PF1 PF2 PF3/P4 PL0 PL1 PL2 PL3 BK
+ * all playfield colors in front of all players
+ * bit 3 PF0 PF1 PL0 PL1 PL2 PL3 PF2 PF3/P4 BK
+ * pf 0+1 in front of all players in front of pf 2+3
+ * bit 4 missiles colors are PF3 (P4)
+ * missiles have the same priority as pf3
+ * bit 5 PL0+PL1 and PL2+PL3 bits xored
+ * 00: playfield, 01: PL0/2, 10: PL1/3 11: black (EOR)
+ * bit 7+6 CTIA mod (00) or GTIA mode 1 to 3 (01, 10, 11)
+ *************************************************************************/
+
+/* player/missile #4 color is equal to playfield #3 */
+#define PM4 PF3
+
+/* bit masks for players and missiles */
+#define P0 0x01
+#define P1 0x02
+#define P2 0x04
+#define P3 0x08
+#define M0 0x10
+#define M1 0x20
+#define M2 0x40
+#define M3 0x80
+
+/************************************************************************
+ * Contents of the following table:
+ *
+ * PL0 -PL3 are the player/missile colors 0 to 3
+ * P000-P011 are the 4 available color clocks for playfield color 0
+ * P100-P111 are the 4 available color clocks for playfield color 1
+ * P200-P211 are the 4 available color clocks for playfield color 2
+ * P300-P311 are the 4 available color clocks for playfield color 3
+ * ILL is some undefined color. On my 800XL it looked light yellow ;)
+ *
+ * Each line holds the 8 bitmasks and resulting colors for player and
+ * missile number 0 to 3 in their fixed priority order.
+ * The 8 lines per block are for the 8 available playfield colors.
+ * Yes, 8 colors because the text modes 2,3 and graphics mode F can
+ * be combined with players. The result is the players color with
+ * luminance of the modes foreground (ie. colpf1).
+ * Any combination of players/missiles (256) is checked for the highest
+ * priority player or missile and the resulting color is stored into
+ * antic.prio_table. The second part (20-3F) contains the resulting
+ * color values for the EOR mode, which is derived from the *visible*
+ * player/missile colors calculated for the first part (00-1F).
+ * The priorities of combining priority bits (which games use!) are:
+ ************************************************************************/
+static UINT8 _pm_colors[32][8*2*8] = {
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 00
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 01
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 02
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, 0,P2, 0,M3, 0,P3, 0,
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, 0,P2, 0,M3, 0,P3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 03
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 04
+ M0, 0,P0, 0,M1, 0,P1, 0,M2, 0,P2, 0,M3, 0,P3, 0,
+ M0, 0,P0, 0,M1, 0,P1, 0,M2, 0,P2, 0,M3, 0,P3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 05
+ M0, ILL,P0, ILL,M1, ILL,P1, ILL,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
+ M0, 0,P0, 0,M1, 0,P1, 0,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 06
+ M0, 0,P0, ILL,M1, 0,P1, ILL,M2, 0,P2, 0,M3, 0,P3, 0,
+ M0, 0,P0, 0,M1, 0,P1, 0,M2, 0,P2, 0,M3, 0,P3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 07
+ M0, ILL,P0, ILL,M1, ILL,P1, ILL,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
+ M0, 0,P0, 0,M1, 0,P1, 0,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 08
+ M0, 0,P0, 0,M1, 0,P1, 0,M2, 0,P2, 0,M3, 0,P3, 0,
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 09
+ M0, ILL,P0, ILL,M1, ILL,P1, ILL,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 0A
+ M0, ILL,P0, ILL,M1, ILL,P1, ILL,M2, 0,P2, 0,M3, 0,P3, 0,
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 0B
+ M0, ILL,P0, ILL,M1, ILL,P1, ILL,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 0C
+ M0, 0,P0, 0,M1, 0,P1, 0,M2, 0,P2, 0,M3, 0,P3, 0,
+ M0, 0,P0, 0,M1, 0,P1, 0,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 0D
+ M0, 0,P0, 0,M1, 0,P1, 0,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
+ M0, 0,P0, 0,M1, 0,P1, 0,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 0E
+ M0, 0,P0, 0,M1, 0,P1, 0,M2, 0,P2, 0,M3, 0,P3, 0,
+ M0, 0,P0, 0,M1, 0,P1, 0,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 0F
+ M0, 0,P0, 0,M1, 0,P1, 0,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
+ M0, 0,P0, 0,M1, 0,P1, 0,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
+ M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
+ M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
+ M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
+ },
+ {
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 10
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
+ P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
+ P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
+ P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
+ },
+ {
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 11
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
+ P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
+ P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
+ P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
+ },
+ {
+ P0, PL0,P1, PL1,M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2, PL2,P3, PL3, // 12
+ P0, PL0,P1, PL1,M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2, 0,P3, 0,
+ P0, PL0,P1, PL1,M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2, 0,P3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ P0,P000,P1,P100,M0,P400,M1,P400,M2,P400,M3,P400,P2,P200,P3,P300,
+ P0,P001,P1,P101,M0,P401,M1,P401,M2,P401,M3,P401,P2,P201,P3,P301,
+ P0,P010,P1,P110,M0,P410,M1,P410,M2,P410,M3,P410,P2,P210,P3,P310,
+ P0,P011,P1,P111,M0,P411,M1,P411,M2,P411,M3,P411,P2,P211,P3,P311
+ },
+ {
+ P0, PL0,P1, PL1,M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2, PL2,P3, PL3, // 13
+ P0, PL0,P1, PL1,M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2, PL2,P3, PL3,
+ P0, PL0,P1, PL1,M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2, ILL,P3, ILL,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ P0,P000,P1,P100,M0,P400,M1,P400,M2,P400,M3,P400,P2,P200,P3,P300,
+ P0,P001,P1,P101,M0,P401,M1,P401,M2,P401,M3,P401,P2,P201,P3,P301,
+ P0,P010,P1,P110,M0,P410,M1,P410,M2,P410,M3,P410,P2,P210,P3,P310,
+ P0,P011,P1,P111,M0,P411,M1,P411,M2,P411,M3,P411,P2,P211,P3,P311
+ },
+ {
+ M0, PM4,M1, PM4,M2, PM4,M3, PM4,P0, PL0,P1, PL1,P2, PL2,P3, PL3, // 14
+ M0, PM4,M1, PM4,M2, PM4,M3, PM4,P0, 0,P1, 0,P2, 0,P3, 0,
+ M0, PM4,M1, PM4,M2, PM4,M3, PM4,P0, 0,P1, 0,P2, 0,P3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P400,M1,P400,M2,P400,M3,P400,P0,P000,P1,P100,P2,P200,P3,P300,
+ M0,P401,M1,P401,M2,P401,M3,P401,P0,P001,P1,P101,P2,P201,P3,P301,
+ M0,P410,M1,P410,M2,P410,M3,P410,P0,P010,P1,P110,P2,P210,P3,P310,
+ M0,P411,M1,P411,M2,P411,M3,P411,P0,P011,P1,P111,P2,P211,P3,P311
+ },
+ {
+ M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2,P0, PL0,P1, PL1, PL2,P3, PL3, // 15
+ M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2,P0, ILL,P1, ILL, PL2,P3, PL3,
+ M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2,P0, 0,P1, 0, ILL,P3, ILL,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,M1,P100,M2,P200,M3,P300,P2,P0,P000,P1,P100,P200,P3,P300,
+ M0,P001,M1,P101,M2,P201,M3,P301,P2,P0,P001,P1,P101,P201,P3,P301,
+ M0,P010,M1,P110,M2,P210,M3,P310,P2,P0,P010,P1,P110,P210,P3,P310,
+ M0,P011,M1,P111,M2,P211,M3,P311,P2,P0,P011,P1,P111,P211,P3,P311
+ },
+ {
+ M0, PM4,M1, PM4,M2, PM4,M3, PM4,P0, PL0,P1, PL1,P2, PL2,P3, PL3, // 16
+ M0, PM4,M1, PM4,M2, PM4,M3, PM4,P0, ILL,P1, ILL,P2, 0,P3, 0,
+ M0, PM4,M1, PM4,M2, PM4,M3, PM4,P0, 0,P1, 0,P2, 0,P3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,M1,P100,M2,P200,M3,P300,P0,P000,P1,P100,P2,P200,P3,P300,
+ M0,P001,M1,P101,M2,P201,M3,P301,P0,P001,P1,P101,P2,P201,P3,P301,
+ M0,P010,M1,P110,M2,P210,M3,P310,P0,P010,P1,P110,P2,P210,P3,P310,
+ M0,P011,M1,P111,M2,P211,M3,P311,P0,P011,P1,P111,P2,P211,P3,P311
+ },
+ {
+ M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2,P0, PL0,P1, PL1, PL2,P3, PL3, // 17
+ M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2,P0, ILL,P1, ILL, PL2,P3, PL3,
+ M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2,P0, 0,P1, 0, ILL,P3, ILL,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ M0,P000,M1,P100,M2,P200,M3,P300,P2,P0,P000,P1,P100,P200,P3,P300,
+ M0,P001,M1,P101,M2,P201,M3,P301,P2,P0,P001,P1,P101,P201,P3,P301,
+ M0,P010,M1,P110,M2,P210,M3,P310,P2,P0,P010,P1,P110,P210,P3,P310,
+ M0,P011,M1,P111,M2,P211,M3,P311,P2,P0,P011,P1,P111,P211,P3,P311
+ },
+ {
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 18
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
+ P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
+ P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
+ P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
+ },
+ {
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 19
+ P0, ILL,P1, ILL,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ P0,P000,P1,P100,P2,P200,P3,P300,M0,P000,M1,P100,M2,P200,M3,P300,
+ P0,P001,P1,P101,P2,P201,P3,P301,M0,P001,M1,P101,M2,P201,M3,P301,
+ P0,P010,P1,P110,P2,P210,P3,P310,M0,P010,M1,P110,M2,P210,M3,P310,
+ P0,P011,P1,P111,P2,P211,P3,P311,M0,P011,M1,P111,M2,P211,M3,P311
+ },
+ {
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 1A
+ P0, ILL,P1, ILL,P2, 0,P3, 0,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ P0, PL0,P1, PL1,P2, ILL,P3, ILL,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
+ P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
+ P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
+ P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
+ },
+ {
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 1B
+ P0, ILL,P1, ILL,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ P0, PL0,P1, PL1,P2, ILL,P3, ILL,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
+ P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
+ P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
+ P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
+ },
+ {
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 1C
+ P0, 0,P1, 0,P2, 0,P3, 0,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ P0, 0,P1, 0,P2, ILL,P3, ILL,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
+ P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
+ P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
+ P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
+ },
+ {
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 1D
+ P0, 0,P1, 0,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ P0, 0,P1, 0,P2, ILL,P3, ILL,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
+ P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
+ P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
+ P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
+ },
+ {
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 1E
+ P0, 0,P1, 0,P2, 0,P3, 0,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ P0, 0,P1, 0,P2, ILL,P3, ILL,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
+ P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
+ P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
+ P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
+ },
+ {
+ P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 1F
+ P0, 0,P1, 0,P2, 0,P3, 0,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ P0, 0,P1, 0,P2, ILL,P3, ILL,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
+ P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
+ P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
+ P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
+ }
+};
+
+/************************************************************************
+ * prio_init
+ * Initialize player/missile priority lookup tables
+ ************************************************************************/
+static void prio_init(void)
+{
+ int i, j, pm, p, c;
+ UINT8 * prio;
+
+ /* 32 priority bit combinations */
+ for( i = 0; i < 32; i++ )
+ {
+ /* 8 playfield colors */
+ for( j = 0; j < 8; j++ )
+ {
+ prio = &_pm_colors[i][j*16];
+ /* 256 player/missile combinations to build */
+ for( pm = 0; pm < 256; pm++ )
+ {
+ c = PFD; /* assume playfield color */
+ for( p = 0; (c == PFD) && (p < 16); p += 2 )
+ {
+ if (((prio[p] & pm) == prio[p]) && (prio[p+1]))
+ c = prio[p+1];
+ }
+ antic.prio_table[i][(j << 8) + pm] = c;
+ if( (c==PL0 || c==P000 || c==P001 || c==P010 || c==P011) &&
+ (pm & (P0+P1))==(P0+P1))
+ c = EOR;
+ if( (c==PL2 || c==P200 || c==P201 || c==P210 || c==P211) &&
+ (pm & (P2+P3))==(P2+P3))
+ c = EOR;
+ antic.prio_table[32 + i][(j << 8) + pm] = c;
+ }
+ }
+ }
+}
+
+/************************************************************************
+ * cclk_init
+ * Initialize "color clock" lookup tables
+ ************************************************************************/
+static void cclk_init(void)
+{
+ static UINT8 _pf_21[4] = {T00,T01,T10,T11};
+ static UINT8 _pf_1b[4] = {G00,G01,G10,G11};
+ static UINT8 _pf_210b[4] = {PBK,PF0,PF1,PF2};
+ static UINT8 _pf_310b[4] = {PBK,PF0,PF1,PF3};
+ int i;
+ UINT8 * dst;
+
+ /* setup color translation for the ANTIC modes */
+ for( i = 0; i < 256; i++ )
+ {
+ /****** text mode (2,3) **********/
+ dst = (UINT8 *)&antic.pf_21[0x000+i];
+ *dst++ = _pf_21[(i>>6)&3];
+ *dst++ = _pf_21[(i>>4)&3];
+ *dst++ = _pf_21[(i>>2)&3];
+ *dst++ = _pf_21[(i>>0)&3];
+
+ /****** 4 color text (4,5) with pf2, D, E **********/
+ dst = (UINT8 *)&antic.pf_x10b[0x000+i];
+ *dst++ = _pf_210b[(i>>6)&3];
+ *dst++ = _pf_210b[(i>>4)&3];
+ *dst++ = _pf_210b[(i>>2)&3];
+ *dst++ = _pf_210b[(i>>0)&3];
+ dst = (UINT8 *)&antic.pf_x10b[0x100+i];
+ *dst++ = _pf_310b[(i>>6)&3];
+ *dst++ = _pf_310b[(i>>4)&3];
+ *dst++ = _pf_310b[(i>>2)&3];
+ *dst++ = _pf_310b[(i>>0)&3];
+
+ /****** pf0 color text (6,7), 9, B, C **********/
+ dst = (UINT8 *)&antic.pf_3210b2[0x000+i*2];
+ *dst++ = (i&0x80)?PF0:PBK;
+ *dst++ = (i&0x40)?PF0:PBK;
+ *dst++ = (i&0x20)?PF0:PBK;
+ *dst++ = (i&0x10)?PF0:PBK;
+ *dst++ = (i&0x08)?PF0:PBK;
+ *dst++ = (i&0x04)?PF0:PBK;
+ *dst++ = (i&0x02)?PF0:PBK;
+ *dst++ = (i&0x01)?PF0:PBK;
+
+ /****** pf1 color text (6,7), 9, B, C **********/
+ dst = (UINT8 *)&antic.pf_3210b2[0x200+i*2];
+ *dst++ = (i&0x80)?PF1:PBK;
+ *dst++ = (i&0x40)?PF1:PBK;
+ *dst++ = (i&0x20)?PF1:PBK;
+ *dst++ = (i&0x10)?PF1:PBK;
+ *dst++ = (i&0x08)?PF1:PBK;
+ *dst++ = (i&0x04)?PF1:PBK;
+ *dst++ = (i&0x02)?PF1:PBK;
+ *dst++ = (i&0x01)?PF1:PBK;
+
+ /****** pf2 color text (6,7), 9, B, C **********/
+ dst = (UINT8 *)&antic.pf_3210b2[0x400+i*2];
+ *dst++ = (i&0x80)?PF2:PBK;
+ *dst++ = (i&0x40)?PF2:PBK;
+ *dst++ = (i&0x20)?PF2:PBK;
+ *dst++ = (i&0x10)?PF2:PBK;
+ *dst++ = (i&0x08)?PF2:PBK;
+ *dst++ = (i&0x04)?PF2:PBK;
+ *dst++ = (i&0x02)?PF2:PBK;
+ *dst++ = (i&0x01)?PF2:PBK;
+
+ /****** pf3 color text (6,7), 9, B, C **********/
+ dst = (UINT8 *)&antic.pf_3210b2[0x600+i*2];
+ *dst++ = (i&0x80)?PF3:PBK;
+ *dst++ = (i&0x40)?PF3:PBK;
+ *dst++ = (i&0x20)?PF3:PBK;
+ *dst++ = (i&0x10)?PF3:PBK;
+ *dst++ = (i&0x08)?PF3:PBK;
+ *dst++ = (i&0x04)?PF3:PBK;
+ *dst++ = (i&0x02)?PF3:PBK;
+ *dst++ = (i&0x01)?PF3:PBK;
+
+ /****** 4 color graphics 4 cclks (8) **********/
+ dst = (UINT8 *)&antic.pf_210b4[i*4];
+ *dst++ = _pf_210b[(i>>6)&3];
+ *dst++ = _pf_210b[(i>>6)&3];
+ *dst++ = _pf_210b[(i>>6)&3];
+ *dst++ = _pf_210b[(i>>6)&3];
+ *dst++ = _pf_210b[(i>>4)&3];
+ *dst++ = _pf_210b[(i>>4)&3];
+ *dst++ = _pf_210b[(i>>4)&3];
+ *dst++ = _pf_210b[(i>>4)&3];
+ *dst++ = _pf_210b[(i>>2)&3];
+ *dst++ = _pf_210b[(i>>2)&3];
+ *dst++ = _pf_210b[(i>>2)&3];
+ *dst++ = _pf_210b[(i>>2)&3];
+ *dst++ = _pf_210b[(i>>0)&3];
+ *dst++ = _pf_210b[(i>>0)&3];
+ *dst++ = _pf_210b[(i>>0)&3];
+ *dst++ = _pf_210b[(i>>0)&3];
+
+ /****** 4 color graphics 2 cclks (A) **********/
+ dst = (UINT8 *)&antic.pf_210b2[i*2];
+ *dst++ = _pf_210b[(i>>6)&3];
+ *dst++ = _pf_210b[(i>>6)&3];
+ *dst++ = _pf_210b[(i>>4)&3];
+ *dst++ = _pf_210b[(i>>4)&3];
+ *dst++ = _pf_210b[(i>>2)&3];
+ *dst++ = _pf_210b[(i>>2)&3];
+ *dst++ = _pf_210b[(i>>0)&3];
+ *dst++ = _pf_210b[(i>>0)&3];
+
+ /****** high resolution graphics (F) **********/
+ dst = (UINT8 *)&antic.pf_1b[i];
+ *dst++ = _pf_1b[(i>>6)&3];
+ *dst++ = _pf_1b[(i>>4)&3];
+ *dst++ = _pf_1b[(i>>2)&3];
+ *dst++ = _pf_1b[(i>>0)&3];
+
+ /****** gtia mode 1 **********/
+ dst = (UINT8 *)&antic.pf_gtia1[i];
+ *dst++ = GT1+((i>>4)&15);
+ *dst++ = GT1+((i>>4)&15);
+ *dst++ = GT1+(i&15);
+ *dst++ = GT1+(i&15);
+
+ /****** gtia mode 2 **********/
+ dst = (UINT8 *)&antic.pf_gtia2[i];
+ *dst++ = GT2+((i>>4)&15);
+ *dst++ = GT2+((i>>4)&15);
+ *dst++ = GT2+(i&15);
+ *dst++ = GT2+(i&15);
+
+ /****** gtia mode 3 **********/
+ dst = (UINT8 *)&antic.pf_gtia3[i];
+ *dst++ = GT3+((i>>4)&15);
+ *dst++ = GT3+((i>>4)&15);
+ *dst++ = GT3+(i&15);
+ *dst++ = GT3+(i&15);
+
+ }
+
+ /* setup used color tables */
+ for( i = 0; i < 256; i++ )
+ {
+ /* used colors in text modes 2,3 */
+ antic.uc_21[i] = (i) ? PF2 | PF1 : PF2;
+
+ /* used colors in text modes 4,5 and graphics modes D,E */
+ switch( i & 0x03 )
+ {
+ case 0x01: antic.uc_x10b[0x000+i] |= PF0; antic.uc_x10b[0x100+i] |= PF0; break;
+ case 0x02: antic.uc_x10b[0x000+i] |= PF1; antic.uc_x10b[0x100+i] |= PF1; break;
+ case 0x03: antic.uc_x10b[0x000+i] |= PF2; antic.uc_x10b[0x100+i] |= PF3; break;
+ }
+ switch( i & 0x0c )
+ {
+ case 0x04: antic.uc_x10b[0x000+i] |= PF0; antic.uc_x10b[0x100+i] |= PF0; break;
+ case 0x08: antic.uc_x10b[0x000+i] |= PF1; antic.uc_x10b[0x100+i] |= PF1; break;
+ case 0x0c: antic.uc_x10b[0x000+i] |= PF2; antic.uc_x10b[0x100+i] |= PF3; break;
+ }
+ switch( i & 0x30 )
+ {
+ case 0x10: antic.uc_x10b[0x000+i] |= PF0; antic.uc_x10b[0x100+i] |= PF0; break;
+ case 0x20: antic.uc_x10b[0x000+i] |= PF1; antic.uc_x10b[0x100+i] |= PF1; break;
+ case 0x30: antic.uc_x10b[0x000+i] |= PF2; antic.uc_x10b[0x100+i] |= PF3; break;
+ }
+ switch( i & 0xc0 )
+ {
+ case 0x40: antic.uc_x10b[0x000+i] |= PF0; antic.uc_x10b[0x100+i] |= PF0; break;
+ case 0x80: antic.uc_x10b[0x000+i] |= PF1; antic.uc_x10b[0x100+i] |= PF1; break;
+ case 0xc0: antic.uc_x10b[0x000+i] |= PF2; antic.uc_x10b[0x100+i] |= PF3; break;
+ }
+
+ /* used colors in text modes 6,7 and graphics modes 9,B,C */
+ if( i )
+ {
+ antic.uc_3210b2[0x000+i*2] |= PF0;
+ antic.uc_3210b2[0x200+i*2] |= PF1;
+ antic.uc_3210b2[0x400+i*2] |= PF2;
+ antic.uc_3210b2[0x600+i*2] |= PF3;
+ }
+
+ /* used colors in graphics mode 8 */
+ switch( i & 0x03 )
+ {
+ case 0x01: antic.uc_210b4[i*4] |= PF0; break;
+ case 0x02: antic.uc_210b4[i*4] |= PF1; break;
+ case 0x03: antic.uc_210b4[i*4] |= PF2; break;
+ }
+ switch( i & 0x0c )
+ {
+ case 0x04: antic.uc_210b4[i*4] |= PF0; break;
+ case 0x08: antic.uc_210b4[i*4] |= PF1; break;
+ case 0x0c: antic.uc_210b4[i*4] |= PF2; break;
+ }
+ switch( i & 0x30 )
+ {
+ case 0x10: antic.uc_210b4[i*4] |= PF0; break;
+ case 0x20: antic.uc_210b4[i*4] |= PF1; break;
+ case 0x30: antic.uc_210b4[i*4] |= PF2; break;
+ }
+ switch( i & 0xc0 )
+ {
+ case 0x40: antic.uc_210b4[i*4] |= PF0; break;
+ case 0x80: antic.uc_210b4[i*4] |= PF1; break;
+ case 0xc0: antic.uc_210b4[i*4] |= PF2; break;
+ }
+
+ /* used colors in graphics mode A */
+ switch( i & 0x03 )
+ {
+ case 0x01: antic.uc_210b2[i*2] |= PF0; break;
+ case 0x02: antic.uc_210b2[i*2] |= PF1; break;
+ case 0x03: antic.uc_210b2[i*2] |= PF2; break;
+ }
+ switch( i & 0x0c )
+ {
+ case 0x04: antic.uc_210b2[i*2] |= PF0; break;
+ case 0x08: antic.uc_210b2[i*2] |= PF1; break;
+ case 0x0c: antic.uc_210b2[i*2] |= PF2; break;
+ }
+ switch( i & 0x30 )
+ {
+ case 0x10: antic.uc_210b2[i*2] |= PF0; break;
+ case 0x20: antic.uc_210b2[i*2] |= PF1; break;
+ case 0x30: antic.uc_210b2[i*2] |= PF2; break;
+ }
+ switch( i & 0xc0 )
+ {
+ case 0x40: antic.uc_210b2[i*2] |= PF0; break;
+ case 0x80: antic.uc_210b2[i*2] |= PF1; break;
+ case 0xc0: antic.uc_210b2[i*2] |= PF2; break;
+ }
+
+ /* used colors in graphics mode F */
+ if( i )
+ antic.uc_1b[i] |= PF1;
+
+ /* used colors in GTIA graphics modes */
+ /* GTIA 1 is 16 different luminances with hue of colbk */
+ antic.uc_g1[i] = 0x00;
+ /* GTIA 2 is all 9 colors (8..15 is colbk) */
+ switch( i & 0x0f )
+ {
+ case 0x00: antic.uc_g2[i] = 0x10; break;
+ case 0x01: antic.uc_g2[i] = 0x20; break;
+ case 0x02: antic.uc_g2[i] = 0x40; break;
+ case 0x03: antic.uc_g2[i] = 0x80; break;
+ case 0x04: antic.uc_g2[i] = 0x01; break;
+ case 0x05: antic.uc_g2[i] = 0x02; break;
+ case 0x06: antic.uc_g2[i] = 0x04; break;
+ case 0x07: antic.uc_g2[i] = 0x08; break;
+ default: antic.uc_g2[i] = 0x00;
+ }
+
+ /* GTIA 3 is 16 different hues with luminance of colbk */
+ antic.uc_g3[i] = 0x00;
+ }
+}
+
+/************************************************************************
+ * atari_vh_start
+ * Initialize the ATARI800 video emulation
+ ************************************************************************/
+VIDEO_START( atari )
+{
+ int i;
+
+ LOG(("atari antic_vh_start\n"));
+ memset(&antic, 0, sizeof(antic));
+
+ antic.cclk_expand = auto_malloc(21 * 256 * sizeof(UINT32));
+
+ antic.pf_21 = &antic.cclk_expand[ 0 * 256];
+ antic.pf_x10b = &antic.cclk_expand[ 1 * 256];
+ antic.pf_3210b2 = &antic.cclk_expand[ 3 * 256];
+ antic.pf_210b4 = &antic.cclk_expand[11 * 256];
+ antic.pf_210b2 = &antic.cclk_expand[15 * 256];
+ antic.pf_1b = &antic.cclk_expand[17 * 256];
+ antic.pf_gtia1 = &antic.cclk_expand[18 * 256];
+ antic.pf_gtia2 = &antic.cclk_expand[19 * 256];
+ antic.pf_gtia3 = &antic.cclk_expand[20 * 256];
+
+ antic.used_colors = auto_malloc(21 * 256 * sizeof(UINT8));
+
+ memset(antic.used_colors, 0, 21 * 256 * sizeof(UINT8));
+
+ antic.uc_21 = &antic.used_colors[ 0 * 256];
+ antic.uc_x10b = &antic.used_colors[ 1 * 256];
+ antic.uc_3210b2 = &antic.used_colors[ 3 * 256];
+ antic.uc_210b4 = &antic.used_colors[11 * 256];
+ antic.uc_210b2 = &antic.used_colors[15 * 256];
+ antic.uc_1b = &antic.used_colors[17 * 256];
+ antic.uc_g1 = &antic.used_colors[18 * 256];
+ antic.uc_g2 = &antic.used_colors[19 * 256];
+ antic.uc_g3 = &antic.used_colors[20 * 256];
+
+ /* reset the ANTIC color tables */
+ for( i = 0; i < 256; i ++ )
+ antic.color_lookup[i] = (machine->pens[0] << 8) + machine->pens[0];
+
+ LOG(("atari cclk_init\n"));
+ cclk_init();
+
+ for( i = 0; i < 64; i++ )
+ {
+ antic.prio_table[i] = auto_malloc(8*256);
+ }
+
+ LOG(("atari prio_init\n"));
+ prio_init();
+
+ for( i = 0; i < machine->screen[0].height; i++ )
+ {
+ antic.video[i] = auto_malloc(sizeof(VIDEO));
+ memset(antic.video[i], 0, sizeof(VIDEO));
+ }
+
+ video_start_generic_bitmapped(machine);
+}
+
+/************************************************************************
+ * atari_vh_screenrefresh
+ * Refresh screen bitmap.
+ * Note: Actual drawing is done scanline wise during atari_interrupt
+ ************************************************************************/
+VIDEO_UPDATE( atari )
+{
+ UINT32 new_tv_artifacts;
+
+ video_update_generic_bitmapped(machine, screen, bitmap, cliprect);
+
+ new_tv_artifacts = readinputportbytag_safe("artifacts", 0);
+ if( tv_artifacts != new_tv_artifacts )
+ {
+ tv_artifacts = new_tv_artifacts;
+ }
+ if( atari_frame_counter > 0 )
+ {
+ if( --atari_frame_counter )
+ {
+// ui_draw_text(atari_frame_message, 0, height - 10);
+ }
+ }
+ return 0;
+}
+
+static renderer_function antic_renderer = antic_mode_0_xx;
+
+static void artifacts_gfx(UINT8 *src, UINT8 *dst, int width)
+{
+ int x;
+ UINT8 n, bits = 0;
+ UINT8 b = gtia.w.colbk & 0xf0;
+ UINT8 c = gtia.w.colpf1 & 0x0f;
+ UINT8 atari_A = Machine->remapped_colortable[((b+0x30)&0xf0)+c];
+ UINT8 atari_B = Machine->remapped_colortable[((b+0x70)&0xf0)+c];
+ UINT8 atari_C = Machine->remapped_colortable[b+c];
+ UINT8 atari_D = Machine->remapped_colortable[gtia.w.colbk];
+
+ for( x = 0; x < width * 4; x++ )
+ {
+ n = *src++;
+ bits <<= 2;
+ switch( n )
+ {
+ case G00:
+ break;
+ case G01:
+ bits |= 1;
+ break;
+ case G10:
+ bits |= 2;
+ break;
+ case G11:
+ bits |= 3;
+ break;
+ default:
+ *dst++ = antic.color_lookup[n];
+ *dst++ = antic.color_lookup[n];
+ continue;
+ }
+ switch( (bits >> 1) & 7 )
+ {
+ case 0: /* 0 0 0 */
+ case 1: /* 0 0 1 */
+ case 4: /* 1 0 0 */
+ *dst++ = atari_D;
+ break;
+ case 3: /* 0 1 1 */
+ case 6: /* 1 1 0 */
+ case 7: /* 1 1 1 */
+ *dst++ = atari_C;
+ break;
+ case 2: /* 0 1 0 */
+ *dst++ = atari_B;
+ break;
+ case 5: /* 1 0 1 */
+ *dst++ = atari_A;
+ break;
+ }
+ switch( bits & 7 )
+ {
+ case 0: /* 0 0 0 */
+ case 1: /* 0 0 1 */
+ case 4: /* 1 0 0 */
+ *dst++ = atari_D;
+ break;
+ case 3: /* 0 1 1 */
+ case 6: /* 1 1 0 */
+ case 7: /* 1 1 1 */
+ *dst++ = atari_C;
+ break;
+ case 2: /* 0 1 0 */
+ *dst++ = atari_A;
+ break;
+ case 5: /* 1 0 1 */
+ *dst++ = atari_B;
+ break;
+ }
+ }
+}
+
+static void artifacts_txt(UINT8 * src, UINT8 * dst, int width)
+{
+ int x;
+ UINT8 n, bits = 0;
+ UINT8 b = gtia.w.colpf2 & 0xf0;
+ UINT8 c = gtia.w.colpf1 & 0x0f;
+ UINT8 atari_A = Machine->remapped_colortable[((b+0x30)&0xf0)+c];
+ UINT8 atari_B = Machine->remapped_colortable[((b+0x70)&0xf0)+c];
+ UINT8 atari_C = Machine->remapped_colortable[b+c];
+ UINT8 atari_D = Machine->remapped_colortable[gtia.w.colpf2];
+
+ for( x = 0; x < width * 4; x++ )
+ {
+ n = *src++;
+ bits <<= 2;
+ switch( n )
+ {
+ case T00:
+ break;
+ case T01:
+ bits |= 1;
+ break;
+ case T10:
+ bits |= 2;
+ break;
+ case T11:
+ bits |= 3;
+ break;
+ default:
+ *dst++ = antic.color_lookup[n];
+ *dst++ = antic.color_lookup[n];
+ continue;
+ }
+ switch( (bits >> 1) & 7 )
+ {
+ case 0: /* 0 0 0 */
+ case 1: /* 0 0 1 */
+ case 4: /* 1 0 0 */
+ *dst++ = atari_D;
+ break;
+ case 3: /* 0 1 1 */
+ case 6: /* 1 1 0 */
+ case 7: /* 1 1 1 */
+ *dst++ = atari_C;
+ break;
+ case 2: /* 0 1 0 */
+ *dst++ = atari_A;
+ break;
+ case 5: /* 1 0 1 */
+ *dst++ = atari_B;
+ break;
+ }
+ switch( bits & 7 )
+ {
+ case 0:/* 0 0 0 */
+ case 1:/* 0 0 1 */
+ case 4:/* 1 0 0 */
+ *dst++ = atari_D;
+ break;
+ case 3: /* 0 1 1 */
+ case 6: /* 1 1 0 */
+ case 7: /* 1 1 1 */
+ *dst++ = atari_C;
+ break;
+ case 2: /* 0 1 0 */
+ *dst++ = atari_B;
+ break;
+ case 5: /* 1 0 1 */
+ *dst++ = atari_A;
+ break;
+ }
+ }
+}
+
+
+static void antic_linerefresh(void)
+{
+ int x, y;
+ UINT8 *src;
+ UINT32 *dst;
+ UINT32 scanline[4 + (HCHARS * 2) + 4];
+
+ /* increment the scanline */
+ if( ++antic.scanline == Machine->screen[0].height )
+ {
+ /* and return to the top if the frame was complete */
+ antic.scanline = 0;
+ antic.modelines = 0;
+ /* count frames gone since last write to hitclr */
+ gtia.h.hitclr_frames++;
+ }
+
+ if( antic.scanline < MIN_Y || antic.scanline > MAX_Y )
+ return;
+
+ y = antic.scanline - MIN_Y;
+ src = &antic.cclock[PMOFFSET - antic.hscrol_old + 12];
+ dst = scanline;
+
+ if( tv_artifacts )
+ {
+ if( (antic.cmd & 0x0f) == 2 || (antic.cmd & 0x0f) == 3 )
+ {
+ artifacts_txt(src, (UINT8*)(dst + 3), HCHARS);
+ return;
+ }
+ else
+ if( (antic.cmd & 0x0f) == 15 )
+ {
+ artifacts_gfx(src, (UINT8*)(dst + 3), HCHARS);
+ return;
+ }
+ }
+ dst[0] = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+ dst[1] = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+ dst[2] = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+ if ( (antic.cmd & ANTIC_HSCR) == 0 || (antic.pfwidth == 48) || (antic.pfwidth == 32))
+ {
+ /* no hscroll */
+ dst[3] = antic.color_lookup[src[BYTE_XOR(0)]] | antic.color_lookup[src[BYTE_XOR(1)]] << 16;
+ src += 2;
+ dst += 4;
+ for( x = 1; x < HCHARS-1; x++ )
+ {
+ *dst++ = antic.color_lookup[src[BYTE_XOR(0)]] | antic.color_lookup[src[BYTE_XOR(1)]] << 16;
+ *dst++ = antic.color_lookup[src[BYTE_XOR(2)]] | antic.color_lookup[src[BYTE_XOR(3)]] << 16;
+ src += 4;
+ }
+ dst[0] = antic.color_lookup[src[BYTE_XOR(0)]] | antic.color_lookup[src[BYTE_XOR(1)]] << 16;
+ }
+ else
+ {
+ /* if hscroll is enabled, more data are fetched by ANTIC, but it still renders playfield
+ of width defined by pfwidth. */
+ switch( antic.pfwidth )
+ {
+ case 0:
+ {
+ dst[3] = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+ dst += 4;
+ for ( x = 1; x < HCHARS-1; x++ )
+ {
+ *dst++ = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+ *dst++ = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+ }
+ dst[0] = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+ }
+ break;
+ /* support for narrow playfield (32) with horizontal scrolling should be added here */
+ case 40:
+ {
+ dst[3] = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+ dst += 4;
+ for ( x = 1; x < HCHARS-2; x++ )
+ {
+ if ( x == 1 )
+ {
+ *dst++ = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+ }
+ else
+ {
+ *dst++ = antic.color_lookup[src[BYTE_XOR(0)]] | antic.color_lookup[src[BYTE_XOR(1)]] << 16;
+ }
+ *dst++ = antic.color_lookup[src[BYTE_XOR(2)]] | antic.color_lookup[src[BYTE_XOR(3)]] << 16;
+ src += 4;
+ }
+ for ( ; x < HCHARS-1; x++ )
+ {
+ *dst++ = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+ *dst++ = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+ }
+ dst[0] = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+ }
+ break;
+ }
+ }
+ dst[1] = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+ dst[2] = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+ dst[3] = antic.color_lookup[PBK] | antic.color_lookup[PBK] << 16;
+
+ draw_scanline8(tmpbitmap, 12, y, sizeof(scanline), (const UINT8 *) scanline, Machine->pens, -1);
+}
+
+#if VERBOSE
+static int cycle(void)
+{
+ return video_screen_get_hpos(0) * CYCLES_PER_LINE / Machine->screen[0].width;
+}
+#endif
+
+static void after(int cycles, void (*function)(running_machine *machine, int), const char *funcname)
+{
+ attotime duration = attotime_make(0, attotime_to_attoseconds(video_screen_get_scan_period(0)) * cycles / CYCLES_PER_LINE);
+ (void)funcname;
+ LOG((" after %3d (%5.1f us) %s\n", cycles, attotime_to_double(duration) * 1.0e6, funcname));
+ timer_set(duration, 0, function);
+}
+
+static TIMER_CALLBACK( antic_issue_dli )
+{
+ if( antic.w.nmien & DLI_NMI )
+ {
+ LOG((" @cycle #%3d issue DLI\n", cycle()));
+ antic.r.nmist |= DLI_NMI;
+ cpunum_set_input_line(0, INPUT_LINE_NMI, PULSE_LINE);
+ }
+ else
+ {
+ LOG((" @cycle #%3d DLI not enabled\n", cycle()));
+ }
+}
+
+
+static renderer_function renderer[2][19][5] = {
+ /* no playfield narrow normal wide */
+ {
+ {antic_mode_0_xx,antic_mode_0_xx,antic_mode_0_xx,antic_mode_0_xx},
+ {antic_mode_0_xx,antic_mode_0_xx,antic_mode_0_xx,antic_mode_0_xx},
+ {antic_mode_0_xx,antic_mode_2_32,antic_mode_2_40,antic_mode_2_48},
+ {antic_mode_0_xx,antic_mode_3_32,antic_mode_3_40,antic_mode_3_48},
+ {antic_mode_0_xx,antic_mode_4_32,antic_mode_4_40,antic_mode_4_48},
+ {antic_mode_0_xx,antic_mode_5_32,antic_mode_5_40,antic_mode_5_48},
+ {antic_mode_0_xx,antic_mode_6_32,antic_mode_6_40,antic_mode_6_48},
+ {antic_mode_0_xx,antic_mode_7_32,antic_mode_7_40,antic_mode_7_48},
+ {antic_mode_0_xx,antic_mode_8_32,antic_mode_8_40,antic_mode_8_48},
+ {antic_mode_0_xx,antic_mode_9_32,antic_mode_9_40,antic_mode_9_48},
+ {antic_mode_0_xx,antic_mode_a_32,antic_mode_a_40,antic_mode_a_48},
+ {antic_mode_0_xx,antic_mode_b_32,antic_mode_b_40,antic_mode_b_48},
+ {antic_mode_0_xx,antic_mode_c_32,antic_mode_c_40,antic_mode_c_48},
+ {antic_mode_0_xx,antic_mode_d_32,antic_mode_d_40,antic_mode_d_48},
+ {antic_mode_0_xx,antic_mode_e_32,antic_mode_e_40,antic_mode_e_48},
+ {antic_mode_0_xx,antic_mode_f_32,antic_mode_f_40,antic_mode_f_48},
+ {antic_mode_0_xx, gtia_mode_1_32, gtia_mode_1_40, gtia_mode_1_48},
+ {antic_mode_0_xx, gtia_mode_2_32, gtia_mode_2_40, gtia_mode_2_48},
+ {antic_mode_0_xx, gtia_mode_3_32, gtia_mode_3_40, gtia_mode_3_48},
+ },
+ /* with hscrol enabled playfield width is +32 color clocks */
+ /* no playfield narrow->normal normal->wide wide->wide */
+ {
+ {antic_mode_0_xx,antic_mode_0_xx,antic_mode_0_xx,antic_mode_0_xx},
+ {antic_mode_0_xx,antic_mode_0_xx,antic_mode_0_xx,antic_mode_0_xx},
+ {antic_mode_0_xx,antic_mode_2_40,antic_mode_2_48,antic_mode_2_48},
+ {antic_mode_0_xx,antic_mode_3_40,antic_mode_3_48,antic_mode_3_48},
+ {antic_mode_0_xx,antic_mode_4_40,antic_mode_4_48,antic_mode_4_48},
+ {antic_mode_0_xx,antic_mode_5_40,antic_mode_5_48,antic_mode_5_48},
+ {antic_mode_0_xx,antic_mode_6_40,antic_mode_6_48,antic_mode_6_48},
+ {antic_mode_0_xx,antic_mode_7_40,antic_mode_7_48,antic_mode_7_48},
+ {antic_mode_0_xx,antic_mode_8_40,antic_mode_8_48,antic_mode_8_48},
+ {antic_mode_0_xx,antic_mode_9_40,antic_mode_9_48,antic_mode_9_48},
+ {antic_mode_0_xx,antic_mode_a_40,antic_mode_a_48,antic_mode_a_48},
+ {antic_mode_0_xx,antic_mode_b_40,antic_mode_b_48,antic_mode_b_48},
+ {antic_mode_0_xx,antic_mode_c_40,antic_mode_c_48,antic_mode_c_48},
+ {antic_mode_0_xx,antic_mode_d_40,antic_mode_d_48,antic_mode_d_48},
+ {antic_mode_0_xx,antic_mode_e_40,antic_mode_e_48,antic_mode_e_48},
+ {antic_mode_0_xx,antic_mode_f_40,antic_mode_f_48,antic_mode_f_48},
+ {antic_mode_0_xx, gtia_mode_1_40, gtia_mode_1_48, gtia_mode_1_48},
+ {antic_mode_0_xx, gtia_mode_2_40, gtia_mode_2_48, gtia_mode_2_48},
+ {antic_mode_0_xx, gtia_mode_3_40, gtia_mode_3_48, gtia_mode_3_48},
+ }
+};
+
+/*****************************************************************************
+ *
+ * Antic Line Done
+ *
+ *****************************************************************************/
+static TIMER_CALLBACK( antic_line_done )
+{
+ LOG((" @cycle #%3d antic_line_done\n", cycle()));
+ if( antic.w.wsync )
+ {
+ LOG((" @cycle #%3d release WSYNC\n", cycle()));
+ /* release the CPU if it was actually waiting for HSYNC */
+ cpu_trigger(TRIGGER_HSYNC);
+ /* and turn off the 'wait for hsync' flag */
+ antic.w.wsync = 0;
+ }
+ LOG((" @cycle #%3d release CPU\n", cycle()));
+ /* release the CPU (held for emulating cycles stolen by ANTIC DMA) */
+ cpu_trigger(TRIGGER_STEAL);
+
+ /* refresh the display (translate color clocks to pixels) */
+ antic_linerefresh();
+}
+
+/*****************************************************************************
+ *
+ * Antic Steal Cycles
+ * This is called once per scanline by a interrupt issued in the
+ * atari_scanline_render function. Set a new timer for the HSYNC
+ * position and release the CPU; but hold it again immediately until
+ * TRIGGER_HSYNC if WSYNC (D01A) was accessed
+ *
+ *****************************************************************************/
+static TIMER_CALLBACK( antic_steal_cycles )
+{
+ LOG((" @cycle #%3d steal %d cycles\n", cycle(), antic.steal_cycles));
+ after(antic.steal_cycles, antic_line_done, "antic_line_done");
+ antic.steal_cycles = 0;
+ cpunum_spinuntil_trigger( 0, TRIGGER_STEAL );
+}
+
+
+/*****************************************************************************
+ *
+ * Antic Scan Line Render
+ * Render the scanline to the scrbitmap buffer.
+ * Also transport player/missile data to the grafp and grafm registers
+ * of the GTIA if enabled (DMA_PLAYER or DMA_MISSILE)
+ *
+ *****************************************************************************/
+static TIMER_CALLBACK( antic_scanline_render )
+{
+ VIDEO *video = antic.video[antic.scanline];
+ LOG((" @cycle #%3d render mode $%X lines to go #%d\n", cycle(), (antic.cmd & 0x0f), antic.modelines));
+
+ (*antic_renderer)(video);
+
+ /* if player/missile graphics is enabled */
+ if( antic.scanline < 256 && (antic.w.dmactl & (DMA_PLAYER|DMA_MISSILE)) )
+ {
+ /* new player/missile graphics data for every scanline ? */
+ if( antic.w.dmactl & DMA_PM_DBLLINE )
+ {
+ /* transport missile data to GTIA ? */
+ if( antic.w.dmactl & DMA_MISSILE )
+ {
+ antic.steal_cycles += 1;
+ atari_gtia_w(0x11, RDPMGFXD(3*256));
+ }
+ /* transport player data to GTIA ? */
+ if( antic.w.dmactl & DMA_PLAYER )
+ {
+ antic.steal_cycles += 4;
+ atari_gtia_w(0x0d, RDPMGFXD(4*256));
+ atari_gtia_w(0x0e, RDPMGFXD(5*256));
+ atari_gtia_w(0x0f, RDPMGFXD(6*256));
+ atari_gtia_w(0x10, RDPMGFXD(7*256));
+ }
+ }
+ else
+ {
+ /* transport missile data to GTIA ? */
+ if( antic.w.dmactl & DMA_MISSILE )
+ {
+ if( (antic.scanline & 1) == 0 ) /* even line ? */
+ antic.steal_cycles += 1;
+ atari_gtia_w(0x11, RDPMGFXS(3*128));
+ }
+ /* transport player data to GTIA ? */
+ if( antic.w.dmactl & DMA_PLAYER )
+ {
+ if( (antic.scanline & 1) == 0 ) /* even line ? */
+ antic.steal_cycles += 4;
+ atari_gtia_w(0x0d, RDPMGFXS(4*128));
+ atari_gtia_w(0x0e, RDPMGFXS(5*128));
+ atari_gtia_w(0x0f, RDPMGFXS(6*128));
+ atari_gtia_w(0x10, RDPMGFXS(7*128));
+ }
+ }
+ }
+
+ gtia_render(video);
+
+ antic.steal_cycles += CYCLES_REFRESH;
+ LOG((" run CPU for %d cycles\n", CYCLES_HSYNC - CYCLES_HSTART - antic.steal_cycles));
+ after(CYCLES_HSYNC - CYCLES_HSTART - antic.steal_cycles, antic_steal_cycles, "antic_steal_cycles");
+}
+
+
+
+INLINE void LMS(int new_cmd)
+{
+ /**************************************************************
+ * If the LMS bit (load memory scan) of the current display
+ * list command is set, load the video source address from the
+ * following two bytes and split it up into video page/offset.
+ * Steal two more cycles from the CPU for fetching the address.
+ **************************************************************/
+ if( new_cmd & ANTIC_LMS )
+ {
+ int addr = RDANTIC();
+ antic.doffs = ++antic.doffs & DOFFS;
+ addr += 256 * RDANTIC();
+ antic.doffs = ++antic.doffs & DOFFS;
+ antic.vpage = addr & VPAGE;
+ antic.voffs = addr & VOFFS;
+ LOG((" LMS $%04x\n", addr));
+ /* steal two more clock cycles from the cpu */
+ antic.steal_cycles += 2;
+ }
+}
+
+/*****************************************************************************
+ *
+ * Antic Scan Line DMA
+ * This is called once per scanline from Atari Interrupt
+ * If the ANTIC DMA is active (DMA_ANTIC) and the scanline not inside
+ * the VBL range (VBL_START - TOTAL_LINES or 0 - VBL_END)
+ * check if all mode lines of the previous ANTIC command were done and
+ * if so, read a new command and set up the renderer function
+ *
+ *****************************************************************************/
+static void antic_scanline_dma(int param)
+{
+ LOG((" @cycle #%3d DMA fetch\n", cycle()));
+ if (antic.scanline == VBL_END)
+ antic.r.nmist &= ~VBL_NMI;
+ if( antic.w.dmactl & DMA_ANTIC )
+ {
+ if( antic.scanline >= VBL_END && antic.scanline < VBL_START )
+ {
+ if( antic.modelines <= 0 )
+ {
+ int h = 0, w = antic.w.dmactl & 3;
+ UINT8 vscrol_subtract = 0;
+ UINT8 new_cmd;
+
+ new_cmd = RDANTIC();
+ antic.doffs = ++antic.doffs & DOFFS;
+ /* steal at one clock cycle from the CPU for fetching the command */
+ antic.steal_cycles += 1;
+ LOG((" ANTIC CMD $%02x\n", new_cmd));
+ /* command 1 .. 15 ? */
+ if (new_cmd & ANTIC_MODE)
+ {
+ antic.w.chbasl = 0;
+ /* vertical scroll mode changed ? */
+ if( (antic.cmd ^ new_cmd) & ANTIC_VSCR )
+ {
+ /* vertical scroll activate now ? */
+ if( new_cmd & ANTIC_VSCR )
+ {
+ antic.vscrol_old =
+ vscrol_subtract =
+ antic.w.chbasl = antic.w.vscrol;
+ }
+ else
+ {
+ vscrol_subtract = ~antic.vscrol_old;
+ }
+ }
+ /* does this command have horizontal scroll enabled ? */
+ if( new_cmd & ANTIC_HSCR )
+ {
+ h = 1;
+ antic.hscrol_old = antic.w.hscrol;
+ }
+ else
+ {
+ antic.hscrol_old = 0;
+ }
+ }
+ /* Set the ANTIC mode renderer function */
+ antic_renderer = renderer[h][new_cmd & ANTIC_MODE][w];
+
+ switch( new_cmd & ANTIC_MODE )
+ {
+ case 0x00:
+ /* generate 1 .. 8 empty lines */
+ antic.modelines = ((new_cmd >> 4) & 7) + 1;
+ /* did the last ANTIC command have vertical scroll enabled ? */
+ if( antic.cmd & ANTIC_VSCR )
+ {
+ /* yes, generate vscrol_old additional empty lines */
+ antic.modelines += antic.vscrol_old;
+ }
+ /* leave only bit 7 (DLI) set in ANTIC command */
+ new_cmd &= ANTIC_DLI;
+ break;
+ case 0x01:
+ /* ANTIC "jump" with DLI: issue interrupt immediately */
+ if( new_cmd & ANTIC_DLI )
+ {
+ /* remove the DLI bit */
+ new_cmd &= ~ANTIC_DLI;
+ after(CYCLES_DLI_NMI, antic_issue_dli, "antic_issue_dli");
+ }
+ /* load memory scan bit set ? */
+ if( new_cmd & ANTIC_LMS )
+ {
+ int addr = RDANTIC();
+ antic.doffs = ++antic.doffs & DOFFS;
+ addr += 256 * RDANTIC();
+ antic.dpage = addr & DPAGE;
+ antic.doffs = addr & DOFFS;
+ /* produce empty scanlines until vblank start */
+ antic.modelines = VBL_START + 1 - antic.scanline;
+ if( antic.modelines < 0 )
+ antic.modelines = Machine->screen[0].height - antic.scanline;
+ LOG((" JVB $%04x\n", antic.dpage|antic.doffs));
+ }
+ else
+ {
+ int addr = RDANTIC();
+ antic.doffs = ++antic.doffs & DOFFS;
+ addr += 256 * RDANTIC();
+ antic.dpage = addr & DPAGE;
+ antic.doffs = addr & DOFFS;
+ /* produce a single empty scanline */
+ antic.modelines = 1;
+ LOG((" JMP $%04x\n", antic.dpage|antic.doffs));
+ }
+ break;
+ case 0x02:
+ LMS(new_cmd);
+ antic.chbase = (antic.w.chbash & 0xfc) << 8;
+ antic.modelines = 8 - (vscrol_subtract & 7);
+ if( antic.w.chactl & 4 ) /* decrement chbasl? */
+ antic.w.chbasl = antic.modelines - 1;
+ break;
+ case 0x03:
+ LMS(new_cmd);
+ antic.chbase = (antic.w.chbash & 0xfc) << 8;
+ antic.modelines = 10 - (vscrol_subtract & 9);
+ if( antic.w.chactl & 4 ) /* decrement chbasl? */
+ antic.w.chbasl = antic.modelines - 1;
+ break;
+ case 0x04:
+ LMS(new_cmd);
+ antic.chbase = (antic.w.chbash & 0xfc) << 8;
+ antic.modelines = 8 - (vscrol_subtract & 7);
+ if( antic.w.chactl & 4 ) /* decrement chbasl? */
+ antic.w.chbasl = antic.modelines - 1;
+ break;
+ case 0x05:
+ LMS(new_cmd);
+ antic.chbase = (antic.w.chbash & 0xfc) << 8;
+ antic.modelines = 16 - (vscrol_subtract & 15);
+ if( antic.w.chactl & 4 ) /* decrement chbasl? */
+ antic.w.chbasl = antic.modelines - 1;
+ break;
+ case 0x06:
+ LMS(new_cmd);
+ antic.chbase = (antic.w.chbash & 0xfe) << 8;
+ antic.modelines = 8 - (vscrol_subtract & 7);
+ if( antic.w.chactl & 4 ) /* decrement chbasl? */
+ antic.w.chbasl = antic.modelines - 1;
+ break;
+ case 0x07:
+ LMS(new_cmd);
+ antic.chbase = (antic.w.chbash & 0xfe) << 8;
+ antic.modelines = 16 - (vscrol_subtract & 15);
+ if( antic.w.chactl & 4 ) /* decrement chbasl? */
+ antic.w.chbasl = antic.modelines - 1;
+ break;
+ case 0x08:
+ LMS(new_cmd);
+ antic.modelines = 8 - (vscrol_subtract & 7);
+ break;
+ case 0x09:
+ LMS(new_cmd);
+ antic.modelines = 4 - (vscrol_subtract & 3);
+ break;
+ case 0x0a:
+ LMS(new_cmd);
+ antic.modelines = 4 - (vscrol_subtract & 3);
+ break;
+ case 0x0b:
+ LMS(new_cmd);
+ antic.modelines = 2 - (vscrol_subtract & 1);
+ break;
+ case 0x0c:
+ LMS(new_cmd);
+ antic.modelines = 1;
+ break;
+ case 0x0d:
+ LMS(new_cmd);
+ antic.modelines = 2 - (vscrol_subtract & 1);
+ break;
+ case 0x0e:
+ LMS(new_cmd);
+ antic.modelines = 1;
+ break;
+ case 0x0f:
+ LMS(new_cmd);
+ /* bits 6+7 of the priority select register determine */
+ /* if newer GTIA or plain graphics modes are used */
+ switch (gtia.w.prior >> 6)
+ {
+ case 0: break;
+ case 1: antic_renderer = renderer[h][16][w]; break;
+ case 2: antic_renderer = renderer[h][17][w]; break;
+ case 3: antic_renderer = renderer[h][18][w]; break;
+ }
+ antic.modelines = 1;
+ break;
+ }
+ /* set new (current) antic command */
+ antic.cmd = new_cmd;
+ }
+ }
+ else
+ {
+ LOG((" out of visible range\n"));
+ antic.cmd = 0x00;
+ antic_renderer = antic_mode_0_xx;
+ }
+ }
+ else
+ {
+ LOG((" DMA is off\n"));
+ antic.cmd = 0x00;
+ antic_renderer = antic_mode_0_xx;
+ }
+
+ antic.r.nmist &= ~DLI_NMI;
+ if( antic.modelines == 1 && (antic.cmd & antic.w.nmien & DLI_NMI) )
+ after(CYCLES_DLI_NMI, antic_issue_dli, "antic_issue_dli");
+
+ after(CYCLES_HSTART, antic_scanline_render, "antic_scanline_render");
+}
+
+/*****************************************************************************
+ *
+ * Generic Atari Interrupt Dispatcher
+ * This is called once per scanline and handles:
+ * vertical blank interrupt
+ * ANTIC DMA to possibly access the next display list command
+ *
+ *****************************************************************************/
+
+static void generic_atari_interrupt(void (*handle_keyboard)(void), int button_count)
+{
+ int button_port, i;
+
+ LOG(("ANTIC #%3d @cycle #%d scanline interrupt\n", antic.scanline, cycle()));
+
+ if( antic.scanline < VBL_START )
+ {
+ antic_scanline_dma(0);
+ return;
+ }
+
+ if( antic.scanline == VBL_START )
+ {
+ button_port = readinputportbytag_safe("djoy_b", 0);
+
+ /* specify buttons relevant to this Atari variant */
+ for (i = 0; i < button_count; i++)
+ {
+ if ((gtia.w.gractl & GTIA_TRIGGER) == 0)
+ gtia.r.but[i] = 1;
+ gtia.r.but[i] &= (button_port >> i) & 1;
+ }
+
+ /* specify buttons not relevant to this Atari variant */
+ for (i = button_count; i < 4; i++)
+ gtia.r.but[i] = 1;
+
+ handle_keyboard();
+
+ /* do nothing new for the rest of the frame */
+ antic.modelines = Machine->screen[0].height - VBL_START;
+ antic_renderer = antic_mode_0_xx;
+
+ /* if the CPU want's to be interrupted at vertical blank... */
+ if( antic.w.nmien & VBL_NMI )
+ {
+ LOG((" cause VBL NMI\n"));
+ /* set the VBL NMI status bit */
+ antic.r.nmist |= VBL_NMI;
+ cpunum_set_input_line(0, INPUT_LINE_NMI, PULSE_LINE);
+ }
+ }
+
+ /* refresh the display (translate color clocks to pixels) */
+ antic_linerefresh();
+}
+
+
+
+void a400_interrupt(void)
+{
+ generic_atari_interrupt(a800_handle_keyboard, 4);
+}
+
+void a800_interrupt(void)
+{
+ generic_atari_interrupt(a800_handle_keyboard, 4);
+}
+
+void a800xl_interrupt(void)
+{
+ generic_atari_interrupt(a800_handle_keyboard, 2);
+}
+
+void a5200_interrupt(void)
+{
+ generic_atari_interrupt(a5200_handle_keypads, 4);
+}
diff --git a/src/mame/video/atarifb.c b/src/mame/video/atarifb.c
new file mode 100644
index 00000000000..d483de49d91
--- /dev/null
+++ b/src/mame/video/atarifb.c
@@ -0,0 +1,190 @@
+/*************************************************************************
+
+ Atari Football hardware
+
+*************************************************************************/
+
+#include "driver.h"
+#include "atarifb.h"
+#include "ui.h"
+
+/* local */
+size_t atarifb_alphap1_vram_size;
+size_t atarifb_alphap2_vram_size;
+UINT8 *atarifb_alphap1_vram;
+UINT8 *atarifb_alphap2_vram;
+UINT8 *atarifb_scroll_register;
+
+
+static const rectangle bigfield_area = { 4*8, 34*8-1, 0*8, 32*8-1 };
+static const rectangle left_area = { 0*8, 3*8-1, 0*8, 32*8-1 };
+static const rectangle right_area = { 34*8, 38*8-1, 0*8, 32*8-1 };
+
+/***************************************************************************
+***************************************************************************/
+WRITE8_HANDLER( atarifb_alphap1_vram_w )
+{
+ atarifb_alphap1_vram[offset] = data;
+}
+
+WRITE8_HANDLER( atarifb_alphap2_vram_w )
+{
+ atarifb_alphap2_vram[offset] = data;
+}
+
+/***************************************************************************
+***************************************************************************/
+WRITE8_HANDLER( atarifb_scroll_w )
+{
+ *atarifb_scroll_register = data - 8;
+}
+
+
+VIDEO_UPDATE( atarifb )
+{
+ int offs,obj;
+ int sprite_bank;
+
+ /* Soccer uses a different graphics set for sprites */
+ if (atarifb_game == 4)
+ sprite_bank = 2;
+ else
+ sprite_bank = 1;
+
+ for (offs = atarifb_alphap1_vram_size - 1;offs >= 0;offs--)
+ {
+ int charcode;
+ int flipbit;
+ int disable;
+ int sx,sy;
+
+ sx = 8 * (offs / 32) + 35*8;
+ sy = 8 * (offs % 32) + 8;
+
+ charcode = atarifb_alphap1_vram[offs] & 0x3f;
+ flipbit = (atarifb_alphap1_vram[offs] & 0x40) >> 6;
+ disable = (atarifb_alphap1_vram[offs] & 0x80) >> 7;
+
+ if (!disable)
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ charcode, 0,
+ flipbit,flipbit,sx,sy,
+ &right_area,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ for (offs = atarifb_alphap2_vram_size - 1;offs >= 0;offs--)
+ {
+ int charcode;
+ int flipbit;
+ int disable;
+ int sx,sy;
+
+ sx = 8 * (offs / 32);
+ sy = 8 * (offs % 32) + 8;
+
+ charcode = atarifb_alphap2_vram[offs] & 0x3f;
+ flipbit = (atarifb_alphap2_vram[offs] & 0x40) >> 6;
+ disable = (atarifb_alphap2_vram[offs] & 0x80) >> 7;
+
+ if (!disable)
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ charcode, 0,
+ flipbit,flipbit,sx,sy,
+ &left_area,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int charcode;
+ int flipx,flipy;
+ int sx,sy;
+
+ dirtybuffer[offs]=0;
+
+ charcode = videoram[offs] & 0x3f;
+ flipx = (videoram[offs] & 0x40) >> 6;
+ flipy = (videoram[offs] & 0x80) >> 7;
+
+ sx = (8 * (offs % 32) - *atarifb_scroll_register);
+ sy = 8 * (offs / 32) + 8;
+
+ /* Soccer hack */
+ if (atarifb_game == 4)
+ {
+ sy += 8;
+ }
+
+ /* Baseball hack */
+ if (atarifb_game == 0x03) sx -= 8;
+
+ if (sx < 0) sx += 256;
+ if (sx > 255) sx -= 256;
+
+ drawgfx(tmpbitmap,machine->gfx[1],
+ charcode, 0,
+ flipx,flipy,sx,sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+
+ /* copy the character mapped graphics */
+ copybitmap(bitmap,tmpbitmap,0,0,8*3,0,&bigfield_area,TRANSPARENCY_NONE,0);
+
+ /* Draw our motion objects */
+ for (obj=0;obj<16;obj++)
+ {
+ int charcode;
+ int flipx,flipy;
+ int sx,sy;
+ int shade = 0;
+
+ sy = 255 - spriteram[obj*2 + 1];
+ if (sy == 255) continue;
+
+ charcode = spriteram[obj*2] & 0x3f;
+ flipx = (spriteram[obj*2] & 0x40);
+ flipy = (spriteram[obj*2] & 0x80);
+ sx = spriteram[obj*2 + 0x20] + 8*3;
+
+ /* Note on Atari Soccer: */
+ /* There are 3 sets of 2 bits each, where the 2 bits represent */
+ /* black, dk grey, grey and white. I think the 3 sets determine the */
+ /* color of each bit in the sprite, but I haven't implemented it that way. */
+ if (atarifb_game == 4)
+ {
+ shade = ((spriteram[obj*2+1 + 0x20]) & 0x07);
+
+ drawgfx(bitmap,machine->gfx[sprite_bank+1],
+ charcode, shade,
+ flipx,flipy,sx,sy,
+ &bigfield_area,TRANSPARENCY_PEN,0);
+
+ shade = ((spriteram[obj*2+1 + 0x20]) & 0x08) >> 3;
+ }
+
+ drawgfx(bitmap,machine->gfx[sprite_bank],
+ charcode, shade,
+ flipx,flipy,sx,sy,
+ &bigfield_area,TRANSPARENCY_PEN,0);
+
+ /* If this isn't soccer, handle the multiplexed sprites */
+ if (atarifb_game != 4)
+ {
+ /* The down markers are multiplexed by altering the y location during */
+ /* mid-screen. We'll fake it by essentially doing the same thing here. */
+ if ((charcode == 0x11) && (sy == 0x07))
+ {
+ sy = 0xf1; /* When multiplexed, it's 0x10...why? */
+ drawgfx(bitmap,machine->gfx[sprite_bank],
+ charcode, 0,
+ flipx,flipy,sx,sy,
+ &bigfield_area,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/atarig1.c b/src/mame/video/atarig1.c
new file mode 100644
index 00000000000..9b571586235
--- /dev/null
+++ b/src/mame/video/atarig1.c
@@ -0,0 +1,221 @@
+/***************************************************************************
+
+ Atari G1 hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "atarig1.h"
+
+
+
+/*************************************
+ *
+ * Globals we own
+ *
+ *************************************/
+
+UINT8 atarig1_pitfight;
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static int pfscroll_xoffset;
+static UINT16 current_control;
+static UINT8 playfield_tile_bank;
+static UINT16 playfield_xscroll;
+static UINT16 playfield_yscroll;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha[tile_index];
+ int code = data & 0xfff;
+ int color = (data >> 12) & 0x0f;
+ int opaque = data & 0x8000;
+ SET_TILE_INFO(1, code, color, opaque ? TILE_FORCE_LAYER0 : 0);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data = atarigen_playfield[tile_index];
+ int code = (playfield_tile_bank << 12) | (data & 0xfff);
+ int color = (data >> 12) & 7;
+ SET_TILE_INFO(0, code, color, (data >> 15) & 1);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( atarig1 )
+{
+ static const struct atarirle_desc modesc_hydra =
+ {
+ REGION_GFX3,/* region where the GFX data lives */
+ 256, /* number of entries in sprite RAM */
+ 0, /* left clip coordinate */
+ 255, /* right clip coordinate */
+
+ 0x200, /* base palette entry */
+ 0x100, /* maximum number of colors */
+
+ {{ 0x7fff,0,0,0,0,0,0,0 }}, /* mask for the code index */
+ {{ 0,0x00f0,0,0,0,0,0,0 }}, /* mask for the color */
+ {{ 0,0,0xffc0,0,0,0,0,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xffc0,0,0,0,0 }}, /* mask for the Y position */
+ {{ 0,0,0,0,0xffff,0,0,0 }}, /* mask for the scale factor */
+ {{ 0x8000,0,0,0,0,0,0,0 }}, /* mask for the horizontal flip */
+ {{ 0,0,0,0,0,0x00ff,0,0 }}, /* mask for the order */
+ {{ 0 }}, /* mask for the priority */
+ {{ 0 }} /* mask for the VRAM target */
+ };
+
+ static const struct atarirle_desc modesc_pitfight =
+ {
+ REGION_GFX3,/* region where the GFX data lives */
+ 256, /* number of entries in sprite RAM */
+ 40, /* left clip coordinate */
+ 295, /* right clip coordinate */
+
+ 0x200, /* base palette entry */
+ 0x100, /* maximum number of colors */
+
+ {{ 0x7fff,0,0,0,0,0,0,0 }}, /* mask for the code index */
+ {{ 0,0x00f0,0,0,0,0,0,0 }}, /* mask for the color */
+ {{ 0,0,0xffc0,0,0,0,0,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xffc0,0,0,0,0 }}, /* mask for the Y position */
+ {{ 0,0,0,0,0xffff,0,0,0 }}, /* mask for the scale factor */
+ {{ 0x8000,0,0,0,0,0,0,0 }}, /* mask for the horizontal flip */
+ {{ 0,0,0,0,0,0,0x00ff,0 }}, /* mask for the order */
+ {{ 0 }}, /* mask for the priority */
+ {{ 0 }} /* mask for the VRAM target */
+ };
+
+ /* blend the playfields and free the temporary one */
+ atarigen_blend_gfx(machine, 0, 2, 0x0f, 0x10);
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,64);
+
+ /* initialize the motion objects */
+ atarirle_init(0, atarig1_pitfight ? &modesc_pitfight : &modesc_hydra);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ tilemap_set_transparent_pen(atarigen_alpha_tilemap, 0);
+
+ /* reset statics */
+ current_control = 0;
+ pfscroll_xoffset = atarig1_pitfight ? 2 : 0;
+ playfield_tile_bank = 0;
+ playfield_xscroll = 0;
+ playfield_yscroll = 0;
+}
+
+
+
+/*************************************
+ *
+ * Periodic scanline updater
+ *
+ *************************************/
+
+WRITE16_HANDLER( atarig1_mo_control_w )
+{
+ logerror("MOCONT = %d (scan = %d)\n", data, video_screen_get_vpos(0));
+
+ /* set the control value */
+ COMBINE_DATA(&current_control);
+}
+
+
+void atarig1_scanline_update(running_machine *machine, int scrnum, int scanline)
+{
+ UINT16 *base = &atarigen_alpha[(scanline / 8) * 64 + 48];
+ int i;
+
+ //if (scanline == 0) logerror("-------\n");
+
+ /* keep in range */
+ if (base >= &atarigen_alpha[0x800])
+ return;
+
+ /* update the playfield scrolls */
+ for (i = 0; i < 8; i++)
+ {
+ UINT16 word;
+
+ /* first word controls horizontal scroll */
+ word = *base++;
+ if (word & 0x8000)
+ {
+ int newscroll = ((word >> 6) + pfscroll_xoffset) & 0x1ff;
+ if (newscroll != playfield_xscroll)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_set_scrollx(atarigen_playfield_tilemap, 0, newscroll);
+ playfield_xscroll = newscroll;
+ }
+ }
+
+ /* second word controls vertical scroll and tile bank */
+ word = *base++;
+ if (word & 0x8000)
+ {
+ int newscroll = ((word >> 6) - (scanline + i)) & 0x1ff;
+ int newbank = word & 7;
+ if (newscroll != playfield_yscroll)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, newscroll);
+ playfield_yscroll = newscroll;
+ }
+ if (newbank != playfield_tile_bank)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_mark_all_tiles_dirty(atarigen_playfield_tilemap);
+ playfield_tile_bank = newbank;
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( atarig1 )
+{
+ /* draw the playfield */
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+
+ /* copy the motion objects on top */
+ copybitmap(bitmap, atarirle_get_vram(0, 0), 0, 0, 0, 0, cliprect, TRANSPARENCY_PEN, 0);
+
+ /* add the alpha on top */
+ tilemap_draw(bitmap, cliprect, atarigen_alpha_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/atarig42.c b/src/mame/video/atarig42.c
new file mode 100644
index 00000000000..b0f08f43825
--- /dev/null
+++ b/src/mame/video/atarig42.c
@@ -0,0 +1,266 @@
+/***************************************************************************
+
+ Atari G42 hardware
+
+*****************************************************************************
+
+ MO data has 12 bits total: MVID0-11
+ MVID9-11 form the priority
+ MVID0-9 form the color bits
+
+ PF data has 13 bits total: PF.VID0-12
+ PF.VID10-12 form the priority
+ PF.VID0-9 form the color bits
+
+ Upper bits come from the low 5 bits of the HSCROLL value in alpha RAM
+ Playfield bank comes from low 2 bits of the VSCROLL value in alpha RAM
+ For GX2, there are 4 bits of bank
+
+****************************************************************************/
+
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "atarig42.h"
+
+
+
+/*************************************
+ *
+ * Globals we own
+ *
+ *************************************/
+
+UINT16 atarig42_playfield_base;
+UINT16 atarig42_motion_object_base;
+UINT16 atarig42_motion_object_mask;
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static UINT16 current_control;
+static UINT8 playfield_tile_bank;
+static UINT8 playfield_color_bank;
+static UINT16 playfield_xscroll;
+static UINT16 playfield_yscroll;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha[tile_index];
+ int code = data & 0xfff;
+ int color = (data >> 12) & 0x0f;
+ int opaque = data & 0x8000;
+ SET_TILE_INFO(1, code, color, opaque ? TILE_FORCE_LAYER0 : 0);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data = atarigen_playfield[tile_index];
+ int code = (playfield_tile_bank << 12) | (data & 0xfff);
+ int color = (atarig42_playfield_base >> 5) + ((playfield_color_bank << 3) & 0x18) + ((data >> 12) & 7);
+ SET_TILE_INFO(0, code, color, (data >> 15) & 1);
+ tileinfo->category = (playfield_color_bank >> 2) & 7;
+}
+
+
+static TILEMAP_MAPPER( atarig42_playfield_scan )
+{
+ int bank = 1 - (col / (num_cols / 2));
+ return bank * (num_rows * num_cols / 2) + row * (num_cols / 2) + (col % (num_cols / 2));
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( atarig42 )
+{
+ static const struct atarirle_desc modesc =
+ {
+ REGION_GFX3,/* region where the GFX data lives */
+ 256, /* number of entries in sprite RAM */
+ 0, /* left clip coordinate */
+ 0, /* right clip coordinate */
+
+ 0x000, /* base palette entry */
+ 0x400, /* maximum number of colors */
+
+ {{ 0x7fff,0,0,0,0,0,0,0 }}, /* mask for the code index */
+ {{ 0,0x03f0,0,0,0,0,0,0 }}, /* mask for the color */
+ {{ 0,0,0xffc0,0,0,0,0,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xffc0,0,0,0,0 }}, /* mask for the Y position */
+ {{ 0,0,0,0,0xffff,0,0,0 }}, /* mask for the scale factor */
+ {{ 0x8000,0,0,0,0,0,0,0 }}, /* mask for the horizontal flip */
+ {{ 0,0,0,0,0,0,0x00ff,0 }}, /* mask for the order */
+ {{ 0,0x0e00,0,0,0,0,0,0 }}, /* mask for the priority */
+ {{ 0 }} /* mask for the VRAM target */
+ };
+ struct atarirle_desc adjusted_modesc = modesc;
+ int i;
+
+ /* blend the playfields and free the temporary one */
+ atarigen_blend_gfx(machine, 0, 2, 0x0f, 0x30);
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, atarig42_playfield_scan, TILEMAP_TYPE_PEN, 8,8, 128,64);
+
+ /* initialize the motion objects */
+ adjusted_modesc.palettebase = atarig42_motion_object_base;
+ for (i = 0; i < 8; i++)
+ adjusted_modesc.colormask.data[i] &= atarig42_motion_object_mask;
+ atarirle_init(0, &adjusted_modesc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ tilemap_set_transparent_pen(atarigen_alpha_tilemap, 0);
+
+ /* reset statics */
+ current_control = 0;
+ playfield_tile_bank = 0;
+ playfield_color_bank = 0;
+ playfield_xscroll = 0;
+ playfield_yscroll = 0;
+}
+
+
+
+/*************************************
+ *
+ * Periodic scanline updater
+ *
+ *************************************/
+
+WRITE16_HANDLER( atarig42_mo_control_w )
+{
+ logerror("MOCONT = %d (scan = %d)\n", data, video_screen_get_vpos(0));
+
+ /* set the control value */
+ COMBINE_DATA(&current_control);
+}
+
+
+void atarig42_scanline_update(running_machine *machine, int scrnum, int scanline)
+{
+ UINT16 *base = &atarigen_alpha[(scanline / 8) * 64 + 48];
+ int i;
+
+ if (scanline == 0) logerror("-------\n");
+
+ /* keep in range */
+ if (base >= &atarigen_alpha[0x800])
+ return;
+
+ /* update the playfield scrolls */
+ for (i = 0; i < 8; i++)
+ {
+ UINT16 word;
+
+ word = *base++;
+ if (word & 0x8000)
+ {
+ int newscroll = (word >> 5) & 0x3ff;
+ int newbank = word & 0x1f;
+ if (newscroll != playfield_xscroll)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_set_scrollx(atarigen_playfield_tilemap, 0, newscroll);
+ playfield_xscroll = newscroll;
+ }
+ if (newbank != playfield_color_bank)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_mark_all_tiles_dirty(atarigen_playfield_tilemap);
+ playfield_color_bank = newbank;
+ }
+ }
+
+ word = *base++;
+ if (word & 0x8000)
+ {
+ int newscroll = ((word >> 6) - (scanline + i)) & 0x1ff;
+ int newbank = word & 7;
+ if (newscroll != playfield_yscroll)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, newscroll);
+ playfield_yscroll = newscroll;
+ }
+ if (newbank != playfield_tile_bank)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_mark_all_tiles_dirty(atarigen_playfield_tilemap);
+ playfield_tile_bank = newbank;
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( atarig42 )
+{
+ /* draw the playfield */
+ fillbitmap(priority_bitmap, 0, cliprect);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 1, 1);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 2, 2);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 3, 3);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 4, 4);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 5, 5);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 6, 6);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 7, 7);
+
+ /* copy the motion objects on top */
+ {
+ mame_bitmap *mo_bitmap = atarirle_get_vram(0, 0);
+ int left = cliprect->min_x;
+ int top = cliprect->min_y;
+ int right = cliprect->max_x + 1;
+ int bottom = cliprect->max_y + 1;
+ int x, y;
+
+ /* now blend with the playfield */
+ for (y = top; y < bottom; y++)
+ {
+ UINT16 *pf = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+ UINT16 *mo = (UINT16 *)mo_bitmap->base + y * mo_bitmap->rowpixels;
+ UINT8 *pri = (UINT8 *)priority_bitmap->base + priority_bitmap->rowpixels * y;
+ for (x = left; x < right; x++)
+ if (mo[x])
+ {
+ int pfpri = pri[x];
+ int mopri = mo[x] >> ATARIMO_PRIORITY_SHIFT;
+ if (mopri >= pfpri)
+ pf[x] = mo[x] & ATARIRLE_DATA_MASK;
+ }
+ }
+ }
+
+ /* add the alpha on top */
+ tilemap_draw(bitmap, cliprect, atarigen_alpha_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/atarigt.c b/src/mame/video/atarigt.c
new file mode 100644
index 00000000000..04c86451c84
--- /dev/null
+++ b/src/mame/video/atarigt.c
@@ -0,0 +1,681 @@
+/***************************************************************************
+
+ Atari GT hardware
+
+*****************************************************************************
+
+ MO data has 12 bits total: MVID0-11
+ MVID9-11 form the priority
+ MVID0-9 form the color bits
+
+ PF data has 13 bits total: PF.VID0-12
+ PF.VID10-12 form the priority
+ PF.VID0-9 form the color bits
+
+ Upper bits come from the low 5 bits of the HSCROLL value in alpha RAM
+ Playfield bank comes from low 2 bits of the VSCROLL value in alpha RAM
+ For GX2, there are 4 bits of bank
+
+****************************************************************************/
+
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "atarigt.h"
+
+
+
+/*************************************
+ *
+ * Constants
+ *
+ *************************************/
+
+#define CRAM_ENTRIES 0x4000
+#define TRAM_ENTRIES 0x4000
+#define MRAM_ENTRIES 0x8000
+
+
+
+/*************************************
+ *
+ * Globals we own
+ *
+ *************************************/
+
+UINT16 *atarigt_colorram;
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static mame_bitmap *pf_bitmap;
+static mame_bitmap *an_bitmap;
+
+static UINT8 playfield_tile_bank;
+static UINT8 playfield_color_bank;
+static UINT16 playfield_xscroll;
+static UINT16 playfield_yscroll;
+
+static UINT32 tram_checksum;
+static UINT16 *cram, *tram;
+static UINT32 *mram;
+
+static pen_t *substitute_pens;
+
+static UINT32 *expanded_mram;
+
+static UINT8 rshift, gshift, bshift;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha32[tile_index / 2] >> (16 * (~tile_index & 1));
+ int code = data & 0xfff;
+ int color = (data >> 12) & 0x0f;
+ SET_TILE_INFO(1, code, color, 0);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data = atarigen_playfield32[tile_index / 2] >> (16 * (~tile_index & 1));
+ int code = (playfield_tile_bank << 12) | (data & 0xfff);
+ int color = (data >> 12) & 7;
+ SET_TILE_INFO(0, code, color, (data >> 15) & 1);
+}
+
+
+static TILEMAP_MAPPER( atarigt_playfield_scan )
+{
+ int bank = 1 - (col / (num_cols / 2));
+ return bank * (num_rows * num_cols / 2) + row * (num_cols / 2) + (col % (num_cols / 2));
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( atarigt )
+{
+ static const struct atarirle_desc modesc =
+ {
+ REGION_GFX3,/* region where the GFX data lives */
+ 256, /* number of entries in sprite RAM */
+ 0, /* left clip coordinate */
+ 0, /* right clip coordinate */
+
+ 0x0000, /* base palette entry */
+ 0x1000, /* maximum number of colors */
+
+ {{ 0x7fff,0,0,0,0,0,0,0 }}, /* mask for the code index */
+ {{ 0,0x0ff0,0,0,0,0,0,0 }}, /* mask for the color */
+ {{ 0,0,0xffc0,0,0,0,0,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xffc0,0,0,0,0 }}, /* mask for the Y position */
+ {{ 0,0,0,0,0xffff,0,0,0 }}, /* mask for the scale factor */
+ {{ 0x8000,0,0,0,0,0,0,0 }}, /* mask for the horizontal flip */
+ {{ 0,0,0,0,0,0,0x00ff,0 }}, /* mask for the order */
+ {{ 0,0x0e00,0,0,0,0,0,0 }}, /* mask for the priority */
+ {{ 0,0x8000,0,0,0,0,0,0 }} /* mask for the VRAM target */
+ };
+ struct atarirle_desc adjusted_modesc = modesc;
+ int i;
+
+ /* blend the playfields and free the temporary one */
+ atarigen_blend_gfx(machine, 0, 2, 0x0f, 0x30);
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, atarigt_playfield_scan, TILEMAP_TYPE_PEN, 8,8, 128,64);
+
+ /* initialize the motion objects */
+ atarirle_init(0, &adjusted_modesc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+
+ /* allocate temp bitmaps */
+ pf_bitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+ an_bitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+
+ /* allocate memory */
+ expanded_mram = auto_malloc(sizeof(*expanded_mram) * MRAM_ENTRIES * 3);
+
+ /* map pens 1:1 */
+ substitute_pens = auto_malloc(65536 * sizeof(*substitute_pens));
+ for (i = 0; i < machine->drv->total_colors; i++)
+ substitute_pens[i] = i;
+ machine->pens = substitute_pens;
+
+ /* compute shift values */
+ rshift = 16;
+ gshift = 8;
+ bshift = 0;
+
+ /* reset statics */
+ playfield_tile_bank = 0;
+ playfield_color_bank = 0;
+ playfield_xscroll = 0;
+ playfield_yscroll = 0;
+ tram_checksum = 0;
+ memset(atarigt_colorram, 0, 0x80000);
+}
+
+
+
+/*************************************
+ *
+ * Color RAM access
+ *
+ *************************************/
+
+void atarigt_colorram_w(offs_t address, UINT16 data, UINT16 mem_mask)
+{
+ UINT16 olddata;
+
+ /* update the raw data */
+ address = (address & 0x7ffff) / 2;
+ olddata = atarigt_colorram[address];
+ COMBINE_DATA(&atarigt_colorram[address]);
+
+ /* update the TRAM checksum */
+ if (address >= 0x10000 && address < 0x14000)
+ tram_checksum += atarigt_colorram[address] - olddata;
+
+ /* update expanded MRAM */
+ else if (address >= 0x20000 && address < 0x28000)
+ {
+ expanded_mram[0 * MRAM_ENTRIES + (address & 0x7fff)] = (atarigt_colorram[address] >> 8) << rshift;
+ expanded_mram[1 * MRAM_ENTRIES + (address & 0x7fff)] = (atarigt_colorram[address] & 0xff) << gshift;
+ }
+ else if (address >= 0x30000 && address < 0x38000)
+ expanded_mram[2 * MRAM_ENTRIES + (address & 0x7fff)] = (atarigt_colorram[address] & 0xff) << bshift;
+}
+
+
+UINT16 atarigt_colorram_r(offs_t address)
+{
+ address &= 0x7ffff;
+ return atarigt_colorram[address / 2];
+}
+
+
+
+/*************************************
+ *
+ * Periodic scanline updater
+ *
+ *************************************/
+
+void atarigt_scanline_update(running_machine *machine, int scrnum, int scanline)
+{
+ UINT32 *base = &atarigen_alpha32[(scanline / 8) * 32 + 24];
+ int i;
+
+ /* keep in range */
+ if (base >= &atarigen_alpha32[0x400])
+ return;
+
+ /* update the playfield scrolls */
+ for (i = 0; i < 8; i++)
+ {
+ UINT32 word = *base++;
+
+ if (word & 0x80000000)
+ {
+ int newscroll = (word >> 21) & 0x3ff;
+ int newbank = (word >> 16) & 0x1f;
+ if (newscroll != playfield_xscroll)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_set_scrollx(atarigen_playfield_tilemap, 0, newscroll);
+ playfield_xscroll = newscroll;
+ }
+ if (newbank != playfield_color_bank)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_set_palette_offset(atarigen_playfield_tilemap, (newbank & 0x1f) << 8);
+ playfield_color_bank = newbank;
+ }
+ }
+
+ if (word & 0x00008000)
+ {
+ int newscroll = ((word >> 6) - (scanline + i)) & 0x1ff;
+ int newbank = word & 15;
+ if (newscroll != playfield_yscroll)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, newscroll);
+ playfield_yscroll = newscroll;
+ }
+ if (newbank != playfield_tile_bank)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_mark_all_tiles_dirty(atarigen_playfield_tilemap);
+ playfield_tile_bank = newbank;
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+/*
+
+ How it works:
+
+ Incoming data from AN = AN.VID0-7
+ Incoming data from PF = PF.VID0-12
+ Incoming data from MO = MVID0-11
+ Incoming data from TMO = TVID0-11
+
+ !MGEP = 1 if:
+ MVID9-11 < PF.VID10-12
+ or (PF.VID12 and R188 is installed [yes on T-Mek & Rage])
+ !MGEP = 0 if:
+ R177 is installed [no on T-Mek & Rage]
+
+ First, the CRAM:
+
+ GAL @ 13M, takes as input:
+ ANZ (AN.VID0-3 == 0)
+ MOZ (MVID0-5 == 0)
+ PFZ (PF.VID0-5 == 0)
+ MVID10
+ MVID11
+ PF.VID10
+ PF.VID11
+ AN.VID7
+ !MGEP
+ And outputs:
+ CRA10-12
+ CRMUXA-B
+
+ Index to the CRAM:
+ CRA13 = LATCH & 0x08
+ CRA12 \
+ CRA11 = output from GAL
+ CRA10 /
+ CRA9 \
+ CRA8 |
+ CRA7 |
+ CRA6 |
+ CRA5 = output from MUX, as selected by GAL, either PF.VID0-9, MVID0-9, or AN.VID0-7
+ CRA4 |
+ CRA3 |
+ CRA2 |
+ CRA1 |
+ CRA0 /
+ Output from CRAM (16 bits):
+ /TLEN
+ CRR0-4
+ CRG0-4
+ CRB0-4
+
+ Next, the TRAM:
+
+ GAL @ 14K, takes as input:
+ ANZ (AN.VID0-3 == 0)
+ MOZ (MVID0-5 == 0)
+ PFZ (PF.VID0-5 == 0)
+ TVID8
+ TVID9
+ TVID10
+ PF.VID10
+ PF.VID11
+ AN.VID7
+ !MGEP
+ !68.TRAN
+ And outputs:
+ TRA8-11
+ TRMUXA-B
+
+ Index to the TRAM:
+ TRA13 = LATCH & 0x20
+ TRA12 = LATCH & 0x10
+ TRA11 \
+ TRA10 = output from GAL
+ TRA9 |
+ TRA8 /
+ TRA7 \
+ TRA6 |
+ TRA5 |
+ TRA4 = output from MUX, as selected by GAL, either PF.VID0-7, MVID0-7, or AN.VID0-7
+ TRA3 |
+ TRA2 |
+ TRA1 |
+ TRA0 /
+ Output from TRAM (16 bits):
+ TLPRI
+ TRR0-4
+ TRG0-4
+ TRB0-4
+
+ Finally, the MRAM:
+
+ GAL @ 5F, takes as input:
+ TLPRI
+ !TLEN
+ PFZ
+ PF.VID12
+ TVID9-11
+ And outputs:
+ TLDIS
+ (PFPRI)
+ (TLPRID)
+ enable for CRAM latches
+ MRA10-12
+
+ The CRAM outputs are gated by the enable signal from 5F; it outputs
+ BMRA0-4
+ GMRA0-4
+ RMRA0-4
+
+ The TRAM outputs are gated by the TLDIS signal from 5F
+ BMRA5-9
+ GMRA5-9
+ RMRA5-9
+
+ Index to MRAM:
+ MRA14 = LATCH & 0x80
+ MRA13 = LATCH & 0x40
+ MRA12 \
+ MRA11 = output from GAL
+ MRA10 /
+ MRA9 \
+ MRA8 |
+ MRA7 = TRAM output
+ MRA6 |
+ MRA5 /
+ MRA4 \
+ MRA3 |
+ MRA2 = CRAM output
+ MRA1 |
+ MRA0 /
+
+ And even beyond that:
+
+ LATCH & 0x04 -> LCRD2
+ LATCH & 0x02 -> LCRD1
+ LATCH & 0x01 -> LCRD0
+
+ GAL @ 22E, takes as input:
+ LCRD0-2
+ PF.VID12
+ PFZ
+ ANZ
+ MVZ
+
+ And outputs SUMRED, SUMGRN, SUMBLU,
+ which bypass everything!
+
+-------------------------------------------------
+
+TMEK GALs:
+
+ 13M:
+ CRA12=68.A13*!7M3 -- when writing with 68020's A13 == 1
+ +MGEP*!AN.VID7*ANZ*!MVZ*7M3 -- !opaque_alpha && apix==0 && mopix!=0 && pfpix==0
+ +PFZ*!AN.VID7*ANZ*!MVZ*7M3 -- !opaque_alpha && apix==0 && mopix!=0 && mopri>=pfpri
+
+ CRA11=68.A12*!7M3 -- when writing with 68020's A12 == 1
+ +MGEP*!AN.VID7*ANZ*!MVZ*MVID11*7M3 -- !opaque_alpha && apix==0 && mopix!=0 && mopri>=pfpri && mopix11!=0
+ +PFZ*!AN.VID7*ANZ*!MVZ*MVID11*7M3 -- !opaque_alpha && apix==0 && mopix!=0 && pfpix==0 && mopix11!=0
+ +!AN.VID7*ANZ*MVZ*PF.VID11*7M3 -- !opaque_alpha && apix==0 && mopix==0 && pfpix11!=0
+ +!MGEP*!PFZ*!AN.VID7*ANZ*PF.VID11*7M3 -- !opaque_alpha && apix==0 && pfpix!=0 && mopri<pfpri && pfpix11!=0
+
+ CRA10=68.A11*!7M3 -- when writing with 68020's A11 == 1
+ +MGEP*!AN.VID7*ANZ*!MVZ*MVID10*7M3 -- !opaque_alpha && apix==0 && mopix!=0 && mopri>=pfpri && mopix10!=0
+ +PFZ*!AN.VID7*ANZ*!MVZ*MVID10*7M3 -- !opaque_alpha && apix==0 && mopix!=0 && pfpix==0 && mopix10!=0
+ +!AN.VID7*ANZ*MVZ*PF.VID10*7M3 -- !opaque_alpha && apix==0 && mopix==0 && pfpix10!=0
+ +!MGEP*!PFZ*!AN.VID7*ANZ*PF.VID10*7M3 -- !opaque_alpha && apix==0 && pfpix!=0 && mopri<pfpri && pfpix10!=0
+
+ CRMUXB=!AN.VID7*ANZ*7M3 -- !opaque_alpha && apix==0
+
+ !CRMUXA=!7M3
+ +MGEP*!AN.VID7*ANZ*!MVZ
+ +PFZ*!AN.VID7*ANZ*!MVZ
+
+
+ 14K:
+ TRA11=68.A12*!7M1 -- when writing with 68020's A12 == 1
+
+ TRA10=68.A11*!7M1 -- when writing with 68020's A11 == 1
+ +!AN.VID7*ANZ*PFZ*7M1*!MVZ -- !opaque_alpha && apix==0 && pfpix==0 && mopix!=0
+ +MGEP*!AN.VID7*ANZ*7M1*!MVZ -- !opaque_alpha && apix==0 && mopri>=pfpri && mopix!=0
+
+ TRA9=68.A10*!7M1 -- when writing with 68020's A10 == 1
+ +!AN.VID7*ANZ*TVID9*7M1 -- !opaque_alpha && apix==0 && tvid9==1
+
+ TRA8=68.A9*!7M1 -- when writing with 68020's A9 == 1
+ +!AN.VID7*ANZ*TVID8*7M1 -- !opaque_alpha && apix==0 && tvid8==1
+
+ TRMUXB=7M1 -- 1
+ TRMUXA=GND -- 0
+
+ 5F:
+ MRA12:=TVID11
+ MRA11:=TVID10
+ MRA10:=TVID9
+ (PFPRI):=PF.VID12
+
+ !TLDIS=PFZ*TLEN -- enabled if pfpix==0 && tlen
+ +!(PFPRI)*TLEN -- or if pf.vid12==0 && tlen
+
+ !(CRADIS)=!(PFPRI)*TLPRI -- enabled if pfvid.12==0 && tlpri
+ (TLPRID):=TLPRI
+
+ 22E:
+ LCRD0 LCRD1 LCRD2 MVZ ANZ PFZ PF.VID12 LLD3 LLA3 GND J SUMBLU1K SUMGRN1K SUMRED1K (OE2) (OE1) SUMBLU SUMGRN SUMRED VCC
+ SUMRED.OE=(OE1)
+ !SUMRED=!SUMGRN
+ SUMGRN.OE=(OE1)
+ SUMGRN=!LCRD1*LCRD2*LLA3
+ +LCRD1*LCRD0*LCRD2*J
+ +LCRD1*LCRD0*!LCRD2*!LLD3
+ +!LCRD1*LCRD0*!LCRD2*LLD3
+ +!LCRD0*LCRD2*LLA3
+ +LCRD1*!LCRD0*!LCRD2*LLD3
+ SUMBLU.OE=(OE1)
+ !SUMBLU=!SUMGRN
+
+ (OE1)=!LCRD1*LCRD2*!PF.VID12*LLD3*J -- (LCR & 6)==4 && LLD3 && !PF.VID12 [LCR==4 || LCR==5]
+ +!LCRD1*LCRD2*PFZ*LLD3*J -- (LCR & 6)==4 && LLD3 && PFZ [LCR==4 || LCR==5]
+ +!LCRD0*LCRD2*!PF.VID12*LLD3 -- (LCR & 5)==4 && LLD3 && !PF.VID12 [LCR==4 || LCR==6]
+ +!LCRD0*LCRD2*PFZ*LLD3 -- (LCR & 5)==4 && LLD3 && PFZ [LCR==4 || LCR==6]
+ +!LCRD1*!LCRD0*LCRD2*!PF.VID12*J -- LCR==4 && !PF.VID12 [LCR==4]
+ +!LCRD1*!LCRD0*LCRD2*PFZ*J -- LCR==4 && PFZ [LCR==4]
+
+ (OE2)=LCRD1*LCRD0*!LCRD2*!PF.VID12*LLA3*J -- LCR==3 && LLA3 && !PF.VID12 [LCR==3]
+ +LCRD1*LCRD0*!LCRD2*PFZ*LLA3*J -- LCR==3 && LLA3 && PFZ [LCR==3]
+ +!LCRD1*LCRD0*!LCRD2*!MVZ*!PF.VID12*J -- LCR==1 && !MVZ && !PF.VID12 [LCR==1]
+ +!LCRD1*LCRD0*!LCRD2*!MVZ*PFZ*J -- LCR==1 && !MVZ && PFZ [LCR==1]
+ +LCRD1*!LCRD0*LCRD2*!PF.VID12*LLD3 -- LCR==6 && LLD3 && !PF.VID12 [LCR==6]
+ +LCRD1*!LCRD0*LCRD2*PFZ*LLD3 -- LCR==6 && LLD3 && PFZ [LCR==6]
+
+ SUMRED1K.OE=(OE2)
+ !SUMRED1K=!LCRD1*!LCRD2*!LLD3 -- (LCR & 6)==0 && !LLD3
+ +LCRD0*LCRD2*!LLA3 -- (LCR & 5)==5 && !LLA3
+ +LCRD1*LCRD0*!LCRD2*LLD3 -- LCR==3 && LLD3
+ +!LCRD0*!LCRD2*!LLD3 -- (LCR & 5)==0 && !LLD3
+ +LCRD1*!LCRD0*LCRD2*!J -- LCR==6 && !J
+ +!LCRD1*!LCRD0*LLD3 -- (LCR & 3)==0 && LLD3
+ SUMGRN1K.OE=(OE2)
+ !SUMGRN1K=!SUMRED1K
+ SUMBLU1K.OE=(OE2)
+ !SUMBLU1K=!SUMRED1K
+
+-------------------------------------------------
+
+PrimRage GALs:
+
+ 13M:
+ CRA12=68.A13*!7M3 -- when writing with 68020's A13 == 1
+ +!AN.VID7*ANZ*!MVZ*MVID11*7M3 -- !opaque_alpha && apix==0 && mopix!=0 && mvid11!=0
+ +MGEP*!AN.VID7*ANZ*!MVZ*7M3 -- !opaque_alpha && apix==0 && mopix!=0 && pfpix==0
+ +PFZ*!AN.VID7*ANZ*!MVZ*7M3 -- !opaque_alpha && apix==0 && mopix!=0 && mopri>=pfpri
+
+ CRA11=68.A12*!7M3 -- when writing with 68020's A12 == 1
+ +!AN.VID7*ANZ*MVZ*PF.VID11*7M3 -- !opaque_alpha && apix==0 && mopix==0 && pfpix11!=0
+ +!MGEP*!PFZ*!AN.VID7*ANZ*PF.VID11*!MVID11*7M3 -- !opaque_alpha && apix==0 && pfpix!=0 && mopri<pfpri && pfpix11!=0 && mvid11==0
+
+ CRA10=68.A11*!7M3 -- when writing with 68020's A11 == 1
+ +!AN.VID7*ANZ*MVZ*PF.VID10*7M3 -- !opaque_alpha && apix==0 && mopix==0 && pfpix10!=0
+ +!AN.VID7*ANZ*!MVZ*MVID11*MVID10*7M3 *- !opaque_alpha && apix==0 && mopix!=0 && mvid11 && mvid10
+ +MGEP*!AN.VID7*ANZ*!MVZ*MVID10*7M3 -- !opaque_alpha && apix==0 && mopix!=0 && mopri>=pfpri && mopix10!=0
+ +PFZ*!AN.VID7*ANZ*!MVZ*MVID10*7M3 -- !opaque_alpha && apix==0 && mopix!=0 && pfpix==0 && mopix10!=0
+ +!MGEP*!PFZ*!AN.VID7*ANZ*PF.VID10*!MVID11*7M3 *- !opaque_alpha && apix==0 && pfpix!=0 && mopri<pfpri && mopix11==0
+
+ CRMUXB=!AN.VID7*ANZ*7M3
+
+ !CRMUXA=!7M3
+ +!AN.VID7*ANZ*!MVZ*MVID11
+ +MGEP*!AN.VID7*ANZ*!MVZ
+ +PFZ*!AN.VID7*ANZ*!MVZ
+
+*/
+
+
+VIDEO_UPDATE( atarigt )
+{
+ mame_bitmap *mo_bitmap = atarirle_get_vram(0, 0);
+ mame_bitmap *tm_bitmap = atarirle_get_vram(0, 1);
+ int color_latch;
+ int x, y;
+
+ /* draw the playfield */
+ tilemap_draw(pf_bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+
+ /* draw the alpha layer */
+ tilemap_draw(an_bitmap, cliprect, atarigen_alpha_tilemap, 0, 0);
+
+ /* cache pointers */
+ color_latch = atarigt_colorram[0x30000/2];
+ cram = (UINT16 *)&atarigt_colorram[0x00000/2] + 0x2000 * ((color_latch >> 3) & 1);
+ tram = (UINT16 *)&atarigt_colorram[0x20000/2] + 0x1000 * ((color_latch >> 4) & 3);
+ mram = expanded_mram + 0x2000 * ((color_latch >> 6) & 3);
+
+ /* now do the nasty blend */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *an = (UINT16 *)an_bitmap->base + y * an_bitmap->rowpixels;
+ UINT16 *pf = (UINT16 *)pf_bitmap->base + y * pf_bitmap->rowpixels;
+ UINT16 *mo = (UINT16 *)mo_bitmap->base + y * mo_bitmap->rowpixels;
+ UINT16 *tm = (UINT16 *)tm_bitmap->base + y * tm_bitmap->rowpixels;
+ UINT32 *dst = (UINT32 *)bitmap->base + y * bitmap->rowpixels;
+
+ /* Primal Rage: no TRAM, slightly different priorities */
+ if (atarigt_is_primrage)
+ {
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ UINT8 pfpri = (pf[x] >> 10) & 7;
+ UINT8 mopri = mo[x] >> ATARIRLE_PRIORITY_SHIFT;
+ UINT8 mgep = (mopri >= pfpri) && !(pfpri & 4);
+ UINT16 cra;
+ UINT32 rgb;
+
+ /* compute CRA -- unlike T-Mek, MVID11 enforces MO priority and is ignored */
+ if (an[x] & 0x8f)
+ cra = an[x] & 0xff;
+ else if ((mo[x] & 0x3f) && ((mo[x] & 0x800) || mgep || !(pf[x] & 0x3f)))
+ cra = 0x1000 | (mo[x] & 0x7ff);
+ else
+ cra = pf[x] & 0xfff;
+ cra = cram[cra];
+
+ /* compute the result */
+ rgb = mram[0 * MRAM_ENTRIES + ((cra >> 10) & 0x01f)];
+ rgb |= mram[1 * MRAM_ENTRIES + ((cra >> 5) & 0x01f)];
+ rgb |= mram[2 * MRAM_ENTRIES + ((cra >> 0) & 0x01f)];
+
+ /* final override */
+ if (color_latch & 7)
+ if (!(pf[x] & 0x3f) || !(pf[x] & 0x2000))
+ rgb = (0xff << rshift) | (0xff << gshift) | (0xff << bshift);
+
+ dst[x] = rgb;
+ }
+ }
+
+ /* T-Mek: full TRAM and all effects */
+ else
+ {
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ UINT8 pfpri = (pf[x] >> 10) & 7;
+ UINT8 mopri = mo[x] >> ATARIRLE_PRIORITY_SHIFT;
+ UINT8 mgep = (mopri >= pfpri) && !(pfpri & 4);
+ int no_tra = 0, no_cra = 0;
+ UINT16 cra, tra, mra;
+ UINT32 rgb;
+
+ /* compute CRA/TRA */
+ if (an[x] & 0x8f)
+ {
+ cra = an[x] & 0xff;
+ tra = tm[x] & 0xff;
+ }
+ else if ((mo[x] & 0x3f) && (mgep || !(pf[x] & 0x3f)))
+ {
+ cra = 0x1000 | (mo[x] & 0xfff);
+ tra = 0x400 | (tm[x] & 0x3ff);
+ }
+ else
+ {
+ cra = pf[x] & 0xfff;
+ tra = tm[x] & 0x3ff;
+ }
+ cra = cram[cra];
+ tra = tram[tra];
+
+ /* compute MRA */
+ mra = (tm[x] & 0xe00) << 1;
+
+ /* turn off CRA/TRA as appropriate */
+ if (!(pf[x] & 0x1000) && (tra & 0x8000))
+ no_cra = 1;
+ if (!(!(cra & 0x8000) && (!(pf[x] & 0x1000) || !(pf[x] & 0x3f))))
+ no_tra = 1;
+ if (no_cra)
+ cra = 0;
+ if (no_tra)
+ tra = 0;
+
+ /* compute the result */
+ rgb = mram[0 * MRAM_ENTRIES + mra + ((cra >> 10) & 0x01f) + ((tra >> 5) & 0x3e0)];
+ rgb |= mram[1 * MRAM_ENTRIES + mra + ((cra >> 5) & 0x01f) + ((tra >> 0) & 0x3e0)];
+ rgb |= mram[2 * MRAM_ENTRIES + mra + ((cra >> 0) & 0x01f) + ((tra << 5) & 0x3e0)];
+
+ /* final override */
+ if (color_latch & 7)
+ if (!(pf[x] & 0x3f) || !(pf[x] & 0x2000))
+ rgb = (0xff << rshift) | (0xff << gshift) | (0xff << bshift);
+
+ dst[x] = rgb;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/atarigx2.c b/src/mame/video/atarigx2.c
new file mode 100644
index 00000000000..8c1f109f337
--- /dev/null
+++ b/src/mame/video/atarigx2.c
@@ -0,0 +1,259 @@
+/***************************************************************************
+
+ Atari GX2 hardware
+
+*****************************************************************************
+
+ MO data has 12 bits total: MVID0-11
+ MVID9-11 form the priority
+ MVID0-9 form the color bits
+
+ PF data has 13 bits total: PF.VID0-12
+ PF.VID10-12 form the priority
+ PF.VID0-9 form the color bits
+
+ Upper bits come from the low 5 bits of the HSCROLL value in alpha RAM
+ Playfield bank comes from low 2 bits of the VSCROLL value in alpha RAM
+ For GX2, there are 4 bits of bank
+
+****************************************************************************/
+
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "atarigx2.h"
+
+
+
+/*************************************
+ *
+ * Globals we own
+ *
+ *************************************/
+
+UINT16 atarigx2_playfield_base;
+UINT16 atarigx2_motion_object_base;
+UINT16 atarigx2_motion_object_mask;
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static UINT16 current_control;
+static UINT8 playfield_tile_bank;
+static UINT8 playfield_color_bank;
+static UINT16 playfield_xscroll;
+static UINT16 playfield_yscroll;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha32[tile_index / 2] >> (16 * (~tile_index & 1));
+ int code = data & 0xfff;
+ int color = (data >> 12) & 0x0f;
+ int opaque = data & 0x8000;
+ SET_TILE_INFO(1, code, color, opaque ? TILE_FORCE_LAYER0 : 0);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data = atarigen_playfield32[tile_index / 2] >> (16 * (~tile_index & 1));
+ int code = (playfield_tile_bank << 12) | (data & 0xfff);
+ int color = (atarigx2_playfield_base >> 5) + ((playfield_color_bank << 3) & 0x18) + ((data >> 12) & 7);
+ SET_TILE_INFO(0, code, color, (data >> 15) & 1);
+ tileinfo->category = (playfield_color_bank >> 2) & 7;
+}
+
+
+static TILEMAP_MAPPER( atarigx2_playfield_scan )
+{
+ int bank = 1 - (col / (num_cols / 2));
+ return bank * (num_rows * num_cols / 2) + row * (num_cols / 2) + (col % (num_cols / 2));
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( atarigx2 )
+{
+ static const struct atarirle_desc modesc =
+ {
+ REGION_GFX3,/* region where the GFX data lives */
+ 256, /* number of entries in sprite RAM */
+ 0, /* left clip coordinate */
+ 0, /* right clip coordinate */
+
+ 0x000, /* base palette entry */
+ 0x400, /* maximum number of colors */
+
+ {{ 0x7fff,0,0,0,0,0,0,0 }}, /* mask for the code index */
+ {{ 0,0x03f0,0,0,0,0,0,0 }}, /* mask for the color */
+ {{ 0,0,0xffc0,0,0,0,0,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xffc0,0,0,0,0 }}, /* mask for the Y position */
+ {{ 0,0,0,0,0xffff,0,0,0 }}, /* mask for the scale factor */
+ {{ 0x8000,0,0,0,0,0,0,0 }}, /* mask for the horizontal flip */
+ {{ 0,0,0,0,0,0,0x00ff,0 }}, /* mask for the order */
+ {{ 0,0x0e00,0,0,0,0,0,0 }}, /* mask for the priority */
+ {{ 0 }} /* mask for the VRAM target */
+ };
+ struct atarirle_desc adjusted_modesc = modesc;
+ int i;
+
+ /* blend the playfields and free the temporary one */
+ atarigen_blend_gfx(machine, 0, 2, 0x0f, 0x30);
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, atarigx2_playfield_scan, TILEMAP_TYPE_PEN, 8,8, 128,64);
+
+ /* initialize the motion objects */
+ adjusted_modesc.palettebase = atarigx2_motion_object_base;
+ for (i = 0; i < 8; i++)
+ adjusted_modesc.colormask.data[i] &= atarigx2_motion_object_mask;
+ atarirle_init(0, &adjusted_modesc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ tilemap_set_transparent_pen(atarigen_alpha_tilemap, 0);
+
+ /* reset statics */
+ current_control = 0;
+ playfield_tile_bank = 0;
+ playfield_color_bank = 0;
+ playfield_xscroll = 0;
+ playfield_yscroll = 0;
+}
+
+
+
+/*************************************
+ *
+ * Periodic scanline updater
+ *
+ *************************************/
+
+WRITE16_HANDLER( atarigx2_mo_control_w )
+{
+ logerror("MOCONT = %d (scan = %d)\n", data, video_screen_get_vpos(0));
+
+ /* set the control value */
+ COMBINE_DATA(&current_control);
+}
+
+
+void atarigx2_scanline_update(running_machine *machine, int scrnum, int scanline)
+{
+ UINT32 *base = &atarigen_alpha32[(scanline / 8) * 32 + 24];
+ int i;
+
+ if (scanline == 0) logerror("-------\n");
+
+ /* keep in range */
+ if (base >= &atarigen_alpha32[0x400])
+ return;
+
+ /* update the playfield scrolls */
+ for (i = 0; i < 8; i++)
+ {
+ UINT32 word = *base++;
+
+ if (word & 0x80000000)
+ {
+ int newscroll = (word >> 21) & 0x3ff;
+ int newbank = (word >> 16) & 0x1f;
+ if (newscroll != playfield_xscroll)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_set_scrollx(atarigen_playfield_tilemap, 0, newscroll);
+ playfield_xscroll = newscroll;
+ }
+ if (newbank != playfield_color_bank)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_mark_all_tiles_dirty(atarigen_playfield_tilemap);
+ playfield_color_bank = newbank;
+ }
+ }
+
+ if (word & 0x00008000)
+ {
+ int newscroll = ((word >> 6) - (scanline + i)) & 0x1ff;
+ int newbank = word & 15;
+ if (newscroll != playfield_yscroll)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, newscroll);
+ playfield_yscroll = newscroll;
+ }
+ if (newbank != playfield_tile_bank)
+ {
+ video_screen_update_partial(0, scanline + i - 1);
+ tilemap_mark_all_tiles_dirty(atarigen_playfield_tilemap);
+ playfield_tile_bank = newbank;
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( atarigx2 )
+{
+ /* draw the playfield */
+ fillbitmap(priority_bitmap, 0, cliprect);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 1, 1);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 2, 2);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 3, 3);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 4, 4);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 5, 5);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 6, 6);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 7, 7);
+
+ /* copy the motion objects on top */
+ {
+ mame_bitmap *mo_bitmap = atarirle_get_vram(0, 0);
+ int left = cliprect->min_x;
+ int top = cliprect->min_y;
+ int right = cliprect->max_x + 1;
+ int bottom = cliprect->max_y + 1;
+ int x, y;
+
+ /* now blend with the playfield */
+ for (y = top; y < bottom; y++)
+ {
+ UINT16 *pf = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+ UINT16 *mo = (UINT16 *)mo_bitmap->base + y * mo_bitmap->rowpixels;
+ UINT8 *pri = (UINT8 *)priority_bitmap->base + y * priority_bitmap->rowpixels;
+ for (x = left; x < right; x++)
+ if (mo[x] && (mo[x] >> ATARIRLE_PRIORITY_SHIFT) >= pri[x])
+ pf[x] = mo[x] & ATARIRLE_DATA_MASK;
+ }
+ }
+
+ /* add the alpha on top */
+ tilemap_draw(bitmap, cliprect, atarigen_alpha_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/atarimo.c b/src/mame/video/atarimo.c
new file mode 100644
index 00000000000..3fd5e39f374
--- /dev/null
+++ b/src/mame/video/atarimo.c
@@ -0,0 +1,1092 @@
+/*##########################################################################
+
+ atarimo.c
+
+ Common motion object management functions for Atari raster games.
+
+##########################################################################*/
+
+#include "driver.h"
+#include "atarimo.h"
+
+
+/*##########################################################################
+ TYPES & STRUCTURES
+##########################################################################*/
+
+/* internal structure containing a word index, shift and mask */
+struct atarimo_mask
+{
+ int word; /* word index */
+ int shift; /* shift amount */
+ int mask; /* final mask */
+};
+
+/* internal structure containing the state of the motion objects */
+struct atarimo_data
+{
+ UINT32 gfxchanged; /* true if the gfx info has changed */
+ gfx_element gfxelement[MAX_GFX_ELEMENTS]; /* local copy of graphics elements */
+ int gfxgranularity[MAX_GFX_ELEMENTS];
+
+ mame_bitmap *bitmap; /* temporary bitmap to render to */
+
+ int linked; /* are the entries linked? */
+ int split; /* are entries split or together? */
+ int reverse; /* render in reverse order? */
+ int swapxy; /* render in swapped X/Y order? */
+ UINT8 nextneighbor; /* does the neighbor bit affect the next object? */
+ int slipshift; /* log2(pixels_per_SLIP) */
+ int slipoffset; /* pixel offset for SLIP */
+
+ int entrycount; /* number of entries per bank */
+ int entrybits; /* number of bits needed to represent entrycount */
+ int bankcount; /* number of banks */
+
+ int tilewidth; /* width of non-rotated tile */
+ int tileheight; /* height of non-rotated tile */
+ int tilexshift; /* bits to shift X coordinate when drawing */
+ int tileyshift; /* bits to shift Y coordinate when drawing */
+ int bitmapwidth; /* width of the full playfield bitmap */
+ int bitmapheight; /* height of the full playfield bitmap */
+ int bitmapxmask; /* x coordinate mask for the playfield bitmap */
+ int bitmapymask; /* y coordinate mask for the playfield bitmap */
+
+ int spriterammask; /* combined mask when accessing sprite RAM with raw addresses */
+ int spriteramsize; /* total size of sprite RAM, in entries */
+ int sliprammask; /* combined mask when accessing SLIP RAM with raw addresses */
+ int slipramsize; /* total size of SLIP RAM, in entries */
+
+ UINT32 palettebase; /* base palette entry */
+ int maxcolors; /* maximum number of colors */
+ int transpen; /* transparent pen index */
+
+ UINT32 bank; /* current bank number */
+ UINT32 xscroll; /* current x scroll offset */
+ UINT32 yscroll; /* current y scroll offset */
+
+ int maxperline; /* maximum number of entries/line */
+
+ struct atarimo_mask linkmask; /* mask for the link */
+ struct atarimo_mask gfxmask; /* mask for the graphics bank */
+ struct atarimo_mask codemask; /* mask for the code index */
+ struct atarimo_mask codehighmask; /* mask for the upper code index */
+ struct atarimo_mask colormask; /* mask for the color */
+ struct atarimo_mask xposmask; /* mask for the X position */
+ struct atarimo_mask yposmask; /* mask for the Y position */
+ struct atarimo_mask widthmask; /* mask for the width, in tiles*/
+ struct atarimo_mask heightmask; /* mask for the height, in tiles */
+ struct atarimo_mask hflipmask; /* mask for the horizontal flip */
+ struct atarimo_mask vflipmask; /* mask for the vertical flip */
+ struct atarimo_mask prioritymask; /* mask for the priority */
+ struct atarimo_mask neighbormask; /* mask for the neighbor */
+ struct atarimo_mask absolutemask; /* mask for absolute coordinates */
+
+ struct atarimo_mask specialmask; /* mask for the special value */
+ int specialvalue; /* resulting value to indicate "special" */
+ atarimo_special_cb specialcb; /* callback routine for special entries */
+ int codehighshift; /* shift count for the upper code */
+
+ struct atarimo_entry *spriteram; /* pointer to sprite RAM */
+ UINT16 ** slipram; /* pointer to the SLIP RAM pointer */
+ UINT16 * codelookup; /* lookup table for codes */
+ UINT8 * colorlookup; /* lookup table for colors */
+ UINT8 * gfxlookup; /* lookup table for graphics */
+
+ struct atarimo_entry *activelist[ATARIMO_MAXPERBANK]; /* pointers to active motion objects */
+ struct atarimo_entry **activelast; /* pointer to the last pointer in the active list */
+ UINT32 last_link; /* previous starting point */
+
+ UINT8 * dirtygrid; /* grid of dirty rects for blending */
+ int dirtywidth; /* width of dirty grid */
+ int dirtyheight; /* height of dirty grid */
+
+ rectangle rectlist[ATARIMO_MAXPERBANK]; /* list of bounding rectangles */
+ int rectcount;
+
+ UINT32 last_xpos; /* (during processing) the previous X position */
+ UINT32 next_xpos; /* (during processing) the next X position */
+};
+
+
+
+/*##########################################################################
+ MACROS
+##########################################################################*/
+
+/* data extraction */
+#define EXTRACT_DATA(_input, _mask) (((_input)->data[(_mask).word] >> (_mask).shift) & (_mask).mask)
+
+
+
+/*##########################################################################
+ GLOBAL VARIABLES
+##########################################################################*/
+
+UINT16 *atarimo_0_spriteram;
+UINT16 *atarimo_0_slipram;
+
+UINT16 *atarimo_1_spriteram;
+UINT16 *atarimo_1_slipram;
+
+
+
+/*##########################################################################
+ STATIC VARIABLES
+##########################################################################*/
+
+static struct atarimo_data atarimo[ATARIMO_MAX];
+static emu_timer *force_update_timer;
+
+
+/*##########################################################################
+ STATIC FUNCTION DECLARATIONS
+##########################################################################*/
+
+static int mo_render_object(running_machine *machine, struct atarimo_data *mo, const struct atarimo_entry *entry, const rectangle *cliprect);
+
+
+
+/*##########################################################################
+ INLINE FUNCTIONS
+##########################################################################*/
+
+/*---------------------------------------------------------------
+ compute_log: Computes the number of bits necessary to
+ hold a given value. The input must be an even power of
+ two.
+---------------------------------------------------------------*/
+
+INLINE int compute_log(int value)
+{
+ int log = 0;
+
+ if (value == 0)
+ return -1;
+ while (!(value & 1))
+ log++, value >>= 1;
+ if (value != 1)
+ return -1;
+ return log;
+}
+
+
+/*---------------------------------------------------------------
+ round_to_powerof2: Rounds a number up to the nearest
+ power of 2. Even powers of 2 are rounded up to the
+ next greatest power (e.g., 4 returns 8).
+---------------------------------------------------------------*/
+
+INLINE int round_to_powerof2(int value)
+{
+ int log = 0;
+
+ if (value == 0)
+ return 1;
+ while ((value >>= 1) != 0)
+ log++;
+ return 1 << (log + 1);
+}
+
+
+/*---------------------------------------------------------------
+ convert_mask: Converts a 4-word mask into a word index,
+ shift, and adjusted mask. Returns 0 if invalid.
+---------------------------------------------------------------*/
+
+INLINE int convert_mask(const struct atarimo_entry *input, struct atarimo_mask *result)
+{
+ int i, temp;
+
+ /* determine the word and make sure it's only 1 */
+ result->word = -1;
+ for (i = 0; i < 4; i++)
+ if (input->data[i])
+ {
+ if (result->word == -1)
+ result->word = i;
+ else
+ return 0;
+ }
+
+ /* if all-zero, it's valid */
+ if (result->word == -1)
+ {
+ result->word = result->shift = result->mask = 0;
+ return 1;
+ }
+
+ /* determine the shift and final mask */
+ result->shift = 0;
+ temp = input->data[result->word];
+ while (!(temp & 1))
+ {
+ result->shift++;
+ temp >>= 1;
+ }
+ result->mask = temp;
+ return 1;
+}
+
+
+/*---------------------------------------------------------------
+ init_gfxelement: Make a copy of the main gfxelement that
+ gives us full control over colors.
+---------------------------------------------------------------*/
+
+INLINE void init_gfxelement(running_machine *machine, struct atarimo_data *mo, int idx)
+{
+ mo->gfxelement[idx] = *machine->gfx[idx];
+ mo->gfxgranularity[idx] = mo->gfxelement[idx].color_granularity;
+ mo->gfxelement[idx].color_granularity = 1;
+ mo->gfxelement[idx].color_base = 0;
+ mo->gfxelement[idx].total_colors = 65536;
+}
+
+static struct atarimo_data atarimo[ATARIMO_MAX];
+static emu_timer *force_update_timer;
+
+/*---------------------------------------------------------------
+ init_savestate: Initialize save states
+---------------------------------------------------------------*/
+
+static void init_savestate(int index, struct atarimo_data *mo)
+{
+ state_save_register_item("atarimo", index, mo->gfxchanged);
+ state_save_register_item("atarimo", index, mo->palettebase);
+ state_save_register_item("atarimo", index, mo->bank);
+ state_save_register_item("atarimo", index, mo->xscroll);
+ state_save_register_item("atarimo", index, mo->yscroll);
+ state_save_register_item("atarimo", index, mo->last_link);
+ state_save_register_item("atarimo", index, mo->last_xpos);
+ state_save_register_item("atarimo", index, mo->next_xpos);
+
+#if 0
+ // These are not modified in code
+ // Left in for completeness
+ state_save_register_item("atarimo", index, mo->reverse);
+ state_save_register_item("atarimo", index, mo->split);
+ state_save_register_item("atarimo", index, mo->linked);
+ state_save_register_item("atarimo", index, mo->swapxy);
+ state_save_register_item("atarimo", index, mo->nextneighbor);
+ state_save_register_item("atarimo", index, mo->slipshift);
+ state_save_register_item("atarimo", index, mo->slipoffset);
+ state_save_register_item("atarimo", index, mo->slipramsize);
+ state_save_register_item("atarimo", index, mo->sliprammask);
+ state_save_register_item("atarimo", index, mo->entrycount);
+ state_save_register_item("atarimo", index, mo->entrybits);
+ state_save_register_item("atarimo", index, mo->bankcount);
+ state_save_register_item("atarimo", index, mo->tilewidth);
+ state_save_register_item("atarimo", index, mo->tileheight);
+ state_save_register_item("atarimo", index, mo->tilexshift);
+ state_save_register_item("atarimo", index, mo->tileyshift);
+ state_save_register_item("atarimo", index, mo->bitmapwidth);
+ state_save_register_item("atarimo", index, mo->bitmapheight);
+ state_save_register_item("atarimo", index, mo->bitmapxmask);
+ state_save_register_item("atarimo", index, mo->bitmapymask);
+ state_save_register_item("atarimo", index, mo->spriteramsize);
+ state_save_register_item("atarimo", index, mo->spriterammask);
+ state_save_register_item("atarimo", index, mo->maxcolors);
+ state_save_register_item("atarimo", index, mo->transpen);
+ state_save_register_item("atarimo", index, mo->maxperline);
+ state_save_register_item("atarimo", index, mo->specialvalue);
+ state_save_register_item("atarimo", index, mo->codehighshift);
+ state_save_register_item("atarimo", index, mo->dirtywidth);
+ state_save_register_item("atarimo", index, mo->dirtyheight);
+#endif
+
+ state_save_register_bitmap("atarimo", index, "bitmap", mo->bitmap);
+
+ state_save_register_memory("atarimo", index, "spriteram", mo->spriteram, sizeof(struct atarimo_entry), mo->spriteramsize);
+
+ state_save_register_item_pointer("atarimo", index, mo->codelookup, round_to_powerof2(mo->codemask.mask));
+
+ state_save_register_item_pointer("atarimo", index, mo->colorlookup, round_to_powerof2(mo->colormask.mask));
+
+ state_save_register_item_pointer("atarimo", index, mo->dirtygrid, mo->dirtywidth * mo->dirtyheight);
+
+ state_save_register_item_pointer("atarimo", index, mo->gfxlookup, round_to_powerof2(mo->gfxmask.mask));
+
+}
+
+/*##########################################################################
+ GLOBAL FUNCTIONS
+##########################################################################*/
+
+static TIMER_CALLBACK( force_update )
+{
+ int scanline = param;
+
+ if (scanline > 0)
+ video_screen_update_partial(0, scanline - 1);
+
+ scanline += 64;
+ if (scanline >= machine->screen[0].visarea.max_y)
+ scanline = 0;
+ timer_adjust(force_update_timer, video_screen_get_time_until_pos(0, scanline, 0), scanline, attotime_zero);
+}
+
+/*---------------------------------------------------------------
+ atarimo_init: Configures the motion objects using the input
+ description. Allocates all memory necessary and generates
+ the attribute lookup table.
+---------------------------------------------------------------*/
+
+void atarimo_init(running_machine *machine, int map, const struct atarimo_desc *desc)
+{
+ gfx_element *gfx = machine->gfx[desc->gfxindex];
+ struct atarimo_data *mo = &atarimo[map];
+ int i;
+
+ assert_always(map >= 0 && map < ATARIMO_MAX, "atarimo_init: map out of range");
+
+ /* determine the masks first */
+ convert_mask(&desc->linkmask, &mo->linkmask);
+ convert_mask(&desc->gfxmask, &mo->gfxmask);
+ convert_mask(&desc->codemask, &mo->codemask);
+ convert_mask(&desc->codehighmask, &mo->codehighmask);
+ convert_mask(&desc->colormask, &mo->colormask);
+ convert_mask(&desc->xposmask, &mo->xposmask);
+ convert_mask(&desc->yposmask, &mo->yposmask);
+ convert_mask(&desc->widthmask, &mo->widthmask);
+ convert_mask(&desc->heightmask, &mo->heightmask);
+ convert_mask(&desc->hflipmask, &mo->hflipmask);
+ convert_mask(&desc->vflipmask, &mo->vflipmask);
+ convert_mask(&desc->prioritymask, &mo->prioritymask);
+ convert_mask(&desc->neighbormask, &mo->neighbormask);
+ convert_mask(&desc->absolutemask, &mo->absolutemask);
+
+ /* copy in the basic data */
+ mo->gfxchanged = 0;
+
+ mo->linked = desc->linked;
+ mo->split = desc->split;
+ mo->reverse = desc->reverse;
+ mo->swapxy = desc->swapxy;
+ mo->nextneighbor = desc->nextneighbor;
+ mo->slipshift = desc->slipheight ? compute_log(desc->slipheight) : 0;
+ mo->slipoffset = desc->slipoffset;
+
+ mo->entrycount = round_to_powerof2(mo->linkmask.mask);
+ mo->entrybits = compute_log(mo->entrycount);
+ mo->bankcount = desc->banks;
+
+ mo->tilewidth = gfx->width;
+ mo->tileheight = gfx->height;
+ mo->tilexshift = compute_log(mo->tilewidth);
+ mo->tileyshift = compute_log(mo->tileheight);
+ mo->bitmapwidth = round_to_powerof2(mo->xposmask.mask);
+ mo->bitmapheight = round_to_powerof2(mo->yposmask.mask);
+ mo->bitmapxmask = mo->bitmapwidth - 1;
+ mo->bitmapymask = mo->bitmapheight - 1;
+
+ mo->spriteramsize = mo->bankcount * mo->entrycount;
+ mo->spriterammask = mo->spriteramsize - 1;
+ mo->slipramsize = mo->bitmapheight >> mo->slipshift;
+ mo->sliprammask = mo->slipramsize - 1;
+
+ mo->palettebase = desc->palettebase;
+ mo->maxcolors = desc->maxcolors / gfx->color_granularity;
+ mo->transpen = desc->transpen;
+
+ mo->bank = 0;
+ mo->xscroll = 0;
+ mo->yscroll = 0;
+
+ mo->maxperline = desc->maxlinks ? desc->maxlinks : 0x400;
+
+ convert_mask(&desc->specialmask, &mo->specialmask);
+ mo->specialvalue = desc->specialvalue;
+ mo->specialcb = desc->specialcb;
+ mo->codehighshift = compute_log(round_to_powerof2(mo->codemask.mask));
+
+ mo->slipram = (map == 0) ? &atarimo_0_slipram : &atarimo_1_slipram;
+
+ mo->last_link = -1;
+
+ /* allocate the temp bitmap */
+ mo->bitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ fillbitmap(mo->bitmap, desc->transpen, NULL);
+
+ /* allocate the spriteram */
+ mo->spriteram = auto_malloc(sizeof(mo->spriteram[0]) * mo->spriteramsize);
+
+ /* clear it to zero */
+ memset(mo->spriteram, 0, sizeof(mo->spriteram[0]) * mo->spriteramsize);
+
+ /* allocate the code lookup */
+ mo->codelookup = auto_malloc(sizeof(mo->codelookup[0]) * round_to_powerof2(mo->codemask.mask));
+
+ /* initialize it 1:1 */
+ for (i = 0; i < round_to_powerof2(mo->codemask.mask); i++)
+ mo->codelookup[i] = i;
+
+ /* allocate the color lookup */
+ mo->colorlookup = auto_malloc(sizeof(mo->colorlookup[0]) * round_to_powerof2(mo->colormask.mask));
+
+ /* initialize it 1:1 */
+ for (i = 0; i < round_to_powerof2(mo->colormask.mask); i++)
+ mo->colorlookup[i] = i;
+
+ /* allocate dirty grid */
+ mo->dirtywidth = (machine->screen[0].width >> mo->tilexshift) + 2;
+ mo->dirtyheight = (machine->screen[0].height >> mo->tileyshift) + 2;
+ mo->dirtygrid = auto_malloc(mo->dirtywidth * mo->dirtyheight);
+
+ /* allocate the gfx lookup */
+ mo->gfxlookup = auto_malloc(sizeof(mo->gfxlookup[0]) * round_to_powerof2(mo->gfxmask.mask));
+
+ /* initialize it with the gfxindex we were passed in */
+ for (i = 0; i < round_to_powerof2(mo->gfxmask.mask); i++)
+ mo->gfxlookup[i] = desc->gfxindex;
+
+ /* initialize the gfx elements so we have full control over colors */
+ init_gfxelement(machine, mo, desc->gfxindex);
+
+ /* start a timer to update a few times during refresh */
+ force_update_timer = timer_alloc(force_update);
+ timer_adjust(force_update_timer,video_screen_get_time_until_pos(0, 0, 0), 0, attotime_zero);
+
+ init_savestate(map, mo);
+
+ logerror("atarimo_init:\n");
+ logerror(" width=%d (shift=%d), height=%d (shift=%d)\n", mo->tilewidth, mo->tilexshift, mo->tileheight, mo->tileyshift);
+ logerror(" spriteram mask=%X, size=%d\n", mo->spriterammask, mo->spriteramsize);
+ logerror(" slipram mask=%X, size=%d\n", mo->sliprammask, mo->slipramsize);
+ logerror(" bitmap size=%dx%d\n", mo->bitmapwidth, mo->bitmapheight);
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_get_code_lookup: Returns a pointer to the code
+ lookup table.
+---------------------------------------------------------------*/
+
+UINT16 *atarimo_get_code_lookup(int map, int *size)
+{
+ struct atarimo_data *mo = &atarimo[map];
+
+ if (size)
+ *size = round_to_powerof2(mo->codemask.mask);
+ return mo->codelookup;
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_get_color_lookup: Returns a pointer to the color
+ lookup table.
+---------------------------------------------------------------*/
+
+UINT8 *atarimo_get_color_lookup(int map, int *size)
+{
+ struct atarimo_data *mo = &atarimo[map];
+
+ if (size)
+ *size = round_to_powerof2(mo->colormask.mask);
+ return mo->colorlookup;
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_get_gfx_lookup: Returns a pointer to the graphics
+ lookup table.
+---------------------------------------------------------------*/
+
+UINT8 *atarimo_get_gfx_lookup(int map, int *size)
+{
+ struct atarimo_data *mo = &atarimo[map];
+
+ mo->gfxchanged = 1;
+ if (size)
+ *size = round_to_powerof2(mo->gfxmask.mask);
+ return mo->gfxlookup;
+}
+
+
+/*---------------------------------------------------------------
+ update_active_list: Update the list of active objects.
+---------------------------------------------------------------*/
+
+static void update_active_list(struct atarimo_data *mo, int link)
+{
+ struct atarimo_entry *bankbase = &mo->spriteram[mo->bank << mo->entrybits];
+ UINT8 movisit[ATARIMO_MAXPERBANK];
+ struct atarimo_entry **current;
+ int i;
+
+ /* reset the visit map */
+ memset(movisit, 0, mo->entrycount);
+
+ /* remember the last link */
+ mo->last_link = link;
+
+ /* visit all the motion objects and copy their data into the display list */
+ for (i = 0, current = mo->activelist; i < mo->maxperline && !movisit[link]; i++)
+ {
+ struct atarimo_entry *modata = &bankbase[link];
+
+ /* copy the current entry into the list */
+ *current++ = modata;
+
+ /* link to the next object */
+ movisit[link] = 1;
+ if (mo->linked)
+ link = EXTRACT_DATA(modata, mo->linkmask);
+ else
+ link = (link + 1) & mo->linkmask.mask;
+ }
+
+ /* note the last entry */
+ mo->activelast = current;
+}
+
+
+/*---------------------------------------------------------------
+ get_dirty_base: Return the dirty grid pointer for a given
+ X and Y position.
+---------------------------------------------------------------*/
+
+INLINE UINT8 *get_dirty_base(struct atarimo_data *mo, int x, int y)
+{
+ UINT8 *result = mo->dirtygrid;
+ result += ((y >> mo->tileyshift) + 1) * mo->dirtywidth;
+ result += (x >> mo->tilexshift) + 1;
+ return result;
+}
+
+
+/*---------------------------------------------------------------
+ erase_dirty_grid: Erases the dirty grid within a given
+ cliprect.
+---------------------------------------------------------------*/
+
+static void erase_dirty_grid(struct atarimo_data *mo, const rectangle *cliprect)
+{
+ int sx = cliprect->min_x >> mo->tilexshift;
+ int ex = cliprect->max_x >> mo->tilexshift;
+ int sy = cliprect->min_y >> mo->tileyshift;
+ int ey = cliprect->max_y >> mo->tileyshift;
+ int y;
+
+ /* loop over all grid rows that intersect our cliprect */
+ for (y = sy; y <= ey; y++)
+ {
+ /* get the base pointer and memset the row */
+ UINT8 *dirtybase = get_dirty_base(mo, cliprect->min_x, y << mo->tileyshift);
+ memset(dirtybase, 0, ex - sx + 1);
+ }
+}
+
+
+/*---------------------------------------------------------------
+ convert_dirty_grid_to_rects: Converts a dirty grid into a
+ series of cliprects.
+---------------------------------------------------------------*/
+
+static void convert_dirty_grid_to_rects(struct atarimo_data *mo, const rectangle *cliprect, struct atarimo_rect_list *rectlist)
+{
+ int sx = cliprect->min_x >> mo->tilexshift;
+ int ex = cliprect->max_x >> mo->tilexshift;
+ int sy = cliprect->min_y >> mo->tileyshift;
+ int ey = cliprect->max_y >> mo->tileyshift;
+ int tilewidth = 1 << mo->tilexshift;
+ int tileheight = 1 << mo->tileyshift;
+ rectangle *rect;
+ int x, y;
+
+ /* initialize the rect list */
+ rectlist->numrects = 0;
+ rectlist->rect = mo->rectlist;
+ rect = &mo->rectlist[-1];
+
+ /* loop over all grid rows that intersect our cliprect */
+ for (y = sy; y <= ey; y++)
+ {
+ UINT8 *dirtybase = get_dirty_base(mo, cliprect->min_x, y << mo->tileyshift);
+ int can_add_to_existing = 0;
+
+ /* loop over all grid columns that intersect our cliprect */
+ for (x = sx; x <= ex; x++)
+ {
+ /* if this tile is dirty, add that to our rectlist */
+ if (*dirtybase++)
+ {
+ /* if we can't add to an existing rect, create a new one */
+ if (!can_add_to_existing)
+ {
+ /* advance pointers */
+ rectlist->numrects++;
+ rect++;
+
+ /* make a rect describing this grid square */
+ rect->min_x = x << mo->tilexshift;
+ rect->max_x = rect->min_x + tilewidth - 1;
+ rect->min_y = y << mo->tileyshift;
+ rect->max_y = rect->min_y + tileheight - 1;
+
+ /* neighboring grid squares can add to this one */
+ can_add_to_existing = 1;
+ }
+
+ /* if we can add to the previous rect, just expand its width */
+ else
+ rect->max_x += tilewidth;
+ }
+
+ /* once we hit a non-dirty square, we can no longer add on */
+ else
+ can_add_to_existing = 0;
+ }
+ }
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_render: Render the motion objects to the
+ destination bitmap.
+---------------------------------------------------------------*/
+
+mame_bitmap *atarimo_render(running_machine *machine, int map, const rectangle *cliprect, struct atarimo_rect_list *rectlist)
+{
+ struct atarimo_data *mo = &atarimo[map];
+ int startband, stopband, band, i;
+ rectangle *rect;
+
+ /* if the graphics info has changed, recompute */
+ if (mo->gfxchanged)
+ {
+ mo->gfxchanged = 0;
+ for (i = 0; i < round_to_powerof2(mo->gfxmask.mask); i++)
+ init_gfxelement(machine, mo, mo->gfxlookup[i]);
+ }
+
+ /* compute start/stop bands */
+ startband = ((cliprect->min_y + mo->yscroll - mo->slipoffset) & mo->bitmapymask) >> mo->slipshift;
+ stopband = ((cliprect->max_y + mo->yscroll - mo->slipoffset) & mo->bitmapymask) >> mo->slipshift;
+ if (startband > stopband)
+ startband -= mo->bitmapheight >> mo->slipshift;
+ if (!mo->slipshift)
+ stopband = startband;
+
+ /* erase the dirty grid */
+ erase_dirty_grid(mo, cliprect);
+
+ /* loop over SLIP bands */
+ for (band = startband; band <= stopband; band++)
+ {
+ struct atarimo_entry **first, **current, **last;
+ rectangle bandclip;
+ int link, step;
+
+ /* if we don't use SLIPs, just recapture from 0 */
+ if (!mo->slipshift)
+ {
+ link = 0;
+ bandclip = *cliprect;
+ }
+
+ /* otherwise, grab the SLIP and compute the bandrect */
+ else
+ {
+ int slipentry = band & mo->sliprammask;
+ link = ((*mo->slipram)[slipentry] >> mo->linkmask.shift) & mo->linkmask.mask;
+
+ /* start with the cliprect */
+ bandclip = *cliprect;
+
+ /* compute minimum Y and wrap around if necessary */
+ bandclip.min_y = ((band << mo->slipshift) - mo->yscroll + mo->slipoffset) & mo->bitmapymask;
+ if (bandclip.min_y > machine->screen[0].visarea.max_y)
+ bandclip.min_y -= mo->bitmapheight;
+
+ /* maximum Y is based on the minimum */
+ bandclip.max_y = bandclip.min_y + (1 << mo->slipshift) - 1;
+
+ /* keep within the cliprect */
+ sect_rect(&bandclip, cliprect);
+ }
+
+ /* if this matches the last link, we don't need to re-process the list */
+ if (link != mo->last_link)
+ update_active_list(mo, link);
+
+ /* set the start and end points */
+ if (mo->reverse)
+ {
+ first = mo->activelast - 1;
+ last = mo->activelist - 1;
+ step = -1;
+ }
+ else
+ {
+ first = mo->activelist;
+ last = mo->activelast;
+ step = 1;
+ }
+
+ /* initialize the parameters */
+ mo->next_xpos = 123456;
+
+ /* render the mos */
+ for (current = first; current != last; current += step)
+ mo_render_object(machine, mo, *current, &bandclip);
+ }
+
+ /* convert the dirty grid to a rectlist */
+ convert_dirty_grid_to_rects(mo, cliprect, rectlist);
+
+ /* clip the rectlist */
+ for (i = 0, rect = rectlist->rect; i < rectlist->numrects; i++, rect++)
+ sect_rect(rect, cliprect);
+
+ /* return the bitmap */
+ return mo->bitmap;
+}
+
+
+/*---------------------------------------------------------------
+ mo_render_object: Internal processing callback that
+ renders to the backing bitmap and then copies the result
+ to the destination.
+---------------------------------------------------------------*/
+
+static int mo_render_object(running_machine *machine, struct atarimo_data *mo, const struct atarimo_entry *entry, const rectangle *cliprect)
+{
+ int gfxindex = mo->gfxlookup[EXTRACT_DATA(entry, mo->gfxmask)];
+ const gfx_element *gfx = &mo->gfxelement[gfxindex];
+ mame_bitmap *bitmap = mo->bitmap;
+ int x, y, sx, sy;
+
+ /* extract data from the various words */
+ int code = mo->codelookup[EXTRACT_DATA(entry, mo->codemask)] | (EXTRACT_DATA(entry, mo->codehighmask) << mo->codehighshift);
+ int color = mo->colorlookup[EXTRACT_DATA(entry, mo->colormask)];
+ int xpos = EXTRACT_DATA(entry, mo->xposmask);
+ int ypos = -EXTRACT_DATA(entry, mo->yposmask);
+ int hflip = EXTRACT_DATA(entry, mo->hflipmask);
+ int vflip = EXTRACT_DATA(entry, mo->vflipmask);
+ int width = EXTRACT_DATA(entry, mo->widthmask) + 1;
+ int height = EXTRACT_DATA(entry, mo->heightmask) + 1;
+ int priority = EXTRACT_DATA(entry, mo->prioritymask);
+ int xadv, yadv, rendered = 0;
+ UINT8 *dirtybase;
+
+#ifdef TEMPDEBUG
+int temp = EXTRACT_DATA(entry, mo->codemask);
+if ((temp & 0xff00) == 0xc800)
+{
+ static UINT8 hits[256];
+ if (!hits[temp & 0xff])
+ {
+ fprintf(stderr, "code = %04X\n", temp);
+ hits[temp & 0xff] = 1;
+ }
+}
+#endif
+
+ /* compute the effective color, merging in priority */
+ color = (color * mo->gfxgranularity[gfxindex]) | (priority << ATARIMO_PRIORITY_SHIFT);
+ color += mo->palettebase;
+
+ /* add in the scroll positions if we're not in absolute coordinates */
+ if (!EXTRACT_DATA(entry, mo->absolutemask))
+ {
+ xpos -= mo->xscroll;
+ ypos -= mo->yscroll;
+ }
+
+ /* adjust for height */
+ ypos -= height << mo->tileyshift;
+
+ /* handle previous hold bits */
+ if (mo->next_xpos != 123456)
+ xpos = mo->next_xpos;
+ mo->next_xpos = 123456;
+
+ /* check for the hold bit */
+ if (EXTRACT_DATA(entry, mo->neighbormask))
+ {
+ if (!mo->nextneighbor)
+ xpos = mo->last_xpos + mo->tilewidth;
+ else
+ mo->next_xpos = xpos + mo->tilewidth;
+ }
+ mo->last_xpos = xpos;
+
+ /* adjust the final coordinates */
+ xpos &= mo->bitmapxmask;
+ ypos &= mo->bitmapymask;
+ if (xpos > machine->screen[0].visarea.max_x) xpos -= mo->bitmapwidth;
+ if (ypos > machine->screen[0].visarea.max_y) ypos -= mo->bitmapheight;
+
+ /* is this one special? */
+ if (mo->specialmask.mask != 0 && EXTRACT_DATA(entry, mo->specialmask) == mo->specialvalue)
+ {
+ if (mo->specialcb)
+ return (*mo->specialcb)(bitmap, cliprect, code, color, xpos, ypos, NULL);
+ return 0;
+ }
+
+ /* adjust for h flip */
+ xadv = mo->tilewidth;
+ if (hflip)
+ {
+ xpos += (width - 1) << mo->tilexshift;
+ xadv = -xadv;
+ }
+
+ /* adjust for v flip */
+ yadv = mo->tileheight;
+ if (vflip)
+ {
+ ypos += (height - 1) << mo->tileyshift;
+ yadv = -yadv;
+ }
+
+ /* standard order is: loop over Y first, then X */
+ if (!mo->swapxy)
+ {
+ /* loop over the height */
+ for (y = 0, sy = ypos; y < height; y++, sy += yadv)
+ {
+ /* clip the Y coordinate */
+ if (sy <= cliprect->min_y - mo->tileheight)
+ {
+ code += width;
+ continue;
+ }
+ else if (sy > cliprect->max_y)
+ break;
+
+ /* loop over the width */
+ for (x = 0, sx = xpos; x < width; x++, sx += xadv, code++)
+ {
+ /* clip the X coordinate */
+ if (sx <= -cliprect->min_x - mo->tilewidth || sx > cliprect->max_x)
+ continue;
+
+ /* draw the sprite */
+ drawgfx(bitmap, gfx, code, color, hflip, vflip, sx, sy, cliprect, TRANSPARENCY_PEN_RAW, mo->transpen);
+ rendered = 1;
+
+ /* mark the grid dirty */
+ dirtybase = get_dirty_base(mo, sx, sy);
+ dirtybase[0] = 1;
+ dirtybase[1] = 1;
+ dirtybase[mo->dirtywidth] = 1;
+ dirtybase[mo->dirtywidth + 1] = 1;
+ }
+ }
+ }
+
+ /* alternative order is swapped */
+ else
+ {
+ /* loop over the width */
+ for (x = 0, sx = xpos; x < width; x++, sx += xadv)
+ {
+ /* clip the X coordinate */
+ if (sx <= cliprect->min_x - mo->tilewidth)
+ {
+ code += height;
+ continue;
+ }
+ else if (sx > cliprect->max_x)
+ break;
+
+ /* loop over the height */
+ dirtybase = get_dirty_base(mo, sx, ypos);
+ for (y = 0, sy = ypos; y < height; y++, sy += yadv, code++)
+ {
+ /* clip the X coordinate */
+ if (sy <= -cliprect->min_y - mo->tileheight || sy > cliprect->max_y)
+ continue;
+
+ /* draw the sprite */
+ drawgfx(bitmap, gfx, code, color, hflip, vflip, sx, sy, cliprect, TRANSPARENCY_PEN_RAW, mo->transpen);
+ rendered = 1;
+
+ /* mark the grid dirty */
+ dirtybase = get_dirty_base(mo, sx, sy);
+ dirtybase[0] = 1;
+ dirtybase[1] = 1;
+ dirtybase[mo->dirtywidth] = 1;
+ dirtybase[mo->dirtywidth + 1] = 1;
+ }
+ }
+ }
+
+ return rendered;
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_set_bank: Set the banking value for
+ the motion objects.
+---------------------------------------------------------------*/
+
+void atarimo_set_bank(int map, int bank)
+{
+ struct atarimo_data *mo = &atarimo[map];
+ if (mo->bank != bank)
+ {
+ mo->bank = bank;
+ mo->last_link = -1;
+ }
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_set_xscroll: Set the horizontal scroll value for
+ the motion objects.
+---------------------------------------------------------------*/
+
+void atarimo_set_xscroll(int map, int xscroll)
+{
+ struct atarimo_data *mo = &atarimo[map];
+ mo->xscroll = xscroll;
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_set_yscroll: Set the vertical scroll value for
+ the motion objects.
+---------------------------------------------------------------*/
+
+void atarimo_set_yscroll(int map, int yscroll)
+{
+ struct atarimo_data *mo = &atarimo[map];
+ mo->yscroll = yscroll;
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_get_bank: Returns the banking value
+ for the motion objects.
+---------------------------------------------------------------*/
+
+int atarimo_get_bank(int map)
+{
+ return atarimo[map].bank;
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_get_xscroll: Returns the horizontal scroll value
+ for the motion objects.
+---------------------------------------------------------------*/
+
+int atarimo_get_xscroll(int map)
+{
+ return atarimo[map].xscroll;
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_get_yscroll: Returns the vertical scroll value for
+ the motion objects.
+---------------------------------------------------------------*/
+
+int atarimo_get_yscroll(int map)
+{
+ return atarimo[map].yscroll;
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_0_spriteram_w: Write handler for the spriteram.
+---------------------------------------------------------------*/
+
+WRITE16_HANDLER( atarimo_0_spriteram_w )
+{
+ int entry, idx, bank;
+
+ COMBINE_DATA(&atarimo_0_spriteram[offset]);
+ if (atarimo[0].split)
+ {
+ entry = offset & atarimo[0].linkmask.mask;
+ idx = (offset >> atarimo[0].entrybits) & 3;
+ }
+ else
+ {
+ entry = (offset >> 2) & atarimo[0].linkmask.mask;
+ idx = offset & 3;
+ }
+ bank = offset >> (2 + atarimo[0].entrybits);
+ COMBINE_DATA(&atarimo[0].spriteram[(bank << atarimo[0].entrybits) + entry].data[idx]);
+ atarimo[0].last_link = -1;
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_1_spriteram_w: Write handler for the spriteram.
+---------------------------------------------------------------*/
+
+WRITE16_HANDLER( atarimo_1_spriteram_w )
+{
+ int entry, idx, bank;
+
+ COMBINE_DATA(&atarimo_1_spriteram[offset]);
+ if (atarimo[1].split)
+ {
+ entry = offset & atarimo[1].linkmask.mask;
+ idx = (offset >> atarimo[1].entrybits) & 3;
+ }
+ else
+ {
+ entry = (offset >> 2) & atarimo[1].linkmask.mask;
+ idx = offset & 3;
+ }
+ bank = offset >> (2 + atarimo[1].entrybits);
+ COMBINE_DATA(&atarimo[1].spriteram[(bank << atarimo[1].entrybits) + entry].data[idx]);
+ atarimo[1].last_link = -1;
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_0_spriteram_expanded_w: Write handler for the
+ expanded form of spriteram.
+---------------------------------------------------------------*/
+
+WRITE16_HANDLER( atarimo_0_spriteram_expanded_w )
+{
+ int entry, idx, bank;
+
+ COMBINE_DATA(&atarimo_0_spriteram[offset]);
+ if (!(offset & 1))
+ {
+ offset >>= 1;
+ if (atarimo[0].split)
+ {
+ entry = offset & atarimo[0].linkmask.mask;
+ idx = (offset >> atarimo[0].entrybits) & 3;
+ }
+ else
+ {
+ entry = (offset >> 2) & atarimo[0].linkmask.mask;
+ idx = offset & 3;
+ }
+ bank = offset >> (2 + atarimo[0].entrybits);
+ COMBINE_DATA(&atarimo[0].spriteram[(bank << atarimo[0].entrybits) + entry].data[idx]);
+ atarimo[0].last_link = -1;
+ }
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_0_slipram_w: Write handler for the slipram.
+---------------------------------------------------------------*/
+
+WRITE16_HANDLER( atarimo_0_slipram_w )
+{
+ COMBINE_DATA(&atarimo_0_slipram[offset]);
+}
+
+
+/*---------------------------------------------------------------
+ atarimo_1_slipram_w: Write handler for the slipram.
+---------------------------------------------------------------*/
+
+WRITE16_HANDLER( atarimo_1_slipram_w )
+{
+ COMBINE_DATA(&atarimo_1_slipram[offset]);
+}
diff --git a/src/mame/video/atarimo.h b/src/mame/video/atarimo.h
new file mode 100644
index 00000000000..41395169b14
--- /dev/null
+++ b/src/mame/video/atarimo.h
@@ -0,0 +1,133 @@
+/*##########################################################################
+
+ atarimo.h
+
+ Common motion object management functions for Atari raster games.
+
+##########################################################################*/
+
+#ifndef __ATARIMO__
+#define __ATARIMO__
+
+
+/*##########################################################################
+ CONSTANTS
+##########################################################################*/
+
+/* maximum number of motion object processors */
+#define ATARIMO_MAX 2
+
+/* maximum objects per bank */
+#define ATARIMO_MAXPERBANK 1024
+
+/* shift to get to priority in raw data */
+#define ATARIMO_PRIORITY_SHIFT 12
+#define ATARIMO_PRIORITY_MASK ((~0 << ATARIMO_PRIORITY_SHIFT) & 0xffff)
+#define ATARIMO_DATA_MASK (ATARIMO_PRIORITY_MASK ^ 0xffff)
+
+
+
+/*##########################################################################
+ TYPES & STRUCTURES
+##########################################################################*/
+
+/* callback for special processing */
+typedef int (*atarimo_special_cb)(mame_bitmap *bitmap, const rectangle *clip, int code, int color, int xpos, int ypos, rectangle *mobounds);
+
+/* description for a four-word mask */
+struct atarimo_entry
+{
+ UINT16 data[4];
+};
+
+/* description of the motion objects */
+struct atarimo_desc
+{
+ UINT8 gfxindex; /* index to which gfx system */
+ UINT8 banks; /* number of motion object banks */
+ UINT8 linked; /* are the entries linked? */
+ UINT8 split; /* are the entries split? */
+ UINT8 reverse; /* render in reverse order? */
+ UINT8 swapxy; /* render in swapped X/Y order? */
+ UINT8 nextneighbor; /* does the neighbor bit affect the next object? */
+ UINT16 slipheight; /* pixels per SLIP entry (0 for no-slip) */
+ UINT8 slipoffset; /* pixel offset for SLIPs */
+ UINT16 maxlinks; /* maximum number of links to visit/scanline (0=all) */
+
+ UINT16 palettebase; /* base palette entry */
+ UINT16 maxcolors; /* maximum number of colors */
+ UINT8 transpen; /* transparent pen index */
+
+ struct atarimo_entry linkmask; /* mask for the link */
+ struct atarimo_entry gfxmask; /* mask for the graphics bank */
+ struct atarimo_entry codemask; /* mask for the code index */
+ struct atarimo_entry codehighmask; /* mask for the upper code index */
+ struct atarimo_entry colormask; /* mask for the color */
+ struct atarimo_entry xposmask; /* mask for the X position */
+ struct atarimo_entry yposmask; /* mask for the Y position */
+ struct atarimo_entry widthmask; /* mask for the width, in tiles*/
+ struct atarimo_entry heightmask; /* mask for the height, in tiles */
+ struct atarimo_entry hflipmask; /* mask for the horizontal flip */
+ struct atarimo_entry vflipmask; /* mask for the vertical flip */
+ struct atarimo_entry prioritymask; /* mask for the priority */
+ struct atarimo_entry neighbormask; /* mask for the neighbor */
+ struct atarimo_entry absolutemask; /* mask for absolute coordinates */
+
+ struct atarimo_entry specialmask; /* mask for the special value */
+ UINT16 specialvalue; /* resulting value to indicate "special" */
+ atarimo_special_cb specialcb; /* callback routine for special entries */
+};
+
+/* rectangle list */
+struct atarimo_rect_list
+{
+ int numrects;
+ rectangle * rect;
+};
+
+
+/*##########################################################################
+ FUNCTION PROTOTYPES
+##########################################################################*/
+
+/* setup/shutdown */
+void atarimo_init(running_machine *machine, int map, const struct atarimo_desc *desc);
+UINT16 *atarimo_get_code_lookup(int map, int *size);
+UINT8 *atarimo_get_color_lookup(int map, int *size);
+UINT8 *atarimo_get_gfx_lookup(int map, int *size);
+
+/* core processing */
+mame_bitmap *atarimo_render(running_machine *machine, int map, const rectangle *cliprect, struct atarimo_rect_list *rectlist);
+
+/* atrribute setters */
+void atarimo_set_bank(int map, int bank);
+void atarimo_set_xscroll(int map, int xscroll);
+void atarimo_set_yscroll(int map, int yscroll);
+
+/* atrribute getters */
+int atarimo_get_bank(int map);
+int atarimo_get_xscroll(int map);
+int atarimo_get_yscroll(int map);
+
+/* write handlers */
+WRITE16_HANDLER( atarimo_0_spriteram_w );
+WRITE16_HANDLER( atarimo_0_spriteram_expanded_w );
+WRITE16_HANDLER( atarimo_0_slipram_w );
+
+WRITE16_HANDLER( atarimo_1_spriteram_w );
+WRITE16_HANDLER( atarimo_1_slipram_w );
+
+
+
+/*##########################################################################
+ GLOBAL VARIABLES
+##########################################################################*/
+
+extern UINT16 *atarimo_0_spriteram;
+extern UINT16 *atarimo_0_slipram;
+
+extern UINT16 *atarimo_1_spriteram;
+extern UINT16 *atarimo_1_slipram;
+
+
+#endif
diff --git a/src/mame/video/atarirle.c b/src/mame/video/atarirle.c
new file mode 100644
index 00000000000..f5e354ede30
--- /dev/null
+++ b/src/mame/video/atarirle.c
@@ -0,0 +1,1760 @@
+/*##########################################################################
+
+ atarirle.c
+
+ RLE sprite handling for early-to-mid 90's Atari raster games.
+
+############################################################################
+
+ Description:
+
+ Beginning with Hydra, and continuing through to Primal Rage, Atari used
+ RLE-compressed sprites. These sprites were decoded, colored, and scaled
+ on the fly using an AMD 29C101 ALU unit. The instructions for the ALU
+ were read from 3 512-byte PROMs and fed into the instruction input.
+
+ See the bottom of the source for more details on the operation of these
+ components.
+
+##########################################################################*/
+
+#include "driver.h"
+#include "atarirle.h"
+
+
+/*##########################################################################
+ TYPES & STRUCTURES
+##########################################################################*/
+
+/* internal structure containing a word index, shift and mask */
+struct atarirle_mask
+{
+ int word; /* word index */
+ int shift; /* shift amount */
+ int mask; /* final mask */
+};
+
+/* internal structure for sorting the motion objects */
+struct mo_sort_entry
+{
+ struct mo_sort_entry *next;
+ int entry;
+};
+
+/* internal structure describing each object in the ROMs */
+struct atarirle_info
+{
+ INT16 width;
+ INT16 height;
+ INT16 xoffs;
+ INT16 yoffs;
+ UINT8 bpp;
+ const UINT16 * table;
+ const UINT16 * data;
+};
+
+/* internal structure containing the state of the motion objects */
+struct atarirle_data
+{
+ int bitmapwidth; /* width of the full playfield bitmap */
+ int bitmapheight; /* height of the full playfield bitmap */
+ int bitmapxmask; /* x coordinate mask for the playfield bitmap */
+ int bitmapymask; /* y coordinate mask for the playfield bitmap */
+
+ int spriterammask; /* combined mask when accessing sprite RAM with raw addresses */
+ int spriteramsize; /* total size of sprite RAM, in entries */
+
+ int palettebase; /* base palette entry */
+ int maxcolors; /* maximum number of colors */
+
+ rectangle cliprect; /* clipping rectangle */
+
+ struct atarirle_mask codemask; /* mask for the code index */
+ struct atarirle_mask colormask; /* mask for the color */
+ struct atarirle_mask xposmask; /* mask for the X position */
+ struct atarirle_mask yposmask; /* mask for the Y position */
+ struct atarirle_mask scalemask; /* mask for the scale factor */
+ struct atarirle_mask hflipmask; /* mask for the horizontal flip */
+ struct atarirle_mask ordermask; /* mask for the order */
+ struct atarirle_mask prioritymask; /* mask for the priority */
+ struct atarirle_mask vrammask; /* mask for the VRAM target */
+
+ const UINT16 * rombase; /* pointer to the base of the GFX ROM */
+ int romlength; /* length of the GFX ROM */
+ int objectcount; /* number of objects in the ROM */
+ struct atarirle_info *info; /* list of info records */
+ struct atarirle_entry *spriteram; /* pointer to sprite RAM */
+
+ mame_bitmap *vram[2][2]; /* pointers to VRAM bitmaps and backbuffers */
+ int partial_scanline; /* partial update scanline */
+
+ UINT8 control_bits; /* current control bits */
+ UINT8 command; /* current command */
+ UINT8 is32bit; /* 32-bit or 16-bit? */
+ UINT16 checksums[256]; /* checksums for each 0x40000 bytes */
+};
+
+
+
+/*##########################################################################
+ MACROS
+##########################################################################*/
+
+/* data extraction */
+#define EXTRACT_DATA(_input, _mask) (((_input)->data[(_mask).word] >> (_mask).shift) & (_mask).mask)
+
+
+
+/*##########################################################################
+ GLOBAL VARIABLES
+##########################################################################*/
+
+UINT16 *atarirle_0_spriteram;
+UINT32 *atarirle_0_spriteram32;
+
+//UINT16 *atarirle_0_command;
+//UINT32 *atarirle_0_command32;
+
+//UINT16 *atarirle_0_table;
+//UINT32 *atarirle_0_table32;
+
+int atarirle_hilite_index = -1;
+
+
+
+/*##########################################################################
+ STATIC VARIABLES
+##########################################################################*/
+
+static struct atarirle_data atarirle[ATARIRLE_MAX];
+
+static UINT8 rle_bpp[8];
+static UINT16 *rle_table[8];
+
+
+
+/*##########################################################################
+ STATIC FUNCTION DECLARATIONS
+##########################################################################*/
+
+static void build_rle_tables(void);
+static int count_objects(const UINT16 *base, int length);
+static void prescan_rle(const struct atarirle_data *mo, int which);
+static void sort_and_render(struct atarirle_data *mo);
+static void compute_checksum(struct atarirle_data *mo);
+static void draw_rle(struct atarirle_data *mo, mame_bitmap *bitmap, int code, int color, int hflip, int vflip,
+ int x, int y, int xscale, int yscale, const rectangle *clip);
+static void draw_rle_zoom(mame_bitmap *bitmap, const struct atarirle_info *gfx,
+ UINT32 palette, int sx, int sy, int scalex, int scaley,
+ const rectangle *clip);
+static void draw_rle_zoom_hflip(mame_bitmap *bitmap, const struct atarirle_info *gfx,
+ UINT32 palette, int sx, int sy, int scalex, int scaley,
+ const rectangle *clip);
+
+
+
+/*##########################################################################
+ INLINE FUNCTIONS
+##########################################################################*/
+
+/*---------------------------------------------------------------
+ compute_log: Computes the number of bits necessary to
+ hold a given value. The input must be an even power of
+ two.
+---------------------------------------------------------------*/
+
+INLINE int compute_log(int value)
+{
+ int log = 0;
+
+ if (value == 0)
+ return -1;
+ while (!(value & 1))
+ log++, value >>= 1;
+ if (value != 1)
+ return -1;
+ return log;
+}
+
+
+/*---------------------------------------------------------------
+ round_to_powerof2: Rounds a number up to the nearest
+ power of 2. Even powers of 2 are rounded up to the
+ next greatest power (e.g., 4 returns 8).
+---------------------------------------------------------------*/
+
+INLINE int round_to_powerof2(int value)
+{
+ int log = 0;
+
+ if (value == 0)
+ return 1;
+ while ((value >>= 1) != 0)
+ log++;
+ return 1 << (log + 1);
+}
+
+
+/*---------------------------------------------------------------
+ collapse_bits: Moving right-to-left, for each 1 bit in
+ the mask, copy the corresponding bit from the input
+ value into the result, packing the bits along the way.
+---------------------------------------------------------------*/
+
+INLINE int collapse_bits(int value, int mask)
+{
+ int testmask, ormask;
+ int result = 0;
+
+ for (testmask = ormask = 1; testmask != 0; testmask <<= 1)
+ if (mask & testmask)
+ {
+ if (value & testmask)
+ result |= ormask;
+ ormask <<= 1;
+ }
+ return result;
+}
+
+
+/*---------------------------------------------------------------
+ convert_mask: Converts a 4-word mask into a word index,
+ shift, and adjusted mask. Returns 0 if invalid.
+---------------------------------------------------------------*/
+
+INLINE int convert_mask(const struct atarirle_entry *input, struct atarirle_mask *result)
+{
+ int i, temp;
+
+ /* determine the word and make sure it's only 1 */
+ result->word = -1;
+ for (i = 0; i < 8; i++)
+ if (input->data[i])
+ {
+ if (result->word == -1)
+ result->word = i;
+ else
+ return 0;
+ }
+
+ /* if all-zero, it's valid */
+ if (result->word == -1)
+ {
+ result->word = result->shift = result->mask = 0;
+ return 1;
+ }
+
+ /* determine the shift and final mask */
+ result->shift = 0;
+ temp = input->data[result->word];
+ while (!(temp & 1))
+ {
+ result->shift++;
+ temp >>= 1;
+ }
+ result->mask = temp;
+ return 1;
+}
+
+
+
+/*##########################################################################
+ GLOBAL FUNCTIONS
+##########################################################################*/
+
+/*---------------------------------------------------------------
+ atarirle_init: Configures the motion objects using the input
+ description. Allocates all memory necessary and generates
+ the attribute lookup table.
+---------------------------------------------------------------*/
+
+void atarirle_init(int map, const struct atarirle_desc *desc)
+{
+ const UINT16 *base = (const UINT16 *)memory_region(desc->region);
+ struct atarirle_data *mo = &atarirle[map];
+ int i;
+
+ /* verify the map index */
+ assert_always(map >= 0 && map < ATARIRLE_MAX, "Invalid map index");
+
+ /* build and allocate the generic tables */
+ build_rle_tables();
+
+ /* determine the masks first */
+ convert_mask(&desc->codemask, &mo->codemask);
+ convert_mask(&desc->colormask, &mo->colormask);
+ convert_mask(&desc->xposmask, &mo->xposmask);
+ convert_mask(&desc->yposmask, &mo->yposmask);
+ convert_mask(&desc->scalemask, &mo->scalemask);
+ convert_mask(&desc->hflipmask, &mo->hflipmask);
+ convert_mask(&desc->ordermask, &mo->ordermask);
+ convert_mask(&desc->prioritymask, &mo->prioritymask);
+ convert_mask(&desc->vrammask, &mo->vrammask);
+
+ /* copy in the basic data */
+ mo->bitmapwidth = round_to_powerof2(mo->xposmask.mask);
+ mo->bitmapheight = round_to_powerof2(mo->yposmask.mask);
+ mo->bitmapxmask = mo->bitmapwidth - 1;
+ mo->bitmapymask = mo->bitmapheight - 1;
+
+ mo->spriteramsize = desc->spriteramentries;
+ mo->spriterammask = desc->spriteramentries - 1;
+
+ mo->palettebase = desc->palettebase;
+ mo->maxcolors = desc->maxcolors / 16;
+
+ mo->rombase = base;
+ mo->romlength = memory_region_length(desc->region);
+ mo->objectcount = count_objects(base, mo->romlength);
+
+ mo->cliprect = Machine->screen[0].visarea;
+ if (desc->rightclip)
+ {
+ mo->cliprect.min_x = desc->leftclip;
+ mo->cliprect.max_x = desc->rightclip;
+ }
+
+ /* compute the checksums */
+ memset(mo->checksums, 0, sizeof(mo->checksums));
+ for (i = 0; i < mo->romlength / 0x20000; i++)
+ {
+ const UINT16 *csbase = &mo->rombase[0x10000 * i];
+ int cursum = 0, j;
+ for (j = 0; j < 0x10000; j++)
+ cursum += *csbase++;
+ mo->checksums[i] = cursum;
+ }
+
+ /* allocate the object info */
+ mo->info = auto_malloc(sizeof(mo->info[0]) * mo->objectcount);
+
+ /* fill in the data */
+ memset(mo->info, 0, sizeof(mo->info[0]) * mo->objectcount);
+ for (i = 0; i < mo->objectcount; i++)
+ prescan_rle(mo, i);
+
+ /* allocate the spriteram */
+ mo->spriteram = auto_malloc(sizeof(mo->spriteram[0]) * mo->spriteramsize);
+
+ /* clear it to zero */
+ memset(mo->spriteram, 0, sizeof(mo->spriteram[0]) * mo->spriteramsize);
+
+ /* allocate bitmaps */
+ mo->vram[0][0] = auto_bitmap_alloc(Machine->screen[0].width, Machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+ mo->vram[0][1] = auto_bitmap_alloc(Machine->screen[0].width, Machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+ fillbitmap(mo->vram[0][0], 0, NULL);
+ fillbitmap(mo->vram[0][1], 0, NULL);
+
+ /* allocate alternate bitmaps if needed */
+ if (mo->vrammask.mask != 0)
+ {
+ mo->vram[1][0] = auto_bitmap_alloc(Machine->screen[0].width, Machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+ mo->vram[1][1] = auto_bitmap_alloc(Machine->screen[0].width, Machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+ fillbitmap(mo->vram[1][0], 0, NULL);
+ fillbitmap(mo->vram[1][1], 0, NULL);
+ }
+
+ mo->partial_scanline = -1;
+}
+
+
+
+/*---------------------------------------------------------------
+ atarirle_control_w: Write handler for MO control bits.
+---------------------------------------------------------------*/
+
+void atarirle_control_w(int map, UINT8 bits)
+{
+ struct atarirle_data *mo = &atarirle[map];
+ int scanline = video_screen_get_vpos(0);
+ int oldbits = mo->control_bits;
+
+//logerror("atarirle_control_w(%d)\n", bits);
+
+ /* do nothing if nothing changed */
+ if (oldbits == bits)
+ return;
+
+ /* force a partial update first */
+ video_screen_update_partial(0, scanline);
+
+ /* if the erase flag was set, erase the front map */
+ if (oldbits & ATARIRLE_CONTROL_ERASE)
+ {
+ rectangle cliprect = mo->cliprect;
+
+ /* compute the top and bottom of the rect */
+ if (mo->partial_scanline + 1 > cliprect.min_y)
+ cliprect.min_y = mo->partial_scanline + 1;
+ if (scanline < cliprect.max_y)
+ cliprect.max_y = scanline;
+
+//logerror(" partial erase %d-%d (frame %d)\n", cliprect.min_y, cliprect.max_y, (oldbits & ATARIRLE_CONTROL_FRAME) >> 2);
+
+ /* erase the bitmap */
+ fillbitmap(mo->vram[0][(oldbits & ATARIRLE_CONTROL_FRAME) >> 2], 0, &cliprect);
+ if (mo->vrammask.mask != 0)
+ fillbitmap(mo->vram[1][(oldbits & ATARIRLE_CONTROL_FRAME) >> 2], 0, &cliprect);
+ }
+
+ /* update the bits */
+ mo->control_bits = bits;
+
+ /* if mogo is set, do a render on the rising edge */
+ if (!(oldbits & ATARIRLE_CONTROL_MOGO) && (bits & ATARIRLE_CONTROL_MOGO))
+ {
+ if (mo->command == ATARIRLE_COMMAND_DRAW)
+ sort_and_render(mo);
+ else if (mo->command == ATARIRLE_COMMAND_CHECKSUM)
+ compute_checksum(mo);
+ }
+
+ /* remember where we left off */
+ mo->partial_scanline = scanline;
+}
+
+
+
+/*---------------------------------------------------------------
+ atarirle_control_w: Write handler for MO command bits.
+---------------------------------------------------------------*/
+
+void atarirle_command_w(int map, UINT8 command)
+{
+ struct atarirle_data *mo = &atarirle[map];
+ mo->command = command;
+}
+
+
+
+/*---------------------------------------------------------------
+ video_eof_atarirle: Flush remaining changes.
+---------------------------------------------------------------*/
+
+VIDEO_EOF( atarirle )
+{
+ int i;
+
+//logerror("video_eof_atarirle\n");
+
+ /* loop over all RLE handlers */
+ for (i = 0; i < ATARIRLE_MAX; i++)
+ {
+ struct atarirle_data *mo = &atarirle[i];
+
+ /* if the erase flag is set, erase to the end of the screen */
+ if (mo->control_bits & ATARIRLE_CONTROL_ERASE)
+ {
+ rectangle cliprect = mo->cliprect;
+
+ /* compute top only; bottom is equal to visible_area */
+ if (mo->partial_scanline + 1 > cliprect.min_y)
+ cliprect.min_y = mo->partial_scanline + 1;
+
+//logerror(" partial erase %d-%d (frame %d)\n", cliprect.min_y, cliprect.max_y, (mo->control_bits & ATARIRLE_CONTROL_FRAME) >> 2);
+
+ /* erase the bitmap */
+ fillbitmap(mo->vram[0][(mo->control_bits & ATARIRLE_CONTROL_FRAME) >> 2], 0, &cliprect);
+ if (mo->vrammask.mask != 0)
+ fillbitmap(mo->vram[1][(mo->control_bits & ATARIRLE_CONTROL_FRAME) >> 2], 0, &cliprect);
+ }
+
+ /* reset the partial scanline to -1 so we can detect full updates */
+ mo->partial_scanline = -1;
+ }
+}
+
+
+
+/*---------------------------------------------------------------
+ atarirle_0_spriteram_w: Write handler for the spriteram.
+---------------------------------------------------------------*/
+
+WRITE16_HANDLER( atarirle_0_spriteram_w )
+{
+ int entry = (offset >> 3) & atarirle[0].spriterammask;
+ int idx = offset & 7;
+
+ /* combine raw data */
+ COMBINE_DATA(&atarirle_0_spriteram[offset]);
+
+ /* store a copy in our local spriteram */
+ atarirle[0].spriteram[entry].data[idx] = atarirle_0_spriteram[offset];
+ atarirle[0].is32bit = 0;
+}
+
+
+
+/*---------------------------------------------------------------
+ atarirle_0_spriteram32_w: Write handler for the spriteram.
+---------------------------------------------------------------*/
+
+WRITE32_HANDLER( atarirle_0_spriteram32_w )
+{
+ int entry = (offset >> 2) & atarirle[0].spriterammask;
+ int idx = 2 * (offset & 3);
+
+ /* combine raw data */
+ COMBINE_DATA(&atarirle_0_spriteram32[offset]);
+
+ /* store a copy in our local spriteram */
+ atarirle[0].spriteram[entry].data[idx+0] = atarirle_0_spriteram32[offset] >> 16;
+ atarirle[0].spriteram[entry].data[idx+1] = atarirle_0_spriteram32[offset];
+ atarirle[0].is32bit = 1;
+}
+
+
+
+/*---------------------------------------------------------------
+ atarirle_get_vram: Return the VRAM bitmap.
+---------------------------------------------------------------*/
+
+mame_bitmap *atarirle_get_vram(int map, int idx)
+{
+ struct atarirle_data *mo = &atarirle[map];
+//logerror("atarirle_get_vram (frame %d)\n", (mo->control_bits & ATARIRLE_CONTROL_FRAME) >> 2);
+ return mo->vram[idx][(mo->control_bits & ATARIRLE_CONTROL_FRAME) >> 2];
+}
+
+
+
+/*---------------------------------------------------------------
+ build_rle_tables: Builds internal table for RLE mapping.
+---------------------------------------------------------------*/
+
+static void build_rle_tables(void)
+{
+ UINT16 *base;
+ int i;
+
+ /* allocate all 5 tables */
+ base = auto_malloc(0x500 * sizeof(UINT16));
+
+ /* assign the tables */
+ rle_table[0] = &base[0x000];
+ rle_table[1] = &base[0x100];
+ rle_table[2] = rle_table[3] = &base[0x200];
+ rle_table[4] = rle_table[6] = &base[0x300];
+ rle_table[5] = rle_table[7] = &base[0x400];
+
+ /* set the bpps */
+ rle_bpp[0] = 4;
+ rle_bpp[1] = rle_bpp[2] = rle_bpp[3] = 5;
+ rle_bpp[4] = rle_bpp[5] = rle_bpp[6] = rle_bpp[7] = 6;
+
+ /* build the 4bpp table */
+ for (i = 0; i < 256; i++)
+ rle_table[0][i] = (((i & 0xf0) + 0x10) << 4) | (i & 0x0f);
+
+ /* build the 5bpp table */
+ for (i = 0; i < 256; i++)
+ rle_table[2][i] = (((i & 0xe0) + 0x20) << 3) | (i & 0x1f);
+
+ /* build the special 5bpp table */
+ for (i = 0; i < 256; i++)
+ {
+ if ((i & 0x0f) == 0)
+ rle_table[1][i] = (((i & 0xf0) + 0x10) << 4) | (i & 0x0f);
+ else
+ rle_table[1][i] = (((i & 0xe0) + 0x20) << 3) | (i & 0x1f);
+ }
+
+ /* build the 6bpp table */
+ for (i = 0; i < 256; i++)
+ rle_table[5][i] = (((i & 0xc0) + 0x40) << 2) | (i & 0x3f);
+
+ /* build the special 6bpp table */
+ for (i = 0; i < 256; i++)
+ {
+ if ((i & 0x0f) == 0)
+ rle_table[4][i] = (((i & 0xf0) + 0x10) << 4) | (i & 0x0f);
+ else
+ rle_table[4][i] = (((i & 0xc0) + 0x40) << 2) | (i & 0x3f);
+ }
+}
+
+
+
+/*---------------------------------------------------------------
+ count_objects: Determines the number of objects in the
+ motion object ROM.
+---------------------------------------------------------------*/
+
+int count_objects(const UINT16 *base, int length)
+{
+ int lowest_address = length;
+ int i;
+
+ /* first determine the lowest address of all objects */
+ for (i = 0; i < lowest_address; i += 4)
+ {
+ int offset = ((base[i + 2] & 0xff) << 16) | base[i + 3];
+//logerror("count_objects: i=%d offset=%08X\n", i, offset);
+ if (offset > i && offset < lowest_address)
+ lowest_address = offset;
+ }
+
+ /* that determines how many objects */
+ return lowest_address / 4;
+}
+
+
+
+/*---------------------------------------------------------------
+ prescan_rle: Prescans an RLE object, computing the
+ width, height, and other goodies.
+---------------------------------------------------------------*/
+
+static void prescan_rle(const struct atarirle_data *mo, int which)
+{
+ struct atarirle_info *rledata = &mo->info[which];
+ UINT16 *base = (UINT16 *)&mo->rombase[which * 4];
+ const UINT16 *end = mo->rombase + mo->romlength / 2;
+ int width = 0, height, flags, offset;
+ const UINT16 *table;
+
+ /* look up the offset */
+ rledata->xoffs = (INT16)base[0];
+ rledata->yoffs = (INT16)base[1];
+
+ /* determine the depth and table */
+ flags = base[2];
+ rledata->bpp = rle_bpp[(flags >> 8) & 7];
+ table = rledata->table = rle_table[(flags >> 8) & 7];
+
+ /* determine the starting offset */
+ offset = ((base[2] & 0xff) << 16) | base[3];
+ rledata->data = base = (UINT16 *)&mo->rombase[offset];
+
+ /* make sure it's valid */
+ if (offset < which * 4 || offset >= mo->romlength)
+ {
+ memset(rledata, 0, sizeof(*rledata));
+ return;
+ }
+
+ /* first pre-scan to determine the width and height */
+ for (height = 0; height < 1024 && base < end; height++)
+ {
+ int tempwidth = 0;
+ int entry_count = *base++;
+
+ /* if the high bit is set, assume we're inverted */
+ if (entry_count & 0x8000)
+ {
+ entry_count ^= 0xffff;
+
+ /* also change the ROM data so we don't have to do this again at runtime */
+ base[-1] ^= 0xffff;
+ }
+
+ /* we're done when we hit 0 */
+ if (entry_count == 0)
+ break;
+
+ /* track the width */
+ while (entry_count-- && base < end)
+ {
+ int word = *base++;
+ int count, value;
+
+ /* decode the low byte first */
+ count = table[word & 0xff];
+ value = count & 0xff;
+ tempwidth += count >> 8;
+
+ /* decode the upper byte second */
+ count = table[word >> 8];
+ value = count & 0xff;
+ tempwidth += count >> 8;
+ }
+
+ /* only remember the max */
+ if (tempwidth > width)
+ width = tempwidth;
+ }
+
+ /* fill in the data */
+ rledata->width = width;
+ rledata->height = height;
+}
+
+
+
+/*---------------------------------------------------------------
+ compute_checksum: Compute the checksum values on the ROMs.
+---------------------------------------------------------------*/
+
+static void compute_checksum(struct atarirle_data *mo)
+{
+ int reqsums = mo->spriteram[0].data[0] + 1;
+ int i;
+
+ /* number of checksums is in the first word */
+ if (reqsums > 256)
+ reqsums = 256;
+
+ /* stuff them back */
+ if (!mo->is32bit)
+ {
+ for (i = 0; i < reqsums; i++)
+ atarirle_0_spriteram[i] = mo->checksums[i];
+ }
+ else
+ {
+ for (i = 0; i < reqsums; i++)
+ if (i & 1)
+ atarirle_0_spriteram32[i/2] = (atarirle_0_spriteram32[i/2] & 0xffff0000) | mo->checksums[i];
+ else
+ atarirle_0_spriteram32[i/2] = (atarirle_0_spriteram32[i/2] & 0x0000ffff) | (mo->checksums[i] << 16);
+ }
+}
+
+
+/*---------------------------------------------------------------
+ sort_and_render: Render all motion objects in order.
+---------------------------------------------------------------*/
+
+static void sort_and_render(struct atarirle_data *mo)
+{
+ mame_bitmap *bitmap1 = mo->vram[0][(~mo->control_bits & ATARIRLE_CONTROL_FRAME) >> 2];
+ mame_bitmap *bitmap2 = mo->vram[1][(~mo->control_bits & ATARIRLE_CONTROL_FRAME) >> 2];
+ struct atarirle_entry *obj = mo->spriteram;
+ struct mo_sort_entry sort_entry[256];
+ struct mo_sort_entry *list_head[256];
+ struct mo_sort_entry *current;
+ int i;
+
+struct atarirle_entry *hilite = NULL;
+int count = 0;
+
+ /* sort the motion objects into their proper priorities */
+ memset(list_head, 0, sizeof(list_head));
+ for (i = 0; i < 256; i++, obj++)
+ {
+ int order = EXTRACT_DATA(obj, mo->ordermask);
+ sort_entry[i].entry = i;
+ sort_entry[i].next = list_head[order];
+ list_head[order] = &sort_entry[i];
+ }
+
+ /* now loop back and process */
+ count = 0;
+ for (i = 1; i < 256; i++)
+ for (current = list_head[i]; current; current = current->next)
+ {
+ int scale, code;
+
+ /* extract scale and code */
+ obj = &mo->spriteram[current->entry];
+ scale = EXTRACT_DATA(obj, mo->scalemask);
+ code = EXTRACT_DATA(obj, mo->codemask);
+
+ /* make sure they are in range */
+ if (scale > 0 && code < mo->objectcount)
+ {
+ int hflip = EXTRACT_DATA(obj, mo->hflipmask);
+ int color = EXTRACT_DATA(obj, mo->colormask);
+ int priority = EXTRACT_DATA(obj, mo->prioritymask);
+ int x = EXTRACT_DATA(obj, mo->xposmask);
+ int y = EXTRACT_DATA(obj, mo->yposmask);
+ int which = EXTRACT_DATA(obj, mo->vrammask);
+
+if (count++ == atarirle_hilite_index)
+ hilite = obj;
+
+ if (x & ((mo->xposmask.mask + 1) >> 1))
+ x = (INT16)(x | ~mo->xposmask.mask);
+ if (y & ((mo->yposmask.mask + 1) >> 1))
+ y = (INT16)(y | ~mo->yposmask.mask);
+ x += mo->cliprect.min_x;
+
+ /* merge priority and color */
+ color = (color << 4) | (priority << ATARIRLE_PRIORITY_SHIFT);
+
+ /* render to one or both bitmaps */
+ if (which == 0)
+ draw_rle(mo, bitmap1, code, color, hflip, 0, x, y, scale, scale, &mo->cliprect);
+ if (bitmap2 && which != 0)
+ draw_rle(mo, bitmap2, code, color, hflip, 0, x, y, scale, scale, &mo->cliprect);
+ }
+ }
+
+if (hilite)
+{
+ int scale, code, which;
+
+ /* extract scale and code */
+ obj = hilite;
+ scale = EXTRACT_DATA(obj, mo->scalemask);
+ code = EXTRACT_DATA(obj, mo->codemask);
+ which = EXTRACT_DATA(obj, mo->vrammask);
+
+ /* make sure they are in range */
+ if (scale > 0 && code < mo->objectcount)
+ {
+ int hflip = EXTRACT_DATA(obj, mo->hflipmask);
+ int color = EXTRACT_DATA(obj, mo->colormask);
+ int priority = EXTRACT_DATA(obj, mo->prioritymask);
+ int x = EXTRACT_DATA(obj, mo->xposmask);
+ int y = EXTRACT_DATA(obj, mo->yposmask);
+ int scaled_xoffs, scaled_yoffs;
+ const struct atarirle_info *info;
+
+ if (x & ((mo->xposmask.mask + 1) >> 1))
+ x = (INT16)(x | ~mo->xposmask.mask);
+ if (y & ((mo->yposmask.mask + 1) >> 1))
+ y = (INT16)(y | ~mo->yposmask.mask);
+ x += mo->cliprect.min_x;
+
+ /* merge priority and color */
+ color = (color << 4) | (priority << ATARIRLE_PRIORITY_SHIFT);
+
+ info = &mo->info[code];
+ scaled_xoffs = (scale * info->xoffs) >> 12;
+ scaled_yoffs = (scale * info->yoffs) >> 12;
+
+ /* we're hflipped, account for it */
+ if (hflip)
+ scaled_xoffs = ((scale * info->width) >> 12) - scaled_xoffs;
+
+ /* adjust for the x and y offsets */
+ x -= scaled_xoffs;
+ y -= scaled_yoffs;
+
+ do
+ {
+ int scaled_width = (scale * info->width + 0x7fff) >> 12;
+ int scaled_height = (scale * info->height + 0x7fff) >> 12;
+ int dx, dy, ex, ey, sx = x, sy = y, tx, ty;
+
+ /* make sure we didn't end up with 0 */
+ if (scaled_width == 0) scaled_width = 1;
+ if (scaled_height == 0) scaled_height = 1;
+
+ /* compute the remaining parameters */
+ dx = (info->width << 12) / scaled_width;
+ dy = (info->height << 12) / scaled_height;
+ ex = sx + scaled_width - 1;
+ ey = sy + scaled_height - 1;
+
+ /* left edge clip */
+ if (sx < Machine->screen[0].visarea.min_x)
+ sx = Machine->screen[0].visarea.min_x;
+ if (sx > Machine->screen[0].visarea.max_x)
+ break;
+
+ /* right edge clip */
+ if (ex > Machine->screen[0].visarea.max_x)
+ ex = Machine->screen[0].visarea.max_x;
+ else if (ex < Machine->screen[0].visarea.min_x)
+ break;
+
+ /* top edge clip */
+ if (sy < Machine->screen[0].visarea.min_y)
+ sy = Machine->screen[0].visarea.min_y;
+ else if (sy > Machine->screen[0].visarea.max_y)
+ break;
+
+ /* bottom edge clip */
+ if (ey > Machine->screen[0].visarea.max_y)
+ ey = Machine->screen[0].visarea.max_y;
+ else if (ey < Machine->screen[0].visarea.min_y)
+ break;
+
+ for (ty = sy; ty <= ey; ty++)
+ {
+ *BITMAP_ADDR16(bitmap1, ty, sx) = mame_rand(Machine) & 0xff;
+ *BITMAP_ADDR16(bitmap1, ty, ex) = mame_rand(Machine) & 0xff;
+ }
+ for (tx = sx; tx <= ex; tx++)
+ {
+ *BITMAP_ADDR16(bitmap1, sy, tx) = mame_rand(Machine) & 0xff;
+ *BITMAP_ADDR16(bitmap1, ey, tx) = mame_rand(Machine) & 0xff;
+ }
+ } while (0);
+fprintf(stderr, " Sprite: c=%04X l=%04X h=%d X=%4d (o=%4d w=%3d) Y=%4d (o=%4d h=%d) s=%04X\n",
+ code, color, hflip,
+ x, -scaled_xoffs, (scale * info->width) >> 12,
+ y, -scaled_yoffs, (scale * info->height) >> 12, scale);
+ }
+
+}
+}
+
+
+
+/*---------------------------------------------------------------
+ draw_rle: Render a single RLE-compressed motion
+ object.
+---------------------------------------------------------------*/
+
+void draw_rle(struct atarirle_data *mo, mame_bitmap *bitmap, int code, int color, int hflip, int vflip,
+ int x, int y, int xscale, int yscale, const rectangle *clip)
+{
+ UINT32 palettebase = mo->palettebase + color;
+ const struct atarirle_info *info = &mo->info[code];
+ int scaled_xoffs = (xscale * info->xoffs) >> 12;
+ int scaled_yoffs = (yscale * info->yoffs) >> 12;
+
+ /* we're hflipped, account for it */
+ if (hflip)
+ scaled_xoffs = ((xscale * info->width) >> 12) - scaled_xoffs;
+
+//if (clip->min_y == Machine->screen[0].visarea.min_y)
+//logerror(" Sprite: c=%04X l=%04X h=%d X=%4d (o=%4d w=%3d) Y=%4d (o=%4d h=%d) s=%04X\n",
+// code, color, hflip,
+// x, -scaled_xoffs, (xscale * info->width) >> 12,
+// y, -scaled_yoffs, (yscale * info->height) >> 12, xscale);
+
+ /* adjust for the x and y offsets */
+ x -= scaled_xoffs;
+ y -= scaled_yoffs;
+
+ /* bail on a NULL object */
+ if (!info->data)
+ return;
+
+ /* 16-bit case */
+ assert(bitmap->bpp == 16);
+ if (!hflip)
+ draw_rle_zoom(bitmap, info, palettebase, x, y, xscale << 4, yscale << 4, clip);
+ else
+ draw_rle_zoom_hflip(bitmap, info, palettebase, x, y, xscale << 4, yscale << 4, clip);
+}
+
+
+
+/*---------------------------------------------------------------
+ draw_rle_zoom: Draw an RLE-compressed object to a 16-bit
+ bitmap.
+---------------------------------------------------------------*/
+
+void draw_rle_zoom(mame_bitmap *bitmap, const struct atarirle_info *gfx,
+ UINT32 palette, int sx, int sy, int scalex, int scaley,
+ const rectangle *clip)
+{
+ const UINT16 *row_start = gfx->data;
+ const UINT16 *table = gfx->table;
+ volatile int current_row = 0;
+
+ int scaled_width = (scalex * gfx->width + 0x7fff) >> 16;
+ int scaled_height = (scaley * gfx->height + 0x7fff) >> 16;
+
+ int pixels_to_skip = 0, xclipped = 0;
+ int dx, dy, ex, ey;
+ int y, sourcey;
+
+ /* make sure we didn't end up with 0 */
+ if (scaled_width == 0) scaled_width = 1;
+ if (scaled_height == 0) scaled_height = 1;
+
+ /* compute the remaining parameters */
+ dx = (gfx->width << 16) / scaled_width;
+ dy = (gfx->height << 16) / scaled_height;
+ ex = sx + scaled_width - 1;
+ ey = sy + scaled_height - 1;
+ sourcey = dy / 2;
+
+ /* left edge clip */
+ if (sx < clip->min_x)
+ pixels_to_skip = clip->min_x - sx, xclipped = 1;
+ if (sx > clip->max_x)
+ return;
+
+ /* right edge clip */
+ if (ex > clip->max_x)
+ ex = clip->max_x, xclipped = 1;
+ else if (ex < clip->min_x)
+ return;
+
+ /* top edge clip */
+ if (sy < clip->min_y)
+ {
+ sourcey += (clip->min_y - sy) * dy;
+ sy = clip->min_y;
+ }
+ else if (sy > clip->max_y)
+ return;
+
+ /* bottom edge clip */
+ if (ey > clip->max_y)
+ ey = clip->max_y;
+ else if (ey < clip->min_y)
+ return;
+
+ /* loop top to bottom */
+ for (y = sy; y <= ey; y++, sourcey += dy)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, sx);
+ int j, sourcex = dx / 2, rle_end = 0;
+ const UINT16 *base;
+ int entry_count;
+
+ /* loop until we hit the row we're on */
+ for ( ; current_row != (sourcey >> 16); current_row++)
+ row_start += 1 + *row_start;
+
+ /* grab our starting parameters from this row */
+ base = row_start;
+ entry_count = *base++;
+
+ /* non-clipped case */
+ if (!xclipped)
+ {
+ /* decode the pixels */
+ for (j = 0; j < entry_count; j++)
+ {
+ int word = *base++;
+ int count, value;
+
+ /* decode the low byte first */
+ count = table[word & 0xff];
+ value = count & 0xff;
+ rle_end += (count & 0xff00) << 8;
+
+ /* store copies of the value until we pass the end of this chunk */
+ if (value)
+ {
+ value += palette;
+ while (sourcex < rle_end)
+ *dest++ = value, sourcex += dx;
+ }
+ else
+ {
+ while (sourcex < rle_end)
+ dest++, sourcex += dx;
+ }
+
+ /* decode the upper byte second */
+ count = table[word >> 8];
+ value = count & 0xff;
+ rle_end += (count & 0xff00) << 8;
+
+ /* store copies of the value until we pass the end of this chunk */
+ if (value)
+ {
+ value += palette;
+ while (sourcex < rle_end)
+ *dest++ = value, sourcex += dx;
+ }
+ else
+ {
+ while (sourcex < rle_end)
+ dest++, sourcex += dx;
+ }
+ }
+ }
+
+ /* clipped case */
+ else
+ {
+ const UINT16 *end = BITMAP_ADDR16(bitmap, y, ex);
+ int to_be_skipped = pixels_to_skip;
+
+ /* decode the pixels */
+ for (j = 0; j < entry_count && dest <= end; j++)
+ {
+ int word = *base++;
+ int count, value;
+
+ /* decode the low byte first */
+ count = table[word & 0xff];
+ value = count & 0xff;
+ rle_end += (count & 0xff00) << 8;
+
+ /* store copies of the value until we pass the end of this chunk */
+ if (to_be_skipped)
+ {
+ while (to_be_skipped && sourcex < rle_end)
+ dest++, sourcex += dx, to_be_skipped--;
+ if (to_be_skipped) goto next3;
+ }
+ if (value)
+ {
+ value += palette;
+ while (sourcex < rle_end && dest <= end)
+ *dest++ = value, sourcex += dx;
+ }
+ else
+ {
+ while (sourcex < rle_end)
+ dest++, sourcex += dx;
+ }
+
+ next3:
+ /* decode the upper byte second */
+ count = table[word >> 8];
+ value = count & 0xff;
+ rle_end += (count & 0xff00) << 8;
+
+ /* store copies of the value until we pass the end of this chunk */
+ if (to_be_skipped)
+ {
+ while (to_be_skipped && sourcex < rle_end)
+ dest++, sourcex += dx, to_be_skipped--;
+ if (to_be_skipped) goto next4;
+ }
+ if (value)
+ {
+ value += palette;
+ while (sourcex < rle_end && dest <= end)
+ *dest++ = value, sourcex += dx;
+ }
+ else
+ {
+ while (sourcex < rle_end)
+ dest++, sourcex += dx;
+ }
+ next4:
+ ;
+ }
+ }
+ }
+}
+
+
+
+/*---------------------------------------------------------------
+ draw_rle_zoom_hflip: Draw an RLE-compressed object to a
+ 16-bit bitmap with horizontal flip.
+---------------------------------------------------------------*/
+
+void draw_rle_zoom_hflip(mame_bitmap *bitmap, const struct atarirle_info *gfx,
+ UINT32 palette, int sx, int sy, int scalex, int scaley,
+ const rectangle *clip)
+{
+ const UINT16 *row_start = gfx->data;
+ const UINT16 *table = gfx->table;
+ volatile int current_row = 0;
+
+ int scaled_width = (scalex * gfx->width + 0x7fff) >> 16;
+ int scaled_height = (scaley * gfx->height + 0x7fff) >> 16;
+ int pixels_to_skip = 0, xclipped = 0;
+ int dx, dy, ex, ey;
+ int y, sourcey;
+
+ /* make sure we didn't end up with 0 */
+ if (scaled_width == 0) scaled_width = 1;
+ if (scaled_height == 0) scaled_height = 1;
+
+ /* compute the remaining parameters */
+ dx = (gfx->width << 16) / scaled_width;
+ dy = (gfx->height << 16) / scaled_height;
+ ex = sx + scaled_width - 1;
+ ey = sy + scaled_height - 1;
+ sourcey = dy / 2;
+
+ /* left edge clip */
+ if (sx < clip->min_x)
+ sx = clip->min_x, xclipped = 1;
+ if (sx > clip->max_x)
+ return;
+
+ /* right edge clip */
+ if (ex > clip->max_x)
+ pixels_to_skip = ex - clip->max_x, xclipped = 1;
+ else if (ex < clip->min_x)
+ return;
+
+ /* top edge clip */
+ if (sy < clip->min_y)
+ {
+ sourcey += (clip->min_y - sy) * dy;
+ sy = clip->min_y;
+ }
+ else if (sy > clip->max_y)
+ return;
+
+ /* bottom edge clip */
+ if (ey > clip->max_y)
+ ey = clip->max_y;
+ else if (ey < clip->min_y)
+ return;
+
+ /* loop top to bottom */
+ for (y = sy; y <= ey; y++, sourcey += dy)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, ex);
+ int j, sourcex = dx / 2, rle_end = 0;
+ const UINT16 *base;
+ int entry_count;
+
+ /* loop until we hit the row we're on */
+ for ( ; current_row != (sourcey >> 16); current_row++)
+ row_start += 1 + *row_start;
+
+ /* grab our starting parameters from this row */
+ base = row_start;
+ entry_count = *base++;
+
+ /* non-clipped case */
+ if (!xclipped)
+ {
+ /* decode the pixels */
+ for (j = 0; j < entry_count; j++)
+ {
+ int word = *base++;
+ int count, value;
+
+ /* decode the low byte first */
+ count = table[word & 0xff];
+ value = count & 0xff;
+ rle_end += (count & 0xff00) << 8;
+
+ /* store copies of the value until we pass the end of this chunk */
+ if (value)
+ {
+ value += palette;
+ while (sourcex < rle_end)
+ *dest-- = value, sourcex += dx;
+ }
+ else
+ {
+ while (sourcex < rle_end)
+ dest--, sourcex += dx;
+ }
+
+ /* decode the upper byte second */
+ count = table[word >> 8];
+ value = count & 0xff;
+ rle_end += (count & 0xff00) << 8;
+
+ /* store copies of the value until we pass the end of this chunk */
+ if (value)
+ {
+ value += palette;
+ while (sourcex < rle_end)
+ *dest-- = value, sourcex += dx;
+ }
+ else
+ {
+ while (sourcex < rle_end)
+ dest--, sourcex += dx;
+ }
+ }
+ }
+
+ /* clipped case */
+ else
+ {
+ const UINT16 *start = BITMAP_ADDR16(bitmap, y, sx);
+ int to_be_skipped = pixels_to_skip;
+
+ /* decode the pixels */
+ for (j = 0; j < entry_count && dest >= start; j++)
+ {
+ int word = *base++;
+ int count, value;
+
+ /* decode the low byte first */
+ count = table[word & 0xff];
+ value = count & 0xff;
+ rle_end += (count & 0xff00) << 8;
+
+ /* store copies of the value until we pass the end of this chunk */
+ if (to_be_skipped)
+ {
+ while (to_be_skipped && sourcex < rle_end)
+ dest--, sourcex += dx, to_be_skipped--;
+ if (to_be_skipped) goto next3;
+ }
+ if (value)
+ {
+ value += palette;
+ while (sourcex < rle_end && dest >= start)
+ *dest-- = value, sourcex += dx;
+ }
+ else
+ {
+ while (sourcex < rle_end)
+ dest--, sourcex += dx;
+ }
+
+ next3:
+ /* decode the upper byte second */
+ count = table[word >> 8];
+ value = count & 0xff;
+ rle_end += (count & 0xff00) << 8;
+
+ /* store copies of the value until we pass the end of this chunk */
+ if (to_be_skipped)
+ {
+ while (to_be_skipped && sourcex < rle_end)
+ dest--, sourcex += dx, to_be_skipped--;
+ if (to_be_skipped) goto next4;
+ }
+ if (value)
+ {
+ value += palette;
+ while (sourcex < rle_end && dest >= start)
+ *dest-- = value, sourcex += dx;
+ }
+ else
+ {
+ while (sourcex < rle_end)
+ dest--, sourcex += dx;
+ }
+ next4:
+ ;
+ }
+ }
+ }
+}
+
+
+/***************************************************************************
+
+ The mapping of the bits from the PROMs is like this:
+
+ D23 ->
+ D22 ->
+ D21 ->
+ D20 ->
+ D19 ->
+ D18 ->
+ D17 -> instruction bit 8
+ D16 -> instruction bit 7
+
+ D15 -> instruction bit 6
+ D14 -> instruction bit 5
+ D13 -> instruction bit 4
+ D12 -> instruction bit 3
+ D11 -> instruction bit 2
+ D10 -> instruction bit 1 (modified via a PAL)
+ D9 -> instruction bit 0
+ D8 -> carry in
+
+ D7 -> A bit 3
+ D6 -> A bit 2
+ D5 -> A bit 1
+ D4 -> A bit 0
+ D3 -> B bit 3
+ D2 -> B bit 2
+ D1 -> B bit 1
+ D0 -> B bit 0
+
+ Although much of the logic is contained in the ALU, the program counter
+ is fed externally. Jumps are decoded like this:
+
+ if (D13 && D14)
+ {
+ switch (D11 | D10 | D9)
+ {
+ case 0: condition = true;
+ case 1: condition = ALU.LT;
+ case 2: condition = ALU.Z;
+ case 3: condition = ALU.N;
+ case 4: condition = BLT.HFLIP;
+ case 5: condition = /BLT.SCAN;
+ case 6: condition = ALU.C;
+ case 7: condition = MOTIMEP;
+ }
+ condition ^= D12;
+ if (condition)
+ PC = D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0;
+ }
+
+ Here is the code from Guardians of the Hood:
+
+ I C A B
+ --- - - -
+ 000: A0 C8 00 -> 064 0 0 0 (latch UC.RASCAS)
+ 001: 01 C8 66 -> 0E4 0 6 6
+ 002: 01 89 66 -> 0C4 1 6 6
+ 003: 03 82 66 -> 1C1 0 6 6
+ 004: 01 B8 65 -> 0DC 0 6 5
+ 005: 01 82 66 -> 0C1 0 6 6
+ 006: 01 89 55 -> 0C4 1 5 5
+ 007: 01 C8 77 -> 0E4 0 7 7
+ 008: 01 89 77 -> 0C4 1 7 7
+ 009: 03 82 77 -> 1C1 0 7 7
+ 00A: 03 82 77 -> 1C1 0 7 7
+ 00B: 03 82 77 -> 1C1 0 7 7
+ 00C: 03 82 77 -> 1C1 0 7 7
+ 00D: 01 C8 88 -> 0E4 0 8 8
+ 00E: 01 B8 79 -> 0DC 0 7 9
+ 00F: 03 82 99 -> 1C1 0 9 9
+ 010: 01 82 99 -> 0C1 0 9 9
+ 011: 01 B8 61 -> 0DC 0 6 1
+ 012: 01 82 11 -> 0C1 0 1 1
+ 013: 01 96 11 -> 0CB 0 1 1
+ 014: 03 82 11 -> 1C1 0 1 1
+ 015: 03 82 11 -> 1C1 0 1 1
+ 016: 03 82 11 -> 1C1 0 1 1
+ 017: 03 82 11 -> 1C1 0 1 1
+ 018: 00 EE 18 -> 077 0 1 8 if /MOTIMEP JUMP 018
+ 019: 84 B8 11 -> 05C 0 1 1
+ 01A: 01 B8 72 -> 0DC 0 7 2
+ 01B: 00 C8 00 -> 064 0 0 0
+ 01C: 9C B8 88 -> 05C 0 8 8
+ 01D: 98 B8 88 -> 05C 0 8 8
+ 01E: 01 96 22 -> 0CB 0 2 2
+ 01F: 00 F4 1C -> 07A 0 1 C if NZ JUMP 01C
+ 020: 00 38 11 -> 01C 0 1 1
+ 021: 03 34 00 -> 19A 0 0 0
+ 022: 03 34 00 -> 19A 0 0 0
+ 023: 03 34 00 -> 19A 0 0 0
+ 024: 00 11 99 -> 008 1 9 9
+ 025: 02 34 00 -> 11A 0 0 0
+ 026: 84 B4 00 -> 05A 0 0 0
+ 027: 00 C8 00 -> 064 0 0 0
+ 028: 00 C8 00 -> 064 0 0 0
+ 029: 10 3E 00 -> 01F 0 0 0
+ 02A: 00 E5 3B -> 072 1 3 B if Z JUMP 13B
+ 02B: 00 05 00 -> 002 1 0 0
+ 02C: 9C B4 00 -> 05A 0 0 0
+ 02D: 98 B4 00 -> 05A 0 0 0
+ 02E: 00 EE 2E -> 077 0 2 E if /MOTIMEP JUMP 02E
+ 02F: 10 3E 00 -> 01F 0 0 0
+ 030: 00 05 00 -> 002 1 0 0
+ 031: 00 F4 35 -> 07A 0 3 5 if NZ JUMP 035
+ 032: A8 B8 55 -> 05C 0 5 5 (latch UC.HFLIP)
+ 033: A8 FE 35 -> 07F 0 3 5 if MOTIMEP JUMP 035 (latch UC.HFLIP)
+ 034: 00 E1 47 -> 070 1 4 7 JUMP 147
+ 035: 01 B8 72 -> 0DC 0 7 2
+ 036: 01 B8 8F -> 0DC 0 8 F
+ 037: 01 83 5F -> 0C1 1 5 F
+ 038: 84 B8 FF -> 05C 0 F F
+ 039: 00 EE 39 -> 077 0 3 9 if /MOTIMEP JUMP 039
+ 03A: 19 BE FF -> 0DF 0 F F
+ 03B: 00 E4 68 -> 072 0 6 8 if Z JUMP 068
+ 03C: 84 B8 88 -> 05C 0 8 8
+ 03D: 00 EE 3D -> 077 0 3 D if /MOTIMEP JUMP 03D
+ 03E: 19 BE AA -> 0DF 0 A A
+ 03F: 00 EE 3F -> 077 0 3 F if /MOTIMEP JUMP 03F
+ 040: 19 BE BB -> 0DF 0 B B
+ 041: 00 EE 41 -> 077 0 4 1 if /MOTIMEP JUMP 041
+ 042: 19 BE CC -> 0DF 0 C C
+ 043: 00 EE 43 -> 077 0 4 3 if /MOTIMEP JUMP 043
+ 044: 19 BE DD -> 0DF 0 D D
+ 045: 00 EE 45 -> 077 0 4 5 if /MOTIMEP JUMP 045
+ 046: 19 BE EE -> 0DF 0 E E
+ 047: 00 C8 00 -> 064 0 0 0
+ 048: 01 82 1F -> 0C1 0 1 F
+ 049: 84 B8 FF -> 05C 0 F F
+ 04A: 11 BE FF -> 0DF 0 F F
+ 04B: 00 C8 00 -> 064 0 0 0
+ 04C: 00 C8 00 -> 064 0 0 0
+ 04D: 9C B8 99 -> 05C 0 9 9
+ 04E: 90 B8 99 -> 05C 0 9 9
+ 04F: 00 C8 00 -> 064 0 0 0
+ 050: 84 B8 99 -> 05C 0 9 9
+ 051: 9C B8 AA -> 05C 0 A A
+ 052: 98 B8 AA -> 05C 0 A A
+ 053: 00 C8 00 -> 064 0 0 0
+ 054: 00 C8 00 -> 064 0 0 0
+ 055: 9C B8 BB -> 05C 0 B B
+ 056: 98 B8 BB -> 05C 0 B B
+ 057: 00 C8 00 -> 064 0 0 0
+ 058: 00 C8 00 -> 064 0 0 0
+ 059: 9C B8 CC -> 05C 0 C C
+ 05A: 98 B8 CC -> 05C 0 C C
+ 05B: 00 C8 00 -> 064 0 0 0
+ 05C: 00 C8 00 -> 064 0 0 0
+ 05D: 9C B8 DD -> 05C 0 D D
+ 05E: 98 B8 DD -> 05C 0 D D
+ 05F: 00 C8 00 -> 064 0 0 0
+ 060: 00 C8 00 -> 064 0 0 0
+ 061: 9C B8 EE -> 05C 0 E E
+ 062: 98 B8 EE -> 05C 0 E E
+ 063: 00 C8 00 -> 064 0 0 0
+ 064: 00 C8 00 -> 064 0 0 0
+ 065: 9C B8 FF -> 05C 0 F F
+ 066: 98 B8 FF -> 05C 0 F F
+ 067: 01 82 69 -> 0C1 0 6 9
+ 068: 01 82 68 -> 0C1 0 6 8
+ 069: 01 96 22 -> 0CB 0 2 2
+ 06A: 00 F4 36 -> 07A 0 3 6 if NZ JUMP 036
+ 06B: 01 B8 72 -> 0DC 0 7 2
+ 06C: 01 96 22 -> 0CB 0 2 2
+ 06D: 01 C8 44 -> 0E4 0 4 4
+ 06E: 01 96 44 -> 0CB 0 4 4
+ 06F: 01 B8 43 -> 0DC 0 4 3
+ 070: 02 B8 44 -> 15C 0 4 4
+ 071: 02 B8 44 -> 15C 0 4 4
+ 072: 02 B8 44 -> 15C 0 4 4
+ 073: 02 B8 44 -> 15C 0 4 4
+ 074: 02 B8 33 -> 15C 0 3 3
+ 075: 01 93 43 -> 0C9 1 4 3
+ 076: 02 B8 33 -> 15C 0 3 3
+ 077: 00 38 33 -> 01C 0 3 3
+ 078: 01 C8 33 -> 0E4 0 3 3
+ 079: 01 89 33 -> 0C4 1 3 3
+ 07A: 01 82 33 -> 0C1 0 3 3
+ 07B: 01 C8 00 -> 0E4 0 0 0
+ 07C: 00 B8 00 -> 05C 0 0 0
+ 07D: 00 F4 87 -> 07A 0 8 7 if NZ JUMP 087
+ 07E: 01 89 11 -> 0C4 1 1 1
+ 07F: 84 B8 11 -> 05C 0 1 1
+ 080: 00 EE 80 -> 077 0 8 0 if /MOTIMEP JUMP 080
+ 081: 11 BE 00 -> 0DF 0 0 0
+ 082: A4 B8 22 -> 05C 0 2 2 (latch UC.COLOR)
+ 083: 01 96 22 -> 0CB 0 2 2
+ 084: 00 F6 7C -> 07B 0 7 C if P JUMP 07C
+ 085: 8C B8 22 -> 05C 0 2 2
+ 086: 00 E0 86 -> 070 0 8 6 JUMP 086
+ 087: 84 B8 00 -> 05C 0 0 0
+ 088: 00 EE 88 -> 077 0 8 8 if /MOTIMEP JUMP 088
+ 089: 19 BE 55 -> 0DF 0 5 5
+ 08A: A8 B8 55 -> 05C 0 5 5 (latch UC.HFLIP)
+ 08B: 03 82 55 -> 1C1 0 5 5
+ 08C: 00 C8 00 -> 064 0 0 0
+ 08D: 19 BE FF -> 0DF 0 F F
+ 08E: A4 B8 FF -> 05C 0 F F (latch UC.COLOR)
+ 08F: 00 C8 00 -> 064 0 0 0
+ 090: 00 C8 00 -> 064 0 0 0
+ 091: 19 BE 66 -> 0DF 0 6 6
+ 092: B0 C8 00 -> 064 0 0 0 (latch UC.FORMAT)
+ 093: 00 C8 00 -> 064 0 0 0
+ 094: 00 C8 00 -> 064 0 0 0
+ 095: 19 BE 77 -> 0DF 0 7 7
+ 096: 00 C8 00 -> 064 0 0 0
+ 097: 00 C8 00 -> 064 0 0 0
+ 098: 00 C8 00 -> 064 0 0 0
+ 099: 19 BE 88 -> 0DF 0 8 8
+ 09A: 00 C8 00 -> 064 0 0 0
+ 09B: 00 C8 00 -> 064 0 0 0
+ 09C: 00 C8 00 -> 064 0 0 0
+ 09D: 19 BE 00 -> 0DF 0 0 0
+ 09E: 84 B8 55 -> 05C 0 5 5
+ 09F: 00 C8 00 -> 064 0 0 0
+ 0A0: 00 C8 00 -> 064 0 0 0
+ 0A1: 09 BE DD -> 0DF 0 D D
+ 0A2: 00 C8 00 -> 064 0 0 0
+ 0A3: 00 C8 00 -> 064 0 0 0
+ 0A4: 09 BE EE -> 0DF 0 E E
+ 0A5: 01 C8 AA -> 0E4 0 A A
+ 0A6: 01 C8 BB -> 0E4 0 B B
+ 0A7: 09 BE 99 -> 0DF 0 9 9
+ 0A8: 01 B8 8F -> 0DC 0 8 F
+ 0A9: 01 82 FF -> 0C1 0 F F
+ 0AA: 09 BE 55 -> 0DF 0 5 5
+ 0AB: 01 C8 CC -> 0E4 0 C C
+ 0AC: 00 B8 DD -> 05C 0 D D
+ 0AD: 00 F6 B1 -> 07B 0 B 1 if P JUMP 0B1
+ 0AE: 01 A9 DD -> 0D4 1 D D
+ 0AF: 01 82 4C -> 0C1 0 4 C
+ 0B0: 01 89 CC -> 0C4 1 C C
+ 0B1: 01 82 CC -> 0C1 0 C C
+ 0B2: 00 B8 EE -> 05C 0 E E
+ 0B3: 00 F6 B7 -> 07B 0 B 7 if P JUMP 0B7
+ 0B4: 01 A9 EE -> 0D4 1 E E
+ 0B5: 01 82 4C -> 0C1 0 4 C
+ 0B6: 01 89 CC -> 0C4 1 C C
+ 0B7: 03 82 CC -> 1C1 0 C C
+ 0B8: 01 82 FF -> 0C1 0 F F
+ 0B9: 43 86 DA -> 1C3 0 D A
+ 0BA: 43 86 EB -> 1C3 0 E B
+ 0BB: 01 82 FF -> 0C1 0 F F
+ 0BC: 43 86 DA -> 1C3 0 D A
+ 0BD: 43 86 EB -> 1C3 0 E B
+ 0BE: 01 82 FF -> 0C1 0 F F
+ 0BF: 43 86 DA -> 1C3 0 D A
+ 0C0: 43 86 EB -> 1C3 0 E B
+ 0C1: 01 82 FF -> 0C1 0 F F
+ 0C2: 43 86 DA -> 1C3 0 D A
+ 0C3: 43 86 EB -> 1C3 0 E B
+ 0C4: 01 82 FF -> 0C1 0 F F
+ 0C5: 43 86 DA -> 1C3 0 D A
+ 0C6: 43 86 EB -> 1C3 0 E B
+ 0C7: 01 82 FF -> 0C1 0 F F
+ 0C8: 43 86 DA -> 1C3 0 D A
+ 0C9: 43 86 EB -> 1C3 0 E B
+ 0CA: 01 82 FF -> 0C1 0 F F
+ 0CB: 43 86 DA -> 1C3 0 D A
+ 0CC: 43 86 EB -> 1C3 0 E B
+ 0CD: 01 82 FF -> 0C1 0 F F
+ 0CE: 41 86 DA -> 0C3 0 D A
+ 0CF: 41 86 EB -> 0C3 0 E B
+ 0D0: 02 B8 DD -> 15C 0 D D
+ 0D1: 02 B8 EE -> 15C 0 E E
+ 0D2: 01 82 FF -> 0C1 0 F F
+ 0D3: 41 86 DA -> 0C3 0 D A
+ 0D4: 41 86 EB -> 0C3 0 E B
+ 0D5: 02 B8 DD -> 15C 0 D D
+ 0D6: 02 B8 EE -> 15C 0 E E
+ 0D7: 01 82 FF -> 0C1 0 F F
+ 0D8: 41 86 DA -> 0C3 0 D A
+ 0D9: 41 86 EB -> 0C3 0 E B
+ 0DA: 02 B8 DD -> 15C 0 D D
+ 0DB: 02 B8 EE -> 15C 0 E E
+ 0DC: 01 82 FF -> 0C1 0 F F
+ 0DD: 41 86 DA -> 0C3 0 D A
+ 0DE: 41 86 EB -> 0C3 0 E B
+ 0DF: 00 B8 CC -> 05C 0 C C
+ 0E0: 00 F6 E2 -> 07B 0 E 2 if P JUMP 0E2
+ 0E1: 01 A9 AA -> 0D4 1 A A
+ 0E2: 01 82 CC -> 0C1 0 C C
+ 0E3: 00 F6 E5 -> 07B 0 E 5 if P JUMP 0E5
+ 0E4: 01 A9 BB -> 0D4 1 B B
+ 0E5: 01 C8 CC -> 0E4 0 C C
+ 0E6: 01 89 CC -> 0C4 1 C C
+ 0E7: 03 82 CC -> 1C1 0 C C
+ 0E8: 03 82 CC -> 1C1 0 C C
+ 0E9: 03 82 CC -> 1C1 0 C C
+ 0EA: 01 B8 4F -> 0DC 0 4 F
+ 0EB: 03 82 FF -> 1C1 0 F F
+ 0EC: 00 D2 48 -> 069 0 4 8
+ 0ED: 00 E5 19 -> 072 1 1 9 if Z JUMP 119
+ 0EE: 02 B8 88 -> 15C 0 8 8
+ 0EF: 02 B8 88 -> 15C 0 8 8
+ 0F0: 02 B8 88 -> 15C 0 8 8
+ 0F1: 02 B8 88 -> 15C 0 8 8
+ 0F2: 01 80 88 -> 0C0 0 8 8
+ 0F3: 84 B8 88 -> 05C 0 8 8
+ 0F4: 00 EE F4 -> 077 0 F 4 if /MOTIMEP JUMP 0F4
+ 0F5: 19 BE 88 -> 0DF 0 8 8
+ 0F6: AC B8 88 -> 05C 0 8 8 (latch UC.RATE)
+ 0F7: 01 82 88 -> 0C1 0 8 8
+ 0F8: 02 B8 88 -> 15C 0 8 8
+ 0F9: 00 F8 FC -> 07C 0 F C if /BLT.HFLIP JUMP 0FC
+ 0FA: 01 82 A6 -> 0C1 0 A 6
+ 0FB: 00 E0 FD -> 070 0 F D JUMP 0FD
+ 0FC: 01 93 A6 -> 0C9 1 A 6
+ 0FD: 01 93 B7 -> 0C9 1 B 7
+ 0FE: B0 B8 99 -> 05C 0 9 9 (latch UC.FORMAT)
+ 0FF: 84 B8 55 -> 05C 0 5 5
+ 100: 01 C8 EE -> 0E4 0 E E
+ 101: 00 C8 00 -> 064 0 0 0
+ 102: 09 BE DD -> 0DF 0 D D
+ 103: 00 E6 7C -> 073 0 7 C if N JUMP 07C
+ 104: 00 93 F7 -> 049 1 F 7
+ 105: 00 ED 0B -> 076 1 0 B if C JUMP 10B
+ 106: B4 B8 DD -> 05C 0 D D (latch UC.TRANS)
+ 107: B8 B8 77 -> 05C 0 7 7 (latch UC.XYPOS)
+ 108: A0 B8 33 -> 05C 0 3 3 (latch UC.RASCAS)
+ 109: B8 B8 66 -> 05C 0 6 6 (latch UC.XYPOS)
+ 10A: BC C8 00 -> 064 0 0 0 (latch UC.SCAN)
+ 10B: 01 82 C7 -> 0C1 0 C 7
+ 10C: 01 82 8E -> 0C1 0 8 E
+ 10D: 00 D2 4E -> 069 0 4 E
+ 10E: 00 E5 14 -> 072 1 1 4 if Z JUMP 114
+ 10F: 01 93 4E -> 0C9 1 4 E
+ 110: 01 96 EE -> 0CB 0 E E
+ 111: 01 83 D5 -> 0C1 1 D 5
+ 112: 00 FD 14 -> 07E 1 1 4 if NC JUMP 114
+ 113: 01 89 99 -> 0C4 1 9 9
+ 114: 00 FB 14 -> 07D 1 1 4 if BLT.SCAN JUMP 114
+ 115: A0 C8 00 -> 064 0 0 0 (latch UC.RASCAS)
+ 116: 84 B8 55 -> 05C 0 5 5
+ 117: B0 B8 99 -> 05C 0 9 9 (latch UC.FORMAT)
+ 118: 00 E1 02 -> 070 1 0 2 JUMP 102
+ 119: AC B8 88 -> 05C 0 8 8 (latch UC.RATE)
+ 11A: 00 F9 1D -> 07C 1 1 D if /BLT.HFLIP JUMP 11D
+ 11B: 01 82 A6 -> 0C1 0 A 6
+ 11C: 00 E1 1E -> 070 1 1 E JUMP 11E
+ 11D: 01 93 A6 -> 0C9 1 A 6
+ 11E: 01 93 B7 -> 0C9 1 B 7
+ 11F: B0 B8 99 -> 05C 0 9 9 (latch UC.FORMAT)
+ 120: 84 B8 55 -> 05C 0 5 5
+ 121: 01 B8 4E -> 0DC 0 4 E
+ 122: 01 89 EE -> 0C4 1 E E
+ 123: 02 B8 EE -> 15C 0 E E
+ 124: 09 BE DD -> 0DF 0 D D
+ 125: 00 E6 7C -> 073 0 7 C if N JUMP 07C
+ 126: 01 82 8E -> 0C1 0 8 E
+ 127: 00 D2 4E -> 069 0 4 E
+ 128: 00 E5 33 -> 072 1 3 3 if Z JUMP 133
+ 129: 01 93 4E -> 0C9 1 4 E
+ 12A: 01 96 EE -> 0CB 0 E E
+ 12B: 00 93 F7 -> 049 1 F 7
+ 12C: 00 ED 32 -> 076 1 3 2 if C JUMP 132
+ 12D: B4 B8 DD -> 05C 0 D D (latch UC.TRANS)
+ 12E: B8 B8 77 -> 05C 0 7 7 (latch UC.XYPOS)
+ 12F: A0 B8 33 -> 05C 0 3 3 (latch UC.RASCAS)
+ 130: B8 B8 66 -> 05C 0 6 6 (latch UC.XYPOS)
+ 131: BC C8 00 -> 064 0 0 0 (latch UC.SCAN)
+ 132: 01 82 C7 -> 0C1 0 C 7
+ 133: 01 83 D5 -> 0C1 1 D 5
+ 134: 00 FD 36 -> 07E 1 3 6 if NC JUMP 136
+ 135: 01 89 99 -> 0C4 1 9 9
+ 136: 00 FB 36 -> 07D 1 3 6 if BLT.SCAN JUMP 136
+ 137: A0 C8 00 -> 064 0 0 0 (latch UC.RASCAS)
+ 138: 84 B8 55 -> 05C 0 5 5
+ 139: B0 B8 99 -> 05C 0 9 9 (latch UC.FORMAT)
+ 13A: 00 E1 24 -> 070 1 2 4 JUMP 124
+ 13B: 08 3E 00 -> 01F 0 0 0
+ 13C: 00 EF 3C -> 077 1 3 C if /MOTIMEP JUMP 13C
+ 13D: 18 3E 00 -> 01F 0 0 0
+ 13E: 00 E5 75 -> 072 1 7 5 if Z JUMP 175
+ 13F: 00 C8 00 -> 064 0 0 0
+ 140: 9C B8 44 -> 05C 0 4 4
+ 141: 98 B8 44 -> 05C 0 4 4
+ 142: 00 C8 00 -> 064 0 0 0
+ 143: 00 C8 00 -> 064 0 0 0
+ 144: 9C B8 11 -> 05C 0 1 1
+ 145: 98 B8 11 -> 05C 0 1 1
+ 146: 00 E1 5A -> 070 1 5 A JUMP 15A
+ 147: 00 38 11 -> 01C 0 1 1
+ 148: 03 34 00 -> 19A 0 0 0
+ 149: 03 34 00 -> 19A 0 0 0
+ 14A: 03 34 00 -> 19A 0 0 0
+ 14B: 00 11 99 -> 008 1 9 9
+ 14C: 00 EF 4C -> 077 1 4 C if /MOTIMEP JUMP 14C
+ 14D: 02 34 00 -> 11A 0 0 0
+ 14E: 84 B4 00 -> 05A 0 0 0
+ 14F: 01 C8 00 -> 0E4 0 0 0
+ 150: 9C B8 00 -> 05C 0 0 0
+ 151: 98 B8 00 -> 05C 0 0 0
+ 152: 00 C8 00 -> 064 0 0 0
+ 153: 00 C8 00 -> 064 0 0 0
+ 154: 9C B8 11 -> 05C 0 1 1
+ 155: 98 B8 11 -> 05C 0 1 1
+ 156: 00 C8 00 -> 064 0 0 0
+ 157: 00 C8 00 -> 064 0 0 0
+ 158: 9C B8 44 -> 05C 0 4 4
+ 159: 98 B8 44 -> 05C 0 4 4
+ 15A: 09 BE DD -> 0DF 0 D D
+ 15B: 01 82 8E -> 0C1 0 8 E
+ 15C: 00 D2 4E -> 069 0 4 E
+ 15D: 00 E5 67 -> 072 1 6 7 if Z JUMP 167
+ 15E: 01 93 4E -> 0C9 1 4 E
+ 15F: 01 96 EE -> 0CB 0 E E
+ 160: 00 93 F7 -> 049 1 F 7
+ 161: 00 ED 67 -> 076 1 6 7 if C JUMP 167
+ 162: B4 B8 DD -> 05C 0 D D (latch UC.TRANS)
+ 163: B8 B8 77 -> 05C 0 7 7 (latch UC.XYPOS)
+ 164: A0 B8 33 -> 05C 0 3 3 (latch UC.RASCAS)
+ 165: B8 B8 66 -> 05C 0 6 6 (latch UC.XYPOS)
+ 166: BC C8 00 -> 064 0 0 0 (latch UC.SCAN)
+ 167: 01 82 C7 -> 0C1 0 C 7
+ 168: 01 83 D5 -> 0C1 1 D 5
+ 169: 00 FD 6C -> 07E 1 6 C if NC JUMP 16C
+ 16A: 01 89 99 -> 0C4 1 9 9
+ 16B: 01 C8 00 -> 0E4 0 0 0
+ 16C: 01 96 00 -> 0CB 0 0 0
+ 16D: 00 F5 6C -> 07A 1 6 C if NZ JUMP 16C
+ 16E: A0 C8 00 -> 064 0 0 0 (latch UC.RASCAS)
+ 16F: 84 B8 55 -> 05C 0 5 5
+ 170: B0 B8 99 -> 05C 0 9 9 (latch UC.FORMAT)
+ 171: 01 C8 00 -> 0E4 0 0 0
+ 172: 01 96 00 -> 0CB 0 0 0
+ 173: 00 F5 72 -> 07A 1 7 2 if NZ JUMP 172
+ 174: 00 E1 5A -> 070 1 5 A JUMP 15A
+ 175: 84 B8 88 -> 05C 0 8 8
+ 176: 00 EF 76 -> 077 1 7 6 if /MOTIMEP JUMP 176
+ 177: 19 BE AA -> 0DF 0 A A
+ 178: B0 B8 AA -> 05C 0 A A (latch UC.FORMAT)
+ 179: 01 C8 77 -> 0E4 0 7 7
+ 17A: 84 B8 77 -> 05C 0 7 7
+ 17B: 01 C8 BB -> 0E4 0 B B
+ 17C: 00 C8 00 -> 064 0 0 0
+ 17D: 00 C8 00 -> 064 0 0 0
+ 17E: 00 C8 00 -> 064 0 0 0
+ 17F: 08 3E 00 -> 01F 0 0 0
+ 180: 01 80 BB -> 0C0 0 B B
+ 181: 01 89 77 -> 0C4 1 7 7
+ 182: 00 F5 7F -> 07A 1 7 F if NZ JUMP 17F
+ 183: 84 B8 AA -> 05C 0 A A
+ 184: 00 C8 00 -> 064 0 0 0
+ 185: 00 C8 00 -> 064 0 0 0
+ 186: 9C B8 BB -> 05C 0 B B
+ 187: 98 B8 BB -> 05C 0 B B
+ 188: 01 96 AA -> 0CB 0 A A
+ 189: 00 F7 8B -> 07B 1 8 B if P JUMP 18B
+ 18A: 00 E1 8A -> 070 1 8 A JUMP 18A
+ 18B: 00 C8 00 -> 064 0 0 0
+ 18C: 00 E1 78 -> 070 1 7 8 JUMP 178
+
+***************************************************************************/
diff --git a/src/mame/video/atarirle.h b/src/mame/video/atarirle.h
new file mode 100644
index 00000000000..7e1138de483
--- /dev/null
+++ b/src/mame/video/atarirle.h
@@ -0,0 +1,97 @@
+/*##########################################################################
+
+ atarirle.h
+
+ Common RLE-based motion object management functions for early 90's
+ Atari raster games.
+
+##########################################################################*/
+
+#ifndef __ATARIRLE__
+#define __ATARIRLE__
+
+
+/*##########################################################################
+ CONSTANTS
+##########################################################################*/
+
+/* maximum number of motion object processors */
+#define ATARIRLE_MAX 1
+
+#define ATARIRLE_PRIORITY_SHIFT 12
+#define ATARIRLE_BANK_SHIFT 15
+#define ATARIRLE_PRIORITY_MASK ((~0 << ATARIRLE_PRIORITY_SHIFT) & 0xffff)
+#define ATARIRLE_DATA_MASK (ATARIRLE_PRIORITY_MASK ^ 0xffff)
+
+#define ATARIRLE_CONTROL_MOGO 1
+#define ATARIRLE_CONTROL_ERASE 2
+#define ATARIRLE_CONTROL_FRAME 4
+
+#define ATARIRLE_COMMAND_NOP 0
+#define ATARIRLE_COMMAND_DRAW 1
+#define ATARIRLE_COMMAND_CHECKSUM 2
+
+
+/*##########################################################################
+ TYPES & STRUCTURES
+##########################################################################*/
+
+/* description for an eight-word mask */
+struct atarirle_entry
+{
+ UINT16 data[8];
+};
+
+/* description of the motion objects */
+struct atarirle_desc
+{
+ UINT8 region; /* region where the GFX data lives */
+ UINT16 spriteramentries; /* number of entries in sprite RAM */
+ UINT16 leftclip; /* left clip coordinate */
+ UINT16 rightclip; /* right clip coordinate */
+
+ UINT16 palettebase; /* base palette entry */
+ UINT16 maxcolors; /* maximum number of colors */
+
+ struct atarirle_entry codemask; /* mask for the code index */
+ struct atarirle_entry colormask; /* mask for the color */
+ struct atarirle_entry xposmask; /* mask for the X position */
+ struct atarirle_entry yposmask; /* mask for the Y position */
+ struct atarirle_entry scalemask; /* mask for the scale factor */
+ struct atarirle_entry hflipmask; /* mask for the horizontal flip */
+ struct atarirle_entry ordermask; /* mask for the order */
+ struct atarirle_entry prioritymask; /* mask for the priority */
+ struct atarirle_entry vrammask; /* mask for the VRAM target */
+};
+
+
+
+/*##########################################################################
+ FUNCTION PROTOTYPES
+##########################################################################*/
+
+/* setup/shutdown */
+void atarirle_init(int map, const struct atarirle_desc *desc);
+
+/* control handlers */
+void atarirle_control_w(int map, UINT8 bits);
+void atarirle_command_w(int map, UINT8 command);
+VIDEO_EOF( atarirle );
+
+/* write handlers */
+WRITE16_HANDLER( atarirle_0_spriteram_w );
+WRITE32_HANDLER( atarirle_0_spriteram32_w );
+
+/* render helpers */
+mame_bitmap *atarirle_get_vram(int map, int idx);
+
+
+
+/*##########################################################################
+ GLOBAL VARIABLES
+##########################################################################*/
+
+extern UINT16 *atarirle_0_spriteram;
+extern UINT32 *atarirle_0_spriteram32;
+
+#endif
diff --git a/src/mame/video/atarisy1.c b/src/mame/video/atarisy1.c
new file mode 100644
index 00000000000..16276fb83d1
--- /dev/null
+++ b/src/mame/video/atarisy1.c
@@ -0,0 +1,664 @@
+/***************************************************************************
+
+ Atari System 1 hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "atarisy1.h"
+
+
+
+/*************************************
+ *
+ * Constants
+ *
+ *************************************/
+
+/* the color and remap PROMs are mapped as follows */
+#define PROM1_BANK_4 0x80 /* active low */
+#define PROM1_BANK_3 0x40 /* active low */
+#define PROM1_BANK_2 0x20 /* active low */
+#define PROM1_BANK_1 0x10 /* active low */
+#define PROM1_OFFSET_MASK 0x0f /* postive logic */
+
+#define PROM2_BANK_6_OR_7 0x80 /* active low */
+#define PROM2_BANK_5 0x40 /* active low */
+#define PROM2_PLANE_5_ENABLE 0x20 /* active high */
+#define PROM2_PLANE_4_ENABLE 0x10 /* active high */
+#define PROM2_PF_COLOR_MASK 0x0f /* negative logic */
+#define PROM2_BANK_7 0x08 /* active low, plus PROM2_BANK_6_OR_7 low as well */
+#define PROM2_MO_COLOR_MASK 0x07 /* negative logic */
+
+
+
+/*************************************
+ *
+ * Globals we own
+ *
+ *************************************/
+
+UINT16 *atarisy1_bankselect;
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+/* playfield parameters */
+static UINT16 playfield_lookup[256];
+static UINT8 playfield_tile_bank;
+static UINT16 playfield_priority_pens;
+static emu_timer *yscroll_reset_timer;
+
+/* INT3 tracking */
+static int next_timer_scanline;
+static emu_timer *scanline_timer;
+static emu_timer *int3off_timer;
+
+/* graphics bank tracking */
+static UINT8 bank_gfx[3][8];
+static UINT8 bank_color_shift[MAX_GFX_ELEMENTS];
+
+/* basic form of a graphics bank */
+static gfx_layout objlayout =
+{
+ 8,8, /* 8*8 sprites */
+ 4096, /* 4096 of them */
+ 6, /* 6 bits per pixel */
+ { 5*8*0x10000, 4*8*0x10000, 3*8*0x10000, 2*8*0x10000, 1*8*0x10000, 0*8*0x10000 },
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
+ 8*8 /* every sprite takes 8 consecutive bytes */
+};
+
+
+
+/*************************************
+ *
+ * Prototypes
+ *
+ *************************************/
+
+static void update_timers(int scanline);
+static void decode_gfx(running_machine *machine, UINT16 *pflookup, UINT16 *molookup);
+static int get_bank(running_machine *machine, UINT8 prom1, UINT8 prom2, int bpp);
+static TIMER_CALLBACK( int3_callback );
+static TIMER_CALLBACK( int3off_callback );
+static TIMER_CALLBACK( reset_yscroll_callback );
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha[tile_index];
+ int code = data & 0x3ff;
+ int color = (data >> 10) & 0x07;
+ int opaque = data & 0x2000;
+ SET_TILE_INFO(0, code, color, opaque ? TILE_FORCE_LAYER0 : 0);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data = atarigen_playfield[tile_index];
+ UINT16 lookup = playfield_lookup[((data >> 8) & 0x7f) | (playfield_tile_bank << 7)];
+ int gfxindex = (lookup >> 8) & 15;
+ int code = ((lookup & 0xff) << 8) | (data & 0xff);
+ int color = 0x20 + (((lookup >> 12) & 15) << bank_color_shift[gfxindex]);
+ SET_TILE_INFO(gfxindex, code, color, (data >> 15) & 1);
+}
+
+
+
+/*************************************
+ *
+ * Generic video system start
+ *
+ *************************************/
+
+VIDEO_START( atarisy1 )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 0, /* index to which gfx system */
+ 8, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 1, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 0, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0x38, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x100, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0,0,0,0x003f }}, /* mask for the link */
+ {{ 0,0xff00,0,0 }}, /* mask for the graphics bank */
+ {{ 0,0xffff,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0xff00,0,0 }}, /* mask for the color */
+ {{ 0,0,0x3fe0,0 }}, /* mask for the X position */
+ {{ 0x3fe0,0,0,0 }}, /* mask for the Y position */
+ {{ 0 }}, /* mask for the width, in tiles*/
+ {{ 0x000f,0,0,0 }}, /* mask for the height, in tiles */
+ {{ 0x8000,0,0,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0,0,0x8000,0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0,0xffff,0,0 }}, /* mask for the special value */
+ 0xffff, /* resulting value to indicate "special" */
+ 0 /* callback routine for special entries */
+ };
+
+ UINT16 motable[256];
+ UINT16 *codelookup;
+ UINT8 *colorlookup, *gfxlookup;
+ int i, size;
+
+ /* first decode the graphics */
+ decode_gfx(machine, playfield_lookup, motable);
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,64);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ tilemap_set_transparent_pen(atarigen_alpha_tilemap, 0);
+
+ /* modify the motion object code lookup */
+ codelookup = atarimo_get_code_lookup(0, &size);
+ for (i = 0; i < size; i++)
+ codelookup[i] = (i & 0xff) | ((motable[i >> 8] & 0xff) << 8);
+
+ /* modify the motion object color and gfx lookups */
+ colorlookup = atarimo_get_color_lookup(0, &size);
+ gfxlookup = atarimo_get_gfx_lookup(0, &size);
+ for (i = 0; i < size; i++)
+ {
+ colorlookup[i] = ((motable[i] >> 12) & 15) << 1;
+ gfxlookup[i] = (motable[i] >> 8) & 15;
+ }
+
+ /* reset the statics */
+ atarimo_set_yscroll(0, 256);
+ next_timer_scanline = -1;
+ scanline_timer = timer_alloc(int3_callback);
+ int3off_timer = timer_alloc(int3off_callback);
+ yscroll_reset_timer = timer_alloc(reset_yscroll_callback);
+}
+
+
+
+/*************************************
+ *
+ * Graphics bank selection
+ *
+ *************************************/
+
+WRITE16_HANDLER( atarisy1_bankselect_w )
+{
+ UINT16 oldselect = *atarisy1_bankselect;
+ UINT16 newselect = oldselect, diff;
+ int scanline = video_screen_get_vpos(0);
+
+ /* update memory */
+ COMBINE_DATA(&newselect);
+ diff = oldselect ^ newselect;
+
+ /* sound CPU reset */
+ if (diff & 0x0080)
+ {
+ cpunum_set_input_line(1, INPUT_LINE_RESET, (newselect & 0x0080) ? CLEAR_LINE : ASSERT_LINE);
+ if (!(newselect & 0x0080)) atarigen_sound_reset();
+ }
+
+ /* if MO or playfield banks change, force a partial update */
+ if (diff & 0x003c)
+ video_screen_update_partial(0, scanline);
+
+ /* motion object bank select */
+ atarimo_set_bank(0, (newselect >> 3) & 7);
+ update_timers(scanline);
+
+ /* playfield bank select */
+ if (diff & 0x0004)
+ {
+ playfield_tile_bank = (newselect >> 2) & 1;
+ tilemap_mark_all_tiles_dirty(atarigen_playfield_tilemap);
+ }
+
+ /* stash the new value */
+ *atarisy1_bankselect = newselect;
+}
+
+
+
+/*************************************
+ *
+ * Playfield priority pens
+ *
+ *************************************/
+
+WRITE16_HANDLER( atarisy1_priority_w )
+{
+ UINT16 oldpens = playfield_priority_pens;
+ UINT16 newpens = oldpens;
+
+ /* force a partial update in case this changes mid-screen */
+ COMBINE_DATA(&newpens);
+ if (oldpens != newpens)
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ playfield_priority_pens = newpens;
+}
+
+
+
+/*************************************
+ *
+ * Playfield horizontal scroll
+ *
+ *************************************/
+
+WRITE16_HANDLER( atarisy1_xscroll_w )
+{
+ UINT16 oldscroll = *atarigen_xscroll;
+ UINT16 newscroll = oldscroll;
+
+ /* force a partial update in case this changes mid-screen */
+ COMBINE_DATA(&newscroll);
+ if (oldscroll != newscroll)
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ /* set the new scroll value */
+ tilemap_set_scrollx(atarigen_playfield_tilemap, 0, newscroll);
+
+ /* update the data */
+ *atarigen_xscroll = newscroll;
+}
+
+
+
+/*************************************
+ *
+ * Playfield vertical scroll
+ *
+ *************************************/
+
+static TIMER_CALLBACK( reset_yscroll_callback )
+{
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, param);
+}
+
+
+WRITE16_HANDLER( atarisy1_yscroll_w )
+{
+ UINT16 oldscroll = *atarigen_yscroll;
+ UINT16 newscroll = oldscroll;
+ int scanline = video_screen_get_vpos(0);
+ int adjusted_scroll;
+
+ /* force a partial update in case this changes mid-screen */
+ COMBINE_DATA(&newscroll);
+ video_screen_update_partial(0, scanline);
+
+ /* because this latches a new value into the scroll base,
+ we need to adjust for the scanline */
+ adjusted_scroll = newscroll;
+ if (scanline <= Machine->screen[0].visarea.max_y)
+ adjusted_scroll -= (scanline + 1);
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, adjusted_scroll);
+
+ /* but since we've adjusted it, we must reset it to the normal value
+ once we hit scanline 0 again */
+ timer_adjust(yscroll_reset_timer, video_screen_get_time_until_pos(0, 0, 0), newscroll, attotime_zero);
+
+ /* update the data */
+ *atarigen_yscroll = newscroll;
+}
+
+
+
+/*************************************
+ *
+ * Sprite RAM write handler
+ *
+ *************************************/
+
+WRITE16_HANDLER( atarisy1_spriteram_w )
+{
+ int active_bank = atarimo_get_bank(0);
+ int oldword = atarimo_0_spriteram[offset];
+ int newword = oldword;
+ COMBINE_DATA(&newword);
+
+ /* if the data changed, and it modified the live sprite bank, do some extra work */
+ if (oldword != newword && (offset >> 8) == active_bank)
+ {
+ /* if modifying a timer, beware */
+ if (((offset & 0xc0) == 0x00 && atarimo_0_spriteram[offset | 0x40] == 0xffff) ||
+ ((offset & 0xc0) == 0x40 && (newword == 0xffff || oldword == 0xffff)))
+ {
+ /* if the timer is in the active bank, update the display list */
+ atarimo_0_spriteram_w(offset, data, 0);
+ update_timers(video_screen_get_vpos(0));
+ }
+
+ /* if we're about to modify data in the active sprite bank, make sure the video is up-to-date */
+ /* Road Runner needs this to work; note the +2 kludge -- +1 would be correct since the video */
+ /* renders the next scanline's sprites to the line buffers, but Road Runner still glitches */
+ /* without the extra +1 */
+ else
+ video_screen_update_partial(0, video_screen_get_vpos(0) + 2);
+ }
+
+ /* let the MO handler do the basic work */
+ atarimo_0_spriteram_w(offset, data, 0);
+}
+
+
+
+/*************************************
+ *
+ * MO interrupt handlers
+ *
+ *************************************/
+
+static TIMER_CALLBACK( int3off_callback )
+{
+ /* clear the state */
+ atarigen_scanline_int_ack_w(0, 0, 0);
+}
+
+
+static TIMER_CALLBACK( int3_callback )
+{
+ int scanline = param;
+
+ /* update the state */
+ atarigen_scanline_int_gen();
+
+ /* set a timer to turn it off */
+ timer_adjust(int3off_timer, video_screen_get_scan_period(0), 0, attotime_zero);
+
+ /* determine the time of the next one */
+ next_timer_scanline = -1;
+ update_timers(scanline);
+}
+
+
+
+/*************************************
+ *
+ * MO interrupt state read
+ *
+ *************************************/
+
+READ16_HANDLER( atarisy1_int3state_r )
+{
+ return atarigen_scanline_int_state ? 0x0080 : 0x0000;
+}
+
+
+
+/*************************************
+ *
+ * Timer updater
+ *
+ *************************************/
+
+static void update_timers(int scanline)
+{
+ UINT16 *base = &atarimo_0_spriteram[atarimo_get_bank(0) * 64 * 4];
+ int link = 0, best = scanline, found = 0;
+ UINT8 spritevisit[64];
+
+ /* track which ones we've visited */
+ memset(spritevisit, 0, sizeof(spritevisit));
+
+ /* walk the list until we loop */
+ while (!spritevisit[link])
+ {
+ /* timers are indicated by 0xffff in entry 2 */
+ if (base[link + 0x40] == 0xffff)
+ {
+ int data = base[link];
+ int vsize = (data & 15) + 1;
+ int ypos = (256 - (data >> 5) - vsize * 8 - 1) & 0x1ff;
+
+ /* note that we found something */
+ found = 1;
+
+ /* is this a better entry than the best so far? */
+ if (best <= scanline)
+ {
+ if ((ypos <= scanline && ypos < best) || ypos > scanline)
+ best = ypos;
+ }
+ else
+ {
+ if (ypos < best)
+ best = ypos;
+ }
+ }
+
+ /* link to the next */
+ spritevisit[link] = 1;
+ link = base[link + 0xc0] & 0x3f;
+ }
+
+ /* if nothing was found, use scanline -1 */
+ if (!found)
+ best = -1;
+
+ /* update the timer */
+ if (best != next_timer_scanline)
+ {
+ next_timer_scanline = best;
+
+ /* set a new one */
+ if (best != -1)
+ timer_adjust(scanline_timer, video_screen_get_time_until_pos(0, best, 0), best, attotime_zero);
+ else
+ timer_adjust(scanline_timer, attotime_never, 0, attotime_zero);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( atarisy1 )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* high priority MO? */
+ if (mo[x] & ATARIMO_PRIORITY_MASK)
+ {
+ /* only gets priority if MO pen is not 1 */
+ if ((mo[x] & 0x0f) != 1)
+ pf[x] = 0x300 + ((pf[x] & 0x0f) << 4) + (mo[x] & 0x0f);
+ }
+
+ /* low priority */
+ else
+ {
+ /* priority pens for playfield color 0 */
+ if ((pf[x] & 0xf8) != 0 || !(playfield_priority_pens & (1 << (pf[x] & 0x07))))
+ pf[x] = mo[x];
+ }
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+
+ /* add the alpha on top */
+ tilemap_draw(bitmap, cliprect, atarigen_alpha_tilemap, 0, 0);
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Graphics decoding
+ *
+ *************************************/
+
+static void decode_gfx(running_machine *machine, UINT16 *pflookup, UINT16 *molookup)
+{
+ UINT8 *prom1 = &memory_region(REGION_PROMS)[0x000];
+ UINT8 *prom2 = &memory_region(REGION_PROMS)[0x200];
+ int obj, i;
+
+ /* reset the globals */
+ memset(&bank_gfx[0][0], 0, sizeof(bank_gfx));
+
+ /* loop for two sets of objects */
+ for (obj = 0; obj < 2; obj++)
+ {
+ /* loop for 256 objects in the set */
+ for (i = 0; i < 256; i++, prom1++, prom2++)
+ {
+ int bank, bpp, color, offset;
+
+ /* determine the bpp */
+ bpp = 4;
+ if (*prom2 & PROM2_PLANE_4_ENABLE)
+ {
+ bpp = 5;
+ if (*prom2 & PROM2_PLANE_5_ENABLE)
+ bpp = 6;
+ }
+
+ /* determine the offset */
+ offset = *prom1 & PROM1_OFFSET_MASK;
+
+ /* determine the bank */
+ bank = get_bank(machine, *prom1, *prom2, bpp);
+
+ /* set the value */
+ if (obj == 0)
+ {
+ /* playfield case */
+ color = (~*prom2 & PROM2_PF_COLOR_MASK) >> (bpp - 4);
+ if (bank == 0)
+ {
+ bank = 1;
+ offset = color = 0;
+ }
+ pflookup[i] = offset | (bank << 8) | (color << 12);
+ }
+ else
+ {
+ /* motion objects (high bit ignored) */
+ color = (~*prom2 & PROM2_MO_COLOR_MASK) >> (bpp - 4);
+ molookup[i] = offset | (bank << 8) | (color << 12);
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Graphics bank mapping
+ *
+ *************************************/
+
+static int get_bank(running_machine *machine, UINT8 prom1, UINT8 prom2, int bpp)
+{
+ int bank_index, i, gfx_index;
+
+ /* determine the bank index */
+ if ((prom1 & PROM1_BANK_1) == 0)
+ bank_index = 1;
+ else if ((prom1 & PROM1_BANK_2) == 0)
+ bank_index = 2;
+ else if ((prom1 & PROM1_BANK_3) == 0)
+ bank_index = 3;
+ else if ((prom1 & PROM1_BANK_4) == 0)
+ bank_index = 4;
+ else if ((prom2 & PROM2_BANK_5) == 0)
+ bank_index = 5;
+ else if ((prom2 & PROM2_BANK_6_OR_7) == 0)
+ {
+ if ((prom2 & PROM2_BANK_7) == 0)
+ bank_index = 7;
+ else
+ bank_index = 6;
+ }
+ else
+ return 0;
+
+ /* find the bank */
+ if (bank_gfx[bpp - 4][bank_index])
+ return bank_gfx[bpp - 4][bank_index];
+
+ /* if the bank is out of range, call it 0 */
+ if (0x80000 * (bank_index - 1) >= memory_region_length(REGION_GFX2))
+ return 0;
+
+ /* don't have one? let's make it ... first find any empty slot */
+ for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
+ if (machine->gfx[gfx_index] == NULL)
+ break;
+ assert(gfx_index != MAX_GFX_ELEMENTS);
+
+ /* tweak the structure for the number of bitplanes we have */
+ objlayout.planes = bpp;
+ for (i = 0; i < bpp; i++)
+ objlayout.planeoffset[i] = (bpp - i - 1) * 0x10000 * 8;
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&objlayout);
+ decodegfx(machine->gfx[gfx_index], &memory_region(REGION_GFX2)[0x80000 * (bank_index - 1)], 0, machine->gfx[gfx_index]->total_elements);
+
+ /* set the color information */
+ machine->gfx[gfx_index]->color_base = 256;
+ machine->gfx[gfx_index]->color_granularity = 8;
+ machine->gfx[gfx_index]->total_colors = 0x40;
+ bank_color_shift[gfx_index] = bpp - 3;
+
+ /* set the entry and return it */
+ return bank_gfx[bpp - 4][bank_index] = gfx_index;
+}
diff --git a/src/mame/video/atarisy2.c b/src/mame/video/atarisy2.c
new file mode 100644
index 00000000000..906b69c93b6
--- /dev/null
+++ b/src/mame/video/atarisy2.c
@@ -0,0 +1,371 @@
+/***************************************************************************
+
+ Atari System 2 hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "slapstic.h"
+#include "atarisy2.h"
+
+
+
+/*************************************
+ *
+ * Globals we own
+ *
+ *************************************/
+
+UINT16 *atarisy2_slapstic;
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static emu_timer *yscroll_reset_timer;
+static UINT32 playfield_tile_bank[2];
+static UINT32 videobank;
+static UINT16 *vram;
+
+
+
+/*************************************
+ *
+ * Prototypes
+ *
+ *************************************/
+
+static TIMER_CALLBACK( reset_yscroll_callback );
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha[tile_index];
+ int code = data & 0x3ff;
+ int color = (data >> 13) & 0x07;
+ SET_TILE_INFO(2, code, color, 0);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data = atarigen_playfield[tile_index];
+ int code = playfield_tile_bank[(data >> 10) & 1] + (data & 0x3ff);
+ int color = (data >> 11) & 7;
+ SET_TILE_INFO(0, code, color, 0);
+ tileinfo->category = (~data >> 14) & 3;
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( atarisy2 )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 1, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 0, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x00, /* base palette entry */
+ 0x40, /* maximum number of colors */
+ 15, /* transparent pen index */
+
+ {{ 0,0,0,0x07f8 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0,0x07ff,0,0 }}, /* mask for the code index */
+ {{ 0x0007,0,0,0 }}, /* mask for the upper code index */
+ {{ 0,0,0,0x3000 }}, /* mask for the color */
+ {{ 0,0,0xffc0,0 }}, /* mask for the X position */
+ {{ 0x7fc0,0,0,0 }}, /* mask for the Y position */
+ {{ 0 }}, /* mask for the width, in tiles*/
+ {{ 0,0x3800,0,0 }}, /* mask for the height, in tiles */
+ {{ 0,0x4000,0,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0,0,0,0xc000 }}, /* mask for the priority */
+ {{ 0,0x8000,0,0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0 /* callback routine for special entries */
+ };
+
+ /* allocate banked memory */
+ vram = auto_malloc(0x8000);
+ memset(vram, 0, 0x8000);
+ atarigen_alpha = &vram[0x0000];
+ atarimo_0_spriteram = &vram[0x0c00];
+ atarigen_playfield = &vram[0x2000];
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 128,64);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,48);
+ tilemap_set_transparent_pen(atarigen_alpha_tilemap, 0);
+
+ /* reset the statics */
+ yscroll_reset_timer = timer_alloc(reset_yscroll_callback);
+ videobank = 0;
+}
+
+
+
+/*************************************
+ *
+ * Scroll/playfield bank write
+ *
+ *************************************/
+
+WRITE16_HANDLER( atarisy2_xscroll_w )
+{
+ UINT16 oldscroll = *atarigen_xscroll;
+ UINT16 newscroll = oldscroll;
+ COMBINE_DATA(&newscroll);
+
+ /* if anything has changed, force a partial update */
+ if (newscroll != oldscroll)
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ /* update the playfield scrolling - hscroll is clocked on the following scanline */
+ tilemap_set_scrollx(atarigen_playfield_tilemap, 0, newscroll >> 6);
+
+ /* update the playfield banking */
+ if (playfield_tile_bank[0] != (newscroll & 0x0f) * 0x400)
+ {
+ playfield_tile_bank[0] = (newscroll & 0x0f) * 0x400;
+ tilemap_mark_all_tiles_dirty(atarigen_playfield_tilemap);
+ }
+
+ /* update the data */
+ *atarigen_xscroll = newscroll;
+}
+
+
+static TIMER_CALLBACK( reset_yscroll_callback )
+{
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, param);
+}
+
+
+WRITE16_HANDLER( atarisy2_yscroll_w )
+{
+ UINT16 oldscroll = *atarigen_yscroll;
+ UINT16 newscroll = oldscroll;
+ COMBINE_DATA(&newscroll);
+
+ /* if anything has changed, force a partial update */
+ if (newscroll != oldscroll)
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ /* if bit 4 is zero, the scroll value is clocked in right away */
+ if (!(newscroll & 0x10))
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, (newscroll >> 6) - video_screen_get_vpos(0));
+ else
+ timer_adjust(yscroll_reset_timer, video_screen_get_time_until_pos(0, 0, 0), newscroll >> 6, attotime_zero);
+
+ /* update the playfield banking */
+ if (playfield_tile_bank[1] != (newscroll & 0x0f) * 0x400)
+ {
+ playfield_tile_bank[1] = (newscroll & 0x0f) * 0x400;
+ tilemap_mark_all_tiles_dirty(atarigen_playfield_tilemap);
+ }
+
+ /* update the data */
+ *atarigen_yscroll = newscroll;
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM write handler
+ *
+ *************************************/
+
+WRITE16_HANDLER( atarisy2_paletteram_w )
+{
+ static const int intensity_table[16] =
+ {
+ #define ZB 115
+ #define Z3 78
+ #define Z2 37
+ #define Z1 17
+ #define Z0 9
+ 0, ZB+Z0, ZB+Z1, ZB+Z1+Z0, ZB+Z2, ZB+Z2+Z0, ZB+Z2+Z1, ZB+Z2+Z1+Z0,
+ ZB+Z3, ZB+Z3+Z0, ZB+Z3+Z1, ZB+Z3+Z1+Z0,ZB+ Z3+Z2, ZB+Z3+Z2+Z0, ZB+Z3+Z2+Z1, ZB+Z3+Z2+Z1+Z0
+ };
+ static const int color_table[16] =
+ { 0x0, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xe, 0xf, 0xf };
+
+ int newword, inten, red, green, blue;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ newword = paletteram16[offset];
+
+ inten = intensity_table[newword & 15];
+ red = (color_table[(newword >> 12) & 15] * inten) >> 4;
+ green = (color_table[(newword >> 8) & 15] * inten) >> 4;
+ blue = (color_table[(newword >> 4) & 15] * inten) >> 4;
+ palette_set_color(Machine, offset, MAKE_RGB(red, green, blue));
+}
+
+
+
+/*************************************
+ *
+ * Video RAM bank read/write handlers
+ *
+ *************************************/
+
+READ16_HANDLER( atarisy2_slapstic_r )
+{
+ int result = atarisy2_slapstic[offset];
+ slapstic_tweak(offset);
+
+ /* an extra tweak for the next opcode fetch */
+ videobank = slapstic_tweak(0x1234) * 0x1000;
+ return result;
+}
+
+
+WRITE16_HANDLER( atarisy2_slapstic_w )
+{
+ slapstic_tweak(offset);
+
+ /* an extra tweak for the next opcode fetch */
+ videobank = slapstic_tweak(0x1234) * 0x1000;
+}
+
+
+
+/*************************************
+ *
+ * Video RAM read/write handlers
+ *
+ *************************************/
+
+READ16_HANDLER( atarisy2_videoram_r )
+{
+ return vram[offset | videobank];
+}
+
+
+WRITE16_HANDLER( atarisy2_videoram_w )
+{
+ int offs = offset | videobank;
+
+ /* alpharam? */
+ if (offs < 0x0c00)
+ {
+ COMBINE_DATA(&atarigen_alpha[offs]);
+ tilemap_mark_tile_dirty(atarigen_alpha_tilemap, offs);
+ }
+
+ /* spriteram? */
+ else if (offs < 0x1000)
+ {
+ /* force an update if the link of object 0 is about to change */
+ if (offs == 0x0c03)
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ atarimo_0_spriteram_w(offs - 0x0c00, data, mem_mask);
+ }
+
+ /* playfieldram? */
+ else if (offs >= 0x2000)
+ {
+ offs -= 0x2000;
+ COMBINE_DATA(&atarigen_playfield[offs]);
+ tilemap_mark_tile_dirty(atarigen_playfield_tilemap, offs);
+ }
+
+ /* generic case */
+ else
+ {
+ COMBINE_DATA(&vram[offs]);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( atarisy2 )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ fillbitmap(priority_bitmap, 0, cliprect);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 1, 1);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 2, 2);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 3, 3);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ UINT8 *pri = (UINT8 *)priority_bitmap->base + priority_bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x] != 0x0f)
+ {
+ int mopriority = mo[x] >> ATARIMO_PRIORITY_SHIFT;
+
+ /* high priority PF? */
+ if ((mopriority + pri[x]) & 2)
+ {
+ /* only gets priority if PF pen is less than 8 */
+ if (!(pf[x] & 0x08))
+ pf[x] = mo[x] & ATARIMO_DATA_MASK;
+ }
+
+ /* low priority */
+ else
+ pf[x] = mo[x] & ATARIMO_DATA_MASK;
+
+ /* erase behind ourselves */
+ mo[x] = 0x0f;
+ }
+ }
+
+ /* add the alpha on top */
+ tilemap_draw(bitmap, cliprect, atarigen_alpha_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/atetris.c b/src/mame/video/atetris.c
new file mode 100644
index 00000000000..91fce2e9bb5
--- /dev/null
+++ b/src/mame/video/atetris.c
@@ -0,0 +1,67 @@
+/***************************************************************************
+
+ Atari Tetris hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "atetris.h"
+
+
+static tilemap *bg_tilemap;
+
+
+/*************************************
+ *
+ * Tilemap callback
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ int code = videoram[tile_index * 2] | ((videoram[tile_index * 2 + 1] & 7) << 8);
+ int color = (videoram[tile_index * 2 + 1] & 0xf0) >> 4;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+
+
+/*************************************
+ *
+ * Video RAM write
+ *
+ *************************************/
+
+WRITE8_HANDLER( atetris_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( atetris )
+{
+ bg_tilemap = tilemap_create(get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( atetris )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0,0);
+ return 0;
+}
diff --git a/src/mame/video/attckufo.c b/src/mame/video/attckufo.c
new file mode 100644
index 00000000000..609391bee73
--- /dev/null
+++ b/src/mame/video/attckufo.c
@@ -0,0 +1,171 @@
+/***************************************************************************
+
+ Attack ufo video emulation
+ based on MOS 6560 emulator by
+ PeT mess@utanet.at
+
+ Differences between 6560 and Attack Ufo chip:
+ - no invert mode
+ - no multicolor
+ - 16 col chars
+
+***************************************************************************/
+
+#include "driver.h"
+#include "sound/custom.h"
+#include "includes/attckufo.h"
+
+#define MAX_LINES 261
+
+const rgb_t attckufo_palette[] =
+{
+/* ripped from vice, a very excellent emulator */
+ MAKE_RGB(0x00, 0x00, 0x00),
+ MAKE_RGB(0xff, 0xff, 0xff),
+ MAKE_RGB(0xf0, 0x00, 0x00),
+ MAKE_RGB(0x00, 0xf0, 0xf0),
+
+ MAKE_RGB(0x60, 0x00, 0x60),
+ MAKE_RGB(0x00, 0xa0, 0x00),
+ MAKE_RGB(0x00, 0x00, 0xf0),
+ MAKE_RGB(0xd0, 0xd0, 0x00),
+
+ MAKE_RGB(0xc0, 0xa0, 0x00),
+ MAKE_RGB(0xff, 0xa0, 0x00),
+ MAKE_RGB(0xf0, 0x80, 0x80),
+ MAKE_RGB(0x00, 0xff, 0xff),
+
+ MAKE_RGB(0xff, 0x00, 0xff),
+ MAKE_RGB(0x00, 0xff, 0x00),
+ MAKE_RGB(0x00, 0xa0, 0xff),
+ MAKE_RGB(0xff, 0xff, 0x00)
+};
+
+
+
+UINT8 attckufo_regs[16];
+
+#define CHARS_X ((int)attckufo_regs[2]&0x7f)
+#define CHARS_Y (((int)attckufo_regs[3]&0x7e)>>1)
+
+
+#define XSIZE (CHARS_X*8)
+#define YSIZE (CHARS_Y*8)
+
+#define CHARGENADDR (((int)attckufo_regs[5]&0xf)<<10)
+#define VIDEOADDR ( ( ((int)attckufo_regs[5]&0xf0)<<(10-4))\
+ | ( ((int)attckufo_regs[2]&0x80)<<(9-7)) )
+
+static int rasterline = 0;
+
+static int chars_x, chars_y;
+static int xsize, ysize ;
+static int chargenaddr, videoaddr;
+
+WRITE8_HANDLER ( attckufo_port_w )
+{
+ switch (offset)
+ {
+ case 0xa:
+ case 0xb:
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ attckufo_soundport_w (offset, data);
+ break;
+ }
+ if (attckufo_regs[offset] != data)
+ {
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 5:
+ case 0xe:
+ case 0xf:
+ video_screen_update_partial(0, rasterline);
+ break;
+ }
+ attckufo_regs[offset] = data;
+ switch (offset)
+ {
+ case 2:
+ /* ntsc values >= 31 behave like 31 */
+ chars_x = CHARS_X;
+ videoaddr = VIDEOADDR;
+ xsize = XSIZE;
+ break;
+ case 3:
+ chars_y = CHARS_Y;
+ ysize = YSIZE;
+ break;
+ case 5:
+ chargenaddr = CHARGENADDR;
+ videoaddr = VIDEOADDR;
+ break;
+ }
+ }
+}
+
+ READ8_HANDLER ( attckufo_port_r )
+{
+ int val;
+
+ switch (offset)
+ {
+ case 3:
+ val = ((rasterline & 1) << 7) | (attckufo_regs[offset] & 0x7f);
+ break;
+ case 4: /*rasterline */
+ val = (rasterline / 2) & 0xff;
+ break;
+ default:
+ val = attckufo_regs[offset];
+ break;
+ }
+ return val;
+}
+
+INTERRUPT_GEN( attckufo_raster_interrupt )
+{
+ rasterline++;
+ if (rasterline >= MAX_LINES)
+ rasterline = 0;
+}
+
+VIDEO_UPDATE( attckufo )
+{
+ int x, y, yy;
+
+ for (y = cliprect->min_y & ~7; y <= cliprect->max_y; y += 8)
+ {
+ UINT16 *destrow = BITMAP_ADDR16(bitmap, y, 0);
+ int offs = videoaddr + (y / 8) * chars_x;
+ int ymin = MAX(y, cliprect->min_y) & 7;
+ int ymax = MIN(y + 7, cliprect->max_y) & 7;
+
+ for (x = cliprect->min_x & ~7; x <= cliprect->max_x; x += 8)
+ {
+ UINT8 ch = program_read_byte(offs + x/8);
+ UINT8 attr = program_read_byte(offs + x/8 + 0x400) & 0xf;
+ UINT16 *dest = destrow;
+
+ for (yy = ymin; yy <= ymax; yy++)
+ {
+ UINT8 code = program_read_byte(chargenaddr + ch * 8 + yy);
+ dest[x + 0] = (code & 0x80) ? attr : 0;
+ dest[x + 1] = (code & 0x40) ? attr : 0;
+ dest[x + 2] = (code & 0x20) ? attr : 0;
+ dest[x + 3] = (code & 0x10) ? attr : 0;
+ dest[x + 4] = (code & 0x08) ? attr : 0;
+ dest[x + 5] = (code & 0x04) ? attr : 0;
+ dest[x + 6] = (code & 0x02) ? attr : 0;
+ dest[x + 7] = (code & 0x01) ? attr : 0;
+ dest += bitmap->rowpixels;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/avgdvg.c b/src/mame/video/avgdvg.c
new file mode 100644
index 00000000000..85a82b03205
--- /dev/null
+++ b/src/mame/video/avgdvg.c
@@ -0,0 +1,1523 @@
+/*************************************************************************
+
+ avgdvg.c: Atari DVG and AVG
+
+ Some parts of this code are based on the original version by Eric
+ Smith, Brad Oliver, Bernd Wiebelt, Aaron Giles, Andrew Caldwell
+
+ The schematics and Jed Margolin's article on Vector Generators were
+ very helpful in understanding the hardware.
+
+
+**************************************************************************/
+
+#include "driver.h"
+#include "avgdvg.h"
+#include "video/vector.h"
+
+
+/*************************************
+ *
+ * Global variables
+ *
+ *************************************/
+
+UINT8 *tempest_colorram;
+UINT8 *mhavoc_colorram;
+UINT16 *quantum_colorram;
+
+UINT16 *quantum_vectorram;
+
+
+
+/*************************************
+ *
+ * Macros and defines
+ *
+ *************************************/
+
+#define MASTER_CLOCK (12096000)
+#define VGSLICE (10000)
+#define MAXVECT (10000)
+
+#define VGVECTOR 0
+#define VGCLIP 1
+
+#define OP0 (vg->op & 1)
+#define OP1 (vg->op & 2)
+#define OP2 (vg->op & 4)
+#define OP3 (vg->op & 8)
+
+#define ST3 (vg->state_latch & 8)
+
+
+/*************************************
+ *
+ * Typedefs
+ *
+ *************************************/
+
+typedef struct _vgvector
+{
+ int x; int y;
+ rgb_t color;
+ int intensity;
+ int arg1; int arg2;
+ int status;
+} vgvector;
+
+typedef struct _vgdata
+{
+ UINT16 pc;
+ UINT8 sp;
+ UINT16 dvx;
+ UINT16 dvy;
+ UINT8 dvy12;
+ UINT16 timer;
+ UINT16 stack[4];
+ UINT16 data;
+
+ UINT8 state_latch;
+ UINT8 int_latch;
+ UINT8 scale;
+ UINT8 bin_scale;
+ UINT8 intensity;
+ UINT8 color;
+ UINT8 enspkl;
+ UINT8 spkl_shift;
+ UINT8 map;
+
+ UINT16 hst;
+ UINT16 lst;
+ UINT16 izblank;
+
+ UINT8 op;
+ UINT8 halt;
+ UINT8 sync_halt;
+
+ UINT16 xdac_xor;
+ UINT16 ydac_xor;
+
+ INT32 xpos;
+ INT32 ypos;
+
+ INT32 clipx_min;
+ INT32 clipy_min;
+ INT32 clipx_max;
+ INT32 clipy_max;
+} vgdata;
+
+typedef struct _vgconf
+{
+ int (*handler[8])(vgdata *);
+ UINT8 (*state_addr)(vgdata *);
+ void (*update_databus)(vgdata *);
+ void (*vggo)(vgdata *);
+ void (*vgrst)(vgdata *);
+} vgconf;
+
+
+/*************************************
+ *
+ * Static variables
+ *
+ *************************************/
+
+static int xmin, xmax, ymin, ymax;
+static int xcenter, ycenter;
+static emu_timer *vg_run_timer, *vg_halt_timer;
+
+static int flip_x, flip_y;
+
+static vgdata vgd, *vg;
+static vgconf *vgc;
+static int nvect;
+static vgvector vectbuf[MAXVECT];
+
+
+/*************************************
+ *
+ * Flipping
+ *
+ *************************************/
+
+void avg_set_flip_x(int flip)
+{
+ flip_x = flip;
+}
+
+void avg_set_flip_y(int flip)
+{
+ flip_y = flip;
+}
+
+static void avg_apply_flipping(int *x, int *y)
+{
+ if (flip_x)
+ *x += (xcenter - *x) << 1;
+ if (flip_y)
+ *y += (ycenter - *y) << 1;
+}
+
+
+/*************************************
+ *
+ * Vector buffering
+ *
+ *************************************/
+
+static void vg_flush (void)
+{
+ int i;
+
+ for (i = 0; i < nvect; i++)
+ {
+ if (vectbuf[i].status == VGVECTOR)
+ vector_add_point(vectbuf[i].x, vectbuf[i].y, vectbuf[i].color, vectbuf[i].intensity);
+
+ if (vectbuf[i].status == VGCLIP)
+ vector_add_clip(vectbuf[i].x, vectbuf[i].y, vectbuf[i].arg1, vectbuf[i].arg2);
+ }
+
+ nvect=0;
+}
+
+static void vg_add_point_buf(int x, int y, rgb_t color, int intensity)
+{
+ if (nvect < MAXVECT)
+ {
+ vectbuf[nvect].status = VGVECTOR;
+ vectbuf[nvect].x = x;
+ vectbuf[nvect].y = y;
+ vectbuf[nvect].color = color;
+ vectbuf[nvect].intensity = intensity;
+ nvect++;
+ }
+}
+
+static void vg_add_clip (int xmin, int ymin, int xmax, int ymax)
+{
+ if (nvect < MAXVECT)
+ {
+ vectbuf[nvect].status = VGCLIP;
+ vectbuf[nvect].x = xmin;
+ vectbuf[nvect].y = ymin;
+ vectbuf[nvect].arg1 = xmax;
+ vectbuf[nvect].arg2 = ymax;
+ nvect++;
+ }
+}
+
+
+/*************************************
+ *
+ * DVG handler functions
+ *
+ *************************************/
+
+static void dvg_data(vgdata *vg)
+{
+ /*
+ * DVG uses low bit of state for address
+ */
+ vg->data = vectorram[(vg->pc << 1) | (vg->state_latch & 1)];
+}
+
+static UINT8 dvg_state_addr(vgdata *vg)
+{
+ UINT8 addr;
+
+ addr =((((vg->state_latch >> 4) ^ 1) & 1) << 7) | (vg->state_latch & 0xf);
+
+ if (OP3)
+ addr |= ((vg->op & 7) << 4);
+
+ return addr;
+}
+
+static int dvg_dmapush(vgdata *vg)
+{
+ if (OP0 == 0)
+ {
+ vg->sp = (vg->sp + 1) & 0xf;
+ vg->stack[vg->sp & 3] = vg->pc;
+ }
+ return 0;
+}
+
+static int dvg_dmald(vgdata *vg)
+{
+ if (OP0)
+ {
+ vg->pc = vg->stack[vg->sp & 3];
+ vg->sp = (vg->sp - 1) & 0xf;
+ }
+ else
+ {
+ vg->pc = vg->dvy;
+ }
+
+ return 0;
+}
+
+static void dvg_draw_to(int x, int y, int intensity)
+{
+ if (((x | y) & 0x400) == 0)
+ vg_add_point_buf(xcenter + ((x - 0x200) << 16),
+ ycenter - ((y - 0x200) << 16),
+ VECTOR_COLOR111(7), intensity << 4);
+}
+
+static int dvg_gostrobe(vgdata *vg)
+{
+ int scale, fin, dx, dy, c, mx, my, countx, county, bit, cycles;
+
+ if (vg->op == 0xf)
+ {
+
+ scale = (vg->scale +
+ (((vg->dvy & 0x800) >> 11)
+ | (((vg->dvx & 0x800) ^ 0x800) >> 10)
+ | ((vg->dvx & 0x800) >> 9))) & 0xf;
+
+ vg->dvy &= 0xf00;
+ vg->dvx &= 0xf00;
+ }
+ else
+ {
+ scale = (vg->scale + vg->op) & 0xf;
+ }
+
+ fin = 0xfff - (((2 << scale) & 0x7ff) ^ 0xfff);
+
+ /* Count up or down */
+ dx = (vg->dvx & 0x400)? -1: +1;
+ dy = (vg->dvy & 0x400)? -1: +1;
+
+ /* Scale factor for rate multipliers */
+ mx = (vg->dvx << 2) & 0xfff;
+ my = (vg->dvy << 2) & 0xfff;
+
+ cycles = 8 * fin;
+ c=0;
+
+ while (fin--)
+ {
+
+ /*
+ * The 7497 Bit Rate Multiplier is a 6 bit counter with
+ * clever decoding of output bits to perform the following
+ * operation:
+ *
+ * fout = m/64 * fin
+ *
+ * where fin is the input frequency, fout is the output
+ * frequency and m is a factor at the input pins. Output
+ * pulses are more or less evenly spaced so we get straight
+ * lines. The DVG has two cascaded 7497s for each coordinate.
+ */
+
+ countx = 0;
+ county = 0;
+
+ for (bit = 0; bit < 12; bit++)
+ {
+ if ((c & ((1 << (bit+1)) - 1)) == ((1 << bit) - 1))
+ {
+ if (mx & (1 << (11 - bit)))
+ countx = 1;
+
+ if (my & (1 << (11 - bit)))
+ county = 1;
+ }
+ }
+
+ c = (c + 1) & 0xfff;
+
+ /*
+ * Since x- and y-counters always hold the correct count
+ * wrt. to each other, we can do clipping exactly like the
+ * hardware does. That is, as soon as any counter's bit 10
+ * changes to high, we finish the vector. If bit 10 changes
+ * from high to low, we start a new vector.
+ */
+
+ if (countx)
+ {
+ /* Is y valid and x entering or leaving the valid range? */
+ if (((vg->ypos & 0x400) == 0)
+ && ((vg->xpos ^ (vg->xpos + dx)) & 0x400))
+ {
+ if ((vg->xpos + dx) & 0x400)
+ /* We are leaving the valid range */
+ dvg_draw_to(vg->xpos, vg->ypos, vg->intensity);
+ else
+ /* We are entering the valid range */
+ dvg_draw_to((vg->xpos + dx) & 0xfff, vg->ypos, 0);
+ }
+ vg->xpos = (vg->xpos + dx) & 0xfff;
+ }
+
+ if (county)
+ {
+ if (((vg->xpos & 0x400) == 0)
+ && ((vg->ypos ^ (vg->ypos + dy)) & 0x400))
+ {
+ if ((vg->xpos & 0x400) == 0)
+ {
+ if ((vg->ypos + dy) & 0x400)
+ dvg_draw_to(vg->xpos, vg->ypos, vg->intensity);
+ else
+ dvg_draw_to(vg->xpos, (vg->ypos + dy) & 0xfff, 0);
+ }
+ }
+ vg->ypos = (vg->ypos + dy) & 0xfff;
+ }
+
+ }
+
+ dvg_draw_to(vg->xpos, vg->ypos, vg->intensity);
+
+ return cycles;
+}
+
+static int dvg_haltstrobe(vgdata *vg)
+{
+ vg->halt = OP0;
+
+ if (OP0 == 0)
+ {
+ vg->xpos = vg->dvx & 0xfff;
+ vg->ypos = vg->dvy & 0xfff;
+ dvg_draw_to(vg->xpos, vg->ypos, 0);
+ }
+ return 0;
+}
+
+static int dvg_latch3(vgdata *vg)
+{
+ vg->dvx = (vg->dvx & 0xff) | ((vg->data & 0xf) << 8);
+ vg->intensity = vg->data >> 4;
+ return 0;
+}
+
+static int dvg_latch2(vgdata *vg)
+{
+ vg->dvx &= 0xf00;
+ if (vg->op != 0xf)
+ vg->dvx = (vg->dvx & 0xf00) | vg->data;
+
+ if ((vg->op & 0xa) == 0xa)
+ vg->scale = vg->intensity;
+
+ vg->pc++;
+ return 0;
+}
+
+static int dvg_latch1(vgdata *vg)
+{
+ vg->dvy = (vg->dvy & 0xff)
+ | ((vg->data & 0xf) << 8);
+ vg->op = vg->data >> 4;
+
+ if (vg->op == 0xf)
+ {
+ vg->dvx &= 0xf00;
+ vg->dvy &= 0xf00;
+ }
+
+ return 0;
+}
+
+static int dvg_latch0(vgdata *vg)
+{
+ vg->dvy &= 0xf00;
+ if (vg->op == 0xf)
+ dvg_latch3(vg);
+ else
+ vg->dvy = (vg->dvy & 0xf00) | vg->data;
+
+ vg->pc++;
+ return 0;
+}
+
+
+/********************************************************************
+ *
+ * AVG handler functions
+ *
+ * AVG is in many ways different from DVG. The only thing they have
+ * in common is the state machine approach. There are small
+ * differences among the AVGs, mostly related to color and vector
+ * clipping.
+ *
+ *******************************************************************/
+
+static void avg_data(vgdata *vg)
+{
+ vg->data = vectorram[vg->pc ^ 1];
+}
+
+static void starwars_data(vgdata *vg)
+{
+ vg->data = vectorram[vg->pc];
+}
+
+static void quantum_data(vgdata *vg)
+{
+ vg->data = quantum_vectorram[vg->pc >> 1];
+}
+
+static void mhavoc_data(vgdata *vg)
+{
+ UINT8 *bank;
+
+ if (vg->pc & 0x2000)
+ {
+ bank = &memory_region(REGION_CPU1)[0x18000];
+ vg->data = bank[(vg->map << 13) | ((vg->pc ^ 1) & 0x1fff)];
+ }
+ else
+ {
+ vg->data = vectorram[vg->pc ^ 1];
+ }
+}
+
+static UINT8 avg_state_addr(vgdata *vg)
+{
+ return (((vg->state_latch >> 4) ^ 1) << 7)
+ | (vg->op << 4)
+ | (vg->state_latch & 0xf);
+}
+
+static int avg_latch0(vgdata *vg)
+{
+ vg->dvy = (vg->dvy & 0x1f00) | vg->data;
+ vg->pc++;
+
+ return 0;
+}
+
+static int quantum_st2st3(vgdata *vg)
+{
+ /* Quantum doesn't decode latch0 or latch2 but ST2 and ST3 are fed
+ * into the address controller which incremets the PC
+ */
+ vg->pc++;
+ return 0;
+}
+
+static int avg_latch1(vgdata *vg)
+{
+ vg->dvy12 = (vg->data >> 4) &1;
+ vg->op = vg->data >> 5;
+
+ vg->int_latch = 0;
+ vg->dvy = (vg->dvy12 << 12)
+ | ((vg->data & 0xf) << 8 );
+ vg->dvx = 0;
+ vg->pc++;
+
+ return 0;
+}
+
+static int quantum_latch1(vgdata *vg)
+{
+ vg->dvy = vg->data & 0x1fff;
+ vg->dvy12 = (vg->data >> 12) & 1;
+ vg->op = vg->data >> 13;
+
+ vg->int_latch = 0;
+ vg->dvx = 0;
+ vg->pc++;
+
+ return 0;
+}
+
+static int bzone_latch1(vgdata *vg)
+{
+ /*
+ * Battle Zone has clipping hardware. We need to remember the
+ * position of the beam when the analog switches hst or lst get
+ * turened off.
+ */
+
+ if (vg->hst == 0)
+ {
+ vg->clipx_max = vg->xpos;
+ vg->clipy_min = vg->ypos;
+ }
+
+ if (vg->lst == 0)
+ {
+ vg->clipx_min = vg->xpos;
+ vg->clipy_max = vg->ypos;
+ }
+
+ if (vg->lst==0 || vg->hst==0)
+ {
+ vg_add_clip(vg->clipx_min, vg->clipy_min, vg->clipx_max, vg->clipy_max);
+ }
+ vg->lst = vg->hst = 1;
+
+ return avg_latch1(vg);
+}
+
+static int mhavoc_latch1(vgdata *vg)
+{
+ /*
+ * Major Havoc just has ymin clipping
+ */
+
+ if (vg->lst == 0)
+ {
+ vg_add_clip(0, vg->ypos, xmax << 16, ymax << 16);
+ }
+ vg->lst = 1;
+
+ return avg_latch1(vg);
+}
+
+static int avg_latch2(vgdata *vg)
+{
+ vg->dvx = (vg->dvx & 0x1f00) | vg->data;
+ vg->pc++;
+
+ return 0;
+}
+
+static int avg_latch3(vgdata *vg)
+{
+ vg->int_latch = vg->data >> 4;
+ vg->dvx = ((vg->int_latch & 1) << 12)
+ | ((vg->data & 0xf) << 8 )
+ | (vg->dvx & 0xff);
+ vg->pc++;
+
+ return 0;
+}
+
+static int quantum_latch3(vgdata *vg)
+{
+ vg->int_latch = vg->data >> 12;
+ vg->dvx = vg->data & 0xfff;
+ vg->pc++;
+
+ return 0;
+}
+
+
+static int avg_strobe0(vgdata *vg)
+{
+ int i;
+
+ if (OP0)
+ {
+ vg->stack[vg->sp & 3] = vg->pc;
+ }
+ else
+ {
+ /*
+ * Normalization is done to get roughly constant deflection
+ * speeds. See Jed's essay why this is important. In addition
+ * to the intensity and overall time saving issues it is also
+ * needed to avoid accumulation of DAC errors. The X/Y DACs
+ * only use bits 3-12. The normalization ensures that the
+ * first three bits hold no important information.
+ *
+ * The circuit doesn't check for dvx=dvy=0. In this case
+ * shifting goes on as long as VCTR, SCALE and CNTR are
+ * low. We cut off after 16 shifts.
+ */
+ i = 0;
+ while ((((vg->dvy ^ (vg->dvy << 1)) & 0x1000) == 0)
+ && (((vg->dvx ^ (vg->dvx << 1)) & 0x1000) == 0)
+ && (i++ < 16))
+ {
+ vg->dvy = (vg->dvy & 0x1000) | ((vg->dvy << 1) & 0x1fff);
+ vg->dvx = (vg->dvx & 0x1000) | ((vg->dvx << 1) & 0x1fff);
+ vg->timer >>= 1;
+ vg->timer |= 0x4000 | (OP1 << 6);
+ }
+
+ if (OP1)
+ vg->timer &= 0xff;
+ }
+
+ return 0;
+}
+
+static int quantum_strobe0(vgdata *vg)
+{
+ int i;
+
+ if (OP0)
+ {
+ vg->stack[vg->sp & 3] = vg->pc;
+ }
+ else
+ {
+ /*
+ * Quantum normalizes to 12 bit
+ */
+ i = 0;
+ while ((((vg->dvy ^ (vg->dvy << 1)) & 0x800) == 0)
+ && (((vg->dvx ^ (vg->dvx << 1)) & 0x800) == 0)
+ && (i++ < 16))
+ {
+ vg->dvy = (vg->dvy << 1) & 0xfff;
+ vg->dvx = (vg->dvx << 1) & 0xfff;
+ vg->timer >>= 1;
+ vg->timer |= 0x2000 ;
+ }
+ }
+
+ return 0;
+}
+
+static int avg_common_strobe1(vgdata *vg)
+{
+ if (OP2)
+ {
+ if (OP1)
+ vg->sp = (vg->sp - 1) & 0xf;
+ else
+ vg->sp = (vg->sp + 1) & 0xf;
+ }
+ return 0;
+}
+
+static int avg_strobe1(vgdata *vg)
+{
+ int i;
+
+ if (OP2 == 0)
+ {
+ for (i = vg->bin_scale; i > 0; i--)
+ {
+ vg->timer >>= 1;
+ vg->timer |= 0x4000 | (OP1 << 6);
+ }
+ if (OP1)
+ vg->timer &= 0xff;
+ }
+
+ return avg_common_strobe1(vg);
+}
+
+static int quantum_strobe1(vgdata *vg)
+{
+ int i;
+
+ if (OP2 == 0)
+ {
+ for (i = vg->bin_scale; i > 0; i--)
+ {
+ vg->timer >>= 1;
+ vg->timer |= 0x2000;
+ }
+ }
+
+ return avg_common_strobe1(vg);
+}
+
+static int avg_common_strobe2(vgdata *vg)
+{
+ if (OP2)
+ {
+ if (OP0)
+ {
+ vg->pc = vg->dvy << 1;
+
+ if (vg->dvy == 0)
+ {
+ /*
+ * Tempest and Quantum keep the AVG in an endless
+ * loop. I.e. at one point the AVG jumps to address 0
+ * and starts over again. The main CPU updates vector
+ * RAM while AVG is running. The hardware takes care
+ * that the AVG dosen't read vector RAM while the CPU
+ * writes to it. Usually we wait until the AVG stops
+ * (halt flag) and then draw all vectors at once. This
+ * doesn't work for Tempest and Quantum so we wait for
+ * the jump to zero and draw vectors then.
+ *
+ * Note that this has nothing to do with the real hardware
+ * because for a vector monitor it is perfectly okay to
+ * have the AVG drawing all the time. In the emulation we
+ * somehow have to divide the stream of vectors into
+ * 'frames'.
+ */
+
+ vector_clear_list();
+ vg_flush();
+ }
+ }
+ else
+ {
+ vg->pc = vg->stack[vg->sp & 3];
+ }
+ }
+ else
+ {
+ if (vg->dvy12)
+ {
+ vg->scale = vg->dvy & 0xff;
+ vg->bin_scale = (vg->dvy >> 8) & 7;
+ }
+ }
+
+ return 0;
+}
+
+static int avg_strobe2(vgdata *vg)
+{
+ if ((OP2 == 0) && (vg->dvy12 == 0))
+ {
+ vg->color = vg->dvy & 0x7;
+ vg->intensity = (vg->dvy >> 4) & 0xf;
+ }
+
+ return avg_common_strobe2(vg);
+}
+
+static int mhavoc_strobe2(vgdata *vg)
+{
+ if (OP2 == 0)
+ {
+ if (vg->dvy12)
+ {
+ if (vg->dvy & 0x800)
+ vg->lst = 0;
+ }
+ else
+ {
+ vg->color = vg->dvy & 0xf;
+
+ vg->intensity = (vg->dvy >> 4) & 0xf;
+ vg->map = (vg->dvy >> 8) & 0x3;
+ if (vg->dvy & 0x800)
+ {
+ vg->enspkl = 1;
+ vg->spkl_shift = ((vg->dvy >> 3) & 1)
+ | ((vg->dvy >> 1) & 2)
+ | ((vg->dvy << 1) & 4)
+ | ((vg->dvy << 2) & 8)
+ | ((mame_rand(Machine) & 0x7) << 4);
+ }
+ else
+ {
+ vg->enspkl = 0;
+ }
+
+ /* Major Havoc can do X-flipping by inverting the DAC input */
+ if (vg->dvy & 0x400)
+ vg->xdac_xor = 0x1ff;
+ else
+ vg->xdac_xor = 0x200;
+ }
+ }
+
+ return avg_common_strobe2(vg);
+}
+
+static int tempest_strobe2(vgdata *vg)
+{
+ if ((OP2 == 0) && (vg->dvy12 == 0))
+ {
+ if (vg->dvy & 0x800)
+ vg->color = vg->dvy & 0xf;
+ else
+ vg->intensity = (vg->dvy >> 4) & 0xf;
+ }
+
+ return avg_common_strobe2(vg);
+}
+
+static int quantum_strobe2(vgdata *vg)
+{
+ if ((OP2 == 0) && (vg->dvy12 == 0) && (vg->dvy & 0x800))
+ {
+ vg->color = vg->dvy & 0xf;
+ vg->intensity = (vg->dvy >> 4) & 0xf;
+ }
+
+ return avg_common_strobe2(vg);
+}
+
+static int starwars_strobe2(vgdata *vg)
+{
+ if ((OP2 == 0) && (vg->dvy12 == 0))
+ {
+ vg->intensity = vg->dvy & 0xff;
+ vg->color = (vg->dvy >> 8) & 0xf;
+ }
+
+ return avg_common_strobe2(vg);
+}
+
+static int bzone_strobe2(vgdata *vg)
+{
+ if ((OP2 == 0) && (vg->dvy12 == 0))
+ {
+ vg->intensity = (vg->dvy >> 4) & 0xf;
+
+ if (!(vg->dvy & 0x400))
+ {
+ vg->lst = vg->dvy & 0x200;
+ vg->hst = vg->lst ^ 0x200;
+ /*
+ * If izblank is true the zblank signal gets
+ * inverted. This behaviour can't be handled with the
+ * clipping we have right now. Battle Zone doesn't seem to
+ * invert zblank so it's no issue.
+ */
+ vg->izblank = vg->dvy & 0x100;
+ }
+ }
+ return avg_common_strobe2(vg);
+}
+
+static int avg_common_strobe3(vgdata *vg)
+{
+ int cycles=0;
+
+ vg->halt = OP0;
+
+ if ((vg->op & 5) == 0)
+ {
+ if (OP1)
+ {
+ cycles = 0x100 - (vg->timer & 0xff);
+ }
+ else
+ {
+ cycles = 0x8000 - vg->timer;
+ }
+ vg->timer = 0;
+
+ vg->xpos += ((((vg->dvx >> 3) ^ vg->xdac_xor) - 0x200) * cycles * (vg->scale ^ 0xff)) >> 4;
+ vg->ypos -= ((((vg->dvy >> 3) ^ vg->ydac_xor) - 0x200) * cycles * (vg->scale ^ 0xff)) >> 4;
+ }
+ if (OP2)
+ {
+ cycles = 0x8000 - vg->timer;
+ vg->timer = 0;
+ vg->xpos = xcenter;
+ vg->ypos = ycenter;
+ vg_add_point_buf(vg->xpos, vg->ypos, 0, 0);
+ }
+
+ return cycles;
+}
+
+static int avg_strobe3(vgdata *vg)
+{
+ int cycles;
+
+ cycles = avg_common_strobe3(vg);
+
+ if ((vg->op & 5) == 0)
+ {
+ vg_add_point_buf(vg->xpos, vg->ypos, VECTOR_COLOR111(vg->color),
+ (((vg->int_latch >> 1) == 1)? vg->intensity: vg->int_latch & 0xe) << 4);
+ }
+
+ return cycles;
+}
+
+static int bzone_strobe3(vgdata *vg)
+{
+ /* Battle Zone is B/W */
+ int cycles;
+
+ cycles = avg_common_strobe3(vg);
+
+ if ((vg->op & 5) == 0)
+ {
+ vg_add_point_buf(vg->xpos, vg->ypos, VECTOR_COLOR111(7),
+ (((vg->int_latch >> 1) == 1)? vg->intensity: vg->int_latch & 0xe) << 4);
+ }
+
+ return cycles;
+}
+
+static int tempest_strobe3(vgdata *vg)
+{
+ int cycles, r, g, b, bit0, bit1, bit2, bit3, x, y;
+ UINT8 data;
+
+ cycles = avg_common_strobe3(vg);
+
+ if ((vg->op & 5) == 0)
+ {
+ data = tempest_colorram[vg->color];
+ bit3 = (~data >> 3) & 1;
+ bit2 = (~data >> 2) & 1;
+ bit1 = (~data >> 1) & 1;
+ bit0 = (~data >> 0) & 1;
+
+ r = bit1 * 0xf3 + bit0 * 0x0c;
+ g = bit3 * 0xf3;
+ b = bit2 * 0xf3;
+
+ x = vg->xpos;
+ y = vg->ypos;
+
+ avg_apply_flipping(&x, &y);
+
+ vg_add_point_buf(y - ycenter + xcenter,
+ x - xcenter + ycenter, MAKE_RGB(r, g, b),
+ (((vg->int_latch >> 1) == 1)? vg->intensity: vg->int_latch & 0xe) << 4);
+ }
+
+ return cycles;
+}
+
+static int mhavoc_strobe3(vgdata *vg)
+{
+ int cycles, r, g, b, bit0, bit1, bit2, bit3, dx, dy, i;
+
+ UINT8 data;
+
+ vg->halt = OP0;
+ cycles = 0;
+
+ if ((vg->op & 5) == 0)
+ {
+ if (OP1)
+ {
+ cycles = 0x100 - (vg->timer & 0xff);
+ }
+ else
+ {
+ cycles = 0x8000 - vg->timer;
+ }
+ vg->timer = 0;
+ dx = ((((vg->dvx >> 3) ^ vg->xdac_xor) - 0x200) * (vg->scale ^ 0xff));
+ dy = ((((vg->dvy >> 3) ^ vg->ydac_xor) - 0x200) * (vg->scale ^ 0xff));
+
+
+ if (vg->enspkl)
+ {
+ for (i=0; i<cycles/8; i++)
+ {
+ vg->xpos += dx/2;
+ vg->ypos -= dy/2;
+ data = mhavoc_colorram[0xf +
+ (((vg->spkl_shift & 1) << 3)
+ | (vg->spkl_shift & 4)
+ | ((vg->spkl_shift & 0x10) >> 3)
+ | ((vg->spkl_shift & 0x40) >> 6))];
+ bit3 = (~data >> 3) & 1;
+ bit2 = (~data >> 2) & 1;
+ bit1 = (~data >> 1) & 1;
+ bit0 = (~data >> 0) & 1;
+ r = bit3 * 0xcb + bit2 * 0x34;
+ g = bit1 * 0xcb;
+ b = bit0 * 0xcb;
+
+ vg_add_point_buf(vg->xpos, vg->ypos, MAKE_RGB(r, g, b),
+ (((vg->int_latch >> 1) == 1)? vg->intensity: vg->int_latch & 0xe) << 4);
+ vg->spkl_shift = (((vg->spkl_shift & 0x40) >> 6)
+ ^ ((vg->spkl_shift & 0x20) >> 5)
+ ^ 1 )
+ | (vg->spkl_shift << 1);
+
+ if ((vg->spkl_shift & 0x7f) == 0x7f)
+ vg->spkl_shift = 0;
+ }
+ }
+ else
+ {
+ vg->xpos += (dx * cycles) >> 4;
+ vg->ypos -= (dy * cycles) >> 4;
+ data = mhavoc_colorram[vg->color];
+
+ bit3 = (~data >> 3) & 1;
+ bit2 = (~data >> 2) & 1;
+ bit1 = (~data >> 1) & 1;
+ bit0 = (~data >> 0) & 1;
+ r = bit3 * 0xcb + bit2 * 0x34;
+ g = bit1 * 0xcb;
+ b = bit0 * 0xcb;
+
+ vg_add_point_buf(vg->xpos, vg->ypos, MAKE_RGB(r, g, b),
+ (((vg->int_latch >> 1) == 1)? vg->intensity: vg->int_latch & 0xe) << 4);
+ }
+ }
+ if (OP2)
+ {
+ cycles = 0x8000 - vg->timer;
+ vg->timer = 0;
+ vg->xpos = xcenter;
+ vg->ypos = ycenter;
+ vg_add_point_buf(vg->xpos, vg->ypos, 0, 0);
+ }
+
+ return cycles;
+}
+
+static int starwars_strobe3(vgdata *vg)
+{
+ int cycles;
+
+ cycles = avg_common_strobe3(vg);
+
+ if ((vg->op & 5) == 0)
+ {
+ vg_add_point_buf(vg->xpos, vg->ypos, VECTOR_COLOR111(vg->color),
+ ((vg->int_latch >> 1) * vg->intensity) >> 3);
+ }
+
+ return cycles;
+}
+
+static int quantum_strobe3(vgdata *vg)
+{
+ int cycles=0, r, g, b, bit0, bit1, bit2, bit3, x, y;
+
+ UINT16 data;
+
+ vg->halt = OP0;
+
+ if ((vg->op & 5) == 0)
+ {
+ data = quantum_colorram[vg->color];
+ bit3 = (~data >> 3) & 1;
+ bit2 = (~data >> 2) & 1;
+ bit1 = (~data >> 1) & 1;
+ bit0 = (~data >> 0) & 1;
+
+ g = bit1 * 0xaa + bit0 * 0x54;
+ b = bit2 * 0xce;
+ r = bit3 * 0xce;
+
+ cycles = 0x4000 - vg->timer;
+ vg->timer = 0;
+
+ vg->xpos += (((((vg->dvx & 0xfff) >> 2) ^ vg->xdac_xor) - 0x200) * cycles * (vg->scale ^ 0xff)) >> 4;
+ vg->ypos -= (((((vg->dvy & 0xfff) >> 2) ^ vg->ydac_xor) - 0x200) * cycles * (vg->scale ^ 0xff)) >> 4;
+
+ x = vg->xpos;
+ y = vg->ypos;
+
+ avg_apply_flipping(&x, &y);
+
+ vg_add_point_buf(y - ycenter + xcenter,
+ x - xcenter + ycenter, MAKE_RGB(r, g, b),
+ ((vg->int_latch == 2)? vg->intensity: vg->int_latch) << 4);
+ }
+ if (OP2)
+ {
+ cycles = 0x4000 - vg->timer;
+ vg->timer = 0;
+ vg->xpos = xcenter;
+ vg->ypos = ycenter;
+ vg_add_point_buf(vg->xpos, vg->ypos, 0, 0);
+ }
+
+ return cycles;
+}
+
+static void avg_vggo(vgdata *vg)
+{
+ vg->pc = 0;
+ vg->sp = 0;
+}
+
+static void dvg_vggo(vgdata *vg)
+{
+ vg->dvy = 0;
+ vg->op = 0;
+}
+
+static void avg_vgrst(vgdata *vg)
+{
+ vg->state_latch = 0;
+ vg->bin_scale = 0;
+ vg->scale = 0;
+ vg->color = 0;
+}
+
+static void mhavoc_vgrst(vgdata *vg)
+{
+ avg_vgrst(vg);
+ vg->enspkl = 0;
+}
+
+static void dvg_vgrst(vgdata *vg)
+{
+ vg->state_latch = 0;
+ vg->dvy = 0;
+ vg->op = 0;
+}
+
+static void vg_set_halt(int dummy)
+{
+ vg->halt = dummy;
+ vg->sync_halt = dummy;
+}
+
+static TIMER_CALLBACK( vg_set_halt_callback )
+{
+ vg_set_halt(param);
+}
+
+
+/********************************************************************
+ *
+ * State Machine
+ *
+ * The state machine is a 256x4 bit PROM connected to a latch. The
+ * address of the next state is generated from the latched previous
+ * state, an op code and the halt flag. Op codes come from vector
+ * RAM/ROM. The state machine is clocked with 1.5 MHz. Three bits of
+ * the state are decoded and used to trigger various parts of the
+ * hardware.
+ *
+ *******************************************************************/
+
+static TIMER_CALLBACK( run_state_machine )
+{
+ int cycles = 0;
+ UINT8 *state_prom = memory_region(REGION_USER1);
+
+ while (cycles < VGSLICE)
+ {
+ /* Get next state */
+ vg->state_latch = (vg->state_latch & 0x10)
+ | (state_prom[vgc->state_addr(vg)] & 0xf);
+
+ if (ST3)
+ {
+ /* Read vector RAM/ROM */
+ vgc->update_databus(vg);
+
+ /* Decode state and call the corresponding handler */
+ cycles += (vgc->handler[vg->state_latch & 7])(vg);
+ }
+
+ /* If halt flag was set, let CPU catch up before we make halt visible */
+ if (vg->halt && !(vg->state_latch & 0x10))
+ timer_adjust(vg_halt_timer, attotime_mul(ATTOTIME_IN_HZ(MASTER_CLOCK), cycles), 1, attotime_zero);
+
+ vg->state_latch = (vg->halt << 4) | (vg->state_latch & 0xf);
+ cycles += 8;
+ }
+
+ timer_adjust(vg_run_timer, attotime_mul(ATTOTIME_IN_HZ(MASTER_CLOCK), cycles), 0, attotime_zero);
+}
+
+
+/*************************************
+ *
+ * VG halt/vggo
+ *
+ ************************************/
+
+int avgdvg_done(void)
+{
+ return vg->sync_halt;
+}
+
+WRITE8_HANDLER( avgdvg_go_w )
+{
+ if (vg->sync_halt && (nvect > 10))
+ {
+ /*
+ * This is a good time to start a new frame. Major Havoc
+ * sometimes sets VGGO after a very short vector list. That's
+ * why we ignore frames with less than 10 vectors.
+ */
+ vector_clear_list();
+ }
+ vg_flush();
+
+ vgc->vggo(vg);
+ vg_set_halt(0);
+ timer_adjust(vg_run_timer, attotime_zero, 0, attotime_zero);
+}
+
+WRITE16_HANDLER( avgdvg_go_word_w )
+{
+ avgdvg_go_w(offset, data);
+}
+
+
+/*************************************
+ *
+ * Reset
+ *
+ ************************************/
+
+WRITE8_HANDLER( avgdvg_reset_w )
+{
+ vgc->vgrst(vg);
+ vg_set_halt(1);
+}
+
+WRITE16_HANDLER( avgdvg_reset_word_w )
+{
+ avgdvg_reset_w (0,0);
+}
+
+MACHINE_RESET( avgdvg )
+{
+ avgdvg_reset_w (0,0);
+}
+
+
+/*************************************
+ *
+ * Vector generator init
+ *
+ ************************************/
+
+static VIDEO_START( avgdvg )
+{
+ xmin = machine->screen[0].visarea.min_x;
+ ymin = machine->screen[0].visarea.min_y;
+ xmax = machine->screen[0].visarea.max_x;
+ ymax = machine->screen[0].visarea.max_y;
+
+ xcenter = ((xmax + xmin) / 2) << 16;
+ ycenter = ((ymax + ymin) / 2) << 16;
+
+ flip_x = flip_y = 0;
+
+ vg_halt_timer = timer_alloc(vg_set_halt_callback);
+ vg_run_timer = timer_alloc(run_state_machine);
+
+ /*
+ * The x and y DACs use 10 bit of the counter values which are in
+ * two's complement representation. The DAC input is xored with
+ * 0x200 to convert the value to unsigned.
+ */
+ vg->xdac_xor = 0x200;
+ vg->ydac_xor = 0x200;
+
+ state_save_register_item("AVG", 0, vg->pc);
+ state_save_register_item("AVG", 0, vg->sp);
+ state_save_register_item("AVG", 0, vg->dvx);
+ state_save_register_item("AVG", 0, vg->dvy);
+ state_save_register_item("AVG", 0, vg->dvy12);
+ state_save_register_item("AVG", 0, vg->timer);
+ state_save_register_item_array("AVG", 0, vg->stack);
+ state_save_register_item("AVG", 0, vg->data);
+ state_save_register_item("AVG", 0, vg->state_latch);
+ state_save_register_item("AVG", 0, vg->int_latch);
+ state_save_register_item("AVG", 0, vg->scale);
+ state_save_register_item("AVG", 0, vg->bin_scale);
+ state_save_register_item("AVG", 0, vg->intensity);
+ state_save_register_item("AVG", 0, vg->color);
+ state_save_register_item("AVG", 0, vg->enspkl);
+ state_save_register_item("AVG", 0, vg->spkl_shift);
+ state_save_register_item("AVG", 0, vg->map);
+ state_save_register_item("AVG", 0, vg->hst);
+ state_save_register_item("AVG", 0, vg->lst);
+ state_save_register_item("AVG", 0, vg->izblank);
+ state_save_register_item("AVG", 0, vg->op);
+ state_save_register_item("AVG", 0, vg->halt);
+ state_save_register_item("AVG", 0, vg->sync_halt);
+ state_save_register_item("AVG", 0, vg->xdac_xor);
+ state_save_register_item("AVG", 0, vg->ydac_xor);
+ state_save_register_item("AVG", 0, vg->xpos);
+ state_save_register_item("AVG", 0, vg->ypos);
+ state_save_register_item("AVG", 0, vg->clipx_min);
+ state_save_register_item("AVG", 0, vg->clipy_min);
+ state_save_register_item("AVG", 0, vg->clipx_max);
+ state_save_register_item("AVG", 0, vg->clipy_max);
+
+ video_start_vector(machine);
+}
+
+
+/*************************************
+ *
+ * Configuration of VG variants
+ *
+ *************************************/
+
+static vgconf dvg_default =
+{
+ {
+ dvg_dmapush,
+ dvg_dmald,
+ dvg_gostrobe,
+ dvg_haltstrobe,
+ dvg_latch0,
+ dvg_latch1,
+ dvg_latch2,
+ dvg_latch3
+ },
+ dvg_state_addr,
+ dvg_data,
+ dvg_vggo,
+ dvg_vgrst
+};
+
+static vgconf avg_default =
+{
+ {
+ avg_latch0,
+ avg_latch1,
+ avg_latch2,
+ avg_latch3,
+ avg_strobe0,
+ avg_strobe1,
+ avg_strobe2,
+ avg_strobe3
+ },
+ avg_state_addr,
+ avg_data,
+ avg_vggo,
+ avg_vgrst
+};
+
+static vgconf avg_mhavoc =
+{
+ {
+ avg_latch0,
+ mhavoc_latch1,
+ avg_latch2,
+ avg_latch3,
+ avg_strobe0,
+ avg_strobe1,
+ mhavoc_strobe2,
+ mhavoc_strobe3
+ },
+ avg_state_addr,
+ mhavoc_data,
+ avg_vggo,
+ mhavoc_vgrst
+};
+
+static vgconf avg_starwars =
+{
+ {
+ avg_latch0,
+ avg_latch1,
+ avg_latch2,
+ avg_latch3,
+ avg_strobe0,
+ avg_strobe1,
+ starwars_strobe2,
+ starwars_strobe3
+ },
+ avg_state_addr,
+ starwars_data,
+ avg_vggo,
+ avg_vgrst
+};
+
+static vgconf avg_tempest =
+{
+ {
+ avg_latch0,
+ avg_latch1,
+ avg_latch2,
+ avg_latch3,
+ avg_strobe0,
+ avg_strobe1,
+ tempest_strobe2,
+ tempest_strobe3
+ },
+ avg_state_addr,
+ avg_data,
+ avg_vggo,
+ avg_vgrst
+};
+
+static vgconf avg_bzone =
+{
+ {
+ avg_latch0,
+ bzone_latch1,
+ avg_latch2,
+ avg_latch3,
+ avg_strobe0,
+ avg_strobe1,
+ bzone_strobe2,
+ bzone_strobe3
+ },
+ avg_state_addr,
+ avg_data,
+ avg_vggo,
+ avg_vgrst
+};
+
+static vgconf avg_quantum =
+{
+ {
+ quantum_st2st3,
+ quantum_latch1,
+ quantum_st2st3,
+ quantum_latch3,
+ quantum_strobe0,
+ quantum_strobe1,
+ quantum_strobe2,
+ quantum_strobe3
+ },
+ avg_state_addr,
+ quantum_data,
+ avg_vggo,
+ avg_vgrst
+};
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ ************************************/
+
+VIDEO_START( dvg )
+{
+ vgc = &dvg_default;
+ vg = &vgd;
+ video_start_avgdvg(machine);
+}
+
+VIDEO_START( avg )
+{
+ vgc = &avg_default;
+ vg = &vgd;
+ video_start_avgdvg(machine);
+}
+
+VIDEO_START( avg_starwars )
+{
+ vgc = &avg_starwars;
+ vg = &vgd;
+ video_start_avgdvg(machine);
+}
+
+VIDEO_START( avg_tempest )
+{
+ vgc = &avg_tempest;
+ vg = &vgd;
+ video_start_avgdvg(machine);
+}
+
+VIDEO_START( avg_mhavoc )
+{
+ vgc = &avg_mhavoc;
+ vg = &vgd;
+ video_start_avgdvg(machine);
+}
+
+VIDEO_START( avg_bzone )
+{
+ vgc = &avg_bzone;
+ vg = &vgd;
+ video_start_avgdvg(machine);
+}
+
+VIDEO_START( avg_quantum )
+{
+ vgc = &avg_quantum;
+ vg = &vgd;
+ video_start_avgdvg(machine);
+}
+
diff --git a/src/mame/video/avgdvg.h b/src/mame/video/avgdvg.h
new file mode 100644
index 00000000000..065c0cd28d1
--- /dev/null
+++ b/src/mame/video/avgdvg.h
@@ -0,0 +1,29 @@
+#ifndef __AVGDVG__
+#define __AVGDVG__
+
+extern UINT8 *tempest_colorram;
+extern UINT8 *mhavoc_colorram;
+extern UINT16 *quantum_colorram;
+extern UINT16 *quantum_vectorram;
+
+int avgdvg_done(void);
+WRITE8_HANDLER( avgdvg_go_w );
+WRITE8_HANDLER( avgdvg_reset_w );
+WRITE16_HANDLER( avgdvg_go_word_w );
+WRITE16_HANDLER( avgdvg_reset_word_w );
+
+/* Tempest and Quantum use this capability */
+void avg_set_flip_x(int flip);
+void avg_set_flip_y(int flip);
+
+VIDEO_START( dvg );
+VIDEO_START( avg );
+VIDEO_START( avg_tempest );
+VIDEO_START( avg_mhavoc );
+VIDEO_START( avg_starwars );
+VIDEO_START( avg_quantum );
+VIDEO_START( avg_bzone );
+
+MACHINE_RESET( avgdvg );
+
+#endif
diff --git a/src/mame/video/aztarac.c b/src/mame/video/aztarac.c
new file mode 100644
index 00000000000..a671a0731a6
--- /dev/null
+++ b/src/mame/video/aztarac.c
@@ -0,0 +1,95 @@
+/*************************************************************************
+
+ Centuri Aztarac hardware
+
+*************************************************************************/
+
+#include "driver.h"
+#include "video/vector.h"
+#include "aztarac.h"
+
+#define AVECTOR(x, y, color, intensity) \
+vector_add_point (xcenter + ((x) << 16), ycenter - ((y) << 16), color, intensity)
+
+UINT16 *aztarac_vectorram;
+
+static int xcenter, ycenter;
+
+INLINE void read_vectorram (int addr, int *x, int *y, int *c)
+{
+ *c = aztarac_vectorram[addr] & 0xffff;
+ *x = aztarac_vectorram[addr + 0x800] & 0x03ff;
+ *y = aztarac_vectorram[addr + 0x1000] & 0x03ff;
+ if (*x & 0x200) *x |= 0xfffffc00;
+ if (*y & 0x200) *y |= 0xfffffc00;
+}
+
+WRITE16_HANDLER( aztarac_ubr_w )
+{
+ int x, y, c, intensity, xoffset, yoffset, color;
+ int defaddr, objaddr=0, ndefs;
+
+ if (data) /* data is the global intensity (always 0xff in Aztarac). */
+ {
+ vector_clear_list();
+
+ while (1)
+ {
+ read_vectorram (objaddr, &xoffset, &yoffset, &c);
+ objaddr++;
+
+ if (c & 0x4000)
+ break;
+
+ if ((c & 0x2000) == 0)
+ {
+ defaddr = (c >> 1) & 0x7ff;
+ AVECTOR (xoffset, yoffset, 0, 0);
+
+ read_vectorram (defaddr, &x, &ndefs, &c);
+ ndefs++;
+
+ if (c & 0xff00)
+ {
+ /* latch color only once */
+ intensity = (c >> 8);
+ color = VECTOR_COLOR222(c & 0x3f);
+ while (ndefs--)
+ {
+ defaddr++;
+ read_vectorram (defaddr, &x, &y, &c);
+ if ((c & 0xff00) == 0)
+ AVECTOR (x + xoffset, y + yoffset, 0, 0);
+ else
+ AVECTOR (x + xoffset, y + yoffset, color, intensity);
+ }
+ }
+ else
+ {
+ /* latch color for every definition */
+ while (ndefs--)
+ {
+ defaddr++;
+ read_vectorram (defaddr, &x, &y, &c);
+ color = VECTOR_COLOR222(c & 0x3f);
+ AVECTOR (x + xoffset, y + yoffset, color, c >> 8);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+VIDEO_START( aztarac )
+{
+ int xmin = machine->screen[0].visarea.min_x;
+ int ymin = machine->screen[0].visarea.min_y;
+ int xmax = machine->screen[0].visarea.max_x;
+ int ymax = machine->screen[0].visarea.max_y;
+
+ xcenter=((xmax + xmin) / 2) << 16;
+ ycenter=((ymax + ymin) / 2) << 16;
+
+ video_start_vector(machine);
+}
diff --git a/src/mame/video/badlands.c b/src/mame/video/badlands.c
new file mode 100644
index 00000000000..0920d05c388
--- /dev/null
+++ b/src/mame/video/badlands.c
@@ -0,0 +1,147 @@
+/***************************************************************************
+
+ Atari Bad Lands hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "includes/badlands.h"
+
+
+
+/*************************************
+ *
+ * Local variables
+ *
+ *************************************/
+
+static UINT8 playfield_tile_bank;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data = atarigen_playfield[tile_index];
+ int code = (data & 0x1fff) + ((data & 0x1000) ? (playfield_tile_bank << 12) : 0);
+ int color = (data >> 13) & 0x07;
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+
+
+/*************************************
+ *
+ * Generic video system start
+ *
+ *************************************/
+
+VIDEO_START( badlands )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 1, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 0, /* are the entries linked? */
+ 1, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 0, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x80, /* base palette entry */
+ 0x80, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0x1f }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0x0fff,0,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0,0x0007 }}, /* mask for the color */
+ {{ 0,0,0,0xff80 }}, /* mask for the X position */
+ {{ 0,0xff80,0,0 }}, /* mask for the Y position */
+ {{ 0 }}, /* mask for the width, in tiles*/
+ {{ 0,0x000f,0,0 }}, /* mask for the height, in tiles */
+ {{ 0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0,0,0,0x0008 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0 /* callback routine for special entries */
+ };
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+}
+
+
+
+/*************************************
+ *
+ * Playfield bank write handler
+ *
+ *************************************/
+
+WRITE16_HANDLER( badlands_pf_bank_w )
+{
+ if (ACCESSING_LSB)
+ if (playfield_tile_bank != (data & 1))
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ playfield_tile_bank = data & 1;
+ tilemap_mark_all_tiles_dirty(atarigen_playfield_tilemap);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( badlands )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* not yet verified
+ */
+ if ((mo[x] & ATARIMO_PRIORITY_MASK) || !(pf[x] & 8))
+ pf[x] = mo[x] & ATARIMO_DATA_MASK;
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/bagman.c b/src/mame/video/bagman.c
new file mode 100644
index 00000000000..0fa37eb744b
--- /dev/null
+++ b/src/mame/video/bagman.c
@@ -0,0 +1,153 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/resnet.h"
+
+
+UINT8 *bagman_video_enable;
+
+static tilemap *bg_tilemap;
+
+
+WRITE8_HANDLER( bagman_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( bagman_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Bagman has two 32 bytes palette PROMs, connected to the RGB output this
+ way:
+
+ bit 7 -- 220 ohm resistor -- \
+ -- 470 ohm resistor -- | -- 470 ohm pulldown resistor -- BLUE
+
+ -- 220 ohm resistor -- \
+ -- 470 ohm resistor -- | -- 470 ohm pulldown resistor -- GREEN
+ -- 1 kohm resistor -- /
+
+ -- 220 ohm resistor -- \
+ -- 470 ohm resistor -- | -- 470 ohm pulldown resistor -- RED
+ bit 0 -- 1 kohm resistor -- /
+
+***************************************************************************/
+PALETTE_INIT( bagman )
+{
+ int i;
+ static const int resistances_rg[3] = { 1000, 470, 220 };
+ static const int resistances_b [2] = { 470, 220 };
+ double weights_r[3], weights_g[3], weights_b[2];
+
+
+ compute_resistor_weights(0, 255, -1.0,
+ 3, resistances_rg, weights_r, 470, 0,
+ 3, resistances_rg, weights_g, 470, 0,
+ 2, resistances_b, weights_b, 470, 0);
+
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = combine_3_weights(weights_r, bit0, bit1, bit2);
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = combine_3_weights(weights_g, bit0, bit1, bit2);
+ /* blue component */
+ bit0 = (color_prom[i] >> 6) & 0x01;
+ bit1 = (color_prom[i] >> 7) & 0x01;
+ b = combine_2_weights(weights_b, bit0, bit1);
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+WRITE8_HANDLER( bagman_flipscreen_w )
+{
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int gfxbank = (machine->gfx[2] && (colorram[tile_index] & 0x10)) ? 2 : 0;
+ int code = videoram[tile_index] + 8 * (colorram[tile_index] & 0x20);
+ int color = colorram[tile_index] & 0x0f;
+
+ SET_TILE_INFO(gfxbank, code, color, 0);
+}
+
+VIDEO_START( bagman )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int sx,sy,flipx,flipy;
+
+
+ sx = spriteram[offs + 3];
+ sy = 240 - spriteram[offs + 2];
+ flipx = spriteram[offs] & 0x40;
+ flipy = spriteram[offs] & 0x80;
+ if (flip_screen_x)
+ {
+ sx = 240 - sx +1; /* compensate misplacement */
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ if (spriteram[offs + 2] && spriteram[offs + 3])
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs] & 0x3f) + 2 * (spriteram[offs + 1] & 0x20),
+ spriteram[offs + 1] & 0x1f,
+ flipx,flipy,
+ sx,sy+1, /* compensate misplacement */
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+VIDEO_UPDATE( bagman )
+{
+ if (*bagman_video_enable == 0)
+ return 0;
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/balsente.c b/src/mame/video/balsente.c
new file mode 100644
index 00000000000..3accd77acdf
--- /dev/null
+++ b/src/mame/video/balsente.c
@@ -0,0 +1,239 @@
+/***************************************************************************
+
+ video/balsente.c
+
+ Functions to emulate the video hardware of the machine.
+
+****************************************************************************/
+
+#include "driver.h"
+#include "balsente.h"
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static UINT8 *local_videoram;
+static UINT8 *sprite_data;
+static UINT32 sprite_mask;
+static UINT8 *sprite_bank[2];
+
+static UINT8 palettebank_vis;
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( balsente )
+{
+ /* reset the system */
+ palettebank_vis = 0;
+ sprite_bank[0] = memory_region(REGION_GFX1);
+ sprite_bank[1] = memory_region(REGION_GFX1) + 0x10000;
+
+ /* allocate a local copy of video RAM */
+ local_videoram = auto_malloc(256 * 256);
+
+ /* determine sprite size */
+ sprite_data = memory_region(REGION_GFX1);
+ sprite_mask = memory_region_length(REGION_GFX1) - 1;
+
+ /* register for saving */
+ state_save_register_global_pointer(local_videoram, 256 * 256);
+ state_save_register_global(palettebank_vis);
+}
+
+
+
+/*************************************
+ *
+ * Video RAM write
+ *
+ *************************************/
+
+WRITE8_HANDLER( balsente_videoram_w )
+{
+ videoram[offset] = data;
+
+ /* expand the two pixel values into two bytes */
+ local_videoram[offset * 2 + 0] = data >> 4;
+ local_videoram[offset * 2 + 1] = data & 15;
+}
+
+
+
+/*************************************
+ *
+ * Palette banking
+ *
+ *************************************/
+
+WRITE8_HANDLER( balsente_palette_select_w )
+{
+ /* only update if changed */
+ if (palettebank_vis != (data & 3))
+ {
+ /* update the scanline palette */
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1 + BALSENTE_VBEND);
+ palettebank_vis = data & 3;
+ }
+
+ logerror("balsente_palette_select_w(%d) scanline=%d\n", data & 3, video_screen_get_vpos(0));
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM write
+ *
+ *************************************/
+
+WRITE8_HANDLER( balsente_paletteram_w )
+{
+ int r, g, b;
+
+ paletteram[offset] = data & 0x0f;
+
+ r = paletteram[(offset & ~3) + 0];
+ g = paletteram[(offset & ~3) + 1];
+ b = paletteram[(offset & ~3) + 2];
+
+ palette_set_color_rgb(Machine, offset / 4, pal4bit(r), pal4bit(g), pal4bit(b));
+}
+
+
+
+/*************************************
+ *
+ * Sprite banking
+ *
+ *************************************/
+
+WRITE8_HANDLER( shrike_sprite_select_w )
+{
+ if( sprite_data != sprite_bank[(data & 0x80 >> 7) ^ 1 ])
+ {
+ logerror( "shrike_sprite_select_w( 0x%02x )\n", data );
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1 + BALSENTE_VBEND);
+ sprite_data = sprite_bank[(data & 0x80 >> 7) ^ 1];
+ }
+
+ shrike_shared_6809_w( 1, data );
+}
+
+
+
+/*************************************
+ *
+ * Sprite drawing
+ *
+ *************************************/
+
+static void draw_one_sprite(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8 *sprite)
+{
+ int flags = sprite[0];
+ int image = sprite[1] | ((flags & 7) << 8);
+ int ypos = sprite[2] + 17 + BALSENTE_VBEND;
+ int xpos = sprite[3];
+ UINT8 *src;
+ int x, y;
+
+ /* get a pointer to the source image */
+ src = &sprite_data[(64 * image) & sprite_mask];
+ if (flags & 0x80) src += 4 * 15;
+
+ /* loop over y */
+ for (y = 0; y < 16; y++, ypos = (ypos + 1) & 255)
+ {
+ if (ypos >= (16 + BALSENTE_VBEND) && ypos >= cliprect->min_y && ypos <= cliprect->max_y)
+ {
+ const pen_t *pens = &machine->pens[palettebank_vis * 256];
+ UINT8 *old = &local_videoram[(ypos - BALSENTE_VBEND) * 256 + xpos];
+ int currx = xpos;
+
+ /* standard case */
+ if (!(flags & 0x40))
+ {
+ /* loop over x */
+ for (x = 0; x < 4; x++, old += 2)
+ {
+ int ipixel = *src++;
+ int left = ipixel & 0xf0;
+ int right = (ipixel << 4) & 0xf0;
+
+ /* left pixel, combine with the background */
+ if (left && currx >= 0 && currx < 256)
+ *BITMAP_ADDR16(bitmap, ypos, currx) = pens[left | old[0]];
+ currx++;
+
+ /* right pixel, combine with the background */
+ if (right && currx >= 0 && currx < 256)
+ *BITMAP_ADDR16(bitmap, ypos, currx) = pens[right | old[1]];
+ currx++;
+ }
+ }
+
+ /* hflip case */
+ else
+ {
+ src += 4;
+
+ /* loop over x */
+ for (x = 0; x < 4; x++, old += 2)
+ {
+ int ipixel = *--src;
+ int left = (ipixel << 4) & 0xf0;
+ int right = ipixel & 0xf0;
+
+ /* left pixel, combine with the background */
+ if (left && currx >= 0 && currx < 256)
+ *BITMAP_ADDR16(bitmap, ypos, currx) = pens[left | old[0]];
+ currx++;
+
+ /* right pixel, combine with the background */
+ if (right && currx >= 0 && currx < 256)
+ *BITMAP_ADDR16(bitmap, ypos, currx) = pens[right | old[1]];
+ currx++;
+ }
+ src += 4;
+ }
+ }
+ else
+ src += 4;
+ if (flags & 0x80) src -= 2 * 4;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main screen refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( balsente )
+{
+ const pen_t *pens = &machine->pens[palettebank_vis * 256];
+ int y, i;
+
+ /* draw scanlines from the VRAM directly */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ draw_scanline8(bitmap, 0, y, 256, &local_videoram[(y - BALSENTE_VBEND) * 256], pens, -1);
+ }
+
+ /* draw the sprite images */
+ for (i = 0; i < 40; i++)
+ draw_one_sprite(machine, bitmap, cliprect, &spriteram[(0xe0 + i * 4) & 0xff]);
+
+ return 0;
+}
diff --git a/src/mame/video/bankp.c b/src/mame/video/bankp.c
new file mode 100644
index 00000000000..ba2ce02cc51
--- /dev/null
+++ b/src/mame/video/bankp.c
@@ -0,0 +1,205 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *bankp_videoram2;
+UINT8 *bankp_colorram2;
+
+static int scroll_x;
+static int priority;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+static colortable *bankp_colortable;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Bank Panic has a 32x8 palette PROM (I'm not sure whether the second 16
+ bytes are used - they contain the same colors as the first 16 with only
+ one different) and two 256x4 lookup table PROMs (one for charset #1, one
+ for charset #2 - only the first 128 nibbles seem to be used).
+
+ I don't know for sure how the palette PROM is connected to the RGB output,
+ but it's probably the usual:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( bankp )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ /* allocate the colortable */
+ bankp_colortable = colortable_alloc(machine, 32);
+
+ for (i = 0;i < 32;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ colortable_palette_set_color(bankp_colortable,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* charset #1 lookup table */
+ for (i = 0;i < machine->gfx[0]->total_colors * machine->gfx[0]->color_granularity;i++)
+ colortable_entry_set_value(bankp_colortable, machine->gfx[0]->color_base + i, *color_prom++ & 0x0f);
+
+ color_prom += 128; /* skip the bottom half of the PROM - seems to be not used */
+
+ /* charset #2 lookup table */
+ for (i = 0;i < machine->gfx[1]->total_colors * machine->gfx[1]->color_granularity;i++)
+ colortable_entry_set_value(bankp_colortable, machine->gfx[1]->color_base + i, *color_prom++ & 0x0f);
+
+ /* the bottom half of the PROM seems to be not used */
+}
+
+WRITE8_HANDLER( bankp_scroll_w )
+{
+ scroll_x = data;
+}
+
+WRITE8_HANDLER( bankp_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( bankp_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( bankp_videoram2_w )
+{
+ bankp_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( bankp_colorram2_w )
+{
+ bankp_colorram2[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( bankp_out_w )
+{
+ /* bits 0-1 are playfield priority */
+ /* TODO: understand how this works */
+ priority = data & 0x03;
+
+ /* bits 2-3 unknown (2 is used) */
+
+ /* bit 4 controls NMI */
+ interrupt_enable_w(0,(data & 0x10)>>4);
+
+ /* bit 5 controls screen flip */
+ flip_screen_set(data & 0x20);
+
+ /* bits 6-7 unknown */
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = bankp_videoram2[tile_index] + 256 * (bankp_colorram2[tile_index] & 0x07);
+ int color = bankp_colorram2[tile_index] >> 4;
+ int flags = (bankp_colorram2[tile_index] & 0x08) ? TILE_FLIPX : 0;
+
+ SET_TILE_INFO(1, code, color, flags);
+ tileinfo->group = color;
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = videoram[tile_index] + 256 * ((colorram[tile_index] & 3) >> 0);
+ int color = colorram[tile_index] >> 3;
+ int flags = (colorram[tile_index] & 0x04) ? TILE_FLIPX : 0;
+
+ SET_TILE_INFO(0, code, color, flags);
+ tileinfo->group = color;
+}
+
+VIDEO_START( bankp )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ colortable_configure_tilemap_groups(bankp_colortable, bg_tilemap, machine->gfx[1], 0);
+ colortable_configure_tilemap_groups(bankp_colortable, fg_tilemap, machine->gfx[0], 0);
+}
+
+VIDEO_UPDATE( bankp )
+{
+ if (flip_screen)
+ {
+ tilemap_set_scrollx(fg_tilemap, 0, -scroll_x);
+ tilemap_set_scrollx(bg_tilemap, 0, 0);
+ }
+ else
+ {
+ tilemap_set_scrollx(fg_tilemap, 0, scroll_x);
+ tilemap_set_scrollx(bg_tilemap, 0, 0);
+ }
+
+
+ // only one bit matters?
+ switch (priority)
+ {
+ case 0: // combat hawk uses this
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_OPAQUE, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ break;
+ case 1:
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_OPAQUE, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ break;
+ case 2:
+ tilemap_draw(bitmap, cliprect, fg_tilemap, TILEMAP_DRAW_OPAQUE, 0);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ break;
+ case 3:
+ tilemap_draw(bitmap, cliprect, fg_tilemap, TILEMAP_DRAW_OPAQUE, 0); // just a guess
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ break;
+ }
+ return 0;
+}
diff --git a/src/mame/video/baraduke.c b/src/mame/video/baraduke.c
new file mode 100644
index 00000000000..7c9cf582ddc
--- /dev/null
+++ b/src/mame/video/baraduke.c
@@ -0,0 +1,350 @@
+#include "driver.h"
+
+UINT8 *baraduke_textram, *baraduke_videoram, *baraduke_spriteram;
+
+static tilemap *tx_tilemap, *bg_tilemap[2];
+static int xscroll[2], yscroll[2];
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs.
+
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+
+PALETTE_INIT( baraduke )
+{
+ int i;
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ for (i = 0; i < 2048; i++)
+ {
+ /* red component */
+ bit0 = (color_prom[2048] >> 0) & 0x01;
+ bit1 = (color_prom[2048] >> 1) & 0x01;
+ bit2 = (color_prom[2048] >> 2) & 0x01;
+ bit3 = (color_prom[2048] >> 3) & 0x01;
+ r = 0x0e*bit0 + 0x1f*bit1 + 0x43*bit2 + 0x8f*bit3;
+
+ /* green component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ g = 0x0e*bit0 + 0x1f*bit1 + 0x43*bit2 + 0x8f*bit3;
+
+ /* blue component */
+ bit0 = (color_prom[0] >> 4) & 0x01;
+ bit1 = (color_prom[0] >> 5) & 0x01;
+ bit2 = (color_prom[0] >> 6) & 0x01;
+ bit3 = (color_prom[0] >> 7) & 0x01;
+ b = 0x0e*bit0 + 0x1f*bit1 + 0x43*bit2 + 0x8f*bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/* convert from 32x32 to 36x28 */
+static TILEMAP_MAPPER( tx_tilemap_scan )
+{
+ int offs;
+
+ row += 2;
+ col -= 2;
+ if (col & 0x20)
+ offs = row + ((col & 0x1f) << 5);
+ else
+ offs = col + (row << 5);
+
+ return offs;
+}
+
+static TILE_GET_INFO( tx_get_tile_info )
+{
+ SET_TILE_INFO(
+ 0,
+ baraduke_textram[tile_index],
+ (baraduke_textram[tile_index+0x400] << 2) & 0x1ff,
+ 0);
+}
+
+static TILE_GET_INFO( get_tile_info0 )
+{
+ int code = baraduke_videoram[2*tile_index];
+ int attr = baraduke_videoram[2*tile_index + 1];
+
+ SET_TILE_INFO(
+ 1,
+ code + ((attr & 0x03) << 8),
+ attr,
+ 0);
+}
+
+static TILE_GET_INFO( get_tile_info1 )
+{
+ int code = baraduke_videoram[0x1000 + 2*tile_index];
+ int attr = baraduke_videoram[0x1000 + 2*tile_index + 1];
+
+ SET_TILE_INFO(
+ 2,
+ code + ((attr & 0x03) << 8),
+ attr,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( baraduke )
+{
+ tx_tilemap = tilemap_create(tx_get_tile_info,tx_tilemap_scan,TILEMAP_TYPE_PEN,8,8,36,28);
+ bg_tilemap[0] = tilemap_create(get_tile_info0,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ bg_tilemap[1] = tilemap_create(get_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_transparent_pen(tx_tilemap,3);
+ tilemap_set_transparent_pen(bg_tilemap[0],7);
+ tilemap_set_transparent_pen(bg_tilemap[1],7);
+
+ tilemap_set_scrolldx(tx_tilemap,0,512-288);
+ tilemap_set_scrolldy(tx_tilemap,16,16);
+
+ spriteram = baraduke_spriteram + 0x1800;
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ8_HANDLER( baraduke_videoram_r )
+{
+ return baraduke_videoram[offset];
+}
+
+WRITE8_HANDLER( baraduke_videoram_w )
+{
+ baraduke_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap[offset/0x1000],(offset&0xfff)/2);
+}
+
+READ8_HANDLER( baraduke_textram_r )
+{
+ return baraduke_textram[offset];
+}
+
+WRITE8_HANDLER( baraduke_textram_w )
+{
+ baraduke_textram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset & 0x3ff);
+}
+
+
+static void scroll_w(int layer,int offset,int data)
+{
+ switch (offset)
+ {
+ case 0: /* high scroll x */
+ xscroll[layer] = (xscroll[layer] & 0xff) | (data << 8);
+ break;
+ case 1: /* low scroll x */
+ xscroll[layer] = (xscroll[layer] & 0xff00) | data;
+ break;
+ case 2: /* scroll y */
+ yscroll[layer] = data;
+ break;
+ }
+}
+
+WRITE8_HANDLER( baraduke_scroll0_w )
+{
+ scroll_w(0, offset, data);
+}
+WRITE8_HANDLER( baraduke_scroll1_w )
+{
+ scroll_w(1, offset, data);
+}
+
+
+static int copy_sprites;
+
+READ8_HANDLER( baraduke_spriteram_r )
+{
+ return baraduke_spriteram[offset];
+}
+
+WRITE8_HANDLER( baraduke_spriteram_w )
+{
+ baraduke_spriteram[offset] = data;
+
+ /* a write to this offset tells the sprite chip to buffer the sprite list */
+ if (offset == 0x1ff2)
+ copy_sprites = 1;
+}
+
+
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int sprite_priority)
+{
+ const UINT8 *source = &spriteram[0];
+ const UINT8 *finish = &spriteram[0x0800-16]; /* the last is NOT a sprite */
+
+ int sprite_xoffs = spriteram[0x07f5] - 256 * (spriteram[0x07f4] & 1);
+ int sprite_yoffs = spriteram[0x07f7];
+
+ while( source<finish )
+ {
+/*
+ source[10] S-FT ---P
+ source[11] TTTT TTTT
+ source[12] CCCC CCCX
+ source[13] XXXX XXXX
+ source[14] ---T -S-F
+ source[15] YYYY YYYY
+*/
+ int priority = source[10] & 0x01;
+ if (priority == sprite_priority)
+ {
+ static const int gfx_offs[2][2] =
+ {
+ { 0, 1 },
+ { 2, 3 }
+ };
+ int attr1 = source[10];
+ int attr2 = source[14];
+ int color = source[12];
+ int sx = source[13] + (color & 0x01)*256;
+ int sy = 240 - source[15];
+ int flipx = (attr1 & 0x20) >> 5;
+ int flipy = (attr2 & 0x01);
+ int sizex = (attr1 & 0x80) >> 7;
+ int sizey = (attr2 & 0x04) >> 2;
+ int sprite = (source[11] & 0xff)*4;
+ int x,y;
+
+ if ((attr1 & 0x10) && !sizex) sprite += 1;
+ if ((attr2 & 0x10) && !sizey) sprite += 2;
+ color = color >> 1;
+
+ sx += sprite_xoffs;
+ sy -= sprite_yoffs;
+
+ sy -= 16 * sizey;
+
+ if (flip_screen)
+ {
+ sx = 496+3 - 16 * sizex - sx;
+ sy = 240 - 16 * sizey - sy;
+ flipx ^= 1;
+ flipy ^= 1;
+ }
+
+ for (y = 0;y <= sizey;y++)
+ {
+ for (x = 0;x <= sizex;x++)
+ {
+ drawgfx( bitmap, machine->gfx[3],
+ sprite + gfx_offs[y ^ (sizey * flipy)][x ^ (sizex * flipx)],
+ color,
+ flipx,flipy,
+ -71 + ((sx + 16*x) & 0x1ff),
+ 1 + ((sy + 16*y) & 0xff),
+ cliprect,TRANSPARENCY_PEN,0xf);
+ }
+ }
+ }
+
+ source+=16;
+ }
+}
+
+
+static void set_scroll(int layer)
+{
+ static const int xdisp[2] = { 26, 24 };
+ int scrollx, scrolly;
+
+ scrollx = xscroll[layer] + xdisp[layer];
+ scrolly = yscroll[layer] + 9;
+ if (flip_screen)
+ {
+ scrollx = -scrollx + 3;
+ scrolly = -scrolly;
+ }
+
+ tilemap_set_scrollx(bg_tilemap[layer], 0, scrollx);
+ tilemap_set_scrolly(bg_tilemap[layer], 0, scrolly);
+}
+
+
+VIDEO_UPDATE( baraduke )
+{
+ int back;
+
+ /* flip screen is embedded in the sprite control registers */
+ /* can't use flip_screen_set() because the visible area is asymmetrical */
+ flip_screen = spriteram[0x07f6] & 0x01;
+ tilemap_set_flip(ALL_TILEMAPS,flip_screen ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
+ set_scroll(0);
+ set_scroll(1);
+
+ if (((xscroll[0] & 0x0e00) >> 9) == 6)
+ back = 1;
+ else
+ back = 0;
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap[back],TILEMAP_DRAW_OPAQUE,0);
+ draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap[back ^ 1],0,0);
+ draw_sprites(machine, bitmap,cliprect,1);
+
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+
+VIDEO_EOF( baraduke )
+{
+ if (copy_sprites)
+ {
+ int i,j;
+
+ for (i = 0;i < 0x800;i += 16)
+ {
+ for (j = 10;j < 16;j++)
+ spriteram[i+j] = spriteram[i+j - 6];
+ }
+
+ copy_sprites = 0;
+ }
+}
diff --git a/src/mame/video/batman.c b/src/mame/video/batman.c
new file mode 100644
index 00000000000..0ad8499ccff
--- /dev/null
+++ b/src/mame/video/batman.c
@@ -0,0 +1,311 @@
+/***************************************************************************
+
+ Atari Batman hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "batman.h"
+#include "thunderj.h"
+
+
+
+/*************************************
+ *
+ * Globals
+ *
+ *************************************/
+
+UINT8 batman_alpha_tile_bank;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha[tile_index];
+ int code = ((data & 0x400) ? (batman_alpha_tile_bank * 0x400) : 0) + (data & 0x3ff);
+ int color = (data >> 11) & 0x0f;
+ int opaque = data & 0x8000;
+ SET_TILE_INFO(2, code, color, opaque ? TILE_FORCE_LAYER0 : 0);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data1 = atarigen_playfield[tile_index];
+ UINT16 data2 = atarigen_playfield_upper[tile_index] & 0xff;
+ int code = data1 & 0x7fff;
+ int color = 0x10 + (data2 & 0x0f);
+ SET_TILE_INFO(0, code, color, (data1 >> 15) & 1);
+ tileinfo->category = (data2 >> 4) & 3;
+}
+
+
+static TILE_GET_INFO( get_playfield2_tile_info )
+{
+ UINT16 data1 = atarigen_playfield2[tile_index];
+ UINT16 data2 = atarigen_playfield_upper[tile_index] >> 8;
+ int code = data1 & 0x7fff;
+ int color = data2 & 0x0f;
+ SET_TILE_INFO(0, code, color, (data1 >> 15) & 1);
+ tileinfo->category = (data2 >> 4) & 3;
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( batman )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 1, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 1, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 8, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x100, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0x03ff,0,0,0 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0,0x7fff,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0x000f,0 }}, /* mask for the color */
+ {{ 0,0,0xff80,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xff80 }}, /* mask for the Y position */
+ {{ 0,0,0,0x0070 }}, /* mask for the width, in tiles*/
+ {{ 0,0,0,0x0007 }}, /* mask for the height, in tiles */
+ {{ 0,0x8000,0,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0,0,0x0070,0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ NULL /* callback routine for special entries */
+ };
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8,8, 64,64);
+
+ /* initialize the second playfield */
+ atarigen_playfield2_tilemap = tilemap_create(get_playfield2_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8,8, 64,64);
+ tilemap_set_transparent_pen(atarigen_playfield2_tilemap, 0);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ tilemap_set_transparent_pen(atarigen_alpha_tilemap, 0);
+}
+
+
+
+/*************************************
+ *
+ * Periodic scanline updater
+ *
+ *************************************/
+
+void batman_scanline_update(running_machine *machine, int scrnum, int scanline)
+{
+ /* update the scanline parameters */
+ if (scanline <= machine->screen[scrnum].visarea.max_y && atarivc_state.rowscroll_enable)
+ {
+ UINT16 *base = &atarigen_alpha[scanline / 8 * 64 + 48];
+ int scan, i;
+
+ for (scan = 0; scan < 8; scan++, scanline++)
+ for (i = 0; i < 2; i++)
+ {
+ int data = *base++;
+ switch (data & 15)
+ {
+ case 9:
+ video_screen_update_partial(0, scanline - 1);
+ atarivc_state.mo_xscroll = (data >> 7) & 0x1ff;
+ atarimo_set_xscroll(0, atarivc_state.mo_xscroll);
+ break;
+
+ case 10:
+ video_screen_update_partial(0, scanline - 1);
+ atarivc_state.pf1_xscroll_raw = (data >> 7) & 0x1ff;
+ atarivc_update_pf_xscrolls();
+ tilemap_set_scrollx(atarigen_playfield_tilemap, 0, atarivc_state.pf0_xscroll);
+ tilemap_set_scrollx(atarigen_playfield2_tilemap, 0, atarivc_state.pf1_xscroll);
+ break;
+
+ case 11:
+ video_screen_update_partial(0, scanline - 1);
+ atarivc_state.pf0_xscroll_raw = (data >> 7) & 0x1ff;
+ atarivc_update_pf_xscrolls();
+ tilemap_set_scrollx(atarigen_playfield_tilemap, 0, atarivc_state.pf0_xscroll);
+ break;
+
+ case 13:
+ video_screen_update_partial(0, scanline - 1);
+ atarivc_state.mo_yscroll = (data >> 7) & 0x1ff;
+ atarimo_set_yscroll(0, atarivc_state.mo_yscroll);
+ break;
+
+ case 14:
+ video_screen_update_partial(0, scanline - 1);
+ atarivc_state.pf1_yscroll = (data >> 7) & 0x1ff;
+ tilemap_set_scrolly(atarigen_playfield2_tilemap, 0, atarivc_state.pf1_yscroll);
+ break;
+
+ case 15:
+ video_screen_update_partial(0, scanline - 1);
+ atarivc_state.pf0_yscroll = (data >> 7) & 0x1ff;
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, atarivc_state.pf0_yscroll);
+ break;
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( batman )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ fillbitmap(priority_bitmap, 0, cliprect);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0x00);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 1, 0x01);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 2, 0x02);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 3, 0x03);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield2_tilemap, 0, 0x80);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield2_tilemap, 1, 0x84);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield2_tilemap, 2, 0x88);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield2_tilemap, 3, 0x8c);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ UINT8 *pri = (UINT8 *)priority_bitmap->base + priority_bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* verified on real hardware:
+
+ for all MO colors, MO priority 0:
+ obscured by low fg playfield pens priority 1-3
+ obscured by high fg playfield pens priority 3 only
+ obscured by bg playfield priority 3 only
+
+ for all MO colors, MO priority 1:
+ obscured by low fg playfield pens priority 2-3
+ obscured by high fg playfield pens priority 3 only
+ obscured by bg playfield priority 3 only
+
+ for all MO colors, MO priority 2-3:
+ obscured by low fg playfield pens priority 3 only
+ obscured by high fg playfield pens priority 3 only
+ obscured by bg playfield priority 3 only
+ */
+ int mopriority = mo[x] >> ATARIMO_PRIORITY_SHIFT;
+
+ /* upper bit of MO priority signals special rendering and doesn't draw anything */
+ if (mopriority & 4)
+ continue;
+
+ /* foreground playfield case */
+ if (pri[x] & 0x80)
+ {
+ int pfpriority = (pri[x] >> 2) & 3;
+
+ /* playfield priority 3 always wins */
+ if (pfpriority == 3)
+ ;
+
+ /* priority is consistent for upper pens in playfield */
+ else if (pf[x] & 0x08)
+ pf[x] = mo[x] & ATARIMO_DATA_MASK;
+
+ /* otherwise, we need to compare */
+ else if (mopriority >= pfpriority)
+ pf[x] = mo[x] & ATARIMO_DATA_MASK;
+ }
+
+ /* background playfield case */
+ else
+ {
+ int pfpriority = pri[x] & 3;
+
+ /* playfield priority 3 always wins */
+ if (pfpriority == 3)
+ ;
+
+ /* otherwise, MOs get shown */
+ else
+ pf[x] = mo[x] & ATARIMO_DATA_MASK;
+ }
+
+ /* don't erase yet -- we need to make another pass later */
+ }
+ }
+
+ /* add the alpha on top */
+ tilemap_draw(bitmap, cliprect, atarigen_alpha_tilemap, 0, 0);
+
+ /* now go back and process the upper bit of MO priority */
+ rectlist.rect -= rectlist.numrects;
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ int mopriority = mo[x] >> ATARIMO_PRIORITY_SHIFT;
+
+ /* upper bit of MO priority might mean palette kludges */
+ if (mopriority & 4)
+ {
+ /* if bit 2 is set, start setting high palette bits */
+ if (mo[x] & 2)
+ thunderj_mark_high_palette(bitmap, pf, mo, x, y);
+ }
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/battlane.c b/src/mame/video/battlane.c
new file mode 100644
index 00000000000..9c5089a16eb
--- /dev/null
+++ b/src/mame/video/battlane.c
@@ -0,0 +1,250 @@
+/***************************************************************************
+
+ Battle Lane Vol. 5
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *battlane_spriteram;
+UINT8 *battlane_tileram;
+
+static tilemap *bg_tilemap;
+
+static int battlane_video_ctrl;
+extern int battlane_cpu_control;
+
+static mame_bitmap *screen_bitmap;
+
+/*
+ Video control register
+
+ 0x80 = low bit of blue component (taken when writing to palette)
+ 0x0e = Bitmap plane (bank?) select (0-7)
+ 0x01 = Scroll MSB
+*/
+
+WRITE8_HANDLER( battlane_palette_w )
+{
+ int r, g, b;
+ int bit0, bit1, bit2;
+
+ /* red component */
+
+ bit0 = (~data >> 0) & 0x01;
+ bit1 = (~data >> 1) & 0x01;
+ bit2 = (~data >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* green component */
+
+ bit0 = (~data >> 3) & 0x01;
+ bit1 = (~data >> 4) & 0x01;
+ bit2 = (~data >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* blue component */
+
+ bit0 = (~battlane_video_ctrl >> 7) & 0x01;
+ bit1 = (~data >> 6) & 0x01;
+ bit2 = (~data >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(Machine, offset, MAKE_RGB(r, g, b));
+}
+
+WRITE8_HANDLER( battlane_scrollx_w )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, ((battlane_video_ctrl & 0x01) << 8) + data);
+}
+
+WRITE8_HANDLER( battlane_scrolly_w )
+{
+ tilemap_set_scrolly(bg_tilemap, 0, ((battlane_cpu_control & 0x01) << 8) + data);
+}
+
+WRITE8_HANDLER( battlane_tileram_w )
+{
+ battlane_tileram[offset] = data;
+ //tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( battlane_spriteram_w )
+{
+ battlane_spriteram[offset] = data;
+}
+
+WRITE8_HANDLER( battlane_bitmap_w )
+{
+ int i, orval;
+
+ orval = (~battlane_video_ctrl >> 1) & 0x07;
+
+ if (!orval)
+ orval = 7;
+
+ for (i = 0; i < 8; i++)
+ {
+ if (data & 1 << i)
+ {
+ *BITMAP_ADDR8(screen_bitmap, offset % 0x100, (offset / 0x100) * 8 + i) |= orval;
+ }
+ else
+ {
+ *BITMAP_ADDR8(screen_bitmap, offset % 0x100, (offset / 0x100) * 8 + i) &= ~orval;
+ }
+ }
+}
+
+WRITE8_HANDLER( battlane_video_ctrl_w )
+{
+ battlane_video_ctrl = data;
+}
+
+static TILE_GET_INFO( get_tile_info_bg )
+{
+ int code = battlane_tileram[tile_index];
+ int attr = battlane_tileram[tile_index + 0x400];
+ int gfxn = (attr & 0x01) + 1;
+ int color = (attr >> 1) & 0x03;
+
+ SET_TILE_INFO(gfxn, code, color, 0);
+}
+
+static TILEMAP_MAPPER( battlane_tilemap_scan_rows_2x2 )
+{
+ /*
+ Tilemap Memory Organization
+
+ 0 15 16 31
+ +-----------------+----------------+
+ |0 15|256 |0
+ | | |
+ | screen 0 | screen 1 |
+ | | |
+ |240 255| 511|15
+ +-----------------+----------------+
+ |512 |768 |16
+ | | |
+ | screen 2 | screen 3 |
+ | | |
+ | 767| 1023|31
+ +-----------------+-----------------
+
+ */
+
+ return (row & 0xf) * 16 + (col & 0xf) + (row & 0x10) * 32 + (col & 0x10) * 16;
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+VIDEO_START( battlane )
+{
+ bg_tilemap = tilemap_create(get_tile_info_bg, battlane_tilemap_scan_rows_2x2,
+ TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+
+ screen_bitmap = auto_bitmap_alloc(32 * 8, 32 * 8, BITMAP_FORMAT_INDEXED8);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs, attr, code, color, sx, sy, flipx, flipy, dy;
+
+ for (offs = 0; offs < 0x100; offs += 4)
+ {
+ /*
+ 0x80 = Bank 2
+ 0x40 =
+ 0x20 = Bank 1
+ 0x10 = Y Double
+ 0x08 = Color
+ 0x04 = X Flip
+ 0x02 = Y Flip
+ 0x01 = Sprite Enable
+ */
+
+ attr = battlane_spriteram[offs + 1];
+ code = battlane_spriteram[offs + 3];
+
+ code += 256 * ((attr >> 6) & 0x02);
+ code += 256 * ((attr >> 5) & 0x01);
+
+ if (attr & 0x01)
+ {
+ color = (attr >> 3) & 0x01;
+
+ sx = battlane_spriteram[offs + 2];
+ sy = battlane_spriteram[offs];
+
+ flipx = attr & 0x04;
+ flipy = attr & 0x02;
+
+ if (!flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+
+ if (attr & 0x10) /* Double Y direction */
+ {
+ dy = flipy ? 16 : -16;
+
+ drawgfx(bitmap,machine->gfx[0],
+ code + 1,
+ color,
+ flipx, flipy,
+ sx, sy + dy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+ }
+ }
+}
+
+static void draw_fg_bitmap(running_machine *machine, mame_bitmap *bitmap )
+{
+ int x, y, data;
+
+ for (y = 0; y < 32 * 8; y++)
+ {
+ for (x = 0; x < 32 * 8; x++)
+ {
+ data = *BITMAP_ADDR8(screen_bitmap, y, x);
+
+ if (data)
+ {
+ if (flip_screen)
+ {
+ *BITMAP_ADDR16(bitmap, 255 - y, 255 - x) = machine->pens[data];
+ }
+ else
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[data];
+ }
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( battlane )
+{
+ tilemap_mark_all_tiles_dirty(bg_tilemap); // HACK
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ draw_fg_bitmap(machine, bitmap);
+ return 0;
+}
diff --git a/src/mame/video/battlera.c b/src/mame/video/battlera.c
new file mode 100644
index 00000000000..99d3f132d4d
--- /dev/null
+++ b/src/mame/video/battlera.c
@@ -0,0 +1,413 @@
+/*******************************************************************************
+
+ Battle Rangers - Bryan McPhail, mish@tendril.co.uk
+
+ This file only implements necessary features - not all PC-Engine video
+ features are used in this game (no DMA for one).
+
+*******************************************************************************/
+
+#include "driver.h"
+#include "cpu/h6280/h6280.h"
+
+static int HuC6270_registers[20];
+static int VDC_register,vram_ptr;
+static UINT8 *HuC6270_vram,*tile_dirty,*sprite_dirty,*vram_dirty;
+static mame_bitmap *tile_bitmap,*front_bitmap;
+
+static int current_scanline,inc_value;
+static int irq_enable,rcr_enable,sb_enable,bb_enable,bldwolf_vblank;
+
+
+
+/******************************************************************************/
+
+VIDEO_START( battlera )
+{
+ HuC6270_vram=auto_malloc(0x20000);
+ tile_dirty=auto_malloc(0x1000);
+ sprite_dirty=auto_malloc(0x400);
+ vram_dirty=auto_malloc(0x1000);
+
+ memset(HuC6270_vram,0,0x20000);
+ memset(tile_dirty,1,0x1000);
+ memset(sprite_dirty,1,0x400);
+ memset(vram_dirty,1,0x1000);
+
+ tile_bitmap=auto_bitmap_alloc(512,512,machine->screen[0].format);
+ front_bitmap=auto_bitmap_alloc(512,512,machine->screen[0].format);
+
+ vram_ptr=0;
+ inc_value=1;
+ current_scanline=0;
+ irq_enable=rcr_enable=sb_enable=bb_enable=0;
+}
+
+/******************************************************************************/
+
+WRITE8_HANDLER( battlera_palette_w )
+{
+ int pal_word;
+
+ paletteram[offset]=data;
+ if (offset%2) offset-=1;
+
+ pal_word=paletteram[offset] | (paletteram[offset+1]<<8);
+ palette_set_color_rgb(Machine, offset/2, pal3bit(pal_word >> 3), pal3bit(pal_word >> 6), pal3bit(pal_word >> 0));
+}
+
+/******************************************************************************/
+
+READ8_HANDLER( HuC6270_debug_r )
+{
+ return HuC6270_vram[offset];
+}
+
+WRITE8_HANDLER( HuC6270_debug_w )
+{
+ HuC6270_vram[offset]=data;
+}
+READ8_HANDLER( HuC6270_register_r )
+{
+ int rr;
+
+ if ((current_scanline+56)==HuC6270_registers[6]) rr=1; else rr=0;
+
+ return 0 /* CR flag */
+ | (0 << 1) /* OR flag */
+ | (rr << 2) /* RR flag */
+ | (0 << 3) /* DS flag */
+ | (0 << 4) /* DV flag */
+ | (bldwolf_vblank << 5) /* VD flag (1 when vblank else 0) */
+ | (0 << 6) /* BSY flag (1 when dma active, else 0) */
+ | (0 << 7); /* Always zero */
+}
+
+WRITE8_HANDLER( HuC6270_register_w )
+{
+ switch (offset) {
+ case 0: /* Select data region */
+ VDC_register=data;
+ break;
+ case 1: /* Unused */
+ break;
+ }
+}
+
+/******************************************************************************/
+
+#ifdef UNUSED_FUNCTION
+READ8_HANDLER( HuC6270_data_r )
+{
+ int result;
+
+ switch (offset) {
+ case 0: /* LSB */
+ return HuC6270_vram[(HuC6270_registers[1]<<1)|1];
+
+ case 1:/* MSB */
+ result=HuC6270_vram[(HuC6270_registers[1]<<1)|0];
+ HuC6270_registers[1]=(HuC6270_registers[1]+inc_value)&0xffff;
+ return result;
+ }
+
+ return 0;
+}
+#endif
+
+WRITE8_HANDLER( HuC6270_data_w )
+{
+ switch (offset) {
+ case 0: /* LSB */
+ switch (VDC_register) {
+
+ case 0: /* MAWR */
+ HuC6270_registers[0]=(HuC6270_registers[0]&0xff00) | (data);
+ return;
+
+ case 1: /* MARR */
+ HuC6270_registers[0]=(HuC6270_registers[1]&0xff00) | (data);
+ return;
+
+ case 2: /* VRAM */
+ if (HuC6270_vram[(HuC6270_registers[0]<<1)|1]!=data) {
+ HuC6270_vram[(HuC6270_registers[0]<<1)|1]=data;
+ tile_dirty[HuC6270_registers[0]>>4]=1;
+ sprite_dirty[HuC6270_registers[0]>>6]=1;
+ }
+ if (HuC6270_registers[0]<0x1000) vram_dirty[HuC6270_registers[0]]=1;
+ return;
+
+ case 3: break; /* Unused */
+ case 4: break; /* Unused */
+
+ case 5: /* CR - Control register */
+ /* Bits 0,1 unknown */
+ rcr_enable=data&0x4; /* Raster interrupt enable */
+ irq_enable=data&0x8; /* VBL interrupt enable */
+ /* Bits 4,5 unknown (EX) */
+ sb_enable=data&0x40; /* Sprites enable */
+ bb_enable=data&0x80; /* Background enable */
+ return;
+
+ case 6: /* RCR - Raster counter register */
+ HuC6270_registers[6]=(HuC6270_registers[6]&0xff00) | (data);
+ return;
+
+ case 7: /* BXR - X scroll */
+ HuC6270_registers[7]=(HuC6270_registers[7]&0xff00) | (data);
+ return;
+
+ case 8: /* BYR - Y scroll */
+ HuC6270_registers[8]=(HuC6270_registers[8]&0xff00) | (data);
+ return;
+
+ case 15: /* DMA */
+ case 16:
+ case 17:
+ case 18:
+ logerror("%04x: dma 2 %02x\n",activecpu_get_pc(),data);
+ break;
+
+ case 19: /* SATB */
+ HuC6270_registers[19]=(HuC6270_registers[19]&0xff00) | (data);
+ return;
+
+ }
+ break;
+
+ /*********************************************/
+
+ case 1: /* MSB (Autoincrement on this write) */
+ switch (VDC_register) {
+
+ case 0: /* MAWR - Memory Address Write Register */
+ HuC6270_registers[0]=(HuC6270_registers[0]&0xff) | (data<<8);
+ return;
+
+ case 1: /* MARR */
+ HuC6270_registers[1]=(HuC6270_registers[1]&0xff) | (data<<8);
+ return;
+
+ case 2: /* VWR - VRAM */
+ if (HuC6270_vram[(HuC6270_registers[0]<<1)|0]!=data) {
+ HuC6270_vram[(HuC6270_registers[0]<<1)|0]=data;
+ tile_dirty[HuC6270_registers[0]>>4]=1;
+ sprite_dirty[HuC6270_registers[0]>>6]=1;
+ if (HuC6270_registers[0]<0x1000) vram_dirty[HuC6270_registers[0]]=1;
+ }
+ HuC6270_registers[0]+=inc_value;
+ HuC6270_registers[0]=HuC6270_registers[0]&0xffff;
+ return;
+
+ case 5: /* CR */
+ /* IW - Auto-increment values */
+ switch ((data>>3)&3) {
+ case 0: inc_value=1; break;
+ case 1: inc_value=32;break;
+ case 2: inc_value=64; break;
+ case 3: inc_value=128; break;
+ }
+
+ /* DR, TE unknown */
+ return;
+
+ case 6: /* RCR - Raster counter register */
+ HuC6270_registers[6]=(HuC6270_registers[6]&0xff) | (data<<8);
+ return;
+
+ case 7: /* BXR - X scroll */
+ HuC6270_registers[7]=(HuC6270_registers[7]&0xff) | (data<<8);
+ return;
+
+ case 8: /* BYR - Y scroll */
+ HuC6270_registers[8]=(HuC6270_registers[8]&0xff) | (data<<8);
+ return;
+
+ case 15: /* DMA */
+ case 16:
+ case 17:
+ case 18:
+ logerror("%04x: dma 2 %02x\n",activecpu_get_pc(),data);
+ break;
+
+ case 19: /* SATB - Sprites */
+ HuC6270_registers[19]=(HuC6270_registers[19]&0xff) | (data<<8);
+ return;
+ }
+ break;
+ }
+ logerror("%04x: unknown write to VDC_register %02x (%02x) at %02x\n",activecpu_get_pc(),VDC_register,data,offset);
+}
+
+/******************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *clip,int pri)
+{
+ int offs,my,mx,code,code2,fx,fy,cgy=0,cgx,colour,i,yinc;
+
+ /* Draw sprites, starting at SATB, draw in _reverse_ order */
+ for (offs=(HuC6270_registers[19]<<1)+0x200-8; offs>=(HuC6270_registers[19]<<1); offs-=8)
+ {
+ if ((HuC6270_vram[offs+7]&0x80) && !pri) continue;
+ if (!(HuC6270_vram[offs+7]&0x80) && pri) continue;
+
+ code=HuC6270_vram[offs+5] + (HuC6270_vram[offs+4]<<8);
+ code=code>>1;
+
+ my=HuC6270_vram[offs+1] + (HuC6270_vram[offs+0]<<8);
+ mx=HuC6270_vram[offs+3] + (HuC6270_vram[offs+2]<<8);
+
+ mx-=32;
+ my-=57;
+
+ fx=HuC6270_vram[offs+6]&0x8;
+ fy=HuC6270_vram[offs+6]&0x80;
+ cgx=HuC6270_vram[offs+6]&1;
+ colour=HuC6270_vram[offs+7]&0xf;
+
+ switch ((HuC6270_vram[offs+6]>>4)&3) {
+ case 0: cgy=1; break;
+ case 1: cgy=2; break;
+ case 2: cgy=0; break; /* Illegal */
+ case 3: cgy=4; break;
+ }
+
+ if (cgx && cgy==2) code=code&0x3fc; /* Title screen */
+
+ if (fx && cgx) {code2=code; code++;} /* Swap tile order on X flips */
+ else code2=code+1;
+
+ yinc = 16;
+ if (fy) { my += 16*(cgy-1); yinc = -16; } /* Swap tile order on Y flips */
+
+ for (i=0; i<cgy; i++) {
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ colour,
+ fx,fy,
+ mx,my,
+ clip,TRANSPARENCY_PEN,0);
+
+ if (cgx)
+ drawgfx(bitmap,machine->gfx[1],
+ code2,
+ colour,
+ fx,fy,
+ mx+16,my,
+ clip,TRANSPARENCY_PEN,0);
+ my += yinc;
+ /* if (cgx) */ /* Different from console? */
+ code += 2;
+ code2 += 2;
+ /*else code += 1; */ /* Different from console? */
+ }
+ }
+
+}
+
+static void screenrefresh(running_machine *machine, mame_bitmap *bitmap,const rectangle *clip)
+{
+ int offs,code,scrollx,scrolly,mx,my;
+
+ /* Dynamically decode chars if dirty */
+ for (code = 0x0000;code < 0x1000;code++)
+ if (tile_dirty[code])
+ decodechar(machine->gfx[0],code,HuC6270_vram,machine->drv->gfxdecodeinfo[0].gfxlayout);
+
+ /* Dynamically decode sprites if dirty */
+ for (code = 0x0000;code < 0x400;code++)
+ if (sprite_dirty[code])
+ decodechar(machine->gfx[1],code,HuC6270_vram,machine->drv->gfxdecodeinfo[1].gfxlayout);
+
+ /* NB: If first 0x1000 byte is always tilemap, no need to decode the first batch of tiles/sprites */
+
+ mx=-1;
+ my=0;
+ for (offs = 0x0000;offs < 0x2000;offs += 2)
+ {
+ mx++;
+ if (mx==64) {mx=0; my++;}
+ code=HuC6270_vram[offs+1] + ((HuC6270_vram[offs] & 0x0f) << 8);
+
+ /* If this tile was changed OR tilemap was changed, redraw */
+ if (tile_dirty[code] || vram_dirty[offs/2]) {
+ vram_dirty[offs/2]=0;
+ drawgfx(tile_bitmap,machine->gfx[0],
+ code,
+ HuC6270_vram[offs] >> 4,
+ 0,0,
+ 8*mx,8*my,
+ 0,TRANSPARENCY_NONE,0);
+ drawgfx(front_bitmap,machine->gfx[2],
+ 0,
+ 0, /* fill the spot with pen 256 */
+ 0,0,
+ 8*mx,8*my,
+ 0,TRANSPARENCY_NONE,0);
+ drawgfx(front_bitmap,machine->gfx[0],
+ code,
+ HuC6270_vram[offs] >> 4,
+ 0,0,
+ 8*mx,8*my,
+ 0,TRANSPARENCY_PENS,0x1);
+ }
+ }
+
+ /* Nothing dirty after a screen refresh */
+ for (code = 0x0000;code < 0x1000;code++)
+ tile_dirty[code]=0;
+ for (code = 0x0000;code < 0x400;code++)
+ sprite_dirty[code]=0;
+
+ /* Render bitmap */
+ scrollx=-HuC6270_registers[7];
+ scrolly=-HuC6270_registers[8]+clip->min_y-1;
+
+ copyscrollbitmap(bitmap,tile_bitmap,1,&scrollx,1,&scrolly,clip,TRANSPARENCY_NONE,0);
+
+ /* Todo: Background enable (not used anyway) */
+
+ /* Render low priority sprites, if enabled */
+ if (sb_enable) draw_sprites(machine,bitmap,clip,0);
+
+ /* Render background over sprites */
+ copyscrollbitmap(bitmap,front_bitmap,1,&scrollx,1,&scrolly,clip,TRANSPARENCY_COLOR,256);
+
+ /* Render high priority sprites, if enabled */
+ if (sb_enable) draw_sprites(machine,bitmap,clip,1);
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( battlera )
+{
+ screenrefresh(machine,bitmap,cliprect);
+ return 0;
+}
+
+/******************************************************************************/
+
+INTERRUPT_GEN( battlera_interrupt )
+{
+ current_scanline=255-cpu_getiloops(); /* 8 lines clipped at top */
+
+ /* If raster interrupt occurs, refresh screen _up_ to this point */
+ if (rcr_enable && (current_scanline+56)==HuC6270_registers[6]) {
+ video_screen_update_partial(0, current_scanline);
+ cpunum_set_input_line(0, 0, HOLD_LINE); /* RCR interrupt */
+ }
+
+ /* Start of vblank */
+ else if (current_scanline==240) {
+ bldwolf_vblank=1;
+ video_screen_update_partial(0, 240);
+ if (irq_enable)
+ cpunum_set_input_line(0, 0, HOLD_LINE); /* VBL */
+ }
+
+ /* End of vblank */
+ if (current_scanline==254) {
+ bldwolf_vblank=0;
+ }
+}
diff --git a/src/mame/video/battlex.c b/src/mame/video/battlex.c
new file mode 100644
index 00000000000..a0b1a69a5a6
--- /dev/null
+++ b/src/mame/video/battlex.c
@@ -0,0 +1,120 @@
+#include "driver.h"
+
+static int battlex_scroll_lsb;
+static int battlex_scroll_msb;
+
+static tilemap *bg_tilemap;
+
+PALETTE_INIT( battlex )
+{
+ int i,col;
+
+ for (col = 0;col < 8;col++)
+ {
+ for (i = 0;i < 16;i++)
+ {
+ int data = i | col;
+ int g = pal1bit(data >> 0);
+ int b = pal1bit(data >> 1);
+ int r = pal1bit(data >> 2);
+
+#if 0
+ /* from Tim's shots, bit 3 seems to have no effect (see e.g. Laser Ship on title screen) */
+ if (i & 8)
+ {
+ r /= 2;
+ g /= 2;
+ b /= 2;
+ }
+#endif
+
+ palette_set_color(machine, i + 16 * col,MAKE_RGB(r,g,b));
+ }
+ }
+}
+
+WRITE8_HANDLER( battlex_palette_w )
+{
+ palette_set_color_rgb(Machine,16*8 + offset,pal1bit(data >> 2),pal1bit(data >> 0),pal1bit(data >> 1));
+}
+
+WRITE8_HANDLER( battlex_scroll_x_lsb_w )
+{
+ battlex_scroll_lsb = data;
+}
+
+WRITE8_HANDLER( battlex_scroll_x_msb_w )
+{
+ battlex_scroll_msb = data;
+}
+
+WRITE8_HANDLER( battlex_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+WRITE8_HANDLER( battlex_flipscreen_w )
+{
+ /* bit 4 is used, but for what? */
+
+ /* bit 7 is flip screen */
+
+ if (flip_screen != (data & 0x80))
+ {
+ flip_screen_set(data & 0x80);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int tile = videoram[tile_index*2] | (((videoram[tile_index*2+1] & 0x01)) << 8);
+ int color = (videoram[tile_index*2+1] & 0x0e) >> 1;
+
+ SET_TILE_INFO(0,tile,color,0);
+}
+
+VIDEO_START( battlex )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ const gfx_element *gfx = machine->gfx[1];
+ UINT8 *source = spriteram;
+ UINT8 *finish = spriteram + 0x200;
+
+ while( source<finish )
+ {
+ int sx = (source[0] & 0x7f) * 2 - (source[0] & 0x80) * 2;
+ int sy = source[3];
+ int tile = source[2] & 0x7f;
+ int color = source[1] & 0x07; /* bits 3,4,5 also used during explosions */
+ int flipy = source[1] & 0x80;
+ int flipx = source[1] & 0x40;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,gfx,tile,color,flipx,flipy,sx,sy,cliprect,TRANSPARENCY_PEN,0);
+
+ source += 4;
+ }
+
+}
+
+VIDEO_UPDATE(battlex)
+{
+ tilemap_set_scrollx(bg_tilemap, 0, battlex_scroll_lsb | (battlex_scroll_msb << 8));
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/battlnts.c b/src/mame/video/battlnts.c
new file mode 100644
index 00000000000..9d291b1b439
--- /dev/null
+++ b/src/mame/video/battlnts.c
@@ -0,0 +1,67 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+static int spritebank;
+
+static int layer_colorbase[2];
+
+/***************************************************************************
+
+ Callback for the K007342
+
+***************************************************************************/
+
+static void tile_callback(int layer, int bank, int *code, int *color, int *flags)
+{
+ *code |= ((*color & 0x0f) << 9) | ((*color & 0x40) << 2);
+ *color = layer_colorbase[layer];
+}
+
+/***************************************************************************
+
+ Callback for the K007420
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color)
+{
+ *code |= ((*color & 0xc0) << 2) | spritebank;
+ *code = (*code << 2) | ((*color & 0x30) >> 4);
+ *color = 0;
+}
+
+WRITE8_HANDLER( battlnts_spritebank_w )
+{
+ spritebank = 1024 * (data & 1);
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( battlnts )
+{
+ layer_colorbase[0] = 0;
+ layer_colorbase[1] = 0;
+
+ K007342_vh_start(0,tile_callback);
+ K007420_vh_start(machine,1,sprite_callback);
+}
+
+/***************************************************************************
+
+ Screen Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( battlnts ){
+
+ K007342_tilemap_update();
+
+ K007342_tilemap_draw( bitmap, cliprect, 0, TILEMAP_DRAW_OPAQUE ,0);
+ K007420_sprites_draw( bitmap, cliprect );
+ K007342_tilemap_draw( bitmap, cliprect, 0, 1 | TILEMAP_DRAW_OPAQUE ,0);
+ return 0;
+}
diff --git a/src/mame/video/bbusters.c b/src/mame/video/bbusters.c
new file mode 100644
index 00000000000..9c0e157c3f3
--- /dev/null
+++ b/src/mame/video/bbusters.c
@@ -0,0 +1,299 @@
+/***************************************************************************
+
+ Emulation by Bryan McPhail, mish@tendril.co.uk
+
+ Like NeoGeo sprite scale Y line selection is from an external rom.
+
+ For 16 high sprites scale data starts at 0x3800 (9 scale levels)
+ For 32 high sprites scale data starts at 0x7000 (17 scale levels)
+ For 64 high sprites scale data starts at 0xa000 (33 scale levels)
+ For 128 pixel high sprites scale data starts 0xc000 (65 scale levels)
+
+ 0xe000 and up - possibly X scale data? unconfirmed
+
+ Sprites are also double buffered, and this seems to be performed
+ by having two complete sprite chips that are toggled per frame, rather
+ than just ram. Beast Busters has 4 sprite chips as it has two sprite
+ banks.
+
+ Todo: Sprite priority looks to be wrong on level 2 (some sprites should
+ be behind the playfield).
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *fix_tilemap,*pf1_tilemap,*pf2_tilemap;
+static const UINT8 *scale_table_ptr;
+static UINT8 scale_line_count;
+
+UINT16 *bbuster_pf1_data,*bbuster_pf2_data,*bbuster_pf1_scroll_data,*bbuster_pf2_scroll_data;
+
+/******************************************************************************/
+
+static TILE_GET_INFO( get_bbuster_tile_info )
+{
+ UINT16 tile=videoram16[tile_index];
+ SET_TILE_INFO(0,tile&0xfff,tile>>12,0);
+}
+
+static TILE_GET_INFO( get_pf1_tile_info )
+{
+ UINT16 tile=bbuster_pf1_data[tile_index];
+ SET_TILE_INFO(3,tile&0xfff,tile>>12,0);
+}
+
+static TILE_GET_INFO( get_pf2_tile_info )
+{
+ UINT16 tile=bbuster_pf2_data[tile_index];
+ SET_TILE_INFO(4,tile&0xfff,tile>>12,0);
+}
+
+WRITE16_HANDLER( bbuster_video_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty(fix_tilemap,offset);
+}
+
+WRITE16_HANDLER( bbuster_pf1_w )
+{
+ COMBINE_DATA(&bbuster_pf1_data[offset]);
+ tilemap_mark_tile_dirty(pf1_tilemap,offset);
+}
+
+WRITE16_HANDLER( bbuster_pf2_w )
+{
+ COMBINE_DATA(&bbuster_pf2_data[offset]);
+ tilemap_mark_tile_dirty(pf2_tilemap,offset);
+}
+
+/******************************************************************************/
+
+VIDEO_START( bbuster )
+{
+ fix_tilemap = tilemap_create(get_bbuster_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ pf1_tilemap = tilemap_create(get_pf1_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,128,32);
+ pf2_tilemap = tilemap_create(get_pf2_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,128,32);
+
+ tilemap_set_transparent_pen(pf1_tilemap, 15);
+ tilemap_set_transparent_pen(fix_tilemap, 15);
+}
+
+VIDEO_START( mechatt )
+{
+ fix_tilemap = tilemap_create(get_bbuster_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ pf1_tilemap = tilemap_create(get_pf1_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,256,32);
+ pf2_tilemap = tilemap_create(get_pf2_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,256,32);
+
+ tilemap_set_transparent_pen(pf1_tilemap, 15);
+ tilemap_set_transparent_pen(fix_tilemap, 15);
+}
+
+/******************************************************************************/
+
+#define ADJUST_4x4 \
+ if ((dx&0x10) && (dy&0x10)) code+=3; \
+ else if (dy&0x10) code+=2; \
+ else if (dx&0x10) code+=1
+
+#define ADJUST_8x8 \
+ if ((dx&0x20) && (dy&0x20)) code+=12; \
+ else if (dy&0x20) code+=8; \
+ else if (dx&0x20) code+=4
+
+#define ADJUST_16x16 \
+ if ((dx&0x40) && (dy&0x40)) code+=48; \
+ else if (dy&0x40) code+=32; \
+ else if (dx&0x40) code+=16
+
+INLINE const UINT8 *get_source_ptr(running_machine *machine, UINT32 sprite, int dx, int dy, int bank, int block)
+{
+ const gfx_element *gfx=machine->gfx[bank];
+ int source_base,code=0;
+
+ /* Get a tile index from the x,y position in the block */
+ switch (block)
+ {
+ case 0: /* 16 x 16 sprite */
+ break;
+
+ case 1: /* 32 x 32 block
+ 0 1
+ 2 3
+ */
+ ADJUST_4x4;
+ break;
+
+ case 2: /* 64 by 64 block
+ 0 1 4 5
+ 2 3 6 7
+
+ 8 9 12 13
+ 10 11 14 15
+ */
+ ADJUST_4x4;
+ ADJUST_8x8;
+ break;
+
+ case 3: /* 128 by 128 block */
+ ADJUST_4x4;
+ ADJUST_8x8;
+ ADJUST_16x16;
+ break;
+ }
+
+ source_base=((sprite+code) % gfx->total_elements) * 16;
+ return gfx->gfxdata + ((source_base+(dy%16)) * gfx->line_modulo);
+}
+
+static void bbusters_draw_block(running_machine *machine, mame_bitmap *dest,int x,int y,int size,int flipx,int flipy,UINT32 sprite,int color,int bank,int block)
+{
+ const pen_t *pal = &machine->remapped_colortable[machine->gfx[bank]->color_base + machine->gfx[bank]->color_granularity * (color % machine->gfx[bank]->total_colors)];
+ UINT32 xinc=(scale_line_count * 0x10000 ) / size;
+ UINT8 pixel;
+ int x_index;
+ int dy=y;
+ int sx,ex=scale_line_count;
+
+ while (scale_line_count) {
+
+ if (dy>=16 && dy<240) {
+ UINT16 *destline = BITMAP_ADDR16(dest, dy, 0);
+ UINT8 srcline=*scale_table_ptr;
+ const UINT8 *srcptr=0;
+
+ if (!flipy)
+ srcline=size-srcline-1;
+
+ if (flipx)
+ x_index=(ex-1)*0x10000;
+ else
+ x_index=0;
+
+ for (sx=0; sx<size; sx++) {
+ if ((sx%16)==0)
+ srcptr=get_source_ptr(machine,sprite,sx,srcline,bank,block);
+
+ pixel=*srcptr++;
+ if (x+(x_index>>16)>=0 && x+(x_index>>16)<256 && pixel!=15)
+ destline[x+(x_index>>16)]=pal[pixel];
+
+ if (flipx)
+ x_index-=xinc;
+ else
+ x_index+=xinc;
+ }
+ }
+
+ dy++;
+ scale_table_ptr--;
+ scale_line_count--;
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const UINT16 *source, int bank, int colval, int colmask)
+{
+ const UINT8 *scale_table=memory_region(REGION_USER1);
+ int offs;
+
+ for (offs = 0;offs <0x800 ;offs += 4) {
+ int x,y,sprite,colour,fx,fy,scale;
+ int block;
+
+ sprite=source[offs+1];
+ colour=source[offs+0];
+
+ if (colour==0xf7 && (sprite==0x3fff || sprite==0xffff))
+ continue;
+
+ y=source[offs+3];
+ if (y>254) continue; /* Speedup */
+ x=source[offs+2];
+ if (x&0x200) x=-(0x100-(x&0xff));
+ if (x>256) continue; /* Speedup */
+
+ /*
+ Source[0]:
+ 0xf000: Colour
+ 0x0800: FX
+ 0x0400: FY?
+ 0x0300: Block control
+ 0x0080: ?
+ 0x007f: scale
+
+ Scale varies according to block size.
+ Block type 0: 0x70 = no scale, 0x7f == half size - 16 pixel sprite
+ Block type 1: 0x60 = no scale, 0x6f == half size - 32 pixel sprite
+ Block type 2: 0x40 = no scale, 0x5f == half size - 64 pixel sprite
+ Block type 3: 0x00 = no scale, 0x3f == half size - 128 pixel sprite
+
+ */
+ colour=colour>>12;
+ block=(source[offs+0]>>8)&0x3;
+ fy=source[offs+0]&0x400;
+ fx=source[offs+0]&0x800;
+ sprite=sprite&0x3fff;
+
+ if ((colour&colmask)!=colval)
+ continue;
+
+ switch ((source[offs+0]>>8)&0x3) {
+ case 0:
+ scale=source[offs+0]&0x7;
+ scale_table_ptr=scale_table+0x387f+(0x80*scale);
+ scale_line_count=0x10-scale;
+ bbusters_draw_block(machine,bitmap,x,y,16,fx,fy,sprite,colour,bank,block);
+ break;
+ case 1: /* 2 x 2 */
+ scale=source[offs+0]&0xf;
+ scale_table_ptr=scale_table+0x707f+(0x80*scale);
+ scale_line_count=0x20-scale;
+ bbusters_draw_block(machine,bitmap,x,y,32,fx,fy,sprite,colour,bank,block);
+ break;
+ case 2: /* 64 by 64 block (2 x 2) x 2 */
+ scale=source[offs+0]&0x1f;
+ scale_table_ptr=scale_table+0xa07f+(0x80*scale);
+ scale_line_count=0x40-scale;
+ bbusters_draw_block(machine,bitmap,x,y,64,fx,fy,sprite,colour,bank,block);
+ break;
+ case 3: /* 2 x 2 x 2 x 2 */
+ scale=source[offs+0]&0x3f;
+ scale_table_ptr=scale_table+0xc07f+(0x80*scale);
+ scale_line_count=0x80-scale;
+ bbusters_draw_block(machine,bitmap,x,y,128,fx,fy,sprite,colour,bank,block);
+ break;
+ }
+ }
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( bbuster )
+{
+ tilemap_set_scrollx( pf1_tilemap,0, bbuster_pf1_scroll_data[0] );
+ tilemap_set_scrolly( pf1_tilemap,0, bbuster_pf1_scroll_data[1] );
+ tilemap_set_scrollx( pf2_tilemap,0, bbuster_pf2_scroll_data[0] );
+ tilemap_set_scrolly( pf2_tilemap,0, bbuster_pf2_scroll_data[1] );
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+// draw_sprites(machine,bitmap,buffered_spriteram16_2,2,0x8,0x8);
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ draw_sprites(machine,bitmap,buffered_spriteram16_2,2,0,0);
+ draw_sprites(machine,bitmap,buffered_spriteram16,1,0,0);
+ tilemap_draw(bitmap,cliprect,fix_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( mechatt )
+{
+ tilemap_set_scrollx( pf1_tilemap,0, bbuster_pf1_scroll_data[0] );
+ tilemap_set_scrolly( pf1_tilemap,0, bbuster_pf1_scroll_data[1] );
+ tilemap_set_scrollx( pf2_tilemap,0, bbuster_pf2_scroll_data[0] );
+ tilemap_set_scrolly( pf2_tilemap,0, bbuster_pf2_scroll_data[1] );
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ draw_sprites(machine,bitmap,buffered_spriteram16,1,0,0);
+ tilemap_draw(bitmap,cliprect,fix_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/beathead.c b/src/mame/video/beathead.c
new file mode 100644
index 00000000000..1fe943e179c
--- /dev/null
+++ b/src/mame/video/beathead.c
@@ -0,0 +1,232 @@
+/***************************************************************************
+
+ Atari "Stella on Steroids" hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "beathead.h"
+
+
+
+/*************************************
+ *
+ * Globals we own
+ *
+ *************************************/
+
+UINT32 * beathead_vram_bulk_latch;
+UINT32 * beathead_palette_select;
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static offs_t scanline_offset[240];
+static UINT8 scanline_palette[240];
+
+static int current_scanline;
+static UINT32 finescroll;
+static offs_t vram_latch_offset;
+
+static offs_t hsyncram_offset;
+static offs_t hsyncram_start;
+static UINT8 * hsyncram;
+
+
+
+/*************************************
+ *
+ * Video start/stop
+ *
+ *************************************/
+
+VIDEO_START( beathead )
+{
+ hsyncram = auto_malloc(0x800);
+}
+
+
+
+/*************************************
+ *
+ * VRAM handling
+ *
+ *************************************/
+
+WRITE32_HANDLER( beathead_vram_transparent_w )
+{
+ /* writes to this area appear to handle transparency */
+ if (!(data & 0x000000ff)) mem_mask |= 0x000000ff;
+ if (!(data & 0x0000ff00)) mem_mask |= 0x0000ff00;
+ if (!(data & 0x00ff0000)) mem_mask |= 0x00ff0000;
+ if (!(data & 0xff000000)) mem_mask |= 0xff000000;
+ COMBINE_DATA(&videoram32[offset]);
+}
+
+
+WRITE32_HANDLER( beathead_vram_bulk_w )
+{
+ /* it appears that writes to this area pass in a mask for 4 words in VRAM */
+ /* allowing them to be filled from a preset latch */
+ offset &= ~3;
+ data = data & ~mem_mask & 0x0f0f0f0f;
+
+ /* for now, just handle the bulk fill case; the others we'll catch later */
+ if (data == 0x0f0f0f0f)
+ videoram32[offset+0] =
+ videoram32[offset+1] =
+ videoram32[offset+2] =
+ videoram32[offset+3] = *beathead_vram_bulk_latch;
+ else
+ logerror("Detected bulk VRAM write with mask %08x\n", data);
+}
+
+
+WRITE32_HANDLER( beathead_vram_latch_w )
+{
+ /* latch the address */
+ vram_latch_offset = (4 * offset) & 0x7ffff;
+}
+
+
+WRITE32_HANDLER( beathead_vram_copy_w )
+{
+ /* copy from VRAM to VRAM, for 1024 bytes */
+ offs_t dest_offset = (4 * offset) & 0x7ffff;
+ memcpy(&videoram32[dest_offset / 4], &videoram32[vram_latch_offset / 4], 0x400);
+}
+
+
+
+/*************************************
+ *
+ * Scroll offset handling
+ *
+ *************************************/
+
+WRITE32_HANDLER( beathead_finescroll_w )
+{
+ UINT32 oldword = finescroll;
+ UINT32 newword = COMBINE_DATA(&finescroll);
+
+ /* if VBLANK is going off on a non-zero scanline, suspend time */
+ if ((oldword & 8) && !(newword & 8) && current_scanline != 0)
+ {
+ logerror("Suspending time! (scanline = %d)\n", current_scanline);
+ cpunum_set_input_line(0, INPUT_LINE_HALT, ASSERT_LINE);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Palette handling
+ *
+ *************************************/
+
+WRITE32_HANDLER( beathead_palette_w )
+{
+ int newword = COMBINE_DATA(&paletteram32[offset]);
+ int r = ((newword >> 9) & 0x3e) | ((newword >> 15) & 0x01);
+ int g = ((newword >> 4) & 0x3e) | ((newword >> 15) & 0x01);
+ int b = ((newword << 1) & 0x3e) | ((newword >> 15) & 0x01);
+ palette_set_color_rgb(Machine, offset, pal6bit(r), pal6bit(g), pal6bit(b));
+}
+
+
+
+/*************************************
+ *
+ * HSYNC RAM handling
+ *
+ *************************************/
+
+READ32_HANDLER( beathead_hsync_ram_r )
+{
+ /* offset 0 is probably write-only */
+ if (offset == 0)
+ logerror("%08X:Unexpected HSYNC RAM read at offset 0\n", activecpu_get_previouspc());
+
+ /* offset 1 reads the data */
+ else
+ return hsyncram[hsyncram_offset];
+
+ return 0;
+}
+
+WRITE32_HANDLER( beathead_hsync_ram_w )
+{
+ /* offset 0 selects the address, and can specify the start address */
+ if (offset == 0)
+ {
+ COMBINE_DATA(&hsyncram_offset);
+ if (hsyncram_offset & 0x800)
+ hsyncram_start = hsyncram_offset & 0x7ff;
+ }
+
+ /* offset 1 writes the data */
+ else
+ COMBINE_DATA(&hsyncram[hsyncram_offset]);
+}
+
+
+
+/*************************************
+ *
+ * Scanline updater
+ *
+ *************************************/
+
+void beathead_scanline_update(int scanline)
+{
+ /* remember the current scanline */
+ current_scanline = scanline;
+
+ /* grab the latch for the previous scanline */
+ scanline--;
+ if (scanline < 0 || scanline >= 240)
+ return;
+
+ /* cache the offset and palette for this scanline */
+ scanline_offset[scanline] = (finescroll & 8) ? ~0 : vram_latch_offset + (finescroll & 3);
+ scanline_palette[scanline] = *beathead_palette_select & 0x7f;
+}
+
+
+
+/*************************************
+ *
+ * Main screen refresher
+ *
+ *************************************/
+
+VIDEO_UPDATE( beathead )
+{
+ int x, y;
+
+ /* generate the final screen */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ offs_t src = scanline_offset[y] + cliprect->min_x;
+ UINT8 scanline[336];
+
+ /* unswizzle the scanline first */
+ if (scanline_offset[y] != ~0)
+ {
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ scanline[x] = ((UINT8 *)videoram32)[BYTE4_XOR_LE(src++)];
+ }
+ else
+ memset(scanline, 0, sizeof(scanline));
+
+ /* then draw it */
+ draw_scanline8(bitmap, cliprect->min_x, y, cliprect->max_x - cliprect->min_x + 1, &scanline[cliprect->min_x], &machine->pens[scanline_palette[y] * 256], -1);
+ }
+ return 0;
+}
diff --git a/src/mame/video/beezer.c b/src/mame/video/beezer.c
new file mode 100644
index 00000000000..2b05958c830
--- /dev/null
+++ b/src/mame/video/beezer.c
@@ -0,0 +1,70 @@
+#include "driver.h"
+#include "cpu/m6809/m6809.h"
+#include "machine/6522via.h"
+
+static int scanline=0;
+
+INTERRUPT_GEN( beezer_interrupt )
+{
+ scanline = (scanline + 1) % 0x80;
+ via_0_ca2_w (0, scanline & 0x10);
+ if ((scanline & 0x78) == 0x78)
+ cpunum_set_input_line(0, M6809_FIRQ_LINE, ASSERT_LINE);
+ else
+ cpunum_set_input_line(0, M6809_FIRQ_LINE, CLEAR_LINE);
+}
+
+VIDEO_UPDATE( beezer )
+{
+ int x,y;
+
+ for (y = machine->screen[0].visarea.min_y; y <= machine->screen[0].visarea.max_y; y+=2)
+ {
+ for (x = machine->screen[0].visarea.min_x; x <= machine->screen[0].visarea.max_x; x++)
+ {
+ *BITMAP_ADDR16(bitmap, y+1, x) = machine->pens[videoram[0x80*y+x] & 0x0f];
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[(videoram[0x80*y+x] >> 4)& 0x0f];
+ }
+ }
+
+ return 0;
+}
+
+WRITE8_HANDLER( beezer_map_w )
+{
+ /*
+ bit 7 -- 330 ohm resistor -- BLUE
+ -- 560 ohm resistor -- BLUE
+ -- 330 ohm resistor -- GREEN
+ -- 560 ohm resistor -- GREEN
+ -- 1.2 kohm resistor -- GREEN
+ -- 330 ohm resistor -- RED
+ -- 560 ohm resistor -- RED
+ bit 0 -- 1.2 kohm resistor -- RED
+ */
+
+ int r, g, b, bit0, bit1, bit2;
+
+ /* red component */
+ bit0 = (data >> 0) & 0x01;
+ bit1 = (data >> 1) & 0x01;
+ bit2 = (data >> 2) & 0x01;
+ r = 0x26 * bit0 + 0x50 * bit1 + 0x89 * bit2;
+ /* green component */
+ bit0 = (data >> 3) & 0x01;
+ bit1 = (data >> 4) & 0x01;
+ bit2 = (data >> 5) & 0x01;
+ g = 0x26 * bit0 + 0x50 * bit1 + 0x89 * bit2;
+ /* blue component */
+ bit0 = (data >> 6) & 0x01;
+ bit1 = (data >> 7) & 0x01;
+ b = 0x5f * bit0 + 0xa0 * bit1;
+
+ palette_set_color(Machine, offset, MAKE_RGB(r, g, b));
+}
+
+READ8_HANDLER( beezer_line_r )
+{
+ return (scanline & 0xfe) << 1;
+}
+
diff --git a/src/mame/video/bfm_adr2.c b/src/mame/video/bfm_adr2.c
new file mode 100644
index 00000000000..d6892c4ad39
--- /dev/null
+++ b/src/mame/video/bfm_adr2.c
@@ -0,0 +1,510 @@
+/***************************************************************************
+
+ Bellfruit Adder2 video board driver, (under heavy construction !!!)
+
+ 30-12-2006: State save support added (J. Wallace)
+ 16-08-2005: Decoupled from AGEMAME by El Condor
+ 19-08-2005: Re-Animator
+
+
+CPU memorymap:
+
+ hex |r/w| D D D D D D D D |
+ location | | 7 6 5 4 3 2 1 0 | function
+-----------+---+-----------------+-----------------------------------------
+0000 | W | ? ? ? ? ? ? D D | Screen Page latch
+
+ bit0 --> 0 = display screen0
+ 1 = display screen1
+
+ bit1 --> 0 = CPU can access screen0
+ 1 = CPU can access screen1
+
+-----------+---+-----------------+-----------------------------------------
+0000-7FFF | R | D D D D D D D D | Paged ROM (4 pages)
+-----------+---+-----------------+-----------------------------------------
+8000-917F |R/W| D D D D D D D D | Paged Screen RAM (2 pages)
+ | screen size 128 x 35 bytes
+-----------+---+-----------------+-----------------------------------------
+9180-9FFF |R/W| D D D D D D D D | RAM (used for program + stack)
+-----------+---+-----------------+-----------------------------------------
+A000-BFFF |R/W| D D D D D D D D | ?window into character RAM/ROM?
+-----------+---+-----------------+-----------------------------------------
+C000-DFFF |?/W| D D D D D D D D | I/O registers
+C000 | W | ? ? ? ? ? ? D D | program ROM page select
+ controls what portion of the eprom is
+ mapped at 0000 - 7FFFF
+
+ ______________________________________
+ |bit1 | bit0 | Address in eprom |
+ |-----+------+-------------------------+
+ |0 | 0 | 00000 - 07FFF |
+ |-----+------+-------------------------+
+ |0 | 1 | 08000 - 0FFFF (not used)|
+ |-----+------+-------------------------+
+ |1 | 0 | 10000 - 17FFF (not used)|
+ |-----+------+-------------------------+
+ |1 | 1 | 18000 - 1FFFF |
+
+-----------+---+-----------------+-----------------------------------------
+C001 | W | ? ? ? ? ? ? ? D | Palette enable (seems to turn off red)
+ | | | 0 = palette disabled (red signal always 0)
+ | | | 1 = palette enabled
+-----------+---+-----------------+-----------------------------------------
+C002 | W | ? ? ? ? D D D D | Character page register (not used)
+-----------+---+-----------------+-----------------------------------------
+C100 |R/W| ? ? ? ? ? ? ? ? | Raster IRQ ? (not used in game software)
+-----------+---+-----------------+-----------------------------------------
+C101 |R/W| ? ? ? ? ? ? ? D | Vertical Blanking IRQ enable
+ | | | bit0 0 = disabled
+ | | | 1 = enabled, generate IRQ
+-----------+---+-----------------+-----------------------------------------
+C102 |R/W| ? ? ? ? ? ? ? D | Pre Vertical Blanking IRQ enable
+ | | | bit0 0 = disabled
+ | | | 1 = enabled,
+ | | | generate IRQ 100 cycles
+ | | | before VBL
+-----------+---+-----------------+-----------------------------------------
+C103 | R | ? ? ? D D D D D | IRQ status
+ | | |
+ | | | b0 = Raster IRQ status
+ | | | b1 = VBL start
+ | | | b2 = VBL end
+ | | | b3 = UART IRQ
+ | | | b4 = ???
+ | | |
+C103 | W | D D D D D D D D | Raster IRQ line number
+-----------+---+-----------------+-----------------------------------------
+C200 |R/W| D D D D D D D D | UART control reg. (MC6850 compatible)
+-----------+---+-----------------+-----------------------------------------
+C201 |R/W| D D D D D D D D | UART data reg. (MC6850 compatible)
+-----------+---+-----------------+-----------------------------------------
+C202 | W | ? ? ? ? ? ? ? ? | ??
+-----------+---+-----------------+-----------------------------------------
+C300-C301 |R/W| D D D D D D D D | ?external MC6850??
+-----------+---+-----------------+-----------------------------------------
+C302 |R/W| D D D D D D D D | board unlock? something something?
+-----------+---+-----------------+-----------------------------------------
+E000-FFFF | R | D D D D D D D D | 8K ROM
+-----------+---+-----------------+-----------------------------------------
+
+***************************************************************************/
+
+#include "driver.h"
+#include "cpu/m6809/m6809.h"
+#include "machine/bfm_bd1.h" // vfd
+#include "video/bfm_adr2.h"
+#include "rendlay.h"
+
+#ifdef MAME_DEBUG
+#define LOG_CTRL(x) logerror x // show UART information
+#else
+#define LOG_CTRL(x)
+#endif
+
+// local vars /////////////////////////////////////////////////////////////
+
+#define SL_DISPLAY 0x02 // displayed Adder screen, 1=screen1 0=screen0
+#define SL_ACCESS 0x01 // accessable Adder screen, 1=screen1 0=screen0
+
+static int adder2_screen_page_reg; // access/display select
+static int adder2_c101;
+static int adder2_rx;
+static int adder_vbl_triggered; // flag <>0, VBL IRQ triggered
+int adder2_acia_triggered; // flag <>0, ACIA receive IRQ
+
+static UINT8 adder_ram[0xE80]; // normal RAM
+static UINT8 adder_screen_ram[2][0x1180]; // paged display RAM
+
+static tilemap *tilemap0; // tilemap screen0
+static tilemap *tilemap1; // timemap screen1
+
+UINT8 adder2_data_from_sc2;
+UINT8 adder2_data_to_sc2;
+
+UINT8 adder2_data;
+UINT8 adder2_sc2data;
+
+///////////////////////////////////////////////////////////////////////////
+
+static TILE_GET_INFO( get_tile0_info )
+{
+ short data;
+ int code, color, flags,x,y;
+
+ y = tile_index / 50;
+ x = tile_index - (y*50);
+
+ tile_index = y * 128 + (x * 2);
+
+ data = adder_screen_ram[0][tile_index ]<<8;
+ data |= adder_screen_ram[0][tile_index + 1];
+
+ code = data & 0x1FFF;
+ color = 0;
+ flags = ((data & 0x4000)?TILE_FLIPY:0) |
+ ((data & 0x2000)?TILE_FLIPX:0);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static TILE_GET_INFO( get_tile1_info )
+{
+ short data;
+ int code, color, flags,x,y;
+
+ y = tile_index / 50;
+ x = tile_index - (y*50);
+
+ tile_index = y * 128 + (x * 2);
+
+ data = adder_screen_ram[1][tile_index ]<<8;
+ data |= adder_screen_ram[1][tile_index + 1];
+
+ code = data & 0x1FFF;
+ color = 0;
+ flags = ((data & 0x4000)?TILE_FLIPY:0) |
+ ((data & 0x2000)?TILE_FLIPX:0);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+// video initialisation ///////////////////////////////////////////////////
+
+VIDEO_RESET( adder2 )
+{
+ adder2_screen_page_reg = 0;
+ adder2_c101 = 0;
+ adder2_rx = 0;
+ adder_vbl_triggered = 0;
+ adder2_acia_triggered = 0;
+ adder2_data_from_sc2 = 0;
+ adder2_data_to_sc2 = 0;
+
+ {
+ UINT8 *rom = memory_region(REGION_CPU2);
+
+ memory_configure_bank(2, 0, 4, &rom[0x00000], 0x08000);
+
+ memory_set_bank(2,0&0x03);
+ }
+}
+
+VIDEO_START( adder2 )
+{
+ state_save_register_global(adder2_screen_page_reg);
+ state_save_register_global(adder2_c101);
+ state_save_register_global(adder2_rx);
+ state_save_register_global(adder_vbl_triggered);
+ state_save_register_global(adder2_acia_triggered);
+
+ state_save_register_global(adder2_data_from_sc2);
+ state_save_register_global(adder2_data_to_sc2);
+
+ state_save_register_item_array("Adder", 0, adder_ram);
+ state_save_register_item_2d_array("Adder", 0, adder_screen_ram);
+
+ tilemap0 = tilemap_create(get_tile0_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 50, 35);
+
+ tilemap1 = tilemap_create(get_tile1_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 50, 35);
+}
+
+// video update ///////////////////////////////////////////////////////////
+static rectangle visible1 = { 0, 400-1, 0, 280-1 }; //minx,maxx, miny,maxy
+
+VIDEO_UPDATE( adder2 )
+{
+ if (adder2_screen_page_reg & SL_DISPLAY) tilemap_draw(bitmap, &visible1, tilemap1, 0, 0);
+ else tilemap_draw(bitmap, &visible1, tilemap0, 0, 0);
+
+ return 0;
+}
+
+// adder2 palette initialisation //////////////////////////////////////////
+
+PALETTE_INIT( adder2 )
+{
+ palette_set_color(machine, 0,MAKE_RGB(0x00,0x00,0x00));
+ palette_set_color(machine, 1,MAKE_RGB(0x00,0x00,0xFF));
+ palette_set_color(machine, 2,MAKE_RGB(0x00,0xFF,0x00));
+ palette_set_color(machine, 3,MAKE_RGB(0x00,0xFF,0xFF));
+ palette_set_color(machine, 4,MAKE_RGB(0xFF,0x00,0x00));
+ palette_set_color(machine, 5,MAKE_RGB(0xFF,0x00,0xFF));
+ palette_set_color(machine, 6,MAKE_RGB(0xFF,0xFF,0x00));
+ palette_set_color(machine, 7,MAKE_RGB(0xFF,0xFF,0xFF));
+ palette_set_color(machine, 8,MAKE_RGB(0x80,0x80,0x80));
+ palette_set_color(machine, 9,MAKE_RGB(0x00,0x00,0x80));
+ palette_set_color(machine,10,MAKE_RGB(0x00,0x80,0x00));
+ palette_set_color(machine,11,MAKE_RGB(0x00,0x80,0x80));
+ palette_set_color(machine,12,MAKE_RGB(0x80,0x00,0x00));
+ palette_set_color(machine,13,MAKE_RGB(0x80,0x00,0x80));
+ palette_set_color(machine,14,MAKE_RGB(0x80,0x80,0x00));
+ palette_set_color(machine,15,MAKE_RGB(0x80,0x80,0x80));
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+MACHINE_RESET( adder2 )
+{
+ // setup the standard bellfruit BD1 display /////////////////////////////
+
+ BFM_BD1_init(0);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+INTERRUPT_GEN( adder2_vbl )
+{
+ if ( adder2_c101 & 0x01 )
+ {
+ adder_vbl_triggered = 1;
+ cpunum_set_input_line(1, M6809_IRQ_LINE, HOLD_LINE );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static READ8_HANDLER( screen_ram_r )
+{
+ return adder2_screen_page_reg & SL_ACCESS ? adder_screen_ram[1][offset]:adder_screen_ram[0][offset];
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static WRITE8_HANDLER( screen_ram_w )
+{
+ int dirty_off = (offset>>7)*50 + ((offset & 0x7F)>>1);
+
+ if ( offset > 102 && offset < 102+1+16 )
+ { // format xxxrrggb ////////////////////////////////////////////////////
+ int pal;
+ UINT8 r,g,b;
+
+ pal = offset-102-1;
+
+ r = ((data & 0x18)>>3) * 85; // 00011000b = 0x18
+ g = ((data & 0x06)>>1) * 85; // 00000110b = 0x06
+ b = ((data & 0x01) ) * 255;
+ palette_set_color(Machine, pal, MAKE_RGB(r,g,b));
+ }
+
+ if ( adder2_screen_page_reg & SL_ACCESS )
+ {
+ adder_screen_ram[1][offset] = data;
+ tilemap_mark_tile_dirty(tilemap1, dirty_off);
+ }
+
+ else
+ {
+ adder_screen_ram[0][offset] = data;
+ tilemap_mark_tile_dirty(tilemap0, dirty_off);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static READ8_HANDLER( normal_ram_r )
+{
+ return adder_ram[offset];
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static WRITE8_HANDLER( normal_ram_w )
+{
+ adder_ram[offset] = data;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static WRITE8_HANDLER( adder2_rom_page_w )
+{
+ memory_set_bank(2,data&0x03);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static WRITE8_HANDLER( adder2_c001_w )
+{
+ logerror("c101 = %02X\n",data);
+
+ //adder2_screen_page_reg = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static WRITE8_HANDLER( adder2_screen_page_w )
+{
+ adder2_screen_page_reg = data;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static READ8_HANDLER( adder2_vbl_ctrl_r )
+{
+ adder_vbl_triggered = 0; // clear VBL start IRQ
+
+ return adder2_c101;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static WRITE8_HANDLER( adder2_vbl_ctrl_w )
+{
+ adder2_c101 = data;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static READ8_HANDLER( adder2_uart_ctrl_r )
+{
+ int status = 0;
+
+ if ( adder2_data_from_sc2 ) status |= 0x01; // receive buffer full
+ if ( !adder2_data_to_sc2 ) status |= 0x02; // transmit buffer empty
+
+ return status;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static WRITE8_HANDLER( adder2_uart_ctrl_w )
+{
+ adder2_data_from_sc2 = 0; // data available for adder from sc2
+ adder2_sc2data = 0; // data
+ adder2_data_to_sc2 = 0; // data available for sc2 from adder
+ adder2_data = 0; // data
+
+ LOG_CTRL(("adder2 uart ctrl:%02X\n", data));
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static READ8_HANDLER( adder2_uart_rx_r )
+{
+ int data = adder2_sc2data;
+ adder2_data_from_sc2 = 0; // clr flag, data from scorpion2 board available
+
+ LOG_CTRL(("rsc2:%02X (%c)\n",data, data ));
+
+ return data;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static WRITE8_HANDLER( adder2_uart_tx_w )
+{
+ adder2_data_to_sc2 = 1; // set flag, data from adder available
+ adder2_data = data; // store data
+
+ LOG_CTRL(("ssc2 %02X(%c)\n",data, data ));
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static READ8_HANDLER( adder2_irq_r )
+{
+ int status = 0;
+
+ if ( adder_vbl_triggered ) status |= 0x02;
+ if ( adder2_acia_triggered ) status |= 0x08;
+
+ return status;
+}
+
+////////////////////////////////////////////////////////////////////
+// //
+// decode character data to a format which can be decoded by MAME //
+// //
+////////////////////////////////////////////////////////////////////
+
+void adder2_decode_char_roms(void)
+{
+ UINT8 *p;
+
+ p = memory_region(REGION_GFX1);
+
+ if ( p )
+ {
+ UINT8 *s;
+
+ s = malloc_or_die( 0x40000 );
+ {
+ int x, y;
+
+ memcpy(s, p, 0x40000);
+
+ y = 0;
+
+ while ( y < 128 )
+ {
+ x = 0;
+ while ( x < 64 )
+ {
+ UINT8 *src = s + (y*256*8)+(x*4);
+
+ *p++ = src[0*256+0];*p++ = src[0*256+1];*p++ = src[0*256+2];*p++ = src[0*256+3];
+ *p++ = src[1*256+0];*p++ = src[1*256+1];*p++ = src[1*256+2];*p++ = src[1*256+3];
+ *p++ = src[2*256+0];*p++ = src[2*256+1];*p++ = src[2*256+2];*p++ = src[2*256+3];
+ *p++ = src[3*256+0];*p++ = src[3*256+1];*p++ = src[3*256+2];*p++ = src[3*256+3];
+ *p++ = src[4*256+0];*p++ = src[4*256+1];*p++ = src[4*256+2];*p++ = src[4*256+3];
+ *p++ = src[5*256+0];*p++ = src[5*256+1];*p++ = src[5*256+2];*p++ = src[5*256+3];
+ *p++ = src[6*256+0];*p++ = src[6*256+1];*p++ = src[6*256+2];*p++ = src[6*256+3];
+ *p++ = src[7*256+0];*p++ = src[7*256+1];*p++ = src[7*256+2];*p++ = src[7*256+3];
+ x++;
+ }
+ y++;
+ }
+ free(s);
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// adder2 board memorymap /////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+
+ADDRESS_MAP_START( adder2_memmap, ADDRESS_SPACE_PROGRAM, 8 )
+
+ AM_RANGE(0x0000, 0x0000) AM_WRITE(adder2_screen_page_w) // screen access/display select
+ AM_RANGE(0x0000, 0x7FFF) AM_READ(MRA8_BANK2) // 8k paged ROM (4 pages)
+ AM_RANGE(0x8000, 0x917F) AM_READWRITE(screen_ram_r, screen_ram_w)
+ AM_RANGE(0x9180, 0x9FFF) AM_READWRITE(normal_ram_r, normal_ram_w)
+
+ AM_RANGE(0xC000, 0xC000) AM_WRITE(adder2_rom_page_w) // ROM page select
+ AM_RANGE(0xC001, 0xC001) AM_WRITE(adder2_c001_w) // ??
+
+ AM_RANGE(0xC101, 0xC101) AM_READWRITE(adder2_vbl_ctrl_r, adder2_vbl_ctrl_w)
+ AM_RANGE(0xC103, 0xC103) AM_READ(adder2_irq_r) // IRQ latch read
+
+ // MC6850 compatible uart connected to main (scorpion2) board ///////////////////////////////////////
+
+ AM_RANGE(0xC200, 0xC200) AM_READWRITE( adder2_uart_ctrl_r, adder2_uart_ctrl_w ) // 6850 compatible uart control reg
+ AM_RANGE(0xC201, 0xC201) AM_READWRITE( adder2_uart_rx_r, adder2_uart_tx_w ) // 6850 compatible uart data reg
+
+ AM_RANGE(0xE000, 0xFFFF) AM_ROM // 8k ROM
+ADDRESS_MAP_END
+
+static const gfx_layout charlayout =
+{
+ 8,8, // 8 * 8 characters
+ 8192, // 8192 characters
+ 4, // 4 bits per pixel
+ { 0,1,2,3 },
+ { 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4 },
+ { 0*8*4, 1*8*4, 2*8*4, 3*8*4, 4*8*4, 5*8*4, 6*8*4, 7*8*4 },
+ 8*8*4
+};
+
+// this is a strange beast !!!!
+//
+// characters are grouped by 64 (512 pixels)
+// there are max 128 of these groups
+
+GFXDECODE_START( adder2 )
+ GFXDECODE_ENTRY( REGION_GFX1, 0, charlayout, 0, 16 )
+GFXDECODE_END
+
+///////////////////////////////////////////////////////////////////////////
diff --git a/src/mame/video/bfm_adr2.h b/src/mame/video/bfm_adr2.h
new file mode 100644
index 00000000000..f1309dfce32
--- /dev/null
+++ b/src/mame/video/bfm_adr2.h
@@ -0,0 +1,24 @@
+#ifndef INC_BFMADDER2
+#define INC_BFMADDER2
+
+extern UINT8 adder2_data_from_sc2; // data available for adder from sc2
+extern UINT8 adder2_sc2data; // data
+extern UINT8 adder2_data_to_sc2; // data available for sc2 from adder
+extern UINT8 adder2_data; // data
+
+extern int adder2_acia_triggered; // flag <>0, ACIA receive IRQ
+
+GFXDECODE_EXTERN( adder2 );
+extern void adder2_decode_char_roms(void);
+
+MACHINE_RESET( adder2 );
+INTERRUPT_GEN( adder2_vbl );
+
+ADDRESS_MAP_EXTERN( adder2_memmap );
+
+VIDEO_START( adder2 );
+VIDEO_RESET( adder2 );
+VIDEO_UPDATE( adder2 );
+PALETTE_INIT( adder2 );
+
+#endif
diff --git a/src/mame/video/bigevglf.c b/src/mame/video/bigevglf.c
new file mode 100644
index 00000000000..067ec1a1ed2
--- /dev/null
+++ b/src/mame/video/bigevglf.c
@@ -0,0 +1,95 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+#include "driver.h"
+
+
+UINT8 *bigevglf_spriteram1;
+UINT8 *bigevglf_spriteram2;
+
+
+static UINT32 vidram_bank = 0;
+static UINT32 plane_selected = 0;
+static UINT32 plane_visible = 0;
+static UINT8 *vidram;
+
+
+static mame_bitmap *tmp_bitmap[4];
+
+WRITE8_HANDLER(bigevglf_palette_w)
+{
+ int color;
+
+ paletteram[offset] = data;
+ color = paletteram[offset&0x3ff] | (paletteram[0x400+(offset&0x3ff)] << 8);
+ palette_set_color_rgb(Machine, offset&0x3ff, pal4bit(color >> 4), pal4bit(color >> 0), pal4bit(color >> 8));
+}
+
+WRITE8_HANDLER( bigevglf_gfxcontrol_w )
+{
+/* bits used: 0,1,2,3
+ 0 and 2 select plane,
+ 1 and 3 select visible plane,
+*/
+ plane_selected=((data & 4)>>1) | (data&1);
+ plane_visible =((data & 8)>>2) | ((data&2)>>1);
+}
+
+WRITE8_HANDLER( bigevglf_vidram_addr_w )
+{
+ vidram_bank = (data & 0xff) * 0x100;
+}
+
+WRITE8_HANDLER( bigevglf_vidram_w )
+{
+ UINT32 x,y,o;
+ o = vidram_bank + offset;
+ vidram[ o+0x10000*plane_selected ] = data;
+ y = o >>8;
+ x = (o & 255);
+ *BITMAP_ADDR16(tmp_bitmap[plane_selected], y, x) = data;
+}
+
+READ8_HANDLER( bigevglf_vidram_r )
+{
+ return vidram[ 0x10000 * plane_selected + vidram_bank + offset];
+}
+
+VIDEO_START( bigevglf )
+{
+ tmp_bitmap[0] = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ tmp_bitmap[1] = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ tmp_bitmap[2] = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ tmp_bitmap[3] = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ vidram = auto_malloc(0x100*0x100 * 4);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int i,j;
+ for (i = 0xc0-4; i >= 0; i-=4)
+ {
+ int code,sx,sy;
+ code = bigevglf_spriteram2[i+1];
+ sx = bigevglf_spriteram2[i+3];
+ sy = 200-bigevglf_spriteram2[i];
+ for(j=0;j<16;j++)
+ drawgfx(bitmap,machine->gfx[0],
+ bigevglf_spriteram1[(code<<4)+j]+((bigevglf_spriteram1[0x400+(code<<4)+j]&0xf)<<8),
+ bigevglf_spriteram2[i+2] & 0xf,
+ 0,0,
+ sx+((j&1)<<3),sy+((j>>1)<<3),
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( bigevglf )
+{
+ copybitmap(bitmap,tmp_bitmap[ plane_visible ],0,0,0,0,cliprect,TRANSPARENCY_NONE, 0);
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/bigstrkb.c b/src/mame/video/bigstrkb.c
new file mode 100644
index 00000000000..345147d7a63
--- /dev/null
+++ b/src/mame/video/bigstrkb.c
@@ -0,0 +1,145 @@
+/* Big Striker (bootleg) Video Hardware */
+
+#include "driver.h"
+
+static tilemap *bsb_tilemap, *bsb_tilemap2, *bsb_tilemap3;
+
+extern UINT16 *bsb_videoram, *bsb_videoram2, *bsb_videoram3;
+extern UINT16 *bsb_vidreg1, *bsb_vidreg2;
+extern UINT16 *bigstrkb_spriteram;
+
+/* Sprites */
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ /*- SPR RAM Format -**
+
+ 16 bytes per sprite
+
+ nnnn nnnn nnnn nnnn aaaa aaaa aaaa aaaa xxxx xxxx xxxx xxxx yyyy yyyy yyyy yyyy
+ ( rest unused )
+ **- End of Comments -*/
+
+ const gfx_element *gfx = machine->gfx[2];
+ UINT16 *source = bigstrkb_spriteram;
+ UINT16 *finish = source + 0x800/2;
+
+ while( source<finish )
+ {
+ int xpos, ypos, num, attr;
+
+ int flipx, col;
+
+ xpos = source[2];
+ ypos = source[3];
+ num = source[0];
+ attr = source[1];
+
+ ypos = 0xffff - ypos;
+
+
+ xpos -= 126;
+ ypos -= 16;
+
+ flipx = attr & 0x0100;
+ col = attr & 0x000f;
+
+ drawgfx(bitmap,gfx,num,col,flipx,0,xpos,ypos,cliprect,TRANSPARENCY_PEN,15);
+ source+=8;
+ }
+}
+
+/* Tilemaps */
+
+static TILEMAP_MAPPER( bsb_bg_scan )
+{
+ int offset;
+
+ offset = ((col&0xf)*16) + (row&0xf);
+ offset += (col >> 4) * 0x100;
+ offset += (row >> 4) * 0x800;
+
+ return offset;
+}
+
+static TILE_GET_INFO( get_bsb_tile_info )
+{
+ int tileno,col;
+
+ tileno = bsb_videoram[tile_index] & 0x0fff;
+ col= bsb_videoram[tile_index] & 0xf000;
+
+ SET_TILE_INFO(0,tileno,col>>12,0);
+}
+
+WRITE16_HANDLER( bsb_videoram_w )
+{
+ bsb_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bsb_tilemap,offset);
+}
+
+static TILE_GET_INFO( get_bsb_tile2_info )
+{
+ int tileno,col;
+
+ tileno = bsb_videoram2[tile_index] & 0x0fff;
+ col= bsb_videoram2[tile_index] & 0xf000;
+
+ SET_TILE_INFO(1,tileno,col>>12,0);
+}
+
+WRITE16_HANDLER( bsb_videoram2_w )
+{
+ bsb_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(bsb_tilemap2,offset);
+}
+
+
+static TILE_GET_INFO( get_bsb_tile3_info )
+{
+ int tileno,col;
+
+ tileno = bsb_videoram3[tile_index] & 0x0fff;
+ col= bsb_videoram3[tile_index] & 0xf000;
+
+ SET_TILE_INFO(1,tileno+0x2000,(col>>12)+(0x100/16),0);
+}
+
+WRITE16_HANDLER( bsb_videoram3_w )
+{
+ bsb_videoram3[offset] = data;
+ tilemap_mark_tile_dirty(bsb_tilemap3,offset);
+}
+
+/* Video Start / Update */
+
+VIDEO_START(bigstrkb)
+{
+ bsb_tilemap = tilemap_create(get_bsb_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ bsb_tilemap2 = tilemap_create(get_bsb_tile2_info,bsb_bg_scan,TILEMAP_TYPE_PEN, 16, 16,128,64);
+ bsb_tilemap3 = tilemap_create(get_bsb_tile3_info,bsb_bg_scan,TILEMAP_TYPE_PEN, 16, 16,128,64);
+
+ tilemap_set_transparent_pen(bsb_tilemap,15);
+// tilemap_set_transparent_pen(bsb_tilemap2,15);
+ tilemap_set_transparent_pen(bsb_tilemap3,15);
+}
+
+VIDEO_UPDATE(bigstrkb)
+{
+// fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ tilemap_set_scrollx(bsb_tilemap2,0, bsb_vidreg1[0]+(256-14));
+ tilemap_set_scrolly(bsb_tilemap2,0, bsb_vidreg2[0]);
+
+ tilemap_set_scrollx(bsb_tilemap3,0, bsb_vidreg1[1]+(256-14));
+ tilemap_set_scrolly(bsb_tilemap3,0, bsb_vidreg2[1]);
+
+ tilemap_draw(bitmap,cliprect,bsb_tilemap2,0,0);
+ tilemap_draw(bitmap,cliprect,bsb_tilemap3,0,0);
+
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bsb_tilemap,0,0);
+
+// popmessage ("Regs %08x %08x %08x %08x",bsb_vidreg2[0],bsb_vidreg2[1],bsb_vidreg2[2],bsb_vidreg2[3]);
+ return 0;
+}
diff --git a/src/mame/video/bionicc.c b/src/mame/video/bionicc.c
new file mode 100644
index 00000000000..fc759b953ef
--- /dev/null
+++ b/src/mame/video/bionicc.c
@@ -0,0 +1,232 @@
+/***************************************************************************
+
+Bionic Commando Video Hardware
+
+This board handles tile/tile and tile/sprite priority with a PROM. Its
+working is complicated and hardcoded in the driver.
+
+The PROM is a 256x4 chip, with address inputs wired as follows:
+
+A0 bg opaque
+A1 \
+A2 | fg pen
+A3 |
+A4 /
+A5 fg has priority over sprites (bit 5 of tile attribute)
+A6 fg has not priority over bg (bits 6 & 7 of tile attribute both set)
+A7 sprite opaque
+
+The output selects the active layer, it can be:
+0 bg
+1 fg
+2 sprite
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *bionicc_fgvideoram;
+UINT16 *bionicc_bgvideoram;
+UINT16 *bionicc_txvideoram;
+
+static tilemap *tx_tilemap, *bg_tilemap, *fg_tilemap;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = bionicc_bgvideoram[2*tile_index+1];
+ SET_TILE_INFO(
+ 1,
+ (bionicc_bgvideoram[2*tile_index] & 0xff) + ((attr & 0x07) << 8),
+ (attr & 0x18) >> 3,
+ TILE_FLIPXY((attr & 0xc0) >> 6));
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = bionicc_fgvideoram[2*tile_index+1];
+ int flags;
+
+ if ((attr & 0xc0) == 0xc0)
+ {
+ tileinfo->category = 1;
+ tileinfo->group = 0;
+ flags = 0;
+ }
+ else
+ {
+ tileinfo->category = 0;
+ tileinfo->group = (attr & 0x20) >> 5;
+ flags = TILE_FLIPXY((attr & 0xc0) >> 6);
+ }
+
+ SET_TILE_INFO(
+ 2,
+ (bionicc_fgvideoram[2*tile_index] & 0xff) + ((attr & 0x07) << 8),
+ (attr & 0x18) >> 3,
+ flags);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int attr = bionicc_txvideoram[tile_index + 0x400];
+ SET_TILE_INFO(
+ 0,
+ (bionicc_txvideoram[tile_index] & 0xff) + ((attr & 0x00c0) << 2),
+ attr & 0x3f,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( bionicc )
+{
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,32,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,64,64);
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,64);
+
+ tilemap_set_transparent_pen(tx_tilemap,3);
+ tilemap_set_transmask(fg_tilemap,0,0xffff,0x8000); /* split type 0 is completely transparent in front half */
+ tilemap_set_transmask(fg_tilemap,1,0xffc1,0x803e); /* split type 1 has pens 1-5 opaque in front half */
+ tilemap_set_transparent_pen(bg_tilemap,15);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( bionicc_bgvideoram_w )
+{
+ COMBINE_DATA(&bionicc_bgvideoram[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( bionicc_fgvideoram_w )
+{
+ COMBINE_DATA(&bionicc_fgvideoram[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( bionicc_txvideoram_w )
+{
+ COMBINE_DATA(&bionicc_txvideoram[offset]);
+ tilemap_mark_tile_dirty(tx_tilemap,offset&0x3ff);
+}
+
+WRITE16_HANDLER( bionicc_paletteram_w )
+{
+ data = COMBINE_DATA(&paletteram16[offset]);
+ paletteram16_RRRRGGGGBBBBIIII_word_w(offset,(data & 0xfff0) | ((data & 0x0007) << 1),0);
+}
+
+WRITE16_HANDLER( bionicc_scroll_w )
+{
+ static UINT16 scroll[4];
+
+ data = COMBINE_DATA(&scroll[offset]);
+
+ switch (offset)
+ {
+ case 0:
+ tilemap_set_scrollx(fg_tilemap,0,data);
+ break;
+ case 1:
+ tilemap_set_scrolly(fg_tilemap,0,data);
+ break;
+ case 2:
+ tilemap_set_scrollx(bg_tilemap,0,data);
+ break;
+ case 3:
+ tilemap_set_scrolly(bg_tilemap,0,data);
+ break;
+ }
+}
+
+WRITE16_HANDLER( bionicc_gfxctrl_w )
+{
+ if (ACCESSING_MSB)
+ {
+ flip_screen_set(data & 0x0100);
+
+ tilemap_set_enable(bg_tilemap,data & 0x2000); /* guess */
+ tilemap_set_enable(fg_tilemap,data & 0x1000); /* guess */
+
+ coin_counter_w(0,data & 0x8000);
+ coin_counter_w(1,data & 0x4000);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+ const gfx_element *gfx = machine->gfx[3];
+
+ for (offs = (spriteram_size-8)/2;offs >= 0;offs -= 4)
+ {
+ int tile_number = buffered_spriteram16[offs] & 0x7ff;
+ if( tile_number!=0x7FF ){
+ int attr = buffered_spriteram16[offs+1];
+ int color = (attr&0x3C)>>2;
+ int flipx = attr&0x02;
+ int flipy = 0;
+ int sx = (INT16)buffered_spriteram16[offs+3]; /* signed */
+ int sy = (INT16)buffered_spriteram16[offs+2]; /* signed */
+ if(sy>512-16) sy-=512;
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx( bitmap, gfx,
+ tile_number,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+}
+
+VIDEO_UPDATE( bionicc )
+{
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,1|TILEMAP_DRAW_LAYER1,0); /* nothing in FRONT */
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0|TILEMAP_DRAW_LAYER1,0);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0|TILEMAP_DRAW_LAYER0,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_EOF( bionicc )
+{
+ buffer_spriteram16_w(0,0,0);
+}
diff --git a/src/mame/video/bishi.c b/src/mame/video/bishi.c
new file mode 100644
index 00000000000..6895ec1b352
--- /dev/null
+++ b/src/mame/video/bishi.c
@@ -0,0 +1,96 @@
+/***************************************************************************
+
+ Bishi Bashi Champ Mini Game Senshuken
+ (c) 1996 Konami
+
+ Video hardware emulation.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/konamiic.h"
+#include "machine/konamigx.h"
+
+static int layer_colorbase[4], layerpri[4];
+
+static void bishi_tile_callback(int layer, int *code, int *color, int *flags)
+{
+// *code -= '0';
+// *color = layer_colorbase[layer] | (*color>>2 & 0x0f);
+// K055555GX_decode_vmixcolor(layer, color);
+// if (*color) mame_printf_debug("plane %x col %x [55 %x %x]\n", layer, *color, layer_colorbase[layer], K055555_get_palette_index(layer));
+
+ *color = layer_colorbase[layer] + ((*color & 0xf0));
+}
+
+VIDEO_START(bishi)
+{
+ assert(machine->screen[0].format == BITMAP_FORMAT_RGB32);
+
+ K055555_vh_start();
+ K054338_vh_start();
+
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_8, 1, NULL, bishi_tile_callback, 0);
+
+ K056832_set_LayerAssociation(0);
+
+ K056832_set_LayerOffset(0, -2, 0);
+ K056832_set_LayerOffset(1, 2, 0);
+ K056832_set_LayerOffset(2, 4, 0);
+ K056832_set_LayerOffset(3, 6, 0);
+
+ // the 55555 is set to "0x10, 0x11, 0x12, 0x13", but these values are almost correct...
+ layer_colorbase[0] = 0x00;
+ layer_colorbase[1] = 0x40; // this one is wrong
+ layer_colorbase[2] = 0x80;
+ layer_colorbase[3] = 0xc0;
+}
+
+/* useful function to sort the three tile layers by priority order */
+static void sortlayers(int *layer,int *pri)
+{
+#define SWAP(a,b) \
+ if (pri[a] < pri[b]) \
+ { \
+ int t; \
+ t = pri[a]; pri[a] = pri[b]; pri[b] = t; \
+ t = layer[a]; layer[a] = layer[b]; layer[b] = t; \
+ }
+
+ SWAP(0,1)
+ SWAP(0,2)
+ SWAP(0,3)
+ SWAP(1,2)
+ SWAP(1,3)
+ SWAP(2,3)
+}
+
+VIDEO_UPDATE(bishi)
+{
+ int layers[4], i;/*, old;*/
+/* int bg_colorbase, new_colorbase, plane, dirty; */
+ static const int pris[4] = { K55_PRIINP_0, K55_PRIINP_3, K55_PRIINP_6, K55_PRIINP_7 };
+ static const int enables[4] = { K55_INP_VRAM_A, K55_INP_VRAM_B, K55_INP_VRAM_C, K55_INP_VRAM_D };
+
+ K054338_update_all_shadows(machine);
+ K054338_fill_backcolor(machine, bitmap, 0);
+
+ for (i = 0; i < 4; i++)
+ {
+ layers[i] = i;
+ layerpri[i] = K055555_read_register(pris[i]);
+ }
+
+ sortlayers(layers, layerpri);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ for (i = 0; i < 4; i++)
+ {
+ if (K055555_read_register(K55_INPUT_ENABLES) & enables[layers[i]])
+ {
+ K056832_tilemap_draw(machine, bitmap, cliprect, layers[i], 0, 1<<i);
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/bking2.c b/src/mame/video/bking2.c
new file mode 100644
index 00000000000..688c940af62
--- /dev/null
+++ b/src/mame/video/bking2.c
@@ -0,0 +1,364 @@
+/***************************************************************************
+
+ bking2.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+extern UINT8* bking2_playfield_ram;
+
+
+static int pc3259_output[4];
+static int pc3259_mask;
+
+static UINT8 xld1;
+static UINT8 xld2;
+static UINT8 xld3;
+static UINT8 yld1;
+static UINT8 yld2;
+static UINT8 yld3;
+
+static int ball1_pic;
+static int ball2_pic;
+static int crow_pic;
+static int crow_flip;
+static int palette_bank;
+static int controller;
+static int hit;
+
+static mame_bitmap* helper0;
+static mame_bitmap* helper1;
+
+static tilemap* bg_tilemap;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 390 ohm resistor -- BLUE
+ -- 220 ohm resistor -- BLUE
+ -- 820 ohm resistor -- GREEN
+ -- 390 ohm resistor -- GREEN
+ -- 220 ohm resistor -- GREEN
+ -- 820 ohm resistor -- RED
+ -- 390 ohm resistor -- RED
+ bit 0 -- 220 ohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( bking2 )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x92 * bit0 + 0x46 * bit1 + 0x27 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x92 * bit0 + 0x46 * bit1 + 0x27 * bit2;
+ /* blue component */
+ bit0 = (*color_prom >> 6) & 0x01;
+ bit1 = (*color_prom >> 7) & 0x01;
+ bit2 = 0;
+ b = 0x92 * bit0 + 0x46 * bit1 + 0x27 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color PROM A7-A8 is the palette select */
+
+ /* character colors. Image bits go to A0-A2 of the color PROM */
+ for (i = 0; i < TOTAL_COLORS(0); i++)
+ {
+ COLOR(0,i) = ((i << 4) & 0x180) | (i & 0x07);
+ }
+
+ /* crow colors. Image bits go to A5-A6. */
+ for (i = 0; i < TOTAL_COLORS(1); i++)
+ {
+ COLOR(1,i) = ((i << 5) & 0x180) | ((i & 0x03) << 5);
+ }
+
+ /* ball colors. Ball 1 image bit goes to A3. Ball 2 to A4. */
+ for (i = 0; i < TOTAL_COLORS(2); i++)
+ {
+ COLOR(2,i) = ((i << 6) & 0x180) | ((i & 0x01) << 3);
+ COLOR(3,i) = ((i << 6) & 0x180) | ((i & 0x01) << 4);
+ }
+}
+
+
+WRITE8_HANDLER( bking2_xld1_w )
+{
+ xld1 = -data;
+}
+
+WRITE8_HANDLER( bking2_yld1_w )
+{
+ yld1 = -data;
+}
+
+WRITE8_HANDLER( bking2_xld2_w )
+{
+ xld2 = -data;
+}
+
+WRITE8_HANDLER( bking2_yld2_w )
+{
+ yld2 = -data;
+}
+
+WRITE8_HANDLER( bking2_xld3_w )
+{
+ xld3 = -data;
+}
+
+WRITE8_HANDLER( bking2_yld3_w )
+{
+ yld3 = -data;
+}
+
+
+WRITE8_HANDLER( bking2_cont1_w )
+{
+ /* D0 = COIN LOCK */
+ /* D1 = BALL 5 (Controller selection) */
+ /* D2 = VINV (flip screen) */
+ /* D3 = Not Connected */
+ /* D4-D7 = CROW0-CROW3 (selects crow picture) */
+
+ coin_lockout_global_w(~data & 0x01);
+
+ flip_screen = data & 0x04;
+
+ tilemap_set_flip(ALL_TILEMAPS, flip_screen ? TILEMAP_FLIPX | TILEMAP_FLIPY : 0);
+
+ controller = data & 0x02;
+
+ crow_pic = (data >> 4) & 0x0f;
+}
+
+WRITE8_HANDLER( bking2_cont2_w )
+{
+ /* D0-D2 = BALL10 - BALL12 (Selects player 1 ball picture) */
+ /* D3-D5 = BALL20 - BALL22 (Selects player 2 ball picture) */
+ /* D6 = HIT1 */
+ /* D7 = HIT2 */
+
+ ball1_pic = (data >> 0) & 0x07;
+ ball2_pic = (data >> 3) & 0x07;
+
+ hit = data >> 6;
+}
+
+WRITE8_HANDLER( bking2_cont3_w )
+{
+ /* D0 = CROW INV (inverts Crow picture and coordinates) */
+ /* D1-D2 = COLOR 0 - COLOR 1 (switches 4 color palettes, global across all graphics) */
+ /* D3 = SOUND STOP */
+
+ crow_flip = ~data & 0x01;
+
+ if (palette_bank != ((data >> 1) & 0x03))
+ {
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ palette_bank = (data >> 1) & 0x03;
+
+ sound_global_enable(~data & 0x08);
+}
+
+
+WRITE8_HANDLER( bking2_msk_w )
+{
+ pc3259_mask++;
+}
+
+
+WRITE8_HANDLER( bking2_hitclr_w )
+{
+ pc3259_mask = 0;
+
+ pc3259_output[0] = 0;
+ pc3259_output[1] = 0;
+ pc3259_output[2] = 0;
+ pc3259_output[3] = 0;
+}
+
+
+WRITE8_HANDLER( bking2_playfield_w )
+{
+ bking2_playfield_ram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+
+READ8_HANDLER( bking2_input_port_5_r )
+{
+ return readinputport(controller ? 7 : 5);
+}
+
+READ8_HANDLER( bking2_input_port_6_r )
+{
+ return readinputport(controller ? 8 : 6);
+}
+
+READ8_HANDLER( bking2_pos_r )
+{
+ return pc3259_output[offset / 8] << 4;
+}
+
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 code0 = bking2_playfield_ram[2 * tile_index + 0];
+ UINT8 code1 = bking2_playfield_ram[2 * tile_index + 1];
+
+ int flags = 0;
+
+ if (code1 & 4) flags |= TILE_FLIPX;
+ if (code1 & 8) flags |= TILE_FLIPY;
+
+ SET_TILE_INFO(0, code0 + 256 * code1, palette_bank, flags);
+}
+
+
+VIDEO_START( bking2 )
+{
+ bg_tilemap = tilemap_create(get_tile_info, tilemap_scan_rows, 0, 8, 8, 32, 32);
+ helper0 = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ helper1 = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+}
+
+
+VIDEO_UPDATE( bking2 )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* draw the balls */
+
+ drawgfx(bitmap, machine->gfx[2],
+ ball1_pic,
+ palette_bank,
+ 0, 0,
+ xld1, yld1,
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ drawgfx(bitmap, machine->gfx[3],
+ ball2_pic,
+ palette_bank,
+ 0, 0,
+ xld2, yld2,
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ /* draw the crow */
+
+ drawgfx(bitmap, machine->gfx[1],
+ crow_pic,
+ palette_bank,
+ crow_flip, crow_flip,
+ crow_flip ? xld3 - 16 : 256 - xld3, crow_flip ? yld3 - 16 : 256 - yld3,
+ cliprect, TRANSPARENCY_PEN, 0);
+ return 0;
+}
+
+
+VIDEO_EOF( bking2 )
+{
+ static rectangle rect = { 0, 7, 0, 15 };
+
+ int xld = 0;
+ int yld = 0;
+
+ UINT32 latch = 0;
+
+ if (pc3259_mask == 6) /* player 1 */
+ {
+ xld = xld1;
+ yld = yld1;
+
+ drawgfx(helper1, machine->gfx[2],
+ ball1_pic,
+ 0,
+ 0, 0,
+ 0, 0,
+ &rect, TRANSPARENCY_NONE, 0);
+
+ latch = 0x0C00;
+ }
+
+ if (pc3259_mask == 3) /* player 2 */
+ {
+ xld = xld2;
+ yld = yld2;
+
+ drawgfx(helper1, machine->gfx[3],
+ ball2_pic,
+ 0,
+ 0, 0,
+ 0, 0,
+ &rect, TRANSPARENCY_NONE, 0);
+
+ latch = 0x0400;
+ }
+
+ tilemap_set_scrollx(bg_tilemap, 0, flip_screen ? -xld : xld);
+ tilemap_set_scrolly(bg_tilemap, 0, flip_screen ? -yld : yld);
+
+ tilemap_draw(helper0, &rect, bg_tilemap, 0, 0);
+
+ tilemap_set_scrollx(bg_tilemap, 0, 0);
+ tilemap_set_scrolly(bg_tilemap, 0, 0);
+
+ if (latch != 0)
+ {
+ const UINT8* MASK = memory_region(REGION_USER1) + 8 * hit;
+
+ int x;
+ int y;
+
+ for (y = rect.min_y; y <= rect.max_y; y++)
+ {
+ const UINT16* p0 = BITMAP_ADDR16(helper0, y, 0);
+ const UINT16* p1 = BITMAP_ADDR16(helper1, y, 0);
+
+ for (x = rect.min_x; x <= rect.max_x; x++)
+ {
+ if (MASK[p0[x] & 7] && p1[x])
+ {
+ int col = (xld + x) / 8 + 1;
+ int row = (yld + y) / 8 + 0;
+
+ latch |= (flip_screen ? 31 - col : col) << 0;
+ latch |= (flip_screen ? 31 - row : row) << 5;
+
+ pc3259_output[0] = (latch >> 0x0) & 0xf;
+ pc3259_output[1] = (latch >> 0x4) & 0xf;
+ pc3259_output[2] = (latch >> 0x8) & 0xf;
+ pc3259_output[3] = (latch >> 0xc) & 0xf;
+
+ return;
+ }
+ }
+ }
+ }
+}
diff --git a/src/mame/video/bladestl.c b/src/mame/video/bladestl.c
new file mode 100644
index 00000000000..8bbe1945576
--- /dev/null
+++ b/src/mame/video/bladestl.c
@@ -0,0 +1,75 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+static int layer_colorbase[2];
+extern int bladestl_spritebank;
+
+PALETTE_INIT( bladestl )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ /* build the lookup table for sprites. Palette is dynamic. */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = 0x20 + (*(color_prom++) & 0x0f);
+}
+
+/***************************************************************************
+
+ Callback for the K007342
+
+***************************************************************************/
+
+static void tile_callback(int layer, int bank, int *code, int *color, int *flags)
+{
+ *code |= ((*color & 0x0f) << 8) | ((*color & 0x40) << 6);
+ *color = layer_colorbase[layer];
+}
+
+/***************************************************************************
+
+ Callback for the K007420
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color)
+{
+ *code |= ((*color & 0xc0) << 2) + bladestl_spritebank;
+ *code = (*code << 2) | ((*color & 0x30) >> 4);
+ *color = 0 + (*color & 0x0f);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( bladestl )
+{
+ layer_colorbase[0] = 0;
+ layer_colorbase[1] = 1;
+
+ K007342_vh_start(0,tile_callback);
+ K007420_vh_start(machine,1,sprite_callback);
+}
+
+/***************************************************************************
+
+ Screen Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( bladestl )
+{
+ K007342_tilemap_update();
+
+ K007342_tilemap_draw( bitmap, cliprect, 1, TILEMAP_DRAW_OPAQUE ,0);
+ K007420_sprites_draw( bitmap, cliprect );
+ K007342_tilemap_draw( bitmap, cliprect, 1, 1 | TILEMAP_DRAW_OPAQUE ,0);
+ K007342_tilemap_draw( bitmap, cliprect, 0, 0 ,0);
+ K007342_tilemap_draw( bitmap, cliprect, 0, 1 ,0);
+ return 0;
+}
diff --git a/src/mame/video/blktiger.c b/src/mame/video/blktiger.c
new file mode 100644
index 00000000000..e9f672a2ad5
--- /dev/null
+++ b/src/mame/video/blktiger.c
@@ -0,0 +1,248 @@
+#include "driver.h"
+
+UINT8 *blktiger_txvideoram;
+
+#define BGRAM_BANK_SIZE 0x1000
+#define BGRAM_BANKS 4
+
+static UINT32 blktiger_scroll_bank;
+static UINT8 *scroll_ram;
+static UINT8 screen_layout;
+static UINT8 chon,objon,bgon;
+
+static tilemap *tx_tilemap,*bg_tilemap8x4,*bg_tilemap4x8;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( bg8x4_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x0f) + ((row & 0x0f) << 4) + ((col & 0x70) << 4) + ((row & 0x30) << 7);
+}
+
+static TILEMAP_MAPPER( bg4x8_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x0f) + ((row & 0x0f) << 4) + ((col & 0x30) << 4) + ((row & 0x70) << 6);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ /* the tile priority table is a guess compiled by looking at the game. It
+ was not derived from a PROM so it could be wrong. */
+ static int split_table[16] =
+ {
+ 3,0,2,2, /* the fourth could be 1 instead of 2 */
+ 0,1,0,0,
+ 0,0,0,0,
+ 0,0,0,0
+ };
+ UINT8 attr = scroll_ram[2*tile_index + 1];
+ int color = (attr & 0x78) >> 3;
+ SET_TILE_INFO(
+ 1,
+ scroll_ram[2*tile_index] + ((attr & 0x07) << 8),
+ color,
+ (attr & 0x80) ? TILE_FLIPX : 0);
+ tileinfo->group = split_table[color];
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ UINT8 attr = blktiger_txvideoram[tile_index + 0x400];
+ SET_TILE_INFO(
+ 0,
+ blktiger_txvideoram[tile_index] + ((attr & 0xe0) << 3),
+ attr & 0x1f,
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( blktiger )
+{
+ scroll_ram = auto_malloc(BGRAM_BANK_SIZE * BGRAM_BANKS);
+
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ bg_tilemap8x4 = tilemap_create(get_bg_tile_info,bg8x4_scan, TILEMAP_TYPE_PEN, 16,16,128,64);
+ bg_tilemap4x8 = tilemap_create(get_bg_tile_info,bg4x8_scan, TILEMAP_TYPE_PEN, 16,16,64,128);
+
+ tilemap_set_transparent_pen(tx_tilemap,3);
+
+ tilemap_set_transmask(bg_tilemap8x4,0,0xffff,0x8000); /* split type 0 is totally transparent in front half */
+ tilemap_set_transmask(bg_tilemap8x4,1,0xfff0,0x800f); /* split type 1 has pens 4-15 transparent in front half */
+ tilemap_set_transmask(bg_tilemap8x4,2,0xff00,0x80ff); /* split type 1 has pens 8-15 transparent in front half */
+ tilemap_set_transmask(bg_tilemap8x4,3,0xf000,0x8fff); /* split type 1 has pens 12-15 transparent in front half */
+ tilemap_set_transmask(bg_tilemap4x8,0,0xffff,0x8000);
+ tilemap_set_transmask(bg_tilemap4x8,1,0xfff0,0x800f);
+ tilemap_set_transmask(bg_tilemap4x8,2,0xff00,0x80ff);
+ tilemap_set_transmask(bg_tilemap4x8,3,0xf000,0x8fff);
+
+ state_save_register_global(blktiger_scroll_bank);
+ state_save_register_global(screen_layout);
+ state_save_register_global(chon);
+ state_save_register_global(objon);
+ state_save_register_global(bgon);
+ state_save_register_global_pointer(scroll_ram, BGRAM_BANK_SIZE * BGRAM_BANKS);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( blktiger_txvideoram_w )
+{
+ blktiger_txvideoram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset & 0x3ff);
+}
+
+READ8_HANDLER( blktiger_bgvideoram_r )
+{
+ return scroll_ram[offset + blktiger_scroll_bank];
+}
+
+WRITE8_HANDLER( blktiger_bgvideoram_w )
+{
+ offset += blktiger_scroll_bank;
+
+ scroll_ram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap8x4,offset/2);
+ tilemap_mark_tile_dirty(bg_tilemap4x8,offset/2);
+}
+
+WRITE8_HANDLER( blktiger_bgvideoram_bank_w )
+{
+ blktiger_scroll_bank = (data % BGRAM_BANKS) * BGRAM_BANK_SIZE;
+}
+
+
+WRITE8_HANDLER( blktiger_scrolly_w )
+{
+ static UINT8 scroll[2];
+ int scrolly;
+
+ scroll[offset] = data;
+ scrolly = scroll[0] | (scroll[1] << 8);
+ tilemap_set_scrolly(bg_tilemap8x4,0,scrolly);
+ tilemap_set_scrolly(bg_tilemap4x8,0,scrolly);
+}
+
+WRITE8_HANDLER( blktiger_scrollx_w )
+{
+ static UINT8 scroll[2];
+ int scrollx;
+
+ scroll[offset] = data;
+ scrollx = scroll[0] | (scroll[1] << 8);
+ tilemap_set_scrollx(bg_tilemap8x4,0,scrollx);
+ tilemap_set_scrollx(bg_tilemap4x8,0,scrollx);
+}
+
+
+WRITE8_HANDLER( blktiger_video_control_w )
+{
+ /* bits 0 and 1 are coin counters */
+ coin_counter_w(0,data & 1);
+ coin_counter_w(1,data & 2);
+
+ /* bit 5 resets the sound CPU */
+ cpunum_set_input_line(1, INPUT_LINE_RESET, (data & 0x20) ? ASSERT_LINE : CLEAR_LINE);
+
+ /* bit 6 flips screen */
+ flip_screen_set(data & 0x40);
+
+ /* bit 7 enables characters? Just a guess */
+ chon = ~data & 0x80;
+}
+
+WRITE8_HANDLER( blktiger_video_enable_w )
+{
+ /* not sure which is which, but I think that bit 1 and 2 enable background and sprites */
+ /* bit 1 enables bg ? */
+ bgon = ~data & 0x02;
+
+ /* bit 2 enables sprites ? */
+ objon = ~data & 0x04;
+}
+
+WRITE8_HANDLER( blktiger_screen_layout_w )
+{
+ screen_layout = data;
+ tilemap_set_enable(bg_tilemap8x4, screen_layout);
+ tilemap_set_enable(bg_tilemap4x8,!screen_layout);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ /* Draw the sprites. */
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int attr = buffered_spriteram[offs+1];
+ int sx = buffered_spriteram[offs + 3] - ((attr & 0x10) << 4);
+ int sy = buffered_spriteram[offs + 2];
+ int code = buffered_spriteram[offs] | ((attr & 0xe0) << 3);
+ int color = attr & 0x07;
+ int flipx = attr & 0x08;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ }
+
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx,flip_screen,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+VIDEO_UPDATE( blktiger )
+{
+ fillbitmap(bitmap,machine->pens[1023],cliprect);
+
+ if (bgon)
+ tilemap_draw(bitmap,cliprect,screen_layout ? bg_tilemap8x4 : bg_tilemap4x8,TILEMAP_DRAW_LAYER1,0);
+
+ if (objon)
+ draw_sprites(machine, bitmap,cliprect);
+
+ if (bgon)
+ tilemap_draw(bitmap,cliprect,screen_layout ? bg_tilemap8x4 : bg_tilemap4x8,TILEMAP_DRAW_LAYER0,0);
+
+ if (chon)
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_EOF( blktiger )
+{
+ buffer_spriteram_w(0,0);
+}
diff --git a/src/mame/video/blmbycar.c b/src/mame/video/blmbycar.c
new file mode 100644
index 00000000000..061bfc842c7
--- /dev/null
+++ b/src/mame/video/blmbycar.c
@@ -0,0 +1,259 @@
+/***************************************************************************
+
+ -= Blomby Car =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z with:
+
+ Q shows the background
+ W shows the foreground
+ A shows the sprites
+
+ Keys can be used together!
+
+
+ [ 2 Scrolling Layers ]
+
+ The Tilemaps are 64 x 32 tiles in size (1024 x 512).
+ Tiles are 16 x 16 x 4, with 32 color codes and 2 priority
+ leves (wrt sprites). Each tile needs 4 bytes.
+
+ [ 1024? Sprites ]
+
+ They use the same graphics the tilemaps use (16 x 16 x 4 tiles)
+ with 16 color codes and 2 levels of priority
+
+
+***************************************************************************/
+
+#include "driver.h"
+
+/* Variables needed by driver: */
+
+UINT16 *blmbycar_vram_0, *blmbycar_scroll_0;
+UINT16 *blmbycar_vram_1, *blmbycar_scroll_1;
+
+
+/***************************************************************************
+
+
+ Palette
+
+
+***************************************************************************/
+
+/* xxxxBBBBGGGGRRRR */
+
+WRITE16_HANDLER( blmbycar_palette_w )
+{
+ data = COMBINE_DATA(&paletteram16[offset]);
+ palette_set_color_rgb( Machine, offset, pal4bit(data >> 4), pal4bit(data >> 0), pal4bit(data >> 8));
+}
+
+
+
+/***************************************************************************
+
+
+ Tilemaps
+
+ Offset: Bits: Value:
+
+ 0.w Code
+ 2.w fedc ba98 ---- ----
+ ---- ---- 7--- ---- Flip Y
+ ---- ---- -6-- ---- Flip X
+ ---- ---- --5- ---- Priority (0 = Low)
+ ---- ---- ---4 3210 Color
+
+***************************************************************************/
+
+static tilemap *tilemap_0, *tilemap_1;
+
+#define DIM_NX (0x40)
+#define DIM_NY (0x20)
+
+static TILE_GET_INFO( get_tile_info_0 )
+{
+ UINT16 code = blmbycar_vram_0[ tile_index * 2 + 0 ];
+ UINT16 attr = blmbycar_vram_0[ tile_index * 2 + 1 ];
+ SET_TILE_INFO(
+ 0,
+ code,
+ attr & 0x1f,
+ TILE_FLIPYX((attr >> 6) & 3));
+
+ tileinfo->category = (attr >> 5) & 1;
+}
+
+static TILE_GET_INFO( get_tile_info_1 )
+{
+ UINT16 code = blmbycar_vram_1[ tile_index * 2 + 0 ];
+ UINT16 attr = blmbycar_vram_1[ tile_index * 2 + 1 ];
+ SET_TILE_INFO(
+ 0,
+ code,
+ attr & 0x1f,
+ TILE_FLIPYX((attr >> 6) & 3));
+
+ tileinfo->category = (attr >> 5) & 1;
+}
+
+
+WRITE16_HANDLER( blmbycar_vram_0_w )
+{
+ COMBINE_DATA(&blmbycar_vram_0[offset]);
+ tilemap_mark_tile_dirty(tilemap_0, offset/2);
+}
+
+WRITE16_HANDLER( blmbycar_vram_1_w )
+{
+ COMBINE_DATA(&blmbycar_vram_1[offset]);
+ tilemap_mark_tile_dirty(tilemap_1, offset/2);
+}
+
+
+/***************************************************************************
+
+
+ Video Init
+
+
+***************************************************************************/
+
+VIDEO_START( blmbycar )
+{
+ tilemap_0 = tilemap_create( get_tile_info_0, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, DIM_NX, DIM_NY );
+
+ tilemap_1 = tilemap_create( get_tile_info_1, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, DIM_NX, DIM_NY );
+
+ tilemap_set_scroll_rows(tilemap_0,1);
+ tilemap_set_scroll_cols(tilemap_0,1);
+
+ tilemap_set_scroll_rows(tilemap_1,1);
+ tilemap_set_scroll_cols(tilemap_1,1);
+ tilemap_set_transparent_pen(tilemap_1,0);
+}
+
+
+/***************************************************************************
+
+
+ Sprites Drawing
+
+ Offset: Bits: Value:
+
+ 0.w f--- ---- ---- ---- End Of Sprites
+ -edc ba9- ---- ----
+ ---- ---8 7654 3210 Y (Signed)
+
+ 2.w Code
+
+ 4.w f--- ---- ---- ---- Flip Y
+ -e-- ---- ---- ---- Flip X
+ --dc ba98 7654 ----
+ ---- ---- ---- 3210 Color (Bit 3 = Priority)
+
+ 6.w f--- ---- ---- ---- ? Is this ever used ?
+ -e-- ---- ---- ---- ? 1 = Don't Draw ?
+ --dc ba9- ---- ----
+ ---- ---8 7654 3210 X (Signed)
+
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT16 *source, *finish;
+
+ source = spriteram16 + 0x6/2; // !
+ finish = spriteram16 + spriteram_size/2 - 8/2;
+
+ /* Find "the end of sprites" marker */
+
+ for ( ; source < finish; source += 8/2 )
+ if (source[0] & 0x8000) break;
+
+ /* Draw sprites in reverse order for pdrawfgfx */
+
+ source -= 8/2;
+ finish = spriteram16;
+
+ for ( ; source >= finish; source -= 8/2 )
+ {
+ int y = source[0];
+ int code = source[1];
+ int attr = source[2];
+ int x = source[3];
+
+ int flipx = attr & 0x4000;
+ int flipy = attr & 0x8000;
+ int pri = (~attr >> 3) & 0x1; // Priority (1 = Low)
+ int pri_mask = ~((1 << (pri+1)) - 1); // Above the first "pri" levels
+
+ if (x & 0x4000) continue; // ? To get rid of the "shadow" blocks
+
+ x = (x & 0x1ff) - 0x10;
+ y = 0xf0 - ((y & 0xff) - (y & 0x100));
+
+ pdrawgfx( bitmap, machine->gfx[0],
+ code,
+ 0x20 + (attr & 0xf),
+ flipx, flipy,
+ x, y,
+ cliprect, TRANSPARENCY_PEN,0,
+ pri_mask );
+ }
+}
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+VIDEO_UPDATE( blmbycar )
+{
+ int i,layers_ctrl = -1;
+
+ tilemap_set_scrolly( tilemap_0, 0, blmbycar_scroll_0[ 0 ]);
+ tilemap_set_scrollx( tilemap_0, 0, blmbycar_scroll_0[ 1 ]);
+
+ tilemap_set_scrolly( tilemap_1, 0, blmbycar_scroll_1[ 0 ]+1);
+ tilemap_set_scrollx( tilemap_1, 0, blmbycar_scroll_1[ 1 ]+5);
+
+#ifdef MAME_DEBUG
+if (input_code_pressed(KEYCODE_Z))
+{
+ int msk = 0;
+
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+// if (input_code_pressed(KEYCODE_E)) msk |= 4;
+ if (input_code_pressed(KEYCODE_A)) msk |= 8;
+ if (msk != 0) layers_ctrl &= msk;
+}
+#endif
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ if (layers_ctrl&1)
+ for (i = 0; i <= 1; i++)
+ tilemap_draw(bitmap, cliprect, tilemap_0, i, i);
+ else fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ if (layers_ctrl&2)
+ for (i = 0; i <= 1; i++)
+ tilemap_draw(bitmap, cliprect, tilemap_1, i, i);
+
+ if (layers_ctrl&8)
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/blockade.c b/src/mame/video/blockade.c
new file mode 100644
index 00000000000..1ef3e0673e3
--- /dev/null
+++ b/src/mame/video/blockade.c
@@ -0,0 +1,35 @@
+#include "driver.h"
+#include "includes/blockade.h"
+
+static tilemap *bg_tilemap;
+
+WRITE8_HANDLER( blockade_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+
+ if (input_port_3_r(0) & 0x80)
+ {
+ logerror("blockade_videoram_w: scanline %d\n", video_screen_get_vpos(0));
+ cpu_spinuntil_int();
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index];
+
+ SET_TILE_INFO(0, code, 0, 0);
+}
+
+VIDEO_START( blockade )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+VIDEO_UPDATE( blockade )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/blockhl.c b/src/mame/video/blockhl.c
new file mode 100644
index 00000000000..119a8a20fab
--- /dev/null
+++ b/src/mame/video/blockhl.c
@@ -0,0 +1,67 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+
+static int layer_colorbase[3],sprite_colorbase;
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void tile_callback(int layer,int bank,int *code,int *color, int *flags, int *priority)
+{
+ *code |= ((*color & 0x0f) << 8);
+ *color = layer_colorbase[layer] + ((*color & 0xe0) >> 5);
+}
+
+/***************************************************************************
+
+ Callbacks for the K051960
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority,int *shadow)
+{
+ if(*color & 0x10)
+ *priority = 0xfe; // under K052109_tilemap[0]
+ else
+ *priority = 0xfc; // under K052109_tilemap[1]
+
+ *color = sprite_colorbase + (*color & 0x0f);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( blockhl )
+{
+ layer_colorbase[0] = 0;
+ layer_colorbase[1] = 16;
+ layer_colorbase[2] = 32;
+ sprite_colorbase = 48;
+
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,NORMAL_PLANE_ORDER,sprite_callback);
+}
+
+
+VIDEO_UPDATE( blockhl )
+{
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ K052109_tilemap_update();
+
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],0,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],0,2);
+
+ K051960_sprites_draw(bitmap,cliprect,0,-1); // draw sprites with pdrawgfx
+ return 0;
+}
diff --git a/src/mame/video/blockout.c b/src/mame/video/blockout.c
new file mode 100644
index 00000000000..a26e61ba702
--- /dev/null
+++ b/src/mame/video/blockout.c
@@ -0,0 +1,138 @@
+#include "driver.h"
+
+
+
+UINT16 *blockout_videoram;
+UINT16 *blockout_frontvideoram;
+
+
+
+static void setcolor(int color,int rgb)
+{
+ int bit0,bit1,bit2,bit3;
+ int r,g,b;
+
+
+ /* red component */
+ bit0 = (rgb >> 0) & 0x01;
+ bit1 = (rgb >> 1) & 0x01;
+ bit2 = (rgb >> 2) & 0x01;
+ bit3 = (rgb >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ /* green component */
+ bit0 = (rgb >> 4) & 0x01;
+ bit1 = (rgb >> 5) & 0x01;
+ bit2 = (rgb >> 6) & 0x01;
+ bit3 = (rgb >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ /* blue component */
+ bit0 = (rgb >> 8) & 0x01;
+ bit1 = (rgb >> 9) & 0x01;
+ bit2 = (rgb >> 10) & 0x01;
+ bit3 = (rgb >> 11) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(Machine,color,MAKE_RGB(r,g,b));
+}
+
+WRITE16_HANDLER( blockout_paletteram_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ setcolor(offset,paletteram16[offset]);
+}
+
+WRITE16_HANDLER( blockout_frontcolor_w )
+{
+ static UINT16 color;
+
+ COMBINE_DATA(&color);
+ setcolor(512,color);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+VIDEO_START( blockout )
+{
+ /* Allocate temporary bitmaps */
+ tmpbitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+}
+
+
+
+static void updatepixels(int x,int y)
+{
+ UINT16 front,back;
+ int color;
+
+
+ if (x < Machine->screen[0].visarea.min_x ||
+ x > Machine->screen[0].visarea.max_x ||
+ y < Machine->screen[0].visarea.min_y ||
+ y > Machine->screen[0].visarea.max_y)
+ return;
+
+ front = blockout_videoram[y*256+x/2];
+ back = blockout_videoram[0x10000 + y*256+x/2];
+
+ if (front>>8) color = front>>8;
+ else color = (back>>8) + 256;
+ *BITMAP_ADDR16(tmpbitmap, y, x) = Machine->pens[color];
+
+ if (front&0xff) color = front&0xff;
+ else color = (back&0xff) + 256;
+ *BITMAP_ADDR16(tmpbitmap, y, x+1) = Machine->pens[color];
+}
+
+
+
+WRITE16_HANDLER( blockout_videoram_w )
+{
+ UINT16 oldword = blockout_videoram[offset];
+ COMBINE_DATA(&blockout_videoram[offset]);
+
+ if (oldword != blockout_videoram[offset])
+ {
+ updatepixels((offset % 256)*2,(offset / 256) % 256);
+ }
+}
+
+
+
+VIDEO_UPDATE( blockout )
+{
+ copybitmap(bitmap,tmpbitmap,0,0,0,0,cliprect,TRANSPARENCY_NONE,0);
+
+ {
+ int x,y;
+
+ pen_t color = machine->pens[512];
+
+ for (y = 0;y < 256;y++)
+ {
+ for (x = 0;x < 320;x+=8)
+ {
+ int d = blockout_frontvideoram[y*64+(x/8)];
+
+ if (d)
+ {
+ if (d&0x80) *BITMAP_ADDR16(bitmap, y, x+0) = color;
+ if (d&0x40) *BITMAP_ADDR16(bitmap, y, x+1) = color;
+ if (d&0x20) *BITMAP_ADDR16(bitmap, y, x+2) = color;
+ if (d&0x10) *BITMAP_ADDR16(bitmap, y, x+3) = color;
+ if (d&0x08) *BITMAP_ADDR16(bitmap, y, x+4) = color;
+ if (d&0x04) *BITMAP_ADDR16(bitmap, y, x+5) = color;
+ if (d&0x02) *BITMAP_ADDR16(bitmap, y, x+6) = color;
+ if (d&0x01) *BITMAP_ADDR16(bitmap, y, x+7) = color;
+ }
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/bloodbro.c b/src/mame/video/bloodbro.c
new file mode 100644
index 00000000000..814954973bc
--- /dev/null
+++ b/src/mame/video/bloodbro.c
@@ -0,0 +1,278 @@
+/***************************************************************************
+
+ Video Hardware for Blood Brothers
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *bloodbro_txvideoram;
+UINT16 *bloodbro_bgvideoram,*bloodbro_fgvideoram;
+UINT16 *bloodbro_scroll;
+
+static tilemap *bg_tilemap,*fg_tilemap,*tx_tilemap;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = bloodbro_bgvideoram[tile_index];
+ SET_TILE_INFO(
+ 1,
+ code & 0xfff,
+ code >> 12,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = bloodbro_fgvideoram[tile_index];
+ SET_TILE_INFO(
+ 2,
+ code & 0xfff,
+ code >> 12,
+ 0);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int code = bloodbro_txvideoram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ code & 0xfff,
+ code >> 12,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( bloodbro )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,32,16);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,16);
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,15);
+ tilemap_set_transparent_pen(tx_tilemap,15);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( bloodbro_bgvideoram_w )
+{
+ COMBINE_DATA(&bloodbro_bgvideoram[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE16_HANDLER( bloodbro_fgvideoram_w )
+{
+ COMBINE_DATA(&bloodbro_fgvideoram[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE16_HANDLER( bloodbro_txvideoram_w )
+{
+ COMBINE_DATA(&bloodbro_txvideoram[offset]);
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+
+ Blood Bros / Skysmash Spriteram
+ -------------------------------
+
+ Slightly more sophisticated successor to the Toki sprite chip.
+
+ It has "big sprites" created by setting width or height >0. Tile
+ numbers are read consecutively.
+
+ +0 x....... ........ sprite disabled if set
+ +0 .x...... ........ Flip y (no evidence for this!!)
+ +0 ..x..... ........ Flip x
+ +0 ....x... ........ Priority (1=high)
+ +0 ......xx x....... Width: do this many tiles horizontally
+ +0 ........ .xxx.... Height: do this many tiles vertically
+ +0 ........ ....xxxx Color bank
+
+ +1 ...xxxxx xxxxxxxx Tile number
+ +2 .......x xxxxxxxx X coordinate
+ +3 .......x xxxxxxxx Y coordinate
+
+
+ Weststry Bootleg Spriteram
+ --------------------------
+
+ Lacks the "big sprite" feature of the original. Needs some
+ tile number remapping for some reason.
+
+ +0 .......x xxxxxxxx Sprite Y coordinate
+ +1 ...xxxxx xxxxxxxx Sprite tile number
+ +2 xxxx.... ........ Sprite color bank
+ +2 ......x. ........ Sprite flip x
+ +2 ........ x....... Priority ??
+ +3 .......x xxxxxxxx Sprite X coordinate
+
+***************************************************************************/
+
+/* SPRITE INFO (8 bytes)
+
+ D-F?P?SS SSSSCCCC
+ ---TTTTT TTTTTTTT
+ -------X XXXXXXXX
+ -------- YYYYYYYY */
+
+static void bloodbro_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+ for (offs = 0;offs < spriteram_size/2;offs += 4)
+ {
+ int sx,sy,x,y,width,height,attributes,tile_number,color,flipx,flipy,pri_mask;
+
+ attributes = spriteram16[offs+0];
+ if (attributes & 0x8000) continue; /* disabled */
+
+ width = ((attributes>>7)&7);
+ height = ((attributes>>4)&7);
+ pri_mask = (attributes & 0x0800) ? 0x02 : 0;
+ tile_number = spriteram16[offs+1]&0x1fff;
+ sx = spriteram16[offs+2]&0x1ff;
+ sy = spriteram16[offs+3]&0x1ff;
+ if (sx >= 256) sx -= 512;
+ if (sy >= 256) sy -= 512;
+
+ flipx = attributes & 0x2000;
+ flipy = attributes & 0x4000; /* ?? */
+ color = attributes & 0xf;
+
+ for (x = 0;x <= width;x++)
+ {
+ for (y = 0;y <= height;y++)
+ {
+ pdrawgfx(bitmap,machine->gfx[3],
+ tile_number++,
+ color,
+ flipx,flipy,
+ flipx ? (sx + 16*(width-x)) : (sx + 16*x),flipy ? (sy + 16*(height-y)) : (sy + 16*y),
+ cliprect,TRANSPARENCY_PEN,15,
+ pri_mask);
+ }
+ }
+ }
+}
+
+/* SPRITE INFO (8 bytes)
+
+ D------- YYYYYYYY
+ ---TTTTT TTTTTTTT
+ CCCC--F? -?--???? Priority??
+ -------X XXXXXXXX
+*/
+
+static void weststry_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ /* TODO: the last two entries are not sprites - control registers? */
+ for (offs = 0;offs < spriteram_size/2 - 8;offs += 4)
+ {
+ int data = spriteram16[offs+2];
+ int data0 = spriteram16[offs+0];
+ int code = spriteram16[offs+1]&0x1fff;
+ int sx = spriteram16[offs+3]&0x1ff;
+ int sy = 0xf0-(data0&0xff);
+ int flipx = data & 0x200;
+ int flipy = data & 0x400; /* ??? */
+ int color = (data&0xf000)>>12;
+ int pri_mask = (data & 0x0080) ? 0x02 : 0;
+
+ if (sx >= 256) sx -= 512;
+
+ if (data0 & 0x8000) continue; /* disabled */
+
+ /* Remap code 0x800 <-> 0x1000 */
+ code = (code&0x7ff) | ((code&0x800)<<1) | ((code&0x1000)>>1);
+
+ pdrawgfx(bitmap,machine->gfx[3],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15,
+ pri_mask);
+ }
+}
+
+
+
+VIDEO_UPDATE( bloodbro )
+{
+ tilemap_set_scrollx(bg_tilemap,0,bloodbro_scroll[0x10]); /* ? */
+ tilemap_set_scrolly(bg_tilemap,0,bloodbro_scroll[0x11]); /* ? */
+ tilemap_set_scrollx(fg_tilemap,0,bloodbro_scroll[0x12]);
+ tilemap_set_scrolly(fg_tilemap,0,bloodbro_scroll[0x13]);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,1);
+ bloodbro_draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( weststry )
+{
+// tilemap_set_scrollx(bg_tilemap,0,bloodbro_scroll[0x10]); /* ? */
+// tilemap_set_scrolly(bg_tilemap,0,bloodbro_scroll[0x11]); /* ? */
+// tilemap_set_scrollx(fg_tilemap,0,bloodbro_scroll[0x12]);
+// tilemap_set_scrolly(fg_tilemap,0,bloodbro_scroll[0x13]);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,1);
+ weststry_draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( skysmash )
+{
+ tilemap_set_scrollx(bg_tilemap,0,bloodbro_scroll[0x08]);
+ tilemap_set_scrolly(bg_tilemap,0,bloodbro_scroll[0x09]); /* ? */
+ tilemap_set_scrollx(fg_tilemap,0,bloodbro_scroll[0x0a]);
+ tilemap_set_scrolly(fg_tilemap,0,bloodbro_scroll[0x0b]); /* ? */
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,1);
+ bloodbro_draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+
diff --git a/src/mame/video/blstroid.c b/src/mame/video/blstroid.c
new file mode 100644
index 00000000000..ac53febf351
--- /dev/null
+++ b/src/mame/video/blstroid.c
@@ -0,0 +1,180 @@
+/***************************************************************************
+
+ Atari Blasteroids hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "blstroid.h"
+
+
+
+/*************************************
+ *
+ * Globals we own
+ *
+ *************************************/
+
+UINT16 *blstroid_priorityram;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data = atarigen_playfield[tile_index];
+ int code = data & 0x1fff;
+ int color = (data >> 13) & 0x07;
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( blstroid )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 1, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 0, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x000, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0,0,0x0ff8,0 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0,0x3fff,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0,0x000f }}, /* mask for the color */
+ {{ 0,0,0,0xffc0 }}, /* mask for the X position */
+ {{ 0xff80,0,0,0 }}, /* mask for the Y position */
+ {{ 0 }}, /* mask for the width, in tiles*/
+ {{ 0x000f,0,0,0 }}, /* mask for the height, in tiles */
+ {{ 0,0x8000,0,0 }}, /* mask for the horizontal flip */
+ {{ 0,0x4000,0,0 }}, /* mask for the vertical flip */
+ {{ 0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0 /* callback routine for special entries */
+ };
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,8, 64,64);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+}
+
+
+
+/*************************************
+ *
+ * Periodic scanline updater
+ *
+ *************************************/
+
+static TIMER_CALLBACK( irq_off )
+{
+ /* clear the interrupt */
+ atarigen_scanline_int_ack_w(0, 0, 0);
+}
+
+
+static TIMER_CALLBACK( irq_on )
+{
+ /* generate the interrupt */
+ atarigen_scanline_int_gen();
+ atarigen_update_interrupts();
+}
+
+
+void blstroid_scanline_update(running_machine *machine, int scrnum, int scanline)
+{
+ int offset = (scanline / 8) * 64 + 40;
+
+ /* check for interrupts */
+ if (offset < 0x1000)
+ if (atarigen_playfield[offset] & 0x8000)
+ {
+ attotime period_on;
+ attotime period_off;
+
+ /* fix me - the only thing this IRQ does it tweak the starting MO link */
+ /* unfortunately, it does it too early for the given MOs! */
+ /* perhaps it is not actually hooked up on the real PCB... */
+ return;
+
+ /* set a timer to turn the interrupt on at HBLANK of the 7th scanline */
+ /* and another to turn it off one scanline later */
+ period_on = video_screen_get_time_until_pos(scrnum, video_screen_get_vpos(scrnum) + 7, machine->screen[scrnum].width * 0.9);
+ period_off = video_screen_get_time_until_pos(scrnum, video_screen_get_vpos(scrnum) + 8, machine->screen[scrnum].width * 0.9);
+
+ timer_set(period_on, 0, irq_on);
+ timer_set(period_off, 0, irq_off);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( blstroid )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* verified via schematics
+
+ priority address = HPPPMMMM
+ */
+ int priaddr = ((pf[x] & 8) << 4) | (pf[x] & 0x70) | ((mo[x] & 0xf0) >> 4);
+ if (blstroid_priorityram[priaddr] & 1)
+ pf[x] = mo[x];
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/blueprnt.c b/src/mame/video/blueprnt.c
new file mode 100644
index 00000000000..4ecb540fce5
--- /dev/null
+++ b/src/mame/video/blueprnt.c
@@ -0,0 +1,133 @@
+#include "driver.h"
+
+UINT8 *blueprnt_scrollram;
+static int gfx_bank;
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Blue Print doesn't have color PROMs. For sprites, the ROM data is directly
+ converted into colors; for characters, it is converted through the color
+ code (bits 0-2 = RBG for 01 pixels, bits 3-5 = RBG for 10 pixels, 00 pixels
+ always black, 11 pixels use the OR of bits 0-2 and 3-5. Bit 6 is intensity
+ control)
+
+***************************************************************************/
+
+PALETTE_INIT( blueprnt )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < 16;i++)
+ {
+ int r = ((i >> 0) & 1) * ((i & 0x08) ? 0xbf : 0xff);
+ int g = ((i >> 2) & 1) * ((i & 0x08) ? 0xbf : 0xff);
+ int b = ((i >> 1) & 1) * ((i & 0x08) ? 0xbf : 0xff);
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ /* chars */
+ for (i = 0;i < 128;i++)
+ {
+ int base = (i & 0x40) ? 8 : 0;
+ COLOR(0,4*i+0) = base + 0;
+ COLOR(0,4*i+1) = base + ((i >> 0) & 7);
+ COLOR(0,4*i+2) = base + ((i >> 3) & 7);
+ COLOR(0,4*i+3) = base + (((i >> 0) & 7) | ((i >> 3) & 7));
+ }
+
+ /* sprites */
+ for (i = 0;i < 8;i++)
+ COLOR(1,i) = i;
+}
+
+WRITE8_HANDLER( blueprnt_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( blueprnt_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( blueprnt_flipscreen_w )
+{
+ flip_screen_set(~data & 0x02);
+
+ if (gfx_bank != ((data & 0x04) >> 2))
+ {
+ gfx_bank = ((data & 0x04) >> 2);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + 256 * gfx_bank;
+ int color = attr & 0x7f;
+
+ tileinfo->category = (attr & 0x80) ? 1 : 0;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( blueprnt )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols_flip_x,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(bg_tilemap, 0);
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = 0; offs < spriteram_size; offs += 4)
+ {
+ int code = spriteram[offs + 1];
+ int sx = spriteram[offs + 3];
+ int sy = 240 - spriteram[offs];
+ int flipx = spriteram[offs + 2] & 0x40;
+ int flipy = spriteram[offs + 2 - 4] & 0x80; // -4? Awkward, isn't it?
+
+ if (flip_screen)
+ {
+ sx = 248 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ // sprites are slightly misplaced, regardless of the screen flip
+ drawgfx(bitmap, machine->gfx[1], code, 0, flipx, flipy, 2+sx, sy-1,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( blueprnt )
+{
+ int i;
+
+ if (flip_screen)
+ for (i = 0; i < 32; i++)
+ tilemap_set_scrolly(bg_tilemap, i, blueprnt_scrollram[32 - i]);
+ else
+ for (i = 0; i < 32; i++)
+ tilemap_set_scrolly(bg_tilemap, i, blueprnt_scrollram[30 - i]);
+
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine,bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 1, 0);
+ return 0;
+}
diff --git a/src/mame/video/bogeyman.c b/src/mame/video/bogeyman.c
new file mode 100644
index 00000000000..a649518219c
--- /dev/null
+++ b/src/mame/video/bogeyman.c
@@ -0,0 +1,155 @@
+#include "driver.h"
+
+UINT8 *bogeyman_videoram2, *bogeyman_colorram2;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+PALETTE_INIT( bogeyman )
+{
+ int i;
+
+ /* first 16 colors are RAM */
+
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* green component */
+ bit0 = (color_prom[0] >> 3) & 0x01;
+ bit1 = (color_prom[256] >> 0) & 0x01;
+ bit2 = (color_prom[256] >> 1) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* blue component */
+ bit0 = 0;
+ bit1 = (color_prom[256] >> 2) & 0x01;
+ bit2 = (color_prom[256] >> 3) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i+16,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( bogeyman_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( bogeyman_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( bogeyman_videoram2_w )
+{
+ bogeyman_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( bogeyman_colorram2_w )
+{
+ bogeyman_colorram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( bogeyman_paletteram_w )
+{
+ /* RGB output is inverted */
+ paletteram_BBGGGRRR_w(offset, ~data);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int gfxbank = ((((attr & 0x01) << 8) + videoram[tile_index]) / 0x80) + 3;
+ int code = videoram[tile_index] & 0x7f;
+ int color = (attr >> 1) & 0x07;
+
+ SET_TILE_INFO(gfxbank, code, color, 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = bogeyman_colorram2[tile_index];
+ int tile = bogeyman_videoram2[tile_index] | ((attr & 0x03) << 8);
+ int gfxbank = tile / 0x200;
+ int code = tile & 0x1ff;
+
+ SET_TILE_INFO(gfxbank, code, 0, 0);
+}
+
+VIDEO_START( bogeyman )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16, 16, 16, 16);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0; offs < spriteram_size; offs += 4)
+ {
+ int attr = spriteram[offs];
+
+ if (attr & 0x01)
+ {
+ int code = spriteram[offs + 1] + ((attr & 0x40) << 2);
+ int color = (attr & 0x08) >> 3;
+ int flipx = !(attr & 0x04);
+ int flipy = attr & 0x02;
+ int sx = spriteram[offs + 3];
+ int sy = (240 - spriteram[offs + 2]) & 0xff;
+ int multi = attr & 0x10;
+
+ if (multi) sy -= 16;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[2],
+ code, color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+
+ if (multi)
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ code + 1, color,
+ flipx, flipy,
+ sx, sy + (flip_screen ? -16 : 16),
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( bogeyman )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/bombjack.c b/src/mame/video/bombjack.c
new file mode 100644
index 00000000000..11d8e07d072
--- /dev/null
+++ b/src/mame/video/bombjack.c
@@ -0,0 +1,140 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static UINT8 background_image;
+
+static tilemap *fg_tilemap, *bg_tilemap;
+
+WRITE8_HANDLER( bombjack_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( bombjack_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( bombjack_background_w )
+{
+ if (background_image != data)
+ {
+ background_image = data;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+WRITE8_HANDLER( bombjack_flipscreen_w )
+{
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 *tilerom = memory_region(REGION_GFX4);
+
+ int offs = (background_image & 0x07) * 0x200 + tile_index;
+ int code = (background_image & 0x10) ? tilerom[offs] : 0;
+ int attr = tilerom[offs + 0x100];
+ int color = attr & 0x0f;
+ int flags = (attr & 0x80) ? TILE_FLIPY : 0;
+
+ SET_TILE_INFO(1, code, color, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = videoram[tile_index] + 16 * (colorram[tile_index] & 0x10);
+ int color = colorram[tile_index] & 0x0f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( bombjack )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16, 16, 16, 16);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+
+ state_save_register_global(background_image);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 4; offs >= 0; offs -= 4)
+ {
+
+/*
+ abbbbbbb cdefgggg hhhhhhhh iiiiiiii
+
+ a use big sprites (32x32 instead of 16x16)
+ bbbbbbb sprite code
+ c x flip
+ d y flip (used only in death sequence?)
+ e ? (set when big sprites are selected)
+ f ? (set only when the bonus (B) materializes?)
+ gggg color
+ hhhhhhhh x position
+ iiiiiiii y position
+*/
+ int sx,sy,flipx,flipy;
+
+
+ sx = spriteram[offs+3];
+ if (spriteram[offs] & 0x80)
+ sy = 225-spriteram[offs+2];
+ else
+ sy = 241-spriteram[offs+2];
+ flipx = spriteram[offs+1] & 0x40;
+ flipy = spriteram[offs+1] & 0x80;
+ if (flip_screen)
+ {
+ if (spriteram[offs+1] & 0x20)
+ {
+ sx = 224 - sx;
+ sy = 224 - sy;
+ }
+ else
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ }
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[(spriteram[offs] & 0x80) ? 3 : 2],
+ spriteram[offs] & 0x7f,
+ spriteram[offs+1] & 0x0f,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( bombjack )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/boogwing.c b/src/mame/video/boogwing.c
new file mode 100644
index 00000000000..ae21009f1a2
--- /dev/null
+++ b/src/mame/video/boogwing.c
@@ -0,0 +1,203 @@
+#include "driver.h"
+#include "deco16ic.h"
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect, UINT16* spriteram_base, int gfx_region)
+{
+ int offs;
+ int flipscreen=!flip_screen;
+
+ for (offs = 0x400-4;offs >= 0;offs -= 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult,pri=0,spri=0;
+ int trans=TRANSPARENCY_PEN;
+
+ sprite = spriteram_base[offs+1];
+ if (!sprite) continue;
+
+ y = spriteram_base[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ x = spriteram_base[offs+2];
+ colour = (x >>9) & 0x1f;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ // Todo: This should be verified from the prom
+ if (gfx_region==4)
+ {
+ // Sprite 2 priority vs sprite 1
+ if ((spriteram_base[offs+2]&0xc000)==0xc000)
+ spri=4;
+ else if ((spriteram_base[offs+2]&0xc000))
+ spri=16;
+ else
+ spri=64;
+
+ // Transparency
+ if (spriteram_base[offs+2]&0x2000)
+ trans=TRANSPARENCY_ALPHA;
+
+ if (deco16_priority==0x2)
+ {
+ // Additional sprite alpha in this mode
+ if (spriteram_base[offs+2]&0x8000)
+ trans=TRANSPARENCY_ALPHA;
+
+ // Sprite vs playfield
+ if ((spriteram_base[offs+2]&0xc000)==0xc000)
+ pri=4;
+ else if ((spriteram_base[offs+2]&0xc000)==0x8000)
+ pri=16;
+ else
+ pri=64;
+ }
+ else
+ {
+ if ((spriteram_base[offs+2]&0x8000)==0x8000)
+ pri=16;
+ else
+ pri=64;
+ }
+ }
+ else
+ {
+ // Sprite 1 priority vs sprite 2
+ if (spriteram_base[offs+2]&0x8000) // todo - check only in pri mode 2??
+ spri=8;
+ else
+ spri=32;
+
+ // Sprite vs playfield
+ if (deco16_priority==0x1)
+ {
+ if ((spriteram_base[offs+2]&0xc000))
+ pri=16;
+ else
+ pri=64;
+ }
+ else
+ {
+ if ((spriteram_base[offs+2]&0xc000)==0xc000)
+ pri=4;
+ else if ((spriteram_base[offs+2]&0xc000)==0x8000)
+ pri=16;
+ else
+ pri=64;
+ }
+ }
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+ y = 240 - y;
+ x = 304 - x;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flipscreen)
+ {
+ y=240-y;
+ x=304-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ deco16_pdrawgfx(bitmap,machine->gfx[gfx_region],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,trans, 0, pri, spri, 0);
+
+ multi--;
+ }
+ }
+}
+
+static int boogwing_bank_callback(const int bank)
+{
+ return ((bank>>4) & 0x7) * 0x1000;
+}
+
+static int boogwing_bank_callback2(const int bank)
+{
+ int offset=((bank>>4) & 0x7) * 0x1000;
+ if ((bank&0xf)==0xa)
+ offset+=0x800; // strange - transporter level
+ return offset;
+}
+
+VIDEO_START(boogwing)
+{
+ deco16_2_video_init(0);
+
+ deco16_set_tilemap_bank_callback(1,boogwing_bank_callback);
+ deco16_set_tilemap_bank_callback(2,boogwing_bank_callback2);
+ deco16_set_tilemap_bank_callback(3,boogwing_bank_callback2);
+ deco16_set_tilemap_colour_base(1,0);
+ deco16_set_tilemap_transparency_mask(1, 0x1f); // 5bpp graphics
+
+ alpha_set_level(0x80);
+}
+
+VIDEO_UPDATE(boogwing)
+{
+ flip_screen_set( deco16_pf12_control[0]&0x80 );
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+ deco16_pf34_update(deco16_pf3_rowscroll,deco16_pf4_rowscroll);
+
+ /* Draw playfields */
+ deco16_clear_sprite_priority_bitmap();
+ fillbitmap(bitmap,machine->pens[0x400],cliprect); /* pen not confirmed */
+ fillbitmap(priority_bitmap,0,NULL);
+
+ // bit&0x8 is definitely some kind of palette effect
+ // bit&0x4 combines playfields
+ if ((deco16_priority&0x7)==0x5)
+ {
+ deco16_tilemap_2_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ deco16_tilemap_34_combine_draw(bitmap,cliprect,0,32);
+ }
+ else if ((deco16_priority&0x7)==0x1 || (deco16_priority&0x7)==0x2)
+ {
+ deco16_tilemap_4_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,8);
+ deco16_tilemap_3_draw(bitmap,cliprect,0,32);
+ }
+ else if ((deco16_priority&0x7)==0x3)
+ {
+ deco16_tilemap_4_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,8);
+
+ // This mode uses playfield 3 to shadow sprites & playfield 2 (instead of
+ // regular alpha-blending, the destination is inverted). Not yet implemented.
+// deco16_tilemap_3_draw(bitmap,cliprect,TILEMAP_DRAW_ALPHA,32);
+ }
+ else
+ {
+ deco16_tilemap_4_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ deco16_tilemap_3_draw(bitmap,cliprect,0,8);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,32);
+ }
+
+ draw_sprites(machine, bitmap, cliprect, buffered_spriteram16, 3);
+ draw_sprites(machine, bitmap, cliprect, buffered_spriteram16_2, 4);
+
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+ return 0;
+}
diff --git a/src/mame/video/bosco.c b/src/mame/video/bosco.c
new file mode 100644
index 00000000000..c9ecab69210
--- /dev/null
+++ b/src/mame/video/bosco.c
@@ -0,0 +1,338 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/galaga.h"
+
+
+#define MAX_STARS 252
+#define STARS_COLOR_BASE (64*4+64*4+4)
+
+static UINT32 stars_scrollx;
+static UINT32 stars_scrolly;
+
+static INT32 bosco_starcontrol,bosco_starblink[2];
+
+static tilemap *bg_tilemap,*fg_tilemap;
+
+#define VIDEO_RAM_SIZE 0x400
+
+UINT8 *bosco_videoram;
+UINT8 *bosco_radarattr;
+static UINT8 *bosco_radarx,*bosco_radary;
+
+static colortable *bosco_colortable;
+
+
+PALETTE_INIT( bosco )
+{
+ int i;
+
+ bosco_colortable = colortable_alloc(machine, 32+64);
+
+ /* core palette */
+ for (i = 0;i < 32;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ bit0 = ((*color_prom) >> 0) & 0x01;
+ bit1 = ((*color_prom) >> 1) & 0x01;
+ bit2 = ((*color_prom) >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = ((*color_prom) >> 3) & 0x01;
+ bit1 = ((*color_prom) >> 4) & 0x01;
+ bit2 = ((*color_prom) >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = 0;
+ bit1 = ((*color_prom) >> 6) & 0x01;
+ bit2 = ((*color_prom) >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ colortable_palette_set_color(bosco_colortable,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* palette for the stars */
+ for (i = 0;i < 64;i++)
+ {
+ int bits,r,g,b;
+ static const int map[4] = { 0x00, 0x47, 0x97 ,0xde };
+
+ bits = (i >> 0) & 0x03;
+ r = map[bits];
+ bits = (i >> 2) & 0x03;
+ g = map[bits];
+ bits = (i >> 4) & 0x03;
+ b = map[bits];
+
+ colortable_palette_set_color(bosco_colortable,32 + i,MAKE_RGB(r,g,b));
+ }
+
+ /* characters / sprites */
+ for (i = 0;i < 64*4;i++)
+ {
+ colortable_entry_set_value(bosco_colortable, i, (color_prom[i] & 0x0f) + 0x10); /* chars */
+ colortable_entry_set_value(bosco_colortable, i+64*4, color_prom[i] & 0x0f); /* sprites */
+ }
+
+ /* bullets lookup table */
+ /* they use colors 28-31, I think - PAL 5A controls it */
+ for (i = 0;i < 4;i++)
+ colortable_entry_set_value(bosco_colortable, 64*4+64*4+i, 31-i);
+
+ /* now the stars */
+ for (i = 0;i < 64;i++)
+ colortable_entry_set_value(bosco_colortable, 64*4+64*4+4+i, 32 + i);
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/* the video RAM has space for 32x32 tiles and is only partially used for the radar */
+static TILEMAP_MAPPER( fg_tilemap_scan )
+{
+ return col + (row << 5);
+}
+
+
+INLINE void get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int ram_offs)
+{
+ UINT8 attr = bosco_videoram[ram_offs + tile_index + 0x800];
+ tileinfo->category = (attr & 0x20) >> 5;
+ tileinfo->group = attr & 0x3f;
+ SET_TILE_INFO(
+ 0,
+ bosco_videoram[ram_offs + tile_index],
+ attr & 0x3f,
+ TILE_FLIPYX(attr >> 6) ^ TILE_FLIPX);
+}
+
+static TILE_GET_INFO( bg_get_tile_info )
+{
+ get_tile_info(machine,tileinfo,tile_index,0x400);
+}
+
+static TILE_GET_INFO( fg_get_tile_info )
+{
+ get_tile_info(machine,tileinfo,tile_index,0x000);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( bosco )
+{
+ bg_tilemap = tilemap_create(bg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ fg_tilemap = tilemap_create(fg_get_tile_info,fg_tilemap_scan, TILEMAP_TYPE_PEN,8,8, 8,32);
+
+ colortable_configure_tilemap_groups(bosco_colortable, bg_tilemap, machine->gfx[0], 0x1f);
+ colortable_configure_tilemap_groups(bosco_colortable, fg_tilemap, machine->gfx[0], 0x1f);
+
+ tilemap_set_scrolldx(bg_tilemap,3,3);
+
+ spriteram_size = 0x0c;
+ spriteram = bosco_videoram + 0x03d4;
+ spriteram_2 = spriteram + 0x0800;
+ bosco_radarx = bosco_videoram + 0x03f0;
+ bosco_radary = bosco_radarx + 0x0800;
+
+
+ state_save_register_global(stars_scrollx);
+ state_save_register_global(stars_scrolly);
+ state_save_register_global(bosco_starcontrol);
+ state_save_register_global_array(bosco_starblink);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ8_HANDLER( bosco_videoram_r )
+{
+ return bosco_videoram[offset];
+}
+
+WRITE8_HANDLER( bosco_videoram_w )
+{
+ bosco_videoram[offset] = data;
+ if (offset & 0x400)
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+ else
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( bosco_scrollx_w )
+{
+ tilemap_set_scrollx(bg_tilemap,0,data);
+}
+
+WRITE8_HANDLER( bosco_scrolly_w )
+{
+ tilemap_set_scrolly(bg_tilemap,0,data);
+}
+
+WRITE8_HANDLER( bosco_starcontrol_w )
+{
+ bosco_starcontrol = data;
+}
+
+WRITE8_HANDLER( bosco_starblink_w )
+{
+ bosco_starblink[offset] = data & 1;
+}
+
+WRITE8_HANDLER( bosco_starclr_w )
+{
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 2)
+ {
+ int sx = spriteram[offs + 1] - 1;
+ int sy = 240 - spriteram_2[offs];
+ int flipx = spriteram[offs] & 1;
+ int flipy = spriteram[offs] & 2;
+ int color = spriteram_2[offs + 1] & 0x3f;
+ if (flip_screen) sx += 32-2;
+
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs] & 0xfc) >> 2,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PENS,
+ colortable_get_transpen_mask(bosco_colortable, machine->gfx[1], color, 0x0f));
+ }
+}
+
+
+static void draw_bullets(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = 4; offs < 0x10;offs++)
+ {
+ int x,y;
+
+ x = bosco_radarx[offs] + ((~bosco_radarattr[offs] & 0x01) << 8);
+ y = 253 - bosco_radary[offs];
+ if (flip_screen) x -= 3;
+
+ drawgfx(bitmap,machine->gfx[2],
+ ((bosco_radarattr[offs] & 0x0e) >> 1) ^ 0x07,
+ 0,
+ 0,0,
+ x,y,
+ cliprect,TRANSPARENCY_PENS,0xf0);
+ }
+}
+
+
+static void draw_stars(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ if (1)
+ {
+ int star_cntr;
+ int set_a, set_b;
+
+ /* two sets of stars controlled by these bits */
+ set_a = bosco_starblink[0];
+ set_b = bosco_starblink[1] |0x2;
+
+ for (star_cntr = 0;star_cntr < MAX_STARS;star_cntr++)
+ {
+ int x,y;
+
+ if ( (set_a == star_seed_tab[star_cntr].set) || ( set_b == star_seed_tab[star_cntr].set) )
+ {
+ x = ( star_seed_tab[star_cntr].x + stars_scrollx) % 256;
+ y = ( star_seed_tab[star_cntr].y + stars_scrolly) % 256;
+
+ /* dont draw the stars that are off the screen */
+ if ( x < 224 && y < 224 )
+ {
+ if (flip_screen) x += 64;
+
+ if (y >= machine->screen[0].visarea.min_y && y <= machine->screen[0].visarea.max_y)
+ *BITMAP_ADDR16(bitmap, y, x) = STARS_COLOR_BASE + star_seed_tab[star_cntr].col;
+ }
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( bosco )
+{
+ /* the radar tilemap is just 8x32. We rely on the tilemap code to repeat it across
+ the screen, and clip it to only the position where it is supposed to be shown */
+ rectangle fg_clip = *cliprect;
+ rectangle bg_clip = *cliprect;
+ if (flip_screen)
+ {
+ bg_clip.min_x = 8*8;
+ fg_clip.max_x = 8*8-1;
+ }
+ else
+ {
+ bg_clip.max_x = 28*8-1;
+ fg_clip.min_x = 28*8;
+ }
+
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ draw_stars(machine, bitmap,cliprect);
+
+ tilemap_draw(bitmap,&bg_clip,bg_tilemap,0,0);
+ tilemap_draw(bitmap,&fg_clip,fg_tilemap,0,0);
+
+ draw_sprites(machine, bitmap,cliprect);
+
+ /* draw the high priority characters */
+ tilemap_draw(bitmap,&bg_clip,bg_tilemap,1,0);
+ tilemap_draw(bitmap,&fg_clip,fg_tilemap,1,0);
+
+ draw_bullets(machine, bitmap,cliprect);
+
+ return 0;
+}
+
+
+VIDEO_EOF( bosco )
+{
+ static const int speedsx[8] = { -1, -2, -3, 0, 3, 2, 1, 0 };
+ static const int speedsy[8] = { 0, -1, -2, -3, 0, 3, 2, 1 };
+
+ stars_scrollx += speedsx[bosco_starcontrol & 0x07];
+ stars_scrolly += speedsy[(bosco_starcontrol & 0x38) >> 3];
+}
diff --git a/src/mame/video/bottom9.c b/src/mame/video/bottom9.c
new file mode 100644
index 00000000000..5e4e4ece206
--- /dev/null
+++ b/src/mame/video/bottom9.c
@@ -0,0 +1,97 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+
+int bottom9_video_enable;
+
+static int layer_colorbase[3],sprite_colorbase,zoom_colorbase;
+
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ *code |= (*color & 0x3f) << 8;
+ *color = layer_colorbase[layer] + ((*color & 0xc0) >> 6);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051960
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority,int *shadow)
+{
+ /* bit 4 = priority over zoom (0 = have priority) */
+ /* bit 5 = priority over B (1 = have priority) */
+ *priority = (*color & 0x30) >> 4;
+ *color = sprite_colorbase + (*color & 0x0f);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051316
+
+***************************************************************************/
+
+static void zoom_callback(int *code,int *color,int *flags)
+{
+ *flags = (*color & 0x40) ? TILE_FLIPX : 0;
+ *code |= ((*color & 0x03) << 8);
+ *color = zoom_colorbase + ((*color & 0x3c) >> 2);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( bottom9 )
+{
+ layer_colorbase[0] = 0; /* not used */
+ layer_colorbase[1] = 0;
+ layer_colorbase[2] = 16;
+ sprite_colorbase = 32;
+ zoom_colorbase = 48;
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,NORMAL_PLANE_ORDER,sprite_callback);
+ K051316_vh_start_0(machine,REGION_GFX3,4,FALSE,0,zoom_callback);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( bottom9 )
+{
+ K052109_tilemap_update();
+
+ /* note: FIX layer is not used */
+ fillbitmap(bitmap,machine->pens[layer_colorbase[1]],cliprect);
+// if (bottom9_video_enable)
+ {
+ K051960_sprites_draw(bitmap,cliprect,1,1);
+ K051316_zoom_draw_0(bitmap,cliprect,0,0);
+ K051960_sprites_draw(bitmap,cliprect,0,0);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],0,0);
+ /* note that priority 3 is opposite to the basic layer priority! */
+ /* (it IS used, but hopefully has no effect) */
+ K051960_sprites_draw(bitmap,cliprect,2,3);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],0,0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/boxer.c b/src/mame/video/boxer.c
new file mode 100644
index 00000000000..ef1dd57d55a
--- /dev/null
+++ b/src/mame/video/boxer.c
@@ -0,0 +1,89 @@
+/***************************************************************************
+
+Atari Boxer (prototype) video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8* boxer_tile_ram;
+UINT8* boxer_sprite_ram;
+
+
+static void draw_boxer(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ int n;
+
+ for (n = 0; n < 2; n++)
+ {
+ const UINT8* p = memory_region(n == 0 ? REGION_USER1 : REGION_USER2);
+
+ int i;
+ int j;
+
+ int x = 196 - boxer_sprite_ram[0 + 2 * n];
+ int y = 192 - boxer_sprite_ram[1 + 2 * n];
+
+ int l = boxer_sprite_ram[4 + 2 * n] & 15;
+ int r = boxer_sprite_ram[5 + 2 * n] & 15;
+
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 4; j++)
+ {
+ UINT8 code;
+
+ code = p[32 * l + 4 * i + j];
+
+ drawgfx(bitmap, machine->gfx[n],
+ code,
+ 0,
+ code & 0x80, 0,
+ x + 8 * j,
+ y + 8 * i,
+ cliprect,
+ TRANSPARENCY_PEN, 1);
+
+ code = p[32 * r + 4 * i - j + 3];
+
+ drawgfx(bitmap, machine->gfx[n],
+ code,
+ 0,
+ !(code & 0x80), 0,
+ x + 8 * j + 32,
+ y + 8 * i,
+ cliprect,
+ TRANSPARENCY_PEN, 1);
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( boxer )
+{
+ int i;
+ int j;
+
+ fillbitmap(bitmap, 1, cliprect);
+
+ for (i = 0; i < 16; i++)
+ {
+ for (j = 0; j < 32; j++)
+ {
+ UINT8 code = boxer_tile_ram[32 * i + j];
+
+ drawgfx(bitmap, machine->gfx[2],
+ code,
+ 0,
+ code & 0x40, code & 0x40,
+ 8 * j + 4,
+ 8 * (i % 2) + 32 * (i / 2),
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+ }
+
+ draw_boxer(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/brkthru.c b/src/mame/video/brkthru.c
new file mode 100644
index 00000000000..71334d23ad5
--- /dev/null
+++ b/src/mame/video/brkthru.c
@@ -0,0 +1,283 @@
+/***************************************************************************
+
+ breakthru:video.c
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+//UINT8 *brkthru_scroll;
+UINT8 *brkthru_videoram;
+size_t brkthru_videoram_size;
+static int bgscroll;
+static int bgbasecolor;
+static int flipscreen;
+
+static tilemap *fg_tilemap;
+static tilemap *bg_tilemap;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Break Thru has one 256x8 and one 256x4 palette PROMs.
+ I don't know for sure how the palette PROMs are connected to the RGB
+ output, but it's probably the usual:
+
+ bit 7 -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 2.2kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ -- 1 kohm resistor -- RED
+ bit 0 -- 2.2kohm resistor -- RED
+
+ bit 3 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 1 kohm resistor -- BLUE
+ bit 0 -- 2.2kohm resistor -- BLUE
+
+***************************************************************************/
+PALETTE_INIT( brkthru )
+{
+ int i;
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[0] >> 4) & 0x01;
+ bit1 = (color_prom[0] >> 5) & 0x01;
+ bit2 = (color_prom[0] >> 6) & 0x01;
+ bit3 = (color_prom[0] >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ /* BG RAM format
+ 0 1
+ ---- -c-- ---- ---- = Color
+ ---- --xx xxxx xxxx = Code
+ */
+
+ int code = (videoram[tile_index*2] | ((videoram[tile_index*2+1]) << 8)) & 0x3ff;
+ int region = 1 + (code >> 7);
+ int colour = bgbasecolor + ((videoram[tile_index*2+1] & 0x04) >> 2);
+
+ SET_TILE_INFO(region, code & 0x7f,colour,0);
+}
+
+WRITE8_HANDLER( brkthru_bgram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 code = brkthru_videoram[tile_index];
+ SET_TILE_INFO(0, code, 0, 0);
+}
+
+WRITE8_HANDLER( brkthru_fgram_w )
+{
+ brkthru_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+VIDEO_START( brkthru )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,32,16);
+
+ tilemap_set_transparent_pen( fg_tilemap, 0 );
+ tilemap_set_transparent_pen( bg_tilemap, 0 );
+}
+
+
+
+WRITE8_HANDLER( brkthru_1800_w )
+{
+ if (offset == 0) /* low 8 bits of scroll */
+ bgscroll = (bgscroll & 0x100) | data;
+ else if (offset == 1)
+ {
+ int bankaddress;
+ UINT8 *RAM = memory_region(REGION_CPU1);
+
+
+ /* bit 0-2 = ROM bank select */
+ bankaddress = 0x10000 + (data & 0x07) * 0x2000;
+ memory_set_bankptr(1,&RAM[bankaddress]);
+
+ /* bit 3-5 = background tiles color code */
+ if (((data & 0x38) >> 2) != bgbasecolor)
+ {
+ bgbasecolor = (data & 0x38) >> 2;
+ tilemap_mark_all_tiles_dirty (bg_tilemap);
+ }
+
+ /* bit 6 = screen flip */
+ if (flipscreen != (data & 0x40))
+ {
+ flipscreen = data & 0x40;
+ tilemap_set_flip(bg_tilemap,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ tilemap_set_flip(fg_tilemap,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ }
+
+ /* bit 7 = high bit of scroll */
+ bgscroll = (bgscroll & 0xff) | ((data & 0x80) << 1);
+ }
+}
+
+
+#if 0
+static void show_register( mame_bitmap *bitmap, int x, int y, UINT32 data )
+{
+ char buf[5];
+
+ sprintf(buf, "%04X", data);
+ ui_draw_text(y, x, buf);
+}
+#endif
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int prio )
+{
+ int offs;
+ /* Draw the sprites. Note that it is important to draw them exactly in this */
+ /* order, to have the correct priorities. */
+
+ /* Sprite RAM format
+ 0 1 2 3
+ ccc- ---- ---- ---- ---- ---- ---- ---- = Color
+ ---d ---- ---- ---- ---- ---- ---- ---- = Double Size
+ ---- p--- ---- ---- ---- ---- ---- ---- = Priority
+ ---- -bb- ---- ---- ---- ---- ---- ---- = Bank
+ ---- ---e ---- ---- ---- ---- ---- ---- = Enable/Disable
+ ---- ---- ssss ssss ---- ---- ---- ---- = Sprite code
+ ---- ---- ---- ---- yyyy yyyy ---- ---- = Y position
+ ---- ---- ---- ---- ---- ---- xxxx xxxx = X position
+ */
+
+ for (offs = 0;offs < spriteram_size; offs += 4)
+ {
+ if ((spriteram[offs] & 0x09) == prio) /* Enable && Low Priority */
+ {
+ int sx,sy,code,color;
+
+ sx = 240 - spriteram[offs+3];
+ if (sx < -7) sx += 256;
+ sy = 240 - spriteram[offs+2];
+ code = spriteram[offs+1] + 128 * (spriteram[offs] & 0x06);
+ color = (spriteram[offs] & 0xe0) >> 5;
+ if (flipscreen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ }
+
+ if (spriteram[offs] & 0x10) /* double height */
+ {
+ drawgfx(bitmap,machine->gfx[9],
+ code & ~1,
+ color,
+ flipscreen,flipscreen,
+ sx,flipscreen? sy + 16 : sy - 16,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[9],
+ code | 1,
+ color,
+ flipscreen,flipscreen,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ /* redraw with wraparound */
+ drawgfx(bitmap,machine->gfx[9],
+ code & ~1,
+ color,
+ flipscreen,flipscreen,
+ sx,(flipscreen? sy + 16 : sy - 16) + 256,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[9],
+ code | 1,
+ color,
+ flipscreen,flipscreen,
+ sx,sy + 256,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ }
+ else
+ {
+ drawgfx(bitmap,machine->gfx[9],
+ code,
+ color,
+ flipscreen,flipscreen,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ /* redraw with wraparound */
+ drawgfx(bitmap,machine->gfx[9],
+ code,
+ color,
+ flipscreen,flipscreen,
+ sx,sy + 256,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ }
+ }
+ }
+ }
+
+VIDEO_UPDATE( brkthru )
+ {
+ tilemap_set_scrollx(bg_tilemap,0, bgscroll);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_OPAQUE,0);
+
+ /* low priority sprites */
+ draw_sprites(machine, bitmap, cliprect, 0x01 );
+
+ /* draw background over low priority sprites */
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ /* high priority sprites */
+ draw_sprites(machine, bitmap, cliprect, 0x09 );
+
+ /* fg layer */
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+
+/* show_register(bitmap,8,8,(UINT32)flipscreen); */
+
+ return 0;
+}
diff --git a/src/mame/video/bsktball.c b/src/mame/video/bsktball.c
new file mode 100644
index 00000000000..a2d2c41da5d
--- /dev/null
+++ b/src/mame/video/bsktball.c
@@ -0,0 +1,63 @@
+/***************************************************************************
+
+ Atari Basketball hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "bsktball.h"
+
+UINT8 *bsktball_motion;
+
+static tilemap *bg_tilemap;
+
+WRITE8_HANDLER( bsktball_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = videoram[tile_index];
+ int code = ((attr & 0x0f) << 2) | ((attr & 0x30) >> 4);
+ int color = (attr & 0x40) >> 6;
+ int flags = (attr & 0x80) ? TILE_FLIPX : 0;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( bsktball )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int motion;
+
+ for (motion=0;motion<16;motion++)
+ {
+ int pic = bsktball_motion[motion*4];
+ int sy = 28*8 - bsktball_motion[motion*4 + 1];
+ int sx = bsktball_motion[motion*4 + 2];
+ int color = bsktball_motion[motion*4 + 3];
+ int flipx = (pic & 0x80) >> 7;
+
+ pic = (pic & 0x3F);
+ color = (color & 0x3F);
+
+ drawgfx(bitmap,machine->gfx[1],
+ pic, color,
+ flipx,0,sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( bsktball )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/btime.c b/src/mame/video/btime.c
new file mode 100644
index 00000000000..2cbd0d9f6b7
--- /dev/null
+++ b/src/mame/video/btime.c
@@ -0,0 +1,659 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+This file is also used by scregg.c
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *btime_videoram;
+size_t btime_videoram_size;
+UINT8 *btime_colorram;
+UINT8 *lnc_charbank;
+UINT8 *bnj_backgroundram;
+UINT8 *zoar_scrollram;
+UINT8 *deco_charram;
+size_t bnj_backgroundram_size;
+
+static int sprite_dirty[256];
+static int char_dirty[1024];
+
+static UINT8 btime_palette = 0;
+static UINT8 bnj_scroll1 = 0;
+static UINT8 bnj_scroll2 = 0;
+static mame_bitmap *background_bitmap;
+static UINT8 lnc_sound_interrupt_enabled = 0;
+
+/***************************************************************************
+
+ Burger Time doesn't have a color PROM. It uses RAM to dynamically
+ create the palette.
+ The palette RAM is connected to the RGB output this way:
+
+ bit 7 -- 15 kohm resistor -- BLUE (inverted)
+ -- 33 kohm resistor -- BLUE (inverted)
+ -- 15 kohm resistor -- GREEN (inverted)
+ -- 33 kohm resistor -- GREEN (inverted)
+ -- 47 kohm resistor -- GREEN (inverted)
+ -- 15 kohm resistor -- RED (inverted)
+ -- 33 kohm resistor -- RED (inverted)
+ bit 0 -- 47 kohm resistor -- RED (inverted)
+
+***************************************************************************/
+PALETTE_INIT( btime )
+{
+ int i;
+
+
+ /* Burger Time doesn't have a color PROM, but Hamburge has. */
+ /* This function is also used by Eggs. */
+ if (color_prom == 0) return;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ The PROM is connected to the RGB output this way:
+
+ bit 7 -- 47 kohm resistor -- RED
+ -- 33 kohm resistor -- RED
+ -- 15 kohm resistor -- RED
+ -- 47 kohm resistor -- GREEN
+ -- 33 kohm resistor -- GREEN
+ -- 15 kohm resistor -- GREEN
+ -- 33 kohm resistor -- BLUE
+ bit 0 -- 15 kohm resistor -- BLUE
+
+***************************************************************************/
+PALETTE_INIT( lnc )
+{
+ int i;
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 7) & 0x01;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 4) & 0x01;
+ bit1 = (color_prom[i] >> 3) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 0) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+
+MACHINE_RESET( lnc )
+{
+ *lnc_charbank = 1;
+}
+
+
+/***************************************************************************
+
+Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( btime )
+{
+ bnj_scroll1 = 0;
+ bnj_scroll2 = 0;
+ btime_palette = 0;
+}
+
+
+VIDEO_START( bnj )
+{
+ /* the background area is twice as wide as the screen */
+ background_bitmap = auto_bitmap_alloc(2*machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ video_start_btime(machine);
+}
+
+
+WRITE8_HANDLER( btime_paletteram_w )
+{
+ /* RGB output is inverted */
+ paletteram_BBGGGRRR_w(offset,~data);
+}
+
+WRITE8_HANDLER( lnc_videoram_w )
+{
+ btime_videoram[offset] = data;
+ btime_colorram[offset] = *lnc_charbank;
+}
+
+READ8_HANDLER( btime_mirrorvideoram_r )
+{
+ int x,y;
+
+ /* swap x and y coordinates */
+ x = offset / 32;
+ y = offset % 32;
+ offset = 32 * y + x;
+
+ return btime_videoram[offset];
+}
+
+READ8_HANDLER( btime_mirrorcolorram_r )
+{
+ int x,y;
+
+ /* swap x and y coordinates */
+ x = offset / 32;
+ y = offset % 32;
+ offset = 32 * y + x;
+
+ return btime_colorram[offset];
+}
+
+WRITE8_HANDLER( btime_mirrorvideoram_w )
+{
+ int x,y;
+
+ /* swap x and y coordinates */
+ x = offset / 32;
+ y = offset % 32;
+ offset = 32 * y + x;
+
+ btime_videoram[offset] = data;
+}
+
+WRITE8_HANDLER( lnc_mirrorvideoram_w )
+{
+ int x,y;
+
+ /* swap x and y coordinates */
+ x = offset / 32;
+ y = offset % 32;
+ offset = 32 * y + x;
+
+ lnc_videoram_w(offset,data);
+}
+
+WRITE8_HANDLER( btime_mirrorcolorram_w )
+{
+ int x,y;
+
+ /* swap x and y coordinates */
+ x = offset / 32;
+ y = offset % 32;
+ offset = 32 * y + x;
+
+ btime_colorram[offset] = data;
+}
+
+WRITE8_HANDLER( deco_charram_w )
+{
+ if (deco_charram[offset] == data) return;
+
+ deco_charram[offset] = data;
+
+ offset &= 0x1fff;
+
+ /* dirty sprite */
+ sprite_dirty[offset >> 5] = 1;
+
+ /* diry char */
+ char_dirty [offset >> 3] = 1;
+}
+
+WRITE8_HANDLER( bnj_background_w )
+{
+ bnj_backgroundram[offset] = data;
+}
+
+WRITE8_HANDLER( bnj_scroll1_w )
+{
+ bnj_scroll1 = data;
+}
+
+WRITE8_HANDLER( bnj_scroll2_w )
+{
+ bnj_scroll2 = data;
+}
+
+WRITE8_HANDLER( zoar_video_control_w )
+{
+ // Zoar video control
+ //
+ // Bit 0-2 = Unknown (always 0). Marked as MCOL on schematics
+ // Bit 3-4 = Palette
+ // Bit 7 = Flip Screen
+
+ btime_palette = (data & 0x30) >> 3;
+ flip_screen_set(data & 0x80);
+}
+
+WRITE8_HANDLER( btime_video_control_w )
+{
+ // Btime video control
+ //
+ // Bit 0 = Flip screen
+ // Bit 1-7 = Unknown
+
+ flip_screen_set(data & 0x01);
+}
+
+WRITE8_HANDLER( bnj_video_control_w )
+{
+ /* Bnj/Lnc works a little differently than the btime/eggs (apparently). */
+ /* According to the information at: */
+ /* http://www.davesclassics.com/arcade/Switch_Settings/BumpNJump.sw */
+ /* SW8 is used for cocktail video selection (as opposed to controls), */
+ /* but bit 7 of the input port is used for vblank input. */
+ /* My guess is that this switch open circuits some connection to */
+ /* the monitor hardware. */
+ /* For now we just check 0x40 in DSW1, and ignore the write if we */
+ /* are in upright controls mode. */
+
+ if (input_port_3_r(0) & 0x40) /* cocktail mode */
+ btime_video_control_w(offset, data);
+}
+
+WRITE8_HANDLER( lnc_video_control_w )
+{
+ // I have a feeling that this only works by coincidence. I couldn't
+ // figure out how NMI's are disabled by the sound processor
+ lnc_sound_interrupt_enabled = data & 0x08;
+
+ bnj_video_control_w(offset, data & 0x01);
+}
+
+WRITE8_HANDLER( disco_video_control_w )
+{
+ btime_palette = (data >> 2) & 0x03;
+
+ if (!(input_port_3_r(0) & 0x40)) /* cocktail mode */
+ {
+ flip_screen_set(data & 0x01);
+ }
+}
+
+
+INTERRUPT_GEN( lnc_sound_interrupt )
+{
+ if (lnc_sound_interrupt_enabled)
+ cpunum_set_input_line(1, INPUT_LINE_NMI, PULSE_LINE);
+}
+
+
+static void draw_chars(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8 transparency, UINT8 color, int priority)
+{
+ offs_t offs;
+
+ for (offs = 0; offs < btime_videoram_size; offs++)
+ {
+ UINT8 x = 31 - (offs / 32);
+ UINT8 y = offs % 32;
+
+ UINT16 code = btime_videoram[offs] + 256 * (btime_colorram[offs] & 3);
+
+ /* check priority */
+ if ((priority != -1) && (priority != ((code >> 7) & 0x01))) continue;
+
+ if (flip_screen)
+ {
+ x = 31 - x;
+ y = 31 - y;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flip_screen,flip_screen,
+ 8*x,8*y,
+ cliprect,transparency,0);
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8 color,
+ UINT8 sprite_y_adjust, UINT8 sprite_y_adjust_flip_screen,
+ UINT8 *sprite_ram, offs_t interleave)
+{
+ int i;
+ offs_t offs;
+
+ /* draw the sprites */
+ for (i = 0, offs = 0; i < 8; i++, offs += 4*interleave)
+ {
+ int x, y;
+ UINT8 flipx,flipy;
+
+ if (!(sprite_ram[offs + 0] & 0x01)) continue;
+
+ x = 240 - sprite_ram[offs + 3*interleave];
+ y = 240 - sprite_ram[offs + 2*interleave];
+
+ flipx = sprite_ram[offs + 0] & 0x04;
+ flipy = sprite_ram[offs + 0] & 0x02;
+
+ if (flip_screen)
+ {
+ x = 240 - x;
+ y = 240 - y + sprite_y_adjust_flip_screen;
+
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ y = y - sprite_y_adjust;
+
+ drawgfx(bitmap,machine->gfx[1],
+ sprite_ram[offs + interleave],
+ color,
+ flipx,flipy,
+ x, y,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ y = y + (flip_screen ? -256 : 256);
+
+ // Wrap around
+ drawgfx(bitmap,machine->gfx[1],
+ sprite_ram[offs + interleave],
+ color,
+ flipx,flipy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8* tmap, UINT8 color)
+{
+ int i;
+
+ int scroll = -(bnj_scroll2 | ((bnj_scroll1 & 0x03) << 8));
+
+ // One extra iteration for wrap around
+ for (i = 0; i < 5; i++, scroll += 256)
+ {
+ offs_t offs;
+ offs_t tileoffset = tmap[i & 3] * 0x100;
+
+ // Skip if this title is completely off the screen
+ if (scroll > 256) break;
+ if (scroll < -256) continue;
+
+ for (offs = 0; offs < 0x100; offs++)
+ {
+ int x = 240 - (16 * (offs / 16) + scroll);
+ int y = 16 * (offs % 16);
+
+ if (flip_screen)
+ {
+ x = 240 - x;
+ y = 240 - y;
+ }
+
+ drawgfx(bitmap, machine->gfx[2],
+ memory_region(REGION_GFX3)[tileoffset + offs],
+ color,
+ flip_screen,flip_screen,
+ x,y,
+ cliprect,TRANSPARENCY_NONE,0);
+ }
+ }
+}
+
+
+static void decode_modified(running_machine *machine, UINT8 *sprite_ram, int interleave)
+{
+ int i,offs;
+
+
+ /* decode dirty characters */
+ for (offs = btime_videoram_size - 1;offs >= 0;offs--)
+ {
+ int code;
+
+ code = btime_videoram[offs] + 256 * (btime_colorram[offs] & 3);
+
+ if (char_dirty[code])
+ {
+ decodechar(machine->gfx[0],code,deco_charram,machine->drv->gfxdecodeinfo[0].gfxlayout);
+
+ char_dirty[code] = 0;
+ }
+ }
+
+ /* decode dirty sprites */
+ for (i = 0, offs = 0;i < 8; i++, offs += 4*interleave)
+ {
+ int code;
+
+ code = sprite_ram[offs + interleave];
+
+ if (sprite_dirty[code])
+ {
+ decodechar(machine->gfx[1],code,deco_charram,machine->drv->gfxdecodeinfo[1].gfxlayout);
+
+ sprite_dirty[code] = 0;
+ }
+ }
+}
+
+
+VIDEO_UPDATE( btime )
+{
+ if (bnj_scroll1 & 0x10)
+ {
+ int i, start;
+
+ // Generate tile map
+ static UINT8 btime_tilemap[4];
+
+ if (flip_screen)
+ start = 0;
+ else
+ start = 1;
+
+ for (i = 0; i < 4; i++)
+ {
+ btime_tilemap[i] = start | (bnj_scroll1 & 0x04);
+ start = (start + 1) & 0x03;
+ }
+
+ draw_background(machine, bitmap, cliprect, btime_tilemap, 0);
+
+ draw_chars(machine, bitmap, cliprect, TRANSPARENCY_PEN, 0, -1);
+ }
+ else
+ {
+ draw_chars(machine, bitmap, cliprect, TRANSPARENCY_NONE, 0, -1);
+ }
+
+ draw_sprites(machine, bitmap, cliprect, 0, 1, 0, btime_videoram, 0x20);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( eggs )
+{
+ draw_chars(machine, bitmap, cliprect, TRANSPARENCY_NONE, 0, -1);
+
+ draw_sprites(machine, bitmap, cliprect, 0, 0, 0, btime_videoram, 0x20);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( lnc )
+{
+ draw_chars(machine, bitmap, cliprect, TRANSPARENCY_NONE, 0, -1);
+
+ draw_sprites(machine, bitmap, cliprect, 0, 1, 2, btime_videoram, 0x20);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( zoar )
+{
+ if (bnj_scroll1 & 0x04)
+ {
+ draw_background(machine, bitmap, cliprect, zoar_scrollram, btime_palette);
+
+ draw_chars(machine, bitmap, cliprect, TRANSPARENCY_PEN, btime_palette + 1, -1);
+ }
+ else
+ {
+ draw_chars(machine, bitmap, cliprect, TRANSPARENCY_NONE, btime_palette + 1, -1);
+ }
+
+ /* The order is important for correct priorities */
+ draw_sprites(machine, bitmap, cliprect, btime_palette + 1, 1, 2, btime_videoram + 0x1f, 0x20);
+ draw_sprites(machine, bitmap, cliprect, btime_palette + 1, 1, 2, btime_videoram, 0x20);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( bnj )
+{
+ if (bnj_scroll1)
+ {
+ int scroll, offs;
+
+ for (offs = bnj_backgroundram_size-1; offs >=0; offs--)
+ {
+ int sx,sy;
+
+ sx = 16 * ((offs < 0x100) ? ((offs % 0x80) / 8) : ((offs % 0x80) / 8) + 16);
+ sy = 16 * (((offs % 0x100) < 0x80) ? offs % 8 : (offs % 8) + 8);
+ sx = 496 - sx;
+
+ if (flip_screen)
+ {
+ sx = 496 - sx;
+ sy = 240 - sy;
+ }
+
+ drawgfx(background_bitmap, machine->gfx[2],
+ (bnj_backgroundram[offs] >> 4) + ((offs & 0x80) >> 3) + 32,
+ 0,
+ flip_screen, flip_screen,
+ sx, sy,
+ 0, TRANSPARENCY_NONE, 0);
+ }
+
+ /* copy the background bitmap to the screen */
+ scroll = (bnj_scroll1 & 0x02) * 128 + 511 - bnj_scroll2;
+ if (!flip_screen)
+ scroll = 767-scroll;
+ copyscrollbitmap (bitmap, background_bitmap, 1, &scroll, 0, 0, cliprect,TRANSPARENCY_NONE, 0);
+
+ /* copy the low priority characters followed by the sprites
+ then the high priority characters */
+ draw_chars(machine, bitmap, cliprect, TRANSPARENCY_PEN, 0, 1);
+ draw_sprites(machine, bitmap, cliprect, 0, 0, 0, btime_videoram, 0x20);
+ draw_chars(machine, bitmap, cliprect, TRANSPARENCY_PEN, 0, 0);
+ }
+ else
+ {
+ draw_chars(machine, bitmap, cliprect, TRANSPARENCY_NONE, 0, -1);
+
+ draw_sprites(machine, bitmap, cliprect, 0, 0, 0, btime_videoram, 0x20);
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( cookrace )
+{
+ int offs;
+
+ for (offs = bnj_backgroundram_size-1; offs >=0; offs--)
+ {
+ int sx,sy;
+
+ sx = 31 - (offs / 32);
+ sy = offs % 32;
+
+ if (flip_screen)
+ {
+ sx = 31 - sx;
+ sy = 31 - sy;
+ }
+
+ drawgfx(bitmap, machine->gfx[2],
+ bnj_backgroundram[offs],
+ 0,
+ flip_screen, flip_screen,
+ 8*sx,8*sy,
+ cliprect, TRANSPARENCY_NONE, 0);
+ }
+
+ draw_chars(machine, bitmap, cliprect, TRANSPARENCY_PEN, 0, -1);
+
+ draw_sprites(machine, bitmap, cliprect, 0, 1, 0, btime_videoram, 0x20);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( disco )
+{
+ decode_modified(machine, spriteram, 1);
+
+ draw_chars(machine, bitmap, cliprect, TRANSPARENCY_NONE, btime_palette, -1);
+
+ draw_sprites(machine, bitmap, cliprect, btime_palette, 0, 0, spriteram, 1);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( progolf )
+{
+ decode_modified(machine, spriteram, 1);
+
+ draw_chars(machine, bitmap, cliprect, TRANSPARENCY_NONE, /*btime_palette*/0, -1);
+
+// draw_sprites(machine, bitmap, cliprect, 0/*btime_palette*/, 0, 0, spriteram, 1);
+
+ return 0;
+}
diff --git a/src/mame/video/btoads.c b/src/mame/video/btoads.c
new file mode 100644
index 00000000000..fb8306010ba
--- /dev/null
+++ b/src/mame/video/btoads.c
@@ -0,0 +1,487 @@
+/*************************************************************************
+
+ BattleToads
+
+ Video hardware emulation
+
+**************************************************************************/
+
+#include "driver.h"
+#include "cpu/tms34010/tms34010.h"
+#include "video/tlc34076.h"
+#include "btoads.h"
+
+
+#define BT_DEBUG 0
+
+
+
+/*************************************
+ *
+ * Global variables
+ *
+ *************************************/
+
+UINT16 *btoads_vram_fg0, *btoads_vram_fg1, *btoads_vram_fg_data;
+UINT16 *btoads_vram_bg0, *btoads_vram_bg1;
+UINT16 *btoads_sprite_scale;
+UINT16 *btoads_sprite_control;
+
+static UINT8 *vram_fg_draw, *vram_fg_display;
+
+static int xscroll0, yscroll0;
+static int xscroll1, yscroll1;
+static int screen_control;
+
+static UINT16 sprite_source_offs;
+static UINT8 *sprite_dest_base;
+static UINT16 sprite_dest_offs;
+
+static UINT16 misc_control;
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( btoads )
+{
+ /* initialize the swapped pointers */
+ vram_fg_draw = (UINT8 *)btoads_vram_fg0;
+ vram_fg_display = (UINT8 *)btoads_vram_fg1;
+}
+
+
+
+/*************************************
+ *
+ * Control registers
+ *
+ *************************************/
+
+WRITE16_HANDLER( btoads_misc_control_w )
+{
+ COMBINE_DATA(&misc_control);
+
+ /* bit 3 controls sound reset line */
+ cpunum_set_input_line(1, INPUT_LINE_RESET, (misc_control & 8) ? CLEAR_LINE : ASSERT_LINE);
+}
+
+
+WRITE16_HANDLER( btoads_display_control_w )
+{
+ if (ACCESSING_MSB)
+ {
+ /* allow multiple changes during display */
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+
+ /* bit 15 controls which page is rendered and which page is displayed */
+ if (data & 0x8000)
+ {
+ vram_fg_draw = (UINT8 *)btoads_vram_fg1;
+ vram_fg_display = (UINT8 *)btoads_vram_fg0;
+ }
+ else
+ {
+ vram_fg_draw = (UINT8 *)btoads_vram_fg0;
+ vram_fg_display = (UINT8 *)btoads_vram_fg1;
+ }
+
+ /* stash the remaining data for later */
+ screen_control = data >> 8;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Scroll registers
+ *
+ *************************************/
+
+WRITE16_HANDLER( btoads_scroll0_w )
+{
+ /* allow multiple changes during display */
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+
+ /* upper bits are Y scroll, lower bits are X scroll */
+ if (ACCESSING_MSB)
+ yscroll0 = data >> 8;
+ if (ACCESSING_LSB)
+ xscroll0 = data & 0xff;
+}
+
+
+WRITE16_HANDLER( btoads_scroll1_w )
+{
+ /* allow multiple changes during display */
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+
+ /* upper bits are Y scroll, lower bits are X scroll */
+ if (ACCESSING_MSB)
+ yscroll1 = data >> 8;
+ if (ACCESSING_LSB)
+ xscroll1 = data & 0xff;
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM
+ *
+ *************************************/
+
+WRITE16_HANDLER( btoads_paletteram_w )
+{
+ tlc34076_lsb_w(offset/2, data, mem_mask);
+}
+
+
+READ16_HANDLER( btoads_paletteram_r )
+{
+ return tlc34076_lsb_r(offset/2, mem_mask);
+}
+
+
+
+/*************************************
+ *
+ * Background video RAM
+ *
+ *************************************/
+
+WRITE16_HANDLER( btoads_vram_bg0_w )
+{
+ COMBINE_DATA(&btoads_vram_bg0[offset & 0x3fcff]);
+}
+
+
+WRITE16_HANDLER( btoads_vram_bg1_w )
+{
+ COMBINE_DATA(&btoads_vram_bg1[offset & 0x3fcff]);
+}
+
+
+READ16_HANDLER( btoads_vram_bg0_r )
+{
+ return btoads_vram_bg0[offset & 0x3fcff];
+}
+
+
+READ16_HANDLER( btoads_vram_bg1_r )
+{
+ return btoads_vram_bg1[offset & 0x3fcff];
+}
+
+
+
+/*************************************
+ *
+ * Foreground video RAM
+ *
+ *************************************/
+
+WRITE16_HANDLER( btoads_vram_fg_display_w )
+{
+ if (ACCESSING_LSB)
+ vram_fg_display[offset] = data;
+}
+
+
+WRITE16_HANDLER( btoads_vram_fg_draw_w )
+{
+ if (ACCESSING_LSB)
+ vram_fg_draw[offset] = data;
+}
+
+
+READ16_HANDLER( btoads_vram_fg_display_r )
+{
+ return vram_fg_display[offset];
+}
+
+
+READ16_HANDLER( btoads_vram_fg_draw_r )
+{
+ return vram_fg_draw[offset];
+}
+
+
+
+/*************************************
+ *
+ * Sprite rendering
+ *
+ *************************************/
+
+static void render_sprite_row(UINT16 *sprite_source, UINT32 address)
+{
+ int flipxor = ((*btoads_sprite_control >> 10) & 1) ? 0xffff : 0x0000;
+ int width = (~*btoads_sprite_control & 0x1ff) + 2;
+ int color = (~*btoads_sprite_control >> 8) & 0xf0;
+ int srcoffs = sprite_source_offs << 8;
+ int srcend = srcoffs + (width << 8);
+ int srcstep = 0x100 - btoads_sprite_scale[0];
+ int dststep = 0x100 - btoads_sprite_scale[8];
+ int dstoffs = sprite_dest_offs << 8;
+
+ /* non-shadow case */
+ if (!(misc_control & 0x10))
+ {
+ for ( ; srcoffs < srcend; srcoffs += srcstep, dstoffs += dststep)
+ {
+ UINT16 src = sprite_source[(srcoffs >> 10) & 0x1ff];
+ if (src)
+ {
+ src = (src >> (((srcoffs ^ flipxor) >> 6) & 0x0c)) & 0x0f;
+ if (src)
+ sprite_dest_base[(dstoffs >> 8) & 0x1ff] = src | color;
+ }
+ }
+ }
+
+ /* shadow case */
+ else
+ {
+ for ( ; srcoffs < srcend; srcoffs += srcstep, dstoffs += dststep)
+ {
+ UINT16 src = sprite_source[(srcoffs >> 10) & 0x1ff];
+ if (src)
+ {
+ src = (src >> (((srcoffs ^ flipxor) >> 6) & 0x0c)) & 0x0f;
+ if (src)
+ sprite_dest_base[(dstoffs >> 8) & 0x1ff] = color;
+ }
+ }
+ }
+
+ sprite_source_offs += width;
+ sprite_dest_offs = dstoffs >> 8;
+}
+
+
+
+/*************************************
+ *
+ * Shift register read/write
+ *
+ *************************************/
+
+void btoads_to_shiftreg(UINT32 address, UINT16 *shiftreg)
+{
+ address &= ~0x40000000;
+
+ /* reads from this first region are usual shift register reads */
+ if (address >= 0xa0000000 && address <= 0xa3ffffff)
+ memcpy(shiftreg, &vram_fg_display[TOWORD(address & 0x3fffff)], TOBYTE(0x1000));
+
+ /* reads from this region set the sprite destination address */
+ else if (address >= 0xa4000000 && address <= 0xa7ffffff)
+ {
+ sprite_dest_base = &vram_fg_draw[TOWORD(address & 0x3fc000)];
+ sprite_dest_offs = (INT16)((address & 0x3ff) << 2) >> 2;
+ }
+
+ /* reads from this region set the sprite source address */
+ else if (address >= 0xa8000000 && address <= 0xabffffff)
+ {
+ memcpy(shiftreg, &btoads_vram_fg_data[TOWORD(address & 0x7fc000)], TOBYTE(0x2000));
+ sprite_source_offs = (address & 0x003fff) >> 3;
+ }
+
+ else
+ logerror("%08X:btoads_to_shiftreg(%08X)\n", activecpu_get_pc(), address);
+}
+
+
+void btoads_from_shiftreg(UINT32 address, UINT16 *shiftreg)
+{
+ address &= ~0x40000000;
+
+ /* writes to this first region are usual shift register writes */
+ if (address >= 0xa0000000 && address <= 0xa3ffffff)
+ memcpy(&vram_fg_display[TOWORD(address & 0x3fc000)], shiftreg, TOBYTE(0x1000));
+
+ /* writes to this region are ignored for our purposes */
+ else if (address >= 0xa4000000 && address <= 0xa7ffffff)
+ ;
+
+ /* writes to this region copy standard data */
+ else if (address >= 0xa8000000 && address <= 0xabffffff)
+ memcpy(&btoads_vram_fg_data[TOWORD(address & 0x7fc000)], shiftreg, TOBYTE(0x2000));
+
+ /* writes to this region render the current sprite data */
+ else if (address >= 0xac000000 && address <= 0xafffffff)
+ render_sprite_row(shiftreg, address);
+
+ else
+ logerror("%08X:btoads_from_shiftreg(%08X)\n", activecpu_get_pc(), address);
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+void btoads_scanline_update(running_machine *machine, int screen, mame_bitmap *bitmap, int scanline, const tms34010_display_params *params)
+{
+ UINT32 fulladdr = ((params->rowaddr << 16) | params->coladdr) >> 4;
+ UINT16 *bg0_base = &btoads_vram_bg0[(fulladdr + (yscroll0 << 10)) & 0x3fc00];
+ UINT16 *bg1_base = &btoads_vram_bg1[(fulladdr + (yscroll1 << 10)) & 0x3fc00];
+ UINT8 *spr_base = &vram_fg_display[fulladdr & 0x3fc00];
+ UINT16 *dst = BITMAP_ADDR16(bitmap, scanline, 0);
+ int coladdr = fulladdr & 0x3ff;
+ int x;
+
+ /* for each scanline, switch off the render mode */
+ switch (screen_control & 3)
+ {
+ /* mode 0: used in ship level, snake boss, title screen (free play) */
+ case 0:
+
+ /* mode 2: used in EOA screen, jetpack level, first level, high score screen */
+ case 2:
+ for (x = params->heblnk; x < params->hsblnk; x += 2, coladdr++)
+ {
+ UINT8 sprpix = spr_base[coladdr & 0xff];
+
+ if (sprpix)
+ {
+ dst[x + 0] = sprpix;
+ dst[x + 1] = sprpix;
+ }
+ else
+ {
+ UINT16 bg0pix = bg0_base[(coladdr + xscroll0) & 0xff];
+ UINT16 bg1pix = bg1_base[(coladdr + xscroll1) & 0xff];
+
+ if (bg1pix & 0xff)
+ dst[x + 0] = bg1pix & 0xff;
+ else
+ dst[x + 0] = bg0pix & 0xff;
+
+ if (bg1pix >> 8)
+ dst[x + 1] = bg1pix >> 8;
+ else
+ dst[x + 1] = bg0pix >> 8;
+ }
+ }
+ break;
+
+ /* mode 1: used in snow level, title screen (free play), top part of rolling ball level */
+ case 1:
+ for (x = params->heblnk; x < params->hsblnk; x += 2, coladdr++)
+ {
+ UINT8 sprpix = spr_base[coladdr & 0xff];
+
+ if (sprpix && !(sprpix & 0x80))
+ {
+ dst[x + 0] = sprpix;
+ dst[x + 1] = sprpix;
+ }
+ else
+ {
+ UINT16 bg0pix = bg0_base[(coladdr + xscroll0) & 0xff];
+ UINT16 bg1pix = bg1_base[(coladdr + xscroll1) & 0xff];
+
+ if (bg0pix & 0xff)
+ dst[x + 0] = bg0pix & 0xff;
+ else if (bg1pix & 0x80)
+ dst[x + 0] = bg1pix & 0xff;
+ else if (sprpix)
+ dst[x + 0] = sprpix;
+ else
+ dst[x + 0] = bg1pix & 0xff;
+
+ if (bg0pix >> 8)
+ dst[x + 1] = bg0pix >> 8;
+ else if (bg1pix & 0x8000)
+ dst[x + 1] = bg1pix >> 8;
+ else if (sprpix)
+ dst[x + 1] = sprpix;
+ else
+ dst[x + 1] = bg1pix >> 8;
+ }
+ }
+ break;
+
+ /* mode 3: used in toilet level, toad intros, bottom of rolling ball level */
+ case 3:
+ for (x = params->heblnk; x < params->hsblnk; x += 2, coladdr++)
+ {
+ UINT16 bg0pix = bg0_base[(coladdr + xscroll0) & 0xff];
+ UINT16 bg1pix = bg1_base[(coladdr + xscroll1) & 0xff];
+ UINT8 sprpix = spr_base[coladdr & 0xff];
+
+ if (bg1pix & 0x80)
+ dst[x + 0] = bg1pix & 0xff;
+ else if (sprpix & 0x80)
+ dst[x + 0] = sprpix;
+ else if (bg1pix & 0xff)
+ dst[x + 0] = bg1pix & 0xff;
+ else if (sprpix)
+ dst[x + 0] = sprpix;
+ else
+ dst[x + 0] = bg0pix & 0xff;
+
+ if (bg1pix & 0x8000)
+ dst[x + 1] = bg1pix >> 8;
+ else if (sprpix & 0x80)
+ dst[x + 1] = sprpix;
+ else if (bg1pix >> 8)
+ dst[x + 1] = bg1pix >> 8;
+ else if (sprpix)
+ dst[x + 1] = sprpix;
+ else
+ dst[x + 1] = bg0pix >> 8;
+ }
+ break;
+ }
+
+ /* debugging - dump the screen contents to a file */
+#if BT_DEBUG
+ if (input_code_pressed(KEYCODE_X))
+ {
+ static int count = 0;
+ char name[10];
+ FILE *f;
+ int i;
+
+ sprintf(name, "disp%d.log", count++);
+ f = fopen(name, "w");
+ fprintf(f, "screen_control = %04X\n\n", screen_control << 8);
+
+ for (i = 0; i < 3; i++)
+ {
+ UINT16 *base = (i == 0) ? (UINT16 *)vram_fg_display : (i == 1) ? btoads_vram_bg0 : btoads_vram_bg1;
+ int xscr = (i == 0) ? 0 : (i == 1) ? xscroll0 : xscroll1;
+ int yscr = (i == 0) ? 0 : (i == 1) ? yscroll0 : yscroll1;
+ int y;
+
+ for (y = 0; y < 224; y++)
+ {
+ UINT32 offs = ((y + yscr) & 0xff) * TOWORD(0x4000);
+ for (x = 0; x < 256; x++)
+ {
+ UINT16 pix = base[offs + ((x + xscr) & 0xff)];
+ fprintf(f, "%02X%02X", pix & 0xff, pix >> 8);
+ if (x % 16 == 15) fprintf(f, " ");
+ }
+ fprintf(f, "\n");
+ }
+ fprintf(f, "\n\n");
+ }
+ fclose(f);
+ }
+
+ logerror("---VBLANK---\n");
+#endif
+}
diff --git a/src/mame/video/bublbobl.c b/src/mame/video/bublbobl.c
new file mode 100644
index 00000000000..707bcc987cd
--- /dev/null
+++ b/src/mame/video/bublbobl.c
@@ -0,0 +1,98 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+#include "driver.h"
+#include <ctype.h>
+
+
+
+UINT8 *bublbobl_objectram;
+size_t bublbobl_objectram_size;
+int bublbobl_video_enable;
+
+
+VIDEO_UPDATE( bublbobl )
+{
+ int offs;
+ int sx,sy,xc,yc;
+ int gfx_num,gfx_attr,gfx_offs;
+ const UINT8 *prom_line;
+
+
+ /* Bubble Bobble doesn't have a real video RAM. All graphics (characters */
+ /* and sprites) are stored in the same memory region, and information on */
+ /* the background character columns is stored in the area dd00-dd3f */
+
+ /* This clears & redraws the entire screen each pass */
+ fillbitmap(bitmap,machine->pens[255],cliprect);
+
+ if (!bublbobl_video_enable) return 0;
+
+ sx = 0;
+
+ for (offs = 0;offs < bublbobl_objectram_size;offs += 4)
+ {
+ /* skip empty sprites */
+ /* this is dword aligned so the UINT32 * cast shouldn't give problems */
+ /* on any architecture */
+ if (*(UINT32 *)(&bublbobl_objectram[offs]) == 0)
+ continue;
+
+ gfx_num = bublbobl_objectram[offs + 1];
+ gfx_attr = bublbobl_objectram[offs + 3];
+ prom_line = memory_region(REGION_PROMS) + 0x80 + ((gfx_num & 0xe0) >> 1);
+
+ gfx_offs = ((gfx_num & 0x1f) * 0x80);
+ if ((gfx_num & 0xa0) == 0xa0)
+ gfx_offs |= 0x1000;
+
+ sy = -bublbobl_objectram[offs + 0];
+
+ for (yc = 0;yc < 32;yc++)
+ {
+ if (prom_line[yc/2] & 0x08) continue; /* NEXT */
+
+ if (!(prom_line[yc/2] & 0x04)) /* next column */
+ {
+ sx = bublbobl_objectram[offs + 2];
+ if (gfx_attr & 0x40) sx -= 256;
+ }
+
+ for (xc = 0;xc < 2;xc++)
+ {
+ int goffs,code,color,flipx,flipy,x,y;
+
+ goffs = gfx_offs + xc * 0x40 + (yc & 7) * 0x02 +
+ (prom_line[yc/2] & 0x03) * 0x10;
+ code = videoram[goffs] + 256 * (videoram[goffs + 1] & 0x03) + 1024 * (gfx_attr & 0x0f);
+ color = (videoram[goffs + 1] & 0x3c) >> 2;
+ flipx = videoram[goffs + 1] & 0x40;
+ flipy = videoram[goffs + 1] & 0x80;
+ x = sx + xc * 8;
+ y = (sy + yc * 8) & 0xff;
+
+ if (flip_screen)
+ {
+ x = 248 - x;
+ y = 248 - y;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+
+ sx += 16;
+ }
+ return 0;
+}
diff --git a/src/mame/video/buggychl.c b/src/mame/video/buggychl.c
new file mode 100644
index 00000000000..4b93edd304d
--- /dev/null
+++ b/src/mame/video/buggychl.c
@@ -0,0 +1,275 @@
+#include "driver.h"
+#include "profiler.h"
+
+
+
+UINT8 *buggychl_scrollv,*buggychl_scrollh;
+static UINT8 buggychl_sprite_lookup[0x2000];
+UINT8 *buggychl_character_ram;
+
+static int *dirtychar;
+
+static mame_bitmap *tmpbitmap1,*tmpbitmap2;
+static int sl_bank,bg_on,sky_on,sprite_color_base,bg_scrollx;
+
+
+
+PALETTE_INIT( buggychl )
+{
+ int i;
+
+ /* arbitrary blue shading for the sky */
+ for (i = 0;i < 128;i++)
+ palette_set_color(machine,i+128,MAKE_RGB(0,i,2*i));
+}
+
+
+
+
+VIDEO_START( buggychl )
+{
+ dirtybuffer = auto_malloc(videoram_size);
+ dirtychar = auto_malloc(256 * sizeof(*dirtychar));
+ tmpbitmap1 = auto_bitmap_alloc(256,256,machine->screen[0].format);
+ tmpbitmap2 = auto_bitmap_alloc(256,256,machine->screen[0].format);
+
+ memset(dirtybuffer,1,videoram_size);
+ memset(dirtychar,0xff,256 * sizeof(*dirtychar));
+}
+
+
+
+WRITE8_HANDLER( buggychl_chargen_w )
+{
+ if (buggychl_character_ram[offset] != data)
+ {
+ buggychl_character_ram[offset] = data;
+
+ dirtychar[(offset / 8) & 0xff] = 1;
+ }
+}
+
+WRITE8_HANDLER( buggychl_sprite_lookup_bank_w )
+{
+ sl_bank = (data & 0x10) << 8;
+}
+
+WRITE8_HANDLER( buggychl_sprite_lookup_w )
+{
+ buggychl_sprite_lookup[offset + sl_bank] = data;
+}
+
+WRITE8_HANDLER( buggychl_ctrl_w )
+{
+/*
+ bit7 = lamp
+ bit6 = lockout
+ bit4 = OJMODE
+ bit3 = SKY OFF
+ bit2 = /SN3OFF
+ bit1 = HINV
+ bit0 = VINV
+*/
+
+ flip_screen_y_set(data & 0x01);
+ flip_screen_x_set(data & 0x02);
+
+ bg_on = data & 0x04;
+ sky_on = data & 0x08;
+
+ sprite_color_base = (data & 0x10) ? 1*16 : 3*16;
+
+ coin_lockout_global_w((~data & 0x40) >> 6);
+ set_led_status(0,~data & 0x80);
+}
+
+WRITE8_HANDLER( buggychl_bg_scrollx_w )
+{
+ bg_scrollx = -(data - 0x12);
+}
+
+
+
+
+static void draw_sky(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int x,y;
+
+ for (y = 0;y < 256;y++)
+ {
+ for (x = 0;x < 256;x++)
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[128 + x/2];
+ }
+ }
+}
+
+
+static void draw_bg(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+ int scroll[256];
+
+ for (offs = 0;offs < 0x400;offs++)
+ {
+ int code = videoram[0x400+offs];
+
+ if (dirtybuffer[0x400+offs] || dirtychar[code])
+ {
+ int sx = offs % 32;
+ int sy = offs / 32;
+
+ dirtybuffer[0x400+offs] = 0;
+
+ if (flip_screen_x) sx = 31 - sx;
+ if (flip_screen_y) sy = 31 - sy;
+
+ drawgfx(tmpbitmap1,machine->gfx[0],
+ code,
+ 2,
+ flip_screen_x,flip_screen_y,
+ 8*sx,8*sy,
+ NULL,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ /* first copy to a temp bitmap doing column scroll */
+ for (offs = 0;offs < 256;offs++)
+ scroll[offs] = -buggychl_scrollv[offs/8];
+
+ copyscrollbitmap(tmpbitmap2,tmpbitmap1,1,&bg_scrollx,256,scroll,NULL,TRANSPARENCY_NONE,0);
+
+ /* then copy to the screen doing row scroll */
+ for (offs = 0;offs < 256;offs++)
+ scroll[offs] = -buggychl_scrollh[offs];
+
+ copyscrollbitmap(bitmap,tmpbitmap2,256,scroll,0,0,cliprect,TRANSPARENCY_COLOR,32);
+}
+
+
+static void draw_fg(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+
+ for (offs = 0;offs < 0x400;offs++)
+ {
+ int sx = offs % 32;
+ int sy = offs / 32;
+ /* the following line is most likely wrong */
+ int transp = (bg_on && sx >= 22) ? TRANSPARENCY_NONE : TRANSPARENCY_PEN;
+
+ int code = videoram[offs];
+
+ if (flip_screen_x) sx = 31 - sx;
+ if (flip_screen_y) sy = 31 - sy;
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ 0,
+ flip_screen_x,flip_screen_y,
+ 8*sx,8*sy,
+ cliprect,transp,0);
+ }
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ profiler_mark(PROFILER_USER1);
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int sx,sy,flipy,zoom,ch,x,px,y;
+ const UINT8 *lookup;
+ const UINT8 *zoomx_rom,*zoomy_rom;
+
+
+ sx = spriteram[offs+3] - ((spriteram[offs+2] & 0x80) << 1);
+ sy = 256-64 - spriteram[offs] + ((spriteram[offs+1] & 0x80) << 1);
+ flipy = spriteram[offs+1] & 0x40;
+ zoom = spriteram[offs+1] & 0x3f;
+ zoomy_rom = memory_region(REGION_GFX2) + (zoom << 6);
+ zoomx_rom = memory_region(REGION_GFX2) + 0x2000 + (zoom << 3);
+
+ lookup = buggychl_sprite_lookup + ((spriteram[offs+2] & 0x7f) << 6);
+
+ for (y = 0;y < 64;y++)
+ {
+ int dy = flip_screen_y ? (255 - sy - y) : (sy + y);
+
+ if ((dy & ~0xff) == 0)
+ {
+ int charline,base_pos;
+
+ charline = zoomy_rom[y] & 0x07;
+ base_pos = zoomy_rom[y] & 0x38;
+ if (flipy) base_pos ^= 0x38;
+
+ px = 0;
+ for (ch = 0;ch < 4;ch++)
+ {
+ int pos,code,realflipy;
+ const UINT8 *pendata;
+
+ pos = base_pos + 2*ch;
+ code = 8 * (lookup[pos] | ((lookup[pos+1] & 0x07) << 8));
+ realflipy = (lookup[pos+1] & 0x80) ? !flipy : flipy;
+ code += (realflipy ? (charline ^ 7) : charline);
+ pendata = machine->gfx[1]->gfxdata + code*16;
+
+ for (x = 0;x < 16;x++)
+ {
+ int col;
+
+ col = pendata[x];
+ if (col)
+ {
+ int dx = flip_screen_x ? (255 - sx - px) : (sx + px);
+ if ((dx & ~0xff) == 0)
+ *BITMAP_ADDR16(bitmap, dy, dx) = machine->pens[sprite_color_base+col];
+ }
+
+ /* the following line is almost certainly wrong */
+ if (zoomx_rom[7-(2*ch+x/8)] & (1 << (x & 7)))
+ px++;
+ }
+ }
+ }
+ }
+ }
+
+ profiler_mark(PROFILER_END);
+}
+
+
+VIDEO_UPDATE( buggychl )
+{
+ int code;
+
+
+ if (sky_on)
+ draw_sky(machine, bitmap, cliprect);
+ else
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ /* decode modified characters */
+ for (code = 0;code < 256;code++)
+ {
+ if (dirtychar[code])
+ decodechar(machine->gfx[0],code,buggychl_character_ram,machine->drv->gfxdecodeinfo[0].gfxlayout);
+ }
+
+ if (bg_on)
+ draw_bg(machine, bitmap, cliprect);
+
+ draw_sprites(machine, bitmap, cliprect);
+
+ draw_fg(machine, bitmap, cliprect);
+
+ for (code = 0;code < 256;code++)
+ dirtychar[code] = 0;
+ return 0;
+}
diff --git a/src/mame/video/bwing.c b/src/mame/video/bwing.c
new file mode 100644
index 00000000000..38fe4fdf19f
--- /dev/null
+++ b/src/mame/video/bwing.c
@@ -0,0 +1,304 @@
+/*****************************************************************************
+
+B-Wings (c) 1984 Data East Corporation
+Zaviga (c) 1984 Data East Corporation
+
+drivers by Acho A. Tang
+
+*****************************************************************************/
+// Directives
+
+#include "driver.h"
+
+#define BW_DEBUG 0
+
+#define BW_NTILES_L2 7
+#define BW_NTILES (1<<BW_NTILES_L2)
+
+//****************************************************************************
+// Local Vars
+
+static tilemap *scrollmap[2], *charmap, *fgmap, *bgmap;
+static gfx_element *fgfx, *bgfx;
+static UINT8 *srbase[4], *fgdata, *bgdata;
+static int *srxlat;
+static unsigned sreg[8], palatch=0, srbank=0, mapmask=0, mapflip=0;
+
+//****************************************************************************
+// Local Functions
+
+static void fill_srxlat(int *xlat)
+{
+ unsigned base, offset, i;
+
+ for(base=0; base<0x2000; base+=0x400)
+ {
+ for(i=0; i<0x100; i++)
+ {
+ offset = base + (i<<2 & ~0x3f) + (i & 0x0f);
+
+ xlat[base+i] = offset;
+ xlat[base+i+0x100] = offset + 0x10;
+ xlat[base+i+0x200] = offset + 0x20;
+ xlat[base+i+0x300] = offset + 0x30;
+ }
+ }
+}
+
+//****************************************************************************
+// Exports
+
+gfx_layout bwing_tilelayout =
+{
+ 16, 16,
+ BW_NTILES,
+ 3,
+ { 0x4000*8, 0x2000*8, 0 },
+ { 7, 6, 5, 4, 3, 2, 1, 0, 128+7, 128+6, 128+5, 128+4, 128+3, 128+2, 128+1, 128+0 },
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8,
+ 8*8, 9*8,10*8,11*8,12*8,13*8,14*8,15*8 },
+ 32*8
+};
+
+
+WRITE8_HANDLER( bwing_spriteram_w ) { buffered_spriteram[offset] = data; }
+WRITE8_HANDLER( bwing_videoram_w ) { videoram[offset] = data; tilemap_mark_tile_dirty(charmap, offset); }
+
+
+READ8_HANDLER ( bwing_scrollram_r )
+{
+ if (!srbank) offset = srxlat[offset];
+
+ return((srbase[srbank])[offset]);
+}
+
+
+WRITE8_HANDLER( bwing_scrollram_w )
+{
+ if (!srbank)
+ {
+ offset = srxlat[offset];
+
+ tilemap_mark_tile_dirty(scrollmap[offset>>12], offset & 0xfff);
+ }
+
+ (srbase[srbank])[offset] = data;
+}
+
+
+WRITE8_HANDLER( bwing_scrollreg_w )
+{
+ static unsigned bp_ready=0;
+ unsigned i;
+ UINT8 *src;
+
+ sreg[offset] = data;
+
+ switch (offset)
+ {
+ case 6: palatch = data; break; // one of the palette components is latched through I/O(yike)
+
+ case 7:
+ // tile graphics are decoded in RAM on the fly and tile codes are banked + interleaved(ouch)
+ mapmask = data;
+ srbank = data >> 6;
+
+ if (srbank) bp_ready |= 1<<(srbank-1) & 7;
+
+ if (bp_ready == 7 && !srbank)
+ {
+ src = srbase[1];
+ for (i=0; i<BW_NTILES; i++) decodechar(fgfx, i, src, &bwing_tilelayout);
+
+ src += 0x1000;
+ for (i=0; i<BW_NTILES; i++) decodechar(bgfx, i, src, &bwing_tilelayout);
+
+ bp_ready = 0;
+ }
+
+ #if BW_DEBUG
+ logerror("(%1d)%04x: w=%02x a=%04x f=%d\n",cpu_getactivecpu(),activecpu_get_pc(),data,0x1b00+offset,cpu_getcurrentframe());
+ #endif
+ break;
+ }
+
+ #if BW_DEBUG
+ (memory_region(REGION_CPU1))[0x1b10 + offset] = data;
+ #endif
+}
+
+
+WRITE8_HANDLER( bwing_paletteram_w )
+{
+ static const float rgb[4][3]={{0.85,0.95,1.00},{0.90,1.00,1.00},{0.80,1.00,1.00},{0.75,0.90,1.10}};
+ int r, g, b, i;
+
+ paletteram[offset] = data;
+
+ r = ~data & 7;
+ g = ~data>>4 & 7;
+ b = ~palatch & 7;
+
+ r = ((r<<5) + (r<<2) + (r>>1));
+ g = ((g<<5) + (g<<2) + (g>>1));
+ b = ((b<<5) + (b<<2) + (b>>1));
+
+ if ((i = readinputport(7)) < 4)
+ {
+ r = (float)r * rgb[i][0];
+ g = (float)g * rgb[i][1];
+ b = (float)b * rgb[i][2];
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ }
+
+ palette_set_color(Machine, offset, MAKE_RGB(r, g, b));
+
+ #if BW_DEBUG
+ paletteram[offset+0x40] = palatch;
+ #endif
+}
+
+//****************************************************************************
+// Initializations
+
+#define BW_SET_TILE_INFO(GFX, CODE, COLOR) { \
+ tileinfo->pen_data = GFX->gfxdata + (CODE) * GFX->char_modulo; \
+ tileinfo->palette_base = GFX->color_base + ((COLOR) << 3); \
+ }
+
+static TILE_GET_INFO( get_fgtileinfo )
+{
+ unsigned code = fgdata[tile_index];
+ BW_SET_TILE_INFO(fgfx, code & (BW_NTILES-1), code >> 7);
+}
+
+static TILE_GET_INFO( get_bgtileinfo )
+{
+ unsigned code = bgdata[tile_index];
+ BW_SET_TILE_INFO(bgfx, code & (BW_NTILES-1), code >> 7);
+}
+
+static TILE_GET_INFO( get_charinfo )
+{
+ SET_TILE_INFO(0, videoram[tile_index], 0, 0);
+}
+
+static TILEMAP_MAPPER( bwing_scan_cols )
+{
+ return((col<<6) + row);
+}
+
+
+VIDEO_START( bwing )
+{
+ UINT32 *dwptr;
+ int i;
+
+ charmap = tilemap_create(get_charinfo,tilemap_scan_cols,TILEMAP_TYPE_PEN, 8, 8,32,32);
+ fgmap = tilemap_create(get_fgtileinfo,bwing_scan_cols,TILEMAP_TYPE_PEN,16,16,64,64);
+ bgmap = tilemap_create(get_bgtileinfo,bwing_scan_cols,TILEMAP_TYPE_PEN,16,16,64,64);
+ srxlat = auto_malloc(0x8000);
+
+ scrollmap[0] = fgmap;
+ scrollmap[1] = bgmap;
+ tilemap_set_transparent_pen(charmap, 0);
+ tilemap_set_transparent_pen(fgmap, 0);
+
+ fill_srxlat(srxlat);
+
+ fgdata = memory_region(REGION_USER1);
+ bgdata = fgdata + 0x1000;
+
+ for (i=0; i<4; i++) srbase[i] = fgdata + i * 0x2000;
+ for (i=0; i<8; i++) sreg[i] = 0;
+
+ fgfx = machine->gfx[2];
+ bgfx = machine->gfx[3];
+
+ if ((dwptr = fgfx->pen_usage))
+ {
+ dwptr[0] = 0;
+ for(i=1; i<BW_NTILES; i++) dwptr[i] = -1;
+ }
+}
+
+//****************************************************************************
+// Realtime
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bmp, const rectangle *clip, UINT8 *ram, int pri)
+{
+ int attrib, fx, fy, code, x, y, color, i;
+ gfx_element *gfx = machine->gfx[1];
+
+ for (i=0; i<0x200; i+=4)
+ {
+ attrib = ram[i]; if (!(attrib & 1) || (color = attrib>>3 & 1) != pri) continue;
+ code = ram[i+1]; code += attrib<<3 & 0x100;
+ y = ram[i+2]; y -= attrib<<1 & 0x100;
+ x = ram[i+3]; x -= attrib<<2 & 0x100;
+ fx = attrib & 0x04;
+ fy = ~attrib & 0x02;
+
+ // normal/cocktail
+ if (mapmask & 0x20) { fx = !fx; fy = !fy; x = 240 - x; y = 240 - y; }
+
+ // single/double
+ if (!(attrib & 0x10))
+ drawgfx(bmp, gfx, code, color, fx, fy, x, y, clip, TRANSPARENCY_PEN, 0);
+ else
+ drawgfxzoom(bmp, gfx, code, color, fx, fy, x, y, clip, TRANSPARENCY_PEN, 0, 1<<16, 2<<16);
+ }
+}
+
+
+VIDEO_UPDATE( bwing )
+{
+ unsigned x, y, shiftx;
+
+ if (mapmask & 0x20)
+ { mapflip = TILEMAP_FLIPX; shiftx = -8; }
+ else
+ { mapflip = TILEMAP_FLIPY; shiftx = 8; }
+
+ // draw background
+ if (!(mapmask & 1))
+ {
+ tilemap_set_flip(bgmap, mapflip);
+ x = ((sreg[1]<<2 & 0x300) + sreg[2] + shiftx) & 0x3ff;
+ tilemap_set_scrollx(bgmap, 0, x);
+ y = (sreg[1]<<4 & 0x300) + sreg[3];
+ tilemap_set_scrolly(bgmap, 0, y);
+ tilemap_draw(bitmap, cliprect, bgmap, 0, 0);
+ }
+ else
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ // draw low priority sprites
+ draw_sprites(machine, bitmap, cliprect, buffered_spriteram, 0);
+
+ // draw foreground
+ if (!(mapmask & 2))
+ {
+ tilemap_set_flip(fgmap, mapflip);
+ x = ((sreg[1]<<6 & 0x300) + sreg[4] + shiftx) & 0x3ff;
+ tilemap_set_scrollx(fgmap, 0, x);
+ y = (sreg[1]<<8 & 0x300) + sreg[5];
+ tilemap_set_scrolly(fgmap, 0, y);
+ tilemap_draw(bitmap, cliprect, fgmap, 0, 0);
+ }
+
+ // draw high priority sprites
+ draw_sprites(machine, bitmap, cliprect, buffered_spriteram, 1);
+
+ // draw text layer
+// if (mapmask & 4)
+ {
+ tilemap_set_flip(charmap, mapflip);
+ tilemap_draw(bitmap, cliprect, charmap, 0, 0);
+ }
+ return 0;
+}
+
+//****************************************************************************
diff --git a/src/mame/video/cabal.c b/src/mame/video/cabal.c
new file mode 100644
index 00000000000..dcf5d5da26c
--- /dev/null
+++ b/src/mame/video/cabal.c
@@ -0,0 +1,149 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *background_layer,*text_layer;
+
+
+static TILE_GET_INFO( get_back_tile_info )
+{
+ int tile = videoram16[tile_index];
+ int color = (tile>>12)&0xf;
+
+ tile &= 0xfff;
+
+ SET_TILE_INFO(
+ 1,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ int tile = colorram16[tile_index];
+ int color = (tile>>10);
+
+ tile &= 0x3ff;
+
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+
+VIDEO_START( cabal )
+{
+ background_layer = tilemap_create(get_back_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,16,16);
+ text_layer = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,32,32);
+
+ tilemap_set_transparent_pen(text_layer,3);
+ tilemap_set_transparent_pen(background_layer,15);
+}
+
+
+/**************************************************************************/
+
+WRITE16_HANDLER( cabal_flipscreen_w )
+{
+ if (ACCESSING_LSB)
+ {
+ int flip = (data & 0x20) ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0;
+ tilemap_set_flip(background_layer,flip);
+ tilemap_set_flip(text_layer,flip);
+
+ flip_screen_set(data & 0x20);
+ }
+}
+
+WRITE16_HANDLER( cabal_background_videoram16_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty(background_layer,offset);
+}
+
+WRITE16_HANDLER( cabal_text_videoram16_w )
+{
+ COMBINE_DATA(&colorram16[offset]);
+ tilemap_mark_tile_dirty(text_layer,offset);
+}
+
+
+/********************************************************************
+
+ Cabal Spriteram
+ ---------------
+
+ +0 .......x ........ Sprite enable bit
+ +0 ........ xxxxxxxx Sprite Y coordinate
+ +1 ..??.... ........ ??? unknown ???
+ +1 ....xxxx xxxxxxxx Sprite tile number
+ +2 .xxxx... ........ Sprite color bank
+ +2 .....x.. ........ Sprite flip x
+ +2 .......x xxxxxxxx Sprite X coordinate
+ +3 (unused)
+
+ -------E YYYYYYYY
+ ----BBTT TTTTTTTT
+ -CCCCF-X XXXXXXXX
+ -------- --------
+
+********************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs,data0,data1,data2;
+
+ for( offs = spriteram_size/2 - 4; offs >= 0; offs -= 4 )
+ {
+ data0 = spriteram16[offs];
+ data1 = spriteram16[offs+1];
+ data2 = spriteram16[offs+2];
+
+ if( data0 & 0x100 )
+ {
+ int tile_number = data1 & 0xfff;
+ int color = ( data2 & 0x7800 ) >> 11;
+ int sy = ( data0 & 0xff );
+ int sx = ( data2 & 0x1ff );
+ int flipx = ( data2 & 0x0400 );
+ int flipy = 0;
+
+ if ( sx>256 ) sx -= 512;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx( bitmap,machine->gfx[2],
+ tile_number,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0xf );
+ }
+ }
+}
+
+
+VIDEO_UPDATE( cabal )
+{
+ tilemap_draw(bitmap,cliprect,background_layer,TILEMAP_DRAW_OPAQUE,0);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,text_layer,0,0);
+ return 0;
+}
+
+
diff --git a/src/mame/video/canyon.c b/src/mame/video/canyon.c
new file mode 100644
index 00000000000..8055c34ff60
--- /dev/null
+++ b/src/mame/video/canyon.c
@@ -0,0 +1,97 @@
+/***************************************************************************
+
+Atari Canyon Bomber video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/canyon.h"
+
+static tilemap *bg_tilemap;
+
+UINT8* canyon_videoram;
+
+
+WRITE8_HANDLER( canyon_videoram_w )
+{
+ canyon_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 code = canyon_videoram[tile_index];
+
+ SET_TILE_INFO(0, code & 0x3f, code >> 7, 0);
+}
+
+
+VIDEO_START( canyon )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle* cliprect)
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ {
+ int x = canyon_videoram[0x3d0 + 2 * i + 0x1];
+ int y = canyon_videoram[0x3d0 + 2 * i + 0x8];
+ int c = canyon_videoram[0x3d0 + 2 * i + 0x9];
+
+ drawgfx(bitmap, machine->gfx[1],
+ c >> 3,
+ i,
+ !(c & 0x80), 0,
+ 224 - x,
+ 240 - y,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+}
+
+
+static void draw_bombs(mame_bitmap *bitmap, const rectangle* cliprect)
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ {
+ int sx = 254 - canyon_videoram[0x3d0 + 2 * i + 0x5];
+ int sy = 246 - canyon_videoram[0x3d0 + 2 * i + 0xc];
+
+ rectangle rect;
+
+ rect.min_x = sx;
+ rect.min_y = sy;
+ rect.max_x = sx + 1;
+ rect.max_y = sy + 1;
+
+ if (rect.min_x < cliprect->min_x) rect.min_x = cliprect->min_x;
+ if (rect.min_y < cliprect->min_y) rect.min_y = cliprect->min_y;
+ if (rect.max_x > cliprect->max_x) rect.max_x = cliprect->max_x;
+ if (rect.max_y > cliprect->max_y) rect.max_y = cliprect->max_y;
+
+ fillbitmap(bitmap, i, &rect);
+ }
+}
+
+
+VIDEO_UPDATE( canyon )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ draw_sprites(machine, bitmap, cliprect);
+
+ draw_bombs(bitmap, cliprect);
+
+ /* watchdog is disabled during service mode */
+ watchdog_enable(!(readinputport(2) & 0x10));
+
+ return 0;
+}
diff --git a/src/mame/video/capbowl.c b/src/mame/video/capbowl.c
new file mode 100644
index 00000000000..54b93f0d19e
--- /dev/null
+++ b/src/mame/video/capbowl.c
@@ -0,0 +1,197 @@
+/***************************************************************************
+
+ Coors Light Bowling/Bowl-O-Rama hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/tms34061.h"
+#include "cpu/m6809/m6809.h"
+#include "capbowl.h"
+
+UINT8 *capbowl_rowaddress;
+
+static offs_t blitter_addr;
+
+
+
+/*************************************
+ *
+ * TMS34061 interfacing
+ *
+ *************************************/
+
+static void generate_interrupt(int state)
+{
+ cpunum_set_input_line(0, M6809_FIRQ_LINE, state);
+}
+
+static struct tms34061_interface tms34061intf =
+{
+ 0, /* the screen we are acting on */
+ 8, /* VRAM address is (row << rowshift) | col */
+ 0x10000, /* size of video RAM */
+ generate_interrupt /* interrupt gen callback */
+};
+
+
+
+/*************************************
+ *
+ * Video start
+ *
+ *************************************/
+
+VIDEO_START( capbowl )
+{
+ /* initialize TMS34061 emulation */
+ tms34061_start(&tms34061intf);
+}
+
+
+
+/*************************************
+ *
+ * TMS34061 I/O
+ *
+ *************************************/
+
+WRITE8_HANDLER( capbowl_tms34061_w )
+{
+ int func = (offset >> 8) & 3;
+ int col = offset & 0xff;
+
+ /* Column address (CA0-CA8) is hooked up the A0-A7, with A1 being inverted
+ during register access. CA8 is ignored */
+ if (func == 0 || func == 2)
+ col ^= 2;
+
+ /* Row address (RA0-RA8) is not dependent on the offset */
+ tms34061_w(col, *capbowl_rowaddress, func, data);
+}
+
+
+READ8_HANDLER( capbowl_tms34061_r )
+{
+ int func = (offset >> 8) & 3;
+ int col = offset & 0xff;
+
+ /* Column address (CA0-CA8) is hooked up the A0-A7, with A1 being inverted
+ during register access. CA8 is ignored */
+ if (func == 0 || func == 2)
+ col ^= 2;
+
+ /* Row address (RA0-RA8) is not dependent on the offset */
+ return tms34061_r(col, *capbowl_rowaddress, func);
+}
+
+
+
+/*************************************
+ *
+ * Bowl-o-rama blitter
+ *
+ *************************************/
+
+WRITE8_HANDLER( bowlrama_blitter_w )
+{
+ switch (offset)
+ {
+ case 0x08: /* Write address high byte (only 2 bits used) */
+ blitter_addr = (blitter_addr & ~0xff0000) | (data << 16);
+ break;
+
+ case 0x17: /* Write address mid byte (8 bits) */
+ blitter_addr = (blitter_addr & ~0x00ff00) | (data << 8);
+ break;
+
+ case 0x18: /* Write Address low byte (8 bits) */
+ blitter_addr = (blitter_addr & ~0x0000ff) | (data << 0);
+ break;
+
+ default:
+ logerror("PC=%04X Write to unsupported blitter address %02X Data=%02X\n", activecpu_get_pc(), offset, data);
+ break;
+ }
+}
+
+
+READ8_HANDLER( bowlrama_blitter_r )
+{
+ UINT8 data = memory_region(REGION_GFX1)[blitter_addr];
+ UINT8 result = 0;
+
+ switch (offset)
+ {
+ /* Read Mask: Graphics data are 4bpp (2 pixels per byte).
+ This function returns 0's for new pixel data.
+ This allows data to be read as a mask, AND the mask with
+ the screen data, then OR new data read by read data command. */
+ case 0:
+ if (!(data & 0xf0))
+ result |= 0xf0; /* High nibble is transparent */
+ if (!(data & 0x0f))
+ result |= 0x0f; /* Low nibble is transparent */
+ break;
+
+ /* Read data and increment address */
+ case 4:
+ result = data;
+ blitter_addr = (blitter_addr + 1) & 0x3ffff;
+ break;
+
+ default:
+ logerror("PC=%04X Read from unsupported blitter address %02X\n", activecpu_get_pc(), offset);
+ break;
+ }
+
+ return result;
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( capbowl )
+{
+ struct tms34061_display state;
+ int x, y;
+
+ /* first get the current display state */
+ tms34061_get_display_state(&state);
+
+ /* if we're blanked, just fill with black */
+ if (state.blanked)
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* now regenerate the bitmap */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ UINT8 *src = &state.vram[256 * y];
+ int ybase = 16 * y;
+
+ /* first update the palette for this scanline */
+ for (x = 0; x < 16; x++)
+ {
+ palette_set_color_rgb(machine, ybase + x, pal4bit(src[0]), pal4bit(src[1] >> 4), pal4bit(src[1]));
+ src += 2;
+ }
+
+ /* expand row to 8bpp */
+ for (x = cliprect->min_x & ~1; x <= cliprect->max_x; x += 2)
+ {
+ int pix = src[x/2];
+ *dest++ = ybase + (pix >> 4);
+ *dest++ = ybase + (pix & 0x0f);
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/carjmbre.c b/src/mame/video/carjmbre.c
new file mode 100644
index 00000000000..db939fcc791
--- /dev/null
+++ b/src/mame/video/carjmbre.c
@@ -0,0 +1,148 @@
+/*
+Car Jamboree
+Omori Electric CAD (OEC) 1981
+*/
+
+#include "driver.h"
+
+static tilemap *carjmbre_tilemap;
+
+static UINT8 carjmbre_flipscreen;
+static UINT16 carjmbre_bgcolor;
+
+PALETTE_INIT( carjmbre )
+{
+ int i,bit0,bit1,bit2,r,g,b;
+
+ for (i = 0;i < machine->drv->total_colors; i++)
+ {
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( carjmbre_flipscreen_w )
+{
+ carjmbre_flipscreen = data?(TILEMAP_FLIPX|TILEMAP_FLIPY):0;
+ tilemap_set_flip( ALL_TILEMAPS,carjmbre_flipscreen );
+}
+
+WRITE8_HANDLER( carjmbre_bgcolor_w )
+{
+ int oldbg,i;
+
+ oldbg=carjmbre_bgcolor;
+
+ carjmbre_bgcolor&=0xff00>>(offset*8);
+ carjmbre_bgcolor|=((~data)&0xff)<<(offset*8);
+
+ if(oldbg!=carjmbre_bgcolor)
+ {
+ memset(dirtybuffer,1,videoram_size);
+
+ for (i=0;i<64;i+=4)
+ palette_set_color_rgb(Machine, i, (carjmbre_bgcolor&0xff)*0x50, (carjmbre_bgcolor&0xff)*0x50, (carjmbre_bgcolor&0xff)!=0?0x50:0);
+ }
+}
+
+static TILE_GET_INFO( get_carjmbre_tile_info ){
+ UINT32 tile_number = videoram[tile_index] & 0xFF;
+ UINT8 attr = videoram[tile_index+0x400];
+ tile_number += (attr & 0x80) << 1; /* bank */
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ (attr&0x7),
+ 0);
+}
+
+WRITE8_HANDLER( carjmbre_videoram_w ){
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(carjmbre_tilemap,offset&0x3ff);
+}
+
+
+
+VIDEO_START( carjmbre )
+{
+
+ carjmbre_tilemap = tilemap_create( get_carjmbre_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+
+ state_save_register_global(carjmbre_flipscreen);
+ state_save_register_global(carjmbre_bgcolor);
+}
+
+VIDEO_UPDATE( carjmbre )
+{
+ int offs,troffs,sx,sy,flipx,flipy;
+
+ //colorram
+ //76543210
+ //x------- graphic bank
+ //-xxx---- unused
+ //----x--- ?? probably colour, only used for ramp and pond
+ //-----xxx colour
+
+ tilemap_draw( bitmap,cliprect,carjmbre_tilemap,0,0 );
+
+ //spriteram[offs]
+ //+0 y pos
+ //+1 sprite number
+ //+2
+ //76543210
+ //x------- flipy
+ //-x------ flipx
+ //--xx---- unused
+ //----x--- ?? probably colour
+ //-----xxx colour
+ //+3 x pos
+ for (offs = spriteram_size-4; offs >= 0; offs-=4)
+ {
+ //before copying the sprites to spriteram the game reorders the first
+ //sprite to last, sprite ordering is incorrect if this isn't undone
+ troffs=(offs-4+spriteram_size)%spriteram_size;
+
+ //unused sprites are marked with ypos <= 0x02 (or >= 0xfd if screen flipped)
+ if (spriteram[troffs] > 0x02 && spriteram[troffs] < 0xfd)
+ {
+ {
+ sx = spriteram[troffs+3]-7;
+ sy = 241-spriteram[troffs];
+ flipx = (spriteram[troffs+2]&0x40)>>6;
+ flipy = (spriteram[troffs+2]&0x80)>>7;
+
+ if (carjmbre_flipscreen)
+ {
+ sx = (256+(226-sx))%256;
+ sy = 242-sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ spriteram[troffs+1],
+ spriteram[troffs+2]&0x07,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/carpolo.c b/src/mame/video/carpolo.c
new file mode 100644
index 00000000000..d13e8de2e85
--- /dev/null
+++ b/src/mame/video/carpolo.c
@@ -0,0 +1,833 @@
+/***************************************************************************
+
+ Exidy Car Polo hardware
+
+ driver by Zsolt Vasvari
+
+****************************************************************************/
+
+#include "driver.h"
+#include "carpolo.h"
+
+
+UINT8 *carpolo_alpharam;
+UINT8 *carpolo_spriteram;
+
+
+/* the screen elements' priorties determine their color */
+#define BACKGROUND_COLOR 0
+#define FIELD_COLOR 1
+#define CAR1_COLOR 2
+#define LINE_COLOR 3
+#define CAR4_COLOR 4
+#define CAR3_COLOR 5
+#define CAR2_COLOR 6
+#define BALL_COLOR 7
+#define NET_COLOR 8
+#define LEFT_GOAL_COLOR 9
+#define RIGHT_GOAL_COLOR 10
+#define SPECIAL_CHAR_COLOR 11
+#define ALPHA0_COLOR 12
+#define ALPHA1_COLOR 13
+#define ALPHA2_COLOR 14
+#define ALPHA3_COLOR 15
+
+#define SCORE_COLOR 16 /* this is only used for collision detection purposes */
+
+#define SPRITE_WIDTH 16
+#define SPRITE_HEIGHT 16
+#define GOAL_WIDTH 16
+#define GOAL_HEIGHT 64
+
+#define LEFT_GOAL_X 2*16-8
+#define RIGHT_GOAL_X 13*16-8
+#define GOAL_Y 7*16
+
+#define TOP_BORDER 16
+#define BOTTOM_BORDER 255
+#define LEFT_BORDER 0
+#define RIGHT_BORDER 239
+
+
+static mame_bitmap *sprite_sprite_collision_bitmap1;
+static mame_bitmap *sprite_sprite_collision_bitmap2;
+static mame_bitmap *sprite_goal_collision_bitmap1;
+static mame_bitmap *sprite_goal_collision_bitmap2;
+static mame_bitmap *sprite_border_collision_bitmap;
+
+
+/***************************************************************************
+ *
+ * Palette generation
+ *
+ * The palette PROM is connected to the RGB output this way.
+ *
+ * bit 0 -- 220 ohm resistor -- BLUE (probably an error on schematics)
+ * -- 470 ohm resistor -- BLUE (probably an error on schematics)
+ * -- 220 ohm resistor -- GREEN
+ * -- 470 ohm resistor -- GREEN
+ * -- 1 kohm resistor -- GREEN
+ * -- 220 ohm resistor -- RED
+ * -- 470 ohm resistor -- RED
+ * bit 7 -- 1 kohm resistor -- RED
+ *
+ **************************************************************************/
+
+PALETTE_INIT( carpolo )
+{
+ /* thanks to Jarek Burczynski for analyzing the circuit */
+// const static float MAX_VOLTAGE = 6.9620;
+ const static float MIN_VOLTAGE = 1.7434;
+ const static float MAX_VOLTAGE = 5.5266;
+
+ const static float r_voltage[] = { 1.7434, 2.1693, 2.5823, 3.0585,
+ 3.4811, 4.0707, 4.7415, 5.4251 };
+
+ const static float g_voltage[] = { 1.7434, 2.1693, 2.5823, 3.0585,
+ 3.4811, 4.0707, 4.7415, 5.4251 };
+// const static float g_voltage[] = { 4.7871, 5.0613, 5.3079, 5.6114,
+// 5.7940, 6.1608, 6.5436, 6.9620 };
+
+ const static float b_voltage[] = { 1.9176, 2.8757, 3.9825, 5.5266 };
+
+
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ /* the -1 is for the fake score color */
+ for (i = 0; i < machine->drv->total_colors - 1; i++)
+ {
+ UINT8 r,g,b;
+ int bit0,bit1,bit2;
+
+ /* red component */
+ bit0 = (*color_prom >> 7) & 0x01;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ //r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ r = ((r_voltage[*color_prom >> 5 ] - MIN_VOLTAGE) / (MAX_VOLTAGE - MIN_VOLTAGE)) * 255.;
+ /* green component */
+ bit0 = (*color_prom >> 4) & 0x01;
+ bit1 = (*color_prom >> 3) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ //g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ g = ((g_voltage[(*color_prom >> 2) & 0x07] - MIN_VOLTAGE) / (MAX_VOLTAGE - MIN_VOLTAGE)) * 255.;
+ /* blue component */
+ bit0 = (*color_prom >> 1) & 0x01;
+ bit1 = (*color_prom >> 0) & 0x01;
+ //b = 0x4f * bit0 + 0xa8 * bit1;
+ b = ((b_voltage[*color_prom & 0x03 ] - MIN_VOLTAGE) / (MAX_VOLTAGE - MIN_VOLTAGE)) * 255.;
+
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ // score color is same as net color
+ if (i == NET_COLOR)
+ {
+ palette_set_color(machine,SCORE_COLOR,MAKE_RGB(r,g,b));
+ }
+
+ color_prom++;
+ }
+
+
+ /* sprite colors */
+ for (i = 0; i < TOTAL_COLORS(0) / 2; i++)
+ {
+ COLOR(0,i*2+1) = i;
+ }
+
+
+ /* the bits in the goal gfx PROM are hooked as follows (all active LO):
+ Bit 3 - goal post
+ Bit 2 - scoring area
+ Bit 1 - net
+ Bit 0 - n/c
+
+ Below I am only filling in the colors actually used. */
+
+ /* left goal */
+ COLOR(1, (0x07 ^ 0x0f)) = LEFT_GOAL_COLOR;
+ COLOR(1, (0x0d ^ 0x0f)) = NET_COLOR;
+ COLOR(1, (0x09 ^ 0x0f)) = SCORE_COLOR;
+
+ /* right goal */
+ COLOR(1, (16 + (0x07 ^ 0x0f))) = RIGHT_GOAL_COLOR;
+ COLOR(1, (16 + (0x0d ^ 0x0f))) = NET_COLOR;
+ COLOR(1, (16 + (0x09 ^ 0x0f))) = SCORE_COLOR;
+
+ /* alpha layer */
+ COLOR(2, 0*2+1) = ALPHA0_COLOR;
+ COLOR(2, 1*2+1) = ALPHA1_COLOR;
+ COLOR(2, 2*2+1) = ALPHA2_COLOR;
+ COLOR(2, 3*2+1) = ALPHA3_COLOR;
+}
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( carpolo )
+{
+ sprite_sprite_collision_bitmap1 = auto_bitmap_alloc(SPRITE_WIDTH*2,SPRITE_HEIGHT*2,machine->screen[0].format);
+ sprite_sprite_collision_bitmap2 = auto_bitmap_alloc(SPRITE_WIDTH*2,SPRITE_HEIGHT*2,machine->screen[0].format);
+
+ sprite_goal_collision_bitmap1 = auto_bitmap_alloc(SPRITE_WIDTH+GOAL_WIDTH,SPRITE_HEIGHT+GOAL_HEIGHT,machine->screen[0].format);
+ sprite_goal_collision_bitmap2 = auto_bitmap_alloc(SPRITE_WIDTH+GOAL_WIDTH,SPRITE_HEIGHT+GOAL_HEIGHT,machine->screen[0].format);
+
+ sprite_border_collision_bitmap = auto_bitmap_alloc(SPRITE_WIDTH,SPRITE_HEIGHT,machine->screen[0].format);
+}
+
+
+/*************************************
+ *
+ * Core video refresh
+ *
+ *************************************/
+
+static void draw_alpha_line(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect,
+ int alpha_line, int video_line)
+{
+ int x;
+
+
+ for (x = 0; x < 32; x++)
+ {
+ UINT8 code, col;
+
+ code = carpolo_alpharam[alpha_line * 32 + x] >> 2;
+ col = carpolo_alpharam[alpha_line * 32 + x] & 0x03;
+
+ drawgfx(bitmap,machine->gfx[2],
+ code,col,
+ 0,0,
+ x*8,video_line*8,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+static void remap_sprite_code(int bank, int code, int *remapped_code, int *flipy)
+{
+ UINT8 *PROM;
+
+
+ PROM = memory_region(REGION_USER1);
+
+ code = (bank << 4) | code;
+ *remapped_code = PROM[code] & 0x0f;
+ *flipy = (PROM[code] & 0x10) >> 4;
+}
+
+
+static void draw_sprite(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect,
+ UINT8 x, UINT8 y, int bank, int code, int col)
+{
+ int remapped_code, flipy;
+
+
+ remap_sprite_code(bank, code, &remapped_code, &flipy);
+
+ x = 240 - x;
+ y = 240 - y;
+
+ drawgfx(bitmap,machine->gfx[0],
+ remapped_code, col,
+ 0, flipy,
+ x, y,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ /* draw with wrap around */
+ drawgfx(bitmap,machine->gfx[0],
+ remapped_code, col,
+ 0, flipy,
+ (INT16)x - 256, y,
+ cliprect,TRANSPARENCY_PEN,0);
+}
+
+
+VIDEO_UPDATE( carpolo )
+{
+ /* draw the playfield elements, in the correct priority order */
+
+ /* score area - position determined by bit 4 of the vertical timing PROM */
+ plot_box(bitmap,0,0,RIGHT_BORDER+1,TOP_BORDER,machine->pens[BACKGROUND_COLOR]);
+
+ /* field */
+ plot_box(bitmap,0,TOP_BORDER,RIGHT_BORDER+1,BOTTOM_BORDER-TOP_BORDER+1,machine->pens[FIELD_COLOR]);
+
+ /* car 1 */
+ draw_sprite(machine, bitmap, cliprect,
+ carpolo_spriteram[0x00], carpolo_spriteram[0x01],
+ 0, carpolo_spriteram[0x0c] & 0x0f, CAR1_COLOR);
+
+ /* border - position determined by bit 4 and 7 of the vertical timing PROM */
+ plot_box(bitmap,0,TOP_BORDER, RIGHT_BORDER+1,1,machine->pens[LINE_COLOR]);
+ plot_box(bitmap,0,BOTTOM_BORDER,RIGHT_BORDER+1,1,machine->pens[LINE_COLOR]);
+ plot_box(bitmap,LEFT_BORDER,TOP_BORDER, 1,BOTTOM_BORDER-TOP_BORDER+1,machine->pens[LINE_COLOR]);
+ plot_box(bitmap,RIGHT_BORDER,TOP_BORDER,1,BOTTOM_BORDER-TOP_BORDER+1,machine->pens[LINE_COLOR]);
+
+ /* car 4 */
+ draw_sprite(machine, bitmap, cliprect,
+ carpolo_spriteram[0x06], carpolo_spriteram[0x07],
+ 0, carpolo_spriteram[0x0d] >> 4, CAR4_COLOR);
+
+ /* car 3 */
+ draw_sprite(machine, bitmap, cliprect,
+ carpolo_spriteram[0x04], carpolo_spriteram[0x05],
+ 0, carpolo_spriteram[0x0d] & 0x0f, CAR3_COLOR);
+
+ /* car 2 */
+ draw_sprite(machine, bitmap, cliprect,
+ carpolo_spriteram[0x02], carpolo_spriteram[0x03],
+ 0, carpolo_spriteram[0x0c] >> 4, CAR2_COLOR);
+
+ /* ball */
+ draw_sprite(machine, bitmap, cliprect,
+ carpolo_spriteram[0x08], carpolo_spriteram[0x09],
+ 1, carpolo_spriteram[0x0e] & 0x0f, BALL_COLOR);
+
+ /* left goal - position determined by bit 6 of the
+ horizontal and vertical timing PROMs */
+ drawgfxzoom(bitmap,machine->gfx[1],
+ 0,0,
+ 0,0,
+ LEFT_GOAL_X,GOAL_Y,
+ cliprect,TRANSPARENCY_PEN,0,
+ 0x20000,0x20000);
+
+ /* right goal */
+ drawgfxzoom(bitmap,machine->gfx[1],
+ 0,1,
+ 1,0,
+ RIGHT_GOAL_X,GOAL_Y,
+ cliprect,TRANSPARENCY_PEN,0,
+ 0x20000,0x20000);
+
+ /* special char - bit 0 of 0x0f enables it,
+ bit 1 marked as WIDE, but never appears to be set */
+ if (carpolo_spriteram[0x0f] & 0x02)
+ {
+ logerror("WIDE!\n");
+ }
+
+ if (carpolo_spriteram[0x0f] & 0x01)
+ {
+ draw_sprite(machine, bitmap, cliprect,
+ carpolo_spriteram[0x0a], carpolo_spriteram[0x0b],
+ 1, carpolo_spriteram[0x0e] >> 4, SPECIAL_CHAR_COLOR);
+ }
+
+
+ /* draw the alpha layer */
+
+ /* there are only 8 lines of text repeated 4 times
+ and bit 3 of the vertical timing PROM controls in
+ which quadrant the line will actually appear */
+
+ draw_alpha_line(machine, bitmap, cliprect, 0, (0*4+0)*2 );
+ draw_alpha_line(machine, bitmap, cliprect, 1, (0*4+0)*2+1);
+ draw_alpha_line(machine, bitmap, cliprect, 2, (3*4+1)*2 );
+ draw_alpha_line(machine, bitmap, cliprect, 3, (3*4+1)*2+1);
+ draw_alpha_line(machine, bitmap, cliprect, 4, (1*4+2)*2 );
+ draw_alpha_line(machine, bitmap, cliprect, 5, (1*4+2)*2+1);
+ draw_alpha_line(machine, bitmap, cliprect, 6, (0*4+3)*2 );
+ draw_alpha_line(machine, bitmap, cliprect, 7, (0*4+3)*2+1);
+ return 0;
+}
+
+
+/*************************************
+ *
+ * End of frame callback
+ *
+ *************************************/
+
+static void normalize_coordinates(int *x1, int *y1, int *x2, int *y2)
+{
+ if (*x1 < *x2)
+ {
+ *x2 = *x2 - *x1;
+ *x1 = 0;
+ }
+ else
+ {
+ *x1 = *x1 - *x2;
+ *x2 = 0;
+ }
+
+ if (*y1 < *y2)
+ {
+ *y2 = *y2 - *y1;
+ *y1 = 0;
+ }
+ else
+ {
+ *y1 = *y1 - *y2;
+ *y2 = 0;
+ }
+}
+
+
+static int check_sprite_sprite_collision(running_machine *machine,
+ int x1, int y1, int code1, int flipy1,
+ int x2, int y2, int code2, int flipy2,
+ int *col_x, int *col_y)
+{
+ int collided = 0;
+
+
+ x1 = 240 - x1;
+ y1 = 240 - y1;
+ x2 = 240 - x2;
+ y2 = 240 - y2;
+
+
+ // check if the two sprites are within collision range
+ if ((abs(x1 - x2) < SPRITE_WIDTH) && (abs(y1 - y2) < SPRITE_HEIGHT))
+ {
+ int x,y;
+
+
+ normalize_coordinates(&x1, &y1, &x2, &y2);
+
+ fillbitmap(sprite_sprite_collision_bitmap1, machine->pens[0], 0);
+ fillbitmap(sprite_sprite_collision_bitmap2, machine->pens[0], 0);
+
+ drawgfx(sprite_sprite_collision_bitmap1,machine->gfx[0],
+ code1,1,
+ 0,flipy1,
+ x1,y1,
+ 0,TRANSPARENCY_PEN,0);
+
+ drawgfx(sprite_sprite_collision_bitmap2,machine->gfx[0],
+ code2,1,
+ 0,flipy2,
+ x2,y2,
+ 0,TRANSPARENCY_PEN,0);
+
+
+ for (x = x1; x < x1 + SPRITE_WIDTH; x++)
+ {
+ for (y = y1; y < y1 + SPRITE_HEIGHT; y++)
+ {
+ if ((*BITMAP_ADDR16(sprite_sprite_collision_bitmap1, y, x) == machine->pens[1]) &&
+ (*BITMAP_ADDR16(sprite_sprite_collision_bitmap2, y, x) == machine->pens[1]))
+ {
+ *col_x = (x1 + x) & 0x0f;
+ *col_y = (y1 + y) & 0x0f;
+
+ collided = 1;
+
+ break;
+ }
+ }
+ }
+ }
+
+ return collided;
+}
+
+
+/* returns 1 for collision with goal post,
+ 2 for collision with scoring area */
+static int check_sprite_left_goal_collision(running_machine *machine, int x1, int y1, int code1, int flipy1, int goalpost_only)
+{
+ int collided = 0;
+
+
+ x1 = 240 - x1;
+ y1 = 240 - y1;
+
+
+ // check if the sprites is within the range of the goal
+ if (((y1 + 16) > GOAL_Y) && (y1 < (GOAL_Y + GOAL_HEIGHT)) &&
+ ((x1 + 16) > LEFT_GOAL_X) && (x1 < (LEFT_GOAL_X + GOAL_WIDTH)))
+ {
+ int x,y;
+ int x2,y2;
+
+
+ x2 = LEFT_GOAL_X;
+ y2 = GOAL_Y;
+
+ normalize_coordinates(&x1, &y1, &x2, &y2);
+
+ fillbitmap(sprite_goal_collision_bitmap1, machine->pens[0], 0);
+ fillbitmap(sprite_goal_collision_bitmap2, machine->pens[0], 0);
+
+ drawgfx(sprite_goal_collision_bitmap1,machine->gfx[0],
+ code1,1,
+ 0,flipy1,
+ x1,y1,
+ 0,TRANSPARENCY_PEN,0);
+
+ drawgfxzoom(sprite_goal_collision_bitmap2,machine->gfx[1],
+ 0,0,
+ 0,0,
+ x2,y2,
+ 0,TRANSPARENCY_PEN,0,
+ 0x20000,0x20000);
+
+ for (x = x1; x < x1 + SPRITE_WIDTH; x++)
+ {
+ for (y = y1; y < y1 + SPRITE_HEIGHT; y++)
+ {
+ if ((*BITMAP_ADDR16(sprite_goal_collision_bitmap1, y, x) == machine->pens[1]))
+ {
+ pen_t pix = *BITMAP_ADDR16(sprite_goal_collision_bitmap2, y, x);
+
+ if (pix == machine->pens[LEFT_GOAL_COLOR])
+ {
+ collided = 1;
+ break;
+ }
+
+ if (!goalpost_only && (pix == machine->pens[SCORE_COLOR]))
+ {
+ collided = 2;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return collided;
+}
+
+
+static int check_sprite_right_goal_collision(running_machine *machine, int x1, int y1, int code1, int flipy1, int goalpost_only)
+{
+ int collided = 0;
+
+
+ x1 = 240 - x1;
+ y1 = 240 - y1;
+
+
+ // check if the sprites is within the range of the goal
+ if (((y1 + 16) > GOAL_Y) && (y1 < (GOAL_Y + GOAL_HEIGHT)) &&
+ ((x1 + 16) > RIGHT_GOAL_X) && (x1 < (RIGHT_GOAL_X + GOAL_WIDTH)))
+ {
+ int x,y;
+ int x2,y2;
+
+
+ x2 = RIGHT_GOAL_X;
+ y2 = GOAL_Y;
+
+ normalize_coordinates(&x1, &y1, &x2, &y2);
+
+ fillbitmap(sprite_goal_collision_bitmap1, machine->pens[0], 0);
+ fillbitmap(sprite_goal_collision_bitmap2, machine->pens[0], 0);
+
+ drawgfx(sprite_goal_collision_bitmap1,machine->gfx[0],
+ code1,1,
+ 0,flipy1,
+ x1,y1,
+ 0,TRANSPARENCY_PEN,0);
+
+ drawgfxzoom(sprite_goal_collision_bitmap2,machine->gfx[1],
+ 0,1,
+ 1,0,
+ x2,y2,
+ 0,TRANSPARENCY_PEN,0,
+ 0x20000,0x20000);
+
+ for (x = x1; x < x1 + SPRITE_WIDTH; x++)
+ {
+ for (y = y1; y < y1 + SPRITE_HEIGHT; y++)
+ {
+ if ((*BITMAP_ADDR16(sprite_goal_collision_bitmap1, y, x) == machine->pens[1]))
+ {
+ pen_t pix = *BITMAP_ADDR16(sprite_goal_collision_bitmap2, y, x);
+
+ if (pix == machine->pens[RIGHT_GOAL_COLOR])
+ {
+ collided = 1;
+ break;
+ }
+
+ if (!goalpost_only && (pix == machine->pens[SCORE_COLOR]))
+ {
+ collided = 2;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return collided;
+}
+
+
+/* returns 1 for collision with vertical border,
+ 2 for collision with horizontal border */
+static int check_sprite_border_collision(running_machine *machine, UINT8 x1, UINT8 y1, int code1, int flipy1)
+{
+ UINT8 x,y;
+ int collided = 0;
+
+
+ x1 = 240 - x1;
+ y1 = 240 - y1;
+
+
+ fillbitmap(sprite_border_collision_bitmap, machine->pens[0], 0);
+
+ drawgfx(sprite_border_collision_bitmap,machine->gfx[0],
+ code1,1,
+ 0,flipy1,
+ 0,0,
+ 0,TRANSPARENCY_PEN,0);
+
+ for (x = 0; x < SPRITE_WIDTH; x++)
+ {
+ for (y = 0; y < SPRITE_HEIGHT; y++)
+ {
+ if ((*BITMAP_ADDR16(sprite_border_collision_bitmap, y, x) == machine->pens[1]))
+ {
+ if (((UINT8)(x1 + x) == LEFT_BORDER) ||
+ ((UINT8)(x1 + x) == RIGHT_BORDER))
+ {
+ collided = 1;
+ break;
+ }
+
+ if (((UINT8)(y1 + y) == TOP_BORDER) ||
+ ((UINT8)(y1 + y) == BOTTOM_BORDER))
+ {
+ collided = 2;
+ break;
+ }
+ }
+ }
+ }
+
+ return collided;
+}
+
+
+VIDEO_EOF( carpolo )
+{
+ int col_x, col_y;
+ int car1_x, car2_x, car3_x, car4_x, ball_x;
+ int car1_y, car2_y, car3_y, car4_y, ball_y;
+ int car1_code, car2_code, car3_code, car4_code, ball_code;
+ int car1_flipy, car2_flipy, car3_flipy, car4_flipy, ball_flipy;
+
+
+ // check car-car collision first
+
+ car1_x = carpolo_spriteram[0x00];
+ car1_y = carpolo_spriteram[0x01];
+ remap_sprite_code(0, carpolo_spriteram[0x0c] & 0x0f, &car1_code, &car1_flipy);
+
+ car2_x = carpolo_spriteram[0x02];
+ car2_y = carpolo_spriteram[0x03];
+ remap_sprite_code(0, carpolo_spriteram[0x0c] >> 4, &car2_code, &car2_flipy);
+
+ car3_x = carpolo_spriteram[0x04];
+ car3_y = carpolo_spriteram[0x05];
+ remap_sprite_code(0, carpolo_spriteram[0x0d] & 0x0f, &car3_code, &car3_flipy);
+
+ car4_x = carpolo_spriteram[0x06];
+ car4_y = carpolo_spriteram[0x07];
+ remap_sprite_code(0, carpolo_spriteram[0x0d] >> 4, &car4_code, &car4_flipy);
+
+ ball_x = carpolo_spriteram[0x08];
+ ball_y = carpolo_spriteram[0x09];
+ remap_sprite_code(1, carpolo_spriteram[0x0e] & 0x0f, &ball_code, &ball_flipy);
+
+
+ // cars 1 and 2
+ if (check_sprite_sprite_collision(machine,
+ car1_x, car1_y, car1_code, car1_flipy,
+ car2_x, car2_y, car2_code, car2_flipy,
+ &col_x, &col_y))
+ {
+ carpolo_generate_car_car_interrupt(0, 1);
+ }
+
+ // cars 1 and 3
+ else if (check_sprite_sprite_collision(machine,
+ car1_x, car1_y, car1_code, car1_flipy,
+ car3_x, car3_y, car3_code, car3_flipy,
+ &col_x, &col_y))
+ {
+ carpolo_generate_car_car_interrupt(0, 2);
+ }
+
+ // cars 1 and 4
+ else if (check_sprite_sprite_collision(machine,
+ car1_x, car1_y, car1_code, car1_flipy,
+ car4_x, car4_y, car4_code, car4_flipy,
+ &col_x, &col_y))
+ {
+ carpolo_generate_car_car_interrupt(0, 3);
+ }
+
+ // cars 2 and 3
+ else if (check_sprite_sprite_collision(machine,
+ car2_x, car2_y, car2_code, car2_flipy,
+ car3_x, car3_y, car3_code, car3_flipy,
+ &col_x, &col_y))
+ {
+ carpolo_generate_car_car_interrupt(1, 2);
+ }
+
+ // cars 2 and 4
+ else if (check_sprite_sprite_collision(machine,
+ car2_x, car2_y, car2_code, car2_flipy,
+ car4_x, car4_y, car4_code, car4_flipy,
+ &col_x, &col_y))
+ {
+ carpolo_generate_car_car_interrupt(1, 3);
+ }
+
+ // cars 3 and 4
+ else if (check_sprite_sprite_collision(machine,
+ car3_x, car3_y, car3_code, car3_flipy,
+ car4_x, car4_y, car4_code, car4_flipy,
+ &col_x, &col_y))
+ {
+ carpolo_generate_car_car_interrupt(2, 3);
+ }
+
+
+
+ // check car-ball collision
+ if (check_sprite_sprite_collision(machine,
+ car1_x, car1_y, car1_code, car1_flipy,
+ ball_x, ball_y, ball_code, ball_flipy,
+ &col_x, &col_y))
+ {
+ carpolo_generate_car_ball_interrupt(0, col_x, col_y);
+ }
+ else if (check_sprite_sprite_collision(machine,
+ car2_x, car2_y, car2_code, car2_flipy,
+ ball_x, ball_y, ball_code, ball_flipy,
+ &col_x, &col_y))
+ {
+ carpolo_generate_car_ball_interrupt(1, col_x, col_y);
+ }
+ else if (check_sprite_sprite_collision(machine,
+ car3_x, car3_y, car3_code, car3_flipy,
+ ball_x, ball_y, ball_code, ball_flipy,
+ &col_x, &col_y))
+ {
+ carpolo_generate_car_ball_interrupt(2, col_x, col_y);
+ }
+ else if (check_sprite_sprite_collision(machine,
+ car4_x, car4_y, car4_code, car4_flipy,
+ ball_x, ball_y, ball_code, ball_flipy,
+ &col_x, &col_y))
+ {
+ carpolo_generate_car_ball_interrupt(3, col_x, col_y);
+ }
+
+
+ // check car-goal collision
+ if (check_sprite_left_goal_collision(machine, car1_x, car1_y, car1_code, car1_flipy, 1))
+ {
+ carpolo_generate_car_goal_interrupt(0, 0);
+ }
+ else if (check_sprite_right_goal_collision(machine, car1_x, car1_y, car1_code, car1_flipy, 1))
+ {
+ carpolo_generate_car_goal_interrupt(0, 1);
+ }
+ else if (check_sprite_left_goal_collision(machine, car2_x, car2_y, car2_code, car2_flipy, 1))
+ {
+ carpolo_generate_car_goal_interrupt(1, 0);
+ }
+ else if (check_sprite_right_goal_collision(machine, car2_x, car2_y, car2_code, car2_flipy, 1))
+ {
+ carpolo_generate_car_goal_interrupt(1, 1);
+ }
+ else if (check_sprite_left_goal_collision(machine, car3_x, car3_y, car3_code, car3_flipy, 1))
+ {
+ carpolo_generate_car_goal_interrupt(2, 0);
+ }
+ else if (check_sprite_right_goal_collision(machine, car3_x, car3_y, car3_code, car3_flipy, 1))
+ {
+ carpolo_generate_car_goal_interrupt(2, 1);
+ }
+ else if (check_sprite_left_goal_collision(machine, car4_x, car4_y, car4_code, car4_flipy, 1))
+ {
+ carpolo_generate_car_goal_interrupt(3, 0);
+ }
+ else if (check_sprite_right_goal_collision(machine, car4_x, car4_y, car4_code, car4_flipy, 1))
+ {
+ carpolo_generate_car_goal_interrupt(3, 1);
+ }
+
+
+ // check ball collision with static screen elements
+ {
+ int col;
+
+ col = check_sprite_left_goal_collision(machine, ball_x, ball_y, ball_code, ball_flipy, 0);
+
+ if (col == 1) carpolo_generate_ball_screen_interrupt(0x05);
+ if (col == 2) carpolo_generate_ball_screen_interrupt(0x03);
+
+
+ col = check_sprite_right_goal_collision(machine, ball_x, ball_y, ball_code, ball_flipy, 0);
+
+ if (col == 1) carpolo_generate_ball_screen_interrupt(0x05 | 0x08);
+ if (col == 2) carpolo_generate_ball_screen_interrupt(0x03 | 0x08);
+
+
+ if (check_sprite_border_collision(machine, ball_x, ball_y, ball_code, ball_flipy))
+ {
+ carpolo_generate_ball_screen_interrupt(0x06);
+ }
+ }
+
+
+ // check car-border collision
+ {
+ int col;
+
+ col = check_sprite_border_collision(machine, car1_x, car1_y, car1_code, car1_flipy);
+
+ if (col)
+ {
+ carpolo_generate_car_border_interrupt(0, (col == 2));
+ }
+ else
+ {
+ col = check_sprite_border_collision(machine, car2_x, car2_y, car2_code, car2_flipy);
+
+ if (col)
+ {
+ carpolo_generate_car_border_interrupt(1, (col == 2));
+ }
+ else
+ {
+ col = check_sprite_border_collision(machine, car3_x, car3_y, car3_code, car3_flipy);
+
+ if (col)
+ {
+ carpolo_generate_car_border_interrupt(2, (col == 2));
+ }
+ else
+ {
+ col = check_sprite_border_collision(machine, car4_x, car4_y, car4_code, car4_flipy);
+
+ if (col)
+ {
+ carpolo_generate_car_border_interrupt(3, (col == 2));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/mame/video/cave.c b/src/mame/video/cave.c
new file mode 100644
index 00000000000..7636e3b250c
--- /dev/null
+++ b/src/mame/video/cave.c
@@ -0,0 +1,1544 @@
+/***************************************************************************
+
+ -= Cave Hardware =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing:
+
+ X/C/V/B/Z with Q shows layer 0 (tiles with priority 0/1/2/3/All)
+ X/C/V/B/Z with W shows layer 1 (tiles with priority 0/1/2/3/All)
+ X/C/V/B/Z with E shows layer 2 (tiles with priority 0/1/2/3/All)
+ X/C/V/B/Z with R shows layer 3 (tiles with priority 0/1/2/3/All)
+ X/C/V/B/Z with A shows sprites (tiles with priority 0/1/2/3/All)
+
+ Keys can be used together!
+
+ [ 1 Layer per chip (games use as many as 4 chips) ]
+
+ Layer Size: 512 x 512
+ Tiles: 8 x 8 & 16 x 16.
+
+ There are 2 tilemaps in memory, one per tiles dimension.
+ A bit decides which one gets displayed.
+ The tiles depth varies with games, from 16 to 256 colors.
+
+ A per layer row-scroll / row-select effect can be enabled:
+
+ a different scroll value is fetched (from tile RAM) for each
+ scan line, and a different tilemap line for each scan line
+
+ [ 1024 Zooming Sprites ]
+
+ There are 2 sprite RAMs. A hardware register's bit selects
+ the one to display (sprites double buffering).
+
+ The sprites are NOT tile based: the "tile" size and start address
+ is selectable for each sprite with a 16 pixel granularity.
+
+ Also note that the zoom is of a peculiar type: pixels are never
+ drawn more than once. So shrinking works as usual (some pixels are
+ just not drawn) while enlarging adds some transparent pixels to
+ the image, uniformly, to reach the final size.
+
+**************************************************************************/
+
+#include "driver.h"
+#include "cave.h"
+
+/* Variables that driver has access to: */
+
+int cave_spritetype;
+int cave_kludge = 0;
+
+UINT16 *cave_videoregs;
+
+UINT16 *cave_vram_0, *cave_vctrl_0;
+UINT16 *cave_vram_1, *cave_vctrl_1;
+UINT16 *cave_vram_2, *cave_vctrl_2;
+UINT16 *cave_vram_3, *cave_vctrl_3;
+
+/* Variables only used here: */
+
+static tilemap *tilemap_0;
+static int tiledim_0, old_tiledim_0;
+static tilemap *tilemap_1;
+static int tiledim_1, old_tiledim_1;
+static tilemap *tilemap_2;
+static int tiledim_2, old_tiledim_2;
+static tilemap *tilemap_3;
+static int tiledim_3, old_tiledim_3;
+
+
+
+#define CAVE_SPRITETYPE_ZBUF 0x01
+#define CAVE_SPRITETYPE_ZOOM 0x02
+static int cave_spritetype2;
+
+#define SPRITE_FLIPX_CAVE 0x01
+#define SPRITE_FLIPY_CAVE 0x02
+#define SPRITE_VISIBLE_CAVE 0x04
+#define SWAP(X,Y) { int temp = X; X = Y; Y = temp; }
+
+struct sprite_cave {
+ int priority, flags;
+
+ const UINT8 *pen_data; /* points to top left corner of tile data */
+ int line_offset;
+
+ const pen_t *pal_data;
+ int tile_width, tile_height;
+ int total_width, total_height; /* in screen coordinates */
+ int x, y, xcount0, ycount0;
+ int zoomx_re, zoomy_re;
+};
+
+static int screen_width, screen_height;
+
+static struct {
+ int clip_left, clip_right, clip_top, clip_bottom;
+ UINT8 *baseaddr;
+ int line_offset;
+ UINT8 *baseaddr_zbuf;
+ int line_offset_zbuf;
+} blit;
+
+#define MAX_PRIORITY 4
+#define MAX_SPRITE_NUM 0x400
+static int num_sprites;
+static struct sprite_cave *sprite_cave;
+static struct sprite_cave *sprite_table[MAX_PRIORITY][MAX_SPRITE_NUM+1];
+static mame_bitmap *sprite_zbuf;
+static UINT16 sprite_zbuf_baseval = 0x10000-MAX_SPRITE_NUM;
+
+static void (*get_sprite_info)(running_machine *machine);
+static void (*cave_sprite_draw)( int priority );
+
+static void sprite_init_cave(running_machine *machine);
+static void sprite_draw_cave( int priority );
+static void sprite_draw_cave_zbuf( int priority );
+static void sprite_draw_donpachi( int priority );
+static void sprite_draw_donpachi_zbuf( int priority );
+
+static int spriteram_bank;
+static int spriteram_bank_delay;
+
+/***************************************************************************
+
+ Palette Init Routines
+
+ Function needed for games with 4 bit sprites, rather than 8 bit,
+ or games with an odd colors mapping for the layers.
+
+***************************************************************************/
+
+PALETTE_INIT( dfeveron )
+{
+ int color, pen;
+
+ /* Fill the 0-3fff range, used by sprites ($40 color codes * $100 pens)
+ Here sprites have 16 pens, but the sprite drawing routine always
+ multiplies the color code by $100 (for consistency).
+ That's why we need this function. */
+
+ for( color = 0; color < 0x40; color++ )
+ for( pen = 0; pen < 16; pen++ )
+ colortable[color * 256 + pen] = color * 16 + pen;
+}
+
+PALETTE_INIT( ddonpach )
+{
+ int color, pen;
+
+ /* Fill the 8000-83ff range ($40 color codes * $10 pens) for
+ layers 0 & 1 which are 4 bits deep rather than 8 bits deep
+ like layer 2, but use the first 16 color of every 256 for
+ any given color code. */
+
+ for( color = 0; color < 0x40; color++ )
+ for( pen = 0; pen < 16; pen++ )
+ colortable[color * 16 + pen + 0x8000] = 0x4000 + color * 256 + pen;
+}
+
+PALETTE_INIT( mazinger )
+{
+ int color, pen;
+
+ /* Sprites (encrypted) are 4 bit deep */
+ for( color = 0; color < 0x40; color++ )
+ for( pen = 0; pen < 256; pen++ )
+ colortable[color * 256 + pen] = color * 16 + pen;
+
+ /* Layer 0 is 6 bit deep, there are 64 color codes but only $400
+ colors are actually addressable */
+ for( color = 0; color < 0x40; color++ )
+ for( pen = 0; pen < 64; pen++ )
+ colortable[color * 64 + pen + 0x4400] = 0x400 + (color % (64/4)) * 64 + pen;
+}
+
+PALETTE_INIT( sailormn )
+{
+ int color, pen;
+
+ /* Sprites (encrypted) are 4 bit deep */
+ for( color = 0; color < 0x40; color++ )
+ for( pen = 0; pen < 256; pen++ )
+ colortable[color * 256 + pen] = color * 16 + pen;
+
+ /* Layer 2 is 6 bit deep, there are 64 color codes but only $400
+ colors are actually addressable */
+ for( color = 0; color < 0x40; color++ )
+ for( pen = 0; pen < 64; pen++ )
+ colortable[color * 64 + pen + 0x4c00] = 0xc00 + (color % (64/4)) * 64 + pen;
+}
+
+PALETTE_INIT( pwrinst2 )
+{
+ int color, pen;
+
+ for( color = 0; color < 0x80; color++ )
+ for( pen = 0; pen < 16; pen++ )
+ colortable[color * 256 + pen] = color * 16 + pen;
+
+ for( color = 0x8000; color < machine->drv->color_table_len; color++ )
+ colortable[color] = (color - 0x8000) % machine->drv->total_colors;
+}
+
+PALETTE_INIT( korokoro )
+{
+ int color, pen;
+
+ for( color = 0; color < 0x40; color++ )
+ for( pen = 0; pen < 16; pen++ )
+ colortable[color * 256 + pen] = 0x3c00 + color * 16 + pen;
+}
+
+/***************************************************************************
+
+ Tiles Format
+
+ Offset: Bits: Value:
+
+ 0.w fe-- ---- ---- --- Priority
+ --dc ba98 ---- ---- Color
+ ---- ---- 7654 3210
+
+ 2.w Code
+
+
+ When a row-scroll / row-select effect is enabled, the scroll values are
+ fetched starting from tile RAM + $1000, 4 bytes per scan line:
+
+ Offset: Value:
+
+ 0.w Tilemap line to display
+ 2.w X Scroll value
+
+***************************************************************************/
+
+INLINE void get_tile_info(running_machine *machine, tile_data *tileinfo, int tile_index, int GFX, UINT16 *VRAM, int TDIM)
+{
+ UINT32 code, color, pri, tile;
+
+ if ( TDIM )
+ {
+ tile = (tile_index % (512/8))/2 + ((tile_index / (512/8))/2)*(512/16);
+
+ code = (VRAM[ tile * 2 + 0x0000/2] << 16) +
+ VRAM[ tile * 2 + 0x0002/2];
+
+ color = (code & 0x3f000000) >> (32-8);
+ pri = (code & 0xc0000000) >> (32-2);
+ code = (code & 0x00ffffff) * 4;
+
+ code += tile_index & 1;
+ code += ( (tile_index / (512/8)) & 1 ) * 2;
+ }
+ else
+ {
+ code = (VRAM[ tile_index * 2 + 0x4000/2] << 16) +
+ VRAM[ tile_index * 2 + 0x4002/2];
+
+ color = (code & 0x3f000000) >> (32-8);
+ pri = (code & 0xc0000000) >> (32-2);
+ code = (code & 0x00ffffff);
+ }
+
+ SET_TILE_INFO( GFX,
+ code,
+ color,
+ 0 );
+ tileinfo->category = pri;
+}
+
+/* Sailormn: the lower 2 Megabytes of tiles banked */
+
+static int sailormn_tilebank;
+
+void sailormn_tilebank_w( int bank )
+{
+ if (sailormn_tilebank != bank)
+ {
+ sailormn_tilebank = bank;
+ tilemap_mark_all_tiles_dirty(tilemap_2);
+ }
+}
+
+static TILE_GET_INFO( sailormn_get_tile_info_2 )
+{
+ UINT32 code, color, pri;
+
+ if ( tiledim_2 )
+ {
+ UINT32 tile;
+ tile = (tile_index % (512/8))/2 + ((tile_index / (512/8))/2)*(512/16);
+
+ code = (cave_vram_2[ tile * 2 + 0x0000/2] << 16) +
+ cave_vram_2[ tile * 2 + 0x0002/2];
+
+ color = (code & 0x3f000000) >> (32-8);
+ pri = (code & 0xc0000000) >> (32-2);
+ code = (code & 0x00ffffff) * 4;
+
+ code += tile_index & 1;
+ code += ( (tile_index / (512/8)) & 1 ) * 2;
+ }
+ else
+ {
+ code = (cave_vram_2[ tile_index * 2 + 0x4000/2] << 16) +
+ cave_vram_2[ tile_index * 2 + 0x4002/2];
+
+ color = (code & 0x3f000000) >> (32-8);
+ pri = (code & 0xc0000000) >> (32-2);
+ code = (code & 0x00ffffff);
+ if ((code < 0x10000) && (sailormn_tilebank))
+ code += 0x40000;
+ }
+
+ SET_TILE_INFO( 2,
+ code,
+ color,
+ 0 );
+ tileinfo->category = pri;
+}
+
+
+INLINE void vram_w(UINT16 *VRAM, tilemap *TILEMAP, ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT16 data, ATTR_UNUSED UINT16 mem_mask)
+{
+ if ((VRAM[offset] & ~mem_mask)==(data & ~mem_mask)) return;
+ COMBINE_DATA(&VRAM[offset]);
+ offset /= 2;
+ if ( offset < 0x1000/4 ) // 16x16 tilemap
+ {
+ offset = (offset % (512/16))*2 + (offset / (512/16))*(512/8)*2;
+ tilemap_mark_tile_dirty(TILEMAP, offset + 0);
+ tilemap_mark_tile_dirty(TILEMAP, offset + 1);
+ tilemap_mark_tile_dirty(TILEMAP, offset + 0 + 512/8);
+ tilemap_mark_tile_dirty(TILEMAP, offset + 1 + 512/8);
+ }
+ else if ( offset >= 0x4000/4 ) // 8x8 tilemap
+ tilemap_mark_tile_dirty(TILEMAP,offset - 0x4000/4);
+}
+
+/* Some games, that only ever use the 8x8 tiles and no line scroll,
+ use mirror ram. For example in donpachi, writes to 400000-403fff
+ and 408000-407fff both go to the 8x8 tilemap ram. Use this function
+ in this cases. Note that the get_tile_info function looks in the
+ 4000-7fff range for tiles, so we have to write the data there. */
+INLINE void vram_8x8_w(UINT16 *VRAM, tilemap *TILEMAP,ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT16 data, ATTR_UNUSED UINT16 mem_mask)
+{
+ offset %= 0x4000/2;
+ if ((VRAM[offset] & ~mem_mask)==(data & ~mem_mask)) return;
+ COMBINE_DATA(&VRAM[offset + 0x0000/2]);
+ COMBINE_DATA(&VRAM[offset + 0x4000/2]);
+ tilemap_mark_tile_dirty(TILEMAP,offset/2);
+}
+
+static TILE_GET_INFO( get_tile_info_0 ) { get_tile_info(machine, tileinfo, tile_index, 0, cave_vram_0, tiledim_0 ); }
+static TILE_GET_INFO( get_tile_info_1 ) { get_tile_info(machine, tileinfo, tile_index, 1, cave_vram_1, tiledim_1 ); }
+static TILE_GET_INFO( get_tile_info_2 ) { get_tile_info(machine, tileinfo, tile_index, 2, cave_vram_2, tiledim_2 ); }
+static TILE_GET_INFO( get_tile_info_3 ) { get_tile_info(machine, tileinfo, tile_index, 3, cave_vram_3, tiledim_3 ); }
+
+WRITE16_HANDLER( cave_vram_0_w ) { vram_w (cave_vram_0, tilemap_0, offset, data, mem_mask); }
+WRITE16_HANDLER( cave_vram_0_8x8_w ) { vram_8x8_w(cave_vram_0, tilemap_0, offset, data, mem_mask); }
+
+WRITE16_HANDLER( cave_vram_1_w ) { vram_w (cave_vram_1, tilemap_1, offset, data, mem_mask); }
+WRITE16_HANDLER( cave_vram_1_8x8_w ) { vram_8x8_w(cave_vram_1, tilemap_1, offset, data, mem_mask); }
+
+WRITE16_HANDLER( cave_vram_2_w ) { vram_w (cave_vram_2, tilemap_2, offset, data, mem_mask); }
+WRITE16_HANDLER( cave_vram_2_8x8_w ) { vram_8x8_w(cave_vram_2, tilemap_2, offset, data, mem_mask); }
+
+WRITE16_HANDLER( cave_vram_3_w ) { vram_w (cave_vram_3, tilemap_3, offset, data, mem_mask); }
+WRITE16_HANDLER( cave_vram_3_8x8_w ) { vram_8x8_w(cave_vram_3, tilemap_3, offset, data, mem_mask); }
+
+
+/***************************************************************************
+
+ Video Init Routines
+
+ Depending on the game, there can be from 1 to 4 layers and the
+ tile sizes can be 8x8 or 16x16.
+
+***************************************************************************/
+
+static int cave_layers_offs_x, cave_layers_offs_y;
+static int cave_row_effect_offs_n;
+static int cave_row_effect_offs_f;
+static int background_color;
+
+static void cave_vh_start(running_machine *machine, int num)
+{
+ tilemap_0 = 0;
+ tilemap_1 = 0;
+ tilemap_2 = 0;
+ tilemap_3 = 0;
+
+ tiledim_0 = 0;
+ tiledim_1 = 0;
+ tiledim_2 = 0;
+ tiledim_3 = 0;
+
+ old_tiledim_0 = 0;
+ old_tiledim_1 = 0;
+ old_tiledim_2 = 0;
+ old_tiledim_3 = 0;
+
+ assert((num >= 1) && (num <= 4));
+
+ switch( num )
+ {
+ case 4:
+ tilemap_3 = tilemap_create( get_tile_info_3, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, 512/8,512/8 );
+ tilemap_set_transparent_pen(tilemap_3, 0);
+ tilemap_set_scroll_rows(tilemap_3, 1);
+ tilemap_set_scroll_cols(tilemap_3, 1);
+
+ case 3:
+ tilemap_2 = tilemap_create( get_tile_info_2, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, 512/8,512/8 );
+ tilemap_set_transparent_pen(tilemap_2, 0);
+ tilemap_set_scroll_rows(tilemap_2, 1);
+ tilemap_set_scroll_cols(tilemap_2, 1);
+
+ case 2:
+ tilemap_1 = tilemap_create( get_tile_info_1, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, 512/8,512/8 );
+ tilemap_set_transparent_pen(tilemap_1, 0);
+ tilemap_set_scroll_rows(tilemap_1, 1);
+ tilemap_set_scroll_cols(tilemap_1, 1);
+
+ case 1:
+ tilemap_0 = tilemap_create( get_tile_info_0, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, 512/8,512/8 );
+ tilemap_set_transparent_pen(tilemap_0, 0);
+ tilemap_set_scroll_rows(tilemap_0, 1);
+ tilemap_set_scroll_cols(tilemap_0, 1);
+
+ break;
+ }
+
+ sprite_init_cave(machine);
+
+ cave_layers_offs_x = 0x13;
+ cave_layers_offs_y = -0x12;
+
+ cave_row_effect_offs_n = -1;
+ cave_row_effect_offs_f = 1;
+
+// background_color = machine->drv->gfxdecodeinfo[0].color_codes_start;
+ background_color = machine->drv->gfxdecodeinfo[0].color_codes_start +
+ (machine->drv->gfxdecodeinfo[0].total_color_codes-1) *
+ machine->gfx[0]->color_granularity;
+
+ switch(cave_kludge)
+ {
+ case 1: /* sailormn */
+ cave_row_effect_offs_n = -1;
+ cave_row_effect_offs_f = -1;
+ break;
+ case 2: /* uopoko dfeveron */
+ background_color = 0x3f00;
+ break;
+ case 4: /* pwrinst2 */
+ background_color = 0x7f00;
+ cave_layers_offs_y++;
+ }
+}
+
+VIDEO_START( cave_1_layer ) { cave_vh_start(machine, 1); }
+VIDEO_START( cave_2_layers ) { cave_vh_start(machine, 2); }
+VIDEO_START( cave_3_layers ) { cave_vh_start(machine, 3); }
+VIDEO_START( cave_4_layers ) { cave_vh_start(machine, 4); }
+
+
+VIDEO_START( sailormn_3_layers )
+{
+ cave_vh_start(machine, 2);
+
+ /* Layer 2 (8x8) needs to be handled differently */
+ tilemap_2 = tilemap_create( sailormn_get_tile_info_2, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, 512/8,512/8 );
+ tilemap_set_transparent_pen(tilemap_2, 0);
+ tilemap_set_scroll_rows(tilemap_2, 1);
+ tilemap_set_scroll_cols(tilemap_2, 1);
+}
+
+/***************************************************************************
+
+ Sprites Drawing
+
+ Offset: Bits: Value:
+
+ 00.w fedc ba98 76-- ---- X Position
+ ---- ---- --54 3210
+
+ 02.w fedc ba98 76-- ---- Y Position
+ ---- ---- --54 3210
+
+ 04.w fe-- ---- ---- ----
+ --dc ba98 ---- ---- Color
+ ---- ---- 76-- ----
+ ---- ---- --54 ---- Priority
+ ---- ---- ---- 3--- Flip X
+ ---- ---- ---- -2-- Flip Y
+ ---- ---- ---- --10 Code High Bit(s?)
+
+ 06.w Code Low Bits
+
+ 08/0A.w Zoom X / Y
+
+ 0C.w fedc ba98 ---- ---- Tile Size X
+ ---- ---- 7654 3210 Tile Size Y
+
+ 0E.w Unused
+
+
+***************************************************************************/
+
+static void get_sprite_info_cave(running_machine *machine)
+{
+ const int region = REGION_GFX1;
+
+ const pen_t *base_pal = machine->remapped_colortable + 0;
+ const UINT8 *base_gfx = memory_region(region);
+ int code_max = memory_region_length(region) / (16*16);
+
+ UINT16 *source = spriteram16 + ((spriteram_size/2) / 2) * spriteram_bank;
+ UINT16 *finish = source + ((spriteram_size/2) / 2);
+
+ struct sprite_cave *sprite = sprite_cave;
+
+ int glob_flipx = cave_videoregs[ 0 ] & 0x8000;
+ int glob_flipy = cave_videoregs[ 1 ] & 0x8000;
+
+ int max_x = machine->screen[0].width;
+ int max_y = machine->screen[0].height;
+
+ for (; source < finish; source+=8 )
+ {
+ int x,y,attr,code,zoomx,zoomy,size,flipx,flipy;
+ int total_width_f,total_height_f;
+
+ if (cave_spritetype == 2) /* Hot Dog Storm */
+ {
+ x = (source[ 0 ] & 0x3ff) << 8;
+ y = (source[ 1 ] & 0x3ff) << 8;
+ }
+ else /* all others */
+ {
+ x = source[ 0 ] << 2;
+ y = source[ 1 ] << 2;
+ }
+ attr = source[ 2 ];
+ code = source[ 3 ] + ((attr & 3) << 16);
+ zoomx = source[ 4 ];
+ zoomy = source[ 5 ];
+ size = source[ 6 ];
+
+ sprite->tile_width = ( (size >> 8) & 0x1f ) * 16;
+ sprite->tile_height = ( (size >> 0) & 0x1f ) * 16;
+
+ if ( !sprite->tile_width || !sprite->tile_height ) continue;
+
+ /* Bound checking */
+ code %= code_max;
+ sprite->pen_data = base_gfx + (16*16) * code;
+
+ flipx = attr & 0x0008;
+ flipy = attr & 0x0004;
+
+ sprite->total_width = (total_width_f = sprite->tile_width * zoomx) / 0x100;
+ sprite->total_height = (total_height_f = sprite->tile_height * zoomy) / 0x100;
+
+ if (sprite->total_width <= 1)
+ {
+ sprite->total_width = 1;
+ sprite->zoomx_re = sprite->tile_width << 16;
+ sprite->xcount0 = sprite->zoomx_re / 2;
+ x -= 0x80;
+ }
+ else
+ {
+ sprite->zoomx_re = 0x1000000 / zoomx;
+ sprite->xcount0 = sprite->zoomx_re - 1;
+ }
+
+ if (sprite->total_height <= 1)
+ {
+ sprite->total_height = 1;
+ sprite->zoomy_re = sprite->tile_height << 16;
+ sprite->ycount0 = sprite->zoomy_re / 2;
+ y -= 0x80;
+ }
+ else
+ {
+ sprite->zoomy_re = 0x1000000 / zoomy;
+ sprite->ycount0 = sprite->zoomy_re - 1;
+ }
+
+ if (cave_spritetype == 2)
+ {
+ x >>= 8;
+ y >>= 8;
+ if (flipx && (zoomx != 0x100)) x += sprite->tile_width - sprite->total_width;
+ if (flipy && (zoomy != 0x100)) y += sprite->tile_height - sprite->total_height;
+ }
+ else
+ {
+ if (flipx && (zoomx != 0x100)) x += (sprite->tile_width<<8) - total_width_f - 0x80;
+ if (flipy && (zoomy != 0x100)) y += (sprite->tile_height<<8) - total_height_f - 0x80;
+ x >>= 8;
+ y >>= 8;
+ }
+
+ if (x > 0x1FF) x -= 0x400;
+ if (y > 0x1FF) y -= 0x400;
+
+ if (x + sprite->total_width<=0 || x>=max_x || y + sprite->total_height<=0 || y>=max_y )
+ {continue;}
+
+ sprite->priority = (attr & 0x0030) >> 4;
+ sprite->flags = SPRITE_VISIBLE_CAVE;
+ sprite->line_offset = sprite->tile_width;
+ sprite->pal_data = base_pal + (attr & 0x3f00); // first 0x4000 colors
+
+ if (glob_flipx) { x = max_x - x - sprite->total_width; flipx = !flipx; }
+ if (glob_flipy) { y = max_y - y - sprite->total_height; flipy = !flipy; }
+
+ sprite->x = x;
+ sprite->y = y;
+
+ if (flipx) sprite->flags |= SPRITE_FLIPX_CAVE;
+ if (flipy) sprite->flags |= SPRITE_FLIPY_CAVE;
+
+ sprite++;
+ }
+ num_sprites = sprite - sprite_cave;
+}
+
+static void get_sprite_info_donpachi(running_machine *machine)
+{
+ const int region = REGION_GFX1;
+
+ const pen_t *base_pal = machine->remapped_colortable + 0;
+ const UINT8 *base_gfx = memory_region(region);
+ int code_max = memory_region_length(region) / (16*16);
+
+ UINT16 *source = spriteram16 + ((spriteram_size/2) / 2) * spriteram_bank;
+ UINT16 *finish = source + ((spriteram_size/2) / 2);
+
+ struct sprite_cave *sprite = sprite_cave;
+
+ int glob_flipx = cave_videoregs[ 0 ] & 0x8000;
+ int glob_flipy = cave_videoregs[ 1 ] & 0x8000;
+
+ int max_x = machine->screen[0].width;
+ int max_y = machine->screen[0].height;
+
+ for (; source < finish; source+=8 )
+ {
+ int x,y,attr,code,size,flipx,flipy;
+
+ attr = source[ 0 ];
+ code = source[ 1 ] + ((attr & 3) << 16);
+ x = source[ 2 ] & 0x3FF;
+
+ if (cave_spritetype == 3) /* pwrinst2 */
+ y = (source[ 3 ]+1) & 0x3FF;
+ else
+ y = source[ 3 ] & 0x3FF;
+
+ size = source[ 4 ];
+
+ sprite->tile_width = sprite->total_width = ( (size >> 8) & 0x1f ) * 16;
+ sprite->tile_height = sprite->total_height = ( (size >> 0) & 0x1f ) * 16;
+
+ /* Bound checking */
+ code %= code_max;
+ sprite->pen_data = base_gfx + (16*16) * code;
+
+ if (x > 0x1FF) x -= 0x400;
+ if (y > 0x1FF) y -= 0x400;
+
+ if ( !sprite->tile_width || !sprite->tile_height ||
+ x + sprite->total_width<=0 || x>=max_x || y + sprite->total_height<=0 || y>=max_y )
+ {continue;}
+
+ flipx = attr & 0x0008;
+ flipy = attr & 0x0004;
+
+ if (cave_spritetype == 3) /* pwrinst2 */
+ {
+ sprite->priority = ((attr & 0x0010) >> 4)+2;
+ sprite->pal_data = base_pal + (attr & 0x3f00) + 0x4000*((attr & 0x0020) >> 5);
+ }
+ else
+ {
+ sprite->priority = (attr & 0x0030) >> 4;
+ sprite->pal_data = base_pal + (attr & 0x3f00); // first 0x4000 colors
+ }
+
+ sprite->flags = SPRITE_VISIBLE_CAVE;
+ sprite->line_offset = sprite->tile_width;
+
+ if (glob_flipx) { x = max_x - x - sprite->total_width; flipx = !flipx; }
+ if (glob_flipy) { y = max_y - y - sprite->total_height; flipy = !flipy; }
+
+ sprite->x = x;
+ sprite->y = y;
+
+ if (flipx) sprite->flags |= SPRITE_FLIPX_CAVE;
+ if (flipy) sprite->flags |= SPRITE_FLIPY_CAVE;
+
+ sprite++;
+ }
+ num_sprites = sprite - sprite_cave;
+}
+
+
+static void sprite_init_cave(running_machine *machine)
+{
+ screen_width = machine->screen[0].width;
+ screen_height = machine->screen[0].height;
+
+ if (cave_spritetype == 0 || cave_spritetype == 2) // most of the games
+ {
+ get_sprite_info = get_sprite_info_cave;
+ cave_spritetype2 = CAVE_SPRITETYPE_ZOOM;
+ }
+ else // donpachi ddonpach
+ {
+ get_sprite_info = get_sprite_info_donpachi;
+ cave_spritetype2 = 0;
+ }
+
+ sprite_zbuf = auto_bitmap_alloc( machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16 );
+ blit.baseaddr_zbuf = sprite_zbuf->base;
+ blit.line_offset_zbuf = sprite_zbuf->rowpixels * sprite_zbuf->bpp / 8;
+
+ num_sprites = spriteram_size / 0x10 / 2;
+ sprite_cave = auto_malloc( num_sprites * sizeof(struct sprite_cave) );
+ memset(sprite_cave, 0, num_sprites * sizeof(struct sprite_cave));
+
+ memset(sprite_table,0,sizeof(sprite_table));
+ cave_sprite_draw = sprite_draw_donpachi;
+}
+
+
+static void cave_sprite_check(running_machine *machine, const rectangle *clip )
+{
+ { /* set clip */
+ int left = clip->min_x;
+ int top = clip->min_y;
+ int right = clip->max_x+1;
+ int bottom = clip->max_y+1;
+
+ blit.clip_left = left;
+ blit.clip_top = top;
+ blit.clip_right = right;
+ blit.clip_bottom = bottom;
+ }
+
+ { /* check priority & sprite type */
+ struct sprite_cave *sprite = sprite_cave;
+ const struct sprite_cave *finish = &sprite[num_sprites];
+ int i[4]={0,0,0,0};
+ int priority_check = 0;
+ int spritetype = cave_spritetype2;
+ while( sprite<finish )
+ {
+ if( sprite->x + sprite->total_width > blit.clip_left && sprite->x < blit.clip_right &&
+ sprite->y + sprite->total_height > blit.clip_top && sprite->y < blit.clip_bottom )
+ {
+ sprite_table[sprite->priority][i[sprite->priority]++] = sprite;
+
+ if(!(spritetype&CAVE_SPRITETYPE_ZBUF))
+ {
+ if(priority_check > sprite->priority)
+ spritetype |= CAVE_SPRITETYPE_ZBUF;
+ else
+ priority_check = sprite->priority;
+ }
+ }
+ sprite++;
+ }
+
+ sprite_table[0][i[0]] = 0;
+ sprite_table[1][i[1]] = 0;
+ sprite_table[2][i[2]] = 0;
+ sprite_table[3][i[3]] = 0;
+
+ switch (spritetype)
+ {
+ case CAVE_SPRITETYPE_ZOOM:
+ cave_sprite_draw = sprite_draw_cave;
+ break;
+
+ case CAVE_SPRITETYPE_ZOOM | CAVE_SPRITETYPE_ZBUF:
+ cave_sprite_draw = sprite_draw_cave_zbuf;
+ if (clip->min_y == machine->screen[0].visarea.min_y)
+ {
+ if(!(sprite_zbuf_baseval += MAX_SPRITE_NUM))
+ fillbitmap(sprite_zbuf,0,&machine->screen[0].visarea);
+ }
+ break;
+
+ case CAVE_SPRITETYPE_ZBUF:
+ cave_sprite_draw = sprite_draw_donpachi_zbuf;
+ if (clip->min_y == machine->screen[0].visarea.min_y)
+ {
+ if(!(sprite_zbuf_baseval += MAX_SPRITE_NUM))
+ fillbitmap(sprite_zbuf,0,&machine->screen[0].visarea);
+ }
+ break;
+
+ default:
+ case 0:
+ cave_sprite_draw = sprite_draw_donpachi;
+ }
+ }
+}
+
+static void do_blit_zoom16_cave( const struct sprite_cave *sprite ){
+ /* assumes SPRITE_LIST_RAW_DATA flag is set */
+
+ int x1,x2, y1,y2, dx,dy;
+ int xcount0 = 0x10000 + sprite->xcount0, ycount0 = 0x10000 + sprite->ycount0;
+
+ if( sprite->flags & SPRITE_FLIPX_CAVE ){
+ x2 = sprite->x;
+ x1 = x2+sprite->total_width;
+ dx = -1;
+ if( x2<blit.clip_left ) x2 = blit.clip_left;
+ if( x1>blit.clip_right ){
+ xcount0 += (x1-blit.clip_right)* sprite->zoomx_re;
+ x1 = blit.clip_right;
+ while((xcount0&0xffff)>=sprite->zoomx_re){xcount0 += sprite->zoomx_re; x1--;}
+ }
+ if( x2>=x1 ) return;
+ x1--; x2--;
+ }
+ else {
+ x1 = sprite->x;
+ x2 = x1+sprite->total_width;
+ dx = 1;
+ if( x1<blit.clip_left ){
+ xcount0 += (blit.clip_left-x1)*sprite->zoomx_re;
+ x1 = blit.clip_left;
+ while((xcount0&0xffff)>=sprite->zoomx_re){xcount0 += sprite->zoomx_re; x1++;}
+ }
+ if( x2>blit.clip_right ) x2 = blit.clip_right;
+ if( x1>=x2 ) return;
+ }
+ if( sprite->flags & SPRITE_FLIPY_CAVE ){
+ y2 = sprite->y;
+ y1 = y2+sprite->total_height;
+ dy = -1;
+ if( y2<blit.clip_top ) y2 = blit.clip_top;
+ if( y1>blit.clip_bottom ){
+ ycount0 += (y1-blit.clip_bottom)*sprite->zoomy_re;
+ y1 = blit.clip_bottom;
+ while((ycount0&0xffff)>=sprite->zoomy_re){ycount0 += sprite->zoomy_re; y1--;}
+ }
+ if( y2>=y1 ) return;
+ y1--; y2--;
+ }
+ else {
+ y1 = sprite->y;
+ y2 = y1+sprite->total_height;
+ dy = 1;
+ if( y1<blit.clip_top ){
+ ycount0 += (blit.clip_top-y1)*sprite->zoomy_re;
+ y1 = blit.clip_top;
+ while((ycount0&0xffff)>=sprite->zoomy_re){ycount0 += sprite->zoomy_re; y1++;}
+ }
+ if( y2>blit.clip_bottom ) y2 = blit.clip_bottom;
+ if( y1>=y2 ) return;
+ }
+
+ {
+ const UINT8 *pen_data = sprite->pen_data -1 -sprite->line_offset;
+ const pen_t *pal_data = sprite->pal_data;
+ int x,y;
+ UINT8 pen;
+ int pitch = blit.line_offset*dy/2;
+ UINT16 *dest = (UINT16 *)(blit.baseaddr + blit.line_offset*y1);
+ int ycount = ycount0;
+
+ for( y=y1; y!=y2; y+=dy ){
+ int xcount;
+ const UINT8 *source;
+
+ if (ycount&0xffff0000){
+ xcount = xcount0;
+ pen_data+=sprite->line_offset*(ycount>>16);
+ ycount &= 0xffff;
+ source = pen_data;
+ for( x=x1; x!=x2; x+=dx ){
+ if (xcount&0xffff0000){
+ source+=xcount>>16;
+ xcount &= 0xffff;
+ pen = *source;
+ if (pen) dest[x] = pal_data[pen];
+ }
+ xcount += sprite->zoomx_re;
+ }
+ }
+ ycount += sprite->zoomy_re;
+ dest += pitch;
+ }
+ }
+}
+
+
+static void do_blit_zoom16_cave_zb( const struct sprite_cave *sprite ){
+ /* assumes SPRITE_LIST_RAW_DATA flag is set */
+
+ int x1,x2, y1,y2, dx,dy;
+ int xcount0 = 0x10000 + sprite->xcount0, ycount0 = 0x10000 + sprite->ycount0;
+
+ if( sprite->flags & SPRITE_FLIPX_CAVE ){
+ x2 = sprite->x;
+ x1 = x2+sprite->total_width;
+ dx = -1;
+ if( x2<blit.clip_left ) x2 = blit.clip_left;
+ if( x1>blit.clip_right ){
+ xcount0 += (x1-blit.clip_right)* sprite->zoomx_re;
+ x1 = blit.clip_right;
+ while((xcount0&0xffff)>=sprite->zoomx_re){xcount0 += sprite->zoomx_re; x1--;}
+ }
+ if( x2>=x1 ) return;
+ x1--; x2--;
+ }
+ else {
+ x1 = sprite->x;
+ x2 = x1+sprite->total_width;
+ dx = 1;
+ if( x1<blit.clip_left ){
+ xcount0 += (blit.clip_left-x1)*sprite->zoomx_re;
+ x1 = blit.clip_left;
+ while((xcount0&0xffff)>=sprite->zoomx_re){xcount0 += sprite->zoomx_re; x1++;}
+ }
+ if( x2>blit.clip_right ) x2 = blit.clip_right;
+ if( x1>=x2 ) return;
+ }
+ if( sprite->flags & SPRITE_FLIPY_CAVE ){
+ y2 = sprite->y;
+ y1 = y2+sprite->total_height;
+ dy = -1;
+ if( y2<blit.clip_top ) y2 = blit.clip_top;
+ if( y1>blit.clip_bottom ){
+ ycount0 += (y1-blit.clip_bottom)*sprite->zoomy_re;
+ y1 = blit.clip_bottom;
+ while((ycount0&0xffff)>=sprite->zoomy_re){ycount0 += sprite->zoomy_re; y1--;}
+ }
+ if( y2>=y1 ) return;
+ y1--; y2--;
+ }
+ else {
+ y1 = sprite->y;
+ y2 = y1+sprite->total_height;
+ dy = 1;
+ if( y1<blit.clip_top ){
+ ycount0 += (blit.clip_top-y1)*sprite->zoomy_re;
+ y1 = blit.clip_top;
+ while((ycount0&0xffff)>=sprite->zoomy_re){ycount0 += sprite->zoomy_re; y1++;}
+ }
+ if( y2>blit.clip_bottom ) y2 = blit.clip_bottom;
+ if( y1>=y2 ) return;
+ }
+
+ {
+ const UINT8 *pen_data = sprite->pen_data -1 -sprite->line_offset;
+ const pen_t *pal_data = sprite->pal_data;
+ int x,y;
+ UINT8 pen;
+ int pitch = blit.line_offset*dy/2;
+ UINT16 *dest = (UINT16 *)(blit.baseaddr + blit.line_offset*y1);
+ int pitchz = blit.line_offset_zbuf*dy/2;
+ UINT16 *zbf = (UINT16 *)(blit.baseaddr_zbuf + blit.line_offset_zbuf*y1);
+ UINT16 pri_sp = (UINT16)(sprite - sprite_cave) + sprite_zbuf_baseval;
+ int ycount = ycount0;
+
+ for( y=y1; y!=y2; y+=dy ){
+ int xcount;
+ const UINT8 *source;
+
+ if (ycount&0xffff0000){
+ xcount = xcount0;
+ pen_data+=sprite->line_offset*(ycount>>16);
+ ycount &= 0xffff;
+ source = pen_data;
+ for( x=x1; x!=x2; x+=dx ){
+ if (xcount&0xffff0000){
+ source+=xcount>>16;
+ xcount &= 0xffff;
+ pen = *source;
+ if (pen && (zbf[x]<=pri_sp)){
+ dest[x] = pal_data[pen];
+ zbf[x] = pri_sp;
+ }
+ }
+ xcount += sprite->zoomx_re;
+ }
+ }
+ ycount += sprite->zoomy_re;
+ dest += pitch;
+ zbf += pitchz;
+ }
+ }
+}
+
+static void do_blit_16_cave( const struct sprite_cave *sprite ){
+ /* assumes SPRITE_LIST_RAW_DATA flag is set */
+
+ int x1,x2, y1,y2, dx,dy;
+ int xcount0 = 0, ycount0 = 0;
+
+ if( sprite->flags & SPRITE_FLIPX_CAVE ){
+ x2 = sprite->x;
+ x1 = x2+sprite->total_width;
+ dx = -1;
+ if( x2<blit.clip_left ) x2 = blit.clip_left;
+ if( x1>blit.clip_right ){
+ xcount0 = x1-blit.clip_right;
+ x1 = blit.clip_right;
+ }
+ if( x2>=x1 ) return;
+ x1--; x2--;
+ }
+ else {
+ x1 = sprite->x;
+ x2 = x1+sprite->total_width;
+ dx = 1;
+ if( x1<blit.clip_left ){
+ xcount0 = blit.clip_left-x1;
+ x1 = blit.clip_left;
+ }
+ if( x2>blit.clip_right ) x2 = blit.clip_right;
+ if( x1>=x2 ) return;
+ }
+ if( sprite->flags & SPRITE_FLIPY_CAVE ){
+ y2 = sprite->y;
+ y1 = y2+sprite->total_height;
+ dy = -1;
+ if( y2<blit.clip_top ) y2 = blit.clip_top;
+ if( y1>blit.clip_bottom ){
+ ycount0 = y1-blit.clip_bottom;
+ y1 = blit.clip_bottom;
+ }
+ if( y2>=y1 ) return;
+ y1--; y2--;
+ }
+ else {
+ y1 = sprite->y;
+ y2 = y1+sprite->total_height;
+ dy = 1;
+ if( y1<blit.clip_top ){
+ ycount0 = blit.clip_top-y1;
+ y1 = blit.clip_top;
+ }
+ if( y2>blit.clip_bottom ) y2 = blit.clip_bottom;
+ if( y1>=y2 ) return;
+ }
+
+ {
+ const UINT8 *pen_data = sprite->pen_data;
+ const pen_t *pal_data = sprite->pal_data;
+ int x,y;
+ UINT8 pen;
+ int pitch = blit.line_offset*dy/2;
+ UINT16 *dest = (UINT16 *)(blit.baseaddr + blit.line_offset*y1);
+
+ pen_data+=sprite->line_offset*ycount0+xcount0;
+ for( y=y1; y!=y2; y+=dy ){
+ const UINT8 *source;
+ source = pen_data;
+ for( x=x1; x!=x2; x+=dx ){
+ pen = *source;
+ if (pen) dest[x] = pal_data[pen];
+ source++;
+ }
+ pen_data += sprite->line_offset;
+ dest += pitch;
+ }
+ }
+}
+
+
+static void do_blit_16_cave_zb( const struct sprite_cave *sprite ){
+ /* assumes SPRITE_LIST_RAW_DATA flag is set */
+
+ int x1,x2, y1,y2, dx,dy;
+ int xcount0 = 0, ycount0 = 0;
+
+ if( sprite->flags & SPRITE_FLIPX_CAVE ){
+ x2 = sprite->x;
+ x1 = x2+sprite->total_width;
+ dx = -1;
+ if( x2<blit.clip_left ) x2 = blit.clip_left;
+ if( x1>blit.clip_right ){
+ xcount0 = x1-blit.clip_right;
+ x1 = blit.clip_right;
+ }
+ if( x2>=x1 ) return;
+ x1--; x2--;
+ }
+ else {
+ x1 = sprite->x;
+ x2 = x1+sprite->total_width;
+ dx = 1;
+ if( x1<blit.clip_left ){
+ xcount0 = blit.clip_left-x1;
+ x1 = blit.clip_left;
+ }
+ if( x2>blit.clip_right ) x2 = blit.clip_right;
+ if( x1>=x2 ) return;
+ }
+ if( sprite->flags & SPRITE_FLIPY_CAVE ){
+ y2 = sprite->y;
+ y1 = y2+sprite->total_height;
+ dy = -1;
+ if( y2<blit.clip_top ) y2 = blit.clip_top;
+ if( y1>blit.clip_bottom ){
+ ycount0 = y1-blit.clip_bottom;
+ y1 = blit.clip_bottom;
+ }
+ if( y2>=y1 ) return;
+ y1--; y2--;
+ }
+ else {
+ y1 = sprite->y;
+ y2 = y1+sprite->total_height;
+ dy = 1;
+ if( y1<blit.clip_top ){
+ ycount0 = blit.clip_top-y1;
+ y1 = blit.clip_top;
+ }
+ if( y2>blit.clip_bottom ) y2 = blit.clip_bottom;
+ if( y1>=y2 ) return;
+ }
+
+ {
+ const UINT8 *pen_data = sprite->pen_data;
+ const pen_t *pal_data = sprite->pal_data;
+ int x,y;
+ UINT8 pen;
+ int pitch = blit.line_offset*dy/2;
+ UINT16 *dest = (UINT16 *)(blit.baseaddr + blit.line_offset*y1);
+ int pitchz = blit.line_offset_zbuf*dy/2;
+ UINT16 *zbf = (UINT16 *)(blit.baseaddr_zbuf + blit.line_offset_zbuf*y1);
+ UINT16 pri_sp = (UINT16)(sprite - sprite_cave) + sprite_zbuf_baseval;
+
+ pen_data+=sprite->line_offset*ycount0+xcount0;
+ for( y=y1; y!=y2; y+=dy ){
+ const UINT8 *source;
+ source = pen_data;
+ for( x=x1; x!=x2; x+=dx ){
+ pen = *source;
+ if ( pen && (zbf[x]<=pri_sp))
+ {
+ dest[x] = pal_data[pen];
+ zbf[x] = pri_sp;
+ }
+ source++;
+ }
+ pen_data += sprite->line_offset;
+ dest += pitch;
+ zbf += pitchz;
+ }
+ }
+}
+
+
+static void sprite_draw_cave( int priority )
+{
+ int i=0;
+ while(sprite_table[priority][i])
+ {
+ const struct sprite_cave *sprite = sprite_table[priority][i++];
+ if ((sprite->tile_width == sprite->total_width) && (sprite->tile_height == sprite->total_height))
+ do_blit_16_cave( sprite );
+ else
+ do_blit_zoom16_cave( sprite );
+ }
+}
+
+static void sprite_draw_cave_zbuf( int priority )
+{
+ int i=0;
+ while(sprite_table[priority][i])
+ {
+ const struct sprite_cave *sprite = sprite_table[priority][i++];
+ if ((sprite->tile_width == sprite->total_width) && (sprite->tile_height == sprite->total_height))
+ do_blit_16_cave_zb( sprite );
+ else
+ do_blit_zoom16_cave_zb( sprite );
+ }
+}
+
+static void sprite_draw_donpachi( int priority )
+{
+ int i=0;
+ while(sprite_table[priority][i])
+ do_blit_16_cave( sprite_table[priority][i++] );
+}
+
+static void sprite_draw_donpachi_zbuf( int priority )
+{
+ int i=0;
+ while(sprite_table[priority][i])
+ do_blit_16_cave_zb( sprite_table[priority][i++] );
+}
+
+
+/***************************************************************************
+
+ Screen Drawing
+
+
+ Layers Control Registers (cave_vctrl_0..2)
+
+
+ Offset: Bits: Value:
+
+ 0.w f--- ---- ---- ---- 0 = Layer Flip X
+ -e-- ---- ---- ---- Activate Row-scroll
+ --d- ---- ---- ----
+ ---c ba9- ---- ----
+ ---- ---8 7654 3210 Scroll X
+
+ 2.w f--- ---- ---- ---- 0 = Layer Flip Y
+ -e-- ---- ---- ---- Activate Row-select
+ --d- ---- ---- ---- 0 = 8x8 tiles, 1 = 16x16 tiles
+ ---c ba9- ---- ----
+ ---- ---8 7654 3210 Scroll Y
+
+ 4.w fedc ba98 765- ----
+ ---- ---- ---4 ---- Layer Disable
+ ---- ---- ---- 32--
+ ---- ---- ---- --10 Layer Priority (decides the order
+ of the layers for tiles with the
+ same tile priority)
+
+
+ Row-scroll / row-select data is fetched from tile RAM + $1000.
+
+ Row-select: a tilemap line is specified for each scan line.
+ Row-scroll: a different scroll value is specified for each scan line.
+
+
+ Sprites Registers (cave_videoregs)
+
+
+ Offset: Bits: Value:
+
+ 0.w f--- ---- ---- ---- Sprites Flip X
+ -edc ba98 7654 3210 Sprites Offset X
+
+ 2.w f--- ---- ---- ---- Sprites Flip Y
+ -edc ba98 7654 3210 Sprites Offset Y
+
+ ..
+
+ 8.w fedc ba98 7654 321-
+ ---- ---- ---- ---0 Sprite RAM Bank
+
+ There are more!
+
+***************************************************************************/
+
+INLINE void cave_tilemap_draw(
+ mame_bitmap *bitmap, const rectangle *cliprect,
+ tilemap *TILEMAP, UINT16 *VRAM, UINT16 *VCTRL,
+ UINT32 flags, UINT32 priority, UINT32 priority2 )
+{
+ int sx, sy, flipx, flipy, offs_x, offs_y, offs_row;
+
+ /* Bail out if ... */
+
+ if ( (!TILEMAP) || /* no tilemap; */
+ ((VCTRL[2] & 0x0003) != priority2) || /* tilemap's global priority not the requested one; */
+ ((VCTRL[2] & 0x0010)) ) /* tilemap's disabled. */
+ return;
+
+ flipx = ~VCTRL[0] & 0x8000;
+ flipy = ~VCTRL[1] & 0x8000;
+ tilemap_set_flip(TILEMAP, (flipx ? TILEMAP_FLIPX : 0) | (flipy ? TILEMAP_FLIPY : 0) );
+
+ offs_x = cave_layers_offs_x;
+ offs_y = cave_layers_offs_y;
+
+ offs_row = flipy ? cave_row_effect_offs_f : cave_row_effect_offs_n;
+
+ /* An additional 8 pixel offset for layers with 8x8 tiles. Plus
+ Layer 0 is displaced by 1 pixel wrt Layer 1, so is Layer 2 wrt
+ Layer 1 */
+ if (TILEMAP == tilemap_0) offs_x -= (tiledim_0 ? 1 : (1+8));
+ else if (TILEMAP == tilemap_1) offs_x -= (tiledim_1 ? 2 : (2+8));
+ else if (TILEMAP == tilemap_2) offs_x -= (tiledim_2 ? 3 : (3+8));
+ else if (TILEMAP == tilemap_3) offs_x -= (tiledim_3 ? 4 : (4+8));
+
+ sx = VCTRL[0] - cave_videoregs[0] + (flipx ? (offs_x +2) : -offs_x);
+ sy = VCTRL[1] - cave_videoregs[1] + (flipy ? (offs_y +2) : -offs_y);
+
+ if (VCTRL[1] & 0x4000) // row-select
+ {
+ rectangle clip;
+ int startline, endline, vramdata0, vramdata1;
+
+ /*
+ Row-select:
+
+ A tilemap line is specified for each scan line. This is handled
+ using many horizontal clipping regions (slices) and calling
+ tilemap_draw multiple times.
+ */
+
+ clip.min_x = cliprect->min_x;
+ clip.max_x = cliprect->max_x;
+
+ for(startline = cliprect->min_y; startline <= cliprect->max_y;)
+ {
+ /* Find the largest slice */
+ vramdata0 = (vramdata1 = VRAM[(0x1002+(((sy+offs_row+startline)*4)&0x7ff))/2]);
+ for(endline = startline + 1; endline <= cliprect->max_y; endline++)
+ if((++vramdata1) != VRAM[(0x1002+(((sy+offs_row+endline)*4)&0x7ff))/2]) break;
+
+ tilemap_set_scrolly(TILEMAP, 0, vramdata0 - startline);
+
+ if (VCTRL[0] & 0x4000) // row-scroll, row-select
+ {
+ int line;
+
+ /*
+ Row-scroll:
+
+ A different scroll value is specified for each scan line.
+ This is handled using tilemap_set_scroll_rows and calling
+ tilemap_draw just once.
+ */
+
+ tilemap_set_scroll_rows(TILEMAP,512);
+ for(line = startline; line < endline; line++)
+ tilemap_set_scrollx( TILEMAP,
+ (vramdata0-startline+line) & 511,
+ sx + VRAM[(0x1000+(((sy+offs_row+line)*4)&0x7ff))/2] );
+ }
+ else // no row-scroll, row-select
+ {
+ tilemap_set_scroll_rows(TILEMAP, 1);
+ tilemap_set_scrollx(TILEMAP, 0, sx );
+ }
+
+ if(flipy)
+ {
+ clip.min_y = cliprect->max_y - (endline-1 - cliprect->min_y);
+ clip.max_y = cliprect->max_y - (startline - cliprect->min_y);
+ }
+ else
+ {
+ clip.min_y = startline;
+ clip.max_y = endline - 1;
+ }
+
+ tilemap_draw(bitmap, &clip, TILEMAP, flags, priority);
+
+ startline = endline;
+ }
+ }
+ else if (VCTRL[0] & 0x4000) // row-scroll, no row-select
+ {
+ int line;
+ tilemap_set_scroll_rows(TILEMAP,512);
+ for(line = cliprect->min_y; line <= cliprect->max_y; line++)
+ tilemap_set_scrollx( TILEMAP,
+ (line + sy) & 511,
+ sx + VRAM[(0x1000+(((sy+offs_row+line)*4)&0x7ff))/2] );
+ tilemap_set_scrolly(TILEMAP, 0, sy );
+ tilemap_draw(bitmap, cliprect, TILEMAP, flags, priority);
+ }
+ else
+ {
+ /* DEF_STR( Normal ) scrolling */
+ tilemap_set_scroll_rows(TILEMAP, 1);
+ tilemap_set_scroll_cols(TILEMAP, 1);
+ tilemap_set_scrollx(TILEMAP, 0, sx );
+ tilemap_set_scrolly(TILEMAP, 0, sy );
+ tilemap_draw(bitmap, cliprect, TILEMAP, flags, priority);
+ }
+}
+
+static void cave_tilemap_0_draw( mame_bitmap *bitmap, const rectangle *cliprect, UINT32 flags, UINT32 priority, UINT32 priority2 )
+{ cave_tilemap_draw( bitmap, cliprect, tilemap_0, cave_vram_0, cave_vctrl_0, flags, priority, priority2 ); }
+static void cave_tilemap_1_draw( mame_bitmap *bitmap, const rectangle *cliprect, UINT32 flags, UINT32 priority, UINT32 priority2 )
+{ cave_tilemap_draw( bitmap, cliprect, tilemap_1, cave_vram_1, cave_vctrl_1, flags, priority, priority2 ); }
+static void cave_tilemap_2_draw( mame_bitmap *bitmap, const rectangle *cliprect, UINT32 flags, UINT32 priority, UINT32 priority2 )
+{ cave_tilemap_draw( bitmap, cliprect, tilemap_2, cave_vram_2, cave_vctrl_2, flags, priority, priority2 ); }
+static void cave_tilemap_3_draw( mame_bitmap *bitmap, const rectangle *cliprect, UINT32 flags, UINT32 priority, UINT32 priority2 )
+{ cave_tilemap_draw( bitmap, cliprect, tilemap_3, cave_vram_3, cave_vctrl_3, flags, priority, priority2 ); }
+
+
+VIDEO_UPDATE( cave )
+{
+ int pri, pri2;
+ int layers_ctrl = -1;
+
+ blit.baseaddr = bitmap->base;
+ blit.line_offset = bitmap->rowpixels * bitmap->bpp / 8;
+
+ /* Choose the tilemap to display (8x8 tiles or 16x16 tiles) */
+ if (tilemap_0)
+ { tiledim_0 = cave_vctrl_0[ 1 ] & 0x2000;
+ if (tiledim_0 != old_tiledim_0) tilemap_mark_all_tiles_dirty(tilemap_0);
+ old_tiledim_0 = tiledim_0; }
+
+ if (tilemap_1)
+ { tiledim_1 = cave_vctrl_1[ 1 ] & 0x2000;
+ if (tiledim_1 != old_tiledim_1) tilemap_mark_all_tiles_dirty(tilemap_1);
+ old_tiledim_1 = tiledim_1; }
+
+ if (tilemap_2)
+ { tiledim_2 = cave_vctrl_2[ 1 ] & 0x2000;
+ if (tiledim_2 != old_tiledim_2) tilemap_mark_all_tiles_dirty(tilemap_2);
+ old_tiledim_2 = tiledim_2; }
+
+ if (tilemap_3)
+ { tiledim_3 = cave_vctrl_3[ 1 ] & 0x2000;
+ if (tiledim_3 != old_tiledim_3) tilemap_mark_all_tiles_dirty(tilemap_3);
+ old_tiledim_3 = tiledim_3; }
+
+
+#ifdef MAME_DEBUG
+{
+ static int rasflag, old_rasflag;
+ if ( input_code_pressed(KEYCODE_Z) || input_code_pressed(KEYCODE_X) || input_code_pressed(KEYCODE_C) ||
+ input_code_pressed(KEYCODE_V) || input_code_pressed(KEYCODE_B) )
+ {
+ int msk = 0, val = 0;
+
+ if (input_code_pressed(KEYCODE_X)) val = 1; // priority 0 only
+ if (input_code_pressed(KEYCODE_C)) val = 2; // "" 1
+ if (input_code_pressed(KEYCODE_V)) val = 4; // "" 2
+ if (input_code_pressed(KEYCODE_B)) val = 8; // "" 3
+
+ if (input_code_pressed(KEYCODE_Z)) val = 1|2|4|8; // All of the above priorities
+
+ if (input_code_pressed(KEYCODE_Q)) msk |= val << 0; // for layer 0
+ if (input_code_pressed(KEYCODE_W)) msk |= val << 4; // for layer 1
+ if (input_code_pressed(KEYCODE_E)) msk |= val << 8; // for layer 2
+ if (input_code_pressed(KEYCODE_R)) msk |= val << 12; // for layer 3
+ if (input_code_pressed(KEYCODE_A)) msk |= val << 16; // for sprites
+ if (msk != 0) layers_ctrl &= msk;
+
+#if 1
+ /* Show the video registers (cave_videoregs) */
+ popmessage("%04X %04X %04X %04X %04X %04X %04X %04X",
+ cave_videoregs[0], cave_videoregs[1], cave_videoregs[2], cave_videoregs[3],
+ cave_videoregs[4], cave_videoregs[5], cave_videoregs[6], cave_videoregs[7] );
+#endif
+ /* Show the scroll / flags registers of the selected layer */
+ if ((tilemap_0)&&(msk&0x000f)) popmessage("x:%04X y:%04X f:%04X",cave_vctrl_0[0],cave_vctrl_0[1],cave_vctrl_0[2]);
+ if ((tilemap_1)&&(msk&0x00f0)) popmessage("x:%04X y:%04X f:%04X",cave_vctrl_1[0],cave_vctrl_1[1],cave_vctrl_1[2]);
+ if ((tilemap_2)&&(msk&0x0f00)) popmessage("x:%04X y:%04X f:%04X",cave_vctrl_2[0],cave_vctrl_2[1],cave_vctrl_2[2]);
+ if ((tilemap_3)&&(msk&0xf000)) popmessage("x:%04X y:%04X f:%04X",cave_vctrl_3[0],cave_vctrl_3[1],cave_vctrl_3[2]);
+ }
+
+ /* Show the row / "column" scroll enable flags, when they change state */
+ rasflag = 0;
+ if (tilemap_0) { rasflag |= (cave_vctrl_0[0] & 0x4000) ? 0x0001 : 0;
+ rasflag |= (cave_vctrl_0[1] & 0x4000) ? 0x0002 : 0; }
+ if (tilemap_1) { rasflag |= (cave_vctrl_1[0] & 0x4000) ? 0x0010 : 0;
+ rasflag |= (cave_vctrl_1[1] & 0x4000) ? 0x0020 : 0; }
+ if (tilemap_2) { rasflag |= (cave_vctrl_2[0] & 0x4000) ? 0x0100 : 0;
+ rasflag |= (cave_vctrl_2[1] & 0x4000) ? 0x0200 : 0; }
+ if (tilemap_3) { rasflag |= (cave_vctrl_3[0] & 0x4000) ? 0x1000 : 0;
+ rasflag |= (cave_vctrl_3[1] & 0x4000) ? 0x2000 : 0; }
+ if (rasflag != old_rasflag)
+ {
+ popmessage("Line Effect: 0:%c%c 1:%c%c 2:%c%c 3:%c%c",
+ (rasflag&0x0001)?'x':' ', (rasflag&0x0002)?'y':' ',
+ (rasflag&0x0010)?'x':' ', (rasflag&0x0020)?'y':' ',
+ (rasflag&0x0100)?'x':' ', (rasflag&0x0200)?'y':' ',
+ (rasflag&0x1000)?'x':' ', (rasflag&0x2000)?'y':' ' );
+ old_rasflag = rasflag;
+ }
+}
+#endif
+
+ cave_sprite_check(machine, cliprect);
+
+ fillbitmap(bitmap,machine->remapped_colortable[background_color],cliprect);
+
+ /*
+ Tiles and sprites are ordered by priority (0 back, 3 front) with
+ sprites going below tiles of their same priority.
+
+ Sprites with the same priority are ordered by their place in
+ sprite RAM (last sprite is the frontmost).
+
+ Tiles with the same priority are ordered by the priority of their layer.
+
+ Tiles with the same priority *and* the same priority of their layer
+ are ordered by layer (0 back, 2 front)
+ */
+ for (pri=0;pri<=3;pri++) // tile / sprite priority
+ {
+ if (layers_ctrl&(1<<(pri+16))) (*cave_sprite_draw)( pri );
+
+ for (pri2=0;pri2<=3;pri2++) // priority of the whole layer
+ {
+ if (layers_ctrl&(1<<(pri+ 0))) cave_tilemap_0_draw(bitmap, cliprect, pri, 0, pri2);
+ if (layers_ctrl&(1<<(pri+ 4))) cave_tilemap_1_draw(bitmap, cliprect, pri, 0, pri2);
+ if (layers_ctrl&(1<<(pri+ 8))) cave_tilemap_2_draw(bitmap, cliprect, pri, 0, pri2);
+ if (layers_ctrl&(1<<(pri+12))) cave_tilemap_3_draw(bitmap, cliprect, pri, 0, pri2);
+ }
+ }
+ return 0;
+}
+
+
+
+/**************************************************************/
+void cave_get_sprite_info(running_machine *machine)
+{
+ if(cave_kludge == 3) /* mazinger metmqstr */
+ {
+ if (video_skip_this_frame() == 0)
+ {
+ spriteram_bank = spriteram_bank_delay;
+ (*get_sprite_info)(machine);
+ }
+ spriteram_bank_delay = cave_videoregs[ 4 ] & 1;
+ }
+ else
+ {
+ if (video_skip_this_frame() == 0)
+ {
+ spriteram_bank = cave_videoregs[ 4 ] & 1;
+ (*get_sprite_info)(machine);
+ }
+ }
+}
diff --git a/src/mame/video/cbasebal.c b/src/mame/video/cbasebal.c
new file mode 100644
index 00000000000..11a34eb8df8
--- /dev/null
+++ b/src/mame/video/cbasebal.c
@@ -0,0 +1,187 @@
+#include "driver.h"
+
+
+static UINT8 *cbasebal_textram,*cbasebal_scrollram;
+static tilemap *fg_tilemap,*bg_tilemap;
+static int tilebank,spritebank;
+static int text_on,bg_on,obj_on;
+static int flipscreen;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 attr = cbasebal_scrollram[2*tile_index+1];
+ SET_TILE_INFO(
+ 1,
+ cbasebal_scrollram[2*tile_index] + ((attr & 0x07) << 8) + 0x800 * tilebank,
+ (attr & 0xf0) >> 4,
+ (attr & 0x08) ? TILE_FLIPX : 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 attr = cbasebal_textram[tile_index+0x800];
+ SET_TILE_INFO(
+ 0,
+ cbasebal_textram[tile_index] + ((attr & 0xf0) << 4),
+ attr & 0x07,
+ (attr & 0x08) ? TILE_FLIPX : 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( cbasebal )
+{
+ cbasebal_textram = auto_malloc(0x1000);
+ cbasebal_scrollram = auto_malloc(0x1000);
+
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,64,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,3);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( cbasebal_textram_w )
+{
+ cbasebal_textram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x7ff);
+}
+
+READ8_HANDLER( cbasebal_textram_r )
+{
+ return cbasebal_textram[offset];
+}
+
+WRITE8_HANDLER( cbasebal_scrollram_w )
+{
+ cbasebal_scrollram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+READ8_HANDLER( cbasebal_scrollram_r )
+{
+ return cbasebal_scrollram[offset];
+}
+
+WRITE8_HANDLER( cbasebal_gfxctrl_w )
+{
+ /* bit 0 is unknown - toggles continuously */
+
+ /* bit 1 is flip screen */
+ flipscreen = data & 0x02;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ /* bit 2 is unknown - unused? */
+
+ /* bit 3 is tile bank */
+ if (tilebank != ((data & 0x08) >> 3))
+ {
+ tilebank = (data & 0x08) >> 3;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ /* bit 4 is sprite bank */
+ spritebank = (data & 0x10) >> 4;
+
+ /* bits 5 is text enable */
+ text_on = ~data & 0x20;
+
+ /* bits 6-7 are bg/sprite enable (don't know which is which) */
+ bg_on = ~data & 0x40;
+ obj_on = ~data & 0x80;
+
+ /* other bits unknown, but used */
+}
+
+WRITE8_HANDLER( cbasebal_scrollx_w )
+{
+ static UINT8 scroll[2];
+
+ scroll[offset] = data;
+ tilemap_set_scrollx(bg_tilemap,0,scroll[0] + 256 * scroll[1]);
+}
+
+WRITE8_HANDLER( cbasebal_scrolly_w )
+{
+ static UINT8 scroll[2];
+
+ scroll[offset] = data;
+ tilemap_set_scrolly(bg_tilemap,0,scroll[0] + 256 * scroll[1]);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs,sx,sy;
+
+ /* the last entry is not a sprite, we skip it otherwise spang shows a bubble */
+ /* moving diagonally across the screen */
+ for (offs = spriteram_size-8;offs >= 0;offs -= 4)
+ {
+ int code = spriteram[offs];
+ int attr = spriteram[offs+1];
+ int color = attr & 0x07;
+ int flipx = attr & 0x08;
+ sx = spriteram[offs+3] + ((attr & 0x10) << 4);
+ sy = ((spriteram[offs+2] + 8) & 0xff) - 8;
+ code += (attr & 0xe0) << 3;
+ code += spritebank * 0x800;
+
+ if (flipscreen)
+ {
+ sx = 496 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ }
+
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx,flipscreen,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+VIDEO_UPDATE( cbasebal )
+{
+ if (bg_on)
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ else
+ fillbitmap(bitmap,machine->pens[768],cliprect);
+
+ if (obj_on)
+ draw_sprites(machine, bitmap,cliprect);
+
+ if (text_on)
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/cbuster.c b/src/mame/video/cbuster.c
new file mode 100644
index 00000000000..e800d5db0e8
--- /dev/null
+++ b/src/mame/video/cbuster.c
@@ -0,0 +1,161 @@
+/***************************************************************************
+
+ Crude Buster Video emulation - Bryan McPhail, mish@tendril.co.uk
+
+***************************************************************************/
+
+#include "driver.h"
+#include "deco16ic.h"
+
+static int twocrude_pri;
+
+/******************************************************************************/
+
+static int bank_callback(const int bank)
+{
+ return ((bank>>4)&0x7) * 0x1000;
+}
+
+VIDEO_START( twocrude )
+{
+ deco16_2_video_init(0);
+
+ deco16_set_tilemap_bank_callback(0, bank_callback);
+ deco16_set_tilemap_bank_callback(1, bank_callback);
+ deco16_set_tilemap_bank_callback(2, bank_callback);
+ deco16_set_tilemap_bank_callback(3, bank_callback);
+
+ deco16_pf1_colour_bank=0x00;
+ deco16_pf2_colour_bank=0x20;
+ deco16_pf4_colour_bank=0x40;
+ deco16_pf3_colour_bank=0x30;
+}
+
+/******************************************************************************/
+
+static void update_24bitcol(int offset)
+{
+ UINT8 r,g,b; /* The highest palette value seems to be 0x8e */
+
+ r = (UINT8)((float)((paletteram16[offset] >> 0) & 0xff)*1.75);
+ g = (UINT8)((float)((paletteram16[offset] >> 8) & 0xff)*1.75);
+ b = (UINT8)((float)((paletteram16_2[offset] >> 0) & 0xff)*1.75);
+
+ palette_set_color(Machine,offset,MAKE_RGB(r,g,b));
+}
+
+WRITE16_HANDLER( twocrude_palette_24bit_rg_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ update_24bitcol(offset);
+}
+
+WRITE16_HANDLER( twocrude_palette_24bit_b_w )
+{
+ COMBINE_DATA(&paletteram16_2[offset]);
+ update_24bitcol(offset);
+}
+
+/******************************************************************************/
+
+void twocrude_pri_w(int pri)
+{
+ twocrude_pri=pri;
+}
+
+/******************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ sprite = buffered_spriteram16[offs+1] & 0x7fff;
+ if (!sprite) continue;
+
+ y = buffered_spriteram16[offs];
+ x = buffered_spriteram16[offs+2];
+
+ if ((y&0x8000) && pri==1) continue;
+ if (!(y&0x8000) && pri==0) continue;
+
+ colour = (x >> 9) &0xf;
+ if (x&0x2000) colour+=64;
+
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 256) x -= 512;
+ if (y >= 256) y -= 512;
+ x = 240 - x;
+ y = 240 - y;
+
+ if (x>256) continue; /* Speedup */
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen) {
+ y=240-y;
+ x=240-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ multi--;
+ }
+ }
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( twocrude )
+{
+ flip_screen_set( !(deco16_pf12_control[0]&0x80) );
+
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+ deco16_pf34_update(deco16_pf3_rowscroll,deco16_pf4_rowscroll);
+
+ /* Draw playfields & sprites */
+ deco16_tilemap_4_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ draw_sprites(machine,bitmap,cliprect,0);
+
+ if (twocrude_pri) {
+ deco16_tilemap_2_draw(bitmap,cliprect,0,0);
+ deco16_tilemap_3_draw(bitmap,cliprect,0,0);
+ }
+ else {
+ deco16_tilemap_3_draw(bitmap,cliprect,0,0);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,0);
+ }
+
+ draw_sprites(machine,bitmap,cliprect,1);
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+ return 0;
+}
diff --git a/src/mame/video/ccastles.c b/src/mame/video/ccastles.c
new file mode 100644
index 00000000000..26dd241c730
--- /dev/null
+++ b/src/mame/video/ccastles.c
@@ -0,0 +1,366 @@
+/***************************************************************************
+
+ Atari Crystal Castles hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "ccastles.h"
+#include "video/resnet.h"
+
+
+
+/*************************************
+ *
+ * Globals
+ *
+ *************************************/
+
+static double rweights[3], gweights[3], bweights[3];
+static mame_bitmap *spritebitmap;
+
+static UINT8 video_control[8];
+static UINT8 bitmode_addr[2];
+static UINT8 hscroll;
+static UINT8 vscroll;
+
+static const UINT8 *syncprom;
+static const UINT8 *wpprom;
+static const UINT8 *priprom;
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( ccastles )
+{
+ static const int resistances[3] = { 22000, 10000, 4700 };
+
+ /* get pointers to our PROMs */
+ syncprom = memory_region(REGION_PROMS) + 0x000;
+ wpprom = memory_region(REGION_PROMS) + 0x200;
+ priprom = memory_region(REGION_PROMS) + 0x300;
+
+ /* compute the color output resistor weights at startup */
+ compute_resistor_weights(0, 255, -1.0,
+ 3, resistances, rweights, 1000, 0,
+ 3, resistances, gweights, 1000, 0,
+ 3, resistances, bweights, 1000, 0);
+
+ /* allocate a bitmap for drawing sprites */
+ spritebitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ /* register for savestates */
+ state_save_register_global_array(video_control);
+ state_save_register_global_array(bitmode_addr);
+ state_save_register_global(hscroll);
+ state_save_register_global(vscroll);
+}
+
+
+
+/*************************************
+ *
+ * Video control registers
+ *
+ *************************************/
+
+WRITE8_HANDLER( ccastles_hscroll_w )
+{
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ hscroll = data;
+}
+
+
+WRITE8_HANDLER( ccastles_vscroll_w )
+{
+ vscroll = data;
+}
+
+
+WRITE8_HANDLER( ccastles_video_control_w )
+{
+ /* only D3 matters */
+ video_control[offset] = (data >> 3) & 1;
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM accesses
+ *
+ *************************************/
+
+WRITE8_HANDLER( ccastles_paletteram_w )
+{
+ int bit0, bit1, bit2;
+ int r, g, b;
+
+ /* extract the raw RGB bits */
+ r = ((data & 0xc0) >> 6) | ((offset & 0x20) >> 3);
+ b = (data & 0x38) >> 3;
+ g = (data & 0x07);
+
+ /* red component (inverted) */
+ bit0 = (~r >> 0) & 0x01;
+ bit1 = (~r >> 1) & 0x01;
+ bit2 = (~r >> 2) & 0x01;
+ r = combine_3_weights(rweights, bit0, bit1, bit2);
+
+ /* green component (inverted) */
+ bit0 = (~g >> 0) & 0x01;
+ bit1 = (~g >> 1) & 0x01;
+ bit2 = (~g >> 2) & 0x01;
+ g = combine_3_weights(gweights, bit0, bit1, bit2);
+
+ /* blue component (inverted) */
+ bit0 = (~b >> 0) & 0x01;
+ bit1 = (~b >> 1) & 0x01;
+ bit2 = (~b >> 2) & 0x01;
+ b = combine_3_weights(bweights, bit0, bit1, bit2);
+
+ palette_set_color(Machine, offset & 0x1f, MAKE_RGB(r, g, b));
+}
+
+
+
+/*************************************
+ *
+ * Video RAM access via the write
+ * protect PROM
+ *
+ *************************************/
+
+INLINE void ccastles_write_vram(UINT16 addr, UINT8 data, UINT8 bitmd, UINT8 pixba)
+{
+ UINT8 *dest = &videoram[addr & 0x7ffe];
+ UINT8 promaddr = 0;
+ UINT8 wpbits;
+
+ /*
+ Inputs to the write-protect PROM:
+
+ Bit 7 = BA1520 = 0 if (BA15-BA12 != 0), or 1 otherwise
+ Bit 6 = DRBA11
+ Bit 5 = DRBA10
+ Bit 4 = /BITMD
+ Bit 3 = GND
+ Bit 2 = BA0
+ Bit 1 = PIXB
+ Bit 0 = PIXA
+ */
+ promaddr |= ((addr & 0xf000) == 0) << 7;
+ promaddr |= (addr & 0x0c00) >> 5;
+ promaddr |= (!bitmd) << 4;
+ promaddr |= (addr & 0x0001) << 2;
+ promaddr |= (pixba << 0);
+
+ /* look up the PROM result */
+ wpbits = wpprom[promaddr];
+
+ /* write to the appropriate parts of VRAM depending on the result */
+ if (!(wpbits & 1))
+ dest[0] = (dest[0] & 0xf0) | (data & 0x0f);
+ if (!(wpbits & 2))
+ dest[0] = (dest[0] & 0x0f) | (data & 0xf0);
+ if (!(wpbits & 4))
+ dest[1] = (dest[1] & 0xf0) | (data & 0x0f);
+ if (!(wpbits & 8))
+ dest[1] = (dest[1] & 0x0f) | (data & 0xf0);
+}
+
+
+
+/*************************************
+ *
+ * Autoincrement control for bit mode
+ *
+ *************************************/
+
+INLINE void bitmode_autoinc(void)
+{
+ /* auto increment in the x-direction if it's enabled */
+ if (!video_control[0]) /* /AX */
+ {
+ if (!video_control[2]) /* /XINC */
+ bitmode_addr[0]++;
+ else
+ bitmode_addr[0]--;
+ }
+
+ /* auto increment in the y-direction if it's enabled */
+ if (!video_control[1]) /* /AY */
+ {
+ if (!video_control[3]) /* /YINC */
+ bitmode_addr[1]++;
+ else
+ bitmode_addr[1]--;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Standard video RAM access
+ *
+ *************************************/
+
+WRITE8_HANDLER( ccastles_videoram_w )
+{
+ /* direct writes to VRAM go through the write protect PROM as well */
+ ccastles_write_vram(offset, data, 0, 0);
+}
+
+
+
+/*************************************
+ *
+ * Bit mode video RAM access
+ *
+ *************************************/
+
+READ8_HANDLER( ccastles_bitmode_r )
+{
+ /* in bitmode, the address comes from the autoincrement latches */
+ UINT16 addr = (bitmode_addr[1] << 7) | (bitmode_addr[0] >> 1);
+
+ /* the appropriate pixel is selected into the upper 4 bits */
+ UINT8 result = videoram[addr] << ((~bitmode_addr[0] & 1) * 4);
+
+ /* autoincrement because /BITMD was selected */
+ bitmode_autoinc();
+
+ /* the low 4 bits of the data lines are not driven so make them all 1's */
+ return result | 0x0f;
+}
+
+
+WRITE8_HANDLER( ccastles_bitmode_w )
+{
+ /* in bitmode, the address comes from the autoincrement latches */
+ UINT16 addr = (bitmode_addr[1] << 7) | (bitmode_addr[0] >> 1);
+
+ /* the upper 4 bits of data are replicated to the lower 4 bits */
+ data = (data & 0xf0) | (data >> 4);
+
+ /* write through the generic VRAM routine, passing the low 2 X bits as PIXB/PIXA */
+ ccastles_write_vram(addr, data, 1, bitmode_addr[0] & 3);
+
+ /* autoincrement because /BITMD was selected */
+ bitmode_autoinc();
+}
+
+
+WRITE8_HANDLER( ccastles_bitmode_addr_w )
+{
+ /* write through to video RAM and also to the addressing latches */
+ ccastles_write_vram(offset, data, 0, 0);
+ bitmode_addr[offset] = data;
+}
+
+
+
+/*************************************
+ *
+ * Video updating
+ *
+ *************************************/
+
+VIDEO_UPDATE( ccastles )
+{
+ UINT8 *spriteaddr = &spriteram[video_control[7] * 0x100]; /* BUF1/BUF2 */
+ int flip = video_control[4] ? 0xff : 0x00; /* PLAYER2 */
+ pen_t black = get_black_pen(machine);
+ int x, y, offs;
+
+ /* draw the sprites */
+ fillbitmap(spritebitmap, 0x0f, cliprect);
+ for (offs = 0; offs < 320/2; offs += 4)
+ {
+ int x = spriteaddr[offs+3];
+ int y = 256 - 16 - spriteaddr[offs+1];
+ int which = spriteaddr[offs];
+ int color = spriteaddr[offs+2] >> 7;
+
+ drawgfx(spritebitmap, machine->gfx[0], which, color, flip, flip, x, y, cliprect, TRANSPARENCY_PEN, 7);
+ }
+
+ /* draw the bitmap to the screen, looping over Y */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *dst = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+
+ /* if we're in the VBLANK region, just fill with black */
+ if (syncprom[y] & 1)
+ {
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ dst[x] = black;
+ }
+
+ /* non-VBLANK region: merge the sprites and the bitmap */
+ else
+ {
+ UINT16 *mosrc = (UINT16 *)spritebitmap->base + y * spritebitmap->rowpixels;
+ int effy = (((y - ccastles_vblank_end) + (flip ? 0 : vscroll)) ^ flip) & 0xff;
+ UINT8 *src;
+
+ /* the "POTATO" chip does some magic here; this is just a guess */
+ if (effy < 24)
+ effy = 24;
+ src = &videoram[effy * 128];
+
+ /* loop over X */
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ /* if we're in the HBLANK region, just store black */
+ if (x >= 256)
+ dst[x] = black;
+
+ /* otherwise, process normally */
+ else
+ {
+ int effx = (hscroll + (x ^ flip)) & 255;
+
+ /* low 4 bits = left pixel, high 4 bits = right pixel */
+ UINT8 pix = (src[effx / 2] >> ((effx & 1) * 4)) & 0x0f;
+ UINT8 mopix = mosrc[x];
+ UINT8 prindex, prvalue;
+
+ /* Inputs to the priority PROM:
+
+ Bit 7 = GND
+ Bit 6 = /CRAM
+ Bit 5 = BA4
+ Bit 4 = MV2
+ Bit 3 = MV1
+ Bit 2 = MV0
+ Bit 1 = MPI
+ Bit 0 = BIT3
+ */
+ prindex = 0x40;
+ prindex |= (mopix & 7) << 2;
+ prindex |= (mopix & 8) >> 2;
+ prindex |= (pix & 8) >> 3;
+ prvalue = priprom[prindex];
+
+ /* Bit 1 of prvalue selects the low 4 bits of the final pixel */
+ if (prvalue & 2)
+ pix = mopix;
+
+ /* Bit 0 of prvalue selects bit 4 of the final color */
+ pix |= (prvalue & 1) << 4;
+
+ /* store the pixel value and also a priority value based on the topmost bit */
+ dst[x] = pix;
+ }
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/cchasm.c b/src/mame/video/cchasm.c
new file mode 100644
index 00000000000..0c4cfd92693
--- /dev/null
+++ b/src/mame/video/cchasm.c
@@ -0,0 +1,136 @@
+/***************************************************************************
+
+ Cinematronics Cosmic Chasm hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/vector.h"
+#include "cchasm.h"
+
+#define HALT 0
+#define JUMP 1
+#define COLOR 2
+#define SCALEY 3
+#define POSY 4
+#define SCALEX 5
+#define POSX 6
+#define LENGTH 7
+
+UINT16 *cchasm_ram;
+
+static int xcenter, ycenter;
+
+static TIMER_CALLBACK( cchasm_refresh_end )
+{
+ cpunum_set_input_line (0, 2, ASSERT_LINE);
+}
+
+static void cchasm_refresh (void)
+{
+
+ int pc = 0;
+ int done = 0;
+ int opcode, data;
+ int currentx = 0, currenty = 0;
+ int scalex = 0, scaley = 0;
+ int color = 0;
+ int total_length = 1; /* length of all lines drawn in a frame */
+ int move = 0;
+
+ vector_clear_list();
+
+ while (!done)
+ {
+ data = cchasm_ram[pc];
+ opcode = data >> 12;
+ data &= 0xfff;
+ if ((opcode > COLOR) && (data & 0x800))
+ data |= 0xfffff000;
+
+ pc++;
+
+ switch (opcode)
+ {
+ case HALT:
+ done=1;
+ break;
+ case JUMP:
+ pc = data - 0xb00;
+ logerror("JUMP to %x\n", data);
+ break;
+ case COLOR:
+ color = VECTOR_COLOR444(data ^ 0xfff);
+ break;
+ case SCALEY:
+ scaley = data << 5;
+ break;
+ case POSY:
+ move = 1;
+ currenty = ycenter + (data << 16);
+ break;
+ case SCALEX:
+ scalex = data << 5;
+ break;
+ case POSX:
+ move = 1;
+ currentx = xcenter - (data << 16);
+ break;
+ case LENGTH:
+ if (move)
+ {
+ vector_add_point (currentx, currenty, 0, 0);
+ move = 0;
+ }
+
+ currentx -= data * scalex;
+ currenty += data * scaley;
+
+ total_length += abs(data);
+
+ if (color)
+ vector_add_point (currentx, currenty, color, 0xff);
+ else
+ move = 1;
+ break;
+ default:
+ logerror("Unknown refresh proc opcode %x with data %x at pc = %x\n", opcode, data, pc-2);
+ done = 1;
+ break;
+ }
+ }
+ /* Refresh processor runs with 6 MHz */
+ timer_set (attotime_mul(ATTOTIME_IN_HZ(6000000), total_length), 0, cchasm_refresh_end);
+}
+
+
+WRITE16_HANDLER( cchasm_refresh_control_w )
+{
+ if (ACCESSING_MSB)
+ {
+ switch (data >> 8)
+ {
+ case 0x37:
+ cchasm_refresh();
+ break;
+ case 0xf7:
+ cpunum_set_input_line (0, 2, CLEAR_LINE);
+ break;
+ }
+ }
+}
+
+VIDEO_START( cchasm )
+{
+ int xmin, xmax, ymin, ymax;
+
+ xmin=machine->screen[0].visarea.min_x;
+ ymin=machine->screen[0].visarea.min_y;
+ xmax=machine->screen[0].visarea.max_x;
+ ymax=machine->screen[0].visarea.max_y;
+
+ xcenter=((xmax+xmin)/2) << 16;
+ ycenter=((ymax+ymin)/2) << 16;
+
+ video_start_vector(machine);
+}
diff --git a/src/mame/video/cclimber.c b/src/mame/video/cclimber.c
new file mode 100644
index 00000000000..1475456b880
--- /dev/null
+++ b/src/mame/video/cclimber.c
@@ -0,0 +1,935 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/cclimber.h"
+
+
+UINT8 *cclimber_bsvideoram;
+size_t cclimber_bsvideoram_size;
+UINT8 *cclimber_bigspriteram;
+UINT8 *cclimber_column_scroll;
+static int palettebank;
+static int sidepanel_enabled;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Crazy Climber has three 32x8 palette PROMs.
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( cclimber )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + (offs)])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+
+ /* character and sprite lookup table */
+ /* they use colors 0-63 */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ {
+ /* pen 0 always uses color 0 (background in River Patrol and Silver Land) */
+ if (i % 4 == 0) COLOR(0,i) = 0;
+ else COLOR(0,i) = i;
+ }
+
+ /* big sprite lookup table */
+ /* it uses colors 64-95 */
+ for (i = 0;i < TOTAL_COLORS(2);i++)
+ {
+ if (i % 4 == 0) COLOR(2,i) = 0;
+ else COLOR(2,i) = i + 64;
+ }
+}
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Swimmer has two 256x4 char/sprite palette PROMs and one 32x8 big sprite
+ palette PROM.
+ The palette PROMs are connected to the RGB output this way:
+ (the 500 and 250 ohm resistors are made of 1 kohm resistors in parallel)
+
+ bit 3 -- 250 ohm resistor -- BLUE
+ -- 500 ohm resistor -- BLUE
+ -- 250 ohm resistor -- GREEN
+ bit 0 -- 500 ohm resistor -- GREEN
+ bit 3 -- 1 kohm resistor -- GREEN
+ -- 250 ohm resistor -- RED
+ -- 500 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+ bit 7 -- 250 ohm resistor -- BLUE
+ -- 500 ohm resistor -- BLUE
+ -- 250 ohm resistor -- GREEN
+ -- 500 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 250 ohm resistor -- RED
+ -- 500 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+ Additionally, the background color of the score panel is determined by
+ these resistors:
+
+ /--- tri-state -- 470 -- BLUE
+ +5V -- 1kohm ------- tri-state -- 390 -- GREEN
+ \--- tri-state -- 1000 -- RED
+
+***************************************************************************/
+
+#define BGPEN (256+32)
+#define SIDEPEN (256+32+1)
+
+PALETTE_INIT( swimmer )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + (offs)])
+
+
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x20 * bit0 + 0x40 * bit1 + 0x80 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i+256] >> 0) & 0x01;
+ bit2 = (color_prom[i+256] >> 1) & 0x01;
+ g = 0x20 * bit0 + 0x40 * bit1 + 0x80 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (color_prom[i+256] >> 2) & 0x01;
+ bit2 = (color_prom[i+256] >> 3) & 0x01;
+ b = 0x20 * bit0 + 0x40 * bit1 + 0x80 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ /* side panel */
+ if (i % 8)
+ {
+ COLOR(0,i) = i;
+ COLOR(0,i+256) = i;
+ }
+ else
+ {
+ /* background */
+ COLOR(0,i) = BGPEN;
+ COLOR(0,i+256) = SIDEPEN;
+ }
+ }
+
+ color_prom += 2 * 256;
+
+ /* big sprite */
+ for (i = 0;i < 32;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x20 * bit0 + 0x40 * bit1 + 0x80 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x20 * bit0 + 0x40 * bit1 + 0x80 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x20 * bit0 + 0x40 * bit1 + 0x80 * bit2;
+
+ palette_set_color(machine,i+256,MAKE_RGB(r,g,b));
+
+ if (i % 8 == 0) COLOR(2,i) = BGPEN; /* enforce transparency */
+ else COLOR(2,i) = i+256;
+ }
+
+ /* background */
+ palette_set_color(machine,BGPEN,MAKE_RGB(0,0,0));
+ /* side panel background color */
+#if 0
+ // values calculated from the resistors don't seem to match the real board
+ palette_set_color(machine,SIDEPEN,MAKE_RGB(0x24,0x5d,0x4e));
+#endif
+ palette_set_color(machine,SIDEPEN,MAKE_RGB(0x20,0x98,0x79));
+}
+
+
+
+/***************************************************************************
+
+ Swimmer can directly set the background color.
+ The latch is connected to the RGB output this way:
+ (the 500 and 250 ohm resistors are made of 1 kohm resistors in parallel)
+
+ bit 7 -- 250 ohm resistor -- RED
+ -- 500 ohm resistor -- RED
+ -- 250 ohm resistor -- GREEN
+ -- 500 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 250 ohm resistor -- BLUE
+ -- 500 ohm resistor -- BLUE
+ bit 0 -- 1 kohm resistor -- BLUE
+
+***************************************************************************/
+WRITE8_HANDLER( swimmer_bgcolor_w )
+{
+ int bit0,bit1,bit2;
+ int r,g,b;
+
+
+ /* red component */
+ bit0 = 0;
+ bit1 = (data >> 6) & 0x01;
+ bit2 = (data >> 7) & 0x01;
+ r = 0x20 * bit0 + 0x40 * bit1 + 0x80 * bit2;
+
+ /* green component */
+ bit0 = (data >> 3) & 0x01;
+ bit1 = (data >> 4) & 0x01;
+ bit2 = (data >> 5) & 0x01;
+ g = 0x20 * bit0 + 0x40 * bit1 + 0x80 * bit2;
+
+ /* blue component */
+ bit0 = (data >> 0) & 0x01;
+ bit1 = (data >> 1) & 0x01;
+ bit2 = (data >> 2) & 0x01;
+ b = 0x20 * bit0 + 0x40 * bit1 + 0x80 * bit2;
+
+ palette_set_color(Machine,BGPEN,MAKE_RGB(r,g,b));
+}
+
+
+
+WRITE8_HANDLER( cclimber_colorram_w )
+{
+ /* bit 5 of the address is not used for color memory. There is just */
+ /* 512 bytes of memory; every two consecutive rows share the same memory */
+ /* region. */
+ offset &= 0xffdf;
+
+ colorram[offset] = data;
+ colorram[offset + 0x20] = data;
+}
+
+
+
+WRITE8_HANDLER( cclimber_bigsprite_videoram_w )
+{
+ cclimber_bsvideoram[offset] = data;
+}
+
+
+
+WRITE8_HANDLER( swimmer_palettebank_w )
+{
+ palettebank = data & 1;
+}
+
+
+
+WRITE8_HANDLER( swimmer_sidepanel_enable_w )
+{
+ sidepanel_enabled = data & 1;
+}
+
+
+
+static void cclimber_draw_big_sprite(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+ int ox,oy,sx,sy,flipx,flipy;
+ int color;
+
+
+ ox = 136 - cclimber_bigspriteram[3];
+ oy = 128 - cclimber_bigspriteram[2];
+ flipx = cclimber_bigspriteram[1] & 0x10;
+ flipy = cclimber_bigspriteram[1] & 0x20;
+ if (flip_screen_y) /* only the Y direction has to be flipped */
+ {
+ oy = 128 - oy;
+ flipy = !flipy;
+ }
+ color = cclimber_bigspriteram[1] & 0x07; /* cclimber */
+// color = cclimber_bigspriteram[1] & 0x03; /* swimmer */
+
+ for (offs = cclimber_bsvideoram_size - 1;offs >= 0;offs--)
+ {
+ sx = offs % 16;
+ sy = offs / 16;
+ if (flipx) sx = 15 - sx;
+ if (flipy) sy = 15 - sy;
+
+ drawgfx(bitmap,machine->gfx[2],
+// cclimber_bsvideoram[offs], /* cclimber */
+ cclimber_bsvideoram[offs] + ((cclimber_bigspriteram[1] & 0x08) << 5), /* swimmer */
+ color,
+ flipx,flipy,
+ (ox+8*sx) & 0xff,(oy+8*sy) & 0xff,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ /* wraparound */
+ drawgfx(bitmap,machine->gfx[2],
+// cclimber_bsvideoram[offs], /* cclimber */
+ cclimber_bsvideoram[offs] + ((cclimber_bigspriteram[1] & 0x08) << 5), /* swimmer */
+ color,
+ flipx,flipy,
+ ((ox+8*sx) & 0xff) - 256,(oy+8*sy) & 0xff,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+VIDEO_UPDATE( cclimber )
+{
+ int offs;
+
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int sx,sy,flipx,flipy;
+
+ sx = offs % 32;
+ sy = offs / 32;
+ flipx = colorram[offs] & 0x40;
+ flipy = colorram[offs] & 0x80;
+ /* vertical flipping flips two adjacent characters */
+ if (flipy) sy ^= 1;
+
+ if (flip_screen_x)
+ {
+ sx = 31 - sx;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ sy = 31 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(tmpbitmap,machine->gfx[(colorram[offs] & 0x10) ? 1 : 0],
+ videoram[offs] + 8 * (colorram[offs] & 0x20),
+ colorram[offs] & 0x0f,
+ flipx,flipy,
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+
+
+ /* copy the temporary bitmap to the screen */
+ {
+ int scroll[32];
+
+
+ if (flip_screen_x)
+ {
+ for (offs = 0;offs < 32;offs++)
+ {
+ scroll[offs] = -cclimber_column_scroll[31 - offs];
+ if (flip_screen_y) scroll[offs] = -scroll[offs];
+ }
+ }
+ else
+ {
+ for (offs = 0;offs < 32;offs++)
+ {
+ scroll[offs] = -cclimber_column_scroll[offs];
+ if (flip_screen_y) scroll[offs] = -scroll[offs];
+ }
+ }
+
+ copyscrollbitmap(bitmap,tmpbitmap,0,0,32,scroll,cliprect,TRANSPARENCY_NONE,0);
+ }
+
+
+ if (cclimber_bigspriteram[0] & 1)
+ /* draw the "big sprite" below sprites */
+ cclimber_draw_big_sprite(machine, bitmap, cliprect);
+
+
+ /* Draw the sprites. Note that it is important to draw them exactly in this */
+ /* order, to have the correct priorities. */
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int sx,sy,flipx,flipy;
+
+
+ sx = spriteram[offs + 3];
+ sy = 240 - spriteram[offs + 2];
+ flipx = spriteram[offs] & 0x40;
+ flipy = spriteram[offs] & 0x80;
+ if (flip_screen_x)
+ {
+ sx = 240 - sx;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[spriteram[offs + 1] & 0x10 ? 4 : 3],
+ (spriteram[offs] & 0x3f) + 2 * (spriteram[offs + 1] & 0x20),
+ spriteram[offs + 1] & 0x0f,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+
+ if ((cclimber_bigspriteram[0] & 1) == 0)
+ /* draw the "big sprite" over sprites */
+ cclimber_draw_big_sprite(machine, bitmap, cliprect);
+ return 0;
+}
+
+
+VIDEO_UPDATE( cannonb )
+{
+ int offs;
+
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int attr,code,color,sx,sy,flipx,flipy;
+
+ code = videoram[offs];
+ attr = colorram[offs] & 0x20;
+ color = colorram[offs] & 0x0f;
+ sx = offs % 32;
+ sy = offs / 32;
+ flipx = colorram[offs] & 0x40;
+ flipy = colorram[offs] & 0x80;
+ /* vertical flipping flips two adjacent characters */
+ if (flipy) sy ^= 1;
+
+ if (flip_screen_x)
+ {
+ sx = 31 - sx;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ sy = 31 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(tmpbitmap,machine->gfx[0],
+ code + 8 * attr,
+ color,
+ flipx,flipy,
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+
+
+ /* copy the temporary bitmap to the screen */
+ {
+ int scroll[32];
+
+
+ if (flip_screen_x)
+ {
+ for (offs = 0;offs < 32;offs++)
+ {
+ scroll[offs] = -cclimber_column_scroll[31 - offs];
+ if (flip_screen_y) scroll[offs] = -scroll[offs];
+ }
+ }
+ else
+ {
+ for (offs = 0;offs < 32;offs++)
+ {
+ scroll[offs] = -cclimber_column_scroll[offs];
+ if (flip_screen_y) scroll[offs] = -scroll[offs];
+ }
+ }
+
+ copyscrollbitmap(bitmap,tmpbitmap,0,0,32,scroll,cliprect,TRANSPARENCY_NONE,0);
+ }
+
+
+ if (cclimber_bigspriteram[0] & 1)
+ /* draw the "big sprite" below sprites */
+ cclimber_draw_big_sprite(machine, bitmap, cliprect);
+
+
+ /* Draw the sprites. Note that it is important to draw them exactly in this */
+ /* order, to have the correct priorities. */
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int code,color,sx,sy,flipx,flipy;
+
+ code = spriteram[offs] & 0x3f;
+ color = spriteram[offs + 1] & 0x0f;
+ sx = spriteram[offs + 3];
+ sy = 240 - spriteram[offs + 2];
+ flipx = spriteram[offs] & 0x40;
+ flipy = spriteram[offs] & 0x80;
+ if (flip_screen_x)
+ {
+ sx = 240 - sx;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[3],
+ code + 0x40,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ if ((cclimber_bigspriteram[0] & 1) == 0)
+ /* draw the "big sprite" over sprites */
+ cclimber_draw_big_sprite(machine, bitmap, cliprect);
+ return 0;
+}
+
+
+VIDEO_UPDATE( swimmer )
+{
+ int offs;
+
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int sx,sy,flipx,flipy,color;
+
+ sx = offs % 32;
+ sy = offs / 32;
+ flipx = colorram[offs] & 0x40;
+ flipy = colorram[offs] & 0x80;
+ /* vertical flipping flips two adjacent characters */
+ if (flipy) sy ^= 1;
+
+ color = (colorram[offs] & 0x0f) + 0x10 * palettebank;
+ if (sx >= 24 && sidepanel_enabled)
+ {
+ color += 32;
+ }
+
+ if (flip_screen_x)
+ {
+ sx = 31 - sx;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ sy = 31 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(tmpbitmap,machine->gfx[0],
+ videoram[offs] + ((colorram[offs] & 0x10) << 4),
+ color,
+ flipx,flipy,
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+
+
+ /* copy the temporary bitmap to the screen */
+ {
+ int scroll[32];
+
+
+ if (flip_screen_y)
+ {
+ for (offs = 0;offs < 32;offs++)
+ scroll[offs] = cclimber_column_scroll[31 - offs];
+ }
+ else
+ {
+ for (offs = 0;offs < 32;offs++)
+ scroll[offs] = -cclimber_column_scroll[offs];
+ }
+
+ copyscrollbitmap(bitmap,tmpbitmap,0,0,32,scroll,cliprect,TRANSPARENCY_NONE,0);
+ }
+
+
+ if (cclimber_bigspriteram[0] & 1)
+ /* draw the "big sprite" below sprites */
+ cclimber_draw_big_sprite(machine, bitmap, cliprect);
+
+
+ /* Draw the sprites. Note that it is important to draw them exactly in this */
+ /* order, to have the correct priorities. */
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int sx,sy,flipx,flipy;
+
+
+ sx = spriteram[offs + 3];
+ sy = 240 - spriteram[offs + 2];
+ flipx = spriteram[offs] & 0x40;
+ flipy = spriteram[offs] & 0x80;
+ if (flip_screen_x)
+ {
+ sx = 240 - sx;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs] & 0x3f) | (spriteram[offs + 1] & 0x10) << 2,
+ (spriteram[offs + 1] & 0x0f) + 0x10 * palettebank,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+
+ if ((cclimber_bigspriteram[0] & 1) == 0)
+ /* draw the "big sprite" over sprites */
+ cclimber_draw_big_sprite(machine, bitmap, cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( yamato )
+{
+ int offs;
+ int i,j;
+
+ /* bg gradient */
+ fillbitmap(bitmap, 0, cliprect);
+
+ for(i=8;i<256;i++)
+ {
+ pen_t pen = 16*4+8*4 + memory_region(REGION_USER1)[(flip_screen_x?0x1280:0x1200)+(i>>1)];
+
+ for(j=0;j<256;j++)
+ {
+ *BITMAP_ADDR16(bitmap, j, i-8) = pen;
+ }
+ }
+
+
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int sx,sy,flipx,flipy;
+
+ sx = offs % 32;
+ sy = offs / 32;
+ flipx = colorram[offs] & 0x40;
+ flipy = colorram[offs] & 0x80;
+ /* vertical flipping flips two adjacent characters */
+ if (flipy) sy ^= 1;
+
+ if (flip_screen_x)
+ {
+ sx = 31 - sx;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ sy = 31 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(tmpbitmap,machine->gfx[(colorram[offs] & 0x10) ? 1 : 0],
+ videoram[offs] + 8 * (colorram[offs] & 0x20),
+ colorram[offs] & 0x0f,
+ flipx,flipy,
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+
+
+ /* copy the temporary bitmap to the screen */
+ {
+ int scroll[32];
+
+
+ if (flip_screen_x)
+ {
+ for (offs = 0;offs < 32;offs++)
+ {
+ scroll[offs] = -cclimber_column_scroll[31 - offs];
+ if (flip_screen_y) scroll[offs] = -scroll[offs];
+ }
+ }
+ else
+ {
+ for (offs = 0;offs < 32;offs++)
+ {
+ scroll[offs] = -cclimber_column_scroll[offs];
+ if (flip_screen_y) scroll[offs] = -scroll[offs];
+ }
+ }
+
+ copyscrollbitmap(bitmap,tmpbitmap,0,0,32,scroll,cliprect,TRANSPARENCY_PEN,0);
+ }
+
+
+ if (cclimber_bigspriteram[0] & 1)
+ /* draw the "big sprite" below sprites */
+ cclimber_draw_big_sprite(machine, bitmap, cliprect);
+
+
+ /* Draw the sprites. Note that it is important to draw them exactly in this */
+ /* order, to have the correct priorities. */
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int sx,sy,flipx,flipy;
+
+
+ sx = spriteram[offs + 3];
+ sy = 240 - spriteram[offs + 2];
+ flipx = spriteram[offs] & 0x40;
+ flipy = spriteram[offs] & 0x80;
+ if (flip_screen_x)
+ {
+ sx = 240 - sx;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[spriteram[offs + 1] & 0x10 ? 4 : 3],
+ (spriteram[offs] & 0x3f) + 2 * (spriteram[offs + 1] & 0x20),
+ spriteram[offs + 1] & 0x0f,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+
+ if ((cclimber_bigspriteram[0] & 1) == 0)
+ /* draw the "big sprite" over sprites */
+ cclimber_draw_big_sprite(machine, bitmap, cliprect);
+ return 0;
+}
+
+
+/* Top Roller */
+
+#define PRIORITY_OVER 0x20
+#define PRIORITY_UNDER 0x00
+#define PRIORITY_MASK 0x20
+
+static tilemap *bg_tilemap;
+
+UINT8 *toprollr_videoram2;
+UINT8 *toprollr_videoram3;
+UINT8 *toprollr_videoram4;
+
+
+static TILE_GET_INFO( get_tile_info_bg )
+{
+ int code = toprollr_videoram3[tile_index];
+ int attr = toprollr_videoram4[tile_index];
+ int flipx,flipy,bank,palette;
+
+ bank=(attr&0x40)<<2;
+
+
+
+
+
+ flipx=1;
+ flipy=0;
+
+ code+=bank;
+
+ palette=(attr&0xf)+0x18 ;
+
+ SET_TILE_INFO(1, code, palette, (flipx?TILE_FLIPX:0)|(flipy?TILE_FLIPY:0));
+}
+
+VIDEO_START( toprollr )
+{
+ bg_tilemap = tilemap_create(get_tile_info_bg,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+}
+
+static void toprollr_draw_big_sprite(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int priority)
+{
+ if((cclimber_bigspriteram[1]&PRIORITY_MASK)==priority)
+ {
+ int code,xs,ys,palette,bank,x,y;
+ int flipx=0;
+ int flipy=0;
+
+ xs=136-cclimber_bigspriteram[3];
+ ys=128-cclimber_bigspriteram[2];
+
+
+ if(xs==0)
+ {
+ return;
+ }
+
+ if (flip_screen_x)
+ {
+ flipx^=1;
+ }
+
+ palette=cclimber_bigspriteram[1]&0x7;
+
+ bank=(cclimber_bigspriteram[1]>>3)&3;
+
+
+ for(y=0;y<16;y++)
+ for(x=0;x<16;x++)
+ {
+ int sx=x;
+ int sy=y;
+ if (flipx) sx = 15 - x;
+ if (flipy) sy = 15 - y;
+
+ code=cclimber_bsvideoram[y*16+x]+bank*256;
+
+ drawgfx(bitmap, machine->gfx[3], code, palette, flipx, flipy,(sx*8+xs)&0xff,(sy*8+ys)&0xff, cliprect, TRANSPARENCY_PEN, 0);
+ drawgfx(bitmap, machine->gfx[3], code, palette, flipx, flipy,((sx*8+xs)&0xff)-256,((sy*8+ys)&0xff)-256, cliprect, TRANSPARENCY_PEN, 0);
+ }
+ }
+}
+
+VIDEO_UPDATE( toprollr )
+{
+
+ UINT32 x,y;
+ int offs;
+ rectangle myclip=*cliprect;
+ myclip.min_x=4*8;
+ myclip.max_x=29*8-1;
+
+ fillbitmap(bitmap, 0, cliprect);
+
+ tilemap_set_scrollx(bg_tilemap,0,toprollr_videoram3[0]+8);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ tilemap_draw(bitmap, &myclip,bg_tilemap,0,0);
+
+ toprollr_draw_big_sprite(machine, bitmap, &myclip, PRIORITY_UNDER);
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int sx,sy,flipx,flipy,palette;
+
+ sx = spriteram[offs + 3]-8;
+ sy = 240 - spriteram[offs + 2];
+ flipx = spriteram[offs] & 0x40;
+ flipy = spriteram[offs] & 0x80;
+ if (flip_screen_x)
+ {
+ sx = 240 - sx;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ palette=0x08+(spriteram[offs + 1] & 0x0f);
+
+ drawgfx(bitmap,machine->gfx[2],
+ (spriteram[offs] & 0x3f) + 2 * (spriteram[offs + 1] & 0x20)+8*(spriteram[offs + 1] & 0x10),
+ palette,
+ flipx,flipy,
+ sx,sy,
+ &myclip,TRANSPARENCY_PEN,0);
+ }
+
+ toprollr_draw_big_sprite(machine, bitmap, &myclip, PRIORITY_OVER);
+
+ for(y=0;y<32;y++)
+ for(x=0;x<32;x++)
+ {
+ int sx=x*8;
+ int sy=y*8;
+ int flipx=0;
+ int flipy=0;
+
+ int code=videoram[y*32+x];
+ int attr=(x>16)?(toprollr_videoram2[(y&0xfe)*32+x]):(toprollr_videoram2[y*32+x]);
+ int palette;
+
+ if (flip_screen_x)
+ {
+ sx = 240 - sx;
+ flipx^=1;
+ }
+ if (flip_screen_y)
+ {
+ sy = 240 - sy;
+ flipy^=1;
+ }
+
+ palette=8+(attr&0xf);
+ drawgfx(bitmap, machine->gfx[0], code+((attr&0xf0)<<4),palette, flipx, flipy, sx, sy, cliprect, TRANSPARENCY_PEN, 0);
+
+ }
+ return 0;
+}
+
+
+
diff --git a/src/mame/video/centiped.c b/src/mame/video/centiped.c
new file mode 100644
index 00000000000..b0489694ff4
--- /dev/null
+++ b/src/mame/video/centiped.c
@@ -0,0 +1,520 @@
+/*************************************************************************
+
+ Atari Centipede hardware
+
+*************************************************************************/
+
+#include "driver.h"
+#include "centiped.h"
+
+
+static tilemap *bg_tilemap;
+UINT8 centiped_flipscreen, *bullsdrt_tiles_bankram;
+static UINT8 bullsdrt_sprites_bank;
+static UINT8 penmask[64];
+
+
+
+/*************************************
+ *
+ * Tilemap callback
+ *
+ *************************************/
+
+static TILE_GET_INFO( centiped_get_tile_info )
+{
+ int data = videoram[tile_index];
+ SET_TILE_INFO(0, (data & 0x3f) + 0x40, 0, TILE_FLIPYX(data >> 6));
+}
+
+
+static TILE_GET_INFO( warlords_get_tile_info )
+{
+ int data = videoram[tile_index];
+ int color = ((tile_index & 0x10) >> 4) | ((tile_index & 0x200) >> 8) | (centiped_flipscreen >> 5);
+ SET_TILE_INFO(0, data & 0x3f, color, TILE_FLIPYX(data >> 6));
+}
+
+
+static TILE_GET_INFO( milliped_get_tile_info )
+{
+ int data = videoram[tile_index];
+ int bank = (data >> 6) & 1;
+ int color = (data >> 6) & 3;
+ /* Flip both x and y if flipscreen is non-zero */
+ int flip_tiles = (centiped_flipscreen) ? 0x03 : 0;
+ SET_TILE_INFO(0, (data & 0x3f) + 0x40 + (bank * 0x80), color, TILE_FLIPYX(flip_tiles));
+}
+
+
+static TILE_GET_INFO( bullsdrt_get_tile_info )
+{
+ int data = videoram[tile_index];
+ int bank = bullsdrt_tiles_bankram[tile_index & 0x1f] & 0x0f;
+ SET_TILE_INFO(0, (data & 0x3f) + 0x40 * bank, 0, TILE_FLIPYX(data >> 6));
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( centiped )
+{
+ bg_tilemap = tilemap_create(centiped_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+
+ centiped_flipscreen = 0;
+
+ state_save_register_global(centiped_flipscreen);
+ state_save_register_global(bullsdrt_sprites_bank);
+}
+
+
+VIDEO_START( warlords )
+{
+ bg_tilemap = tilemap_create(warlords_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+
+ /* we overload centiped_flipscreen here to track the cocktail/upright state */
+ centiped_flipscreen = readinputport(0) & 0x80;
+ tilemap_set_flip(bg_tilemap, centiped_flipscreen ? TILEMAP_FLIPX : 0);
+}
+
+
+VIDEO_START( milliped )
+{
+ bg_tilemap = tilemap_create(milliped_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+
+ centiped_flipscreen = 0;
+ state_save_register_global(centiped_flipscreen);
+}
+
+
+VIDEO_START( bullsdrt )
+{
+ bg_tilemap = tilemap_create(bullsdrt_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+
+ centiped_flipscreen = 0;
+}
+
+
+
+/*************************************
+ *
+ * Video RAM writes
+ *
+ *************************************/
+
+WRITE8_HANDLER( centiped_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+
+/*************************************
+ *
+ * Screen flip
+ *
+ *************************************/
+
+WRITE8_HANDLER( centiped_flip_screen_w )
+{
+ centiped_flipscreen = data >> 7;
+}
+
+
+
+/*************************************
+ *
+ * Tiles bank
+ *
+ *************************************/
+
+WRITE8_HANDLER( bullsdrt_tilesbank_w )
+{
+ bullsdrt_tiles_bankram[offset] = data;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+}
+
+
+
+/*************************************
+ *
+ * Sprites bank
+ *
+ *************************************/
+
+WRITE8_HANDLER( bullsdrt_sprites_bank_w )
+{
+ bullsdrt_sprites_bank = data;
+}
+
+
+
+/*************************************
+ *
+ * Palette init
+ *
+ *************************************/
+
+static void init_penmask(void)
+{
+ int i;
+
+ for (i = 0; i < 64; i++)
+ {
+ UINT8 mask = 1;
+ if (((i >> 0) & 3) == 0) mask |= 2;
+ if (((i >> 2) & 3) == 0) mask |= 4;
+ if (((i >> 4) & 3) == 0) mask |= 8;
+ penmask[i] = mask;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Centipede doesn't have a color PROM. Eight RAM locations control
+ the color of characters and sprites. The meanings of the four bits are
+ (all bits are inverted):
+
+ bit 3 alternate
+ blue
+ green
+ bit 0 red
+
+ The alternate bit affects blue and green, not red. The way I weighted its
+ effect might not be perfectly accurate, but is reasonably close.
+
+***************************************************************************/
+
+#define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+#define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+PALETTE_INIT( centiped )
+{
+ int i;
+
+ /* characters use colors 0-3 */
+ for (i = 0; i < TOTAL_COLORS(0); i++)
+ COLOR(0,i) = i;
+
+ /* Centipede is unusual because the sprite color code specifies the */
+ /* colors to use one by one, instead of a combination code. */
+ /* bit 5-4 = color to use for pen 11 */
+ /* bit 3-2 = color to use for pen 10 */
+ /* bit 1-0 = color to use for pen 01 */
+ /* pen 00 is transparent */
+ for (i = 0; i < TOTAL_COLORS(1); i += 4)
+ {
+ COLOR(1,i+0) = 0;
+ COLOR(1,i+1) = 4 + ((i >> 2) & 3);
+ COLOR(1,i+2) = 4 + ((i >> 4) & 3);
+ COLOR(1,i+3) = 4 + ((i >> 6) & 3);
+ }
+
+ /* create a pen mask for sprite drawing */
+ init_penmask();
+}
+
+
+WRITE8_HANDLER( centiped_paletteram_w )
+{
+ int r, g, b;
+
+ paletteram[offset] = data;
+
+ r = 0xff * ((~data >> 0) & 1);
+ g = 0xff * ((~data >> 1) & 1);
+ b = 0xff * ((~data >> 2) & 1);
+
+ if (~data & 0x08) /* alternate = 1 */
+ {
+ /* when blue component is not 0, decrease it. When blue component is 0, */
+ /* decrease green component. */
+ if (b) b = 0xc0;
+ else if (g) g = 0xc0;
+ }
+
+ /* bit 2 of the output palette RAM is always pulled high, so we ignore */
+ /* any palette changes unless the write is to a palette RAM address */
+ /* that is actually used */
+ if (offset & 4)
+ palette_set_color(Machine, ((offset >> 1) & 4) | (offset & 3), MAKE_RGB(r, g, b));
+}
+
+
+
+/***************************************************************************
+
+ Convert the color PROM into a more useable format.
+
+ The palette PROM are connected to the RGB output this way:
+
+ bit 2 -- RED
+ -- GREEN
+ bit 0 -- BLUE
+
+***************************************************************************/
+
+PALETTE_INIT( warlords )
+{
+ int i, j;
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int r = ((*color_prom >> 2) & 0x01) * 0xff;
+ int g = ((*color_prom >> 1) & 0x01) * 0xff;
+ int b = ((*color_prom >> 0) & 0x01) * 0xff;
+
+ /* Colors 0x40-0x7f are converted to grey scale as it's used on the
+ upright version that had an overlay */
+ if (i >= machine->drv->total_colors / 2)
+ {
+ /* Use the standard ratios: r = 30%, g = 59%, b = 11% */
+ int grey = (r * 0x4d / 0xff) + (g * 0x96 / 0xff) + (b * 0x1c / 0xff);
+ r = g = b = grey;
+ }
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < 4; j++)
+ {
+ COLOR(0,i*4+j) = i*16+j;
+ COLOR(1,i*4+j) = i*16+j*4;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Millipede doesn't have a color PROM, it uses RAM.
+ The RAM seems to be conncted to the video output this way:
+
+ bit 7 red
+ red
+ red
+ green
+ green
+ blue
+ blue
+ bit 0 blue
+
+***************************************************************************/
+
+PALETTE_INIT( milliped )
+{
+ int i;
+
+ /* characters use colors 0-15 */
+ for (i = 0; i < TOTAL_COLORS(0); i++)
+ COLOR(0,i) = i;
+
+ /* Millipede is unusual because the sprite color code specifies the */
+ /* colors to use one by one, instead of a combination code. */
+ /* bit 7-6 = palette bank (there are 4 groups of 4 colors) */
+ /* bit 5-4 = color to use for pen 11 */
+ /* bit 3-2 = color to use for pen 10 */
+ /* bit 1-0 = color to use for pen 01 */
+ /* pen 00 is transparent */
+ for (i = 0; i < TOTAL_COLORS(1); i += 4)
+ {
+ int base = 16 + 4 * ((i >> 8) & 3);
+ COLOR(1,i+0) = 0;
+ COLOR(1,i+1) = base + ((i >> 2) & 3);
+ COLOR(1,i+2) = base + ((i >> 4) & 3);
+ COLOR(1,i+3) = base + ((i >> 6) & 3);
+ }
+
+ /* create a pen mask for sprite drawing */
+ init_penmask();
+}
+
+
+WRITE8_HANDLER( milliped_paletteram_w )
+{
+ int bit0,bit1,bit2;
+ int r,g,b;
+
+ paletteram[offset] = data;
+
+ /* red component */
+ bit0 = (~data >> 5) & 0x01;
+ bit1 = (~data >> 6) & 0x01;
+ bit2 = (~data >> 7) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* green component */
+ bit0 = 0;
+ bit1 = (~data >> 3) & 0x01;
+ bit2 = (~data >> 4) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* blue component */
+ bit0 = (~data >> 0) & 0x01;
+ bit1 = (~data >> 1) & 0x01;
+ bit2 = (~data >> 2) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(Machine, offset, MAKE_RGB(r, g, b));
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( centiped )
+{
+ rectangle spriteclip = *cliprect;
+ int offs;
+
+ /* draw the background */
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* apply the sprite clip */
+ if (centiped_flipscreen)
+ spriteclip.min_x += 8;
+ else
+ spriteclip.max_x -= 8;
+
+ /* draw the sprites */
+ for (offs = 0; offs < 0x10; offs++)
+ {
+ int code = ((spriteram[offs] & 0x3e) >> 1) | ((spriteram[offs] & 0x01) << 6);
+ int color = spriteram[offs + 0x30];
+ int flipx = (spriteram[offs] >> 6) & 1;
+ int flipy = (spriteram[offs] >> 7) & 1;
+ int x = spriteram[offs + 0x20];
+ int y = 240 - spriteram[offs + 0x10];
+
+ drawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy, x, y,
+ &spriteclip, TRANSPARENCY_PENS, penmask[color & 0x3f]);
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( warlords )
+{
+ int upright_mode = input_port_0_r(0) & 0x80;
+ int offs;
+
+ /* if the cocktail/upright switch flipped, force refresh */
+ if (centiped_flipscreen != upright_mode)
+ {
+ centiped_flipscreen = upright_mode;
+ tilemap_set_flip(bg_tilemap, upright_mode ? TILEMAP_FLIPX : 0);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ /* draw the background */
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* draw the sprites */
+ for (offs = 0; offs < 0x10; offs++)
+ {
+ int code = spriteram[offs] & 0x3f;
+ int flipx = (spriteram[offs] >> 6) & 1;
+ int flipy = (spriteram[offs] >> 7) & 1;
+ int x = spriteram[offs + 0x20];
+ int y = 248 - spriteram[offs + 0x10];
+
+ /* The four quadrants have different colors. This is not 100% accurate,
+ because right on the middle the sprite could actually have two or more
+ different color, but this is not noticable, as the color that
+ changes between the quadrants is mostly used on the paddle sprites */
+ int color = ((y & 0x80) >> 6) | ((x & 0x80) >> 7) | (upright_mode >> 5);
+
+ /* in upright mode, sprites are flipped */
+ if (upright_mode)
+ {
+ x = 248 - x;
+ flipx = !flipx;
+ }
+
+ drawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy, x, y,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( bullsdrt )
+{
+ rectangle spriteclip = *cliprect;
+
+ int offs;
+
+ /* draw the background */
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* apply the sprite clip */
+ if (centiped_flipscreen)
+ spriteclip.min_x += 8;
+ else
+ spriteclip.max_x -= 8;
+
+ /* draw the sprites */
+ for (offs = 0; offs < 0x10; offs++)
+ {
+ int code = ((spriteram[offs] & 0x3e) >> 1) | ((spriteram[offs] & 0x01) << 6) | (bullsdrt_sprites_bank * 0x20);
+ int color = spriteram[offs + 0x30];
+ int flipy = (spriteram[offs] >> 7) & 1;
+ int x = spriteram[offs + 0x20];
+ int y = 240 - spriteram[offs + 0x10];
+
+ drawgfx(bitmap, machine->gfx[1], code, color & 0x3f, 1, flipy, x, y,
+ &spriteclip, TRANSPARENCY_PEN, 0);
+ }
+ return 0;
+}
+
+/*
+ * This varies from Centipede, in that flipx is not in
+ * the data, but is determined by VIDROT value at 0x2506.
+ */
+VIDEO_UPDATE( milliped )
+{
+ rectangle spriteclip = *cliprect;
+ int offs;
+
+ /* draw the background */
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* apply the sprite clip */
+ if (centiped_flipscreen)
+ spriteclip.min_x += 8;
+ else
+ spriteclip.max_x -= 8;
+
+ /* draw the sprites */
+ for (offs = 0; offs < 0x10; offs++)
+ {
+ int code = ((spriteram[offs] & 0x3e) >> 1) | ((spriteram[offs] & 0x01) << 6);
+ int color = spriteram[offs + 0x30];
+ int flipx = centiped_flipscreen;
+ int flipy = (spriteram[offs] & 0x80);
+ int x = spriteram[offs + 0x20];
+ int y = 240 - spriteram[offs + 0x10];
+ if (flipx) {
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy, x, y,
+ &spriteclip, TRANSPARENCY_PENS, penmask[color & 0x3f]);
+ }
+ return 0;
+}
+
diff --git a/src/mame/video/chaknpop.c b/src/mame/video/chaknpop.c
new file mode 100644
index 00000000000..482f1854b5c
--- /dev/null
+++ b/src/mame/video/chaknpop.c
@@ -0,0 +1,286 @@
+/*
+ * Chack'n Pop (C) 1983 TAITO Corp.
+ * emulate video hardware
+ */
+
+#include "driver.h"
+
+#define GFX_FLIP_X 0x01
+#define GFX_FLIP_Y 0x02
+#define GFX_VRAM_BANK 0x04
+#define GFX_UNKNOWN1 0x08
+#define GFX_TX_BANK1 0x20
+#define GFX_UNKNOWN2 0x40
+#define GFX_TX_BANK2 0x80
+
+#define TX_COLOR1 0x0b
+#define TX_COLOR2 0x01
+
+UINT8 *chaknpop_txram;
+UINT8 *chaknpop_sprram;
+size_t chaknpop_sprram_size;
+UINT8 *chaknpop_attrram;
+
+static UINT8 *vram1;
+static UINT8 *vram2;
+static UINT8 *vram3;
+static UINT8 *vram4;
+
+static tilemap *tx_tilemap;
+
+static UINT8 gfxmode;
+static UINT8 flip_x, flip_y;
+
+
+/***************************************************************************
+ palette decode
+***************************************************************************/
+
+PALETTE_INIT( chaknpop )
+{
+ int i;
+
+ for (i = 0; i < 1024; i++)
+ {
+ int col, r, g, b;
+ int bit0, bit1, bit2;
+
+ col = (color_prom[i]&0x0f)+((color_prom[i+1024]&0x0f)<<4);
+
+ /* red component */
+ bit0 = (col >> 0) & 0x01;
+ bit1 = (col >> 1) & 0x01;
+ bit2 = (col >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* green component */
+ bit0 = (col >> 3) & 0x01;
+ bit1 = (col >> 4) & 0x01;
+ bit2 = (col >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* blue component */
+ bit0 = 0;
+ bit1 = (col >> 6) & 0x01;
+ bit2 = (col >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ }
+}
+
+/***************************************************************************
+ Memory handlers
+***************************************************************************/
+
+static void set_vram_bank(void)
+{
+ UINT8 *RAM = memory_region(REGION_CPU1);
+ int bankaddress;
+
+ if (gfxmode & GFX_VRAM_BANK)
+ bankaddress = 0x14000;
+ else
+ bankaddress = 0x10000;
+
+ memory_set_bankptr(STATIC_BANK1, &RAM[bankaddress]); /* Select 2 banks of 16k */
+}
+
+
+static void tx_tilemap_mark_all_dirty(void)
+{
+ tilemap_mark_all_tiles_dirty(tx_tilemap);
+ tilemap_set_flip(tx_tilemap, flip_x | flip_y);
+}
+
+READ8_HANDLER( chaknpop_gfxmode_r )
+{
+ return gfxmode;
+}
+
+WRITE8_HANDLER( chaknpop_gfxmode_w )
+{
+ if (gfxmode != data)
+ {
+ int all_dirty = 0;
+
+ gfxmode = data;
+ set_vram_bank();
+
+ if (flip_x != (gfxmode & GFX_FLIP_X))
+ {
+ flip_x = gfxmode & GFX_FLIP_X;
+ all_dirty = 1;
+ }
+
+ if (flip_y != (gfxmode & GFX_FLIP_Y))
+ {
+ flip_y = gfxmode & GFX_FLIP_Y;
+ all_dirty = 1;
+ }
+
+ if (all_dirty)
+ tx_tilemap_mark_all_dirty();
+ }
+}
+
+WRITE8_HANDLER( chaknpop_txram_w )
+{
+ chaknpop_txram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap, offset);
+}
+
+WRITE8_HANDLER( chaknpop_attrram_w )
+{
+ if (chaknpop_attrram[offset] != data)
+ {
+ chaknpop_attrram[offset] = data;
+
+ if (offset == TX_COLOR1 || offset == TX_COLOR2)
+ tx_tilemap_mark_all_dirty();
+ }
+}
+
+
+/***************************************************************************
+ Callback for the tilemap code
+***************************************************************************/
+
+/*
+ * I'm not sure how to handle attributes about color
+ */
+
+static TILE_GET_INFO( chaknpop_get_tx_tile_info )
+{
+ int tile = chaknpop_txram[tile_index];
+ int tile_h_bank = (gfxmode & GFX_TX_BANK2) << 2; /* 0x00-0xff -> 0x200-0x2ff */
+ int color = chaknpop_attrram[TX_COLOR2];
+
+ if (tile == 0x74)
+ color = chaknpop_attrram[TX_COLOR1];
+
+ if (gfxmode & GFX_TX_BANK1 && tile >= 0xc0)
+ tile += 0xc0; /* 0xc0-0xff -> 0x180-0x1bf */
+ tile |= tile_h_bank;
+
+ SET_TILE_INFO(1, tile, color, 0);
+}
+
+
+/***************************************************************************
+ Initialize video hardware emulation
+***************************************************************************/
+
+VIDEO_START( chaknpop )
+{
+ UINT8 *RAM = memory_region(REGION_CPU1);
+
+ /* info offset type w h col row */
+ tx_tilemap = tilemap_create(chaknpop_get_tx_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ vram1 = &RAM[0x10000];
+ vram2 = &RAM[0x12000];
+ vram3 = &RAM[0x14000];
+ vram4 = &RAM[0x16000];
+
+ set_vram_bank();
+ tx_tilemap_mark_all_dirty();
+
+ state_save_register_global(gfxmode);
+ state_save_register_global_pointer(vram1, 0x2000);
+ state_save_register_global_pointer(vram2, 0x2000);
+ state_save_register_global_pointer(vram3, 0x2000);
+ state_save_register_global_pointer(vram4, 0x2000);
+ state_save_register_global(flip_x);
+ state_save_register_global(flip_y);
+
+ state_save_register_func_postload(set_vram_bank);
+ state_save_register_func_postload(tx_tilemap_mark_all_dirty);
+}
+
+
+/***************************************************************************
+ Screen refresh
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ /* Draw the sprites */
+ for (offs = 0; offs < chaknpop_sprram_size; offs += 4)
+ {
+ int sx = chaknpop_sprram[offs + 3];
+ int sy = 256 - 15 - chaknpop_sprram[offs];
+ int flipx = chaknpop_sprram[offs+1] & 0x40;
+ int flipy = chaknpop_sprram[offs+1] & 0x80;
+ int color = (chaknpop_sprram[offs + 2] & 7);
+ int tile = (chaknpop_sprram[offs + 1] & 0x3f) | ((chaknpop_sprram[offs + 2] & 0x38) << 3);
+
+ if (flip_x)
+ {
+ sx = 240 - sx;
+ flipx = !flipx;
+ }
+ if (flip_y)
+ {
+ sy = 242 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ tile,
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+}
+
+static void draw_bitmap(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int dx = flip_x ? -1 : 1;
+ int offs, i;
+
+ for (offs = 0; offs < 0x2000; offs++)
+ {
+ int x = ((offs & 0x1f) << 3) + 7;
+ int y = offs >> 5;
+
+ if (!flip_x)
+ x = 255 - x;
+
+ if (!flip_y)
+ y = 255 - y;
+
+ for (i = 0x80; i > 0; i >>= 1, x += dx)
+ {
+ pen_t color = 0;
+
+ if (vram1[offs] & i)
+ color |= 0x200; // green lower cage
+ if (vram2[offs] & i)
+ color |= 0x080;
+ if (vram3[offs] & i)
+ color |= 0x100; // green upper cage
+ if (vram4[offs] & i)
+ color |= 0x040; // tx mask
+
+ if (color)
+ {
+ pen_t pen = *BITMAP_ADDR16(bitmap, y, x);
+ pen |= color;
+ *BITMAP_ADDR16(bitmap, y, x) = pen;
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( chaknpop )
+{
+ tilemap_draw(bitmap, cliprect, tx_tilemap, 0, 0);
+ draw_sprites(machine,bitmap,cliprect);
+ draw_bitmap(bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/champbas.c b/src/mame/video/champbas.c
new file mode 100644
index 00000000000..62e865876b8
--- /dev/null
+++ b/src/mame/video/champbas.c
@@ -0,0 +1,151 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static int gfxbank;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Pac Man has a 16 bytes palette PROM and a 128 bytes color lookup table PROM.
+
+ Pengo has a 32 bytes palette PROM and a 256 bytes color lookup table PROM
+ (actually that's 512 bytes, but the high address bit is grounded).
+
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( champbas )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* TODO: there are 32 colors in the palette, but we are suing only 16 */
+ /* the only difference between the two banks is color #14, grey instead of green */
+
+ /* character lookup table */
+ /* sprites use the same color lookup table as characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = (*(color_prom++) & 0x0f);
+}
+
+WRITE8_HANDLER( champbas_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( champbas_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( champbas_gfxbank_w )
+{
+ if (gfxbank != (data & 0x01))
+ {
+ gfxbank = data & 0x01;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( champbas_flipscreen_w )
+{
+ if (flip_screen != data)
+ {
+ flip_screen_set(data);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index];
+ int color = (colorram[tile_index] & 0x1f) + 32;
+
+ SET_TILE_INFO(gfxbank, code, color, 0);
+}
+
+VIDEO_START( champbas )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 2; offs >= 0; offs -= 2)
+ {
+ int code = spriteram[offs] >> 2;
+ int color = spriteram[offs + 1];
+ int flipx = spriteram[offs] & 0x01;
+ int flipy = spriteram[offs] & 0x02;
+ int sx = ((256 + 16 - spriteram_2[offs + 1]) & 0xff) - 16;
+ int sy = spriteram_2[offs] - 16;
+
+ drawgfx(bitmap,
+ machine->gfx[2 + gfxbank],
+ code, color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_COLOR, 0);
+ }
+}
+
+VIDEO_UPDATE( champbas )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/changela.c b/src/mame/video/changela.c
new file mode 100644
index 00000000000..aee25ff082b
--- /dev/null
+++ b/src/mame/video/changela.c
@@ -0,0 +1,836 @@
+/**************************************************************************
+Change Lanes - Video Hardware
+(C) Taito 1983
+
+Jarek Burczynski
+Phil Stroffolino
+Tomasz Slanina
+Adam Bousley
+
+Todo: Priority between tree0 and tree1.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+extern UINT8 changela_tree0_col;
+extern UINT8 changela_tree1_col;
+extern UINT8 changela_left_bank_col;
+extern UINT8 changela_right_bank_col;
+extern UINT8 changela_boat_shore_col;
+extern UINT8 changela_collision_reset;
+extern UINT8 changela_tree_collision_reset;
+
+
+static UINT32 slopeROM_bank;
+static UINT8 tree_en;
+static UINT8 horizon;
+
+static UINT8* memory_devices;
+static UINT8* tree_ram;
+static UINT32 mem_dev_selected; /* an offset within memory_devices area */
+
+static mame_bitmap *obj0_bitmap, *river_bitmap, *tree0_bitmap, *tree1_bitmap;
+
+static emu_timer* changela_scanline_timer;
+static TIMER_CALLBACK( changela_scanline_callback );
+
+VIDEO_START( changela )
+{
+ memory_devices = auto_malloc(4 * 0x800); /* 0 - not connected, 1,2,3 - RAMs*/
+ tree_ram = auto_malloc(2 * 0x20);
+
+ obj0_bitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ river_bitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ tree0_bitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ tree1_bitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ changela_scanline_timer = timer_alloc(changela_scanline_callback);
+ timer_adjust(changela_scanline_timer, video_screen_get_time_until_pos(0, 30, 0), 30, attotime_zero);
+
+ state_save_register_global(slopeROM_bank);
+ state_save_register_global(tree_en);
+ state_save_register_global(horizon);
+ state_save_register_global(mem_dev_selected);
+
+ state_save_register_global_pointer(memory_devices, 4*0x800);
+ state_save_register_global_pointer(tree_ram, 2*0x20);
+}
+
+/**************************************************************************
+
+ Obj 0 - Sprite Layer
+
+***************************************************************************/
+static void draw_obj0(mame_bitmap *bitmap, int sy)
+{
+ int sx, i;
+
+ UINT8* ROM = memory_region(REGION_USER1);
+ UINT8* RAM = spriteram;
+
+ for(sx = 0; sx < 256; sx++)
+ {
+ int vr = (RAM[sx*4 + 0] & 0x80) >> 7;
+ int hr = (RAM[sx*4 + 0] & 0x40) >> 6;
+ int hs = (RAM[sx*4 + 0] & 0x20) >> 5;
+ UINT32 vsize = RAM[sx*4 + 0] & 0x1f;
+ UINT8 ypos = ~RAM[sx*4 + 1];
+ UINT8 tile = RAM[sx*4 + 2];
+ UINT8 xpos = RAM[sx*4 + 3];
+
+ if(sy - ypos <= vsize)
+ {
+ for(i = 0; i < 16; i++)
+ {
+ UINT32 A7, A8, rom_addr;
+ UINT8 counter, data;
+ UINT8 sum = sy - ypos;
+
+ counter = i;
+ if(hr) counter ^= 0x0f;
+
+ A8 = ((tile & 0x02) >> 1) ^ ((hr & hs) ^ hs);
+ A7 = ( (((vr ^ ((sum & 0x10) >> 4)) & ((vsize & 0x10) >> 4)) ^ 0x01) & (tile & 0x01) ) ^ 0x01;
+ rom_addr = (counter >> 1) | ((sum & 0x0f) << 3) | (A7 << 7) | (A8 << 8) | ((tile >> 2) << 9);
+ if(vr) rom_addr ^= (0x0f << 3);
+
+ if(counter & 1)
+ data = ROM[rom_addr] & 0x0f;
+ else
+ data = (ROM[rom_addr] & 0xf0) >> 4;
+
+ if((data != 0x0f) && (data != 0))
+ *BITMAP_ADDR16(bitmap, sy, xpos+i) = Machine->pens[data | 0x10];
+
+ if(hs)
+ {
+ if(counter & 1)
+ data = ROM[rom_addr ^ 0x100] & 0x0f;
+ else
+ data = (ROM[rom_addr ^ 0x100] & 0xf0) >> 4;
+
+ if((data != 0x0f) && (data != 0))
+ *BITMAP_ADDR16(bitmap, sy, xpos+i+16) = Machine->pens[data | 0x10];
+ }
+ }
+ }
+ }
+}
+
+/**************************************************************************
+
+ Obj 1 - Text Layer
+
+***************************************************************************/
+static void draw_obj1(running_machine *machine, mame_bitmap *bitmap)
+{
+ int sx, sy;
+
+ UINT8* ROM = memory_region(REGION_GFX2);
+ UINT8* RAM = videoram;
+
+ UINT8 reg[4] = { 0 }; /* 4x4-bit registers (U58, U59) */
+
+ UINT8 tile;
+ UINT8 attrib = 0;
+
+ for(sy = 0; sy < 256; sy++)
+ {
+ for(sx = 0; sx < 256; sx++)
+ {
+ int c0, c1, col, sum;
+
+ /* 11 Bits: H1, H3, H4, H5, H6, H7, V3, V4, V5, V6, V7 */
+ int ram_addr = ((sx & 0xf8) >> 2) | ((sy & 0xf8) << 3);
+ int tile_addr = RAM[ram_addr];
+
+ if(!(RAM[ram_addr+1] & 0x10) && (sx & 0x04)) /* D4=0 enables latch at U32 */
+ attrib = RAM[ram_addr+1];
+
+ tile = ROM[(tile_addr << 4) | ((sx & 0x04) >> 2) | ((sy & 0x07) << 1)];
+ reg[(sx & 0x0c) >> 2] = tile;
+ sum = (sx & 0x0f) + (attrib & 0x0f); /* 4-bit adder (U45) */
+
+ /* Multiplexors (U57) */
+ if((sum & 0x03) == 0)
+ {
+ c0 = (reg[(sum & 0x0c) >> 2] & 0x08) >> 3;
+ c1 = (reg[(sum & 0x0c) >> 2] & 0x80) >> 7;
+ }
+ else if((sum & 0x03) == 1)
+ {
+ c0 = (reg[(sum & 0x0c) >> 2] & 0x04) >> 2;
+ c1 = (reg[(sum & 0x0c) >> 2] & 0x40) >> 6;
+ }
+ else if((sum & 0x03) == 2)
+ {
+ c0 = (reg[(sum & 0x0c) >> 2] & 0x02) >> 1;
+ c1 = (reg[(sum & 0x0c) >> 2] & 0x20) >> 5;
+ }
+ else
+ {
+ c0 = (reg[(sum & 0x0c) >> 2] & 0x01) >> 0;
+ c1 = (reg[(sum & 0x0c) >> 2] & 0x10) >> 4;
+ }
+
+ col = c0 | (c1 << 1) | ((attrib & 0xc0) >> 4);
+ if((col & 0x07) != 0x07)
+ *BITMAP_ADDR16(bitmap, sy, sx) = machine->pens[col | 0x20];
+ }
+ }
+}
+
+/**************************************************************************
+
+ River Video Generator
+
+***************************************************************************/
+static void draw_river(mame_bitmap *bitmap, int sy)
+{
+ int sx, i, j;
+
+ UINT8* ROM = memory_region(REGION_USER2);
+ UINT8* RAM = memory_devices + 0x800;
+ UINT8* TILE_ROM = memory_region(REGION_GFX1);
+ UINT8* TILE_RAM = memory_devices + 0x1000;
+ UINT8* PROM = memory_region(REGION_PROMS);
+
+ static UINT8 v_count = 0;
+
+ int preload = ((sy < 32) ? 1 : 0);
+
+ UINT8 math_train[10] = { 0 };
+ UINT8 pre_train[3] = { 0 };
+
+ UINT8 state = 0;
+ UINT8 prev_state = 0;
+
+ UINT8 ram_count = 0;
+ UINT8 rom_count = 0;
+
+ int hosc = 0;
+ int carry = 0;
+
+ /* Update Counters */
+ if(sy == 30) v_count = horizon;
+ v_count = (v_count+1) & 0xff;
+
+ /* ----- STATE MACHINE ----- */
+ for(i = 0; i < 0x20; i++)
+ {
+ int rom_addr, ram_addr, ram_a5;
+ int mux45, mux61;
+
+ state = PROM[i];
+
+ /* Update Counters */
+ if(prev_state & 0x80)
+ ram_count = (ram_count+1) & 0x0f;
+ if((state & 0x40) && !(prev_state & 0x40))
+ rom_count = (rom_count+1) & 0x0f;
+
+ if(prev_state & 0x02)
+ carry = (((pre_train[1] + pre_train[2] + carry) > 0x0f) ? 1 : 0);
+ if(!(state & 0x08))
+ carry = 0;
+
+ if(prev_state & 0x10)
+ hosc = (math_train[8] << 4) | math_train[9];
+
+ rom_addr = slopeROM_bank | ((v_count & 0x7e) << 2) | ((rom_count & 0x0e) >> 1);
+ ram_a5 = ((state & 0x01) & ((state & 0x40) >> 6) & preload) ^ 0x01;
+ ram_addr = (ram_a5 << 5) | (ram_count << 1) | ((state & 0x20) >> 5);
+ mux45 = rom_count & 0x01;
+ mux61 = v_count & 0x01;
+
+ switch(state)
+ {
+ case 0x01:
+ case 0x09:
+ case 0x19:
+ case 0x0d:
+ case 0x8d:
+ pre_train[0] = ( mux45 ? ((ROM[rom_addr] & 0xf0) >> 4) : (ROM[rom_addr] & 0x0f) );
+ break;
+ case 0x0f:
+ case 0x2f:
+ math_train[0] = RAM[ram_addr] = ( mux45 ? ((ROM[rom_addr] & 0xf0) >> 4) : (ROM[rom_addr] & 0x0f) );
+ break;
+ case 0x4d:
+ case 0x69:
+ case 0x6d:
+ case 0xc5:
+ case 0xcd:
+ pre_train[0] = RAM[ram_addr] & 0x0f;
+ break;
+ case 0xea:
+ case 0xee:
+ math_train[0] = RAM[ram_addr] = ( mux61 ? (pre_train[1]) : ((pre_train[1] + pre_train[2] + carry) & 0x0f) );
+ break;
+ default:
+ break;
+ }
+
+ /* Shift each item down the train */
+ if(state & 0x02)
+ {
+ for(j = 9; j > 0; j--)
+ {
+ math_train[j] = math_train[j-1];
+ }
+ }
+ else
+ {
+ pre_train[2] = pre_train[1];
+ pre_train[1] = pre_train[0];
+ }
+
+ prev_state = state;
+ }
+
+ if(!(v_count & 0x80))
+ {
+ int h_count = 0x80 | (hosc >> 1);
+ int tile_v = ((math_train[3] & 0x0c) >> 2) | ((math_train[2] & 0x0f) << 2) | ((math_train[1] & 0x07) << 6);
+ int tile_h = (math_train[7] & 0x0f) | ((math_train[6] & 0x0f) << 4) | ((math_train[5] & 0x01) << 8);
+
+ /* Burst of 16 10Mhz Clocks */
+ for(sx = 0; sx < 16; sx++)
+ {
+ int ram_addr, rom_addr;
+ int col;
+
+ for(i = 0; i < 2; i++)
+ {
+ if(h_count > 0xff)
+ {
+ h_count = ((math_train[9] & 0x0f) >> 1) | ((math_train[8] & 0x0f) << 3) | 0x80;
+ tile_h = (tile_h+1) & 0xfff;
+
+ /* Skip one count if LSB is high */
+ if(((math_train[9] & 0x01) && (tile_h & 0x01)))
+ h_count--;
+ }
+ else
+ h_count++;
+ }
+
+ ram_addr = ((tile_h & 0x1f8) >> 3) | ((tile_v & 0x1f0) << 2);
+ rom_addr = ((tile_h & 0x06) >> 1) | ((tile_v & 0x0f) << 2) | ((TILE_RAM[ram_addr] & 0x7f) << 6);
+
+ if(tile_h & 0x01)
+ col = TILE_ROM[rom_addr] & 0x0f;
+ else
+ col = (TILE_ROM[rom_addr] & 0xf0) >> 4;
+
+ *BITMAP_ADDR16(bitmap, sy, sx) = Machine->pens[col];
+ }
+
+ for(sx = 16; sx < 256; sx++)
+ {
+ int ram_addr, rom_addr;
+ int col;
+
+ for(i = 0; i < 4; i++)
+ {
+ if(h_count > 0xff)
+ {
+ h_count = ((math_train[9] & 0x0f) >> 1) | ((math_train[8] & 0x0f) << 3) | 0x80;
+ tile_h = (tile_h+1) & 0xfff;
+
+ /* Skip one count if LSB is high */
+ if(((math_train[9] & 0x01) && (tile_h & 0x01)))
+ h_count--;
+ }
+ else
+ h_count++;
+ }
+
+ ram_addr = ((tile_h & 0x1f8) >> 3) | ((tile_v & 0x1f0) << 2);
+ rom_addr = ((tile_h & 0x06) >> 1) | ((tile_v & 0x0f) << 2) | ((TILE_RAM[ram_addr] & 0x7f) << 6);
+
+ if(tile_h & 0x01)
+ col = TILE_ROM[rom_addr] & 0x0f;
+ else
+ col = (TILE_ROM[rom_addr] & 0xf0) >> 4;
+
+ *BITMAP_ADDR16(bitmap, sy, sx) = Machine->pens[col];
+ }
+ }
+}
+
+/**************************************************************************
+
+ Tree Generators
+
+***************************************************************************/
+static void draw_tree(mame_bitmap *bitmap, int sy, int tree_num)
+{
+ int sx, i, j;
+
+ /* State machine */
+ UINT8* ROM = memory_region(REGION_USER2);
+ UINT8* RAM = memory_devices + 0x840 + 0x40*tree_num;
+ UINT8* PROM = memory_region(REGION_PROMS);
+
+ /* Tree Data */
+ UINT8* RAM2 = tree_ram + 0x20*tree_num;
+ UINT8* TILE_ROM = ( tree_num ? (memory_region(REGION_USER3) + 0x1000) : (memory_region(REGION_GFX1) + 0x2000) );
+ UINT8* TILE_RAM = ( tree_num ? (memory_region(REGION_USER3)) : (memory_devices + 0x1800) );
+
+ static UINT8 v_count = 0;
+ static int tree_on[2] = { 0 };
+
+ int preload = ((sy < 32) ? 1 : 0);
+
+ UINT8 math_train[10] = { 0 };
+ UINT8 pre_train[3] = { 0 };
+ UINT8 tree_train[3] = { 0 };
+
+ UINT8 state = 0;
+ UINT8 prev_state = 0;
+
+ UINT8 ram_count = 0;
+ UINT8 rom_count = 0;
+
+ int hosc = 0;
+ int carry = 0;
+ int tree_carry = 0;
+
+ int h_count, tile_v, tile_h;
+ int all_ff;
+
+ /* Update Counters */
+ if(sy == 30)
+ {
+ tree_on[tree_num] = 0;
+ if(tree_num == 0)
+ v_count = horizon;
+ }
+ if(tree_num == 0)
+ v_count = (v_count+1) & 0xff;
+
+ /* ----- STATE MACHINE ----- */
+ for(i = 0; i < 0x20; i++)
+ {
+ int rom_addr, ram_addr, ram_a5, ram2_addr;
+ int mux45, mux61;
+
+ state = PROM[i];
+
+ /* Update Counters */
+ if(prev_state & 0x80)
+ ram_count = (ram_count+1) & 0x0f;
+ if((state & 0x40) && !(prev_state & 0x40))
+ rom_count = (rom_count+1) & 0x0f;
+
+ if(prev_state & 0x02)
+ {
+ carry = (((pre_train[1] + pre_train[2] + carry) > 0x0f) ? 1 : 0);
+ tree_carry = (((tree_train[1] + tree_train[2] + tree_carry) > 0x0f) ? 1 : 0);
+ }
+ if(!(state & 0x08))
+ carry = tree_carry = 0;
+
+ if(prev_state & 0x10)
+ hosc = (math_train[8] << 4) | math_train[9];
+
+ rom_addr = slopeROM_bank | ((v_count & 0x7e) << 2) | ((rom_count & 0x0e) >> 1);
+ ram_a5 = ((state & 0x01) & ((state & 0x40) >> 6) & preload) ^ 0x01;
+ ram_addr = (ram_a5 << 5) | (ram_count << 1) | ((state & 0x20) >> 5);
+ ram2_addr = (ram_count << 1) | ((state & 0x20) >> 5);
+ mux45 = rom_count & 0x01;
+ mux61 = v_count & 0x01;
+
+ switch(state)
+ {
+ case 0x01: case 0x09: case 0x19: case 0x0d: case 0x8d:
+ pre_train[0] = ( mux45 ? ((ROM[rom_addr] & 0xf0) >> 4) : (ROM[rom_addr] & 0x0f) );
+ break;
+ case 0x0f: case 0x2f:
+ RAM[ram_addr] = ( mux45 ? ((ROM[rom_addr] & 0xf0) >> 4) : (ROM[rom_addr] & 0x0f) );
+ break;
+ case 0x4d: case 0x69: case 0x6d: case 0xc5: case 0xcd:
+ pre_train[0] = RAM[ram_addr] & 0x0f;
+ break;
+ case 0xea: case 0xee:
+ RAM[ram_addr] = ( mux61 ? (pre_train[1]) : ((pre_train[1] + pre_train[2] + carry) & 0x0f) );
+ break;
+ default:
+ break;
+ }
+
+ if(!tree_on[tree_num])
+ {
+ int mux82 = (v_count & 0x01) ^ 0x01;
+
+ switch(state)
+ {
+ case 0x01: case 0x09: case 0x19: case 0x0d: case 0x8d:
+ tree_train[0] = RAM2[ram2_addr] = pre_train[0];
+ break;
+ case 0x0f: case 0x2f:
+ math_train[0] = RAM2[ram2_addr] = RAM[ram_addr] & 0x0f;
+ break;
+ case 0x4d: case 0x69: case 0x6d: case 0xc5: case 0xcd:
+ tree_train[0] = RAM2[ram2_addr] = pre_train[0];
+ break;
+ case 0xea: case 0xee:
+ math_train[0] = RAM2[ram2_addr] = ( mux82 ? ((tree_train[1] + tree_train[2] + tree_carry) & 0x0f) : (tree_train[1]) );
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ int mux82 = ((state & 0x04) ? 0 : 1);
+
+ switch(state)
+ {
+ case 0x01: case 0x09: case 0x19: case 0x0d: case 0x8d:
+ tree_train[0] = RAM2[ram2_addr];
+ break;
+ case 0x0f: case 0x2f:
+ math_train[0] = RAM2[ram2_addr];
+ break;
+ case 0x4d: case 0x69: case 0x6d: case 0xc5: case 0xcd:
+ tree_train[0] = RAM2[ram2_addr];
+ break;
+ case 0xea: case 0xee:
+ math_train[0] = RAM2[ram2_addr] = ( mux82 ? ((tree_train[1] + tree_train[2] + tree_carry) & 0x0f) : (tree_train[1]) );
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Shift each item down the train */
+ if(state & 0x02)
+ {
+ for(j = 9; j > 0; j--)
+ math_train[j] = math_train[j-1];
+ }
+ else
+ {
+ pre_train[2] = pre_train[1];
+ pre_train[1] = pre_train[0];
+ tree_train[2] = tree_train[1];
+ tree_train[1] = tree_train[0];
+ }
+
+ prev_state = state;
+ }
+
+ h_count = 0x80 | (hosc >> 1);
+ tile_v = ((math_train[3] & 0x0c) >> 2) | ((math_train[2] & 0x0f) << 2) | ((math_train[1] & 0x07) << 6);
+ tile_h = (math_train[7] & 0x0f) | ((math_train[6] & 0x0f) << 4) | ((math_train[5] & 0x01) << 8);
+ all_ff = 1;
+
+ /* Burst of 16 10Mhz clocks */
+ for(sx = 0; sx < 16; sx++)
+ {
+ int ram_addr, rom_addr, col;
+
+ for(i = 0; i < 2; i++)
+ {
+ if(h_count > 0xff)
+ {
+ h_count = ((math_train[9] & 0x0f) >> 1) | ((math_train[8] & 0x0f) << 3) | 0x80;
+ tile_h = (tile_h+1) & 0xfff;
+
+ /* Skip one count if LSB is high */
+ if(((math_train[9] & 0x01) && (tile_h & 0x01)))
+ h_count--;
+ }
+ else
+ h_count++;
+ }
+
+ ram_addr = ((tile_h & 0x1f8) >> 3) | ((tile_v & 0x1f0) << 2);
+ rom_addr = ((tile_h & 0x06) >> 1) | ((tile_v & 0x0f) << 2) | ((TILE_RAM[ram_addr] & 0x7f) << 6);
+
+ if(!(v_count & 0x80) && (tree_en & (0x01 << tree_num)) && ((TILE_ROM[rom_addr] & 0xf0) == 0))
+ tree_on[tree_num] = 1;
+
+ if(tree_on[tree_num])
+ {
+ if(tile_h & 0x01)
+ col = TILE_ROM[rom_addr] & 0x0f;
+ else
+ col = (TILE_ROM[rom_addr] & 0xf0) >> 4;
+
+ if(col != 0x0f)
+ all_ff = 0;
+
+ if(col != 0x0f && col != 0x00)
+ *BITMAP_ADDR16(bitmap, sy, sx) = Machine->pens[col | 0x30];
+ }
+ }
+
+ for(sx = 16; sx < 256; sx++)
+ {
+ int ram_addr, rom_addr, col;
+
+ for(i = 0; i < 4; i++)
+ {
+ if(h_count > 0xff)
+ {
+ h_count = ((math_train[9] & 0x0f) >> 1) | ((math_train[8] & 0x0f) << 3) | 0x80;
+ tile_h = (tile_h+1) & 0xfff;
+
+ /* Skip one count if LSB is high */
+ if(((math_train[9] & 0x01) && (tile_h & 0x01)))
+ h_count--;
+ }
+ else
+ h_count++;
+ }
+
+ ram_addr = ((tile_h & 0x1f8) >> 3) | ((tile_v & 0x1f0) << 2);
+ rom_addr = ((tile_h & 0x06) >> 1) | ((tile_v & 0x0f) << 2) | ((TILE_RAM[ram_addr] & 0x7f) << 6);
+
+ if(!(v_count & 0x80) && (tree_en & (0x01 << tree_num)) && ((TILE_ROM[rom_addr] & 0xf0) == 0))
+ tree_on[tree_num] = 1;
+
+ if(tree_on[tree_num])
+ {
+ if(tile_h & 0x01)
+ col = TILE_ROM[rom_addr] & 0x0f;
+ else
+ col = (TILE_ROM[rom_addr] & 0xf0) >> 4;
+
+ if(col != 0x0f)
+ all_ff = 0;
+
+ if(col != 0x0f && col != 0x00)
+ *BITMAP_ADDR16(bitmap, sy, sx) = Machine->pens[col | 0x30];
+ }
+ }
+
+ /* Tree on only stays high if a pixel that is not 0xf is encountered,
+ because any non 0xf pixel sets U56 high */
+ if(all_ff) tree_on[tree_num] = 0;
+}
+
+/*
+--+-------------------+-----------------------------------------------------+-----------------------------------------------------------------
+St| PROM contents: | Main signals: | DESCRIPTION
+at+-------------------+-----------------------------------------------------+-----------------------------------------------------------------
+e:|7 6 5 4 3 2 1 0 Hex|/RAMw /RAMr /ROM /AdderOutput AdderInput TrainInputs|
+ | | enable GateU61Enable Enable Enable |
+--+-------------------+-----------------------------------------------------+-----------------------------------------------------------------
+00|0 0 0 0 1 1 0 1 0d | 1 1 0 1 0 1 | (noop ROM 00-lsb to adder)
+01|0 0 0 0 1 1 1 1 0f | 0 1 0 1 1 0 | ROM 00-lsb to train, and to RAM 00
+02|0 1 0 0 1 1 0 1 4d | 1 0 1 1 0 1 | (noop RAM 00 to adder)
+03|0 0 1 0 1 1 1 1 2f | 0 1 0 1 1 0 | ROM 00-msb to train, and to RAM 01
+04|1 1 0 0 1 1 0 1 cd | 1 0 1 1 0 1 | (noop RAM 00 to adder)
+05|0 0 0 0 1 1 1 1 0f | 0 1 0 1 1 0 | ROM 01-lsb to train, and to RAM 02
+06|0 1 0 0 1 1 0 1 4d | 1 0 1 1 0 1 | (noop RAM 02 to adder)
+07|0 0 1 0 1 1 1 1 2f | 0 1 0 1 1 0 | ROM 01-msb to train, and to RAM 03
+08|1 1 0 0 0 1 0 1 c5 | 1 0 1 1 0 1 | CLR carry
+09|0 0 0 0 1 1 0 1 0d | 1 1 0 1 0 1 | ROM 02-lsb to adder
+0a|0 1 1 0 1 1 0 1 6d | 1 0 1 1 0 1 | RAM 05 to adder
+0b|1 1 1 0 1 1 1 0 ee | 0 1 1 0 1 0 | Adder to train, and to RAM 05, CLOCK carry
+0c|0 0 0 0 1 1 0 1 0d | 1 1 0 1 0 1 | ROM 02-msb to adder
+0d|0 1 1 0 1 1 0 1 6d | 1 0 1 1 0 1 | RAM 07 to adder
+0e|1 1 1 0 1 1 1 0 ee | 0 1 1 0 1 0 | Adder to train, and to RAM 07, CLOCK carry
+0f|0 0 0 0 1 1 0 1 0d | 1 1 0 1 0 1 | ROM 03-lsb to adder
+10|0 1 1 0 1 1 0 1 6d | 1 0 1 1 0 1 | RAM 09 to adder
+11|1 1 1 0 1 1 1 0 ee | 0 1 1 0 1 0 | Adder to train, and to RAM 09, CLOCK carry
+12|1 0 0 0 1 1 0 1 8d | 1 1 0 1 0 1 | (noop ROM 03-msb to adder)
+13|0 1 0 0 1 1 0 1 4d | 1 0 1 1 0 1 | (noop RAM 0c to adder)
+14|0 0 0 0 0 0 0 1 01 | 1 1 0 1 0 1 | ROM 04-lsb to adder, CLR carry
+15|0 1 1 0 1 0 0 1 69 | 1 0 1 1 0 1 | RAM 0d to adder
+16|1 1 1 0 1 0 1 0 ea | 0 1 1 0 1 0 | Adder to train and to RAM 0d, CLOCK carry
+17|0 0 0 0 1 0 0 1 09 | 1 1 0 1 0 1 | ROM 04-msb to adder
+18|0 1 1 0 1 0 0 1 69 | 1 0 1 1 0 1 | RAM 0f to adder
+19|1 1 1 0 1 0 1 0 ea | 0 1 1 0 1 0 | Adder to train and to RAM 0f, CLOCK carry
+1a|0 0 0 1 1 0 0 1 19 | 1 1 0 1 0 1 | ROM 05-lsb to adder, /LD HOSC
+1b|0 1 1 0 1 0 0 1 69 | 1 0 1 1 0 1 | RAM 11 to adder
+1c|1 1 1 0 1 0 1 0 ea | 0 1 1 0 1 0 | Adder to train and to RAM 11, CLOCK carry
+1d|0 0 0 0 1 0 0 1 09 | 1 1 0 1 0 1 | ROM 05-msb to adder
+1e|0 1 1 0 1 0 0 1 69 | 1 0 1 1 0 1 | RAM 13 to adder
+1f|1 1 1 0 1 0 1 0 ea | 0 1 1 0 1 0 | Adder to train and to RAM 13, CLOCK carry
+ * ========================= ====================
+ * only one of these signals these signals select
+ * can be active at a time the output for the result
+ * ------- SOURCE -------- ----- TARGET -----
+ *
+ ******************
+ result needs to be
+ written back to RAM
+*/
+
+static TIMER_CALLBACK( changela_scanline_callback )
+{
+ int sy = param;
+ int sx;
+
+ /* clear the current scanline first */
+ rectangle rect = { 0, 255, sy, sy };
+ fillbitmap(river_bitmap, 0x00, &rect);
+ fillbitmap(obj0_bitmap, 0x00, &rect);
+ fillbitmap(tree0_bitmap, 0x00, &rect);
+ fillbitmap(tree1_bitmap, 0x00, &rect);
+
+ draw_river(river_bitmap, sy);
+ draw_obj0(obj0_bitmap, sy);
+ draw_tree(tree0_bitmap, sy, 0);
+ draw_tree(tree1_bitmap, sy, 1);
+
+ /* Collision Detection */
+ for(sx = 1; sx < 256; sx++)
+ {
+ int riv_col, prev_col;
+
+ if((*BITMAP_ADDR16(river_bitmap, sy, sx) == machine->pens[0x08])
+ || (*BITMAP_ADDR16(river_bitmap, sy, sx) == machine->pens[0x09])
+ || (*BITMAP_ADDR16(river_bitmap, sy, sx) == machine->pens[0x0a]))
+ riv_col = 1;
+ else
+ riv_col = 0;
+
+ if((*BITMAP_ADDR16(river_bitmap, sy, sx-1) == machine->pens[0x08])
+ || (*BITMAP_ADDR16(river_bitmap, sy, sx-1) == machine->pens[0x09])
+ || (*BITMAP_ADDR16(river_bitmap, sy, sx-1) == machine->pens[0x0a]))
+ prev_col = 1;
+ else
+ prev_col = 0;
+
+ if(*BITMAP_ADDR16(obj0_bitmap, sy, sx) == machine->pens[0x14]) /* Car Outline Color */
+ {
+ /* Tree 0 Collision */
+ if(*BITMAP_ADDR16(tree0_bitmap, sy, sx) != 0)
+ changela_tree0_col = 1;
+
+ /* Tree 1 Collision */
+ if(*BITMAP_ADDR16(tree1_bitmap, sy, sx) != 0)
+ changela_tree1_col = 1;
+
+ /* Hit Right Bank */
+ if(riv_col == 0 && prev_col == 1)
+ changela_right_bank_col = 1;
+
+ /* Hit Left Bank */
+ if(riv_col == 1 && prev_col == 0)
+ changela_left_bank_col = 1;
+
+ /* Boat Hit Shore */
+ if(riv_col == 1)
+ changela_boat_shore_col = 1;
+ }
+ }
+ if(!changela_tree_collision_reset)
+ {
+ changela_tree0_col = 0;
+ changela_tree1_col = 0;
+ }
+ if(!changela_collision_reset)
+ {
+ changela_left_bank_col = 0;
+ changela_right_bank_col = 0;
+ changela_boat_shore_col = 0;
+ }
+
+ sy++;
+ if(sy > 256) sy = 30;
+ timer_adjust(changela_scanline_timer, video_screen_get_time_until_pos(0, sy, 0), sy, attotime_zero);
+}
+
+VIDEO_UPDATE( changela )
+{
+ copybitmap(bitmap, river_bitmap, 0, 0, 0, 0, &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ copybitmap(bitmap, obj0_bitmap, 0, 0, 0, 0, &machine->screen[0].visarea, TRANSPARENCY_PEN, 0);
+ copybitmap(bitmap, tree0_bitmap, 0, 0, 0, 0, &machine->screen[0].visarea, TRANSPARENCY_PEN, 0);
+ copybitmap(bitmap, tree1_bitmap, 0, 0, 0, 0, &machine->screen[0].visarea, TRANSPARENCY_PEN, 0);
+ draw_obj1(machine, bitmap);
+
+ return 0;
+}
+
+WRITE8_HANDLER( changela_colors_w )
+{
+ /* Each color is combined from 3 bits from open-colelctor outputs of ram.
+ Each of the bits is connected to a 220, 470, or 1000 Ohm resistor.
+ There is also a 680 Ohm pull-up resistor connected to 5V, and a
+ 2.2k resisor connected to GND. Thus these output voltages are obtained:
+ Val | Vout
+ 000 | 0.766 (220 || 470 || 1k || 2.2k)
+ 001 | 0.855 (220 || 470 || 2.2k)
+ 010 | 0.984 (220 || 1k || 2.2k)
+ 011 | 1.136 (220 || 2.2k)
+ 100 | 1.455 (470 || 1k || 2.2k)
+ 101 | 1.814 (470 || 2.2k)
+ 110 | 2.514 (1k || 2.2k)
+ 111 | 3.819 (2.2k)
+ Which were normalized to produce the following table: */
+
+ UINT8 color_table[8] = { 0, 7, 18, 31, 58, 88, 146, 255 };
+
+ int r, g, b;
+ UINT32 c, color_index;
+
+ c = (data) | ((offset & 0x01) << 8); /* a0 used as D8 bit input */
+
+ c ^= 0x1ff; /* active low */
+
+ color_index = offset >> 1;
+ color_index ^= 0x30; /* A4 and A5 lines are negated */
+
+ r = color_table[(c >> 0) & 0x07];
+ g = color_table[(c >> 3) & 0x07];
+ b = color_table[(c >> 6) & 0x07];
+
+ palette_set_color_rgb(Machine,color_index,r,g,b);
+}
+
+
+WRITE8_HANDLER( changela_mem_device_select_w )
+{
+ mem_dev_selected = (data & 0x07) * 0x800;
+
+ tree_en = (data & 0x30) >> 4;
+
+ /*
+ (data & 0x07) possible settings:
+ 0 - not connected (no device)
+ 1 - ADR1 is 2114 RAM at U59 (state machine) (accessible range: 0x0000-0x003f)
+ 2 - ADR2 is 2128 RAM at U109 (River RAM) (accessible range: 0x0000-0x07ff)
+ 3 - ADR3 is 2128 RAM at U114 (Tree RAM) (accessible range: 0x0000-0x07ff)
+ 4 - ADR4 is 2732 ROM at U7 (Tree ROM) (accessible range: 0x0000-0x07ff)
+ 5 - SLOPE is ROM at U44 (state machine) (accessible range: 0x0000-0x07ff)
+ */
+}
+
+WRITE8_HANDLER( changela_mem_device_w )
+{
+ memory_devices[mem_dev_selected + offset] = data;
+
+ if(mem_dev_selected == 0x800)
+ {
+ memory_devices[mem_dev_selected + 0x40 + offset] = data;
+ memory_devices[mem_dev_selected + 0x80 + offset] = data;
+ }
+}
+
+
+READ8_HANDLER( changela_mem_device_r )
+{
+ return memory_devices[mem_dev_selected + offset];
+}
+
+
+WRITE8_HANDLER( changela_slope_rom_addr_hi_w )
+{
+ slopeROM_bank = (data & 0x03) << 9;
+}
+
+WRITE8_HANDLER( changela_slope_rom_addr_lo_w )
+{
+ horizon = data;
+}
+
+
diff --git a/src/mame/video/cheekyms.c b/src/mame/video/cheekyms.c
new file mode 100644
index 00000000000..a09fe248dfe
--- /dev/null
+++ b/src/mame/video/cheekyms.c
@@ -0,0 +1,180 @@
+/*************************************************************************
+ Universal Cheeky Mouse Driver
+ (c)Lee Taylor May 1998, All rights reserved.
+
+ For use only in offical Mame releases.
+ Not to be distrabuted as part of any commerical work.
+***************************************************************************
+Functions to emulate the video hardware of the machine.
+***************************************************************************/
+
+#include "driver.h"
+#include "sound/dac.h"
+
+
+static int man_scroll = -1;
+static UINT8 sprites[0x20];
+static int char_palette = 0;
+
+
+PALETTE_INIT( cheekyms )
+{
+ int i,j,bit,r,g,b;
+
+ for (i = 0; i < 6; i++)
+ {
+ for (j = 0;j < 0x20;j++)
+ {
+ /* red component */
+ bit = (color_prom[0x20*(i/2)+j] >> ((4*(i&1))+0)) & 0x01;
+ r = 0xff * bit;
+ /* green component */
+ bit = (color_prom[0x20*(i/2)+j] >> ((4*(i&1))+1)) & 0x01;
+ g = 0xff * bit;
+ /* blue component */
+ bit = (color_prom[0x20*(i/2)+j] >> ((4*(i&1))+2)) & 0x01;
+ b = 0xff * bit;
+
+ palette_set_color(machine,(i*0x20)+j,MAKE_RGB(r,g,b));
+ }
+ }
+}
+
+
+WRITE8_HANDLER( cheekyms_sprite_w )
+{
+ sprites[offset] = data;
+}
+
+
+WRITE8_HANDLER( cheekyms_port_40_w )
+{
+ static int last_dac = -1;
+
+ /* The lower bits probably trigger sound samples */
+
+ if (last_dac != (data & 0x80))
+ {
+ last_dac = data & 0x80;
+
+ DAC_data_w(0, last_dac ? 0x80 : 0);
+ }
+}
+
+
+WRITE8_HANDLER( cheekyms_port_80_w )
+{
+ /* Bits 0-1 Sound enables, not sure which bit is which */
+
+ /* Bit 2 is interrupt enable */
+ interrupt_enable_w(offset, data & 0x04);
+
+ /* Bit 3-5 Man scroll amount */
+ man_scroll = (data >> 3) & 0x07;
+
+ /* Bit 6 is palette select (Selects either 0 = PROM M9, 1 = PROM M8) */
+ char_palette = (data >> 2) & 0x10;
+
+ /* Bit 7 is screen flip */
+ flip_screen_set(data & 0x80);
+}
+
+
+
+VIDEO_UPDATE( cheekyms )
+{
+ int offs;
+
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ /* Draw the sprites first, because they're supposed to appear below
+ the characters */
+ for (offs = 0; offs < sizeof(sprites)/sizeof(sprites[0]); offs += 4)
+ {
+ int v1, sx, sy, col, code;
+
+ v1 = sprites[offs + 0];
+ sy = sprites[offs + 1];
+ sx = 256 - sprites[offs + 2];
+ col = (~sprites[offs + 3] & 0x07);
+
+ if (!(sprites[offs + 3] & 0x08)) continue;
+
+ code = (~v1 << 1) & 0x1f;
+
+ if (v1 & 0x80)
+ {
+ if (!flip_screen)
+ {
+ code++;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ col,
+ 0,0,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ code + 0x20,
+ col,
+ 0,0,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ drawgfx(bitmap,machine->gfx[1],
+ code + 0x21,
+ col,
+ 0,0,
+ sx + 8*(v1 & 2),sy + 8*(~v1 & 2),
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+
+
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int sx,sy,man_area,color;
+
+ sx = offs % 32;
+ sy = offs / 32;
+
+
+ man_area = ((sy >= 6) && (sy <= 26) && (sx >= 8) && (sx <= 12));
+
+ if (sx >= 30)
+ {
+ if (sy < 12)
+ color = 0x15;
+ else if (sy < 20)
+ color = 0x16;
+ else
+ color = 0x14;
+ }
+ else
+ {
+ color = ((sx >> 1) & 0x0f) + char_palette;
+ if (sy == 4 || sy == 27)
+ color = 0xc + char_palette;
+ }
+
+ if (flip_screen)
+ {
+ sx = 31 - sx;
+ sy = 31 - sy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ videoram[offs],
+ color,
+ flip_screen,flip_screen,
+ 8*sx, 8*sy - (man_area ? man_scroll : 0),
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/chqflag.c b/src/mame/video/chqflag.c
new file mode 100644
index 00000000000..0cc190b2ccf
--- /dev/null
+++ b/src/mame/video/chqflag.c
@@ -0,0 +1,87 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/konamiic.h"
+#include "cpu/z80/z80.h"
+
+#define SPRITEROM_MEM_REGION REGION_GFX1
+#define ZOOMROM0_MEM_REGION REGION_GFX2
+#define ZOOMROM1_MEM_REGION REGION_GFX3
+
+static int sprite_colorbase,zoom_colorbase[2];
+
+/***************************************************************************
+
+ Callbacks for the K051960
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority,int *shadow)
+{
+ *priority = (*color & 0x10) >> 4;
+ *color = sprite_colorbase + (*color & 0x0f);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051316
+
+***************************************************************************/
+
+static void zoom_callback_0(int *code,int *color,int *flags)
+{
+ *code |= ((*color & 0x03) << 8);
+ *color = zoom_colorbase[0] + ((*color & 0x3c) >> 2);
+}
+
+static void zoom_callback_1(int *code,int *color,int *flags)
+{
+ *flags = TILE_FLIPYX((*color & 0xc0) >> 6);
+ *code |= ((*color & 0x0f) << 8);
+ *color = zoom_colorbase[1] + ((*color & 0x10) >> 4);
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( chqflag )
+{
+ sprite_colorbase = 0;
+ zoom_colorbase[0] = 0x10;
+ zoom_colorbase[1] = 0x02;
+
+ K051960_vh_start(machine,SPRITEROM_MEM_REGION,NORMAL_PLANE_ORDER,sprite_callback);
+ K051316_vh_start_0(machine,ZOOMROM0_MEM_REGION,4,FALSE,0,zoom_callback_0);
+ K051316_vh_start_1(machine,ZOOMROM1_MEM_REGION,8,TRUE,0xc0,zoom_callback_1);
+
+ K051316_set_offset(0,7,0);
+ K051316_wraparound_enable(1,1);
+}
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( chqflag )
+{
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ K051316_zoom_draw_1(bitmap,cliprect,TILEMAP_DRAW_LAYER1,0);
+ K051960_sprites_draw(bitmap,cliprect,0,0);
+ K051316_zoom_draw_1(bitmap,cliprect,TILEMAP_DRAW_LAYER0,0);
+ K051960_sprites_draw(bitmap,cliprect,1,1);
+ K051316_zoom_draw_0(bitmap,cliprect,0,0);
+ return 0;
+}
diff --git a/src/mame/video/cinemat.c b/src/mame/video/cinemat.c
new file mode 100644
index 00000000000..009ccdca6b3
--- /dev/null
+++ b/src/mame/video/cinemat.c
@@ -0,0 +1,254 @@
+/***************************************************************************
+
+ Cinematronics vector hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/vector.h"
+#include "cpu/ccpu/ccpu.h"
+#include "cinemat.h"
+
+
+/*************************************
+ *
+ * Constants
+ *
+ *************************************/
+
+enum
+{
+ COLOR_BILEVEL,
+ COLOR_16LEVEL,
+ COLOR_64LEVEL,
+ COLOR_RGB,
+ COLOR_QB3
+};
+
+
+
+/*************************************
+ *
+ * Local variables
+ *
+ *************************************/
+
+static int color_mode;
+static rgb_t vector_color;
+static INT16 lastx, lasty;
+static UINT8 last_control;
+
+
+
+/*************************************
+ *
+ * Vector rendering
+ *
+ *************************************/
+
+void cinemat_vector_callback(INT16 sx, INT16 sy, INT16 ex, INT16 ey, UINT8 shift)
+{
+ int intensity = 0xff;
+
+ /* adjust for slop */
+ sx = sx - Machine->screen[0].visarea.min_x;
+ ex = ex - Machine->screen[0].visarea.min_x;
+ sy = sy - Machine->screen[0].visarea.min_y;
+ ey = ey - Machine->screen[0].visarea.min_y;
+
+ /* point intensity is determined by the shift value */
+ if (sx == ex && sy == ey)
+ intensity = 0x1ff * shift / 8;
+
+ /* move to the starting position if we're not there already */
+ if (sx != lastx || sy != lasty)
+ vector_add_point(sx << 16, sy << 16, 0, 0);
+
+ /* draw the vector */
+ vector_add_point(ex << 16, ey << 16, vector_color, intensity);
+
+ /* remember the last point */
+ lastx = ex;
+ lasty = ey;
+}
+
+
+
+/*************************************
+ *
+ * Vector color handling
+ *
+ *************************************/
+
+WRITE8_HANDLER(cinemat_vector_control_w)
+{
+ int r, g, b, i;
+
+ switch (color_mode)
+ {
+ case COLOR_BILEVEL:
+ /* color is either bright or dim, selected by the value sent to the port */
+ vector_color = (data & 1) ? MAKE_RGB(0x80,0x80,0x80) : MAKE_RGB(0xff,0xff,0xff);
+ break;
+
+ case COLOR_16LEVEL:
+ /* on the rising edge of the data value, latch bits 0-3 of the */
+ /* X register as the intensity */
+ if (data != last_control && data)
+ {
+ int xval = cpunum_get_reg(0, CCPU_X) & 0x0f;
+ i = (xval + 1) * 255 / 16;
+ vector_color = MAKE_RGB(i,i,i);
+ }
+ break;
+
+ case COLOR_64LEVEL:
+ /* on the rising edge of the data value, latch bits 2-7 of the */
+ /* X register as the intensity */
+ if (data != last_control && data)
+ {
+ int xval = cpunum_get_reg(0, CCPU_X);
+ xval = (~xval >> 2) & 0x3f;
+ i = (xval + 1) * 255 / 64;
+ vector_color = MAKE_RGB(i,i,i);
+ }
+ break;
+
+ case COLOR_RGB:
+ /* on the rising edge of the data value, latch the X register */
+ /* as 4-4-4 BGR values */
+ if (data != last_control && data)
+ {
+ int xval = cpunum_get_reg(0, CCPU_X);
+ r = (~xval >> 0) & 0x0f;
+ r = r * 255 / 15;
+ g = (~xval >> 4) & 0x0f;
+ g = g * 255 / 15;
+ b = (~xval >> 8) & 0x0f;
+ b = b * 255 / 15;
+ vector_color = MAKE_RGB(r,g,b);
+ }
+ break;
+
+ case COLOR_QB3:
+ {
+ static int lastx, lasty;
+
+ /* on the falling edge of the data value, remember the original X,Y values */
+ /* they will be restored on the rising edge; this is to simulate the fact */
+ /* that the Rockola color hardware did not overwrite the beam X,Y position */
+ /* on an IV instruction if data == 0 here */
+ if (data != last_control && !data)
+ {
+ lastx = cpunum_get_reg(0, CCPU_X);
+ lasty = cpunum_get_reg(0, CCPU_Y);
+ }
+
+ /* on the rising edge of the data value, latch the Y register */
+ /* as 2-3-3 BGR values */
+ if (data != last_control && data)
+ {
+ int yval = cpunum_get_reg(0, CCPU_Y);
+ r = (~yval >> 0) & 0x07;
+ r = r * 255 / 7;
+ g = (~yval >> 3) & 0x07;
+ g = g * 255 / 7;
+ b = (~yval >> 6) & 0x03;
+ b = b * 255 / 3;
+ vector_color = MAKE_RGB(r,g,b);
+
+ /* restore the original X,Y values */
+ cpunum_set_reg(0, CCPU_X, lastx);
+ cpunum_set_reg(0, CCPU_Y, lasty);
+ }
+ }
+ break;
+ }
+
+ /* remember the last value */
+ last_control = data;
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( cinemat_bilevel )
+{
+ color_mode = COLOR_BILEVEL;
+ video_start_vector(machine);
+}
+
+
+VIDEO_START( cinemat_16level )
+{
+ color_mode = COLOR_16LEVEL;
+ video_start_vector(machine);
+}
+
+
+VIDEO_START( cinemat_64level )
+{
+ color_mode = COLOR_64LEVEL;
+ video_start_vector(machine);
+}
+
+
+VIDEO_START( cinemat_color )
+{
+ color_mode = COLOR_RGB;
+ video_start_vector(machine);
+}
+
+
+VIDEO_START( cinemat_qb3color )
+{
+ color_mode = COLOR_QB3;
+ video_start_vector(machine);
+}
+
+
+
+/*************************************
+ *
+ * End-of-frame
+ *
+ *************************************/
+
+VIDEO_EOF( cinemat )
+{
+ vector_clear_list();
+}
+
+
+
+/*************************************
+ *
+ * Space War update
+ *
+ *************************************/
+
+VIDEO_UPDATE( spacewar )
+{
+ int sw_option = readinputportbytag("INPUTS");
+
+ video_update_vector(machine, screen, bitmap, cliprect);
+
+ /* set the state of the artwork */
+ output_set_value("pressed3", (~sw_option >> 0) & 1);
+ output_set_value("pressed8", (~sw_option >> 1) & 1);
+ output_set_value("pressed4", (~sw_option >> 2) & 1);
+ output_set_value("pressed9", (~sw_option >> 3) & 1);
+ output_set_value("pressed1", (~sw_option >> 4) & 1);
+ output_set_value("pressed6", (~sw_option >> 5) & 1);
+ output_set_value("pressed2", (~sw_option >> 6) & 1);
+ output_set_value("pressed7", (~sw_option >> 7) & 1);
+ output_set_value("pressed5", (~sw_option >> 10) & 1);
+ output_set_value("pressed0", (~sw_option >> 11) & 1);
+ return 0;
+}
+
diff --git a/src/mame/video/circus.c b/src/mame/video/circus.c
new file mode 100644
index 00000000000..e391a34a8f4
--- /dev/null
+++ b/src/mame/video/circus.c
@@ -0,0 +1,272 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+ CHANGES:
+ MAB 05 MAR 99 - changed overlay support to use artwork functions
+ AAT 12 MAY 02 - rewrote Ripcord and added pixel-wise collision
+
+***************************************************************************/
+
+#include "driver.h"
+#include "sound/samples.h"
+#include "circus.h"
+
+static int clown_x=0,clown_y=0;
+int clown_z=0;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+***************************************************************************/
+
+WRITE8_HANDLER( circus_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( circus_clown_x_w )
+{
+ clown_x = 240-data;
+}
+
+WRITE8_HANDLER( circus_clown_y_w )
+{
+ clown_y = 240-data;
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index];
+
+ SET_TILE_INFO(0, code, 0, 0);
+}
+
+VIDEO_START( circus )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_line(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int x1, int y1, int x2, int y2, int dotted)
+{
+ /* Draws horizontal and Vertical lines only! */
+
+ int count, skip;
+
+ /* Draw the Line */
+
+ if (dotted > 0)
+ skip = 2;
+ else
+ skip = 1;
+
+ if (x1 == x2)
+ {
+ for (count = y2; count >= y1; count -= skip)
+ {
+ *BITMAP_ADDR16(bitmap, count, x1) = machine->pens[1];
+ }
+ }
+ else
+ {
+ for (count = x2; count >= x1; count -= skip)
+ {
+ *BITMAP_ADDR16(bitmap, y1, count) = machine->pens[1];
+ }
+ }
+}
+
+static void draw_robot_box (running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int x, int y)
+{
+ /* Box */
+
+ int ex = x + 24;
+ int ey = y + 26;
+
+ draw_line(machine,bitmap,cliprect,x,y,ex,y,0); /* Top */
+ draw_line(machine,bitmap,cliprect,x,ey,ex,ey,0); /* Bottom */
+ draw_line(machine,bitmap,cliprect,x,y,x,ey,0); /* Left */
+ draw_line(machine,bitmap,cliprect,ex,y,ex,ey,0); /* Right */
+
+ /* Score Grid */
+
+ ey = y + 10;
+ draw_line(machine,bitmap,cliprect,x+8,ey,ex,ey,0); /* Horizontal Divide Line */
+ draw_line(machine,bitmap,cliprect,x+8,y,x+8,ey,0);
+ draw_line(machine,bitmap,cliprect,x+16,y,x+16,ey,0);
+}
+
+static void circus_draw_fg(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /* The sync generator hardware is used to */
+ /* draw the border and diving boards */
+
+ draw_line (machine,bitmap,cliprect,0,18,255,18,0);
+ draw_line (machine,bitmap,cliprect,0,249,255,249,1);
+ draw_line (machine,bitmap,cliprect,0,18,0,248,0);
+ draw_line (machine,bitmap,cliprect,247,18,247,248,0);
+
+ draw_line (machine,bitmap,cliprect,0,137,17,137,0);
+ draw_line (machine,bitmap,cliprect,231,137,248,137,0);
+ draw_line (machine,bitmap,cliprect,0,193,17,193,0);
+ draw_line (machine,bitmap,cliprect,231,193,248,193,0);
+
+ drawgfx(bitmap,machine->gfx[1],
+ clown_z,
+ 0,
+ 0,0,
+ clown_y,clown_x,
+ cliprect,TRANSPARENCY_PEN,0);
+}
+
+VIDEO_UPDATE( circus )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ circus_draw_fg(machine, bitmap, cliprect);
+ return 0;
+}
+
+static void robotbwl_draw_scoreboard(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ /* The sync generator hardware is used to */
+ /* draw the bowling alley & scorecards */
+
+ for(offs=15;offs<=63;offs+=24)
+ {
+ draw_robot_box(machine, bitmap, cliprect, offs, 31);
+ draw_robot_box(machine, bitmap, cliprect, offs, 63);
+ draw_robot_box(machine, bitmap, cliprect, offs, 95);
+
+ draw_robot_box(machine, bitmap, cliprect, offs+152, 31);
+ draw_robot_box(machine, bitmap, cliprect, offs+152, 63);
+ draw_robot_box(machine, bitmap, cliprect, offs+152, 95);
+ }
+
+ draw_robot_box(machine, bitmap, cliprect, 39, 127); /* 10th Frame */
+ draw_line(machine,bitmap, cliprect, 39,137,47,137,0); /* Extra digit box */
+
+ draw_robot_box(machine, bitmap, cliprect, 39+152, 127);
+ draw_line(machine,bitmap, cliprect, 39+152,137,47+152,137,0);
+}
+
+static void robotbwl_draw_bowling_alley(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ draw_line(machine,bitmap, cliprect, 103,17,103,205,0);
+ draw_line(machine,bitmap, cliprect, 111,17,111,203,1);
+ draw_line(machine,bitmap, cliprect, 152,17,152,205,0);
+ draw_line(machine,bitmap, cliprect, 144,17,144,203,1);
+}
+
+static void robotbwl_draw_ball(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ drawgfx(bitmap,machine->gfx[1],
+ clown_z,
+ 0,
+ 0,0,
+ clown_y+8,clown_x+8, /* Y is horizontal position */
+ cliprect,TRANSPARENCY_PEN,0);
+}
+
+VIDEO_UPDATE( robotbwl )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ robotbwl_draw_scoreboard(machine, bitmap, cliprect);
+ robotbwl_draw_bowling_alley(machine, bitmap, cliprect);
+ robotbwl_draw_ball(machine, bitmap, cliprect);
+ return 0;
+}
+
+static void crash_draw_car(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ drawgfx(bitmap,machine->gfx[1],
+ clown_z,
+ 0,
+ 0,0,
+ clown_y,clown_x, /* Y is horizontal position */
+ cliprect,TRANSPARENCY_PEN,0);
+}
+
+VIDEO_UPDATE( crash )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ crash_draw_car(machine, bitmap, cliprect);
+ return 0;
+}
+
+static void ripcord_draw_skydiver(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const gfx_element *gfx;
+ const pen_t *pal_ptr;
+ UINT8 *src_lineptr, *src_pixptr;
+ UINT16 *dst_lineptr, *dst_lineend;
+ UINT32 code, color;
+ int sx, sy;
+ int src_pitch, dst_width, dst_height, dst_pitch, dst_pixoffs, dst_pixend;
+ int collision, eax, edx;
+
+ gfx = machine->gfx[0];
+
+ code = clown_z;
+ color = 0;
+
+ sx = clown_y;
+ sy = clown_x - 1;
+ dst_width = 16;
+ dst_height = 16;
+ edx = 1;
+
+ gfx = machine->gfx[1];
+ pal_ptr = &machine->remapped_colortable[gfx->color_base + color * gfx->color_granularity];
+ src_lineptr = gfx->gfxdata + code * gfx->char_modulo;
+ src_pitch = gfx->line_modulo;
+ dst_pitch = bitmap->rowpixels;
+
+ dst_lineptr = BITMAP_ADDR16(bitmap, sy, 0);
+ dst_pixend = (sx + dst_width) & 0xff;
+ dst_lineend = dst_lineptr + dst_pitch * dst_height;
+
+ // draw sky diver and check collision on a pixel basis
+ collision = 0;
+ do
+ {
+ src_pixptr = src_lineptr;
+ dst_pixoffs = sx;
+
+ do
+ {
+ eax = *src_pixptr;
+ src_pixptr ++;
+ if (eax)
+ {
+ eax = pal_ptr[eax];
+ collision |= dst_lineptr[dst_pixoffs];
+ dst_lineptr[dst_pixoffs] = eax;
+ }
+ dst_pixoffs += edx;
+
+ } while((dst_pixoffs &= 0xff) != dst_pixend);
+
+ src_lineptr += src_pitch;
+
+ } while((dst_lineptr += dst_pitch) != dst_lineend);
+
+ // report collision only when the character is not blank and within display area
+ if (collision && code!=0xf && clown_x>0 && clown_x<240 && clown_y>-12 && clown_y<240)
+ {
+ cpunum_set_input_line(0, 0, ASSERT_LINE); // interrupt accuracy is critical in Ripcord
+ cpunum_set_input_line(0, 0, CLEAR_LINE);
+ }
+}
+
+VIDEO_UPDATE( ripcord )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ ripcord_draw_skydiver(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/circusc.c b/src/mame/video/circusc.c
new file mode 100644
index 00000000000..242ef0111d2
--- /dev/null
+++ b/src/mame/video/circusc.c
@@ -0,0 +1,199 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+UINT8 *circusc_videoram,*circusc_colorram;
+static tilemap *bg_tilemap;
+
+UINT8 *circusc_spritebank;
+UINT8 *circusc_scroll;
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Circus Charlie has one 32x8 palette PROM and two 256x4 lookup table PROMs
+ (one for characters, one for sprites).
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( circusc )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = *(color_prom++) & 0x0f;
+
+ /* characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = (*(color_prom++) & 0x0f) + 0x10;
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 attr = circusc_colorram[tile_index];
+ tileinfo->category = (attr & 0x10) >> 4;
+ SET_TILE_INFO(
+ 0,
+ circusc_videoram[tile_index] + ((attr & 0x20) << 3),
+ attr & 0x0f,
+ TILE_FLIPYX((attr & 0xc0) >> 6));
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( circusc )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_scroll_cols(bg_tilemap,32);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( circusc_videoram_w )
+{
+ circusc_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( circusc_colorram_w )
+{
+ circusc_colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( circusc_flipscreen_w )
+{
+ flip_screen_set(data & 1);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+ UINT8 *sr;
+
+
+ if ((*circusc_spritebank & 0x01) != 0)
+ sr = spriteram;
+ else sr = spriteram_2;
+
+ for (offs = 0; offs < spriteram_size;offs += 4)
+ {
+ int sx,sy,flipx,flipy;
+
+
+ sx = sr[offs + 2];
+ sy = sr[offs + 3];
+ flipx = sr[offs + 1] & 0x40;
+ flipy = sr[offs + 1] & 0x80;
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+
+ drawgfx(bitmap,machine->gfx[1],
+ sr[offs + 0] + 8 * (sr[offs + 1] & 0x20),
+ sr[offs + 1] & 0x0f,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_COLOR,0);
+
+ }
+}
+
+VIDEO_UPDATE( circusc )
+{
+ int i;
+
+ for (i = 0;i < 10;i++)
+ tilemap_set_scrolly(bg_tilemap,i,0);
+ for (i = 10;i < 32;i++)
+ tilemap_set_scrolly(bg_tilemap,i,*circusc_scroll);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,1,0);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/cischeat.c b/src/mame/video/cischeat.c
new file mode 100644
index 00000000000..3d0887145f8
--- /dev/null
+++ b/src/mame/video/cischeat.c
@@ -0,0 +1,1375 @@
+/***************************************************************************
+
+ -= Jaleco Driving Games =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z or X with:
+
+ Q,W,E shows scroll 0,1,2
+ R,T shows road 0,1
+ A,S,D,F shows sprites with priority 0,1,2,3
+ X shows some info on each sprite
+ M disables sprites zooming
+ U toggles the display of some hardware registers'
+ values ($80000/2/4/6)
+
+ Keys can be used together!
+ Additionally, layers can be disabled, writing to $82400
+ (fake video register):
+
+ ---- ---- --54 ---- Enable Road 1,0
+ ---- ---- ---- 3--- Enable Sprites
+ ---- ---- ---- -210 Enable Scroll 2,1,0
+
+ 0 is the same as 0x3f
+
+[ 3 Scrolling Layers ]
+
+ see Megasys1.c
+
+ Tile Format: Cisco Heat F1 GP Star
+
+ Colour fedc b--- ---- ---- fedc ---- ---- ----
+ Code ---- -a98 7654 3210 ---- ba98 7654 3210
+
+ Layer Size: May be different from Megasys1?
+
+[ 2 Road Layers ]
+
+ Each of the 256 (not all visible) lines of the screen
+ can display any of the lines of gfx in ROM, which are
+ larger than the sceen and can therefore be scrolled
+
+ Cisco Heat F1 GP Star
+ Line Width 1024 1024
+ Zoom No Yes
+
+[ 256 Sprites ]
+
+ Sprites are made of several 16x16 tiles (up to 256x256 pixels)
+ and can be zoomed in and out. See below for sprite RAM format.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "megasys1.h"
+
+/* Variables only used here: */
+
+static int cischeat_ip_select;
+
+#ifdef MAME_DEBUG
+static int debugsprites; // For debug purposes
+#endif
+
+/* Variables that driver has access to: */
+
+UINT16 *cischeat_roadram[2];
+UINT16 *f1gpstr2_ioready;
+
+#ifdef MAME_DEBUG
+#define SHOW_READ_ERROR(_format_,_offset_)\
+{\
+ popmessage(_format_,_offset_);\
+ logerror("CPU #0 PC %06X : Warning, ",activecpu_get_pc()); \
+ logerror(_format_ "\n",_offset_);\
+}
+#define SHOW_WRITE_ERROR(_format_,_offset_,_data_)\
+{\
+ popmessage(_format_,_offset_,_data_);\
+ logerror("CPU #0 PC %06X : Warning, ",activecpu_get_pc()); \
+ logerror(_format_ "\n",_offset_,_data_); \
+}
+
+#else
+
+#define SHOW_READ_ERROR(_format_,_offset_)\
+{\
+ logerror("CPU #0 PC %06X : Warning, ",activecpu_get_pc()); \
+ logerror(_format_ "\n",_offset_);\
+}
+#define SHOW_WRITE_ERROR(_format_,_offset_,_data_)\
+{\
+ logerror("CPU #0 PC %06X : Warning, ",activecpu_get_pc()); \
+ logerror(_format_ "\n",_offset_,_data_); \
+}
+
+#endif
+
+#define MEGASYS1_VREG_SCROLL(_n_, _dir_) megasys1_scroll##_dir_[_n_] = new_data;
+
+
+#define cischeat_tmap_SET_SCROLL(_n_) \
+ if (megasys1_tmap[_n_]) \
+ { \
+ tilemap_set_scrollx(megasys1_tmap[_n_], 0, megasys1_scrollx[_n_]); \
+ tilemap_set_scrolly(megasys1_tmap[_n_], 0, megasys1_scrolly[_n_]); \
+ }
+
+#define cischeat_tmap_DRAW(_n_) \
+ if ( (megasys1_tmap[_n_]) && (megasys1_active_layers & (1 << _n_) ) ) \
+ { \
+ tilemap_draw(bitmap, cliprect, megasys1_tmap[_n_], flag, 0 ); \
+ flag = 0; \
+ }
+
+
+/***************************************************************************
+
+
+ Video Hardware Init
+
+
+***************************************************************************/
+
+static void prepare_shadows(void)
+{
+ int i;
+ for (i = 0;i < 16;i++)
+ gfx_drawmode_table[i] = DRAWMODE_SOURCE;
+
+ gfx_drawmode_table[ 0] = DRAWMODE_SHADOW;
+ gfx_drawmode_table[15] = DRAWMODE_NONE;
+}
+
+/**************************************************************************
+ Cisco Heat
+**************************************************************************/
+
+/* 32 colour codes for the tiles */
+VIDEO_START( cischeat )
+{
+ video_start_megasys1(machine);
+
+ megasys1_bits_per_color_code = 5;
+
+ prepare_shadows();
+}
+
+/**************************************************************************
+ F1 GrandPrix Star
+**************************************************************************/
+
+/* 16 colour codes for the tiles */
+VIDEO_START( f1gpstar )
+{
+ video_start_cischeat(machine);
+
+ megasys1_bits_per_color_code = 4;
+}
+
+VIDEO_START( bigrun )
+{
+ video_start_f1gpstar(machine);
+}
+
+
+
+/***************************************************************************
+
+
+ Hardware registers access
+
+
+***************************************************************************/
+
+/* This function returns the status of the shift (ACTIVE_LOW):
+
+ 1 - low shift
+ 0 - high shift
+
+ and allows the shift to be handled using two buttons */
+
+static int read_shift(void)
+{
+ static int ret = 1; /* start with low shift */
+ switch ( (readinputport(0) >> 2) & 3 )
+ {
+ case 1 : ret = 1; break; // low shift: button 3
+ case 2 : ret = 0; break; // high shift: button 4
+ }
+ return ret;
+}
+
+
+/*
+ F1 GP Star has a real pedal, while Cisco Heat's is connected to
+ a switch. The Former game stores, during boot, the value that
+ corresponds to the pedal not pressed, and compares against it:
+
+ The value returned must decrease when the pedal is pressed.
+ We support just 2 values for now..
+*/
+
+static int read_accelerator(void)
+{
+ if (readinputport(0) & 1) return 0x00; // pedal pressed
+ else return 0xff;
+}
+
+
+/**************************************************************************
+ Big Run
+**************************************************************************/
+
+READ16_HANDLER( bigrun_vregs_r )
+{
+ switch (offset)
+ {
+ case 0x0000/2 : return readinputport(1); // Coins
+ case 0x0002/2 : return readinputport(2) +
+ (read_shift()<<1); // Buttons
+ case 0x0004/2 : return readinputport(3); // Motor Limit Switches
+ case 0x0006/2 : return readinputport(4); // DSW 1 & 2
+
+ case 0x0008/2 : return soundlatch2_word_r(0,0); // From sound cpu
+
+ case 0x0010/2 :
+ switch (cischeat_ip_select & 0x3)
+ {
+ case 0 : return readinputport(6); // Driving Wheel
+ case 1 : return 0xffff; // Cockpit: Up / Down Position
+ case 2 : return 0xffff; // Cockpit: Left / Right Position?
+ case 3 : return ~read_accelerator(); // Accelerator (Pedal)
+ default: return 0xffff;
+ }
+
+
+ case 0x2200/2 : return readinputport(5); // DSW 3 (4 bits)
+
+ default: SHOW_READ_ERROR("vreg %04X read!",offset*2);
+ return megasys1_vregs[offset];
+ }
+}
+
+WRITE16_HANDLER( bigrun_vregs_w )
+{
+ UINT16 old_data = megasys1_vregs[offset];
+ UINT16 new_data = COMBINE_DATA(&megasys1_vregs[offset]);
+
+ switch (offset)
+ {
+ case 0x0000/2 : // leds
+ if (ACCESSING_LSB)
+ {
+ coin_counter_w(0,new_data & 0x01);
+ coin_counter_w(1,new_data & 0x02);
+ set_led_status(0,new_data & 0x10); // start button
+ set_led_status(1,new_data & 0x20); // ?
+ }
+ break;
+
+ case 0x0002/2 : // ?? 91/1/91/1 ...
+ break;
+
+ case 0x0004/2 : // motor (seat?)
+ if (ACCESSING_LSB)
+ set_led_status(2, (new_data != old_data) ? 1 : 0);
+ break;
+
+ case 0x0006/2 : // motor (wheel?)
+ break;
+
+ case 0x000a/2 : // to sound cpu
+ soundlatch_word_w(0,new_data,0);
+ break;
+
+ case 0x000c/2 : break; // ??
+
+ case 0x0010/2 : cischeat_ip_select = new_data; break;
+ case 0x0012/2 : cischeat_ip_select = new_data+1; break; // value above + 1
+
+ case 0x2000/2+0 : MEGASYS1_VREG_SCROLL(0,x) break;
+ case 0x2000/2+1 : MEGASYS1_VREG_SCROLL(0,y) break;
+ case 0x2000/2+2 : megasys1_set_vreg_flag(0,new_data);break;
+
+ case 0x2008/2+0 : MEGASYS1_VREG_SCROLL(1,x) break;
+ case 0x2008/2+1 : MEGASYS1_VREG_SCROLL(1,y) break;
+ case 0x2008/2+2 : megasys1_set_vreg_flag(1,new_data);break;
+
+ case 0x2100/2+0 : MEGASYS1_VREG_SCROLL(2,x) break;
+ case 0x2100/2+1 : MEGASYS1_VREG_SCROLL(2,y) break;
+ case 0x2100/2+2 : megasys1_set_vreg_flag(2,new_data);break;
+
+ case 0x2108/2 : break; // ? written with 0 only
+ case 0x2208/2 : break; // watchdog reset
+
+ /* Not sure about this one.. */
+ case 0x2308/2 : cpunum_set_input_line(1, INPUT_LINE_RESET, (new_data & 2) ? ASSERT_LINE : CLEAR_LINE );
+ cpunum_set_input_line(2, INPUT_LINE_RESET, (new_data & 2) ? ASSERT_LINE : CLEAR_LINE );
+ cpunum_set_input_line(3, INPUT_LINE_RESET, (new_data & 1) ? ASSERT_LINE : CLEAR_LINE );
+ break;
+
+ default: SHOW_WRITE_ERROR("vreg %04X <- %04X",offset*2,data);
+ }
+}
+
+
+/**************************************************************************
+ Cisco Heat
+**************************************************************************/
+
+READ16_HANDLER( cischeat_vregs_r )
+{
+ switch (offset)
+ {
+ case 0x0000/2 : return readinputport(1); // Coins
+ case 0x0002/2 : return readinputport(2) +
+ (read_shift()<<1); // Buttons
+ case 0x0004/2 : return readinputport(3); // Motor Limit Switches
+ case 0x0006/2 : return readinputport(4); // DSW 1 & 2
+
+ case 0x0010/2 :
+ switch (cischeat_ip_select & 0x3)
+ {
+ case 0 : return readinputport(6); // Driving Wheel
+ case 1 : return ~0; // Cockpit: Up / Down Position?
+ case 2 : return ~0; // Cockpit: Left / Right Position?
+ default: return ~0;
+ }
+
+ case 0x2200/2 : return readinputport(5); // DSW 3 (4 bits)
+ case 0x2300/2 : return soundlatch2_r(0); // From sound cpu
+
+ default: SHOW_READ_ERROR("vreg %04X read!",offset*2);
+ return megasys1_vregs[offset];
+ }
+}
+
+WRITE16_HANDLER( cischeat_vregs_w )
+{
+ UINT16 old_data = megasys1_vregs[offset];
+ UINT16 new_data = COMBINE_DATA(&megasys1_vregs[offset]);
+
+ switch (offset)
+ {
+ case 0x0000/2 : // leds
+ if (ACCESSING_LSB)
+ {
+ coin_counter_w(0,new_data & 0x01);
+ coin_counter_w(1,new_data & 0x02);
+ set_led_status(0,new_data & 0x10); // start button
+ set_led_status(1,new_data & 0x20); // ?
+ }
+ break;
+
+ case 0x0002/2 : // ?? 91/1/91/1 ...
+ break;
+
+ case 0x0004/2 : // motor (seat?)
+ if (ACCESSING_LSB)
+ set_led_status(2, (new_data != old_data) ? 1 : 0);
+ break;
+
+ case 0x0006/2 : // motor (wheel?)
+ break;
+
+ case 0x0010/2 : cischeat_ip_select = new_data; break;
+ case 0x0012/2 : break; // value above + 1
+
+ case 0x2000/2+0 : MEGASYS1_VREG_SCROLL(0,x) break;
+ case 0x2000/2+1 : MEGASYS1_VREG_SCROLL(0,y) break;
+ case 0x2000/2+2 : megasys1_set_vreg_flag(0,new_data);break;
+
+ case 0x2008/2+0 : MEGASYS1_VREG_SCROLL(1,x) break;
+ case 0x2008/2+1 : MEGASYS1_VREG_SCROLL(1,y) break;
+ case 0x2008/2+2 : megasys1_set_vreg_flag(1,new_data);break;
+
+ case 0x2100/2+0 : MEGASYS1_VREG_SCROLL(2,x) break;
+ case 0x2100/2+1 : MEGASYS1_VREG_SCROLL(2,y) break;
+ case 0x2100/2+2 : megasys1_set_vreg_flag(2,new_data);break;
+
+ case 0x2108/2 : break; // ? written with 0 only
+ case 0x2208/2 : break; // watchdog reset
+
+ case 0x2300/2 : /* Sound CPU: reads latch during int 4, and stores command */
+ soundlatch_word_w(0,new_data,0);
+ cpunum_set_input_line(3,4,HOLD_LINE);
+ break;
+
+ /* Not sure about this one.. */
+ case 0x2308/2 : cpunum_set_input_line(1, INPUT_LINE_RESET, (new_data & 2) ? ASSERT_LINE : CLEAR_LINE );
+ cpunum_set_input_line(2, INPUT_LINE_RESET, (new_data & 2) ? ASSERT_LINE : CLEAR_LINE );
+ cpunum_set_input_line(3, INPUT_LINE_RESET, (new_data & 1) ? ASSERT_LINE : CLEAR_LINE );
+ break;
+
+ default: SHOW_WRITE_ERROR("vreg %04X <- %04X",offset*2,data);
+ }
+}
+
+
+
+/**************************************************************************
+ F1 GrandPrix Star
+**************************************************************************/
+
+READ16_HANDLER( f1gpstar_vregs_r )
+{
+ switch (offset)
+ {
+ case 0x0000/2 : // DSW 1&2: coinage changes with Country
+ {
+ int val = readinputport(1);
+ if (val & 0x0200) return readinputport(6) | val; // JP, US
+ else return readinputport(7) | val; // UK, FR
+ }
+
+// case 0x0002/2 : return 0xFFFF;
+ case 0x0004/2 : return readinputport(2) +
+ (read_shift()<<5); // Buttons
+
+ case 0x0006/2 : return readinputport(3); // ? Read at boot only
+ case 0x0008/2 : return soundlatch2_r(0); // From sound cpu
+
+ case 0x000c/2 : return readinputport(4); // DSW 3
+
+ case 0x0010/2 : // Accel + Driving Wheel
+ return (read_accelerator()&0xff) + ((readinputport(5)&0xff)<<8);
+
+ default: SHOW_READ_ERROR("vreg %04X read!",offset*2);
+ return megasys1_vregs[offset];
+ }
+}
+
+READ16_HANDLER( f1gpstr2_vregs_r )
+{
+ if ((offset >= 0x1000/2) && (offset < 0x2000/2))
+ return megasys1_vregs[offset];
+
+ switch (offset)
+ {
+ case 0x0018/2 :
+ return (f1gpstr2_ioready[0]&1) ? 0xff : 0xf0;
+
+ default:
+ return f1gpstar_vregs_r(offset,mem_mask);
+ }
+}
+
+/**************************************************************************
+ Wild Pilot
+**************************************************************************/
+
+READ16_HANDLER( wildplt_vregs_r )
+{
+ if ((offset >= 0x1000/2) && (offset < 0x2000/2))
+ return megasys1_vregs[offset];
+
+ switch (offset)
+ {
+ case 0x0000/2 : return readinputport(0); // DSW 1 & 2
+
+ case 0x0004/2 : return readinputport(1); // Buttons
+
+ case 0x0008/2 : return soundlatch2_r(0); // From sound cpu
+
+ case 0x0010/2 : // X, Y
+ return readinputport(2) | (readinputport(3)<<8);
+
+ case 0x0018/2 :
+ return (f1gpstr2_ioready[0]&1) ? 0xff : 0xf0;
+
+ default: SHOW_READ_ERROR("vreg %04X read!",offset*2);
+ return megasys1_vregs[offset];
+ }
+}
+
+
+WRITE16_HANDLER( f1gpstar_vregs_w )
+{
+// UINT16 old_data = megasys1_vregs[offset];
+ UINT16 new_data = COMBINE_DATA(&megasys1_vregs[offset]);
+
+ switch (offset)
+ {
+/*
+CPU #0 PC 00234A : Warning, vreg 0000 <- 0000
+CPU #0 PC 002350 : Warning, vreg 0002 <- 0000
+CPU #0 PC 00235C : Warning, vreg 0006 <- 0000
+*/
+ // "shudder" motors, leds
+ case 0x0004/2 :
+ if (ACCESSING_LSB)
+ {
+ coin_counter_w(0,new_data & 0x01);
+ coin_counter_w(1,new_data & 0x02);
+ set_led_status(0,new_data & 0x04); // start button
+ set_led_status(1,new_data & 0x20); // ?
+ // wheel | seat motor
+ set_led_status(2, ((new_data >> 3) | (new_data >> 4)) & 1 );
+ }
+ break;
+ case 0x0014/2 : break;
+
+ /* Usually written in sequence, but not always */
+ case 0x0008/2 : soundlatch_word_w(0,new_data,0); break;
+ case 0x0018/2 : cpunum_set_input_line(3,4,HOLD_LINE); break;
+
+ case 0x0010/2 : break;
+
+ case 0x2000/2+0 : MEGASYS1_VREG_SCROLL(0,x) break;
+ case 0x2000/2+1 : MEGASYS1_VREG_SCROLL(0,y) break;
+ case 0x2000/2+2 : megasys1_set_vreg_flag(0,new_data);break;
+
+ case 0x2008/2+0 : MEGASYS1_VREG_SCROLL(1,x) break;
+ case 0x2008/2+1 : MEGASYS1_VREG_SCROLL(1,y) break;
+ case 0x2008/2+2 : megasys1_set_vreg_flag(1,new_data);break;
+
+ case 0x2100/2+0 : MEGASYS1_VREG_SCROLL(2,x) break;
+ case 0x2100/2+1 : MEGASYS1_VREG_SCROLL(2,y) break;
+ case 0x2100/2+2 : megasys1_set_vreg_flag(2,new_data);break;
+
+ case 0x2108/2 : break; // ? written with 0 only
+ case 0x2208/2 : break; // watchdog reset
+
+ /* Not sure about this one. Values: $10 then 0, $7 then 0 */
+ case 0x2308/2 : cpunum_set_input_line(1, INPUT_LINE_RESET, (new_data & 1) ? ASSERT_LINE : CLEAR_LINE );
+ cpunum_set_input_line(2, INPUT_LINE_RESET, (new_data & 2) ? ASSERT_LINE : CLEAR_LINE );
+ cpunum_set_input_line(3, INPUT_LINE_RESET, (new_data & 4) ? ASSERT_LINE : CLEAR_LINE );
+ break;
+
+ default: SHOW_WRITE_ERROR("vreg %04X <- %04X",offset*2,data);
+ }
+}
+
+WRITE16_HANDLER( f1gpstr2_vregs_w )
+{
+// UINT16 old_data = megasys1_vregs[offset];
+ UINT16 new_data = COMBINE_DATA(&megasys1_vregs[offset]);
+
+ if ((offset >= 0x1000/2) && (offset < 0x2000/2))
+ return;
+
+ switch (offset)
+ {
+ case 0x0000/2 :
+ if (ACCESSING_LSB)
+ {
+ cpunum_set_input_line(4,4,(new_data & 4)?ASSERT_LINE:CLEAR_LINE);
+ cpunum_set_input_line(4,2,(new_data & 2)?ASSERT_LINE:CLEAR_LINE);
+ }
+ break;
+
+ default:
+ f1gpstar_vregs_w(offset,data,mem_mask);
+ }
+}
+
+/**************************************************************************
+ Scud Hammer
+**************************************************************************/
+
+WRITE16_HANDLER( scudhamm_vregs_w )
+{
+// int old_data = megasys1_vregs[offset];
+ int new_data = COMBINE_DATA(&megasys1_vregs[offset]);
+
+ switch (offset)
+ {
+ case 0x000/2+0 : MEGASYS1_VREG_SCROLL(0,x) break;
+ case 0x000/2+1 : MEGASYS1_VREG_SCROLL(0,y) break;
+ case 0x000/2+2 : megasys1_set_vreg_flag(0,new_data);break;
+
+// UNUSED LAYER
+ case 0x008/2+0 :
+ case 0x008/2+1 :
+ case 0x008/2+2 :
+ break;
+
+ case 0x100/2+0 : MEGASYS1_VREG_SCROLL(2,x) break;
+ case 0x100/2+1 : MEGASYS1_VREG_SCROLL(2,y) break;
+ case 0x100/2+2 : megasys1_set_vreg_flag(2,new_data);break;
+
+ case 0x208/2 : watchdog_reset_w(0,0); break;
+
+ default: SHOW_WRITE_ERROR("vreg %04X <- %04X",offset*2,data);
+ }
+}
+
+
+
+
+/***************************************************************************
+
+
+ Road Drawing
+
+
+***************************************************************************/
+
+/* horizontal size of 1 line and 1 tile of the road */
+#define X_SIZE (1024)
+#define TILE_SIZE (64)
+
+
+/**************************************************************************
+
+ Cisco Heat road format
+
+
+ Offset: Bits: Value:
+
+ 00.w Code
+
+ 02.w X Scroll
+
+ 04.w fedc ---- ---- ---- unused?
+ ---- ba98 ---- ---- Priority
+ ---- ---- 76-- ---- unused?
+ ---- ---- --54 3210 Color
+
+ 06.w Unused
+
+**************************************************************************/
+
+/* Draw the road in the given bitmap. The priority1 and priority2 parameters
+ specify the range of lines to draw */
+
+static void cischeat_draw_road(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int road_num, int priority1, int priority2, int transparency)
+{
+ int curr_code,sx,sy;
+ int min_priority, max_priority;
+
+ rectangle rect = *cliprect;
+ gfx_element *gfx = machine->gfx[(road_num & 1)?5:4];
+
+ UINT16 *roadram = cischeat_roadram[road_num & 1];
+
+ int min_y = rect.min_y;
+ int max_y = rect.max_y;
+
+ int max_x = rect.max_x;
+
+ if (priority1 < priority2) { min_priority = priority1; max_priority = priority2; }
+ else { min_priority = priority2; max_priority = priority1; }
+
+ /* Move the priority values in place */
+ min_priority = (min_priority & 7) * 0x100;
+ max_priority = (max_priority & 7) * 0x100;
+
+ /* Let's draw from the top to the bottom of the visible screen */
+ for (sy = min_y ; sy <= max_y ; sy ++)
+ {
+ int code = roadram[ sy * 4 + 0 ];
+ int xscroll = roadram[ sy * 4 + 1 ];
+ int attr = roadram[ sy * 4 + 2 ];
+
+ /* high byte is a priority information */
+ if ( ((attr & 0x700) < min_priority) || ((attr & 0x700) > max_priority) )
+ continue;
+
+ /* line number converted to tile number (each tile is TILE_SIZE x 1) */
+ code = code * (X_SIZE/TILE_SIZE);
+
+ xscroll %= X_SIZE;
+ curr_code = code + xscroll/TILE_SIZE;
+
+ for (sx = -(xscroll%TILE_SIZE) ; sx <= max_x ; sx +=TILE_SIZE)
+ {
+ drawgfx(bitmap,gfx,
+ curr_code++,
+ attr,
+ 0,0,
+ sx,sy,
+ &rect,
+ transparency,15);
+
+ /* wrap around */
+ if (curr_code%(X_SIZE/TILE_SIZE)==0) curr_code = code;
+ }
+ }
+
+}
+
+
+
+/**************************************************************************
+
+ F1 GrandPrix Star road format
+
+ Offset: Bits: Value:
+
+ 00.w fedc ---- ---- ---- Priority
+ ---- ba98 7654 3210 X Scroll (After Zoom)
+
+ 02.w fedc ba-- ---- ---- unused?
+ ---- --98 7654 3210 X Zoom
+
+ 04.w fe-- ---- ---- ---- unused?
+ --dc ba98 ---- ---- Color
+ ---- ---- 7654 3210 ?
+
+ 06.w Code
+
+
+ Imagine an "empty" line, 2 * X_SIZE wide, with the gfx from
+ the ROM - whose original size is X_SIZE - in the middle.
+
+ Zooming acts on this latter and can shrink it to 1 pixel or
+ widen it to 2 * X_SIZE, while *keeping it centered* in the
+ empty line. Scrolling acts on the resulting line.
+
+
+**************************************************************************/
+
+/* Draw the road in the given bitmap. The priority1 and priority2 parameters
+ specify the range of lines to draw */
+
+static void f1gpstar_draw_road(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int road_num, int priority1, int priority2, int transparency)
+{
+ int sx,sy;
+ int xstart;
+ int min_priority, max_priority;
+
+ rectangle rect = *cliprect;
+ gfx_element *gfx = machine->gfx[(road_num & 1)?5:4];
+
+ UINT16 *roadram = cischeat_roadram[road_num & 1];
+
+ int min_y = rect.min_y;
+ int max_y = rect.max_y;
+
+ int max_x = rect.max_x << 16; // use fixed point values (16.16), for accuracy
+
+ if (priority1 < priority2) { min_priority = priority1; max_priority = priority2; }
+ else { min_priority = priority2; max_priority = priority1; }
+
+ /* Move the priority values in place */
+ min_priority = (min_priority & 7) * 0x1000;
+ max_priority = (max_priority & 7) * 0x1000;
+
+ /* Let's draw from the top to the bottom of the visible screen */
+ for (sy = min_y ; sy <= max_y ; sy ++)
+ {
+ int xscale, xdim;
+
+ int xscroll = roadram[ sy * 4 + 0 ];
+ int xzoom = roadram[ sy * 4 + 1 ];
+ int attr = roadram[ sy * 4 + 2 ];
+ int code = roadram[ sy * 4 + 3 ];
+
+ /* highest nibble is a priority information */
+ if ( ((xscroll & 0x7000) < min_priority) || ((xscroll & 0x7000) > max_priority) )
+ continue;
+
+ /* zoom code range: 000-3ff scale range: 0.0-2.0 */
+ xscale = ( ((xzoom & 0x3ff)+1) << (16+1) ) / 0x400;
+
+ /* line number converted to tile number (each tile is TILE_SIZE x 1) */
+ code = code * (X_SIZE/TILE_SIZE);
+
+ /* dimension of a tile after zoom */
+ xdim = TILE_SIZE * xscale;
+
+ xscroll %= 2 * X_SIZE;
+
+ xstart = (X_SIZE - xscroll) * 0x10000;
+ xstart -= (X_SIZE * xscale) / 2;
+
+ /* let's approximate to the nearest greater integer value
+ to avoid holes in between tiles */
+ xscale += (1<<16)/TILE_SIZE;
+
+ /* Draw the line */
+ for (sx = xstart ; sx <= max_x ; sx += xdim)
+ {
+ drawgfxzoom(bitmap,gfx,
+ code++,
+ attr >> 8,
+ 0,0,
+ sx / 0x10000, sy,
+ &rect,
+ transparency,15,
+ xscale, 1 << 16);
+
+ /* stop when the end of the line of gfx is reached */
+ if ((code % (X_SIZE/TILE_SIZE)) == 0) break;
+ }
+
+ }
+}
+
+
+/***************************************************************************
+
+ Cisco Heat & F1 GP Star Sprites Drawing
+
+ Offset: Bits: Value:
+
+ 00 fed- ---- ---- ---- unused?
+ ---c ---- ---- ---- Don't display this sprite
+ ---- ba98 ---- ---- unused?
+ ---- ---- 7654 ---- Number of tiles along Y, minus 1 (1-16)
+ ---- ---- ---- 3210 Number of tiles along X, minus 1 (1-16)
+
+ 02/04 fed- ---- ---- ---- unused?
+ ---c ---- ---- ---- Flip X/Y
+ ---- ba9- ---- ---- ? X/Y zoom ?
+ ---- ---8 7654 3210 X/Y zoom
+
+ 06/08 fedc ba-- ---- ---- ? X/Y position ?
+ ---- --98 7654 3210 X/Y position
+
+ 0A 0 ?
+
+ 0C Code
+
+ 0E fed- ---- ---- ---- unused?
+ ---c ---- ---- ---- Use pen 0 as shadow
+ ---- ba98 ---- ---- Priority
+ ---- ---- 7--- ---- unused?
+ ---- ---- -654 3210 Color
+
+***************************************************************************/
+
+#define SHRINK(_org_,_fact_) ( ( ( (_org_) << 16 ) * (_fact_ & 0x01ff) ) / 0x80 )
+
+/* Draw sprites, in the given priority range, to a bitmap.
+
+ Priorities between 0 and 15 cover sprites whose priority nibble
+ is between 0 and 15. Priorities between 0+16 and 15+16 cover
+ sprites whose priority nibble is between 0 and 15 and whose
+ colour code's high bit is set. */
+
+static void cischeat_draw_sprites(running_machine *machine, mame_bitmap *bitmap , const rectangle *cliprect, int priority1, int priority2)
+{
+ int x, sx, flipx, xzoom, xscale, xdim, xnum, xstart, xend, xinc;
+ int y, sy, flipy, yzoom, yscale, ydim, ynum, ystart, yend, yinc;
+ int code, attr, color, size, shadow;
+
+ int min_priority, max_priority, high_sprites;
+
+ UINT16 *source = spriteram16;
+ const UINT16 *finish = source + 0x1000/2;
+
+
+ /* Move the priority values in place */
+ high_sprites = (priority1 >= 16) | (priority2 >= 16);
+ priority1 = (priority1 & 0x0f) * 0x100;
+ priority2 = (priority2 & 0x0f) * 0x100;
+
+ if (priority1 < priority2) { min_priority = priority1; max_priority = priority2; }
+ else { min_priority = priority2; max_priority = priority1; }
+
+ for (; source < finish; source += 0x10/2 )
+ {
+ size = source[ 0 ];
+ if (size & 0x1000) continue;
+
+ /* number of tiles */
+ xnum = ( (size & 0x0f) >> 0 ) + 1;
+ ynum = ( (size & 0xf0) >> 4 ) + 1;
+
+ xzoom = source[ 1 ];
+ yzoom = source[ 2 ];
+ flipx = xzoom & 0x1000;
+ flipy = yzoom & 0x1000;
+
+ sx = source[ 3 ];
+ sy = source[ 4 ];
+ sx = (sx & 0x1ff) - (sx & 0x200);
+ sy = (sy & 0x1ff) - (sy & 0x200);
+
+ /* use fixed point values (16.16), for accuracy */
+ sx <<= 16;
+ sy <<= 16;
+
+ /* dimension of a tile after zoom */
+#ifdef MAME_DEBUG
+ if ( input_code_pressed(KEYCODE_Z) && input_code_pressed(KEYCODE_M) )
+ {
+ xdim = 16 << 16;
+ ydim = 16 << 16;
+ }
+ else
+#endif
+ {
+ xdim = SHRINK(16,xzoom);
+ ydim = SHRINK(16,yzoom);
+ }
+
+ if ( ( (xdim / 0x10000) == 0 ) || ( (ydim / 0x10000) == 0) ) continue;
+
+ /* the y pos passed to the hardware is the that of the last line,
+ we need the y pos of the first line */
+ sy -= (ydim * ynum);
+
+ code = source[ 6 ];
+ attr = source[ 7 ];
+ color = attr & 0x007f;
+ shadow = attr & 0x1000;
+
+ /* high byte is a priority information */
+ if ( ((attr & 0x700) < min_priority) || ((attr & 0x700) > max_priority) )
+ continue;
+
+ if ( high_sprites && !(color & 0x80) )
+ continue;
+
+#ifdef MAME_DEBUG
+if ( (debugsprites) && ( ((attr & 0x0300)>>8) != (debugsprites-1) ) ) { continue; };
+#endif
+
+ xscale = xdim / 16;
+ yscale = ydim / 16;
+
+
+ /* let's approximate to the nearest greater integer value
+ to avoid holes in between tiles */
+ if (xscale & 0xffff) xscale += (1<<16)/16;
+ if (yscale & 0xffff) yscale += (1<<16)/16;
+
+
+ if (flipx) { xstart = xnum-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = xnum; xinc = +1; }
+
+ if (flipy) { ystart = ynum-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = ynum; yinc = +1; }
+
+ for (y = ystart; y != yend; y += yinc)
+ {
+ for (x = xstart; x != xend; x += xinc)
+ {
+ drawgfxzoom(bitmap,machine->gfx[3],
+ code++,
+ color,
+ flipx,flipy,
+ (sx + x * xdim) / 0x10000, (sy + y * ydim) / 0x10000,
+ cliprect,
+ shadow ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,15,
+ xscale, yscale );
+ }
+ }
+#ifdef MAME_DEBUG
+#if 0
+if (input_code_pressed(KEYCODE_X))
+{ /* Display some info on each sprite */
+ sprintf(buf, "%04x",attr);
+ ui_draw_text(buf, sx>>16, sy>>16);
+}
+#endif
+#endif
+ } /* end sprite loop */
+}
+
+
+/***************************************************************************
+
+ Big Run Sprites Drawing
+
+ Offset: Bits: Value:
+
+ 00 fed- ---- ---- ---- unused?
+ ---c ---- ---- ---- Don't display this sprite
+ ---- ba98 ---- ---- unused?
+ ---- ---- 7654 ---- Number of tiles along Y, minus 1 (1-16)
+ ---- ---- ---- 3210 Number of tiles along X, minus 1 (1-16)
+
+ 02 fedc ba98 ---- ---- Y zoom
+ ---- ---- 7654 3210 X zoom
+
+ 04/06 fed- ---- ---- ----
+ ---c ---- ---- ---- X/Y flip
+ ---- ba9- ---- ----
+ ---- ---8 7654 3210 X/Y position (signed)
+
+ 08 ?
+ 0A ?
+
+ 0C Code
+
+ 0E fed- ---- ---- ---- unused?
+ ---c ---- ---- ---- Use pen 0 as shadow
+ ---- ba98 ---- ---- Priority
+ ---- ---- 76-- ---- unused?
+ ---- ---- --54 3210 Color
+
+***************************************************************************/
+
+static void bigrun_draw_sprites(running_machine *machine, mame_bitmap *bitmap , const rectangle *cliprect, int priority1, int priority2)
+{
+ int x, sx, flipx, xzoom, xscale, xdim, xnum, xstart, xend, xinc;
+ int y, sy, flipy, yzoom, yscale, ydim, ynum, ystart, yend, yinc;
+ int code, attr, color, size, shadow;
+
+ int min_priority, max_priority, high_sprites;
+
+ UINT16 *source = spriteram16;
+ const UINT16 *finish = source + 0x1000/2;
+
+ /* Move the priority values in place */
+ high_sprites = (priority1 >= 16) | (priority2 >= 16);
+ priority1 = (priority1 & 0x0f) * 0x100;
+ priority2 = (priority2 & 0x0f) * 0x100;
+
+ if (priority1 < priority2) { min_priority = priority1; max_priority = priority2; }
+ else { min_priority = priority2; max_priority = priority1; }
+
+ for (; source < finish; source += 0x10/2 )
+ {
+ size = source[ 0 ];
+ if (size & 0x1000) continue;
+
+ /* number of tiles */
+ xnum = ( (size & 0x0f) >> 0 ) + 1;
+ ynum = ( (size & 0xf0) >> 4 ) + 1;
+
+ yzoom = (source[ 1 ] >> 8) & 0xff;
+ xzoom = (source[ 1 ] >> 0) & 0xff;
+
+ sx = source[ 2 ];
+ sy = source[ 3 ];
+ flipx = sx & 0x1000;
+ flipy = sy & 0x1000;
+// sx = (sx & 0x1ff) - (sx & 0x200);
+// sy = (sy & 0x1ff) - (sy & 0x200);
+ sx = (sx & 0x0ff) - (sx & 0x100);
+ sy = (sy & 0x0ff) - (sy & 0x100);
+
+ /* use fixed point values (16.16), for accuracy */
+ sx <<= 16;
+ sy <<= 16;
+
+ /* dimension of a tile after zoom */
+#ifdef MAME_DEBUG
+ if ( input_code_pressed(KEYCODE_Z) && input_code_pressed(KEYCODE_M) )
+ {
+ xdim = 16 << 16;
+ ydim = 16 << 16;
+ }
+ else
+#endif
+ {
+ xdim = SHRINK(16,xzoom);
+ ydim = SHRINK(16,yzoom);
+ }
+
+ if ( ( (xdim / 0x10000) == 0 ) || ( (ydim / 0x10000) == 0) ) continue;
+
+// sy -= (ydim * ynum);
+
+ code = source[ 6 ];
+ attr = source[ 7 ];
+ color = attr & 0x007f;
+ shadow = attr & 0x1000;
+
+ /* high byte is a priority information */
+ if ( ((attr & 0x700) < min_priority) || ((attr & 0x700) > max_priority) )
+ continue;
+
+ if ( high_sprites && !(color & 0x80) )
+ continue;
+
+#ifdef MAME_DEBUG
+if ( (debugsprites) && ( ((attr & 0x0300)>>8) != (debugsprites-1) ) ) { continue; };
+#endif
+
+ xscale = xdim / 16;
+ yscale = ydim / 16;
+
+
+ /* let's approximate to the nearest greater integer value
+ to avoid holes in between tiles */
+ if (xscale & 0xffff) xscale += (1<<16)/16;
+ if (yscale & 0xffff) yscale += (1<<16)/16;
+
+
+ if (flipx) { xstart = xnum-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = xnum; xinc = +1; }
+
+ if (flipy) { ystart = ynum-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = ynum; yinc = +1; }
+
+ for (y = ystart; y != yend; y += yinc)
+ {
+ for (x = xstart; x != xend; x += xinc)
+ {
+ drawgfxzoom(bitmap,machine->gfx[3],
+ code++,
+ color,
+ flipx,flipy,
+ (sx + x * xdim) / 0x10000, (sy + y * ydim) / 0x10000,
+ cliprect,
+ shadow ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,15,
+ xscale, yscale );
+ }
+ }
+#ifdef MAME_DEBUG
+#if 0
+if (input_code_pressed(KEYCODE_X))
+{ /* Display some info on each sprite */
+ sprintf(buf, "%04x",attr);
+ ui_draw_text(buf, sx>>16, sy>>16);
+}
+#endif
+#endif
+ } /* end sprite loop */
+}
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+#define CISCHEAT_LAYERSCTRL \
+debugsprites = 0; \
+if ( input_code_pressed(KEYCODE_Z) || input_code_pressed(KEYCODE_X) ) \
+{ \
+ int msk = 0; \
+ if (input_code_pressed(KEYCODE_Q)) { msk |= 0x01;} \
+ if (input_code_pressed(KEYCODE_W)) { msk |= 0x02;} \
+ if (input_code_pressed(KEYCODE_E)) { msk |= 0x04;} \
+ if (input_code_pressed(KEYCODE_A)) { msk |= 0x08; debugsprites = 1;} \
+ if (input_code_pressed(KEYCODE_S)) { msk |= 0x08; debugsprites = 2;} \
+ if (input_code_pressed(KEYCODE_D)) { msk |= 0x08; debugsprites = 3;} \
+ if (input_code_pressed(KEYCODE_F)) { msk |= 0x08; debugsprites = 4;} \
+ if (input_code_pressed(KEYCODE_R)) { msk |= 0x10;} \
+ if (input_code_pressed(KEYCODE_T)) { msk |= 0x20;} \
+ \
+ if (msk != 0) megasys1_active_layers &= msk; \
+} \
+\
+{ \
+ static int show_unknown; \
+ if ( input_code_pressed(KEYCODE_Z) && input_code_pressed_once(KEYCODE_U) ) \
+ show_unknown ^= 1; \
+ if (show_unknown) \
+ popmessage("0:%04X 2:%04X 4:%04X 6:%04X c:%04X", \
+ megasys1_vregs[0],megasys1_vregs[1],megasys1_vregs[2],megasys1_vregs[3],megasys1_vregs[0xc/2] ); \
+}
+
+
+/**************************************************************************
+ Big Run
+**************************************************************************/
+
+VIDEO_UPDATE( bigrun )
+{
+ int i;
+ int megasys1_active_layers1, flag;
+
+#ifdef MAME_DEBUG
+ /* FAKE Videoreg */
+ megasys1_active_layers = megasys1_vregs[0x2400/2];
+ if (megasys1_active_layers == 0) megasys1_active_layers = 0x3f;
+#else
+ megasys1_active_layers = 0x3f;
+#endif
+
+ megasys1_active_layers1 = megasys1_active_layers;
+
+#ifdef MAME_DEBUG
+ CISCHEAT_LAYERSCTRL
+#endif
+
+ cischeat_tmap_SET_SCROLL(0)
+ cischeat_tmap_SET_SCROLL(1)
+ cischeat_tmap_SET_SCROLL(2)
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ for (i = 7; i >= 4; i--)
+ { /* bitmap, road, min_priority, max_priority, transparency */
+ if (megasys1_active_layers & 0x10) cischeat_draw_road(machine,bitmap,cliprect,0,i,i,TRANSPARENCY_NONE);
+ if (megasys1_active_layers & 0x20) cischeat_draw_road(machine,bitmap,cliprect,1,i,i,TRANSPARENCY_PEN);
+ }
+
+ flag = 0;
+ cischeat_tmap_DRAW(0)
+ cischeat_tmap_DRAW(1)
+
+ for (i = 3; i >= 0; i--)
+ { /* bitmap, road, min_priority, max_priority, transparency */
+ if (megasys1_active_layers & 0x10) cischeat_draw_road(machine,bitmap,cliprect,0,i,i,TRANSPARENCY_PEN);
+ if (megasys1_active_layers & 0x20) cischeat_draw_road(machine,bitmap,cliprect,1,i,i,TRANSPARENCY_PEN);
+ }
+
+ if (megasys1_active_layers & 0x08) bigrun_draw_sprites(machine,bitmap,cliprect,15,0);
+
+ cischeat_tmap_DRAW(2)
+
+ megasys1_active_layers = megasys1_active_layers1;
+ return 0;
+}
+
+
+/**************************************************************************
+ Cisco Heat
+**************************************************************************/
+
+VIDEO_UPDATE( cischeat )
+{
+ int megasys1_active_layers1, flag;
+
+#ifdef MAME_DEBUG
+ /* FAKE Videoreg */
+ megasys1_active_layers = megasys1_vregs[0x2400/2];
+ if (megasys1_active_layers == 0) megasys1_active_layers = 0x3f;
+#else
+ megasys1_active_layers = 0x3f;
+#endif
+
+ megasys1_active_layers1 = megasys1_active_layers;
+
+#ifdef MAME_DEBUG
+ CISCHEAT_LAYERSCTRL
+#endif
+
+ cischeat_tmap_SET_SCROLL(0)
+ cischeat_tmap_SET_SCROLL(1)
+ cischeat_tmap_SET_SCROLL(2)
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ /* bitmap, road, priority, transparency */
+ if (megasys1_active_layers & 0x10) cischeat_draw_road(machine,bitmap,cliprect,0,7,5,TRANSPARENCY_NONE);
+ if (megasys1_active_layers & 0x20) cischeat_draw_road(machine,bitmap,cliprect,1,7,5,TRANSPARENCY_PEN);
+
+ flag = 0;
+ cischeat_tmap_DRAW(0)
+// else fillbitmap(bitmap,machine->pens[0],cliprect);
+ cischeat_tmap_DRAW(1)
+
+ if (megasys1_active_layers & 0x08) cischeat_draw_sprites(machine,bitmap,cliprect,15,3);
+ if (megasys1_active_layers & 0x10) cischeat_draw_road(machine,bitmap,cliprect,0,4,1,TRANSPARENCY_PEN);
+ if (megasys1_active_layers & 0x20) cischeat_draw_road(machine,bitmap,cliprect,1,4,1,TRANSPARENCY_PEN);
+ if (megasys1_active_layers & 0x08) cischeat_draw_sprites(machine,bitmap,cliprect,2,2);
+ if (megasys1_active_layers & 0x10) cischeat_draw_road(machine,bitmap,cliprect,0,0,0,TRANSPARENCY_PEN);
+ if (megasys1_active_layers & 0x20) cischeat_draw_road(machine,bitmap,cliprect,1,0,0,TRANSPARENCY_PEN);
+ if (megasys1_active_layers & 0x08) cischeat_draw_sprites(machine,bitmap,cliprect,1,0);
+ cischeat_tmap_DRAW(2)
+
+ /* for the map screen */
+ if (megasys1_active_layers & 0x08) cischeat_draw_sprites(machine,bitmap,cliprect,0+16,0+16);
+
+
+ megasys1_active_layers = megasys1_active_layers1;
+ return 0;
+}
+
+
+
+/**************************************************************************
+ F1 GrandPrix Star
+**************************************************************************/
+
+VIDEO_UPDATE( f1gpstar )
+{
+ int megasys1_active_layers1, flag;
+
+#ifdef MAME_DEBUG
+ /* FAKE Videoreg */
+ megasys1_active_layers = megasys1_vregs[0x2400/2];
+ if (megasys1_active_layers == 0) megasys1_active_layers = 0x3f;
+#else
+ megasys1_active_layers = 0x3f;
+#endif
+
+ megasys1_active_layers1 = megasys1_active_layers;
+
+#ifdef MAME_DEBUG
+ CISCHEAT_LAYERSCTRL
+#endif
+
+ cischeat_tmap_SET_SCROLL(0)
+ cischeat_tmap_SET_SCROLL(1)
+ cischeat_tmap_SET_SCROLL(2)
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+/* 1: clouds 5, grad 7, road 0 2: clouds 5, grad 7, road 0, tunnel roof 0 */
+
+ /* road 1!! 0!! */ /* bitmap, road, min_priority, max_priority, transparency */
+ if (megasys1_active_layers & 0x20) f1gpstar_draw_road(machine,bitmap,cliprect,1,6,7,TRANSPARENCY_PEN);
+ if (megasys1_active_layers & 0x10) f1gpstar_draw_road(machine,bitmap,cliprect,0,6,7,TRANSPARENCY_PEN);
+
+ flag = 0;
+ cischeat_tmap_DRAW(0)
+// else fillbitmap(bitmap,machine->pens[0],cliprect);
+ cischeat_tmap_DRAW(1)
+
+ /* road 1!! 0!! */ /* bitmap, road, min_priority, max_priority, transparency */
+ if (megasys1_active_layers & 0x20) f1gpstar_draw_road(machine,bitmap,cliprect,1,1,5,TRANSPARENCY_PEN);
+ if (megasys1_active_layers & 0x10) f1gpstar_draw_road(machine,bitmap,cliprect,0,1,5,TRANSPARENCY_PEN);
+
+ if (megasys1_active_layers & 0x08) cischeat_draw_sprites(machine,bitmap,cliprect,15,2);
+
+ /* road 1!! 0!! */ /* bitmap, road, min_priority, max_priority, transparency */
+ if (megasys1_active_layers & 0x20) f1gpstar_draw_road(machine,bitmap,cliprect,1,0,0,TRANSPARENCY_PEN);
+ if (megasys1_active_layers & 0x10) f1gpstar_draw_road(machine,bitmap,cliprect,0,0,0,TRANSPARENCY_PEN);
+
+ if (megasys1_active_layers & 0x08) cischeat_draw_sprites(machine,bitmap,cliprect,1,1);
+ cischeat_tmap_DRAW(2)
+ if (megasys1_active_layers & 0x08) cischeat_draw_sprites(machine,bitmap,cliprect,0,0);
+
+
+ megasys1_active_layers = megasys1_active_layers1;
+ return 0;
+}
+
+
+
+/**************************************************************************
+ Scud Hammer
+**************************************************************************/
+
+extern UINT16 scudhamm_motor_command;
+
+ READ16_HANDLER( scudhamm_motor_pos_r );
+ READ16_HANDLER( scudhamm_motor_status_r );
+ READ16_HANDLER( scudhamm_analog_r );
+
+VIDEO_UPDATE( scudhamm )
+{
+ int megasys1_active_layers1, flag;
+ megasys1_active_layers = 0x0d;
+ megasys1_active_layers1 = megasys1_active_layers;
+
+#ifdef MAME_DEBUG
+debugsprites = 0;
+if ( input_code_pressed(KEYCODE_Z) || input_code_pressed(KEYCODE_X) )
+{
+ int msk = 0;
+ if (input_code_pressed(KEYCODE_Q)) { msk |= 0x1;}
+ if (input_code_pressed(KEYCODE_W)) { msk |= 0x2;}
+ if (input_code_pressed(KEYCODE_E)) { msk |= 0x4;}
+ if (input_code_pressed(KEYCODE_A)) { msk |= 0x8; debugsprites = 1;}
+ if (input_code_pressed(KEYCODE_S)) { msk |= 0x8; debugsprites = 2;}
+ if (input_code_pressed(KEYCODE_D)) { msk |= 0x8; debugsprites = 3;}
+ if (input_code_pressed(KEYCODE_F)) { msk |= 0x8; debugsprites = 4;}
+
+ if (msk != 0) megasys1_active_layers &= msk;
+#if 1
+ popmessage("Cmd: %04X Pos:%04X Lim:%04X Inp:%04X",
+ scudhamm_motor_command,
+ scudhamm_motor_pos_r(0,0),
+ scudhamm_motor_status_r(0,0),
+ scudhamm_analog_r(0,0) );
+#endif
+
+}
+#endif
+
+ cischeat_tmap_SET_SCROLL(0)
+// cischeat_tmap_SET_SCROLL(1)
+ cischeat_tmap_SET_SCROLL(2)
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ flag = 0;
+ cischeat_tmap_DRAW(0)
+// else fillbitmap(bitmap,machine->pens[0],cliprect);
+// cischeat_tmap_DRAW(1)
+ if (megasys1_active_layers & 0x08) cischeat_draw_sprites(machine,bitmap,cliprect,0,15);
+ cischeat_tmap_DRAW(2)
+
+ megasys1_active_layers = megasys1_active_layers1;
+ return 0;
+}
+
diff --git a/src/mame/video/citycon.c b/src/mame/video/citycon.c
new file mode 100644
index 00000000000..e37b0c8be7e
--- /dev/null
+++ b/src/mame/video/citycon.c
@@ -0,0 +1,170 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+UINT8 *citycon_videoram;
+UINT8 *citycon_linecolor;
+UINT8 *citycon_scroll;
+
+static int bg_image;
+static tilemap *bg_tilemap,*fg_tilemap;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( citycon_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x60) << 5);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ SET_TILE_INFO(
+ 0,
+ citycon_videoram[tile_index],
+ (tile_index & 0x03e0) >> 5, /* color depends on scanline only */
+ 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 *rom = memory_region(REGION_GFX4);
+ int code = rom[0x1000 * bg_image + tile_index];
+ SET_TILE_INFO(
+ 3 + bg_image,
+ code,
+ rom[0xc000 + 0x100 * bg_image + code],
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( citycon )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info,citycon_scan,TILEMAP_TYPE_PEN,8,8,128,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,citycon_scan,TILEMAP_TYPE_PEN, 8,8,128,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_scroll_rows(fg_tilemap,32);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( citycon_videoram_w )
+{
+ citycon_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+
+WRITE8_HANDLER( citycon_linecolor_w )
+{
+ citycon_linecolor[offset] = data;
+}
+
+
+WRITE8_HANDLER( citycon_background_w )
+{
+ /* bits 4-7 control the background image */
+ if (bg_image != (data >> 4))
+ {
+ bg_image = (data >> 4);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ /* bit 0 flips screen */
+ /* it is also used to multiplex player 1 and player 2 controls */
+ flip_screen_set(data & 0x01);
+
+ /* bits 1-3 are unknown */
+// if ((data & 0x0e) != 0) logerror("background register = %02x\n",data);
+}
+
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size-4;offs >= 0;offs -= 4)
+ {
+ int sx,sy,flipx;
+
+
+ sx = spriteram[offs + 3];
+ sy = 239 - spriteram[offs];
+ flipx = ~spriteram[offs + 2] & 0x10;
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 238 - sy;
+ flipx = !flipx;
+ }
+
+ drawgfx(bitmap,machine->gfx[spriteram[offs + 1] & 0x80 ? 2 : 1],
+ spriteram[offs + 1] & 0x7f,
+ spriteram[offs + 2] & 0x0f,
+ flipx,flip_screen,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+INLINE void changecolor_RRRRGGGGBBBBxxxx(int color,int indx)
+{
+ int data = paletteram[2*indx | 1] | (paletteram[2*indx] << 8);
+ palette_set_color_rgb(Machine,color,pal4bit(data >> 12),pal4bit(data >> 8),pal4bit(data >> 4));
+}
+
+VIDEO_UPDATE( citycon )
+{
+ int offs,scroll;
+
+
+ /* Update the virtual palette to support text color code changing on every scanline. */
+ for (offs = 0;offs < 256;offs++)
+ {
+ int indx = citycon_linecolor[offs];
+ int i;
+
+ for (i = 0;i < 4;i++)
+ changecolor_RRRRGGGGBBBBxxxx(640 + 4*offs + i,512 + 4*indx + i);
+ }
+
+
+ scroll = citycon_scroll[0]*256 + citycon_scroll[1];
+ tilemap_set_scrollx(bg_tilemap,0,scroll >> 1);
+ for (offs = 6;offs < 32;offs++)
+ tilemap_set_scrollx(fg_tilemap,offs,scroll);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/cloak.c b/src/mame/video/cloak.c
new file mode 100644
index 00000000000..29e7c66d5af
--- /dev/null
+++ b/src/mame/video/cloak.c
@@ -0,0 +1,231 @@
+/***************************************************************************
+
+ Atari Cloak & Dagger hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "cloak.h"
+
+static mame_bitmap *tmpbitmap2;
+static UINT8 x,y,bmap;
+static UINT8 *tmpvideoram,*tmpvideoram2;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ CLOAK & DAGGER uses RAM to dynamically
+ create the palette. The resolution is 9 bit (3 bits per gun). The palette
+ contains 64 entries, but it is accessed through a memory windows 128 bytes
+ long: writing to the first 64 bytes sets the msb of the red component to 0,
+ while writing to the last 64 bytes sets it to 1.
+
+ Colors 0-15 Character mapped graphics
+ Colors 16-31 Bitmapped graphics (maybe 8 colors per bitmap?)
+ Colors 32-47 Sprites
+ Colors 48-63 not used
+
+ These are the exact resistor values from the schematics:
+
+ bit 8 -- diode |< -- pullup 1 kohm -- 2.2 kohm resistor -- pulldown 100 pf -- RED
+ -- diode |< -- pullup 1 kohm -- 4.7 kohm resistor -- pulldown 100 pf -- RED
+ -- diode |< -- pullup 1 kohm -- 10 kohm resistor -- pulldown 100 pf -- RED
+ -- diode |< -- pullup 1 kohm -- 2.2 kohm resistor -- pulldown 100 pf -- GREEN
+ -- diode |< -- pullup 1 kohm -- 4.7 kohm resistor -- pulldown 100 pf -- GREEN
+ -- diode |< -- pullup 1 kohm -- 10 kohm resistor -- pulldown 100 pf -- GREEN
+ -- diode |< -- pullup 1 kohm -- 2.2 kohm resistor -- pulldown 100 pf -- BLUE
+ -- diode |< -- pullup 1 kohm -- 4.7 kohm resistor -- pulldown 100 pf -- BLUE
+ bit 0 -- diode |< -- pullup 1 kohm -- 10 kohm resistor -- pulldown 100 pf -- BLUE
+
+***************************************************************************/
+WRITE8_HANDLER( cloak_paletteram_w )
+{
+ int r,g,b;
+ int bit0,bit1,bit2;
+
+ /* a write to offset 64-127 means to set the msb of the red component */
+ int color = data | ((offset & 0x40) << 2);
+
+ r = (~color & 0x1c0) >> 6;
+ g = (~color & 0x038) >> 3;
+ b = (~color & 0x007);
+
+ // the following is WRONG! fix it
+
+ bit0 = (r >> 0) & 0x01;
+ bit1 = (r >> 1) & 0x01;
+ bit2 = (r >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = (g >> 0) & 0x01;
+ bit1 = (g >> 1) & 0x01;
+ bit2 = (g >> 2) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = (b >> 0) & 0x01;
+ bit1 = (b >> 1) & 0x01;
+ bit2 = (b >> 2) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(Machine,offset & 0x3f,MAKE_RGB(r,g,b));
+}
+
+WRITE8_HANDLER( cloak_clearbmp_w )
+{
+ bmap = data & 0x01;
+
+ if (data & 0x02) /* clear */
+ {
+ if (bmap)
+ {
+ fillbitmap(tmpbitmap, Machine->pens[16], &Machine->screen[0].visarea);
+ memset(tmpvideoram, 0, 256*256);
+ }
+ else
+ {
+ fillbitmap(tmpbitmap2, Machine->pens[16], &Machine->screen[0].visarea);
+ memset(tmpvideoram2, 0, 256*256);
+ }
+ }
+}
+
+static void adjust_xy(int offset)
+{
+ switch(offset)
+ {
+ case 0x00: x--; y++; break;
+ case 0x01: y--; break;
+ case 0x02: x--; break;
+ case 0x04: x++; y++; break;
+ case 0x05: y++; break;
+ case 0x06: x++; break;
+ }
+}
+
+READ8_HANDLER( graph_processor_r )
+{
+ int ret;
+
+ if (bmap)
+ {
+ ret = tmpvideoram2[y * 256 + x];
+ }
+ else
+ {
+ ret = tmpvideoram[y * 256 + x];
+ }
+
+ adjust_xy(offset);
+
+ return ret;
+}
+
+WRITE8_HANDLER( graph_processor_w )
+{
+ int color;
+
+ switch (offset)
+ {
+ case 0x03: x = data; break;
+ case 0x07: y = data; break;
+ default:
+ color = data & 0x07;
+
+ if (bmap)
+ {
+ *BITMAP_ADDR16(tmpbitmap, y, (x-6)&0xff) = Machine->pens[16 + color];
+ tmpvideoram[y*256+x] = color;
+ }
+ else
+ {
+ *BITMAP_ADDR16(tmpbitmap2, y, (x-6)&0xff) = Machine->pens[16 + color];
+ tmpvideoram2[y*256+x] = color;
+ }
+
+ adjust_xy(offset);
+ break;
+ }
+}
+
+WRITE8_HANDLER( cloak_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( cloak_flipscreen_w )
+{
+ flip_screen_set(data & 0x80);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index];
+
+ SET_TILE_INFO(0, code, 0, 0);
+}
+
+static void refresh_bitmaps(void)
+{
+ int lx,ly;
+
+ for (ly = 0; ly < 256; ly++)
+ {
+ for (lx = 0; lx < 256; lx++)
+ {
+ *BITMAP_ADDR16(tmpbitmap, ly, (lx-6)&0xff) = Machine->pens[16 + tmpvideoram[ly*256+lx]];
+ *BITMAP_ADDR16(tmpbitmap2, ly, (lx-6)&0xff) = Machine->pens[16 + tmpvideoram2[ly*256+lx]];
+ }
+ }
+}
+
+VIDEO_START( cloak )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tmpbitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ tmpbitmap2 = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ tmpvideoram = auto_malloc(256*256);
+ tmpvideoram2 = auto_malloc(256*256);
+
+ state_save_register_global(x);
+ state_save_register_global(y);
+ state_save_register_global(bmap);
+ state_save_register_global_pointer(tmpvideoram, 256*256);
+ state_save_register_global_pointer(tmpvideoram2, 256*256);
+ state_save_register_func_postload(refresh_bitmaps);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = (spriteram_size / 4) - 1; offs >= 0; offs--)
+ {
+ int code = spriteram[offs + 64] & 0x7f;
+ int flipx = spriteram[offs + 64] & 0x80;
+ int flipy = 0;
+ int sx = spriteram[offs + 192];
+ int sy = 240 - spriteram[offs];
+
+ if (flip_screen)
+ {
+ sx -= 9;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1], code, 0, flipx, flipy,
+ sx, sy, cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( cloak )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ copybitmap(bitmap, (bmap ? tmpbitmap2 : tmpbitmap),flip_screen,flip_screen,0,0,cliprect,TRANSPARENCY_COLOR,16);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/cloud9.c b/src/mame/video/cloud9.c
new file mode 100644
index 00000000000..239c140bd7d
--- /dev/null
+++ b/src/mame/video/cloud9.c
@@ -0,0 +1,332 @@
+/***************************************************************************
+
+ Atari Cloud 9 (prototype) hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "cloud9.h"
+#include "video/resnet.h"
+
+
+/*************************************
+ *
+ * Globals
+ *
+ *************************************/
+
+static double rweights[3], gweights[3], bweights[3];
+static mame_bitmap *spritebitmap;
+
+static UINT8 video_control[8];
+static UINT8 bitmode_addr[2];
+
+static const UINT8 *syncprom;
+static const UINT8 *wpprom;
+static const UINT8 *priprom;
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( cloud9 )
+{
+ static const int resistances[3] = { 22000, 10000, 4700 };
+
+ /* allocate second bank of videoram */
+ videoram = auto_malloc(0x8000);
+ memory_set_bankptr(1, videoram);
+
+ /* get pointers to our PROMs */
+ syncprom = memory_region(REGION_PROMS) + 0x000;
+ wpprom = memory_region(REGION_PROMS) + 0x200;
+ priprom = memory_region(REGION_PROMS) + 0x300;
+
+ /* compute the color output resistor weights at startup */
+ compute_resistor_weights(0, 255, -1.0,
+ 3, resistances, rweights, 1000, 0,
+ 3, resistances, gweights, 1000, 0,
+ 3, resistances, bweights, 1000, 0);
+
+ /* allocate a bitmap for drawing sprites */
+ spritebitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ /* register for savestates */
+ state_save_register_global_pointer(videoram, 0x8000);
+ state_save_register_global_array(video_control);
+ state_save_register_global_array(bitmode_addr);
+}
+
+
+
+/*************************************
+ *
+ * Video control registers
+ *
+ *************************************/
+
+WRITE8_HANDLER( cloud9_video_control_w )
+{
+ /* only D7 matters */
+ video_control[offset] = (data >> 7) & 1;
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM accesses
+ *
+ *************************************/
+
+WRITE8_HANDLER( cloud9_paletteram_w )
+{
+ int bit0, bit1, bit2;
+ int r, g, b;
+
+ /* extract the raw RGB bits */
+ r = (data & 0xe0) >> 5;
+ g = (data & 0x1c) >> 2;
+ b = ((data & 0x03) << 1) | ((offset & 0x40) >> 6);
+
+ /* red component (inverted) */
+ bit0 = (~r >> 0) & 0x01;
+ bit1 = (~r >> 1) & 0x01;
+ bit2 = (~r >> 2) & 0x01;
+ r = combine_3_weights(rweights, bit0, bit1, bit2);
+
+ /* green component (inverted) */
+ bit0 = (~g >> 0) & 0x01;
+ bit1 = (~g >> 1) & 0x01;
+ bit2 = (~g >> 2) & 0x01;
+ g = combine_3_weights(gweights, bit0, bit1, bit2);
+
+ /* blue component (inverted) */
+ bit0 = (~b >> 0) & 0x01;
+ bit1 = (~b >> 1) & 0x01;
+ bit2 = (~b >> 2) & 0x01;
+ b = combine_3_weights(bweights, bit0, bit1, bit2);
+
+ palette_set_color(Machine, offset & 0x3f, MAKE_RGB(r, g, b));
+}
+
+
+
+/*************************************
+ *
+ * Video RAM access via the write
+ * protect PROM
+ *
+ *************************************/
+
+INLINE void cloud9_write_vram(UINT16 addr, UINT8 data, UINT8 bitmd, UINT8 pixba)
+{
+ UINT8 *dest = &videoram[0x0000 | (addr & 0x3fff)];
+ UINT8 *dest2 = &videoram[0x4000 | (addr & 0x3fff)];
+ UINT8 promaddr = 0;
+ UINT8 wpbits;
+
+ /*
+ Inputs to the write-protect PROM:
+
+ Bit 7 = BITMD
+ Bit 6 = video_control[4]
+ Bit 5 = video_control[6]
+ Bit 4 = 1 if (A15-A12 != 4)
+ Bit 3 = !(A13 | A12 | A11)
+ Bit 2 = A9 & A10
+ Bit 1 = PIXB
+ Bit 0 = PIXA
+ */
+ promaddr |= bitmd << 7;
+ promaddr |= video_control[4] << 6;
+ promaddr |= video_control[6] << 5;
+ promaddr |= ((addr & 0xf000) != 0x4000) << 4;
+ promaddr |= ((addr & 0x3800) == 0x0000) << 3;
+ promaddr |= ((addr & 0x0600) == 0x0600) << 2;
+ promaddr |= (pixba << 0);
+
+ /* look up the PROM result */
+ wpbits = wpprom[promaddr];
+
+ /* write to the appropriate parts of VRAM depending on the result */
+ if (!(wpbits & 1))
+ dest2[0] = (dest2[0] & 0x0f) | (data & 0xf0);
+ if (!(wpbits & 2))
+ dest2[0] = (dest2[0] & 0xf0) | (data & 0x0f);
+ if (!(wpbits & 4))
+ dest[0] = (dest[0] & 0x0f) | (data & 0xf0);
+ if (!(wpbits & 8))
+ dest[0] = (dest[0] & 0xf0) | (data & 0x0f);
+}
+
+
+
+/*************************************
+ *
+ * Autoincrement control for bit mode
+ *
+ *************************************/
+
+INLINE void bitmode_autoinc(void)
+{
+ /* auto increment in the x-direction if it's enabled */
+ if (!video_control[0]) /* /AX */
+ bitmode_addr[0]++;
+
+ /* auto increment in the y-direction if it's enabled */
+ if (!video_control[1]) /* /AY */
+ bitmode_addr[1]++;
+}
+
+
+
+/*************************************
+ *
+ * Standard video RAM access
+ *
+ *************************************/
+
+WRITE8_HANDLER( cloud9_videoram_w )
+{
+ /* direct writes to VRAM go through the write protect PROM as well */
+ cloud9_write_vram(offset, data, 0, 0);
+}
+
+
+
+/*************************************
+ *
+ * Bit mode video RAM access
+ *
+ *************************************/
+
+READ8_HANDLER( cloud9_bitmode_r )
+{
+ /* in bitmode, the address comes from the autoincrement latches */
+ UINT16 addr = (bitmode_addr[1] << 6) | (bitmode_addr[0] >> 2);
+
+ /* the appropriate pixel is selected into the upper 4 bits */
+ UINT8 result = videoram[((~bitmode_addr[0] & 2) << 13) | addr] << ((bitmode_addr[0] & 1) * 4);
+
+ /* autoincrement because /BITMD was selected */
+ bitmode_autoinc();
+
+ /* the upper 4 bits of the data lines are not driven so make them all 1's */
+ return (result >> 4) | 0xf0;
+}
+
+
+WRITE8_HANDLER( cloud9_bitmode_w )
+{
+ /* in bitmode, the address comes from the autoincrement latches */
+ UINT16 addr = (bitmode_addr[1] << 6) | (bitmode_addr[0] >> 2);
+
+ /* the lower 4 bits of data are replicated to the upper 4 bits */
+ data = (data & 0x0f) | (data << 4);
+
+ /* write through the generic VRAM routine, passing the low 2 X bits as PIXB/PIXA */
+ cloud9_write_vram(addr, data, 1, bitmode_addr[0] & 3);
+
+ /* autoincrement because /BITMD was selected */
+ bitmode_autoinc();
+}
+
+
+WRITE8_HANDLER( cloud9_bitmode_addr_w )
+{
+ /* write through to video RAM and also to the addressing latches */
+ cloud9_write_vram(offset, data, 0, 0);
+ bitmode_addr[offset] = data;
+}
+
+
+
+/*************************************
+ *
+ * Video updating
+ *
+ *************************************/
+
+VIDEO_UPDATE( cloud9 )
+{
+ UINT8 *spriteaddr = spriteram;
+ int flip = video_control[5] ? 0xff : 0x00; /* PLAYER2 */
+ pen_t black = get_black_pen(machine);
+ int x, y, offs;
+
+ /* draw the sprites */
+ fillbitmap(spritebitmap, 0x00, cliprect);
+ for (offs = 0; offs < 0x20; offs++)
+ if (spriteaddr[offs + 0x00] != 0)
+ {
+ int x = spriteaddr[offs + 0x60];
+ int y = 256 - 15 - spriteaddr[offs + 0x00];
+ int xflip = spriteaddr[offs + 0x40] & 0x80;
+ int yflip = spriteaddr[offs + 0x40] & 0x40;
+ int which = spriteaddr[offs + 0x20];
+ int color = 0;
+
+ drawgfx(spritebitmap, machine->gfx[0], which, color, xflip, yflip, x, y, cliprect, TRANSPARENCY_PEN, 0);
+ if (x >= 256 - 16)
+ drawgfx(spritebitmap, machine->gfx[0], which, color, xflip, yflip, x - 256, y, cliprect, TRANSPARENCY_PEN, 0);
+ }
+
+ /* draw the bitmap to the screen, looping over Y */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *dst = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+
+ /* if we're in the VBLANK region, just fill with black */
+ if (~syncprom[y] & 2)
+ {
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ dst[x] = black;
+ }
+
+ /* non-VBLANK region: merge the sprites and the bitmap */
+ else
+ {
+ UINT16 *mosrc = (UINT16 *)spritebitmap->base + y * spritebitmap->rowpixels;
+ int effy = y ^ flip;
+ UINT8 *src[2];
+
+ /* two videoram arrays */
+ src[0] = &videoram[0x4000 | (effy * 64)];
+ src[1] = &videoram[0x0000 | (effy * 64)];
+
+ /* loop over X */
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ /* if we're in the HBLANK region, just store black */
+ if (x >= 256)
+ dst[x] = black;
+
+ /* otherwise, process normally */
+ else
+ {
+ int effx = x ^ flip;
+
+ /* low 4 bits = left pixel, high 4 bits = right pixel */
+ UINT8 pix = (src[(effx >> 1) & 1][effx / 4] >> ((~effx & 1) * 4)) & 0x0f;
+ UINT8 mopix = mosrc[x];
+
+ /* sprites have priority if sprite pixel != 0 or some other condition */
+ if (mopix != 0)
+ pix = mopix | 0x10;
+
+ /* the high bit is the bank select */
+ pix |= video_control[7] << 5;
+
+ /* store the pixel value and also a priority value based on the topmost bit */
+ dst[x] = pix;
+ }
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/clshroad.c b/src/mame/video/clshroad.c
new file mode 100644
index 00000000000..88b0ca995c5
--- /dev/null
+++ b/src/mame/video/clshroad.c
@@ -0,0 +1,359 @@
+/***************************************************************************
+
+ -= Clash Road =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+ [ 2 Horizontally Scrolling Layers ]
+
+ Size : 512 x 256
+ Tiles: 16 x 16 x 4.
+
+ These 2 layers share the same graphics and X scroll value.
+ The tile codes are stuffed together in memory too: first one
+ layer's row, then the other's (and so on for all the rows).
+
+ [ 1 Fixed Layer ]
+
+ Size : (256 + 32) x 256
+ Tiles: 8 x 8 x 4.
+
+ This is like a 32x32 tilemap, but the top and bottom rows (that
+ fall outside the visible area) are used to widen the tilemap
+ horizontally, adding 2 vertical columns both sides.
+
+ The result is a 36x28 visible tilemap.
+
+ [ 64? sprites ]
+
+ Sprites are 16 x 16 x 4.
+
+***************************************************************************/
+
+#include "driver.h"
+
+/* Variables only used here: */
+
+static tilemap *tilemap_0a, *tilemap_0b, *tilemap_1;
+
+/* Variables & functions needed by drivers: */
+
+UINT8 *clshroad_vram_0, *clshroad_vram_1;
+UINT8 *clshroad_vregs;
+
+WRITE8_HANDLER( clshroad_vram_0_w );
+WRITE8_HANDLER( clshroad_vram_1_w );
+WRITE8_HANDLER( clshroad_flipscreen_w );
+
+
+WRITE8_HANDLER( clshroad_flipscreen_w )
+{
+ flip_screen_set( data & 1 );
+}
+
+
+PALETTE_INIT( clshroad )
+{
+ int i;
+ for (i = 0;i < 256;i++)
+ palette_set_color_rgb(machine,i, pal4bit(color_prom[i + 256 * 0]),
+ pal4bit(color_prom[i + 256 * 1]),
+ pal4bit(color_prom[i + 256 * 2]));
+}
+
+PALETTE_INIT( firebatl )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+#if 1
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ bit3 = (color_prom[i] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* green component */
+ bit0 = (color_prom[i + 256] >> 0) & 0x01;
+ bit1 = (color_prom[i + 256] >> 1) & 0x01;
+ bit2 = (color_prom[i + 256] >> 2) & 0x01;
+ bit3 = (color_prom[i + 256] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* blue component */
+ bit0 = (color_prom[i + 2*256] >> 0) & 0x01;
+ bit1 = (color_prom[i + 2*256] >> 1) & 0x01;
+ bit2 = (color_prom[i + 2*256] >> 2) & 0x01;
+ bit3 = (color_prom[i + 2*256] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+#endif
+
+ color_prom += 3*256;
+ /* color_prom now points to the beginning of the lookup table */
+
+
+ for (i = 0;i < TOTAL_COLORS(2);i++)
+ COLOR(2,i) = ((color_prom[i] & 0x0f) << 4) + (color_prom[i+256] & 0x0f);
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/***************************************************************************
+
+ Layers 0 Tiles Format
+
+Offset:
+
+ 00-3f: Even bytes: Codes Odd bytes: Colors <- Layer B First Row
+ 40-7f: Even bytes: Codes Odd bytes: Colors <- Layer A First Row
+ .. <- 2nd Row
+ .. <- 3rd Row
+ etc.
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info_0a )
+{
+ UINT8 code;
+ tile_index = (tile_index & 0x1f) + (tile_index & ~0x1f)*2;
+ code = clshroad_vram_0[ tile_index * 2 + 0x40 ];
+// color = clshroad_vram_0[ tile_index * 2 + 0x41 ];
+ SET_TILE_INFO(
+ 1,
+ code,
+ 0,
+ 0);
+}
+
+static TILE_GET_INFO( get_tile_info_0b )
+{
+ UINT8 code;
+ tile_index = (tile_index & 0x1f) + (tile_index & ~0x1f)*2;
+ code = clshroad_vram_0[ tile_index * 2 + 0x00 ];
+// color = clshroad_vram_0[ tile_index * 2 + 0x01 ];
+ SET_TILE_INFO(
+ 1,
+ code,
+ 0,
+ 0);
+}
+
+WRITE8_HANDLER( clshroad_vram_0_w )
+{
+ int tile_index = offset / 2;
+ int tile = (tile_index & 0x1f) + (tile_index & ~0x3f)/2;
+ clshroad_vram_0[offset] = data;
+ if (tile_index & 0x20) tilemap_mark_tile_dirty(tilemap_0a, tile);
+ else tilemap_mark_tile_dirty(tilemap_0b, tile);
+}
+
+/***************************************************************************
+
+ Layer 1 Tiles Format
+
+Offset:
+
+ 000-3ff Code
+ 400-7ff 7654---- Code (High bits)
+ ----3210 Color
+
+ This is like a 32x32 tilemap, but the top and bottom rows (that
+ fall outside the visible area) are used to widen the tilemap
+ horizontally, adding 2 vertical columns both sides.
+
+ The result is a 36x28 visible tilemap.
+
+***************************************************************************/
+
+/* logical (col,row) -> memory offset */
+static TILEMAP_MAPPER( tilemap_scan_rows_extra )
+{
+ // The leftmost columns come from the bottom rows
+ if (col <= 0x01) return row + (col + 0x1e) * 0x20;
+ // The rightmost columns come from the top rows
+ if (col >= 0x22) return row + (col - 0x22) * 0x20;
+
+ // These are not visible, but *must* be mapped to other tiles than
+ // those used by the leftmost and rightmost columns (tilemap "bug"?)
+ if (row <= 0x01) return 0;
+ if (row >= 0x1e) return 0;
+
+ // "normal" layout for the rest.
+ return (col-2) + row * 0x20;
+}
+
+static TILE_GET_INFO( get_tile_info_fb1 )
+{
+ UINT8 code = clshroad_vram_1[ tile_index + 0x000 ];
+ UINT8 color = clshroad_vram_1[ tile_index + 0x400 ];
+ SET_TILE_INFO(
+ 2,
+ code,
+ color & 0x3f,
+ 0);
+}
+
+static TILE_GET_INFO( get_tile_info_1 )
+{
+ UINT8 code = clshroad_vram_1[ tile_index + 0x000 ];
+ UINT8 color = clshroad_vram_1[ tile_index + 0x400 ];
+ SET_TILE_INFO(
+ 2,
+ code + ((color & 0xf0)<<4),
+ color & 0x0f,
+ 0);
+}
+
+WRITE8_HANDLER( clshroad_vram_1_w )
+{
+ clshroad_vram_1[offset] = data;
+ tilemap_mark_tile_dirty(tilemap_1, offset % 0x400);
+}
+
+
+VIDEO_START( firebatl )
+{
+ /* These 2 use the graphics and scroll value */
+ tilemap_0a = tilemap_create(get_tile_info_0a,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,0x20,0x10);
+ tilemap_0b = tilemap_create(get_tile_info_0b,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,0x20,0x10);
+ /* Text (No scrolling) */
+ tilemap_1 = tilemap_create(get_tile_info_fb1,tilemap_scan_rows_extra,TILEMAP_TYPE_COLORTABLE,8,8,0x24,0x20);
+
+ tilemap_set_scroll_rows( tilemap_0a, 1);
+ tilemap_set_scroll_rows( tilemap_0b, 1);
+ tilemap_set_scroll_rows( tilemap_1, 1);
+
+ tilemap_set_scroll_cols( tilemap_0a, 1);
+ tilemap_set_scroll_cols( tilemap_0b, 1);
+ tilemap_set_scroll_cols( tilemap_1, 1);
+
+ tilemap_set_scrolldx( tilemap_0a, -0x30, -0xb5);
+ tilemap_set_scrolldx( tilemap_0b, -0x30, -0xb5);
+
+ tilemap_set_transparent_pen( tilemap_0b, 0 );
+ tilemap_set_transparent_pen( tilemap_1, 0x0f );
+}
+
+VIDEO_START( clshroad )
+{
+ /* These 2 use the graphics and scroll value */
+ tilemap_0a = tilemap_create(get_tile_info_0a,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,0x20,0x10);
+ tilemap_0b = tilemap_create(get_tile_info_0b,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,0x20,0x10);
+ /* Text (No scrolling) */
+ tilemap_1 = tilemap_create(get_tile_info_1,tilemap_scan_rows_extra,TILEMAP_TYPE_PEN,8,8,0x24,0x20);
+
+ tilemap_set_scroll_rows( tilemap_0a, 1);
+ tilemap_set_scroll_rows( tilemap_0b, 1);
+ tilemap_set_scroll_rows( tilemap_1, 1);
+
+ tilemap_set_scroll_cols( tilemap_0a, 1);
+ tilemap_set_scroll_cols( tilemap_0b, 1);
+ tilemap_set_scroll_cols( tilemap_1, 1);
+
+ tilemap_set_scrolldx( tilemap_0a, -0x30, -0xb5);
+ tilemap_set_scrolldx( tilemap_0b, -0x30, -0xb5);
+
+ tilemap_set_transparent_pen( tilemap_0b, 0x0f );
+ tilemap_set_transparent_pen( tilemap_1, 0x0f );
+}
+
+
+/***************************************************************************
+
+ Sprites Drawing
+
+Offset: Format: Value:
+
+ 0
+
+ 1 Y (Bottom-up)
+
+ 2 765432--
+ ------10 Code (high bits)
+
+ 3 76------
+ --543210 Code (low bits)
+
+ 4
+
+ 5 X (low bits)
+
+ 6 X (High bits)
+
+ 7 7654----
+ ----3210 Color
+
+- Sprite flipping ?
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int i;
+
+ for (i = 0; i < spriteram_size ; i += 8)
+ {
+ int y = 240 - spriteram[i+1];
+ int code = (spriteram[i+3] & 0x3f) + (spriteram[i+2] << 6);
+ int x = spriteram[i+5] + (spriteram[i+6] << 8);
+ int attr = spriteram[i+7];
+
+ int flipx = 0;
+ int flipy = 0;
+
+ x -= 0x4a/2;
+ if (flip_screen)
+ {
+ y = 240 - y;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ attr & 0x0f,
+ flipx,flipy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,15 );
+ }
+}
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+VIDEO_UPDATE( clshroad )
+{
+ int scrollx = clshroad_vregs[ 0 ] + (clshroad_vregs[ 1 ] << 8);
+// int priority = clshroad_vregs[ 2 ];
+
+ /* Only horizontal scrolling (these 2 layers use the same value) */
+ tilemap_set_scrollx(tilemap_0a, 0, scrollx);
+ tilemap_set_scrollx(tilemap_0b, 0, scrollx);
+
+ tilemap_draw(bitmap,cliprect,tilemap_0a,0,0); // Opaque
+ tilemap_draw(bitmap,cliprect,tilemap_0b,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,tilemap_1,0,0);
+ return 0;
+}
diff --git a/src/mame/video/cninja.c b/src/mame/video/cninja.c
new file mode 100644
index 00000000000..ca295198657
--- /dev/null
+++ b/src/mame/video/cninja.c
@@ -0,0 +1,526 @@
+/***************************************************************************
+
+ Caveman Ninja Video emulation - Bryan McPhail, mish@tendril.co.uk
+
+****************************************************************************/
+
+#include "driver.h"
+#include "deco16ic.h"
+#include "cninja.h"
+
+/******************************************************************************/
+
+static int cninja_bank_callback(const int bank)
+{
+ if ((bank>>4)&0xf) return 0x0000; /* Only 2 banks */
+ return 0x1000;
+}
+
+static int edrandy_bank_callback(const int bank)
+{
+ if ((bank>>4)&0xf) return 0x0000; /* Only 2 banks */
+ return 0x1000;
+}
+
+static int robocop2_bank_callback(const int bank)
+{
+ return (bank&0x30)<<8;
+}
+
+static int mutantf_1_bank_callback(const int bank)
+{
+ return ((bank>>4)&0x3)<<12;
+}
+
+static int mutantf_2_bank_callback(const int bank)
+{
+ return ((bank>>5)&0x1)<<14;
+}
+
+/******************************************************************************/
+
+VIDEO_START( cninja )
+{
+ deco16_2_video_init(1);
+
+ deco16_set_tilemap_bank_callback(2,cninja_bank_callback);
+ deco16_set_tilemap_bank_callback(3,cninja_bank_callback);
+ deco16_set_tilemap_colour_base(3,48);
+}
+
+VIDEO_START( stoneage )
+{
+ deco16_2_video_init(1);
+
+ deco16_set_tilemap_bank_callback(2,edrandy_bank_callback);
+ deco16_set_tilemap_bank_callback(3,edrandy_bank_callback);
+ deco16_set_tilemap_colour_base(3,48);
+
+ /* The bootleg has broken scroll registers */
+ tilemap_set_scrolldx(deco16_get_tilemap(3,0),-10,-10);
+ tilemap_set_scrolldx(deco16_get_tilemap(1,0),-10,-10);
+ tilemap_set_scrolldx(deco16_get_tilemap(0,1),2,2);
+}
+
+VIDEO_START( edrandy )
+{
+ deco16_2_video_init(0);
+
+ deco16_set_tilemap_bank_callback(2,edrandy_bank_callback);
+ deco16_set_tilemap_bank_callback(3,edrandy_bank_callback);
+ deco16_set_tilemap_colour_base(3,48);
+}
+
+VIDEO_START( robocop2 )
+{
+ deco16_2_video_init(0);
+
+ deco16_set_tilemap_bank_callback(1,robocop2_bank_callback);
+ deco16_set_tilemap_bank_callback(2,robocop2_bank_callback);
+ deco16_set_tilemap_bank_callback(3,robocop2_bank_callback);
+ deco16_set_tilemap_colour_base(3,48);
+}
+
+VIDEO_START( mutantf )
+{
+ deco16_2_video_init(0);
+
+ deco16_set_tilemap_bank_callback(0,mutantf_1_bank_callback);
+ deco16_set_tilemap_bank_callback(1,mutantf_2_bank_callback);
+ deco16_set_tilemap_bank_callback(2,mutantf_1_bank_callback);
+ deco16_set_tilemap_bank_callback(3,mutantf_1_bank_callback);
+
+ deco16_set_tilemap_colour_base(1,0x30);
+ deco16_set_tilemap_colour_base(2,0x20);
+ deco16_set_tilemap_colour_base(3,0x40);
+
+ alpha_set_level(0x80);
+}
+
+/******************************************************************************/
+
+VIDEO_EOF( cninja )
+{
+ deco16_raster_display_position=0;
+}
+
+static void raster_pf3_draw(mame_bitmap *bitmap, const rectangle *cliprect, int flags, int pri)
+{
+ tilemap *tmap=deco16_get_tilemap(2,0);
+ int ptr=0,start,end=0;
+ rectangle clip;
+ int overflow=deco16_raster_display_position;
+
+ clip.min_x = cliprect->min_x;
+ clip.max_x = cliprect->max_x;
+
+ /* Finish list up to end of visible display */
+ deco16_raster_display_list[overflow++]=255;
+ deco16_raster_display_list[overflow++]=deco16_pf12_control[1];
+ deco16_raster_display_list[overflow++]=deco16_pf12_control[2];
+ deco16_raster_display_list[overflow++]=deco16_pf12_control[3];
+ deco16_raster_display_list[overflow++]=deco16_pf12_control[4];
+ deco16_raster_display_list[overflow++]=deco16_pf34_control[1];
+ deco16_raster_display_list[overflow++]=deco16_pf34_control[2];
+ deco16_raster_display_list[overflow++]=deco16_pf34_control[3];
+ deco16_raster_display_list[overflow++]=deco16_pf34_control[4];
+
+ while (ptr<overflow) {
+ start=end;
+ end=deco16_raster_display_list[ptr++];
+
+ /* Restore state of registers before IRQ */
+ deco16_pf12_control[1]=deco16_raster_display_list[ptr++];
+ deco16_pf12_control[2]=deco16_raster_display_list[ptr++];
+ deco16_pf12_control[3]=deco16_raster_display_list[ptr++];
+ deco16_pf12_control[4]=deco16_raster_display_list[ptr++];
+ deco16_pf34_control[1]=deco16_raster_display_list[ptr++];
+ deco16_pf34_control[2]=deco16_raster_display_list[ptr++];
+ deco16_pf34_control[3]=deco16_raster_display_list[ptr++];
+ deco16_pf34_control[4]=deco16_raster_display_list[ptr++];
+
+ clip.min_y = start;
+ clip.max_y = end;
+
+ /* Update tilemap for this register state, and draw */
+ deco16_pf34_update(deco16_pf3_rowscroll,deco16_pf4_rowscroll);
+ tilemap_draw(bitmap,&clip,tmap,flags,pri);
+ }
+}
+
+/******************************************************************************/
+
+static void cninja_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0x400-4;offs >=0 ;offs -= 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult,pri=0;
+
+ sprite = buffered_spriteram16[offs+1];
+ if (!sprite) continue;
+
+ x = buffered_spriteram16[offs+2];
+
+ /* Sprite/playfield priority */
+ switch (x&0xc000) {
+ case 0x0000: pri=0; break;
+ case 0x4000: pri=0xf0; break;
+ case 0x8000: pri=0xf0|0xcc; break;
+ case 0xc000: pri=0xf0|0xcc; break; /* Perhaps 0xf0|0xcc|0xaa (Sprite under bottom layer) */
+ }
+
+ y = buffered_spriteram16[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+ colour = (x >> 9) &0x1f;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 256) x -= 512;
+ if (y >= 256) y -= 512;
+ x = 240 - x;
+ y = 240 - y;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen) {
+ y=240-y;
+ x=240-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ pdrawgfx(bitmap,machine->gfx[3],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0,pri);
+
+ multi--;
+ }
+ }
+}
+
+static void robocop2_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0x400-4;offs >=0 ;offs -= 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult,pri=0;
+ sprite = buffered_spriteram16[offs+1];
+ if (!sprite) continue;
+
+ x = buffered_spriteram16[offs+2];
+
+ /* Sprite/playfield priority */
+ switch (x&0xc000) {
+ case 0x0000: pri=0; break;
+ case 0x4000: pri=0xf0; break;
+ case 0x8000: pri=0xf0|0xcc; break;
+ case 0xc000: pri=0xf0|0xcc; break; /* Perhaps 0xf0|0xcc|0xaa (Sprite under bottom layer) */
+ }
+
+ y = buffered_spriteram16[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+ colour = (x >> 9) &0x1f;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+ x = 304 - x;
+ y = 240 - y;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen) {
+ y=240-y;
+ x=304-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ pdrawgfx(bitmap,machine->gfx[3],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0,pri);
+
+ multi--;
+ }
+ }
+}
+
+static void mutantf_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, const UINT16 *spriteptr, int gfxbank)
+{
+ int offs,end,inc;
+
+ /*
+ Alternate format from most 16 bit games - same as Captain America
+
+ Word 0:
+ 0x8000: Y flip
+ 0x4000: X flip
+ 0x2000: Flash (Sprite toggles on/off every frame)
+ 0x1fff: Y value
+ Word 1:
+ 0xffff: X value
+ Word 2:
+ 0xf000: Block height
+ 0x0f00: Block width
+ 0x00e0: Unused?
+ 0x001f: Colour
+ Word 3:
+ 0xffff: Sprite value
+ */
+
+ /* This may look strange, but the alpha-blended sprite chip definitely draws end to
+ front, ie, reversed from normal pdrawgfx style. */
+ if (gfxbank==4) {
+ offs=0;
+ end=0x400;
+ inc=4;
+ } else {
+ offs=0x3fc;
+ end=-4;
+ inc=-4;
+ }
+
+ while (offs!=end)
+ {
+ int x,y,sprite,colour,fx,fy,w,h,sx,sy,x_mult,y_mult;
+ int trans=TRANSPARENCY_PEN;
+
+ sprite = spriteptr[offs+3];
+ if (!sprite) {
+ offs+=inc;
+ continue;
+ }
+
+ sx = spriteptr[offs+1];
+
+ h = (spriteptr[offs+2]&0xf000)>>12;
+ w = (spriteptr[offs+2]&0x0f00)>> 8;
+
+ sy = spriteptr[offs];
+ if ((sy&0x2000) && (cpu_getcurrentframe() & 1)) {
+ offs+=inc;
+ continue;
+ }
+
+ colour = (spriteptr[offs+2] >>0) & 0x1f;
+
+ if (gfxbank==4) { /* Seems to be always alpha'd */
+ trans=TRANSPARENCY_ALPHA;
+ colour&=0xf;
+ }
+
+ fx = (spriteptr[offs+0]&0x4000);
+ fy = (spriteptr[offs+0]&0x8000);
+
+ if (flip_screen) {
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+
+ sx = sx & 0x01ff;
+ sy = sy & 0x01ff;
+ if (sx>0x180) sx=-(0x200 - sx);
+ if (sy>0x180) sy=-(0x200 - sy);
+
+ if (fx) { x_mult=-16; sx+=16*w; } else { x_mult=16; sx-=16; }
+ if (fy) { y_mult=-16; sy+=16*h; } else { y_mult=16; sy-=16; }
+ } else {
+ sx = sx & 0x01ff;
+ sy = sy & 0x01ff;
+ if (sx&0x100) sx=-(0x100 - (sx&0xff));
+ if (sy&0x100) sy=-(0x100 - (sy&0xff));
+ sx = 304 - sx;
+ sy = 240 - sy;
+ if (sx >= 432) sx -= 512;
+ if (sy >= 384) sy -= 512;
+ if (fx) { x_mult=-16; sx+=16; } else { x_mult=16; sx-=16*w; }
+ if (fy) { y_mult=-16; sy+=16; } else { y_mult=16; sy-=16*h; }
+ }
+
+ for (x=0; x<w; x++) {
+ for (y=0; y<h; y++) {
+ pdrawgfx(bitmap,machine->gfx[gfxbank],
+ sprite + y + h * x,
+ colour,
+ fx,fy,
+ sx + x_mult * (w-x),sy + y_mult * (h-y),
+ cliprect,trans,0,0);
+ }
+ }
+
+ offs+=inc;
+ }
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( cninja )
+{
+ flip_screen_set( deco16_pf12_control[0]&0x80 );
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+ deco16_pf34_update(deco16_pf3_rowscroll,deco16_pf4_rowscroll);
+
+ /* Draw playfields */
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[512],cliprect);
+ deco16_tilemap_4_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,1);
+ deco16_tilemap_3_draw(bitmap,cliprect,0,2);
+ deco16_tilemap_2_draw(bitmap,cliprect,TILEMAP_DRAW_LAYER1,2);
+ deco16_tilemap_2_draw(bitmap,cliprect,TILEMAP_DRAW_LAYER0,4);
+ cninja_draw_sprites(machine,bitmap,cliprect);
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( edrandy )
+{
+ flip_screen_set( deco16_pf12_control[0]&0x80 );
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+ deco16_pf34_update(deco16_pf3_rowscroll,deco16_pf4_rowscroll);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ deco16_tilemap_4_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,1);
+ if (deco16_raster_display_position)
+ raster_pf3_draw(bitmap,cliprect,0,2);
+ else
+ deco16_tilemap_3_draw(bitmap,cliprect,0,2);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,4);
+ cninja_draw_sprites(machine,bitmap,cliprect);
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( robocop2 )
+{
+ /* One of the tilemap chips can switch between 2 tilemaps at 4bpp, or 1 at 8bpp */
+ if (deco16_priority&4) {
+ deco16_set_tilemap_colour_mask(2,0);
+ deco16_set_tilemap_colour_mask(3,0);
+ deco16_pf34_set_gfxbank(0,4);
+ } else {
+ deco16_set_tilemap_colour_mask(2,0xf);
+ deco16_set_tilemap_colour_mask(3,0xf);
+ deco16_pf34_set_gfxbank(0,2);
+ }
+
+ /* Update playfields */
+ flip_screen_set( deco16_pf12_control[0]&0x80 );
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+ deco16_pf34_update(deco16_pf3_rowscroll,deco16_pf4_rowscroll);
+
+ /* Draw playfields */
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0x200],cliprect);
+ if ((deco16_priority&4)==0)
+ deco16_tilemap_4_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,1);
+
+ /* Switchable priority */
+ switch (deco16_priority&0x8) {
+ case 8:
+ deco16_tilemap_2_draw(bitmap,cliprect,0,2);
+ if (deco16_raster_display_position)
+ raster_pf3_draw(bitmap,cliprect,0,4);
+ else
+ deco16_tilemap_3_draw(bitmap,cliprect,0,4);
+ break;
+ default:
+ case 0:
+ if (deco16_raster_display_position)
+ raster_pf3_draw(bitmap,cliprect,0,2);
+ else
+ deco16_tilemap_3_draw(bitmap,cliprect,0,2);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,4);
+ break;
+ }
+
+ robocop2_draw_sprites(machine,bitmap,cliprect);
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( mutantf )
+{
+ flip_screen_set( deco16_pf12_control[0]&0x80 );
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+ deco16_pf34_update(deco16_pf3_rowscroll,deco16_pf4_rowscroll);
+
+ /* Draw playfields */
+ fillbitmap(bitmap,machine->pens[0x400],cliprect); /* Confirmed */
+
+ /* There is no priority prom on this board, but there is a
+ priority control word, the only values used in game appear
+ to be 2, 6 & 7 though:
+
+ Bit 0: If set sprite chip 2 above sprite chip 1 else vice versa
+ Bit 1: Always set?
+ Bit 2: Almost always set (Sometimes not set on screen transitions)
+
+ The other bits may control alpha blend on the 2nd sprite chip, or
+ layer order.
+ */
+ deco16_tilemap_4_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,0);
+ deco16_tilemap_3_draw(bitmap,cliprect,0,0);
+
+ /* We need to abuse the priority bitmap a little by clearing it before
+ drawing each sprite layer. This is because there is no priority
+ orthogonality between sprite layers, but the alpha layer must obey
+ priority between sprites in each layer. Ie, if we didn't do this,
+ then when two alpha blended shadows overlapped then they would be 25%
+ transparent against the background, rather than 50% */
+ if (deco16_priority&1) {
+ fillbitmap(priority_bitmap,0,cliprect);
+ mutantf_draw_sprites(machine,bitmap,cliprect,buffered_spriteram16,3);
+ fillbitmap(priority_bitmap,0,cliprect);
+ mutantf_draw_sprites(machine,bitmap,cliprect,buffered_spriteram16_2,4);
+ } else {
+ fillbitmap(priority_bitmap,0,cliprect);
+ mutantf_draw_sprites(machine,bitmap,cliprect,buffered_spriteram16_2,4);
+ fillbitmap(priority_bitmap,0,cliprect);
+ mutantf_draw_sprites(machine,bitmap,cliprect,buffered_spriteram16,3);
+ }
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+ return 0;
+}
diff --git a/src/mame/video/combatsc.c b/src/mame/video/combatsc.c
new file mode 100644
index 00000000000..2f7107fe1c1
--- /dev/null
+++ b/src/mame/video/combatsc.c
@@ -0,0 +1,640 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+static tilemap *bg_tilemap[2];
+static tilemap *textlayer;
+static UINT8 *private_spriteram[2];
+static int priority;
+
+static UINT8 *combasc_io_ram;
+static int combasc_vreg;
+
+static int combasc_bank_select; /* 0x00..0x1f */
+static int combasc_video_circuit; /* 0 or 1 */
+static UINT8 *combasc_page[2];
+static UINT8 combasc_scrollram0[0x40];
+static UINT8 combasc_scrollram1[0x40];
+static UINT8 *combasc_scrollram;
+
+
+PALETTE_INIT( combasc )
+{
+ int i,pal,clut = 0;
+ for( pal=0; pal<8; pal++ )
+ {
+ switch( pal )
+ {
+ case 0: /* other sprites */
+ case 2: /* other sprites(alt) */
+ clut = 1; /* 0 is wrong for Firing Range III targets */
+ break;
+
+ case 4: /* player sprites */
+ case 6: /* player sprites(alt) */
+ clut = 2;
+ break;
+
+ case 1: /* background */
+ case 3: /* background(alt) */
+ clut = 1;
+ break;
+
+ case 5: /* foreground tiles */
+ case 7: /* foreground tiles(alt) */
+ clut = 3;
+ break;
+ }
+
+ for( i=0; i<256; i++ )
+ {
+ if ((pal & 1) == 0) /* sprites */
+ {
+ if (color_prom[256 * clut + i] == 0)
+ *(colortable++) = 0;
+ else
+ *(colortable++) = 16 * pal + color_prom[256 * clut + i];
+ }
+ else /* chars */
+ *(colortable++) = 16 * pal + color_prom[256 * clut + i];
+ }
+ }
+}
+
+PALETTE_INIT( combascb )
+{
+ int i,pal;
+ for( pal=0; pal<8; pal++ )
+ {
+ for( i=0; i<256; i++ )
+ {
+ if ((pal & 1) == 0) /* sprites */
+ *(colortable++) = 16 * pal + (color_prom[i] ^ 0x0f);
+ else /* chars */
+ *(colortable++) = 16 * pal + (i & 0x0f); /* no lookup? */
+ }
+ }
+}
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info0 )
+{
+ UINT8 attributes = combasc_page[0][tile_index];
+ int bank = 4*((combasc_vreg & 0x0f) - 1);
+ int number,color;
+
+ if (bank < 0) bank = 0;
+ if ((attributes & 0xb0) == 0) bank = 0; /* text bank */
+
+ if (attributes & 0x80) bank += 1;
+ if (attributes & 0x10) bank += 2;
+ if (attributes & 0x20) bank += 4;
+
+ color = ((K007121_ctrlram[0][6]&0x10)*2+16) + (attributes & 0x0f);
+
+ number = combasc_page[0][tile_index + 0x400] + 256*bank;
+
+ SET_TILE_INFO(
+ 0,
+ number,
+ color,
+ 0);
+ tileinfo->category = (attributes & 0x40) >> 6;
+}
+
+static TILE_GET_INFO( get_tile_info1 )
+{
+ UINT8 attributes = combasc_page[1][tile_index];
+ int bank = 4*((combasc_vreg >> 4) - 1);
+ int number, color;
+
+ if (bank < 0) bank = 0;
+ if ((attributes & 0xb0) == 0) bank = 0; /* text bank */
+
+ if (attributes & 0x80) bank += 1;
+ if (attributes & 0x10) bank += 2;
+ if (attributes & 0x20) bank += 4;
+
+ color = ((K007121_ctrlram[1][6]&0x10)*2+16+4*16) + (attributes & 0x0f);
+
+ number = combasc_page[1][tile_index + 0x400] + 256*bank;
+
+ SET_TILE_INFO(
+ 1,
+ number,
+ color,
+ 0);
+ tileinfo->category = (attributes & 0x40) >> 6;
+}
+
+static TILE_GET_INFO( get_text_info )
+{
+ UINT8 attributes = combasc_page[0][tile_index + 0x800];
+ int number = combasc_page[0][tile_index + 0xc00];
+ int color = 16 + (attributes & 0x0f);
+
+ SET_TILE_INFO(
+ 0,
+ number,
+ color,
+ 0);
+}
+
+
+static TILE_GET_INFO( get_tile_info0_bootleg )
+{
+ UINT8 attributes = combasc_page[0][tile_index];
+ int bank = 4*((combasc_vreg & 0x0f) - 1);
+ int number, pal, color;
+
+ if (bank < 0) bank = 0;
+ if ((attributes & 0xb0) == 0) bank = 0; /* text bank */
+
+ if (attributes & 0x80) bank += 1;
+ if (attributes & 0x10) bank += 2;
+ if (attributes & 0x20) bank += 4;
+
+ pal = (bank == 0 || bank >= 0x1c || (attributes & 0x40)) ? 1 : 3;
+ color = pal*16;// + (attributes & 0x0f);
+ number = combasc_page[0][tile_index + 0x400] + 256*bank;
+
+ SET_TILE_INFO(
+ 0,
+ number,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_tile_info1_bootleg )
+{
+ UINT8 attributes = combasc_page[1][tile_index];
+ int bank = 4*((combasc_vreg >> 4) - 1);
+ int number, pal, color;
+
+ if (bank < 0) bank = 0;
+ if ((attributes & 0xb0) == 0) bank = 0; /* text bank */
+
+ if (attributes & 0x80) bank += 1;
+ if (attributes & 0x10) bank += 2;
+ if (attributes & 0x20) bank += 4;
+
+ pal = (bank == 0 || bank >= 0x1c || (attributes & 0x40)) ? 5 : 7;
+ color = pal*16;// + (attributes & 0x0f);
+ number = combasc_page[1][tile_index + 0x400] + 256*bank;
+
+ SET_TILE_INFO(
+ 1,
+ number,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_text_info_bootleg )
+{
+// UINT8 attributes = combasc_page[0][tile_index + 0x800];
+ int number = combasc_page[0][tile_index + 0xc00];
+ int color = 16;// + (attributes & 0x0f);
+
+ SET_TILE_INFO(
+ 1,
+ number,
+ color,
+ 0);
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( combasc )
+{
+ combasc_vreg = -1;
+
+ bg_tilemap[0] = tilemap_create(get_tile_info0,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ bg_tilemap[1] = tilemap_create(get_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ textlayer = tilemap_create(get_text_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,32,32);
+
+ private_spriteram[0] = auto_malloc(0x800);
+ private_spriteram[1] = auto_malloc(0x800);
+ memset(private_spriteram[0],0,0x800);
+ memset(private_spriteram[1],0,0x800);
+
+ tilemap_set_transparent_pen(bg_tilemap[0],0);
+ tilemap_set_transparent_pen(bg_tilemap[1],0);
+ tilemap_set_transparent_pen(textlayer,0);
+
+ tilemap_set_scroll_rows(textlayer,32);
+}
+
+VIDEO_START( combascb )
+{
+ combasc_vreg = -1;
+
+ bg_tilemap[0] = tilemap_create(get_tile_info0_bootleg,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ bg_tilemap[1] = tilemap_create(get_tile_info1_bootleg,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ textlayer = tilemap_create(get_text_info_bootleg, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ private_spriteram[0] = auto_malloc(0x800);
+ private_spriteram[1] = auto_malloc(0x800);
+ memset(private_spriteram[0],0,0x800);
+ memset(private_spriteram[1],0,0x800);
+
+ tilemap_set_transparent_pen(bg_tilemap[0],0);
+ tilemap_set_transparent_pen(bg_tilemap[1],0);
+
+ tilemap_set_scroll_rows(bg_tilemap[0],32);
+ tilemap_set_scroll_rows(bg_tilemap[1],32);
+}
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ8_HANDLER( combasc_video_r )
+{
+ return videoram[offset];
+}
+
+WRITE8_HANDLER( combasc_video_w )
+{
+ videoram[offset] = data;
+ if( offset<0x800 )
+ {
+ if (combasc_video_circuit)
+ tilemap_mark_tile_dirty(bg_tilemap[1],offset & 0x3ff);
+ else
+ tilemap_mark_tile_dirty(bg_tilemap[0],offset & 0x3ff);
+ }
+ else if( offset<0x1000 && combasc_video_circuit==0 )
+ {
+ tilemap_mark_tile_dirty( textlayer,offset & 0x3ff);
+ }
+}
+
+
+WRITE8_HANDLER( combasc_vreg_w )
+{
+ if (data != combasc_vreg)
+ {
+ tilemap_mark_all_tiles_dirty( textlayer );
+ if ((data & 0x0f) != (combasc_vreg & 0x0f))
+ tilemap_mark_all_tiles_dirty( bg_tilemap[0] );
+ if ((data >> 4) != (combasc_vreg >> 4))
+ tilemap_mark_all_tiles_dirty( bg_tilemap[1] );
+ combasc_vreg = data;
+ }
+}
+
+static WRITE8_HANDLER( combascb_sh_irqtrigger_w )
+{
+ soundlatch_w(offset,data);
+ cpunum_set_input_line_and_vector(1,0,HOLD_LINE,0xff);
+}
+
+static READ8_HANDLER( combascb_io_r )
+{
+ return readinputport(offset);
+}
+
+static WRITE8_HANDLER( combascb_priority_w )
+{
+ priority = data & 0x20;
+}
+
+WRITE8_HANDLER( combasc_bankselect_w )
+{
+ UINT8 *page = memory_region(REGION_CPU1) + 0x10000;
+
+ if (data & 0x40)
+ {
+ combasc_video_circuit = 1;
+ videoram = combasc_page[1];
+ combasc_scrollram = combasc_scrollram1;
+ }
+ else
+ {
+ combasc_video_circuit = 0;
+ videoram = combasc_page[0];
+ combasc_scrollram = combasc_scrollram0;
+ }
+
+ priority = data & 0x20;
+
+ if (data & 0x10)
+ {
+ memory_set_bankptr(1,page + 0x4000 * ((data & 0x0e) >> 1));
+ }
+ else
+ {
+ memory_set_bankptr(1,page + 0x20000 + 0x4000 * (data & 1));
+ }
+}
+
+WRITE8_HANDLER( combascb_bankselect_w )
+{
+ if (data & 0x40)
+ {
+ combasc_video_circuit = 1;
+ videoram = combasc_page[1];
+ }
+ else
+ {
+ combasc_video_circuit = 0;
+ videoram = combasc_page[0];
+ }
+
+ data = data & 0x1f;
+ if( data != combasc_bank_select )
+ {
+ UINT8 *page = memory_region(REGION_CPU1) + 0x10000;
+ combasc_bank_select = data;
+
+ if (data & 0x10)
+ {
+ memory_set_bankptr(1,page + 0x4000 * ((data & 0x0e) >> 1));
+ }
+ else
+ {
+ memory_set_bankptr(1,page + 0x20000 + 0x4000 * (data & 1));
+ }
+
+ if (data == 0x1f)
+ {
+ memory_set_bankptr(1,page + 0x20000 + 0x4000 * (data & 1));
+ memory_install_read8_handler(0, ADDRESS_SPACE_PROGRAM, 0x4400, 0x4403, 0, 0, combascb_io_r);/* IO RAM & Video Registers */
+ memory_install_write8_handler(0, ADDRESS_SPACE_PROGRAM, 0x4400, 0x4400, 0, 0, combascb_priority_w);
+ memory_install_write8_handler(0, ADDRESS_SPACE_PROGRAM, 0x4800, 0x4800, 0, 0, combascb_sh_irqtrigger_w);
+ memory_install_write8_handler(0, ADDRESS_SPACE_PROGRAM, 0x4c00, 0x4c00, 0, 0, combasc_vreg_w);
+ }
+ else
+ {
+ memory_install_read8_handler(0, ADDRESS_SPACE_PROGRAM, 0x4000, 0x7fff, 0, 0, MRA8_BANK1); /* banked ROM */
+ memory_install_write8_handler(0, ADDRESS_SPACE_PROGRAM, 0x4000, 0x7fff, 0, 0, MWA8_ROM);
+ }
+ }
+}
+
+MACHINE_RESET( combasc )
+{
+ UINT8 *MEM = memory_region(REGION_CPU1) + 0x38000;
+
+
+ combasc_io_ram = MEM + 0x0000;
+ combasc_page[0] = MEM + 0x4000;
+ combasc_page[1] = MEM + 0x6000;
+
+ memset( combasc_io_ram, 0x00, 0x4000 );
+ memset( combasc_page[0], 0x00, 0x2000 );
+ memset( combasc_page[1], 0x00, 0x2000 );
+
+ combasc_bank_select = -1;
+ combasc_bankselect_w( 0,0 );
+}
+
+WRITE8_HANDLER( combasc_pf_control_w )
+{
+ K007121_ctrl_w(combasc_video_circuit,offset,data);
+
+ if (offset == 7)
+ tilemap_set_flip(bg_tilemap[combasc_video_circuit],(data & 0x08) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ if (offset == 3)
+ {
+ if (data & 0x08)
+ memcpy(private_spriteram[combasc_video_circuit],combasc_page[combasc_video_circuit]+0x1000,0x800);
+ else
+ memcpy(private_spriteram[combasc_video_circuit],combasc_page[combasc_video_circuit]+0x1800,0x800);
+ }
+}
+
+READ8_HANDLER( combasc_scrollram_r )
+{
+ return combasc_scrollram[offset];
+}
+
+WRITE8_HANDLER( combasc_scrollram_w )
+{
+ combasc_scrollram[offset] = data;
+}
+
+
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, const UINT8 *source,int circuit,UINT32 pri_mask)
+{
+ int base_color = (circuit*4)*16+(K007121_ctrlram[circuit][6]&0x10)*2;
+
+ K007121_sprites_draw(machine,circuit,bitmap,cliprect,source,base_color,0,0,pri_mask);
+}
+
+
+VIDEO_UPDATE( combasc )
+{
+ int i;
+
+
+ if (K007121_ctrlram[0][0x01] & 0x02)
+ {
+ tilemap_set_scroll_rows(bg_tilemap[0],32);
+ for (i = 0;i < 32;i++)
+ {
+ tilemap_set_scrollx(bg_tilemap[0],i,combasc_scrollram0[i]);
+ }
+ }
+ else
+ {
+ tilemap_set_scroll_rows(bg_tilemap[0],1);
+ tilemap_set_scrollx(bg_tilemap[0],0,K007121_ctrlram[0][0x00] | ((K007121_ctrlram[0][0x01] & 0x01) << 8));
+ }
+
+ if (K007121_ctrlram[1][0x01] & 0x02)
+ {
+ tilemap_set_scroll_rows(bg_tilemap[1],32);
+ for (i = 0;i < 32;i++)
+ {
+ tilemap_set_scrollx(bg_tilemap[1],i,combasc_scrollram1[i]);
+ }
+ }
+ else
+ {
+ tilemap_set_scroll_rows(bg_tilemap[1],1);
+ tilemap_set_scrollx(bg_tilemap[1],0,K007121_ctrlram[1][0x00] | ((K007121_ctrlram[1][0x01] & 0x01) << 8));
+ }
+
+ tilemap_set_scrolly(bg_tilemap[0],0,K007121_ctrlram[0][0x02]);
+ tilemap_set_scrolly(bg_tilemap[1],0,K007121_ctrlram[1][0x02]);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ if (priority == 0)
+ {
+ tilemap_draw(bitmap,cliprect,bg_tilemap[1],TILEMAP_DRAW_OPAQUE|0,4);
+ tilemap_draw(bitmap,cliprect,bg_tilemap[1],TILEMAP_DRAW_OPAQUE|1,8);
+ tilemap_draw(bitmap,cliprect,bg_tilemap[0],0,1);
+ tilemap_draw(bitmap,cliprect,bg_tilemap[0],1,2);
+
+ /* we use the priority buffer so sprites are drawn front to back */
+ draw_sprites(machine,bitmap,cliprect,private_spriteram[1],1,0x0f00);
+ draw_sprites(machine,bitmap,cliprect,private_spriteram[0],0,0x4444);
+ }
+ else
+ {
+ tilemap_draw(bitmap,cliprect,bg_tilemap[0],TILEMAP_DRAW_OPAQUE|0,1);
+ tilemap_draw(bitmap,cliprect,bg_tilemap[0],TILEMAP_DRAW_OPAQUE|1,2);
+ tilemap_draw(bitmap,cliprect,bg_tilemap[1],1,4);
+ tilemap_draw(bitmap,cliprect,bg_tilemap[1],0,8);
+
+ /* we use the priority buffer so sprites are drawn front to back */
+ draw_sprites(machine,bitmap,cliprect,private_spriteram[1],1,0x0f00);
+ draw_sprites(machine,bitmap,cliprect,private_spriteram[0],0,0x4444);
+ }
+
+ if (K007121_ctrlram[0][0x01] & 0x08)
+ {
+ for (i = 0;i < 32;i++)
+ {
+ tilemap_set_scrollx(textlayer,i,combasc_scrollram0[0x20+i] ? 0 : TILE_LINE_DISABLED);
+ tilemap_draw(bitmap,cliprect,textlayer,0,0);
+ }
+ }
+
+ /* chop the extreme columns if necessary */
+ if (K007121_ctrlram[0][0x03] & 0x40)
+ {
+ rectangle clip;
+
+ clip = *cliprect;
+ clip.max_x = clip.min_x + 7;
+ fillbitmap(bitmap,machine->pens[0],&clip);
+
+ clip = *cliprect;
+ clip.min_x = clip.max_x - 7;
+ fillbitmap(bitmap,machine->pens[0],&clip);
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+
+/***************************************************************************
+
+ bootleg Combat School sprites. Each sprite has 5 bytes:
+
+byte #0: sprite number
+byte #1: y position
+byte #2: x position
+byte #3:
+ bit 0: x position (bit 0)
+ bits 1..3: ???
+ bit 4: flip x
+ bit 5: unused?
+ bit 6: sprite bank # (bit 2)
+ bit 7: ???
+byte #4:
+ bits 0,1: sprite bank # (bits 0 & 1)
+ bits 2,3: unused?
+ bits 4..7: sprite color
+
+***************************************************************************/
+
+static void bootleg_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, const UINT8 *source, int circuit )
+{
+ const gfx_element *gfx = machine->gfx[circuit+2];
+
+ int limit = ( circuit) ? (program_read_byte(0xc2)*256 + program_read_byte(0xc3)) : (program_read_byte(0xc0)*256 + program_read_byte(0xc1));
+ const UINT8 *finish;
+
+ source+=0x1000;
+ finish = source;
+ source+=0x400;
+ limit = (0x3400-limit)/8;
+ if( limit>=0 ) finish = source-limit*8;
+ source-=8;
+
+ while( source>finish )
+ {
+ UINT8 attributes = source[3]; /* PBxF ?xxX */
+ {
+ int number = source[0];
+ int x = source[2] - 71 + (attributes & 0x01)*256;
+ int y = 242 - source[1];
+ UINT8 color = source[4]; /* CCCC xxBB */
+
+ int bank = (color & 0x03) | ((attributes & 0x40) >> 4);
+
+ number = ((number & 0x02) << 1) | ((number & 0x04) >> 1) | (number & (~6));
+ number += 256*bank;
+
+ color = (circuit*4)*16 + (color >> 4);
+
+ /* hacks to select alternate palettes */
+// if(combasc_vreg == 0x40 && (attributes & 0x40)) color += 1*16;
+// if(combasc_vreg == 0x23 && (attributes & 0x02)) color += 1*16;
+// if(combasc_vreg == 0x66 ) color += 2*16;
+
+ drawgfx( bitmap, gfx,
+ number, color,
+ attributes & 0x10,0, /* flip */
+ x,y,
+ cliprect, TRANSPARENCY_PEN, 15 );
+ }
+ source -= 8;
+ }
+}
+
+VIDEO_UPDATE( combascb )
+{
+ int i;
+
+ for( i=0; i<32; i++ )
+ {
+ tilemap_set_scrollx( bg_tilemap[0],i, combasc_io_ram[0x040+i]+5 );
+ tilemap_set_scrollx( bg_tilemap[1],i, combasc_io_ram[0x060+i]+3 );
+ }
+ tilemap_set_scrolly( bg_tilemap[0],0, combasc_io_ram[0x000] );
+ tilemap_set_scrolly( bg_tilemap[1],0, combasc_io_ram[0x020] );
+
+ if (priority == 0)
+ {
+ tilemap_draw( bitmap,cliprect,bg_tilemap[1],TILEMAP_DRAW_OPAQUE,0);
+ bootleg_draw_sprites(machine, bitmap,cliprect, combasc_page[0], 0 );
+ tilemap_draw( bitmap,cliprect,bg_tilemap[0],0 ,0);
+ bootleg_draw_sprites(machine, bitmap,cliprect, combasc_page[1], 1 );
+ }
+ else
+ {
+ tilemap_draw( bitmap,cliprect,bg_tilemap[0],TILEMAP_DRAW_OPAQUE,0);
+ bootleg_draw_sprites(machine, bitmap,cliprect, combasc_page[0], 0 );
+ tilemap_draw( bitmap,cliprect,bg_tilemap[1],0 ,0);
+ bootleg_draw_sprites(machine, bitmap,cliprect, combasc_page[1], 1 );
+ }
+
+ tilemap_draw( bitmap,cliprect,textlayer,0,0);
+ return 0;
+}
diff --git a/src/mame/video/commando.c b/src/mame/video/commando.c
new file mode 100644
index 00000000000..16c5a533aec
--- /dev/null
+++ b/src/mame/video/commando.c
@@ -0,0 +1,140 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *commando_videoram2, *commando_colorram2;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+WRITE8_HANDLER( commando_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( commando_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( commando_videoram2_w )
+{
+ commando_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( commando_colorram2_w )
+{
+ commando_colorram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( commando_scrollx_w )
+{
+ static UINT8 scroll[2];
+
+ scroll[offset] = data;
+ tilemap_set_scrollx(bg_tilemap,0,scroll[0] | (scroll[1] << 8));
+}
+
+WRITE8_HANDLER( commando_scrolly_w )
+{
+ static UINT8 scroll[2];
+
+ scroll[offset] = data;
+ tilemap_set_scrolly(bg_tilemap,0,scroll[0] | (scroll[1] << 8));
+}
+
+WRITE8_HANDLER( commando_c804_w )
+{
+ // bits 0 and 1 are coin counters
+ coin_counter_w(0, data & 0x01);
+ coin_counter_w(1, data & 0x02);
+
+ // bit 4 resets the sound CPU
+ cpunum_set_input_line(1, INPUT_LINE_RESET, (data & 0x10) ? ASSERT_LINE : CLEAR_LINE);
+
+ // bit 7 flips screen
+ flip_screen_set(data & 0x80);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + ((attr & 0xc0) << 2);
+ int color = attr & 0x0f;
+ int flags = TILE_FLIPYX((attr & 0x30) >> 4);
+
+ SET_TILE_INFO(1, code, color, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = commando_colorram2[tile_index];
+ int code = commando_videoram2[tile_index] + ((attr & 0xc0) << 2);
+ int color = attr & 0x0f;
+ int flags = TILE_FLIPYX((attr & 0x30) >> 4);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( commando )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 3);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 4; offs >= 0; offs -= 4)
+ {
+ // bit 1 of attr is not used
+ int attr = buffered_spriteram[offs + 1];
+ int bank = (attr & 0xc0) >> 6;
+ int code = buffered_spriteram[offs] + 256 * bank;
+ int color = (attr & 0x30) >> 4;
+ int flipx = attr & 0x04;
+ int flipy = attr & 0x08;
+ int sx = buffered_spriteram[offs + 3] - ((attr & 0x01) << 8);
+ int sy = buffered_spriteram[offs + 2];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if (bank < 3)
+ drawgfx(bitmap,machine->gfx[2], code, color, flipx, flipy, sx, sy,
+ cliprect, TRANSPARENCY_PEN, 15);
+ }
+}
+
+VIDEO_UPDATE( commando )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
+
+VIDEO_EOF( commando )
+{
+ buffer_spriteram_w(0, 0);
+}
diff --git a/src/mame/video/compgolf.c b/src/mame/video/compgolf.c
new file mode 100644
index 00000000000..390df0fd4b5
--- /dev/null
+++ b/src/mame/video/compgolf.c
@@ -0,0 +1,132 @@
+/****************************************************************************************
+
+ Competition Golf Final Round
+ video hardware emulation
+
+****************************************************************************************/
+
+#include "driver.h"
+
+UINT8 *compgolf_bg_ram;
+static tilemap *text_tilemap, *background_tilemap;
+
+int compgolf_scrollx_lo = 0, compgolf_scrolly_lo = 0, compgolf_scrollx_hi = 0, compgolf_scrolly_hi = 0;
+
+PALETTE_INIT( compgolf )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+WRITE8_HANDLER( compgolf_video_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(text_tilemap, offset/2);
+}
+
+WRITE8_HANDLER( compgolf_back_w )
+{
+ compgolf_bg_ram[offset] = data;
+ tilemap_mark_tile_dirty(background_tilemap, offset/2);
+}
+
+static TILE_GET_INFO( get_text_info )
+{
+ tile_index<<=1;
+ SET_TILE_INFO(2, videoram[tile_index+1]|(videoram[tile_index]<<8), videoram[tile_index]>>2, 0);
+}
+
+static TILEMAP_MAPPER( back_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x0f) + ((row & 0x0f) << 4) + ((col & 0x10) << 4) + ((row & 0x10) << 5);
+}
+
+static TILE_GET_INFO( get_back_info )
+{
+ int attr = compgolf_bg_ram[tile_index*2];
+ int code = compgolf_bg_ram[tile_index*2+1] + ((attr & 1) << 8);
+ int color = (attr & 0x3e) >> 1;
+
+ SET_TILE_INFO(1,code,color,0);
+}
+
+VIDEO_START( compgolf )
+{
+ background_tilemap = tilemap_create(get_back_info,back_scan,TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+ text_tilemap = tilemap_create(get_text_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(text_tilemap,0);
+}
+
+/*
+preliminary sprite list:
+ 0 1 2 3
+xx------ xxxxxxxx -------- -------- sprite code
+---x---- -------- -------- -------- Double Height
+----x--- -------- -------- -------- Color,all of it?
+-------- -------- xxxxxxxx -------- Y pos
+-------- -------- -------- xxxxxxxx X pos
+-----x-- -------- -------- -------- Flip X
+-------- -------- -------- -------- Flip Y(used?)
+*/
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs,fx,fy,x,y,color,sprite;
+
+ for (offs = 0;offs < 0x60;offs += 4)
+ {
+ sprite = spriteram[offs+1] + (((spriteram[offs] & 0xc0) >> 6)*0x100);
+ x = 240 - spriteram[offs+3];
+ y = spriteram[offs+2];
+ color = (spriteram[offs] & 8)>>3;
+ fx = spriteram[offs]&4;
+ fy = 0; /* ? */
+
+ drawgfx(bitmap,machine->gfx[0],
+ sprite,
+ color,fx,fy,x,y,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ /* Double Height */
+ if(spriteram[offs] & 0x10)
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ sprite+1,
+ color,fx,fy,x,y+16,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( compgolf )
+{
+ int scrollx = compgolf_scrollx_hi + compgolf_scrollx_lo;
+ int scrolly = compgolf_scrolly_hi + compgolf_scrolly_lo;
+
+ tilemap_set_scrollx(background_tilemap,0,scrollx);
+ tilemap_set_scrolly(background_tilemap,0,scrolly);
+
+ tilemap_draw(bitmap, cliprect, background_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, text_tilemap, 0, 0);
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/contra.c b/src/mame/video/contra.c
new file mode 100644
index 00000000000..656d8139b9d
--- /dev/null
+++ b/src/mame/video/contra.c
@@ -0,0 +1,281 @@
+/***************************************************************************
+
+ gryzor: video.c
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+//static int spriteram_offset;
+static UINT8 *private_spriteram_2,*private_spriteram;
+
+UINT8 *contra_fg_vram,*contra_fg_cram;
+UINT8 *contra_text_vram,*contra_text_cram;
+UINT8 *contra_bg_vram,*contra_bg_cram;
+
+static tilemap *bg_tilemap, *fg_tilemap, *tx_tilemap;
+static rectangle bg_clip, fg_clip, tx_clip;
+
+/***************************************************************************
+**
+** Contra has palette RAM, but it also has four lookup table PROMs
+**
+** 0 sprites #0
+** 1 tiles #0
+** 2 sprites #1
+** 3 tiles #1
+**
+***************************************************************************/
+
+PALETTE_INIT( contra )
+{
+ int i,chip,pal,clut;
+
+ for (chip = 0;chip < 2;chip++)
+ {
+ for (pal = 0;pal < 8;pal++)
+ {
+ clut = (pal & 1) + 2 * chip;
+ for (i = 0;i < 256;i++)
+ {
+ if ((pal & 1) == 0) /* sprites */
+ {
+ if (color_prom[256 * clut + i] == 0)
+ *(colortable++) = 0;
+ else
+ *(colortable++) = 16 * pal + color_prom[256 * clut + i];
+ }
+ else
+ *(colortable++) = 16 * pal + color_prom[256 * clut + i];
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = contra_fg_cram[tile_index];
+ int bit0 = (K007121_ctrlram[0][0x05] >> 0) & 0x03;
+ int bit1 = (K007121_ctrlram[0][0x05] >> 2) & 0x03;
+ int bit2 = (K007121_ctrlram[0][0x05] >> 4) & 0x03;
+ int bit3 = (K007121_ctrlram[0][0x05] >> 6) & 0x03;
+ int bank = ((attr & 0x80) >> 7) |
+ ((attr >> (bit0+2)) & 0x02) |
+ ((attr >> (bit1+1)) & 0x04) |
+ ((attr >> (bit2 )) & 0x08) |
+ ((attr >> (bit3-1)) & 0x10) |
+ ((K007121_ctrlram[0][0x03] & 0x01) << 5);
+ int mask = (K007121_ctrlram[0][0x04] & 0xf0) >> 4;
+
+ bank = (bank & ~(mask << 1)) | ((K007121_ctrlram[0][0x04] & mask) << 1);
+
+ SET_TILE_INFO(
+ 0,
+ contra_fg_vram[tile_index]+bank*256,
+ ((K007121_ctrlram[0][6]&0x30)*2+16)+(attr&7),
+ 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = contra_bg_cram[tile_index];
+ int bit0 = (K007121_ctrlram[1][0x05] >> 0) & 0x03;
+ int bit1 = (K007121_ctrlram[1][0x05] >> 2) & 0x03;
+ int bit2 = (K007121_ctrlram[1][0x05] >> 4) & 0x03;
+ int bit3 = (K007121_ctrlram[1][0x05] >> 6) & 0x03;
+ int bank = ((attr & 0x80) >> 7) |
+ ((attr >> (bit0+2)) & 0x02) |
+ ((attr >> (bit1+1)) & 0x04) |
+ ((attr >> (bit2 )) & 0x08) |
+ ((attr >> (bit3-1)) & 0x10) |
+ ((K007121_ctrlram[1][0x03] & 0x01) << 5);
+ int mask = (K007121_ctrlram[1][0x04] & 0xf0) >> 4;
+
+ bank = (bank & ~(mask << 1)) | ((K007121_ctrlram[0][0x04] & mask) << 1);
+
+ SET_TILE_INFO(
+ 1,
+ contra_bg_vram[tile_index]+bank*256,
+ ((K007121_ctrlram[1][6]&0x30)*2+16)+(attr&7),
+ 0);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int attr = contra_text_cram[tile_index];
+ int bit0 = (K007121_ctrlram[0][0x05] >> 0) & 0x03;
+ int bit1 = (K007121_ctrlram[0][0x05] >> 2) & 0x03;
+ int bit2 = (K007121_ctrlram[0][0x05] >> 4) & 0x03;
+ int bit3 = (K007121_ctrlram[0][0x05] >> 6) & 0x03;
+ int bank = ((attr & 0x80) >> 7) |
+ ((attr >> (bit0+2)) & 0x02) |
+ ((attr >> (bit1+1)) & 0x04) |
+ ((attr >> (bit2 )) & 0x08) |
+ ((attr >> (bit3-1)) & 0x10);
+ SET_TILE_INFO(
+ 0,
+ contra_text_vram[tile_index]+bank*256,
+ ((K007121_ctrlram[0][6]&0x30)*2+16)+(attr&7),
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( contra )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,32,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,32,32);
+
+ private_spriteram = auto_malloc(0x800);
+ private_spriteram_2 = auto_malloc(0x800);
+
+ bg_clip = machine->screen[0].visarea;
+ bg_clip.min_x += 40;
+
+ fg_clip = bg_clip;
+
+ tx_clip = machine->screen[0].visarea;
+ tx_clip.max_x = 39;
+ tx_clip.min_x = 0;
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( contra_fg_vram_w )
+{
+ contra_fg_vram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE8_HANDLER( contra_fg_cram_w ){
+ contra_fg_cram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE8_HANDLER( contra_bg_vram_w )
+{
+ contra_bg_vram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( contra_bg_cram_w )
+{
+ contra_bg_cram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( contra_text_vram_w )
+{
+ contra_text_vram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+WRITE8_HANDLER( contra_text_cram_w )
+{
+ contra_text_cram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+WRITE8_HANDLER( contra_K007121_ctrl_0_w )
+{
+ if (offset == 3)
+ {
+ if ((data&0x8)==0)
+ memcpy(private_spriteram,spriteram+0x800,0x800);
+ else
+ memcpy(private_spriteram,spriteram,0x800);
+ }
+ if (offset == 6)
+ {
+ if (K007121_ctrlram[0][6] != data)
+ tilemap_mark_all_tiles_dirty( fg_tilemap );
+ }
+ if (offset == 7)
+ tilemap_set_flip(fg_tilemap,(data & 0x08) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ K007121_ctrl_0_w(offset,data);
+}
+
+WRITE8_HANDLER( contra_K007121_ctrl_1_w )
+{
+ if (offset == 3)
+ {
+ if ((data&0x8)==0)
+ memcpy(private_spriteram_2,spriteram+0x2800,0x800);
+ else
+ memcpy(private_spriteram_2,spriteram+0x2000,0x800);
+ }
+ if (offset == 6)
+ {
+ if (K007121_ctrlram[1][6] != data )
+ tilemap_mark_all_tiles_dirty( bg_tilemap );
+ }
+ if (offset == 7)
+ tilemap_set_flip(bg_tilemap,(data & 0x08) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ K007121_ctrl_1_w(offset,data);
+}
+
+
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int bank )
+{
+ const UINT8 *source;
+ int base_color = (K007121_ctrlram[bank][6]&0x30)*2;
+
+ if (bank==0) source=private_spriteram;
+ else source=private_spriteram_2;
+
+ K007121_sprites_draw(machine,bank,bitmap,cliprect,source,base_color,40,0,-1);
+}
+
+VIDEO_UPDATE( contra )
+{
+ rectangle bg_finalclip = bg_clip;
+ rectangle fg_finalclip = fg_clip;
+ rectangle tx_finalclip = tx_clip;
+
+ sect_rect(&bg_finalclip, cliprect);
+ sect_rect(&fg_finalclip, cliprect);
+ sect_rect(&tx_finalclip, cliprect);
+
+ tilemap_set_scrollx( fg_tilemap,0, K007121_ctrlram[0][0x00] - 40 );
+ tilemap_set_scrolly( fg_tilemap,0, K007121_ctrlram[0][0x02] );
+ tilemap_set_scrollx( bg_tilemap,0, K007121_ctrlram[1][0x00] - 40 );
+ tilemap_set_scrolly( bg_tilemap,0, K007121_ctrlram[1][0x02] );
+
+ tilemap_draw( bitmap,&bg_finalclip, bg_tilemap, 0 ,0);
+ tilemap_draw( bitmap,&fg_finalclip, fg_tilemap, 0 ,0);
+ draw_sprites( machine,bitmap,cliprect, 0 );
+ draw_sprites( machine,bitmap,cliprect, 1 );
+ tilemap_draw( bitmap,&tx_finalclip, tx_tilemap, 0 ,0);
+ return 0;
+}
diff --git a/src/mame/video/cop01.c b/src/mame/video/cop01.c
new file mode 100644
index 00000000000..0de69518f79
--- /dev/null
+++ b/src/mame/video/cop01.c
@@ -0,0 +1,226 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+UINT8 *cop01_bgvideoram,*cop01_fgvideoram;
+
+static UINT8 mightguy_vreg[4];
+static tilemap *bg_tilemap,*fg_tilemap;
+
+
+
+PALETTE_INIT( cop01 )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the lookup tables */
+
+ /* characters use colors 0-15 (or 0-127, but the eight rows are identical) */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = i;
+
+ /* background tiles use colors 192-255 */
+ /* I don't know how much of the lookup table PROM is hooked up, */
+ /* I'm only using the first 32 bytes because the rest is empty. */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = 0xc0 + (i & 0x30) + (color_prom[((i & 0x40) >> 2) + (i & 0x0f)] & 0x0f);
+ color_prom += 256;
+
+ /* sprites use colors 128-143 (or 128-191, but the four rows are identical) */
+ for (i = 0;i < TOTAL_COLORS(2);i++)
+ COLOR(2,i) = 0x80 + (*(color_prom++) & 0x0f);
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int tile = cop01_bgvideoram[tile_index];
+ int attr = cop01_bgvideoram[tile_index+0x800];
+ int pri = (attr & 0x80) >> 7;
+
+ /* kludge: priority is not actually pen based, but color based. Since the
+ * game uses a lookup table, the two are not the same thing.
+ * Palette entries with bits 2&3 set have priority over sprites.
+ * tilemap.c can't handle that yet, so I'm cheating, because I know that
+ * color codes using the second row of the lookup table don't use palette
+ * entries 12-15.
+ * The only place where this has any effect is the beach at the bottom of
+ * the screen right at the beginning of mightguy. cop01 doesn't seem to
+ * use priority at all.
+ */
+ if (attr & 0x10) pri = 0;
+
+ SET_TILE_INFO(1,tile + ((attr & 0x03) << 8),(attr & 0x1c) >> 2,0);
+ tileinfo->group = pri;
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int tile = cop01_fgvideoram[tile_index];
+ SET_TILE_INFO(0,tile,0,0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( cop01 )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,15);
+
+ /* priority doesn't exactly work this way, see above */
+ tilemap_set_transmask(bg_tilemap,0,0xffff,0x0000); /* split type 0 is totally transparent in front half */
+ tilemap_set_transmask(bg_tilemap,1,0x0fff,0xf000); /* split type 1 has pens 0-11 transparent in front half */
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( cop01_background_w )
+{
+ cop01_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x7ff);
+}
+
+WRITE8_HANDLER( cop01_foreground_w )
+{
+ cop01_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE8_HANDLER( cop01_vreg_w )
+{
+ /* 0x40: --xx---- sprite bank, coin counters, flip screen
+ * -----x-- flip screen
+ * ------xx coin counters
+ * 0x41: xxxxxxxx xscroll
+ * 0x42: ---xx--- ? matches the bg tile color most of the time, but not
+ * during level transitions. Maybe sprite palette bank?
+ * (the four banks in the PROM are identical)
+ * ------x- unused (xscroll overflow)
+ * -------x msb xscroll
+ * 0x43: xxxxxxxx yscroll
+ */
+ mightguy_vreg[offset] = data;
+
+ if (offset == 0)
+ {
+ coin_counter_w(0,data & 1);
+ coin_counter_w(1,data & 2);
+ flip_screen_set(data & 4);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs,code,attr,sx,sy,flipx,flipy,color;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ code = spriteram[offs+1];
+ attr = spriteram[offs+2];
+ /* xxxx---- color
+ * ----xx-- flipy,flipx
+ * -------x msbx
+ */
+ color = attr>>4;
+ flipx = attr & 0x04;
+ flipy = attr & 0x08;
+
+ sx = (spriteram[offs+3] - 0x80) + 256 * (attr & 0x01);
+ sy = 240 - spriteram[offs];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if (code&0x80)
+ code += (mightguy_vreg[0]&0x30)<<3;
+
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0 );
+ }
+}
+
+
+VIDEO_UPDATE( cop01 )
+{
+ tilemap_set_scrollx(bg_tilemap,0,mightguy_vreg[1] + 256 * (mightguy_vreg[2] & 1));
+ tilemap_set_scrolly(bg_tilemap,0,mightguy_vreg[3]);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0 );
+ return 0;
+}
diff --git a/src/mame/video/copsnrob.c b/src/mame/video/copsnrob.c
new file mode 100644
index 00000000000..45eb605ab19
--- /dev/null
+++ b/src/mame/video/copsnrob.c
@@ -0,0 +1,159 @@
+/***************************************************************************
+
+ Atari Cops'n Robbers hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "copsnrob.h"
+
+
+UINT8 *copsnrob_bulletsram;
+UINT8 *copsnrob_carimage;
+UINT8 *copsnrob_cary;
+UINT8 *copsnrob_trucky;
+UINT8 *copsnrob_truckram;
+
+
+VIDEO_UPDATE( copsnrob )
+{
+ int offs, x, y;
+
+ /* redrawing the entire display is faster in this case */
+
+ for (offs = videoram_size;offs >= 0;offs--)
+ {
+ int sx,sy;
+
+ sx = 31 - (offs % 32);
+ sy = offs / 32;
+
+ drawgfx(bitmap,machine->gfx[0],
+ videoram[offs] & 0x3f,0,
+ 0,0,
+ 8*sx,8*sy,
+ cliprect,TRANSPARENCY_NONE,0);
+ }
+
+
+ /* Draw the cars. Positioning was based on a screen shot */
+ if (copsnrob_cary[0])
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ copsnrob_carimage[0],0,
+ 1,0,
+ 0xe4,256-copsnrob_cary[0],
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ if (copsnrob_cary[1])
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ copsnrob_carimage[1],0,
+ 1,0,
+ 0xc4,256-copsnrob_cary[1],
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ if (copsnrob_cary[2])
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ copsnrob_carimage[2],0,
+ 0,0,
+ 0x24,256-copsnrob_cary[2],
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ if (copsnrob_cary[3])
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ copsnrob_carimage[3],0,
+ 0,0,
+ 0x04,256-copsnrob_cary[3],
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+
+ /* Draw the beer truck. Positioning was based on a screen shot.
+ We scan the truck's window RAM for a location whose bit is set and
+ which corresponds either to the truck's front end or the truck's back
+ end (based on the value of the truck image line sync register). We
+ then draw a truck image in the proper place and continue scanning.
+ This is not a perfect emulation of the game hardware, but it should
+ suffice for the way the game software uses the hardware. It does take
+ care of the problem of displaying multiple beer trucks and of scrolling
+ truck images smoothly off the top of the screen. */
+
+ for (y = 0; y < 256; y++)
+ {
+ /* y is going up the screen, but the truck window RAM locations
+ go down the screen. */
+
+ if (copsnrob_truckram[255-y])
+ {
+ /* The hardware only uses the low 5 bits of the truck image line
+ sync register. */
+ if ((copsnrob_trucky[0] & 0x1f) == ((y+31) & 0x1f))
+ {
+ /* We've hit a truck's back end, so draw the truck. The front
+ end may be off the top of the screen, but we don't care. */
+ drawgfx(bitmap,machine->gfx[2],
+ 0,0,
+ 0,0,
+ 0x80,256-(y+31),
+ cliprect,TRANSPARENCY_PEN,0);
+ /* Skip past this truck's front end so we don't draw this
+ truck twice. */
+ y += 31;
+ }
+ else if ((copsnrob_trucky[0] & 0x1f) == (y & 0x1f))
+ {
+ /* We missed a truck's back end (it was off the bottom of the
+ screen) but have hit its front end, so draw the truck. */
+ drawgfx(bitmap,machine->gfx[2],
+ 0,0,
+ 0,0,
+ 0x80,256-y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+
+
+ /* Draw the bullets.
+ They are flickered on/off every frame by the software, so don't
+ play it with frameskip 1 or 3, as they could become invisible */
+
+ for (x = 0; x < 256; x++)
+ {
+ int bullet, mask1, mask2, val;
+
+
+ val = copsnrob_bulletsram[x];
+
+ // Check for the most common case
+ if (!(val & 0x0f)) continue;
+
+ mask1 = 0x01;
+ mask2 = 0x10;
+
+ // Check each bullet
+ for (bullet = 0; bullet < 4; bullet++)
+ {
+ if (val & mask1)
+ {
+ for (y = 0; y <= machine->screen[0].visarea.max_y; y++)
+ {
+ if (copsnrob_bulletsram[y] & mask2)
+ {
+ *BITMAP_ADDR16(bitmap, y, 256-x) = machine->pens[1];
+ }
+ }
+ }
+
+ mask1 <<= 1;
+ mask2 <<= 1;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/cosmic.c b/src/mame/video/cosmic.c
new file mode 100644
index 00000000000..b7aebdfa96b
--- /dev/null
+++ b/src/mame/video/cosmic.c
@@ -0,0 +1,667 @@
+/***************************************************************************
+
+ COSMIC.C
+
+ emulation of video hardware of cosmic machines of 1979-1980(ish)
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+static pen_t (*map_color)(UINT8 x, UINT8 y);
+
+static int color_registers[3];
+static int background_enable;
+static int magspot_pen_mask;
+
+
+
+WRITE8_HANDLER( cosmic_color_register_w )
+{
+ color_registers[offset] = data ? 1 : 0;
+}
+
+
+static pen_t panic_map_color(UINT8 x, UINT8 y)
+{
+ offs_t offs;
+ pen_t pen;
+
+
+ offs = (color_registers[0] << 9) | (color_registers[2] << 10) | ((x >> 4) << 5) | (y >> 3);
+ pen = memory_region(REGION_USER1)[offs];
+
+ if (color_registers[1])
+ pen >>= 4;
+
+ return pen & 0x0f;
+}
+
+static pen_t cosmica_map_color(UINT8 x, UINT8 y)
+{
+ offs_t offs;
+ pen_t pen;
+
+
+ offs = (color_registers[0] << 9) | ((x >> 4) << 5) | (y >> 3);
+ pen = memory_region(REGION_USER1)[offs];
+
+ if (color_registers[0]) /* yes, 0 again according to the schematics */
+ pen >>= 4;
+
+ return pen & 0x07;
+}
+
+static pen_t cosmicg_map_color(UINT8 x, UINT8 y)
+{
+ offs_t offs;
+ pen_t pen;
+
+
+ offs = (color_registers[0] << 8) | (color_registers[1] << 9) | ((y >> 4) << 4) | (x >> 4);
+ pen = memory_region(REGION_USER1)[offs];
+
+ /* the upper 4 bits are for cocktail mode support */
+
+ return pen & 0x0f;
+}
+
+static pen_t magspot2_map_color(UINT8 x, UINT8 y)
+{
+ offs_t offs;
+ pen_t pen;
+
+
+ offs = (color_registers[0] << 9) | ((x >> 3) << 4) | (y >> 4);
+ pen = memory_region(REGION_USER1)[offs];
+
+ if (color_registers[1])
+ pen >>= 4;
+
+ return pen & magspot_pen_mask;
+}
+
+
+
+/*
+ * Panic Color table setup
+ *
+ * Bit 0 = RED, Bit 1 = GREEN, Bit 2 = BLUE
+ *
+ * First 8 colors are normal intensities
+ *
+ * But, bit 3 can be used to pull Blue via a 2k resistor to 5v
+ * (1k to ground) so second version of table has blue set to 2/3
+ */
+
+PALETTE_INIT( panic )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int r = 0xff * ((i >> 0) & 1);
+ int g = 0xff * ((i >> 1) & 1);
+ int b;
+ if ((i & 0x0c) == 0x08)
+ b = 0xaa;
+ else
+ b = 0xff * ((i >> 2) & 1);
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = *(color_prom++) & 0x07;
+
+
+ map_color = panic_map_color;
+}
+
+
+/*
+ * Cosmic Alien Color table setup
+ *
+ * 8 colors, 16 sprite color codes
+ *
+ * Bit 0 = RED, Bit 1 = GREEN, Bit 2 = BLUE
+ *
+ */
+
+PALETTE_INIT( cosmica )
+{
+ int i;
+
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ palette_set_color_rgb(machine,i,pal1bit(i >> 0),pal1bit(i >> 1),pal1bit(i >> 2));
+
+
+ for (i = 0;i < TOTAL_COLORS(0)/2;i++)
+ {
+ COLOR(0,i) = * color_prom & 0x07;
+ COLOR(0,i+(TOTAL_COLORS(0)/2)) = (*(color_prom++) >> 4) & 0x07;
+ }
+
+
+ map_color = cosmica_map_color;
+}
+
+
+/*
+ * Cosmic guerilla table setup
+ *
+ * Use AA for normal, FF for Full Red
+ * Bit 0 = R, bit 1 = G, bit 2 = B, bit 4 = High Red
+ *
+ * It's possible that the background is dark gray and not black, as the
+ * resistor chain would never drop to zero, Anybody know ?
+ */
+
+PALETTE_INIT( cosmicg )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int r,g,b;
+
+ if (i > 8) r = 0xff;
+ else r = 0xaa * ((i >> 0) & 1);
+
+ g = 0xaa * ((i >> 1) & 1);
+ b = 0xaa * ((i >> 2) & 1);
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+
+ map_color = cosmicg_map_color;
+}
+
+PALETTE_INIT( magspot2 )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int r,g,b;
+
+ if ((i & 0x09) == 0x08)
+ r = 0xaa;
+ else
+ r = 0xff * ((i >> 0) & 1);
+
+ g = 0xff * ((i >> 1) & 1);
+ b = 0xff * ((i >> 2) & 1);
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ {
+ COLOR(0,i) = *(color_prom++) & 0x0f;
+ }
+
+
+ map_color = magspot2_map_color;
+ magspot_pen_mask = 0x0f;
+}
+
+
+PALETTE_INIT( nomnlnd )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ palette_set_color_rgb(machine,i,pal1bit(i >> 0),pal1bit(i >> 1),pal1bit(i >> 2));
+
+
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ {
+ COLOR(0,i) = *(color_prom++) & 0x07;
+ }
+
+
+ map_color = magspot2_map_color;
+ magspot_pen_mask = 0x07;
+}
+
+
+WRITE8_HANDLER( cosmic_background_enable_w )
+{
+ background_enable = data;
+}
+
+
+static void draw_bitmap(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ offs_t offs;
+
+
+ for (offs = 0; offs < videoram_size; offs++)
+ {
+ UINT8 data = videoram[offs];
+
+ if (data != 0) /* optimization, not absolutely neccessary */
+ {
+ int i;
+ UINT8 x = offs << 3;
+ UINT8 y = offs >> 5;
+
+ pen_t pen = machine->pens[map_color(x, y)];
+
+
+ for (i = 0; i < 8; i++)
+ {
+ if (data & 0x80)
+ {
+ if (flip_screen)
+ *BITMAP_ADDR16(bitmap, 255-y, 255-x) = pen;
+ else
+ *BITMAP_ADDR16(bitmap, y, x) = pen;
+ }
+
+ x++;
+ data <<= 1;
+ }
+ }
+ }
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int color_mask, int extra_sprites)
+{
+ int offs;
+
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ if (spriteram[offs] != 0)
+ {
+ int code, color;
+
+ code = ~spriteram[offs ] & 0x3f;
+ color = ~spriteram[offs+3] & color_mask;
+
+ if (extra_sprites)
+ {
+ code |= (spriteram[offs+3] & 0x08) << 3;
+ }
+
+ if (spriteram[offs] & 0x80)
+ {
+ /* 16x16 sprite */
+
+ drawgfx(bitmap,machine->gfx[0],
+ code, color,
+ 0, ~spriteram[offs] & 0x40,
+ 256-spriteram[offs+2],spriteram[offs+1],
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ /* 32x32 sprite */
+
+ drawgfx(bitmap,machine->gfx[1],
+ code >> 2, color,
+ 0, ~spriteram[offs] & 0x40,
+ 256-spriteram[offs+2],spriteram[offs+1],
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+}
+
+
+static void cosmica_draw_starfield(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 y = 0;
+ UINT8 map = 0;
+ UINT8 *PROM = memory_region(REGION_USER2);
+
+
+ while (1)
+ {
+ int va = y & 0x01;
+ int vb = (y >> 1) & 0x01;
+
+
+ UINT8 x = 0;
+
+ while (1)
+ {
+ UINT8 x1;
+ int hc, hb_;
+
+
+ if (flip_screen)
+ x1 = x - cpu_getcurrentframe();
+ else
+ x1 = x + cpu_getcurrentframe();
+
+
+ hc = (x1 >> 2) & 0x01;
+ hb_ = (x >> 5) & 0x01; /* not a bug, this one is the real x */
+
+
+ if ((x1 & 0x1f) == 0)
+ {
+ // flip-flop at IC11 is clocked
+ map = PROM[(x1 >> 5) | (y >> 1 << 3)];
+ }
+
+
+ if ((!(hc & va) & (vb ^ hb_)) && /* right network */
+ (((x1 ^ map) & (hc | 0x1e)) == 0x1e)) /* left network */
+ {
+ /* RGB order is reversed -- bit 7=R, 6=G, 5=B */
+ int col = (map >> 7) | ((map >> 5) & 0x02) | ((map >> 3) & 0x04);
+
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[col];
+ }
+
+
+ x++;
+ if (x == 0) break;
+ }
+
+
+ y++;
+ if (y == 0) break;
+ }
+}
+
+
+static void devzone_draw_grid(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 y;
+ UINT8 *horz_PROM = memory_region(REGION_USER2);
+ UINT8 *vert_PROM = memory_region(REGION_USER3);
+ offs_t horz_addr = 0;
+
+ UINT8 count = 0;
+ UINT8 horz_data = 0;
+ UINT8 vert_data;
+
+
+ for (y = 32; y < 224; y++)
+ {
+ UINT8 x = 0;
+
+
+ while (1)
+ {
+ int x1;
+
+
+ /* for the vertical lines, each bit indicates
+ if there should be a line at the x position */
+ vert_data = vert_PROM[x >> 3];
+
+
+ /* the horizontal (perspective) lines are RLE encoded.
+ When the screen is flipped, the address should be
+ decrementing. But since it's just a mirrored image,
+ this is easier. */
+ if (count == 0)
+ {
+ count = horz_PROM[horz_addr++];
+ }
+
+ count++;
+
+ if (count == 0)
+ {
+ horz_data = horz_PROM[horz_addr++];
+ }
+
+
+ for (x1 = 0; x1 < 8; x1++)
+ {
+ if (!(vert_data & horz_data & 0x80)) /* NAND gate */
+ {
+ pen_t pen = machine->pens[4]; /* blue */
+
+ if (flip_screen)
+ *BITMAP_ADDR16(bitmap, 255-y, 255-x) = pen;
+ else
+ *BITMAP_ADDR16(bitmap, y, x) = pen;
+ }
+
+ horz_data = (horz_data << 1) | 0x01;
+ vert_data = (vert_data << 1) | 0x01;
+
+ x++;
+ }
+
+
+ if (x == 0) break;
+ }
+ }
+}
+
+
+static void nomnlnd_draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 y = 0;
+ UINT8 water = cpu_getcurrentframe();
+ UINT8 *PROM = memory_region(REGION_USER2);
+
+
+ /* all positioning is via logic gates:
+
+ tree is displayed where
+
+ __ __
+ HD' ^ HC' ^ HB'
+
+ and
+ __ __ __
+ (VB' ^ VC' ^ VD') X (VB' ^ VC' ^ VD')
+
+
+ water is displayed where
+ __ __
+ HD' ^ HC' ^ HB ^ HA'
+
+ and vertically the same equation as the trees,
+ but final result inverted.
+
+
+ The colors are coded in logic gates:
+
+ trees:
+ P1 P2 BGR
+ R = Plane1 ^ Plane2 0 0 000
+ G = Plane2 0 1 010
+ B = Plane1 ^ ~Plane2 1 0 100
+ 1 1 011
+
+ water:
+ P1 P2 BGR or
+ R = Plane1 ^ Plane2 0 0 100 000
+ G = Plane2 v Plane2 0 1 110 010
+ B = ~Plane1 or 1 0 010 010
+ 0 based oh HD 1 1 011 011
+
+ Not sure about B, the logic seems convulated for such
+ a simple result.
+
+ */
+
+ while (1)
+ {
+ int vb_ = (y >> 5) & 0x01;
+ int vc_ = (y >> 6) & 0x01;
+ int vd_ = y >> 7;
+
+ UINT8 x = 0;
+
+
+ while (1)
+ {
+ int color = 0;
+
+ int hd = (x >> 3) & 0x01;
+ int ha_ = (x >> 4) & 0x01;
+ int hb_ = (x >> 5) & 0x01;
+ int hc_ = (x >> 6) & 0x01;
+ int hd_ = x >> 7;
+
+
+ if ((!vb_ & vc_ & !vd_) ^ (vb_ & !vc_ & vd_))
+ {
+ /* tree */
+ if (!hd_ & hc_ & !hb_)
+ {
+ offs_t offs = ((x >> 3) & 0x03) | ((y & 0x1f) << 2) |
+ (flip_screen ? 0x80 : 0);
+
+ UINT8 plane1 = PROM[offs ] << (x & 0x07);
+ UINT8 plane2 = PROM[offs | 0x0400] << (x & 0x07);
+
+ plane1 >>= 7;
+ plane2 >>= 7;
+
+ color = (plane1 & plane2) | // R
+ (plane2 ) << 1 | // G
+ (plane1 & !plane2) << 2; // B
+ }
+ }
+ else
+ {
+ /* water */
+ if (hd_ & !hc_ & hb_ & !ha_)
+ {
+ offs_t offs = hd | (water << 1) | 0x0200;
+
+ UINT8 plane1 = PROM[offs ] << (x & 0x07);
+ UINT8 plane2 = PROM[offs | 0x0400] << (x & 0x07);
+
+ plane1 >>= 7;
+ plane2 >>= 7;
+
+ color = ( plane1 & plane2) | // R
+ ( plane1 | plane2) << 1 | // G
+ (!plane1 & hd) << 2; // B - see above
+ }
+ }
+
+
+ if (color != 0)
+ {
+ pen_t pen = machine->pens[color];
+
+ if (flip_screen)
+ *BITMAP_ADDR16(bitmap, 255-y, 255-x) = pen;
+ else
+ *BITMAP_ADDR16(bitmap, y, x) = pen;
+ }
+
+
+ x++;
+ if (x == 0) break;
+ }
+
+
+ // this is obviously wrong
+// if (vb_)
+// {
+ water++;
+// }
+
+
+ y++;
+ if (y == 0) break;
+ }
+}
+
+
+VIDEO_UPDATE( cosmicg )
+{
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ draw_bitmap(machine, bitmap, cliprect);
+ return 0;
+}
+
+
+VIDEO_UPDATE( panic )
+{
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ draw_bitmap(machine, bitmap, cliprect);
+
+ draw_sprites(machine, bitmap, cliprect, 0x07, 1);
+ return 0;
+}
+
+
+VIDEO_UPDATE( cosmica )
+{
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ cosmica_draw_starfield(machine, bitmap, cliprect);
+
+ draw_bitmap(machine, bitmap, cliprect);
+
+ draw_sprites(machine, bitmap, cliprect, 0x0f, 0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( magspot2 )
+{
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ draw_bitmap(machine, bitmap, cliprect);
+
+ draw_sprites(machine, bitmap, cliprect, 0x07, 0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( devzone )
+{
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ if (background_enable)
+ {
+ devzone_draw_grid(machine, bitmap, cliprect);
+ }
+
+ draw_bitmap(machine, bitmap, cliprect);
+
+ draw_sprites(machine, bitmap, cliprect, 0x07, 0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( nomnlnd )
+{
+ /* according to the video summation logic on pg4, the trees and river
+ have the highest priority */
+
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ draw_bitmap(machine, bitmap, cliprect);
+
+ draw_sprites(machine, bitmap, cliprect, 0x07, 0);
+
+ if (background_enable)
+ {
+ nomnlnd_draw_background(machine, bitmap, cliprect);
+ }
+ return 0;
+}
diff --git a/src/mame/video/cps1.c b/src/mame/video/cps1.c
new file mode 100644
index 00000000000..1ee5e333d8d
--- /dev/null
+++ b/src/mame/video/cps1.c
@@ -0,0 +1,1955 @@
+/***************************************************************************
+
+These are some of the CPS-B chip numbers:
+
+NAME CPS-B # C-board PAL's B-board PAL's
+Forgotten Worlds / Lost Worlds CPS-B-01 DL-0411-10001 None LWCH1 & LW10
+Ghouls 'n Ghosts CPS-B-01 DL-0411-10001 None DM620, LW10
+Strider CPS-B-01 DL-0411-10001 None ST24N1 & LW10 or ST22B
+Dynasty Wars CPS-B-02 DL-0411-10002 ? ?
+Willow CPS-B-03 DL-0411-10003 None WL24B & LW10
+UN Squadron / Area 88 CPS-B-11 DL-0411-10004 None AR24B & LW10
+Street Fighter II (ETC Rev G) CPS-B-11 DL-0411-10004 None STF29 & IOB1
+Final Fight (World / Japan) CPS-B-04 DL-0411-10005 None S224B & LW10
+Final Fight (US) CPS-B-04* DL-0411-10001 None S224B & LW10
+ *actually CPS-B-01, the original number was scratched out and "04" stamped over it
+Varth CPS-B-04 DL-0411-10005 None VA24B & LW10
+1941 CPS-B-05 DL-0411-10006 ? YI24B & ?
+Street Fighter II (US Rev D) CPS-B-05 DL-0411-10006 C632 STF29 & IOB1
+Mercs (US) CPS-B-12 DL-0411-10007 C628 0224B & IOB1
+Street Fighter II (Japan Rev C) CPS-B-12 DL-0411-10007 C632 STF29 & IOB1
+Magic Sword (US) CPS-B-13 DL-0411-10008 None MS24B & IOB1
+Street Fighter II (Japan) CPS-B-13 DL-0411-10008 C632 STF29 & IOB1
+Chiki Chiki Boys / Mega Twins CPS-B-14 DL-0411-10009 ? ?
+Street Fighter II (US Rev I) CPS-B-14 DL-0411-10009 C632 STF29 & IOB1
+Nemo CPS-B-15 DL-0411-10010 ? NM24B & ?
+Carrier Air Wing CPS-B-16 DL-0411-10011 None CA24B & IOB1
+Street Fighter II CPS-B-17 DL-0411-10012 C632 STF29 & IOB1
+Three Wonders* CPS-B-21 DL-0921-10014 IOC1 & C632 RT24B & IOB1
+King of Dragons* CPS-B-21 DL-0921-10014 IOC1 & C632 KD29B & IOB1
+Captain Commando* (US) CPS-B-21 DL-0921-10014 IOC1 & C632 CC63B, CCPRG & IOB1
+Knights of the Round* CPS-B-21 DL-0921-10014 IOC1 & C632 KR63B, BPRG1 & IOB1
+Street Fighter II' Champion Edition CPS-B-21 DL-0921-10014 IOC1 & C632 S9263B, BPRG1 & IOB1
+Capcom World 2* CPS-B-21 DL-0921-10014 IOC1 Q522B & IOB1
+Quiz and Dragons* CPS-B-21 DL-0921-10014 IOC1 QD22B & IOB1
+Warriors of Fate* CPS-B-21 DL-0921-10014 IOC1 TK263B, BPRG1 & IOB1
+Street Fighter II Turbo Hyper Fighting CPS-B-21 DL-0921-10014 IOC1 & C632 S9263B, BPRG1 & IOB1
+Cadillacs and Dinosaurs* CPS-B-21 DL-0921-10014 IOC1 CD63B, BPRG1 & IOB1
+Punisher* CPS-B-21 DL-0921-10014 IOC1 PS63B, BPRG1 & IOB1
+Saturday Night Slam Masters* CPS-B-21 DL-0921-10014 IOC1 MB63B, BPRG1 & IOB1
+Muscle Bomber Duo* CPS-B-21 DL-0921-10014 ? ?
+Pnickies CPS-B-21? DL-0921-10014? ? ?
+Pang 3 CPS-B-21 DL-0921-10014 IOC1 & C632 CP1B1F, CP1B8K & CP1B9KA
+Megaman the Power Battle CPS-B-21 DL-0921-10014 IOC1 & C632 RCM63B, BPRG1 & IOB1
+
+Street Fighter Zero changer system (Japan) CPS-B-21 DL-0921-10014 ? ?
+
+*denotes Suicide Battery
+
+You can set the suicide CPS-B-21 chips to their default layer register and priority bit values
+if you pull pins 45 and 46 high (floating the pins seems to work, too). The default is the same
+values as Street Fighter 2 CE/Turbo.
+
+
+
+OUTPUT PORTS
+0x00-0x01 OBJ RAM base (/256)
+0x02-0x03 Scroll1 (8x8) RAM base (/256)
+0x04-0x05 Scroll2 (16x16) RAM base (/256)
+0x06-0x07 Scroll3 (32x32) RAM base (/256)
+0x08-0x09 rowscroll RAM base (/256)
+0x0a-0x0b Palette base (/256)
+0x0c-0x0d Scroll 1 X
+0x0e-0x0f Scroll 1 Y
+0x10-0x11 Scroll 2 X
+0x12-0x13 Scroll 2 Y
+0x14-0x15 Scroll 3 X
+0x16-0x17 Scroll 3 Y
+0x18-0x19 Starfield 1 X
+0x1a-0x1b Starfield 1 Y
+0x1c-0x1d Starfield 2 X
+0x1e-0x1f Starfield 2 Y
+0x20-0x21 start offset for the rowscroll matrix
+0x22-0x23 unknown but widely used - usually 0x0e. bit 0 enables rowscroll
+ on layer 2. bit 15 is flip screen.
+
+
+Some registers move from game to game.. following example strider
+0x66-0x67 Layer control register
+ bits 14-15 seem to be unused
+ ghouls sets bits 15 in service mode when you press button 2 in
+ the input test
+ bits 6-13 (4 groups of 2 bits) select layer draw order
+ bits 1-5 enable the three tilemap layers and the two starfield
+ layers (the bit order changes from game to game).
+ Only Forgotten Worlds and Strider use the starfield.
+ bit 0 could be rowscroll related. It is set by captain commando,
+ varth, mtwins, mssword, cawing while rowscroll is active. However
+ kodj and sf2 do NOT set this bit while they are using rowscroll.
+ Games known to use row scrolling:
+ SF2
+ Mega Twins (underwater, cave)
+ Carrier Air Wing (hazy background at beginning of mission 8, put 07 at ff8501 to jump there)
+ Magic Sword (fire on floor 3; screen distort after continue)
+ Varth (title screen)
+ Captain Commando (end game sequence)
+0x68-0x69 Priority mask \ Tiles in the layer just below sprites can have
+0x6a-0x6b Priority mask | four priority levels, each one associated with one
+0x6c-0x6d Priority mask | of these masks. The masks indicate pens in the tile
+0x6e-0x6f Priority mask / that have priority over sprites.
+0x70-0x71 Control register (usually 0x003f). The details of how this register
+ works are unknown, but it definitely affects the palette; experiments
+ on the real board show that values different from 0x3f in the low 6
+ bits cause wrong colors. The other bits seem to be unused.
+ There is one CPS2 game (Slammasters II) setting this to 0x2f: the
+ purpose is unknown.
+ The only other places where this register seems to be set to a value
+ different from 0x3f is during startup tests. Examples:
+ ghouls 0x02
+ strider 0x02
+ unsquad 0x0f
+ kod 0x0f
+ mtwins 0x0f
+
+Fixed registers
+0x80-0x81 Sound command
+0x88-0x89 Sound fade
+
+Known Bug List
+==============
+CPS2:
+* CPS2 can do raster effects, certainly used by ssf2 (Cammy, DeeJay, T.Hawk levels),
+ msh (lava level, early in attract mode) and maybe others (xmcotaj, vsavj).
+ IRQ4 is some sort of scanline interrupt used for that purpose.
+
+* Its unknown what CPS2_OBJ_BASE register (0x400000) does but it is not a object base
+ register. All games use 0x7000 even if 0x7080 is used at this register (checked on
+ real HW). Maybe it sets the object bank used when cps2_objram_bank is set.
+
+* Sprites are currently lagged by one frame to keep sync with backgrounds. This causes
+ sprites to stay on screen one frame longer (visable in VSAV attract mode).
+
+Marvel Vs. Capcom
+* Sometimes currupt gfx are displayed on the 32x32 layer as the screen flashes at the
+ start of super combo moves. The problem seems to be due to tiles being fetched before
+ the first 32x32 tile offset and results in data coming from 16x16 or 8x8 tiles instead.
+
+CPS1:
+SF2
+* Missing chain in the foreground in Ken's level, and sign in Cun Li's level.
+ Those graphics are in the backmost layer.
+
+UN Squadron
+* DOT TEST in service mode shows garbage chars
+
+Magic Sword.
+* during attract mode, characters are shown with a black background. There is
+a background, but the layers are disabled. I think this IS the correct
+behaviour.
+
+King of Dragons (World).
+* Distortion effect missing on character description screen during attract
+mode. The game rapidly toggles on and off the layer enable bit. Again, I
+think this IS the correct behaviour. The Japanese version does the
+distortion as expected.
+
+3wonders
+* one bad tile at the end of level 1
+* writes to output ports 42, 44, 46.
+
+qad
+* layer enable mask incomplete
+
+wof
+* In round 8, when the player goes over a bridge, there is a problem with
+some sprites. When an enemy falls to the floor near the edge of the bridge,
+parts of it become visible under the bridge.
+
+
+Unknown issues
+==============
+
+There are often some redundant high bits in the scroll layer's attributes.
+I think that these are spare bits that the game uses for to store additional
+information, not used by the hardware.
+The games seem to use them to mark platforms, kill zones and no-go areas.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "cps1.h"
+
+#define VERBOSE 0
+
+#define CPS1_DUMP_VIDEO 0
+
+/********************************************************************
+
+ Configuration table:
+
+********************************************************************/
+
+/* Game specific data */
+struct CPS1config
+{
+ const char *name; /* game driver name */
+
+ /* Some games interrogate a couple of registers on bootup. */
+ /* These are CPS1 board B self test checks. They wander from game to */
+ /* game. */
+ int cpsb_addr; /* CPS board B test register address */
+ int cpsb_value; /* CPS board B test register expected value */
+
+ /* some games use as a protection check the ability to do 16-bit multiplies */
+ /* with a 32-bit result, by writing the factors to two ports and reading the */
+ /* result from two other ports. */
+ /* It looks like this feature was introduced with 3wonders (CPSB ID = 08xx) */
+ int mult_factor1;
+ int mult_factor2;
+ int mult_result_lo;
+ int mult_result_hi;
+
+ int layer_control;
+ int priority[4];
+ int control_reg; /* Control register? seems to be always 0x3f */
+
+ /* ideally, the layer enable masks should consist of only one bit, */
+ /* but in many cases it is unknown which bit is which. */
+ int layer_enable_mask[5];
+
+ int bank_scroll1;
+ int bank_scroll2;
+ int bank_scroll3;
+
+ /* Some characters aren't visible */
+ const int start_scroll2;
+ const int end_scroll2;
+ const int start_scroll3;
+ const int end_scroll3;
+
+ int kludge; /* Ghouls n Ghosts sprite kludge */
+};
+
+struct CPS1config *cps1_game_config;
+
+/* CPSB ID multiply protection ctrl priority masks unknwn layer enable masks */
+#define CPS_B_01 0x00,0x0000, 0,0,0,0, /* n/a */ 0x66,{0x68,0x6a,0x6c,0x6e},0x70, {0x02,0x04,0x08,0x30,0x30}
+#define CPS_B_02 0x60,0x0002, 0,0,0,0, /* n/a */ 0x6c,{0x6a,0x68,0x66,0x64},0x62, {0x02,0x04,0x08,0x00,0x00}
+#define CPS_B_03 0x00,0x0000, 0,0,0,0, /* n/a */ 0x70,{0x6e,0x6c,0x6a,0x68},0x66, {0x20,0x10,0x08,0x00,0x00}
+#define CPS_B_04 0x60,0x0004, 0,0,0,0, /* n/a */ 0x6e,{0x66,0x70,0x68,0x72},0x6a, {0x02,0x0c,0x0c,0x00,0x00}
+#define CPS_B_05 0x60,0x0005, 0,0,0,0, /* n/a */ 0x68,{0x6a,0x6c,0x6e,0x70},0x72, {0x02,0x08,0x20,0x14,0x14}
+#define CPS_B_11 0x72,0x0401, 0,0,0,0, /* n/a */ 0x66,{0x68,0x6a,0x6c,0x6e},0x70, {0x08,0x10,0x20,0x00,0x00}
+#define CPS_B_12 0x60,0x0402, 0,0,0,0, /* n/a */ 0x6c,{0x6a,0x68,0x66,0x64},0x62, {0x02,0x04,0x08,0x00,0x00}
+#define CPS_B_13 0x6e,0x0403, 0,0,0,0, /* n/a */ 0x62,{0x64,0x66,0x68,0x6a},0x6c, {0x20,0x02,0x04,0x00,0x00}
+#define CPS_B_14 0x5e,0x0404, 0,0,0,0, /* n/a */ 0x52,{0x54,0x56,0x58,0x5a},0x5c, {0x08,0x20,0x10,0x00,0x00}
+#define CPS_B_15 0x4e,0x0405, 0,0,0,0, /* n/a */ 0x42,{0x44,0x46,0x48,0x4a},0x4c, {0x04,0x02,0x20,0x00,0x00}
+#define CPS_B_16 0x40,0x0406, 0,0,0,0, /* n/a */ 0x4c,{0x4a,0x48,0x46,0x44},0x42, {0x10,0x0a,0x0a,0x00,0x00}
+#define CPS_B_17 0x48,0x0407, 0,0,0,0, /* n/a */ 0x54,{0x52,0x50,0x4e,0x4c},0x4a, {0x08,0x10,0x02,0x00,0x00}
+#define CPS_B_18 0xd0,0x0408, 0,0,0,0, /* n/a */ 0xdc,{0xda,0xd8,0xd6,0xd4},0xd2, {0x10,0x08,0x02,0x00,0x00}
+#define NOBATTRY 0x00,0x0000, 0x40,0x42,0x44,0x46, 0x66,{0x68,0x6a,0x6c,0x6e},0x70, {0x02,0x04,0x08,0x30,0x30} // pang3 sets layer enable to 0x26 on startup
+#define BATTRY_1 0x72,0x0800, 0x4e,0x4c,0x4a,0x48, 0x68,{0x66,0x64,0x62,0x60},0x70, {0x20,0x04,0x08,0x12,0x12}
+#define BATTRY_2 0x00,0x0000, 0x5e,0x5c,0x5a,0x58, 0x60,{0x6e,0x6c,0x6a,0x68},0x70, {0x30,0x08,0x30,0x00,0x00}
+#define BATTRY_3 0x00,0x0000, 0x46,0x44,0x42,0x40, 0x60,{0x6e,0x6c,0x6a,0x68},0x70, {0x20,0x12,0x12,0x00,0x00}
+#define BATTRY_4 0x00,0x0000, 0x46,0x44,0x42,0x40, 0x68,{0x66,0x64,0x62,0x60},0x70, {0x20,0x10,0x02,0x00,0x00}
+#define BATTRY_5 0x00,0x0000, 0x4e,0x4c,0x4a,0x48, 0x60,{0x6e,0x6c,0x6a,0x68},0x70, {0x20,0x06,0x06,0x00,0x00}
+#define BATTRY_6 0x00,0x0000, 0x00,0x00,0x00,0x00, 0x60,{0x6e,0x6c,0x6a,0x68},0x70, {0x20,0x14,0x14,0x00,0x00}
+#define BATTRY_7 0x00,0x0000, 0x00,0x00,0x00,0x00, 0x6c,{0x00,0x00,0x00,0x00},0x52, {0x14,0x02,0x14,0x00,0x00}
+#define QSOUND_1 0x00,0x0000, 0x00,0x00,0x00,0x00, 0x62,{0x64,0x66,0x68,0x6a},0x6c, {0x10,0x08,0x04,0x00,0x00}
+#define QSOUND_2 0x00,0x0000, 0x00,0x00,0x00,0x00, 0x4a,{0x4c,0x4e,0x40,0x42},0x44, {0x16,0x16,0x16,0x00,0x00}
+#define QSOUND_3 0x4e,0x0c00, 0x00,0x00,0x00,0x00, 0x52,{0x54,0x56,0x48,0x4a},0x4c, {0x04,0x02,0x20,0x00,0x00}
+#define QSOUND_4 0x6e,0x0c01, 0x00,0x00,0x00,0x00, 0x56,{0x40,0x42,0x68,0x6a},0x6c, {0x04,0x08,0x10,0x00,0x00}
+#define QSOUND_5 0x5e,0x0c02, 0x00,0x00,0x00,0x00, 0x6a,{0x6c,0x6e,0x70,0x72},0x5c, {0x04,0x08,0x10,0x00,0x00}
+#define HACK_B_1 0x00,0x0000, 0x00,0x00,0x00,0x00, 0x54,{0x52,0x50,0x4e,0x4c},0x5c, {0xff,0xff,0xff,0x00,0x00}
+
+
+static struct CPS1config cps1_config_table[]=
+{
+ /* name CPSB banks tile limits kludge */
+ {"forgottn",CPS_B_01, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 7 },
+ {"lostwrld",CPS_B_01, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 7 },
+ {"ghouls", CPS_B_01, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 1 },
+ {"ghoulsu", CPS_B_01, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 1 },
+ {"daimakai",CPS_B_01, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 1 },
+ {"strider", CPS_B_01, 1,0,1, 0x0000,0xffff,0x0000,0xffff },
+ {"stridrua",CPS_B_01, 1,0,1, 0x0000,0xffff,0x0000,0xffff },
+ {"striderj",CPS_B_01, 1,0,1, 0x0000,0xffff,0x0000,0xffff },
+ {"stridrja",CPS_B_01, 1,0,1, 0x0000,0xffff,0x0000,0xffff },
+ {"dynwar", CPS_B_02, 0,1,1, 0x0000,0xffff,0x0000,0xffff },
+ {"dynwarj", CPS_B_02, 0,1,1, 0x0000,0xffff,0x0000,0xffff },
+ {"willow", CPS_B_03, 0,1,0, 0x0000,0xffff,0x0000,0xffff },
+ {"willowj", CPS_B_03, 0,1,0, 0x0000,0xffff,0x0000,0xffff },
+ {"willowje",CPS_B_03, 0,1,0, 0x0000,0xffff,0x0000,0xffff },
+ {"ffight", CPS_B_04, 0,0,0, 0x0001,0xffff,0x0001,0xffff },
+ {"ffightu", CPS_B_04, 0,0,0, 0x0001,0xffff,0x0001,0xffff },
+ {"ffightua",CPS_B_01, 0,0,0, 0x0001,0xffff,0x0001,0xffff },
+ {"ffightub",CPS_B_05, 0,0,0, 0x0001,0xffff,0x0001,0xffff }, // I think
+ {"ffightj", CPS_B_04, 0,0,0, 0x0001,0xffff,0x0001,0xffff },
+ {"ffightj1",CPS_B_02, 0,0,0, 0x0001,0xffff,0x0001,0xffff },
+ {"1941", CPS_B_05, 0,0,0, 0x0000,0xffff,0x0400,0x07ff },
+ {"1941j", CPS_B_05, 0,0,0, 0x0000,0xffff,0x0400,0x07ff },
+ {"unsquad", CPS_B_11, 0,0,0, 0x0000,0xffff,0x0001,0xffff }, /* CPSB ID not checked, but it's the same as sf2eg */
+ {"area88", CPS_B_11, 0,0,0, 0x0000,0xffff,0x0001,0xffff }, /* CPSB ID not checked, but it's the same as sf2eg */
+ {"mercs", CPS_B_12, 0,0,0, 0x0600,0x5bff,0x0700,0x17ff, 4 }, /* (uses port 74) */
+ {"mercsu", CPS_B_12, 0,0,0, 0x0600,0x5bff,0x0700,0x17ff, 4 }, /* (uses port 74) */
+ {"mercsua", CPS_B_12, 0,0,0, 0x0600,0x5bff,0x0700,0x17ff, 4 }, /* (uses port 74) */
+ {"mercsj", CPS_B_12, 0,0,0, 0x0600,0x5bff,0x0700,0x17ff, 4 }, /* (uses port 74) */
+ {"msword", CPS_B_13, 0,0,0, 0x2800,0x37ff,0x0000,0xffff, 3 }, /* CPSB ID not checked, but it's the same as sf2j */
+ {"mswordr1",CPS_B_13, 0,0,0, 0x2800,0x37ff,0x0000,0xffff, 3 }, /* CPSB ID not checked, but it's the same as sf2j */
+ {"mswordu", CPS_B_13, 0,0,0, 0x2800,0x37ff,0x0000,0xffff, 3 }, /* CPSB ID not checked, but it's the same as sf2j */
+ {"mswordj", CPS_B_13, 0,0,0, 0x2800,0x37ff,0x0000,0xffff, 3 }, /* CPSB ID not checked, but it's the same as sf2j */
+ {"mtwins", CPS_B_14, 0,0,0, 0x0000,0x3fff,0x0e00,0xffff },
+ {"chikij", CPS_B_14, 0,0,0, 0x0000,0x3fff,0x0e00,0xffff },
+ {"nemo", CPS_B_15, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"nemoj", CPS_B_15, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"cawing", CPS_B_16, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"cawingr1",CPS_B_16, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"cawingu", CPS_B_16, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"cawingj", CPS_B_16, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2", CPS_B_11, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2eb", CPS_B_17, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2ua", CPS_B_17, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2ub", CPS_B_17, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2ud", CPS_B_05, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2ue", CPS_B_18, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2uf", CPS_B_15, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2ui", CPS_B_14, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2uk", CPS_B_17, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, // check CPS_B
+ {"sf2j", CPS_B_13, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2ja", CPS_B_17, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2jc", CPS_B_12, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ /* from here onwards the CPS-B board has suicide battery and multiply protection */
+ {"3wonders",BATTRY_1, 0,1,0, 0x0000,0xffff,0x0000,0xffff, 2 },
+ {"3wonderu",BATTRY_1, 0,1,0, 0x0000,0xffff,0x0000,0xffff, 2 },
+ {"wonder3", BATTRY_1, 0,1,0, 0x0000,0xffff,0x0000,0xffff, 2 },
+ {"kod", BATTRY_2, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"kodu", BATTRY_2, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"kodj", BATTRY_2, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"kodb", BATTRY_2, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* bootleg, doesn't use multiply protection */
+ {"captcomm",BATTRY_3, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"captcomu",BATTRY_3, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"captcomj",BATTRY_3, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"knights", BATTRY_4, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 3 },
+ {"knightsu",BATTRY_4, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 3 },
+ {"knightsj",BATTRY_4, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 3 },
+ {"sf2ce", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2ceua", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2ceub", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2ceuc", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2cej", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2rb", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2rb2", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2red", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2v004", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2accp2",NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2m1", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2m2", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2m3", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2m4", HACK_B_1, 2,2,2, 0x0000,0xffff,0x0000,0xffff, 10 },
+ {"sf2m5", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff, 10 },
+ {"sf2m6", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff, 10 },
+ {"sf2m7", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff, 10 },
+ {"sf2yyc", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff, 10 },
+ {"sf2koryu",NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff, 10 },
+ {"varth", CPS_B_04, 0,0,0, 0x0000,0xffff,0x0c00,0x0fff }, /* CPSB test has been patched out (60=0008) */
+ {"varthr1", CPS_B_04, 0,0,0, 0x0000,0xffff,0x0c00,0x0fff }, /* CPSB test has been patched out (60=0008) */
+ {"varthu", CPS_B_04, 0,0,0, 0x0000,0xffff,0x0c00,0x0fff }, /* CPSB test has been patched out (60=0008) */
+ {"varthj", BATTRY_5, 0,0,0, 0x0000,0xffff,0x0c00,0x0fff }, /* CPSB test has been patched out (72=0001) */
+ {"cworld2j",BATTRY_6, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* The 0x76 priority values are incorrect values */
+ {"wof", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* bootleg? */
+ {"wofa", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* bootleg? */
+ {"wofu", QSOUND_1, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"wofj", QSOUND_1, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"dino", QSOUND_2, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* layer enable never used */
+ {"dinou", QSOUND_2, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* layer enable never used */
+ {"dinoj", QSOUND_2, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* layer enable never used */
+ {"punisher",QSOUND_3, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"punishru",QSOUND_3, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"punishrj",QSOUND_3, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"slammast",QSOUND_4, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"slammasu",QSOUND_4, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"mbomberj",QSOUND_4, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"mbombrd", QSOUND_5, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"mbombrdj",QSOUND_5, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2hf", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2t", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"sf2tj", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff },
+ {"qad", BATTRY_7, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* TODO: layer enable */
+ {"qadj", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"qtono2", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"megaman", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"rockmanj",NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"pnickj", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ {"pang3", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 5 }, /* EEPROM port is among the CPS registers */
+ {"pang3j", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 5 }, /* EEPROM port is among the CPS registers */
+ #ifdef MESS
+ {"sfzch", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff },
+ #endif
+
+ /* CPS2 games */
+ {"cps2", NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff },
+ {"ssf2", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff },
+ {"ssf2u", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff },
+ {"ssf2a", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff },
+ {"ssf2ar1", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff },
+ {"ssf2j", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff },
+ {"ssf2jr1", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff },
+ {"ssf2jr2", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff },
+ {"ssf2tb", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff },
+ {"ssf2tbr1",NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff },
+ {"ssf2tbj", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff },
+ {"ssf2t", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff, 9 },
+ {"ssf2tu", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff, 9 },
+ {"ssf2tur1",NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff, 9 },
+ {"ssf2ta", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff, 9 },
+ {"ssf2xj", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff, 9 },
+ {"xmcota", NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff, 8 },
+ {"xmcotau", NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff, 8 },
+ {"xmcotah", NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff, 8 },
+ {"xmcotaj", NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff, 8 },
+ {"xmcotaj1",NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff, 8 },
+ {"xmcotajr",NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff, 8 },
+ {"xmcotaa", NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff, 8 },
+ {"hsf2", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff, 9 },
+ {"hsf2j", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff, 9 },
+ {0} /* End of table */
+};
+
+static int cps_version;
+int cps1_scanline1;
+int cps1_scanline2;
+int cps1_scancalls;
+
+#ifdef UNUSED_FUNCTION
+void cps_setversion(int v)
+{
+ cps_version=v;
+}
+#endif
+
+
+static MACHINE_RESET( cps )
+{
+ const char *gamename = machine->gamedrv->name;
+ struct CPS1config *pCFG=&cps1_config_table[0];
+
+ while(pCFG->name)
+ {
+ if (strcmp(pCFG->name, gamename) == 0)
+ {
+ break;
+ }
+ pCFG++;
+ }
+ cps1_game_config=pCFG;
+
+ if (!cps1_game_config->name)
+ {
+ gamename="cps2";
+ pCFG=&cps1_config_table[0];
+ while(pCFG->name)
+ {
+ if (strcmp(pCFG->name, gamename) == 0)
+ {
+ break;
+ }
+ pCFG++;
+ }
+ cps1_game_config=pCFG;
+ }
+
+ if (strcmp(gamename, "sf2rb" )==0)
+ {
+ /* Patch out protection check */
+ UINT16 *rom = (UINT16 *)memory_region(REGION_CPU1);
+ rom[0xe5464/2] = 0x6012;
+ }
+ if (strcmp(gamename, "sf2rb2" )==0)
+ {
+ /* Patch out protection check */
+ UINT16 *rom = (UINT16 *)memory_region(REGION_CPU1);
+ rom[0xe5332/2] = 0x6014;
+ }
+
+#if 0
+ if (strcmp(gamename, "sf2accp2" )==0)
+ {
+ /* Patch out a odd branch which would be incorrectly interpreted
+ by the cpu core as a 32-bit branch. This branch would make the
+ game crash (address error, since it would branch to an odd address)
+ if location 180ca6 (outside ROM space) isn't 0. Protection check? */
+ UINT16 *rom = (UINT16 *)memory_region(REGION_CPU1);
+ rom[0x11756/2] = 0x4e71;
+ }
+ else if (strcmp(gamename, "ghouls" )==0)
+ {
+ /* Patch out self-test... it takes forever */
+ UINT16 *rom = (UINT16 *)memory_region(REGION_CPU1);
+ rom[0x61964/2] = 0x4ef9;
+ rom[0x61966/2] = 0x0000;
+ rom[0x61968/2] = 0x0400;
+ }
+#endif
+}
+
+
+int cps1_port(int offset)
+{
+ return cps1_output[offset/2];
+}
+
+INLINE UINT16 *cps1_base(int offset,int boundary)
+{
+ int base=cps1_port(offset)*256;
+ /*
+ The scroll RAM must start on a 0x4000 boundary.
+ Some games do not do this.
+ For example:
+ Captain commando - continue screen will not display
+ Muscle bomber games - will animate garbage during gameplay
+ Mask out the irrelevant bits.
+ */
+ base &= ~(boundary-1);
+ return &cps1_gfxram[(base&0x3ffff)/2];
+}
+
+
+
+READ16_HANDLER( cps1_output_r )
+{
+#if VERBOSE
+if (offset >= 0x18/2) logerror("PC %06x: read output port %02x\n",activecpu_get_pc(),offset*2);
+#endif
+
+ /* Some games interrogate a couple of registers on bootup. */
+ /* These are CPS1 board B self test checks. They wander from game to */
+ /* game. */
+ if (offset && offset == cps1_game_config->cpsb_addr/2)
+ return cps1_game_config->cpsb_value;
+
+ /* some games use as a protection check the ability to do 16-bit multiplies */
+ /* with a 32-bit result, by writing the factors to two ports and reading the */
+ /* result from two other ports. */
+ if (offset && offset == cps1_game_config->mult_result_lo/2)
+ return (cps1_output[cps1_game_config->mult_factor1/2] *
+ cps1_output[cps1_game_config->mult_factor2/2]) & 0xffff;
+ if (offset && offset == cps1_game_config->mult_result_hi/2)
+ return (cps1_output[cps1_game_config->mult_factor1/2] *
+ cps1_output[cps1_game_config->mult_factor2/2]) >> 16;
+
+ /* Pang 3 EEPROM interface */
+ if (cps1_game_config->kludge == 5 && offset == 0x7a/2)
+ return cps1_eeprom_port_r(0,mem_mask);
+
+ return cps1_output[offset];
+}
+
+WRITE16_HANDLER( cps1_output_w )
+{
+ /* Pang 3 EEPROM interface */
+ if (cps1_game_config->kludge == 5 && offset == 0x7a/2)
+ {
+ cps1_eeprom_port_w(0,data,mem_mask);
+ return;
+ }
+
+ data = COMBINE_DATA(&cps1_output[offset]);
+
+ /* To mark scanlines for raster effects */
+ if(offset == 0x52/2)
+ {
+ cps1_scanline2 = (data & 0x1ff);
+ }
+ if(offset == 0x50/2)
+ {
+ cps1_scanline1 = (data & 0x1ff);
+ }
+
+
+#ifdef MAME_DEBUG
+if (cps1_game_config->control_reg && offset == cps1_game_config->control_reg/2 && data != 0x3f)
+ logerror("control_reg = %04x",data);
+#endif
+#if VERBOSE
+if (offset > 0x22/2 &&
+ offset != cps1_game_config->layer_control/2 &&
+ offset != cps1_game_config->priority[0]/2 &&
+ offset != cps1_game_config->priority[1]/2 &&
+ offset != cps1_game_config->priority[2]/2 &&
+ offset != cps1_game_config->priority[3]/2 &&
+ offset != cps1_game_config->control_reg/2)
+ logerror("PC %06x: write %02x to output port %02x\n",activecpu_get_pc(),data,offset*2);
+
+#ifdef MAME_DEBUG
+if (offset == 0x22/2 && (data & ~0x8001) != 0x0e)
+ logerror("port 22 = %04x",data);
+if (cps1_game_config->priority[0] && offset == cps1_game_config->priority[0]/2 && data != 0x00)
+ popmessage("priority0 %04x",data);
+#endif
+#endif
+}
+
+
+
+/* Public variables */
+UINT16 *cps1_gfxram;
+UINT16 *cps1_output;
+
+size_t cps1_gfxram_size;
+size_t cps1_output_size;
+
+/* Offset of each palette entry */
+static int palette_basecolor[6];
+#define cps1_palette_entries (32*8) /* Number colour schemes in palette */
+
+const int cps1_scroll_size =0x4000; /* scroll1, scroll2, scroll3 */
+const int cps1_obj_size =0x0800;
+const int cps1_other_size =0x0800;
+const int cps1_palette_align=0x0800; /* can't be larger than this, breaks ringdest & batcirc otherwise */
+const int cps1_palette_size=cps1_palette_entries*32; /* Size of palette RAM */
+
+static UINT16 *cps1_scroll1;
+static UINT16 *cps1_scroll2;
+static UINT16 *cps1_scroll3;
+static UINT16 *cps1_obj;
+static UINT16 *cps1_buffered_obj;
+static UINT16 *cps1_palette;
+UINT16 *cps1_other;
+static UINT16 *cps1_old_palette;
+
+/* Working variables */
+static int cps1_last_sprite_offset; /* Offset of the last sprite */
+static int cps1_stars_enabled[2]; /* Layer enabled [Y/N] */
+
+tilemap *cps1_bg_tilemap[3];
+
+
+int cps1_scroll1x, cps1_scroll1y;
+int cps1_scroll2x, cps1_scroll2y;
+int cps1_scroll3x, cps1_scroll3y;
+static int stars1x, stars1y, stars2x, stars2y;
+
+
+/* Output ports */
+#define CPS1_OBJ_BASE 0x00 /* Base address of objects */
+#define CPS1_SCROLL1_BASE 0x02 /* Base address of scroll 1 */
+#define CPS1_SCROLL2_BASE 0x04 /* Base address of scroll 2 */
+#define CPS1_SCROLL3_BASE 0x06 /* Base address of scroll 3 */
+#define CPS1_OTHER_BASE 0x08 /* Base address of other video */
+#define CPS1_PALETTE_BASE 0x0a /* Base address of palette */
+#define CPS1_SCROLL1_SCROLLX 0x0c /* Scroll 1 X */
+#define CPS1_SCROLL1_SCROLLY 0x0e /* Scroll 1 Y */
+#define CPS1_SCROLL2_SCROLLX 0x10 /* Scroll 2 X */
+#define CPS1_SCROLL2_SCROLLY 0x12 /* Scroll 2 Y */
+#define CPS1_SCROLL3_SCROLLX 0x14 /* Scroll 3 X */
+#define CPS1_SCROLL3_SCROLLY 0x16 /* Scroll 3 Y */
+#define CPS1_STARS1_SCROLLX 0x18 /* Stars 1 X */
+#define CPS1_STARS1_SCROLLY 0x1a /* Stars 1 Y */
+#define CPS1_STARS2_SCROLLX 0x1c /* Stars 2 X */
+#define CPS1_STARS2_SCROLLY 0x1e /* Stars 2 Y */
+
+#define CPS1_ROWSCROLL_OFFS 0x20 /* base of row scroll offsets in other RAM */
+
+#define CPS1_SCROLL2_WIDTH 0x40
+#define CPS1_SCROLL2_HEIGHT 0x40
+
+
+/*
+CPS1 VIDEO RENDERER
+
+*/
+/* first 0x4000 of gfx ROM are used, but 0x0000-0x1fff is == 0x2000-0x3fff */
+static const int stars_rom_size = 0x2000;
+
+/* PSL: CPS2 support */
+const int cps2_obj_size =0x2000;
+UINT16 *cps2_objram1,*cps2_objram2;
+UINT16 *cps2_output;
+
+size_t cps2_output_size;
+static UINT16 *cps2_buffered_obj;
+static int pri_ctrl; /* Sprite layer priorities */
+static int cps2_objram_bank;
+static int cps2_last_sprite_offset; /* Offset of the last sprite */
+
+#define CPS2_OBJ_BASE 0x00 /* Unknown (not base address of objects). Could be bass address of bank used when object swap bit set? */
+#define CPS2_OBJ_UK1 0x02 /* Unknown (nearly always 0x807d, or 0x808e when screen flipped) */
+#define CPS2_OBJ_PRI 0x04 /* Layers priorities */
+#define CPS2_OBJ_UK2 0x06 /* Unknown (usually 0x0000, 0x1101 in ssf2, 0x0001 in 19XX) */
+#define CPS2_OBJ_XOFFS 0x08 /* X offset (usually 0x0040) */
+#define CPS2_OBJ_YOFFS 0x0a /* Y offset (always 0x0010) */
+
+INLINE int cps2_port(int offset)
+{
+ return cps2_output[offset/2];
+}
+
+
+
+
+static void cps1_gfx_decode(void)
+{
+ int size=memory_region_length(REGION_GFX1);
+ int i,j,gfxsize;
+ UINT8 *cps1_gfx = memory_region(REGION_GFX1);
+
+
+ gfxsize=size/4;
+
+ for (i = 0;i < gfxsize;i++)
+ {
+ UINT32 src = cps1_gfx[4*i] + (cps1_gfx[4*i+1]<<8) + (cps1_gfx[4*i+2]<<16) + (cps1_gfx[4*i+3]<<24);
+ UINT32 dwval = 0;
+
+ for (j = 0;j < 8;j++)
+ {
+ int n = 0;
+ UINT32 mask = (0x80808080 >> j) & src;
+
+ if (mask & 0x000000ff) n |= 1;
+ if (mask & 0x0000ff00) n |= 2;
+ if (mask & 0x00ff0000) n |= 4;
+ if (mask & 0xff000000) n |= 8;
+
+ dwval |= n << (j * 4);
+ }
+ cps1_gfx[4*i ] = dwval>>0;
+ cps1_gfx[4*i+1] = dwval>>8;
+ cps1_gfx[4*i+2] = dwval>>16;
+ cps1_gfx[4*i+3] = dwval>>24;
+ }
+}
+
+static void unshuffle(UINT64 *buf,int len)
+{
+ int i;
+ UINT64 t;
+
+ if (len == 2) return;
+
+ assert(len % 4 == 0); /* must not happen */
+
+ len /= 2;
+
+ unshuffle(buf,len);
+ unshuffle(buf + len,len);
+
+ for (i = 0;i < len/2;i++)
+ {
+ t = buf[len/2 + i];
+ buf[len/2 + i] = buf[len + i];
+ buf[len + i] = t;
+ }
+}
+
+static void cps2_gfx_decode(void)
+{
+ const int banksize=0x200000;
+ int size=memory_region_length(REGION_GFX1);
+ int i;
+
+ for (i = 0;i < size;i += banksize)
+ unshuffle((UINT64 *)(memory_region(REGION_GFX1) + i),banksize/8);
+
+ cps1_gfx_decode();
+}
+
+
+DRIVER_INIT( cps1 )
+{
+ cps1_gfx_decode();
+}
+
+
+
+DRIVER_INIT( cps2_video )
+{
+ cps2_gfx_decode();
+
+ cps1_scanline1 = 262;
+ cps1_scanline2 = 262;
+ cps1_scancalls = 0;
+}
+
+
+#if CPS1_DUMP_VIDEO
+static void cps1_dump_video(void)
+{
+ FILE *fp;
+ fp=fopen("SCROLL1.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(cps1_scroll1, cps1_scroll_size, 1, fp);
+ fclose(fp);
+ }
+ fp=fopen("SCROLL2.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(cps1_scroll2, cps1_scroll_size, 1, fp);
+ fclose(fp);
+ }
+ fp=fopen("SCROLL3.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(cps1_scroll3, cps1_scroll_size, 1, fp);
+ fclose(fp);
+ }
+
+ fp=fopen("OBJ.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(cps1_obj, cps1_obj_size, 1, fp);
+ fclose(fp);
+ }
+ if (cps_version == 2)
+ {
+ /* PSL: CPS2 support */
+ fp=fopen("OBJCPS2.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(cps2_objram1, cps2_obj_size, 1, fp);
+ fwrite(cps2_objram2, cps2_obj_size, 1, fp);
+ fclose(fp);
+ }
+ fp=fopen("CPS2OUTP.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(cps2_output, cps2_output_size, 1, fp);
+ fclose(fp);
+ }
+
+ }
+
+
+ fp=fopen("OTHER.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(cps1_other, cps1_other_size, 1, fp);
+ fclose(fp);
+ }
+
+ fp=fopen("PALETTE.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(cps1_palette, cps1_palette_size, 1, fp);
+ fclose(fp);
+ }
+
+ fp=fopen("OUTPUT.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(cps1_output, cps1_output_size, 1, fp);
+ fclose(fp);
+ }
+ fp=fopen("VIDEO.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(cps1_gfxram, cps1_gfxram_size, 1, fp);
+ fclose(fp);
+ }
+
+}
+#endif
+
+
+void cps1_get_video_base(void )
+{
+ int layercontrol, scroll1xoff, scroll2xoff, scroll3xoff;
+
+ /* Re-calculate the VIDEO RAM base */
+ if (cps1_scroll1 != cps1_base(CPS1_SCROLL1_BASE,cps1_scroll_size))
+ {
+ cps1_scroll1 = cps1_base(CPS1_SCROLL1_BASE,cps1_scroll_size);
+ tilemap_mark_all_tiles_dirty(cps1_bg_tilemap[0]);
+ }
+ if (cps1_scroll2 != cps1_base(CPS1_SCROLL2_BASE,cps1_scroll_size))
+ {
+ cps1_scroll2 = cps1_base(CPS1_SCROLL2_BASE,cps1_scroll_size);
+ tilemap_mark_all_tiles_dirty(cps1_bg_tilemap[1]);
+ }
+ if (cps1_scroll3 != cps1_base(CPS1_SCROLL3_BASE,cps1_scroll_size))
+ {
+ cps1_scroll3 = cps1_base(CPS1_SCROLL3_BASE,cps1_scroll_size);
+ tilemap_mark_all_tiles_dirty(cps1_bg_tilemap[2]);
+ }
+
+ /* Some of the sf2 hacks use only sprite port 0x9100 and the scroll layers are offset */
+ if (cps1_game_config->kludge == 10)
+ {
+ cps1_output[CPS1_OBJ_BASE/2] = 0x9100;
+ cps1_obj=cps1_base(CPS1_OBJ_BASE, cps1_obj_size);
+ scroll1xoff = -0x0c;
+ scroll2xoff = -0x0e;
+ scroll3xoff = -0x10;
+ }
+ else
+ {
+ cps1_obj=cps1_base(CPS1_OBJ_BASE, cps1_obj_size);
+ scroll1xoff = 0;
+ scroll2xoff = 0;
+ scroll3xoff = 0;
+ }
+ cps1_palette=cps1_base(CPS1_PALETTE_BASE,cps1_palette_align);
+ cps1_other=cps1_base(CPS1_OTHER_BASE,cps1_other_size);
+
+ /* Get scroll values */
+ cps1_scroll1x=cps1_port(CPS1_SCROLL1_SCROLLX) + scroll1xoff;
+ cps1_scroll1y=cps1_port(CPS1_SCROLL1_SCROLLY);
+ cps1_scroll2x=cps1_port(CPS1_SCROLL2_SCROLLX) + scroll2xoff;
+ cps1_scroll2y=cps1_port(CPS1_SCROLL2_SCROLLY);
+ cps1_scroll3x=cps1_port(CPS1_SCROLL3_SCROLLX) + scroll3xoff;
+ cps1_scroll3y=cps1_port(CPS1_SCROLL3_SCROLLY);
+ stars1x =cps1_port(CPS1_STARS1_SCROLLX);
+ stars1y =cps1_port(CPS1_STARS1_SCROLLY);
+ stars2x =cps1_port(CPS1_STARS2_SCROLLX);
+ stars2y =cps1_port(CPS1_STARS2_SCROLLY);
+
+ /* Get layer enable bits */
+ layercontrol=cps1_port(cps1_game_config->layer_control);
+ tilemap_set_enable(cps1_bg_tilemap[0],layercontrol & cps1_game_config->layer_enable_mask[0]);
+ tilemap_set_enable(cps1_bg_tilemap[1],layercontrol & cps1_game_config->layer_enable_mask[1]);
+ tilemap_set_enable(cps1_bg_tilemap[2],layercontrol & cps1_game_config->layer_enable_mask[2]);
+ cps1_stars_enabled[0] = layercontrol & cps1_game_config->layer_enable_mask[3];
+ cps1_stars_enabled[1] = layercontrol & cps1_game_config->layer_enable_mask[4];
+
+
+#ifdef MAME_DEBUG
+{
+ int enablemask;
+
+#if 0
+if (input_code_pressed(KEYCODE_Z))
+{
+ if (input_code_pressed(KEYCODE_Q)) cps1_layer_enabled[3]=0;
+ if (input_code_pressed(KEYCODE_W)) cps1_layer_enabled[2]=0;
+ if (input_code_pressed(KEYCODE_E)) cps1_layer_enabled[1]=0;
+ if (input_code_pressed(KEYCODE_R)) cps1_layer_enabled[0]=0;
+ if (input_code_pressed(KEYCODE_T))
+ {
+ popmessage("%d %d %d %d layer %02x",
+ (layercontrol>>0x06)&03,
+ (layercontrol>>0x08)&03,
+ (layercontrol>>0x0a)&03,
+ (layercontrol>>0x0c)&03,
+ layercontrol&0xc03f
+ );
+ }
+
+}
+#endif
+
+ enablemask = 0;
+ if (cps1_game_config->layer_enable_mask[0] == cps1_game_config->layer_enable_mask[1])
+ enablemask = cps1_game_config->layer_enable_mask[0];
+ if (cps1_game_config->layer_enable_mask[0] == cps1_game_config->layer_enable_mask[2])
+ enablemask = cps1_game_config->layer_enable_mask[0];
+ if (cps1_game_config->layer_enable_mask[1] == cps1_game_config->layer_enable_mask[2])
+ enablemask = cps1_game_config->layer_enable_mask[1];
+ if (enablemask)
+ {
+ if (((layercontrol & enablemask) && (layercontrol & enablemask) != enablemask))
+ popmessage("layer %02x",layercontrol&0xc03f);
+ }
+}
+#endif
+
+{
+ int enablemask;
+ enablemask = cps1_game_config->layer_enable_mask[0] | cps1_game_config->layer_enable_mask[1]
+ | cps1_game_config->layer_enable_mask[2]
+ | cps1_game_config->layer_enable_mask[3] | cps1_game_config->layer_enable_mask[4];
+ if (((layercontrol & ~enablemask) & 0xc03e) != 0)
+ popmessage("layer %02x contact MAMEDEV",layercontrol&0xc03f);
+}
+
+}
+
+
+WRITE16_HANDLER( cps1_gfxram_w )
+{
+ int page = (offset >> 7) & 0x3c0;
+ COMBINE_DATA(&cps1_gfxram[offset]);
+
+ if (page == (cps1_port(CPS1_SCROLL1_BASE) & 0x3c0))
+ tilemap_mark_tile_dirty(cps1_bg_tilemap[0],offset/2 & 0x0fff);
+ if (page == (cps1_port(CPS1_SCROLL2_BASE) & 0x3c0))
+ tilemap_mark_tile_dirty(cps1_bg_tilemap[1],offset/2 & 0x0fff);
+ if (page == (cps1_port(CPS1_SCROLL3_BASE) & 0x3c0))
+ tilemap_mark_tile_dirty(cps1_bg_tilemap[2],offset/2 & 0x0fff);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( tilemap0_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (row & 0x1f) + ((col & 0x3f) << 5) + ((row & 0x20) << 6);
+}
+
+static TILEMAP_MAPPER( tilemap1_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (row & 0x0f) + ((col & 0x3f) << 4) + ((row & 0x30) << 6);
+}
+
+static TILEMAP_MAPPER( tilemap2_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (row & 0x07) + ((col & 0x3f) << 3) + ((row & 0x38) << 6);
+}
+
+static UINT8 empty_tile[32*32/2];
+
+static TILE_GET_INFO( get_tile0_info )
+{
+ int base = cps1_game_config->bank_scroll1 * 0x08000;
+ int code = cps1_scroll1[2*tile_index];
+ int attr = cps1_scroll1[2*tile_index+1];
+ int gfxset;
+
+ /* allows us to reproduce a problem seen with a ffight board where USA and Japanese
+ roms have been mixed to be reproduced (ffightua) -- it looks like each column
+ should alternate between the left and right side of the 16x16 tiles */
+ if (tile_index&0x20) gfxset = 1;
+ else gfxset = 0;
+
+ /* knights & msword */
+ if (cps1_game_config->kludge == 3)
+ if (code == 0xf020) { gfxset = 4; code = 0; } // use a blank tile (see startup text..)
+
+ /* 0x0020 appears to never be drawn for CPS1 games (it is drawn for CPS2 games though, see gigawing '0' in score for example) */
+ if (cps_version == 1 && code == 0x0020) { gfxset = 4; code = 0; }
+
+ SET_TILE_INFO(
+ gfxset,
+ code + base,
+ (attr & 0x1f) + palette_basecolor[1],
+ TILE_FLIPYX((attr & 0x60) >> 5));
+ tileinfo->group = (attr & 0x0180) >> 7;
+}
+
+static TILE_GET_INFO( get_tile1_info )
+{
+ int base = cps1_game_config->bank_scroll2 * 0x04000;
+ const int startcode = cps1_game_config->start_scroll2;
+ const int endcode = cps1_game_config->end_scroll2;
+ int code = cps1_scroll2[2*tile_index];
+ int attr = cps1_scroll2[2*tile_index+1];
+
+ SET_TILE_INFO(
+ 2,
+ code + base,
+ (attr & 0x1f) + palette_basecolor[2],
+ TILE_FLIPYX((attr & 0x60) >> 5));
+ tileinfo->group = (attr & 0x0180) >> 7;
+
+ if (code < startcode || code > endcode
+ /*
+ MERCS has an gap in the scroll 2 layout
+ (bad tiles at start of level 2)*/
+ || (cps1_game_config->kludge == 4 && (code >= 0x1e00 && code < 0x5400))
+ )
+ {
+ tileinfo->pen_data = empty_tile;
+ }
+}
+
+static TILE_GET_INFO( get_tile2_info )
+{
+ int base = cps1_game_config->bank_scroll3 * 0x1000;
+ const int startcode = cps1_game_config->start_scroll3;
+ const int endcode = cps1_game_config->end_scroll3;
+ int code = cps1_scroll3[2*tile_index];
+ int attr = cps1_scroll3[2*tile_index+1];
+
+ if (cps1_game_config->kludge == 2 && code < 0x0e00)
+ {
+ code += 0x1000;
+ }
+ if (cps1_game_config->kludge == 8 && code >= 0x5800)
+ {
+ code -= 0x4000;
+ }
+ if (cps1_game_config->kludge == 9 && code < 0x5600)
+ {
+ code += 0x4000;
+ }
+
+ SET_TILE_INFO(
+ 3,
+ code + base,
+ (attr & 0x1f) + palette_basecolor[3],
+ TILE_FLIPYX((attr & 0x60) >> 5));
+ tileinfo->group = (attr & 0x0180) >> 7;
+
+ if (code < startcode || code > endcode)
+ {
+ tileinfo->pen_data = empty_tile;
+ }
+}
+
+
+
+static void cps1_update_transmasks(void)
+{
+ int i;
+
+ for (i = 0;i < 4;i++)
+ {
+ int mask;
+
+ /* Get transparency registers */
+ if (cps1_game_config->priority[i])
+ mask = cps1_port(cps1_game_config->priority[i]) ^ 0xffff;
+ else mask = 0xffff; /* completely transparent if priority masks not defined (mercs, qad) */
+
+ tilemap_set_transmask(cps1_bg_tilemap[0],i,mask,0x8000);
+ tilemap_set_transmask(cps1_bg_tilemap[1],i,mask,0x8000);
+ tilemap_set_transmask(cps1_bg_tilemap[2],i,mask,0x8000);
+ }
+}
+
+static void cps1_create_empty_8x8_tile(running_machine *machine)
+{
+ /* for the 8x8 layer we can't use GFX_RAW so we need to create an empty tile
+ so that the 'don't draw tile' kludges work */
+ static const gfx_layout empty_layout8x8 =
+ {
+ 8,8,
+ 1,
+ 4,
+ { 0, 1, 2, 3 },
+ { 1*4, 0*4, 3*4, 2*4, 5*4, 4*4, 7*4, 6*4 },
+ { 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64 },
+ 64*8
+ };
+
+ machine->gfx[4] = allocgfx(&empty_layout8x8);
+ decodechar(machine->gfx[4], 0, (UINT8 *)empty_tile, &empty_layout8x8);
+ machine->gfx[4]->total_colors = 0x100;
+
+}
+
+static VIDEO_START( cps )
+{
+ int i;
+
+ machine_reset_cps(machine);
+
+ cps1_bg_tilemap[0] = tilemap_create(get_tile0_info,tilemap0_scan,TILEMAP_TYPE_PEN, 8, 8,64,64);
+ cps1_bg_tilemap[1] = tilemap_create(get_tile1_info,tilemap1_scan,TILEMAP_TYPE_PEN,16,16,64,64);
+ cps1_bg_tilemap[2] = tilemap_create(get_tile2_info,tilemap2_scan,TILEMAP_TYPE_PEN,32,32,64,64);
+
+ /* front masks will change at runtime to handle sprite occluding */
+ cps1_update_transmasks();
+ memset(empty_tile,0xff,sizeof(empty_tile));
+
+ cps1_create_empty_8x8_tile(machine);
+
+ cps1_old_palette=auto_malloc(cps1_palette_size);
+ memset(cps1_old_palette, 0x00, cps1_palette_size);
+ for (i = 0;i < cps1_palette_entries*16;i++)
+ {
+ palette_set_color(machine,i,MAKE_RGB(0,0,0));
+ }
+
+ cps1_buffered_obj = auto_malloc (cps1_obj_size);
+ memset(cps1_buffered_obj, 0x00, cps1_obj_size);
+
+ if (cps_version==2) {
+ cps2_buffered_obj = auto_malloc (cps2_obj_size);
+ memset(cps2_buffered_obj, 0x00, cps2_obj_size);
+ }
+
+ memset(cps1_gfxram, 0, cps1_gfxram_size); /* Clear GFX RAM */
+ memset(cps1_output, 0, cps1_output_size); /* Clear output ports */
+
+ if (cps_version == 2)
+ {
+ memset(cps2_objram1, 0, cps2_obj_size);
+ memset(cps2_objram2, 0, cps2_obj_size);
+ }
+
+ /* Put in some defaults */
+ cps1_output[CPS1_OBJ_BASE/2] = 0x9200;
+ cps1_output[CPS1_SCROLL1_BASE/2] = 0x9000;
+ cps1_output[CPS1_SCROLL2_BASE/2] = 0x9040;
+ cps1_output[CPS1_SCROLL3_BASE/2] = 0x9080;
+ cps1_output[CPS1_OTHER_BASE/2] = 0x9100;
+ cps1_output[CPS1_PALETTE_BASE/2] = 0x90c0;
+
+ assert_always(cps1_game_config, "cps1_game_config hasn't been set up yet");
+
+ /* Set up old base */
+ cps1_get_video_base(); /* Calculate base pointers */
+ cps1_get_video_base(); /* Calculate old base pointers */
+
+ /* set palette banks */
+ palette_basecolor[0] = 0*32; /* obj */
+ palette_basecolor[1] = 1*32; /* scroll1 */
+ palette_basecolor[2] = 2*32; /* scroll2 */
+ palette_basecolor[3] = 3*32; /* scroll3 */
+ palette_basecolor[4] = 4*32; /* stars1 */
+ palette_basecolor[5] = 5*32; /* stars2 */
+}
+
+VIDEO_START( cps1 )
+{
+ cps_version=1;
+ video_start_cps(machine);
+}
+
+VIDEO_START( cps2 )
+{
+ if (cps_version != 99)
+ {
+ cps_version=2;
+ }
+ video_start_cps(machine);
+}
+
+/***************************************************************************
+
+ Build palette from palette RAM
+
+ 12 bit RGB with a 4 bit brightness value.
+
+***************************************************************************/
+
+void cps1_build_palette(running_machine *machine)
+{
+ int offset;
+
+ for (offset = 0; offset < cps1_palette_entries*16; offset++)
+ {
+ int palette = cps1_palette[offset];
+
+ if (palette != cps1_old_palette[offset])
+ {
+ int red, green, blue, bright;
+
+ bright = 0x10 + (palette>>12);
+
+ red = ((palette>>8)&0x0f) * bright * 0x11 / 0x1f;
+ green = ((palette>>4)&0x0f) * bright * 0x11 / 0x1f;
+ blue = ((palette>>0)&0x0f) * bright * 0x11 / 0x1f;
+
+ palette_set_color (machine, offset, MAKE_RGB(red, green, blue));
+ cps1_old_palette[offset] = palette;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+
+ Sprites
+ =======
+
+ Sprites are represented by a number of 8 byte values
+
+ xx xx yy yy nn nn aa aa
+
+ where xxxx = x position
+ yyyy = y position
+ nnnn = tile number
+ aaaa = attribute word
+ 0x0001 colour
+ 0x0002 colour
+ 0x0004 colour
+ 0x0008 colour
+ 0x0010 colour
+ 0x0020 X Flip
+ 0x0040 Y Flip
+ 0x0080 X & Y offset toggle (used in Marvel vs. Capcom.)
+ 0x0100 X block size (in sprites)
+ 0x0200 X block size
+ 0x0400 X block size
+ 0x0800 X block size
+ 0x1000 Y block size (in sprites)
+ 0x2000 Y block size
+ 0x4000 Y block size
+ 0x8000 Y block size
+
+ The end of the table (may) be marked by an attribute value of 0xff00.
+
+***************************************************************************/
+
+static void cps1_find_last_sprite(void) /* Find the offset of last sprite */
+{
+ int offset=0;
+ /* Locate the end of table marker */
+ while (offset < cps1_obj_size/2)
+ {
+ int colour=cps1_buffered_obj[offset+3];
+ if ((colour & 0xff00) == 0xff00)
+ {
+ /* Marker found. This is the last sprite. */
+ cps1_last_sprite_offset=offset-4;
+ return;
+ }
+ offset+=4;
+ }
+ /* Sprites must use full sprite RAM */
+ cps1_last_sprite_offset=cps1_obj_size/2-4;
+}
+
+
+static void cps1_render_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+#define DRAWSPRITE(CODE,COLOR,FLIPX,FLIPY,SX,SY) \
+{ \
+ if (flip_screen) \
+ pdrawgfx(bitmap,machine->gfx[2], \
+ CODE, \
+ COLOR, \
+ !(FLIPX),!(FLIPY), \
+ 511-16-(SX),255-16-(SY), \
+ cliprect,TRANSPARENCY_PEN,15,0x02); \
+ else \
+ pdrawgfx(bitmap,machine->gfx[2], \
+ CODE, \
+ COLOR, \
+ FLIPX,FLIPY, \
+ SX,SY, \
+ cliprect,TRANSPARENCY_PEN,15,0x02); \
+}
+
+
+ int i, baseadd;
+ UINT16 *base=cps1_buffered_obj;
+
+ /* some sf2 hacks draw the sprites in reverse order */
+ if (cps1_game_config->kludge == 10)
+ {
+ base += cps1_last_sprite_offset;
+ baseadd = -4;
+ }
+ else
+ {
+ baseadd = 4;
+ }
+
+ for (i=cps1_last_sprite_offset; i>=0; i-=4)
+ {
+ int x=*(base+0);
+ int y=*(base+1);
+ int code =*(base+2);
+ int colour=*(base+3);
+ int col=colour&0x1f;
+
+// x-=0x20;
+// y+=0x20;
+
+ if (cps1_game_config->kludge == 7)
+ {
+ code += 0x4000;
+ }
+ if (cps1_game_config->kludge == 1 && code >= 0x01000)
+ {
+ code += 0x4000;
+ }
+ if (cps1_game_config->kludge == 2 && code >= 0x02a00)
+ {
+ code += 0x4000;
+ }
+
+ if (code < machine->gfx[1]->total_elements)
+ {
+ if (colour & 0xff00 )
+ {
+ /* handle blocked sprites */
+ int nx=(colour & 0x0f00) >> 8;
+ int ny=(colour & 0xf000) >> 12;
+ int nxs,nys,sx,sy;
+ nx++;
+ ny++;
+
+ if (colour & 0x40)
+ {
+ /* Y flip */
+ if (colour &0x20)
+ {
+ for (nys=0; nys<ny; nys++)
+ {
+ for (nxs=0; nxs<nx; nxs++)
+ {
+ sx = (x+nxs*16) & 0x1ff;
+ sy = (y+nys*16) & 0x1ff;
+
+ DRAWSPRITE(
+ code+(nx-1)-nxs+0x10*(ny-1-nys),
+ (col&0x1f) + palette_basecolor[0],
+ 1,1,
+ sx,sy);
+ }
+ }
+ }
+ else
+ {
+ for (nys=0; nys<ny; nys++)
+ {
+ for (nxs=0; nxs<nx; nxs++)
+ {
+ sx = (x+nxs*16) & 0x1ff;
+ sy = (y+nys*16) & 0x1ff;
+
+ DRAWSPRITE(
+ code+nxs+0x10*(ny-1-nys),
+ (col&0x1f) + palette_basecolor[0],
+ 0,1,
+ sx,sy);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (colour &0x20)
+ {
+ for (nys=0; nys<ny; nys++)
+ {
+ for (nxs=0; nxs<nx; nxs++)
+ {
+ sx = (x+nxs*16) & 0x1ff;
+ sy = (y+nys*16) & 0x1ff;
+
+ DRAWSPRITE(
+ code+(nx-1)-nxs+0x10*nys,
+ (col&0x1f) + palette_basecolor[0],
+ 1,0,
+ sx,sy);
+ }
+ }
+ }
+ else
+ {
+ for (nys=0; nys<ny; nys++)
+ {
+ for (nxs=0; nxs<nx; nxs++)
+ {
+ sx = (x+nxs*16) & 0x1ff;
+ sy = (y+nys*16) & 0x1ff;
+
+ DRAWSPRITE(
+ code+nxs+0x10*nys,
+ (col&0x1f) + palette_basecolor[0],
+ 0,0,
+ sx,sy);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Simple case... 1 sprite */
+ DRAWSPRITE(
+ code,
+ (col&0x1f) + palette_basecolor[0],
+ colour&0x20,colour&0x40,
+ x & 0x1ff,y & 0x1ff);
+ }
+ }
+ base += baseadd;
+ }
+#undef DRAWSPRITE
+}
+
+
+
+
+WRITE16_HANDLER( cps2_objram_bank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ cps2_objram_bank = data & 1;
+ }
+}
+
+READ16_HANDLER( cps2_objram1_r )
+{
+ if (cps2_objram_bank & 1)
+ return cps2_objram2[offset];
+ else
+ return cps2_objram1[offset];
+}
+
+READ16_HANDLER( cps2_objram2_r )
+{
+ if (cps2_objram_bank & 1)
+ return cps2_objram1[offset];
+ else
+ return cps2_objram2[offset];
+}
+
+WRITE16_HANDLER( cps2_objram1_w )
+{
+ if (cps2_objram_bank & 1)
+ COMBINE_DATA(&cps2_objram2[offset]);
+ else
+ COMBINE_DATA(&cps2_objram1[offset]);
+}
+
+WRITE16_HANDLER( cps2_objram2_w )
+{
+ if (cps2_objram_bank & 1)
+ COMBINE_DATA(&cps2_objram1[offset]);
+ else
+ COMBINE_DATA(&cps2_objram2[offset]);
+}
+
+static UINT16 *cps2_objbase(void)
+{
+ int baseptr;
+ baseptr = 0x7000;
+
+ if (cps2_objram_bank & 1) baseptr ^= 0x0080;
+
+//popmessage("%04x %d",cps2_port(CPS2_OBJ_BASE),cps2_objram_bank&1);
+
+ if (baseptr == 0x7000)
+ return cps2_objram1;
+ else //if (baseptr == 0x7080)
+ return cps2_objram2;
+}
+
+
+static void cps2_find_last_sprite(void) /* Find the offset of last sprite */
+{
+ int offset=0;
+ UINT16 *base=cps2_buffered_obj;
+
+ /* Locate the end of table marker */
+ while (offset < cps2_obj_size/2)
+ {
+ if (base[offset+1]>=0x8000
+ || base[offset+3]>=0xff00)
+ {
+ /* Marker found. This is the last sprite. */
+ cps2_last_sprite_offset=offset-4;
+ return;
+ }
+
+ offset+=4;
+ }
+ /* Sprites must use full sprite RAM */
+ cps2_last_sprite_offset=cps2_obj_size/2-4;
+#undef DRAWSPRITE
+}
+
+static void cps2_render_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int *primasks)
+{
+#define DRAWSPRITE(CODE,COLOR,FLIPX,FLIPY,SX,SY) \
+{ \
+ if (flip_screen) \
+ pdrawgfx(bitmap,machine->gfx[2], \
+ CODE, \
+ COLOR, \
+ !(FLIPX),!(FLIPY), \
+ 511-16-(SX),255-16-(SY), \
+ cliprect,TRANSPARENCY_PEN,15,primasks[priority]); \
+ else \
+ pdrawgfx(bitmap,machine->gfx[2], \
+ CODE, \
+ COLOR, \
+ FLIPX,FLIPY, \
+ SX,SY, \
+ cliprect,TRANSPARENCY_PEN,15,primasks[priority]); \
+}
+
+ int i;
+ UINT16 *base=cps2_buffered_obj;
+ int xoffs = 64-cps2_port(CPS2_OBJ_XOFFS);
+ int yoffs = 16-cps2_port(CPS2_OBJ_YOFFS);
+
+#ifdef MAME_DEBUG
+ if (input_code_pressed(KEYCODE_Z) && input_code_pressed(KEYCODE_R))
+ {
+ return;
+ }
+#endif
+
+ for (i=cps2_last_sprite_offset; i>=0; i-=4)
+ {
+ int x=base[i+0];
+ int y=base[i+1];
+ int priority=(x>>13)&0x07;
+ int code = base[i+2]+((y & 0x6000) <<3);
+ int colour= base[i+3];
+ int col=colour&0x1f;
+
+ if(colour & 0x80)
+ {
+ x += cps2_port(CPS2_OBJ_XOFFS); /* fix the offset of some games */
+ y += cps2_port(CPS2_OBJ_YOFFS); /* like Marvel vs. Capcom ending credits */
+ }
+
+ if (colour & 0xff00 )
+ {
+ /* handle blocked sprites */
+ int nx=(colour & 0x0f00) >> 8;
+ int ny=(colour & 0xf000) >> 12;
+ int nxs,nys,sx,sy;
+ nx++;
+ ny++;
+
+ if (colour & 0x40)
+ {
+ /* Y flip */
+ if (colour &0x20)
+ {
+ for (nys=0; nys<ny; nys++)
+ {
+ for (nxs=0; nxs<nx; nxs++)
+ {
+ sx = (x+nxs*16+xoffs) & 0x3ff;
+ sy = (y+nys*16+yoffs) & 0x3ff;
+ DRAWSPRITE(
+ code+(nx-1)-nxs+0x10*(ny-1-nys),
+ (col&0x1f) + palette_basecolor[0],
+ 1,1,
+ sx,sy);
+ }
+ }
+ }
+ else
+ {
+ for (nys=0; nys<ny; nys++)
+ {
+ for (nxs=0; nxs<nx; nxs++)
+ {
+ sx = (x+nxs*16+xoffs) & 0x3ff;
+ sy = (y+nys*16+yoffs) & 0x3ff;
+
+ DRAWSPRITE(
+ code+nxs+0x10*(ny-1-nys),
+ (col&0x1f) + palette_basecolor[0],
+ 0,1,
+ sx,sy);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (colour &0x20)
+ {
+ for (nys=0; nys<ny; nys++)
+ {
+ for (nxs=0; nxs<nx; nxs++)
+ {
+ sx = (x+nxs*16+xoffs) & 0x3ff;
+ sy = (y+nys*16+yoffs) & 0x3ff;
+
+ DRAWSPRITE(
+ code+(nx-1)-nxs+0x10*nys,
+ (col&0x1f) + palette_basecolor[0],
+ 1,0,
+ sx,sy);
+ }
+ }
+ }
+ else
+ {
+ for (nys=0; nys<ny; nys++)
+ {
+ for (nxs=0; nxs<nx; nxs++)
+ {
+ sx = (x+nxs*16+xoffs) & 0x3ff;
+ sy = (y+nys*16+yoffs) & 0x3ff;
+
+ DRAWSPRITE(
+// code+nxs+0x10*nys,
+ (code & ~0xf) + ((code + nxs) & 0xf) + 0x10*nys, // pgear fix
+ (col&0x1f) + palette_basecolor[0],
+ 0,0,
+ sx,sy);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Simple case... 1 sprite */
+ DRAWSPRITE(
+ code,
+ (col&0x1f) + palette_basecolor[0],
+ colour&0x20,colour&0x40,
+ (x+xoffs) & 0x3ff,(y+yoffs) & 0x3ff);
+ }
+ }
+}
+
+
+
+
+static void cps1_render_stars(running_machine *machine,mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+ UINT8 *stars_rom = memory_region(REGION_GFX2);
+
+ if (!stars_rom && (cps1_stars_enabled[0] || cps1_stars_enabled[1]))
+ {
+#ifdef MAME_DEBUG
+ popmessage("stars enabled but no stars ROM");
+#endif
+ return;
+ }
+
+ if (cps1_stars_enabled[0])
+ {
+ for (offs = 0;offs < stars_rom_size/2;offs++)
+ {
+ int col = stars_rom[8*offs+4];
+ if (col != 0x0f)
+ {
+ int sx = (offs / 256) * 32;
+ int sy = (offs % 256);
+ sx = (sx - stars2x + (col & 0x1f)) & 0x1ff;
+ sy = (sy - stars2y) & 0xff;
+ if (flip_screen)
+ {
+ sx = 511 - sx;
+ sy = 255 - sy;
+ }
+
+ col = ((col & 0xe0) >> 1) + (cpu_getcurrentframe()/16 & 0x0f);
+
+ if (sx >= cliprect->min_x && sx <= cliprect->max_x &&
+ sy >= cliprect->min_y && sy <= cliprect->max_y)
+ *BITMAP_ADDR16(bitmap, sy, sx) = machine->pens[0xa00+col];
+ }
+ }
+ }
+
+ if (cps1_stars_enabled[1])
+ {
+ for (offs = 0;offs < stars_rom_size/2;offs++)
+ {
+ int col = stars_rom[8*offs];
+ if (col != 0x0f)
+ {
+ int sx = (offs / 256) * 32;
+ int sy = (offs % 256);
+ sx = (sx - stars1x + (col & 0x1f)) & 0x1ff;
+ sy = (sy - stars1y) & 0xff;
+ if (flip_screen)
+ {
+ sx = 511 - sx;
+ sy = 255 - sy;
+ }
+
+ col = ((col & 0xe0) >> 1) + (cpu_getcurrentframe()/16 & 0x0f);
+
+ if (sx >= cliprect->min_x && sx <= cliprect->max_x &&
+ sy >= cliprect->min_y && sy <= cliprect->max_y)
+ *BITMAP_ADDR16(bitmap, sy, sx) = machine->pens[0x800+col];
+ }
+ }
+ }
+}
+
+
+static void cps1_render_layer(running_machine *machine,mame_bitmap *bitmap,const rectangle *cliprect,int layer,int primask)
+{
+ switch (layer)
+ {
+ case 0:
+ cps1_render_sprites(machine,bitmap,cliprect);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ tilemap_draw(bitmap,cliprect,cps1_bg_tilemap[layer-1],TILEMAP_DRAW_LAYER1,primask);
+ break;
+ }
+}
+
+static void cps1_render_high_layer(mame_bitmap *bitmap, const rectangle *cliprect, int layer)
+{
+ switch (layer)
+ {
+ case 0:
+ /* there are no high priority sprites */
+ break;
+ case 1:
+ case 2:
+ case 3:
+ tilemap_draw(NULL,cliprect,cps1_bg_tilemap[layer-1],TILEMAP_DRAW_LAYER0,1);
+ break;
+ }
+}
+
+
+/***************************************************************************
+
+ Refresh screen
+
+***************************************************************************/
+
+VIDEO_UPDATE( cps1 )
+{
+ int layercontrol,l0,l1,l2,l3;
+ int videocontrol=cps1_port(0x22);
+
+
+ flip_screen_set(videocontrol & 0x8000);
+
+ layercontrol = cps1_output[cps1_game_config->layer_control/2];
+
+ /* Get video memory base registers */
+ cps1_get_video_base();
+
+ /* Find the offset of the last sprite in the sprite table */
+ cps1_find_last_sprite();
+ if (cps_version == 2)
+ {
+ cps2_find_last_sprite();
+ }
+ /* Build palette */
+ cps1_build_palette(machine);
+
+ cps1_update_transmasks();
+
+ tilemap_set_scrollx(cps1_bg_tilemap[0],0,cps1_scroll1x);
+ tilemap_set_scrolly(cps1_bg_tilemap[0],0,cps1_scroll1y);
+ if (videocontrol & 0x01) /* linescroll enable */
+ {
+ int scrly=-cps1_scroll2y;
+ int i;
+ int otheroffs;
+
+ tilemap_set_scroll_rows(cps1_bg_tilemap[1],1024);
+
+ otheroffs = cps1_port(CPS1_ROWSCROLL_OFFS);
+
+ for (i = 0;i < 256;i++)
+ tilemap_set_scrollx(cps1_bg_tilemap[1],(i - scrly) & 0x3ff,cps1_scroll2x + cps1_other[(i + otheroffs) & 0x3ff]);
+ }
+ else
+ {
+ tilemap_set_scroll_rows(cps1_bg_tilemap[1],1);
+ tilemap_set_scrollx(cps1_bg_tilemap[1],0,cps1_scroll2x);
+ }
+ tilemap_set_scrolly(cps1_bg_tilemap[1],0,cps1_scroll2y);
+ tilemap_set_scrollx(cps1_bg_tilemap[2],0,cps1_scroll3x);
+ tilemap_set_scrolly(cps1_bg_tilemap[2],0,cps1_scroll3y);
+
+
+ /* Blank screen */
+ fillbitmap(bitmap,machine->pens[4095],cliprect);
+
+ cps1_render_stars(machine,bitmap,cliprect);
+
+ /* Draw layers (0 = sprites, 1-3 = tilemaps) */
+ l0 = (layercontrol >> 0x06) & 03;
+ l1 = (layercontrol >> 0x08) & 03;
+ l2 = (layercontrol >> 0x0a) & 03;
+ l3 = (layercontrol >> 0x0c) & 03;
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ if (cps_version == 1)
+ {
+ cps1_render_layer(machine,bitmap,cliprect,l0,0);
+ if (l1 == 0) cps1_render_high_layer(bitmap,cliprect,l0); /* prepare mask for sprites */
+ cps1_render_layer(machine,bitmap,cliprect,l1,0);
+ if (l2 == 0) cps1_render_high_layer(bitmap,cliprect,l1); /* prepare mask for sprites */
+ cps1_render_layer(machine,bitmap,cliprect,l2,0);
+ if (l3 == 0) cps1_render_high_layer(bitmap,cliprect,l2); /* prepare mask for sprites */
+ cps1_render_layer(machine,bitmap,cliprect,l3,0);
+ }
+ else
+ {
+ int l0pri,l1pri,l2pri,l3pri;
+ int primasks[8],i;
+ l0pri = (pri_ctrl >> 4*l0) & 0x0f;
+ l1pri = (pri_ctrl >> 4*l1) & 0x0f;
+ l2pri = (pri_ctrl >> 4*l2) & 0x0f;
+ l3pri = (pri_ctrl >> 4*l3) & 0x0f;
+
+#if 0
+if ( (cps2_port(CPS2_OBJ_BASE) != 0x7080 && cps2_port(CPS2_OBJ_BASE) != 0x7000) ||
+ cps2_port(CPS2_OBJ_UK1) != 0x807d ||
+ (cps2_port(CPS2_OBJ_UK2) != 0x0000 && cps2_port(CPS2_OBJ_UK2) != 0x1101 && cps2_port(CPS2_OBJ_UK2) != 0x0001) ||
+ popmessage("base %04x uk1 %04x uk2 %04x",
+ cps2_port(CPS2_OBJ_BASE),
+ cps2_port(CPS2_OBJ_UK1),
+ cps2_port(CPS2_OBJ_UK2));
+
+if (0 && input_code_pressed(KEYCODE_Z))
+ popmessage("order: %d (%d) %d (%d) %d (%d) %d (%d)",l0,l0pri,l1,l1pri,l2,l2pri,l3,l3pri);
+#endif
+
+ /* take out the CPS1 sprites layer */
+ if (l0 == 0) { l0 = l1; l1 = 0; l0pri = l1pri; }
+ if (l1 == 0) { l1 = l2; l2 = 0; l1pri = l2pri; }
+ if (l2 == 0) { l2 = l3; l3 = 0; l2pri = l3pri; }
+
+ {
+ int mask0 = 0xaa;
+ int mask1 = 0xcc;
+ if(l0pri>l1pri) mask0 &= ~0x88;
+ if(l0pri>l2pri) mask0 &= ~0xa0;
+ if(l1pri>l2pri) mask1 &= ~0xc0;
+
+ primasks[0] = 0xff;
+ for (i = 1;i < 8;i++)
+ {
+ if (i <= l0pri && i <= l1pri && i <= l2pri)
+ {
+ primasks[i] = 0xfe;
+ continue;
+ }
+ primasks[i] = 0;
+ if (i <= l0pri) primasks[i] |= mask0;
+ if (i <= l1pri) primasks[i] |= mask1;
+ if (i <= l2pri) primasks[i] |= 0xf0;
+ }
+ }
+
+ cps1_render_layer(machine,bitmap,cliprect,l0,1);
+ cps1_render_layer(machine,bitmap,cliprect,l1,2);
+ cps1_render_layer(machine,bitmap,cliprect,l2,4);
+ cps2_render_sprites(machine,bitmap,cliprect,primasks);
+ }
+
+#if CPS1_DUMP_VIDEO
+ if (input_code_pressed(KEYCODE_F))
+ {
+ cps1_dump_video();
+ }
+#endif
+ return 0;
+}
+
+VIDEO_EOF( cps1 )
+{
+ /* Get video memory base registers */
+ cps1_get_video_base();
+
+ if (cps_version == 1)
+ {
+ /* CPS1 sprites have to be delayed one frame */
+ memcpy(cps1_buffered_obj, cps1_obj, cps1_obj_size);
+ }
+}
+
+void cps2_set_sprite_priorities(void)
+{
+ pri_ctrl = cps2_port(CPS2_OBJ_PRI);
+}
+
+void cps2_objram_latch(void)
+{
+ cps2_set_sprite_priorities();
+ memcpy(cps2_buffered_obj, cps2_objbase(), cps2_obj_size);
+}
+
diff --git a/src/mame/video/crbaloon.c b/src/mame/video/crbaloon.c
new file mode 100644
index 00000000000..fd5442540d2
--- /dev/null
+++ b/src/mame/video/crbaloon.c
@@ -0,0 +1,167 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/crbaloon.h"
+
+static UINT8 spritectrl[3];
+
+INT8 crbaloon_collision;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Crazy Balloon has no PROMs, the color code directly maps to a color:
+ all bits are inverted
+ bit 3 HALF (intensity)
+ bit 2 BLUE
+ bit 1 GREEN
+ bit 0 RED
+
+***************************************************************************/
+PALETTE_INIT( crbaloon )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int intensity,r,g,b;
+
+
+ intensity = (~i & 0x08) ? 0xff : 0x55;
+
+ /* red component */
+ r = intensity * ((~i >> 0) & 1);
+ /* green component */
+ g = intensity * ((~i >> 1) & 1);
+ /* blue component */
+ b = intensity * ((~i >> 2) & 1);
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ for (i = 0;i < TOTAL_COLORS(0);i += 2)
+ {
+ COLOR(0,i) = 15; /* black background */
+ COLOR(0,i + 1) = i / 2; /* colored foreground */
+ }
+}
+
+WRITE8_HANDLER( crbaloon_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( crbaloon_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( crbaloon_spritectrl_w )
+{
+ spritectrl[offset] = data;
+}
+
+WRITE8_HANDLER( crbaloon_flipscreen_w )
+{
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index];
+ int color = colorram[tile_index] & 0x0f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( crbaloon )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows_flip_xy,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tmpbitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ state_save_register_global_array(spritectrl);
+ state_save_register_global(crbaloon_collision);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int x,y;
+
+ /* Check Collision - Draw balloon in background colour, if no */
+ /* collision occured, bitmap will be same as tmpbitmap */
+
+ int bx = spritectrl[1];
+ int by = spritectrl[2] - 32;
+
+ tilemap_draw(tmpbitmap, 0, bg_tilemap, 0, 0);
+
+ if (flip_screen)
+ {
+ by += 32;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ spritectrl[0] & 0x0f,
+ 15,
+ 0,0,
+ bx,by,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ crbaloon_collision = 0;
+
+ for (x = bx; x < bx + machine->gfx[1]->width; x++)
+ {
+ for (y = by; y < by + machine->gfx[1]->height; y++)
+ {
+ if ((x < machine->screen[0].visarea.min_x) ||
+ (x > machine->screen[0].visarea.max_x) ||
+ (y < machine->screen[0].visarea.min_y) ||
+ (y > machine->screen[0].visarea.max_y))
+ {
+ continue;
+ }
+
+ if (*BITMAP_ADDR16(bitmap, y, x) != *BITMAP_ADDR16(tmpbitmap, y, x))
+ {
+ crbaloon_collision = -1;
+ break;
+ }
+ }
+ }
+
+
+ /* actually draw the balloon */
+
+ drawgfx(bitmap,machine->gfx[1],
+ spritectrl[0] & 0x0f,
+ (spritectrl[0] & 0xf0) >> 4,
+ 0,0,
+ bx,by,
+ cliprect,TRANSPARENCY_PEN,0);
+}
+
+VIDEO_UPDATE( crbaloon )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/crgolf.c b/src/mame/video/crgolf.c
new file mode 100644
index 00000000000..0cb3e15a805
--- /dev/null
+++ b/src/mame/video/crgolf.c
@@ -0,0 +1,236 @@
+/***************************************************************************
+
+ Kitco Crowns Golf hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "crgolf.h"
+
+
+/* globals */
+UINT8 *crgolf_color_select;
+UINT8 *crgolf_screen_flip;
+UINT8 *crgolf_screen_select;
+UINT8 *crgolf_screenb_enable;
+UINT8 *crgolf_screena_enable;
+
+
+/* local variables */
+static mame_bitmap *screena;
+static mame_bitmap *screenb;
+static mame_bitmap *highbit;
+
+
+
+/*************************************
+ *
+ * Video RAM writes
+ *
+ *************************************/
+
+WRITE8_HANDLER( crgolf_videoram_bit0_w )
+{
+ mame_bitmap *screen = (*crgolf_screen_select & 1) ? screenb : screena;
+ int x = (offset % 32) * 8;
+ int y = offset / 32;
+ UINT16 *dest = (UINT16 *)screen->base + screen->rowpixels * y + x;
+
+ dest[0] = (dest[0] & ~0x01) | ((data >> 7) & 0x01);
+ dest[1] = (dest[1] & ~0x01) | ((data >> 6) & 0x01);
+ dest[2] = (dest[2] & ~0x01) | ((data >> 5) & 0x01);
+ dest[3] = (dest[3] & ~0x01) | ((data >> 4) & 0x01);
+ dest[4] = (dest[4] & ~0x01) | ((data >> 3) & 0x01);
+ dest[5] = (dest[5] & ~0x01) | ((data >> 2) & 0x01);
+ dest[6] = (dest[6] & ~0x01) | ((data >> 1) & 0x01);
+ dest[7] = (dest[7] & ~0x01) | ((data >> 0) & 0x01);
+}
+
+
+WRITE8_HANDLER( crgolf_videoram_bit1_w )
+{
+ mame_bitmap *screen = (*crgolf_screen_select & 1) ? screenb : screena;
+ int x = (offset % 32) * 8;
+ int y = offset / 32;
+ UINT16 *dest = (UINT16 *)screen->base + screen->rowpixels * y + x;
+
+ dest[0] = (dest[0] & ~0x02) | ((data >> 6) & 0x02);
+ dest[1] = (dest[1] & ~0x02) | ((data >> 5) & 0x02);
+ dest[2] = (dest[2] & ~0x02) | ((data >> 4) & 0x02);
+ dest[3] = (dest[3] & ~0x02) | ((data >> 3) & 0x02);
+ dest[4] = (dest[4] & ~0x02) | ((data >> 2) & 0x02);
+ dest[5] = (dest[5] & ~0x02) | ((data >> 1) & 0x02);
+ dest[6] = (dest[6] & ~0x02) | ((data >> 0) & 0x02);
+ dest[7] = (dest[7] & ~0x02) | ((data << 1) & 0x02);
+}
+
+
+WRITE8_HANDLER( crgolf_videoram_bit2_w )
+{
+ mame_bitmap *screen = (*crgolf_screen_select & 1) ? screenb : screena;
+ int x = (offset % 32) * 8;
+ int y = offset / 32;
+ UINT16 *dest = (UINT16 *)screen->base + screen->rowpixels * y + x;
+
+ dest[0] = (dest[0] & ~0x04) | ((data >> 5) & 0x04);
+ dest[1] = (dest[1] & ~0x04) | ((data >> 4) & 0x04);
+ dest[2] = (dest[2] & ~0x04) | ((data >> 3) & 0x04);
+ dest[3] = (dest[3] & ~0x04) | ((data >> 2) & 0x04);
+ dest[4] = (dest[4] & ~0x04) | ((data >> 1) & 0x04);
+ dest[5] = (dest[5] & ~0x04) | ((data >> 0) & 0x04);
+ dest[6] = (dest[6] & ~0x04) | ((data << 1) & 0x04);
+ dest[7] = (dest[7] & ~0x04) | ((data << 2) & 0x04);
+}
+
+
+
+/*************************************
+ *
+ * Video RAM reads
+ *
+ *************************************/
+
+READ8_HANDLER( crgolf_videoram_bit0_r )
+{
+ mame_bitmap *screen = (*crgolf_screen_select & 1) ? screenb : screena;
+ int x = (offset % 32) * 8;
+ int y = offset / 32;
+ UINT16 *source = (UINT16 *)screen->base + screen->rowpixels * y + x;
+
+ return ((source[0] & 0x01) << 7) |
+ ((source[1] & 0x01) << 6) |
+ ((source[2] & 0x01) << 5) |
+ ((source[3] & 0x01) << 4) |
+ ((source[4] & 0x01) << 3) |
+ ((source[5] & 0x01) << 2) |
+ ((source[6] & 0x01) << 1) |
+ ((source[7] & 0x01) << 0);
+}
+
+
+READ8_HANDLER( crgolf_videoram_bit1_r )
+{
+ mame_bitmap *screen = (*crgolf_screen_select & 1) ? screenb : screena;
+ int x = (offset % 32) * 8;
+ int y = offset / 32;
+ UINT16 *source = (UINT16 *)screen->base + screen->rowpixels * y + x;
+
+ return ((source[0] & 0x02) << 6) |
+ ((source[1] & 0x02) << 5) |
+ ((source[2] & 0x02) << 4) |
+ ((source[3] & 0x02) << 3) |
+ ((source[4] & 0x02) << 2) |
+ ((source[5] & 0x02) << 1) |
+ ((source[6] & 0x02) << 0) |
+ ((source[7] & 0x02) >> 1);
+}
+
+
+READ8_HANDLER( crgolf_videoram_bit2_r )
+{
+ mame_bitmap *screen = (*crgolf_screen_select & 1) ? screenb : screena;
+ int x = (offset % 32) * 8;
+ int y = offset / 32;
+ UINT16 *source = (UINT16 *)screen->base + screen->rowpixels * y + x;
+
+ return ((source[0] & 0x04) << 5) |
+ ((source[1] & 0x04) << 4) |
+ ((source[2] & 0x04) << 3) |
+ ((source[3] & 0x04) << 2) |
+ ((source[4] & 0x04) << 1) |
+ ((source[5] & 0x04) << 0) |
+ ((source[6] & 0x04) >> 1) |
+ ((source[7] & 0x04) >> 2);
+}
+
+
+
+/*************************************
+ *
+ * Color PROM decoding
+ *
+ *************************************/
+
+PALETTE_INIT( crgolf )
+{
+ int i;
+
+ for (i = 0; i < 32; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* blue component */
+ bit0 = (*color_prom >> 6) & 0x01;
+ bit1 = (*color_prom >> 7) & 0x01;
+ b = 0x4f * bit0 + 0xa8 * bit1;
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ color_prom++;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( crgolf )
+{
+ /* allocate temporary bitmaps */
+ screena = auto_bitmap_alloc(256, 256, machine->screen[0].format);
+ screenb = auto_bitmap_alloc(256, 256, machine->screen[0].format);
+ highbit = auto_bitmap_alloc(256, 256, machine->screen[0].format);
+
+ /* initialize the "high bit" bitmap */
+ fillbitmap(screena, 0, NULL);
+ fillbitmap(screenb, 8, NULL);
+ fillbitmap(highbit, 16, NULL);
+
+ /* register for save states */
+ state_save_register_bitmap("video", 0, "screena", screena);
+ state_save_register_bitmap("video", 0, "screenb", screenb);
+ state_save_register_bitmap("video", 0, "highbit", highbit);
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( crgolf )
+{
+ int flip = *crgolf_screen_flip & 1;
+
+ /* draw screen b if enabled */
+ if (~*crgolf_screenb_enable & 1)
+ copybitmap(bitmap, screenb, flip, flip, 0, 0, cliprect, TRANSPARENCY_NONE, 0);
+ else
+ fillbitmap(bitmap, 8, cliprect);
+
+ /* draw screen a if enabled */
+ if (~*crgolf_screena_enable & 1)
+ copybitmap(bitmap, screena, flip, flip, 0, 0, cliprect, TRANSPARENCY_PEN, 0);
+
+ /* apply the color select bit */
+ if (*crgolf_color_select)
+ copybitmap(bitmap, highbit, 0, 0, 0, 0, cliprect, TRANSPARENCY_BLEND, 0);
+ return 0;
+}
diff --git a/src/mame/video/crimfght.c b/src/mame/video/crimfght.c
new file mode 100644
index 00000000000..fcd9ad6c28c
--- /dev/null
+++ b/src/mame/video/crimfght.c
@@ -0,0 +1,86 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+static int layer_colorbase[3],sprite_colorbase;
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ *flags = (*color & 0x20) ? TILE_FLIPX : 0;
+ *code |= ((*color & 0x1f) << 8) | (bank << 13);
+ *color = layer_colorbase[layer] + ((*color & 0xc0) >> 6);
+}
+
+/***************************************************************************
+
+ Callbacks for the K051960
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority,int *shadow)
+{
+ /* Weird priority scheme. Why use three bits when two would suffice? */
+ /* The PROM allows for mixed priorities, where sprites would have */
+ /* priority over text but not on one or both of the other two planes. */
+ /* Luckily, this isn't used by the game. */
+ switch (*color & 0x70)
+ {
+ case 0x10: *priority = 0; break;
+ case 0x00: *priority = 1; break;
+ case 0x40: *priority = 2; break;
+ case 0x20: *priority = 3; break;
+ /* 0x60 == 0x20 */
+ /* 0x50 priority over F and A, but not over B */
+ /* 0x30 priority over F, but not over A and B */
+ /* 0x70 == 0x30 */
+ }
+ /* bit 7 is on in the "Game Over" sprites, meaning unknown */
+ /* in Aliens it is the top bit of the code, but that's not needed here */
+ *color = sprite_colorbase + (*color & 0x0f);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( crimfght )
+{
+ paletteram = auto_malloc(0x400);
+
+ layer_colorbase[0] = 0;
+ layer_colorbase[1] = 4;
+ layer_colorbase[2] = 8;
+ sprite_colorbase = 16;
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,NORMAL_PLANE_ORDER,sprite_callback);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( crimfght )
+{
+ K052109_tilemap_update();
+
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],TILEMAP_DRAW_OPAQUE,0);
+ K051960_sprites_draw(bitmap,cliprect,2,2);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],0,0);
+ K051960_sprites_draw(bitmap,cliprect,1,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],0,0);
+ K051960_sprites_draw(bitmap,cliprect,0,0);
+ return 0;
+}
diff --git a/src/mame/video/crospang.c b/src/mame/video/crospang.c
new file mode 100644
index 00000000000..c25e16c7327
--- /dev/null
+++ b/src/mame/video/crospang.c
@@ -0,0 +1,210 @@
+/*
+
+ Cross Pang
+ video hardware emulation
+
+ -- this seems to be the same as the tumblepop bootleg based hardware
+ in tumbleb.c
+
+
+*/
+
+#include "driver.h"
+
+static int xsproff, ysproff; // sprite offsets
+static tilemap *bg_layer,*fg_layer;
+UINT16 *crospang_bg_videoram,*crospang_fg_videoram;
+static int bestri_tilebank;
+WRITE16_HANDLER( bestri_tilebank_w)
+{
+ bestri_tilebank = (data>>10) & 0xf;
+ //printf("bestri %04x\n", data);
+
+ tilemap_mark_all_tiles_dirty(fg_layer);
+ tilemap_mark_all_tiles_dirty(bg_layer);
+}
+
+
+WRITE16_HANDLER ( bestri_bg_scrolly_w )
+{
+ /* Very Strange */
+ int scroll = (data&0x3ff)^ 0x0155;
+ tilemap_set_scrolly(bg_layer,0,-scroll+7);
+}
+
+WRITE16_HANDLER ( bestri_fg_scrolly_w )
+{
+ /* Very Strange */
+ int scroll = (data&0x3ff)^ 0x00ab;
+ tilemap_set_scrolly(fg_layer,0,-scroll+7);
+}
+
+WRITE16_HANDLER ( bestri_fg_scrollx_w )
+{
+// printf("fg_layer x %04x\n",data);
+ tilemap_set_scrollx(fg_layer,0,data+32);
+}
+
+WRITE16_HANDLER ( bestri_bg_scrollx_w )
+{
+// printf("bg_layer x %04x\n",data);
+ tilemap_set_scrollx(bg_layer,0,data-60);
+}
+
+
+WRITE16_HANDLER ( crospang_fg_scrolly_w )
+{
+ tilemap_set_scrolly(fg_layer,0,data+8);
+}
+
+WRITE16_HANDLER ( crospang_bg_scrolly_w )
+{
+ tilemap_set_scrolly(bg_layer,0,data+8);
+}
+
+WRITE16_HANDLER ( crospang_fg_scrollx_w )
+{
+ tilemap_set_scrollx(fg_layer,0,data);
+}
+
+WRITE16_HANDLER ( crospang_bg_scrollx_w )
+{
+ tilemap_set_scrollx(bg_layer,0,data+4);
+}
+
+
+WRITE16_HANDLER ( crospang_fg_videoram_w )
+{
+ COMBINE_DATA(&crospang_fg_videoram[offset]);
+ tilemap_mark_tile_dirty(fg_layer,offset);
+}
+
+WRITE16_HANDLER ( crospang_bg_videoram_w )
+{
+ COMBINE_DATA(&crospang_bg_videoram[offset]);
+ tilemap_mark_tile_dirty(bg_layer,offset);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int data = crospang_bg_videoram[tile_index];
+ int tile = data & 0xfff;
+ int color = (data >> 12) & 0x0f;
+
+ SET_TILE_INFO(1,tile+ bestri_tilebank * 0x1000,color + 0x20,0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int data = crospang_fg_videoram[tile_index];
+ int tile = data & 0xfff;
+ int color = (data >> 12) & 0x0f;
+
+ SET_TILE_INFO(1,tile+ bestri_tilebank * 0x1000,color + 0x10,0);
+}
+
+/*
+
+ offset
+
+ 0 -------yyyyyyyyy y offset
+ -----hh--------- sprite height
+ ---a------------ alpha blending enable
+ f--------------- flip x
+ -??-?----------- unused
+
+ 1 --ssssssssssssss sprite code
+ ??-------------- unused
+
+ 2 -------xxxxxxxxx x offset
+ ---cccc--------- colors
+ ???------------- unused
+
+ 3 ---------------- unused
+
+*/
+
+/* jumpkids / tumbleb.c! */
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+ int flipscreen = 0;
+
+ for (offs = 0;offs < spriteram_size/2;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ sprite = spriteram16[offs+1] & 0x7fff;
+ if (!sprite) continue;
+
+ y = spriteram16[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ x = spriteram16[offs+2];
+ colour = (x >>9) & 0xf;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+ y = 240 - y;
+ x = 304 - x;
+
+ // sprite &= ~multi; /* Todo: I bet TumblePop bootleg doesn't do this either */
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flipscreen)
+ {
+ y=240-y;
+ x=304-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x-xsproff,y-ysproff + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ multi--;
+ }
+ }
+}
+
+VIDEO_START( crospang )
+{
+ bg_layer = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ fg_layer = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ tilemap_set_transparent_pen(fg_layer,0);
+ bestri_tilebank = 0;
+// xsproff = 4;
+// ysproff = 7;
+ xsproff = 5;
+ ysproff = 7;
+}
+
+VIDEO_UPDATE( crospang )
+{
+ tilemap_draw(bitmap,cliprect,bg_layer,0,0);
+ tilemap_draw(bitmap,cliprect,fg_layer,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/crshrace.c b/src/mame/video/crshrace.c
new file mode 100644
index 00000000000..9d89c3d168e
--- /dev/null
+++ b/src/mame/video/crshrace.c
@@ -0,0 +1,220 @@
+#include "driver.h"
+#include "video/konamiic.h"
+#include "crshrace.h"
+
+
+UINT16 *crshrace_videoram1,*crshrace_videoram2;
+//UINT16 *crshrace_roz_ctrl1,*crshrace_roz_ctrl2;
+
+static int roz_bank,gfxctrl,flipscreen;
+
+static tilemap *tilemap1,*tilemap2;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info1 )
+{
+ int code = crshrace_videoram1[tile_index];
+
+ SET_TILE_INFO(1,(code & 0xfff) + (roz_bank << 12),code >> 12,0);
+}
+
+static TILE_GET_INFO( get_tile_info2 )
+{
+ int code = crshrace_videoram2[tile_index];
+
+ SET_TILE_INFO(0,code,0,0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( crshrace )
+{
+ tilemap1 = tilemap_create(get_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ tilemap2 = tilemap_create(get_tile_info2,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,64);
+
+ K053936_wraparound_enable(0, 1);
+ K053936_set_offset(0, -48, -21);
+
+ tilemap_set_transparent_pen(tilemap1,0x0f);
+ tilemap_set_transparent_pen(tilemap2,0xff);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( crshrace_videoram1_w )
+{
+ COMBINE_DATA(&crshrace_videoram1[offset]);
+ tilemap_mark_tile_dirty(tilemap1,offset);
+}
+
+WRITE16_HANDLER( crshrace_videoram2_w )
+{
+ COMBINE_DATA(&crshrace_videoram2[offset]);
+ tilemap_mark_tile_dirty(tilemap2,offset);
+}
+
+WRITE16_HANDLER( crshrace_roz_bank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ if (roz_bank != (data & 0xff))
+ {
+ roz_bank = data & 0xff;
+ tilemap_mark_all_tiles_dirty(tilemap1);
+ }
+ }
+}
+
+
+WRITE16_HANDLER( crshrace_gfxctrl_w )
+{
+ if (ACCESSING_LSB)
+ {
+ gfxctrl = data & 0xdf;
+ flipscreen = data & 0x20;
+ }
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+
+ offs = 0;
+ while (offs < 0x0400 && (buffered_spriteram16[offs] & 0x4000) == 0)
+ {
+ int attr_start;
+ int map_start;
+ int ox,oy,x,y,xsize,ysize,zoomx,zoomy,flipx,flipy,color;
+ /* table hand made by looking at the ship explosion in aerofgt attract mode */
+ /* it's almost a logarithmic scale but not exactly */
+ static const int zoomtable[16] = { 0,7,14,20,25,30,34,38,42,46,49,52,54,57,59,61 };
+
+ attr_start = 4 * (buffered_spriteram16[offs++] & 0x03ff);
+
+ ox = buffered_spriteram16[attr_start + 1] & 0x01ff;
+ xsize = (buffered_spriteram16[attr_start + 1] & 0x0e00) >> 9;
+ zoomx = (buffered_spriteram16[attr_start + 1] & 0xf000) >> 12;
+ oy = buffered_spriteram16[attr_start + 0] & 0x01ff;
+ ysize = (buffered_spriteram16[attr_start + 0] & 0x0e00) >> 9;
+ zoomy = (buffered_spriteram16[attr_start + 0] & 0xf000) >> 12;
+ flipx = buffered_spriteram16[attr_start + 2] & 0x4000;
+ flipy = buffered_spriteram16[attr_start + 2] & 0x8000;
+ color = (buffered_spriteram16[attr_start + 2] & 0x1f00) >> 8;
+ map_start = buffered_spriteram16[attr_start + 3] & 0x7fff;
+
+ zoomx = 16 - zoomtable[zoomx]/8;
+ zoomy = 16 - zoomtable[zoomy]/8;
+
+ if (buffered_spriteram16[attr_start + 2] & 0x20ff) color = mame_rand(machine);
+
+ for (y = 0;y <= ysize;y++)
+ {
+ int sx,sy;
+
+ if (flipy) sy = ((oy + zoomy * (ysize - y) + 16) & 0x1ff) - 16;
+ else sy = ((oy + zoomy * y + 16) & 0x1ff) - 16;
+
+ for (x = 0;x <= xsize;x++)
+ {
+ int code;
+
+ if (flipx) sx = ((ox + zoomx * (xsize - x) + 16) & 0x1ff) - 16;
+ else sx = ((ox + zoomx * x + 16) & 0x1ff) - 16;
+
+ code = buffered_spriteram16_2[map_start & 0x7fff];
+ map_start++;
+
+ if (flipscreen)
+ drawgfxzoom(bitmap,machine->gfx[2],
+ code,
+ color,
+ !flipx,!flipy,
+ 304-sx,208-sy,
+ cliprect,TRANSPARENCY_PEN,15,
+ 0x1000 * zoomx,0x1000 * zoomy);
+ else
+ drawgfxzoom(bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15,
+ 0x1000 * zoomx,0x1000 * zoomy);
+ }
+ }
+ }
+}
+
+
+static void draw_bg(mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ tilemap_draw(bitmap,cliprect,tilemap2,0,0);
+}
+
+
+static void draw_fg(mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ K053936_0_zoom_draw(bitmap,cliprect,tilemap1,0,0);
+}
+
+
+VIDEO_UPDATE( crshrace )
+{
+ if (gfxctrl & 0x04) /* display disable? */
+ {
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ return 0;
+ }
+
+ fillbitmap(bitmap,machine->pens[0x1ff],cliprect);
+
+ switch (gfxctrl & 0xfb)
+ {
+ case 0x00: /* high score screen */
+ draw_sprites(machine,bitmap,cliprect);
+ draw_bg(bitmap,cliprect);
+ draw_fg(bitmap,cliprect);
+ break;
+ case 0x01:
+ case 0x02:
+ draw_bg(bitmap,cliprect);
+ draw_fg(bitmap,cliprect);
+ draw_sprites(machine,bitmap,cliprect);
+ break;
+ default:
+popmessage("gfxctrl = %02x",gfxctrl);
+ break;
+ }
+ return 0;
+}
+
+VIDEO_EOF( crshrace )
+{
+ buffer_spriteram16_w(0,0,0);
+ buffer_spriteram16_2_w(0,0,0);
+}
diff --git a/src/mame/video/csk.c b/src/mame/video/csk.c
new file mode 100644
index 00000000000..85600183865
--- /dev/null
+++ b/src/mame/video/csk.c
@@ -0,0 +1,273 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+#define CPK_VIDEO_SIZE 0x800
+
+static UINT8 * cpk_colorram;
+static UINT8 * cpk_videoram;
+static UINT8 * cpk_palette;
+static UINT8 * cpk_palette2;
+static UINT8 * cpk_expram;
+
+static UINT8 * dirtybuffer1;
+static mame_bitmap *tmpbitmap2;
+
+static int hopperOK = 0;
+static int intstate1 = 0; /* unknown */
+static int intstate2 = 0; /* unknown */
+static int oldstate = 0;
+static int machinestate = 0;
+static int abilityflag = 0;
+static int sleepcountdown = 0;
+
+
+
+/* Palette handling */
+
+WRITE8_HANDLER( cpk_palette_w )
+{
+ cpk_palette[offset] = data;
+}
+
+WRITE8_HANDLER( cpk_palette2_w )
+{
+ int newword;
+
+ cpk_palette2[offset] = data;
+
+ newword = cpk_palette[offset] + 256 * cpk_palette2[offset];
+ palette_set_color_rgb(Machine,offset,pal5bit(newword >> 0),pal5bit(newword >> 5),pal5bit(newword >> 10));
+}
+
+/* Video handling */
+
+READ8_HANDLER( cpk_videoram_r )
+{
+ return cpk_videoram[offset];
+}
+
+WRITE8_HANDLER( cpk_videoram_w )
+{
+ if (cpk_videoram[offset] != data)
+ {
+ cpk_videoram[offset] = data;
+ dirtybuffer[offset] = 1;
+ }
+}
+
+READ8_HANDLER( cpk_colorram_r )
+{
+ return cpk_colorram[offset];
+}
+
+WRITE8_HANDLER( cpk_colorram_w )
+{
+ if (cpk_colorram[offset] != data)
+ {
+ cpk_colorram[offset] = data;
+ dirtybuffer[offset] = 1;
+ }
+}
+
+READ8_HANDLER( cpk_expansion_r )
+{
+ UINT8 * RAM = memory_region(REGION_GFX3);
+ return RAM[offset];
+}
+
+
+WRITE8_HANDLER( cpk_expansion_w )
+{
+ if (cpk_expram[offset] != data)
+ {
+ cpk_expram[offset] = data;
+ dirtybuffer1[offset] = 1;
+ }
+}
+
+/* Machine init/deinit */
+
+VIDEO_START( cska )
+{
+ int i;
+
+ dirtybuffer = auto_malloc(CPK_VIDEO_SIZE * sizeof(UINT8));
+ dirtybuffer1 = auto_malloc(CPK_VIDEO_SIZE * sizeof(UINT8));
+ cpk_colorram = auto_malloc(CPK_VIDEO_SIZE * sizeof(UINT8));
+ cpk_videoram = auto_malloc(CPK_VIDEO_SIZE * sizeof(UINT8));
+ cpk_expram = auto_malloc(CPK_VIDEO_SIZE * sizeof(UINT8));
+
+ cpk_palette = auto_malloc(0x800 * sizeof(UINT8));
+ cpk_palette2 = auto_malloc(0x800 * sizeof(UINT8));
+
+ tmpbitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ tmpbitmap2 = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ /* leave everything at the default, but map all foreground 0 pens as transparent */
+ for (i = 0;i < 16;i++)
+ {
+// palette_used_colors[64 * i] = PALETTE_COLOR_TRANSPARENT;
+ }
+}
+
+
+
+static void init_csk227_internals(void)
+{
+ hopperOK = 0xf9d0;
+ machinestate = 0xf6b0;
+ intstate1 = 0xf08c;
+ intstate2 = 0xf08d;
+ sleepcountdown = 0xf994;
+}
+
+static void init_csk234_internals(void)
+{
+ hopperOK = 0xf9ca;
+ machinestate = 0xf6ad;
+ intstate1 = 0xf088;
+ intstate2 = 0xf089;
+ sleepcountdown = 0xf98e;
+}
+
+MACHINE_RESET (cpk)
+{
+ static int initonce = 0;
+
+ memset(cpk_videoram, 0, CPK_VIDEO_SIZE);
+ memset(cpk_colorram, 0, CPK_VIDEO_SIZE);
+ memset(cpk_expram, 0, CPK_VIDEO_SIZE);
+ memset(dirtybuffer, 1, CPK_VIDEO_SIZE);
+ memset(dirtybuffer1, 0, CPK_VIDEO_SIZE);
+ memset(cpk_palette, 0, 0x800);
+ memset(cpk_palette2, 0, 0x800);
+
+ if (!initonce)
+ {
+ initonce = 1;
+
+ if (strcmp(machine->gamedrv->name,"csk227it") == 0)
+ init_csk227_internals();
+ else if (strcmp(machine->gamedrv->name,"csk234it") == 0)
+ init_csk234_internals();
+ }
+}
+
+INTERRUPT_GEN( cska_interrupt )
+{
+ UINT8 * RAM = memory_region(REGION_CPU1);
+
+ RAM[ hopperOK ] = 1; /* simulate hopper working! */
+
+ if (oldstate == 5)
+ {
+ if (RAM[sleepcountdown] == 0 && RAM[sleepcountdown+1] == 0)
+ oldstate = RAM[ machinestate ];
+ }
+ else oldstate = RAM[ machinestate ];
+
+ abilityflag = (oldstate == 5 || (RAM[ intstate1 ] == 1 && RAM[ intstate2 ] == 5)) ? 1 : 0;
+
+ if (cpu_getiloops() % 2)
+ cpunum_set_input_line(0, 0, HOLD_LINE);
+ else
+ cpunum_set_input_line(0, INPUT_LINE_NMI, PULSE_LINE);
+
+}
+
+
+
+/* Screen refresh section */
+
+VIDEO_UPDATE( cska )
+{
+ int offs;
+
+// palette_init_used_colors();
+
+ for (offs = CPK_VIDEO_SIZE-1; offs >= 0; offs--)
+ {
+// int color = ((cpk_colorram[offs] & 0xe0) >> 4) + 1;
+// memset(&palette_used_colors[64 * color + 1],PALETTE_COLOR_USED,63);
+ }
+
+ if (abilityflag)
+// memset(&palette_used_colors[0], PALETTE_COLOR_USED, 64);
+
+// if (palette_recalc())
+ {
+ memset(dirtybuffer, 1, CPK_VIDEO_SIZE);
+ }
+
+#if 0
+ if (keyboard_pressed(KEYCODE_9))
+ {
+ FILE * f = fopen("dump.bin", "wb");
+ if (f)
+ {
+ fwrite(&cpk_videoram[0], 1, CPK_VIDEO_SIZE, f);
+ fwrite(&cpk_colorram[0], 1, CPK_VIDEO_SIZE, f);
+ fclose(f);
+ }
+ }
+#endif
+
+ if (abilityflag)
+ {
+ for (offs = (CPK_VIDEO_SIZE)-1; offs >= 0; offs--)
+ {
+ if (dirtybuffer1[offs] || dirtybuffer[offs])
+ {
+ int sx,sy;
+
+
+ dirtybuffer1[offs] = 0;
+
+ sx = offs % 64;
+ sy = offs / 64;
+
+ drawgfx(tmpbitmap2,machine->gfx[1+(offs % 4)],
+ cpk_expram[offs],
+ 0,
+ 0,0,
+ 8*sx,32*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+ copybitmap(bitmap,tmpbitmap2,0,0,0,0,cliprect,TRANSPARENCY_NONE,0);
+ }
+
+ for (offs = CPK_VIDEO_SIZE-1; offs >= 0; offs--)
+ {
+ int tile = cpk_videoram[offs] + ((cpk_colorram[offs] & 0x1f) << 8);
+ int color = (tile != 0x1fff) ? (((cpk_colorram[offs] & 0xe0) >> 4) + 1) : 0;
+
+ if (dirtybuffer[offs])
+ {
+ int sx,sy;
+
+
+ dirtybuffer[offs] = 0;
+
+ sx = offs % 64;
+ sy = offs / 64;
+
+ drawgfx(tmpbitmap,machine->gfx[0],
+ tile,
+ color,
+ 0,0,
+ 8*sx,8*sy,
+ 0, TRANSPARENCY_NONE, 0);
+ }
+ }
+
+ copybitmap(bitmap,tmpbitmap,0,0,0,0,cliprect, (abilityflag) ? TRANSPARENCY_COLOR : TRANSPARENCY_NONE, 0);
+ return 0;
+}
diff --git a/src/mame/video/cvs.c b/src/mame/video/cvs.c
new file mode 100644
index 00000000000..e1b5e2cfdd7
--- /dev/null
+++ b/src/mame/video/cvs.c
@@ -0,0 +1,639 @@
+/***************************************************************************
+
+ video\cvs.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/s2636.h"
+#include "cpu/s2650/s2650.h"
+
+#define MAX_STARS 250
+#define STARS_COLOR_BASE 16
+
+#ifdef LSB_FIRST
+#define BL0 0
+#define BL1 1
+#define BL2 2
+#define BL3 3
+#define WL0 0
+#define WL1 1
+#else
+#define BL0 3
+#define BL1 2
+#define BL2 1
+#define BL3 0
+#define WL0 1
+#define WL1 0
+#endif
+
+struct star
+{
+ int x,y,code;
+};
+
+static struct star stars[MAX_STARS];
+static int total_stars;
+static int scroll[8];
+static int stars_on=0;
+static int character_mode=0;
+static int character_page=0;
+static int scroll_reg = 0;
+static int stars_scroll=0;
+
+static UINT8 *dirty_character;
+static UINT8 *character_1_ram;
+static UINT8 *character_2_ram;
+static UINT8 *character_3_ram;
+UINT8 *cvs_bullet_ram;
+
+mame_bitmap *cvs_collision_bitmap;
+mame_bitmap *cvs_collision_background;
+static mame_bitmap *scrolled_background;
+
+int cvs_collision_register=0;
+
+static int ModeOffset[4] = {223,191,255,127};
+
+/******************************************************
+ * Convert Colour prom to format for Mame Colour Map *
+ * *
+ * There is a prom used for colour mapping and plane *
+ * priority. This is converted to a colour table here *
+ * *
+ * colours are taken from SRAM and are programmable *
+ ******************************************************/
+
+PALETTE_INIT( cvs )
+{
+ int attr,col,map;
+
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ /* Colour Mapping Prom */
+
+ for(attr = 0;attr < 256; attr++)
+ {
+ for(col = 0; col < 8; col++)
+ {
+ map = color_prom[(col * 256) + attr];
+
+ /* bits 1 and 3 are swopped over */
+
+ COLOR(0,attr*8 + col) = ((map & 1) << 2) + (map & 2) + ((map & 4) >> 2);
+ }
+ }
+
+ /* Background Collision Map */
+
+ for(map=0;map<8;map++)
+ {
+ COLOR(0,2048+map) = (map & 4) >> 2;
+ COLOR(0,2056+map) = (map & 2) >> 1;
+ COLOR(0,2064+map) = ((map & 2) >> 1) || ((map & 4) >> 2);
+ }
+
+ /* Sprites */
+
+ for(map=0;map<8;map++)
+ {
+ COLOR(0,map*2 + 2072) = 0;
+ COLOR(0,map*2 + 2073) = 8 + map;
+ }
+
+ /* Initialise Dirty Character Array */
+ dirty_character = auto_malloc(0x100);
+ character_1_ram = auto_malloc(0x2000);
+ character_2_ram = character_1_ram + 0x800;
+ character_3_ram = character_2_ram + 0x800;
+
+ memset(dirty_character, 0, 256);
+ memset(character_1_ram, 0, 1024);
+ memset(character_2_ram, 0, 1024);
+ memset(character_3_ram, 0, 1024);
+
+ /* Set Sprite chip offsets */
+
+ s2636_x_offset = -26;
+ s2636_y_offset = 3;
+
+ /* Set Scroll fixed areas */
+
+ scroll[0]=0;
+ scroll[6]=0;
+ scroll[7]=0;
+}
+
+WRITE8_HANDLER( cvs_video_fx_w )
+{
+ logerror("%4x : Data Port = %2x\n",activecpu_get_pc(),data);
+
+ /* Unimplemented */
+
+ if(data & 2) logerror(" SHADE BRIGHTER TO RIGHT\n");
+ if(data & 4) logerror(" SCREEN ROTATE\n");
+ if(data & 8) logerror(" SHADE BRIGHTER TO LEFT\n");
+ if(data & 64) logerror(" SHADE BRIGHTER TO BOTTOM\n");
+ if(data & 128) logerror(" SHADE BRIGHTER TO TOP\n");
+
+ /* Implemented */
+
+ stars_on = data & 1;
+ set_led_status(1,data & 16); /* Lamp 1 */
+ set_led_status(2,data & 32); /* Lamp 2 */
+}
+
+READ8_HANDLER( cvs_character_mode_r )
+{
+ /* Really a write - uses address info */
+
+ int value = offset + 0x10;
+ int newmode = (value >> 4) & 3;
+
+ character_mode = newmode;
+ character_page = (value << 2) & 0x300;
+
+ return 0;
+}
+
+READ8_HANDLER( cvs_collision_r )
+{
+ return cvs_collision_register;
+}
+
+READ8_HANDLER( cvs_collision_clear )
+{
+ cvs_collision_register=0;
+ return 0;
+}
+
+WRITE8_HANDLER( cvs_scroll_w )
+{
+ scroll_reg = 255 - data;
+
+ scroll[1]=scroll_reg;
+ scroll[2]=scroll_reg;
+ scroll[3]=scroll_reg;
+ scroll[4]=scroll_reg;
+ scroll[5]=scroll_reg;
+}
+
+WRITE8_HANDLER( cvs_videoram_w )
+{
+ if(!activecpu_get_reg(S2650_FO))
+ {
+ // Colour Map
+
+ colorram_w(offset,data);
+ }
+ else
+ {
+ // Data
+
+ videoram_w(offset,data);
+ }
+}
+
+READ8_HANDLER( cvs_videoram_r )
+{
+ if(!activecpu_get_reg(S2650_FO))
+ {
+ // Colour Map
+
+ return colorram[offset];
+ }
+ else
+ {
+ // Data
+
+ return videoram[offset];
+ }
+}
+
+WRITE8_HANDLER( cvs_bullet_w )
+{
+ if(!activecpu_get_reg(S2650_FO))
+ {
+ // Bullet Ram
+
+ cvs_bullet_ram[offset] = data;
+ }
+ else
+ {
+ // Pallette Ram - Inverted ?
+ offset &= 0x0f;
+ data ^= 0xff;
+
+ paletteram[offset] = data;
+ palette_set_color_rgb(Machine, offset, pal2bit(data >> 0), pal3bit(data >> 2), pal3bit(data >> 5));
+ }
+}
+
+READ8_HANDLER( cvs_bullet_r )
+{
+ if(!activecpu_get_reg(S2650_FO))
+ {
+ // Bullet Ram
+
+ return cvs_bullet_ram[offset];
+ }
+ else
+ {
+ // Pallette Ram
+
+ return (paletteram[offset] ^ 0xff);
+ }
+}
+
+WRITE8_HANDLER( cvs_2636_1_w )
+{
+ if(!activecpu_get_reg(S2650_FO))
+ {
+ // First 2636
+
+ s2636_w(s2636_1_ram,offset,data,s2636_1_dirty);
+ }
+ else
+ {
+ // Character Ram 1
+
+ if(character_1_ram[character_page + offset] != data)
+ {
+ character_1_ram[character_page + offset] = data;
+ dirty_character[128+((character_page + offset)>>3)] = 1;
+ }
+ }
+}
+
+READ8_HANDLER( cvs_2636_1_r )
+{
+ if(!activecpu_get_reg(S2650_FO))
+ {
+ // First 2636
+
+ return s2636_1_ram[offset];
+ }
+ else
+ {
+ // Character Ram 1
+
+ return character_1_ram[character_page + offset];
+ }
+}
+
+WRITE8_HANDLER( cvs_2636_2_w )
+{
+ if(!activecpu_get_reg(S2650_FO))
+ {
+ // Second 2636
+
+ s2636_w(s2636_2_ram,offset,data,s2636_2_dirty);
+ }
+ else
+ {
+ // Character Ram 2
+
+ if(character_2_ram[character_page + offset] != data)
+ {
+ character_2_ram[character_page + offset] = data;
+ dirty_character[128+((character_page + offset)>>3)] = 1;
+ }
+ }
+}
+
+READ8_HANDLER( cvs_2636_2_r )
+{
+ if(!activecpu_get_reg(S2650_FO))
+ {
+ // Second 2636
+
+ return s2636_2_ram[offset];
+ }
+ else
+ {
+ // Character Ram 2
+
+ return character_2_ram[character_page + offset];
+ }
+}
+
+WRITE8_HANDLER( cvs_2636_3_w )
+{
+ if(!activecpu_get_reg(S2650_FO))
+ {
+ // Third 2636
+
+ s2636_w(s2636_3_ram,offset,data,s2636_3_dirty);
+ }
+ else
+ {
+ // Character Ram 3
+
+ if(character_3_ram[character_page + offset] != data)
+ {
+ character_3_ram[character_page + offset] = data;
+ dirty_character[128+((character_page + offset)>>3)] = 1;
+ }
+ }
+}
+
+READ8_HANDLER( cvs_2636_3_r )
+{
+ if(!activecpu_get_reg(S2650_FO))
+ {
+ // Third 2636
+
+ return s2636_3_ram[offset];
+ }
+ else
+ {
+ // Character Ram 3
+
+ return character_3_ram[character_page + offset];
+ }
+}
+
+VIDEO_START( cvs )
+{
+ int generator = 0;
+ int x,y;
+
+ colorram = auto_malloc(0x400);
+ paletteram = auto_malloc(0x100);
+
+ video_start_generic(machine);
+
+ /* precalculate the star background */
+
+ total_stars = 0;
+
+ for (y = 255;y >= 0;y--)
+ {
+ for (x = 511;x >= 0;x--)
+ {
+ int bit1,bit2;
+
+ generator <<= 1;
+ bit1 = (~generator >> 17) & 1;
+ bit2 = (generator >> 5) & 1;
+
+ if (bit1 ^ bit2) generator |= 1;
+
+ if (((~generator >> 16) & 1) && (generator & 0xfe) == 0xfe)
+ {
+ if(((~(generator >> 12)) & 0x01) && ((~(generator >> 13)) & 0x01))
+ {
+ if (total_stars < MAX_STARS)
+ {
+ stars[total_stars].x = x;
+ stars[total_stars].y = y;
+ stars[total_stars].code = 1;
+
+ total_stars++;
+ }
+ }
+ }
+ }
+ }
+
+ /* Need 3 bitmaps for 2636 chips */
+
+ s2636_1_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,BITMAP_FORMAT_INDEXED8);
+ s2636_2_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,BITMAP_FORMAT_INDEXED8);
+ s2636_3_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,BITMAP_FORMAT_INDEXED8);
+
+ /* 3 bitmaps for collision detection */
+
+ cvs_collision_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,BITMAP_FORMAT_INDEXED8);
+ cvs_collision_background = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,BITMAP_FORMAT_INDEXED8);
+ scrolled_background = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,BITMAP_FORMAT_INDEXED8);
+}
+
+INTERRUPT_GEN( cvs_interrupt )
+{
+ stars_scroll++;
+
+ cpunum_set_input_line_vector(0,0,0x03);
+ cpunum_set_input_line(0,0,PULSE_LINE);
+}
+
+INLINE void plot_star(running_machine* machine, mame_bitmap *bitmap, int x, int y)
+{
+ if (flip_screen_x)
+ {
+ x = 255 - x;
+ }
+ if (flip_screen_y)
+ {
+ y = 255 - y;
+ }
+
+ if (*BITMAP_ADDR16(bitmap, y, x) == machine->pens[0])
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[7];
+ }
+}
+
+VIDEO_UPDATE( cvs )
+{
+ int offs;
+
+ /* for every character in the Video RAM, check if it has been modified */
+ /* since last time and update it accordingly. */
+
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int character_bank;
+ int forecolor;
+
+ int character = videoram[offs];
+
+ int sx = (offs % 32) * 8;
+ int sy = (offs / 32) * 8;
+
+ /* Decide if RAM or ROM based character */
+
+ if(character > ModeOffset[character_mode])
+ {
+ /* re-generate character if dirty */
+
+ if (dirty_character[character])
+ {
+ decodechar(machine->gfx[1],character,character_1_ram-1024,machine->drv->gfxdecodeinfo[1].gfxlayout);
+
+ dirty_character[character] = 0;
+ }
+
+ character_bank=1;
+ }
+ else
+ {
+ character_bank=0;
+ }
+
+ /* Main Screen */
+
+ drawgfx(tmpbitmap,machine->gfx[character_bank],
+ character,
+ colorram[offs],
+ 0,0,
+ sx,sy,
+ 0,TRANSPARENCY_NONE,0);
+
+
+ /* Foreground for Collision Detection */
+
+ forecolor = 0;
+ if(colorram[offs] & 0x80)
+ {
+ forecolor=258;
+ }
+ else
+ {
+ if((colorram[offs] & 0x03) == 3) forecolor=256;
+ else if((colorram[offs] & 0x01) == 0) forecolor=257;
+ }
+
+ if(forecolor)
+ drawgfx(cvs_collision_background,machine->gfx[character_bank],
+ character,
+ forecolor,
+ 0,0,
+ sx,sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+
+
+ /* Update screen - 8 regions, fixed scrolling area */
+
+ copyscrollbitmap(bitmap,tmpbitmap,0,0,8,scroll,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ copyscrollbitmap(scrolled_background,cvs_collision_background,0,0,8,scroll,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+
+ /* 2636's */
+
+ fillbitmap(s2636_1_bitmap,0,0);
+ s2636_update_bitmap(machine,s2636_1_bitmap,s2636_1_ram,s2636_1_dirty,2,cvs_collision_bitmap);
+
+ fillbitmap(s2636_2_bitmap,0,0);
+ s2636_update_bitmap(machine,s2636_2_bitmap,s2636_2_ram,s2636_2_dirty,3,cvs_collision_bitmap);
+
+ fillbitmap(s2636_3_bitmap,0,0);
+ s2636_update_bitmap(machine,s2636_3_bitmap,s2636_3_ram,s2636_3_dirty,4,cvs_collision_bitmap);
+
+ /* Bullet Hardware */
+
+ for (offs = 8; offs < 256; offs++ )
+ {
+ if(cvs_bullet_ram[offs] != 0)
+ {
+ int ct;
+ for(ct=0;ct<4;ct++)
+ {
+ int bx=255-7-cvs_bullet_ram[offs]-ct;
+
+ /* Bullet/Object Collision */
+
+ if((cvs_collision_register & 8) == 0)
+ {
+ if ((*BITMAP_ADDR8(s2636_1_bitmap, offs, bx) != 0) ||
+ (*BITMAP_ADDR8(s2636_2_bitmap, offs, bx) != 0) ||
+ (*BITMAP_ADDR8(s2636_3_bitmap, offs, bx) != 0))
+ cvs_collision_register |= 8;
+ }
+
+ /* Bullet/Background Collision */
+
+ if((cvs_collision_register & 0x80) == 0)
+ {
+ if (*BITMAP_ADDR8(scrolled_background, offs, bx) != machine->pens[0])
+ cvs_collision_register |= 0x80;
+ }
+
+ *BITMAP_ADDR16(bitmap, offs, bx) = machine->pens[7];
+ }
+ }
+ }
+
+ /* Update 2636 images */
+
+ {
+ int sx;
+ UINT32 S1,S2,S3,SB,pen;
+
+ for(sx=255;sx>7;sx--)
+ {
+ UINT32 *sp1 = (UINT32 *)BITMAP_ADDR8(s2636_1_bitmap, sx, 0);
+ UINT32 *sp2 = (UINT32 *)BITMAP_ADDR8(s2636_2_bitmap, sx, 0);
+ UINT32 *sp3 = (UINT32 *)BITMAP_ADDR8(s2636_3_bitmap, sx, 0);
+ UINT64 *dst = (UINT64 *)BITMAP_ADDR16(bitmap, sx, 0);
+ UINT8 *spb = (UINT8 *)BITMAP_ADDR8(scrolled_background, sx, 0);
+
+ for(offs=0;offs<62;offs++)
+ {
+ S1 = (*sp1++);
+ S2 = (*sp2++);
+ S3 = (*sp3++);
+
+ pen = S1 | S2 | S3;
+
+ if(pen)
+ {
+ UINT16 *address = (UINT16 *)dst;
+ if (pen & 0xff000000) address[BL3] = machine->pens[(pen >> 24) & 15];
+ if (pen & 0x00ff0000) address[BL2] = machine->pens[(pen >> 16) & 15];
+ if (pen & 0x0000ff00) address[BL1] = machine->pens[(pen >> 8) & 15];
+ if (pen & 0x000000ff) address[BL0] = machine->pens[(pen & 15)];
+
+ /* Collision Detection */
+
+ SB = 0;
+ if (spb[BL3] != machine->pens[0]) SB = 0x08000000;
+ if (spb[BL2] != machine->pens[0]) SB |= 0x00080000;
+ if (spb[BL1] != machine->pens[0]) SB |= 0x00000800;
+ if (spb[BL0] != machine->pens[0]) SB |= 0x00000008;
+
+ if (S1 & S2) cvs_collision_register |= 1;
+ if (S2 & S3) cvs_collision_register |= 2;
+ if (S1 & S3) cvs_collision_register |= 4;
+
+ if (SB)
+ {
+ if (S1 & SB) cvs_collision_register |= 16;
+ if (S2 & SB) cvs_collision_register |= 32;
+ if (S3 & SB) cvs_collision_register |= 64;
+ }
+ }
+
+ dst++;
+ spb+=4;
+ }
+ }
+ }
+
+ /* Stars */
+
+ if(stars_on)
+ {
+ for (offs = 0;offs < total_stars;offs++)
+ {
+ int x,y;
+
+
+ x = ((stars[offs].x + stars_scroll) % 512) / 2;
+ y = (stars[offs].y + (stars_scroll + stars[offs].x) / 512) % 256;
+
+ if (y >= machine->screen[0].visarea.min_y &&
+ y <= machine->screen[0].visarea.max_y)
+ {
+ if ((y & 1) ^ ((x >> 4) & 1))
+ {
+ plot_star(machine, bitmap, x, y);
+ }
+ }
+ }
+
+ }
+ return 0;
+}
diff --git a/src/mame/video/cyberbal.c b/src/mame/video/cyberbal.c
new file mode 100644
index 00000000000..b5274731132
--- /dev/null
+++ b/src/mame/video/cyberbal.c
@@ -0,0 +1,411 @@
+/***************************************************************************
+
+ Atari Cyberball hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "cyberbal.h"
+
+
+#define SCREEN_WIDTH (42*16)
+
+
+
+/*************************************
+ *
+ * Globals we own
+ *
+ *************************************/
+
+UINT16 *cyberbal_paletteram_0;
+UINT16 *cyberbal_paletteram_1;
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static UINT8 current_screen;
+static UINT8 total_screens;
+static UINT16 current_slip[2];
+static UINT8 playfield_palette_bank[2];
+static UINT16 playfield_xscroll[2];
+static UINT16 playfield_yscroll[2];
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha[tile_index];
+ int code = data & 0xfff;
+ int color = (data >> 12) & 0x07;
+ SET_TILE_INFO(2, code, color, (data >> 15) & 1);
+}
+
+
+static TILE_GET_INFO( get_alpha2_tile_info )
+{
+ UINT16 data = atarigen_alpha2[tile_index];
+ int code = data & 0xfff;
+ int color = (data >> 12) & 0x07;
+ SET_TILE_INFO(2, code, 0x80 | color, (data >> 15) & 1);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data = atarigen_playfield[tile_index];
+ int code = data & 0x1fff;
+ int color = (data >> 11) & 0x0f;
+ SET_TILE_INFO(0, code, color, (data >> 15) & 1);
+}
+
+
+static TILE_GET_INFO( get_playfield2_tile_info )
+{
+ UINT16 data = atarigen_playfield2[tile_index];
+ int code = data & 0x1fff;
+ int color = (data >> 11) & 0x0f;
+ SET_TILE_INFO(0, code, 0x80 | color, (data >> 15) & 1);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+static void video_start_cyberbal_common(running_machine* machine, int screens)
+{
+ static const struct atarimo_desc mo0desc =
+ {
+ 1, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 1, /* does the neighbor bit affect the next object? */
+ 1024, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x600, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0,0,0x07f8,0 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0x7fff,0,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0,0x000f }}, /* mask for the color */
+ {{ 0,0,0,0xffc0 }}, /* mask for the X position */
+ {{ 0,0xff80,0,0 }}, /* mask for the Y position */
+ {{ 0 }}, /* mask for the width, in tiles*/
+ {{ 0,0x000f,0,0 }}, /* mask for the height, in tiles */
+ {{ 0x8000,0,0,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0 }}, /* mask for the priority */
+ {{ 0,0,0,0x0010 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0 /* callback routine for special entries */
+ };
+
+ static const struct atarimo_desc mo1desc =
+ {
+ 1, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 1, /* does the neighbor bit affect the next object? */
+ 1024, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0xe00, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0,0,0x07f8,0 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0x7fff,0,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0,0x000f }}, /* mask for the color */
+ {{ 0,0,0,0xffc0 }}, /* mask for the X position */
+ {{ 0,0xff80,0,0 }}, /* mask for the Y position */
+ {{ 0 }}, /* mask for the width, in tiles*/
+ {{ 0,0x000f,0,0 }}, /* mask for the height, in tiles */
+ {{ 0x8000,0,0,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0 }}, /* mask for the priority */
+ {{ 0,0,0,0x0010 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0 /* callback routine for special entries */
+ };
+
+ /* set the slip variables */
+ atarimo_0_slipram = &current_slip[0];
+ atarimo_1_slipram = &current_slip[1];
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,8, 64,64);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &mo0desc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,8, 64,32);
+ tilemap_set_transparent_pen(atarigen_alpha_tilemap, 0);
+
+ /* allocate the second screen if necessary */
+ if (screens == 2)
+ {
+ /* initialize the playfield */
+ atarigen_playfield2_tilemap = tilemap_create(get_playfield2_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,8, 64,64);
+ tilemap_set_scrollx(atarigen_playfield2_tilemap, 0, 0);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 1, &mo1desc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha2_tilemap = tilemap_create(get_alpha2_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,8, 64,32);
+ tilemap_set_scrollx(atarigen_alpha2_tilemap, 0, 0);
+ tilemap_set_transparent_pen(atarigen_alpha2_tilemap, 0);
+ }
+
+ /* reset statics */
+ current_slip[0] = 0;
+ current_slip[1] = 0;
+ total_screens = screens;
+ current_screen = 0;
+}
+
+
+VIDEO_START( cyberbal )
+{
+ video_start_cyberbal_common(machine, 2);
+
+ /* adjust the sprite positions */
+ atarimo_set_xscroll(0, 4);
+ atarimo_set_xscroll(1, 4);
+}
+
+
+VIDEO_START( cyberb2p )
+{
+ video_start_cyberbal_common(machine, 1);
+
+ /* adjust the sprite positions */
+ atarimo_set_xscroll(0, 5);
+}
+
+
+
+/*************************************
+ *
+ * Screen switcher
+ *
+ *************************************/
+
+void cyberbal_set_screen(int which)
+{
+ if (which < total_screens)
+ current_screen = which;
+}
+
+
+
+/*************************************
+ *
+ * Palette tweaker
+ *
+ *************************************/
+
+INLINE void set_palette_entry(int entry, UINT16 value)
+{
+ int r, g, b;
+
+ r = ((value >> 9) & 0x3e) | ((value >> 15) & 1);
+ g = ((value >> 4) & 0x3e) | ((value >> 15) & 1);
+ b = ((value << 1) & 0x3e) | ((value >> 15) & 1);
+
+ palette_set_color_rgb(Machine, entry, pal6bit(r), pal6bit(g), pal6bit(b));
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM write handlers
+ *
+ *************************************/
+
+WRITE16_HANDLER( cyberbal_paletteram_0_w )
+{
+ COMBINE_DATA(&cyberbal_paletteram_0[offset]);
+ set_palette_entry(offset, cyberbal_paletteram_0[offset]);
+}
+
+READ16_HANDLER( cyberbal_paletteram_0_r )
+{
+ return cyberbal_paletteram_0[offset];
+}
+
+
+WRITE16_HANDLER( cyberbal_paletteram_1_w )
+{
+ COMBINE_DATA(&cyberbal_paletteram_1[offset]);
+ set_palette_entry(offset + 0x800, cyberbal_paletteram_1[offset]);
+}
+
+READ16_HANDLER( cyberbal_paletteram_1_r )
+{
+ return cyberbal_paletteram_1[offset];
+}
+
+
+
+/*************************************
+ *
+ * Periodic scanline updater
+ *
+ *************************************/
+
+void cyberbal_scanline_update(running_machine *machine, int scrnum, int scanline)
+{
+ int i;
+
+ /* loop over screens */
+ for (i = 0; i < total_screens; i++)
+ {
+ UINT16 *vram = i ? atarigen_alpha2 : atarigen_alpha;
+ UINT16 *base = &vram[((scanline - 8) / 8) * 64 + 47];
+ int update_screen = i;
+
+ /* keep in range */
+ if (base < vram)
+ base += 0x800;
+ else if (base >= &vram[0x800])
+ return;
+
+ /* update the current parameters */
+ if (!(base[3] & 1))
+ {
+ if (((base[3] >> 1) & 7) != playfield_palette_bank[i])
+ {
+ video_screen_update_partial(update_screen, scanline - 1);
+ playfield_palette_bank[i] = (base[3] >> 1) & 7;
+ tilemap_set_palette_offset(i ? atarigen_playfield2_tilemap : atarigen_playfield_tilemap, playfield_palette_bank[i] << 8);
+ }
+ }
+ if (!(base[4] & 1))
+ {
+ int newscroll = 2 * (((base[4] >> 7) + 4) & 0x1ff);
+ if (newscroll != playfield_xscroll[i])
+ {
+ video_screen_update_partial(update_screen, scanline - 1);
+ tilemap_set_scrollx(i ? atarigen_playfield2_tilemap : atarigen_playfield_tilemap, 0, newscroll);
+ playfield_xscroll[i] = newscroll;
+ }
+ }
+ if (!(base[5] & 1))
+ {
+ /* a new vscroll latches the offset into a counter; we must adjust for this */
+ int newscroll = ((base[5] >> 7) - (scanline)) & 0x1ff;
+ if (newscroll != playfield_yscroll[i])
+ {
+ video_screen_update_partial(update_screen, scanline - 1);
+ tilemap_set_scrolly(i ? atarigen_playfield2_tilemap : atarigen_playfield_tilemap, 0, newscroll);
+ playfield_yscroll[i] = newscroll;
+ }
+ }
+ if (!(base[7] & 1))
+ {
+ if (current_slip[i] != base[7])
+ {
+ video_screen_update_partial(update_screen, scanline - 1);
+ current_slip[i] = base[7];
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+static void update_one_screen(running_machine* machine, int screen, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ struct atarimo_rect_list rectlist;
+ rectangle tempclip = *cliprect;
+ mame_bitmap *mobitmap;
+ int x, y, r, mooffset, temp;
+
+ /* draw the playfield */
+ tilemap_draw(bitmap, cliprect, screen ? atarigen_playfield2_tilemap : atarigen_playfield_tilemap, 0, 0);
+
+ /* draw the MOs -- note some kludging to get this to work correctly for 2 screens */
+ mooffset = 0;
+ tempclip.min_x -= mooffset;
+ tempclip.max_x -= mooffset;
+ temp = machine->screen[screen].visarea.max_x;
+ if (temp > SCREEN_WIDTH)
+ machine->screen[screen].visarea.max_x /= 2;
+ mobitmap = atarimo_render(machine, screen, cliprect, &rectlist);
+ tempclip.min_x += mooffset;
+ tempclip.max_x += mooffset;
+ machine->screen[screen].visarea.max_x = temp;
+
+ /* draw and merge the MO */
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y + mooffset;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* not verified: logic is all controlled in a PAL
+ */
+ pf[x] = mo[x];
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+
+ /* add the alpha on top */
+ tilemap_draw(bitmap, cliprect, screen ? atarigen_alpha2_tilemap : atarigen_alpha_tilemap, 0, 0);
+}
+
+
+VIDEO_UPDATE( cyberbal )
+{
+ update_one_screen(machine, screen, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/darius.c b/src/mame/video/darius.c
new file mode 100644
index 00000000000..27edc7c3687
--- /dev/null
+++ b/src/mame/video/darius.c
@@ -0,0 +1,155 @@
+#include "driver.h"
+#include "video/taitoic.h"
+
+
+static tilemap *fg_tilemap;
+UINT16 *darius_fg_ram;
+
+struct tempsprite
+{
+ int gfx;
+ int code,color;
+ int flipx,flipy;
+ int x,y;
+ int zoomx,zoomy;
+ int primask;
+};
+static struct tempsprite *spritelist;
+
+
+/***************************************************************************/
+
+INLINE void actual_get_fg_tile_info(running_machine *machine, tile_data *tileinfo, int tile_index, UINT16 *ram,int gfxnum)
+{
+ UINT16 code = (ram[tile_index + 0x2000] & 0x7ff);
+ UINT16 attr = ram[tile_index];
+
+ SET_TILE_INFO(
+ gfxnum,
+ code,
+ ((attr & 0xff) << 2),
+ TILE_FLIPYX((attr & 0xc000) >> 14));
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ actual_get_fg_tile_info(machine, tileinfo, tile_index, darius_fg_ram, 2);
+}
+
+static void dirty_fg_tilemap(void)
+{
+ tilemap_mark_all_tiles_dirty(fg_tilemap);
+}
+
+/***************************************************************************/
+
+VIDEO_START( darius )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,128,64);
+
+ spritelist = auto_malloc(0x800 * sizeof(*spritelist));
+
+ /* (chips, gfxnum, x_offs, y_offs, y_invert, opaque, dblwidth) */
+ PC080SN_vh_start(1,1,-16,8,0,1,1);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ /* colors from saved states are often screwy (and this doesn't help...) */
+ state_save_register_func_postload(dirty_fg_tilemap);
+}
+
+/***************************************************************************/
+
+READ16_HANDLER( darius_fg_layer_r )
+{
+ return darius_fg_ram[offset];
+}
+
+WRITE16_HANDLER( darius_fg_layer_w )
+{
+ COMBINE_DATA(&darius_fg_ram[offset]);
+ if (offset < 0x4000)
+ tilemap_mark_tile_dirty(fg_tilemap,(offset & 0x1fff));
+}
+
+/***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int primask, int x_offs, int y_offs)
+{
+ int offs,curx,cury;
+ UINT16 code,data,sx,sy;
+ UINT8 flipx,flipy,color,priority;
+
+ /* pdrawgfx() needs us to draw sprites front to back, so we have to build a list
+ while processing sprite ram and then draw them all at the end */
+ struct tempsprite *sprite_ptr = spritelist;
+
+ for (offs = spriteram_size/2-4; offs >= 0; offs -= 4)
+ {
+ code = spriteram16[offs+2] &0x1fff;
+
+ if (code)
+ {
+ data = spriteram16[offs];
+ sy = (256-data) & 0x1ff;
+
+ data = spriteram16[offs+1];
+ sx = data & 0x3ff;
+
+ data = spriteram16[offs+2];
+ flipx = ((data & 0x4000) >> 14);
+ flipy = ((data & 0x8000) >> 15);
+
+ data = spriteram16[offs+3];
+ priority = (data &0x80) >> 7; // 0 = low
+ if (priority != primask) continue;
+ color = (data & 0x7f);
+
+ curx = sx - x_offs;
+ cury = sy + y_offs;
+
+ if (curx > 900) curx -= 1024;
+ if (cury > 400) cury -= 512;
+
+ sprite_ptr->code = code;
+ sprite_ptr->color = color;
+ sprite_ptr->flipx = flipx;
+ sprite_ptr->flipy = flipy;
+ sprite_ptr->x = curx;
+ sprite_ptr->y = cury;
+
+ drawgfx(bitmap,machine->gfx[0],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+
+
+VIDEO_UPDATE( darius )
+{
+ int xoffs = 36*8*screen;
+
+ PC080SN_tilemap_update();
+
+ // draw bottom layer(always active)
+ PC080SN_tilemap_draw_offset(bitmap,cliprect,0,0,TILEMAP_DRAW_OPAQUE,0,-xoffs,0);
+
+ /* Sprites can be under/over the layer below text layer */
+ draw_sprites(machine,bitmap,cliprect,0,xoffs,-8); // draw sprites with priority 0 which are under the mid layer
+
+ // draw middle layer
+ PC080SN_tilemap_draw_offset(bitmap,cliprect,0,1,0,0,-xoffs,0);
+
+ draw_sprites(machine,bitmap,cliprect,1,xoffs,-8); // draw sprites with priority 1 which are over the mid layer
+
+ /* top(text) layer is in fixed position */
+ tilemap_set_scrollx(fg_tilemap,0,0+xoffs);
+ tilemap_set_scrolly(fg_tilemap,0,-8);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/darkmist.c b/src/mame/video/darkmist.c
new file mode 100644
index 00000000000..a34e016fd0a
--- /dev/null
+++ b/src/mame/video/darkmist.c
@@ -0,0 +1,225 @@
+#include "driver.h"
+
+/*defined in drivers/darkmist.c */
+
+extern UINT8 * darkmist_scroll;
+extern int darkmist_hw;
+
+static int spritebank;
+
+/* vis. flags */
+
+#define DISPLAY_SPR 1
+#define DISPLAY_FG 2 /* 2 or 8 */
+#define DISPLAY_BG 4
+#define DISPLAY_TXT 16
+
+static tilemap *bgtilemap, *fgtilemap, *txtilemap;
+
+static TILE_GET_INFO( get_bgtile_info )
+{
+ int code,attr,pal;
+
+ code=memory_region(REGION_USER1)[tile_index]; /* TTTTTTTT */
+ attr=memory_region(REGION_USER2)[tile_index]; /* -PPP--TT - FIXED BITS (0xxx00xx) */
+ code+=(attr&3)<<8;
+ pal=(attr>>4);
+
+ SET_TILE_INFO(
+ 1,
+ code,
+ pal,
+ 0);
+}
+
+static TILE_GET_INFO( get_fgtile_info )
+{
+ int code,attr,pal;
+
+ code=memory_region(REGION_USER3)[tile_index]; /* TTTTTTTT */
+ attr=memory_region(REGION_USER4)[tile_index]; /* -PPP--TT - FIXED BITS (0xxx00xx) */
+ pal=attr>>4;
+
+ code+=(attr&3)<<8;
+
+ code+=0x400;
+
+ pal+=16;
+
+ SET_TILE_INFO(
+ 1,
+ code,
+ pal,
+ 0);
+}
+
+static TILE_GET_INFO( get_txttile_info )
+{
+ int code,attr,pal;
+
+ code=videoram[tile_index];
+ attr=videoram[tile_index+0x400];
+ pal=(attr>>1);
+
+ code+=(attr&1)<<8;
+
+ pal+=48;
+
+ SET_TILE_INFO(
+ 0,
+ code,
+ pal,
+ 0);
+}
+
+PALETTE_INIT(darkmist)
+{
+ int i;
+
+ /* black color */
+ palette_set_color(machine, 0x100, MAKE_RGB(0,0,0));
+
+ /* color lookup tables */
+
+ for (i = 0;i < 256;i++)
+ {
+ if (*color_prom & 0x40)
+ *(colortable++) = 0x100;
+ else
+ *(colortable++) = (*color_prom & 0x3f) + 0x80;
+ color_prom++;
+ }
+
+ for (i = 0;i < 256;i++)
+ {
+ if (*color_prom & 0x40)
+ *(colortable++) = 0x100;
+ else
+ *(colortable++) = (*color_prom & 0x3f) + 0x00;
+ color_prom++;
+ }
+
+ for (i = 0;i < 256;i++)
+ {
+ if (*color_prom & 0x40)
+ *(colortable++) = 0x100;
+ else
+ *(colortable++) = (*color_prom & 0x3f) + 0x40;
+ color_prom++;
+ }
+
+ for (i = 0;i < 256;i++)
+ {
+ if (*color_prom & 0x40)
+ *(colortable++) = 0x100;
+ else
+ *(colortable++) = (*color_prom & 0x3f) + 0xc0;
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER(darkmist_palette_w)
+{
+ paletteram[offset]=data;
+ offset&=0xff;
+ palette_set_color_rgb(Machine, offset, pal4bit(paletteram[offset+0x200]), pal4bit(paletteram[offset] >> 4), pal4bit(paletteram[offset]));
+}
+
+READ8_HANDLER(darkmist_palette_r)
+{
+ return paletteram[offset];
+}
+
+WRITE8_HANDLER(darkmist_spritebank_w)
+{
+ spritebank=data<<8;
+}
+
+VIDEO_START(darkmist)
+{
+ bgtilemap = tilemap_create( get_bgtile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,512,64 );
+ fgtilemap = tilemap_create( get_fgtile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,256 );
+ txtilemap = tilemap_create( get_txttile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+ tilemap_set_transparent_pen(fgtilemap, 0);
+ tilemap_set_transparent_pen(txtilemap, 0);
+}
+
+VIDEO_UPDATE( darkmist)
+{
+
+#define DM_GETSCROLL(n) (((darkmist_scroll[(n)]<<1)&0xff) + ((darkmist_scroll[(n)]&0x80)?1:0) +( ((darkmist_scroll[(n)-1]<<4) | (darkmist_scroll[(n)-1]<<12) )&0xff00))
+
+ tilemap_set_scrollx(bgtilemap, 0, DM_GETSCROLL(0x2));
+ tilemap_set_scrolly(bgtilemap, 0, DM_GETSCROLL(0x6));
+ tilemap_set_scrollx(fgtilemap, 0, DM_GETSCROLL(0xa));
+ tilemap_set_scrolly(fgtilemap, 0, DM_GETSCROLL(0xe));
+
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ if(darkmist_hw & DISPLAY_BG)
+ {
+ tilemap_draw(bitmap,cliprect,bgtilemap, 0,0);
+ }
+
+
+ if(darkmist_hw & DISPLAY_FG)
+ {
+ tilemap_draw(bitmap,cliprect,fgtilemap, 0,0);
+ }
+
+ if(darkmist_hw & DISPLAY_SPR)
+ {
+/*
+ Sprites
+
+ 76543210
+0 - TTTT TTTT - tile
+1 - xyBP PPP? - palette (P), flips (x,y), B - use spritebank,
+ ? - unknown, according to gamecode top bit of one of coords(y/x)
+2 - YYYY YYYY - y coord
+3 - XXXX XXXX - x coord
+
+*/
+ int i,fx,fy,tile,palette;
+ for(i=0;i<spriteram_size;i+=32)
+ {
+ fy=spriteram[i+1]&0x40;
+ fx=spriteram[i+1]&0x80;
+
+ tile=spriteram[i+0];
+
+ if(spriteram[i+1]&0x20)
+ {
+ tile+=spritebank;
+ }
+
+ palette=((spriteram[i+1])>>1)&0xf;
+
+ if(spriteram[i+1]&0x1)
+ palette=mame_rand(machine)&15;
+
+ palette+=32;
+
+ drawgfx(
+ bitmap,machine->gfx[2],
+ tile,
+ palette,
+ fx,fy,
+ spriteram[i+3],spriteram[i+2],
+ cliprect,
+ TRANSPARENCY_PEN,0 );
+ }
+
+ }
+
+ if(darkmist_hw & DISPLAY_TXT)
+ {
+ tilemap_mark_all_tiles_dirty(txtilemap);
+ tilemap_draw(bitmap,cliprect,txtilemap, 0,0);
+ }
+
+
+ return 0;
+}
+
+
diff --git a/src/mame/video/darkseal.c b/src/mame/video/darkseal.c
new file mode 100644
index 00000000000..525942e7d46
--- /dev/null
+++ b/src/mame/video/darkseal.c
@@ -0,0 +1,311 @@
+/***************************************************************************
+
+ Dark Seal Video emulation - Bryan McPhail, mish@tendril.co.uk
+
+****************************************************************************
+
+Data East custom chip 55: Generates two playfields, playfield 1 is underneath
+playfield 2. Dark Seal uses two of these chips. 1 playfield is _always_ off
+in this game.
+
+ 16 bytes of control registers per chip.
+
+ Word 0:
+ Mask 0x0080: Flip screen
+ Mask 0x007f: ?
+ Word 2:
+ Mask 0xffff: Playfield 2 X scroll (top playfield)
+ Word 4:
+ Mask 0xffff: Playfield 2 Y scroll (top playfield)
+ Word 6:
+ Mask 0xffff: Playfield 1 X scroll (bottom playfield)
+ Word 8:
+ Mask 0xffff: Playfield 1 Y scroll (bottom playfield)
+ Word 0xa:
+ Mask 0xc000: Playfield 1 shape??
+ Mask 0x3000: Playfield 1 rowscroll style (maybe mask 0x3800??)
+ Mask 0x0300: Playfield 1 colscroll style (maybe mask 0x0700??)?
+
+ Mask 0x00c0: Playfield 2 shape??
+ Mask 0x0030: Playfield 2 rowscroll style (maybe mask 0x0038??)
+ Mask 0x0003: Playfield 2 colscroll style (maybe mask 0x0007??)?
+ Word 0xc:
+ Mask 0x8000: Playfield 1 is 8*8 tiles else 16*16
+ Mask 0x4000: Playfield 1 rowscroll enabled
+ Mask 0x2000: Playfield 1 colscroll enabled
+ Mask 0x1f00: ?
+
+ Mask 0x0080: Playfield 2 is 8*8 tiles else 16*16
+ Mask 0x0040: Playfield 2 rowscroll enabled
+ Mask 0x0020: Playfield 2 colscroll enabled
+ Mask 0x001f: ?
+ Word 0xe:
+ ??
+
+Locations 0 & 0xe are mostly unknown:
+
+ 0 14
+Caveman Ninja (bottom): 0053 1100 (changes to 1111 later)
+Caveman Ninja (top): 0010 0081
+Two Crude (bottom): 0053 0000
+Two Crude (top): 0010 0041
+Dark Seal (bottom): 0010 0000
+Dark Seal (top): 0053 4101
+Tumblepop: 0010 0000
+Super Burger Time: 0010 0000
+
+Location 0xe looks like it could be a mirror of another byte..
+
+**************************************************************************
+
+Sprites - Data East custom chip 52
+
+ 8 bytes per sprite, unknowns bits seem unused.
+
+ Word 0:
+ Mask 0x8000 - ?
+ Mask 0x4000 - Y flip
+ Mask 0x2000 - X flip
+ Mask 0x1000 - Sprite flash
+ Mask 0x0800 - ?
+ Mask 0x0600 - Sprite height (1x, 2x, 4x, 8x)
+ Mask 0x01ff - Y coordinate
+
+ Word 2:
+ Mask 0xffff - Sprite number
+
+ Word 4:
+ Mask 0x8000 - ?
+ Mask 0x4000 - Sprite is drawn beneath top 8 pens of playfield 4
+ Mask 0x3e00 - Colour (32 palettes, most games only use 16)
+ Mask 0x01ff - X coordinate
+
+ Word 6:
+ Always unused.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *darkseal_pf12_row,*darkseal_pf34_row;
+UINT16 *darkseal_pf1_data,*darkseal_pf2_data,*darkseal_pf3_data;
+
+static UINT16 darkseal_control_0[8];
+static UINT16 darkseal_control_1[8];
+
+static tilemap *pf1_tilemap,*pf2_tilemap,*pf3_tilemap;
+static int flipscreen;
+
+/***************************************************************************/
+
+/* Function for all 16x16 1024x1024 layers */
+static TILEMAP_MAPPER( darkseal_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x20) << 5) + ((row & 0x20) << 6);
+}
+
+INLINE void get_bg_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int gfx_bank,UINT16 *gfx_base)
+{
+ int tile,color;
+
+ tile=gfx_base[tile_index];
+ color=tile >> 12;
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ gfx_bank,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info2 ) { get_bg_tile_info(machine,tileinfo,tile_index,1,darkseal_pf2_data); }
+static TILE_GET_INFO( get_bg_tile_info3 ) { get_bg_tile_info(machine,tileinfo,tile_index,2,darkseal_pf3_data); }
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int tile=darkseal_pf1_data[tile_index];
+ int color=tile >> 12;
+
+ tile=tile&0xfff;
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+/******************************************************************************/
+
+static void update_24bitcol(int offset)
+{
+ int r,g,b;
+
+ r = (paletteram16[offset] >> 0) & 0xff;
+ g = (paletteram16[offset] >> 8) & 0xff;
+ b = (paletteram16_2[offset] >> 0) & 0xff;
+
+ palette_set_color(Machine,offset,MAKE_RGB(r,g,b));
+}
+
+WRITE16_HANDLER( darkseal_palette_24bit_rg_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ update_24bitcol(offset);
+}
+
+WRITE16_HANDLER( darkseal_palette_24bit_b_w )
+{
+ COMBINE_DATA(&paletteram16_2[offset]);
+ update_24bitcol(offset);
+}
+
+/******************************************************************************/
+
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ sprite = buffered_spriteram16[offs+1] & 0x1fff;
+ if (!sprite) continue;
+
+ y = buffered_spriteram16[offs];
+ x = buffered_spriteram16[offs+2];
+
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ colour = (x >> 9) &0x1f;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 256) x -= 512;
+ if (y >= 256) y -= 512;
+ x = 240 - x;
+ y = 240 - y;
+
+ if (x>256) continue; /* Speedup */
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flipscreen)
+ {
+ y=240-y;
+ x=240-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ multi--;
+ }
+ }
+}
+
+/******************************************************************************/
+
+WRITE16_HANDLER( darkseal_pf1_data_w )
+{
+ COMBINE_DATA(&darkseal_pf1_data[offset]);
+ tilemap_mark_tile_dirty(pf1_tilemap,offset);
+}
+
+WRITE16_HANDLER( darkseal_pf2_data_w )
+{
+ COMBINE_DATA(&darkseal_pf2_data[offset]);
+ tilemap_mark_tile_dirty(pf2_tilemap,offset);
+}
+
+WRITE16_HANDLER( darkseal_pf3_data_w )
+{
+ COMBINE_DATA(&darkseal_pf3_data[offset]);
+ tilemap_mark_tile_dirty(pf3_tilemap,offset);
+}
+
+WRITE16_HANDLER( darkseal_pf3b_data_w ) /* Mirror */
+{
+ darkseal_pf3_data_w(offset+0x800,data,mem_mask);
+}
+
+WRITE16_HANDLER( darkseal_control_0_w )
+{
+ COMBINE_DATA(&darkseal_control_0[offset]);
+}
+
+WRITE16_HANDLER( darkseal_control_1_w )
+{
+ COMBINE_DATA(&darkseal_control_1[offset]);
+}
+
+/******************************************************************************/
+
+VIDEO_START( darkseal )
+{
+ pf1_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,64);
+ pf2_tilemap = tilemap_create(get_bg_tile_info2,darkseal_scan, TILEMAP_TYPE_PEN,16,16,64,64);
+ pf3_tilemap = tilemap_create(get_bg_tile_info3,darkseal_scan, TILEMAP_TYPE_PEN, 16,16,64,64);
+
+ tilemap_set_transparent_pen(pf1_tilemap,0);
+ tilemap_set_transparent_pen(pf2_tilemap,0);
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( darkseal )
+{
+ flipscreen=!(darkseal_control_0[0]&0x80);
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ /* Update scroll registers */
+ tilemap_set_scrollx( pf1_tilemap,0, darkseal_control_1[3] );
+ tilemap_set_scrolly( pf1_tilemap,0, darkseal_control_1[4] );
+ tilemap_set_scrollx( pf2_tilemap,0, darkseal_control_1[1]);
+ tilemap_set_scrolly( pf2_tilemap,0, darkseal_control_1[2] );
+
+ if (darkseal_control_0[6]&0x4000) { /* Rowscroll enable */
+ int offs,scrollx=darkseal_control_0[3];
+
+ tilemap_set_scroll_rows(pf3_tilemap,512);
+ for (offs = 0;offs < 512;offs++)
+ tilemap_set_scrollx( pf3_tilemap,offs, scrollx + darkseal_pf34_row[offs+0x40] );
+ }
+ else {
+ tilemap_set_scroll_rows(pf3_tilemap,1);
+ tilemap_set_scrollx( pf3_tilemap,0, darkseal_control_0[3] );
+ }
+ tilemap_set_scrolly( pf3_tilemap,0, darkseal_control_0[4] );
+
+ tilemap_draw(bitmap,cliprect,pf3_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ return 0;
+}
+
+/******************************************************************************/
diff --git a/src/mame/video/dassault.c b/src/mame/video/dassault.c
new file mode 100644
index 00000000000..7d7699259ce
--- /dev/null
+++ b/src/mame/video/dassault.c
@@ -0,0 +1,196 @@
+/***************************************************************************
+
+ Desert Assault Video emulation - Bryan McPhail, mish@tendril.co.uk
+
+****************************************************************************/
+
+#include "driver.h"
+#include "deco16ic.h"
+
+/******************************************************************************/
+
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect, int pf_priority)
+{
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+ int offs, bank, gfxbank;
+ const UINT16 *spritebase;
+
+ /* Have to loop over the two sprite sources */
+ for (bank=0; bank<2; bank++)
+ {
+ for (offs = 0x800-4;offs >= 0; offs -= 4)
+ {
+ int trans=TRANSPARENCY_PEN, pmask=0;
+
+ /* Draw the main spritebank after the other one */
+ if (bank==0)
+ {
+ spritebase=buffered_spriteram16;
+ gfxbank=3;
+ }
+ else
+ {
+ spritebase=buffered_spriteram16_2;
+ gfxbank=4;
+ }
+
+ sprite = spritebase[offs+1] & 0x7fff;
+ if (!sprite) continue;
+
+ x = spritebase[offs+2];
+
+ /* Alpha on chip 2 only */
+ if (bank==1 && x&0xc000)
+ trans=TRANSPARENCY_ALPHA;
+
+ y = spritebase[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+ colour = (x >> 9) &0x1f;
+ if (y&0x8000) colour+=32;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+ x = 304 - x;
+ y = 240 - y;
+
+ if (x>320) continue; /* Speedup */
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen) {
+ y=240-y;
+ x=304-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ /* Priority */
+ switch (pf_priority&3) {
+ case 0:
+ if (bank==0) {
+ switch (spritebase[offs+2]&0xc000) {
+ case 0xc000: pmask=1; break;
+ case 0x8000: pmask=8; break;
+ case 0x4000: pmask=32; break;
+ case 0x0000: pmask=128; break;
+ }
+ } else {
+ if (spritebase[offs+2]&0x8000) pmask=64; /* Check */
+ else pmask=64;
+ }
+ break;
+
+ case 1:
+ if (bank==0) {
+ switch (spritebase[offs+2]&0xc000) {
+ case 0xc000: pmask=1; break;
+ case 0x8000: pmask=8; break;
+ case 0x4000: pmask=32; break;
+ case 0x0000: pmask=128; break;
+ }
+ } else {
+ if (spritebase[offs+2]&0x8000) pmask=16; /* Check */
+ else pmask=16;
+ }
+ break;
+
+ case 2: /* Unused */
+ case 3:
+ if (bank==0) {
+ switch (spritebase[offs+2]&0xc000) {
+ case 0xc000: pmask=1; break;
+ case 0x8000: pmask=8; break;
+ case 0x4000: pmask=32; break;
+ case 0x0000: pmask=128; break;
+ }
+ } else {
+ if (spritebase[offs+2]&0x8000) pmask=64; /* Check */
+ else pmask=64;
+ }
+ break;
+ }
+
+ while (multi >= 0)
+ {
+ deco16_pdrawgfx(bitmap,machine->gfx[gfxbank],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,trans,0,pmask,1<<bank, 1);
+
+ multi--;
+ }
+ }
+ }
+}
+
+/******************************************************************************/
+
+static int dassault_bank_callback(const int bank)
+{
+ return ((bank>>4)&0xf)<<12;
+}
+
+VIDEO_START( dassault )
+{
+ deco16_2_video_init(0);
+
+ deco16_set_tilemap_bank_callback(0,dassault_bank_callback);
+ deco16_set_tilemap_bank_callback(1,dassault_bank_callback);
+ deco16_set_tilemap_bank_callback(2,dassault_bank_callback);
+ deco16_set_tilemap_bank_callback(3,dassault_bank_callback);
+
+ alpha_set_level(0x80);
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( dassault )
+{
+ /* Update tilemaps */
+ flip_screen_set( deco16_pf12_control[0]&0x80 );
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+ deco16_pf34_update(deco16_pf3_rowscroll,deco16_pf4_rowscroll);
+
+ /* Draw playfields/update priority bitmap */
+ deco16_clear_sprite_priority_bitmap();
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[3072],cliprect);
+ deco16_tilemap_4_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+
+ /* The middle playfields can be swapped priority-wise */
+ if ((deco16_priority&3)==0) {
+ deco16_tilemap_2_draw(bitmap,cliprect,0,2);
+ deco16_tilemap_3_draw(bitmap,cliprect,0,16);
+ } else if ((deco16_priority&3)==1) {
+ deco16_tilemap_3_draw(bitmap,cliprect,0,2);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,64);
+ } else if ((deco16_priority&3)==3) {
+ deco16_tilemap_3_draw(bitmap,cliprect,0,2);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,16);
+ } else {
+ /* Unused */
+ }
+
+ /* Draw sprites - two sprite generators, with selectable priority */
+ draw_sprites(machine,bitmap,cliprect,deco16_priority);
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+ return 0;
+}
diff --git a/src/mame/video/dbz.c b/src/mame/video/dbz.c
new file mode 100644
index 00000000000..091a4a3bdd4
--- /dev/null
+++ b/src/mame/video/dbz.c
@@ -0,0 +1,194 @@
+/*
+ Dragonball Z
+ (c) 1993 Banpresto
+ Dragonball Z 2 Super Battle
+ (c) 1994 Banpresto
+
+ Video hardware emulation.
+*/
+
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+static tilemap *dbz_bg1_tilemap, *dbz_bg2_tilemap;
+UINT16 *dbz_bg1_videoram, *dbz_bg2_videoram;
+static int sprite_colorbase, layer_colorbase[6], layer[5], layerpri[5];
+
+static void dbz_tile_callback(int layer, int *code, int *color, int *flags)
+{
+ *color = (layer_colorbase[layer] << 1) + ((*color & 0x3c) >> 2);
+}
+
+static void dbz_sprite_callback(int *code, int *color, int *priority_mask)
+{
+ int pri = (*color & 0x3c0) >> 5;
+
+ if(pri <= layerpri[3]) *priority_mask = 0xff00;
+ else if (pri > layerpri[3] && pri <= layerpri[2]) *priority_mask = 0xfff0;
+ else if (pri > layerpri[2] && pri <= layerpri[1]) *priority_mask = 0xfffc;
+ else *priority_mask = 0xfffe;
+
+ *color = (sprite_colorbase << 1) + (*color & 0x1f);
+}
+
+/* Background Tilemaps */
+
+WRITE16_HANDLER( dbz_bg2_videoram_w )
+{
+ COMBINE_DATA(&dbz_bg2_videoram[offset]);
+ tilemap_mark_tile_dirty(dbz_bg2_tilemap,offset/2);
+}
+
+static TILE_GET_INFO( get_dbz_bg2_tile_info )
+{
+ int tileno, colour, flag;
+
+ tileno = dbz_bg2_videoram[tile_index*2+1] & 0x7fff;
+ colour = (dbz_bg2_videoram[tile_index*2] & 0x000f);
+ flag = (dbz_bg2_videoram[tile_index*2] & 0x0080) ? TILE_FLIPX : 0;
+
+ SET_TILE_INFO(0,tileno,colour + (layer_colorbase[5] << 1),flag);
+}
+
+WRITE16_HANDLER( dbz_bg1_videoram_w )
+{
+ COMBINE_DATA(&dbz_bg1_videoram[offset]);
+ tilemap_mark_tile_dirty(dbz_bg1_tilemap,offset/2);
+}
+
+static TILE_GET_INFO( get_dbz_bg1_tile_info )
+{
+ int tileno, colour, flag;
+
+ tileno = dbz_bg1_videoram[tile_index*2+1] & 0x7fff;
+ colour = (dbz_bg1_videoram[tile_index*2] & 0x000f);
+ flag = (dbz_bg1_videoram[tile_index*2] & 0x0080) ? TILE_FLIPX : 0;
+
+ SET_TILE_INFO(1,tileno,colour + (layer_colorbase[4] << 1),flag);
+}
+
+/* useful function to sort the four tile layers by priority order */
+static void sortlayers(int *layer, int *pri)
+{
+#define SWAP(a,b) \
+ if (pri[a] <= pri[b]) \
+ { \
+ int t; \
+ t = pri[a]; pri[a] = pri[b]; pri[b] = t; \
+ t = layer[a]; layer[a] = layer[b]; layer[b] = t; \
+ }
+
+ SWAP(0, 1)
+ SWAP(0, 2)
+ SWAP(0, 3)
+ SWAP(0, 4)
+ SWAP(1, 2)
+ SWAP(1, 3)
+ SWAP(1, 4)
+ SWAP(2, 3)
+ SWAP(2, 4)
+ SWAP(3, 4)
+}
+
+VIDEO_START( dbz )
+{
+ K053251_vh_start();
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_4, 1, NULL, dbz_tile_callback, 1);
+ K053247_vh_start(machine, REGION_GFX2, -52, 16, NORMAL_PLANE_ORDER, dbz_sprite_callback);
+
+ dbz_bg1_tilemap = tilemap_create(get_dbz_bg1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,64,32);
+ dbz_bg2_tilemap = tilemap_create(get_dbz_bg2_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,64,32);
+
+ tilemap_set_transparent_pen(dbz_bg1_tilemap,0);
+ tilemap_set_transparent_pen(dbz_bg2_tilemap,0);
+
+ K053936_wraparound_enable(0, 1);
+ K053936_set_offset(0, -46, -16);
+
+ K053936_wraparound_enable(1, 1);
+ K053936_set_offset(1, -46, -16);
+
+ if (!strcmp(machine->gamedrv->name, "dbz"))
+ K056832_set_LayerOffset(0, -34, -16);
+ else
+ K056832_set_LayerOffset(0, -35, -16);
+
+ K056832_set_LayerOffset(1, -31, -16);
+ K056832_set_LayerOffset(3, -31, -16); //?
+
+ K053247_set_SpriteOffset(-87,32);
+}
+
+VIDEO_UPDATE( dbz )
+{
+ static const int K053251_CI[6] = { K053251_CI3, K053251_CI4, K053251_CI4, K053251_CI4, K053251_CI2, K053251_CI1 };
+ int plane, new_colorbase;
+
+ sprite_colorbase = K053251_get_palette_index(K053251_CI0);
+
+ for (plane=0; plane<6; plane++)
+ {
+ new_colorbase = K053251_get_palette_index(K053251_CI[plane]);
+ if (layer_colorbase[plane] != new_colorbase)
+ {
+ layer_colorbase[plane] = new_colorbase;
+ if(plane <= 3)
+ K056832_mark_plane_dirty(plane);
+ else if(plane == 4)
+ tilemap_mark_all_tiles_dirty(dbz_bg1_tilemap);
+ else if(plane == 5)
+ tilemap_mark_all_tiles_dirty(dbz_bg2_tilemap);
+ }
+ }
+
+ //layers priority
+
+ layer[0] = 0;
+ layerpri[0] = K053251_get_priority(K053251_CI3);
+ layer[1] = 1;
+ layerpri[1] = K053251_get_priority(K053251_CI4);
+ layer[2] = 3;
+ layerpri[2] = K053251_get_priority(K053251_CI0);
+ layer[3] = 4;
+ layerpri[3] = K053251_get_priority(K053251_CI2);
+ layer[4] = 5;
+ layerpri[4] = K053251_get_priority(K053251_CI1);
+
+ sortlayers(layer, layerpri);
+
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ for(plane = 0; plane < 5; plane++)
+ {
+ int flag, pri;
+
+ if(plane == 0)
+ {
+ flag = TILEMAP_DRAW_OPAQUE;
+ pri = 0;
+ }
+ else
+ {
+ flag = 0;
+ pri = 1 << (plane - 1);
+ }
+
+ if(layer[plane] == 4)
+ {
+ K053936_1_zoom_draw(bitmap,cliprect,dbz_bg1_tilemap,flag,pri);
+ }
+ else if(layer[plane] == 5)
+ {
+ K053936_0_zoom_draw(bitmap,cliprect,dbz_bg2_tilemap,flag,pri);
+ }
+ else
+ {
+ K056832_tilemap_draw(machine, bitmap,cliprect,layer[plane],flag,pri);
+ }
+ }
+
+ K053247_sprites_draw(machine, bitmap, cliprect);
+ return 0;
+}
+
diff --git a/src/mame/video/dc.c b/src/mame/video/dc.c
new file mode 100644
index 00000000000..1e39276a020
--- /dev/null
+++ b/src/mame/video/dc.c
@@ -0,0 +1,48 @@
+/*
+ dc.c - Dreamcast video emulation
+
+*/
+
+#include "driver.h"
+#include "dc.h"
+
+VIDEO_START(dc)
+{
+}
+
+VIDEO_UPDATE(dc)
+{
+ return 0;
+}
+
+READ64_HANDLER( pvr_ctrl_r )
+{
+ return 0;
+}
+
+WRITE64_HANDLER( pvr_ctrl_w )
+{
+ mame_printf_verbose("PVRCTRL: write %llx to %x, mask %llx\n", data, offset, mem_mask);
+}
+
+READ64_HANDLER( pvr_ta_r )
+{
+ return 0;
+}
+
+WRITE64_HANDLER( pvr_ta_w )
+{
+ mame_printf_verbose("PVR TA: write %llx to %x, mask %llx\n", data, offset, mem_mask);
+}
+
+
+WRITE64_HANDLER( ta_fifo_poly_w )
+{
+ mame_printf_verbose("Poly FIFO: write %llx to %x, mask %llx\n", data, offset, mem_mask);
+}
+
+WRITE64_HANDLER( ta_fifo_yuv_w )
+{
+ mame_printf_verbose("YUV FIFO: write %llx to %x, mask %llx\n", data, offset, mem_mask);
+}
+
diff --git a/src/mame/video/dcheese.c b/src/mame/video/dcheese.c
new file mode 100644
index 00000000000..a406753887a
--- /dev/null
+++ b/src/mame/video/dcheese.c
@@ -0,0 +1,331 @@
+/***************************************************************************
+
+ HAR MadMax hardware
+
+**************************************************************************/
+
+
+#include "driver.h"
+#include "dcheese.h"
+
+
+/*************************************
+ *
+ * Constants
+ *
+ *************************************/
+
+#define DSTBITMAP_WIDTH 512
+#define DSTBITMAP_HEIGHT 512
+
+
+
+/*************************************
+ *
+ * Local variables
+ *
+ *************************************/
+
+static UINT16 blitter_color[2];
+static UINT16 blitter_xparam[16];
+static UINT16 blitter_yparam[16];
+static UINT16 blitter_vidparam[32];
+
+static mame_bitmap *dstbitmap;
+static emu_timer *blitter_timer;
+
+
+
+/*************************************
+ *
+ * Palette translation
+ *
+ *************************************/
+
+PALETTE_INIT( dcheese )
+{
+ const UINT16 *src = (UINT16 *)memory_region(REGION_USER1);
+ int i;
+
+ /* really 65536 colors, but they don't use the later ones so we can stay */
+ /* within MAME's limits */
+ for (i = 0; i < 65534; i++)
+ {
+ int data = *src++;
+ palette_set_color_rgb(machine, i, pal6bit(data >> 0), pal5bit(data >> 6), pal5bit(data >> 11));
+ }
+}
+
+
+
+/*************************************
+ *
+ * Scanline interrupt
+ *
+ *************************************/
+
+static void update_scanline_irq(void)
+{
+ /* if not in range, don't bother */
+ if (blitter_vidparam[0x22/2] <= blitter_vidparam[0x1e/2])
+ {
+ int effscan;
+ attotime time;
+
+ /* compute the effective scanline of the interrupt */
+ effscan = blitter_vidparam[0x22/2] - blitter_vidparam[0x1a/2];
+ if (effscan < 0)
+ effscan += blitter_vidparam[0x1e/2];
+
+ /* determine the time; if it's in this scanline, bump to the next frame */
+ time = video_screen_get_time_until_pos(0, effscan, 0);
+ if (attotime_compare(time, video_screen_get_scan_period(0)) < 0)
+ time = attotime_add(time, video_screen_get_frame_period(0));
+ timer_adjust(blitter_timer, time, 0, attotime_zero);
+ }
+}
+
+
+static TIMER_CALLBACK( blitter_scanline_callback )
+{
+ dcheese_signal_irq(3);
+ update_scanline_irq();
+}
+
+
+static TIMER_CALLBACK( dcheese_signal_irq_callback )
+{
+ dcheese_signal_irq(param);
+}
+
+
+/*************************************
+ *
+ * Video start
+ *
+ *************************************/
+
+VIDEO_START( dcheese )
+{
+ /* the destination bitmap is not directly accessible to the CPU */
+ dstbitmap = auto_bitmap_alloc(DSTBITMAP_WIDTH, DSTBITMAP_HEIGHT, machine->screen[0].format);
+
+ /* create a timer */
+ blitter_timer = timer_alloc(blitter_scanline_callback);
+
+ /* register for saving */
+ state_save_register_global_array(blitter_color);
+ state_save_register_global_array(blitter_xparam);
+ state_save_register_global_array(blitter_yparam);
+ state_save_register_global_array(blitter_vidparam);
+ state_save_register_global_bitmap(dstbitmap);
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( dcheese )
+{
+ int x, y;
+
+ /* update the pixels */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ UINT16 *src = BITMAP_ADDR16(dstbitmap, (y + blitter_vidparam[0x28/2]) % DSTBITMAP_HEIGHT, 0);
+
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ dest[x] = src[x];
+ }
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Blitter implementation
+ *
+ *************************************/
+
+static void do_clear(void)
+{
+ int y;
+
+ /* clear the requested scanlines */
+ for (y = blitter_vidparam[0x2c/2]; y < blitter_vidparam[0x2a/2]; y++)
+ memset(BITMAP_ADDR16(dstbitmap, y % DSTBITMAP_HEIGHT, 0), 0, DSTBITMAP_WIDTH * 2);
+
+ /* signal an IRQ when done (timing is just a guess) */
+ timer_set(video_screen_get_scan_period(0), 1, dcheese_signal_irq_callback);
+}
+
+
+static void do_blit(void)
+{
+ INT32 srcminx = blitter_xparam[0] << 12;
+ INT32 srcmaxx = blitter_xparam[1] << 12;
+ INT32 srcminy = blitter_yparam[0] << 12;
+ INT32 srcmaxy = blitter_yparam[1] << 12;
+ INT32 srcx = ((blitter_xparam[2] & 0x0fff) | ((blitter_xparam[3] & 0x0fff) << 12)) << 7;
+ INT32 srcy = ((blitter_yparam[2] & 0x0fff) | ((blitter_yparam[3] & 0x0fff) << 12)) << 7;
+ INT32 dxdx = (INT32)(((blitter_xparam[4] & 0x0fff) | ((blitter_xparam[5] & 0x0fff) << 12)) << 12) >> 12;
+ INT32 dxdy = (INT32)(((blitter_xparam[6] & 0x0fff) | ((blitter_xparam[7] & 0x0fff) << 12)) << 12) >> 12;
+ INT32 dydx = (INT32)(((blitter_yparam[4] & 0x0fff) | ((blitter_yparam[5] & 0x0fff) << 12)) << 12) >> 12;
+ INT32 dydy = (INT32)(((blitter_yparam[6] & 0x0fff) | ((blitter_yparam[7] & 0x0fff) << 12)) << 12) >> 12;
+ UINT8 *src = memory_region(REGION_GFX1);
+ UINT32 pagemask = (memory_region_length(REGION_GFX1) - 1) / 0x40000;
+ int xstart = blitter_xparam[14];
+ int xend = blitter_xparam[15] + 1;
+ int ystart = blitter_yparam[14];
+ int yend = blitter_yparam[15];
+ int color = (blitter_color[0] << 8) & 0xff00;
+ int mask = (blitter_color[0] >> 8) & 0x00ff;
+ int opaque = (dxdx | dxdy | dydx | dydy) == 0; /* bit of a hack for fredmem */
+ int x, y;
+
+ /* loop over target rows */
+ for (y = ystart; y <= yend; y++)
+ {
+ UINT16 *dst = BITMAP_ADDR16(dstbitmap, y % DSTBITMAP_HEIGHT, 0);
+
+ /* loop over target columns */
+ for (x = xstart; x <= xend; x++)
+ {
+ /* compute current X/Y positions */
+ int sx = (srcx + dxdx * (x - xstart) + dxdy * (y - ystart)) & 0xffffff;
+ int sy = (srcy + dydx * (x - xstart) + dydy * (y - ystart)) & 0xffffff;
+
+ /* clip to source cliprect */
+ if (sx >= srcminx && sx <= srcmaxx && sy >= srcminy && sy <= srcmaxy)
+ {
+ /* page comes from bit 22 of Y and bit 21 of X */
+ int page = (((sy >> 21) & 2) | ((sx >> 21) & 1) | ((sx >> 20) & 4)) & pagemask;
+ int pix = src[0x40000 * page + ((sy >> 12) & 0x1ff) * 512 + ((sx >> 12) & 0x1ff)];
+
+ /* only non-zero pixels get written */
+ if (pix | opaque)
+ dst[x % DSTBITMAP_WIDTH] = (pix & mask) | color;
+ }
+ }
+ }
+
+ /* signal an IRQ when done (timing is just a guess) */
+ timer_set(attotime_make(0, attotime_to_attoseconds(video_screen_get_scan_period(0)) / 2), 2, dcheese_signal_irq_callback);
+
+ /* these extra parameters are written but they are always zero, so I don't know what they do */
+ if (blitter_xparam[8] != 0 || blitter_xparam[9] != 0 || blitter_xparam[10] != 0 || blitter_xparam[11] != 0 ||
+ blitter_yparam[8] != 0 || blitter_yparam[9] != 0 || blitter_yparam[10] != 0 || blitter_yparam[11] != 0)
+ {
+ logerror("%06X:blit! (%04X)\n", activecpu_get_pc(), blitter_color[0]);
+ logerror(" %04X %04X %04X %04X - %04X %04X %04X %04X - %04X %04X %04X %04X - %04X %04X %04X %04X\n",
+ blitter_xparam[0], blitter_xparam[1], blitter_xparam[2], blitter_xparam[3],
+ blitter_xparam[4], blitter_xparam[5], blitter_xparam[6], blitter_xparam[7],
+ blitter_xparam[8], blitter_xparam[9], blitter_xparam[10], blitter_xparam[11],
+ blitter_xparam[12], blitter_xparam[13], blitter_xparam[14], blitter_xparam[15]);
+ logerror(" %04X %04X %04X %04X - %04X %04X %04X %04X - %04X %04X %04X %04X - %04X %04X %04X %04X\n",
+ blitter_yparam[0], blitter_yparam[1], blitter_yparam[2], blitter_yparam[3],
+ blitter_yparam[4], blitter_yparam[5], blitter_yparam[6], blitter_yparam[7],
+ blitter_yparam[8], blitter_yparam[9], blitter_yparam[10], blitter_yparam[11],
+ blitter_yparam[12], blitter_yparam[13], blitter_yparam[14], blitter_yparam[15]);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Blitter read/write
+ *
+ *************************************/
+
+WRITE16_HANDLER( madmax_blitter_color_w )
+{
+ COMBINE_DATA(&blitter_color[offset]);
+}
+
+
+WRITE16_HANDLER( madmax_blitter_xparam_w )
+{
+ COMBINE_DATA(&blitter_xparam[offset]);
+}
+
+
+WRITE16_HANDLER( madmax_blitter_yparam_w )
+{
+ COMBINE_DATA(&blitter_yparam[offset]);
+}
+
+
+WRITE16_HANDLER( madmax_blitter_vidparam_w )
+{
+ COMBINE_DATA(&blitter_vidparam[offset]);
+
+ switch (offset)
+ {
+ case 0x10/2: /* horiz front porch */
+ case 0x12/2: /* horiz display start */
+ case 0x14/2: /* horiz display end */
+ case 0x16/2: /* horiz back porch */
+
+ case 0x18/2: /* vert front porch */
+ case 0x1a/2: /* vert display start */
+ case 0x1c/2: /* vert display end */
+ case 0x1e/2: /* vert back porch */
+ break;
+
+ case 0x22/2: /* scanline interrupt */
+ update_scanline_irq();
+ break;
+
+ case 0x24/2: /* writes here after writing to 0x28 */
+ break;
+
+ case 0x28/2: /* display starting y */
+ case 0x2a/2: /* clear end y */
+ case 0x2c/2: /* clear start y */
+ break;
+
+ case 0x38/2: /* blit */
+ do_blit();
+ break;
+
+ case 0x3e/2: /* clear */
+ do_clear();
+ break;
+
+ default:
+ logerror("%06X:write to %06X = %04X & %04x\n", activecpu_get_pc(), 0x2a0000 + 2 * offset, data, mem_mask ^ 0xffff);
+ break;
+ }
+}
+
+
+WRITE16_HANDLER( madmax_blitter_unknown_w )
+{
+ /* written to just before the blitter command register is written */
+ logerror("%06X:write to %06X = %04X & %04X\n", activecpu_get_pc(), 0x300000 + 2 * offset, data, mem_mask ^ 0xffff);
+}
+
+
+READ16_HANDLER( madmax_blitter_vidparam_r )
+{
+ /* analog inputs seem to be hooked up here -- might not actually map to blitter */
+ if (offset == 0x02/2)
+ return readinputport(3);
+ if (offset == 0x0e/2)
+ return readinputport(4);
+
+ /* early code polls on this bit, wants it to be 0 */
+ if (offset == 0x36/2)
+ return 0xffff ^ (1 << 5);
+
+ /* log everything else */
+ logerror("%06X:read from %06X\n", activecpu_get_pc(), 0x2a0000 + 2 * offset);
+ return 0xffff;
+}
diff --git a/src/mame/video/dcon.c b/src/mame/video/dcon.c
new file mode 100644
index 00000000000..45745e92d17
--- /dev/null
+++ b/src/mame/video/dcon.c
@@ -0,0 +1,329 @@
+/***************************************************************************
+
+ D-Con video hardware.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *dcon_back_data,*dcon_fore_data,*dcon_mid_data,*dcon_scroll_ram,*dcon_textram;
+
+static tilemap *background_layer,*foreground_layer,*midground_layer,*text_layer;
+static UINT16 dcon_enable;
+static int dcon_gfx_bank_select;
+
+/******************************************************************************/
+
+READ16_HANDLER( dcon_control_r )
+{
+ return dcon_enable;
+}
+
+WRITE16_HANDLER( dcon_control_w )
+{
+ if (ACCESSING_LSB)
+ {
+ dcon_enable=data;
+ if ((dcon_enable&4)==4)
+ tilemap_set_enable(foreground_layer,0);
+ else
+ tilemap_set_enable(foreground_layer,1);
+
+ if ((dcon_enable&2)==2)
+ tilemap_set_enable(midground_layer,0);
+ else
+ tilemap_set_enable(midground_layer,1);
+
+ if ((dcon_enable&1)==1)
+ tilemap_set_enable(background_layer,0);
+ else
+ tilemap_set_enable(background_layer,1);
+ }
+}
+
+WRITE16_HANDLER( dcon_gfxbank_w )
+{
+ if (data&1)
+ dcon_gfx_bank_select=0x1000;
+ else
+ dcon_gfx_bank_select=0;
+}
+
+WRITE16_HANDLER( dcon_background_w )
+{
+ COMBINE_DATA(&dcon_back_data[offset]);
+ tilemap_mark_tile_dirty(background_layer,offset);
+}
+
+WRITE16_HANDLER( dcon_foreground_w )
+{
+ COMBINE_DATA(&dcon_fore_data[offset]);
+ tilemap_mark_tile_dirty(foreground_layer,offset);
+}
+
+WRITE16_HANDLER( dcon_midground_w )
+{
+ COMBINE_DATA(&dcon_mid_data[offset]);
+ tilemap_mark_tile_dirty(midground_layer,offset);
+}
+
+WRITE16_HANDLER( dcon_text_w )
+{
+ COMBINE_DATA(&dcon_textram[offset]);
+ tilemap_mark_tile_dirty(text_layer,offset);
+}
+
+static TILE_GET_INFO( get_back_tile_info )
+{
+ int tile=dcon_back_data[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile&=0xfff;
+
+ SET_TILE_INFO(
+ 1,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_fore_tile_info )
+{
+ int tile=dcon_fore_data[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile&=0xfff;
+
+ SET_TILE_INFO(
+ 2,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_mid_tile_info )
+{
+ int tile=dcon_mid_data[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile&=0xfff;
+
+ SET_TILE_INFO(
+ 3,
+ tile|dcon_gfx_bank_select,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ int tile = dcon_textram[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile&=0xfff;
+
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+VIDEO_START( dcon )
+{
+ background_layer = tilemap_create(get_back_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,32,32);
+ foreground_layer = tilemap_create(get_fore_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ midground_layer = tilemap_create(get_mid_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ text_layer = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,32);
+
+ tilemap_set_transparent_pen(midground_layer,15);
+ tilemap_set_transparent_pen(foreground_layer,15);
+ tilemap_set_transparent_pen(text_layer,15);
+
+ dcon_gfx_bank_select = 0;
+}
+
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs,fx,fy,x,y,color,sprite;
+ int dx,dy,ax,ay,inc,pri_mask = 0;
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ if ((spriteram16[offs+0]&0x8000)!=0x8000) continue;
+ sprite = spriteram16[offs+1];
+
+ switch((sprite>>14) & 3)
+ {
+ case 0: pri_mask = 0xf0; // above foreground layer
+ break;
+ case 1: pri_mask = 0xfc; // above midground layer
+ break;
+ case 2: pri_mask = 0xfe; // above background layer
+ break;
+ case 3: pri_mask = 0; // above text layer
+ break;
+ }
+
+ sprite &= 0x3fff;
+
+ y = spriteram16[offs+3];
+ x = spriteram16[offs+2];
+
+ if (x&0x8000) x=0-(0x200-(x&0x1ff));
+ else x&=0x1ff;
+ if (y&0x8000) y=0-(0x200-(y&0x1ff));
+ else y&=0x1ff;
+
+ color = spriteram16[offs+0]&0x3f;
+ fx = spriteram16[offs+0]&0x4000;
+ fy = spriteram16[offs+0]&0x2000;
+ dy=((spriteram16[offs+0]&0x0380)>>7)+1;
+ dx=((spriteram16[offs+0]&0x1c00)>>10)+1;
+
+ inc = 0;
+
+ for (ax=0; ax<dx; ax++)
+ for (ay=0; ay<dy; ay++) {
+ if (!fx && !fy)
+ {
+ pdrawgfx(bitmap,machine->gfx[4],
+ sprite + inc,
+ color,fx,fy,x+ax*16,y+ay*16,
+ cliprect,TRANSPARENCY_PEN,15,pri_mask);
+
+ // wrap around y
+ pdrawgfx(bitmap,machine->gfx[4],
+ sprite + inc,
+ color,fx,fy,x+ax*16,y+ay*16 + 512,
+ cliprect,TRANSPARENCY_PEN,15,pri_mask);
+
+ // wrap around y
+ pdrawgfx(bitmap,machine->gfx[4],
+ sprite + inc,
+ color,fx,fy,x+ax*16,y+ay*16 - 512,
+ cliprect,TRANSPARENCY_PEN,15,pri_mask);
+ }
+ else if (fx && !fy)
+ {
+ pdrawgfx(bitmap,machine->gfx[4],
+ sprite + inc,
+ color,fx,fy,x+(dx-1-ax)*16,y+ay*16,
+ cliprect,TRANSPARENCY_PEN,15,pri_mask);
+
+ // wrap around y
+ pdrawgfx(bitmap,machine->gfx[4],
+ sprite + inc,
+ color,fx,fy,x+(dx-1-ax)*16,y+ay*16 + 512,
+ cliprect,TRANSPARENCY_PEN,15,pri_mask);
+
+ // wrap around y
+ pdrawgfx(bitmap,machine->gfx[4],
+ sprite + inc,
+ color,fx,fy,x+(dx-1-ax)*16,y+ay*16 - 512,
+ cliprect,TRANSPARENCY_PEN,15,pri_mask);
+ }
+ else if (!fx && fy)
+ {
+ pdrawgfx(bitmap,machine->gfx[4],
+ sprite + inc,
+ color,fx,fy,x+ax*16,y+(dy-1-ay)*16,
+ cliprect,TRANSPARENCY_PEN,15,pri_mask);
+
+ // wrap around y
+ pdrawgfx(bitmap,machine->gfx[4],
+ sprite + inc,
+ color,fx,fy,x+ax*16,y+(dy-1-ay)*16 + 512,
+ cliprect,TRANSPARENCY_PEN,15,pri_mask);
+
+ // wrap around y
+ pdrawgfx(bitmap,machine->gfx[4],
+ sprite + inc,
+ color,fx,fy,x+ax*16,y+(dy-1-ay)*16 - 512,
+ cliprect,TRANSPARENCY_PEN,15,pri_mask);
+ }
+ else
+ {
+ pdrawgfx(bitmap,machine->gfx[4],
+ sprite + inc,
+ color,fx,fy,x+(dx-1-ax)*16,y+(dy-1-ay)*16,
+ cliprect,TRANSPARENCY_PEN,15,pri_mask);
+
+ // wrap around y
+ pdrawgfx(bitmap,machine->gfx[4],
+ sprite + inc,
+ color,fx,fy,x+(dx-1-ax)*16,y+(dy-1-ay)*16 + 512,
+ cliprect,TRANSPARENCY_PEN,15,pri_mask);
+
+ // wrap around y
+ pdrawgfx(bitmap,machine->gfx[4],
+ sprite + inc,
+ color,fx,fy,x+(dx-1-ax)*16,y+(dy-1-ay)*16 - 512,
+ cliprect,TRANSPARENCY_PEN,15,pri_mask);
+ }
+
+ inc++;
+ }
+ }
+}
+
+VIDEO_UPDATE( dcon )
+{
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* Setup the tilemaps */
+ tilemap_set_scrollx( background_layer,0, dcon_scroll_ram[0] );
+ tilemap_set_scrolly( background_layer,0, dcon_scroll_ram[1] );
+ tilemap_set_scrollx( midground_layer, 0, dcon_scroll_ram[2] );
+ tilemap_set_scrolly( midground_layer, 0, dcon_scroll_ram[3] );
+ tilemap_set_scrollx( foreground_layer,0, dcon_scroll_ram[4] );
+ tilemap_set_scrolly( foreground_layer,0, dcon_scroll_ram[5] );
+
+ if ((dcon_enable&1)!=1)
+ tilemap_draw(bitmap,cliprect,background_layer,0,0);
+ else
+ fillbitmap(bitmap,machine->pens[15],cliprect); /* Should always be black, not pen 15 */
+
+ tilemap_draw(bitmap,cliprect,midground_layer,0,1);
+ tilemap_draw(bitmap,cliprect,foreground_layer,0,2);
+ tilemap_draw(bitmap,cliprect,text_layer,0,4);
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( sdgndmps )
+{
+ static int last_gfx_bank=0;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* Gfx banking */
+ if (last_gfx_bank!=dcon_gfx_bank_select)
+ {
+ tilemap_mark_all_tiles_dirty(midground_layer);
+ last_gfx_bank=dcon_gfx_bank_select;
+ }
+
+ /* Setup the tilemaps */
+ tilemap_set_scrollx( background_layer,0, dcon_scroll_ram[0]+128 );
+ tilemap_set_scrolly( background_layer,0, dcon_scroll_ram[1] );
+ tilemap_set_scrollx( midground_layer, 0, dcon_scroll_ram[2]+128 );
+ tilemap_set_scrolly( midground_layer, 0, dcon_scroll_ram[3] );
+ tilemap_set_scrollx( foreground_layer,0, dcon_scroll_ram[4]+128 );
+ tilemap_set_scrolly( foreground_layer,0, dcon_scroll_ram[5] );
+ tilemap_set_scrollx( text_layer,0, /*dcon_scroll_ram[6] + */ 128 );
+ tilemap_set_scrolly( text_layer,0, /*dcon_scroll_ram[7] + */ 0 );
+
+ if ((dcon_enable&1)!=1)
+ tilemap_draw(bitmap,cliprect,background_layer,0,0);
+ else
+ fillbitmap(bitmap,machine->pens[15],cliprect); /* Should always be black, not pen 15 */
+
+ tilemap_draw(bitmap,cliprect,midground_layer,0,1);
+ tilemap_draw(bitmap,cliprect,foreground_layer,0,2);
+ tilemap_draw(bitmap,cliprect,text_layer,0,4);
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/dday.c b/src/mame/video/dday.c
new file mode 100644
index 00000000000..0d6c74b6e9f
--- /dev/null
+++ b/src/mame/video/dday.c
@@ -0,0 +1,379 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+ Convention: "sl" stands for "searchlight"
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *dday_bgvideoram;
+UINT8 *dday_fgvideoram;
+UINT8 *dday_textvideoram;
+UINT8 *dday_colorram;
+
+static tilemap *fg_tilemap, *bg_tilemap, *text_tilemap, *sl_tilemap;
+static mame_bitmap *main_bitmap;
+static int control;
+static int sl_image;
+static int sl_enable;
+static int timer_value;
+
+
+/* Note: There seems to be no way to reset this timer via hardware.
+ The game uses a difference method to reset it to 99.
+
+ Thanks Zwaxy for the timer info. */
+
+READ8_HANDLER( dday_countdown_timer_r )
+{
+ return ((timer_value / 10) << 4) | (timer_value % 10);
+}
+
+static TIMER_CALLBACK( countdown_timer_callback )
+{
+ timer_value--;
+
+ if (timer_value < 0)
+ {
+ timer_value = 99;
+ }
+}
+
+static void start_countdown_timer(void)
+{
+ timer_value = 0;
+
+ timer_pulse(ATTOTIME_IN_SEC(1), 0, countdown_timer_callback);
+}
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+***************************************************************************/
+
+PALETTE_INIT( dday )
+{
+ int i;
+
+
+ palette_set_shadow_factor(machine, 1.0/8); /* this matches the previous version of the driver (>>3) */
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ bit3 = (color_prom[i] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* green component */
+ bit0 = (color_prom[i + machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[i + machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[i + machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[i + machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* blue component */
+ bit0 = (color_prom[i + 2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[i + 2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[i + 2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[i + 2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+
+ /* HACK!!! This table is handgenerated, but it matches the screenshot.
+ I have no clue how it really works */
+
+ colortable[0*8+0] = 0;
+ colortable[0*8+1] = 1;
+ colortable[0*8+2] = 21;
+ colortable[0*8+3] = 2;
+ colortable[0*8+4+0] = 0;
+ colortable[0*8+4+1] = 1;
+ colortable[0*8+4+2] = 21;
+ colortable[0*8+4+3] = 2;
+
+ colortable[1*8+0] = 4;
+ colortable[1*8+1] = 5;
+ colortable[1*8+2] = 3;
+ colortable[1*8+3] = 7;
+ colortable[1*8+4+0] = 4;
+ colortable[1*8+4+1] = 5;
+ colortable[1*8+4+2] = 3;
+ colortable[1*8+4+3] = 7;
+
+ colortable[2*8+0] = 8;
+ colortable[2*8+1] = 21;
+ colortable[2*8+2] = 10;
+ colortable[2*8+3] = 3;
+ colortable[2*8+4+0] = 8;
+ colortable[2*8+4+1] = 21;
+ colortable[2*8+4+2] = 10;
+ colortable[2*8+4+3] = 3;
+
+ colortable[3*8+0] = 8;
+ colortable[3*8+1] = 21;
+ colortable[3*8+2] = 10;
+ colortable[3*8+3] = 3;
+ colortable[3*8+4+0] = 8;
+ colortable[3*8+4+1] = 21;
+ colortable[3*8+4+2] = 10;
+ colortable[3*8+4+3] = 3;
+
+ colortable[4*8+0] = 16;
+ colortable[4*8+1] = 17;
+ colortable[4*8+2] = 18;
+ colortable[4*8+3] = 7;
+ colortable[4*8+4+0] = 16;
+ colortable[4*8+4+1] = 17;
+ colortable[4*8+4+2] = 18;
+ colortable[4*8+4+3] = 7;
+
+ colortable[5*8+0] = 29;
+ colortable[5*8+1] = 21;
+ colortable[5*8+2] = 22;
+ colortable[5*8+3] = 27;
+ colortable[5*8+4+0] = 29;
+ colortable[5*8+4+1] = 21;
+ colortable[5*8+4+2] = 22;
+ colortable[5*8+4+3] = 27;
+
+ colortable[6*8+0] = 29;
+ colortable[6*8+1] = 21;
+ colortable[6*8+2] = 26;
+ colortable[6*8+3] = 27;
+ colortable[6*8+4+0] = 29;
+ colortable[6*8+4+1] = 21;
+ colortable[6*8+4+2] = 26;
+ colortable[6*8+4+3] = 27;
+
+ colortable[7*8+0] = 29;
+ colortable[7*8+1] = 2;
+ colortable[7*8+2] = 4;
+ colortable[7*8+3] = 27;
+ colortable[7*8+4+0] = 29;
+ colortable[7*8+4+1] = 2;
+ colortable[7*8+4+2] = 4;
+ colortable[7*8+4+3] = 27;
+}
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code;
+
+ code = dday_bgvideoram[tile_index];
+ SET_TILE_INFO(0, code, code >> 5, 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code, flipx;
+
+ flipx = dday_colorram[tile_index & 0x03e0] & 0x01;
+ code = dday_fgvideoram[flipx ? tile_index ^ 0x1f : tile_index];
+ SET_TILE_INFO(2, code, code >> 5, flipx ? TILE_FLIPX : 0);
+}
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ int code;
+
+ code = dday_textvideoram[tile_index];
+ SET_TILE_INFO(1, code, code >> 5, 0);
+}
+
+static TILE_GET_INFO( get_sl_tile_info )
+{
+ int code, sl_flipx, flipx;
+ UINT8* sl_map;
+
+ sl_map = &memory_region(REGION_USER1)[(sl_image & 0x07) * 0x0200];
+
+ flipx = (tile_index >> 4) & 0x01;
+ sl_flipx = (sl_image >> 3) & 0x01;
+
+ /* bit 4 is really a flip indicator. Need to shift bits 5-9 to the right by 1 */
+ tile_index = ((tile_index & 0x03e0) >> 1) | (tile_index & 0x0f);
+
+ code = sl_map[flipx ? tile_index ^ 0x0f : tile_index];
+
+ if (sl_flipx != flipx)
+ {
+ if (code & 0x80)
+ {
+ /* no mirroring, draw dark spot */
+ code = 1;
+ }
+ }
+
+ SET_TILE_INFO(3, code & 0x3f, 0, flipx ? TILE_FLIPX : 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( dday )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ text_tilemap = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ sl_tilemap = tilemap_create(get_sl_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ main_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ tilemap_set_transmask(bg_tilemap,0,0x00f0,0xff0f); /* pens 0-3 have priority over the foreground layer */
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+
+ tilemap_set_transparent_pen(text_tilemap, 0);
+
+ control = 0;
+ sl_enable = 0;
+ sl_image = 0;
+
+ start_countdown_timer();
+}
+
+WRITE8_HANDLER( dday_bgvideoram_w )
+{
+ dday_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( dday_fgvideoram_w )
+{
+ dday_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+ tilemap_mark_tile_dirty(fg_tilemap, offset ^ 0x1f); /* for flipx case */
+}
+
+WRITE8_HANDLER( dday_textvideoram_w )
+{
+ dday_textvideoram[offset] = data;
+ tilemap_mark_tile_dirty(text_tilemap, offset);
+}
+
+WRITE8_HANDLER( dday_colorram_w )
+{
+ int i;
+
+
+ offset &= 0x03e0;
+
+ dday_colorram[offset & 0x3e0] = data;
+
+ for (i = 0; i < 0x20; i++)
+ {
+ tilemap_mark_tile_dirty(fg_tilemap, offset + i);
+ }
+}
+
+READ8_HANDLER( dday_colorram_r )
+{
+ return dday_colorram[offset & 0x03e0];
+}
+
+
+WRITE8_HANDLER( dday_sl_control_w )
+{
+ if (sl_image != data)
+ {
+ sl_image = data;
+
+ tilemap_mark_all_tiles_dirty(sl_tilemap);
+ }
+}
+
+
+WRITE8_HANDLER( dday_control_w )
+{
+ //if (data & 0xac) logerror("Control = %02X\n", data & 0xac);
+
+ /* bit 0 is coin counter 1 */
+ coin_counter_w(0, data & 0x01);
+
+ /* bit 1 is coin counter 2 */
+ coin_counter_w(1, data & 0x02);
+
+ /* bit 4 is sound enable */
+ if (!(data & 0x10) && (control & 0x10))
+ sndti_reset(SOUND_AY8910, 0);
+
+ sound_global_enable(data & 0x10);
+
+ /* bit 6 is search light enable */
+ sl_enable = data & 0x40;
+
+ control = data;
+}
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( dday )
+{
+ tilemap_draw(main_bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1,0);
+ tilemap_draw(main_bitmap,cliprect,fg_tilemap,0,0);
+ tilemap_draw(main_bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0,0);
+ tilemap_draw(main_bitmap,cliprect,text_tilemap,0,0);
+
+ if (sl_enable)
+ {
+ /* apply shadow */
+
+ mame_bitmap *sl_bitmap;
+ int x, y;
+
+
+ sl_bitmap = tilemap_get_pixmap(sl_tilemap);
+
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT32 src_pixel;
+
+
+ src_pixel = *BITMAP_ADDR16(main_bitmap, y, x);
+
+ if (*BITMAP_ADDR16(sl_bitmap, y, x) == 0xff)
+ {
+ src_pixel += machine->drv->total_colors;
+ }
+
+ *BITMAP_ADDR16(bitmap, y, x) = src_pixel;
+ }
+ }
+ }
+ else
+ {
+ copybitmap(bitmap,main_bitmap,0,0,0,0,cliprect,TRANSPARENCY_NONE,0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/ddragon.c b/src/mame/video/ddragon.c
new file mode 100644
index 00000000000..65be1dfd5be
--- /dev/null
+++ b/src/mame/video/ddragon.c
@@ -0,0 +1,247 @@
+/***************************************************************************
+
+ Video Hardware for some Technos games:
+ Double Dragon, Double Dragon bootleg, Double Dragon II and China Gate
+
+ Two Tile layers.
+ Background layer is 512x512 , tiles are 16x16
+ Top layer is 256x256 , tiles are 8x8
+
+ Sprites are 16x16, 16x32, 32x16, or 32x32 (attribute bits set dimension)
+
+
+BG Tile Layout
+ 0 1
+ ---- -xxx xxxx xxxx = Tile number
+ --xx x--- ---- ---- = Color
+ -x-- ---- ---- ---- = X Flip
+ x--- ---- ---- ---- = Y Flip
+
+
+Top Tile layout.
+ 0 1
+ ---- xxxx xxxx xxxx = Tile number
+ xxxx ---- ---- ---- = Color (China Gate)
+ xxx- ---- ---- ---- = Color (Double Dragon)
+
+
+Sprite layout.
+ 0 1 2 3 4
+ ---- ---- ---- ---- ---- xxxx xxxx xxxx ---- ---- = Sprite number
+ ---- ---- ---- ---- -xxx ---- ---- ---- ---- ---- = Color
+ xxxx xxxx ---- ---- ---- ---- ---- ---- ---- ---- = Y position
+ ---- ---- ---- ---x ---- ---- ---- ---- ---- ---- = Y MSb position ???
+ ---- ---- ---- ---- ---- ---- ---- ---- xxxx xxxx = X position
+ ---- ---- ---- --x- ---- ---- ---- ---- ---- ---- = X MSb position ???
+ ---- ---- ---- -x-- ---- ---- ---- ---- ---- ---- = Y Flip
+ ---- ---- ---- x--- ---- ---- ---- ---- ---- ---- = X Flip
+ ---- ---- --xx ---- ---- ---- ---- ---- ---- ---- = Sprite Dimension
+ ---- ---- x--- ---- ---- ---- ---- ---- ---- ---- = Visible
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *ddragon_bgvideoram,*ddragon_fgvideoram;
+int ddragon_scrollx_hi, ddragon_scrolly_hi;
+UINT8 *ddragon_scrollx_lo;
+UINT8 *ddragon_scrolly_lo;
+UINT8 *ddragon_spriteram;
+int technos_video_hw;
+
+static tilemap *fg_tilemap,*bg_tilemap;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( background_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x0f) + ((row & 0x0f) << 4) + ((col & 0x10) << 4) + ((row & 0x10) << 5);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 attr = ddragon_bgvideoram[2*tile_index];
+ SET_TILE_INFO(
+ 2,
+ ddragon_bgvideoram[2*tile_index+1] + ((attr & 0x07) << 8),
+ (attr >> 3) & 0x07,
+ TILE_FLIPYX((attr & 0xc0) >> 6));
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 attr = ddragon_fgvideoram[2*tile_index];
+ SET_TILE_INFO(
+ 0,
+ ddragon_fgvideoram[2*tile_index+1] + ((attr & 0x07) << 8),
+ attr >> 5,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_16color_tile_info )
+{
+ UINT8 attr = ddragon_fgvideoram[2*tile_index];
+ SET_TILE_INFO(
+ 0,
+ ddragon_fgvideoram[2*tile_index+1] + ((attr & 0x0f) << 8),
+ attr >> 4,
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( ddragon )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,background_scan, TILEMAP_TYPE_PEN, 16,16,32,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+}
+
+VIDEO_START( chinagat )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,background_scan, TILEMAP_TYPE_PEN, 16,16,32,32);
+ fg_tilemap = tilemap_create(get_fg_16color_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( ddragon_bgvideoram_w )
+{
+ ddragon_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+WRITE8_HANDLER( ddragon_fgvideoram_w )
+{
+ ddragon_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset/2);
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+#define DRAW_SPRITE( order, sx, sy ) drawgfx( bitmap, gfx, \
+ (which+order),color,flipx,flipy,sx,sy, \
+ cliprect,TRANSPARENCY_PEN,0);
+
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ const gfx_element *gfx = machine->gfx[1];
+
+ UINT8 *src;
+ int i;
+
+ if ( technos_video_hw == 1 ) { /* China Gate Sprite RAM */
+ src = (UINT8 *) (spriteram);
+ } else {
+ src = (UINT8 *) (&( ddragon_spriteram[0x800] ));
+ }
+
+ for( i = 0; i < ( 64 * 5 ); i += 5 ) {
+ int attr = src[i+1];
+ if ( attr & 0x80 ) { /* visible */
+ int sx = 240 - src[i+4] + ( ( attr & 2 ) << 7 );
+ int sy = 240 - src[i+0] + ( ( attr & 1 ) << 8 );
+ int size = ( attr & 0x30 ) >> 4;
+ int flipx = ( attr & 8 );
+ int flipy = ( attr & 4 );
+ int dx = -16,dy = -16;
+
+ int which;
+ int color;
+
+ if ( technos_video_hw == 2 ) /* Double Dragon 2 */
+ {
+ color = ( src[i+2] >> 5 );
+ which = src[i+3] + ( ( src[i+2] & 0x1f ) << 8 );
+ }
+ else
+ {
+ if ( technos_video_hw == 1 ) /* China Gate */
+ {
+ if ((sx < -7) && (sx > -16)) sx += 256; /* fix sprite clip */
+ if ((sy < -7) && (sy > -16)) sy += 256; /* fix sprite clip */
+ }
+ color = ( src[i+2] >> 4 ) & 0x07;
+ which = src[i+3] + ( ( src[i+2] & 0x0f ) << 8 );
+ }
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ dx = -dx;
+ dy = -dy;
+ }
+
+ which &= ~size;
+
+ switch ( size ) {
+ case 0: /* normal */
+ DRAW_SPRITE( 0, sx, sy );
+ break;
+
+ case 1: /* double y */
+ DRAW_SPRITE( 0, sx, sy + dy );
+ DRAW_SPRITE( 1, sx, sy );
+ break;
+
+ case 2: /* double x */
+ DRAW_SPRITE( 0, sx + dx, sy );
+ DRAW_SPRITE( 2, sx, sy );
+ break;
+
+ case 3:
+ DRAW_SPRITE( 0, sx + dx, sy + dy );
+ DRAW_SPRITE( 1, sx + dx, sy );
+ DRAW_SPRITE( 2, sx, sy + dy );
+ DRAW_SPRITE( 3, sx, sy );
+ break;
+ }
+ }
+ }
+}
+
+#undef DRAW_SPRITE
+
+
+VIDEO_UPDATE( ddragon )
+{
+ int scrollx = ddragon_scrollx_hi + *ddragon_scrollx_lo;
+ int scrolly = ddragon_scrolly_hi + *ddragon_scrolly_lo;
+
+ tilemap_set_scrollx(bg_tilemap,0,scrollx);
+ tilemap_set_scrolly(bg_tilemap,0,scrolly);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/ddragon3.c b/src/mame/video/ddragon3.c
new file mode 100644
index 00000000000..7867797c2eb
--- /dev/null
+++ b/src/mame/video/ddragon3.c
@@ -0,0 +1,224 @@
+/***************************************************************************
+
+ Video Hardware for Double Dragon 3
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *ddragon3_bg_videoram16;
+UINT16 *ddragon3_fg_videoram16;
+UINT16 ddragon3_vreg;
+
+static UINT16 ddragon3_bg_scrollx;
+static UINT16 ddragon3_bg_scrolly;
+static UINT16 ddragon3_fg_scrollx;
+static UINT16 ddragon3_fg_scrolly;
+static UINT16 ddragon3_bg_tilebase;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+
+WRITE16_HANDLER( ddragon3_scroll16_w )
+{
+ switch (offset)
+ {
+ case 0: COMBINE_DATA(&ddragon3_fg_scrollx); break; // Scroll X, BG1
+ case 1: COMBINE_DATA(&ddragon3_fg_scrolly); break; // Scroll Y, BG1
+ case 2: COMBINE_DATA(&ddragon3_bg_scrollx); break; // Scroll X, BG0
+ case 3: COMBINE_DATA(&ddragon3_bg_scrolly); break; // Scroll Y, BG0
+ case 4: break; // Unknown write
+ case 5: flip_screen_set(data & 0x01); break; // Flip Screen
+ case 6:
+ COMBINE_DATA(&ddragon3_bg_tilebase); // BG Tile Base
+ ddragon3_bg_tilebase &= 0x1ff;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ break;
+ }
+}
+
+READ16_HANDLER( ddragon3_scroll16_r )
+{
+ switch (offset)
+ {
+ case 0: return ddragon3_fg_scrollx;
+ case 1: return ddragon3_fg_scrolly;
+ case 2: return ddragon3_bg_scrollx;
+ case 3: return ddragon3_bg_scrolly;
+ case 5: return flip_screen;
+ case 6: return ddragon3_bg_tilebase;
+ }
+
+ return 0;
+}
+
+WRITE16_HANDLER( ddragon3_bg_videoram16_w )
+{
+ COMBINE_DATA(&ddragon3_bg_videoram16[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE16_HANDLER( ddragon3_fg_videoram16_w )
+{
+ COMBINE_DATA(&ddragon3_fg_videoram16[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap, offset / 2);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT16 attr = ddragon3_bg_videoram16[tile_index];
+ int code = (attr & 0x0fff) | ((ddragon3_bg_tilebase & 0x01) << 12);
+ int color = ((attr & 0xf000) >> 12) + 16;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int offs = tile_index * 2;
+ UINT16 attr = ddragon3_fg_videoram16[offs];
+ int code = ddragon3_fg_videoram16[offs + 1] & 0x1fff;
+ int color = attr & 0xf;
+ int flags = (attr & 0x40) ? TILE_FLIPX : 0;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( ddragon3 )
+{
+ state_save_register_global(ddragon3_vreg);
+ state_save_register_global(ddragon3_bg_scrollx);
+ state_save_register_global(ddragon3_bg_scrolly);
+ state_save_register_global(ddragon3_fg_scrollx);
+ state_save_register_global(ddragon3_fg_scrolly);
+ state_save_register_global(ddragon3_bg_tilebase);
+
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+
+ tilemap_set_transparent_pen(bg_tilemap, 0);
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+/*
+ * Sprite Format
+ * ----------------------------------
+ *
+ * Word | Bit(s) | Use
+ * -----+-fedcba9876543210-+----------------
+ * 0 | --------xxxxxxxx | ypos (signed)
+ * -----+------------------+
+ * 1 | --------xxx----- | height
+ * 1 | -----------xx--- | yflip, xflip
+ * 1 | -------------x-- | msb x
+ * 1 | --------------x- | msb y?
+ * 1 | ---------------x | enable
+ * -----+------------------+
+ * 2 | --------xxxxxxxx | tile number
+ * -----+------------------+
+ * 3 | --------xxxxxxxx | bank
+ * -----+------------------+
+ * 4 | ------------xxxx |color
+ * -----+------------------+
+ * 5 | --------xxxxxxxx | xpos
+ * -----+------------------+
+ * 6,7| unused
+ */
+
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT16 *source = spriteram16;
+ UINT16 *finish = source + 0x800;
+
+ while (source < finish)
+ {
+ UINT16 attr = source[1];
+
+ if (attr & 0x01) /* enable */
+ {
+ int i;
+ int bank = source[3] & 0xff;
+ int code = (source[2] & 0xff) + (bank * 256);
+ int color = source[4] & 0xf;
+ int flipx = attr & 0x10;
+ int flipy = attr & 0x08;
+ int sx = source[5] & 0xff;
+ int sy = source[0] & 0xff;
+ int height = (attr >> 5) & 0x07;
+
+ if (attr & 0x04) sx |= 0x100;
+ if (attr & 0x02) sy = 239 + (0x100 - sy); else sy = 240 - sy;
+ if (sx > 0x17f) sx = 0 - (0x200 - sx);
+
+ if (flip_screen)
+ {
+ sx = 304 - sx;
+ sy = 224 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ for (i = 0; i <= height; i++)
+ {
+ drawgfx(bitmap, machine->gfx[1], code + i, color, flipx, flipy,
+ sx, sy + (flip_screen ? (i * 16) : (-i * 16)), cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+ }
+
+ source += 8;
+ }
+}
+
+VIDEO_UPDATE( ddragon3 )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, ddragon3_bg_scrollx);
+ tilemap_set_scrolly(bg_tilemap, 0, ddragon3_bg_scrolly);
+ tilemap_set_scrollx(fg_tilemap, 0, ddragon3_fg_scrollx);
+ tilemap_set_scrolly(fg_tilemap, 0, ddragon3_fg_scrolly);
+
+ if ((ddragon3_vreg & 0x60) == 0x40)
+ {
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_OPAQUE, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ }
+ else if ((ddragon3_vreg & 0x60) == 0x60)
+ {
+ tilemap_draw(bitmap, cliprect, fg_tilemap, TILEMAP_DRAW_OPAQUE, 0);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ }
+ else
+ {
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_OPAQUE, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ }
+ return 0;
+}
+
+VIDEO_UPDATE( ctribe )
+{
+ tilemap_set_scrollx( bg_tilemap, 0, ddragon3_bg_scrollx );
+ tilemap_set_scrolly( bg_tilemap, 0, ddragon3_bg_scrolly );
+ tilemap_set_scrollx( fg_tilemap, 0, ddragon3_fg_scrollx );
+ tilemap_set_scrolly( fg_tilemap, 0, ddragon3_fg_scrolly );
+
+ if(ddragon3_vreg & 8)
+ {
+ tilemap_draw(bitmap, cliprect, fg_tilemap, TILEMAP_DRAW_OPAQUE, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ }
+ else
+ {
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_OPAQUE, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ }
+ return 0;
+}
diff --git a/src/mame/video/ddrible.c b/src/mame/video/ddrible.c
new file mode 100644
index 00000000000..b844e6212eb
--- /dev/null
+++ b/src/mame/video/ddrible.c
@@ -0,0 +1,247 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+extern int ddrible_int_enable_0;
+extern int ddrible_int_enable_1;
+
+UINT8 *ddrible_fg_videoram;
+UINT8 *ddrible_bg_videoram;
+UINT8 *ddrible_spriteram_1;
+UINT8 *ddrible_spriteram_2;
+
+static int ddribble_vregs[2][5];
+static int charbank[2];
+
+static tilemap *fg_tilemap,*bg_tilemap;
+
+
+PALETTE_INIT( ddrible )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ /* build the lookup table for sprites. Palette is dynamic. */
+ for (i = 0;i < TOTAL_COLORS(3);i++)
+ COLOR(3,i) = (*(color_prom++) & 0x0f);
+}
+
+WRITE8_HANDLER( K005885_0_w )
+{
+ switch (offset){
+ case 0x03: /* char bank selection for set 1 */
+ if ((data & 0x03) != charbank[0])
+ {
+ charbank[0] = data & 0x03;
+ tilemap_mark_all_tiles_dirty( fg_tilemap );
+ }
+ break;
+ case 0x04: /* IRQ control, flipscreen */
+ ddrible_int_enable_0 = data & 0x02;
+ break;
+ }
+ ddribble_vregs[0][offset] = data;
+}
+
+WRITE8_HANDLER( K005885_1_w )
+{
+ switch (offset){
+ case 0x03: /* char bank selection for set 2 */
+ if ((data & 0x03) != charbank[1])
+ {
+ charbank[1] = data & 0x03;
+ tilemap_mark_all_tiles_dirty( bg_tilemap );
+ }
+ break;
+ case 0x04: /* IRQ control, flipscreen */
+ ddrible_int_enable_1 = data & 0x02;
+ break;
+ }
+ ddribble_vregs[1][offset] = data;
+}
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( tilemap_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x20) << 6); /* skip 0x400 */
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 attr = ddrible_fg_videoram[tile_index];
+ int num = ddrible_fg_videoram[tile_index + 0x400] +
+ ((attr & 0xc0) << 2) + ((attr & 0x20) << 5) + ((charbank[0] & 2) << 10);
+ SET_TILE_INFO(
+ 0,
+ num,
+ 0,
+ TILE_FLIPYX((attr & 0x30) >> 4));
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 attr = ddrible_bg_videoram[tile_index];
+ int num = ddrible_bg_videoram[tile_index + 0x400] +
+ ((attr & 0xc0) << 2) + ((attr & 0x20) << 5) + (charbank[1] << 11);
+ SET_TILE_INFO(
+ 1,
+ num,
+ 0,
+ TILE_FLIPYX((attr & 0x30) >> 4));
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( ddrible )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan,TILEMAP_TYPE_PEN,8,8,64,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan,TILEMAP_TYPE_PEN, 8,8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+}
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( ddrible_fg_videoram_w )
+{
+ ddrible_fg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0xbff);
+}
+
+WRITE8_HANDLER( ddrible_bg_videoram_w )
+{
+ ddrible_bg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0xbff);
+}
+
+/***************************************************************************
+
+ Double Dribble sprites
+
+Each sprite has 5 bytes:
+byte #0: sprite number
+byte #1:
+ bits 0..2: sprite bank #
+ bit 3: not used?
+ bits 4..7: sprite color
+byte #2: y position
+byte #3: x position
+byte #4: attributes
+ bit 0: x position (high bit)
+ bit 1: ???
+ bits 2..4: sprite size
+ bit 5: flip x
+ bit 6: flip y
+ bit 7: unused?
+
+***************************************************************************/
+
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8* source, int lenght, int gfxset, int flipscreen )
+{
+ gfx_element *gfx = machine->gfx[gfxset];
+ const UINT8 *finish = source + lenght;
+
+ while( source < finish )
+ {
+ int number = source[0] | ((source[1] & 0x07) << 8); /* sprite number */
+ int attr = source[4]; /* attributes */
+ int sx = source[3] | ((attr & 0x01) << 8); /* vertical position */
+ int sy = source[2]; /* horizontal position */
+ int flipx = attr & 0x20; /* flip x */
+ int flipy = attr & 0x40; /* flip y */
+ int color = (source[1] & 0xf0) >> 4; /* color */
+ int width,height;
+
+ if (flipscreen){
+ flipx = !flipx;
+ flipy = !flipy;
+ sx = 240 - sx;
+ sy = 240 - sy;
+
+ if ((attr & 0x1c) == 0x10){ /* ???. needed for some sprites in flipped mode */
+ sx -= 0x10;
+ sy -= 0x10;
+ }
+ }
+
+ switch (attr & 0x1c){
+ case 0x10: /* 32x32 */
+ width = height = 2; number &= (~3); break;
+ case 0x08: /* 16x32 */
+ width = 1; height = 2; number &= (~2); break;
+ case 0x04: /* 32x16 */
+ width = 2; height = 1; number &= (~1); break;
+ /* the hardware allow more sprite sizes, but ddribble doesn't use them */
+ default: /* 16x16 */
+ width = height = 1; break;
+ }
+
+ {
+ static int x_offset[2] = { 0x00, 0x01 };
+ static int y_offset[2] = { 0x00, 0x02 };
+ int x,y, ex, ey;
+
+ for( y=0; y < height; y++ ){
+ for( x=0; x < width; x++ ){
+ ex = flipx ? (width-1-x) : x;
+ ey = flipy ? (height-1-y) : y;
+
+ drawgfx(bitmap,gfx,
+ (number)+x_offset[ex]+y_offset[ey],
+ color,
+ flipx, flipy,
+ sx+x*16,sy+y*16,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+ }
+ }
+ source += 5;
+ }
+}
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( ddrible )
+{
+ tilemap_set_flip(fg_tilemap, (ddribble_vregs[0][4] & 0x08) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ tilemap_set_flip(bg_tilemap, (ddribble_vregs[1][4] & 0x08) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ /* set scroll registers */
+ tilemap_set_scrollx(fg_tilemap,0,ddribble_vregs[0][1] | ((ddribble_vregs[0][2] & 0x01) << 8));
+ tilemap_set_scrollx(bg_tilemap,0,ddribble_vregs[1][1] | ((ddribble_vregs[1][2] & 0x01) << 8));
+ tilemap_set_scrolly(fg_tilemap,0,ddribble_vregs[0][0]);
+ tilemap_set_scrolly(bg_tilemap,0,ddribble_vregs[1][0]);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect,ddrible_spriteram_1,0x07d,2,ddribble_vregs[0][4] & 0x08);
+ draw_sprites(machine,bitmap,cliprect,ddrible_spriteram_2,0x140,3,ddribble_vregs[1][4] & 0x08);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/deadang.c b/src/mame/video/deadang.c
new file mode 100644
index 00000000000..420053ee5a6
--- /dev/null
+++ b/src/mame/video/deadang.c
@@ -0,0 +1,158 @@
+#include "driver.h"
+
+static tilemap *pf3_layer,*pf2_layer,*pf1_layer,*text_layer;
+static int deadangle_tilebank, deadangle_oldtilebank;
+UINT16 *deadang_video_data,*deadang_scroll_ram;
+
+/******************************************************************************/
+
+WRITE16_HANDLER( deadang_foreground_w )
+{
+ COMBINE_DATA(&deadang_video_data[offset]);
+ tilemap_mark_tile_dirty( pf1_layer, offset );
+}
+
+WRITE16_HANDLER( deadang_text_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty( text_layer, offset );
+}
+
+WRITE16_HANDLER( deadang_bank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ deadangle_tilebank = data&1;
+ if (deadangle_tilebank!=deadangle_oldtilebank)
+ {
+ deadangle_oldtilebank = deadangle_tilebank;
+ tilemap_mark_all_tiles_dirty (pf1_layer);
+ }
+ }
+}
+
+/******************************************************************************/
+
+static TILEMAP_MAPPER( bg_scan )
+{
+ return (col&0xf) | ((row&0xf)<<4) | ((col&0x70)<<4) | ((row&0xf0)<<7);
+}
+
+static TILE_GET_INFO( get_pf3_tile_info )
+{
+ const UINT16 *bgMap = (const UINT16 *)memory_region(REGION_GFX6);
+ int code= bgMap[tile_index];
+ SET_TILE_INFO(4,code&0x7ff,code>>12,0);
+}
+
+static TILE_GET_INFO( get_pf2_tile_info )
+{
+ const UINT16 *bgMap = (const UINT16 *)memory_region(REGION_GFX7);
+ int code= bgMap[tile_index];
+ SET_TILE_INFO(3,code&0x7ff,code>>12,0);
+}
+
+static TILE_GET_INFO( get_pf1_tile_info )
+{
+ int tile=deadang_video_data[tile_index];
+ int color=tile >> 12;
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(2,tile+deadangle_tilebank*0x1000,color,0);
+}
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ int tile=(videoram16[tile_index] & 0xff) | ((videoram16[tile_index] >> 6) & 0x300);
+ int color=(videoram16[tile_index] >> 8)&0xf;
+
+ SET_TILE_INFO(0,tile,color,0);
+}
+
+VIDEO_START( deadang )
+{
+ pf3_layer = tilemap_create(get_pf3_tile_info,bg_scan, TILEMAP_TYPE_PEN, 16,16,128,256);
+ pf2_layer = tilemap_create(get_pf2_tile_info,bg_scan, TILEMAP_TYPE_PEN,16,16,128,256);
+ pf1_layer = tilemap_create(get_pf1_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16, 32, 32);
+ text_layer = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(pf2_layer, 15);
+ tilemap_set_transparent_pen(pf1_layer, 15);
+ tilemap_set_transparent_pen(text_layer, 15);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs,fx,fy,x,y,color,sprite,pri;
+
+ for (offs = 0; offs<0x800/2; offs+=4)
+ {
+ /* Don't draw empty sprite table entries */
+ if ((spriteram16[offs+3] & 0xff00)!=0xf00) continue;
+
+ switch (spriteram16[offs+2]&0xc000) {
+ default:
+ case 0xc000: pri=0; break; /* Unknown */
+ case 0x8000: pri=0; break; /* Over all playfields */
+ case 0x4000: pri=0xf0; break; /* Under top playfield */
+ case 0x0000: pri=0xf0|0xcc; break; /* Under middle playfield */
+ }
+
+ fx= spriteram16[offs+0]&0x2000;
+ fy= spriteram16[offs+0]&0x4000;
+ y = spriteram16[offs+0] & 0xff;
+ x = spriteram16[offs+2] & 0xff;
+ if (fy) fy=0; else fy=1;
+ if (spriteram16[offs+2]&0x100) x=0-(0xff-x);
+
+ color = (spriteram16[offs+1]>>12)&0xf;
+ sprite = spriteram16[offs+1]&0xfff;
+
+ if (flip_screen) {
+ x=240-x;
+ y=240-y;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ }
+
+ pdrawgfx(bitmap,machine->gfx[1],
+ sprite,
+ color,fx,fy,x,y,
+ cliprect,TRANSPARENCY_PEN,15,pri);
+ }
+}
+
+VIDEO_UPDATE( deadang )
+{
+ /* Setup the tilemaps */
+ tilemap_set_scrolly( pf3_layer,0, ((deadang_scroll_ram[0x01]&0xf0)<<4)+((deadang_scroll_ram[0x02]&0x7f)<<1)+((deadang_scroll_ram[0x02]&0x80)>>7) );
+ tilemap_set_scrollx( pf3_layer,0, ((deadang_scroll_ram[0x09]&0xf0)<<4)+((deadang_scroll_ram[0x0a]&0x7f)<<1)+((deadang_scroll_ram[0x0a]&0x80)>>7) );
+ tilemap_set_scrolly( pf1_layer,0, ((deadang_scroll_ram[0x11]&0x10)<<4)+((deadang_scroll_ram[0x12]&0x7f)<<1)+((deadang_scroll_ram[0x12]&0x80)>>7) );
+ tilemap_set_scrollx( pf1_layer,0, ((deadang_scroll_ram[0x19]&0x10)<<4)+((deadang_scroll_ram[0x1a]&0x7f)<<1)+((deadang_scroll_ram[0x1a]&0x80)>>7) );
+ tilemap_set_scrolly( pf2_layer,0, ((deadang_scroll_ram[0x21]&0xf0)<<4)+((deadang_scroll_ram[0x22]&0x7f)<<1)+((deadang_scroll_ram[0x22]&0x80)>>7) );
+ tilemap_set_scrollx( pf2_layer,0, ((deadang_scroll_ram[0x29]&0xf0)<<4)+((deadang_scroll_ram[0x2a]&0x7f)<<1)+((deadang_scroll_ram[0x2a]&0x80)>>7) );
+
+ /* Control byte:
+ 0x01: Background playfield disable
+ 0x02: Middle playfield disable
+ 0x04: Top playfield disable
+ 0x08: ? Toggles at start of game
+ 0x10: Sprite disable
+ 0x20: Unused?
+ 0x40: Flipscreen
+ 0x80: Always set?
+ */
+ tilemap_set_enable(pf3_layer,!(deadang_scroll_ram[0x34]&1));
+ tilemap_set_enable(pf1_layer,!(deadang_scroll_ram[0x34]&2));
+ tilemap_set_enable(pf2_layer,!(deadang_scroll_ram[0x34]&4));
+ flip_screen_set( deadang_scroll_ram[0x34]&0x40 );
+
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ fillbitmap(priority_bitmap,0,cliprect);
+ tilemap_draw(bitmap,cliprect,pf3_layer,0,1);
+ tilemap_draw(bitmap,cliprect,pf1_layer,0,2);
+ tilemap_draw(bitmap,cliprect,pf2_layer,0,4);
+ if (!(deadang_scroll_ram[0x34]&0x10)) draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,text_layer,0,0);
+ return 0;
+}
diff --git a/src/mame/video/dec0.c b/src/mame/video/dec0.c
new file mode 100644
index 00000000000..922766606ec
--- /dev/null
+++ b/src/mame/video/dec0.c
@@ -0,0 +1,720 @@
+/***************************************************************************
+
+ Dec0 Video emulation - Bryan McPhail, mish@tendril.co.uk
+
+*********************************************************************
+
+ Each game uses the MXC-06 chip to produce sprites.
+
+ Sprite data: The unknown bits seem to be unused.
+
+ Byte 0:
+ Bit 0 : Y co-ord hi bit
+ Bit 1,2 : Sprite width (1x, 2x, 4x, 8x) - NOT YET EMULATED (todo)
+ Bit 3,4 : Sprite height (1x, 2x, 4x, 8x)
+ Bit 5 - X flip
+ Bit 6 - Y flip
+ Bit 7 - Only display Sprite if set
+ Byte 1: Y-coords
+ Byte 2:
+ Bit 0,1,2,3: Hi bits of sprite number
+ Bit 4,5,6,7: (Probably unused MSB's of sprite)
+ Byte 3: Low bits of sprite number
+ Byte 4:
+ Bit 0 : X co-ords hi bit
+ Bit 1,2: ??
+ Bit 3: Sprite flash (sprite is displayed every other frame)
+ Bit 4,5,6,7: - Colour
+ Byte 5: X-coords
+
+**********************************************************************
+
+ Palette data
+
+ 0x000 - character palettes (Sprites on Midnight R)
+ 0x200 - sprite palettes (Characters on Midnight R)
+ 0x400 - tiles 1
+ 0x600 - tiles 2
+
+ Bad Dudes, Robocop, Heavy Barrel, Hippodrome - 24 bit rgb
+ Sly Spy, Midnight Resistance - 12 bit rgb
+
+ Tile data
+
+ 4 bit palette select, 12 bit tile select
+
+**********************************************************************
+
+ All games contain three BAC06 background generator chips, usual (software)
+configuration is 2 chips of 16*16 tiles, 1 of 8*8.
+
+ Playfield control registers:
+ bank 0:
+ 0:
+ bit 0 (0x1) set = 8*8 tiles, else 16*16 tiles
+ Bit 1 (0x2) unknown
+ bit 2 (0x4) set enables rowscroll
+ bit 3 (0x8) set enables colscroll
+ bit 7 (0x80) set in playfield 1 is reverse screen (set via dip-switch)
+ bit 7 (0x80) in other playfields unknown
+ 2: unknown (00 in bg, 03 in fg+text - maybe controls pf transparency?)
+ 4: unknown (always 00)
+ 6: playfield shape: 00 = 4x1, 01 = 2x2, 02 = 1x4 (low 4 bits only)
+
+ bank 1:
+ 0: horizontal scroll
+ 2: vertical scroll
+ 4: colscroll shifter (low 4 bits, top 4 bits do nothing)
+ 6: rowscroll shifter (low 4 bits, top 4 bits do nothing)
+
+ Row & column scroll can be applied simultaneously or by themselves.
+ The shift register controls the granularity of the scroll offsets
+ (more details given later).
+
+Playfield priority (Bad Dudes, etc):
+ In the bottommost playfield, pens 8-15 can have priority over the next playfield.
+ In that next playfield, pens 8-15 can have priority over sprites.
+
+Bit 0: Playfield inversion
+Bit 1: Enable playfield mixing (for palettes 8-15 only)
+Bit 2: Enable playfield/sprite mixing (for palettes 8-15 only)
+
+Priority word (Midres):
+ Bit 0 set = Playfield 3 drawn over Playfield 2
+ ~ = Playfield 2 drawn over Playfield 3
+ Bit 1 set = Sprites are drawn inbetween playfields
+ ~ = Sprites are on top of playfields
+ Bit 2
+ Bit 3 set = ...
+
+Todo:
+ Implement multi-width sprites (used by Birdtry).
+ Implement sprite/tilemap orthogonality (not strictly needed as no
+ games make deliberate use of it).
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/dec0.h"
+
+static tilemap *pf1_tilemap_0,*pf1_tilemap_1,*pf1_tilemap_2;
+static tilemap *pf2_tilemap_0,*pf2_tilemap_1,*pf2_tilemap_2;
+static tilemap *pf3_tilemap_0,*pf3_tilemap_1,*pf3_tilemap_2;
+
+UINT16 *dec0_pf1_data,*dec0_pf2_data,*dec0_pf3_data;
+UINT16 *dec0_pf1_rowscroll,*dec0_pf2_rowscroll,*dec0_pf3_rowscroll;
+UINT16 *dec0_pf1_colscroll,*dec0_pf2_colscroll,*dec0_pf3_colscroll;
+static UINT16 dec0_pf1_control_0[4];
+static UINT16 dec0_pf1_control_1[4];
+static UINT16 dec0_pf2_control_0[4];
+static UINT16 dec0_pf2_control_1[4];
+static UINT16 dec0_pf3_control_0[4];
+static UINT16 dec0_pf3_control_1[4];
+static UINT16 *dec0_spriteram;
+static UINT16 dec0_pri;
+
+/******************************************************************************/
+
+WRITE16_HANDLER( dec0_update_sprites_w )
+{
+ memcpy(dec0_spriteram,spriteram16,0x800);
+}
+
+/******************************************************************************/
+
+static void update_24bitcol(int offset)
+{
+ int r,g,b;
+
+ r = (paletteram16[offset] >> 0) & 0xff;
+ g = (paletteram16[offset] >> 8) & 0xff;
+ b = (paletteram16_2[offset] >> 0) & 0xff;
+
+ palette_set_color(Machine,offset,MAKE_RGB(r,g,b));
+}
+
+WRITE16_HANDLER( dec0_paletteram_rg_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ update_24bitcol(offset);
+}
+
+WRITE16_HANDLER( dec0_paletteram_b_w )
+{
+ COMBINE_DATA(&paletteram16_2[offset]);
+ update_24bitcol(offset);
+}
+
+/******************************************************************************/
+
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap,const rectangle *cliprect,int pri_mask,int pri_val)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ y = dec0_spriteram[offs];
+ if ((y&0x8000) == 0) continue;
+
+ x = dec0_spriteram[offs+2];
+ colour = x >> 12;
+ if ((colour & pri_mask) != pri_val) continue;
+
+ flash=x&0x800;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x1800) >> 11)) - 1; /* 1x, 2x, 4x, 8x height */
+ /* multi = 0 1 3 7 */
+
+ sprite = dec0_spriteram[offs+1] & 0x0fff;
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 256) x -= 512;
+ if (y >= 256) y -= 512;
+ x = 240 - x;
+ y = 240 - y;
+
+ if (x>256) continue; /* Speedup */
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen) {
+ y=240-y;
+ x=240-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ multi--;
+ }
+ }
+}
+
+/******************************************************************************/
+
+static void custom_tilemap_draw(running_machine* machine,
+ mame_bitmap *bitmap,
+ const rectangle *cliprect,
+ tilemap *tilemap_ptr,
+ const UINT16 *rowscroll_ptr,
+ const UINT16 *colscroll_ptr,
+ const UINT16 *control0,
+ const UINT16 *control1,
+ int flags)
+{
+ const mame_bitmap *src_bitmap = tilemap_get_pixmap(tilemap_ptr);
+ int x, y, p;
+ int column_offset=0, src_x=0, src_y=0;
+ UINT32 scrollx=control1[0];
+ UINT32 scrolly=control1[1];
+ int width_mask = src_bitmap->width - 1;
+ int height_mask = src_bitmap->height - 1;
+ int row_scroll_enabled = (rowscroll_ptr && (control0[0]&0x4));
+ int col_scroll_enabled = (colscroll_ptr && (control0[0]&0x8));
+
+ if (!src_bitmap)
+ return;
+
+ /* Column scroll & row scroll may per applied per pixel, there are
+ shift registers for each which control the granularity of the row/col
+ offset (down to per line level for row, and per 8 lines for column).
+
+ Nb: The row & col selectors are _not_ affected by the shape of the
+ playfield (ie, 256*1024, 512*512 or 1024*256). So even if the tilemap
+ width is only 256, 'src_x' should not wrap at 256 in the code below (to
+ do so would mean the top half of row RAM would never be accessed which
+ is incorrect).
+
+ Nb2: Real hardware exhibits a strange bug with column scroll on 'mode 2'
+ (256*1024) - the first column has a strange additional offset, but
+ curiously the first 'wrap' (at scroll offset 256) does not have this offset,
+ it is displayed as expected. The bug is confimed to only affect this mode,
+ the other two modes work as expected. This bug is not emulated, as it
+ doesn't affect any games.
+ */
+
+ if (flip_screen)
+ src_y = (src_bitmap->height - 256) - scrolly;
+ else
+ src_y = scrolly;
+
+ for (y=0; y<=cliprect->max_y; y++) {
+ if (row_scroll_enabled)
+ src_x=scrollx + rowscroll_ptr[(src_y >> (control1[3]&0xf))&(0x1ff>>(control1[3]&0xf))];
+ else
+ src_x=scrollx;
+
+ if (flip_screen)
+ src_x=(src_bitmap->width - 256) - src_x;
+
+ for (x=0; x<=cliprect->max_x; x++) {
+ if (col_scroll_enabled)
+ column_offset=colscroll_ptr[((src_x >> 3) >> (control1[2]&0xf))&(0x3f>>(control1[2]&0xf))];
+
+ p = *BITMAP_ADDR16(src_bitmap, (src_y + column_offset)&height_mask, src_x&width_mask);
+
+ src_x++;
+ if ((flags&TILEMAP_DRAW_OPAQUE) || (p&0xf))
+ {
+ if( flags & TILEMAP_DRAW_LAYER0 )
+ {
+ /* Top 8 pens of top 8 palettes only */
+ if ((p&0x88)==0x88)
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[p];
+ }
+ else
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[p];
+ }
+ }
+ }
+ src_y++;
+ }
+}
+
+/******************************************************************************/
+
+static void dec0_pf1_draw(running_machine* machine,mame_bitmap *bitmap,const rectangle *cliprect,int flags)
+{
+ switch (dec0_pf1_control_0[3]&0x3) {
+ case 0: /* 4x1 */
+ custom_tilemap_draw(machine,bitmap,cliprect,pf1_tilemap_0,dec0_pf1_rowscroll,dec0_pf1_colscroll,dec0_pf1_control_0,dec0_pf1_control_1,flags);
+ break;
+ case 1: /* 2x2 */
+ default:
+ custom_tilemap_draw(machine,bitmap,cliprect,pf1_tilemap_1,dec0_pf1_rowscroll,dec0_pf1_colscroll,dec0_pf1_control_0,dec0_pf1_control_1,flags);
+ break;
+ case 2: /* 1x4 */
+ custom_tilemap_draw(machine,bitmap,cliprect,pf1_tilemap_2,dec0_pf1_rowscroll,dec0_pf1_colscroll,dec0_pf1_control_0,dec0_pf1_control_1,flags);
+ break;
+ };
+}
+
+static void dec0_pf2_draw(running_machine* machine,mame_bitmap *bitmap,const rectangle *cliprect,int flags)
+{
+ switch (dec0_pf2_control_0[3]&0x3) {
+ case 0: /* 4x1 */
+ custom_tilemap_draw(machine,bitmap,cliprect,pf2_tilemap_0,dec0_pf2_rowscroll,dec0_pf2_colscroll,dec0_pf2_control_0,dec0_pf2_control_1,flags);
+ break;
+ case 1: /* 2x2 */
+ default:
+ custom_tilemap_draw(machine,bitmap,cliprect,pf2_tilemap_1,dec0_pf2_rowscroll,dec0_pf2_colscroll,dec0_pf2_control_0,dec0_pf2_control_1,flags);
+ break;
+ case 2: /* 1x4 */
+ custom_tilemap_draw(machine,bitmap,cliprect,pf2_tilemap_2,dec0_pf2_rowscroll,dec0_pf2_colscroll,dec0_pf2_control_0,dec0_pf2_control_1,flags);
+ break;
+ };
+}
+
+static void dec0_pf3_draw(running_machine* machine,mame_bitmap *bitmap,const rectangle *cliprect,int flags)
+{
+ switch (dec0_pf3_control_0[3]&0x3) {
+ case 0: /* 4x1 */
+ custom_tilemap_draw(machine,bitmap,cliprect,pf3_tilemap_0,dec0_pf3_rowscroll,dec0_pf3_colscroll,dec0_pf3_control_0,dec0_pf3_control_1,flags);
+ break;
+ case 1: /* 2x2 */
+ default:
+ custom_tilemap_draw(machine,bitmap,cliprect,pf3_tilemap_1,dec0_pf3_rowscroll,dec0_pf3_colscroll,dec0_pf3_control_0,dec0_pf3_control_1,flags);
+ break;
+ case 2: /* 1x4 */
+ custom_tilemap_draw(machine,bitmap,cliprect,pf3_tilemap_2,dec0_pf3_rowscroll,dec0_pf3_colscroll,dec0_pf3_control_0,dec0_pf3_control_1,flags);
+ break;
+ };
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( hbarrel )
+{
+ flip_screen_set(dec0_pf1_control_0[0]&0x80);
+
+ dec0_pf3_draw(machine,bitmap,cliprect,TILEMAP_DRAW_OPAQUE);
+ draw_sprites(machine,bitmap,cliprect,0x08,0x08);
+ dec0_pf2_draw(machine,bitmap,cliprect,0);
+
+ /* HB always keeps pf2 on top of pf3, no need explicitly support priority register */
+
+ draw_sprites(machine,bitmap,cliprect,0x08,0x00);
+ dec0_pf1_draw(machine,bitmap,cliprect,0);
+ return 0;
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( baddudes )
+{
+ flip_screen_set(dec0_pf1_control_0[0]&0x80);
+
+ /* WARNING: inverted wrt Midnight Resistance */
+ if ((dec0_pri & 0x01) == 0)
+ {
+ dec0_pf2_draw(machine,bitmap,cliprect,TILEMAP_DRAW_OPAQUE);
+ dec0_pf3_draw(machine,bitmap,cliprect,0);
+
+ if (dec0_pri & 2)
+ dec0_pf2_draw(machine,bitmap,cliprect,TILEMAP_DRAW_LAYER0); /* Foreground pens only */
+
+ draw_sprites(machine,bitmap,cliprect,0x00,0x00);
+
+ if (dec0_pri & 4)
+ dec0_pf3_draw(machine,bitmap,cliprect,TILEMAP_DRAW_LAYER0); /* Foreground pens only */
+ }
+ else
+ {
+ dec0_pf3_draw(machine,bitmap,cliprect,TILEMAP_DRAW_OPAQUE);
+ dec0_pf2_draw(machine,bitmap,cliprect,0);
+
+ if (dec0_pri & 2)
+ dec0_pf3_draw(machine,bitmap,cliprect,TILEMAP_DRAW_LAYER0); /* Foreground pens only */
+
+ draw_sprites(machine,bitmap,cliprect,0x00,0x00);
+
+ if (dec0_pri & 4)
+ dec0_pf2_draw(machine,bitmap,cliprect,TILEMAP_DRAW_LAYER0); /* Foreground pens only */
+ }
+
+ dec0_pf1_draw(machine,bitmap,cliprect,0);
+ return 0;
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( robocop )
+{
+ int trans;
+
+ flip_screen_set(dec0_pf1_control_0[0]&0x80);
+
+ if (dec0_pri & 0x04)
+ trans = 0x08;
+ else
+ trans = 0x00;
+
+ if (dec0_pri & 0x01)
+ {
+ /* WARNING: inverted wrt Midnight Resistance */
+ /* Robocop uses it only for the title screen, so this might be just */
+ /* completely wrong. The top 8 bits of the register might mean */
+ /* something (they are 0x80 in midres, 0x00 here) */
+ dec0_pf2_draw(machine,bitmap,cliprect,TILEMAP_DRAW_LAYER1|TILEMAP_DRAW_OPAQUE);
+
+ if (dec0_pri & 0x02)
+ draw_sprites(machine,bitmap,cliprect,0x08,trans);
+
+ dec0_pf3_draw(machine,bitmap,cliprect,0);
+ }
+ else
+ {
+ dec0_pf3_draw(machine,bitmap,cliprect,TILEMAP_DRAW_OPAQUE);
+
+ if (dec0_pri & 0x02)
+ draw_sprites(machine,bitmap,cliprect,0x08,trans);
+
+ dec0_pf2_draw(machine,bitmap,cliprect,0);
+ }
+
+ if (dec0_pri & 0x02)
+ draw_sprites(machine,bitmap,cliprect,0x08,trans ^ 0x08);
+ else
+ draw_sprites(machine,bitmap,cliprect,0x00,0x00);
+
+ dec0_pf1_draw(machine,bitmap,cliprect,0);
+ return 0;
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( birdtry )
+{
+ flip_screen_set(dec0_pf1_control_0[0]&0x80);
+
+ /* This game doesn't have the extra playfield chip on the game board, but
+ the palette does show through. */
+ fillbitmap(bitmap,machine->pens[768],cliprect);
+ dec0_pf2_draw(machine,bitmap,cliprect,0);
+ draw_sprites(machine,bitmap,cliprect,0x00,0x00);
+ dec0_pf1_draw(machine,bitmap,cliprect,0);
+ return 0;
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( hippodrm )
+{
+ flip_screen_set(dec0_pf1_control_0[0]&0x80);
+
+ if (dec0_pri & 0x01)
+ {
+ dec0_pf2_draw(machine,bitmap,cliprect,TILEMAP_DRAW_OPAQUE);
+ dec0_pf3_draw(machine,bitmap,cliprect,0);
+ }
+ else
+ {
+ dec0_pf3_draw(machine,bitmap,cliprect,TILEMAP_DRAW_OPAQUE);
+ dec0_pf2_draw(machine,bitmap,cliprect,0);
+ }
+
+ draw_sprites(machine,bitmap,cliprect,0x00,0x00);
+ dec0_pf1_draw(machine,bitmap,cliprect,0);
+ return 0;
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( slyspy )
+{
+ flip_screen_set(dec0_pf1_control_0[0]&0x80);
+
+ dec0_pf3_draw(machine,bitmap,cliprect,TILEMAP_DRAW_OPAQUE);
+ dec0_pf2_draw(machine,bitmap,cliprect,0);
+
+ draw_sprites(machine,bitmap,cliprect,0x00,0x00);
+
+ /* Redraw top 8 pens of top 8 palettes over sprites */
+ if (dec0_pri&0x80)
+ dec0_pf2_draw(machine,bitmap,cliprect,TILEMAP_DRAW_LAYER0);
+
+ dec0_pf1_draw(machine,bitmap,cliprect,0);
+ return 0;
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( midres )
+{
+ int trans;
+
+ flip_screen_set(dec0_pf1_control_0[0]&0x80);
+
+ if (dec0_pri & 0x04)
+ trans = 0x00;
+ else trans = 0x08;
+
+ if (dec0_pri & 0x01)
+ {
+ dec0_pf2_draw(machine,bitmap,cliprect,TILEMAP_DRAW_OPAQUE);
+
+ if (dec0_pri & 0x02)
+ draw_sprites(machine,bitmap,cliprect,0x08,trans);
+
+ dec0_pf3_draw(machine,bitmap,cliprect,0);
+ }
+ else
+ {
+ dec0_pf3_draw(machine,bitmap,cliprect,TILEMAP_DRAW_OPAQUE);
+
+ if (dec0_pri & 0x02)
+ draw_sprites(machine,bitmap,cliprect,0x08,trans);
+
+ dec0_pf2_draw(machine,bitmap,cliprect,0);
+ }
+
+ if (dec0_pri & 0x02)
+ draw_sprites(machine,bitmap,cliprect,0x08,trans ^ 0x08);
+ else
+ draw_sprites(machine,bitmap,cliprect,0x00,0x00);
+
+ dec0_pf1_draw(machine,bitmap,cliprect,0);
+ return 0;
+}
+
+/******************************************************************************/
+
+WRITE16_HANDLER( dec0_pf1_control_0_w )
+{
+ COMBINE_DATA(&dec0_pf1_control_0[offset]);
+}
+
+WRITE16_HANDLER( dec0_pf1_control_1_w )
+{
+ COMBINE_DATA(&dec0_pf1_control_1[offset]);
+}
+
+WRITE16_HANDLER( dec0_pf1_data_w )
+{
+ COMBINE_DATA(&dec0_pf1_data[offset]);
+ tilemap_mark_tile_dirty(pf1_tilemap_0,offset);
+ tilemap_mark_tile_dirty(pf1_tilemap_1,offset);
+ tilemap_mark_tile_dirty(pf1_tilemap_2,offset);
+}
+
+WRITE16_HANDLER( dec0_pf2_control_0_w )
+{
+ COMBINE_DATA(&dec0_pf2_control_0[offset]);
+}
+
+WRITE16_HANDLER( dec0_pf2_control_1_w )
+{
+ COMBINE_DATA(&dec0_pf2_control_1[offset]);
+}
+
+WRITE16_HANDLER( dec0_pf2_data_w )
+{
+ COMBINE_DATA(&dec0_pf2_data[offset]);
+ tilemap_mark_tile_dirty(pf2_tilemap_0,offset);
+ tilemap_mark_tile_dirty(pf2_tilemap_1,offset);
+ tilemap_mark_tile_dirty(pf2_tilemap_2,offset);
+}
+
+WRITE16_HANDLER( dec0_pf3_control_0_w )
+{
+ COMBINE_DATA(&dec0_pf3_control_0[offset]);
+}
+
+WRITE16_HANDLER( dec0_pf3_control_1_w )
+{
+ COMBINE_DATA(&dec0_pf3_control_1[offset]);
+}
+
+WRITE16_HANDLER( dec0_pf3_data_w )
+{
+ COMBINE_DATA(&dec0_pf3_data[offset]);
+ tilemap_mark_tile_dirty(pf3_tilemap_0,offset);
+ tilemap_mark_tile_dirty(pf3_tilemap_1,offset);
+ tilemap_mark_tile_dirty(pf3_tilemap_2,offset);
+}
+
+WRITE16_HANDLER( dec0_priority_w )
+{
+ COMBINE_DATA(&dec0_pri);
+}
+
+WRITE8_HANDLER( dec0_pf3_control_8bit_w )
+{
+ static int buffer[0x20];
+ UINT16 myword;
+
+ buffer[offset]=data;
+
+ /* Rearrange little endian bytes from H6280 into big endian words for 68k */
+ offset&=0xffe;
+ myword=buffer[offset] + (buffer[offset+1]<<8);
+
+ if (offset<0x10) dec0_pf3_control_0_w(offset/2,myword,0);
+ else dec0_pf3_control_1_w((offset-0x10)/2,myword,0);
+}
+
+WRITE8_HANDLER( dec0_pf3_data_8bit_w )
+{
+ if (offset&1) { /* MSB has changed */
+ UINT16 lsb=dec0_pf3_data[offset>>1];
+ UINT16 newword=(lsb&0xff) | (data<<8);
+ dec0_pf3_data[offset>>1]=newword;
+ }
+ else { /* LSB has changed */
+ UINT16 msb=dec0_pf3_data[offset>>1];
+ UINT16 newword=(msb&0xff00) | data;
+ dec0_pf3_data[offset>>1]=newword;
+ }
+ tilemap_mark_tile_dirty(pf3_tilemap_0,offset>>1);
+ tilemap_mark_tile_dirty(pf3_tilemap_1,offset>>1);
+ tilemap_mark_tile_dirty(pf3_tilemap_2,offset>>1);
+}
+
+READ8_HANDLER( dec0_pf3_data_8bit_r )
+{
+ if (offset&1) /* MSB */
+ return dec0_pf3_data[offset>>1]>>8;
+
+ return dec0_pf3_data[offset>>1]&0xff;
+}
+
+/******************************************************************************/
+
+static TILEMAP_MAPPER( tile_shape0_scan )
+{
+ return (col & 0xf) + ((row & 0xf) << 4) + ((col & 0x30) << 4);
+}
+
+static TILEMAP_MAPPER( tile_shape1_scan )
+{
+ return (col & 0xf) + ((row & 0xf) << 4) + ((row & 0x10) << 4) + ((col & 0x10) << 5);
+}
+
+static TILEMAP_MAPPER( tile_shape2_scan )
+{
+ return (col & 0xf) + ((row & 0x3f) << 4);
+}
+
+static TILEMAP_MAPPER( tile_shape0_8x8_scan )
+{
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x60) << 5);
+}
+
+static TILEMAP_MAPPER( tile_shape1_8x8_scan )
+{
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((row & 0x20) << 5) + ((col & 0x20) << 6);
+}
+
+static TILEMAP_MAPPER( tile_shape2_8x8_scan )
+{
+ return (col & 0x1f) + ((row & 0x7f) << 5);
+}
+
+static TILE_GET_INFO( get_pf1_tile_info )
+{
+ int tile=dec0_pf1_data[tile_index];
+ SET_TILE_INFO(0,tile&0xfff,tile>>12,0);
+}
+
+static TILE_GET_INFO( get_pf2_tile_info )
+{
+ int tile=dec0_pf2_data[tile_index];
+ int pri=((tile>>12)>7);
+ SET_TILE_INFO(1,tile&0xfff,tile>>12,0);
+ tileinfo->group = pri;
+}
+
+static TILE_GET_INFO( get_pf3_tile_info )
+{
+ int tile=dec0_pf3_data[tile_index];
+ int pri=((tile>>12)>7);
+ SET_TILE_INFO(2,tile&0xfff,tile>>12,0);
+ tileinfo->group = pri;
+}
+
+VIDEO_START( dec0_nodma )
+{
+ pf1_tilemap_0 = tilemap_create(get_pf1_tile_info,tile_shape0_8x8_scan,TILEMAP_TYPE_PEN, 8, 8,128, 32);
+ pf1_tilemap_1 = tilemap_create(get_pf1_tile_info,tile_shape1_8x8_scan,TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ pf1_tilemap_2 = tilemap_create(get_pf1_tile_info,tile_shape2_8x8_scan,TILEMAP_TYPE_PEN, 8, 8, 32,128);
+ pf2_tilemap_0 = tilemap_create(get_pf2_tile_info,tile_shape0_scan, TILEMAP_TYPE_PEN,16,16, 64, 16);
+ pf2_tilemap_1 = tilemap_create(get_pf2_tile_info,tile_shape1_scan, TILEMAP_TYPE_PEN,16,16, 32, 32);
+ pf2_tilemap_2 = tilemap_create(get_pf2_tile_info,tile_shape2_scan, TILEMAP_TYPE_PEN,16,16, 16, 64);
+ pf3_tilemap_0 = tilemap_create(get_pf3_tile_info,tile_shape0_scan, TILEMAP_TYPE_PEN,16,16, 64, 16);
+ pf3_tilemap_1 = tilemap_create(get_pf3_tile_info,tile_shape1_scan, TILEMAP_TYPE_PEN,16,16, 32, 32);
+ pf3_tilemap_2 = tilemap_create(get_pf3_tile_info,tile_shape2_scan, TILEMAP_TYPE_PEN,16,16, 16, 64);
+
+ dec0_spriteram=spriteram16;
+}
+
+VIDEO_START( dec0 )
+{
+ video_start_dec0_nodma(machine);
+ dec0_spriteram=auto_malloc(0x800);
+}
+
+/******************************************************************************/
diff --git a/src/mame/video/dec8.c b/src/mame/video/dec8.c
new file mode 100644
index 00000000000..6f3e222bc22
--- /dev/null
+++ b/src/mame/video/dec8.c
@@ -0,0 +1,823 @@
+/***************************************************************************
+
+Cobra Command:
+ 2 BAC06 background generator chips, same as Dec0.
+ 1 MXC06 chip for sprites, same as Dec0.
+ 256 colours, palette generated by ram.
+
+The Real Ghostbusters:
+1 Deco VSC30 (M60348)
+1 Deco HMC20 (M60232)
+
+ 1 playfield, same as above, with rowscroll
+ 1024 colours from 2 proms.
+ Sprite hardware close to above, there are some unused (unknown) bits per sprite.
+
+Super Real Darwin:
+ 1 playfield, x-scroll only
+ Closer to earlier Darwin 4078 board than above games.
+
+Last Mission/Shackled:
+ Has 1 Deco VSC30 (M60348) (From readme file)
+ Has 1 Deco HMC20 (M60232) (From readme file)
+
+ 1 playfield
+ Sprite hardware same as Karnov.
+ (Shackled) Palettes 8-15 for tiles seem to have priority over sprites.
+
+Gondomania:
+ Has two large square surface mount chips: [ DRL 40, 8053, 8649a ]
+ Has 1 Deco VSC30 (M60348)
+ Has 1 Deco HMC20 (M60232)
+ Priority - all tiles with *pens* 8-15 appear over sprites with palettes 8-15.
+
+Oscar:
+ Uses MXC-06 custom chip for sprites.
+ Uses BAC-06 custom chip for background.
+ I can't find what makes the fix chars...
+ Priority - tiles with palettes 8-15 have their *pens* 8-15 appearing over
+sprites.
+
+***************************************************************************/
+
+#include "driver.h"
+
+//static int scroll1[4];
+static int scroll2[4];
+static tilemap *dec8_pf0_tilemap,*dec8_pf1_tilemap,*dec8_fix_tilemap;
+static int dec8_pf0_control[0x20],dec8_pf1_control[0x20];
+static int gfx_mask,game_uses_priority;
+UINT8 *dec8_pf0_data,*dec8_pf1_data,*dec8_row;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Real Ghostbusters has two 1024x8 palette PROM.
+ I don't know the exact values of the resistors between the RAM and the
+ RGB output. I assumed these values (the same as Commando)
+
+ bit 7 -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 2.2kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ -- 1 kohm resistor -- RED
+ bit 0 -- 2.2kohm resistor -- RED
+
+ bit 7 -- unused
+ -- unused
+ -- unused
+ -- unused
+ -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 1 kohm resistor -- BLUE
+ bit 0 -- 2.2kohm resistor -- BLUE
+
+***************************************************************************/
+PALETTE_INIT( ghostb )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ bit3 = (color_prom[i] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[i] >> 4) & 0x01;
+ bit1 = (color_prom[i] >> 5) & 0x01;
+ bit2 = (color_prom[i] >> 6) & 0x01;
+ bit3 = (color_prom[i] >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[i + machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[i + machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[i + machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[i + machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+WRITE8_HANDLER( dec8_bac06_0_w )
+{
+ dec8_pf0_control[offset]=data;
+}
+
+WRITE8_HANDLER( dec8_bac06_1_w )
+{
+ dec8_pf1_control[offset]=data;
+}
+
+WRITE8_HANDLER( dec8_pf0_data_w )
+{
+ dec8_pf0_data[offset]=data;
+ tilemap_mark_tile_dirty(dec8_pf0_tilemap,offset/2);
+}
+
+WRITE8_HANDLER( dec8_pf1_data_w )
+{
+ dec8_pf1_data[offset]=data;
+ tilemap_mark_tile_dirty(dec8_pf1_tilemap,offset/2);
+}
+
+READ8_HANDLER( dec8_pf0_data_r )
+{
+ return dec8_pf0_data[offset];
+}
+
+READ8_HANDLER( dec8_pf1_data_r )
+{
+ return dec8_pf1_data[offset];
+}
+
+WRITE8_HANDLER( dec8_videoram_w )
+{
+ videoram[offset]=data;
+ tilemap_mark_tile_dirty( dec8_fix_tilemap,offset/2 );
+}
+
+WRITE8_HANDLER( srdarwin_videoram_w )
+{
+ videoram[offset]=data;
+ tilemap_mark_tile_dirty( dec8_fix_tilemap,offset );
+}
+
+#ifdef UNUSED_FUNCTION
+WRITE8_HANDLER( dec8_scroll1_w )
+{
+ scroll1[offset]=data;
+}
+#endif
+
+WRITE8_HANDLER( dec8_scroll2_w )
+{
+ scroll2[offset]=data;
+}
+
+WRITE8_HANDLER( srdarwin_control_w )
+{
+ int bankaddress;
+ UINT8 *RAM = memory_region(REGION_CPU1);
+
+ switch (offset) {
+ case 0: /* Top 3 bits - bank switch, bottom 4 - scroll MSB */
+ bankaddress = 0x10000 + (data >> 5) * 0x4000;
+ memory_set_bankptr(1,&RAM[bankaddress]);
+ scroll2[0]=data&0xf;
+ return;
+
+ case 1:
+ scroll2[1]=data;
+ return;
+ }
+}
+
+WRITE8_HANDLER( lastmiss_control_w )
+{
+ UINT8 *RAM = memory_region(REGION_CPU1);
+
+ /*
+ Bit 0x0f - ROM bank switch.
+ Bit 0x10 - Unused
+ Bit 0x20 - X scroll MSB
+ Bit 0x40 - Y scroll MSB
+ Bit 0x80 - Hold subcpu reset line high if clear, else low
+ */
+ memory_set_bankptr(1,&RAM[0x10000 + (data & 0x0f) * 0x4000]);
+
+ scroll2[0]=(data>>5)&1;
+ scroll2[2]=(data>>6)&1;
+
+ if (data&0x80)
+ cpunum_set_input_line(1, INPUT_LINE_RESET, CLEAR_LINE);
+ else
+ cpunum_set_input_line(1, INPUT_LINE_RESET, ASSERT_LINE);
+}
+
+WRITE8_HANDLER( shackled_control_w )
+{
+ int bankaddress;
+ UINT8 *RAM = memory_region(REGION_CPU1);
+
+ /* Bottom 4 bits - bank switch, Bits 4 & 5 - Scroll MSBs */
+ bankaddress = 0x10000 + (data & 0x0f) * 0x4000;
+ memory_set_bankptr(1,&RAM[bankaddress]);
+
+ scroll2[0]=(data>>5)&1;
+ scroll2[2]=(data>>6)&1;
+}
+
+WRITE8_HANDLER( lastmiss_scrollx_w )
+{
+ scroll2[1]=data;
+}
+
+WRITE8_HANDLER( lastmiss_scrolly_w )
+{
+ scroll2[3]=data;
+}
+
+WRITE8_HANDLER( gondo_scroll_w )
+{
+ switch (offset) {
+ case 0x0:
+ scroll2[1]=data; /* X LSB */
+ break;
+ case 0x8:
+ scroll2[3]=data; /* Y LSB */
+ break;
+ case 0x10:
+ scroll2[0]=(data>>0)&1; /* Bit 0: X MSB */
+ scroll2[2]=(data>>1)&1; /* Bit 1: Y MSB */
+ /* Bit 2 is also used in Gondo & Garyoret */
+ break;
+ }
+}
+
+/******************************************************************************/
+
+/* 'Karnov' sprites, used by Gondomania, Last Mission, Shackled, Ghostbusters */
+static void draw_sprites1(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int offs,x,y,sprite,sprite2,colour,extra,fx,fy;
+
+ for (offs = 0;offs < 0x800;offs += 8)
+ {
+ y=buffered_spriteram[offs+1]+(buffered_spriteram[offs]<<8);
+ if ((y&0x8000) == 0) continue;
+
+ fx=buffered_spriteram[offs+3];
+
+ if ((fx&0x1) == 0) continue;
+
+ extra=fx&0x10;
+ fy=fx&0x2;
+ fx=fx&0x4;
+
+ x = buffered_spriteram[offs+5]+(buffered_spriteram[offs+4]<<8);
+ colour = buffered_spriteram[offs+6] >> 4;
+ if (priority==1 && (colour&8)) continue;
+ if (priority==2 && !(colour&8)) continue;
+ sprite = buffered_spriteram[offs+7]+(buffered_spriteram[offs+6]<<8);
+ sprite &= 0x0fff;
+
+ if (extra) {y=y+16;sprite&=0xffe;}
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ x=(x+16)%0x200;
+ y=(y+16)%0x200;
+ x=256 - x;
+ y=256 - y;
+ if (flip_screen) {
+ y=240-y;
+ x=240-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ if (extra) y=y-16;
+ }
+
+ /* Y Flip determines order of multi-sprite */
+ if (extra && fy) {
+ sprite2=sprite;
+ sprite++;
+ }
+ else
+ sprite2=sprite+1;
+
+ drawgfx(bitmap,machine->gfx[1],
+ sprite,
+ colour,fx,fy,x,y,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ /* 1 more sprite drawn underneath */
+ if (extra)
+ drawgfx(bitmap,machine->gfx[1],
+ sprite2,
+ colour,fx,fy,x,y+16,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+/* 'Dec0' sprites, used by Cobra Command, Oscar */
+static void draw_sprites2(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int offs,x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ /* Sprites */
+ for (offs = 0;offs < 0x800;offs += 8)
+ {
+ y =buffered_spriteram[offs+1]+(buffered_spriteram[offs]<<8);
+ if ((y&0x8000) == 0) continue;
+ x = buffered_spriteram[offs+5]+(buffered_spriteram[offs+4]<<8);
+ colour = ((x & 0xf000) >> 12);
+ flash=x&0x800;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ if (priority==1 && (colour&4)) continue;
+ if (priority==2 && !(colour&4)) continue;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x1800) >> 11)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ /* multi = 0 1 3 7 */
+ sprite = buffered_spriteram[offs+3]+(buffered_spriteram[offs+2]<<8);
+ sprite &= 0x0fff;
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 256) x -= 512;
+ if (y >= 256) y -= 512;
+ x = 240 - x;
+ y = 240 - y;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen) {
+ y=240-y;
+ x=240-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+ multi--;
+ }
+ }
+}
+
+static void srdarwin_draw_sprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri)
+{
+ int offs;
+
+ /* Sprites */
+ for (offs = 0;offs < 0x200;offs += 4)
+ {
+ int multi,fx,sx,sy,sy2,code,color;
+
+ color = (buffered_spriteram[offs+1] & 0x03) + ((buffered_spriteram[offs+1] & 0x08) >> 1);
+ if (pri==0 && color!=0) continue;
+ if (pri==1 && color==0) continue;
+
+ code = buffered_spriteram[offs+3] + ( ( buffered_spriteram[offs+1] & 0xe0 ) << 3 );
+ if (!code) continue;
+
+ sy = buffered_spriteram[offs];
+ if (sy == 0xf8) continue;
+
+ sx = (241 - buffered_spriteram[offs+2]);
+
+ fx = buffered_spriteram[offs+1] & 0x04;
+ multi = buffered_spriteram[offs+1] & 0x10;
+
+ if (flip_screen) {
+ sy=240-sy;
+ sx=240-sx;
+ if (fx) fx=0; else fx=1;
+ sy2=sy-16;
+ }
+ else sy2=sy+16;
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ fx,flip_screen,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ if (multi)
+ drawgfx(bitmap,machine->gfx[1],
+ code+1,
+ color,
+ fx,flip_screen,
+ sx,sy2,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+/* Draw character tiles, each game has different colour masks */
+#if 0
+static void draw_characters(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect, int mask, int shift)
+{
+ int mx,my,tile,color,offs;
+
+ for (offs = 0x800 - 2;offs >= 0;offs -= 2) {
+ tile=videoram[offs+1]+((videoram[offs]&0xf)<<8);
+
+ if (!tile) continue;
+
+ color=(videoram[offs]&mask)>>shift;
+ mx = (offs/2) % 32;
+ my = (offs/2) / 32;
+
+ drawgfx(bitmap,machine->gfx[0],
+ tile,color,0,0,8*mx,8*my,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+#endif
+
+/******************************************************************************/
+
+VIDEO_UPDATE( cobracom )
+{
+ tilemap_set_scrollx( dec8_pf0_tilemap,0, (dec8_pf0_control[0x10]<<8)+dec8_pf0_control[0x11] );
+ tilemap_set_scrolly( dec8_pf0_tilemap,0, (dec8_pf0_control[0x12]<<8)+dec8_pf0_control[0x13] );
+ tilemap_set_scrollx( dec8_pf1_tilemap,0, (dec8_pf1_control[0x10]<<8)+dec8_pf1_control[0x11] );
+ tilemap_set_scrolly( dec8_pf1_tilemap,0, (dec8_pf1_control[0x12]<<8)+dec8_pf1_control[0x13] );
+ flip_screen_set(dec8_pf0_control[0]>>7);
+
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,0,0);
+ draw_sprites2(machine,bitmap,cliprect,1);
+ tilemap_draw(bitmap,cliprect,dec8_pf1_tilemap,0,0);
+ draw_sprites2(machine,bitmap,cliprect,2);
+ tilemap_draw(bitmap,cliprect,dec8_fix_tilemap,0,0);
+ return 0;
+}
+
+/******************************************************************************/
+
+static TILE_GET_INFO( get_bac0_tile_info )
+{
+ int tile,color,offs=tile_index<<1;
+
+ tile=(dec8_pf0_data[offs]<<8) | dec8_pf0_data[offs+1];
+ color=tile >> 12;
+ if (color>7 && game_uses_priority) tileinfo->category=1; else tileinfo->category=0;
+
+ SET_TILE_INFO(
+ 2,
+ tile&0xfff,
+ color&gfx_mask,
+ 0);
+}
+
+static TILE_GET_INFO( get_bac1_tile_info )
+{
+ int tile,color,offs=tile_index<<1;
+
+ tile=(dec8_pf1_data[offs]<<8) | dec8_pf1_data[offs+1];
+ color=tile >> 12;
+ if (color>7 && game_uses_priority) tileinfo->category=1; else tileinfo->category=0;
+
+ SET_TILE_INFO(
+ 3,
+ tile&0xfff,
+ color&3,
+ 0);
+}
+
+static TILEMAP_MAPPER( bac0_scan_rows )
+{
+ /* logical (col,row) -> memory offset */
+ return ((col & 0x0f) + ((row & 0x0f) << 4)) + ((col & 0x10) << 5) + ((row & 0x10) << 4);
+}
+
+static TILE_GET_INFO( get_cobracom_fix_tile_info )
+{
+ int offs=tile_index<<1;
+ int tile=videoram[offs+1]+(videoram[offs]<<8);
+ int color=(tile&0xe000) >> 13;
+
+ SET_TILE_INFO(
+ 0,
+ tile&0xfff,
+ color,
+ 0);
+}
+
+VIDEO_START( cobracom )
+{
+ dec8_pf0_tilemap = tilemap_create(get_bac0_tile_info,bac0_scan_rows,0,16,16,32,32);
+ dec8_pf1_tilemap = tilemap_create(get_bac1_tile_info,bac0_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ dec8_fix_tilemap = tilemap_create(get_cobracom_fix_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(dec8_pf1_tilemap,0);
+ tilemap_set_transparent_pen(dec8_fix_tilemap,0);
+
+ game_uses_priority=0;
+ gfx_mask=0x3;
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( ghostb )
+{
+ if (dec8_pf0_control[0]&0x4) { /* Rowscroll */
+ int offs;
+
+ tilemap_set_scroll_rows(dec8_pf0_tilemap,512);
+ for (offs = 0;offs < 512;offs+=2)
+ tilemap_set_scrollx( dec8_pf0_tilemap,offs/2, (dec8_pf0_control[0x10]<<8)+dec8_pf0_control[0x11] + (dec8_row[offs]<<8)+dec8_row[offs+1] );
+ } else {
+ tilemap_set_scroll_rows(dec8_pf0_tilemap,1);
+ tilemap_set_scrollx( dec8_pf0_tilemap,0, (dec8_pf0_control[0x10]<<8)+dec8_pf0_control[0x11] );
+ }
+ tilemap_set_scrolly( dec8_pf0_tilemap,0, (dec8_pf0_control[0x12]<<8)+dec8_pf0_control[0x13] );
+
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,0,0);
+ draw_sprites1(machine,bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,dec8_fix_tilemap,0,0);
+ return 0;
+}
+
+static TILE_GET_INFO( get_ghostb_fix_tile_info )
+{
+ int offs=tile_index<<1;
+ int tile=videoram[offs+1]+(videoram[offs]<<8);
+ int color=(tile&0xc00) >> 10;
+
+ SET_TILE_INFO(
+ 0,
+ tile&0x3ff,
+ color,
+ 0);
+}
+
+VIDEO_START( ghostb )
+{
+ dec8_pf0_tilemap = tilemap_create(get_bac0_tile_info,bac0_scan_rows,0,16,16,32,32);
+ dec8_fix_tilemap = tilemap_create(get_ghostb_fix_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ tilemap_set_transparent_pen(dec8_fix_tilemap,0);
+
+ game_uses_priority=0;
+ gfx_mask=0xf;
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( oscar )
+{
+ tilemap_set_scrollx( dec8_pf0_tilemap,0, (dec8_pf0_control[0x10]<<8)+dec8_pf0_control[0x11] );
+ tilemap_set_scrolly( dec8_pf0_tilemap,0, (dec8_pf0_control[0x12]<<8)+dec8_pf0_control[0x13] );
+ flip_screen_set(dec8_pf0_control[1]>>7);
+
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,TILEMAP_DRAW_LAYER1 | 0,0);
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,TILEMAP_DRAW_LAYER1 | 1,0);
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,TILEMAP_DRAW_LAYER0 | 0,0);
+ draw_sprites2(machine,bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,TILEMAP_DRAW_LAYER0 | 1,0);
+ tilemap_draw(bitmap,cliprect,dec8_fix_tilemap,0,0);
+ return 0;
+}
+
+static TILE_GET_INFO( get_oscar_fix_tile_info )
+{
+ int offs=tile_index<<1;
+ int tile=videoram[offs+1]+(videoram[offs]<<8);
+ int color=(tile&0xf000) >> 14;
+
+ SET_TILE_INFO(
+ 0,
+ tile&0xfff,
+ color,
+ 0);
+}
+
+VIDEO_START( oscar )
+{
+ dec8_pf0_tilemap = tilemap_create(get_bac0_tile_info,bac0_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ dec8_fix_tilemap = tilemap_create(get_oscar_fix_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(dec8_fix_tilemap,0);
+ tilemap_set_transmask(dec8_pf0_tilemap,0,0x00ff,0xff00); /* Bottom 8 pens */
+
+ game_uses_priority=1;
+ gfx_mask=0x7;
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( lastmiss )
+{
+ tilemap_set_scrollx( dec8_pf0_tilemap,0, ((scroll2[0]<<8)+scroll2[1]) );
+ tilemap_set_scrolly( dec8_pf0_tilemap,0, ((scroll2[2]<<8)+scroll2[3]) );
+
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,0,0);
+ draw_sprites1(machine,bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,dec8_fix_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( shackled )
+{
+ tilemap_set_scrollx( dec8_pf0_tilemap,0, ((scroll2[0]<<8)+scroll2[1]) );
+ tilemap_set_scrolly( dec8_pf0_tilemap,0, ((scroll2[2]<<8)+scroll2[3]) );
+
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,TILEMAP_DRAW_LAYER1 | 0,0);
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,TILEMAP_DRAW_LAYER1 | 1,0);
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,TILEMAP_DRAW_LAYER0 | 0,0);
+ draw_sprites1(machine,bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,TILEMAP_DRAW_LAYER0 | 1,0);
+ tilemap_draw(bitmap,cliprect,dec8_fix_tilemap,0,0);
+ return 0;
+}
+
+static TILEMAP_MAPPER( lastmiss_scan_rows )
+{
+ /* logical (col,row) -> memory offset */
+ return ((col & 0x0f) + ((row & 0x0f) << 4)) + ((col & 0x10) << 4) + ((row & 0x10) << 5);
+}
+
+static TILE_GET_INFO( get_lastmiss_tile_info )
+{
+ int offs=tile_index*2;
+ int tile=dec8_pf0_data[offs+1]+(dec8_pf0_data[offs]<<8);
+ int color=tile >> 12;
+
+ if (color>7 && game_uses_priority) tileinfo->category=1; else tileinfo->category=0;
+
+ SET_TILE_INFO(
+ 2,
+ tile&0xfff,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_lastmiss_fix_tile_info )
+{
+ int offs=tile_index<<1;
+ int tile=videoram[offs+1]+(videoram[offs]<<8);
+ int color=(tile&0xc000) >> 14;
+
+ SET_TILE_INFO(
+ 0,
+ tile&0xfff,
+ color,
+ 0);
+}
+
+VIDEO_START( lastmiss )
+{
+ dec8_pf0_tilemap = tilemap_create(get_lastmiss_tile_info,lastmiss_scan_rows,0,16,16,32,32);
+ dec8_fix_tilemap = tilemap_create(get_lastmiss_fix_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(dec8_fix_tilemap,0);
+ game_uses_priority=0;
+}
+
+VIDEO_START( shackled )
+{
+ dec8_pf0_tilemap = tilemap_create(get_lastmiss_tile_info,lastmiss_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ dec8_fix_tilemap = tilemap_create(get_lastmiss_fix_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(dec8_fix_tilemap,0);
+ tilemap_set_transmask(dec8_pf0_tilemap,0,0x000f,0xfff0); /* Bottom 12 pens */
+ game_uses_priority=1;
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( srdarwin )
+{
+ tilemap_set_scrollx( dec8_pf0_tilemap,0, (scroll2[0]<<8)+scroll2[1] );
+
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,TILEMAP_DRAW_LAYER1,0);
+ srdarwin_draw_sprites(machine,bitmap,cliprect,0); //* (srdarwin37b5gre)
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,TILEMAP_DRAW_LAYER0,0);
+ srdarwin_draw_sprites(machine,bitmap,cliprect,1);
+ tilemap_draw(bitmap,cliprect,dec8_fix_tilemap,0,0);
+ return 0;
+}
+
+static TILE_GET_INFO( get_srdarwin_fix_tile_info )
+{
+ int tile=videoram[tile_index];
+ int color=0; /* ? */
+
+ if (color>1) tileinfo->category=1; else tileinfo->category=0;
+
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+//AT: improved priority and fixed stage 4+ crashes caused by bank overflow
+static TILE_GET_INFO( get_srdarwin_tile_info )
+{
+ int tile=dec8_pf0_data[2*tile_index+1]+(dec8_pf0_data[2*tile_index]<<8);
+ int color=tile >> 12 & 3;
+ int bank;
+
+ tile=tile&0x3ff;
+ bank=(tile/0x100)+2;
+
+ SET_TILE_INFO(
+ bank,
+ tile,
+ color,
+ 0);
+ tileinfo->group = color;
+}
+
+VIDEO_START( srdarwin )
+{
+ dec8_pf0_tilemap = tilemap_create(get_srdarwin_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,16);
+ dec8_fix_tilemap = tilemap_create(get_srdarwin_fix_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(dec8_fix_tilemap,0);
+ tilemap_set_transmask(dec8_pf0_tilemap,0,0xffff,0x0000); //* draw as background only
+ tilemap_set_transmask(dec8_pf0_tilemap,1,0x00ff,0xff00); /* Bottom 8 pens */
+ tilemap_set_transmask(dec8_pf0_tilemap,2,0x00ff,0xff00); /* Bottom 8 pens */
+ tilemap_set_transmask(dec8_pf0_tilemap,3,0x0000,0xffff); //* draw as foreground only
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( gondo )
+{
+ tilemap_set_scrollx( dec8_pf0_tilemap,0, ((scroll2[0]<<8)+scroll2[1]) );
+ tilemap_set_scrolly( dec8_pf0_tilemap,0, ((scroll2[2]<<8)+scroll2[3]) );
+
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,TILEMAP_DRAW_LAYER1,0);
+ draw_sprites1(machine,bitmap,cliprect,2);
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,TILEMAP_DRAW_LAYER0,0);
+ draw_sprites1(machine,bitmap,cliprect,1);
+ tilemap_draw(bitmap,cliprect,dec8_fix_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( garyoret )
+{
+ tilemap_set_scrollx( dec8_pf0_tilemap,0, ((scroll2[0]<<8)+scroll2[1]) );
+ tilemap_set_scrolly( dec8_pf0_tilemap,0, ((scroll2[2]<<8)+scroll2[3]) );
+
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,0,0);
+ draw_sprites1(machine,bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,dec8_pf0_tilemap,1,0);
+ tilemap_draw(bitmap,cliprect,dec8_fix_tilemap,0,0);
+ return 0;
+}
+
+static TILE_GET_INFO( get_gondo_fix_tile_info )
+{
+ int offs=tile_index*2;
+ int tile=videoram[offs+1]+(videoram[offs]<<8);
+ int color=(tile&0x7000) >> 12;
+
+ SET_TILE_INFO(
+ 0,
+ tile&0xfff,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_gondo_tile_info )
+{
+ int offs=tile_index*2;
+ int tile=dec8_pf0_data[offs+1]+(dec8_pf0_data[offs]<<8);
+ int color=tile>> 12;
+
+ if (color>7 && game_uses_priority) tileinfo->category=1; else tileinfo->category=0;
+
+ SET_TILE_INFO(
+ 2,
+ tile&0xfff,
+ color,
+ 0);
+}
+
+VIDEO_START( gondo )
+{
+ dec8_fix_tilemap=tilemap_create(get_gondo_fix_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ dec8_pf0_tilemap=tilemap_create(get_gondo_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ tilemap_set_transparent_pen(dec8_fix_tilemap,0);
+ tilemap_set_transmask(dec8_pf0_tilemap,0,0x00ff,0xff00); /* Bottom 8 pens */
+ game_uses_priority=0;
+}
+
+VIDEO_START( garyoret )
+{
+ dec8_fix_tilemap=tilemap_create(get_gondo_fix_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ dec8_pf0_tilemap=tilemap_create(get_gondo_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ tilemap_set_transparent_pen(dec8_fix_tilemap,0);
+ game_uses_priority=1;
+}
+
+/******************************************************************************/
diff --git a/src/mame/video/deco16ic.c b/src/mame/video/deco16ic.c
new file mode 100644
index 00000000000..c896399ee14
--- /dev/null
+++ b/src/mame/video/deco16ic.c
@@ -0,0 +1,1050 @@
+/********************************************************************************
+
+ Data East video emulation & information by Bryan McPhail, mish@tendril.co.uk (c) 2000-2005 Bryan McPhail
+ Please send me any additions to the table below.
+
+
+ Game Mask Rom CPU Sprites Playfields IO/Protection Other
+ ==============================================================================================
+ Vapor Trail/Kuhga MAA 59 MXC-06 55, 55
+ Crude Buster/Two Crude MAB 59 52 55, 55
+ Dark Seal/Gate Of Doom MAC 59 52 55, 55
+ Edward Randy MAD 59 52 55, 55 60
+ Super Burger Time MAE 59 52 55
+ Mutant Fighter/Death Brade MAF 59 52 55, 56 66
+ Caveman Ninja/Joe & Mac MAG 59 52 55, 55 104
+ Robocop 2 MAH 59 52 55, 55 75
+ Desert Assault/Thunderzone MAJ 59,59 52,52 55, 55
+ China Town MAK 59 52 55
+ Rogha/Wolf Fang MAM 59 52,52,71,71 55, 56 104 113
+ Captain America MAN 101 52,71 56, 56 75
+ Tumblepop MAP 59 52 56
+ Dragon Gun MAR 101 ? 74, 74 146 113,186,187
+ Wizard Fire/Dark Seal 2 MAS 59 52,52,71,71 74, 74 104 113
+ Funky Jet MAT 59 52 74 146
+ Nitro Ball MAV 59 52,52,71,71 56, 74 146 113
+ Diet GoGo MAY 102 52,71 141 104 113
+ Pocket Gal DX MAZ 102 52,71 56 104 153
+ Boogie Wings MBD 102 52,52,71,71 141, 141 104 113,99,200
+1 Double Wings MBE 102 52 141 104
+ Fighter's History MBF 101 52,153 56,74 [Scratched] 200, 153, 170
+ Heavy Smash MBG 156 52 141 153*3
+ Night Slashers MBH 156 52,52,52,153,153,153 74, 141 104 99,200
+ Locked N Loaded MBM 101 ? 74,74 146 113,186,187
+ Joe & Mac Return MBN 156 52 141 223,223
+2 Charlie Ninja MBR 156 52 141 223,223
+ World Cup Volleyball 95 MBX 156 52 141 ?
+ Backfire! MBZ 156 52,52,153,153 141,141 ? 223
+2* Ganbare Gonta MCB 156 52 141 223,223
+ Chain Reaction/Magical Drop MCC 156 52 141 223,223
+ Dunk Dream 95 MCE 156 [MLC] [MLC]
+2 Osman/Cannon Dancer MCF 156 52 141 223,223
+ Avengers In Galactic Storm MCG SH2 [MLC] [MLC]
+ Stadium Hero 96 MCM 156 [MLC] [MLC] 146
+
+ Sotsugyo Shousho 59 52 74 146?
+ Lemmings --- 59 52,52,71,71 None 75
+ Tattoo Assassins --- 101 52,52,71,71 141, 141? ? 99, ?
+
+Note 1: Mitchell game on DECO PCB board number DEC-22V0 (S-NK-3220)
+Note 2: Mitchell games on DECO PCB board number MT5601-0
+Note *: Ganbare! Gonta!! 2 / Lady Killer Part 2 - Party Time
+
+ Custom chip 59 = 68000 cpu
+ Custom chip 101 = Arm6 cpu
+ Custom chip 113 = Alpha blending
+ Custom chip 99 = 'Ace' chip (Special alpha blending?)
+ Custom chip 156 = Encrypted ARM cpu
+ Custom chip 102 = Encrypted 68000 cpu
+
+ Custom chip 55 provides two playfields of 4bpp tiles, with optional
+ rowscroll and column scroll. Some games use two of these to give
+ 4 playfields. Palette banking, tile banking and priority are outside
+ the scope of this chip, and usually differ between games. Some games
+ combine the 4bpp output of each playfield to give an effective 8bpp
+ display.
+
+ Custom chip 56 is the same as 55 but with on-chip decryption, so
+ encrypted roms can be used.
+
+ Custom chip 74 is the same as 56 but with different decryption tables.
+
+ Custom chip 141 is same as 56, but can output up to 8BPP per layer.
+
+ Custom chip 55/56/74/141 control register layout:
+
+ Word 0:
+ Mask 0x0080: Flip screen
+ Mask 0x007f: ? Possibly a bit to set transparent pen 0 on/off
+ Word 2:
+ Mask 0xffff: Playfield 2 X scroll
+ Word 4:
+ Mask 0xffff: Playfield 2 Y scroll
+ Word 6:
+ Mask 0xffff: Playfield 1 X scroll
+ Word 8:
+ Mask 0xffff: Playfield 1 Y scroll
+ Word 0xa:
+ Mask 0x8000: Playfield 1 enable
+ Mask 0x7800: Playfield 1 rowscroll style
+ Mask 0x0700: Playfield 1 colscroll style
+
+ Mask 0x0080: Playfield 2 enable
+ Mask 0x0078: Playfield 2 rowscroll style
+ Mask 0x0007: Playfield 2 colscroll style
+ Word 0xc:
+ Mask 0x8000: Playfield 1 is 8*8 tiles else 16*16
+ Mask 0x4000: Playfield 1 rowscroll enabled
+ Mask 0x2000: Playfield 1 colscroll enabled
+ Mask 0x1800: Seemingly unused
+ Mask 0x0400: Use alternate palette bank (unimplemented/unused by any game)
+ Mask 0x0200: Y flip tiles with top bit of palette code set (palette becomes 3 bits for this tile)
+ Mask 0x0100: X flip tiles with top bit of palette code set (palette becomes 3 bits for this tile)
+
+ Mask 0x0080: Playfield 2 is 8*8 tiles else 16*16
+ Mask 0x0040: Playfield 2 rowscroll enabled
+ Mask 0x0020: Playfield 2 colscroll enabled
+ Mask 0x0018: Seemingly unused
+ Mask 0x0004: Use alternate palette bank (unimplemented/unused by any game)
+ Mask 0x0002: Y flip tiles with top bit of palette code set (palette becomes 3 bits for this tile)
+ Mask 0x0001: X flip tiles with top bit of palette code set (palette becomes 3 bits for this tile)
+
+ Word 0xe:
+ Mask 0xff00: Playfield 1 gfx rom banking (Usually different hookup per game)
+ Mask 0x00ff: Playfield 2 gfx rom banking
+
+Colscroll style:
+ 0 8 pixel columns across bitmap
+ 1 16 pixel columns across bitmap
+ 2 32
+ 3 64
+ 4 128
+ 5 256
+ 6 512
+ 7 1024 (Effectively 0 as 1024 is the width of the bitmap)
+
+Rowscroll style:
+ 0 512 rows down bitmap in 16x16 tile mode, 256 rows in 8x8 mode
+ 1 256 rows in 16x16, 128 in 8x8
+ 2 128 / 64
+ 3 64 / 32
+ 4 32 / 16
+ 5 16 / 8
+ 6 8 / 4
+ 7 4 / 2
+ 8 2 / 1
+ 9-15 Untested on hardware, no known games set this anyway. Assumed invalid (no rowscroll)
+
+ Column and rowscroll can both be applied at once.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "deco16ic.h"
+#include "ui.h"
+
+UINT16 *deco16_pf1_data,*deco16_pf2_data;
+UINT16 *deco16_pf3_data,*deco16_pf4_data;
+UINT16 *deco16_pf1_rowscroll,*deco16_pf2_rowscroll;
+UINT16 *deco16_pf3_rowscroll,*deco16_pf4_rowscroll;
+
+static const UINT16 *pf1_rowscroll_ptr, *pf2_rowscroll_ptr;
+static const UINT16 *pf3_rowscroll_ptr, *pf4_rowscroll_ptr;
+
+UINT16 *deco16_pf12_control,*deco16_pf34_control;
+UINT16 deco16_priority;
+
+UINT16 *deco16_raster_display_list;
+int deco16_raster_display_position;
+
+static int use_custom_pf1, use_custom_pf2, use_custom_pf3, use_custom_pf4;
+
+static tilemap *pf1_tilemap_16x16,*pf2_tilemap_16x16,*pf3_tilemap_16x16,*pf4_tilemap_16x16;
+static tilemap *pf1_tilemap_8x8,*pf2_tilemap_8x8;
+
+static mame_bitmap *sprite_priority_bitmap;
+
+static UINT8 *dirty_palette;
+static int deco16_pf1_bank,deco16_pf2_bank,deco16_pf3_bank,deco16_pf4_bank;
+static int deco16_pf12_16x16_gfx_bank,deco16_pf34_16x16_gfx_bank,deco16_pf12_8x8_gfx_bank;
+static int deco16_pf1_colourmask,deco16_pf2_colourmask,deco16_pf3_colourmask,deco16_pf4_colourmask;
+int deco16_pf1_colour_bank,deco16_pf2_colour_bank,deco16_pf3_colour_bank,deco16_pf4_colour_bank;
+static int deco16_pf1_trans_mask,deco16_pf2_trans_mask,deco16_pf3_trans_mask,deco16_pf4_trans_mask;
+static int (*deco16_bank_callback_1)(const int bank);
+static int (*deco16_bank_callback_2)(const int bank);
+static int (*deco16_bank_callback_3)(const int bank);
+static int (*deco16_bank_callback_4)(const int bank);
+static void custom_tilemap_draw(mame_bitmap *bitmap,tilemap *tilemap0_8x8,tilemap *tilemap0_16x16,
+ tilemap *tilemap1_8x8,tilemap *tilemap1_16x16, const UINT16 *rowscroll_ptr,const UINT16 scrollx,
+ const UINT16 scrolly,const UINT16 control0, const UINT16 control1,int combine_mask,int combine_shift,int trans_mask,int flags,UINT32 priority);
+
+/******************************************************************************/
+
+/* Later games have double buffered paletteram - the real palette ram is
+only updated on a DMA call */
+
+WRITE16_HANDLER( deco16_nonbuffered_palette_w )
+{
+ int r,g,b;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ if (offset&1) offset--;
+
+ b = (paletteram16[offset] >> 0) & 0xff;
+ g = (paletteram16[offset+1] >> 8) & 0xff;
+ r = (paletteram16[offset+1] >> 0) & 0xff;
+
+ palette_set_color(Machine,offset/2,MAKE_RGB(r,g,b));
+}
+
+WRITE16_HANDLER( deco16_buffered_palette_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ dirty_palette[offset/2]=1;
+}
+
+WRITE16_HANDLER( deco16_palette_dma_w )
+{
+ const int m=Machine->drv->total_colors;
+ int r,g,b,i;
+
+ for (i=0; i<m; i++) {
+ if (dirty_palette[i]) {
+ dirty_palette[i]=0;
+
+ b = (paletteram16[i*2] >> 0) & 0xff;
+ g = (paletteram16[i*2+1] >> 8) & 0xff;
+ r = (paletteram16[i*2+1] >> 0) & 0xff;
+
+ palette_set_color(Machine,i,MAKE_RGB(r,g,b));
+ }
+ }
+}
+
+/*****************************************************************************************/
+
+/* */
+READ16_HANDLER( deco16_71_r )
+{
+ return 0xffff;
+}
+
+WRITE16_HANDLER( deco16_priority_w )
+{
+ deco16_priority=data;
+}
+
+/*****************************************************************************************/
+
+static TILEMAP_MAPPER( deco16_scan_rows )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x20) << 5) + ((row & 0x20) << 6);
+}
+
+static TILE_GET_INFO( get_pf4_tile_info )
+{
+ UINT16 tile=deco16_pf4_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco16_pf34_control[6]>>8)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco16_pf34_control[6]>>8)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(
+ deco16_pf34_16x16_gfx_bank,
+ (tile&0xfff)|deco16_pf4_bank,
+ (colour&deco16_pf4_colourmask)+deco16_pf4_colour_bank,
+ flags);
+}
+
+static TILE_GET_INFO( get_pf3_tile_info )
+{
+ UINT16 tile=deco16_pf3_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco16_pf34_control[6]>>0)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco16_pf34_control[6]>>0)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(
+ deco16_pf34_16x16_gfx_bank,
+ (tile&0xfff)|deco16_pf3_bank,
+ (colour&deco16_pf3_colourmask)+deco16_pf3_colour_bank,
+ flags);
+}
+
+static TILE_GET_INFO( get_pf2_tile_info )
+{
+ UINT16 tile=deco16_pf2_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco16_pf12_control[6]>>8)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco16_pf12_control[6]>>8)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(
+ deco16_pf12_16x16_gfx_bank,
+ (tile&0xfff)|deco16_pf2_bank,
+ (colour&deco16_pf2_colourmask)+deco16_pf2_colour_bank,
+ flags);
+}
+
+static TILE_GET_INFO( get_pf1_tile_info )
+{
+ UINT16 tile=deco16_pf1_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco16_pf12_control[6]>>0)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco16_pf12_control[6]>>0)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(
+ deco16_pf12_16x16_gfx_bank,
+ (tile&0xfff)|deco16_pf1_bank,
+ (colour&deco16_pf1_colourmask)+deco16_pf1_colour_bank,
+ flags);
+}
+
+static TILE_GET_INFO( get_pf2_tile_info_b )
+{
+ UINT16 tile=deco16_pf2_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco16_pf12_control[6]>>8)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco16_pf12_control[6]>>8)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(
+ deco16_pf12_8x8_gfx_bank,
+ (tile&0xfff)|deco16_pf2_bank,
+ (colour&deco16_pf2_colourmask)+deco16_pf2_colour_bank,
+ flags);
+}
+
+static TILE_GET_INFO( get_pf1_tile_info_b )
+{
+ UINT16 tile=deco16_pf1_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco16_pf12_control[6]>>0)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco16_pf12_control[6]>>0)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(
+ deco16_pf12_8x8_gfx_bank,
+ (tile&0xfff)|deco16_pf1_bank,
+ (colour&deco16_pf1_colourmask)+deco16_pf1_colour_bank,
+ flags);
+}
+
+/******************************************************************************/
+
+/* Each game can have banking set up differently depending on how the roms are
+connected, and what rom slots are used */
+
+void deco16_set_tilemap_bank_callback(int tmap, int (*callback)(const int bank))
+{
+ switch (tmap) {
+ case 0: deco16_bank_callback_1=callback; break;
+ case 1: deco16_bank_callback_2=callback; break;
+ case 2: deco16_bank_callback_3=callback; break;
+ case 3: deco16_bank_callback_4=callback; break;
+ }
+}
+
+/* Each game can have colours set up differently depending on how the playfield
+generator is connected to paletteram */
+
+void deco16_set_tilemap_colour_base(int tmap, int base)
+{
+ switch (tmap) {
+ case 0: deco16_pf1_colour_bank=base; break;
+ case 1: deco16_pf2_colour_bank=base; break;
+ case 2: deco16_pf3_colour_bank=base; break;
+ case 3: deco16_pf4_colour_bank=base; break;
+ }
+}
+
+void deco16_set_tilemap_colour_mask(int tmap, int mask)
+{
+ switch (tmap) {
+ case 0: deco16_pf1_colourmask=mask; break;
+ case 1: deco16_pf2_colourmask=mask; break;
+ case 2: deco16_pf3_colourmask=mask; break;
+ case 3: deco16_pf4_colourmask=mask; break;
+ }
+}
+
+void deco16_set_tilemap_transparency_mask(int tmap, int mask)
+{
+ switch (tmap) {
+ case 0: deco16_pf1_trans_mask=mask; break;
+ case 1: deco16_pf2_trans_mask=mask; break;
+ case 2: deco16_pf3_trans_mask=mask; break;
+ case 3: deco16_pf4_trans_mask=mask; break;
+ }
+}
+
+void deco16_pf12_set_gfxbank(int small, int big)
+{
+ static int last_small=-1, last_big=-1;
+
+ if (last_small!=small) {
+ if (pf1_tilemap_8x8)
+ tilemap_mark_all_tiles_dirty(pf1_tilemap_8x8);
+ if (pf2_tilemap_8x8)
+ tilemap_mark_all_tiles_dirty(pf2_tilemap_8x8);
+ last_small=small;
+ }
+ deco16_pf12_8x8_gfx_bank=small;
+
+ if (last_big!=big) {
+ if (pf1_tilemap_16x16)
+ tilemap_mark_all_tiles_dirty(pf1_tilemap_16x16);
+ if (pf2_tilemap_16x16)
+ tilemap_mark_all_tiles_dirty(pf2_tilemap_16x16);
+ last_big=big;
+ }
+ deco16_pf12_16x16_gfx_bank=big;
+
+}
+
+void deco16_pf34_set_gfxbank(int small, int big)
+{
+ static int last_big=-1;
+
+ if (last_big!=big) {
+ if (pf3_tilemap_16x16)
+ tilemap_mark_all_tiles_dirty(pf3_tilemap_16x16);
+ if (pf4_tilemap_16x16)
+ tilemap_mark_all_tiles_dirty(pf4_tilemap_16x16);
+ last_big=big;
+ }
+ deco16_pf34_16x16_gfx_bank=big;
+}
+
+tilemap *deco16_get_tilemap(int pf, int size)
+{
+ switch (pf) {
+ case 0: if (size) return pf1_tilemap_8x8; return pf1_tilemap_16x16;
+ case 1: if (size) return pf2_tilemap_8x8; return pf2_tilemap_16x16;
+ case 2: if (size) return 0; return pf3_tilemap_16x16;
+ case 3: if (size) return 0; return pf4_tilemap_16x16;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+WRITE16_HANDLER( deco16_pf1_data_w )
+{
+ COMBINE_DATA(&deco16_pf1_data[offset]);
+ tilemap_mark_tile_dirty(pf1_tilemap_8x8,offset);
+ if (offset<0x800)
+ tilemap_mark_tile_dirty(pf1_tilemap_16x16,offset);
+}
+
+WRITE16_HANDLER( deco16_pf2_data_w )
+{
+ COMBINE_DATA(&deco16_pf2_data[offset]);
+ tilemap_mark_tile_dirty(pf2_tilemap_8x8,offset);
+ if (offset<0x800)
+ tilemap_mark_tile_dirty(pf2_tilemap_16x16,offset);
+}
+
+WRITE16_HANDLER( deco16_pf3_data_w )
+{
+ COMBINE_DATA(&deco16_pf3_data[offset]);
+ tilemap_mark_tile_dirty(pf3_tilemap_16x16,offset);
+}
+
+WRITE16_HANDLER( deco16_pf4_data_w )
+{
+ COMBINE_DATA(&deco16_pf4_data[offset]);
+ tilemap_mark_tile_dirty(pf4_tilemap_16x16,offset);
+}
+
+/*****************************************************************************************/
+
+static void deco16_video_init(int pf12_only, int split, int full_width)
+{
+ sprite_priority_bitmap = auto_bitmap_alloc( Machine->screen[0].width, Machine->screen[0].height, BITMAP_FORMAT_INDEXED8 );
+
+ pf1_tilemap_16x16 = tilemap_create(get_pf1_tile_info, deco16_scan_rows, TILEMAP_TYPE_PEN,16,16,64,32);
+ pf1_tilemap_8x8 = tilemap_create(get_pf1_tile_info_b, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ if (split)
+ pf2_tilemap_16x16 = tilemap_create(get_pf2_tile_info, deco16_scan_rows, TILEMAP_TYPE_PEN,16,16,full_width ? 64 : 32,32);
+ else
+ pf2_tilemap_16x16 = tilemap_create(get_pf2_tile_info, deco16_scan_rows, TILEMAP_TYPE_PEN,16,16,full_width ? 64 : 32,32);
+ pf2_tilemap_8x8 = tilemap_create(get_pf2_tile_info_b, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,full_width ? 64 : 32,32);
+
+ dirty_palette = auto_malloc(4096);
+ deco16_raster_display_list=auto_malloc(20 * 256);
+
+ if (!pf12_only)
+ {
+ pf4_tilemap_16x16 = tilemap_create(get_pf4_tile_info, deco16_scan_rows, TILEMAP_TYPE_PEN,16,16,full_width ? 64 : 32,32);
+ pf3_tilemap_16x16 = tilemap_create(get_pf3_tile_info, deco16_scan_rows, TILEMAP_TYPE_PEN,16,16,full_width ? 64 : 32,32);
+ }
+ else
+ {
+ pf3_tilemap_16x16=0;
+ pf4_tilemap_16x16=0;
+ }
+
+ tilemap_set_transparent_pen(pf1_tilemap_8x8,0);
+ tilemap_set_transparent_pen(pf2_tilemap_8x8,0);
+ tilemap_set_transparent_pen(pf1_tilemap_16x16,0);
+ tilemap_set_transparent_pen(pf2_tilemap_16x16,0);
+ if (split) /* Caveman Ninja only */
+ tilemap_set_transmask(pf2_tilemap_16x16,0,0x00ff,0xff01);
+
+ if (!pf12_only)
+ {
+ tilemap_set_transparent_pen(pf3_tilemap_16x16,0);
+ tilemap_set_transparent_pen(pf4_tilemap_16x16,0);
+ }
+
+
+ deco16_bank_callback_1=0;
+ deco16_bank_callback_2=0;
+ deco16_bank_callback_3=0;
+ deco16_bank_callback_4=0;
+
+ deco16_pf1_trans_mask=0xf;
+ deco16_pf2_trans_mask=0xf;
+ deco16_pf3_trans_mask=0xf;
+ deco16_pf4_trans_mask=0xf;
+
+ deco16_pf1_colourmask=deco16_pf2_colourmask=0xf;
+ deco16_pf3_colourmask=deco16_pf4_colourmask=0xf;
+ deco16_pf1_bank=deco16_pf2_bank=deco16_pf3_bank=deco16_pf4_bank=0;
+ deco16_pf4_colour_bank=deco16_pf2_colour_bank=16;
+ deco16_pf3_colour_bank=deco16_pf1_colour_bank=0;
+
+ deco16_pf12_8x8_gfx_bank=0;
+ deco16_pf12_16x16_gfx_bank=1;
+ deco16_pf34_16x16_gfx_bank=2;
+
+ deco16_raster_display_position=0;
+}
+
+void deco16_1_video_init(void) /* 1 times playfield generator chip */
+{
+ deco16_video_init(1, 0, 1);
+}
+
+void deco16_2_video_init(int split) /* 2 times playfield generator chips */
+{
+ deco16_video_init(0, split, 1);
+}
+
+void deco16_2_video_init_half_width(void) /* 2 times playfield generator chips */
+{
+ deco16_video_init(0, 0, 0);
+}
+
+void deco_allocate_sprite_bitmap(void)
+{
+ /* Allow sprite bitmap to be used by Deco32 games as well */
+ sprite_priority_bitmap = auto_bitmap_alloc( Machine->screen[0].width, Machine->screen[0].height, BITMAP_FORMAT_INDEXED8 );
+}
+
+/*****************************************************************************************/
+
+static int deco16_pf_update(
+ tilemap *tilemap_8x8,
+ tilemap *tilemap_16x16,
+ const UINT16 *rowscroll_ptr,
+ const UINT16 scrollx,
+ const UINT16 scrolly,
+ const UINT16 control0,
+ const UINT16 control1)
+{
+ int rows, cols, offs, use_custom=0;
+
+ /* Toggle between 8x8 and 16x16 modes (and master enable bit) */
+ if (control1&0x80) {
+ if (!tilemap_8x8) popmessage("Deco16: Playfield switched into 8x8 mode but no tilemap defined");
+
+ if (tilemap_8x8) tilemap_set_enable(tilemap_8x8,control0&0x80);
+ if (tilemap_16x16) tilemap_set_enable(tilemap_16x16,0);
+ } else {
+ if (!tilemap_16x16) popmessage("Deco16: Playfield switched into 16x16 mode but no tilemap defined");
+
+ if (tilemap_8x8) tilemap_set_enable(tilemap_8x8,0);
+ if (tilemap_16x16) tilemap_set_enable(tilemap_16x16,control0&0x80);
+ }
+
+ /* Rowscroll enable */
+ if (rowscroll_ptr && (control1&0x60)==0x40) {
+
+ /* Several different rowscroll styles */
+ switch ((control0>>3)&0xf) {
+ case 0: rows=512; break;/* Every line of 512 height bitmap */
+ case 1: rows=256; break;
+ case 2: rows=128; break;
+ case 3: rows=64; break;
+ case 4: rows=32; break;
+ case 5: rows=16; break;
+ case 6: rows=8; break;
+ case 7: rows=4; break;
+ case 8: rows=2; break;
+ default: rows=1; break;
+ }
+
+ if (tilemap_16x16) {
+ tilemap_set_scroll_cols(tilemap_16x16,1);
+ tilemap_set_scroll_rows(tilemap_16x16,rows);
+ tilemap_set_scrolly(tilemap_16x16,0,scrolly);
+
+ for (offs = 0;offs < rows;offs++)
+ tilemap_set_scrollx( tilemap_16x16, offs, scrollx + rowscroll_ptr[offs] );
+ }
+
+ if (tilemap_8x8) {
+ tilemap_set_scroll_cols(tilemap_8x8,1);
+ tilemap_set_scroll_rows(tilemap_8x8,rows/2);
+ tilemap_set_scrolly(tilemap_8x8,0,scrolly);
+
+ for (offs = 0;offs < rows/2;offs++)
+ tilemap_set_scrollx( tilemap_8x8, offs, scrollx + rowscroll_ptr[offs] );
+ }
+ }
+ else if (rowscroll_ptr && (control1&0x60)==0x20) { /* Column scroll */
+
+ /* Column scroll ranges from 8 pixel columns to 512 pixel columns */
+ int mask=(0x40 >> (control0&7))-1;
+ if (mask==-1) mask=0;
+ cols=(8<<(control0&7))&0x3ff;
+ if (!cols) cols=1024;
+ cols=1024 / cols;
+
+ if (tilemap_16x16) {
+ tilemap_set_scroll_cols(tilemap_16x16,cols);
+ tilemap_set_scroll_rows(tilemap_16x16,1);
+ tilemap_set_scrollx(tilemap_16x16,0,scrollx );
+
+ for (offs=0 ; offs < cols;offs++)
+ tilemap_set_scrolly( tilemap_16x16, offs, scrolly + rowscroll_ptr[(offs&mask)+0x200] );
+ }
+
+ if (tilemap_8x8) {
+ cols = cols / 2; /* Adjust because 8x8 tilemap is half the width of 16x16 */
+
+ tilemap_set_scroll_cols(tilemap_8x8,cols);
+ tilemap_set_scroll_rows(tilemap_8x8,1);
+ tilemap_set_scrollx(tilemap_8x8,0,scrollx );
+
+ for (offs=0 ; offs < cols;offs++)
+ tilemap_set_scrolly( tilemap_8x8,offs, scrolly + rowscroll_ptr[(offs&mask)+0x200] );
+ }
+ }
+ else if (control1&0x60) {
+ /* Simultaneous row & column scroll requested - use custom renderer */
+ use_custom=1;
+
+ if (tilemap_16x16) {
+ tilemap_set_scroll_rows(tilemap_16x16,1);
+ tilemap_set_scroll_cols(tilemap_16x16,1);
+ tilemap_set_scrollx( tilemap_16x16,0, scrollx );
+ tilemap_set_scrolly( tilemap_16x16,0, scrolly );
+ }
+
+ if (tilemap_8x8) {
+ tilemap_set_scroll_rows(tilemap_8x8,1);
+ tilemap_set_scroll_cols(tilemap_8x8,1);
+ tilemap_set_scrollx( tilemap_8x8,0, scrollx );
+ tilemap_set_scrolly( tilemap_8x8,0, scrolly );
+
+ }
+
+ } else {
+ if (tilemap_16x16) {
+ tilemap_set_scroll_rows(tilemap_16x16,1);
+ tilemap_set_scroll_cols(tilemap_16x16,1);
+ tilemap_set_scrollx( tilemap_16x16,0, scrollx );
+ tilemap_set_scrolly( tilemap_16x16,0, scrolly );
+ }
+
+ if (tilemap_8x8) {
+ tilemap_set_scroll_rows(tilemap_8x8,1);
+ tilemap_set_scroll_cols(tilemap_8x8,1);
+ tilemap_set_scrollx( tilemap_8x8,0, scrollx );
+ tilemap_set_scrolly( tilemap_8x8,0, scrolly );
+ }
+ }
+
+ return use_custom;
+}
+
+void deco16_pf12_update(const UINT16 *rowscroll_1_ptr, const UINT16 *rowscroll_2_ptr)
+{
+ int bank1, bank2;
+
+ /* Update scrolling and tilemap enable */
+ pf1_rowscroll_ptr=rowscroll_1_ptr;
+ pf2_rowscroll_ptr=rowscroll_2_ptr;
+ use_custom_pf2=deco16_pf_update(pf2_tilemap_8x8,pf2_tilemap_16x16,rowscroll_2_ptr,deco16_pf12_control[3], deco16_pf12_control[4], deco16_pf12_control[5]>>8, deco16_pf12_control[6]>>8);
+ use_custom_pf1=deco16_pf_update(pf1_tilemap_8x8,pf1_tilemap_16x16,rowscroll_1_ptr,deco16_pf12_control[1], deco16_pf12_control[2], deco16_pf12_control[5]&0xff, deco16_pf12_control[6]&0xff);
+
+ /* Update banking and global flip state */
+ if (deco16_bank_callback_1) {
+ bank1=deco16_bank_callback_1(deco16_pf12_control[7]&0xff);
+ if (bank1!=deco16_pf1_bank) {
+ if (pf1_tilemap_8x8) tilemap_mark_all_tiles_dirty(pf1_tilemap_8x8);
+ if (pf1_tilemap_16x16) tilemap_mark_all_tiles_dirty(pf1_tilemap_16x16);
+ }
+
+ deco16_pf1_bank=bank1;
+ }
+
+ if (deco16_bank_callback_2) {
+ bank2=deco16_bank_callback_2(deco16_pf12_control[7]>>8);
+ if (bank2!=deco16_pf2_bank) {
+ if (pf2_tilemap_8x8) tilemap_mark_all_tiles_dirty(pf2_tilemap_8x8);
+ if (pf2_tilemap_16x16) tilemap_mark_all_tiles_dirty(pf2_tilemap_16x16);
+ }
+
+ deco16_pf2_bank=bank2;
+ }
+}
+
+void deco16_pf34_update(const UINT16 *rowscroll_1_ptr, const UINT16 *rowscroll_2_ptr)
+{
+ int bank1, bank2;
+
+ /* Update scrolling and tilemap enable */
+ pf3_rowscroll_ptr=rowscroll_1_ptr;
+ pf4_rowscroll_ptr=rowscroll_2_ptr;
+ use_custom_pf4=deco16_pf_update(0,pf4_tilemap_16x16,rowscroll_2_ptr,deco16_pf34_control[3], deco16_pf34_control[4], deco16_pf34_control[5]>>8, deco16_pf34_control[6]>>8);
+ use_custom_pf3=deco16_pf_update(0,pf3_tilemap_16x16,rowscroll_1_ptr,deco16_pf34_control[1], deco16_pf34_control[2], deco16_pf34_control[5]&0xff, deco16_pf34_control[6]&0xff);
+
+
+ /* Update banking and global flip state */
+ if (deco16_bank_callback_3) {
+ bank1=deco16_bank_callback_3(deco16_pf34_control[7]&0xff);
+ if (bank1!=deco16_pf3_bank) {
+ //if (pf3_tilemap_8x8) tilemap_mark_all_tiles_dirty(pf3_tilemap_8x8);
+ if (pf3_tilemap_16x16) tilemap_mark_all_tiles_dirty(pf3_tilemap_16x16);
+ }
+
+ deco16_pf3_bank=bank1;
+ }
+
+ if (deco16_bank_callback_4) {
+ bank2=deco16_bank_callback_4(deco16_pf34_control[7]>>8);
+ if (bank2!=deco16_pf4_bank) {
+ //if (pf4_tilemap_8x8) tilemap_mark_all_tiles_dirty(pf4_tilemap_8x8);
+ if (pf4_tilemap_16x16) tilemap_mark_all_tiles_dirty(pf4_tilemap_16x16);
+ }
+
+ deco16_pf4_bank=bank2;
+ }
+}
+
+/*****************************************************************************************/
+
+void deco16_print_debug_info(mame_bitmap *bitmap)
+{
+ char buf[64*5];
+
+ if (input_code_pressed(KEYCODE_O))
+ return;
+
+ if (deco16_pf12_control) {
+ sprintf(buf,"%04X %04X %04X %04X\n",deco16_pf12_control[0],deco16_pf12_control[1],deco16_pf12_control[2],deco16_pf12_control[3]);
+ sprintf(&buf[strlen(buf)],"%04X %04X %04X %04X\n",deco16_pf12_control[4],deco16_pf12_control[5],deco16_pf12_control[6],deco16_pf12_control[7]);
+ }
+ else
+ sprintf(buf, "\n\n");
+
+ if (deco16_pf34_control) {
+ sprintf(&buf[strlen(buf)],"%04X %04X %04X %04X\n",deco16_pf34_control[0],deco16_pf34_control[1],deco16_pf34_control[2],deco16_pf34_control[3]);
+ sprintf(&buf[strlen(buf)],"%04X %04X %04X %04X\n",deco16_pf34_control[4],deco16_pf34_control[5],deco16_pf34_control[6],deco16_pf34_control[7]);
+ }
+ else
+ sprintf(&buf[strlen(buf)], "\n\n");
+
+ sprintf(&buf[strlen(buf)],"%04X",deco16_priority);
+
+ ui_draw_text(buf,60,40);
+}
+
+/*****************************************************************************************/
+
+void deco16_clear_sprite_priority_bitmap(void)
+{
+ if (sprite_priority_bitmap)
+ fillbitmap(sprite_priority_bitmap,0,NULL);
+}
+
+/* A special pdrawgfx z-buffered sprite renderer that is needed to properly draw multiple sprite sources with alpha */
+void deco16_pdrawgfx(mame_bitmap *dest,const gfx_element *gfx,
+ UINT32 code,UINT32 color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,UINT32 pri_mask,UINT32 sprite_mask,UINT8 write_pri)
+{
+ int ox,oy,cx,cy;
+ int x_index,y_index,x,y;
+
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+ int source_base = (code % gfx->total_elements) * gfx->height;
+
+ /* check bounds */
+ ox = sx;
+ oy = sy;
+
+ if (sx>319 || sy>247 || sx<-15 || sy<-7)
+ return;
+
+ if (sy<0) sy=0;
+ if (sx<0) sx=0;
+ if (sx>319) cx=319;
+ else cx=ox+16;
+
+ cy=(sy-oy);
+
+ if (flipy) y_index=15-cy; else y_index=cy;
+
+ for( y=0; y<16-cy; y++ )
+ {
+ UINT8 *source = gfx->gfxdata + ((source_base+y_index) * gfx->line_modulo);
+ UINT32 *destb = BITMAP_ADDR32(dest, sy, 0);
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, sy, 0);
+ UINT8 *spri = BITMAP_ADDR8(sprite_priority_bitmap, sy, 0);
+
+ if (sy >= 0 && sy < 248)
+ {
+ if (flipx) { source+=15-(sx-ox); x_index=-1; } else { x_index=1; source+=(sx-ox); }
+
+ for (x=sx; x<cx; x++)
+ {
+ int c = *source;
+ if( c != transparent_color && x >= 0 && x < 320 )
+ {
+ if (pri_mask>pri[x] && sprite_mask>spri[x]) {
+ if (transparency == TRANSPARENCY_ALPHA)
+ destb[x] = alpha_blend32(destb[x], pal[c]);
+ else
+ destb[x] = pal[c];
+ if (write_pri)
+ pri[x] |= pri_mask;
+ }
+ spri[x]|=sprite_mask;
+ }
+ source+=x_index;
+ }
+ }
+
+ sy++;
+ if (sy>247)
+ return;
+ if (flipy) y_index--; else y_index++;
+ }
+}
+
+/*****************************************************************************************/
+
+void deco16_tilemap_1_draw(mame_bitmap *bitmap, const rectangle *cliprect, int flags, UINT32 priority)
+{
+ if (use_custom_pf1)
+ {
+ custom_tilemap_draw(bitmap,pf1_tilemap_8x8,pf1_tilemap_16x16,0,0,pf1_rowscroll_ptr,deco16_pf12_control[1], deco16_pf12_control[2], deco16_pf12_control[5]&0xff, deco16_pf12_control[6]&0xff, 0, 0, deco16_pf1_trans_mask, flags, priority);
+ }
+ else
+ {
+ if (pf1_tilemap_8x8) tilemap_draw(bitmap,cliprect,pf1_tilemap_8x8,flags,priority);
+ if (pf1_tilemap_16x16) tilemap_draw(bitmap,cliprect,pf1_tilemap_16x16,flags,priority);
+ }
+}
+
+void deco16_tilemap_2_draw(mame_bitmap *bitmap, const rectangle *cliprect, int flags, UINT32 priority)
+{
+ if (use_custom_pf2)
+ {
+ custom_tilemap_draw(bitmap,pf2_tilemap_8x8,pf2_tilemap_16x16,0,0,pf2_rowscroll_ptr,deco16_pf12_control[3], deco16_pf12_control[4], deco16_pf12_control[5]>>8, deco16_pf12_control[6]>>8, 0, 0, deco16_pf2_trans_mask, flags, priority);
+ }
+ else
+ {
+ if (pf2_tilemap_8x8) tilemap_draw(bitmap,cliprect,pf2_tilemap_8x8,flags,priority);
+ if (pf2_tilemap_16x16) tilemap_draw(bitmap,cliprect,pf2_tilemap_16x16,flags,priority);
+ }
+}
+
+void deco16_tilemap_3_draw(mame_bitmap *bitmap, const rectangle *cliprect, int flags, UINT32 priority)
+{
+ if (use_custom_pf3) custom_tilemap_draw(bitmap,0,pf3_tilemap_16x16,0,0,pf3_rowscroll_ptr,deco16_pf34_control[1], deco16_pf34_control[2], deco16_pf34_control[5]&0xff, deco16_pf34_control[6]&0xff, 0, 0, deco16_pf3_trans_mask, flags, priority);
+ else if (pf3_tilemap_16x16) tilemap_draw(bitmap,cliprect,pf3_tilemap_16x16,flags,priority);
+}
+
+void deco16_tilemap_4_draw(mame_bitmap *bitmap, const rectangle *cliprect, int flags, UINT32 priority)
+{
+ if (use_custom_pf4) custom_tilemap_draw(bitmap,0,pf4_tilemap_16x16,0,0,pf4_rowscroll_ptr,deco16_pf34_control[3], deco16_pf34_control[4], deco16_pf34_control[5]>>8, deco16_pf34_control[6]>>8, 0, 0, deco16_pf4_trans_mask, flags, priority);
+ else if (pf4_tilemap_16x16) tilemap_draw(bitmap,cliprect,pf4_tilemap_16x16,flags,priority);
+}
+
+/*****************************************************************************************/
+
+// Combines the output of two 4BPP tilemaps into an 8BPP tilemap
+void deco16_tilemap_34_combine_draw(mame_bitmap *bitmap, const rectangle *cliprect, int flags, UINT32 priority)
+{
+ custom_tilemap_draw(bitmap,0,pf3_tilemap_16x16,0,pf4_tilemap_16x16,pf3_rowscroll_ptr,deco16_pf34_control[1], deco16_pf34_control[2], deco16_pf34_control[5]&0xff, deco16_pf34_control[6]&0xff, 0xf, 4, 0xff, flags, priority);
+}
+
+/*****************************************************************************************/
+
+/*
+ Consider this the 'reference rasterizer' for the 56/74/141 tilemap chips - it implements
+ simultaneous row & column scroll which the Mame tilemap core cannot do. It also
+ implements combining the 4BPP output of two tilemaps into 8BPP output. This function
+ is automatically called when the tilemap is in a state the cannot be properly rendered
+ by the Mame core.
+*/
+
+static void custom_tilemap_draw(
+ mame_bitmap *bitmap,
+ tilemap *tilemap0_8x8,
+ tilemap *tilemap0_16x16,
+ tilemap *tilemap1_8x8,
+ tilemap *tilemap1_16x16,
+ const UINT16 *rowscroll_ptr,
+ const UINT16 scrollx,
+ const UINT16 scrolly,
+ const UINT16 control0,
+ const UINT16 control1,
+ int combine_mask,
+ int combine_shift,
+ int trans_mask,
+ int flags,
+ UINT32 priority)
+{
+ tilemap *tilemap0 = (control1&0x80) ? tilemap0_8x8 : tilemap0_16x16;
+ tilemap *tilemap1 = (control1&0x80) ? tilemap1_8x8 : tilemap1_16x16;
+ const mame_bitmap *src_bitmap0 = tilemap0 ? tilemap_get_pixmap(tilemap0) : NULL;
+ const mame_bitmap *src_bitmap1 = tilemap1 ? tilemap_get_pixmap(tilemap1) : NULL;
+ int width_mask, height_mask, x, y, p;
+ int column_offset, src_x=0, src_y=0;
+ int row_type=1 << ((control0>>3)&0xf);
+ int col_type=8 << (control0&7);
+
+ if (!src_bitmap0)
+ return;
+
+ // Playfield disable
+ if (!(control0&0x80))
+ return;
+
+ width_mask=src_bitmap0->width - 1;
+ height_mask=src_bitmap0->height - 1;
+ src_y=scrolly + 8;
+
+ for (y=8; y<248; y++) {
+ if (rowscroll_ptr && (control1&0x40))
+ src_x=scrollx + rowscroll_ptr[src_y / row_type];
+ else
+ src_x=scrollx;
+
+ src_x &= width_mask;
+
+ if (bitmap->bpp == 16)
+ {
+ for (x=0; x<320; x++) {
+ if (rowscroll_ptr && (control1&0x20))
+ column_offset=rowscroll_ptr[0x200 + ((src_x&0x1ff) / col_type)];
+ else
+ column_offset=0;
+
+ p=*BITMAP_ADDR16(src_bitmap0, (src_y + column_offset)&height_mask, src_x);
+ if (src_bitmap1)
+ p|=(*BITMAP_ADDR16(src_bitmap1, (src_y + column_offset)&height_mask, src_x)&combine_mask)<<combine_shift;
+
+ src_x=(src_x+1)&width_mask;
+ if ((flags&TILEMAP_DRAW_OPAQUE) || (p&trans_mask))
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = Machine->pens[p];
+ if (priority_bitmap)
+ {
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+ pri[x]|=priority;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* boogwing */
+ for (x=0; x<320; x++) {
+ if (rowscroll_ptr && (control1&0x20))
+ column_offset=rowscroll_ptr[0x200 + ((src_x&0x1ff) / col_type)];
+ else
+ column_offset=0;
+
+ p=*BITMAP_ADDR16(src_bitmap0, (src_y + column_offset)&height_mask, src_x);
+ if (src_bitmap1)
+ p|=(*BITMAP_ADDR16(src_bitmap1, (src_y + column_offset)&height_mask, src_x)&combine_mask)<<combine_shift;
+
+ src_x=(src_x+1)&width_mask;
+ if ((flags&TILEMAP_DRAW_OPAQUE) || (p&trans_mask))
+ {
+ *BITMAP_ADDR32(bitmap, y, x) = Machine->pens[p];
+ if (priority_bitmap)
+ {
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+ pri[x]|=priority;
+ }
+ }
+ }
+ }
+ src_y=(src_y+1)&height_mask;
+ }
+}
diff --git a/src/mame/video/deco32.c b/src/mame/video/deco32.c
new file mode 100644
index 00000000000..54a0e16a0b4
--- /dev/null
+++ b/src/mame/video/deco32.c
@@ -0,0 +1,1633 @@
+#include "driver.h"
+#include "deco16ic.h"
+#include "deco32.h"
+
+UINT32 *deco32_pf1_data,*deco32_pf2_data,*deco32_pf3_data,*deco32_pf4_data;
+UINT32 *deco32_pf12_control,*deco32_pf34_control;
+UINT32 *deco32_pf1_rowscroll,*deco32_pf2_rowscroll,*deco32_pf3_rowscroll,*deco32_pf4_rowscroll;
+UINT32 *dragngun_sprite_layout_0_ram, *dragngun_sprite_layout_1_ram;
+UINT32 *dragngun_sprite_lookup_0_ram, *dragngun_sprite_lookup_1_ram;
+UINT32 *deco32_ace_ram;
+
+static UINT8 *dirty_palette;
+static tilemap *pf1_tilemap,*pf1a_tilemap,*pf2_tilemap,*pf3_tilemap,*pf4_tilemap;
+static int deco32_pf1_bank,deco32_pf2_bank,deco32_pf3_bank,deco32_pf4_bank;
+static int deco32_pf1_flip,deco32_pf2_flip,deco32_pf3_flip,deco32_pf4_flip;
+static int deco32_pf2_colourbank,deco32_pf4_colourbank,deco32_pri;
+
+static mame_bitmap *sprite0_mix_bitmap, *sprite1_mix_bitmap, *tilemap_alpha_bitmap;
+
+static UINT32 dragngun_sprite_ctrl;
+static int deco32_ace_ram_dirty, has_ace_ram;
+
+int deco32_raster_display_position;
+UINT16 *deco32_raster_display_list;
+
+/******************************************************************************/
+
+WRITE32_HANDLER( deco32_pf1_data_w )
+{
+ COMBINE_DATA(&deco32_pf1_data[offset]);
+ tilemap_mark_tile_dirty(pf1_tilemap,offset);
+ if (pf1a_tilemap && offset<0x400)
+ tilemap_mark_tile_dirty(pf1a_tilemap,offset);
+}
+
+WRITE32_HANDLER( deco32_pf2_data_w )
+{
+ COMBINE_DATA(&deco32_pf2_data[offset]);
+ tilemap_mark_tile_dirty(pf2_tilemap,offset);
+}
+
+WRITE32_HANDLER( deco32_pf3_data_w )
+{
+ COMBINE_DATA(&deco32_pf3_data[offset]);
+ tilemap_mark_tile_dirty(pf3_tilemap,offset);
+}
+
+WRITE32_HANDLER( deco32_pf4_data_w )
+{
+ COMBINE_DATA(&deco32_pf4_data[offset]);
+ tilemap_mark_tile_dirty(pf4_tilemap,offset);
+}
+
+/******************************************************************************/
+
+WRITE32_HANDLER( deco32_pri_w )
+{
+ deco32_pri=data;
+}
+
+WRITE32_HANDLER( dragngun_sprite_control_w )
+{
+ dragngun_sprite_ctrl=data;
+}
+
+WRITE32_HANDLER( dragngun_spriteram_dma_w )
+{
+ /* DMA spriteram to private sprite chip area, and clear cpu ram */
+ memcpy(buffered_spriteram32,spriteram32,spriteram_size);
+ memset(spriteram32,0,0x2000);
+}
+
+WRITE32_HANDLER( deco32_ace_ram_w )
+{
+ /* Some notes pieced together from Tattoo Assassins info:
+
+ Bytes 0 to 0x58 - object alpha control?
+ Bytes 0x5c to 0x7c - tilemap alpha control
+
+ 0 = opaque, 0x10 = 50% transparent, 0x20 = fully transparent
+
+ Byte 0x00: ACEO000P0
+ P8
+ 1P0
+ 1P8
+ O010C1
+ o010C8
+ ??
+
+ Hardware fade registers:
+
+ Byte 0x80: fadeptred
+ Byte 0x84: fadeptgreen
+ Byte 0x88: fadeptblue
+ Byte 0x8c: fadestred
+ Byte 0x90: fadestgreen
+ Byte 0x94: fadestblue
+ Byte 0x98: fadetype
+
+ The 'ST' value lerps between the 'PT' value and the palette entries. So, if PT==0,
+ then ST ranging from 0 to 255 will cause a fade to black (when ST==255 the palette
+ becomes zero).
+
+ 'fadetype' - 1100 for multiplicative fade, 1000 for additive
+ */
+ if (offset>=(0x80/4) && (data!=deco32_ace_ram[offset]))
+ deco32_ace_ram_dirty=1;
+
+ COMBINE_DATA(&deco32_ace_ram[offset]);
+}
+
+static void updateAceRam(running_machine* machine)
+{
+ int r,g,b,i;
+ UINT8 fadeptr=deco32_ace_ram[0x20];
+ UINT8 fadeptg=deco32_ace_ram[0x21];
+ UINT8 fadeptb=deco32_ace_ram[0x22];
+ UINT8 fadepsr=deco32_ace_ram[0x23];
+ UINT8 fadepsg=deco32_ace_ram[0x24];
+ UINT8 fadepsb=deco32_ace_ram[0x25];
+// UINT8 mode=deco32_ace_ram[0x26];
+
+ deco32_ace_ram_dirty=0;
+
+ for (i=0; i<2048; i++)
+ {
+ /* Lerp palette entry to 'fadept' according to 'fadeps' */
+ b = (paletteram32[i] >>16) & 0xff;
+ g = (paletteram32[i] >> 8) & 0xff;
+ r = (paletteram32[i] >> 0) & 0xff;
+
+ if (i>255) /* Screenshots seem to suggest ACE fades do not affect playfield 1 palette (0-255) */
+ {
+ /* Yeah, this should really be fixed point, I know */
+ b = (UINT8)((float)b + (((float)fadeptb - (float)b) * (float)fadepsb/255.0f));
+ g = (UINT8)((float)g + (((float)fadeptg - (float)g) * (float)fadepsg/255.0f));
+ r = (UINT8)((float)r + (((float)fadeptr - (float)r) * (float)fadepsr/255.0f));
+ }
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+/******************************************************************************/
+
+/* Later games have double buffered paletteram - the real palette ram is
+only updated on a DMA call */
+
+WRITE32_HANDLER( deco32_nonbuffered_palette_w )
+{
+ int r,g,b;
+
+ COMBINE_DATA(&paletteram32[offset]);
+
+ b = (paletteram32[offset] >>16) & 0xff;
+ g = (paletteram32[offset] >> 8) & 0xff;
+ r = (paletteram32[offset] >> 0) & 0xff;
+
+ palette_set_color(Machine,offset,MAKE_RGB(r,g,b));
+}
+
+WRITE32_HANDLER( deco32_buffered_palette_w )
+{
+ COMBINE_DATA(&paletteram32[offset]);
+ dirty_palette[offset]=1;
+}
+
+WRITE32_HANDLER( deco32_palette_dma_w )
+{
+ const int m=Machine->drv->total_colors;
+ int r,g,b,i;
+
+ for (i=0; i<m; i++) {
+ if (dirty_palette[i]) {
+ dirty_palette[i]=0;
+
+ if (has_ace_ram)
+ {
+ deco32_ace_ram_dirty=1;
+ }
+ else
+ {
+ b = (paletteram32[i] >>16) & 0xff;
+ g = (paletteram32[i] >> 8) & 0xff;
+ r = (paletteram32[i] >> 0) & 0xff;
+
+ palette_set_color(Machine,i,MAKE_RGB(r,g,b));
+ }
+ }
+ }
+}
+
+/******************************************************************************/
+
+static void captaven_draw_sprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect, const UINT32 *spritedata, int gfxbank)
+{
+ int offs;
+
+ /*
+ Word 0:
+ 0x8000: Y flip
+ 0x4000: X flip
+ 0x2000: Flash (Sprite toggles on/off every frame)
+ 0x1fff: Y value
+ Word 1:
+ 0xffff: X value
+ Word 2:
+ 0xf000: Block height
+ 0x0f00: Block width
+ 0x00c0: Unused?
+ 0x0020: Priority
+ 0x001f: Colour
+ Word 3:
+ 0xffff: Sprite value
+ */
+
+ for (offs = 0x400-4;offs >=0;offs -= 4)
+ {
+ int sx,sy,sprite,colour,fx,fy,x_mult,y_mult,w,h,x,y,prival;
+
+ sy = spritedata[offs+0];
+ sprite = spritedata[offs+3] & 0xffff;
+
+ if (sy==0x00000108 && !sprite)
+ continue; //fix!!!!!
+
+ if (spritedata[offs+2]&0x20)
+ prival=0;
+ else
+ prival=2;
+
+ sx = spritedata[offs+1];
+
+ if ((sy&0x2000) && (cpu_getcurrentframe() & 1)) continue;
+
+ colour = (spritedata[offs+2] >>0) & 0x1f;
+
+ h = (spritedata[offs+2]&0xf000)>>12;
+ w = (spritedata[offs+2]&0x0f00)>> 8;
+ fx = !(spritedata[offs+0]&0x4000);
+ fy = !(spritedata[offs+0]&0x8000);
+
+ if (!flip_screen) {
+ sx = sx & 0x01ff;
+ sy = sy & 0x01ff;
+ if (sx>0x180) sx=-(0x200 - sx);
+ if (sy>0x180) sy=-(0x200 - sy);
+
+ if (fx) { x_mult=-16; sx+=16*w; } else { x_mult=16; sx-=16; }
+ if (fy) { y_mult=-16; sy+=16*h; } else { y_mult=16; sy-=16; }
+ } else {
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+
+ sx = sx & 0x01ff;
+ sy = sy & 0x01ff;
+ if (sx&0x100) sx=-(0x100 - (sx&0xff));
+ if (sy&0x100) sy=-(0x100 - (sy&0xff));
+ sx = 304 - sx;
+ sy = 240 - sy;
+ if (sx >= 432) sx -= 512;
+ if (sy >= 384) sy -= 512;
+ if (fx) { x_mult=-16; sx+=16; } else { x_mult=16; sx-=16*w; }
+ if (fy) { y_mult=-16; sy+=16; } else { y_mult=16; sy-=16*h; }
+ }
+
+ for (x=0; x<w; x++) {
+ for (y=0; y<h; y++) {
+ pdrawgfx(bitmap,machine->gfx[gfxbank],
+ sprite + y + h * x,
+ colour,
+ fx,fy,
+ sx + x_mult * (w-x),sy + y_mult * (h-y),
+ cliprect,TRANSPARENCY_PEN,0,prival);
+ }
+ }
+ }
+}
+
+static void fghthist_draw_sprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect, const UINT32 *spritedata, int gfxbank, int mask, int colourmask)
+{
+ int offs;
+
+ for (offs = 0x400 - 4; offs >= 0; offs -=4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult,pri=0;
+ int trans;
+
+ sprite = spritedata[offs+1] & 0xffff;
+
+ y = spritedata[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ trans=TRANSPARENCY_PEN;
+ x = spritedata[offs+2];
+ colour = (x >>9) & colourmask;
+
+ if ((y&0x8000))
+ pri=8;
+ else
+ pri=128;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ mult=+16;
+
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+
+ while (multi >= 0)
+ {
+ deco16_pdrawgfx(bitmap,machine->gfx[gfxbank],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,trans,0,pri,1<<gfxbank, 1);
+
+ multi--;
+ }
+ }
+}
+
+/*
+ This renders sprites to a 16 bit bitmap, for later mixing.
+ Bottom 8 bits per pixel is palettised sprite data, top 8 is
+ colour/alpha/priority.
+*/
+static void deco32_draw_sprite(mame_bitmap *dest,const gfx_element *gfx,
+ UINT32 code,UINT32 priority,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip)
+{
+ int ox,oy,cx,cy;
+ int x_index,y_index,x,y;
+
+ int source_base = (code % gfx->total_elements) * gfx->height;
+
+ /* check bounds */
+ ox = sx;
+ oy = sy;
+
+ if (sx>319 || sy>247 || sx<-15 || sy<-7)
+ return;
+
+ if (sy<0) sy=0;
+ if (sx<0) sx=0;
+ if (sx>319) cx=319;
+ else cx=ox+16;
+
+ cy=(sy-oy);
+
+ if (flipy) y_index=15-cy; else y_index=cy;
+
+ for( y=0; y<16-cy; y++ )
+ {
+ UINT8 *source = gfx->gfxdata + ((source_base+y_index) * gfx->line_modulo);
+ UINT16 *destb = BITMAP_ADDR16(dest, sy, 0);
+
+ if (flipx) { source+=15-(sx-ox); x_index=-1; } else { x_index=1; source+=(sx-ox); }
+
+ for (x=sx; x<cx; x++)
+ {
+ int c = *source;
+ if( c )
+ destb[x] = c | priority;
+
+ source+=x_index;
+ }
+
+ sy++;
+ if (sy>247)
+ return;
+ if (flipy) y_index--; else y_index++;
+ }
+}
+
+// Merge with Tattass & Fghthist sprite routines later
+static void nslasher_draw_sprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect, const UINT32 *spritedata, int gfxbank)
+{
+ int offs;
+
+ // Draw sprites back to front saving priority & alpha data per pixel for later mixing
+ for (offs = 0; offs<0x400; offs+=4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult; /*,pri=0,spri=0;*/
+ int trans;
+
+ sprite = spritedata[offs+1] & 0xffff;
+
+ y = spritedata[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ trans=TRANSPARENCY_PEN;
+ x = spritedata[offs+2];
+
+ // Prepare colour, priority and alpha info
+ colour = (x>>9) & 0x7f;
+ if (y&0x8000)
+ colour|=0x80;
+ colour<<=8;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ mult=+16;
+
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+
+ while (multi >= 0)
+ {
+ deco32_draw_sprite(bitmap,machine->gfx[gfxbank],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect);
+
+ multi--;
+ }
+ }
+}
+
+INLINE void dragngun_drawgfxzoom( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ UINT32 code,UINT32 color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,
+ int scalex, int scaley,mame_bitmap *pri_buffer,UINT32 pri_mask, int sprite_screen_width, int sprite_screen_height )
+{
+ rectangle myclip;
+
+ if (!scalex || !scaley) return;
+
+ /*
+ scalex and scaley are 16.16 fixed point numbers
+ 1<<15 : shrink to 50%
+ 1<<16 : uniform scale
+ 1<<17 : double to 200%
+ */
+
+ /* KW 991012 -- Added code to force clip to bitmap boundary */
+ if(clip)
+ {
+ myclip.min_x = clip->min_x;
+ myclip.max_x = clip->max_x;
+ myclip.min_y = clip->min_y;
+ myclip.max_y = clip->max_y;
+
+ if (myclip.min_x < 0) myclip.min_x = 0;
+ if (myclip.max_x >= dest_bmp->width) myclip.max_x = dest_bmp->width-1;
+ if (myclip.min_y < 0) myclip.min_y = 0;
+ if (myclip.max_y >= dest_bmp->height) myclip.max_y = dest_bmp->height-1;
+
+ clip=&myclip;
+ }
+
+ {
+ if( gfx )
+ {
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+ int source_base = (code % gfx->total_elements) * gfx->height;
+
+ if (sprite_screen_width && sprite_screen_height)
+ {
+ /* compute sprite increment per screen pixel */
+ int dx = (gfx->width<<16)/sprite_screen_width;
+ int dy = (gfx->height<<16)/sprite_screen_height;
+
+ int ex = sx+sprite_screen_width;
+ int ey = sy+sprite_screen_height;
+
+ int x_index_base;
+ int y_index;
+
+ if( flipx )
+ {
+ x_index_base = (sprite_screen_width-1)*dx;
+ dx = -dx;
+ }
+ else
+ {
+ x_index_base = 0;
+ }
+
+ if( flipy )
+ {
+ y_index = (sprite_screen_height-1)*dy;
+ dy = -dy;
+ }
+ else
+ {
+ y_index = 0;
+ }
+
+ if( clip )
+ {
+ if( sx < clip->min_x)
+ { /* clip left */
+ int pixels = clip->min_x-sx;
+ sx += pixels;
+ x_index_base += pixels*dx;
+ }
+ if( sy < clip->min_y )
+ { /* clip top */
+ int pixels = clip->min_y-sy;
+ sy += pixels;
+ y_index += pixels*dy;
+ }
+ /* NS 980211 - fixed incorrect clipping */
+ if( ex > clip->max_x+1 )
+ { /* clip right */
+ int pixels = ex-clip->max_x-1;
+ ex -= pixels;
+ }
+ if( ey > clip->max_y+1 )
+ { /* clip bottom */
+ int pixels = ey-clip->max_y-1;
+ ey -= pixels;
+ }
+ }
+
+ if( ex>sx )
+ { /* skip if inner loop doesn't draw anything */
+ int y;
+
+ /* case 1: TRANSPARENCY_PEN */
+ if (transparency == TRANSPARENCY_PEN)
+ {
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = gfx->gfxdata + (source_base+(y_index>>16)) * gfx->line_modulo;
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+ UINT8 *pri = BITMAP_ADDR8(pri_buffer, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if( c != transparent_color )
+ {
+ if (((1 << pri[x]) & pri_mask) == 0)
+ dest[x] = pal[c];
+ pri[x] = 31;
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = gfx->gfxdata + (source_base+(y_index>>16)) * gfx->line_modulo;
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if( c != transparent_color ) dest[x] = pal[c];
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 6: TRANSPARENCY_ALPHA */
+ if (transparency == TRANSPARENCY_ALPHA)
+ {
+ if (pri_buffer)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = gfx->gfxdata + (source_base+(y_index>>16)) * gfx->line_modulo;
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+ UINT8 *pri = BITMAP_ADDR8(pri_buffer, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if( c != transparent_color )
+ {
+ if (((1 << pri[x]) & pri_mask) == 0)
+ dest[x] = alpha_blend32(dest[x], pal[c]);
+ pri[x] = 31;
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = gfx->gfxdata + (source_base+(y_index>>16)) * gfx->line_modulo;
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if( c != transparent_color ) dest[x] = alpha_blend32(dest[x], pal[c]);
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void dragngun_draw_sprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect, const UINT32 *spritedata)
+{
+ const UINT32 *layout_ram;
+ const UINT32 *lookup_ram;
+ int offs;
+
+ /*
+ Sprites are built from main control ram, which references tile
+ layout ram, which finally references tile lookup ram which holds
+ the actual tile indices to draw and index into the banking
+ control. Tile lookup and tile layout ram are double buffered.
+
+
+ Main sprite control ram, 8 * 32 bit words per sprite, so
+
+ Word 0:
+ 0x0400 - Banking control for tile layout RAM + tile lookup ram
+ 0x0200 - ?
+ 0x01ff - Index into tile layout RAM
+ Word 1 :
+ Word 2 : X base position
+ Word 3 : Y base position
+ Word 4 :
+ 0x8000: X flip
+ 0x03ff: X size of block in pixels (for scaling)
+ Word 5 :
+ 0x8000: Y flip
+ 0x03ff: Y size of block in pixels (for scaling)
+ Word 6 :
+ 0x1f - colour.
+ 0x20 - ? Used for background at 'frog' boss and title screen dragon.
+ 0x40 - ? priority?
+ 0x80 - Alpha blending enable
+ Word 7 :
+
+
+ Tile layout ram, 4 * 32 bit words per sprite, so
+
+ Word 0:
+ 0x2000 - Selector for tile lookup bank!?!?!?!?!?!?
+ 0x1fff - Index into tile lookup ram (16 bit word based, NOT 32)
+ Word 1:
+ 0xff00 - ?
+ 0x00f0 - Width
+ 0x000f - Height
+ Word 2:
+ 0x01ff - X block offset
+ Word 3:
+ 0x01ff - Y block offset
+ */
+
+ /* Sprite global disable bit */
+ if (dragngun_sprite_ctrl&0x40000000)
+ return;
+
+ for (offs = 0;offs < 0x800;offs += 8)
+ {
+ int sx,sy,colour,fx,fy,w,h,x,y,bx,by,trans,scalex,scaley;
+ int zoomx,zoomy;
+ int xpos,ypos;
+
+ scalex=spritedata[offs+4]&0x3ff;
+ scaley=spritedata[offs+5]&0x3ff;
+ if (!scalex || !scaley) /* Zero pixel size in X or Y - skip block */
+ continue;
+
+ if (spritedata[offs+0]&0x400)
+ layout_ram = dragngun_sprite_layout_1_ram + ((spritedata[offs+0]&0x1ff)*4); //CHECK!
+ else
+ layout_ram = dragngun_sprite_layout_0_ram + ((spritedata[offs+0]&0x1ff)*4); //1ff in drag gun code??
+ h = (layout_ram[1]>>0)&0xf;
+ w = (layout_ram[1]>>4)&0xf;
+ if (!h || !w)
+ continue;
+
+ sx = spritedata[offs+2] & 0x3ff;
+ sy = spritedata[offs+3] & 0x3ff;
+ bx = layout_ram[2] & 0x1ff;
+ by = layout_ram[3] & 0x1ff;
+ if (bx&0x100) bx=1-(bx&0xff);
+ if (by&0x100) by=1-(by&0xff); /* '1 - ' is strange, but correct for Dragongun 'Winners' screen. */
+ if (sx >= 512) sx -= 1024;
+ if (sy >= 512) sy -= 1024;
+
+ colour = spritedata[offs+6]&0x1f;
+
+ if (spritedata[offs+6]&0x80)
+ trans=TRANSPARENCY_ALPHA;
+ else
+ trans=TRANSPARENCY_PEN;
+
+ fx = spritedata[offs+4]&0x8000;
+ fy = spritedata[offs+5]&0x8000;
+
+// if (spritedata[offs+0]&0x400)
+ if (layout_ram[0]&0x2000)
+ lookup_ram = dragngun_sprite_lookup_1_ram + (layout_ram[0]&0x1fff);
+ else
+ lookup_ram = dragngun_sprite_lookup_0_ram + (layout_ram[0]&0x1fff);
+
+ zoomx=scalex * 0x10000 / (w*16);
+ zoomy=scaley * 0x10000 / (h*16);
+
+ if (!fy)
+ ypos=(sy<<16) - (by*zoomy); /* The block offset scales with zoom, the base position does not */
+ else
+ ypos=(sy<<16) + (by*zoomy) - (16*zoomy);
+
+ for (y=0; y<h; y++) {
+ if (!fx)
+ xpos=(sx<<16) - (bx*zoomx); /* The block offset scales with zoom, the base position does not */
+ else
+ xpos=(sx<<16) + (bx*zoomx) - (16*zoomx);
+
+ for (x=0; x<w; x++) {
+ int bank,sprite;
+
+ sprite = ((*(lookup_ram++))&0x3fff);
+
+ /* High bits of the sprite reference into the sprite control bits for banking */
+ switch (sprite&0x3000) {
+ default:
+ case 0x0000: sprite=(sprite&0xfff) | ((dragngun_sprite_ctrl&0x000f)<<12); break;
+ case 0x1000: sprite=(sprite&0xfff) | ((dragngun_sprite_ctrl&0x00f0)<< 8); break;
+ case 0x2000: sprite=(sprite&0xfff) | ((dragngun_sprite_ctrl&0x0f00)<< 4); break;
+ case 0x3000: sprite=(sprite&0xfff) | ((dragngun_sprite_ctrl&0xf000)<< 0); break;
+ }
+
+ /* Because of the unusual interleaved rom layout, we have to mangle the bank bits
+ even further to suit our gfx decode */
+ switch (sprite&0xf000) {
+ case 0x0000: sprite=0xc000 | (sprite&0xfff); break;
+ case 0x1000: sprite=0xd000 | (sprite&0xfff); break;
+ case 0x2000: sprite=0xe000 | (sprite&0xfff); break;
+ case 0x3000: sprite=0xf000 | (sprite&0xfff); break;
+
+ case 0xc000: sprite=0x0000 | (sprite&0xfff); break;
+ case 0xd000: sprite=0x1000 | (sprite&0xfff); break;
+ case 0xe000: sprite=0x2000 | (sprite&0xfff); break;
+ case 0xf000: sprite=0x3000 | (sprite&0xfff); break;
+ }
+
+ if (sprite&0x8000) bank=4; else bank=3;
+ sprite&=0x7fff;
+
+ if (zoomx!=0x10000 || zoomy!=0x10000)
+ dragngun_drawgfxzoom(bitmap,machine->gfx[bank],
+ sprite,
+ colour,
+ fx,fy,
+ xpos>>16,ypos>>16,
+ cliprect,trans,15,zoomx,zoomy,NULL,0,
+ ((xpos+(zoomx<<4))>>16) - (xpos>>16), ((ypos+(zoomy<<4))>>16) - (ypos>>16) );
+ else
+ drawgfx(bitmap,machine->gfx[bank],
+ sprite,
+ colour,
+ fx,fy,
+ xpos>>16,ypos>>16,
+ cliprect,trans,15);
+
+ if (fx)
+ xpos-=zoomx<<4;
+ else
+ xpos+=zoomx<<4;
+ }
+ if (fy)
+ ypos-=zoomy<<4;
+ else
+ ypos+=zoomy<<4;
+ }
+ }
+}
+
+/******************************************************************************/
+
+static UINT32 deco16_scan_rows(UINT32 col,UINT32 row,UINT32 num_cols,UINT32 num_rows)
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x20) << 5);
+}
+
+static TILE_GET_INFO( get_pf1_tile_info )
+{
+ int tile=deco32_pf1_data[tile_index];
+ SET_TILE_INFO(0,(tile&0xfff)|deco32_pf1_bank,(tile>>12)&0xf,0);
+}
+
+static TILE_GET_INFO( get_pf1a_tile_info )
+{
+
+ int tile=deco32_pf1_data[tile_index];
+ SET_TILE_INFO(1,(tile&0xfff)|deco32_pf1_bank,(tile>>12)&0xf,0);
+}
+
+static TILE_GET_INFO( get_pf2_tile_info )
+{
+ UINT32 tile=deco32_pf2_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco32_pf12_control[6]>>8)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco32_pf12_control[6]>>8)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(1,(tile&0xfff)|deco32_pf2_bank,colour+deco32_pf2_colourbank,flags);
+}
+
+static TILE_GET_INFO( get_pf3_tile_info )
+{
+ UINT32 tile=deco32_pf3_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco32_pf34_control[6]>>0)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco32_pf34_control[6]>>0)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(2,(tile&0xfff)|deco32_pf3_bank,colour,flags);
+}
+
+static TILE_GET_INFO( get_pf4_tile_info )
+{
+ UINT32 tile=deco32_pf4_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco32_pf34_control[6]>>8)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco32_pf34_control[6]>>8)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(2,(tile&0xfff)|deco32_pf4_bank,colour+deco32_pf4_colourbank,flags);
+}
+
+/* Captain America tilemap chip 2 has different banking and colour from normal */
+static TILE_GET_INFO( get_ca_pf3_tile_info )
+{
+ int tile=deco32_pf3_data[tile_index];
+ SET_TILE_INFO(2,(tile&0x3fff)+deco32_pf3_bank,(tile >> 14)&3,0);
+}
+
+static TILE_GET_INFO( get_ll_pf3_tile_info )
+{
+ UINT32 tile=deco32_pf3_data[tile_index];
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco32_pf34_control[6]>>0)&0x01)
+ flags|=TILE_FLIPX;
+ if ((deco32_pf34_control[6]>>0)&0x02)
+ flags|=TILE_FLIPY;
+ }
+
+ SET_TILE_INFO(2,(tile&0x0fff)|deco32_pf3_bank,(tile >> 12)&3,flags);
+}
+
+static TILE_GET_INFO( get_ll_pf4_tile_info )
+{
+ UINT32 tile=deco32_pf4_data[tile_index];
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco32_pf34_control[6]>>8)&0x01)
+ flags|=TILE_FLIPX;
+ if ((deco32_pf34_control[6]>>8)&0x02)
+ flags|=TILE_FLIPY;
+ }
+
+ SET_TILE_INFO(2,(tile&0x0fff)|deco32_pf4_bank,(tile >> 12)&3,flags);
+}
+
+VIDEO_START( captaven )
+{
+ pf1_tilemap = tilemap_create(get_pf1_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ pf1a_tilemap =tilemap_create(get_pf1a_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf2_tilemap = tilemap_create(get_pf2_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf3_tilemap = tilemap_create(get_ca_pf3_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ deco32_raster_display_list=auto_malloc(10 * 256);
+ memset(deco32_raster_display_list, 0, 10 * 256);
+
+ tilemap_set_transparent_pen(pf1_tilemap,0);
+ tilemap_set_transparent_pen(pf1a_tilemap,0);
+ tilemap_set_transparent_pen(pf2_tilemap,0);
+ tilemap_set_transparent_pen(pf3_tilemap,0);
+
+ deco32_pf2_colourbank=16;
+ deco32_pf4_colourbank=0;
+ has_ace_ram=0;
+}
+
+VIDEO_START( fghthist )
+{
+ pf1_tilemap = tilemap_create(get_pf1_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ pf2_tilemap = tilemap_create(get_pf2_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf3_tilemap = tilemap_create(get_pf3_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf4_tilemap = tilemap_create(get_pf4_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN, 16,16,64,32);
+ pf1a_tilemap =0;
+ dirty_palette = auto_malloc(4096);
+
+ deco_allocate_sprite_bitmap();
+
+ tilemap_set_transparent_pen(pf1_tilemap,0);
+ tilemap_set_transparent_pen(pf2_tilemap,0);
+ tilemap_set_transparent_pen(pf3_tilemap,0);
+
+ deco32_raster_display_list=0;
+ deco32_pf2_colourbank=deco32_pf4_colourbank=0;
+ has_ace_ram=0;
+}
+
+VIDEO_START( dragngun )
+{
+ pf1_tilemap = tilemap_create(get_pf1_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ pf2_tilemap = tilemap_create(get_pf2_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf3_tilemap = tilemap_create(get_ll_pf3_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf4_tilemap = tilemap_create(get_ll_pf4_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN, 16,16,64,32);
+ pf1a_tilemap =tilemap_create(get_pf1a_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ dirty_palette = auto_malloc(4096);
+ deco32_raster_display_list = auto_malloc(10 * 256);
+
+ tilemap_set_transparent_pen(pf1_tilemap,0);
+ tilemap_set_transparent_pen(pf2_tilemap,0);
+ tilemap_set_transparent_pen(pf3_tilemap,0);
+ tilemap_set_transparent_pen(pf1a_tilemap,0);
+ memset(dirty_palette,0,4096);
+
+ deco32_pf2_colourbank=deco32_pf4_colourbank=0;
+
+ alpha_set_level(0x80);
+ state_save_register_global(dragngun_sprite_ctrl);
+ has_ace_ram=0;
+}
+
+VIDEO_START( lockload )
+{
+ pf1_tilemap = tilemap_create(get_pf1_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ pf2_tilemap = tilemap_create(get_pf2_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf3_tilemap = tilemap_create(get_ll_pf3_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ pf4_tilemap = tilemap_create(get_ll_pf4_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN, 16,16,32,32);
+ pf1a_tilemap =tilemap_create(get_pf1a_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ dirty_palette = auto_malloc(4096);
+ deco32_raster_display_list = auto_malloc(10 * 256);
+ memset(deco32_raster_display_list, 0, 10 * 256);
+
+ tilemap_set_transparent_pen(pf1_tilemap,0);
+ tilemap_set_transparent_pen(pf2_tilemap,0);
+ tilemap_set_transparent_pen(pf3_tilemap,0);
+ tilemap_set_transparent_pen(pf1a_tilemap,0);
+ memset(dirty_palette,0,4096);
+
+ deco32_pf2_colourbank=deco32_pf4_colourbank=0;
+
+ alpha_set_level(0x80);
+ state_save_register_global(dragngun_sprite_ctrl);
+ has_ace_ram=0;
+}
+
+VIDEO_START( nslasher )
+{
+ pf1_tilemap = tilemap_create(get_pf1_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ pf2_tilemap = tilemap_create(get_pf2_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf3_tilemap = tilemap_create(get_pf3_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf4_tilemap = tilemap_create(get_pf4_tile_info, deco16_scan_rows,TILEMAP_TYPE_PEN, 16,16,64,32);
+ pf1a_tilemap =0;
+ dirty_palette = auto_malloc(4096);
+
+ sprite0_mix_bitmap=auto_bitmap_alloc( machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16 );
+ sprite1_mix_bitmap=auto_bitmap_alloc( machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16 );
+ tilemap_alpha_bitmap=auto_bitmap_alloc( machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16 );
+
+ tilemap_set_transparent_pen(pf1_tilemap,0);
+ tilemap_set_transparent_pen(pf2_tilemap,0);
+ tilemap_set_transparent_pen(pf3_tilemap,0);
+ memset(dirty_palette,0,4096);
+
+ deco32_raster_display_list=0;
+ deco32_pf2_colourbank=16;
+ deco32_pf4_colourbank=16;
+ state_save_register_global(deco32_pri);
+ alpha_set_level(0x80);
+ has_ace_ram=1;
+}
+
+/******************************************************************************/
+
+VIDEO_EOF( captaven )
+{
+ memcpy(buffered_spriteram32,spriteram32,spriteram_size);
+ deco32_raster_display_position=0;
+}
+
+VIDEO_EOF( dragngun )
+{
+ deco32_raster_display_position=0;
+}
+
+#if 0
+static void print_debug_info(mame_bitmap *bitmap)
+{
+ int j;
+ char buf[64*5];
+ char *bufptr = buf;
+
+ bufptr += sprintf(bufptr,"%04X %04X %04X %04X\n",deco32_pf12_control[0]&0xffff,deco32_pf12_control[1]&0xffff,deco32_pf12_control[2]&0xffff,deco32_pf12_control[3]&0xffff);
+ bufptr += sprintf(bufptr,"%04X %04X %04X %04X\n",deco32_pf12_control[4]&0xffff,deco32_pf12_control[5]&0xffff,deco32_pf12_control[6]&0xffff,deco32_pf12_control[7]&0xffff);
+
+ bufptr += sprintf(bufptr,"%04X %04X %04X %04X\n",deco32_pf34_control[0]&0xffff,deco32_pf34_control[1]&0xffff,deco32_pf34_control[2]&0xffff,deco32_pf34_control[3]&0xffff);
+ bufptr += sprintf(bufptr,"%04X %04X %04X %04X\n",deco32_pf34_control[4]&0xffff,deco32_pf34_control[5]&0xffff,deco32_pf34_control[6]&0xffff,deco32_pf34_control[7]&0xffff);
+ bufptr += sprintf(bufptr,"%04X\n",deco32_pri);
+
+ ui_draw_text(buf,60,40);
+}
+
+#endif
+
+static void tilemap_raster_draw(mame_bitmap *bitmap, const rectangle *cliprect, int flags, int pri)
+{
+ int ptr=0,sx0,sy0,sx1,sy1,start,end=0;
+ rectangle clip;
+ int overflow=deco32_raster_display_position;
+
+ clip.min_x = cliprect->min_x;
+ clip.max_x = cliprect->max_x;
+
+ /* Finish list up to end of visible display */
+ deco32_raster_display_list[overflow++]=255;
+ deco32_raster_display_list[overflow++]=deco32_pf12_control[1];
+ deco32_raster_display_list[overflow++]=deco32_pf12_control[2];
+ deco32_raster_display_list[overflow++]=deco32_pf12_control[3];
+ deco32_raster_display_list[overflow++]=deco32_pf12_control[4];
+
+ while (ptr<overflow) {
+ start=end;
+ end=deco32_raster_display_list[ptr++];
+ sx0=deco32_raster_display_list[ptr++];
+ sy0=deco32_raster_display_list[ptr++];
+ sx1=deco32_raster_display_list[ptr++];
+ sy1=deco32_raster_display_list[ptr++];
+
+ clip.min_y = start;
+ clip.max_y = end;
+
+ tilemap_set_scrollx(pf2_tilemap,0,sx1);
+ tilemap_set_scrolly(pf2_tilemap,0,sy1);
+ tilemap_draw(bitmap,&clip,pf2_tilemap,flags,pri);
+ }
+}
+
+static void combined_tilemap_draw(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const mame_bitmap *bitmap0 = tilemap_get_pixmap(pf3_tilemap);
+ const mame_bitmap *bitmap1 = tilemap_get_pixmap(pf4_tilemap);
+ int x,y,p;
+
+ const UINT16 width_mask=0x3ff;
+ const UINT16 height_mask=0x1ff;
+ const UINT16 y_src=deco32_pf34_control[2];
+// const UINT32 *rows=deco32_pf3_rowscroll;
+
+ const UINT16 *bitmap0_y;
+ const UINT16 *bitmap1_y;
+ UINT32 *bitmap2_y;
+
+ UINT16 x_src;
+
+ for (y=8; y<248; y++) {
+ const int py=(y_src+y)&height_mask;
+
+ bitmap0_y=BITMAP_ADDR16(bitmap0, py, 0);
+ bitmap1_y=BITMAP_ADDR16(bitmap1, py, 0);
+ bitmap2_y=BITMAP_ADDR32(bitmap, y, 0);
+
+ /* Todo: Should add row enable, and col scroll, but never used as far as I can see */
+ x_src=(deco32_pf34_control[1] + deco32_pf3_rowscroll[py])&width_mask;
+
+ for (x=0; x<320; x++) {
+
+ /* 0x200 is palette base for this tilemap */
+ p = 0x200 +((bitmap0_y[x_src]&0xf) | ((bitmap0_y[x_src]&0x30)<<4) | ((bitmap1_y[x_src]&0xf)<<4));
+
+ bitmap2_y[x]=machine->pens[p];
+
+ x_src=(x_src+1)&width_mask;
+ }
+ }
+}
+
+static void deco32_setup_scroll(tilemap *pf_tilemap, UINT16 height, UINT8 control0, UINT8 control1, UINT16 sy, UINT16 sx, UINT32 *rowdata, UINT32 *coldata)
+{
+ int rows,offs;
+
+ /* Colscroll - not fully supported yet! */
+ if (control1&0x20 && coldata) {
+ sy+=coldata[0];
+ //popmessage("%08x",coldata[0]);
+ }
+
+ /* Rowscroll enable */
+ if (control1&0x40 && rowdata) {
+ tilemap_set_scroll_cols(pf_tilemap,1);
+ tilemap_set_scrolly( pf_tilemap,0, sy );
+
+ /* Several different rowscroll styles */
+ switch ((control0>>3)&0xf) {
+ case 0: rows=512; break;/* Every line of 512 height bitmap */
+ case 1: rows=256; break;
+ case 2: rows=128; break;
+ case 3: rows=64; break;
+ case 4: rows=32; break;
+ case 5: rows=16; break;
+ case 6: rows=8; break;
+ case 7: rows=4; break;
+ case 8: rows=2; break;
+ default: rows=1; break;
+ }
+ if (height<rows) rows/=2; /* 8x8 tile layers have half as many lines as 16x16 */
+
+ tilemap_set_scroll_rows(pf_tilemap,rows);
+ for (offs = 0;offs < rows;offs++)
+ tilemap_set_scrollx( pf_tilemap,offs, sx + rowdata[offs] );
+ }
+ else {
+ tilemap_set_scroll_rows(pf_tilemap,1);
+ tilemap_set_scroll_cols(pf_tilemap,1);
+ tilemap_set_scrollx( pf_tilemap, 0, sx );
+ tilemap_set_scrolly( pf_tilemap, 0, sy );
+ }
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( captaven )
+{
+ int pf1_enable,pf2_enable,pf3_enable;
+ static int last_pf3_bank;
+
+ flip_screen_set(deco32_pf12_control[0]&0x80);
+ tilemap_set_flip(ALL_TILEMAPS,flip_screen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ deco32_setup_scroll(pf1_tilemap, 256,(deco32_pf12_control[5]>>0)&0xff,(deco32_pf12_control[6]>>0)&0xff,deco32_pf12_control[2],deco32_pf12_control[1],deco32_pf1_rowscroll,deco32_pf1_rowscroll+0x200);
+ deco32_setup_scroll(pf1a_tilemap,512,(deco32_pf12_control[5]>>0)&0xff,(deco32_pf12_control[6]>>0)&0xff,deco32_pf12_control[2],deco32_pf12_control[1],deco32_pf1_rowscroll,deco32_pf1_rowscroll+0x200);
+ deco32_setup_scroll(pf2_tilemap, 512,(deco32_pf12_control[5]>>8)&0xff,(deco32_pf12_control[6]>>8)&0xff,deco32_pf12_control[4],deco32_pf12_control[3],deco32_pf2_rowscroll,deco32_pf2_rowscroll+0x200);
+ deco32_setup_scroll(pf3_tilemap, 512,(deco32_pf34_control[5]>>0)&0xff,(deco32_pf34_control[6]>>0)&0xff,deco32_pf34_control[4],deco32_pf34_control[3],deco32_pf3_rowscroll,deco32_pf3_rowscroll+0x200);
+
+ /* PF1 & PF2 only have enough roms for 1 bank */
+ deco32_pf1_bank=0;//(deco32_pf12_control[7]>> 4)&0xf;
+ deco32_pf2_bank=0;//(deco32_pf12_control[7]>>12)&0xf;
+ deco32_pf3_bank=(deco32_pf34_control[7]>> 4)&0xf;
+
+ if (deco32_pf34_control[7]&0x0020) deco32_pf3_bank=0x4000; else deco32_pf3_bank=0;
+ if (deco32_pf3_bank!=last_pf3_bank) tilemap_mark_all_tiles_dirty(pf3_tilemap);
+ last_pf3_bank=deco32_pf3_bank;
+
+ pf1_enable=deco32_pf12_control[5]&0x0080;
+ pf2_enable=deco32_pf12_control[5]&0x8000;
+ pf3_enable=deco32_pf34_control[5]&0x0080;
+
+ tilemap_set_enable(pf1_tilemap,pf1_enable);
+ tilemap_set_enable(pf1a_tilemap,pf1_enable);
+ tilemap_set_enable(pf2_tilemap,pf2_enable);
+ tilemap_set_enable(pf3_tilemap,pf3_enable);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ if ((deco32_pri&1)==0) {
+ if (pf3_enable)
+ tilemap_draw(bitmap,cliprect,pf3_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ else
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ if (deco32_raster_display_position)
+ tilemap_raster_draw(bitmap,cliprect,0,1);
+ else
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,1);
+ } else {
+ if (pf2_enable) {
+ if (deco32_raster_display_position)
+ tilemap_raster_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ }
+ else
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ tilemap_draw(bitmap,cliprect,pf3_tilemap,0,1);
+ }
+
+ captaven_draw_sprites(machine,bitmap,cliprect,buffered_spriteram32,3);
+
+ /* PF1 can be in 8x8 mode or 16x16 mode */
+ if (deco32_pf12_control[6]&0x80)
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1a_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( dragngun )
+{
+ /* Tilemap graphics banking */
+ if ((((deco32_pf12_control[7]>> 4)&0x7)<<12)!=deco32_pf1_bank || deco32_pf1_flip!=((deco32_pf12_control[6]>>0)&0x3)) {
+ tilemap_mark_all_tiles_dirty(pf1_tilemap);
+ tilemap_mark_all_tiles_dirty(pf1a_tilemap);
+ }
+ if ((((deco32_pf12_control[7]>>12)&0x7)<<12)!=deco32_pf2_bank || deco32_pf2_flip!=((deco32_pf12_control[6]>>8)&0x3))
+ tilemap_mark_all_tiles_dirty(pf2_tilemap);
+ if ((((deco32_pf34_control[7]>> 5)&0x7)<<12)!=deco32_pf3_bank || deco32_pf3_flip!=((deco32_pf34_control[6]>>0)&0x3))
+ tilemap_mark_all_tiles_dirty(pf3_tilemap);
+ if ((((deco32_pf34_control[7]>>13)&0x7)<<12)!=deco32_pf4_bank || deco32_pf4_flip!=((deco32_pf34_control[6]>>8)&0x3))
+ tilemap_mark_all_tiles_dirty(pf4_tilemap);
+ deco32_pf1_bank=((deco32_pf12_control[7]>> 5)&0x7)<<12;
+ deco32_pf2_bank=((deco32_pf12_control[7]>>12)&0x7)<<12;
+ deco32_pf3_bank=((deco32_pf34_control[7]>> 5)&0x7)<<12;
+ deco32_pf4_bank=((deco32_pf34_control[7]>>13)&0x7)<<12;
+
+ deco32_pf1_flip=(deco32_pf12_control[6]>>0)&0x3;
+ deco32_pf2_flip=(deco32_pf12_control[6]>>8)&0x3;
+ deco32_pf3_flip=(deco32_pf34_control[6]>>0)&0x3;
+ deco32_pf4_flip=(deco32_pf34_control[6]>>8)&0x3;
+
+ deco32_setup_scroll(pf1_tilemap, 256,(deco32_pf12_control[5]>>0)&0xff,(deco32_pf12_control[6]>>0)&0xff,deco32_pf12_control[2],deco32_pf12_control[1],deco32_pf1_rowscroll,deco32_pf1_rowscroll+0x200);
+ deco32_setup_scroll(pf1a_tilemap,512,(deco32_pf12_control[5]>>0)&0xff,(deco32_pf12_control[6]>>0)&0xff,deco32_pf12_control[2],deco32_pf12_control[1],deco32_pf1_rowscroll,deco32_pf1_rowscroll+0x200);
+ deco32_setup_scroll(pf2_tilemap, 512,(deco32_pf12_control[5]>>8)&0xff,(deco32_pf12_control[6]>>8)&0xff,deco32_pf12_control[4],deco32_pf12_control[3],deco32_pf2_rowscroll,deco32_pf2_rowscroll+0x200);
+ deco32_setup_scroll(pf3_tilemap, 512,(deco32_pf34_control[5]>>0)&0xff,(deco32_pf34_control[6]>>0)&0xff,deco32_pf34_control[2],deco32_pf34_control[1],deco32_pf3_rowscroll,deco32_pf3_rowscroll+0x200);
+ deco32_setup_scroll(pf4_tilemap, 512,(deco32_pf34_control[5]>>8)&0xff,(deco32_pf34_control[6]>>8)&0xff,deco32_pf34_control[4],deco32_pf34_control[3],deco32_pf4_rowscroll,deco32_pf4_rowscroll+0x200);
+
+ tilemap_set_enable(pf1_tilemap, deco32_pf12_control[5]&0x0080);
+ tilemap_set_enable(pf1a_tilemap,deco32_pf12_control[5]&0x0080);
+ tilemap_set_enable(pf2_tilemap, deco32_pf12_control[5]&0x8000);
+ tilemap_set_enable(pf3_tilemap, deco32_pf34_control[5]&0x0080);
+ tilemap_set_enable(pf4_tilemap, deco32_pf34_control[5]&0x8000);
+
+ if ((deco32_pf34_control[5]&0x8000)==0)
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ tilemap_draw(bitmap,cliprect,pf4_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,pf3_tilemap,0,0);
+
+ /* Raster update */
+ if (deco32_raster_display_position) {
+ int ptr=0,start,end=0;
+ rectangle clip;
+ int overflow=deco32_raster_display_position;
+
+ clip.min_x = cliprect->min_x;
+ clip.max_x = cliprect->max_x;
+
+ /* Finish list up to end of visible display */
+ deco32_raster_display_list[overflow++]=255;
+ deco32_raster_display_list[overflow++]=deco32_pf12_control[1];
+ deco32_raster_display_list[overflow++]=deco32_pf12_control[2];
+ deco32_raster_display_list[overflow++]=deco32_pf12_control[3];
+ deco32_raster_display_list[overflow++]=deco32_pf12_control[4];
+
+ while (ptr<overflow) {
+ start=end;
+ end=deco32_raster_display_list[ptr++];
+ deco32_pf12_control[1]=deco32_raster_display_list[ptr++];
+ deco32_pf12_control[2]=deco32_raster_display_list[ptr++];
+ deco32_pf12_control[3]=deco32_raster_display_list[ptr++];
+ deco32_pf12_control[4]=deco32_raster_display_list[ptr++];
+
+ clip.min_y = start;
+ clip.max_y = end;
+
+ deco32_setup_scroll(pf2_tilemap, 512,(deco32_pf12_control[5]>>8)&0xff,(deco32_pf12_control[6]>>8)&0xff,deco32_pf12_control[4],deco32_pf12_control[3],deco32_pf2_rowscroll,deco32_pf2_rowscroll+0x200);
+ tilemap_draw(bitmap,&clip,pf2_tilemap,0,0);
+ }
+ } else {
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ }
+
+ dragngun_draw_sprites(machine,bitmap,cliprect,buffered_spriteram32);
+
+ /* PF1 can be in 8x8 mode or 16x16 mode */
+ if (deco32_pf12_control[6]&0x80)
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1a_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( fghthist )
+{
+ /* Dirty tilemaps if any globals change */
+ if (deco32_pf1_flip!=((deco32_pf12_control[6]>>0)&0x3))
+ tilemap_mark_all_tiles_dirty(pf1_tilemap);
+ if (deco32_pf2_flip!=((deco32_pf12_control[6]>>8)&0x3))
+ tilemap_mark_all_tiles_dirty(pf2_tilemap);
+
+ if ((((deco32_pf12_control[7]>>13)&0x7)<<12)!=deco32_pf2_bank || deco32_pf2_flip!=((deco32_pf12_control[6]>>8)&0x3))
+ tilemap_mark_all_tiles_dirty(pf2_tilemap);
+ if ((((deco32_pf34_control[7]>> 5)&0x7)<<12)!=deco32_pf3_bank || deco32_pf3_flip!=((deco32_pf34_control[6]>>0)&0x3))
+ tilemap_mark_all_tiles_dirty(pf3_tilemap);
+ if ((((deco32_pf34_control[7]>>13)&0x7)<<12)!=deco32_pf4_bank || deco32_pf4_flip!=((deco32_pf34_control[6]>>8)&0x3))
+ tilemap_mark_all_tiles_dirty(pf4_tilemap);
+
+ deco32_pf2_bank=((deco32_pf12_control[7]>>12)&0x3)<<12;
+ deco32_pf3_bank=((deco32_pf34_control[7]>> 5)&0x3)<<12; //WRONG WRONG WRONG check masks
+ deco32_pf4_bank=((deco32_pf34_control[7]>>12)&0x3)<<12;
+ deco32_pf1_flip=(deco32_pf12_control[6]>>0)&0x3;
+ deco32_pf2_flip=(deco32_pf12_control[6]>>8)&0x3;
+ deco32_pf3_flip=(deco32_pf34_control[6]>>0)&0x3;
+ deco32_pf4_flip=(deco32_pf34_control[6]>>8)&0x3;
+
+ /* Enable registers */
+ tilemap_set_enable(pf1_tilemap, deco32_pf12_control[5]&0x0080);
+ tilemap_set_enable(pf2_tilemap, deco32_pf12_control[5]&0x8000);
+ tilemap_set_enable(pf3_tilemap, deco32_pf34_control[5]&0x0080);
+ tilemap_set_enable(pf4_tilemap, deco32_pf34_control[5]&0x8000);
+
+ /* Setup scroll registers */
+ deco32_setup_scroll(pf1_tilemap, 256,(deco32_pf12_control[5]>>0)&0xff,(deco32_pf12_control[6]>>0)&0xff,deco32_pf12_control[2],deco32_pf12_control[1],deco32_pf1_rowscroll,deco32_pf1_rowscroll+0x200);
+ deco32_setup_scroll(pf2_tilemap, 512,(deco32_pf12_control[5]>>8)&0xff,(deco32_pf12_control[6]>>8)&0xff,deco32_pf12_control[4],deco32_pf12_control[3],deco32_pf2_rowscroll,deco32_pf2_rowscroll+0x200);
+ deco32_setup_scroll(pf3_tilemap, 512,(deco32_pf34_control[5]>>0)&0xff,(deco32_pf34_control[6]>>0)&0xff,deco32_pf34_control[2],deco32_pf34_control[1],deco32_pf3_rowscroll,deco32_pf3_rowscroll+0x200);
+ deco32_setup_scroll(pf4_tilemap, 512,(deco32_pf34_control[5]>>8)&0xff,(deco32_pf34_control[6]>>8)&0xff,deco32_pf34_control[4],deco32_pf34_control[3],deco32_pf4_rowscroll,deco32_pf4_rowscroll+0x200);
+
+ /* Draw screen */
+ deco16_clear_sprite_priority_bitmap();
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0x000],cliprect); // Palette index not confirmed
+ tilemap_draw(bitmap,cliprect,pf4_tilemap,0,1);
+ tilemap_draw(bitmap,cliprect,pf3_tilemap,0,4);
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,16);
+ fghthist_draw_sprites(machine, bitmap, cliprect, buffered_spriteram32,3,0, 0xf);
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ return 0;
+}
+
+/*
+ This function mimics the priority PROM/circuit on the pcb. It takes
+ the tilemaps & sprite bitmaps as inputs, and outputs a final pixel
+ based on alpha & priority values. Rendering sprites to temporary
+ bitmaps is the only reasonable way to implement proper priority &
+ blending support - it can't be done in-place on the final framebuffer
+ without a lot of support bitmaps.
+*/
+static void mixDualAlphaSprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect, const gfx_element *gfx0, const gfx_element *gfx1, int mixAlphaTilemap)
+{
+ const pen_t *pal0 = &machine->remapped_colortable[gfx0->color_base];
+ const pen_t *pal1 = &machine->remapped_colortable[gfx1->color_base];
+ const pen_t *pal2 = &machine->remapped_colortable[(deco32_pri&1) ? machine->gfx[1]->color_base : machine->gfx[2]->color_base];
+ int x,y;
+
+ /* Mix sprites into main bitmap, based on priority & alpha */
+ for (y=8; y<248; y++) {
+ UINT8* tilemapPri=BITMAP_ADDR8(priority_bitmap, y, 0);
+ UINT16* sprite0=BITMAP_ADDR16(sprite0_mix_bitmap, y, 0);
+ UINT16* sprite1=BITMAP_ADDR16(sprite1_mix_bitmap, y, 0);
+ UINT32* destLine=BITMAP_ADDR32(bitmap, y, 0);
+ UINT16* alphaTilemap=BITMAP_ADDR16(tilemap_alpha_bitmap, y, 0);
+
+ for (x=0; x<320; x++) {
+ UINT16 priColAlphaPal0=sprite0[x];
+ UINT16 priColAlphaPal1=sprite1[x];
+ UINT16 pri0=(priColAlphaPal0&0x6000)>>13;
+ UINT16 pri1=(priColAlphaPal1&0x6000)>>13;
+ UINT16 col0=((priColAlphaPal0&0x1f00)>>8) % gfx0->total_colors;
+ UINT16 col1=((priColAlphaPal1&0x0f00)>>8) % gfx1->total_colors;
+ UINT16 alpha1=priColAlphaPal1&0x8000;
+
+ // Apply sprite bitmap 0 according to priority rules
+ if ((priColAlphaPal0&0xff)!=0)
+ {
+ /*
+ Sprite 0 priority rules:
+
+ 0 = Sprite above all layers
+ 1 = Sprite under top playfield
+ 2 = Sprite under top two playfields
+ 3 = Sprite under all playfields
+ */
+ if ((pri0&0x3)==0 || (pri0&0x3)==1 || ((pri0&0x3)==2 && mixAlphaTilemap)) // Spri0 on top of everything, or under alpha playfield
+ {
+ destLine[x]=pal0[(priColAlphaPal0&0xff) + (gfx0->color_granularity * col0)];
+ }
+ else if ((pri0&0x3)==2) // Spri0 under top playfield
+ {
+ if (tilemapPri[x]<4)
+ destLine[x]=pal0[(priColAlphaPal0&0xff) + (gfx0->color_granularity * col0)];
+ }
+ else // Spri0 under top & middle playfields
+ {
+ if (tilemapPri[x]<2)
+ destLine[x]=pal0[(priColAlphaPal0&0xff) + (gfx0->color_granularity * col0)];
+ }
+ }
+
+ // Apply sprite bitmap 1 according to priority rules
+ if ((priColAlphaPal1&0xff)!=0)
+ {
+ // Apply alpha for this pixel based on Ace setting
+ if (alpha1)
+ {
+ /*
+ Alpha rules:
+
+ Pri 0 - Over all tilemaps, but under sprite 0 pri 0, pri 1, pri 2
+ Pri 1 -
+ Pri 2 -
+ Pri 3 -
+ */
+ alpha_set_level(0x80);
+
+ /* Alpha values are tied to ACE ram... */
+ //int alpha=((deco32_ace_ram[0x0 + (((priColAlphaPal1&0xf0)>>4)/2)]) * 8)-1;
+ //if (alpha<0)
+ // alpha=0;
+ //alpha_set_level(255-alpha);
+
+ /* I don't really understand how object ACE ram is really hooked up,
+ the only obvious place in Night Slashers is the stagecoach in level 2 */
+
+ if (pri1==0 && (((priColAlphaPal0&0xff)==0 || ((pri0&0x3)!=0 && (pri0&0x3)!=1 && (pri0&0x3)!=2))))
+ {
+ if ((deco32_pri&1)==0 || ((deco32_pri&1)==1 && tilemapPri[x]<4) || ((deco32_pri&1)==1 && mixAlphaTilemap))
+ destLine[x]=alpha_blend32(destLine[x], pal1[(priColAlphaPal1&0xff) + (gfx1->color_granularity * col1)]);
+ }
+ else if (pri1==1 && ((priColAlphaPal0&0xff)==0 || ((pri0&0x3)!=0 && (pri0&0x3)!=1 && (pri0&0x3)!=2)))
+ destLine[x]=alpha_blend32(destLine[x], pal1[(priColAlphaPal1&0xff) + (gfx1->color_granularity * col1)]);
+ else if (pri1==2)// TOdo
+ destLine[x]=alpha_blend32(destLine[x], pal1[(priColAlphaPal1&0xff) + (gfx1->color_granularity * col1)]);
+ else if (pri1==3)// TOdo
+ destLine[x]=alpha_blend32(destLine[x], pal1[(priColAlphaPal1&0xff) + (gfx1->color_granularity * col1)]);
+ }
+ else
+ {
+ /*
+ Non alpha rules:
+
+ Pri 0 - Under sprite 0 pri 0, over all tilemaps
+ */
+ if (pri1==0 && ((priColAlphaPal0&0xff)==0 || ((pri0&0x3)!=0)))
+ destLine[x]=pal1[(priColAlphaPal1&0xff) + (gfx1->color_granularity * col1)];
+ else if (pri1==1) // todo
+ destLine[x]=pal1[(priColAlphaPal1&0xff) + (gfx1->color_granularity * col1)];
+ else if (pri1==2) // todo
+ destLine[x]=pal1[(priColAlphaPal1&0xff) + (gfx1->color_granularity * col1)];
+ else if (pri1==3) // todo
+ destLine[x]=pal1[(priColAlphaPal1&0xff) + (gfx1->color_granularity * col1)];
+ }
+ }
+
+ /* Optionally mix in alpha tilemap */
+ if (mixAlphaTilemap)
+ {
+ UINT16 p=alphaTilemap[x];
+ if (p&0xf)
+ {
+ /* Alpha tilemap under top two sprite 0 priorities */
+ if (((priColAlphaPal0&0xff)==0 || (pri0&0x3)==2 || (pri0&0x3)==3)
+ && ((priColAlphaPal1&0xff)==0 || (pri1&0x3)==2 || (pri1&0x3)==3 || alpha1))
+ {
+ /* Alpha values are tied to ACE ram */
+ int alpha=((deco32_ace_ram[0x17 + (((p&0xf0)>>4)/2)]) * 8)-1;
+ if (alpha<0)
+ alpha=0;
+ alpha_set_level(255-alpha);
+
+ destLine[x]=alpha_blend32(destLine[x], pal2[p]);
+ }
+ }
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( nslasher )
+{
+ int alphaTilemap=0;
+
+ /* Dirty tilemaps if any globals change */
+ if (deco32_pf1_flip!=((deco32_pf12_control[6]>>0)&0x3))
+ tilemap_mark_all_tiles_dirty(pf1_tilemap);
+ if (deco32_pf2_flip!=((deco32_pf12_control[6]>>8)&0x3))
+ tilemap_mark_all_tiles_dirty(pf2_tilemap);
+ if ((((deco32_pf12_control[7]>>12)&0x7)<<12)!=deco32_pf2_bank || deco32_pf2_flip!=((deco32_pf12_control[6]>>8)&0x3))
+ tilemap_mark_all_tiles_dirty(pf2_tilemap);
+ if ((((deco32_pf34_control[7]>> 4)&0x3)<<12)!=deco32_pf3_bank || deco32_pf3_flip!=((deco32_pf34_control[6]>>0)&0x3))
+ tilemap_mark_all_tiles_dirty(pf3_tilemap);
+ if ((((deco32_pf34_control[7]>>12)&0x3)<<12)!=deco32_pf4_bank || deco32_pf4_flip!=((deco32_pf34_control[6]>>8)&0x3))
+ tilemap_mark_all_tiles_dirty(pf4_tilemap);
+
+ deco32_pf2_bank=((deco32_pf12_control[7]>>12)&0x3)<<12;
+ deco32_pf3_bank=((deco32_pf34_control[7]>> 4)&0x3)<<12;
+ deco32_pf4_bank=((deco32_pf34_control[7]>>12)&0x3)<<12;
+ deco32_pf1_flip=(deco32_pf12_control[6]>>0)&0x3;
+ deco32_pf2_flip=(deco32_pf12_control[6]>>8)&0x3;
+ deco32_pf3_flip=(deco32_pf34_control[6]>>0)&0x3;
+ deco32_pf4_flip=(deco32_pf34_control[6]>>8)&0x3;
+
+ /* Setup scroll registers */
+ deco32_setup_scroll(pf1_tilemap, 256,(deco32_pf12_control[5]>>0)&0xff,(deco32_pf12_control[6]>>0)&0xff,deco32_pf12_control[2],deco32_pf12_control[1],deco32_pf1_rowscroll,deco32_pf1_rowscroll+0x200);
+ deco32_setup_scroll(pf2_tilemap, 512,(deco32_pf12_control[5]>>8)&0xff,(deco32_pf12_control[6]>>8)&0xff,deco32_pf12_control[4],deco32_pf12_control[3],deco32_pf2_rowscroll,deco32_pf2_rowscroll+0x200);
+ deco32_setup_scroll(pf3_tilemap, 512,(deco32_pf34_control[5]>>0)&0xff,(deco32_pf34_control[6]>>0)&0xff,deco32_pf34_control[2],deco32_pf34_control[1],deco32_pf3_rowscroll,deco32_pf3_rowscroll+0x200);
+ deco32_setup_scroll(pf4_tilemap, 512,(deco32_pf34_control[5]>>8)&0xff,(deco32_pf34_control[6]>>8)&0xff,deco32_pf34_control[4],deco32_pf34_control[3],deco32_pf4_rowscroll,deco32_pf4_rowscroll+0x200);
+
+ /* Enable registers */
+ tilemap_set_enable(pf1_tilemap, deco32_pf12_control[5]&0x0080);
+ tilemap_set_enable(pf2_tilemap, deco32_pf12_control[5]&0x8000);
+ tilemap_set_enable(pf3_tilemap, deco32_pf34_control[5]&0x0080);
+ tilemap_set_enable(pf4_tilemap, deco32_pf34_control[5]&0x8000);
+
+ /* This is not a conclusive test for deciding if tilemap needs alpha blending */
+ if (deco32_ace_ram[0x17]!=0x0 && deco32_pri)
+ alphaTilemap=1;
+
+ if (deco32_ace_ram_dirty)
+ updateAceRam(machine);
+
+ fillbitmap(sprite0_mix_bitmap,0,cliprect);
+ fillbitmap(sprite1_mix_bitmap,0,cliprect);
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(tilemap_alpha_bitmap,0,cliprect);
+ if ((deco32_pf34_control[5]&0x8000)==0)
+ fillbitmap(bitmap,machine->pens[0x200],cliprect);
+
+ /* Draw sprites to temporary bitmaps, saving alpha & priority info for later mixing */
+ nslasher_draw_sprites(machine,sprite0_mix_bitmap,cliprect,buffered_spriteram32,3);
+ nslasher_draw_sprites(machine,sprite1_mix_bitmap,cliprect,buffered_spriteram32_2,4);
+
+ /* Render alpha-blended tilemap to seperate buffer for proper mixing */
+ if (alphaTilemap)
+ fillbitmap(tilemap_alpha_bitmap,0,cliprect);
+
+ /* Draw playfields & sprites */
+ if (deco32_pri&2)
+ {
+ combined_tilemap_draw(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,4);
+ }
+ else
+ {
+ tilemap_draw(bitmap,cliprect,pf4_tilemap,0,1);
+ if (deco32_pri&1)
+ {
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,2);
+ if (alphaTilemap)
+ tilemap_draw(tilemap_alpha_bitmap,cliprect,pf3_tilemap,0,4);
+ else
+ tilemap_draw(bitmap,cliprect,pf3_tilemap,0,4);
+ }
+ else
+ {
+ tilemap_draw(bitmap,cliprect,pf3_tilemap,0,2);
+ if (alphaTilemap)
+ tilemap_draw(tilemap_alpha_bitmap,cliprect,pf2_tilemap,0,4);
+ else
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,4);
+ }
+ }
+
+ mixDualAlphaSprites(machine, bitmap, cliprect, machine->gfx[3], machine->gfx[4], alphaTilemap);
+
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/deco_mlc.c b/src/mame/video/deco_mlc.c
new file mode 100644
index 00000000000..e8f32ec2bec
--- /dev/null
+++ b/src/mame/video/deco_mlc.c
@@ -0,0 +1,532 @@
+/*
+ The MLC graphics hardware is quite complicated - the usual method of having 'object ram' that
+ controls sprites is expanded into object ram that controls sprite blocks that may be stored
+ in RAM or ROM. Each tile in a block may be specified explicitly via a display list in ROM or
+ calculated as part of a block offset.
+
+ Blocks can be scaled and subpositioned, and are usually 4-6bpp but two 4bpp blocks can be
+ combined into 8bpp with a flag.
+*/
+
+#include "driver.h"
+
+extern int mlc_raster_table[9][256];
+extern UINT32 mlc_clipper[32];
+static mame_bitmap *temp_bitmap;
+static UINT32 colour_mask, *mlc_buffered_spriteram;
+UINT32 *mlc_vram, *mlc_clip_ram;
+
+/******************************************************************************/
+
+VIDEO_START( mlc )
+{
+ alpha_set_level(0x80);
+
+ if (machine->gfx[0]->color_granularity==16)
+ colour_mask=0x7f;
+ else if (machine->gfx[0]->color_granularity==32)
+ colour_mask=0x3f;
+ else
+ colour_mask=0x1f;
+
+ temp_bitmap = auto_bitmap_alloc( 512, 512, BITMAP_FORMAT_RGB32 );
+ mlc_buffered_spriteram = auto_malloc(0x3000);
+}
+
+#ifdef UNUSED_FUNCTION
+static void blitRaster(mame_bitmap *bitmap, int rasterMode)
+{
+ int x,y;
+ for (y=0; y<256; y++) //todo
+ {
+ UINT32* src=BITMAP_ADDR32(temp_bitmap, y&0x1ff, 0);
+ UINT32* dst=BITMAP_ADDR32(bitmap, y, 0);
+ UINT32 xptr=(mlc_raster_table[0][y]<<13);
+
+ if (input_code_pressed(KEYCODE_X))
+ xptr=0;
+
+ for (x=0; x<320; x++)
+ {
+ if (src[x])
+ dst[x]=src[(xptr>>16)&0x1ff];
+
+ //if (input_code_pressed(KEYCODE_X))
+ // xptr+=0x10000;
+ //else if(rasterHackTest[0][y]<0)
+ xptr+=0x10000 - ((mlc_raster_table[2][y]&0x3ff)<<5);
+ //else
+ // xptr+=0x10000 + (mlc_raster_table[0][y]<<5);
+ }
+ }
+}
+#endif
+
+static void mlc_drawgfxzoom( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ UINT32 code1,UINT32 code2, UINT32 color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,int use8bpp,
+ int scalex, int scaley)
+{
+ rectangle myclip;
+
+ if (!scalex || !scaley) return;
+
+ /*
+ scalex and scaley are 16.16 fixed point numbers
+ 1<<15 : shrink to 50%
+ 1<<16 : uniform scale
+ 1<<17 : double to 200%
+ */
+
+ /* KW 991012 -- Added code to force clip to bitmap boundary */
+ if(clip)
+ {
+ myclip.min_x = clip->min_x;
+ myclip.max_x = clip->max_x;
+ myclip.min_y = clip->min_y;
+ myclip.max_y = clip->max_y;
+
+ if (myclip.min_x < 0) myclip.min_x = 0;
+ if (myclip.max_x >= dest_bmp->width) myclip.max_x = dest_bmp->width-1;
+ if (myclip.min_y < 0) myclip.min_y = 0;
+ if (myclip.max_y >= dest_bmp->height) myclip.max_y = dest_bmp->height-1;
+
+ clip=&myclip;
+ }
+
+ {
+ if( gfx )
+ {
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+ int source_base1 = (code1 % gfx->total_elements) * gfx->height;
+ int source_base2 = (code2 % gfx->total_elements) * gfx->height;
+
+ int sprite_screen_height = (scaley*gfx->height+(sy&0xffff))>>16;
+ int sprite_screen_width = (scalex*gfx->width+(sx&0xffff))>>16;
+
+ sx>>=16;
+ sy>>=16;
+
+ if (sprite_screen_width && sprite_screen_height)
+ {
+ /* compute sprite increment per screen pixel */
+ int dx = (gfx->width<<16)/sprite_screen_width;
+ int dy = (gfx->height<<16)/sprite_screen_height;
+
+ int ex = sx+sprite_screen_width;
+ int ey = sy+sprite_screen_height;
+
+ int x_index_base;
+ int y_index;
+
+ if( flipx )
+ {
+ x_index_base = (sprite_screen_width-1)*dx;
+ dx = -dx;
+ }
+ else
+ {
+ x_index_base = 0;
+ }
+
+ if( flipy )
+ {
+ y_index = (sprite_screen_height-1)*dy;
+ dy = -dy;
+ }
+ else
+ {
+ y_index = 0;
+ }
+
+ if( clip )
+ {
+ if( sx < clip->min_x)
+ { /* clip left */
+ int pixels = clip->min_x-sx;
+ sx += pixels;
+ x_index_base += pixels*dx;
+ }
+ if( sy < clip->min_y )
+ { /* clip top */
+ int pixels = clip->min_y-sy;
+ sy += pixels;
+ y_index += pixels*dy;
+ }
+ /* NS 980211 - fixed incorrect clipping */
+ if( ex > clip->max_x+1 )
+ { /* clip right */
+ int pixels = ex-clip->max_x-1;
+ ex -= pixels;
+ }
+ if( ey > clip->max_y+1 )
+ { /* clip bottom */
+ int pixels = ey-clip->max_y-1;
+ ey -= pixels;
+ }
+ }
+
+ if( ex>sx )
+ { /* skip if inner loop doesn't draw anything */
+ int y;
+
+ /* case 1: TRANSPARENCY_PEN */
+ if (transparency == TRANSPARENCY_PEN)
+ {
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source1 = gfx->gfxdata + (source_base1+(y_index>>16)) * gfx->line_modulo;
+ UINT8 *source2 = gfx->gfxdata + (source_base2+(y_index>>16)) * gfx->line_modulo;
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source1[x_index>>16];
+ if (use8bpp)
+ c=(c<<4)|source2[x_index>>16];
+
+ if( c != transparent_color ) dest[x] = pal[c];
+
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 6: TRANSPARENCY_ALPHA */
+ if (transparency == TRANSPARENCY_ALPHA)
+ {
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = gfx->gfxdata + (source_base1+(y_index>>16)) * gfx->line_modulo;
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if( c != transparent_color ) dest[x] = alpha_blend32(dest[x], 0); //pal[c]);
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ UINT32 *index_ptr=0;
+ int offs,fx=0,fy=0,x,y,color,colorOffset,sprite,indx,h,w,bx,by,fx1,fy1;
+ int xmult,ymult,xoffs,yoffs;
+ UINT8 *rom = memory_region(REGION_GFX2) + 0x20000, *index_ptr8;
+ UINT8 *rawrom = memory_region(REGION_GFX2);
+ int blockIsTilemapIndex=0;
+ int sprite2=0,indx2=0,use8bppMode=0;
+ int yscale,xscale;
+ int ybase,yinc;
+ int trans;
+ int useIndicesInRom=0;
+ int hibits=0;
+ int tileFormat=0;
+ int rasterMode=0;
+ int lastRasterMode=0;
+ int rasterDirty=0;
+ int clipper=0;
+ rectangle user_clip;
+ UINT32* mlc_spriteram=mlc_buffered_spriteram; // spriteram32
+
+ for (offs = (0x3000/4)-8; offs>=0; offs-=8)
+ {
+ if ((mlc_spriteram[offs+0]&0x8000)==0)
+ continue;
+ if ((mlc_spriteram[offs+1]&0x2000) && (cpu_getcurrentframe() & 1))
+ continue;
+
+ /*
+ Spriteram (1) format (16 bit):
+
+ Word 0: 0x8000 - Sprite enable
+ 0x4000 - Use ROM or RAM for spriteram 2 (really top bit of index)
+ 0x3fff - Index into spriteram 2
+ Word 1: 0x8000 - X flip
+ 0x4000 - Y flip
+ 0x2000 - Auto-flicker (display sprite only every other frame)
+ 0x1000 - If set combine this 4bpp sprite & next one, into 8bpp sprite
+ 0x0800 - ? (Not seen used anywhere)
+ 0x0400 - Use raster IRQ lookup table when drawing object
+ 0x0300 - Selects clipping window to use
+ 0x00ff - Colour/alpha shadow enable
+ Word 2: 0x07ff - Y position
+ Word 3: 0x07ff - X position
+ Word 4: 0x03ff - X scale
+ Word 5: 0x03ff - Y scale
+
+ Spriteram (2) format (16 bit):
+
+ Word 0: 0xe000 - ? (Always 0x2000?)
+ 0x1000 - X flip
+ 0x0f00 - Width in tiles (0==16)
+ 0x00ff - X position offset
+ Word 1: 0xe000 - ? (Always 0x2000?)
+ 0x1000 - Y flip
+ 0x0f00 - Height in tiles (0==16)
+ 0x00ff - Y position offset
+ Word 2: 0xff00 - ? (Always 0?)
+ 0x00c0 - If set use tile index as pointer into tile index array, else use as tile index directly
+ 0x0080 - If set tile index array format is 12 bit tile, 4 bit colour
+ 0x0040 - If set tile index array is 16 bit tile, 0 bit colour
+ 0x003c - Hi-bits of tile index after array lookup
+ 0x0003 - Hi-bits of tile index, selects ROM or RAM for array
+ Word 3: 0xffff - Low-bits of tile index
+ */
+
+ y = mlc_spriteram[offs+2]&0x7ff;
+ x = mlc_spriteram[offs+3]&0x7ff;
+
+ if (x&0x400) x=-(0x400-(x&0x3ff));
+ if (y&0x400) y=-(0x400-(y&0x3ff));
+
+ fx = mlc_spriteram[offs+1]&0x8000;
+ fy = mlc_spriteram[offs+1]&0x4000;
+ color = mlc_spriteram[offs+1]&0xff;
+ rasterMode = (mlc_spriteram[offs+1]>>10)&0x1;
+ clipper = (mlc_spriteram[offs+1]>>8)&0x3;
+ indx = mlc_spriteram[offs+0]&0x3fff;
+ yscale = mlc_spriteram[offs+4]&0x3ff;
+ xscale = mlc_spriteram[offs+5]&0x3ff;
+ colorOffset = 0;
+
+ /* Clip windows - this mapping seems odd, but is correct for Skull Fang and StadHr96,
+ however there are space for 8 clipping windows, where is the high bit? (Or is it ~0x400?) */
+ clipper=((clipper&2)>>1)|((clipper&1)<<1); // Swap low two bits
+
+ user_clip.min_y=mlc_clip_ram[(clipper*4)+0];
+ user_clip.max_y=mlc_clip_ram[(clipper*4)+1];
+ user_clip.min_x=mlc_clip_ram[(clipper*4)+2];
+ user_clip.max_x=mlc_clip_ram[(clipper*4)+3];
+
+ if (user_clip.min_y < cliprect->min_y) user_clip.min_y=cliprect->min_y;
+ if (user_clip.max_y > cliprect->max_y) user_clip.max_y=cliprect->max_y;
+ if (user_clip.min_x < cliprect->min_x) user_clip.min_x=cliprect->min_x;
+ if (user_clip.max_x > cliprect->max_x) user_clip.max_x=cliprect->max_x;
+
+ /* Any colours out of range (for the bpp value) trigger 'shadow' mode */
+ if (color & (colour_mask+1))
+ trans=TRANSPARENCY_ALPHA;
+ else
+ trans=TRANSPARENCY_PEN;
+ color&=colour_mask;
+
+ /* If this bit is set, combine this block with the next one */
+ if (mlc_spriteram[offs+1]&0x1000) {
+ use8bppMode=1;
+ /* In 8bpp the palette base is stored in the next block */
+ if (offs-8>=0) {
+ color = (mlc_spriteram[offs+1-8]&0x7f);
+ indx2 = mlc_spriteram[offs+0-8]&0x3fff;
+ }
+ } else
+ use8bppMode=0;
+
+ /* Lookup tiles/size in sprite index ram OR in the lookup rom */
+ if (mlc_spriteram[offs+0]&0x4000) {
+ index_ptr8=rom + indx*8; /* Byte ptr */
+ h=(index_ptr8[1]>>0)&0xf;
+ w=(index_ptr8[3]>>0)&0xf;
+
+ if (!h) h=16;
+ if (!w) w=16;
+
+ sprite = (index_ptr8[7]<<8)|index_ptr8[6];
+ sprite |= (index_ptr8[4]&3)<<16;
+
+ if (use8bppMode) {
+ UINT8* index_ptr28=rom + indx2*8;
+ sprite2=(index_ptr28[7]<<8)|index_ptr28[6];
+ }
+ //unused byte 5
+ yoffs=index_ptr8[0]&0xff;
+ xoffs=index_ptr8[2]&0xff;
+
+ fy1=(index_ptr8[1]&0xf0)>>4;
+ fx1=(index_ptr8[3]&0xf0)>>4;
+
+ tileFormat=index_ptr8[4]&0x80;
+
+ if (index_ptr8[4]&0xc0)
+ blockIsTilemapIndex=1;
+ else
+ blockIsTilemapIndex=0;
+
+ useIndicesInRom=0;
+
+ } else {
+ indx&=0x1fff;
+ index_ptr=mlc_vram + indx*4;
+ h=(index_ptr[0]>>8)&0xf;
+ w=(index_ptr[1]>>8)&0xf;
+
+ if (!h) h=16;
+ if (!w) w=16;
+
+ if (use8bppMode) {
+ UINT32* index_ptr2=mlc_vram + ((indx2*4)&0x7fff);
+ sprite2=((index_ptr2[2]&0x3)<<16) | (index_ptr2[3]&0xffff);
+ }
+
+ sprite = ((index_ptr[2]&0x3)<<16) | (index_ptr[3]&0xffff);
+ if (index_ptr[2]&0xc0)
+ blockIsTilemapIndex=1;
+ else
+ blockIsTilemapIndex=0;
+
+ tileFormat=index_ptr[2]&0x80;
+
+ hibits=(index_ptr[2]&0x3c)<<10;
+ useIndicesInRom=index_ptr[2]&3;
+
+ yoffs=index_ptr[0]&0xff;
+ xoffs=index_ptr[1]&0xff;
+
+ fy1=(index_ptr[0]&0xf000)>>12;
+ fx1=(index_ptr[1]&0xf000)>>12;
+ }
+
+ if(fx1&1) fx^=0x8000;
+ if(fy1&1) fy^=0x4000;
+
+ if (fx) xmult=-1; else xmult=1;
+ if (fy) ymult=-1; else ymult=1;
+
+ ybase=y<<16;
+ if (fy)
+ ybase+=(yoffs-15) * (yscale<<8);
+ else
+ ybase-=yoffs * (yscale<<8);
+
+ yinc=(yscale<<8)*16;
+
+ if (fy) yinc=-yinc;
+
+ for (by=0; by<h; by++) {
+ int xbase=x<<16;
+ int xinc=(xscale<<8)*16;
+
+ if (fx)
+ xbase+=(xoffs-15) * (xscale<<8);
+ else
+ xbase-=xoffs * (xscale<<8);
+
+ if (fx) xinc=-xinc;
+
+ for (bx=0; bx<w; bx++) {
+ int tile=sprite;
+ int tile2=sprite2;
+
+ if (blockIsTilemapIndex) {
+ if (useIndicesInRom)
+ {
+ const UINT8* ptr=rawrom+(sprite*2);
+ tile=(*ptr) + ((*(ptr+1))<<8);
+
+ if (use8bppMode) {
+ const UINT8* ptr2=rawrom+(sprite2*2);
+ tile2=(*ptr2) + ((*(ptr2+1))<<8);
+ }
+ else
+ {
+ tile2=0;
+ }
+
+ if (tileFormat)
+ {
+ colorOffset=(tile&0xf000)>>12;
+ tile=(tile&0x0fff)|hibits;
+ tile2=(tile2&0x0fff)|hibits;
+ }
+ else
+ {
+ colorOffset=0;
+ tile=(tile&0xffff)|(hibits<<2);
+ tile2=(tile2&0xffff)|(hibits<<2);
+ }
+ }
+ else
+ {
+ const UINT32* ptr=mlc_vram + ((sprite)&0x7fff);
+ tile=(*ptr)&0xffff;
+
+ if (tileFormat)
+ {
+ colorOffset=(tile&0xf000)>>12;
+ tile=(tile&0x0fff)|hibits;
+ }
+ else
+ {
+ colorOffset=0;
+ tile=(tile&0xffff)|(hibits<<2);
+ }
+
+ tile2=0;
+ }
+ }
+
+ if (rasterMode)
+ rasterDirty=1;
+
+ mlc_drawgfxzoom(/*rasterMode ? temp_bitmap : */bitmap,machine->gfx[0],
+ tile,tile2,
+ color + colorOffset,fx,fy,xbase,ybase,
+ &user_clip,trans,0,
+ use8bppMode,(xscale<<8),(yscale<<8));
+
+ sprite++;
+ sprite2++;
+
+ xbase+=xinc;
+ }
+ ybase+=yinc;
+ }
+
+ if (lastRasterMode!=0 && rasterDirty)
+ {
+ // blitRaster(bitmap, rasterMode);
+// fillbitmap(temp_bitmap,0,cliprect);
+ rasterDirty=0;
+ }
+ lastRasterMode=rasterMode;
+
+ if (use8bppMode)
+ offs-=8;
+ }
+}
+
+VIDEO_EOF( mlc )
+{
+ /* Spriteram is definitely double buffered, as the vram lookup tables
+ are often updated a frame after spriteram is setup to point to a new
+ lookup table. Without buffering incorrect one frame glitches are seen
+ in several places, especially in Hoops.
+ */
+ memcpy(mlc_buffered_spriteram, spriteram32, 0x3000);
+}
+
+VIDEO_UPDATE( mlc )
+{
+// fillbitmap(temp_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect); /* Pen 0 fill colour confirmed from Skull Fang level 2 */
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/decocass.c b/src/mame/video/decocass.c
new file mode 100644
index 00000000000..6358610388f
--- /dev/null
+++ b/src/mame/video/decocass.c
@@ -0,0 +1,714 @@
+/***********************************************************************
+
+ DECO Cassette System video
+
+ ***********************************************************************/
+
+#include "driver.h"
+#include "machine/decocass.h"
+
+static INT32 watchdog_count;
+static INT32 watchdog_flip;
+static INT32 color_missiles;
+static INT32 color_center_bot;
+static INT32 mode_set;
+static INT32 back_h_shift;
+static INT32 back_vl_shift;
+static INT32 back_vr_shift;
+static INT32 part_h_shift;
+static INT32 part_v_shift;
+static INT32 center_h_shift_space;
+static INT32 center_v_shift;
+
+UINT8 *decocass_charram;
+UINT8 *decocass_fgvideoram;
+UINT8 *decocass_colorram;
+UINT8 *decocass_bgvideoram; /* shares bits D0-3 with tileram! */
+UINT8 *decocass_tileram;
+UINT8 *decocass_objectram;
+
+size_t decocass_fgvideoram_size;
+size_t decocass_colorram_size;
+size_t decocass_bgvideoram_size;
+size_t decocass_tileram_size;
+size_t decocass_objectram_size;
+
+static tilemap *fg_tilemap, *bg_tilemap_l, *bg_tilemap_r;
+
+static char *sprite_dirty;
+static char *char_dirty;
+static char *tile_dirty;
+static char object_dirty;
+
+static rectangle bg_tilemap_l_clip;
+static rectangle bg_tilemap_r_clip;
+
+static const UINT32 tile_offset[32*32] = {
+ 0x078,0x079,0x07a,0x07b,0x07c,0x07d,0x07e,0x07f,0x0ff,0x0fe,0x0fd,0x0fc,0x0fb,0x0fa,0x0f9,0x0f8,0x278,0x279,0x27a,0x27b,0x27c,0x27d,0x27e,0x27f,0x2ff,0x2fe,0x2fd,0x2fc,0x2fb,0x2fa,0x2f9,0x2f8,
+ 0x070,0x071,0x072,0x073,0x074,0x075,0x076,0x077,0x0f7,0x0f6,0x0f5,0x0f4,0x0f3,0x0f2,0x0f1,0x0f0,0x270,0x271,0x272,0x273,0x274,0x275,0x276,0x277,0x2f7,0x2f6,0x2f5,0x2f4,0x2f3,0x2f2,0x2f1,0x2f0,
+ 0x068,0x069,0x06a,0x06b,0x06c,0x06d,0x06e,0x06f,0x0ef,0x0ee,0x0ed,0x0ec,0x0eb,0x0ea,0x0e9,0x0e8,0x268,0x269,0x26a,0x26b,0x26c,0x26d,0x26e,0x26f,0x2ef,0x2ee,0x2ed,0x2ec,0x2eb,0x2ea,0x2e9,0x2e8,
+ 0x060,0x061,0x062,0x063,0x064,0x065,0x066,0x067,0x0e7,0x0e6,0x0e5,0x0e4,0x0e3,0x0e2,0x0e1,0x0e0,0x260,0x261,0x262,0x263,0x264,0x265,0x266,0x267,0x2e7,0x2e6,0x2e5,0x2e4,0x2e3,0x2e2,0x2e1,0x2e0,
+ 0x058,0x059,0x05a,0x05b,0x05c,0x05d,0x05e,0x05f,0x0df,0x0de,0x0dd,0x0dc,0x0db,0x0da,0x0d9,0x0d8,0x258,0x259,0x25a,0x25b,0x25c,0x25d,0x25e,0x25f,0x2df,0x2de,0x2dd,0x2dc,0x2db,0x2da,0x2d9,0x2d8,
+ 0x050,0x051,0x052,0x053,0x054,0x055,0x056,0x057,0x0d7,0x0d6,0x0d5,0x0d4,0x0d3,0x0d2,0x0d1,0x0d0,0x250,0x251,0x252,0x253,0x254,0x255,0x256,0x257,0x2d7,0x2d6,0x2d5,0x2d4,0x2d3,0x2d2,0x2d1,0x2d0,
+ 0x048,0x049,0x04a,0x04b,0x04c,0x04d,0x04e,0x04f,0x0cf,0x0ce,0x0cd,0x0cc,0x0cb,0x0ca,0x0c9,0x0c8,0x248,0x249,0x24a,0x24b,0x24c,0x24d,0x24e,0x24f,0x2cf,0x2ce,0x2cd,0x2cc,0x2cb,0x2ca,0x2c9,0x2c8,
+ 0x040,0x041,0x042,0x043,0x044,0x045,0x046,0x047,0x0c7,0x0c6,0x0c5,0x0c4,0x0c3,0x0c2,0x0c1,0x0c0,0x240,0x241,0x242,0x243,0x244,0x245,0x246,0x247,0x2c7,0x2c6,0x2c5,0x2c4,0x2c3,0x2c2,0x2c1,0x2c0,
+ 0x038,0x039,0x03a,0x03b,0x03c,0x03d,0x03e,0x03f,0x0bf,0x0be,0x0bd,0x0bc,0x0bb,0x0ba,0x0b9,0x0b8,0x238,0x239,0x23a,0x23b,0x23c,0x23d,0x23e,0x23f,0x2bf,0x2be,0x2bd,0x2bc,0x2bb,0x2ba,0x2b9,0x2b8,
+ 0x030,0x031,0x032,0x033,0x034,0x035,0x036,0x037,0x0b7,0x0b6,0x0b5,0x0b4,0x0b3,0x0b2,0x0b1,0x0b0,0x230,0x231,0x232,0x233,0x234,0x235,0x236,0x237,0x2b7,0x2b6,0x2b5,0x2b4,0x2b3,0x2b2,0x2b1,0x2b0,
+ 0x028,0x029,0x02a,0x02b,0x02c,0x02d,0x02e,0x02f,0x0af,0x0ae,0x0ad,0x0ac,0x0ab,0x0aa,0x0a9,0x0a8,0x228,0x229,0x22a,0x22b,0x22c,0x22d,0x22e,0x22f,0x2af,0x2ae,0x2ad,0x2ac,0x2ab,0x2aa,0x2a9,0x2a8,
+ 0x020,0x021,0x022,0x023,0x024,0x025,0x026,0x027,0x0a7,0x0a6,0x0a5,0x0a4,0x0a3,0x0a2,0x0a1,0x0a0,0x220,0x221,0x222,0x223,0x224,0x225,0x226,0x227,0x2a7,0x2a6,0x2a5,0x2a4,0x2a3,0x2a2,0x2a1,0x2a0,
+ 0x018,0x019,0x01a,0x01b,0x01c,0x01d,0x01e,0x01f,0x09f,0x09e,0x09d,0x09c,0x09b,0x09a,0x099,0x098,0x218,0x219,0x21a,0x21b,0x21c,0x21d,0x21e,0x21f,0x29f,0x29e,0x29d,0x29c,0x29b,0x29a,0x299,0x298,
+ 0x010,0x011,0x012,0x013,0x014,0x015,0x016,0x017,0x097,0x096,0x095,0x094,0x093,0x092,0x091,0x090,0x210,0x211,0x212,0x213,0x214,0x215,0x216,0x217,0x297,0x296,0x295,0x294,0x293,0x292,0x291,0x290,
+ 0x008,0x009,0x00a,0x00b,0x00c,0x00d,0x00e,0x00f,0x08f,0x08e,0x08d,0x08c,0x08b,0x08a,0x089,0x088,0x208,0x209,0x20a,0x20b,0x20c,0x20d,0x20e,0x20f,0x28f,0x28e,0x28d,0x28c,0x28b,0x28a,0x289,0x288,
+ 0x000,0x001,0x002,0x003,0x004,0x005,0x006,0x007,0x087,0x086,0x085,0x084,0x083,0x082,0x081,0x080,0x200,0x201,0x202,0x203,0x204,0x205,0x206,0x207,0x287,0x286,0x285,0x284,0x283,0x282,0x281,0x280,
+ 0x178,0x179,0x17a,0x17b,0x17c,0x17d,0x17e,0x17f,0x1ff,0x1fe,0x1fd,0x1fc,0x1fb,0x1fa,0x1f9,0x1f8,0x378,0x379,0x37a,0x37b,0x37c,0x37d,0x37e,0x37f,0x3ff,0x3fe,0x3fd,0x3fc,0x3fb,0x3fa,0x3f9,0x3f8,
+ 0x170,0x171,0x172,0x173,0x174,0x175,0x176,0x177,0x1f7,0x1f6,0x1f5,0x1f4,0x1f3,0x1f2,0x1f1,0x1f0,0x370,0x371,0x372,0x373,0x374,0x375,0x376,0x377,0x3f7,0x3f6,0x3f5,0x3f4,0x3f3,0x3f2,0x3f1,0x3f0,
+ 0x168,0x169,0x16a,0x16b,0x16c,0x16d,0x16e,0x16f,0x1ef,0x1ee,0x1ed,0x1ec,0x1eb,0x1ea,0x1e9,0x1e8,0x368,0x369,0x36a,0x36b,0x36c,0x36d,0x36e,0x36f,0x3ef,0x3ee,0x3ed,0x3ec,0x3eb,0x3ea,0x3e9,0x3e8,
+ 0x160,0x161,0x162,0x163,0x164,0x165,0x166,0x167,0x1e7,0x1e6,0x1e5,0x1e4,0x1e3,0x1e2,0x1e1,0x1e0,0x360,0x361,0x362,0x363,0x364,0x365,0x366,0x367,0x3e7,0x3e6,0x3e5,0x3e4,0x3e3,0x3e2,0x3e1,0x3e0,
+ 0x158,0x159,0x15a,0x15b,0x15c,0x15d,0x15e,0x15f,0x1df,0x1de,0x1dd,0x1dc,0x1db,0x1da,0x1d9,0x1d8,0x358,0x359,0x35a,0x35b,0x35c,0x35d,0x35e,0x35f,0x3df,0x3de,0x3dd,0x3dc,0x3db,0x3da,0x3d9,0x3d8,
+ 0x150,0x151,0x152,0x153,0x154,0x155,0x156,0x157,0x1d7,0x1d6,0x1d5,0x1d4,0x1d3,0x1d2,0x1d1,0x1d0,0x350,0x351,0x352,0x353,0x354,0x355,0x356,0x357,0x3d7,0x3d6,0x3d5,0x3d4,0x3d3,0x3d2,0x3d1,0x3d0,
+ 0x148,0x149,0x14a,0x14b,0x14c,0x14d,0x14e,0x14f,0x1cf,0x1ce,0x1cd,0x1cc,0x1cb,0x1ca,0x1c9,0x1c8,0x348,0x349,0x34a,0x34b,0x34c,0x34d,0x34e,0x34f,0x3cf,0x3ce,0x3cd,0x3cc,0x3cb,0x3ca,0x3c9,0x3c8,
+ 0x140,0x141,0x142,0x143,0x144,0x145,0x146,0x147,0x1c7,0x1c6,0x1c5,0x1c4,0x1c3,0x1c2,0x1c1,0x1c0,0x340,0x341,0x342,0x343,0x344,0x345,0x346,0x347,0x3c7,0x3c6,0x3c5,0x3c4,0x3c3,0x3c2,0x3c1,0x3c0,
+ 0x138,0x139,0x13a,0x13b,0x13c,0x13d,0x13e,0x13f,0x1bf,0x1be,0x1bd,0x1bc,0x1bb,0x1ba,0x1b9,0x1b8,0x338,0x339,0x33a,0x33b,0x33c,0x33d,0x33e,0x33f,0x3bf,0x3be,0x3bd,0x3bc,0x3bb,0x3ba,0x3b9,0x3b8,
+ 0x130,0x131,0x132,0x133,0x134,0x135,0x136,0x137,0x1b7,0x1b6,0x1b5,0x1b4,0x1b3,0x1b2,0x1b1,0x1b0,0x330,0x331,0x332,0x333,0x334,0x335,0x336,0x337,0x3b7,0x3b6,0x3b5,0x3b4,0x3b3,0x3b2,0x3b1,0x3b0,
+ 0x128,0x129,0x12a,0x12b,0x12c,0x12d,0x12e,0x12f,0x1af,0x1ae,0x1ad,0x1ac,0x1ab,0x1aa,0x1a9,0x1a8,0x328,0x329,0x32a,0x32b,0x32c,0x32d,0x32e,0x32f,0x3af,0x3ae,0x3ad,0x3ac,0x3ab,0x3aa,0x3a9,0x3a8,
+ 0x120,0x121,0x122,0x123,0x124,0x125,0x126,0x127,0x1a7,0x1a6,0x1a5,0x1a4,0x1a3,0x1a2,0x1a1,0x1a0,0x320,0x321,0x322,0x323,0x324,0x325,0x326,0x327,0x3a7,0x3a6,0x3a5,0x3a4,0x3a3,0x3a2,0x3a1,0x3a0,
+ 0x118,0x119,0x11a,0x11b,0x11c,0x11d,0x11e,0x11f,0x19f,0x19e,0x19d,0x19c,0x19b,0x19a,0x199,0x198,0x318,0x319,0x31a,0x31b,0x31c,0x31d,0x31e,0x31f,0x39f,0x39e,0x39d,0x39c,0x39b,0x39a,0x399,0x398,
+ 0x110,0x111,0x112,0x113,0x114,0x115,0x116,0x117,0x197,0x196,0x195,0x194,0x193,0x192,0x191,0x190,0x310,0x311,0x312,0x313,0x314,0x315,0x316,0x317,0x397,0x396,0x395,0x394,0x393,0x392,0x391,0x390,
+ 0x108,0x109,0x10a,0x10b,0x10c,0x10d,0x10e,0x10f,0x18f,0x18e,0x18d,0x18c,0x18b,0x18a,0x189,0x188,0x308,0x309,0x30a,0x30b,0x30c,0x30d,0x30e,0x30f,0x38f,0x38e,0x38d,0x38c,0x38b,0x38a,0x389,0x388,
+ 0x100,0x101,0x102,0x103,0x104,0x105,0x106,0x107,0x187,0x186,0x185,0x184,0x183,0x182,0x181,0x180,0x300,0x301,0x302,0x303,0x304,0x305,0x306,0x307,0x387,0x386,0x385,0x384,0x383,0x382,0x381,0x380
+};
+
+/********************************************
+ state saving setup
+ ********************************************/
+void decocass_video_state_save_init(void)
+{
+ state_save_register_global(watchdog_count);
+ state_save_register_global(watchdog_flip);
+ state_save_register_global(color_missiles);
+ state_save_register_global(color_center_bot);
+ state_save_register_global(mode_set);
+ state_save_register_global(back_h_shift);
+ state_save_register_global(back_vl_shift);
+ state_save_register_global(back_vr_shift);
+ state_save_register_global(part_h_shift);
+ state_save_register_global(part_v_shift);
+ state_save_register_global(center_h_shift_space);
+ state_save_register_global(center_v_shift);
+}
+
+/********************************************
+ tilemap callbacks
+ ********************************************/
+
+static TILEMAP_MAPPER( fgvideoram_scan_cols )
+{
+ /* logical (col,row) -> memory offset */
+ return (num_cols - 1 - col) * num_rows + row;
+}
+
+static TILEMAP_MAPPER( bgvideoram_scan_cols )
+{
+ /* logical (col,row) -> memory offset */
+ return tile_offset[col * num_rows + row];
+}
+
+static TILE_GET_INFO( get_bg_l_tile_info )
+{
+ int color = (color_center_bot >> 7) & 1;
+ SET_TILE_INFO(
+ 2,
+ (0x80 == (tile_index & 0x80)) ? 16 : decocass_bgvideoram[tile_index] >> 4,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg_r_tile_info )
+{
+ int color = (color_center_bot >> 7) & 1;
+ SET_TILE_INFO(
+ 2,
+ (0x00 == (tile_index & 0x80)) ? 16 : decocass_bgvideoram[tile_index] >> 4,
+ color,
+ TILE_FLIPY);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 code = decocass_fgvideoram[tile_index];
+ UINT8 attr = decocass_colorram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ 256 * (attr & 3) + code,
+ color_center_bot & 1,
+ 0);
+}
+
+/********************************************
+ big object
+ ********************************************/
+
+static void draw_object(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int sx, sy, color;
+
+ if (0 == (mode_set & 0x80)) /* part_h_enable off? */
+ return;
+
+ color = (color_center_bot >> 4) & 15;
+
+ sy = 192 - (part_v_shift & 0x7f);
+
+ if (part_h_shift & 0x80)
+ sx = (part_h_shift & 0x7f) + 1;
+ else
+ sx = 91 - (part_h_shift & 0x7f);
+
+ drawgfx(bitmap, machine->gfx[3], 0, color, 0, 0, sx + 64, sy, cliprect, TRANSPARENCY_PEN, 0);
+ drawgfx(bitmap, machine->gfx[3], 1, color, 0, 0, sx, sy, cliprect, TRANSPARENCY_PEN, 0);
+ drawgfx(bitmap, machine->gfx[3], 0, color, 0, 1, sx + 64, sy - 64, cliprect, TRANSPARENCY_PEN, 0);
+ drawgfx(bitmap, machine->gfx[3], 1, color, 0, 1, sx, sy - 64, cliprect, TRANSPARENCY_PEN, 0);
+}
+
+static void draw_center(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int sx, sy, x, y, color;
+
+ color = 0;
+ if (color_center_bot & 0x10)
+ color |= 4;
+ if (color_center_bot & 0x20)
+ color |= 2;
+ if (color_center_bot & 0x40)
+ color |= 1;
+ if (color_center_bot & 0x80)
+ color = (color & 4) + ((color << 1) & 2) + ((color >> 1) & 1);
+
+ sy = center_v_shift;
+ sx = (center_h_shift_space >> 2) & 0x3c;
+
+ for (y = 0; y < 4; y++)
+ if ((sy + y) >= cliprect->min_y && (sy + y) <= cliprect->max_y)
+ {
+ if (((sy + y) & color_center_bot & 3) == (sy & color_center_bot & 3))
+ for (x = 0; x < 256; x++)
+ if (0 != (x & 16) || 0 != (center_h_shift_space & 1))
+ *BITMAP_ADDR16(bitmap, sy + y, (sx + x) & 255) = machine->pens[color];
+ }
+}
+
+/********************************************
+ memory handlers
+ ********************************************/
+
+WRITE8_HANDLER( decocass_paletteram_w )
+{
+ /*
+ * RGB output is inverted and A4 is inverted too
+ * (ME/ input on 1st paletteram, inverter -> ME/ on 2nd)
+ */
+ offset = (offset & 31) ^ 16;
+ paletteram_BBGGGRRR_w( offset, ~data );
+}
+
+WRITE8_HANDLER( decocass_charram_w )
+{
+ if (data == decocass_charram[offset])
+ return;
+ decocass_charram[offset] = data;
+ /* dirty sprite */
+ sprite_dirty[(offset >> 5) & 255] = 1;
+ /* dirty char */
+ char_dirty[(offset >> 3) & 1023] = 1;
+}
+
+
+WRITE8_HANDLER( decocass_fgvideoram_w )
+{
+ decocass_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty( fg_tilemap, offset );
+}
+
+WRITE8_HANDLER( decocass_colorram_w )
+{
+ decocass_colorram[offset] = data;
+ tilemap_mark_tile_dirty( fg_tilemap, offset );
+}
+
+static void mark_bg_tile_dirty(offs_t offset)
+{
+ if (offset & 0x80)
+ tilemap_mark_tile_dirty( bg_tilemap_r, offset );
+ else
+ tilemap_mark_tile_dirty( bg_tilemap_l, offset );
+}
+
+WRITE8_HANDLER( decocass_tileram_w )
+{
+ if (data == decocass_tileram[offset])
+ return;
+ decocass_tileram[offset] = data;
+ /* dirty tile (64 bytes per tile) */
+ tile_dirty[(offset / 64) & 15] = 1;
+ /* first 1KB of tile RAM is shared with tilemap RAM */
+ if (offset < decocass_bgvideoram_size)
+ mark_bg_tile_dirty( offset );
+}
+
+WRITE8_HANDLER( decocass_objectram_w )
+{
+ if (data == decocass_objectram[offset])
+ return;
+ decocass_objectram[offset] = data;
+ /* dirty the object */
+ object_dirty = 1;
+}
+
+WRITE8_HANDLER( decocass_bgvideoram_w )
+{
+ if (data == decocass_bgvideoram[offset])
+ return;
+ decocass_bgvideoram[offset] = data;
+ mark_bg_tile_dirty( offset );
+}
+
+/* The watchdog is a 4bit counter counting down every frame */
+WRITE8_HANDLER( decocass_watchdog_count_w )
+{
+ LOG(1,("decocass_watchdog_count_w: $%02x\n", data));
+ watchdog_count = data & 0x0f;
+}
+
+WRITE8_HANDLER( decocass_watchdog_flip_w )
+{
+ LOG(1,("decocass_watchdog_flip_w: $%02x\n", data));
+ watchdog_flip = data;
+}
+
+WRITE8_HANDLER( decocass_color_missiles_w )
+{
+ LOG(1,("decocass_color_missiles_w: $%02x\n", data));
+ /* only bits D0-D2 and D4-D6 are connected to
+ * the color RAM demux:
+ * D0-D2 to the IC0 inputs
+ * D4-D6 to the IC1 inputs
+ */
+ color_missiles = data & 0x77;
+}
+
+/*
+ * D0 - ??
+ * D1 - ??
+ * D2 - ptn 1/2
+ * D3 - BKG ena
+ * D4 - center L on
+ * D5 - cross on
+ * D6 - tunnel
+ * D7 - part h enable
+ */
+WRITE8_HANDLER( decocass_mode_set_w )
+{
+ if (data == mode_set)
+ return;
+ LOG(1,("decocass_mode_set_w: $%02x (%s%s%s%s%s%s%s%s)\n", data,
+ (data & 0x01) ? "D0?" : "",
+ (data & 0x02) ? " D1?" : "",
+ (data & 0x04) ? " ptn1/2" : "",
+ (data & 0x08) ? " bkg_ena" : "",
+ (data & 0x10) ? " center_l_on" : "",
+ (data & 0x20) ? " cross_on" : "",
+ (data & 0x40) ? " tunnel" : "",
+ (data & 0x80) ? " part_h_enable" : ""));
+
+ mode_set = data;
+}
+
+WRITE8_HANDLER( decocass_color_center_bot_w )
+{
+ if (data == color_center_bot)
+ return;
+ LOG(1,("decocass_color_center_bot_w: $%02x (color:%d, center_bot:%d)\n", data, data&3, data>>4));
+ /*
+ * D7 CL3/4 (swap 2+4)
+ * D6 CL1
+ * D5 CL2
+ * D4 CL4
+ * D3 nc
+ * D2 nc
+ * D1 CLD4
+ * D0 CLD3
+ */
+
+ if ((color_center_bot ^ data) & 0x80)
+ {
+ tilemap_mark_all_tiles_dirty(bg_tilemap_r);
+ tilemap_mark_all_tiles_dirty(bg_tilemap_l);
+ }
+ if ((color_center_bot ^ data) & 0x01)
+ tilemap_mark_all_tiles_dirty(fg_tilemap);
+ color_center_bot = data;
+}
+
+WRITE8_HANDLER( decocass_back_h_shift_w )
+{
+ if (data == back_h_shift)
+ return;
+ LOG(1,("decocass_back_h_shift_w: $%02x\n", data));
+ back_h_shift = data;
+}
+
+WRITE8_HANDLER( decocass_back_vl_shift_w )
+{
+ if (data == back_vl_shift)
+ return;
+ LOG(1,("decocass_back_vl_shift_w: $%02x\n", data));
+ back_vl_shift = data;
+}
+
+WRITE8_HANDLER( decocass_back_vr_shift_w )
+{
+ if (data == back_vr_shift)
+ return;
+ LOG(1,("decocass_back_vr_shift_w: $%02x\n", data));
+ back_vr_shift = data;
+}
+
+WRITE8_HANDLER( decocass_part_h_shift_w )
+{
+ if (data == part_v_shift )
+ return;
+ LOG(1,("decocass_part_h_shift_w: $%02x\n", data));
+ part_h_shift = data;
+}
+
+WRITE8_HANDLER( decocass_part_v_shift_w )
+{
+ if (data == part_v_shift )
+ return;
+ LOG(1,("decocass_part_v_shift_w: $%02x\n", data));
+ part_v_shift = data;
+}
+
+WRITE8_HANDLER( decocass_center_h_shift_space_w )
+{
+ if (data == center_h_shift_space)
+ return;
+ LOG(1,("decocass_center_h_shift_space_w: $%02x\n", data));
+ center_h_shift_space = data;
+}
+
+WRITE8_HANDLER( decocass_center_v_shift_w )
+{
+ LOG(1,("decocass_center_v_shift_w: $%02x\n", data));
+ center_v_shift = data;
+}
+
+/********************************************
+ memory handlers
+ ********************************************/
+
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect, int color,
+ int sprite_y_adjust, int sprite_y_adjust_flip_screen,
+ UINT8 *sprite_ram, int interleave)
+{
+ int i,offs;
+
+ /* Draw the sprites */
+ for (i = 0, offs = 0;i < 8; i++, offs += 4*interleave)
+ {
+ int sx,sy,flipx,flipy;
+
+ if (!(sprite_ram[offs + 0] & 0x01))
+ continue;
+
+ sx = 240 - sprite_ram[offs + 3*interleave];
+ sy = 240 - sprite_ram[offs + 2*interleave];
+
+ flipx = sprite_ram[offs + 0] & 0x04;
+ flipy = sprite_ram[offs + 0] & 0x02;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy + sprite_y_adjust_flip_screen;
+
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ sy -= sprite_y_adjust;
+
+ drawgfx(bitmap,machine->gfx[1],
+ sprite_ram[offs + interleave],
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ sy += (flip_screen ? -256 : 256);
+
+ // Wrap around
+ drawgfx(bitmap,machine->gfx[1],
+ sprite_ram[offs + interleave],
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+
+static void draw_missiles(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect,
+ int missile_y_adjust, int missile_y_adjust_flip_screen,
+ UINT8 *missile_ram, int interleave)
+{
+ int i,offs,x;
+
+ /* Draw the missiles (16 of them) seemingly with alternating colors
+ * from the E302 latch (color_missiles) */
+ for (i = 0, offs = 0; i < 8; i++, offs += 4*interleave)
+ {
+ int sx,sy;
+
+ sy = 255 - missile_ram[offs + 0*interleave];
+ sx = 255 - missile_ram[offs + 2*interleave];
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy + missile_y_adjust_flip_screen;
+ }
+ sy -= missile_y_adjust;
+ if (sy >= cliprect->min_y && sy <= cliprect->max_y)
+ for (x = 0; x < 4; x++)
+ {
+ if (sx >= cliprect->min_x && sx <= cliprect->max_x)
+ *BITMAP_ADDR16(bitmap, sy, sx) = machine->pens[(color_missiles >> 4) & 7];
+ sx++;
+ }
+
+ sy = 255 - missile_ram[offs + 1*interleave];
+ sx = 255 - missile_ram[offs + 3*interleave];
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy + missile_y_adjust_flip_screen;
+ }
+ sy -= missile_y_adjust;
+ if (sy >= cliprect->min_y && sy <= cliprect->max_y)
+ for (x = 0; x < 4; x++)
+ {
+ if (sx >= cliprect->min_x && sx <= cliprect->max_x)
+ *BITMAP_ADDR16(bitmap, sy, sx) = machine->pens[color_missiles & 7];
+ sx++;
+ }
+ }
+}
+
+
+static void decode_modified(running_machine* machine, UINT8 *sprite_ram, int interleave)
+{
+ int i,offs;
+
+ /* decode dirty characters */
+ for (offs = decocass_fgvideoram_size - 1;offs >= 0;offs--)
+ {
+ int code;
+
+ code = decocass_fgvideoram[offs] + 256 * (decocass_colorram[offs] & 3);
+
+ switch (char_dirty[code])
+ {
+ case 1:
+ decodechar(machine->gfx[0],code,decocass_charram,machine->drv->gfxdecodeinfo[0].gfxlayout);
+ char_dirty[code] = 2;
+ /* fall through */
+ case 2:
+ tilemap_mark_tile_dirty(fg_tilemap, offs);
+ break;
+ default:
+ break;
+ }
+ }
+
+ for (i = 0; i < 1024; i++)
+ {
+ if (char_dirty[i] == 2)
+ char_dirty[i] = 0;
+ }
+
+ /* decode dirty sprites */
+ for (i = 0, offs = 0;i < 8; i++, offs += 4*interleave)
+ {
+ int code;
+
+ code = sprite_ram[offs + interleave];
+ if (sprite_dirty[code])
+ {
+ sprite_dirty[code] = 0;
+
+ decodechar(machine->gfx[1],code,decocass_charram,machine->drv->gfxdecodeinfo[1].gfxlayout);
+ }
+ }
+
+ /* decode dirty tiles */
+ for (offs = 0; offs < decocass_bgvideoram_size; offs++)
+ {
+ int code = (decocass_tileram[offs] >> 4) & 15;
+
+ if (tile_dirty[code])
+ {
+ tile_dirty[code] = 0;
+
+ decodechar(machine->gfx[2],code,decocass_tileram,machine->drv->gfxdecodeinfo[2].gfxlayout);
+
+ /* mark all visible tiles dirty */
+ for (i = offs; i < decocass_bgvideoram_size; i++)
+ if (code == ((decocass_tileram[i] >> 4) & 15))
+ mark_bg_tile_dirty(i);
+ }
+ }
+
+ /* decode object if it is dirty */
+ if (object_dirty)
+ {
+ decodechar(machine->gfx[3], 0, decocass_objectram, machine->drv->gfxdecodeinfo[3].gfxlayout);
+ decodechar(machine->gfx[3], 1, decocass_objectram, machine->drv->gfxdecodeinfo[3].gfxlayout);
+ object_dirty = 0;
+ }
+}
+
+VIDEO_START( decocass )
+{
+ sprite_dirty = auto_malloc(256);
+ char_dirty = auto_malloc(1024);
+ tile_dirty = auto_malloc(16);
+
+ bg_tilemap_l = tilemap_create( get_bg_l_tile_info, bgvideoram_scan_cols, TILEMAP_TYPE_PEN, 16, 16, 32, 32 );
+ bg_tilemap_r = tilemap_create( get_bg_r_tile_info, bgvideoram_scan_cols, TILEMAP_TYPE_PEN, 16, 16, 32, 32 );
+ fg_tilemap = tilemap_create( get_fg_tile_info, fgvideoram_scan_cols, TILEMAP_TYPE_PEN, 8, 8, 32, 32 );
+
+ tilemap_set_transparent_pen( bg_tilemap_l, 0 );
+ tilemap_set_transparent_pen( bg_tilemap_r, 0 );
+ tilemap_set_transparent_pen( fg_tilemap, 0 );
+
+ bg_tilemap_l_clip = machine->screen[0].visarea;
+ bg_tilemap_l_clip.max_y = machine->screen[0].height / 2;
+
+ bg_tilemap_r_clip = machine->screen[0].visarea;
+ bg_tilemap_r_clip.min_y = machine->screen[0].height / 2;
+
+ /* background videroam bits D0-D3 are shared with the tileram */
+ decocass_bgvideoram = decocass_tileram;
+ decocass_bgvideoram_size = 0x0400; /* d000-d3ff */
+}
+
+VIDEO_UPDATE( decocass )
+{
+ int scrollx, scrolly_l, scrolly_r;
+ rectangle clip;
+
+ if (0xc0 != (input_port_2_r(0) & 0xc0)) /* coin slots assert an NMI */
+ cpunum_set_input_line(0, INPUT_LINE_NMI, ASSERT_LINE);
+
+ if (0 == (watchdog_flip & 0x04))
+ watchdog_reset_w (0,0);
+ else if (watchdog_count-- > 0)
+ watchdog_reset_w (0,0);
+
+#if TAPE_UI_DISPLAY
+ if (tape_timer)
+ {
+ attotime tape_time = decocass_adjust_tape_time(tape_time0);
+ popmessage("%c%c [%05.1fs] %c%c",
+ (tape_dir < 0 && tape_speed) ? '<' : ' ',
+ (tape_dir < 0) ? '<' : ' ',
+ attotime_to_double(tape_time),
+ (tape_dir > 0) ? '>' : ' ',
+ (tape_dir > 0 && tape_speed) ? '>' : ' ');
+ }
+#endif
+#ifdef MAME_DEBUG
+ {
+ static int showmsg;
+ if (input_code_pressed_once(KEYCODE_I))
+ showmsg ^= 1;
+ if (showmsg)
+ popmessage("mode:$%02x cm:$%02x ccb:$%02x h:$%02x vl:$%02x vr:$%02x ph:$%02x pv:$%02x ch:$%02x cv:$%02x",
+ mode_set,
+ color_missiles,
+ color_center_bot,
+ back_h_shift,
+ back_vl_shift,
+ back_vr_shift,
+ part_h_shift,
+ part_v_shift,
+ center_h_shift_space,
+ center_v_shift);
+ }
+#endif
+
+ fillbitmap( bitmap, machine->pens[0], cliprect );
+
+ decode_modified(machine, decocass_fgvideoram, 0x20 );
+
+ scrolly_l = back_vl_shift;
+ scrolly_r = 256 - back_vr_shift;
+
+ scrollx = 256 - back_h_shift;
+ if (0 == (mode_set & 0x02))
+ scrollx += 256;
+
+#if 0
+/* this is wrong */
+ if (0 != back_h_shift && 0 == ((mode_set ^ (mode_set >> 1)) & 1))
+ scrollx += 256;
+#endif
+
+ if (0 == (mode_set & 0x04))
+ scrolly_r += 256;
+ else
+ scrolly_l += 256;
+
+ tilemap_set_scrollx( bg_tilemap_l, 0, scrollx );
+ tilemap_set_scrolly( bg_tilemap_l, 0, scrolly_l );
+
+ tilemap_set_scrollx( bg_tilemap_r, 0, scrollx );
+ tilemap_set_scrolly( bg_tilemap_r, 0, scrolly_r );
+
+ if (mode_set & 0x08) /* bkg_ena on ? */
+ {
+ clip = bg_tilemap_l_clip;
+ sect_rect(&clip,cliprect);
+ tilemap_draw(bitmap,&clip, bg_tilemap_l, TILEMAP_DRAW_OPAQUE, 0);
+
+ clip = bg_tilemap_r_clip;
+ sect_rect(&clip,cliprect);
+ tilemap_draw(bitmap,&clip, bg_tilemap_r, TILEMAP_DRAW_OPAQUE, 0);
+ }
+
+ if (mode_set & 0x20)
+ {
+ draw_object(machine,bitmap,cliprect);
+ draw_center(machine,bitmap,cliprect);
+ }
+ else
+ {
+ draw_object(machine,bitmap,cliprect);
+ draw_center(machine,bitmap,cliprect);
+ if (mode_set & 0x08) /* bkg_ena on ? */
+ {
+ clip = bg_tilemap_l_clip;
+ sect_rect(&clip,cliprect);
+ tilemap_draw(bitmap,&clip, bg_tilemap_l, 0, 0);
+
+ clip = bg_tilemap_r_clip;
+ sect_rect(&clip,cliprect);
+ tilemap_draw(bitmap,&clip, bg_tilemap_r, 0, 0);
+ }
+ }
+ tilemap_draw(bitmap,cliprect, fg_tilemap, 0, 0);
+ draw_sprites(machine,bitmap,cliprect, (color_center_bot >> 1) & 1, 0, 0, decocass_fgvideoram, 0x20);
+ draw_missiles(machine,bitmap,cliprect, 1, 0, decocass_colorram, 0x20);
+ return 0;
+}
+
diff --git a/src/mame/video/deniam.c b/src/mame/video/deniam.c
new file mode 100644
index 00000000000..28225ed5212
--- /dev/null
+++ b/src/mame/video/deniam.c
@@ -0,0 +1,401 @@
+#include "driver.h"
+
+
+UINT16 *deniam_videoram,*deniam_textram;
+static int display_enable;
+static int bg_scrollx_offs,bg_scrolly_offs,fg_scrollx_offs,fg_scrolly_offs;
+static int bg_scrollx_reg,bg_scrolly_reg,bg_page_reg;
+static int fg_scrollx_reg,fg_scrolly_reg,fg_page_reg;
+static int bg_page[4],fg_page[4];
+
+static tilemap *bg_tilemap,*fg_tilemap,*tx_tilemap;
+
+
+
+DRIVER_INIT( logicpro )
+{
+ bg_scrollx_reg = 0x00a4/2;
+ bg_scrolly_reg = 0x00a8/2;
+ bg_page_reg = 0x00ac/2;
+ fg_scrollx_reg = 0x00a2/2;
+ fg_scrolly_reg = 0x00a6/2;
+ fg_page_reg = 0x00aa/2;
+
+ bg_scrollx_offs = 0x00d;
+ bg_scrolly_offs = 0x000;
+ fg_scrollx_offs = 0x009;
+ fg_scrolly_offs = 0x000;
+}
+DRIVER_INIT( karianx )
+{
+ bg_scrollx_reg = 0x00a4/2;
+ bg_scrolly_reg = 0x00a8/2;
+ bg_page_reg = 0x00ac/2;
+ fg_scrollx_reg = 0x00a2/2;
+ fg_scrolly_reg = 0x00a6/2;
+ fg_page_reg = 0x00aa/2;
+
+ bg_scrollx_offs = 0x10d;
+ bg_scrolly_offs = 0x080;
+ fg_scrollx_offs = 0x109;
+ fg_scrolly_offs = 0x080;
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( scan_pages )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x3f) + ((row & 0x1f) << 6) + ((col & 0x40) << 5) + ((row & 0x20) << 7);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int page = tile_index >> 11;
+ UINT16 attr = deniam_videoram[bg_page[page] * 0x0800 + (tile_index & 0x7ff)];
+ SET_TILE_INFO(
+ 0,
+ attr,
+ (attr & 0x1fc0) >> 6,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int page = tile_index >> 11;
+ UINT16 attr = deniam_videoram[fg_page[page] * 0x0800 + (tile_index & 0x7ff)];
+ SET_TILE_INFO(
+ 0,
+ attr,
+ (attr & 0x1fc0) >> 6,
+ 0);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ UINT16 attr = deniam_textram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ attr & 0xf1ff,
+ (attr & 0x0e00) >> 9,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( deniam )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,scan_pages, TILEMAP_TYPE_PEN, 8,8,128,64);
+ fg_tilemap = tilemap_create(get_fg_tile_info,scan_pages, TILEMAP_TYPE_PEN,8,8,128,64);
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8, 64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_transparent_pen(tx_tilemap,0);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( deniam_videoram_w )
+{
+ int page,i;
+ COMBINE_DATA(&deniam_videoram[offset]);
+
+ page = offset >> 11;
+ for (i = 0;i < 4;i++)
+ {
+ if (bg_page[i] == page)
+ tilemap_mark_tile_dirty(bg_tilemap,i * 0x800 + (offset & 0x7ff));
+ if (fg_page[i] == page)
+ tilemap_mark_tile_dirty(fg_tilemap,i * 0x800 + (offset & 0x7ff));
+ }
+}
+
+
+WRITE16_HANDLER( deniam_textram_w )
+{
+ COMBINE_DATA(&deniam_textram[offset]);
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+
+WRITE16_HANDLER( deniam_palette_w )
+{
+ int r,g,b;
+
+ data = COMBINE_DATA(&paletteram16[offset]);
+
+ r = ((data << 1) & 0x1e) | ((data >> 12) & 0x01);
+ g = ((data >> 3) & 0x1e) | ((data >> 13) & 0x01);
+ b = ((data >> 7) & 0x1e) | ((data >> 14) & 0x01);
+ palette_set_color_rgb(Machine,offset,pal5bit(r),pal5bit(g),pal5bit(b));
+}
+
+
+static UINT16 coinctrl;
+
+READ16_HANDLER( deniam_coinctrl_r )
+{
+ return coinctrl;
+}
+
+WRITE16_HANDLER( deniam_coinctrl_w )
+{
+ COMBINE_DATA(&coinctrl);
+
+ /* bit 0 is coin counter */
+ coin_counter_w(0,coinctrl & 0x01);
+
+ /* bit 6 is display enable (0 freezes screen) */
+ display_enable = coinctrl & 0x20;
+
+ /* other bits unknown (unused?) */
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+/*
+ * Sprite Format
+ * ------------------
+ *
+ * Word | Bit(s) | Use
+ * -----+-fedcba9876543210-+----------------
+ * 0 | --------xxxxxxxx | display y start
+ * 0 | xxxxxxxx-------- | display y end
+ * 2 | -------xxxxxxxxx | x position
+ * 2 | ------x--------- | unknown (used in logicpr2, maybe just a bug?)
+ * 2 | xxxxxx---------- | unused?
+ * 4 | ---------xxxxxxx | width
+ * 4 | --------x------- | is this flip y like in System 16?
+ * 4 | -------x-------- | flip x
+ * 4 | xxxxxxx--------- | unused?
+ * 6 | xxxxxxxxxxxxxxxx | ROM address low bits
+ * 8 | ----------xxxxxx | color
+ * 8 | --------xx------ | priority
+ * 8 | ---xxxxx-------- | ROM address high bits
+ * 8 | xxx------------- | unused? (extra address bits for larger ROMs?)
+ * a | ---------------- | zoomx like in System 16?
+ * c | ---------------- | zoomy like in System 16?
+ * e | ---------------- |
+ */
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size/2-8;offs >= 0;offs -= 8)
+ {
+ int sx,starty,endy,x,y,start,color,width,flipx,primask;
+ UINT8 *rom = memory_region(REGION_GFX2);
+
+
+ sx = (spriteram16[offs+1] & 0x01ff) + 16*8 - 1;
+ if (sx >= 512) sx -= 512;
+ starty = spriteram16[offs+0] & 0xff;
+ endy = spriteram16[offs+0] >> 8;
+
+ width = spriteram16[offs+2] & 0x007f;
+ flipx = spriteram16[offs+2] & 0x0100;
+ if (flipx) sx++;
+
+ color = 0x40 + (spriteram16[offs+4] & 0x3f);
+
+ primask = 8;
+ switch (spriteram16[offs+4] & 0xc0)
+ {
+ case 0x00: primask |= 4|2|1; break; /* below everything */
+ case 0x40: primask |= 4|2; break; /* below fg and tx */
+ case 0x80: primask |= 4; break; /* below tx */
+ case 0xc0: break; /* above everything */
+ }
+
+
+ start = spriteram16[offs+3] + ((spriteram16[offs+4] & 0x1f00) << 8);
+ rom += 2*start;
+
+ for (y = starty+1;y <= endy;y++)
+ {
+ int drawing = 0;
+ int i=0;
+
+ rom += 2*width; /* note that the first line is skipped */
+ x = 0;
+ while (i < 512) /* safety check */
+ {
+ if (flipx)
+ {
+ if ((rom[i] & 0x0f) == 0x0f)
+ {
+ if (!drawing) drawing = 1;
+ else break;
+ }
+ else
+ {
+ if (rom[i] & 0x0f)
+ {
+ if (sx+x >= cliprect->min_x && sx+x <= cliprect->max_x &&
+ y >= cliprect->min_y && y <= cliprect->max_y)
+ {
+ if ((*BITMAP_ADDR8(priority_bitmap, y, sx+x) & primask) == 0)
+ *BITMAP_ADDR16(bitmap, y, sx+x) = machine->pens[color*16+(rom[i]&0x0f)];
+ *BITMAP_ADDR8(priority_bitmap, y, sx+x) = 8;
+ }
+ }
+ x++;
+ }
+
+ if ((rom[i] & 0xf0) == 0xf0)
+ {
+ if (!drawing) drawing = 1;
+ else break;
+ }
+ else
+ {
+ if (rom[i] & 0xf0)
+ {
+ if (sx+x >= cliprect->min_x && sx+x <= cliprect->max_x &&
+ y >= cliprect->min_y && y <= cliprect->max_y)
+ {
+ if ((*BITMAP_ADDR8(priority_bitmap, y, sx+x) & primask) == 0)
+ *BITMAP_ADDR16(bitmap, y, sx+x) = machine->pens[color*16+(rom[i]>>4)];
+ *BITMAP_ADDR8(priority_bitmap, y, sx+x) = 8;
+ }
+ }
+ x++;
+ }
+
+ i--;
+ }
+ else
+ {
+ if ((rom[i] & 0xf0) == 0xf0)
+ {
+ if (!drawing) drawing = 1;
+ else break;
+ }
+ else
+ {
+ if (rom[i] & 0xf0)
+ {
+ if (sx+x >= cliprect->min_x && sx+x <= cliprect->max_x &&
+ y >= cliprect->min_y && y <= cliprect->max_y)
+ {
+ if ((*BITMAP_ADDR8(priority_bitmap, y, sx+x) & primask) == 0)
+ *BITMAP_ADDR16(bitmap, y, sx+x) = machine->pens[color*16+(rom[i]>>4)];
+ *BITMAP_ADDR8(priority_bitmap, y, sx+x) = 8;
+ }
+ }
+ x++;
+ }
+
+ if ((rom[i] & 0x0f) == 0x0f)
+ {
+ if (!drawing) drawing = 1;
+ else break;
+ }
+ else
+ {
+ if (rom[i] & 0x0f)
+ {
+ if (sx+x >= cliprect->min_x && sx+x <= cliprect->max_x &&
+ y >= cliprect->min_y && y <= cliprect->max_y)
+ {
+ if ((*BITMAP_ADDR8(priority_bitmap, y, sx+x) & primask) == 0)
+ *BITMAP_ADDR16(bitmap, y, sx+x) = machine->pens[color*16+(rom[i]&0x0f)];
+ *BITMAP_ADDR8(priority_bitmap, y, sx+x) = 8;
+ }
+ }
+ x++;
+ }
+
+ i++;
+ }
+ }
+ }
+ }
+}
+
+static void set_bg_page(int page,int value)
+{
+ int tile_index;
+
+ if (bg_page[page] != value)
+ {
+ bg_page[page] = value;
+ for (tile_index = page * 0x800;tile_index < (page+1)*0x800;tile_index++)
+ tilemap_mark_tile_dirty(bg_tilemap,tile_index);
+ }
+}
+
+static void set_fg_page(int page,int value)
+{
+ int tile_index;
+
+ if (fg_page[page] != value)
+ {
+ fg_page[page] = value;
+ for (tile_index = page * 0x800;tile_index < (page+1)*0x800;tile_index++)
+ tilemap_mark_tile_dirty(fg_tilemap,tile_index);
+ }
+}
+
+VIDEO_UPDATE( deniam )
+{
+ int bg_scrollx,bg_scrolly,fg_scrollx,fg_scrolly;
+ int page;
+
+
+ if (!display_enable) return 0; /* don't update (freeze display) */
+
+ bg_scrollx = deniam_textram[bg_scrollx_reg] - bg_scrollx_offs;
+ bg_scrolly = (deniam_textram[bg_scrolly_reg] & 0xff) - bg_scrolly_offs;
+ page = deniam_textram[bg_page_reg];
+ set_bg_page(3,(page >>12) & 0x0f);
+ set_bg_page(2,(page >> 8) & 0x0f);
+ set_bg_page(1,(page >> 4) & 0x0f);
+ set_bg_page(0,(page >> 0) & 0x0f);
+
+ fg_scrollx = deniam_textram[fg_scrollx_reg] - fg_scrollx_offs;
+ fg_scrolly = (deniam_textram[fg_scrolly_reg] & 0xff) - fg_scrolly_offs;
+ page = deniam_textram[fg_page_reg];
+ set_fg_page(3,(page >>12) & 0x0f);
+ set_fg_page(2,(page >> 8) & 0x0f);
+ set_fg_page(1,(page >> 4) & 0x0f);
+ set_fg_page(0,(page >> 0) & 0x0f);
+
+ tilemap_set_scrollx(bg_tilemap,0,bg_scrollx & 0x1ff);
+ tilemap_set_scrolly(bg_tilemap,0,bg_scrolly & 0x0ff);
+ tilemap_set_scrollx(fg_tilemap,0,fg_scrollx & 0x1ff);
+ tilemap_set_scrolly(fg_tilemap,0,fg_scrolly & 0x0ff);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,1);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,2);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,4);
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/destroyr.c b/src/mame/video/destroyr.c
new file mode 100644
index 00000000000..5d67fe1596b
--- /dev/null
+++ b/src/mame/video/destroyr.c
@@ -0,0 +1,90 @@
+/***************************************************************************
+
+Atari Destroyer video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+
+int destroyr_wavemod;
+int destroyr_cursor;
+
+UINT8* destroyr_major_obj_ram;
+UINT8* destroyr_minor_obj_ram;
+UINT8* destroyr_alpha_num_ram;
+
+
+VIDEO_UPDATE( destroyr )
+{
+ int i;
+ int j;
+
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ /* draw major objects */
+
+ for (i = 0; i < 16; i++)
+ {
+ int attr = destroyr_major_obj_ram[2 * i + 0] ^ 0xff;
+ int horz = destroyr_major_obj_ram[2 * i + 1];
+
+ int num = attr & 3;
+ int scan = attr & 4;
+ int flipx = attr & 8;
+
+ if (scan == 0)
+ {
+ if (horz >= 192)
+ horz -= 256;
+ }
+ else
+ {
+ if (horz < 192)
+ continue;
+ }
+
+ drawgfx(bitmap, machine->gfx[2], num, 0, flipx, 0,
+ horz, 16 * i, cliprect, TRANSPARENCY_PEN, 0);
+ }
+
+ /* draw alpha numerics */
+
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 32; j++)
+ {
+ int num = destroyr_alpha_num_ram[32 * i + j];
+
+ drawgfx(bitmap, machine->gfx[0], num, 0, 0, 0,
+ 8 * j, 8 * i, cliprect, TRANSPARENCY_PEN, 0);
+ }
+ }
+
+ /* draw minor objects */
+
+ for (i = 0; i < 2; i++)
+ {
+ int horz = 256 - destroyr_minor_obj_ram[i + 2];
+ int vert = 256 - destroyr_minor_obj_ram[i + 4];
+
+ drawgfx(bitmap, machine->gfx[1], destroyr_minor_obj_ram[i + 0], 0, 0, 0,
+ horz, vert, cliprect, TRANSPARENCY_PEN, 0);
+ }
+
+ /* draw waves */
+
+ for (i = 0; i < 4; i++)
+ {
+ drawgfx(bitmap, machine->gfx[3], destroyr_wavemod ? 1 : 0, 0, 0, 0,
+ 64 * i, 0x4e, cliprect, TRANSPARENCY_PEN, 0);
+ }
+
+ /* draw cursor */
+
+ for (i = 0; i < 256; i++)
+ {
+ if (i & 4)
+ *BITMAP_ADDR16(bitmap, destroyr_cursor ^ 0xff, i) = machine->pens[7];
+ }
+ return 0;
+}
diff --git a/src/mame/video/dietgo.c b/src/mame/video/dietgo.c
new file mode 100644
index 00000000000..daf564ba41f
--- /dev/null
+++ b/src/mame/video/dietgo.c
@@ -0,0 +1,93 @@
+#include "driver.h"
+#include "deco16ic.h"
+
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ sprite = spriteram16[offs+1];
+ if (!sprite) continue;
+
+ y = spriteram16[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ x = spriteram16[offs+2];
+ colour = (x >>9) & 0x1f;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+ y = 240 - y;
+ x = 304 - x;
+
+ if (x>320) continue;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen)
+ {
+ y=240-y;
+ x=304-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ multi--;
+ }
+ }
+}
+
+static int dietgo_bank_callback(const int bank)
+{
+ return ((bank>>4)&0x7) * 0x1000;
+}
+
+VIDEO_START(dietgo)
+{
+ deco16_1_video_init();
+
+ deco16_set_tilemap_bank_callback(0, dietgo_bank_callback);
+ deco16_set_tilemap_bank_callback(1, dietgo_bank_callback);
+}
+
+VIDEO_UPDATE(dietgo)
+{
+ flip_screen_set( deco16_pf12_control[0]&0x80 );
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+
+ fillbitmap(bitmap,machine->pens[256],cliprect); /* not verified */
+
+ deco16_tilemap_2_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/digdug.c b/src/mame/video/digdug.c
new file mode 100644
index 00000000000..ca9654a6ada
--- /dev/null
+++ b/src/mame/video/digdug.c
@@ -0,0 +1,322 @@
+#include "driver.h"
+#include "includes/galaga.h"
+
+
+UINT8 *digdug_videoram,*digdug_objram, *digdug_posram, *digdug_flpram;
+
+static tilemap *bg_tilemap,*tx_tilemap;
+
+
+static INT32 bg_select, tx_color_mode, bg_disable, bg_color_bank;
+
+static colortable *digdug_colortable;
+
+
+/***************************************************************************
+
+ Convert the color PROMs.
+
+ digdug has one 32x8 palette PROM and two 256x4 color lookup table PROMs
+ (one for characters, one for sprites).
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+
+PALETTE_INIT( digdug )
+{
+ int i;
+
+ digdug_colortable = colortable_alloc(machine, 32);
+
+ for (i = 0;i < 32;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ colortable_palette_set_color(digdug_colortable,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* characters - direct mapping */
+ for (i = 0; i < 16; i++)
+ {
+ colortable_entry_set_value(digdug_colortable, i*2+0, 0);
+ colortable_entry_set_value(digdug_colortable, i*2+1, i);
+ }
+
+ /* sprites */
+ for (i = 0;i < 0x100;i++)
+ colortable_entry_set_value(digdug_colortable, 16*2+i, (*color_prom++ & 0x0f) + 0x10);
+
+ /* bg_select */
+ for (i = 0;i < 0x100;i++)
+ colortable_entry_set_value(digdug_colortable, 16*2+256+i, *color_prom++ & 0x0f);
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/* convert from 32x32 to 36x28 */
+static TILEMAP_MAPPER( tilemap_scan )
+{
+ int offs;
+
+ row += 2;
+ col -= 2;
+ if (col & 0x20)
+ offs = row + ((col & 0x1f) << 5);
+ else
+ offs = col + (row << 5);
+
+ return offs;
+}
+
+
+static TILE_GET_INFO( bg_get_tile_info )
+{
+ UINT8 *rom = memory_region(REGION_GFX4);
+ int code = rom[tile_index | (bg_select << 10)];
+ /* when the background is "disabled", it is actually still drawn, but using
+ a color code that makes all pixels black. There are pullups setting the
+ code to 0xf, but also solder pads that optionally connect the lines with
+ tilemap RAM, therefore allowing to pick some bits of the color code from
+ the top 4 bits of alpha code. This feature is not used by Dig Dug. */
+ int color = bg_disable ? 0xf : (code >> 4);
+ SET_TILE_INFO(
+ 2,
+ code,
+ color | bg_color_bank,
+ 0);
+}
+
+static TILE_GET_INFO( tx_get_tile_info )
+{
+ UINT8 code = digdug_videoram[tile_index];
+ int color;
+
+ /* the hardware has two ways to pick the color, either straight from the
+ bottom 4 bits of the character code, or from the top 4 bits through a
+ formula. The former method isnot used by Dig Dug and seems kind of
+ useless (I don't know what use they were thinking of when they added
+ it), anyway here it is reproduced faithfully. */
+ if (tx_color_mode)
+ color = code & 0x0f;
+ else
+ color = ((code >> 4) & 0x0e) | ((code >> 3) & 2);
+
+ /* the hardware has two character sets, one normal and one x-flipped. When
+ screen is flipped, character y flip is done by the hardware inverting the
+ timing signals, while x flip is done by selecting the 2nd character set.
+ We reproduce this here, but since the tilemap system automatically flips
+ characters when screen is flipped, we have to flip them back. */
+ SET_TILE_INFO(
+ 0,
+ (code & 0x7f) | (flip_screen ? 0x80 : 0),
+ color,
+ flip_screen ? TILE_FLIPX : 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( digdug )
+{
+ bg_tilemap = tilemap_create(bg_get_tile_info,tilemap_scan,TILEMAP_TYPE_PEN, 8,8,36,28);
+ tx_tilemap = tilemap_create(tx_get_tile_info,tilemap_scan,TILEMAP_TYPE_PEN,8,8,36,28);
+
+ tilemap_set_transparent_pen(tx_tilemap, 0);
+
+ spriteram = digdug_objram + 0x380;
+ spriteram_2 = digdug_posram + 0x380;
+ spriteram_3 = digdug_flpram + 0x380;
+
+ state_save_register_global(bg_select);
+ state_save_register_global(tx_color_mode);
+ state_save_register_global(bg_disable);
+ state_save_register_global(bg_color_bank);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ8_HANDLER( digdug_videoram_r )
+{
+ return digdug_videoram[offset];
+}
+
+WRITE8_HANDLER( digdug_videoram_w )
+{
+ digdug_videoram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( digdug_PORT_w )
+{
+ switch (offset)
+ {
+ case 0: /* select background picture */
+ case 1:
+ {
+ int shift = offset;
+ int mask = 1 << shift;
+
+ if ((bg_select & mask) != ((data & 1) << shift))
+ {
+ bg_select = (bg_select & ~mask) | ((data & 1) << shift);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+ }
+ break;
+
+ case 2: /* select alpha layer color mode (see tx_get_tile_info) */
+ if (tx_color_mode != (data & 1))
+ {
+ tx_color_mode = data & 1;
+ tilemap_mark_all_tiles_dirty(tx_tilemap);
+ }
+ break;
+
+ case 3: /* "disable" background (see bg_get_tile_info) */
+ if (bg_disable != (data & 1))
+ {
+ bg_disable = data & 1;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+ break;
+
+ case 4: /* background color bank */
+ case 5:
+ {
+ int shift = offset;
+ int mask = 1 << shift;
+
+ if ((bg_color_bank & mask) != ((data & 1) << shift))
+ {
+ bg_color_bank = (bg_color_bank & ~mask) | ((data & 1) << shift);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+ }
+ break;
+
+ case 6: /* n.c. */
+ break;
+
+ case 7: /* FLIP */
+ flip_screen_set(data & 1);
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static rectangle spritevisiblearea =
+{
+ 2*8, 34*8-1,
+ 0*8, 28*8-1
+};
+
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = 0;offs < 0x80;offs += 2)
+ {
+ static int gfx_offs[2][2] =
+ {
+ { 0, 1 },
+ { 2, 3 }
+ };
+ int sprite = spriteram[offs];
+ int color = spriteram[offs+1] & 0x3f;
+ int sx = spriteram_2[offs+1] - 40+1;
+ int sy = 256 - spriteram_2[offs] + 1; // sprites are buffered and delayed by one scanline
+ int flipx = (spriteram_3[offs] & 0x01);
+ int flipy = (spriteram_3[offs] & 0x02) >> 1;
+ int size = (sprite & 0x80) >> 7;
+ int x,y;
+
+ if (size)
+ sprite = (sprite & 0xc0) | ((sprite & ~0xc0) << 2);
+
+ if (flip_screen)
+ {
+ flipx ^= 1;
+ flipy ^= 1;
+ }
+
+ sy -= 16 * size;
+ sy = (sy & 0xff) - 32; // fix wraparound
+
+ for (y = 0;y <= size;y++)
+ {
+ for (x = 0;x <= size;x++)
+ {
+ UINT32 transmask = colortable_get_transpen_mask(digdug_colortable, machine->gfx[1], color, 0x1f);
+ drawgfx(bitmap,machine->gfx[1],
+ sprite + gfx_offs[y ^ (size * flipy)][x ^ (size * flipx)],
+ color,
+ flipx,flipy,
+ ((sx + 16*x) & 0xff), sy + 16*y,
+ &spritevisiblearea,TRANSPARENCY_PENS,transmask);
+ /* wraparound */
+ drawgfx(bitmap,machine->gfx[1],
+ sprite + gfx_offs[y ^ (size * flipy)][x ^ (size * flipx)],
+ color,
+ flipx,flipy,
+ ((sx + 16*x) & 0xff) + 0x100, sy + 16*y,
+ &spritevisiblearea,TRANSPARENCY_PENS,transmask);
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( digdug )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/diverboy.c b/src/mame/video/diverboy.c
new file mode 100644
index 00000000000..f24bbbef543
--- /dev/null
+++ b/src/mame/video/diverboy.c
@@ -0,0 +1,53 @@
+/* Diver Boy - Video Hardware */
+
+#include "driver.h"
+
+UINT16 *diverboy_spriteram;
+size_t diverboy_spriteram_size;
+
+
+VIDEO_START(diverboy)
+{
+}
+
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ UINT16 *source = diverboy_spriteram;
+ UINT16 *finish = source + (diverboy_spriteram_size/2);
+
+ while (source < finish)
+ {
+ INT16 xpos,ypos,number,colr,bank,flash;
+
+ ypos = source[4];
+ xpos = source[0];
+ colr = (source[1]& 0x00f0) >> 4;
+ number = source[3];
+ flash = source[1] & 0x1000;
+
+ colr |= ((source[1] & 0x000c) << 2);
+
+ ypos = 0x100 - ypos;
+
+ bank = (source[1]&0x0002) >> 1;
+
+ if (!flash || (cpu_getcurrentframe() & 1))
+ {
+ drawgfx(bitmap,machine->gfx[bank],
+ number,
+ colr,
+ 0,0,
+ xpos,ypos,
+ cliprect,(source[1] & 0x0008) ? TRANSPARENCY_NONE : TRANSPARENCY_PEN,0);
+ }
+
+ source+=8;
+ }
+}
+
+VIDEO_UPDATE(diverboy)
+{
+// fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/djboy.c b/src/mame/video/djboy.c
new file mode 100644
index 00000000000..ca51dec8513
--- /dev/null
+++ b/src/mame/video/djboy.c
@@ -0,0 +1,83 @@
+/**
+ * @file video/djboy.c
+ *
+ * video hardware for DJ Boy
+ */
+#include "driver.h"
+#include "kan_pand.h"
+
+static UINT8 djboy_videoreg, djboy_scrollx, djboy_scrolly;
+static tilemap *background;
+
+void djboy_set_videoreg( UINT8 data )
+{
+ djboy_videoreg = data;
+}
+
+WRITE8_HANDLER( djboy_scrollx_w )
+{
+ djboy_scrollx = data;
+}
+
+WRITE8_HANDLER( djboy_scrolly_w )
+{
+ djboy_scrolly = data;
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 attr = videoram[tile_index + 0x800];
+ int code = videoram[tile_index] + (attr&0xf)*256;
+ int color = attr>>4;
+ if( color&8 )
+ {
+ code |= 0x1000;
+ }
+ SET_TILE_INFO(1, code, color, 0); /* no flip */
+}
+
+WRITE8_HANDLER( djboy_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty( background, offset & 0x7ff);
+}
+
+VIDEO_START( djboy )
+{
+ background = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pandora_start(0,0,0);
+}
+
+WRITE8_HANDLER( djboy_paletteram_w )
+{
+ int val;
+
+ paletteram[offset] = data;
+ offset &= ~1;
+ val = (paletteram[offset]<<8) | paletteram[offset+1];
+
+ palette_set_color_rgb(Machine,offset/2,pal4bit(val >> 8),pal4bit(val >> 4),pal4bit(val >> 0));
+}
+
+VIDEO_UPDATE( djboy )
+{
+ /**
+ * xx------ msb x
+ * --x----- msb y
+ * ---x---- flipscreen?
+ * ----xxxx ROM bank
+ */
+ int scroll;
+ scroll = djboy_scrollx | ((djboy_videoreg&0xc0)<<2);
+ tilemap_set_scrollx( background, 0, scroll-0x391 );
+ scroll = djboy_scrolly | ((djboy_videoreg&0x20)<<3);
+ tilemap_set_scrolly( background, 0, scroll );
+ tilemap_draw( bitmap, cliprect,background,0,0 );
+ pandora_update(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_EOF( djboy )
+{
+ pandora_eof(machine);
+}
diff --git a/src/mame/video/djmain.c b/src/mame/video/djmain.c
new file mode 100644
index 00000000000..93fd8bf08b3
--- /dev/null
+++ b/src/mame/video/djmain.c
@@ -0,0 +1,194 @@
+/*
+ * Beatmania DJ Main Board (GX753)
+ * emulate video hardware
+ */
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+#define NUM_SPRITES (0x800 / 16)
+#define NUM_LAYERS 2
+
+UINT32 *djmain_obj_ram;
+
+
+static void draw_sprites(running_machine* machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs, pri_code;
+ int sortedlist[NUM_SPRITES];
+
+ machine->gfx[0]->color_base = K055555_read_register(K55_PALBASE_SUB2) * 0x400;
+
+ for (offs = 0; offs < NUM_SPRITES; offs++)
+ sortedlist[offs] = -1;
+
+ /* prebuild a sorted table */
+ for (offs = 0; offs < NUM_SPRITES * 4; offs += 4)
+ {
+ if (djmain_obj_ram[offs] & 0x00008000)
+ {
+ if (djmain_obj_ram[offs] & 0x80000000)
+ continue;
+
+ pri_code = djmain_obj_ram[offs] & (NUM_SPRITES - 1);
+ sortedlist[pri_code] = offs;
+ }
+ }
+
+ for (pri_code = NUM_SPRITES - 1; pri_code >= 0; pri_code--)
+ {
+ static int xoffset[8] = { 0, 1, 4, 5, 16, 17, 20, 21 };
+ static int yoffset[8] = { 0, 2, 8, 10, 32, 34, 40, 42 };
+ static int sizetab[4] = { 1, 2, 4, 8 };
+ int x, y;
+ int ox, oy;
+ int flipx, flipy;
+ int xscale, yscale;
+ int code;
+ int color;
+ int size;
+
+ offs = sortedlist[pri_code];
+ if (offs == -1) continue;
+
+ code = djmain_obj_ram[offs] >> 16;
+ flipx = (djmain_obj_ram[offs] >> 10) & 1;
+ flipy = (djmain_obj_ram[offs] >> 11) & 1;
+ size = sizetab[(djmain_obj_ram[offs] >> 8) & 3];
+
+ ox = (INT16)(djmain_obj_ram[offs + 1] & 0xffff);
+ oy = (INT16)(djmain_obj_ram[offs + 1] >> 16);
+
+ xscale = djmain_obj_ram[offs + 2] >> 16;
+ yscale = djmain_obj_ram[offs + 2] & 0xffff;
+
+ if (!xscale || !yscale)
+ continue;
+
+ xscale = (0x40 << 16) / xscale;
+ yscale = (0x40 << 16) / yscale;
+ ox -= (size * xscale) >> 13;
+ oy -= (size * yscale) >> 13;
+
+ color = (djmain_obj_ram[offs + 3] >> 16) & 15;
+
+ for (x = 0; x < size; x++)
+ for (y = 0; y < size; y++)
+ {
+ int c = code;
+
+ if (flipx)
+ c += xoffset[size - x - 1];
+ else
+ c += xoffset[x];
+
+ if (flipy)
+ c += yoffset[size - y - 1];
+ else
+ c += yoffset[y];
+
+ if (xscale != 0x10000 || yscale != 0x10000)
+ {
+ int sx = ox + ((x * xscale + (1 << 11)) >> 12);
+ int sy = oy + ((y * yscale + (1 << 11)) >> 12);
+ int zw = ox + (((x + 1) * xscale + (1 << 11)) >> 12) - sx;
+ int zh = oy + (((y + 1) * yscale + (1 << 11)) >> 12) - sy;
+
+ drawgfxzoom(bitmap,
+ machine->gfx[0],
+ c,
+ color,
+ flipx,
+ flipy,
+ sx,
+ sy,
+ cliprect,
+ TRANSPARENCY_PEN,
+ 0,
+ (zw << 16) / 16,
+ (zh << 16) / 16);
+ }
+ else
+ {
+ int sx = ox + (x << 4);
+ int sy = oy + (y << 4);
+
+ drawgfx(bitmap,
+ machine->gfx[0],
+ c,
+ color,
+ flipx,
+ flipy,
+ sx,
+ sy,
+ cliprect,
+ TRANSPARENCY_PEN,
+ 0);
+ }
+ }
+ }
+}
+
+
+static void game_tile_callback(int layer, int *code, int *color, int *flags)
+{
+}
+
+VIDEO_START( djmain )
+{
+ static int scrolld[NUM_LAYERS][4][2] = {
+ {{ 0, 0}, {0, 0}, {0, 0}, {0, 0}},
+ {{ 0, 0}, {0, 0}, {0, 0}, {0, 0}}
+ };
+
+ K056832_vh_start(machine, REGION_GFX2, K056832_BPP_4dj, 1, scrolld, game_tile_callback, 1);
+ K055555_vh_start();
+
+ K056832_set_LayerOffset(0, -92, -27);
+ // K056832_set_LayerOffset(1, -87, -27);
+ K056832_set_LayerOffset(1, -88, -27);
+}
+
+VIDEO_UPDATE( djmain )
+{
+ int enables = K055555_read_register(K55_INPUT_ENABLES);
+ int pri[NUM_LAYERS + 1];
+ int order[NUM_LAYERS + 1];
+ int i, j;
+
+ for (i = 0; i < NUM_LAYERS; i++)
+ pri[i] = K055555_read_register(K55_PRIINP_0 + i * 3);
+ pri[i] = K055555_read_register(K55_PRIINP_10);
+
+ for (i = 0; i < NUM_LAYERS + 1; i++)
+ order[i] = i;
+
+ for (i = 0; i < NUM_LAYERS; i++)
+ for (j = i + 1; j < NUM_LAYERS + 1; j++)
+ if (pri[order[i]] > pri[order[j]])
+ {
+ int temp = order[i];
+
+ order[i] = order[j];
+ order[j] = temp;
+ }
+
+ fillbitmap(bitmap, machine->remapped_colortable[0], cliprect);
+
+ for (i = 0; i < NUM_LAYERS + 1; i++)
+ {
+ int layer = order[i];
+
+ if (layer == NUM_LAYERS)
+ {
+ if (enables & K55_INP_SUB2)
+ draw_sprites(machine, bitmap, cliprect);
+ }
+ else
+ {
+ if (enables & (K55_INP_VRAM_A << layer))
+ K056832_tilemap_draw_dj(machine, bitmap, cliprect, layer, 0, 1 << i);
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/dkong.c b/src/mame/video/dkong.c
new file mode 100644
index 00000000000..7d2bd13e02f
--- /dev/null
+++ b/src/mame/video/dkong.c
@@ -0,0 +1,891 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/resnet.h"
+#include "includes/dkong.h"
+
+#define RADARSCP_BCK_COL_OFFSET 256
+#define RADARSCP_GRID_COL_OFFSET (RADARSCP_BCK_COL_OFFSET + 256)
+#define RADARSCP_STAR_COL (RADARSCP_GRID_COL_OFFSET + 8)
+
+#define HW_TRS01 1
+#define HW_TRS02 2
+#define HW_DK4 4
+
+static tilemap *bg_tilemap;
+
+static mame_bitmap *bg_bits;
+static const UINT8 *color_codes;
+static emu_timer *scanline_timer;
+
+static const double cd4049_vl = 1.5/5.0;
+static const double cd4049_vh = 3.5/5.0;
+static const double cd4049_al = 0.01;
+
+static UINT8 sig30Hz = 0;
+static UINT8 grid_sig = 0;
+static UINT8 rflip_sig = 0;
+static UINT8 star_ff = 0;
+
+static int blue_level = 0;
+static double cd4049_a, cd4049_b;
+
+/* Save state relevant */
+
+static UINT8 gfx_bank, palette_bank;
+static UINT8 grid_on;
+static UINT8 snd02_enable;
+static UINT8 sig_ansn;
+static UINT16 grid_col;
+static UINT8 vid_hw;
+static UINT8 sprite_bank;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Donkey Kong has two 256x4 palette PROMs and one 256x4 PROM which contains
+ the color codes to use for characters on a per row/column basis (groups of
+ of 4 characters in the same column - actually row, since the display is
+ rotated)
+ The palette PROMs are connected to the RGB output this way:
+
+ 5V -- 470 ohm resistor -- inverter -- RED
+ bit 3 -- 220 ohm resistor -- inverter -- RED
+ -- 470 ohm resistor -- inverter -- RED
+ -- 1 kohm resistor -- inverter -- RED
+
+ 5V -- 470 ohm resistor -- inverter -- GREEN
+ bit 0 -- 220 ohm resistor -- inverter -- GREEN
+ bit 3 -- 470 ohm resistor -- inverter -- GREEN
+ -- 1 kohm resistor -- inverter -- GREEN
+ 5V -- 680 ohm resistor -- inverter -- BLUE
+ -- 220 ohm resistor -- inverter -- BLUE
+ bit 0 -- 470 ohm resistor -- inverter -- BLUE
+
+ After the mixing stage there is a darlington circuit with approx. linear
+ transfer function for red and green. Minimum output voltage is 0.9 Volt.
+ Blue is transferred through just one transistor. Here we have to
+ substract 0.7 Volts. This signal (0..5V) is inverted by a amplifier
+ circuit with an emitter lowpass RC. The R is a variable resistor.
+ So any calculations done here may be void in reality ...
+***************************************************************************/
+
+/*
+ dkong color interface:
+
+ All outputs are open-collector and pullup resistors are connected to 5V.
+ Red and Green outputs are routed through a complimentary darlington
+ whereas blue is routed through a 1:1 stage leading to a 0.7V cutoff.
+*/
+
+static const res_net_decode_info dkong_decode_info =
+{
+ 2, // there may be two proms needed to construct color
+ 0, // start at 0
+ 255, // end at 255
+ // R, G, B, R, G, B
+ { 256, 256, 0, 0, 0, 0}, // offsets
+ { 1, -2, 0, 0, 2, 0}, // shifts
+ {0x07,0x04,0x03,0x00,0x03,0x00} // masks
+};
+
+static const res_net_info dkong_net_info =
+{
+ RES_NET_VCC_5V | RES_NET_VBIAS_5V | RES_NET_VIN_MB7052 | RES_NET_MONITOR_SANYO_EZV20,
+ {
+ { RES_NET_AMP_DARLINGTON, 470, 0, 3, { 1000, 470, 220 } },
+ { RES_NET_AMP_DARLINGTON, 470, 0, 3, { 1000, 470, 220 } },
+ { RES_NET_AMP_EMITTER, 680, 0, 2, { 470, 220, 0 } } // dkong
+ }
+};
+
+static const res_net_info dkong_net_bck_info =
+{
+ RES_NET_VCC_5V | RES_NET_VBIAS_5V | RES_NET_VIN_MB7052 | RES_NET_MONITOR_SANYO_EZV20,
+ {
+ { RES_NET_AMP_DARLINGTON, 470, 0, 0, { 0 } },
+ { RES_NET_AMP_DARLINGTON, 470, 0, 0, { 0 } },
+ { RES_NET_AMP_EMITTER, 680, 0, 0, { 0 } }
+ }
+};
+
+static const res_net_decode_info dkong3_decode_info =
+{
+ 1, // one prom needed to contruct color
+ 0, // start at 0
+ 255, // end at 255
+ // R, G, B
+ { 0, 0, 512 }, // offsets
+ { 4, 0, 0 }, // shifts
+ {0x0F,0x0F,0x0F } // masks
+};
+
+static const res_net_info dkong3_net_info =
+{
+ RES_NET_VCC_5V | RES_NET_VBIAS_5V | RES_NET_VIN_MB7052 | RES_NET_MONITOR_SANYO_EZV20,
+ {
+ { RES_NET_AMP_DARLINGTON, 470, 0, 4, { 2200, 1000, 470, 220 } },
+ { RES_NET_AMP_DARLINGTON, 470, 0, 4, { 2200, 1000, 470, 220 } },
+ { RES_NET_AMP_DARLINGTON, 470, 0, 4, { 2200, 1000, 470, 220 } }
+ }
+};
+
+/*
+ radarscp interface
+
+ All outputs are open-collector. The pullup resistors are connected to
+ inverters (TTL). All outputs are routed through a complimentary
+ darlington. The blue channel has a pulldown resistor (R8, 0M15) as well.
+*/
+
+static const res_net_info radarscp_net_info =
+{
+ RES_NET_VCC_5V | RES_NET_VBIAS_TTL | RES_NET_VIN_MB7052 | RES_NET_MONITOR_SANYO_EZV20,
+ {
+ { RES_NET_AMP_DARLINGTON, 470, 0, 3, { 1000, 470, 220 } },
+ { RES_NET_AMP_DARLINGTON, 470, 0, 3, { 1000, 470, 220 } },
+ { RES_NET_AMP_DARLINGTON, 680, 150000, 2, { 470, 220, 0 } } // radarscp
+ }
+};
+
+/*
+ radarsc1 interface
+
+ All outputs are open-collector. They are followed by inverters which
+ drive the resistor network. All outputs are routed through a complimentary
+ darlington.
+*/
+
+static const res_net_info radarsc1_net_info =
+{
+ RES_NET_VCC_5V | RES_NET_VBIAS_5V | RES_NET_VIN_TTL_OUT | RES_NET_MONITOR_SANYO_EZV20,
+ {
+ { RES_NET_AMP_DARLINGTON, 0, 0, 4, { 39000, 20000, 10000, 4990 } },
+ { RES_NET_AMP_DARLINGTON, 0, 0, 4, { 39000, 20000, 10000, 4990 } },
+ { RES_NET_AMP_DARLINGTON, 0, 0, 4, { 39000, 20000, 10000, 4990 } }
+ }
+};
+
+/* Radarscp star color */
+
+static const res_net_info radarscp_stars_net_info =
+{
+ RES_NET_VCC_5V | RES_NET_VBIAS_5V | RES_NET_VIN_TTL_OUT | RES_NET_MONITOR_SANYO_EZV20,
+ {
+ { RES_NET_AMP_DARLINGTON, 4700, 470, 0, { 0 } },
+ { RES_NET_AMP_DARLINGTON, 1, 0, 0, { 0 } }, // dummy
+ { RES_NET_AMP_DARLINGTON, 1, 0, 0, { 0 } }, // dummy
+ }
+};
+
+/* Dummy struct to generate background palette entries */
+
+static const res_net_info radarscp_bck_net_info =
+{
+ RES_NET_VCC_5V | RES_NET_VBIAS_5V | RES_NET_VIN_VCC | RES_NET_MONITOR_SANYO_EZV20,
+ {
+ { RES_NET_AMP_DARLINGTON, 1, 0, 0, { 0 } }, // bias/gnd exist in schematics, but not readable
+ { RES_NET_AMP_DARLINGTON, 1, 0, 0, { 0 } }, // bias/gnd exist in schematics, but not readable
+ { RES_NET_AMP_DARLINGTON, 0, 0, 8, { 128,64,32,16,8,4,2,1 } }, // dummy
+ }
+};
+
+/* Dummy struct to generate grid palette entries */
+
+static const res_net_info radarscp_grid_net_info =
+{
+ RES_NET_VCC_5V | RES_NET_VBIAS_5V | RES_NET_VIN_TTL_OUT | RES_NET_MONITOR_SANYO_EZV20,
+ {
+ { RES_NET_AMP_DARLINGTON, 0, 0, 1, { 1 } }, // dummy
+ { RES_NET_AMP_DARLINGTON, 0, 0, 1, { 1 } }, // dummy
+ { RES_NET_AMP_DARLINGTON, 0, 0, 1, { 1 } }, // dummy
+ }
+};
+
+/***************************************************************************
+
+ PALETTE_INIT
+
+***************************************************************************/
+
+PALETTE_INIT( dkong )
+{
+ rgb_t *rgb;
+ int i;
+
+ rgb = compute_res_net_all(color_prom, &dkong_decode_info, &dkong_net_info);
+ palette_set_colors(machine, 0, rgb, 256);
+
+ /* Now treat tri-state black background generation */
+
+ for (i=0;i<256;i++)
+ if ( (i & 0x03) == 0x00 ) // NOR => CS=1 => Tristate => real black
+ {
+ int r,g,b;
+ r = compute_res_net( 1, 0, &dkong_net_bck_info );
+ g = compute_res_net( 1, 1, &dkong_net_bck_info );
+ b = compute_res_net( 1, 2, &dkong_net_bck_info );
+ palette_set_color_rgb(machine,i,r,g,b);
+ }
+
+ palette_normalize_range(machine->palette, 0, 255, 0, 255);
+
+ color_prom += 512;
+ /* color_prom now points to the beginning of the character color codes */
+ color_codes = color_prom; /* we'll need it later */
+ free(rgb);
+}
+
+PALETTE_INIT( radarscp )
+{
+ int i;
+ int r,g,b;
+
+ for (i = 0;i < 256;i++)
+ {
+
+ /* red component */
+ r = compute_res_net( (color_prom[256]>>1) & 0x07, 0, &radarscp_net_info );
+ /* green component */
+ g = compute_res_net( ((color_prom[256]<<2) & 0x04) | ((color_prom[0]>>2) & 0x03), 1, &radarscp_net_info );
+ /* blue component */
+ b = compute_res_net( (color_prom[0]>>0) & 0x03, 2, &radarscp_net_info );
+
+ palette_set_color_rgb(machine,i,r,g,b);
+ color_prom++;
+ }
+
+ /* Now treat tri-state black background generation */
+
+ for (i=0;i<256;i++)
+ if ( (i & 0x03) == 0x00 ) // NOR => CS=1 => Tristate => real black
+ {
+ r = compute_res_net( 1, 0, &dkong_net_bck_info );
+ g = compute_res_net( 1, 1, &dkong_net_bck_info );
+ b = compute_res_net( 1, 2, &dkong_net_bck_info );
+ palette_set_color_rgb(machine,i,r,g,b);
+ }
+
+ /* Star color */
+ r = compute_res_net( 1, 0, &radarscp_stars_net_info );
+ g = compute_res_net( 0, 1, &radarscp_stars_net_info );
+ b = compute_res_net( 0, 2, &radarscp_stars_net_info );
+ palette_set_color_rgb(machine,RADARSCP_STAR_COL,r,g,b);
+
+ /* Oscillating background */
+ for (i = 0;i < 256;i++)
+ {
+ r = compute_res_net( 0, 0, &radarscp_bck_net_info );
+ g = compute_res_net( 0, 1, &radarscp_bck_net_info );
+ b = compute_res_net( i, 2, &radarscp_bck_net_info );
+
+ palette_set_color_rgb(machine,RADARSCP_BCK_COL_OFFSET + i,r,g,b);
+ }
+
+ /* Grid */
+ for (i = 0;i < 8;i++)
+ {
+ r = compute_res_net( i & 1, 0, &radarscp_grid_net_info );
+ g = compute_res_net( (i>>1) & 1, 1, &radarscp_grid_net_info );
+ b = compute_res_net( (i>>2) & 1, 2, &radarscp_grid_net_info );
+
+ palette_set_color_rgb(machine,RADARSCP_GRID_COL_OFFSET + i,r,g,b);
+ }
+ palette_normalize_range(machine->palette, 0, RADARSCP_GRID_COL_OFFSET+7, 0, 255);
+
+
+
+ color_prom += 256;
+ /* color_prom now points to the beginning of the character color codes */
+ color_codes = color_prom; /* we'll need it later */
+}
+
+PALETTE_INIT( radarsc1 )
+{
+ int i;
+ int r,g,b;
+
+ printf("Here\n");
+ for (i = 0;i < 256;i++)
+ {
+
+ /* red component */
+ r = compute_res_net( color_prom[512], 0, &radarsc1_net_info );
+ /* green component */
+ g = compute_res_net( color_prom[256], 1, &radarsc1_net_info );
+ /* blue component */
+ b = compute_res_net( color_prom[0], 2, &radarsc1_net_info );
+
+ palette_set_color_rgb(machine,i,r,g,b);
+ color_prom++;
+ }
+
+ /* Now treat tri-state black background generation */
+
+ for (i=0;i<256;i++)
+ if ( (i & 0x03) == 0x00 ) // NOR => CS=1 => Tristate => real black
+ {
+ r = compute_res_net( 0, 0, &radarsc1_net_info );
+ g = compute_res_net( 0, 1, &radarsc1_net_info );
+ b = compute_res_net( 0, 2, &radarsc1_net_info );
+ palette_set_color_rgb(machine,i,r,g,b);
+ }
+
+ /* Star color */
+ r = compute_res_net( 1, 0, &radarscp_stars_net_info );
+ g = compute_res_net( 0, 1, &radarscp_stars_net_info );
+ b = compute_res_net( 0, 2, &radarscp_stars_net_info );
+ palette_set_color_rgb(machine,RADARSCP_STAR_COL,r,g,b);
+
+ /* Oscillating background */
+ for (i = 0;i < 256;i++)
+ {
+ r = compute_res_net( 0, 0, &radarscp_bck_net_info );
+ g = compute_res_net( 0, 1, &radarscp_bck_net_info );
+ b = compute_res_net( i, 2, &radarscp_bck_net_info );
+
+ palette_set_color_rgb(machine,RADARSCP_BCK_COL_OFFSET + i,r,g,b);
+ }
+
+ /* Grid */
+ for (i = 0;i < 8;i++)
+ {
+ r = compute_res_net( i & 1, 0, &radarscp_grid_net_info );
+ g = compute_res_net( (i>>1) & 1, 1, &radarscp_grid_net_info );
+ b = compute_res_net( (i>>2) & 1, 2, &radarscp_grid_net_info );
+
+ palette_set_color_rgb(machine,RADARSCP_GRID_COL_OFFSET + i,r,g,b);
+ }
+ palette_normalize_range(machine->palette, 0, RADARSCP_GRID_COL_OFFSET+7, 0, 255);
+
+ color_prom += 512;
+ /* color_prom now points to the beginning of the character color codes */
+ color_codes = color_prom; /* we'll need it later */
+}
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Donkey Kong 3 has two 512x8 palette PROMs and one 256x4 PROM which contains
+ the color codes to use for characters on a per row/column basis (groups of
+ of 4 characters in the same column - actually row, since the display is
+ rotated)
+ Interstingly, bytes 0-255 of the palette PROMs contain an inverted palette,
+ as other Nintendo games like Donkey Kong, while bytes 256-511 contain a non
+ inverted palette. This was probably done to allow connection to both the
+ special Nintendo and a standard monitor.
+ I don't know the exact values of the resistors between the PROMs and the
+ RGB output, but they are probably the usual:
+
+ Couriersud: Checked against the schematics.
+ The proms are open collector proms and there is a pullup to
+ +5V of 470 ohm.
+
+ bit 7 -- 220 ohm resistor -- inverter -- RED
+ -- 470 ohm resistor -- inverter -- RED
+ -- 1 kohm resistor -- inverter -- RED
+ -- 2.2kohm resistor -- inverter -- RED
+ -- 220 ohm resistor -- inverter -- GREEN
+ -- 470 ohm resistor -- inverter -- GREEN
+ -- 1 kohm resistor -- inverter -- GREEN
+ bit 0 -- 2.2kohm resistor -- inverter -- GREEN
+
+ bit 3 -- 220 ohm resistor -- inverter -- BLUE
+ -- 470 ohm resistor -- inverter -- BLUE
+ -- 1 kohm resistor -- inverter -- BLUE
+ bit 0 -- 2.2kohm resistor -- inverter -- BLUE
+
+***************************************************************************/
+
+PALETTE_INIT( dkong3 )
+{
+
+ rgb_t *rgb;
+
+ rgb = compute_res_net_all(color_prom, &dkong3_decode_info, &dkong3_net_info);
+ palette_set_colors(machine, 0, rgb, 256);
+ palette_normalize_range(machine->palette, 0, 255, 0, 255);
+ free(rgb);
+
+ color_prom += 1024;
+ /* color_prom now points to the beginning of the character color codes */
+ color_codes = color_prom; /* we'll need it later */
+}
+
+static TILE_GET_INFO( dkong_bg_tile_info )
+{
+ int code = videoram[tile_index] + 256 * gfx_bank;
+ int color = (color_codes[tile_index % 32 + 32 * (tile_index / 32 / 4)] & 0x0f) + 0x10 * palette_bank;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static TILE_GET_INFO( radarsc1_bg_tile_info )
+{
+ int code = videoram[tile_index] + 256 * gfx_bank;
+ int color = (color_codes[tile_index % 32] & 0x0f);
+ color = color | (palette_bank<<4);
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+/***************************************************************************
+
+ I/O Handling
+
+***************************************************************************/
+
+WRITE8_HANDLER( dkong_videoram_w )
+{
+ if (videoram[offset] != data)
+ {
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+ }
+}
+
+WRITE8_HANDLER( radarscp_snd02_w )
+{
+ snd02_enable = data & 0x01;
+}
+
+WRITE8_HANDLER( radarsc1_ansn_w )
+{
+ sig_ansn = data & 0x01;
+}
+
+WRITE8_HANDLER( dkongjr_gfxbank_w )
+{
+ if (gfx_bank != (data & 0x01))
+ {
+ gfx_bank = data & 0x01;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+WRITE8_HANDLER( dkong3_gfxbank_w )
+{
+ if (gfx_bank != (~data & 0x01))
+ {
+ gfx_bank = ~data & 0x01;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+WRITE8_HANDLER( dkong_palettebank_w )
+{
+ int newbank;
+
+ newbank = palette_bank;
+
+ if (data & 1)
+ newbank |= 1 << offset;
+ else
+ newbank &= ~(1 << offset);
+
+ if (palette_bank != newbank)
+ {
+ palette_bank = newbank;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+WRITE8_HANDLER( radarscp_grid_enable_w )
+{
+ grid_on = data & 0x01;
+}
+
+WRITE8_HANDLER( radarscp_grid_color_w )
+{
+ grid_col = (data & 0x07) ^ 0x07;
+ popmessage("Gridcol: %d", grid_col);
+}
+
+WRITE8_HANDLER( dkong_flipscreen_w )
+{
+ flip_screen_set(~data & 0x01);
+}
+
+WRITE8_HANDLER( dkong_spritebank_w )
+{
+ sprite_bank = data & 0x01;
+}
+
+/***************************************************************************
+
+ Draw the game screen in the given mame_bitmap.
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT32 mask_bank, UINT32 shift_bits)
+{
+ int offs;
+
+ /* Draw the sprites. */
+ for (offs = sprite_bank<<9;offs < (sprite_bank<<9) + spriteram_size; offs += 4)
+ {
+ if (spriteram[offs])
+ {
+ /* spriteram[offs + 2] & 0x40 is used by Donkey Kong 3 only */
+ /* spriteram[offs + 2] & 0x30 don't seem to be used (they are */
+ /* probably not part of the color code, since Mario Bros, which */
+ /* has similar hardware, uses a memory mapped port to change */
+ /* palette bank, so it's limited to 16 color codes) */
+
+ int x,y;
+
+ x = spriteram[offs + 3] - 8;
+ y = 240 - spriteram[offs] + 7;
+
+ if (flip_screen)
+ {
+ x = 240 - x;
+ y = VTOTAL - VBEND - y;
+
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs + 1] & 0x7f) + ((spriteram[offs + 2] & mask_bank) << shift_bits),
+ (spriteram[offs + 2] & 0x0f) + 16 * palette_bank,
+ !(spriteram[offs + 2] & 0x80),!(spriteram[offs + 1] & 0x80),
+ x,y,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ /* draw with wrap around - this fixes the 'beheading' bug */
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs + 1] & 0x7f) + ((spriteram[offs + 2] & mask_bank) << shift_bits),
+ (spriteram[offs + 2] & 0x0f) + 16 * palette_bank,
+ (spriteram[offs + 2] & 0x80),(spriteram[offs + 1] & 0x80),
+ x-256,y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs + 1] & 0x7f) + ((spriteram[offs + 2] & mask_bank) << shift_bits),
+ (spriteram[offs + 2] & 0x0f) + 16 * palette_bank,
+ (spriteram[offs + 2] & 0x80),(spriteram[offs + 1] & 0x80),
+ x,y,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ /* draw with wrap around - this fixes the 'beheading' bug */
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs + 1] & 0x7f) + ((spriteram[offs + 2] & mask_bank) << shift_bits),
+ (spriteram[offs + 2] & 0x0f) + 16 * palette_bank,
+ (spriteram[offs + 2] & 0x80),(spriteram[offs + 1] & 0x80),
+ x+256,y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+}
+
+/* The hardware designer must have been a real CD4049 fan
+ * The blue signal is created by "abusing" the 4049
+ * as an amplifier by operating it in the undefined area
+ * between roughly 1.5 and 3.5V. The transfer function
+ * below is an approximation but datasheets state
+ * a wide range for the transfer function.
+ *
+ * SwitcherCad was not a real help since it can not
+ * adequately model the 4049
+ *
+ * Sound02 will mix in noise into the periodic fluctuation
+ * of the background: The 30Hz signal is used
+ * to generate noise with an LS164. This signal is going
+ * through a NAND (Signal RFLIP to video) and then XOR with 128V.
+ * This should really be emulated using the discrete sound interface.
+ * TODO: This should be part of the vblank routine
+ */
+
+INLINE double CD4049(double x)
+{
+ if (x>0)
+ return exp(-cd4049_a * pow(x,cd4049_b));
+ else
+ return 1.0;
+}
+
+/* Actually the sound noise is a multivibrator with
+ * a period of roughly 4.4 ms
+ */
+
+static void radarscp_step(int line_cnt)
+{
+ /* Condensator is illegible in schematics for TRS2 board.
+ * TRS1 board states 3.3u.
+ */
+ const double RC1= 2.2e3 * 22e-6;// 22e-6;
+ const double RC2= 10e3 * 33e-6;
+ const double RC31= 18e3 * 33e-6;
+ const double RC32= (18e3 + 68e3) * 33e-6;
+ const double RC4= 90e3 * 0.47e-6;
+ const double dt= 1./60./(double) VTOTAL;
+ const int period2 = ((long long)(PIXEL_CLOCK) * ( 33L * 68L )) / (long)10000000L / 3; // period/2 in pixel ...
+ static double cv1=0,cv2=0,vg1=0,vg2=0,vg3=0,vg3i=0,cv3=0,cv4=0;
+ static int pixelcnt = 0;
+ double diff;
+ int sig;
+
+ line_cnt += 256;
+ if (line_cnt>511)
+ line_cnt -= VTOTAL;
+ //FIXME: remove after testing
+ //return;
+ /* sound2 mixes in a 30Hz noise signal.
+ * With the current model this has no real effect
+ * Included for completeness
+ */
+
+ line_cnt++;
+ if (line_cnt>=512)
+ line_cnt=512-VTOTAL;
+ if ( ( !(line_cnt & 0x40) && ((line_cnt+1) & 0x40) ) && (mame_rand(Machine) > RAND_MAX/2))
+ sig30Hz = (1-sig30Hz);
+ rflip_sig = snd02_enable & sig30Hz;
+ sig = rflip_sig ^ ((line_cnt & 0x80)>>7);
+ if (vid_hw & HW_TRS01)
+ rflip_sig = !rflip_sig;
+ if (sig) // 128VF
+ diff = (0.0 - cv1);
+ else
+ diff = (3.4 - cv1);
+ diff = diff - diff*exp(0.0 - (1.0/RC1 * dt) );
+ cv1 += diff;
+
+ diff = (cv1 - cv2 - vg1);
+ diff = diff - diff*exp(0.0 - (1.0/RC2 * dt) );
+ cv2 += diff;
+
+ vg1 = (cv1 - cv2)*0.9 + 0.1 * vg2;
+ vg2 = 5*CD4049(vg1/5);
+
+ /* on the real hardware, the gain would be 1.
+ * This will not work here.
+ */
+ vg3i = 0.9*vg2 + 0.1 * vg3;
+ vg3 = 5*CD4049(vg3i/5);
+
+ blue_level = (int)(vg3/5.0*255);
+
+ // Grid signal
+ if (grid_on && sig_ansn)
+ {
+ diff = (0.0 - cv3);
+ diff = diff - diff*exp(0.0 - (1.0/RC32 * dt) );
+ }
+ else
+ {
+ diff = (5.0 - cv3);
+ diff = diff - diff*exp(0.0 - (1.0/RC31 * dt) );
+ }
+ cv3 += diff;
+
+ diff = (vg2 - 0.8 * cv3 - cv4);
+ diff = diff - diff*exp(0.0 - (1.0/RC4 * dt) );
+ cv4 += diff;
+
+ if (CD4049(CD4049(vg2 - cv4))>2.4/5.0) //TTL - Level
+ grid_sig = 0;
+ else
+ grid_sig = 1;
+
+ /* stars */
+ pixelcnt += HTOTAL;
+ if (pixelcnt > period2 )
+ {
+ star_ff = !star_ff;
+ pixelcnt = pixelcnt - period2;
+ }
+
+}
+
+static void radarscp_draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const UINT8 *htable = NULL;
+ int x,y;
+ UINT8 draw_ok;
+ UINT16 *pixel;
+
+ if (vid_hw & HW_TRS01)
+ htable = memory_region(REGION_GFX4);
+
+ y = machine->screen[0].visarea.min_y;
+ while (y <= machine->screen[0].visarea.max_y)
+ {
+ x = machine->screen[0].visarea.min_x;
+ while (x <= machine->screen[0].visarea.max_x)
+ {
+ pixel = BITMAP_ADDR16(bitmap, y, x);
+ draw_ok = !(*pixel & 0x01) && !(*pixel & 0x02);
+ if (vid_hw & HW_TRS01) // Check again from schematics
+ draw_ok = draw_ok && !((htable[ (!rflip_sig<<7) | (x>>2)] >>2) & 0x01);
+ if (draw_ok)
+ *pixel = *(BITMAP_ADDR16(bg_bits, y, x));
+ x++;
+ }
+ y++;
+ }
+}
+
+
+static TIMER_CALLBACK( scanline_callback )
+{
+ const UINT8 *table = memory_region(REGION_GFX3);
+ int table_len = memory_region_length(REGION_GFX3);
+ int x,y,offset;
+ UINT16 *pixel;
+ static int counter=0;
+ int scanline = param;
+
+ y = scanline;
+ radarscp_step(y);
+ if (y <= machine->screen[0].visarea.min_y || y > machine->screen[0].visarea.max_y)
+ counter = 0;
+ offset = ((-flip_screen) ^ rflip_sig) ? 0x000 : 0x400;
+ x = 0;
+ while (x < machine->screen[0].width)
+ {
+ pixel = BITMAP_ADDR16(bg_bits, y, x);
+ if ((counter < table_len) && (x == 4 * (table[counter|offset] & 0x7f)))
+ {
+ if ( star_ff && (table[counter|offset] & 0x80) ) /* star */
+ *pixel = machine->pens[RADARSCP_STAR_COL];
+ else if (grid_sig && !(table[counter|offset] & 0x80)) /* radar */
+ *pixel = machine->pens[RADARSCP_GRID_COL_OFFSET+grid_col];
+ else
+ *pixel = machine->pens[RADARSCP_BCK_COL_OFFSET + blue_level];
+ counter++;
+ }
+ else
+ *pixel = machine->pens[RADARSCP_BCK_COL_OFFSET + blue_level];
+ x++;
+ }
+ while ((counter < table_len) && ( x < 4 * (table[counter|offset] & 0x7f)))
+ counter++;
+ scanline = (scanline+1) % VTOTAL;
+ /* come back at the next appropriate scanline */
+ timer_adjust(scanline_timer, video_screen_get_time_until_pos(0, scanline, 0), scanline, attotime_zero);
+}
+
+static VIDEO_START( dkong_base )
+{
+
+ cd4049_b = (log(0.0 - log(cd4049_al)) - log(0.0 - log((1.0-cd4049_al))) ) / log(cd4049_vh/cd4049_vl);
+ cd4049_a = log(0.0 - log(cd4049_al)) - cd4049_b * log(cd4049_vh);
+
+ gfx_bank = 0;
+ palette_bank = 0;
+ sprite_bank = 0;
+ sig_ansn = 1;
+ vid_hw = HW_DK4;
+
+ state_save_register_global(gfx_bank);
+ state_save_register_global(palette_bank);
+ state_save_register_global(sprite_bank);
+ state_save_register_global(grid_on);
+
+ state_save_register_global(snd02_enable);
+ state_save_register_global(sig_ansn);
+ state_save_register_global(grid_col);
+
+ /* this must be registered here - hmmm */
+ state_save_register_global(flip_screen);
+
+}
+
+VIDEO_START( dkong )
+{
+
+ video_start_dkong_base(machine);
+
+ bg_tilemap = tilemap_create(dkong_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+ tilemap_set_scrolldx(bg_tilemap, 0, 128);
+}
+
+VIDEO_START( radarscp )
+{
+
+ video_start_dkong(machine);
+
+ vid_hw = HW_TRS02;
+
+ bg_bits = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ scanline_timer = timer_alloc(scanline_callback);
+ timer_adjust(scanline_timer, video_screen_get_time_until_pos(0, 0, 0), 0, attotime_zero);
+
+}
+
+VIDEO_START( radarsc1 )
+{
+
+ video_start_dkong_base(machine);
+
+ vid_hw = HW_TRS01;
+
+ bg_tilemap = tilemap_create(radarsc1_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+ tilemap_set_scrolldx(bg_tilemap, 0, 128);
+
+ bg_bits = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ scanline_timer = timer_alloc(scanline_callback);
+ timer_adjust(scanline_timer, video_screen_get_time_until_pos(0, 0, 0), 0, attotime_zero);
+
+}
+
+VIDEO_UPDATE( radarscp )
+{
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect, 0x40, 1);
+ radarscp_draw_background(machine, bitmap, cliprect);
+
+ return 0;
+}
+
+VIDEO_UPDATE( dkong )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect, 0x40, 1);
+ return 0;
+}
+
+VIDEO_UPDATE( pestplce )
+{
+ int offs;
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* Draw the sprites. */
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ if (spriteram[offs])
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ spriteram[offs + 2],
+ (spriteram[offs + 1] & 0x0f) + 16 * palette_bank,
+ spriteram[offs + 1] & 0x80,spriteram[offs + 1] & 0x40,
+ spriteram[offs + 3] - 8,240 - spriteram[offs] + 8,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ return 0;
+}
+
+VIDEO_UPDATE( spclforc )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* it uses spriteram[offs + 2] & 0x10 for sprite bank */
+ draw_sprites(machine, bitmap, cliprect, 0x10, 3);
+ return 0;
+}
diff --git a/src/mame/video/docastle.c b/src/mame/video/docastle.c
new file mode 100644
index 00000000000..d9f80fbc073
--- /dev/null
+++ b/src/mame/video/docastle.c
@@ -0,0 +1,225 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+ (Cocktail mode implemented by Chad Hendrickson Aug 1, 1999)
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/docastle.h"
+
+static tilemap *docastle_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Mr. Do's Castle / Wild Ride / Run Run have a 256 bytes palette PROM which
+ is connected to the RGB output this way:
+
+ bit 7 -- 200 ohm resistor -- RED
+ -- 390 ohm resistor -- RED
+ -- 820 ohm resistor -- RED
+ -- 200 ohm resistor -- GREEN
+ -- 390 ohm resistor -- GREEN
+ -- 820 ohm resistor -- GREEN
+ -- 200 ohm resistor -- BLUE
+ bit 0 -- 390 ohm resistor -- BLUE
+
+***************************************************************************/
+PALETTE_INIT( docastle )
+{
+ int i;
+
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 5) & 0x01;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ r = 0x23 * bit0 + 0x4b * bit1 + 0x91 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 2) & 0x01;
+ bit1 = (*color_prom >> 3) & 0x01;
+ bit2 = (*color_prom >> 4) & 0x01;
+ g = 0x23 * bit0 + 0x4b * bit1 + 0x91 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 0) & 0x01;
+ bit2 = (*color_prom >> 1) & 0x01;
+ b = 0x23 * bit0 + 0x4b * bit1 + 0x91 * bit2;
+
+ /* because the graphics are decoded as 4bpp with the top bit used for transparency
+ or priority, we create matching 3bpp sets of palette entries, which effectively
+ ignores the value of the top bit */
+ palette_set_color(machine, ((i & 0xf8) << 1) | 0x00 | (i & 0x07), MAKE_RGB(r,g,b));
+ palette_set_color(machine, ((i & 0xf8) << 1) | 0x08 | (i & 0x07), MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( docastle_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(docastle_tilemap, offset);
+}
+
+WRITE8_HANDLER( docastle_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(docastle_tilemap, offset);
+}
+
+READ8_HANDLER( docastle_flipscreen_off_r )
+{
+ flip_screen_set(0);
+ tilemap_mark_all_tiles_dirty(docastle_tilemap);
+ return 0;
+}
+
+READ8_HANDLER( docastle_flipscreen_on_r )
+{
+ flip_screen_set(1);
+ tilemap_mark_all_tiles_dirty(docastle_tilemap);
+ return 1;
+}
+
+WRITE8_HANDLER( docastle_flipscreen_off_w )
+{
+ flip_screen_set(0);
+ tilemap_mark_all_tiles_dirty(docastle_tilemap);
+}
+
+WRITE8_HANDLER( docastle_flipscreen_on_w )
+{
+ flip_screen_set(1);
+ tilemap_mark_all_tiles_dirty(docastle_tilemap);
+}
+
+static TILE_GET_INFO( get_tile_info )
+{
+ int code = videoram[tile_index] + 8 * (colorram[tile_index] & 0x20);
+ int color = colorram[tile_index] & 0x1f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static void video_start_common(running_machine *machine, UINT32 tile_transmask)
+{
+ docastle_tilemap = tilemap_create(get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+ tilemap_set_transmask(docastle_tilemap, 0, tile_transmask, 0x0000);
+}
+
+VIDEO_START( docastle )
+{
+ video_start_common(machine, 0x00ff);
+}
+
+VIDEO_START( dorunrun )
+{
+ video_start_common(machine, 0xff00);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ fillbitmap(priority_bitmap,1,NULL);
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int sx,sy,flipx,flipy,code,color;
+
+ if (machine->gfx[1]->total_elements > 256)
+ {
+ /* spriteram
+
+ indoor soccer appears to have a slightly different spriteram
+ format to the other games, allowing a larger number of sprite
+ tiles
+
+ yyyy yyyy xxxx xxxx TX-T pppp tttt tttt
+
+ y = ypos
+ x = xpos
+ X = x-flip
+ T = extra tile number bits
+ p = palette
+ t = tile number
+
+ */
+
+ code = spriteram[offs + 3];
+ color = spriteram[offs + 2] & 0x0f;
+ sx = ((spriteram[offs + 1] + 8) & 0xff) - 8;
+ sy = spriteram[offs];
+ flipx = spriteram[offs + 2] & 0x40;
+ flipy = 0;
+ if (spriteram[offs + 2] & 0x10) code += 0x100;
+ if (spriteram[offs + 2] & 0x80) code += 0x200;
+ }
+ else
+ {
+ /* spriteram
+
+ this is the standard spriteram layout, used by most games
+
+ yyyy yyyy xxxx xxxx YX-p pppp tttt tttt
+
+ y = ypos
+ x = xpos
+ X = x-flip
+ Y = y-flip
+ p = palette
+ t = tile number
+
+ */
+
+ code = spriteram[offs + 3];
+ color = spriteram[offs + 2] & 0x1f;
+ sx = ((spriteram[offs + 1] + 8) & 0xff) - 8;
+ sy = spriteram[offs];
+ flipx = spriteram[offs + 2] & 0x40;
+ flipy = spriteram[offs + 2] & 0x80;
+ }
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ /* first draw the sprite, visible */
+ pdrawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PENS,0x80ff,
+ 0x00);
+
+ /* then draw the mask, behind the background but obscuring following sprites */
+ pdrawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PENS,0x7fff,
+ 0x02);
+ }
+}
+
+VIDEO_UPDATE( docastle )
+{
+ tilemap_draw(bitmap, cliprect, docastle_tilemap, TILEMAP_DRAW_OPAQUE, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, docastle_tilemap, TILEMAP_DRAW_LAYER0, 0);
+ return 0;
+}
diff --git a/src/mame/video/dogfgt.c b/src/mame/video/dogfgt.c
new file mode 100644
index 00000000000..f3de2f0e97e
--- /dev/null
+++ b/src/mame/video/dogfgt.c
@@ -0,0 +1,243 @@
+#include "driver.h"
+#include "dogfgt.h"
+
+
+UINT8 *dogfgt_bgvideoram;
+
+static UINT8 *bitmapram;
+static int bm_plane;
+static mame_bitmap *pixbitmap;
+static int pixcolor;
+static tilemap *bg_tilemap;
+
+#define PIXMAP_COLOR_BASE (16+32)
+
+#define BITMAPRAM_SIZE 0x6000
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Dog-Fight has both palette RAM and PROMs. The PROMs are used for tiles &
+ pixmap, RAM for sprites.
+
+***************************************************************************/
+
+PALETTE_INIT( dogfgt )
+{
+ int i;
+
+ /* first 16 colors are RAM */
+
+ for (i = 0;i < 64;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i+16,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ SET_TILE_INFO(
+ 0,
+ dogfgt_bgvideoram[tile_index],
+ dogfgt_bgvideoram[tile_index + 0x400] & 0x03,
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( dogfgt )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ bitmapram = auto_malloc(BITMAPRAM_SIZE);
+
+ pixbitmap = auto_bitmap_alloc(256,256,machine->screen[0].format);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( dogfgt_plane_select_w )
+{
+ bm_plane = data;
+}
+
+READ8_HANDLER( dogfgt_bitmapram_r )
+{
+ if (bm_plane > 2)
+ {
+ popmessage("bitmapram_r offs %04x plane %d\n",offset,bm_plane);
+ return 0;
+ }
+
+ return bitmapram[offset + BITMAPRAM_SIZE/3 * bm_plane];
+}
+
+static WRITE8_HANDLER( internal_bitmapram_w )
+{
+ int x,y,subx;
+
+
+ bitmapram[offset] = data;
+
+ offset &= (BITMAPRAM_SIZE/3-1);
+ x = 8 * (offset / 256);
+ y = offset % 256;
+
+ for (subx = 0;subx < 8;subx++)
+ {
+ int i,color = 0;
+
+ for (i = 0;i < 3;i++)
+ color |= ((bitmapram[offset + BITMAPRAM_SIZE/3 * i] >> subx) & 1) << i;
+ if (flip_screen)
+ *BITMAP_ADDR16(pixbitmap, y^0xff, (x+subx)^0xff) = PIXMAP_COLOR_BASE + 8*pixcolor + color;
+ else
+ *BITMAP_ADDR16(pixbitmap, y, x+subx) = PIXMAP_COLOR_BASE + 8*pixcolor + color;
+ }
+}
+
+WRITE8_HANDLER( dogfgt_bitmapram_w )
+{
+ if (bm_plane > 2)
+ {
+ popmessage("bitmapram_w offs %04x plane %d\n",offset,bm_plane);
+ return;
+ }
+
+ internal_bitmapram_w(offset + BITMAPRAM_SIZE/3 * bm_plane,data);
+}
+
+WRITE8_HANDLER( dogfgt_bgvideoram_w )
+{
+ dogfgt_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( dogfgt_scroll_w )
+{
+ static int scroll[4];
+
+ scroll[offset] = data;
+
+ tilemap_set_scrollx(bg_tilemap,0,scroll[0] + 256 * scroll[1] + 256);
+ tilemap_set_scrolly(bg_tilemap,0,scroll[2] + 256 * scroll[3]);
+}
+
+WRITE8_HANDLER( dogfgt_1800_w )
+{
+ /* bits 0 and 1 are probably text color (not verified because PROM is missing) */
+ pixcolor = ((data & 0x01) << 1) | ((data & 0x02) >> 1);
+
+ /* bits 4 and 5 are coin counters */
+ coin_counter_w(0,data & 0x10);
+ coin_counter_w(1,data & 0x20);
+
+ /* bit 7 is screen flip */
+ flip_screen_set(data & 0x80);
+
+ /* other bits unused? */
+ logerror("PC %04x: 1800 = %02x\n",activecpu_get_pc(),data);
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ if (spriteram[offs] & 0x01)
+ {
+ int sx,sy,flipx,flipy;
+
+ sx = spriteram[offs+3];
+ sy = (240 - spriteram[offs+2]) & 0xff;
+ flipx = spriteram[offs] & 0x04;
+ flipy = spriteram[offs] & 0x02;
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ spriteram[offs+1] + ((spriteram[offs] & 0x30) << 4),
+ (spriteram[offs] & 0x08) >> 3,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+
+VIDEO_UPDATE( dogfgt )
+{
+ static int lastflip,lastpixcolor;
+ int offs;
+
+
+ if (lastflip != flip_screen || lastpixcolor != pixcolor)
+ {
+ lastflip = flip_screen;
+ lastpixcolor = pixcolor;
+
+ for (offs = 0;offs < BITMAPRAM_SIZE;offs++)
+ internal_bitmapram_w(offs,bitmapram[offs]);
+ }
+
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ draw_sprites(machine, bitmap, cliprect);
+
+ copybitmap(bitmap,pixbitmap,0,0,0,0,cliprect,TRANSPARENCY_COLOR,PIXMAP_COLOR_BASE + 8*pixcolor);
+ return 0;
+}
diff --git a/src/mame/video/dooyong.c b/src/mame/video/dooyong.c
new file mode 100644
index 00000000000..4318fdbd6e7
--- /dev/null
+++ b/src/mame/video/dooyong.c
@@ -0,0 +1,875 @@
+#include "driver.h"
+
+
+UINT8 *dooyong_txvideoram;
+
+static UINT8 sprites_disabled; /* Used by lastday/lastdaya */
+static UINT8 flytiger_pri; /* Used by flytiger */
+static UINT8 tx_pri; /* Used by sadari/gundl94/primella */
+static UINT16 rshark_pri; /* Used by rshark/superx/popbingo */
+
+/* Up to four ROM-based and one RAM-based tilemap */
+static tilemap *bg_tilemap, *bg2_tilemap, *fg_tilemap, *fg2_tilemap;
+static tilemap *tx_tilemap;
+
+/* Tilemap control registers */
+static UINT8 bgscroll8[0x10] = {0}, bg2scroll8[0x10] = {0}, fgscroll8[0x10] = {0}, fg2scroll8[0x10] = {0};
+
+/* These are set at startup to configure the tilemap callbacks */
+static UINT8 *bg_tilerom, *bg2_tilerom, *fg_tilerom, *fg2_tilerom;
+static UINT8 *bg_tilerom2, *bg2_tilerom2, *fg_tilerom2, *fg2_tilerom2; /* For rshark/superx */
+static int bg_gfx, bg2_gfx, fg_gfx, fg2_gfx;
+static int tx_tilemap_mode; /* 0 = lastday/gulfstrm/pollux/flytiger; 1 = bluehawk/primella */
+
+
+/* All the dooyong games have the same tilemap control registers */
+
+INLINE void dooyong_scroll8_w(offs_t offset, UINT8 data, UINT8 *scroll, tilemap *map)
+{
+ UINT8 old = scroll[offset];
+ if (old != data)
+ {
+ scroll[offset] = data;
+ if (map != NULL) switch (offset)
+ {
+ case 0: /* Low byte of x scroll - scroll tilemap */
+ tilemap_set_scrollx(map, 0, data);
+ break;
+ case 1: /* High byte of x scroll - mark tilemap dirty so new tile gfx will be loaded */
+ tilemap_mark_all_tiles_dirty(map);
+ break;
+ case 3: /* Low byte of y scroll */
+ case 4: /* High byte of y scroll */
+ tilemap_set_scrolly(map, 0, (int)scroll[3] | ((int)scroll[4] << 8));
+ break;
+ case 6: /* Tilemap enable and mode control */
+ tilemap_set_enable(map, !(data & 0x10));
+ if ((data & 0x20) != (old & 0x20)) // This sets the tilemap data format
+ tilemap_mark_all_tiles_dirty(map);
+ break;
+ default: /* Other addresses are used but function is unknown */
+ /* 0x05 and 0x07 are initialised on startup */
+ /* 0x02 is initialised on startup by some games and written to continuously by others */
+ /*{
+ const char *name;
+ if (scroll == bgscroll8) name = "bg";
+ else if (scroll == bg2scroll8) name = "bg2";
+ else if (scroll == fgscroll8) name = "fg";
+ else if (scroll == fg2scroll8) name = "fg2";
+ else name = "unknown";
+ printf("Unknown %s tilemap control: 0x%02x = 0x%02x\n", name, (unsigned)offset, (unsigned)data);
+ }*/
+ break;
+ }
+ }
+}
+
+
+/* These handle writes to the tilemap scroll registers in 8-bit machines.
+ There is one per tilemap, wrapping the above function that does the work. */
+
+WRITE8_HANDLER( dooyong_bgscroll8_w )
+{
+ dooyong_scroll8_w(offset, data, bgscroll8, bg_tilemap);
+}
+
+static WRITE8_HANDLER( dooyong_bg2scroll8_w )
+{
+ dooyong_scroll8_w(offset, data, bg2scroll8, bg2_tilemap);
+}
+
+WRITE8_HANDLER( dooyong_fgscroll8_w )
+{
+ dooyong_scroll8_w(offset, data, fgscroll8, fg_tilemap);
+}
+
+WRITE8_HANDLER( dooyong_fg2scroll8_w )
+{
+ dooyong_scroll8_w(offset, data, fg2scroll8, fg2_tilemap);
+}
+
+
+/* These handle writes to the tilemap scroll registers in 16-bit machines.
+ This is just an 8-bit peripheral in a 16-bit machine. */
+
+WRITE16_HANDLER( dooyong_bgscroll16_w )
+{
+ if (ACCESSING_LSB) dooyong_bgscroll8_w(offset, data & 0x00ff);
+}
+
+WRITE16_HANDLER( dooyong_bg2scroll16_w )
+{
+ if (ACCESSING_LSB) dooyong_bg2scroll8_w(offset, data & 0x00ff);
+}
+
+WRITE16_HANDLER( dooyong_fgscroll16_w )
+{
+ if (ACCESSING_LSB) dooyong_fgscroll8_w(offset, data & 0x00ff);
+}
+
+WRITE16_HANDLER( dooyong_fg2scroll16_w )
+{
+ if (ACCESSING_LSB) dooyong_fg2scroll8_w(offset, data & 0x00ff);
+}
+
+
+WRITE8_HANDLER( dooyong_txvideoram8_w )
+{
+ if (dooyong_txvideoram[offset] != data)
+ {
+ dooyong_txvideoram[offset] = data;
+ if (tx_tilemap_mode == 0)
+ tilemap_mark_tile_dirty(tx_tilemap, offset & 0x07ff);
+ else
+ tilemap_mark_tile_dirty(tx_tilemap, offset >> 1);
+ }
+}
+
+
+/* Control registers seem to be different on every game */
+
+WRITE8_HANDLER( lastday_ctrl_w )
+{
+ /* bits 0 and 1 are coin counters */
+ coin_counter_w(0, data & 0x01);
+ coin_counter_w(1, data & 0x02);
+
+ /* bit 3 is used but unknown */
+
+ /* bit 4 disables sprites */
+ sprites_disabled = data & 0x10;
+
+ /* bit 6 is flip screen */
+ flip_screen_set(data & 0x40);
+}
+
+WRITE8_HANDLER( pollux_ctrl_w )
+{
+ /* bit 0 is flip screen */
+ flip_screen_set(data & 0x01);
+
+ /* bits 6 and 7 are coin counters */
+ coin_counter_w(0, data & 0x80);
+ coin_counter_w(1, data & 0x40);
+
+ /* bit 1 is used but unknown */
+
+ /* bit 2 is continuously toggled (unknown) */
+
+ /* bit 4 is used but unknown */
+}
+
+WRITE8_HANDLER( primella_ctrl_w )
+{
+ /* bits 0-2 select ROM bank */
+ memory_set_bank(1, data & 0x07);
+
+ /* bit 3 disables tx layer */
+ tx_pri = data & 0x08;
+
+ /* bit 4 flips screen */
+ flip_screen_set(data & 0x10);
+
+ /* bit 5 used but unknown */
+
+// logerror("%04x: bankswitch = %02x\n",activecpu_get_pc(),data&0xe0);
+}
+
+WRITE8_HANDLER( flytiger_ctrl_w )
+{
+ /* bit 0 is flip screen */
+ flip_screen_set(data & 0x01);
+
+ /* bits 1, 2, 3 used but unknown */
+
+ /* bit 4 changes tilemaps priority */
+ flytiger_pri = data & 0x10;
+}
+
+WRITE16_HANDLER( rshark_ctrl_w )
+{
+ if (ACCESSING_LSB)
+ {
+ /* bit 0 flips screen */
+ flip_screen_set(data & 0x0001);
+
+ /* bit 4 changes tilemaps priority */
+ rshark_pri = data & 0x0010;
+
+ /* bit 5 used but unknown */
+ }
+}
+
+
+/* These games all have ROM-based tilemaps for the backgrounds, title
+ screens and sometimes "bosses" and special attacks. There are three
+ schemes for tilemap encoding. The scheme is chosen based on the
+ contents of the tilemap control variables declared above.
+ Note that although the tilemaps are arbitrarily wide (hundreds of
+ thousands of pixels, depending on the size of the ROM), we only
+ decode a 1024 pixel wide block at a time, and invalidate the tilemap
+ when the x scroll moves out of range (trying to decode the whole lot
+ at once uses hundreds of megabytes of RAM). */
+
+INLINE void lastday_get_tile_info(running_machine *machine, tile_data *tileinfo, int tile_index,
+ const UINT8 *tilerom, UINT8 *scroll, int graphics)
+{
+ int offs = (tile_index + ((int)scroll[1] << 6)) * 2;
+ int attr = tilerom[offs];
+ int code, color, flags;
+ if (scroll[6] & 0x20)
+ { /* lastday/gulfstrm/pollux/flytiger */
+ /* Tiles take two bytes in ROM:
+ MSB LSB
+ [offs + 0x00] cCCC CYXc (bit 9 of gfx code, bits 3-0 of color, Y flip, X flip, bit 8 of gfx code)
+ [offs + 0x01] cccc cccc (bits 7-0 of gfx code)
+ c = gfx code
+ C = color code
+ X = x flip
+ Y = y flip */
+ code = tilerom[offs + 1] | ((attr & 0x01) << 8) | ((attr & 0x80) << 2);
+ color = (attr & 0x78) >> 3;
+ flags = ((attr & 0x02) ? TILE_FLIPX : 0) | ((attr & 0x04) ? TILE_FLIPY : 0);
+ }
+ else
+ { /* primella/popbingo */
+ /* Tiles take two bytes in ROM:
+ MSB LSB
+ [offs + 0x00] YXCC CCcc (Y flip, X flip, bits 3-0 of color code, bits 9-8 of gfx code)
+ [offs + 0x01] cccc cccc (bits 7-0 of gfx code)
+ c = gfx code
+ C = color code
+ X = x flip
+ Y = y flip */
+ code = tilerom[offs + 1] | ((attr & 0x03) << 8);
+ color = (attr & 0x3c) >> 2;
+ flags = ((attr & 0x40) ? TILE_FLIPX : 0) | ((attr & 0x80) ? TILE_FLIPY : 0);
+ }
+
+ SET_TILE_INFO(graphics, code, color, flags);
+}
+
+INLINE void rshark_get_tile_info(running_machine *machine, tile_data *tileinfo, int tile_index,
+ const UINT8 *tilerom1, const UINT8 *tilerom2, UINT8 *scroll, int graphics)
+{
+ /* Tiles take two bytes in tile ROM 1:
+ MSB LSB
+ [offs + 0x00] YX?c cccc (Y flip, X flip, bits 12-8 of gfx code)
+ [offs + 0x01] cccc cccc (bits 7-0 of gfx code)
+ ? = unused/unknown
+ c = gfx code
+ X = x flip
+ Y = y flip */
+ int offs = tile_index + ((int)scroll[1] << 9);
+ int attr = tilerom1[offs * 2];
+ int code = tilerom1[(offs * 2) + 1] | ((attr & 0x1f) << 8);
+ int color = tilerom2[offs] & 0x0f;
+ int flags = ((attr & 0x40) ? TILE_FLIPX : 0) | ((attr & 0x80) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(graphics, code, color, flags);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ if (bg_tilerom2 != NULL)
+ rshark_get_tile_info(machine, tileinfo, tile_index, bg_tilerom, bg_tilerom2, bgscroll8, bg_gfx);
+ else
+ lastday_get_tile_info(machine, tileinfo, tile_index, bg_tilerom, bgscroll8, bg_gfx);
+}
+
+static TILE_GET_INFO( get_bg2_tile_info )
+{
+ if (bg2_tilerom2 != NULL)
+ rshark_get_tile_info(machine, tileinfo, tile_index, bg2_tilerom, bg2_tilerom2, bg2scroll8, bg2_gfx);
+ else
+ lastday_get_tile_info(machine, tileinfo, tile_index, bg2_tilerom, bg2scroll8, bg2_gfx);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ if (fg_tilerom2 != NULL)
+ rshark_get_tile_info(machine, tileinfo, tile_index, fg_tilerom, fg_tilerom2, fgscroll8, fg_gfx);
+ else
+ lastday_get_tile_info(machine, tileinfo, tile_index, fg_tilerom, fgscroll8, fg_gfx);
+}
+
+static TILE_GET_INFO( get_fg2_tile_info )
+{
+ if (fg2_tilerom2 != NULL)
+ rshark_get_tile_info(machine, tileinfo, tile_index, fg2_tilerom, fg2_tilerom2, fg2scroll8, fg2_gfx);
+ else
+ lastday_get_tile_info(machine, tileinfo, tile_index, fg2_tilerom, fg2scroll8, fg2_gfx);
+}
+
+/* flytiger uses some palette banking technique or something, but we
+ don't know what it is. For now, this is the same as the code used
+ for the other layers (hence the really strange colour). */
+
+static TILE_GET_INFO( flytiger_get_fg_tile_info )
+{
+ const UINT8 *tilerom = fg_tilerom;
+
+ int offs = (tile_index + (fgscroll8[1] << 6)) * 2;
+ int attr = tilerom[offs];
+ int code = tilerom[offs + 1] | ((attr & 0x01) << 8) | ((attr & 0x80) << 2);
+ int color = (attr & 0x78) >> 3; //TODO: missing 4th bit or palette bank
+ int flags = ((attr & 0x02) ? TILE_FLIPX : 0) | ((attr & 0x04) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(fg_gfx, code, color, flags);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ /* Each tile takes two bytes of memory:
+ MSB LSB
+ [offs + 0x00] cccc cccc (bits 7-0 of gfx code)
+ [offs + 0x01] CCCC cccc (bits 3-0 of color code, bits 11-8 of gfx code)
+ c = gfx code
+ C = color code */
+ int offs, attr, code, color;
+ if (tx_tilemap_mode == 0)
+ { /* lastday/gulfstrm/pollux/flytiger */
+ offs = tile_index;
+ attr = dooyong_txvideoram[offs | 0x0800];
+ }
+ else
+ { /* bluehawk/primella */
+ offs = tile_index * 2;
+ attr = dooyong_txvideoram[offs + 1];
+ }
+ code = dooyong_txvideoram[offs] | ((attr & 0x0f) << 8);
+ color = (attr & 0xf0) >> 4;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pollux_extensions)
+{
+ /* Sprites take 32 bytes each in memory:
+ MSB LSB
+ [offs + 0x00] cccc cccc (bits 7-0 of gfx code)
+ [offs + 0x01] cccx CCCC (bits 10-8 of gfx code, bit 8 of x position, bits 3-0 of color code)
+ [offs + 0x02] yyyy yyyy
+ [offs + 0x03] xxxx xxxx (bits 7-0 of x offset)
+ ...
+ [offs + 0x1c] ?hhh XY*c (bits 2-0 of height, x flip, y flip, * see note, bit 11 of gfx code)
+ ...
+ ? = unused/unknown
+ E = enable
+ c = gfx code
+ x = x position
+ y = y position
+ C = color code
+ w = width
+ X = x flip
+ Y = y flip
+ * = alters y position in pollux and flytiger - see code below
+ bit 11 of gfx code only used by gulfstrm, pollux, bluehawk and flytiger
+ height only used by pollux, bluehawk and flytiger
+ x flip and y flip only used by pollux and flytiger */
+
+ int offs;
+
+ for (offs = 0; offs < spriteram_size; offs += 32)
+ {
+ int sx, sy, code, color, pri;
+ int flipx = 0, flipy = 0, height = 0, y;
+
+ sx = buffered_spriteram[offs+3] | ((buffered_spriteram[offs+1] & 0x10) << 4);
+ sy = buffered_spriteram[offs+2];
+ code = buffered_spriteram[offs] | ((buffered_spriteram[offs+1] & 0xe0) << 3);
+ color = buffered_spriteram[offs+1] & 0x0f;
+ //TODO: This priority mechanism works for known games, but seems a bit strange.
+ //Are we missing something? (The obvious spare palette bit isn't it.)
+ pri = (((color == 0x00) || (color == 0x0f)) ? 0xfc : 0xf0);
+
+ if (pollux_extensions)
+ {
+ /* gulfstrm, pollux, bluehawk, flytiger */
+ code |= ((buffered_spriteram[offs+0x1c] & 0x01) << 11);
+
+ if (pollux_extensions >= 2)
+ {
+ /* pollux, bluehawk, flytiger */
+ height = (buffered_spriteram[offs+0x1c] & 0x70) >> 4;
+ code &= ~height;
+
+ if (pollux_extensions == 3)
+ {
+ /* bluehawk */
+ sy += 6 - ((~buffered_spriteram[offs+0x1c] & 0x02) << 7);
+ flipx = buffered_spriteram[offs+0x1c] & 0x08;
+ flipy = buffered_spriteram[offs+0x1c] & 0x04;
+ }
+
+ if (pollux_extensions == 4)
+ {
+ /* flytiger */
+ sy -=(buffered_spriteram[offs+0x1c] & 0x02) << 7;
+ flipx = buffered_spriteram[offs+0x1c] & 0x08;
+ flipy = buffered_spriteram[offs+0x1c] & 0x04;
+ }
+ }
+ }
+
+ if (flip_screen)
+ {
+ sx = 498 - sx;
+ sy = 240 - (16 * height) - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ for (y = 0; y <= height; y++)
+ {
+ pdrawgfx(bitmap, machine->gfx[1],
+ code + y,
+ color,
+ flipx, flipy,
+ sx, sy + (16 * (flipy ? (height - y) : y)),
+ cliprect, TRANSPARENCY_PEN, 15,
+ pri);
+ }
+ }
+}
+
+static void rshark_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /* Sprites take 8 16-bit words each in memory:
+ MSB LSB
+ [offs + 0] ???? ???? ???? ???E
+ [offs + 1] ???? ???? hhhh wwww
+ [offs + 2] ???? ???? ???? ????
+ [offs + 3] cccc cccc cccc cccc
+ [offs + 4] ???? ???x xxxx xxxx
+ [offs + 5] ???? ???? ???? ????
+ [offs + 6] ???? ???y yyyy yyyy
+ [offs + 7] ???? ???? ???? CCCC
+ ? = unused/unknown
+ E = enable
+ c = gfx code
+ x = x offset
+ y = y offset (signed)
+ C = color code
+ w = width
+ h = height */
+
+ int offs;
+
+ for (offs = (spriteram_size / 2) - 8; offs >= 0; offs -= 8)
+ {
+ if (buffered_spriteram16[offs] & 0x0001) /* enable */
+ {
+ int sx, sy, code, color, pri;
+ int flipx = 0, flipy = 0, width, height, x, y;
+
+ sx = buffered_spriteram16[offs+4] & 0x01ff;
+ sy = (INT16)buffered_spriteram16[offs+6] & 0x01ff;
+ if (sy & 0x0100) sy |= ~(int)0x01ff; // Correctly sign-extend 9-bit number
+ code = buffered_spriteram16[offs+3];
+ color = buffered_spriteram16[offs+7] & 0x000f;
+ //TODO: This priority mechanism works for known games, but seems a bit strange.
+ //Are we missing something? (The obvious spare palette bit isn't it.)
+ pri = (((color == 0x00) || (color == 0x0f)) ? 0xfc : 0xf0);
+ width = buffered_spriteram16[offs+1] & 0x000f;
+ height = (buffered_spriteram16[offs+1] & 0x00f0) >> 4;
+
+ if (flip_screen)
+ {
+ sx = 498 - (16 * width) - sx;
+ sy = 240 - (16 * height) - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ for (y = 0; y <= height; y++)
+ {
+ int _y = sy + (16 * (flipy ? (height - y) : y));
+ for (x = 0; x <= width; x++)
+ {
+ int _x = sx + (16 * (flipx ? (width - x) : x));
+ pdrawgfx(bitmap, machine->gfx[0],
+ code,
+ color,
+ flipx, flipy,
+ _x, _y,
+ cliprect, TRANSPARENCY_PEN, 15,
+ pri);
+ code++;
+ }
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( lastday )
+{
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 1);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 2);
+ tilemap_draw(bitmap, cliprect, tx_tilemap, 0, 4);
+
+ if (!sprites_disabled)
+ draw_sprites(machine, bitmap, cliprect, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( gulfstrm )
+{
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 1);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 2);
+ tilemap_draw(bitmap, cliprect, tx_tilemap, 0, 4);
+
+ draw_sprites(machine, bitmap, cliprect, 1);
+ return 0;
+}
+
+VIDEO_UPDATE( pollux )
+{
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 1);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 2);
+ tilemap_draw(bitmap, cliprect, tx_tilemap, 0, 4);
+
+ draw_sprites(machine, bitmap, cliprect, 2);
+ return 0;
+}
+
+VIDEO_UPDATE( flytiger )
+{
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ if (flytiger_pri)
+ {
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 1);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 2);
+ }
+ else
+ {
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 1);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 2);
+ }
+ tilemap_draw(bitmap, cliprect, tx_tilemap, 0, 4);
+
+ draw_sprites(machine, bitmap, cliprect, 4);
+ return 0;
+}
+
+
+VIDEO_UPDATE( bluehawk )
+{
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 1);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 2);
+ tilemap_draw(bitmap, cliprect, fg2_tilemap, 0, 4);
+ tilemap_draw(bitmap, cliprect, tx_tilemap, 0, 4);
+
+ draw_sprites(machine, bitmap, cliprect, 3);
+ return 0;
+}
+
+VIDEO_UPDATE( primella )
+{
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ if (tx_pri) tilemap_draw(bitmap, cliprect, tx_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ if (!tx_pri) tilemap_draw(bitmap, cliprect, tx_tilemap, 0, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( rshark )
+{
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 1);
+ tilemap_draw(bitmap, cliprect, bg2_tilemap, 0, (rshark_pri ? 2 : 1));
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 2);
+ tilemap_draw(bitmap, cliprect, fg2_tilemap, 0, 2);
+
+ rshark_draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( popbingo )
+{
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 1);
+
+ rshark_draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
+
+
+VIDEO_START( lastday )
+{
+ /* Configure tilemap callbacks */
+ bg_tilerom = memory_region(REGION_GFX5);
+ fg_tilerom = memory_region(REGION_GFX6);
+ bg_tilerom2 = NULL;
+ fg_tilerom2 = NULL;
+ bg_gfx = 2;
+ fg_gfx = 3;
+ tx_tilemap_mode = 0;
+
+ /* Create tilemaps */
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 32, 8);
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 32, 8);
+ tx_tilemap = tilemap_create(get_tx_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ /* Configure tilemap transparency */
+ tilemap_set_transparent_pen(fg_tilemap, 15);
+ tilemap_set_transparent_pen(tx_tilemap, 15);
+
+ /* Text layer is offset on this machine */
+ tilemap_set_scrolly(tx_tilemap, 0, 8);
+
+ /* Register for save/restore */
+ state_save_register_global_array(bgscroll8);
+ state_save_register_global_array(fgscroll8);
+ state_save_register_global(sprites_disabled);
+}
+
+VIDEO_START( gulfstrm )
+{
+ /* Configure tilemap callbacks */
+ bg_tilerom = memory_region(REGION_GFX5);
+ fg_tilerom = memory_region(REGION_GFX6);
+ bg_tilerom2 = NULL;
+ fg_tilerom2 = NULL;
+ bg_gfx = 2;
+ fg_gfx = 3;
+ tx_tilemap_mode = 0;
+
+ /* Create tilemaps */
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 32, 8);
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 32, 8);
+ tx_tilemap = tilemap_create(get_tx_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ /* Configure tilemap transparency */
+ tilemap_set_transparent_pen(fg_tilemap, 15);
+ tilemap_set_transparent_pen(tx_tilemap, 15);
+
+ /* Text layer is offset on this machine */
+ tilemap_set_scrolly(tx_tilemap, 0, 8);
+
+ /* Register for save/restore */
+ state_save_register_global_array(bgscroll8);
+ state_save_register_global_array(fgscroll8);
+}
+
+VIDEO_START( pollux )
+{
+ /* Configure tilemap callbacks */
+ bg_tilerom = memory_region(REGION_GFX5);
+ fg_tilerom = memory_region(REGION_GFX6);
+ bg_tilerom2 = NULL;
+ fg_tilerom2 = NULL;
+ bg_gfx = 2;
+ fg_gfx = 3;
+ tx_tilemap_mode = 0;
+
+ /* Create tilemaps */
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 32, 8);
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 32, 8);
+ tx_tilemap = tilemap_create(get_tx_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ /* Configure tilemap transparency */
+ tilemap_set_transparent_pen(fg_tilemap, 15);
+ tilemap_set_transparent_pen(tx_tilemap, 15);
+
+ /* Register for save/restore */
+ state_save_register_global_array(bgscroll8);
+ state_save_register_global_array(fgscroll8);
+}
+
+VIDEO_START( bluehawk )
+{
+ /* Configure tilemap callbacks */
+ bg_tilerom = memory_region(REGION_GFX3) + 0x78000;
+ fg_tilerom = memory_region(REGION_GFX4) + 0x78000;
+ fg2_tilerom = memory_region(REGION_GFX5) + 0x38000;
+ bg_tilerom2 = NULL;
+ fg_tilerom2 = NULL;
+ fg2_tilerom2 = NULL;
+ bg_gfx = 2;
+ fg_gfx = 3;
+ fg2_gfx = 4;
+ tx_tilemap_mode = 1;
+
+ /* Create tilemaps */
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 32, 8);
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 32, 8);
+ fg2_tilemap = tilemap_create(get_fg2_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 32, 8);
+ tx_tilemap = tilemap_create(get_tx_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ /* Configure tilemap transparency */
+ tilemap_set_transparent_pen(fg_tilemap, 15);
+ tilemap_set_transparent_pen(fg2_tilemap, 15);
+ tilemap_set_transparent_pen(tx_tilemap, 15);
+
+ /* Register for save/restore */
+ state_save_register_global_array(bgscroll8);
+ state_save_register_global_array(fgscroll8);
+ state_save_register_global_array(fg2scroll8);
+}
+
+VIDEO_START( flytiger )
+{
+ /* Configure tilemap callbacks */
+ bg_tilerom = memory_region(REGION_GFX3) + 0x78000;
+ fg_tilerom = memory_region(REGION_GFX4) + 0x78000;
+ bg_tilerom2 = NULL;
+ fg_tilerom2 = NULL;
+ bg_gfx = 2;
+ fg_gfx = 3;
+ tx_tilemap_mode = 0;
+
+ /* Create tilemaps */
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 32, 8);
+ fg_tilemap = tilemap_create(flytiger_get_fg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 32, 8);
+ tx_tilemap = tilemap_create(get_tx_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ /* Configure tilemap transparency */
+ tilemap_set_transparent_pen(bg_tilemap, 15);
+ tilemap_set_transparent_pen(fg_tilemap, 15);
+ tilemap_set_transparent_pen(tx_tilemap, 15);
+
+ /* Register for save/restore */
+ state_save_register_global_array(bgscroll8);
+ state_save_register_global_array(fgscroll8);
+ state_save_register_global(flytiger_pri);
+}
+
+VIDEO_START( primella )
+{
+ /* Configure memory banking */
+ memory_configure_bank(1, 0, 8, memory_region(REGION_CPU1) + 0x10000, 0x4000);
+
+ /* Configure tilemap callbacks */
+ bg_tilerom = memory_region(REGION_GFX2) + memory_region_length(REGION_GFX2) - 0x8000;
+ fg_tilerom = memory_region(REGION_GFX3) + memory_region_length(REGION_GFX3) - 0x8000;
+ bg_tilerom2 = NULL;
+ fg_tilerom2 = NULL;
+ bg_gfx = 1;
+ fg_gfx = 2;
+ tx_tilemap_mode = 1;
+
+ /* Create tilemaps */
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 32, 8);
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 32, 8);
+ tx_tilemap = tilemap_create(get_tx_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ /* Configure tilemap transparency */
+ tilemap_set_transparent_pen(fg_tilemap, 15);
+ tilemap_set_transparent_pen(tx_tilemap, 15);
+
+ /* Register for save/restore */
+ state_save_register_global_array(bgscroll8);
+ state_save_register_global_array(fgscroll8);
+ state_save_register_global(tx_pri);
+}
+
+VIDEO_START( rshark )
+{
+ /* Configure tilemap callbacks */
+ bg_tilerom = memory_region(REGION_GFX5);
+ bg2_tilerom = memory_region(REGION_GFX4);
+ fg_tilerom = memory_region(REGION_GFX3);
+ fg2_tilerom = memory_region(REGION_GFX2);
+ bg_tilerom2 = memory_region(REGION_GFX6) + 0x60000;
+ bg2_tilerom2 = memory_region(REGION_GFX6) + 0x40000;
+ fg_tilerom2 = memory_region(REGION_GFX6) + 0x20000;
+ fg2_tilerom2 = memory_region(REGION_GFX6) + 0x00000;
+ bg_gfx = 4;
+ bg2_gfx = 3;
+ fg_gfx = 2;
+ fg2_gfx = 1;
+
+ /* Create tilemaps */
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 16, 16, 64, 32);
+ bg2_tilemap = tilemap_create(get_bg2_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 16, 16, 64, 32);
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 16, 16, 64, 32);
+ fg2_tilemap = tilemap_create(get_fg2_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 16, 16, 64, 32);
+
+ /* Configure tilemap transparency */
+ tilemap_set_transparent_pen(bg2_tilemap, 15);
+ tilemap_set_transparent_pen(fg_tilemap, 15);
+ tilemap_set_transparent_pen(fg2_tilemap, 15);
+
+ /* Register for save/restore */
+ state_save_register_global_array(bgscroll8);
+ state_save_register_global_array(bg2scroll8);
+ state_save_register_global_array(fgscroll8);
+ state_save_register_global_array(fg2scroll8);
+ state_save_register_global(rshark_pri);
+}
+
+VIDEO_START( popbingo )
+{
+ /* Configure tilemap callbacks */
+ bg_tilerom = memory_region(REGION_GFX2);
+ bg_gfx = 1;
+
+ /* Create tilemaps */
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 32, 8);
+ bg2_tilemap = fg_tilemap = fg2_tilemap = NULL; /* Stop scroll handler from crashing on these */
+
+ /* Register for save/restore */
+ state_save_register_global_array(bgscroll8);
+ state_save_register_global_array(bg2scroll8); // Not used atm
+ state_save_register_global_array(fgscroll8); // Not used atm
+ state_save_register_global_array(fg2scroll8); // Not used atm
+ state_save_register_global(rshark_pri);
+}
+
+
+VIDEO_EOF( dooyong )
+{
+ buffer_spriteram_w(0, 0);
+}
+
+VIDEO_EOF( rshark )
+{
+ buffer_spriteram16_w(0, 0, 0);
+}
diff --git a/src/mame/video/dotrikun.c b/src/mame/video/dotrikun.c
new file mode 100644
index 00000000000..e1596f3f77c
--- /dev/null
+++ b/src/mame/video/dotrikun.c
@@ -0,0 +1,56 @@
+/***************************************************************************
+
+Dottori Kun (Head On's mini game)
+(c)1990 SEGA
+
+Driver by Takahiro Nogi (nogi@kt.rim.or.jp) 1999/12/15 -
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+static UINT8 color;
+
+
+WRITE8_HANDLER( dotrikun_color_w )
+{
+ color = data;
+
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+}
+
+
+VIDEO_UPDATE( dotrikun )
+{
+ int offs;
+
+ pen_t back_pen = MAKE_RGB(pal1bit(color >> 3), pal1bit(color >> 4), pal1bit(color >> 5));
+ pen_t fore_pen = MAKE_RGB(pal1bit(color >> 0), pal1bit(color >> 1), pal1bit(color >> 2));
+
+ for (offs = 0; offs < videoram_size; offs++)
+ {
+ int i;
+ UINT8 data = videoram[offs];
+
+ UINT8 x = offs << 4;
+ UINT8 y = offs >> 4 << 1;
+
+ for (i = 0; i < 8; i++)
+ {
+ pen_t pen = (data & 0x80) ? fore_pen : back_pen;
+
+ /* I think the video hardware doubles pixels, screen would be too small otherwise */
+ *BITMAP_ADDR32(bitmap, y + 0, x + 0) = pen;
+ *BITMAP_ADDR32(bitmap, y + 0, x + 1) = pen;
+ *BITMAP_ADDR32(bitmap, y + 1, x + 0) = pen;
+ *BITMAP_ADDR32(bitmap, y + 1, x + 1) = pen;
+
+ x = x + 2;
+ data = data << 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/dragrace.c b/src/mame/video/dragrace.c
new file mode 100644
index 00000000000..1e7c88ae2a5
--- /dev/null
+++ b/src/mame/video/dragrace.c
@@ -0,0 +1,81 @@
+/***************************************************************************
+
+Atari Drag Race video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/dragrace.h"
+
+UINT8* dragrace_playfield_ram;
+UINT8* dragrace_position_ram;
+
+static tilemap* bg_tilemap;
+
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 code = dragrace_playfield_ram[tile_index];
+
+ int num = 0;
+ int col = 0;
+
+ num = code & 0x1f;
+
+ if ((code & 0xc0) == 0x40)
+ {
+ num |= 0x20;
+ }
+
+ switch (code & 0xA0)
+ {
+ case 0x00:
+ col = 0;
+ break;
+ case 0x20:
+ col = 1;
+ break;
+ case 0x80:
+ col = (code & 0x40) ? 1 : 0;
+ break;
+ case 0xA0:
+ col = (code & 0x40) ? 3 : 2;
+ break;
+ }
+
+ SET_TILE_INFO(((code & 0xA0) == 0x80) ? 1 : 0, num, col, 0);
+}
+
+
+VIDEO_START( dragrace )
+{
+ bg_tilemap = tilemap_create(
+ get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 16, 16);
+}
+
+
+VIDEO_UPDATE( dragrace )
+{
+ int y;
+
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+
+ for (y = 0; y < 256; y += 4)
+ {
+ rectangle rect = *cliprect;
+
+ int xl = dragrace_position_ram[y + 0] & 15;
+ int xh = dragrace_position_ram[y + 1] & 15;
+ int yl = dragrace_position_ram[y + 2] & 15;
+ int yh = dragrace_position_ram[y + 3] & 15;
+
+ tilemap_set_scrollx(bg_tilemap, 0, 16 * xh + xl - 8);
+ tilemap_set_scrolly(bg_tilemap, 0, 16 * yh + yl);
+
+ if (rect.min_y < y + 0) rect.min_y = y + 0;
+ if (rect.max_y > y + 3) rect.max_y = y + 3;
+
+ tilemap_draw(bitmap, &rect, bg_tilemap, 0, 0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/drgnmst.c b/src/mame/video/drgnmst.c
new file mode 100644
index 00000000000..0aadf24ae73
--- /dev/null
+++ b/src/mame/video/drgnmst.c
@@ -0,0 +1,209 @@
+// remaining gfx glitches
+
+// layer priority register not fully understood
+
+#include "driver.h"
+
+extern UINT16 *drgnmst_vidregs;
+
+extern UINT16 *drgnmst_fg_videoram;
+static tilemap *drgnmst_fg_tilemap;
+extern UINT16 *drgnmst_bg_videoram;
+static tilemap *drgnmst_bg_tilemap;
+extern UINT16 *drgnmst_md_videoram;
+static tilemap *drgnmst_md_tilemap;
+
+extern UINT16 *drgnmst_rowscrollram;
+extern UINT16 *drgnmst_vidregs2;
+
+
+static TILE_GET_INFO( get_drgnmst_fg_tile_info )
+{
+ int tileno,colour, flipyx;
+ tileno = drgnmst_fg_videoram[tile_index*2] & 0xfff;
+ colour = drgnmst_fg_videoram[tile_index*2+1] & 0x1f;
+ flipyx = (drgnmst_fg_videoram[tile_index*2+1] & 0x60)>>5;
+
+ SET_TILE_INFO(1,tileno,colour,TILE_FLIPYX(flipyx));
+}
+
+WRITE16_HANDLER( drgnmst_fg_videoram_w )
+{
+ COMBINE_DATA(&drgnmst_fg_videoram[offset]);
+ tilemap_mark_tile_dirty(drgnmst_fg_tilemap,offset/2);
+}
+
+
+
+static TILE_GET_INFO( get_drgnmst_bg_tile_info )
+{
+ int tileno,colour,flipyx;
+ tileno = (drgnmst_bg_videoram[tile_index*2]& 0x1fff)+0x800;
+ colour = drgnmst_bg_videoram[tile_index*2+1] & 0x1f;
+ flipyx = (drgnmst_bg_videoram[tile_index*2+1] & 0x60)>>5;
+
+ SET_TILE_INFO(3,tileno,colour,TILE_FLIPYX(flipyx));
+}
+
+WRITE16_HANDLER( drgnmst_bg_videoram_w )
+{
+ COMBINE_DATA(&drgnmst_bg_videoram[offset]);
+ tilemap_mark_tile_dirty(drgnmst_bg_tilemap,offset/2);
+}
+
+static TILE_GET_INFO( get_drgnmst_md_tile_info )
+{
+ int tileno,colour,flipyx;
+ tileno = (drgnmst_md_videoram[tile_index*2]& 0x7fff)-0x2000;
+
+ colour = drgnmst_md_videoram[tile_index*2+1] & 0x1f;
+ flipyx = (drgnmst_md_videoram[tile_index*2+1] & 0x60)>>5;
+
+ SET_TILE_INFO(2,tileno,colour,TILE_FLIPYX(flipyx));
+}
+
+WRITE16_HANDLER( drgnmst_md_videoram_w )
+{
+ COMBINE_DATA(&drgnmst_md_videoram[offset]);
+ tilemap_mark_tile_dirty(drgnmst_md_tilemap,offset/2);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ const gfx_element *gfx = machine->gfx[0];
+ UINT16 *source = spriteram16;
+ UINT16 *finish = source + 0x800/2;
+
+ while( source<finish )
+ {
+ int xpos, ypos, number, flipx,flipy,wide,high;
+ int x,y;
+ int incx,incy;
+ int colr;
+
+ number = source[2];
+ xpos = source[0];
+ ypos = source[1];
+ flipx = source[3] & 0x0020;
+ flipy = source[3] & 0x0040;
+ wide = (source[3] & 0x0f00)>>8;
+ high = (source[3] & 0xf000)>>12;
+ colr = (source[3] & 0x001f);
+
+ if ((source[3] & 0xff00) == 0xff00) break;
+
+
+ if (!flipx) { incx = 16;} else { incx = -16; xpos += 16*wide; }
+ if (!flipy) { incy = 16;} else { incy = -16; ypos += 16*high; }
+
+
+ for (y=0;y<=high;y++) {
+ for (x=0;x<=wide;x++) {
+
+ int realx, realy, realnumber;
+
+ realx = xpos+incx*x;
+ realy = ypos+incy*y;
+ realnumber = number+x+y*16;
+
+ drawgfx(bitmap,gfx,realnumber,colr,flipx,flipy,realx,realy,cliprect,TRANSPARENCY_PEN,15);
+
+ }
+ }
+
+ source+=4;
+ }
+}
+
+
+static TILEMAP_MAPPER( drgnmst_fg_tilemap_scan_cols )
+{
+ return (col*32)+(row&0x1f)+((row&0xe0)>>5)*2048;
+}
+
+static TILEMAP_MAPPER( drgnmst_md_tilemap_scan_cols )
+{
+ return (col*16)+(row&0x0f)+((row&0xf0)>>4)*1024;
+}
+
+static TILEMAP_MAPPER( drgnmst_bg_tilemap_scan_cols )
+{
+ return (col*8)+(row&0x07)+((row&0xf8)>>3)*512;
+}
+
+VIDEO_START(drgnmst)
+{
+ drgnmst_fg_tilemap = tilemap_create(get_drgnmst_fg_tile_info,drgnmst_fg_tilemap_scan_cols,TILEMAP_TYPE_PEN, 8, 8, 64,64);
+ tilemap_set_transparent_pen(drgnmst_fg_tilemap,15);
+
+ drgnmst_md_tilemap = tilemap_create(get_drgnmst_md_tile_info,drgnmst_md_tilemap_scan_cols,TILEMAP_TYPE_PEN, 16, 16, 64,64);
+ tilemap_set_transparent_pen(drgnmst_md_tilemap,15);
+
+ drgnmst_bg_tilemap = tilemap_create(get_drgnmst_bg_tile_info,drgnmst_bg_tilemap_scan_cols,TILEMAP_TYPE_PEN, 32, 32, 64,64);
+ tilemap_set_transparent_pen(drgnmst_bg_tilemap,15);
+
+ // do the other tilemaps have rowscroll too? probably not ..
+ tilemap_set_scroll_rows(drgnmst_md_tilemap,1024);
+}
+
+VIDEO_UPDATE(drgnmst)
+{
+ int y, rowscroll_bank;
+
+ tilemap_set_scrollx(drgnmst_bg_tilemap,0, drgnmst_vidregs[10]-18); // verify
+ tilemap_set_scrolly(drgnmst_bg_tilemap,0, drgnmst_vidregs[11]); // verify
+
+// tilemap_set_scrollx(drgnmst_md_tilemap,0, drgnmst_vidregs[8]-16); // rowscrolled
+ tilemap_set_scrolly(drgnmst_md_tilemap,0, drgnmst_vidregs[9]); // verify
+
+ tilemap_set_scrollx(drgnmst_fg_tilemap,0, drgnmst_vidregs[6]-18); // verify (test mode colour test needs it)
+ tilemap_set_scrolly(drgnmst_fg_tilemap,0, drgnmst_vidregs[7]); // verify
+
+ rowscroll_bank = (drgnmst_vidregs[4] & 0x30) >> 4;
+
+ for (y = 0; y < 1024; y++)
+ tilemap_set_scrollx(drgnmst_md_tilemap,y, drgnmst_vidregs[8]-16+drgnmst_rowscrollram[y+0x800*rowscroll_bank]);
+
+ // todo: figure out which bits relate to the order
+ switch (drgnmst_vidregs2[0])
+ {
+ case 0x2451: // fg unsure
+ case 0x2d9a: // fg unsure
+ case 0x2440: // all ok
+ case 0x245a: // fg unsure, title screen
+ tilemap_draw(bitmap,cliprect,drgnmst_fg_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,drgnmst_md_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,drgnmst_bg_tilemap,0,0);
+ break;
+ case 0x23c0: // all ok
+ tilemap_draw(bitmap,cliprect,drgnmst_bg_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,drgnmst_fg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,drgnmst_md_tilemap,0,0);
+ break;
+ case 0x38da: // fg unsure
+ case 0x215a: // fg unsure
+ case 0x2140: // all ok
+ tilemap_draw(bitmap,cliprect,drgnmst_fg_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,drgnmst_bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,drgnmst_md_tilemap,0,0);
+ break;
+ case 0x2d80: // all ok
+ tilemap_draw(bitmap,cliprect,drgnmst_md_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,drgnmst_bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,drgnmst_fg_tilemap,0,0);
+ break;
+ default:
+ tilemap_draw(bitmap,cliprect,drgnmst_bg_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,drgnmst_fg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,drgnmst_md_tilemap,0,0);
+ logerror ("unknown video priority regs %04x\n", drgnmst_vidregs2[0]);
+
+ }
+
+ draw_sprites(machine,bitmap,cliprect);
+
+// popmessage ("x %04x x %04x x %04x x %04x x %04x", drgnmst_vidregs2[0], drgnmst_vidregs[12], drgnmst_vidregs[13], drgnmst_vidregs[14], drgnmst_vidregs[15]);
+// popmessage ("x %04x x %04x y %04x y %04x z %04x z %04x",drgnmst_vidregs[0],drgnmst_vidregs[1],drgnmst_vidregs[2],drgnmst_vidregs[3],drgnmst_vidregs[4],drgnmst_vidregs[5]);
+
+ return 0;
+}
diff --git a/src/mame/video/dribling.c b/src/mame/video/dribling.c
new file mode 100644
index 00000000000..91c61755e48
--- /dev/null
+++ b/src/mame/video/dribling.c
@@ -0,0 +1,85 @@
+/***************************************************************************
+
+ Model Racing Dribbling hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "dribling.h"
+
+
+/*************************************
+ *
+ * Convert the palette PROM into
+ * a real palette
+ *
+ *************************************/
+
+PALETTE_INIT( dribling )
+{
+ const UINT8 *prom = memory_region(REGION_PROMS) + 0x400;
+ int i;
+
+ for (i = 0; i < 256; i++)
+ {
+ int r = (~prom[i] >> 0) & 1; // 220
+ int g = (~prom[i] >> 1) & 3; // 820 + 560 (332 max)
+ int b = (~prom[i] >> 3) & 1; // 220
+
+ r *= 0xff;
+ g *= 0x55;
+ b *= 0xff;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+
+
+/*************************************
+ *
+ * Color control writes
+ *
+ *************************************/
+
+WRITE8_HANDLER( dribling_colorram_w )
+{
+ /* it is very important that we mask off the two bits here */
+ colorram[offset & 0x1f9f] = data;
+}
+
+
+
+/*************************************
+ *
+ * Video update routine
+ *
+ *************************************/
+
+VIDEO_UPDATE( dribling )
+{
+ UINT8 *prombase = memory_region(REGION_PROMS);
+ UINT8 *gfxbase = memory_region(REGION_GFX1);
+ int x, y;
+
+ /* loop over rows */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *dst = BITMAP_ADDR16(bitmap, y, 0);
+
+ /* loop over columns */
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ int b7 = prombase[(x >> 3) | ((y >> 3) << 5)] & 1;
+ int b6 = dribling_abca;
+ int b5 = (x >> 3) & 1;
+ int b4 = (gfxbase[(x >> 3) | (y << 5)] >> (x & 7)) & 1;
+ int b3 = (videoram[(x >> 3) | (y << 5)] >> (x & 7)) & 1;
+ int b2_0 = colorram[(x >> 3) | ((y >> 2) << 7)] & 7;
+
+ /* assemble the various bits into a palette PROM index */
+ dst[x] = (b7 << 7) | (b6 << 6) | (b5 << 5) | (b4 << 4) | (b3 << 3) | b2_0;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/drmicro.c b/src/mame/video/drmicro.c
new file mode 100644
index 00000000000..fddcc3c5ab3
--- /dev/null
+++ b/src/mame/video/drmicro.c
@@ -0,0 +1,166 @@
+/*******************************************************************************
+
+Dr. Micro (c) 1983 Sanritsu
+
+Video hardware
+ driver by Uki
+
+*******************************************************************************/
+
+#include "driver.h"
+
+static int flipscreen;
+
+static UINT8 *drmicro_videoram;
+static tilemap *drmicro_bg1;
+static tilemap *drmicro_bg2;
+
+/****************************************************************************/
+
+void drmicro_flip_w( int flip )
+{
+ flipscreen = flip ? 1 : 0;
+ flip_screen_set(flip);
+}
+
+WRITE8_HANDLER( drmicro_videoram_w )
+{
+ drmicro_videoram[offset] = data;
+
+ if (offset<0x800)
+ tilemap_mark_tile_dirty(drmicro_bg2,(offset & 0x3ff));
+ else
+ tilemap_mark_tile_dirty(drmicro_bg1,(offset & 0x3ff));
+}
+
+READ8_HANDLER( drmicro_videoram_r )
+{
+ return drmicro_videoram[offset];
+}
+
+/****************************************************************************/
+
+static TILE_GET_INFO( get_bg1_tile_info )
+{
+ int code,col,flags;
+
+ code = drmicro_videoram[tile_index + 0x0800];
+ col = drmicro_videoram[tile_index + 0x0c00];
+
+ code += (col & 0xc0) << 2;
+ flags = ((col & 0x20) ? TILEMAP_FLIPY : 0) | ((col & 0x10) ? TILEMAP_FLIPX : 0);
+ col &= 0x0f;
+
+ SET_TILE_INFO( 0, code, col, flags);
+}
+
+static TILE_GET_INFO( get_bg2_tile_info )
+{
+ int code,col,flags;
+
+ code = drmicro_videoram[tile_index + 0x0000];
+ col = drmicro_videoram[tile_index + 0x0400];
+
+ code += (col & 0xc0) << 2;
+ flags = ((col & 0x20) ? TILEMAP_FLIPY : 0) | ((col & 0x10) ? TILEMAP_FLIPX : 0);
+ col &= 0x0f;
+
+ SET_TILE_INFO( 1, code, col, flags);
+}
+
+/****************************************************************************/
+
+PALETTE_INIT( drmicro )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ for (i=0; i<machine->drv->color_table_len; i++)
+ colortable[i] = color_prom[i] & 0x0f;
+}
+
+VIDEO_START( drmicro)
+{
+ drmicro_videoram = auto_malloc(0x1000);
+
+ drmicro_bg1 = tilemap_create(get_bg1_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,32,32);
+ drmicro_bg2 = tilemap_create(get_bg2_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,32,32);
+
+ tilemap_set_transparent_pen(drmicro_bg2,0);
+}
+
+VIDEO_UPDATE( drmicro )
+{
+ int offs,adr,g;
+ int chr,col,attr;
+ int x,y,fx,fy;
+
+ tilemap_draw(bitmap, cliprect, drmicro_bg1, 0, 0);
+ tilemap_draw(bitmap, cliprect, drmicro_bg2, 0, 0);
+
+ /* draw sprites */
+
+ for (g=0;g<2;g++)
+ {
+ adr = 0x800*g;
+
+ for (offs=0x00; offs<0x20; offs +=4)
+ {
+ x = drmicro_videoram[offs + adr + 3];
+ y = drmicro_videoram[offs + adr + 0];
+ attr = drmicro_videoram[offs + adr + 2];
+ chr = drmicro_videoram[offs + adr + 1];
+
+ fx = (chr & 0x01) ^ flipscreen;
+ fy = ((chr & 0x02) >> 1) ^ flipscreen;
+
+ chr = (chr >> 2) | (attr & 0xc0);
+
+ col = (attr & 0x0f) + 0x00;
+
+ if (!flipscreen)
+ y = (240-y) & 0xff;
+ else
+ x = (240-x) & 0xff;
+
+ drawgfx(bitmap,machine->gfx[3-g],
+ chr,
+ col,
+ fx,fy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ if (x>240)
+ {
+ drawgfx(bitmap,machine->gfx[3-g],
+ chr,
+ col,
+ fx,fy,
+ x-256,y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+ return 0;
+}
+
diff --git a/src/mame/video/dynax.c b/src/mame/video/dynax.c
new file mode 100644
index 00000000000..0215ec39338
--- /dev/null
+++ b/src/mame/video/dynax.c
@@ -0,0 +1,1341 @@
+/***************************************************************************
+
+ The CPU controls a video blitter that can read data from the ROMs
+ (instructions to draw pixel by pixel, in a compressed form) and write to
+ up to 8 frame buffers.
+
+ hanamai:
+ There are four scrolling layers. Each layer consists of 2 frame buffers.
+ The 2 images are interleaved to form the final picture sent to the screen.
+
+ drgpunch:
+ There are three scrolling layers. Each layer consists of 2 frame buffers.
+ The 2 images are interleaved to form the final picture sent to the screen.
+
+ mjdialq2:
+ Two scrolling layers.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/dynax.h"
+
+// Log Blitter
+#define VERBOSE 0
+
+
+/* 0 B01234 G01234 R01234 */
+PALETTE_INIT( sprtmtch )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int x = (color_prom[i]<<8) + color_prom[0x200+i];
+ /* The bits are in reverse order! */
+ int r = BITSWAP8((x >> 0) & 0x1f, 7,6,5, 0,1,2,3,4 );
+ int g = BITSWAP8((x >> 5) & 0x1f, 7,6,5, 0,1,2,3,4 );
+ int b = BITSWAP8((x >> 10) & 0x1f, 7,6,5, 0,1,2,3,4 );
+ palette_set_color_rgb(machine,i,pal5bit(r),pal5bit(g),pal5bit(b));
+ }
+}
+
+/***************************************************************************
+
+
+ Video Blitter(s)
+
+
+***************************************************************************/
+
+
+static int dynax_blit_scroll_x, dynax_blit2_scroll_x;
+static int dynax_blit_scroll_y, dynax_blit2_scroll_y;
+static int dynax_blit_wrap_enable, dynax_blit2_wrap_enable;
+static int blit_x,blit_y, blit2_x,blit2_y;
+static int blit_src, blit2_src;
+static int dynax_blit_romregion, dynax_blit2_romregion;
+static int dynax_blit_dest, dynax_blit2_dest;
+static int dynax_blit_pen, dynax_blit2_pen;
+static int dynax_blit_palbank, dynax_blit2_palbank;
+static int dynax_blit_palettes, dynax_blit2_palettes;
+static int dynax_layer_enable;
+static int dynax_blit_backpen;
+
+static int hanamai_layer_half;
+static int hnoridur_layer_half2;
+
+static int extra_scroll_x,extra_scroll_y;
+static int flipscreen;
+
+#define LAYOUT_HANAMAI 0 // 4 layers, interleaved
+#define LAYOUT_HNORIDUR 1 // same as hanamai but some bits are inverted and layer order is reversed
+#define LAYOUT_DRGPUNCH 2 // 3 couples of layers, interleaved
+#define LAYOUT_MJDIALQ2 3 // 2 layers
+#define LAYOUT_JANTOUKI 4 // 2 x (4 couples of layers, interleaved)
+
+static int layer_layout;
+
+static void (*update_irq_func)(void); // some games trigger IRQ at blitter end, some don't
+
+// up to 8 layers, 2 images per layer (interleaved on screen)
+static UINT8 *dynax_pixmap[8][2];
+
+
+
+WRITE8_HANDLER( dynax_extra_scrollx_w )
+{
+ extra_scroll_x = data;
+}
+
+WRITE8_HANDLER( dynax_extra_scrolly_w )
+{
+ extra_scroll_y = data;
+}
+
+
+/* Destination Pen */
+WRITE8_HANDLER( dynax_blit_pen_w )
+{
+ dynax_blit_pen = data;
+#if VERBOSE
+ logerror("P=%02X ",data);
+#endif
+}
+WRITE8_HANDLER( dynax_blit2_pen_w )
+{
+ dynax_blit2_pen = data;
+#if VERBOSE
+ logerror("P'=%02X ",data);
+#endif
+}
+
+/* Destination Layers */
+WRITE8_HANDLER( dynax_blit_dest_w )
+{
+ dynax_blit_dest = data;
+ if (layer_layout == LAYOUT_HNORIDUR)
+ dynax_blit_dest = BITSWAP8(dynax_blit_dest ^ 0x0f, 7,6,5,4, 0,1,2,3);
+
+#if VERBOSE
+ logerror("D=%02X ",data);
+#endif
+}
+WRITE8_HANDLER( dynax_blit2_dest_w )
+{
+ dynax_blit2_dest = data;
+#if VERBOSE
+ logerror("D'=%02X ",data);
+#endif
+}
+WRITE8_HANDLER( tenkai_blit_dest_w )
+{
+ dynax_blit_dest_w(0, BITSWAP8(data, 7,6,5,4, 0,1,2,3));
+}
+
+/* Background Color */
+WRITE8_HANDLER( dynax_blit_backpen_w )
+{
+ dynax_blit_backpen = data;
+#if VERBOSE
+ logerror("B=%02X ",data);
+#endif
+}
+
+/* Layers 0&1 Palettes (Low Bits) */
+WRITE8_HANDLER( dynax_blit_palette01_w )
+{
+ if (layer_layout == LAYOUT_HNORIDUR)
+ dynax_blit_palettes = (dynax_blit_palettes & 0x00ff) | ((data&0x0f)<<12) | ((data&0xf0)<<4);
+ else
+ dynax_blit_palettes = (dynax_blit_palettes & 0xff00) | data;
+#if VERBOSE
+ logerror("P01=%02X ",data);
+#endif
+}
+WRITE8_HANDLER( tenkai_blit_palette01_w )
+{
+ dynax_blit_palettes = (dynax_blit_palettes & 0xff00) | data;
+#if VERBOSE
+ logerror("P01=%02X ",data);
+#endif
+}
+
+/* Layers 4&5 Palettes (Low Bits) */
+WRITE8_HANDLER( dynax_blit_palette45_w )
+{
+ if (layer_layout == LAYOUT_HNORIDUR)
+ dynax_blit2_palettes = (dynax_blit2_palettes & 0x00ff) | ((data&0x0f)<<12) | ((data&0xf0)<<4);
+ else
+ dynax_blit2_palettes = (dynax_blit2_palettes & 0xff00) | data;
+#if VERBOSE
+ logerror("P45=%02X ",data);
+#endif
+}
+
+/* Layer 2&3 Palettes (Low Bits) */
+WRITE8_HANDLER( dynax_blit_palette23_w )
+{
+ if (layer_layout == LAYOUT_HNORIDUR)
+ dynax_blit_palettes = (dynax_blit_palettes & 0xff00) | ((data&0x0f)<<4) | ((data&0xf0)>>4);
+ else
+ dynax_blit_palettes = (dynax_blit_palettes & 0x00ff) | (data<<8);
+#if VERBOSE
+ logerror("P23=%02X ",data);
+#endif
+}
+WRITE8_HANDLER( tenkai_blit_palette23_w )
+{
+ dynax_blit_palettes = (dynax_blit_palettes & 0x00ff) | ((data&0x0f)<<12) | ((data&0xf0)<<4);
+#if VERBOSE
+ logerror("P23=%02X ",data);
+#endif
+}
+/* Layer 6&7 Palettes (Low Bits) */
+WRITE8_HANDLER( dynax_blit_palette67_w )
+{
+ if (layer_layout == LAYOUT_HNORIDUR)
+ dynax_blit2_palettes = (dynax_blit2_palettes & 0xff00) | ((data&0x0f)<<4) | ((data&0xf0)>>4);
+ else
+ dynax_blit2_palettes = (dynax_blit2_palettes & 0x00ff) | (data<<8);
+#if VERBOSE
+ logerror("P67=%02X ",data);
+#endif
+}
+
+
+
+/* Layers Palettes (High Bits) */
+WRITE8_HANDLER( dynax_blit_palbank_w )
+{
+ dynax_blit_palbank = data;
+#if VERBOSE
+ logerror("PB=%02X ",data);
+#endif
+}
+WRITE8_HANDLER( dynax_blit2_palbank_w )
+{
+ dynax_blit2_palbank = data;
+#if VERBOSE
+ logerror("PB'=%02X ",data);
+#endif
+}
+
+/* Which half of the layers to write two (interleaved games only) */
+WRITE8_HANDLER( hanamai_layer_half_w )
+{
+ hanamai_layer_half = (~data) & 1;
+#if VERBOSE
+ logerror("H=%02X ",data);
+#endif
+}
+
+/* Write to both halves of the layers (interleaved games only) */
+WRITE8_HANDLER( hnoridur_layer_half2_w )
+{
+ hnoridur_layer_half2 = (~data) & 1;
+#if VERBOSE
+ logerror("H2=%02X ",data);
+#endif
+}
+
+WRITE8_HANDLER( mjdialq2_blit_dest_w )
+{
+ int mask = (2 >> offset); /* 1 or 2 */
+
+ dynax_blit_dest &= ~mask;
+ if (~data & 1) dynax_blit_dest |= mask;
+}
+
+/* Layers Enable */
+WRITE8_HANDLER( dynax_layer_enable_w )
+{
+ dynax_layer_enable = data;
+#if VERBOSE
+ logerror("E=%02X ",data);
+#endif
+}
+
+WRITE8_HANDLER( jantouki_layer_enable_w )
+{
+ int mask = 1 << (7-offset);
+ dynax_layer_enable = (dynax_layer_enable & ~mask) | ((data & 1) ? mask : 0);
+ dynax_layer_enable |= 1;
+}
+
+WRITE8_HANDLER( mjdialq2_layer_enable_w )
+{
+ int mask = (2 >> offset); /* 1 or 2 */
+
+ dynax_layer_enable &= ~mask;
+ if (~data & 1) dynax_layer_enable |= mask;
+}
+
+
+WRITE8_HANDLER( dynax_flipscreen_w )
+{
+ flipscreen = data & 1;
+ if (data & ~1)
+ logerror("CPU#0 PC %06X: Warning, flip screen <- %02X\n", activecpu_get_pc(), data);
+#if VERBOSE
+ logerror("F=%02X ",data);
+#endif
+}
+
+
+WRITE8_HANDLER( dynax_blit_romregion_w )
+{
+ dynax_blit_romregion = REGION_GFX1 + data;
+#if VERBOSE
+ logerror("GFX%X ",data+1);
+#endif
+}
+
+WRITE8_HANDLER( dynax_blit2_romregion_w )
+{
+ dynax_blit2_romregion = REGION_GFX2 + data;
+#if VERBOSE
+ logerror("GFX%X' ",data+2);
+#endif
+}
+
+/***************************************************************************
+
+ Blitter Data Format
+
+ The blitter reads its commands from the gfx ROMs. They are
+ instructions to draw an image pixel by pixel (in a compressed
+ form) in a frame buffer.
+
+ Fetch 1 Byte from the ROM:
+
+ 7654 ---- Pen to draw with
+ ---- 3210 Command
+
+ Other bytes may follow, depending on the command
+
+ Commands:
+
+ 0 Stop.
+ 1-b Draw 1-b pixels along X.
+ c Followed by 1 byte (N): draw N pixels along X.
+ d Followed by 2 bytes (X,N): skip X pixels, draw N pixels along X.
+ e ? unused
+ f Increment Y
+
+***************************************************************************/
+
+
+/* Plot a pixel (in the pixmaps specified by dynax_blit_dest) */
+INLINE void blitter_plot_pixel(int layer,int mask, int x, int y, int pen, int wrap, int flags)
+{
+ int addr;
+
+ if ( (y > 0xff) && (!(wrap & 2)) ) return; // fixes mjdialq2 & mjangels title screens
+ if ( (x > 0xff) && (!(wrap & 1)) ) return;
+
+ x &= 0xff; // confirmed by some mjdialq2 gfx and especially by mjfriday, which
+ // uses the front layer to mask out the right side of the screen as
+ // it draws stuff on the left, when it shows the girls scrolling
+ // horizontally after you win.
+ y &= 0xff; // seems confirmed by mjdialq2 last picture of gal 6, but it breaks
+ // mjdialq2 title screen so there's something we are missing. <fixed, see above>
+
+ /* "Flip Screen" just means complement the coordinates to 255 */
+ if (flipscreen) { x ^= 0xff; y ^= 0xff; }
+
+ /* Rotate: rotation = SWAPXY + FLIPY */
+ if (flags & 0x08) { int t = x; x = y; y = t; }
+
+ addr = x + (y<<8);
+
+ switch (layer_layout)
+ {
+ case LAYOUT_HANAMAI:
+ if (mask & 0x01) dynax_pixmap[layer+0][hanamai_layer_half^flipscreen][addr] = pen;
+ if (mask & 0x02) dynax_pixmap[layer+1][hanamai_layer_half^flipscreen][addr] = pen;
+ if (mask & 0x04) dynax_pixmap[layer+2][hanamai_layer_half^flipscreen][addr] = pen;
+ if (mask & 0x08) dynax_pixmap[layer+3][hanamai_layer_half^flipscreen][addr] = pen;
+ break;
+
+ case LAYOUT_HNORIDUR:
+ if (mask & 0x01) dynax_pixmap[layer+0][hanamai_layer_half^flipscreen][addr] = pen;
+ if (mask & 0x02) dynax_pixmap[layer+1][hanamai_layer_half^flipscreen][addr] = pen;
+ if (mask & 0x04) dynax_pixmap[layer+2][hanamai_layer_half^flipscreen][addr] = pen;
+ if (mask & 0x08) dynax_pixmap[layer+3][hanamai_layer_half^flipscreen][addr] = pen;
+ if (!hnoridur_layer_half2) break;
+ if (mask & 0x01) dynax_pixmap[layer+0][1^hanamai_layer_half^flipscreen][addr] = pen;
+ if (mask & 0x02) dynax_pixmap[layer+1][1^hanamai_layer_half^flipscreen][addr] = pen;
+ if (mask & 0x04) dynax_pixmap[layer+2][1^hanamai_layer_half^flipscreen][addr] = pen;
+ if (mask & 0x08) dynax_pixmap[layer+3][1^hanamai_layer_half^flipscreen][addr] = pen;
+ break;
+
+ case LAYOUT_JANTOUKI:
+ if (mask & 0x80) dynax_pixmap[layer+3][1^flipscreen][addr] = pen;
+ if (mask & 0x40) dynax_pixmap[layer+3][0^flipscreen][addr] = pen;
+ case LAYOUT_DRGPUNCH:
+ if (mask & 0x20) dynax_pixmap[layer+2][1^flipscreen][addr] = pen;
+ if (mask & 0x10) dynax_pixmap[layer+2][0^flipscreen][addr] = pen;
+ if (mask & 0x08) dynax_pixmap[layer+1][1^flipscreen][addr] = pen;
+ if (mask & 0x04) dynax_pixmap[layer+1][0^flipscreen][addr] = pen;
+ if (mask & 0x02) dynax_pixmap[layer+0][1^flipscreen][addr] = pen;
+ if (mask & 0x01) dynax_pixmap[layer+0][0^flipscreen][addr] = pen;
+ break;
+
+ case LAYOUT_MJDIALQ2:
+ if (mask & 0x01) dynax_pixmap[layer+0][0][addr] = pen;
+ if (mask & 0x02) dynax_pixmap[layer+1][0][addr] = pen;
+ break;
+ }
+}
+
+
+static int blitter_drawgfx( int layer, int mask, int gfx, int src, int pen, int x, int y, int wrap, int flags )
+{
+ UINT8 cmd;
+
+ UINT8 *ROM = memory_region( gfx );
+ size_t ROM_size = memory_region_length( gfx );
+
+ int sx;
+
+ if (layer_layout == LAYOUT_HNORIDUR) // e.g. yarunara
+ pen = ((pen >> 4) & 0xf) | ( (mask & 0x10) ? ((pen & 0x08) << 1) : 0 );
+ else
+ pen = (pen >> 4) & 0xf;
+
+if (flags & 0xf4) popmessage("flags %02x",flags);
+ if ( flags & 1 )
+ {
+ int start,len;
+
+ /* Clear the buffer(s) starting from the given scanline and exit */
+
+ int addr = x + (y<<8);
+
+ if (flipscreen)
+ start = 0;
+ else
+ start = addr;
+
+ len = 0x10000 - addr;
+
+ switch (layer_layout)
+ {
+ case LAYOUT_HANAMAI:
+ if (mask & 0x01) memset(&dynax_pixmap[layer+0][0][start],pen,len);
+ if (mask & 0x01) memset(&dynax_pixmap[layer+0][1][start],pen,len);
+ if (mask & 0x02) memset(&dynax_pixmap[layer+1][0][start],pen,len);
+ if (mask & 0x02) memset(&dynax_pixmap[layer+1][1][start],pen,len);
+ if (mask & 0x04) memset(&dynax_pixmap[layer+2][0][start],pen,len);
+ if (mask & 0x04) memset(&dynax_pixmap[layer+2][1][start],pen,len);
+ if (mask & 0x08) memset(&dynax_pixmap[layer+3][0][start],pen,len);
+ if (mask & 0x08) memset(&dynax_pixmap[layer+3][1][start],pen,len);
+ break;
+
+ case LAYOUT_HNORIDUR:
+ if (mask & 0x01) memset(&dynax_pixmap[layer+0][hanamai_layer_half][start],pen,len);
+ if (mask & 0x02) memset(&dynax_pixmap[layer+1][hanamai_layer_half][start],pen,len);
+ if (mask & 0x04) memset(&dynax_pixmap[layer+2][hanamai_layer_half][start],pen,len);
+ if (mask & 0x08) memset(&dynax_pixmap[layer+3][hanamai_layer_half][start],pen,len);
+ if (!hnoridur_layer_half2) break;
+ if (mask & 0x01) memset(&dynax_pixmap[layer+0][1-hanamai_layer_half][start],pen,len);
+ if (mask & 0x02) memset(&dynax_pixmap[layer+1][1-hanamai_layer_half][start],pen,len);
+ if (mask & 0x04) memset(&dynax_pixmap[layer+2][1-hanamai_layer_half][start],pen,len);
+ if (mask & 0x08) memset(&dynax_pixmap[layer+3][1-hanamai_layer_half][start],pen,len);
+ break;
+
+ case LAYOUT_JANTOUKI:
+ if (mask & 0x80) memset(&dynax_pixmap[layer+3][1][start],pen,len);
+ if (mask & 0x40) memset(&dynax_pixmap[layer+3][0][start],pen,len);
+ case LAYOUT_DRGPUNCH:
+ if (mask & 0x20) memset(&dynax_pixmap[layer+2][1][start],pen,len);
+ if (mask & 0x10) memset(&dynax_pixmap[layer+2][0][start],pen,len);
+ if (mask & 0x08) memset(&dynax_pixmap[layer+1][1][start],pen,len);
+ if (mask & 0x04) memset(&dynax_pixmap[layer+1][0][start],pen,len);
+ if (mask & 0x02) memset(&dynax_pixmap[layer+0][1][start],pen,len);
+ if (mask & 0x01) memset(&dynax_pixmap[layer+0][0][start],pen,len);
+ break;
+
+ case LAYOUT_MJDIALQ2:
+ if (mask & 0x01) memset(&dynax_pixmap[layer+0][0][start],pen,len);
+ if (mask & 0x02) memset(&dynax_pixmap[layer+1][0][start],pen,len);
+ break;
+ }
+
+ return src;
+ }
+
+ sx = x;
+
+ src &= 0xfffff;
+
+ for ( ;; )
+ {
+ if (src >= ROM_size)
+ {
+popmessage("GFXROM OVER %08x",src);
+ return src;
+ }
+ cmd = ROM[src++];
+ src &= 0xfffff;
+ if (!(flags & 0x02)) // Ignore the pens specified in ROM, draw everything with the pen supplied as parameter
+ pen = (pen & 0xf0) | ((cmd & 0xf0)>>4);
+ cmd = (cmd & 0x0f);
+
+ switch (cmd)
+ {
+ case 0xf: // Increment Y
+ /* Rotate: rotation = SWAPXY + FLIPY */
+ if (flags & 0x08)
+ y--;
+ else
+ y++;
+ x = sx;
+ break;
+
+ case 0xe: // unused ? was "change dest mask" in the "rev1" blitter
+ popmessage("Blitter unknown command %06X: %02X\n", src-1, cmd);
+
+ case 0xd: // Skip X pixels
+ if (src >= ROM_size)
+ {
+popmessage("GFXROM OVER %08x",src);
+ return src;
+ }
+ x = sx + ROM[src++];
+ src &= 0xfffff;
+ /* fall through into next case */
+
+ case 0xc: // Draw N pixels
+ if (src >= ROM_size)
+ {
+popmessage("GFXROM OVER %08x",src);
+ return src;
+ }
+ cmd = ROM[src++];
+ src &= 0xfffff;
+ /* fall through into next case */
+
+ case 0xb:
+ case 0xa:
+ case 0x9:
+ case 0x8:
+ case 0x7:
+ case 0x6:
+ case 0x5:
+ case 0x4:
+ case 0x3:
+ case 0x2:
+ case 0x1: // Draw N pixels
+ while (cmd--)
+ blitter_plot_pixel(layer, mask, x++, y, pen, wrap, flags);
+ break;
+
+ case 0x0: // Stop
+ return src;
+ }
+ }
+}
+
+
+
+static void dynax_blitter_start(int flags)
+{
+ int blit_newsrc;
+
+#if VERBOSE
+ logerror("XY=%X,%X SRC=%X BLIT=%X\n",blit_x,blit_y,blit_src,flags);
+#endif
+
+ blit_newsrc =
+ blitter_drawgfx(
+ 0, // layer
+ dynax_blit_dest, // layer mask
+ dynax_blit_romregion, // rom region
+ blit_src, // rom address
+ dynax_blit_pen, // pen
+ blit_x, blit_y, // x,y
+ dynax_blit_wrap_enable, // wrap around
+ flags // flags
+ );
+
+ blit_src = (blit_src & ~0x0fffff) |
+ (blit_newsrc & 0x0fffff) ;
+
+ /* Generate an IRQ */
+ if (update_irq_func)
+ {
+ dynax_blitter_irq = 1;
+ update_irq_func();
+ }
+}
+
+static void jantouki_blitter_start(int flags)
+{
+ int blit_newsrc;
+
+#if VERBOSE
+ logerror("XY=%X,%X SRC=%X BLIT=%X\n",blit_x,blit_y,blit_src,flags);
+#endif
+
+ blit_newsrc =
+ blitter_drawgfx(
+ 0, // layer
+ dynax_blit_dest, // layer mask
+ dynax_blit_romregion, // rom region
+ blit_src, // rom address
+ dynax_blit_pen, // pen
+ blit_x, blit_y, // x,y
+ dynax_blit_wrap_enable, // wrap around
+ flags // flags
+ );
+
+ blit_src = (blit_src & ~0x0fffff) |
+ (blit_newsrc & 0x0fffff) ;
+
+ /* Generate an IRQ */
+ if (update_irq_func)
+ {
+ dynax_blitter_irq = 1;
+ update_irq_func();
+ }
+}
+
+static void jantouki_blitter2_start(int flags)
+{
+ int blit2_newsrc;
+
+#if VERBOSE
+ logerror("XY'=%X,%X SRC'=%X BLIT'=%02X\n",blit2_x,blit2_y,blit2_src,flags);
+#endif
+
+ blit2_newsrc =
+ blitter_drawgfx(
+ 4, // layer
+ dynax_blit2_dest, // layer mask
+ dynax_blit2_romregion, // rom region
+ blit2_src, // rom address
+ dynax_blit2_pen, // pen
+ blit2_x, blit2_y, // x,y
+ dynax_blit2_wrap_enable, // wrap around
+ flags // flags
+ );
+
+ blit2_src = (blit2_src & ~0x0fffff) |
+ (blit2_newsrc & 0x0fffff) ;
+
+ /* Generate an IRQ */
+ if (update_irq_func)
+ {
+ dynax_blitter2_irq = 1;
+ update_irq_func();
+ }
+}
+
+
+
+static WRITE8_HANDLER( dynax_blit_scroll_w )
+{
+ switch( blit_src & 0xc00000 )
+ {
+ case 0x000000: dynax_blit_scroll_x = data;
+ #if VERBOSE
+ logerror("SX=%02X ",data);
+ #endif
+ break;
+ case 0x400000: dynax_blit_scroll_y = data;
+ #if VERBOSE
+ logerror("SY=%02X ",data);
+ #endif
+ break;
+ case 0x800000:
+ case 0xc00000: dynax_blit_wrap_enable = data;
+ #if VERBOSE
+ logerror("WE=%02X ",data);
+ #endif
+ break;
+ }
+}
+
+// inverted scroll values
+static WRITE8_HANDLER( tenkai_blit_scroll_w )
+{
+ switch( blit_src & 0xc00000 )
+ {
+ case 0x000000: dynax_blit_scroll_x = ((data ^ 0xff) + 1) & 0xff;
+ #if VERBOSE
+ logerror("SX=%02X ",data);
+ #endif
+ break;
+ case 0x400000: dynax_blit_scroll_y = data ^ 0xff;
+ #if VERBOSE
+ logerror("SY=%02X ",data);
+ #endif
+ break;
+ case 0x800000:
+ case 0xc00000: dynax_blit_wrap_enable = data;
+ #if VERBOSE
+ logerror("WE=%02X ",data);
+ #endif
+ break;
+ }
+}
+
+static WRITE8_HANDLER( dynax_blit2_scroll_w )
+{
+ switch( blit2_src & 0xc00000 )
+ {
+ case 0x000000: dynax_blit2_scroll_x = data;
+ #if VERBOSE
+ logerror("SX'=%02X ",data);
+ #endif
+ break;
+ case 0x400000: dynax_blit2_scroll_y = data;
+ #if VERBOSE
+ logerror("SY'=%02X ",data);
+ #endif
+ break;
+ case 0x800000:
+ case 0xc00000: dynax_blit2_wrap_enable = data;
+ #if VERBOSE
+ logerror("WE'=%02X ",data);
+ #endif
+ break;
+ }
+}
+
+
+
+WRITE8_HANDLER( dynax_blitter_rev2_w )
+{
+ switch (offset)
+ {
+ case 0: dynax_blitter_start(data); break;
+ case 1: blit_x = data; break;
+ case 2: blit_y = data; break;
+ case 3: blit_src = (blit_src & 0xffff00) | (data << 0); break;
+ case 4: blit_src = (blit_src & 0xff00ff) | (data << 8); break;
+ case 5: blit_src = (blit_src & 0x00ffff) | (data <<16); break;
+ case 6: dynax_blit_scroll_w(0,data); break;
+ }
+}
+
+// different scroll_w
+WRITE8_HANDLER( tenkai_blitter_rev2_w )
+{
+ switch (offset)
+ {
+ case 0: dynax_blitter_start(data); break;
+ case 1: blit_x = data; break;
+ case 2: blit_y = data; break;
+ case 3: blit_src = (blit_src & 0xffff00) | (data << 0); break;
+ case 4: blit_src = (blit_src & 0xff00ff) | (data << 8); break;
+ case 5: blit_src = (blit_src & 0x00ffff) | (data <<16); break;
+ case 6: tenkai_blit_scroll_w(0,data); break;
+ }
+}
+
+
+WRITE8_HANDLER( jantouki_blitter_rev2_w )
+{
+ switch (offset)
+ {
+ case 0: jantouki_blitter_start(data); break;
+ case 1: blit_x = data; break;
+ case 2: blit_y = data; break;
+ case 3: blit_src = (blit_src & 0xffff00) | (data << 0); break;
+ case 4: blit_src = (blit_src & 0xff00ff) | (data << 8); break;
+ case 5: blit_src = (blit_src & 0x00ffff) | (data <<16); break;
+ case 6: dynax_blit_scroll_w(0,data); break;
+ }
+}
+
+WRITE8_HANDLER( jantouki_blitter2_rev2_w )
+{
+ switch (offset)
+ {
+ case 0: jantouki_blitter2_start(data); break;
+ case 1: blit2_x = data; break;
+ case 2: blit2_y = data; break;
+ case 3: blit2_src = (blit2_src & 0xffff00) | (data << 0); break;
+ case 4: blit2_src = (blit2_src & 0xff00ff) | (data << 8); break;
+ case 5: blit2_src = (blit2_src & 0x00ffff) | (data <<16); break;
+ case 6: dynax_blit2_scroll_w(0,data); break;
+ }
+}
+
+
+/***************************************************************************
+
+
+ Video Init
+
+
+***************************************************************************/
+
+static const int *priority_table;
+// 0 1 2 3 4 5 6 7
+static const int priority_hnoridur[8] = { 0x0231, 0x2103, 0x3102, 0x2031, 0x3021, 0x1302, 0x2310, 0x1023 };
+static const int priority_mcnpshnt[8] = { 0x3210, 0x2103, 0x3102, 0x2031, 0x3021, 0x1302, 0x2310, 0x1023 };
+static const int priority_mjelctrn[8] = { 0x0231, 0x0321, 0x2031, 0x2301, 0x3021, 0x3201 ,0x0000, 0x0000 }; // this game doesn't use (hasn't?) layer 1
+
+static void Video_Reset(void)
+{
+ dynax_blit_romregion = REGION_GFX1; dynax_blit2_romregion = REGION_GFX1;
+ dynax_blit_dest = -1; dynax_blit2_dest = -1;
+ dynax_blit_pen = 0x7; dynax_blit2_pen = 0x7;
+ dynax_blit_palbank = 0; dynax_blit2_palbank = 0;
+ dynax_blit_palettes = 0; dynax_blit2_palettes = 0;
+ dynax_layer_enable = -1;
+ dynax_blit_backpen = 0;
+
+ extra_scroll_x = 0;
+ extra_scroll_y = 0;
+
+ hnoridur_layer_half2 = 0;
+
+ update_irq_func = sprtmtch_update_irq;
+}
+
+VIDEO_START( hanamai )
+{
+ dynax_pixmap[0][0] = auto_malloc(256*256);
+ dynax_pixmap[0][1] = auto_malloc(256*256);
+ dynax_pixmap[1][0] = auto_malloc(256*256);
+ dynax_pixmap[1][1] = auto_malloc(256*256);
+ dynax_pixmap[2][0] = auto_malloc(256*256);
+ dynax_pixmap[2][1] = auto_malloc(256*256);
+ dynax_pixmap[3][0] = auto_malloc(256*256);
+ dynax_pixmap[3][1] = auto_malloc(256*256);
+
+ Video_Reset();
+ layer_layout = LAYOUT_HANAMAI;
+}
+
+VIDEO_START( hnoridur )
+{
+ dynax_pixmap[0][0] = auto_malloc(256*256);
+ dynax_pixmap[0][1] = auto_malloc(256*256);
+ dynax_pixmap[1][0] = auto_malloc(256*256);
+ dynax_pixmap[1][1] = auto_malloc(256*256);
+ dynax_pixmap[2][0] = auto_malloc(256*256);
+ dynax_pixmap[2][1] = auto_malloc(256*256);
+ dynax_pixmap[3][0] = auto_malloc(256*256);
+ dynax_pixmap[3][1] = auto_malloc(256*256);
+
+ Video_Reset();
+ layer_layout = LAYOUT_HNORIDUR;
+
+ priority_table = priority_hnoridur;
+}
+
+VIDEO_START( mcnpshnt )
+{
+ video_start_hnoridur(machine);
+ priority_table = priority_mcnpshnt;
+}
+
+VIDEO_START( sprtmtch )
+{
+ dynax_pixmap[0][0] = auto_malloc(256*256);
+ dynax_pixmap[0][1] = auto_malloc(256*256);
+ dynax_pixmap[1][0] = auto_malloc(256*256);
+ dynax_pixmap[1][1] = auto_malloc(256*256);
+ dynax_pixmap[2][0] = auto_malloc(256*256);
+ dynax_pixmap[2][1] = auto_malloc(256*256);
+
+ Video_Reset();
+ layer_layout = LAYOUT_DRGPUNCH;
+}
+
+VIDEO_START( jantouki )
+{
+ dynax_pixmap[0][0] = auto_malloc(256*256);
+ dynax_pixmap[0][1] = auto_malloc(256*256);
+ dynax_pixmap[1][0] = auto_malloc(256*256);
+ dynax_pixmap[1][1] = auto_malloc(256*256);
+ dynax_pixmap[2][0] = auto_malloc(256*256);
+ dynax_pixmap[2][1] = auto_malloc(256*256);
+ dynax_pixmap[3][0] = auto_malloc(256*256);
+ dynax_pixmap[3][1] = auto_malloc(256*256);
+ dynax_pixmap[4][0] = auto_malloc(256*256);
+ dynax_pixmap[4][1] = auto_malloc(256*256);
+ dynax_pixmap[5][0] = auto_malloc(256*256);
+ dynax_pixmap[5][1] = auto_malloc(256*256);
+ dynax_pixmap[6][0] = auto_malloc(256*256);
+ dynax_pixmap[6][1] = auto_malloc(256*256);
+ dynax_pixmap[7][0] = auto_malloc(256*256);
+ dynax_pixmap[7][1] = auto_malloc(256*256);
+
+ Video_Reset();
+ layer_layout = LAYOUT_JANTOUKI;
+
+ update_irq_func = jantouki_update_irq;
+}
+
+VIDEO_START( mjdialq2 )
+{
+ dynax_pixmap[0][0] = auto_malloc(256*256);
+ dynax_pixmap[1][0] = auto_malloc(256*256);
+
+ Video_Reset();
+ layer_layout = LAYOUT_MJDIALQ2;
+
+ update_irq_func = 0;
+}
+
+VIDEO_START( mjelctrn )
+{
+ video_start_hnoridur(machine);
+
+ priority_table = priority_mjelctrn;
+ update_irq_func = mjelctrn_update_irq;
+}
+
+VIDEO_START( neruton )
+{
+ video_start_hnoridur(machine);
+
+// priority_table = priority_mjelctrn;
+ update_irq_func = neruton_update_irq;
+}
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+static void hanamai_copylayer(mame_bitmap *bitmap,const rectangle *cliprect,int i)
+{
+ int color;
+ int scrollx,scrolly;
+
+ switch ( i )
+ {
+ case 0: color = (dynax_blit_palettes >> 0) & 0xf; break;
+ case 1: color = (dynax_blit_palettes >> 4) & 0xf; break;
+ case 2: color = (dynax_blit_palettes >> 8) & 0xf; break;
+ case 3: color = (dynax_blit_palettes >> 12) & 0xf; break;
+ default: return;
+ }
+
+ color += (dynax_blit_palbank & 0x0f) * 16;
+
+ scrollx = dynax_blit_scroll_x;
+ scrolly = dynax_blit_scroll_y;
+
+ if ( (layer_layout == LAYOUT_HANAMAI && i == 1) ||
+ (layer_layout == LAYOUT_HNORIDUR && i == 1) )
+ {
+ scrollx = extra_scroll_x;
+ scrolly = extra_scroll_y;
+ }
+
+ {
+ int dy,length,pen,offs;
+ UINT8 *src1 = dynax_pixmap[i][1];
+ UINT8 *src2 = dynax_pixmap[i][0];
+
+ int palbase = 16*color;
+ offs = 0;
+
+ for (dy = 0; dy < 256; dy++)
+ {
+ UINT16 *dst;
+ UINT16 *dstbase = BITMAP_ADDR16(bitmap, (dy - scrolly) & 0xff, 0);
+
+ length = scrollx;
+ dst = dstbase + 2*(256 - length);
+ while (length--)
+ {
+ pen = *(src1++);
+ if (pen) *dst = palbase + pen;
+ pen = *(src2++);
+ if (pen) *(dst+1) = palbase + pen;
+ dst += 2;
+ }
+
+ length = 256 - scrollx;
+ dst = dstbase;
+ while (length--)
+ {
+ pen = *(src1++);
+ if (pen) *dst = palbase + pen;
+ pen = *(src2++);
+ if (pen) *(dst+1) = palbase + pen;
+ dst += 2;
+ }
+ }
+ }
+}
+
+
+static void jantouki_copylayer(mame_bitmap *bitmap,const rectangle *cliprect,int i, int y)
+{
+ int color,scrollx,scrolly,palettes,palbank;
+
+ if (i < 4) { scrollx = dynax_blit_scroll_x;
+ scrolly = dynax_blit_scroll_y;
+ palettes = dynax_blit_palettes;
+ palbank = dynax_blit_palbank; }
+ else { scrollx = dynax_blit2_scroll_x;
+ scrolly = dynax_blit2_scroll_y;
+ palettes = dynax_blit2_palettes;
+ palbank = dynax_blit2_palbank; }
+
+ switch ( i % 4 )
+ {
+ case 0: color = ((palettes >> 12) & 0xf) + ((palbank & 1) << 4); break;
+ case 1: color = ((palettes >> 8) & 0xf) + ((palbank & 1) << 4); break;
+ case 2: color = ((palettes >> 4) & 0xf) + ((palbank & 1) << 4); break;
+ case 3: color = ((palettes >> 0) & 0xf) + ((palbank & 1) << 4); break;
+ default: return;
+ }
+
+ {
+ int dy,length,pen,offs;
+ UINT8 *src1 = dynax_pixmap[i][1];
+ UINT8 *src2 = dynax_pixmap[i][0];
+
+ int palbase = 16*color;
+ offs = 0;
+
+ for (dy = 0; dy < 256; dy++)
+ {
+ int sy = ((dy - scrolly) & 0xff) + y;
+ UINT16 *dst;
+ UINT16 *dstbase = BITMAP_ADDR16(bitmap, sy, 0);
+
+ if ((sy < cliprect->min_y) || (sy > cliprect->max_y))
+ {
+ src1+=256;
+ src2+=256;
+ continue;
+ }
+
+ length = scrollx;
+ dst = dstbase + 2*(256 - length);
+ while (length--)
+ {
+ pen = *(src1++);
+ if (pen) *dst = palbase + pen;
+ pen = *(src2++);
+ if (pen) *(dst+1) = palbase + pen;
+ dst += 2;
+ }
+
+ length = 256 - scrollx;
+ dst = dstbase;
+ while (length--)
+ {
+ pen = *(src1++);
+ if (pen) *dst = palbase + pen;
+ pen = *(src2++);
+ if (pen) *(dst+1) = palbase + pen;
+ dst += 2;
+ }
+ }
+ }
+}
+
+
+static void mjdialq2_copylayer(mame_bitmap *bitmap,const rectangle *cliprect,int i)
+{
+ int color;
+ int scrollx,scrolly;
+
+ switch ( i )
+ {
+ case 0: color = (dynax_blit_palettes >> 4) & 0xf; break;
+ case 1: color = (dynax_blit_palettes >> 0) & 0xf; break;
+ default: return;
+ }
+
+ color += (dynax_blit_palbank & 1) * 16;
+
+ scrollx = dynax_blit_scroll_x;
+ scrolly = dynax_blit_scroll_y;
+
+ {
+ int dy,length,pen,offs;
+ UINT8 *src = dynax_pixmap[i][0];
+
+ int palbase = 16*color;
+ offs = 0;
+
+ for (dy = 0; dy < 256; dy++)
+ {
+ UINT16 *dst;
+ UINT16 *dstbase = BITMAP_ADDR16(bitmap, (dy - scrolly) & 0xff, 0);
+
+ length = scrollx;
+ dst = dstbase + 256 - length;
+ while (length--)
+ {
+ pen = *(src++);
+ if (pen) *dst = palbase + pen;
+ dst++;
+ }
+
+ length = 256 - scrollx;
+ dst = dstbase;
+ while (length--)
+ {
+ pen = *(src++);
+ if (pen) *dst = palbase + pen;
+ dst++;
+ }
+ }
+ }
+}
+
+
+
+static int hanamai_priority;
+
+WRITE8_HANDLER( hanamai_priority_w )
+{
+ hanamai_priority = data;
+}
+
+WRITE8_HANDLER( tenkai_priority_w )
+{
+ hanamai_priority = BITSWAP8(data, 3,2,1,0, 4,7,5,6);
+}
+
+static int debug_mask(void)
+{
+#ifdef MAME_DEBUG
+ int msk = 0;
+ if (input_code_pressed(KEYCODE_Z))
+ {
+ if (input_code_pressed(KEYCODE_Q)) msk |= 0x01; // layer 0
+ if (input_code_pressed(KEYCODE_W)) msk |= 0x02; // layer 1
+ if (input_code_pressed(KEYCODE_E)) msk |= 0x04; // layer 2
+ if (input_code_pressed(KEYCODE_R)) msk |= 0x08; // layer 3
+ if (input_code_pressed(KEYCODE_A)) msk |= 0x10; // layer 4
+ if (input_code_pressed(KEYCODE_S)) msk |= 0x20; // layer 5
+ if (input_code_pressed(KEYCODE_D)) msk |= 0x40; // layer 6
+ if (input_code_pressed(KEYCODE_F)) msk |= 0x80; // layer 7
+ if (msk != 0) return msk;
+ }
+#endif
+ return -1;
+}
+
+/* A primitive gfx viewer:
+
+ T - Toggle viewer
+ I,O - Change palette (-,+)
+ J,K & N,M - Change "tile" (-,+, slow & fast)
+ R - move "tile" to the next 1/8th of the gfx */
+static int debug_viewer(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+#ifdef MAME_DEBUG
+ static int toggle;
+ if (input_code_pressed_once(KEYCODE_T)) toggle = 1-toggle;
+ if (toggle) {
+ UINT8 *RAM = memory_region( REGION_GFX1 );
+ size_t size = memory_region_length( REGION_GFX1 );
+ static int i = 0, c = 0, r = 0;
+
+ if (input_code_pressed_once(KEYCODE_I)) c = (c-1) & 0x1f;
+ if (input_code_pressed_once(KEYCODE_O)) c = (c+1) & 0x1f;
+ if (input_code_pressed_once(KEYCODE_R)) { r = (r+1) & 0x7; i = size/8 * r; }
+ if (input_code_pressed(KEYCODE_M) | input_code_pressed_once(KEYCODE_K)) {
+ while( i < size && RAM[i] ) i++; while( i < size && !RAM[i] ) i++; }
+ if (input_code_pressed(KEYCODE_N) | input_code_pressed_once(KEYCODE_J)) {
+ if (i >= 2) i-=2; while( i > 0 && RAM[i] ) i--; i++; }
+
+ dynax_blit_palettes = (c & 0xf) * 0x111;
+ dynax_blit_palbank = (c >> 4) & 1;
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ memset(dynax_pixmap[0][0],0,sizeof(UINT8)*0x100*0x100);
+ if (layer_layout != LAYOUT_MJDIALQ2)
+ memset(dynax_pixmap[0][1],0,sizeof(UINT8)*0x100*0x100);
+ for (hanamai_layer_half = 0; hanamai_layer_half < 2; hanamai_layer_half++)
+ blitter_drawgfx(0,1,REGION_GFX1,i,0,cliprect->min_x,cliprect->min_y,3,0);
+ if (layer_layout != LAYOUT_MJDIALQ2) hanamai_copylayer(bitmap, cliprect, 0);
+ else mjdialq2_copylayer(bitmap,cliprect, 0);
+ popmessage("%06X C%02X",i,c);
+
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+
+
+VIDEO_UPDATE( hanamai )
+{
+ int layers_ctrl = ~dynax_layer_enable;
+ int lay[4];
+
+ if (debug_viewer(machine,bitmap,cliprect)) return 0;
+ layers_ctrl &= debug_mask();
+
+ fillbitmap(
+ bitmap,
+ machine->pens[(dynax_blit_backpen & 0xff) + (dynax_blit_palbank & 1) * 256],
+ cliprect);
+
+ /* bit 4 = display enable? */
+ if (!(hanamai_priority & 0x10)) return 0;
+
+ switch (hanamai_priority)
+ {
+ default: popmessage("unknown priority %02x",hanamai_priority);
+ case 0x10: lay[0] = 0; lay[1] = 1; lay[2] = 2; lay[3] = 3; break;
+ case 0x11: lay[0] = 0; lay[1] = 3; lay[2] = 2; lay[3] = 1; break;
+ case 0x12: lay[0] = 0; lay[1] = 1; lay[2] = 3; lay[3] = 2; break;
+ case 0x13: lay[0] = 0; lay[1] = 3; lay[2] = 1; lay[3] = 2; break;
+ case 0x14: lay[0] = 0; lay[1] = 2; lay[2] = 1; lay[3] = 3; break;
+ case 0x15: lay[0] = 0; lay[1] = 2; lay[2] = 3; lay[3] = 1; break;
+ }
+
+ if (layers_ctrl & (1 << lay[0])) hanamai_copylayer( bitmap, cliprect, lay[0] );
+ if (layers_ctrl & (1 << lay[1])) hanamai_copylayer( bitmap, cliprect, lay[1] );
+ if (layers_ctrl & (1 << lay[2])) hanamai_copylayer( bitmap, cliprect, lay[2] );
+ if (layers_ctrl & (1 << lay[3])) hanamai_copylayer( bitmap, cliprect, lay[3] );
+ return 0;
+}
+
+
+VIDEO_UPDATE( hnoridur )
+{
+ int layers_ctrl = ~BITSWAP8(hanamai_priority, 7,6,5,4, 0,1,2,3);
+ int lay[4];
+ int pri;
+
+ if (debug_viewer(machine,bitmap,cliprect)) return 0;
+ layers_ctrl &= debug_mask();
+
+ fillbitmap(
+ bitmap,
+ machine->pens[(dynax_blit_backpen & 0xff) + (dynax_blit_palbank & 0x0f) * 256],
+ cliprect);
+
+ pri = hanamai_priority >> 4;
+
+ if (pri > 7)
+ {
+ popmessage("unknown priority %02x",hanamai_priority);
+ pri = 0;
+ }
+
+ pri = priority_table[pri];
+ lay[0] = (pri >> 12) & 3;
+ lay[1] = (pri >> 8) & 3;
+ lay[2] = (pri >> 4) & 3;
+ lay[3] = (pri >> 0) & 3;
+
+ if (layers_ctrl & (1 << lay[0])) hanamai_copylayer( bitmap, cliprect, lay[0] );
+ if (layers_ctrl & (1 << lay[1])) hanamai_copylayer( bitmap, cliprect, lay[1] );
+ if (layers_ctrl & (1 << lay[2])) hanamai_copylayer( bitmap, cliprect, lay[2] );
+ if (layers_ctrl & (1 << lay[3])) hanamai_copylayer( bitmap, cliprect, lay[3] );
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( sprtmtch )
+{
+ int layers_ctrl = ~dynax_layer_enable;
+
+ if (debug_viewer(machine,bitmap,cliprect)) return 0;
+ layers_ctrl &= debug_mask();
+
+ fillbitmap(
+ bitmap,
+ machine->pens[(dynax_blit_backpen & 0xff) + (dynax_blit_palbank & 1) * 256],
+ cliprect);
+
+ if (layers_ctrl & 1) hanamai_copylayer( bitmap, cliprect, 0 );
+ if (layers_ctrl & 2) hanamai_copylayer( bitmap, cliprect, 1 );
+ if (layers_ctrl & 4) hanamai_copylayer( bitmap, cliprect, 2 );
+ return 0;
+}
+
+VIDEO_UPDATE( jantouki )
+{
+
+ int layers_ctrl = dynax_layer_enable;
+
+ if (debug_viewer(machine,bitmap,cliprect)) return 0;
+ layers_ctrl &= debug_mask();
+
+ fillbitmap(
+ bitmap,
+ machine->pens[(dynax_blit_backpen & 0xff) + (dynax_blit_palbank & 1) * 256],
+ cliprect);
+
+ if (screen==0)
+ {
+ // if (layers_ctrl & 0x01) jantouki_copylayer( bitmap, cliprect, 3, 0 );
+ if (layers_ctrl & 0x02) jantouki_copylayer( bitmap, cliprect, 2, 0 );
+ if (layers_ctrl & 0x04) jantouki_copylayer( bitmap, cliprect, 1, 0 );
+ if (layers_ctrl & 0x08) jantouki_copylayer( bitmap, cliprect, 0, 0 );
+ }
+ else if (screen==1)
+ {
+ if (layers_ctrl & 0x01) jantouki_copylayer( bitmap, cliprect, 3, 0 );
+ if (layers_ctrl & 0x10) jantouki_copylayer( bitmap, cliprect, 7, 0 );
+ if (layers_ctrl & 0x20) jantouki_copylayer( bitmap, cliprect, 6, 0 );
+ if (layers_ctrl & 0x40) jantouki_copylayer( bitmap, cliprect, 5, 0 );
+ if (layers_ctrl & 0x80) jantouki_copylayer( bitmap, cliprect, 4, 0 );
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( mjdialq2 )
+{
+ int layers_ctrl = ~dynax_layer_enable;
+
+ if (debug_viewer(machine,bitmap,cliprect)) return 0;
+ layers_ctrl &= debug_mask();
+
+ fillbitmap(
+ bitmap,
+ machine->pens[(dynax_blit_backpen & 0xff) + (dynax_blit_palbank & 1) * 256],
+ cliprect);
+
+ if (layers_ctrl & 1) mjdialq2_copylayer( bitmap, cliprect, 0 );
+ if (layers_ctrl & 2) mjdialq2_copylayer( bitmap, cliprect, 1 );
+ return 0;
+}
+
+// htengoku uses the mixer chip from ddenlovr
+
+static mame_bitmap *framebuffer;
+
+VIDEO_START(htengoku)
+{
+ video_start_ddenlovr(machine);
+ video_start_hnoridur(machine);
+ framebuffer = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+}
+
+VIDEO_EOF(htengoku)
+{
+ int layer,x,y;
+
+ // render the layers, one by one, "dynax.c" style. Then convert the pixmaps to "ddenlovr.c"
+ // format and let video_eof_ddenlovr do the final compositing (priorities + palettes)
+ for (layer = 0; layer < 4; layer++)
+ {
+ fillbitmap(framebuffer,0,&machine->screen[0].visarea);
+ hanamai_copylayer( framebuffer, &machine->screen[0].visarea, layer );
+
+ for (y=0; y < 256; y++)
+ for (x=0; x < 512; x++)
+ ddenlovr_pixmap[3-layer][y*512+x] = (UINT8)(*BITMAP_ADDR16(framebuffer, y,x));
+ }
+ video_eof_ddenlovr(machine);
+}
diff --git a/src/mame/video/dynduke.c b/src/mame/video/dynduke.c
new file mode 100644
index 00000000000..41f0dc17ac5
--- /dev/null
+++ b/src/mame/video/dynduke.c
@@ -0,0 +1,248 @@
+
+#include "driver.h"
+
+static tilemap *bg_layer,*fg_layer,*tx_layer;
+UINT16 *dynduke_back_data,*dynduke_fore_data,*dynduke_scroll_ram;
+
+static int back_bankbase,fore_bankbase;
+static int back_enable,fore_enable,sprite_enable,txt_enable;
+
+/******************************************************************************/
+
+WRITE16_HANDLER( dynduke_paletteram_w )
+{
+ int color;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ color=paletteram16[offset];
+ palette_set_color_rgb(Machine,offset,pal4bit(color >> 0),pal4bit(color >> 4),pal4bit(color >> 8));
+}
+
+WRITE16_HANDLER( dynduke_background_w )
+{
+ COMBINE_DATA(&dynduke_back_data[offset]);
+ tilemap_mark_tile_dirty(bg_layer,offset);
+}
+
+WRITE16_HANDLER( dynduke_foreground_w )
+{
+ COMBINE_DATA(&dynduke_fore_data[offset]);
+ tilemap_mark_tile_dirty(fg_layer,offset);
+}
+
+WRITE16_HANDLER( dynduke_text_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty(tx_layer,offset);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int tile=dynduke_back_data[tile_index];
+ int color=tile >> 12;
+
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 1,
+ tile+back_bankbase,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int tile=dynduke_fore_data[tile_index];
+ int color=tile >> 12;
+
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 2,
+ tile+fore_bankbase,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int tile=videoram16[tile_index];
+ int color=(tile >> 8) & 0x0f;
+
+ tile = (tile & 0xff) | ((tile & 0xc000) >> 6);
+
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+VIDEO_START( dynduke )
+{
+ bg_layer = tilemap_create(get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 16,16,32,32);
+ fg_layer = tilemap_create(get_fg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,32,32);
+ tx_layer = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+
+ tilemap_set_transparent_pen(fg_layer,15);
+ tilemap_set_transparent_pen(tx_layer,15);
+}
+
+WRITE16_HANDLER( dynduke_gfxbank_w )
+{
+ static int old_back,old_fore;
+
+ if (ACCESSING_LSB)
+ {
+ if (data&0x01) back_bankbase=0x1000; else back_bankbase=0;
+ if (data&0x10) fore_bankbase=0x1000; else fore_bankbase=0;
+
+ if (back_bankbase!=old_back)
+ tilemap_mark_all_tiles_dirty(bg_layer);
+ if (fore_bankbase!=old_fore)
+ tilemap_mark_all_tiles_dirty(fg_layer);
+
+ old_back=back_bankbase;
+ old_fore=fore_bankbase;
+ }
+}
+
+
+WRITE16_HANDLER( dynduke_control_w )
+{
+
+ if (ACCESSING_LSB)
+ {
+ // bit 0x80 toggles, maybe sprite buffering?
+ // bit 0x40 is flipscreen
+ // bit 0x20 not used?
+ // bit 0x10 not used?
+ // bit 0x08 is set on the title screen (sprite disable?)
+ // bit 0x04 unused? txt disable?
+ // bit 0x02 is used on the map screen (fore disable?)
+ // bit 0x01 set when inserting coin.. bg disable?
+
+ if (data&0x1) back_enable = 0; else back_enable = 1;
+ if (data&0x2) fore_enable=0; else fore_enable=1;
+ if (data&0x4) txt_enable = 0; else txt_enable = 1;
+ if (data&0x8) sprite_enable=0; else sprite_enable=1;
+
+ flip_screen_set(data & 0x40);
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int pri)
+{
+ int offs,fx,fy,x,y,color,sprite;
+
+ if (!sprite_enable) return;
+
+ for (offs = 0x800-4;offs >= 0;offs -= 4)
+ {
+ /* Don't draw empty sprite table entries */
+ if ((buffered_spriteram16[offs+3] >> 8)!=0xf) continue;
+ if (((buffered_spriteram16[offs+2]>>13)&3)!=pri) continue;
+
+ fx= buffered_spriteram16[offs+0]&0x2000;
+ fy= buffered_spriteram16[offs+0]&0x4000;
+ y = buffered_spriteram16[offs+0] & 0xff;
+ x = buffered_spriteram16[offs+2] & 0xff;
+
+ if (buffered_spriteram16[offs+2]&0x100) x=0-(0x100-x);
+
+ color = (buffered_spriteram16[offs+0]>>8)&0x1f;
+ sprite = buffered_spriteram16[offs+1];
+ sprite &= 0x3fff;
+
+ if (flip_screen) {
+ x=240-x;
+ y=240-y;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ }
+
+ drawgfx(bitmap,machine->gfx[3],
+ sprite,
+ color,fx,fy,x,y,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri )
+{
+ /* The transparency / palette handling on the background layer is very strange */
+ mame_bitmap *bm = tilemap_get_pixmap(bg_layer);
+ int scrolly, scrollx;
+ int x,y;
+
+ /* if we're disabled, don't draw */
+ if (!back_enable)
+ {
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ return;
+ }
+
+ scrolly = ((dynduke_scroll_ram[0x01]&0x30)<<4)+((dynduke_scroll_ram[0x02]&0x7f)<<1)+((dynduke_scroll_ram[0x02]&0x80)>>7);
+ scrollx = ((dynduke_scroll_ram[0x09]&0x30)<<4)+((dynduke_scroll_ram[0x0a]&0x7f)<<1)+((dynduke_scroll_ram[0x0a]&0x80)>>7);
+
+ for (y=0;y<256;y++)
+ {
+ int realy = (y + scrolly) & 0x1ff;
+ UINT16 *src = BITMAP_ADDR16(bm, realy, 0);
+ UINT16 *dst = BITMAP_ADDR16(bitmap, y, 0);
+
+
+ for (x=0;x<256;x++)
+ {
+ int realx = (x + scrollx) & 0x1ff;
+ UINT16 srcdat = src[realx];
+
+ /* 0x01 - data bits
+ 0x02
+ 0x04
+ 0x08
+ 0x10 - extra colour bit? (first boss)
+ 0x20 - priority over sprites
+ the old driver also had 'bg_palbase' but I don't see what it's for?
+ */
+
+ if ((srcdat & 0x20) == pri)
+ {
+ if (srcdat & 0x10) srcdat += 0x400;
+ //if (srcdat & 0x10) srcdat += mame_rand(machine)&0x1f;
+
+ srcdat = (srcdat & 0x000f) | ((srcdat & 0xffc0) >> 2);
+ dst[x] = srcdat;
+ }
+
+
+ }
+ }
+}
+
+VIDEO_UPDATE( dynduke )
+{
+ /* Setup the tilemaps */
+ tilemap_set_scrolly( fg_layer,0, ((dynduke_scroll_ram[0x11]&0x30)<<4)+((dynduke_scroll_ram[0x12]&0x7f)<<1)+((dynduke_scroll_ram[0x12]&0x80)>>7) );
+ tilemap_set_scrollx( fg_layer,0, ((dynduke_scroll_ram[0x19]&0x30)<<4)+((dynduke_scroll_ram[0x1a]&0x7f)<<1)+((dynduke_scroll_ram[0x1a]&0x80)>>7) );
+ tilemap_set_enable( fg_layer,fore_enable);
+ tilemap_set_enable( tx_layer,txt_enable);
+
+
+ draw_background(machine, bitmap, cliprect,0x00);
+ draw_sprites(machine,bitmap,cliprect,0); // Untested: does anything use it? Could be behind background
+ draw_sprites(machine,bitmap,cliprect,1);
+ draw_background(machine, bitmap, cliprect,0x20);
+
+ draw_sprites(machine,bitmap,cliprect,2);
+ tilemap_draw(bitmap,cliprect,fg_layer,0,0);
+ draw_sprites(machine,bitmap,cliprect,3);
+ tilemap_draw(bitmap,cliprect,tx_layer,0,0);
+
+ return 0;
+}
+
+VIDEO_EOF( dynduke )
+{
+ buffer_spriteram16_w(0,0,0); // Could be a memory location instead
+}
diff --git a/src/mame/video/eolith.c b/src/mame/video/eolith.c
new file mode 100644
index 00000000000..ad55b32611b
--- /dev/null
+++ b/src/mame/video/eolith.c
@@ -0,0 +1,74 @@
+#include "driver.h"
+
+int eolith_buffer = 0;
+static mame_bitmap *bitmaps[2];
+static UINT32 *eo_vram;
+
+static void plot_pixel_rgb(int x, int y, int color)
+{
+ if (bitmaps[eolith_buffer]->bpp == 32)
+ {
+ UINT32 r = (color & 0x001f) << 3;
+ UINT32 g = (color & 0x03e0) >> 2;
+ UINT32 b = (color & 0x7c00) >> 7;
+ *BITMAP_ADDR32(bitmaps[eolith_buffer], y, x) = b | (g<<8) | (r<<16);
+ }
+ else
+ {
+ *BITMAP_ADDR16(bitmaps[eolith_buffer], y, x) = color;
+ }
+}
+
+WRITE32_HANDLER( eolith_vram_w )
+{
+ int x,y;
+ switch(mem_mask)
+ {
+ case 0:
+ eolith_vram_w(offset,data,0x0000ffff);
+ eolith_vram_w(offset,data,0xffff0000);
+ return;
+
+ case 0xffff:
+ if(data & 0x80000000)
+ return;
+ break;
+
+ case 0xffff0000:
+ if(data & 0x8000)
+ return;
+ break;
+ }
+
+ COMBINE_DATA(&eo_vram[offset+(0x40000/4)*eolith_buffer]);
+
+ //logical line width = 336;
+ x = offset % (336/2);
+ y = offset / (336/2);
+
+ if(x < 320/2 && y < 240)
+ {
+ plot_pixel_rgb(x*2, y,(eo_vram[offset+(0x40000/4)*eolith_buffer]>>16) & 0x7fff);
+ plot_pixel_rgb(x*2+1,y, eo_vram[offset+(0x40000/4)*eolith_buffer] & 0x7fff);
+
+ }
+}
+
+
+READ32_HANDLER( eolith_vram_r )
+{
+ return eo_vram[offset+(0x40000/4)*eolith_buffer];
+}
+
+VIDEO_START( eolith )
+{
+ eo_vram = auto_malloc(0x40000*2);
+ bitmaps[0] = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ bitmaps[1] = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+}
+
+VIDEO_UPDATE( eolith )
+{
+ copybitmap(bitmap,bitmaps[eolith_buffer ^ 1],0,0,0,0,cliprect,TRANSPARENCY_NONE, 0);
+ return 0;
+}
diff --git a/src/mame/video/epos.c b/src/mame/video/epos.c
new file mode 100644
index 00000000000..bfbfe84a677
--- /dev/null
+++ b/src/mame/video/epos.c
@@ -0,0 +1,95 @@
+/***************************************************************************
+
+ Epos games
+
+***************************************************************************/
+
+#include "driver.h"
+#include "epos.h"
+
+
+static UINT8 palette;
+
+
+/***************************************************************************
+
+ These games has one 32 byte palette PROM, connected to the RGB output this way:
+
+ bit 7 -- 240 ohm resistor -- RED
+ -- 510 ohm resistor -- RED
+ -- 1 kohm resistor -- RED
+ -- 240 ohm resistor -- GREEN
+ -- 510 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 240 ohm resistor -- BLUE
+ bit 0 -- 510 ohm resistor -- BLUE
+
+***************************************************************************/
+
+static void get_pens(pen_t *pens)
+{
+ offs_t i;
+
+ for (i = 0; i < memory_region_length(REGION_PROMS); i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ UINT8 data = memory_region(REGION_PROMS)[i];
+
+ bit0 = (data >> 7) & 0x01;
+ bit1 = (data >> 6) & 0x01;
+ bit2 = (data >> 5) & 0x01;
+ r = 0x92 * bit0 + 0x4a * bit1 + 0x23 * bit2;
+
+ bit0 = (data >> 4) & 0x01;
+ bit1 = (data >> 3) & 0x01;
+ bit2 = (data >> 2) & 0x01;
+ g = 0x92 * bit0 + 0x4a * bit1 + 0x23 * bit2;
+
+ bit0 = (data >> 1) & 0x01;
+ bit1 = (data >> 0) & 0x01;
+ b = 0xad * bit0 + 0x52 * bit1;
+
+ pens[i] = MAKE_RGB(r, g, b);
+ }
+}
+
+
+WRITE8_HANDLER( epos_port_1_w )
+{
+ /* D0 - start light #1
+ D1 - start light #2
+ D2 - coin counter
+ D3 - palette select
+ D4-D7 - unused
+ */
+
+ set_led_status(0, (data >> 0) & 0x01);
+ set_led_status(1, (data >> 1) & 0x01);
+
+ coin_counter_w(0, (data >> 2) & 0x01);
+
+ palette = (data >> 3) & 0x01;
+}
+
+
+VIDEO_UPDATE( epos )
+{
+ pen_t pens[0x20];
+ offs_t offs;
+
+ get_pens(pens);
+
+ for (offs = 0; offs < videoram_size; offs++)
+ {
+ UINT8 data = videoram[offs];
+
+ int x = (offs % 136) * 2;
+ int y = (offs / 136);
+
+ *BITMAP_ADDR32(bitmap, y, x + 0) = pens[(palette << 4) | (data & 0x0f)];
+ *BITMAP_ADDR32(bitmap, y, x + 1) = pens[(palette << 4) | (data >> 4)];
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/eprom.c b/src/mame/video/eprom.c
new file mode 100644
index 00000000000..9e490918765
--- /dev/null
+++ b/src/mame/video/eprom.c
@@ -0,0 +1,270 @@
+/***************************************************************************
+
+ Atari Escape hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "eprom.h"
+#include "thunderj.h"
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha[tile_index];
+ int code = data & 0x3ff;
+ int color = ((data >> 10) & 0x0f) | ((data >> 9) & 0x20);
+ int opaque = data & 0x8000;
+ SET_TILE_INFO(1, code, color, opaque ? TILE_FORCE_LAYER0 : 0);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data1 = atarigen_playfield[tile_index];
+ UINT16 data2 = atarigen_playfield_upper[tile_index] >> 8;
+ int code = data1 & 0x7fff;
+ int color = 0x10 + (data2 & 0x0f);
+ SET_TILE_INFO(0, code, color, (data1 >> 15) & 1);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( eprom )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 0, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 1, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 8, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x100, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0x03ff,0,0,0 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0,0x7fff,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0x000f,0 }}, /* mask for the color */
+ {{ 0,0,0xff80,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xff80 }}, /* mask for the Y position */
+ {{ 0,0,0,0x0070 }}, /* mask for the width, in tiles*/
+ {{ 0,0,0,0x0007 }}, /* mask for the height, in tiles */
+ {{ 0,0,0,0x0008 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0,0,0x0070,0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0 /* callback routine for special entries */
+ };
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8,8, 64,64);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ tilemap_set_transparent_pen(atarigen_alpha_tilemap, 0);
+}
+
+
+
+/*************************************
+ *
+ * Periodic scanline updater
+ *
+ *************************************/
+
+void eprom_scanline_update(running_machine *machine, int scrnum, int scanline)
+{
+ /* update the playfield */
+ if (scanline == 0)
+ {
+ int xscroll = (atarigen_alpha[0x780] >> 7) & 0x1ff;
+ int yscroll = (atarigen_alpha[0x781] >> 7) & 0x1ff;
+ tilemap_set_scrollx(atarigen_playfield_tilemap, 0, xscroll);
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, yscroll);
+ atarimo_set_xscroll(0, xscroll);
+ atarimo_set_yscroll(0, yscroll);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( eprom )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* verified from the GALs on the real PCB; equations follow
+ *
+ * --- FORCEMC0 forces 3 bits of the MO color to 0 under some conditions
+ * FORCEMC0=!PFX3*PFX4*PFX5*!MPR0
+ * +!PFX3*PFX5*!MPR1
+ * +!PFX3*PFX4*!MPR0*!MPR1
+ *
+ * --- SHADE selects an alternate color bank for the playfield
+ * !SHADE=!MPX0
+ * +MPX1
+ * +MPX2
+ * +MPX3
+ * +!MPX4*!MPX5*!MPX6*!MPX7
+ * +FORCEMC0
+ *
+ * --- PF/M is 1 if playfield has priority, or 0 if MOs have priority
+ * !PF/M=MPR0*MPR1
+ * +PFX3
+ * +!PFX4*MPR1
+ * +!PFX5*MPR1
+ * +!PFX5*MPR0
+ * +!PFX4*!PFX5*!MPR0*!MPR1
+ *
+ * --- M7 is passed as the upper MO bit to the GPC ASIC
+ * M7=MPX0*!MPX1*!MPX2*!MPX3
+ *
+ * --- CL10-9 are outputs from the GPC, specifying which layer to render
+ * CL10 = 1 if pf
+ * CL9 = 1 if mo
+ *
+ * --- CRA10 is the 0x200 bit of the color RAM index; it comes directly from the GPC
+ * CRA10 = CL10
+ *
+ * --- CRA9 is the 0x100 bit of the color RAM index; is comes directly from the GPC
+ * or if the SHADE flag is set, it affects the playfield color bank
+ * CRA9 = SHADE*CL10
+ * +CL9
+ *
+ * --- CRA8-1 are the low 8 bits of the color RAM index; set as expected
+ */
+ int mopriority = (mo[x] >> ATARIMO_PRIORITY_SHIFT) & 7;
+ int pfpriority = (pf[x] >> 4) & 3;
+ int forcemc0 = 0, shade = 1, pfm = 1, m7 = 0;
+
+ /* upper bit of MO priority signals special rendering and doesn't draw anything */
+ if (mopriority & 4)
+ continue;
+
+ /* compute the FORCEMC signal */
+ if (!(pf[x] & 8))
+ {
+ if (((pfpriority == 3) && !(mopriority & 1)) ||
+ ((pfpriority & 2) && !(mopriority & 2)) ||
+ ((pfpriority & 1) && (mopriority == 0)))
+ forcemc0 = 1;
+ }
+
+ /* compute the SHADE signal */
+ if (((mo[x] & 0x0f) != 1) ||
+ ((mo[x] & 0xf0) == 0) ||
+ forcemc0)
+ shade = 0;
+
+ /* compute the PF/M signal */
+ if ((mopriority == 3) ||
+ (pf[x] & 8) ||
+ (!(pfpriority & 1) && (mopriority & 2)) ||
+ (!(pfpriority & 2) && (mopriority & 2)) ||
+ (!(pfpriority & 2) && (mopriority & 1)) ||
+ ((pfpriority == 0) && (mopriority == 0)))
+ pfm = 0;
+
+ /* compute the M7 signal */
+ if ((mo[x] & 0x0f) == 1)
+ m7 = 1;
+
+ /* PF/M and M7 go in the GPC ASIC and select playfield or MO layers */
+ if (!pfm && !m7)
+ {
+ if (!forcemc0)
+ pf[x] = mo[x] & ATARIMO_DATA_MASK;
+ else
+ pf[x] = mo[x] & ATARIMO_DATA_MASK & ~0x70;
+ }
+ else
+ {
+ if (shade)
+ pf[x] |= 0x100;
+ if (m7)
+ pf[x] |= 0x080;
+ }
+
+ /* don't erase yet -- we need to make another pass later */
+ }
+ }
+
+ /* add the alpha on top */
+ tilemap_draw(bitmap, cliprect, atarigen_alpha_tilemap, 0, 0);
+
+ /* now go back and process the upper bit of MO priority */
+ rectlist.rect -= rectlist.numrects;
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ int mopriority = mo[x] >> ATARIMO_PRIORITY_SHIFT;
+
+ /* upper bit of MO priority might mean palette kludges */
+ if (mopriority & 4)
+ {
+ /* if bit 2 is set, start setting high palette bits */
+ if (mo[x] & 2)
+ thunderj_mark_high_palette(bitmap, pf, mo, x, y);
+ }
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/equites.c b/src/mame/video/equites.c
new file mode 100644
index 00000000000..06782a87cd8
--- /dev/null
+++ b/src/mame/video/equites.c
@@ -0,0 +1,681 @@
+/*******************************************************************************
+
+Equites (c) 1984 Alpha Denshi Co./Sega
+Bull Fighter (c) 1984 Alpha Denshi Co./Sega
+The Koukouyakyuh (c) 1985 Alpha Denshi Co.
+Splendor Blast (c) 1985 Alpha Denshi Co.
+High Voltage (c) 1985 Alpha Denshi Co.
+
+drivers by Acho A. Tang
+
+*******************************************************************************/
+// Directives
+
+#include "driver.h"
+
+#define BMPAD 8
+#define BMW_l2 9
+#define FP_PRECISION 20
+#define FP_HALF ((1<<(FP_PRECISION-1))-1)
+
+/******************************************************************************/
+// Imports
+
+extern int equites_id, equites_flip;
+
+/******************************************************************************/
+// Locals
+
+static tilemap *charmap0, *charmap1, *activecharmap, *inactivecharmap;
+static UINT16 *defcharram, *charram0, *charram1, *activecharram, *inactivecharram;
+static UINT8 *dirtybuf;
+static int maskwidth, maskheight, maskcolor;
+static int scrollx, scrolly;
+static int bgcolor[4];
+static rectangle halfclip;
+static struct PRESTEP_TYPE { unsigned sy, fdx; } *prestep;
+static colortable *equites_colortable;
+
+/******************************************************************************/
+// Exports
+
+UINT16 *splndrbt_scrollx, *splndrbt_scrolly;
+
+/******************************************************************************/
+// Initializations
+
+static void video_init_common(running_machine *machine)
+{
+ int i;
+
+ // set defaults
+ maskwidth = 8;
+ maskheight = machine->screen[0].visarea.max_y - machine->screen[0].visarea.min_y + 1;
+ maskcolor = get_black_pen(machine);
+ scrollx = scrolly = 0;
+ for (i=0; i<4; i++) bgcolor[i] = 0;
+
+ // set uniques
+ switch (equites_id)
+ {
+ case 0x8401:
+ maskwidth = 16;
+ break;
+ case 0x8510:
+ scrollx = 128;
+ scrolly = 8;
+ break;
+ case 0x8511:
+ scrollx = 128;
+ scrolly = 8;
+ break;
+ }
+}
+
+// Equites Hardware
+PALETTE_INIT( equites )
+{
+ UINT8 *clut_ptr;
+ int i;
+
+ equites_colortable = colortable_alloc(machine, 256);
+
+ for (i=0; i<256; i++)
+ colortable_palette_set_color(equites_colortable, i, MAKE_RGB(pal4bit(color_prom[i]), pal4bit(color_prom[i+0x100]), pal4bit(color_prom[i+0x200])));
+
+ for (i=0; i<256; i++)
+ colortable_entry_set_value(equites_colortable, i, i);
+
+ clut_ptr = memory_region(REGION_USER1) + 0x80;
+ for (i=0; i<128; i++)
+ colortable_entry_set_value(equites_colortable, i+0x100, clut_ptr[i]);
+}
+
+static TILE_GET_INFO( equites_charinfo )
+{
+ int tile, color;
+
+ tile_index <<= 1;
+ tile = videoram16[tile_index];
+ color = videoram16[tile_index+1];
+ tile &= 0xff;
+ color &= 0x1f;
+
+ SET_TILE_INFO(0, tile, color, 0);
+}
+
+VIDEO_START( equites )
+{
+ charmap0 = tilemap_create(equites_charinfo, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+ tilemap_set_transparent_pen(charmap0, 0);
+ tilemap_set_scrolldx(charmap0, BMPAD, BMPAD);
+ tilemap_set_scrolldy(charmap0, BMPAD, BMPAD);
+
+ video_init_common(machine);
+}
+
+// Splendor Blast Hardware
+PALETTE_INIT( splndrbt )
+{
+ UINT8 *prom_ptr;
+ int i;
+
+ equites_colortable = colortable_alloc(machine, 256);
+
+ for (i=0; i<0x100; i++)
+ colortable_palette_set_color(equites_colortable, i, MAKE_RGB(pal4bit(color_prom[i]), pal4bit(color_prom[i+0x100]), pal4bit(color_prom[i+0x200])));
+
+ for (i = 0; i < 0x100; i++)
+ colortable_entry_set_value(equites_colortable, i, i);
+
+ prom_ptr = memory_region(REGION_USER1);
+ for (i=0; i<0x80; i++)
+ {
+ colortable_entry_set_value(equites_colortable, i + 0x100, prom_ptr[i] + 0x10);
+ colortable_entry_set_value(equites_colortable, i + 0x180, prom_ptr[i]);
+ }
+
+ prom_ptr += 0x100;
+ for (i=0; i<0x400; i++)
+ colortable_entry_set_value(equites_colortable, i + 0x200, prom_ptr[i]);
+}
+
+static TILE_GET_INFO( splndrbt_char0info )
+{
+ int tile, color;
+
+ tile_index <<= 1;
+ tile = charram0[tile_index];
+ color = charram0[tile_index+1];
+ tile &= 0xff;
+ color &= 0x3f;
+
+ SET_TILE_INFO(0, tile, color, 0);
+ if (color & 0x10)
+ tileinfo->flags |= TILE_FORCE_LAYER0;
+}
+
+static TILE_GET_INFO( splndrbt_char1info )
+{
+ int tile, color;
+
+ tile_index <<= 1;
+ tile = charram1[tile_index];
+ color = charram1[tile_index+1];
+ tile &= 0xff;
+ color &= 0x3f;
+ tile += 0x100;
+
+ SET_TILE_INFO(0, tile, color, 0);
+ if (color & 0x10)
+ tileinfo->flags |= TILE_FORCE_LAYER0;
+}
+
+static void splndrbt_video_reset(void)
+{
+ memset(spriteram16, 0, spriteram_size);
+
+ activecharram = charram0;
+ inactivecharram = charram1;
+
+ activecharmap = charmap0;
+ inactivecharmap = charmap1;
+}
+
+static void splndrbt_prestep(
+ struct PRESTEP_TYPE *ps,
+ const rectangle *dst_clip,
+ int src_w, int src_h,
+ int dst_startw, int dst_endw)
+{
+ double DA, DB, DC, D0, D1, Dsum;
+ int i, dst_vish;
+
+ dst_vish = dst_clip->max_y - dst_clip->min_y;
+
+ DA = (double)(src_w << FP_PRECISION) * dst_vish;
+ DB = dst_endw - dst_startw;
+ DC = dst_startw * dst_vish;
+ D1 = 0;
+
+ for (i=0; i<=dst_vish; i++)
+ {
+ D0 = DA / (DB * i + DC);
+ D1 += D0;
+ ps[i].fdx = (unsigned)D0;
+ }
+
+ DA = src_w * dst_vish;
+ D0 = src_h;
+ D1 /= 1 << FP_PRECISION;
+ Dsum = 0.5;
+
+ for (i=0; i<=dst_vish; i++)
+ {
+ ps[i].sy = (unsigned)Dsum;
+ Dsum += (DA * D0) / ((DB * i + DC) * D1);
+ //logerror("dst_y=%3u src_y=%3u\n", i, ps[i].sy);
+ }
+}
+
+VIDEO_START( splndrbt )
+{
+#define BMW (1<<BMW_l2)
+
+ UINT8 *buf8ptr;
+ int i;
+
+ assert(machine->screen[0].format == BITMAP_FORMAT_INDEXED16);
+
+ halfclip = machine->screen[0].visarea;
+ i = halfclip.max_y - halfclip.min_y + 1;
+ halfclip.max_y = halfclip.min_y + (i >> 1) - 1;
+
+ tmpbitmap = auto_bitmap_alloc(BMW, BMW, machine->screen[0].format);
+
+ charmap0 = tilemap_create(splndrbt_char0info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+ tilemap_set_transparent_pen(charmap0, 0);
+ tilemap_set_scrolldx(charmap0, 8, 8);
+ tilemap_set_scrolldy(charmap0, 32, 32);
+
+ charmap1 = tilemap_create(splndrbt_char1info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+ tilemap_set_transparent_pen(charmap1, 0);
+ tilemap_set_scrolldx(charmap1, 8, 8);
+ tilemap_set_scrolldy(charmap1, 32, 32);
+
+ buf8ptr = auto_malloc(videoram_size * 2);
+ charram0 = (UINT16*)buf8ptr;
+ charram1 = (UINT16*)(buf8ptr + videoram_size);
+
+ dirtybuf = auto_malloc(0x800);
+ memset(dirtybuf, 1, 0x800);
+
+ prestep = auto_malloc(i * sizeof(struct PRESTEP_TYPE));
+ splndrbt_prestep(prestep, &machine->screen[0].visarea, BMW, 434, 96, 480);
+
+ defcharram = videoram16 + videoram_size / 2;
+
+ video_init_common(machine);
+ splndrbt_video_reset();
+}
+
+MACHINE_RESET( splndrbt )
+{
+ splndrbt_video_reset();
+}
+
+/******************************************************************************/
+// Realtime Functions
+
+// Equites Hardware
+static void equites_update_clut(running_machine *machine)
+{
+ int i, c;
+
+ /* palette hacks! */
+ c = *bgcolor;
+
+ for (i=0x80; i<0x100; i+=0x08)
+ colortable_entry_set_value(equites_colortable, i, c);
+}
+
+static void equites_draw_scroll(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+#define TILE_BANKBASE 1
+
+ int i, offsx, offsy, skipx, skipy, dispx, dispy, encode, bank, tile, color, fy, fx, fxy, x, y, flipadjx;
+
+ flipadjx = (equites_flip) ? 10 : 0;
+
+ dispy = scrolly & 0x0f;
+ offsy = scrolly & 0xf0;
+ dispx = (scrollx + flipadjx) & 0x0f;
+ offsx = (scrollx + flipadjx)>>4 & 0xf;
+ if (dispy > 7)
+ {
+ offsy += 0x10;
+ dispy -= 0x10;
+ }
+ if (dispx > 7)
+ {
+ offsx++;
+ dispx -= 0x10;
+ }
+
+ for (i=0; i<255; i++)
+ {
+ skipx = i & 0x0f;
+ skipy = i & 0xf0;
+ encode = spriteram16_2[((offsy + skipy) & 0xf0) + ((offsx + skipx) & 0x0f)];
+ bank = (encode>>8 & 0x01) + TILE_BANKBASE;
+ tile = encode & 0xff;
+ fxy = encode & 0x0800;
+ color = encode>>12 & 0x0f;
+ fx = (encode & 0x0400) | fxy;
+ fy = (encode & 0x0200) | fxy;
+ x = (skipx<<4) - dispx + BMPAD;
+ y = skipy - dispy + BMPAD;
+
+ drawgfx( bitmap,
+ machine->gfx[bank],
+ tile, color,
+ fx, fy,
+ x, y,
+ cliprect, TRANSPARENCY_NONE, 0);
+ }
+
+#undef TILE_BANKBASE
+}
+
+static void equites_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+#define SPRITE_BANKBASE 3
+#define SHIFTX -4
+#define SHIFTY 1
+
+ gfx_element *gfx;
+ UINT16 *sptr, *eptr;
+ int encode, bank, tile, color, fy, fx, fxy, absx, absy, sx, sy, flipadjx;
+
+ flipadjx = (equites_flip) ? 8 : 0;
+
+ sptr = spriteram16;
+ eptr = sptr + 0x100;
+ for (; sptr<eptr; sptr+=2)
+ {
+ encode = *(sptr + 1);
+ if (encode)
+ {
+ bank = (encode>>8 & 0x01) + SPRITE_BANKBASE;
+ gfx = machine->gfx[bank];
+ tile = encode & 0xff;
+ fxy = encode & 0x800;
+ encode = ~encode & 0xf600;
+ fx = (encode & 0x400) | fxy;
+ fy = (encode & 0x200) | fxy;
+ color = encode>>12 & 0x0f;
+ encode = *sptr;
+ sx = encode>>8 & 0xff;
+ sy = encode & 0xff;
+ absx = (sx + flipadjx + SHIFTX) & 0xff;
+ absy = (sy + SHIFTY) & 0xff;
+ if (absx >= 248) absx -= 256;
+ if (absy >= 248) absy -= 256;
+
+ drawgfx(bitmap,
+ gfx,
+ tile, color,
+ fx, fy,
+ absx + BMPAD, absy + BMPAD,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+ }
+
+#undef SHIFTY
+#undef SHIFTX
+#undef SPRITE_BANKBASE
+}
+
+VIDEO_UPDATE( equites )
+{
+ equites_update_clut(machine);
+ equites_draw_scroll(machine, bitmap, cliprect);
+ equites_draw_sprites(machine, bitmap, cliprect);
+ plot_box(bitmap, cliprect->min_x, cliprect->min_y, maskwidth, maskheight, maskcolor);
+ plot_box(bitmap, cliprect->max_x-maskwidth+1, cliprect->min_y, maskwidth, maskheight, maskcolor);
+ tilemap_draw(bitmap, cliprect, charmap0, 0, 0);
+ return 0;
+}
+
+// Splendor Blast Hardware
+static void splndrbt_update_clut(running_machine *machine)
+{
+ int c;
+
+ /* palette hacks! */
+ c = *bgcolor;
+
+ switch(equites_id)
+ {
+ case 0x8511:
+ colortable_entry_set_value(equites_colortable, 0x114, c);
+ break;
+ }
+}
+
+static void splndrbt_draw_scroll(running_machine *machine, mame_bitmap *bitmap)
+{
+#define TILE_BANKBASE 1
+
+ int data, bank, tile, color, fx, fy, x, y, i;
+
+ for (i=0; i<0x400; i++)
+ if (dirtybuf[i])
+ {
+ dirtybuf[i] = 0;
+
+ x = (i & 0x1f) << 4;
+ y = (i & ~0x1f) >> 1;
+ if (!(data = spriteram16_2[i])) { plot_box(bitmap, x, y, 16, 16, *bgcolor); continue; }
+ tile = data & 0xff;
+ data >>= 8;
+ bank = TILE_BANKBASE;
+ color = data>>3 & 0x1f;
+ bank += data & 1;
+ fx = data & 4;
+ fy = data & 2;
+
+ drawgfx(bitmap,
+ machine->gfx[bank],
+ tile, color,
+ fx, fy,
+ x, y,
+ 0, TRANSPARENCY_NONE, 0);
+ }
+
+#undef TILE_BANKBASE
+}
+
+static void splndrbt_slantcopy(
+ mame_bitmap *src_bitmap,
+ mame_bitmap *dst_bitmap,
+ const rectangle *dst_clip,
+ int src_x, int src_y,
+ unsigned src_w, unsigned src_h,
+ unsigned dst_startw, unsigned dst_endw,
+ struct PRESTEP_TYPE *ps)
+{
+#define WRAP ((1<<BMW_l2)-1)
+
+ int src_center_x = ((src_x + (src_w>>1)) & WRAP) << FP_PRECISION;
+ int dst_pitch, dst_wdiff, dst_visw, dst_vish;
+ int dst_curline;
+
+ dst_visw = dst_clip->max_x - dst_clip->min_x + 1;
+ dst_vish = dst_clip->max_y - dst_clip->min_y;
+ dst_pitch = dst_bitmap->rowpixels;
+
+ dst_wdiff = dst_endw - dst_startw;
+
+ for (dst_curline = dst_clip->min_y; dst_curline <= dst_clip->max_y; dst_curline++)
+ {
+ const UINT16 *src_ptr = BITMAP_ADDR16(src_bitmap, (src_y + ps[dst_curline - dst_clip->min_y].sy) & WRAP, 0);
+ UINT16 *dst_ptr = BITMAP_ADDR16(dst_bitmap, dst_curline, dst_clip->min_x + dst_visw / 2);
+ int dst_xend = dst_startw + (dst_wdiff * (dst_curline - dst_clip->min_y)) / dst_vish;
+ int src_fsx = FP_HALF;
+ int src_fdx = ps[dst_curline - dst_clip->min_y].fdx;
+ int dst_x;
+
+ if (dst_xend > dst_visw) dst_xend = dst_visw;
+ dst_xend /= 2;
+
+ for (dst_x = 0; dst_x < dst_xend; dst_x++)
+ {
+ dst_ptr[-dst_x - 1] = src_ptr[((src_center_x - src_fsx) >> FP_PRECISION) & WRAP];
+ dst_ptr[dst_x] = src_ptr[((src_center_x + src_fsx) >> FP_PRECISION) & WRAP];
+ src_fsx += src_fdx;
+ }
+ }
+
+#undef WRAP
+}
+
+static void splndrbt_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *clip)
+{
+#define SPRITE_BANKBASE 3
+#define FP_ONE 0x10000
+#define SHIFTX 0
+#define SHIFTY 0
+
+ gfx_element *gfx;
+ UINT16 *data_ptr;
+ int data, sprite, fx, fy, absx, absy, sx, sy, adjy, scalex, scaley, color, i;
+
+ gfx = machine->gfx[SPRITE_BANKBASE];
+ data_ptr = spriteram16 + 1;
+
+ for (i=0; i<0x7e; i+=2)
+ {
+ data = data_ptr[i];
+ if (!data) continue;
+
+ fx = data & 0x2000;
+ fy = data & 0x1000;
+ sprite = data & 0x7f;
+ scaley = (data>>8 & 0x0f) + 1;
+ adjy = 0x10 - scaley;
+ scaley = (scaley << 12) + (scaley << 8) - 1;
+ if (scaley > FP_ONE) scaley = FP_ONE;
+
+ data = data_ptr[i+1];
+ sx = data & 0xff;
+ absx = (sx + SHIFTX) & 0xff;
+ if (absx >= 252) absx -= 256;
+
+ color = data>>8 & 0x1f;
+
+ data = data_ptr[i+0x80];
+ sy = data & 0xff;
+ absy = (-sy + adjy + SHIFTY) & 0xff;
+
+ data = data_ptr[i+0x81];
+ scalex = (data & 0x0f) + 1;
+ scalex <<= 12;
+
+ drawgfxzoom(bitmap,
+ gfx,
+ sprite, color,
+ fx, fy,
+ absx, absy, clip,
+ TRANSPARENCY_PEN, 0,
+ scalex, scaley);
+ }
+
+#undef SHIFTY
+#undef SHIFTX
+#undef FP_ONE
+#undef SPRITE_BANKBASE
+}
+
+VIDEO_UPDATE( splndrbt )
+{
+ splndrbt_update_clut(machine);
+ fillbitmap(bitmap, *bgcolor, &halfclip);
+ splndrbt_draw_scroll(machine, tmpbitmap);
+
+ splndrbt_slantcopy(
+ tmpbitmap, bitmap, cliprect,
+ *splndrbt_scrollx + scrollx, *splndrbt_scrolly + scrolly,
+ BMW, 434, 96, 480, prestep);
+
+ tilemap_draw(bitmap, cliprect, charmap1, 0, 0);
+ splndrbt_draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, charmap0, 0, 0);
+ return 0;
+}
+
+/******************************************************************************/
+// Memory Handlers
+
+// Equites Hardware
+READ16_HANDLER(equites_spriteram_r)
+{
+ if (*spriteram16 == 0x5555) return (0);
+ return (spriteram16[offset]);
+}
+
+WRITE16_HANDLER(equites_charram_w)
+{
+ COMBINE_DATA(videoram16 + offset);
+
+ tilemap_mark_tile_dirty(charmap0, offset>>1);
+}
+
+WRITE16_HANDLER(equites_bgcolor_w)
+{
+ if (!ACCESSING_MSB) return;
+
+ data >>= 8;
+
+ switch (equites_id)
+ {
+ case 0x8400:
+ if (!data) bgcolor[0] = 0;
+ else if (data==0x0e) bgcolor[0] = bgcolor[2];
+ else
+ {
+ bgcolor[2] = bgcolor[1];
+ bgcolor[1] = bgcolor[0] = data;
+ }
+ break;
+ default:
+ *bgcolor = data;
+ }
+}
+
+WRITE16_HANDLER(equites_scrollreg_w)
+{
+ if (ACCESSING_LSB) scrolly = data & 0xff;
+ if (ACCESSING_MSB) scrollx = data >> 8;
+}
+
+// Splendor Blast Hardware
+WRITE16_HANDLER(splndrbt_selchar0_w)
+{
+ activecharram = charram0;
+ inactivecharram = charram1;
+
+ activecharmap = charmap0;
+ inactivecharmap = charmap1;
+}
+
+WRITE16_HANDLER(splndrbt_selchar1_w)
+{
+ activecharram = charram1;
+ inactivecharram = charram0;
+
+ activecharmap = charmap1;
+ inactivecharmap = charmap0;
+}
+
+WRITE16_HANDLER(splndrbt_charram_w)
+{
+ int oddoffs = offset | 1;
+
+ COMBINE_DATA(videoram16 + offset);
+ COMBINE_DATA(defcharram + offset);
+
+ if (data==0x20 && !(offset&1))
+ {
+ activecharram[offset] = inactivecharram[offset] = 0x20;
+ activecharram[oddoffs] = inactivecharram[oddoffs] = 0x08;
+ offset >>= 1;
+ tilemap_mark_tile_dirty(activecharmap, offset);
+ tilemap_mark_tile_dirty(activecharmap, oddoffs);
+ tilemap_mark_tile_dirty(inactivecharmap, offset);
+ tilemap_mark_tile_dirty(inactivecharmap, oddoffs);
+ }
+ else
+ {
+ COMBINE_DATA(activecharram + offset);
+ tilemap_mark_tile_dirty(activecharmap, offset>>1);
+ }
+}
+
+READ16_HANDLER(splndrbt_bankedchar_r)
+{
+ if (defcharram[offset|1]==0x3f) return(0);
+ return(defcharram[offset]);
+}
+
+WRITE16_HANDLER(splndrbt_bankedchar_w)
+{
+ COMBINE_DATA(defcharram + offset);
+ COMBINE_DATA(activecharram + offset);
+ inactivecharram[offset&~1] = 0x20;
+ inactivecharram[offset|1] = 0x08;
+ offset >>= 1;
+ tilemap_mark_tile_dirty(activecharmap, offset);
+ tilemap_mark_tile_dirty(inactivecharmap, offset);
+}
+
+WRITE16_HANDLER(splndrbt_scrollram_w)
+{
+ COMBINE_DATA(spriteram16_2 + offset);
+ dirtybuf[offset] = 1;
+}
+
+#ifdef UNUSED_FUNCTION
+WRITE16_HANDLER(splndrbt_bgcolor_w)
+{
+ data >>= 8;
+
+ if (ACCESSING_MSB && *bgcolor != data)
+ {
+ *bgcolor = data;
+ memset(dirtybuf, 1, 0x400);
+ }
+}
+#endif
+
+/******************************************************************************/
diff --git a/src/mame/video/esd16.c b/src/mame/video/esd16.c
new file mode 100644
index 00000000000..12bac4acaa2
--- /dev/null
+++ b/src/mame/video/esd16.c
@@ -0,0 +1,380 @@
+/***************************************************************************
+
+ -= ESD 16 Bit Games =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z with:
+
+ Q / W Shows Layer 0 / 1
+ A Shows Sprites
+
+ Keys can be used together!
+
+
+ [ 2 Scrolling Layers ]
+
+ Tile Size: 8 x 8 x 8
+ Color Codes: 1 per Layer (banked for Layer 0)
+ Layer Size (tiles) : 128 x 64
+ Layer Size (pixels): 1024 x 512
+
+ [ 256 Sprites ]
+
+ Sprites are made of 16 x 16 x 5 tiles. Size can vary from 1 to
+ 8 tiles vertically, while their width is always 1 tile.
+
+ [ Priorities ]
+
+ The game only uses this scheme:
+
+ Back -> Front: Layer 0, Layer 1, Sprites
+
+***************************************************************************/
+
+#include "driver.h"
+
+/* Variables needed by drivers: */
+
+UINT16 *esd16_vram_0, *esd16_scroll_0;
+UINT16 *esd16_vram_1, *esd16_scroll_1;
+UINT16 *head_layersize;
+static int esd16_tilemap0_color = 0;
+
+/* Functions defined in video: */
+
+WRITE16_HANDLER( esd16_vram_0_w );
+WRITE16_HANDLER( esd16_vram_1_w );
+WRITE16_HANDLER( esd16_tilemap0_color_w );
+
+VIDEO_START( esd16 );
+VIDEO_UPDATE( esd16 );
+
+
+/***************************************************************************
+
+ Tilemaps
+
+ Offset: Bits: Value:
+
+ 0.w Code
+
+ Color code: layer 0 (backmost) can bank at every 256 colors,
+ layer 1 uses the first 256.
+
+***************************************************************************/
+
+static tilemap *esdtilemap_0;
+static tilemap *esdtilemap_1;
+tilemap *esdtilemap_1_16x16;
+
+static TILE_GET_INFO( get_tile_info_0 )
+{
+ UINT16 code = esd16_vram_0[tile_index];
+ SET_TILE_INFO(
+ 1,
+ code,
+ esd16_tilemap0_color,
+ 0);
+}
+
+static TILE_GET_INFO( get_tile_info_1 )
+{
+ UINT16 code = esd16_vram_1[tile_index];
+ SET_TILE_INFO(
+ 1,
+ code,
+ 0,
+ 0);
+}
+
+static TILE_GET_INFO( get_tile_info_1_16x16 )
+{
+ UINT16 code = esd16_vram_1[tile_index];
+ SET_TILE_INFO(
+ 2,
+ code,
+ 0,
+ 0);
+}
+
+WRITE16_HANDLER( esd16_vram_0_w )
+{
+ COMBINE_DATA(&esd16_vram_0[offset]);
+ tilemap_mark_tile_dirty(esdtilemap_0,offset);
+}
+
+WRITE16_HANDLER( esd16_vram_1_w )
+{
+ COMBINE_DATA(&esd16_vram_1[offset]);
+ tilemap_mark_tile_dirty(esdtilemap_1,offset);
+ tilemap_mark_tile_dirty(esdtilemap_1_16x16,offset);
+}
+
+WRITE16_HANDLER( esd16_tilemap0_color_w )
+{
+ esd16_tilemap0_color = data & 3;
+ tilemap_mark_all_tiles_dirty(esdtilemap_0);
+
+ flip_screen_set(data & 0x80);
+}
+
+
+/***************************************************************************
+
+
+ Video Hardware Init
+
+
+***************************************************************************/
+
+
+VIDEO_START( esd16 )
+{
+ esdtilemap_0 = tilemap_create( get_tile_info_0, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, 0x80,0x40);
+
+ esdtilemap_1 = tilemap_create( get_tile_info_1, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, 0x80,0x40);
+
+ /* hedpanic changes tilemap 1 to 16x16 at various times */
+ esdtilemap_1_16x16 = tilemap_create( get_tile_info_1_16x16, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 0x40,0x40);
+
+ tilemap_set_scrolldx(esdtilemap_0, -0x60 + 2, -0x60 );
+ tilemap_set_scrolldx(esdtilemap_1, -0x60 , -0x60 + 2 );
+ tilemap_set_scrolldx(esdtilemap_1_16x16, -0x60 , -0x60 + 2 );
+
+ tilemap_set_transparent_pen(esdtilemap_1,0x00);
+ tilemap_set_transparent_pen(esdtilemap_1_16x16,0x00);
+}
+
+
+
+
+/***************************************************************************
+
+ Sprites Drawing
+
+ Offset: Bits: Value:
+
+ 0.w fedc b--- ---- ----
+ ---- -a9- ---- ---- Y Size: (1 << N) Tiles
+ ---- ---8 7654 3210 Y (Signed, Bottom-Up)
+
+ 2.w Code
+
+ 4.w f--- ---- ---- ---- Sprite priority
+ -ed- ---- ---- ----
+ ---c ---- ---- ---- Color?
+ ---- ba9- ---- ---- Color
+ ---- ---8 7654 3210 X (Signed)
+
+ 6.w fedc ba9- ---- ----
+ ---- ---8 ---- ---- ? 1 (Display Sprite?)
+ ---- ---- 7654 3210
+
+- To Do: Flip X&Y ? They seem unused.
+
+***************************************************************************/
+
+static void esd16_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ int max_x = machine->screen[0].width;
+ int max_y = machine->screen[0].height;
+
+ for ( offs = spriteram_size/2 - 8/2; offs >= 0 ; offs -= 8/2 )
+ {
+ int y, starty, endy, incy;
+
+ int sy = spriteram16[ offs + 0 ];
+ int code = spriteram16[ offs + 1 ];
+ int sx = spriteram16[ offs + 2 ];
+ int attr = spriteram16[ offs + 3 ];
+
+ int dimy = 1 << ((sy >> 9) & 3);
+
+ int flipx = attr & 0x0000;
+ int flipy = attr & 0x0000;
+
+ int color = (sx >> 9) & 0xf;
+
+ int pri_mask;
+
+ if(sx & 0x8000)
+ pri_mask = 0xfffe; // under "tilemap 1"
+ else
+ pri_mask = 0; // above everything
+
+ sx = sx & 0x1ff;
+ if (sx >= 0x180) sx -= 0x200;
+
+ sy = 0x100 - ((sy & 0xff) - (sy & 0x100));
+ sy -= dimy*16;
+
+ if (flip_screen)
+ { flipx = !flipx; sx = max_x - sx - 1 * 16 + 2; // small offset
+ flipy = !flipy; sy = max_y - sy - dimy * 16; }
+
+ if (flipy) { starty = sy+(dimy-1)*16; endy = sy-16; incy = -16; }
+ else { starty = sy; endy = sy+dimy*16; incy = +16; }
+
+ for (y = starty ; y != endy ; y += incy)
+ {
+ pdrawgfx( bitmap, machine->gfx[0],
+ code++,
+ color,
+ flipx, flipy,
+ sx, y,
+ cliprect, TRANSPARENCY_PEN, 0, pri_mask );
+ }
+ }
+}
+
+/* note, check if i can re-merge this with the other or if its really different */
+static void hedpanic_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ int max_x = machine->screen[0].width;
+ int max_y = machine->screen[0].height;
+
+ for ( offs = spriteram_size/2 - 8/2; offs >= 0 ; offs -= 8/2 )
+ {
+ int y, starty, endy, incy;
+
+ int sy = spriteram16[ offs + 0 ];
+ int code = spriteram16[ offs + 1 ];
+ int sx = spriteram16[ offs + 2 ];
+// int attr = spriteram16[ offs + 3 ];
+
+ int dimy = 1 << ((sy >> 9) & 3);
+
+ int flipx = spriteram16[ offs + 0 ] & 0x2000;
+ int flipy = sy & 0x0000;
+
+ int color = (sx >> 9) & 0xf;
+
+ int pri_mask;
+
+ if(sx & 0x8000)
+ pri_mask = 0xfffe; // under "tilemap 1"
+ else
+ pri_mask = 0; // above everything
+
+ sx = sx & 0x1ff;
+ if (sx >= 0x180) sx -= 0x200;
+
+ sy &= 0x1ff;
+
+ sx -= 24;
+
+ sy = 0x1ff-sy;
+
+ if (flip_screen)
+ { flipx = !flipx; sx = max_x - sx - 1 * 16 + 2; // small offset
+ flipy = !flipy; sy = max_y - sy - dimy * 16; }
+
+ if (flipy) { starty = sy+(dimy-1)*16; endy = sy-16; incy = -16; }
+ else { starty = sy-dimy*16; endy = sy; incy = +16; }
+
+ for (y = starty ; y != endy ; y += incy)
+ {
+ pdrawgfx( bitmap, machine->gfx[0],
+ code++,
+ color,
+ flipx, flipy,
+ sx, y,
+ cliprect, TRANSPARENCY_PEN, 0, pri_mask );
+ }
+ }
+}
+
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+VIDEO_UPDATE( esd16 )
+{
+ int layers_ctrl = -1;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_set_scrollx(esdtilemap_0, 0, esd16_scroll_0[0]);
+ tilemap_set_scrolly(esdtilemap_0, 0, esd16_scroll_0[1]);
+
+ tilemap_set_scrollx(esdtilemap_1, 0, esd16_scroll_1[0]);
+ tilemap_set_scrolly(esdtilemap_1, 0, esd16_scroll_1[1]);
+
+#ifdef MAME_DEBUG
+if ( input_code_pressed(KEYCODE_Z) )
+{ int msk = 0;
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+ if (input_code_pressed(KEYCODE_A)) msk |= 4;
+ if (msk != 0) layers_ctrl &= msk; }
+#endif
+
+ if (layers_ctrl & 1) tilemap_draw(bitmap,cliprect,esdtilemap_0,0,0);
+ else fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ if (layers_ctrl & 2) tilemap_draw(bitmap,cliprect,esdtilemap_1,0,1);
+
+ if (layers_ctrl & 4) esd16_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+
+VIDEO_UPDATE( hedpanic )
+{
+ int layers_ctrl = -1;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_set_scrollx(esdtilemap_0, 0, esd16_scroll_0[0]);
+ tilemap_set_scrolly(esdtilemap_0, 0, esd16_scroll_0[1]);
+
+#ifdef MAME_DEBUG
+if ( input_code_pressed(KEYCODE_Z) )
+{ int msk = 0;
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+ if (input_code_pressed(KEYCODE_A)) msk |= 4;
+ if (msk != 0) layers_ctrl &= msk; }
+#endif
+
+ if (layers_ctrl & 1) tilemap_draw(bitmap,cliprect,esdtilemap_0,0,0);
+ else fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ if (layers_ctrl & 2)
+ {
+ if (head_layersize[0]&0x0002)
+ {
+ tilemap_set_scrollx(esdtilemap_1_16x16, 0, esd16_scroll_1[0]);
+ tilemap_set_scrolly(esdtilemap_1_16x16, 0, esd16_scroll_1[1]);
+ tilemap_draw(bitmap,cliprect,esdtilemap_1_16x16,0,1);
+ }
+ else
+ {
+ tilemap_set_scrollx(esdtilemap_1, 0, esd16_scroll_1[0]);
+ tilemap_set_scrolly(esdtilemap_1, 0, esd16_scroll_1[1]);
+ tilemap_draw(bitmap,cliprect,esdtilemap_1,0,1);
+ }
+
+ }
+
+ if (layers_ctrl & 4) hedpanic_draw_sprites(machine,bitmap,cliprect);
+
+
+// popmessage("%04x %04x %04x %04x %04x",head_unknown1[0],head_layersize[0],head_unknown3[0],head_unknown4[0],head_unknown5[0]);
+ return 0;
+}
diff --git a/src/mame/video/espial.c b/src/mame/video/espial.c
new file mode 100644
index 00000000000..2f89e8f530a
--- /dev/null
+++ b/src/mame/video/espial.c
@@ -0,0 +1,243 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/espial.h"
+
+
+UINT8 *espial_videoram;
+UINT8 *espial_colorram;
+UINT8 *espial_attributeram;
+UINT8 *espial_scrollram;
+UINT8 *espial_spriteram_1;
+UINT8 *espial_spriteram_2;
+UINT8 *espial_spriteram_3;
+
+static int flipscreen;
+static tilemap *bg_tilemap;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Espial has two 256x4 palette PROMs.
+
+ I don't know for sure how the palette PROMs are connected to the RGB
+ output, but it's probably the usual:
+
+ bit 3 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ bit 0 -- 470 ohm resistor -- GREEN
+ bit 3 -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( espial )
+{
+ int i;
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i + machine->drv->total_colors] >> 0) & 0x01;
+ bit2 = (color_prom[i + machine->drv->total_colors] >> 1) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (color_prom[i + machine->drv->total_colors] >> 2) & 0x01;
+ bit2 = (color_prom[i + machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 code = espial_videoram[tile_index];
+ UINT8 col = espial_colorram[tile_index];
+ UINT8 attr = espial_attributeram[tile_index];
+ SET_TILE_INFO(0,
+ code | ((attr & 0x03) << 8),
+ col & 0x3f,
+ TILE_FLIPYX(attr >> 2));
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( espial )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+}
+
+VIDEO_START( netwars )
+{
+ /* Net Wars has a tile map that's twice as big as Espial's */
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,64);
+
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+ tilemap_set_scrolldy(bg_tilemap, 0, 0x100);
+}
+
+
+/*************************************
+ *
+ * Memory handlers
+ *
+ *************************************/
+
+WRITE8_HANDLER( espial_videoram_w )
+{
+ espial_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( espial_colorram_w )
+{
+ espial_colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( espial_attributeram_w )
+{
+ espial_attributeram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( espial_scrollram_w )
+{
+ espial_scrollram[offset] = data;
+ tilemap_set_scrolly(bg_tilemap, offset, data);
+}
+
+
+WRITE8_HANDLER( espial_flipscreen_w )
+{
+ flipscreen = data;
+
+ tilemap_set_flip(0, flipscreen ? TILEMAP_FLIPX | TILEMAP_FLIPY : 0);
+}
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+
+ /* Note that it is important to draw them exactly in this */
+ /* order, to have the correct priorities. */
+ for (offs = 0;offs < 16;offs++)
+ {
+ int sx,sy,code,color,flipx,flipy;
+
+
+ sx = espial_spriteram_1[offs + 16];
+ sy = espial_spriteram_2[offs];
+ code = espial_spriteram_1[offs] >> 1;
+ color = espial_spriteram_2[offs + 16];
+ flipx = espial_spriteram_3[offs] & 0x04;
+ flipy = espial_spriteram_3[offs] & 0x08;
+
+ if (flipscreen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+ else
+ {
+ sy = 240 - sy;
+ }
+
+ if (espial_spriteram_1[offs] & 1) /* double height */
+ {
+ if (flipscreen)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ code,color,
+ flipx,flipy,
+ sx,sy + 16,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[1],
+ code + 1,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ code,color,
+ flipx,flipy,
+ sx,sy - 16,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[1],
+ code + 1,color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ else
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ code,color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+
+VIDEO_UPDATE( espial )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/exctsccr.c b/src/mame/video/exctsccr.c
new file mode 100644
index 00000000000..8a7447121a1
--- /dev/null
+++ b/src/mame/video/exctsccr.c
@@ -0,0 +1,247 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static int gfx_bank;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+***************************************************************************/
+PALETTE_INIT( exctsccr )
+{
+ int i,idx;
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ color_prom += machine->drv->total_colors;
+
+ /* characters */
+ idx = 0;
+ for (i = 0;i < 32;i++)
+ {
+ COLOR(0,idx++) = color_prom[256+0+(i*4)];
+ COLOR(0,idx++) = color_prom[256+1+(i*4)];
+ COLOR(0,idx++) = color_prom[256+2+(i*4)];
+ COLOR(0,idx++) = color_prom[256+3+(i*4)];
+ COLOR(0,idx++) = color_prom[256+128+0+(i*4)];
+ COLOR(0,idx++) = color_prom[256+128+1+(i*4)];
+ COLOR(0,idx++) = color_prom[256+128+2+(i*4)];
+ COLOR(0,idx++) = color_prom[256+128+3+(i*4)];
+ }
+
+ /* sprites */
+
+ idx=0;
+
+ for (i = 0;i < 15*16;i++)
+ {
+ if ( (i%16) < 8 )
+ {
+ COLOR(2,idx) = color_prom[i]+16;
+ idx++;
+ }
+ }
+ for (i = 15*16;i < 16*16;i++)
+ {
+ if ( (i%16) > 7 )
+ {
+ COLOR(2,idx) = color_prom[i]+16;
+ idx++;
+ }
+ }
+ for (i = 16;i < 32;i++)
+ {
+ COLOR(2,idx++) = color_prom[256+0+(i*4)]+16;
+ COLOR(2,idx++) = color_prom[256+1+(i*4)]+16;
+ COLOR(2,idx++) = color_prom[256+2+(i*4)]+16;
+ COLOR(2,idx++) = color_prom[256+3+(i*4)]+16;
+ COLOR(2,idx++) = color_prom[256+128+0+(i*4)]+16;
+ COLOR(2,idx++) = color_prom[256+128+1+(i*4)]+16;
+ COLOR(2,idx++) = color_prom[256+128+2+(i*4)]+16;
+ COLOR(2,idx++) = color_prom[256+128+3+(i*4)]+16;
+ }
+
+ /* Patch for goalkeeper */
+ COLOR(2,29*8+7) = 16;
+
+}
+
+static TIMER_CALLBACK( exctsccr_fm_callback )
+{
+ cpunum_set_input_line_and_vector( 1, 0, HOLD_LINE, 0xff );
+}
+
+WRITE8_HANDLER( exctsccr_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( exctsccr_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( exctsccr_gfx_bank_w )
+{
+ if (gfx_bank != (data & 0x01))
+ {
+ gfx_bank = data & 0x01;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( exctsccr_flipscreen_w )
+{
+ if (flip_screen != data)
+ {
+ flip_screen_set(data);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index];
+ int color = colorram[tile_index] & 0x1f;
+
+ SET_TILE_INFO(gfx_bank, code, color, 0);
+}
+
+VIDEO_START( exctsccr )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ timer_pulse(ATTOTIME_IN_HZ(75), 0, exctsccr_fm_callback); /* updates fm */
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+ UINT8 *OBJ1, *OBJ2;
+
+ OBJ1 = videoram;
+ OBJ2 = &(spriteram[0x20]);
+
+ for ( offs = 0x0e; offs >= 0; offs -= 2 ) {
+ int sx,sy,code,bank,flipx,flipy,color;
+
+ sx = 256 - OBJ2[offs+1];
+ sy = OBJ2[offs] - 16;
+
+ code = ( OBJ1[offs] >> 2 ) & 0x3f;
+ flipx = ( OBJ1[offs] ) & 0x01;
+ flipy = ( OBJ1[offs] ) & 0x02;
+ color = ( OBJ1[offs+1] ) & 0x1f;
+ bank = 2;
+ bank += ( ( OBJ1[offs+1] >> 4 ) & 1 );
+
+ drawgfx(bitmap,machine->gfx[bank],
+ code,
+ color,
+ flipx, flipy,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN,0);
+ }
+
+ OBJ1 = spriteram_2;
+ OBJ2 = spriteram;
+
+ for ( offs = 0x0e; offs >= 0; offs -= 2 ) {
+ int sx,sy,code,bank,flipx,flipy,color;
+
+ sx = 256 - OBJ2[offs+1];
+ sy = OBJ2[offs] - 16;
+
+ code = ( OBJ1[offs] >> 2 ) & 0x3f;
+ flipx = ( OBJ1[offs] ) & 0x01;
+ flipy = ( OBJ1[offs] ) & 0x02;
+ color = ( OBJ1[offs+1] ) & 0x1f;
+ bank = 3;
+
+ if ( color == 0 )
+ continue;
+
+ if ( color < 0x10 )
+ bank++;
+
+ if ( color > 0x10 && color < 0x17 )
+ {
+ drawgfx(bitmap,machine->gfx[4],
+ code,
+ 0x0e,
+ flipx, flipy,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN,0);
+
+ color += 6;
+ }
+ if ( color==0x1d && gfx_bank==1 )
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ code,
+ color,
+ flipx, flipy,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[4],
+ code,
+ color,
+ flipx, flipy,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_COLOR, 16);
+
+ } else
+ {
+ drawgfx(bitmap,machine->gfx[bank],
+ code,
+ color,
+ flipx, flipy,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( exctsccr )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/exedexes.c b/src/mame/video/exedexes.c
new file mode 100644
index 00000000000..a193b33b554
--- /dev/null
+++ b/src/mame/video/exedexes.c
@@ -0,0 +1,254 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *exedexes_bg_scroll;
+
+UINT8 *exedexes_nbg_yscroll;
+UINT8 *exedexes_nbg_xscroll;
+
+static int chon,objon,sc1on,sc2on;
+
+#define TileMap(offs) (memory_region(REGION_GFX5)[offs])
+#define BackTileMap(offs) (memory_region(REGION_GFX5)[offs+0x4000])
+
+static tilemap *bg_tilemap, *fg_tilemap, *tx_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Exed Exes has three 256x4 palette PROMs (one per gun), three 256x4 lookup
+ table PROMs (one for characters, one for sprites, one for background tiles)
+ and one 256x4 sprite palette bank selector PROM.
+
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+PALETTE_INIT( exedexes )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* characters use colors 192-207 */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = (*color_prom++) + 192;
+
+ /* 32x32 tiles use colors 0-15 */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = (*color_prom++);
+
+ /* 16x16 tiles use colors 64-79 */
+ for (i = 0;i < TOTAL_COLORS(2);i++)
+ COLOR(2,i) = (*color_prom++) + 64;
+
+ /* sprites use colors 128-191 in four banks */
+ for (i = 0;i < TOTAL_COLORS(3);i++)
+ {
+ COLOR(3,i) = color_prom[0] + 128 + 16 * color_prom[256];
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( exedexes_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap, offset);
+}
+
+WRITE8_HANDLER( exedexes_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap, offset);
+}
+
+WRITE8_HANDLER( exedexes_c804_w )
+{
+ /* bits 0 and 1 are coin counters */
+ coin_counter_w(0, data & 0x01);
+ coin_counter_w(1, data & 0x02);
+
+ coin_lockout_w(0, data & 0x04);
+ coin_lockout_w(1, data & 0x08);
+
+ /* bit 7 is text enable */
+ chon = data & 0x80;
+
+ /* other bits seem to be unused */
+}
+
+WRITE8_HANDLER( exedexes_gfxctrl_w )
+{
+ /* bit 4 is bg enable */
+ sc2on = data & 0x10;
+
+ /* bit 5 is fg enable */
+ sc1on = data & 0x20;
+
+ /* bit 6 is sprite enable */
+ objon = data & 0x40;
+
+ /* other bits seem to be unused */
+}
+
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 *tilerom = memory_region(REGION_GFX5);
+
+ int attr = tilerom[tile_index];
+ int code = attr & 0x3f;
+ int color = tilerom[tile_index + (8 * 8)];
+ int flags = ((attr & 0x40) ? TILE_FLIPX : 0) | ((attr & 0x80) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(1, code, color, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = memory_region(REGION_GFX5)[tile_index];
+
+ SET_TILE_INFO(2, code, 0, 0);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int code = videoram[tile_index] + 2 * (colorram[tile_index] & 0x80);
+ int color = colorram[tile_index] & 0x3f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static TILEMAP_MAPPER( exedexes_bg_tilemap_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return ((col * 32 & 0xe0) >> 5) + ((row * 32 & 0xe0) >> 2) + ((col * 32 & 0x3f00) >> 1) + 0x4000;
+}
+
+static TILEMAP_MAPPER( exedexes_fg_tilemap_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return ((col * 16 & 0xf0) >> 4) + (row * 16 & 0xf0) + (col * 16 & 0x700) + ((row * 16 & 0x700) << 3);
+}
+
+VIDEO_START( exedexes )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, exedexes_bg_tilemap_scan,
+ TILEMAP_TYPE_PEN, 32, 32, 64, 64);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, exedexes_fg_tilemap_scan,
+ TILEMAP_TYPE_PEN, 16, 16, 128, 128);
+
+ tx_tilemap = tilemap_create(get_tx_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_COLORTABLE, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+ tilemap_set_transparent_pen(tx_tilemap, 207);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int offs;
+
+ if (!objon) return;
+
+ priority = priority ? 0x40 : 0x00;
+
+ for (offs = spriteram_size - 32;offs >= 0;offs -= 32)
+ {
+ if ((buffered_spriteram[offs + 1] & 0x40) == priority)
+ {
+ int code,color,flipx,flipy,sx,sy;
+
+ code = buffered_spriteram[offs];
+ color = buffered_spriteram[offs + 1] & 0x0f;
+ flipx = buffered_spriteram[offs + 1] & 0x10;
+ flipy = buffered_spriteram[offs + 1] & 0x20;
+ sx = buffered_spriteram[offs + 3] - ((buffered_spriteram[offs + 1] & 0x80) << 1);
+ sy = buffered_spriteram[offs + 2];
+
+ drawgfx(bitmap,machine->gfx[3],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( exedexes )
+{
+ if (sc2on)
+ {
+ tilemap_set_scrollx(bg_tilemap, 0, ((exedexes_bg_scroll[1]) << 8) + exedexes_bg_scroll[0]);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ }
+ else
+ {
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+ }
+
+ draw_sprites(machine, bitmap, cliprect, 1);
+
+ if (sc1on)
+ {
+ tilemap_set_scrollx(fg_tilemap, 0, ((exedexes_nbg_yscroll[1]) << 8) + exedexes_nbg_yscroll[0]);
+ tilemap_set_scrolly(fg_tilemap, 0, ((exedexes_nbg_xscroll[1]) << 8) + exedexes_nbg_xscroll[0]);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ }
+
+ draw_sprites(machine, bitmap, cliprect, 0);
+
+ if (chon)
+ {
+ tilemap_draw(bitmap, cliprect, tx_tilemap, 0, 0);
+ }
+ return 0;
+}
+
+VIDEO_EOF( exedexes )
+{
+ buffer_spriteram_w(0,0);
+}
diff --git a/src/mame/video/exerion.c b/src/mame/video/exerion.c
new file mode 100644
index 00000000000..b2d32f82ddb
--- /dev/null
+++ b/src/mame/video/exerion.c
@@ -0,0 +1,408 @@
+/***************************************************************************
+
+ Jaleco Exerion
+
+***************************************************************************/
+
+#include "driver.h"
+#include "exerion.h"
+
+
+#define BACKGROUND_X_START 32
+
+#define VISIBLE_X_MIN (12*8)
+#define VISIBLE_X_MAX (52*8)
+#define VISIBLE_Y_MIN (2*8)
+#define VISIBLE_Y_MAX (30*8)
+
+
+UINT8 exerion_cocktail_flip;
+
+static UINT8 char_palette, sprite_palette;
+static UINT8 char_bank;
+
+static UINT16 *background_gfx[4];
+static UINT8 background_latches[13];
+
+static UINT8 *background_mixer;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+
+PALETTE_INIT( exerion )
+{
+ int i;
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the char lookup table */
+
+ /* fg chars */
+ for (i = 0; i < 256; i++)
+ colortable[i + 0x000] = 16 + (color_prom[(i & 0xc0) | ((i & 3) << 4) | ((i >> 2) & 15)] & 15);
+ color_prom += 256;
+
+ /* color_prom now points to the beginning of the sprite lookup table */
+
+ /* sprites */
+ for (i = 0; i < 256; i++)
+ colortable[i + 0x100] = 16 + (color_prom[(i & 0xc0) | ((i & 3) << 4) | ((i >> 2) & 15)] & 15);
+ color_prom += 256;
+
+ /* bg chars (this is not the full story... there are four layers mixed */
+ /* using another PROM */
+ for (i = 0; i < 256; i++)
+ colortable[i + 0x200] = *color_prom++ & 15;
+}
+
+
+
+/*************************************
+ *
+ * Video system startup
+ *
+ *************************************/
+
+VIDEO_START( exerion )
+{
+ UINT16 *dst;
+ UINT8 *src;
+ int i, x, y;
+
+ /* get pointers to the mixing and lookup PROMs */
+ background_mixer = memory_region(REGION_PROMS) + 0x320;
+
+ /* allocate memory for the decoded background graphics */
+ background_gfx[0] = auto_malloc(2 * 256 * 256 * 4);
+ background_gfx[1] = background_gfx[0] + 256 * 256;
+ background_gfx[2] = background_gfx[1] + 256 * 256;
+ background_gfx[3] = background_gfx[2] + 256 * 256;
+
+ /*---------------------------------
+ * Decode the background graphics
+ *
+ * We decode the 4 background layers separately, but shuffle the bits so that
+ * we can OR all four layers together. Each layer has 2 bits per pixel. Each
+ * layer is decoded into the following bit patterns:
+ *
+ * 000a 0000 00AA
+ * 00b0 0000 BB00
+ * 0c00 00CC 0000
+ * d000 DD00 0000
+ *
+ * Where AA,BB,CC,DD are the 2bpp data for the pixel,and a,b,c,d are the OR
+ * of these two bits together.
+ */
+ for (i = 0; i < 4; i++)
+ {
+ src = memory_region(REGION_GFX3) + i * 0x2000;
+ dst = background_gfx[i];
+
+ for (y = 0; y < 256; y++)
+ {
+ for (x = 0; x < 128; x += 4)
+ {
+ UINT8 data = *src++;
+ UINT16 val;
+
+ val = ((data >> 3) & 2) | ((data >> 0) & 1);
+ if (val) val |= 0x100 >> i;
+ *dst++ = val << (2 * i);
+
+ val = ((data >> 4) & 2) | ((data >> 1) & 1);
+ if (val) val |= 0x100 >> i;
+ *dst++ = val << (2 * i);
+
+ val = ((data >> 5) & 2) | ((data >> 2) & 1);
+ if (val) val |= 0x100 >> i;
+ *dst++ = val << (2 * i);
+
+ val = ((data >> 6) & 2) | ((data >> 3) & 1);
+ if (val) val |= 0x100 >> i;
+ *dst++ = val << (2 * i);
+ }
+ for (x = 0; x < 128; x++)
+ *dst++ = 0;
+ }
+ }
+
+ video_start_generic(machine);
+}
+
+
+
+/*************************************
+ *
+ * Video register I/O
+ *
+ *************************************/
+
+WRITE8_HANDLER( exerion_videoreg_w )
+{
+ /* bit 0 = flip screen and joystick input multiplexer */
+ exerion_cocktail_flip = data & 1;
+
+ /* bits 1-2 char lookup table bank */
+ char_palette = (data & 0x06) >> 1;
+
+ /* bits 3 char bank */
+ char_bank = (data & 0x08) >> 3;
+
+ /* bits 4-5 unused */
+
+ /* bits 6-7 sprite lookup table bank */
+ sprite_palette = (data & 0xc0) >> 6;
+}
+
+
+WRITE8_HANDLER( exerion_video_latch_w )
+{
+ background_latches[offset] = data;
+
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+}
+
+
+READ8_HANDLER( exerion_video_timing_r )
+{
+ /* bit 0 is the SNMI signal, which is the negated value of H6, if H7=1 & H8=1 & VBLANK=0, otherwise 1 */
+ /* bit 1 is VBLANK */
+
+ UINT16 hcounter = video_screen_get_hpos(0) + EXERION_HCOUNT_START;
+ UINT8 snmi = 1;
+
+ if (((hcounter & 0x180) == 0x180) && !video_screen_get_vblank(0))
+ {
+ snmi = !((hcounter >> 6) & 0x01);
+ }
+
+ return (video_screen_get_vblank(0) << 1) | snmi;
+}
+
+
+/*************************************
+ *
+ * Background rendering
+ *
+ *************************************/
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int x, y;
+
+ /* loop over all visible scanlines */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *src0 = &background_gfx[0][background_latches[1] * 256];
+ UINT16 *src1 = &background_gfx[1][background_latches[3] * 256];
+ UINT16 *src2 = &background_gfx[2][background_latches[5] * 256];
+ UINT16 *src3 = &background_gfx[3][background_latches[7] * 256];
+ int xoffs0 = background_latches[0];
+ int xoffs1 = background_latches[2];
+ int xoffs2 = background_latches[4];
+ int xoffs3 = background_latches[6];
+ int start0 = background_latches[8] & 0x0f;
+ int start1 = background_latches[9] & 0x0f;
+ int start2 = background_latches[10] & 0x0f;
+ int start3 = background_latches[11] & 0x0f;
+ int stop0 = background_latches[8] >> 4;
+ int stop1 = background_latches[9] >> 4;
+ int stop2 = background_latches[10] >> 4;
+ int stop3 = background_latches[11] >> 4;
+ UINT8 *mixer = &background_mixer[(background_latches[12] << 4) & 0xf0];
+ UINT8 scanline[VISIBLE_X_MAX];
+ const pen_t *pens;
+
+ /* the cocktail flip flag controls whether we count up or down in X */
+ if (!exerion_cocktail_flip)
+ {
+ /* skip processing anything that's not visible */
+ for (x = BACKGROUND_X_START; x < cliprect->min_x; x++)
+ {
+ if (!(++xoffs0 & 0x1f)) start0++, stop0++;
+ if (!(++xoffs1 & 0x1f)) start1++, stop1++;
+ if (!(++xoffs2 & 0x1f)) start2++, stop2++;
+ if (!(++xoffs3 & 0x1f)) start3++, stop3++;
+ }
+
+ /* draw the rest of the scanline fully */
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ UINT16 combined = 0;
+ UINT8 lookupval;
+
+ /* the output enable is controlled by the carries on the start/stop counters */
+ /* they are only active when the start has carried but the stop hasn't */
+ if ((start0 ^ stop0) & 0x10) combined |= src0[xoffs0 & 0xff];
+ if ((start1 ^ stop1) & 0x10) combined |= src1[xoffs1 & 0xff];
+ if ((start2 ^ stop2) & 0x10) combined |= src2[xoffs2 & 0xff];
+ if ((start3 ^ stop3) & 0x10) combined |= src3[xoffs3 & 0xff];
+
+ /* bits 8-11 of the combined value contains the lookup for the mixer PROM */
+ lookupval = mixer[combined >> 8] & 3;
+
+ /* the color index comes from the looked up value combined with the pixel data */
+ scanline[x] = (lookupval << 2) | ((combined >> (2 * lookupval)) & 3);
+
+ /* the start/stop counters are clocked when the low 5 bits of the X counter overflow */
+ if (!(++xoffs0 & 0x1f)) start0++, stop0++;
+ if (!(++xoffs1 & 0x1f)) start1++, stop1++;
+ if (!(++xoffs2 & 0x1f)) start2++, stop2++;
+ if (!(++xoffs3 & 0x1f)) start3++, stop3++;
+ }
+ }
+ else
+ {
+ /* skip processing anything that's not visible */
+ for (x = BACKGROUND_X_START; x < cliprect->min_x; x++)
+ {
+ if (!(xoffs0-- & 0x1f)) start0++, stop0++;
+ if (!(xoffs1-- & 0x1f)) start1++, stop1++;
+ if (!(xoffs2-- & 0x1f)) start2++, stop2++;
+ if (!(xoffs3-- & 0x1f)) start3++, stop3++;
+ }
+
+ /* draw the rest of the scanline fully */
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ UINT16 combined = 0;
+ UINT8 lookupval;
+
+ /* the output enable is controlled by the carries on the start/stop counters */
+ /* they are only active when the start has carried but the stop hasn't */
+ if ((start0 ^ stop0) & 0x10) combined |= src0[xoffs0 & 0xff];
+ if ((start1 ^ stop1) & 0x10) combined |= src1[xoffs1 & 0xff];
+ if ((start2 ^ stop2) & 0x10) combined |= src2[xoffs2 & 0xff];
+ if ((start3 ^ stop3) & 0x10) combined |= src3[xoffs3 & 0xff];
+
+ /* bits 8-11 of the combined value contains the lookup for the mixer PROM */
+ lookupval = mixer[combined >> 8] & 3;
+
+ /* the color index comes from the looked up value combined with the pixel data */
+ scanline[x] = (lookupval << 2) | ((combined >> (2 * lookupval)) & 3);
+
+ /* the start/stop counters are clocked when the low 5 bits of the X counter overflow */
+ if (!(xoffs0-- & 0x1f)) start0++, stop0++;
+ if (!(xoffs1-- & 0x1f)) start1++, stop1++;
+ if (!(xoffs2-- & 0x1f)) start2++, stop2++;
+ if (!(xoffs3-- & 0x1f)) start3++, stop3++;
+ }
+ }
+
+ /* draw the scanline */
+ pens = &machine->remapped_colortable[0x200 + (background_latches[12] >> 4) * 16];
+ draw_scanline8(bitmap, cliprect->min_x, y, cliprect->max_x - cliprect->min_x + 1, &scanline[cliprect->min_x], pens, -1);
+ }
+}
+
+
+/*************************************
+ *
+ * Core refresh routine
+ *
+ *************************************/
+
+VIDEO_UPDATE( exerion )
+{
+ int sx, sy, offs, i;
+
+ /* draw background */
+ draw_background(machine, bitmap, cliprect);
+
+ /* draw sprites */
+ for (i = 0; i < spriteram_size; i += 4)
+ {
+ int flags = spriteram[i + 0];
+ int y = spriteram[i + 1] ^ 255;
+ int code = spriteram[i + 2];
+ int x = spriteram[i + 3] * 2 + 72;
+
+ int xflip = flags & 0x80;
+ int yflip = flags & 0x40;
+ int doubled = flags & 0x10;
+ int wide = flags & 0x08;
+ int code2 = code;
+
+ int color = ((flags >> 1) & 0x03) | ((code >> 5) & 0x04) | (code & 0x08) | (sprite_palette * 16);
+ const gfx_element *gfx = doubled ? machine->gfx[2] : machine->gfx[1];
+
+ if (exerion_cocktail_flip)
+ {
+ x = 64*8 - gfx->width - x;
+ y = 32*8 - gfx->height - y;
+ if (wide) y -= gfx->height;
+ xflip = !xflip;
+ yflip = !yflip;
+ }
+
+ if (wide)
+ {
+ if (yflip)
+ code |= 0x10, code2 &= ~0x10;
+ else
+ code &= ~0x10, code2 |= 0x10;
+
+ drawgfx(bitmap, gfx, code2, color, xflip, yflip, x, y + gfx->height,
+ cliprect, TRANSPARENCY_COLOR, 16);
+ }
+
+ drawgfx(bitmap, gfx, code, color, xflip, yflip, x, y,
+ cliprect, TRANSPARENCY_COLOR, 16);
+
+ if (doubled) i += 4;
+ }
+
+ /* draw the visible text layer */
+ for (sy = cliprect->min_y/8; sy <= cliprect->max_y/8; sy++)
+ for (sx = VISIBLE_X_MIN/8; sx < VISIBLE_X_MAX/8; sx++)
+ {
+ int x = exerion_cocktail_flip ? (63*8 - 8*sx) : 8*sx;
+ int y = exerion_cocktail_flip ? (31*8 - 8*sy) : 8*sy;
+
+ offs = sx + sy * 64;
+ drawgfx(bitmap, machine->gfx[0],
+ videoram[offs] + 256 * char_bank,
+ ((videoram[offs] & 0xf0) >> 4) + char_palette * 16,
+ exerion_cocktail_flip, exerion_cocktail_flip, x, y,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/exidy.c b/src/mame/video/exidy.c
new file mode 100644
index 00000000000..a72cb0ea231
--- /dev/null
+++ b/src/mame/video/exidy.c
@@ -0,0 +1,502 @@
+/*************************************************************************
+
+ Exidy 6502 hardware
+
+*************************************************************************/
+
+#include "driver.h"
+#include "exidy.h"
+
+UINT8 *exidy_characterram;
+
+UINT8 exidy_collision_mask;
+UINT8 exidy_collision_invert;
+
+UINT8 *exidy_palette;
+UINT16 *exidy_colortable;
+
+static mame_bitmap *motion_object_1_vid;
+static mame_bitmap *motion_object_2_vid;
+static mame_bitmap *motion_object_2_clip;
+
+static UINT8 chardirty[256];
+static UINT8 update_complete;
+
+static UINT8 int_condition;
+
+static UINT8 spriteno;
+static UINT8 sprite_enable;
+static UINT8 sprite1_xpos;
+static UINT8 sprite1_ypos;
+static UINT8 sprite2_xpos;
+static UINT8 sprite2_ypos;
+
+static UINT8 color_latch[3];
+
+
+
+/*************************************
+ *
+ * Hard coded palettes
+ *
+ *************************************/
+
+/* Sidetrack/Targ/Spectar don't have a color PROM; colors are changed by the means of 8x3 */
+/* dip switches on the board. Here are the colors they map to. */
+UINT8 sidetrac_palette[PALETTE_LEN*3] =
+{
+ 0x00,0x00,0x00, /* BACKGND */
+ 0x00,0x00,0x00, /* CSPACE0 */
+ 0x00,0xff,0x00, /* CSPACE1 */
+ 0xff,0xff,0xff, /* CSPACE2 */
+ 0xff,0xff,0xff, /* CSPACE3 */
+ 0xff,0x00,0xff, /* 5LINES (unused?) */
+ 0xff,0xff,0x00, /* 5MO2VID */
+ 0xff,0xff,0xff /* 5MO1VID */
+};
+
+/* Targ has different colors */
+UINT8 targ_palette[PALETTE_LEN*3] =
+{
+ /* color use */
+ 0x00,0x00,0xff, /* blue background */
+ 0x00,0xff,0xff, /* cyan characters 192-255 */
+ 0xff,0xff,0x00, /* yellow characters 128-191 */
+ 0xff,0xff,0xff, /* white characters 64-127 */
+ 0xff,0x00,0x00, /* red characters 0- 63 */
+ 0x00,0xff,0xff, /* cyan not used */
+ 0xff,0xff,0xff, /* white bullet sprite */
+ 0x00,0xff,0x00, /* green wummel sprite */
+};
+
+/* Spectar has different colors */
+UINT8 spectar_palette[PALETTE_LEN*3] =
+{
+ /* color use */
+ 0x00,0x00,0xff, /* blue background */
+ 0x00,0xff,0x00, /* green characters 192-255 */
+ 0x00,0xff,0x00, /* green characters 128-191 */
+ 0xff,0xff,0xff, /* white characters 64-127 */
+ 0xff,0x00,0x00, /* red characters 0- 63 */
+ 0x00,0xff,0x00, /* green not used */
+ 0xff,0xff,0x00, /* yellow bullet sprite */
+ 0x00,0xff,0x00, /* green wummel sprite */
+};
+
+
+
+/*************************************
+ *
+ * Hard coded color tables
+ *
+ *************************************/
+
+UINT16 exidy_1bpp_colortable[COLORTABLE_LEN] =
+{
+ /* one-bit characters */
+ 0, 4, /* chars 0x00-0x3F */
+ 0, 3, /* chars 0x40-0x7F */
+ 0, 2, /* chars 0x80-0xBF */
+ 0, 1, /* chars 0xC0-0xFF */
+
+ /* Motion Object 1 */
+ 0, 7,
+
+ /* Motion Object 2 */
+ 0, 6,
+};
+
+UINT16 exidy_2bpp_colortable[COLORTABLE_LEN] =
+{
+ /* two-bit characters */
+ /* (Because this is 2-bit color, the colorspace is only divided
+ in half instead of in quarters. That's why 00-3F = 40-7F and
+ 80-BF = C0-FF) */
+ 0, 0, 4, 3, /* chars 0x00-0x3F */
+ 0, 0, 4, 3, /* chars 0x40-0x7F */
+ 0, 0, 2, 1, /* chars 0x80-0xBF */
+ 0, 0, 2, 1, /* chars 0xC0-0xFF */
+
+ /* Motion Object 1 */
+ 0, 7,
+
+ /* Motion Object 2 */
+ 0, 6,
+};
+
+
+
+/*************************************
+ *
+ * Palettes and colors
+ *
+ *************************************/
+
+PALETTE_INIT( exidy )
+{
+ if (exidy_palette)
+ {
+ int i;
+
+ for (i = 0; i < PALETTE_LEN; i++)
+ palette_set_color_rgb(machine,i,exidy_palette[i*3+0],exidy_palette[i*3+1],exidy_palette[i*3+2]);
+ }
+ memcpy(colortable, exidy_colortable, COLORTABLE_LEN * sizeof(colortable[0]));
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( exidy )
+{
+ video_start_generic(machine);
+
+ motion_object_1_vid = auto_bitmap_alloc(16, 16, machine->screen[0].format);
+ motion_object_2_vid = auto_bitmap_alloc(16, 16, machine->screen[0].format);
+ motion_object_2_clip = auto_bitmap_alloc(16, 16, machine->screen[0].format);
+}
+
+
+
+/*************************************
+ *
+ * Interrupt generation
+ *
+ *************************************/
+
+INLINE void latch_condition(int collision)
+{
+ collision ^= exidy_collision_invert;
+ int_condition = (readinputportbytag("INTSOURCE") & ~0x1c) | (collision & exidy_collision_mask);
+}
+
+
+INTERRUPT_GEN( exidy_vblank_interrupt )
+{
+ /* latch the current condition */
+ latch_condition(0);
+ int_condition &= ~0x80;
+
+ /* set the IRQ line */
+ cpunum_set_input_line(0, 0, ASSERT_LINE);
+}
+
+
+INTERRUPT_GEN( teetert_vblank_interrupt )
+{
+ /* standard stuff */
+ if (cpu_getiloops() == 0)
+ exidy_vblank_interrupt();
+
+ /* plus a pulse on the NMI line */
+ cpunum_set_input_line(0, INPUT_LINE_NMI, PULSE_LINE);
+}
+
+
+READ8_HANDLER( exidy_interrupt_r )
+{
+ /* clear any interrupts */
+ cpunum_set_input_line(0, 0, CLEAR_LINE);
+
+ /* return the latched condition */
+ return int_condition;
+}
+
+
+
+/*************************************
+ *
+ * Character RAM
+ *
+ *************************************/
+
+WRITE8_HANDLER( exidy_characterram_w )
+{
+ if (exidy_characterram[offset] != data)
+ {
+ exidy_characterram[offset] = data;
+ chardirty[offset / 8 % 256] = 1;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM
+ *
+ *************************************/
+
+WRITE8_HANDLER( exidy_color_w )
+{
+ int i;
+
+ color_latch[offset] = data;
+
+ for (i = 0; i < 8; i++)
+ palette_set_color_rgb(Machine, i, pal1bit(color_latch[2] >> i), pal1bit(color_latch[1] >> i), pal1bit(color_latch[0] >> i));
+}
+
+
+
+/*************************************
+ *
+ * Sprite controls
+ *
+ *************************************/
+
+WRITE8_HANDLER( exidy_sprite1_xpos_w )
+{
+ sprite1_xpos = data;
+}
+
+WRITE8_HANDLER( exidy_sprite1_ypos_w )
+{
+ sprite1_ypos = data;
+}
+
+WRITE8_HANDLER( exidy_sprite2_xpos_w )
+{
+ sprite2_xpos = data;
+}
+
+WRITE8_HANDLER( exidy_sprite2_ypos_w )
+{
+ sprite2_ypos = data;
+}
+
+WRITE8_HANDLER( exidy_spriteno_w )
+{
+ spriteno = data;
+}
+
+WRITE8_HANDLER( exidy_sprite_enable_w )
+{
+ sprite_enable = data;
+}
+
+
+
+/*************************************
+ *
+ * Background update
+ *
+ *************************************/
+
+static void update_background(running_machine *machine)
+{
+ int x, y, offs;
+
+ /* update the background and any dirty characters in it */
+ for (y = offs = 0; y < 32; y++)
+ for (x = 0; x < 32; x++, offs++)
+ {
+ int code = videoram[offs];
+
+ /* see if the character is dirty */
+ if (chardirty[code] == 1)
+ {
+ decodechar(machine->gfx[0], code, exidy_characterram, machine->drv->gfxdecodeinfo[0].gfxlayout);
+ chardirty[code] = 2;
+ }
+
+ /* see if the bitmap is dirty */
+ if (dirtybuffer[offs] || chardirty[code])
+ {
+ int color = code >> 6;
+ drawgfx(tmpbitmap, machine->gfx[0], code, color, 0, 0, x * 8, y * 8, NULL, TRANSPARENCY_NONE, 0);
+ dirtybuffer[offs] = 0;
+ }
+ }
+
+ /* reset the char dirty array */
+ for (y = 0; y < 256; y++)
+ if (chardirty[y] == 2)
+ chardirty[y] = 0;
+}
+
+
+
+static TIMER_CALLBACK( collision_irq_callback )
+{
+ /* latch the collision bits */
+ latch_condition(param);
+
+ /* set the IRQ line */
+ cpunum_set_input_line(0, 0, ASSERT_LINE);
+}
+
+
+
+/*************************************
+ *
+ * End-of-frame callback
+ *
+ *************************************/
+
+/***************************************************************************
+
+ Exidy hardware checks for two types of collisions based on the video
+ signals. If the Motion Object 1 and Motion Object 2 signals are on at
+ the same time, an M1M2 collision bit gets set. If the Motion Object 1
+ and Background Character signals are on at the same time, an M1CHAR
+ collision bit gets set. So effectively, there's a pixel-by-pixel
+ collision check comparing Motion Object 1 (the player) to the
+ background and to the other Motion Object (typically a bad guy).
+
+***************************************************************************/
+
+INLINE int sprite_1_enabled(void)
+{
+ /* if the exidy_collision_mask is 0x00, then we are on old hardware that always has */
+ /* sprite 1 enabled regardless */
+ return (!(sprite_enable & 0x80) || (sprite_enable & 0x10) || (exidy_collision_mask == 0x00));
+}
+
+INLINE int sprite_2_enabled(void)
+{
+ return (!(sprite_enable & 0x40));
+}
+
+VIDEO_EOF( exidy )
+{
+ UINT8 enable_set = ((sprite_enable & 0x20) != 0);
+ static const rectangle clip = { 0, 15, 0, 15 };
+ int pen0 = machine->pens[0];
+ int org_1_x = 0, org_1_y = 0;
+ int org_2_x = 0, org_2_y = 0;
+ int sx, sy;
+ int count = 0;
+
+ /* if there is nothing to detect, bail */
+ if (exidy_collision_mask == 0)
+ return;
+
+ /* if the sprites aren't enabled, we can't collide */
+ if (!sprite_1_enabled() && !sprite_2_enabled())
+ {
+ update_complete = 0;
+ return;
+ }
+
+ /* update the background if necessary */
+ if (!update_complete)
+ update_background(machine);
+ update_complete = 0;
+
+ /* draw sprite 1 */
+ if (sprite_1_enabled())
+ {
+ org_1_x = 236 - sprite1_xpos - 4;
+ org_1_y = 244 - sprite1_ypos - 4;
+ drawgfx(motion_object_1_vid, machine->gfx[1],
+ (spriteno & 0x0f) + 16 * enable_set, 0,
+ 0, 0, 0, 0, &clip, TRANSPARENCY_NONE, 0);
+ }
+ else
+ fillbitmap(motion_object_1_vid, pen0, &clip);
+
+ /* draw sprite 2 */
+ if (sprite_2_enabled())
+ {
+ org_2_x = 236 - sprite2_xpos - 4;
+ org_2_y = 244 - sprite2_ypos - 4;
+ drawgfx(motion_object_2_vid, machine->gfx[1],
+ ((spriteno >> 4) & 0x0f) + 32, 0,
+ 0, 0, 0, 0, &clip, TRANSPARENCY_NONE, 0);
+ }
+ else
+ fillbitmap(motion_object_2_vid, pen0, &clip);
+
+ /* draw sprite 2 clipped to sprite 1's location */
+ fillbitmap(motion_object_2_clip, pen0, &clip);
+ if (sprite_1_enabled() && sprite_2_enabled())
+ {
+ sx = org_2_x - org_1_x;
+ sy = org_2_y - org_1_y;
+ drawgfx(motion_object_2_clip, machine->gfx[1],
+ ((spriteno >> 4) & 0x0f) + 32, 0,
+ 0, 0, sx, sy, &clip, TRANSPARENCY_NONE, 0);
+ }
+
+ /* scan for collisions */
+ for (sy = 0; sy < 16; sy++)
+ for (sx = 0; sx < 16; sx++)
+ {
+ if (*BITMAP_ADDR16(motion_object_1_vid, sy, sx) != pen0)
+ {
+ UINT8 collision_mask = 0;
+
+ /* check for background collision (M1CHAR) */
+ if (*BITMAP_ADDR16(tmpbitmap, org_1_y + sy, org_1_x + sx) != pen0)
+ collision_mask |= 0x04;
+
+ /* check for motion object collision (M1M2) */
+ if (*BITMAP_ADDR16(motion_object_2_clip, sy, sx) != pen0)
+ collision_mask |= 0x10;
+
+ /* if we got one, trigger an interrupt */
+ if ((collision_mask & exidy_collision_mask) && count++ < 128)
+ timer_set(video_screen_get_time_until_pos(0, org_1_x + sx, org_1_y + sy), collision_mask, collision_irq_callback);
+ }
+ if (*BITMAP_ADDR16(motion_object_2_vid, sy, sx) != pen0)
+ {
+ /* check for background collision (M2CHAR) */
+ if (*BITMAP_ADDR16(tmpbitmap, org_2_y + sy, org_2_x + sx) != pen0)
+ if ((exidy_collision_mask & 0x08) && count++ < 128)
+ timer_set(video_screen_get_time_until_pos(0, org_2_x + sx, org_2_y + sy), 0x08, collision_irq_callback);
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Standard screen refresh callback
+ *
+ *************************************/
+
+VIDEO_UPDATE( exidy )
+{
+ int sx, sy;
+
+ /* update the background and draw it */
+ update_background(machine);
+ copybitmap(bitmap, tmpbitmap, 0, 0, 0, 0, cliprect, TRANSPARENCY_NONE, 0);
+
+ /* draw sprite 2 first */
+ if (sprite_2_enabled())
+ {
+ sx = 236 - sprite2_xpos - 4;
+ sy = 244 - sprite2_ypos - 4;
+
+ drawgfx(bitmap, machine->gfx[1],
+ ((spriteno >> 4) & 0x0f) + 32, 1,
+ 0, 0, sx, sy, cliprect, TRANSPARENCY_PEN, 0);
+ }
+
+ /* draw sprite 1 next */
+ if (sprite_1_enabled())
+ {
+ UINT8 enable_set = ((sprite_enable & 0x20) != 0);
+
+ sx = 236 - sprite1_xpos - 4;
+ sy = 244 - sprite1_ypos - 4;
+
+ if (sy < 0) sy = 0;
+
+ drawgfx(bitmap, machine->gfx[1],
+ (spriteno & 0x0f) + 16 * enable_set, 0,
+ 0, 0, sx, sy, cliprect, TRANSPARENCY_PEN, 0);
+ }
+
+ /* indicate that we already updated the background */
+ update_complete = 1;
+ return 0;
+}
diff --git a/src/mame/video/exidy440.c b/src/mame/video/exidy440.c
new file mode 100644
index 00000000000..eceade70355
--- /dev/null
+++ b/src/mame/video/exidy440.c
@@ -0,0 +1,463 @@
+/***************************************************************************
+
+ Exidy 440 video system
+
+***************************************************************************/
+
+#include "driver.h"
+#include "exidy440.h"
+
+#define SPRITE_COUNT 40
+
+
+/* globals */
+UINT8 *exidy440_scanline;
+UINT8 *exidy440_imageram;
+UINT8 exidy440_firq_vblank;
+UINT8 exidy440_firq_beam;
+UINT8 topsecex_yscroll;
+
+/* local allocated storage */
+static UINT8 exidy440_latched_x;
+static UINT8 *local_videoram;
+static UINT8 *local_paletteram;
+
+/* local variables */
+static UINT8 firq_enable;
+static UINT8 firq_select;
+static UINT8 palettebank_io;
+static UINT8 palettebank_vis;
+
+/* function prototypes */
+static void exidy440_update_firq(void);
+
+
+
+/*************************************
+ *
+ * Initialize the video system
+ *
+ *************************************/
+
+VIDEO_START( exidy440 )
+{
+ /* reset the system */
+ firq_enable = 0;
+ firq_select = 0;
+ palettebank_io = 0;
+ palettebank_vis = 0;
+ exidy440_firq_vblank = 0;
+ exidy440_firq_beam = 0;
+
+ /* reset Top Secret scroll position */
+ topsecex_yscroll = 0;
+
+ /* allocate a buffer for VRAM */
+ local_videoram = auto_malloc(256 * 256 * 2);
+ memset(local_videoram, 0, 256 * 256 * 2);
+
+ /* allocate a buffer for palette RAM */
+ local_paletteram = auto_malloc(512 * 2);
+ memset(local_paletteram, 0, 512 * 2);
+}
+
+
+
+/*************************************
+ *
+ * Video RAM read/write
+ *
+ *************************************/
+
+READ8_HANDLER( exidy440_videoram_r )
+{
+ UINT8 *base = &local_videoram[(*exidy440_scanline * 256 + offset) * 2];
+
+ /* combine the two pixel values into one byte */
+ return (base[0] << 4) | base[1];
+}
+
+
+WRITE8_HANDLER( exidy440_videoram_w )
+{
+ UINT8 *base = &local_videoram[(*exidy440_scanline * 256 + offset) * 2];
+
+ /* expand the two pixel values into two bytes */
+ base[0] = (data >> 4) & 15;
+ base[1] = data & 15;
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM read/write
+ *
+ *************************************/
+
+READ8_HANDLER( exidy440_paletteram_r )
+{
+ return local_paletteram[palettebank_io * 512 + offset];
+}
+
+
+WRITE8_HANDLER( exidy440_paletteram_w )
+{
+ /* update palette ram in the I/O bank */
+ local_paletteram[palettebank_io * 512 + offset] = data;
+
+ /* if we're modifying the active palette, change the color immediately */
+ if (palettebank_io == palettebank_vis)
+ {
+ int word;
+
+ /* combine two bytes into a word */
+ offset = palettebank_vis * 512 + (offset & 0x1fe);
+ word = (local_paletteram[offset] << 8) + local_paletteram[offset + 1];
+
+ /* extract the 5-5-5 RGB colors */
+ palette_set_color_rgb(Machine, offset / 2, pal5bit(word >> 10), pal5bit(word >> 5), pal5bit(word >> 0));
+ }
+}
+
+
+
+/*************************************
+ *
+ * Horizontal/vertical positions
+ *
+ *************************************/
+
+READ8_HANDLER( exidy440_horizontal_pos_r )
+{
+ /* clear the FIRQ on a read here */
+ exidy440_firq_beam = 0;
+ exidy440_update_firq();
+
+ /* according to the schems, this value is only latched on an FIRQ
+ * caused by collision or beam */
+ return exidy440_latched_x;
+}
+
+
+READ8_HANDLER( exidy440_vertical_pos_r )
+{
+ int result;
+
+ /* according to the schems, this value is latched on any FIRQ
+ * caused by collision or beam, ORed together with CHRCLK,
+ * which probably goes off once per scanline; for now, we just
+ * always return the current scanline */
+ result = video_screen_get_vpos(0);
+ return (result < 255) ? result : 255;
+}
+
+
+
+/*************************************
+ *
+ * Sprite RAM handler
+ *
+ *************************************/
+
+WRITE8_HANDLER( exidy440_spriteram_w )
+{
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ spriteram[offset] = data;
+}
+
+
+
+/*************************************
+ *
+ * Interrupt and I/O control regs
+ *
+ *************************************/
+
+WRITE8_HANDLER( exidy440_control_w )
+{
+ int oldvis = palettebank_vis;
+
+ /* extract the various bits */
+ exidy440_bank_select(data >> 4);
+ firq_enable = (data >> 3) & 1;
+ firq_select = (data >> 2) & 1;
+ palettebank_io = (data >> 1) & 1;
+ palettebank_vis = data & 1;
+
+ /* update the FIRQ in case we enabled something */
+ exidy440_update_firq();
+
+ /* if we're swapping palettes, change all the colors */
+ if (oldvis != palettebank_vis)
+ {
+ int i;
+
+ /* pick colors from the visible bank */
+ offset = palettebank_vis * 512;
+ for (i = 0; i < 256; i++, offset += 2)
+ {
+ /* extract a word and the 5-5-5 RGB components */
+ int word = (local_paletteram[offset] << 8) + local_paletteram[offset + 1];
+ palette_set_color_rgb(Machine, i, pal5bit(word >> 10), pal5bit(word >> 5), pal5bit(word >> 0));
+ }
+ }
+}
+
+
+WRITE8_HANDLER( exidy440_interrupt_clear_w )
+{
+ /* clear the VBLANK FIRQ on a write here */
+ exidy440_firq_vblank = 0;
+ exidy440_update_firq();
+}
+
+
+
+/*************************************
+ *
+ * Interrupt generators
+ *
+ *************************************/
+
+void exidy440_update_firq(void)
+{
+ if (exidy440_firq_vblank || (firq_enable && exidy440_firq_beam))
+ cpunum_set_input_line(0, 1, ASSERT_LINE);
+ else
+ cpunum_set_input_line(0, 1, CLEAR_LINE);
+}
+
+
+INTERRUPT_GEN( exidy440_vblank_interrupt )
+{
+ /* set the FIRQ line on a VBLANK */
+ exidy440_firq_vblank = 1;
+ exidy440_update_firq();
+}
+
+
+
+/*************************************
+ *
+ * IRQ callback handlers
+ *
+ *************************************/
+
+static TIMER_CALLBACK( beam_firq_callback )
+{
+ /* generate the interrupt, if we're selected */
+ if (firq_select && firq_enable)
+ {
+ exidy440_firq_beam = 1;
+ exidy440_update_firq();
+ }
+
+ /* round the x value to the nearest byte */
+ param = (param + 1) / 2;
+
+ /* latch the x value; this convolution comes from the read routine */
+ exidy440_latched_x = (param + 3) ^ 2;
+}
+
+
+static TIMER_CALLBACK( collide_firq_callback )
+{
+ /* generate the interrupt, if we're selected */
+ if (!firq_select && firq_enable)
+ {
+ exidy440_firq_beam = 1;
+ exidy440_update_firq();
+ }
+
+ /* round the x value to the nearest byte */
+ param = (param + 1) / 2;
+
+ /* latch the x value; this convolution comes from the read routine */
+ exidy440_latched_x = (param + 3) ^ 2;
+}
+
+
+
+/*************************************
+ *
+ * Sprite drawing
+ *
+ *************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int scroll_offset)
+{
+ int i;
+
+ /* get a pointer to the palette to look for collision flags */
+ UINT8 *palette = &local_paletteram[palettebank_vis * 512];
+
+ /* start the count high for topsecret, which doesn't use collision flags */
+ int count = exidy440_topsecret ? 128 : 0;
+
+ /* draw the sprite images, checking for collisions along the way */
+ UINT8 *sprite = spriteram + (SPRITE_COUNT - 1) * 4;
+
+ for (i = 0; i < SPRITE_COUNT; i++, sprite -= 4)
+ {
+ int image = (~sprite[3] & 0x3f);
+ int xoffs = (~((sprite[1] << 8) | sprite[2]) & 0x1ff);
+ int yoffs = (~sprite[0] & 0xff) + 1;
+ int x, y, sy;
+ UINT8 *src;
+
+ /* skip if out of range */
+ if (yoffs < cliprect->min_y || yoffs >= cliprect->max_y + 16)
+ continue;
+
+ /* get a pointer to the source image */
+ src = &exidy440_imageram[image * 128];
+
+ /* account for large positive offsets meaning small negative values */
+ if (xoffs >= 0x1ff - 16)
+ xoffs -= 0x1ff;
+
+ /* loop over y */
+ sy = yoffs + scroll_offset;
+ for (y = 0; y < 16; y++, yoffs--, sy--)
+ {
+ /* wrap at the top and bottom of the screen */
+ if (sy >= EXIDY440_VBSTART)
+ sy -= (EXIDY440_VBSTART - EXIDY440_VBEND);
+ else if (sy < EXIDY440_VBEND)
+ sy += (EXIDY440_VBSTART - EXIDY440_VBEND);
+
+ /* stop if we get before the current scanline */
+ if (yoffs < cliprect->min_y)
+ break;
+
+ /* only draw scanlines that are in this cliprect */
+ if (yoffs <= cliprect->max_y)
+ {
+ UINT8 *old = &local_videoram[sy * 512 + xoffs];
+ int currx = xoffs;
+
+ /* loop over x */
+ for (x = 0; x < 8; x++, old += 2)
+ {
+ int ipixel = *src++;
+ int left = ipixel & 0xf0;
+ int right = (ipixel << 4) & 0xf0;
+ int pen;
+
+ /* left pixel */
+ if (left && EXIDY440_HBEND >= 0 && currx < EXIDY440_HBSTART)
+ {
+ /* combine with the background */
+ pen = left | old[0];
+ *BITMAP_ADDR16(bitmap, yoffs, currx) = machine->pens[pen];
+
+ /* check the collisions bit */
+ if ((palette[2 * pen] & 0x80) && count++ < 128)
+ timer_set(video_screen_get_time_until_pos(0, yoffs, currx), currx, collide_firq_callback);
+ }
+ currx++;
+
+ /* right pixel */
+ if (right && EXIDY440_HBEND >= 0 && currx < EXIDY440_HBSTART)
+ {
+ /* combine with the background */
+ pen = right | old[1];
+ *BITMAP_ADDR16(bitmap, yoffs, currx) = machine->pens[pen];
+
+ /* check the collisions bit */
+ if ((palette[2 * pen] & 0x80) && count++ < 128)
+ timer_set(video_screen_get_time_until_pos(0, yoffs, currx), currx, collide_firq_callback);
+ }
+ currx++;
+ }
+ }
+ else
+ src += 8;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Core refresh routine
+ *
+ *************************************/
+
+static void update_screen(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int scroll_offset)
+{
+ int y, sy;
+
+ /* draw any dirty scanlines from the VRAM directly */
+ sy = scroll_offset + cliprect->min_y;
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++, sy++)
+ {
+ /* wrap at the bottom of the screen */
+ if (sy >= EXIDY440_VBSTART)
+ sy -= (EXIDY440_VBSTART - EXIDY440_VBEND);
+
+ /* draw line */
+ draw_scanline8(bitmap, 0, y, (EXIDY440_HBSTART - EXIDY440_HBEND), &local_videoram[sy * 512], machine->pens, -1);
+ }
+
+ /* draw the sprites */
+ draw_sprites(machine, bitmap, cliprect, scroll_offset);
+}
+
+
+
+/*************************************
+ *
+ * Standard screen refresh callback
+ *
+ *************************************/
+
+VIDEO_UPDATE( exidy440 )
+{
+ /* redraw the screen */
+ if (exidy440_topsecret)
+ update_screen(machine, bitmap, cliprect, topsecex_yscroll);
+ else
+ update_screen(machine, bitmap, cliprect, 0);
+
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Standard screen refresh callback
+ *
+ *************************************/
+
+VIDEO_EOF( exidy440 )
+{
+ /* generate an interrupt once/frame for the beam */
+ if (!exidy440_topsecret)
+ {
+ attotime time;
+ attoseconds_t increment;
+ int beamx, beamy;
+ int i;
+
+ beamx = ((input_port_4_r(0) & 0xff) * (EXIDY440_HBSTART - EXIDY440_HBEND)) >> 8;
+ beamy = ((input_port_5_r(0) & 0xff) * (EXIDY440_VBSTART - EXIDY440_VBEND)) >> 8;
+
+ /* The timing of this FIRQ is very important. The games look for an FIRQ
+ and then wait about 650 cycles, clear the old FIRQ, and wait a
+ very short period of time (~130 cycles) for another one to come in.
+ From this, it appears that they are expecting to get beams over
+ a 12 scanline period, and trying to pick roughly the middle one.
+ This is how it is implemented. */
+ increment = attotime_to_attoseconds(video_screen_get_scan_period(0));
+ time = attotime_sub(video_screen_get_time_until_pos(0, beamy, beamx), attotime_make(0, increment * 6));
+ for (i = 0; i <= 12; i++)
+ {
+ timer_set(time, beamx, beam_firq_callback);
+ time = attotime_add(time, attotime_make(0, increment));
+ }
+ }
+}
diff --git a/src/mame/video/exprraid.c b/src/mame/video/exprraid.c
new file mode 100644
index 00000000000..fb9a089e545
--- /dev/null
+++ b/src/mame/video/exprraid.c
@@ -0,0 +1,143 @@
+#include "driver.h"
+
+static int bg_index[4];
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+WRITE8_HANDLER( exprraid_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( exprraid_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( exprraid_flipscreen_w )
+{
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( exprraid_bgselect_w )
+{
+ if (bg_index[offset] != data)
+ {
+ bg_index[offset] = data;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+WRITE8_HANDLER( exprraid_scrollx_w )
+{
+ tilemap_set_scrollx(bg_tilemap, offset, data);
+}
+
+WRITE8_HANDLER( exprraid_scrolly_w )
+{
+ tilemap_set_scrolly(bg_tilemap, 0, data);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 *tilerom = memory_region(REGION_GFX4);
+
+ int data, attr, bank, code, color, flags;
+ int quadrant = 0, offs;
+
+ int sx = tile_index % 32;
+ int sy = tile_index / 32;
+
+ if (sx >= 16) quadrant++;
+ if (sy >= 16) quadrant += 2;
+
+ offs = (sy % 16) * 16 + (sx % 16) + (bg_index[quadrant] & 0x3f) * 0x100;
+
+ data = tilerom[offs];
+ attr = tilerom[offs + 0x4000];
+ bank = (2 * (attr & 0x03) + ((data & 0x80) >> 7)) + 2;
+ code = data & 0x7f;
+ color = (attr & 0x18) >> 3;
+ flags = (attr & 0x04) ? TILE_FLIPX : 0;
+
+ tileinfo->category = ((attr & 0x80) ? 1 : 0);
+
+ SET_TILE_INFO(bank, code, color, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + ((attr & 0x07) << 8);
+ int color = (attr & 0x10) >> 4;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( exprraid )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_scroll_rows(bg_tilemap, 2);
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int attr = spriteram[offs + 1];
+ int code = spriteram[offs + 3] + ((attr & 0xe0) << 3);
+ int color = (attr & 0x03) + ((attr & 0x08) >> 1);
+ int flipx = (attr & 0x04);
+ int flipy = 0;
+ int sx = ((248 - spriteram[offs + 2]) & 0xff) - 8;
+ int sy = spriteram[offs];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1],
+ code, color,
+ flipx, flipy,
+ sx, sy,
+ 0, TRANSPARENCY_PEN, 0);
+
+ /* double height */
+
+ if (attr & 0x10)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ code + 1, color,
+ flipx, flipy,
+ sx, sy + (flip_screen ? -16 : 16),
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+ }
+}
+
+VIDEO_UPDATE( exprraid )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 1, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/exterm.c b/src/mame/video/exterm.c
new file mode 100644
index 00000000000..0b10161ce61
--- /dev/null
+++ b/src/mame/video/exterm.c
@@ -0,0 +1,114 @@
+/***************************************************************************
+
+ Gottlieb Exterminator hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "cpu/tms34010/tms34010.h"
+#include "exterm.h"
+
+
+UINT16 *exterm_master_videoram, *exterm_slave_videoram;
+
+
+
+/*************************************
+ *
+ * Palette setup
+ *
+ *************************************/
+
+PALETTE_INIT( exterm )
+{
+ int i;
+
+ /* initialize 555 RGB lookup */
+ for (i = 0; i < 32768; i++)
+ palette_set_color_rgb(machine, i + 0x800, pal5bit(i >> 10), pal5bit(i >> 5), pal5bit(i >> 0));
+}
+
+
+
+/*************************************
+ *
+ * Master shift register
+ *
+ *************************************/
+
+void exterm_to_shiftreg_master(UINT32 address, UINT16 *shiftreg)
+{
+ memcpy(shiftreg, &exterm_master_videoram[TOWORD(address)], 256 * sizeof(UINT16));
+}
+
+
+void exterm_from_shiftreg_master(UINT32 address, UINT16 *shiftreg)
+{
+ memcpy(&exterm_master_videoram[TOWORD(address)], shiftreg, 256 * sizeof(UINT16));
+}
+
+
+void exterm_to_shiftreg_slave(UINT32 address, UINT16 *shiftreg)
+{
+ memcpy(shiftreg, &exterm_slave_videoram[TOWORD(address)], 256 * 2 * sizeof(UINT8));
+}
+
+
+void exterm_from_shiftreg_slave(UINT32 address, UINT16 *shiftreg)
+{
+ memcpy(&exterm_slave_videoram[TOWORD(address)], shiftreg, 256 * 2 * sizeof(UINT8));
+}
+
+
+
+/*************************************
+ *
+ * Main video refresh
+ *
+ *************************************/
+
+void exterm_scanline_update(running_machine *machine, int screen, mame_bitmap *bitmap, int scanline, const tms34010_display_params *params)
+{
+ UINT16 *bgsrc = &exterm_master_videoram[(params->rowaddr << 8) & 0xff00];
+ UINT16 *fgsrc = NULL;
+ UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0);
+ tms34010_display_params fgparams;
+ int coladdr = params->coladdr;
+ int fgcoladdr = 0;
+ int x;
+
+ /* get parameters for the slave CPU */
+ tms34010_get_display_params(1, &fgparams);
+
+ /* compute info about the slave vram */
+ if (fgparams.enabled && scanline >= fgparams.veblnk && scanline < fgparams.vsblnk && fgparams.heblnk < fgparams.hsblnk)
+ {
+ fgsrc = &exterm_slave_videoram[((fgparams.rowaddr << 8) + (fgparams.yoffset << 7)) & 0xff80];
+ fgcoladdr = (fgparams.coladdr >> 1);
+ }
+
+ /* copy the non-blanked portions of this scanline */
+ for (x = params->heblnk; x < params->hsblnk; x += 2)
+ {
+ UINT16 bgdata, fgdata = 0;
+
+ if (fgsrc != NULL)
+ fgdata = fgsrc[fgcoladdr++ & 0x7f];
+
+ bgdata = bgsrc[coladdr++ & 0xff];
+ if ((bgdata & 0xe000) == 0xe000)
+ dest[x + 0] = bgdata & 0x7ff;
+ else if ((fgdata & 0x00ff) != 0)
+ dest[x + 0] = fgdata & 0x00ff;
+ else
+ dest[x + 0] = (bgdata & 0x8000) ? (bgdata & 0x7ff) : (bgdata + 0x800);
+
+ bgdata = bgsrc[coladdr++ & 0xff];
+ if ((bgdata & 0xe000) == 0xe000)
+ dest[x + 1] = bgdata & 0x7ff;
+ else if ((fgdata & 0xff00) != 0)
+ dest[x + 1] = fgdata >> 8;
+ else
+ dest[x + 1] = (bgdata & 0x8000) ? (bgdata & 0x7ff) : (bgdata + 0x800);
+ }
+}
diff --git a/src/mame/video/exzisus.c b/src/mame/video/exzisus.c
new file mode 100644
index 00000000000..d40f96ac6e3
--- /dev/null
+++ b/src/mame/video/exzisus.c
@@ -0,0 +1,229 @@
+/***************************************************************************
+
+Functions to emulate the video hardware of the machine.
+
+ Video hardware of this hardware is almost similar with "mexico86". So,
+ most routines are derived from mexico86 driver.
+
+***************************************************************************/
+
+
+#include "driver.h"
+
+
+UINT8 *exzisus_videoram0;
+UINT8 *exzisus_videoram1;
+UINT8 *exzisus_objectram0;
+UINT8 *exzisus_objectram1;
+size_t exzisus_objectram_size0;
+size_t exzisus_objectram_size1;
+
+
+
+/***************************************************************************
+ Memory handlers
+***************************************************************************/
+
+READ8_HANDLER ( exzisus_videoram_0_r )
+{
+ return exzisus_videoram0[offset];
+}
+
+
+READ8_HANDLER ( exzisus_videoram_1_r )
+{
+ return exzisus_videoram1[offset];
+}
+
+
+READ8_HANDLER ( exzisus_objectram_0_r )
+{
+ return exzisus_objectram0[offset];
+}
+
+
+READ8_HANDLER ( exzisus_objectram_1_r )
+{
+ return exzisus_objectram1[offset];
+}
+
+
+WRITE8_HANDLER( exzisus_videoram_0_w )
+{
+ exzisus_videoram0[offset] = data;
+}
+
+
+WRITE8_HANDLER( exzisus_videoram_1_w )
+{
+ exzisus_videoram1[offset] = data;
+}
+
+
+WRITE8_HANDLER( exzisus_objectram_0_w )
+{
+ exzisus_objectram0[offset] = data;
+}
+
+
+WRITE8_HANDLER( exzisus_objectram_1_w )
+{
+ exzisus_objectram1[offset] = data;
+}
+
+
+/***************************************************************************
+ Screen refresh
+***************************************************************************/
+
+VIDEO_UPDATE( exzisus )
+{
+ int offs;
+ int sx, sy, xc, yc;
+ int gfx_num, gfx_attr, gfx_offs;
+
+ /* Is this correct ? */
+ fillbitmap(bitmap, machine->pens[1023], cliprect);
+
+ /* ---------- 1st TC0010VCU ---------- */
+ sx = 0;
+ for (offs = 0 ; offs < exzisus_objectram_size0 ; offs += 4)
+ {
+ int height;
+
+ /* Skip empty sprites. */
+ if ( !(*(UINT32 *)(&exzisus_objectram0[offs])) )
+ {
+ continue;
+ }
+
+ gfx_num = exzisus_objectram0[offs + 1];
+ gfx_attr = exzisus_objectram0[offs + 3];
+
+ if ((gfx_num & 0x80) == 0) /* 16x16 sprites */
+ {
+ gfx_offs = ((gfx_num & 0x7f) << 3);
+ height = 2;
+
+ sx = exzisus_objectram0[offs + 2];
+ sx |= (gfx_attr & 0x40) << 2;
+ }
+ else /* tilemaps (each sprite is a 16x256 column) */
+ {
+ gfx_offs = ((gfx_num & 0x3f) << 7) + 0x0400;
+ height = 32;
+
+ if (gfx_num & 0x40) /* Next column */
+ {
+ sx += 16;
+ }
+ else
+ {
+ sx = exzisus_objectram0[offs + 2];
+ sx |= (gfx_attr & 0x40) << 2;
+ }
+ }
+
+ sy = 256 - (height << 3) - (exzisus_objectram0[offs]);
+
+ for (xc = 0 ; xc < 2 ; xc++)
+ {
+ int goffs = gfx_offs;
+ for (yc = 0 ; yc < height ; yc++)
+ {
+ int code, color, x, y;
+
+ code = (exzisus_videoram0[goffs + 1] << 8) | exzisus_videoram0[goffs];
+ color = (exzisus_videoram0[goffs + 1] >> 6) | (gfx_attr & 0x0f);
+ x = (sx + (xc << 3)) & 0xff;
+ y = (sy + (yc << 3)) & 0xff;
+
+ if (flip_screen)
+ {
+ x = 248 - x;
+ y = 248 - y;
+ }
+
+ drawgfx(bitmap, machine->gfx[0],
+ code & 0x3fff,
+ color,
+ flip_screen, flip_screen,
+ x, y,
+ cliprect, TRANSPARENCY_PEN, 15);
+ goffs += 2;
+ }
+ gfx_offs += height << 1;
+ }
+ }
+
+ /* ---------- 2nd TC0010VCU ---------- */
+ sx = 0;
+ for (offs = 0 ; offs < exzisus_objectram_size1 ; offs += 4)
+ {
+ int height;
+
+ /* Skip empty sprites. */
+ if ( !(*(UINT32 *)(&exzisus_objectram1[offs])) )
+ {
+ continue;
+ }
+
+ gfx_num = exzisus_objectram1[offs + 1];
+ gfx_attr = exzisus_objectram1[offs + 3];
+
+ if ((gfx_num & 0x80) == 0) /* 16x16 sprites */
+ {
+ gfx_offs = ((gfx_num & 0x7f) << 3);
+ height = 2;
+
+ sx = exzisus_objectram1[offs + 2];
+ sx |= (gfx_attr & 0x40) << 2;
+ }
+ else /* tilemaps (each sprite is a 16x256 column) */
+ {
+ gfx_offs = ((gfx_num & 0x3f) << 7) + 0x0400; ///
+ height = 32;
+
+ if (gfx_num & 0x40) /* Next column */
+ {
+ sx += 16;
+ }
+ else
+ {
+ sx = exzisus_objectram1[offs + 2];
+ sx |= (gfx_attr & 0x40) << 2;
+ }
+ }
+ sy = 256 - (height << 3) - (exzisus_objectram1[offs]);
+
+ for (xc = 0 ; xc < 2 ; xc++)
+ {
+ int goffs = gfx_offs;
+ for (yc = 0 ; yc < height ; yc++)
+ {
+ int code, color, x, y;
+
+ code = (exzisus_videoram1[goffs + 1] << 8) | exzisus_videoram1[goffs];
+ color = (exzisus_videoram1[goffs + 1] >> 6) | (gfx_attr & 0x0f);
+ x = (sx + (xc << 3)) & 0xff;
+ y = (sy + (yc << 3)) & 0xff;
+
+ if (flip_screen)
+ {
+ x = 248 - x;
+ y = 248 - y;
+ }
+
+ drawgfx(bitmap, machine->gfx[1],
+ code & 0x3fff,
+ color,
+ flip_screen, flip_screen,
+ x, y,
+ cliprect, TRANSPARENCY_PEN, 15);
+ goffs += 2;
+ }
+ gfx_offs += height << 1;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/f1gp.c b/src/mame/video/f1gp.c
new file mode 100644
index 00000000000..fbee23d2261
--- /dev/null
+++ b/src/mame/video/f1gp.c
@@ -0,0 +1,562 @@
+#include "driver.h"
+#include "video/konamiic.h"
+//#include "f1gp.h"
+
+
+UINT16 *f1gp_spr1vram,*f1gp_spr2vram,*f1gp_spr1cgram,*f1gp_spr2cgram;
+UINT16 *f1gp_fgvideoram,*f1gp_rozvideoram;
+UINT16 *f1gp2_sprcgram,*f1gp2_spritelist;
+UINT16 *f1gpb_rozregs, *f1gpb_fgregs;
+size_t f1gp_spr1cgram_size,f1gp_spr2cgram_size;
+
+static UINT16 *zoomdata;
+static int dirtygfx,flipscreen,gfxctrl;
+static UINT8 *dirtychar;
+
+#define TOTAL_CHARS 0x800
+
+static tilemap *fg_tilemap,*roz_tilemap;
+static int f1gp2_roz_bank;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( f1gp_get_roz_tile_info )
+{
+ int code = f1gp_rozvideoram[tile_index];
+
+ SET_TILE_INFO(3,code & 0x7ff,code >> 12,0);
+}
+
+static TILE_GET_INFO( f1gp2_get_roz_tile_info )
+{
+ int code = f1gp_rozvideoram[tile_index];
+
+ SET_TILE_INFO(2,(code & 0x7ff) + (f1gp2_roz_bank << 11),code >> 12,0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = f1gp_fgvideoram[tile_index];
+
+ SET_TILE_INFO(0,code & 0x7fff,0,(code & 0x8000)?TILE_FLIPY:0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( f1gp )
+{
+ roz_tilemap = tilemap_create(f1gp_get_roz_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+
+ K053936_wraparound_enable(0, 1);
+ K053936_set_offset(0, -58, -2);
+
+ tilemap_set_transparent_pen(fg_tilemap,0xff);
+
+ dirtychar = auto_malloc(TOTAL_CHARS);
+ memset(dirtychar,1,TOTAL_CHARS);
+
+ zoomdata = (UINT16 *)memory_region(REGION_GFX4);
+}
+
+VIDEO_START( f1gpb )
+{
+ roz_tilemap = tilemap_create(f1gp_get_roz_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0xff);
+
+ dirtychar = auto_malloc(TOTAL_CHARS);
+ memset(dirtychar,1,TOTAL_CHARS);
+
+ zoomdata = (UINT16 *)memory_region(REGION_GFX4);
+}
+
+VIDEO_START( f1gp2 )
+{
+ roz_tilemap = tilemap_create(f1gp2_get_roz_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+
+ K053936_wraparound_enable(0, 1);
+ K053936_set_offset(0, -48, -21);
+
+ tilemap_set_transparent_pen(fg_tilemap,0xff);
+ tilemap_set_transparent_pen(roz_tilemap,0x0f);
+
+ tilemap_set_scrolldx(fg_tilemap,-80,0);
+ tilemap_set_scrolldy(fg_tilemap,-26,0);
+
+ dirtychar = auto_malloc(TOTAL_CHARS);
+ memset(dirtychar,1,TOTAL_CHARS);
+
+ zoomdata = (UINT16 *)memory_region(REGION_GFX4);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ16_HANDLER( f1gp_zoomdata_r )
+{
+ return zoomdata[offset];
+}
+
+WRITE16_HANDLER( f1gp_zoomdata_w )
+{
+ int oldword = zoomdata[offset];
+ COMBINE_DATA(&zoomdata[offset]);
+ if (oldword != zoomdata[offset])
+ {
+ dirtygfx = 1;
+ dirtychar[offset / 64] = 1;
+ }
+}
+
+READ16_HANDLER( f1gp_rozvideoram_r )
+{
+ return f1gp_rozvideoram[offset];
+}
+
+WRITE16_HANDLER( f1gp_rozvideoram_w )
+{
+ COMBINE_DATA(&f1gp_rozvideoram[offset]);
+ tilemap_mark_tile_dirty(roz_tilemap,offset);
+}
+
+WRITE16_HANDLER( f1gp_fgvideoram_w )
+{
+ COMBINE_DATA(&f1gp_fgvideoram[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE16_HANDLER( f1gp_fgscroll_w )
+{
+ static int scroll[2];
+
+ COMBINE_DATA(&scroll[offset]);
+
+ tilemap_set_scrollx(fg_tilemap,0,scroll[0]);
+ tilemap_set_scrolly(fg_tilemap,0,scroll[1]);
+}
+
+WRITE16_HANDLER( f1gp_gfxctrl_w )
+{
+ if (ACCESSING_LSB)
+ {
+ flipscreen = data & 0x20;
+ gfxctrl = data & 0xdf;
+ }
+}
+
+WRITE16_HANDLER( f1gp2_gfxctrl_w )
+{
+ if (ACCESSING_LSB)
+ {
+ flipscreen = data & 0x20;
+
+ /* bit 0/1 = fg/sprite/roz priority */
+ /* bit 2 = blank screen */
+
+ gfxctrl = data & 0xdf;
+ }
+
+ if (ACCESSING_MSB)
+ {
+ if (f1gp2_roz_bank != (data >> 8))
+ {
+ f1gp2_roz_bank = (data >> 8);
+ tilemap_mark_all_tiles_dirty(roz_tilemap);
+ }
+ }
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void f1gp_draw_sprites(running_machine *machine,mame_bitmap *bitmap,const rectangle *cliprect,int chip,int primask)
+{
+ int attr_start,first;
+ UINT16 *spram = chip ? f1gp_spr2vram : f1gp_spr1vram;
+
+ first = 4 * spram[0x1fe];
+
+ for (attr_start = 0x0200-8;attr_start >= first;attr_start -= 4)
+ {
+ int map_start;
+ int ox,oy,x,y,xsize,ysize,zoomx,zoomy,flipx,flipy,color,pri;
+ /* table hand made by looking at the ship explosion in attract mode */
+ /* it's almost a logarithmic scale but not exactly */
+ static const int zoomtable[16] = { 0,7,14,20,25,30,34,38,42,46,49,52,54,57,59,61 };
+
+ if (!(spram[attr_start + 2] & 0x0080)) continue;
+
+ ox = spram[attr_start + 1] & 0x01ff;
+ xsize = (spram[attr_start + 2] & 0x0700) >> 8;
+ zoomx = (spram[attr_start + 1] & 0xf000) >> 12;
+ oy = spram[attr_start + 0] & 0x01ff;
+ ysize = (spram[attr_start + 2] & 0x7000) >> 12;
+ zoomy = (spram[attr_start + 0] & 0xf000) >> 12;
+ flipx = spram[attr_start + 2] & 0x0800;
+ flipy = spram[attr_start + 2] & 0x8000;
+ color = (spram[attr_start + 2] & 0x000f);// + 16 * spritepalettebank;
+ pri = 0;//spram[attr_start + 2] & 0x0010;
+ map_start = spram[attr_start + 3];
+
+ zoomx = 16 - zoomtable[zoomx]/8;
+ zoomy = 16 - zoomtable[zoomy]/8;
+
+ for (y = 0;y <= ysize;y++)
+ {
+ int sx,sy;
+
+ if (flipy) sy = ((oy + zoomy * (ysize - y) + 16) & 0x1ff) - 16;
+ else sy = ((oy + zoomy * y + 16) & 0x1ff) - 16;
+
+ for (x = 0;x <= xsize;x++)
+ {
+ int code;
+
+ if (flipx) sx = ((ox + zoomx * (xsize - x) + 16) & 0x1ff) - 16;
+ else sx = ((ox + zoomx * x + 16) & 0x1ff) - 16;
+
+ if (chip == 0)
+ code = f1gp_spr1cgram[map_start % (f1gp_spr1cgram_size/2)];
+ else
+ code = f1gp_spr2cgram[map_start % (f1gp_spr2cgram_size/2)];
+
+ pdrawgfxzoom(bitmap,machine->gfx[1 + chip],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15,
+ 0x1000 * zoomx,0x1000 * zoomy,
+// pri ? 0 : 0x2);
+ primask);
+ map_start++;
+ }
+
+ if (xsize == 2) map_start += 1;
+ if (xsize == 4) map_start += 3;
+ if (xsize == 5) map_start += 2;
+ if (xsize == 6) map_start += 1;
+ }
+ }
+}
+
+static void f1gpb_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int attr_start, start_offset = spriteram_size/2 - 4;
+
+ // find the "end of list" to draw the sprites in reverse order
+ for (attr_start = 4;attr_start < spriteram_size/2;attr_start += 4)
+ {
+ if (spriteram16[attr_start+3-4] == 0xffff) /* end of list marker */
+ {
+ start_offset = attr_start - 4;
+ break;
+ }
+ }
+
+ for (attr_start = start_offset;attr_start >= 4;attr_start -= 4)
+ {
+ int code,gfx;
+ int x,y,flipx,flipy,color,pri;
+
+ x = (spriteram16[attr_start + 2] & 0x03ff) - 48;
+ y = (256 - (spriteram16[attr_start + 3 - 4] & 0x03ff)) - 15;
+ flipx = spriteram16[attr_start + 1] & 0x0800;
+ flipy = spriteram16[attr_start + 1] & 0x8000;
+ color = spriteram16[attr_start + 1] & 0x000f;
+ code = spriteram16[attr_start + 0] & 0x3fff;
+ pri = 0; //?
+
+ if((spriteram16[attr_start + 1] & 0x00f0) && (spriteram16[attr_start + 1] & 0x00f0) != 0xc0)
+ {
+ printf("attr %X\n",spriteram16[attr_start + 1] & 0x00f0);
+ code = mame_rand(Machine);
+ }
+
+/*
+ if(spriteram16[attr_start + 1] & ~0x88cf)
+ printf("1 = %X\n",spriteram16[attr_start + 1] & ~0x88cf);
+*/
+ if(code >= 0x2000)
+ {
+ gfx = 1;
+ code -= 0x2000;
+ }
+ else
+ {
+ gfx = 0;
+ }
+
+ pdrawgfx(bitmap,machine->gfx[1 + gfx],
+ code,
+ color,
+ flipx,flipy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,15,
+ pri ? 0 : 0x2);
+
+ // wrap around x
+ pdrawgfx(bitmap,machine->gfx[1 + gfx],
+ code,
+ color,
+ flipx,flipy,
+ x - 512,y,
+ cliprect,TRANSPARENCY_PEN,15,
+ pri ? 0 : 0x2);
+ }
+}
+
+
+VIDEO_UPDATE( f1gp )
+{
+ static const gfx_layout tilelayout =
+ {
+ 16,16,
+ TOTAL_CHARS,
+ 4,
+ { 0, 1, 2, 3 },
+#ifdef LSB_FIRST
+ { 2*4, 3*4, 0*4, 1*4, 6*4, 7*4, 4*4, 5*4,
+ 10*4, 11*4, 8*4, 9*4, 14*4, 15*4, 12*4, 13*4 },
+#else
+ { 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4,
+ 8*4, 9*4, 10*4, 11*4, 12*4, 13*4, 14*4, 15*4 },
+#endif
+ { 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64,
+ 8*64, 9*64, 10*64, 11*64, 12*64, 13*64, 14*64, 15*64 },
+ 64*16,
+ };
+
+
+ if (dirtygfx)
+ {
+ int i;
+
+ dirtygfx = 0;
+
+ for (i = 0;i < TOTAL_CHARS;i++)
+ {
+ if (dirtychar[i])
+ {
+ dirtychar[i] = 0;
+ decodechar(machine->gfx[3],i,(UINT8 *)zoomdata,&tilelayout);
+ }
+ }
+
+ tilemap_mark_all_tiles_dirty(roz_tilemap);
+ }
+
+
+
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ K053936_0_zoom_draw(bitmap,cliprect,roz_tilemap,0,0);
+
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,1);
+
+ /* quick kludge for "continue" screen priority */
+ if (gfxctrl == 0x00)
+ {
+ f1gp_draw_sprites(machine,bitmap,cliprect,0,0x02);
+ f1gp_draw_sprites(machine,bitmap,cliprect,1,0x02);
+ }
+ else
+ {
+ f1gp_draw_sprites(machine,bitmap,cliprect,0,0x00);
+ f1gp_draw_sprites(machine,bitmap,cliprect,1,0x02);
+ }
+ return 0;
+}
+
+VIDEO_UPDATE( f1gpb )
+{
+ UINT32 startx,starty;
+ int incxx,incxy,incyx,incyy;
+
+ static const gfx_layout tilelayout =
+ {
+ 16,16,
+ TOTAL_CHARS,
+ 4,
+ { 0, 1, 2, 3 },
+#ifdef LSB_FIRST
+ { 2*4, 3*4, 0*4, 1*4, 6*4, 7*4, 4*4, 5*4,
+ 10*4, 11*4, 8*4, 9*4, 14*4, 15*4, 12*4, 13*4 },
+#else
+ { 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4,
+ 8*4, 9*4, 10*4, 11*4, 12*4, 13*4, 14*4, 15*4 },
+#endif
+ { 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64,
+ 8*64, 9*64, 10*64, 11*64, 12*64, 13*64, 14*64, 15*64 },
+ 64*16,
+ };
+
+
+ if (dirtygfx)
+ {
+ int i;
+
+ dirtygfx = 0;
+
+ for (i = 0;i < TOTAL_CHARS;i++)
+ {
+ if (dirtychar[i])
+ {
+ dirtychar[i] = 0;
+ decodechar(machine->gfx[3],i,(UINT8 *)zoomdata,&tilelayout);
+ }
+ }
+
+ tilemap_mark_all_tiles_dirty(roz_tilemap);
+ }
+
+ incxy = (INT16)f1gpb_rozregs[1];
+ incyx = -incxy;
+ incxx = incyy = (INT16)f1gpb_rozregs[3];
+ startx = f1gpb_rozregs[0] + 328;
+ starty = f1gpb_rozregs[2];
+
+ tilemap_set_scrolly(fg_tilemap,0,f1gpb_fgregs[0] + 8);
+
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ tilemap_draw_roz(bitmap, cliprect, roz_tilemap,
+ startx << 13, starty << 13,
+ incxx << 5, incxy << 5, incyx << 5, incyy << 5,
+ 1, 0, 0);
+
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,1);
+
+ f1gpb_draw_sprites(machine,bitmap,cliprect);
+
+ return 0;
+}
+
+
+static void f1gp2_draw_sprites(running_machine *machine,mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+
+ offs = 0;
+ while (offs < 0x0400 && (f1gp2_spritelist[offs] & 0x4000) == 0)
+ {
+ int attr_start;
+ int map_start;
+ int ox,oy,x,y,xsize,ysize,zoomx,zoomy,flipx,flipy,color;
+
+ attr_start = 4 * (f1gp2_spritelist[offs++] & 0x01ff);
+
+ ox = f1gp2_spritelist[attr_start + 1] & 0x01ff;
+ xsize = (f1gp2_spritelist[attr_start + 1] & 0x0e00) >> 9;
+ zoomx = (f1gp2_spritelist[attr_start + 1] & 0xf000) >> 12;
+ oy = f1gp2_spritelist[attr_start + 0] & 0x01ff;
+ ysize = (f1gp2_spritelist[attr_start + 0] & 0x0e00) >> 9;
+ zoomy = (f1gp2_spritelist[attr_start + 0] & 0xf000) >> 12;
+ flipx = f1gp2_spritelist[attr_start + 2] & 0x4000;
+ flipy = f1gp2_spritelist[attr_start + 2] & 0x8000;
+ color = (f1gp2_spritelist[attr_start + 2] & 0x1f00) >> 8;
+ map_start = f1gp2_spritelist[attr_start + 3] & 0x7fff;
+
+// aerofgt has the following adjustment, but doing it here would break the title screen
+// ox += (xsize*zoomx+2)/4;
+// oy += (ysize*zoomy+2)/4;
+
+ zoomx = 32 - zoomx;
+ zoomy = 32 - zoomy;
+
+ if (f1gp2_spritelist[attr_start + 2] & 0x20ff) color = mame_rand(machine);
+
+ for (y = 0;y <= ysize;y++)
+ {
+ int sx,sy;
+
+ if (flipy) sy = ((oy + zoomy * (ysize - y)/2 + 16) & 0x1ff) - 16;
+ else sy = ((oy + zoomy * y / 2 + 16) & 0x1ff) - 16;
+
+ for (x = 0;x <= xsize;x++)
+ {
+ int code;
+
+ if (flipx) sx = ((ox + zoomx * (xsize - x) / 2 + 16) & 0x1ff) - 16;
+ else sx = ((ox + zoomx * x / 2 + 16) & 0x1ff) - 16;
+
+ code = f1gp2_sprcgram[map_start & 0x3fff];
+ map_start++;
+
+ if (flipscreen)
+ drawgfxzoom(bitmap,machine->gfx[1],
+ code,
+ color,
+ !flipx,!flipy,
+ 304-sx,208-sy,
+ cliprect,TRANSPARENCY_PEN,15,
+ zoomx << 11,zoomy << 11);
+ else
+ drawgfxzoom(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15,
+ zoomx << 11,zoomy << 11);
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( f1gp2 )
+{
+ if (gfxctrl & 4) /* blank screen */
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ }
+ else
+ {
+ switch (gfxctrl & 3)
+ {
+ case 0:
+ K053936_0_zoom_draw(bitmap,cliprect,roz_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ f1gp2_draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ break;
+ case 1:
+ K053936_0_zoom_draw(bitmap,cliprect,roz_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ f1gp2_draw_sprites(machine,bitmap,cliprect);
+ break;
+ case 2:
+ tilemap_draw(bitmap,cliprect,fg_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ K053936_0_zoom_draw(bitmap,cliprect,roz_tilemap,0,0);
+ f1gp2_draw_sprites(machine,bitmap,cliprect);
+ break;
+#ifdef MAME_DEBUG
+ case 3:
+ popmessage("unsupported priority 3\n");
+#endif
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/fantland.c b/src/mame/video/fantland.c
new file mode 100644
index 00000000000..4f52738338c
--- /dev/null
+++ b/src/mame/video/fantland.c
@@ -0,0 +1,133 @@
+/***************************************************************************
+
+ -= Electronic Devices / International Games =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+ This game has sprites only:
+
+ tiles are 16 x 16 x 6. There are 0x400 sprites, each one is allotted
+ 8 bytes of memory in spriteram (but only 5 are used) :
+
+ Offset: Bits: Value:
+
+ 0 X (low bits)
+
+ 1 7--- ---- X (high bit)
+ -6-- ---- Y (high bit)
+ --5- ---- Flip X
+ ---4 ---- Flip Y
+ ---- 32--
+ ---- --10 Color
+
+ 2 Code (high bits)
+
+ 3 Code (low bits)
+
+ 4 Y (low bits)
+
+ Then 2 tables follow, 0x400 bytes each:
+
+ - the first table contains 1 byte per sprite: an index in the second table
+ - the second table is either an x,y offset or an index in spriteram_2:
+
+ 0 X offset (low bits)
+
+ 1 Y offset (low bits)
+
+ 2 7--- ---- If 1, the following bits are an index in spriteram_2 for the real X&Y & Code offsets
+ -654 321-
+ ---- ---0 X offset (high bit)
+
+ 3 7654 321-
+ ---- ---0 Y offset (high bit)
+
+
+ Spriteram_2 contains 0x4000 X&Y & Code offsets:
+
+ 0 Y offset (low bits)
+
+ 1 7654 321- Code offset
+ ---- ---0 Y offset (high bit)
+
+ 2 X offset (low bits)
+
+ 3 X offset (high bit)
+
+***************************************************************************/
+
+#include "driver.h"
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ UINT8 *indx_ram = spriteram + 0x2000, // this ram contains indexes into offs_ram
+ *offs_ram = spriteram + 0x2400, // this ram contains x,y offsets or indexes into spriteram_2
+ *ram = spriteram, // current sprite pointer in spriteram
+ *ram2 = indx_ram; // current sprite pointer in indx_ram
+
+ for ( ; ram < indx_ram; ram += 8,ram2++)
+ {
+ int attr,code,color, x,y,xoffs,yoffs,flipx,flipy, idx;
+
+ attr = ram[1];
+
+ x = ram[0];
+ code = ram[3] + (ram[2] << 8);
+ y = ram[4];
+
+ color = (attr & 0x03);
+ flipy = (attr & 0x10);
+ flipx = (attr & 0x20);
+
+ y += (attr & 0x40) << 2;
+ x += (attr & 0x80) << 1;
+
+ // Index in the table of offsets
+
+ idx = ram2[0] * 4;
+
+ // Fetch the offsets
+
+ if (offs_ram[idx + 2] & 0x80)
+ {
+ // x,y & code offset is in spriteram_2, this is its index
+
+ idx = (((offs_ram[idx + 2] << 8) + offs_ram[idx + 3]) & 0x3fff) * 4;
+
+ yoffs = spriteram_2[idx + 0] + (spriteram_2[idx + 1] << 8);
+ xoffs = spriteram_2[idx + 2] + (spriteram_2[idx + 3] << 8);
+
+ code += yoffs >> 9;
+ }
+ else
+ {
+ // this is an x,y offset
+
+ yoffs = ((offs_ram[idx + 3] & 0x01) << 8) + offs_ram[idx + 1];
+ xoffs = ((offs_ram[idx + 2] & 0x01) << 8) + offs_ram[idx + 0];
+ }
+
+ yoffs = (yoffs & 0xff) - (yoffs & 0x100);
+ xoffs = (xoffs & 0x1ff);
+
+ if (xoffs >= 0x180) xoffs -= 0x200;
+
+ y += yoffs;
+ x += xoffs;
+
+ y = (y & 0xff) - (y & 0x100);
+ x = (x & 0x1ff);
+
+ if (x >= 0x180) x -= 0x200;
+
+ drawgfx(bitmap,machine->gfx[0], code,color, flipx,flipy, x,y, cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( fantland )
+{
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ draw_sprites(machine,bitmap,cliprect);
+
+ return 0;
+}
diff --git a/src/mame/video/fastfred.c b/src/mame/video/fastfred.c
new file mode 100644
index 00000000000..d08251cccfb
--- /dev/null
+++ b/src/mame/video/fastfred.c
@@ -0,0 +1,407 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "fastfred.h"
+
+extern UINT8 galaxian_stars_on;
+void galaxian_init_stars(running_machine *machine, int colors_offset);
+void galaxian_draw_stars(running_machine *machine, mame_bitmap *bitmap);
+
+UINT8 *fastfred_videoram;
+UINT8 *fastfred_spriteram;
+size_t fastfred_spriteram_size;
+UINT8 *fastfred_attributesram;
+UINT8 *imago_fg_videoram;
+
+
+static rectangle spritevisiblearea =
+{
+ 2*8, 32*8-1,
+ 2*8, 30*8-1
+};
+
+static rectangle spritevisibleareaflipx =
+{
+ 0*8, 30*8-1,
+ 2*8, 30*8-1
+};
+
+static UINT16 charbank;
+static UINT8 colorbank;
+int fastfred_hardware_type;
+static const UINT8 *fastfred_color_prom;
+static tilemap *bg_tilemap, *fg_tilemap, *web_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ bit 0 -- 1 kohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 220 ohm resistor -- RED/GREEN/BLUE
+ bit 3 -- 100 ohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+
+static void set_color(pen_t pen, int i)
+{
+ UINT8 r,g,b;
+ int bit0, bit1, bit2, bit3;
+
+ bit0 = (fastfred_color_prom[i] >> 0) & 0x01;
+ bit1 = (fastfred_color_prom[i] >> 1) & 0x01;
+ bit2 = (fastfred_color_prom[i] >> 2) & 0x01;
+ bit3 = (fastfred_color_prom[i] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (fastfred_color_prom[i + 0x100] >> 0) & 0x01;
+ bit1 = (fastfred_color_prom[i + 0x100] >> 1) & 0x01;
+ bit2 = (fastfred_color_prom[i + 0x100] >> 2) & 0x01;
+ bit3 = (fastfred_color_prom[i + 0x100] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (fastfred_color_prom[i + 0x200] >> 0) & 0x01;
+ bit1 = (fastfred_color_prom[i + 0x200] >> 1) & 0x01;
+ bit2 = (fastfred_color_prom[i + 0x200] >> 2) & 0x01;
+ bit3 = (fastfred_color_prom[i + 0x200] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color_rgb(Machine,pen,r,g,b);
+}
+
+PALETTE_INIT( fastfred )
+{
+ pen_t i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ fastfred_color_prom = color_prom; /* we'll need this later */
+
+ for (i = 0;i < 256;i++)
+ {
+ set_color(i, i);
+ }
+
+
+ /* characters and sprites use the same palette */
+ for (i = 0; i < TOTAL_COLORS(0); i++)
+ {
+ pen_t color;
+
+ if ((i & 0x07) == 0)
+ color = 0;
+ else
+ color = i;
+
+ COLOR(0,i) = COLOR(1,i) = color;
+ }
+}
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 x = tile_index & 0x1f;
+
+ UINT16 code = charbank | fastfred_videoram[tile_index];
+ UINT8 color = colorbank | (fastfred_attributesram[2 * x + 1] & 0x07);
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( fastfred )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+}
+
+
+/*************************************
+ *
+ * Memory handlers
+ *
+ *************************************/
+
+WRITE8_HANDLER( fastfred_videoram_w )
+{
+ fastfred_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( fastfred_attributes_w )
+{
+ if (fastfred_attributesram[offset] != data)
+ {
+ if (offset & 0x01)
+ {
+ /* color change */
+ int i;
+
+ for (i = offset / 2; i < 0x0400; i += 32)
+ tilemap_mark_tile_dirty(bg_tilemap, i);
+ }
+ else
+ {
+ /* coloumn scroll */
+ tilemap_set_scrolly(bg_tilemap, offset / 2, data);
+ }
+
+ fastfred_attributesram[offset] = data;
+ }
+}
+
+
+WRITE8_HANDLER( fastfred_charbank1_w )
+{
+ UINT16 new_data = (charbank & 0x0200) | ((data & 0x01) << 8);
+
+ if (new_data != charbank)
+ {
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+
+ charbank = new_data;
+ }
+}
+
+WRITE8_HANDLER( fastfred_charbank2_w )
+{
+ UINT16 new_data = (charbank & 0x0100) | ((data & 0x01) << 9);
+
+ if (new_data != charbank)
+ {
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+
+ charbank = new_data;
+ }
+}
+
+
+WRITE8_HANDLER( fastfred_colorbank1_w )
+{
+ UINT8 new_data = (colorbank & 0x10) | ((data & 0x01) << 3);
+
+ if (new_data != colorbank)
+ {
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+
+ colorbank = new_data;
+ }
+}
+
+WRITE8_HANDLER( fastfred_colorbank2_w )
+{
+ UINT8 new_data = (colorbank & 0x08) | ((data & 0x01) << 4);
+
+ if (new_data != colorbank)
+ {
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+
+ colorbank = new_data;
+ }
+}
+
+
+WRITE8_HANDLER( fastfred_background_color_w )
+{
+ set_color(0, data);
+}
+
+
+WRITE8_HANDLER( fastfred_flip_screen_x_w )
+{
+ if (flip_screen_x != (data & 0x01))
+ {
+ flip_screen_x = data & 0x01;
+
+ tilemap_set_flip(bg_tilemap, (flip_screen_x ? TILEMAP_FLIPX : 0) | (flip_screen_y ? TILEMAP_FLIPY : 0));
+ }
+}
+
+WRITE8_HANDLER( fastfred_flip_screen_y_w )
+{
+ if (flip_screen_y != (data & 0x01))
+ {
+ flip_screen_y = data & 0x01;
+
+ tilemap_set_flip(bg_tilemap, (flip_screen_x ? TILEMAP_FLIPX : 0) | (flip_screen_y ? TILEMAP_FLIPY : 0));
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = fastfred_spriteram_size - 4; offs >= 0; offs -= 4)
+ {
+ UINT8 code,sx,sy;
+ int flipx,flipy;
+
+ sx = fastfred_spriteram[offs + 3];
+ sy = 240 - fastfred_spriteram[offs];
+
+ if (fastfred_hardware_type == 3)
+ {
+ // Imago
+
+ //fastfred_spriteram[offs + 2] & 0xf8 get only set at startup
+ //the code is greater than 0x3f only at startup
+
+ /* TODO: find correct sprites banking */
+
+ code = (fastfred_spriteram[offs + 1]) & 0x1f;
+
+ code |= fastfred_spriteram[offs + 2]<<5;
+
+ if(fastfred_spriteram[offs + 1] & 0x20)
+ code ^= 0xff;
+
+ flipx = 0;
+ flipy = 0;
+ }
+ else if (fastfred_hardware_type == 2)
+ {
+ // Boggy 84
+ code = fastfred_spriteram[offs + 1] & 0x7f;
+ flipx = 0;
+ flipy = fastfred_spriteram[offs + 1] & 0x80;
+ }
+ else if (fastfred_hardware_type == 1)
+ {
+ // Fly-Boy/Fast Freddie/Red Robin
+ code = fastfred_spriteram[offs + 1] & 0x7f;
+ flipx = 0;
+ flipy = ~fastfred_spriteram[offs + 1] & 0x80;
+ }
+ else
+ {
+ // Jump Coaster
+ code = (fastfred_spriteram[offs + 1] & 0x3f) | 0x40;
+ flipx = ~fastfred_spriteram[offs + 1] & 0x40;
+ flipy = fastfred_spriteram[offs + 1] & 0x80;
+ }
+
+
+ if (flip_screen_x)
+ {
+ sx = 240 - sx;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ colorbank | (fastfred_spriteram[offs + 2] & 0x07),
+ flipx,flipy,
+ sx,sy,
+ flip_screen_x ? &spritevisibleareaflipx : &spritevisiblearea,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+VIDEO_UPDATE( fastfred )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
+
+
+static TILE_GET_INFO( imago_get_tile_info_bg )
+{
+ UINT8 x = tile_index & 0x1f;
+
+ UINT16 code = charbank * 0x100 + fastfred_videoram[tile_index];
+ UINT8 color = colorbank | (fastfred_attributesram[2 * x + 1] & 0x07);
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static TILE_GET_INFO( imago_get_tile_info_fg )
+{
+ int code = imago_fg_videoram[tile_index];
+ SET_TILE_INFO(2, code, 2, 0);
+}
+
+static TILE_GET_INFO( imago_get_tile_info_web )
+{
+ SET_TILE_INFO(3, tile_index & 0x1ff, 0, 0);
+}
+
+WRITE8_HANDLER( imago_fg_videoram_w )
+{
+ imago_fg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( imago_charbank_w )
+{
+ if( charbank != data )
+ {
+ charbank = data;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+VIDEO_START( imago )
+{
+ web_tilemap = tilemap_create(imago_get_tile_info_web,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,32,32);
+ bg_tilemap = tilemap_create(imago_get_tile_info_bg, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ fg_tilemap = tilemap_create(imago_get_tile_info_fg, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(bg_tilemap, 0);
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+
+ /* the game has a galaxian starfield */
+ galaxian_init_stars(machine, 256);
+ galaxian_stars_on = 1;
+
+ /* web colors */
+ palette_set_color(machine,256+64+0,MAKE_RGB(0x50,0x00,0x00));
+ palette_set_color(machine,256+64+1,MAKE_RGB(0x00,0x00,0x00));
+}
+
+VIDEO_UPDATE( imago )
+{
+ tilemap_draw(bitmap,cliprect,web_tilemap,0,0);
+
+ galaxian_draw_stars(machine, bitmap);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ draw_sprites(machine, bitmap, cliprect);
+
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/fastlane.c b/src/mame/video/fastlane.c
new file mode 100644
index 00000000000..6408f8cacb3
--- /dev/null
+++ b/src/mame/video/fastlane.c
@@ -0,0 +1,144 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+UINT8 *fastlane_k007121_regs,*fastlane_videoram1,*fastlane_videoram2;
+static tilemap *layer0, *layer1;
+static rectangle clip0, clip1;
+
+
+PALETTE_INIT( fastlane )
+{
+ int pal,col;
+
+ for (pal = 0;pal < 16;pal++)
+ {
+ for (col = 0;col < 1024;col++)
+ {
+ *(colortable++) = (col & ~0x0f) | color_prom[16 * pal + (col & 0x0f)];
+ }
+ }
+}
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info0 )
+{
+ int attr = fastlane_videoram1[tile_index];
+ int code = fastlane_videoram1[tile_index + 0x400];
+ int bit0 = (K007121_ctrlram[0][0x05] >> 0) & 0x03;
+ int bit1 = (K007121_ctrlram[0][0x05] >> 2) & 0x03;
+ int bit2 = (K007121_ctrlram[0][0x05] >> 4) & 0x03;
+ int bit3 = (K007121_ctrlram[0][0x05] >> 6) & 0x03;
+ int bank = ((attr & 0x80) >> 7) |
+ ((attr >> (bit0+2)) & 0x02) |
+ ((attr >> (bit1+1)) & 0x04) |
+ ((attr >> (bit2 )) & 0x08) |
+ ((attr >> (bit3-1)) & 0x10) |
+ ((K007121_ctrlram[0][0x03] & 0x01) << 5);
+ int mask = (K007121_ctrlram[0][0x04] & 0xf0) >> 4;
+
+ bank = (bank & ~(mask << 1)) | ((K007121_ctrlram[0][0x04] & mask) << 1);
+
+ SET_TILE_INFO(
+ 0,
+ code+bank*256,
+ 1 + 64 * (attr & 0x0f),
+ 0);
+}
+
+static TILE_GET_INFO( get_tile_info1 )
+{
+ int attr = fastlane_videoram2[tile_index];
+ int code = fastlane_videoram2[tile_index + 0x400];
+ int bit0 = (K007121_ctrlram[0][0x05] >> 0) & 0x03;
+ int bit1 = (K007121_ctrlram[0][0x05] >> 2) & 0x03;
+ int bit2 = (K007121_ctrlram[0][0x05] >> 4) & 0x03;
+ int bit3 = (K007121_ctrlram[0][0x05] >> 6) & 0x03;
+ int bank = ((attr & 0x80) >> 7) |
+ ((attr >> (bit0+2)) & 0x02) |
+ ((attr >> (bit1+1)) & 0x04) |
+ ((attr >> (bit2 )) & 0x08) |
+ ((attr >> (bit3-1)) & 0x10) |
+ ((K007121_ctrlram[0][0x03] & 0x01) << 5);
+ int mask = (K007121_ctrlram[0][0x04] & 0xf0) >> 4;
+
+ bank = (bank & ~(mask << 1)) | ((K007121_ctrlram[0][0x04] & mask) << 1);
+
+ SET_TILE_INFO(
+ 0,
+ code+bank*256,
+ 0 + 64 * (attr & 0x0f),
+ 0);
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( fastlane )
+{
+ layer0 = tilemap_create(get_tile_info0,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ layer1 = tilemap_create(get_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_scroll_rows( layer0, 32 );
+
+ clip0 = machine->screen[0].visarea;
+ clip0.min_x += 40;
+
+ clip1 = machine->screen[0].visarea;
+ clip1.max_x = 39;
+ clip1.min_x = 0;
+}
+
+/***************************************************************************
+
+ Memory Handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( fastlane_vram1_w )
+{
+ fastlane_videoram1[offset] = data;
+ tilemap_mark_tile_dirty(layer0,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( fastlane_vram2_w )
+{
+ fastlane_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(layer1,offset & 0x3ff);
+}
+
+
+
+/***************************************************************************
+
+ Screen Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( fastlane )
+{
+ rectangle finalclip0 = clip0, finalclip1 = clip1;
+ int i, xoffs;
+
+ sect_rect(&finalclip0, cliprect);
+ sect_rect(&finalclip1, cliprect);
+
+ /* set scroll registers */
+ xoffs = K007121_ctrlram[0][0x00];
+ for( i=0; i<32; i++ ){
+ tilemap_set_scrollx(layer0, i, fastlane_k007121_regs[0x20 + i] + xoffs - 40);
+ }
+ tilemap_set_scrolly( layer0, 0, K007121_ctrlram[0][0x02] );
+
+ tilemap_draw(bitmap,&finalclip0,layer0,0,0);
+ K007121_sprites_draw(machine,0,bitmap,cliprect,spriteram,0,40,0,-1);
+ tilemap_draw(bitmap,&finalclip1,layer1,0,0);
+ return 0;
+}
diff --git a/src/mame/video/fcombat.c b/src/mame/video/fcombat.c
new file mode 100644
index 00000000000..a22d6346bdb
--- /dev/null
+++ b/src/mame/video/fcombat.c
@@ -0,0 +1,236 @@
+/***************************************************************************
+
+ Jaleco fcombat
+
+***************************************************************************/
+
+#include "driver.h"
+
+int fcombat_sh;
+int fcombat_sv;
+
+
+#define BACKGROUND_X_START 32
+#define BACKGROUND_X_START_FLIP 72
+
+#define VISIBLE_X_MIN (12*8)
+#define VISIBLE_X_MAX (52*8)
+#define VISIBLE_Y_MIN (2*8)
+#define VISIBLE_Y_MAX (30*8)
+
+
+static tilemap *bgmap;
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int tileno,palno;//32*16 x 32
+
+ //palno=(tile_index-(tile_index/32*16)*32*16)/32;
+
+ tileno = memory_region(REGION_USER1)[tile_index];
+ palno=0x18;//memory_region(REGION_USER2)[tile_index]>>3;
+ SET_TILE_INFO(2,tileno,palno,0);
+}
+
+UINT8 fcombat_cocktail_flip;
+
+static UINT8 char_palette, sprite_palette;
+static UINT8 char_bank;
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+
+PALETTE_INIT( fcombat )
+{
+ int i;
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the char lookup table */
+
+ /* fg chars */
+ for (i = 0; i < 256; i++)
+ colortable[i + 0x000] = 16 + (color_prom[(i & 0xc0) | ((i & 3) << 4) | ((i >> 2) & 15)] & 15);
+ color_prom += 256;
+
+ /* color_prom now points to the beginning of the sprite lookup table */
+
+ /* sprites */
+ for (i = 0; i < 256; i++)
+ colortable[i + 0x100] = 16 + (color_prom[(i & 0xc0) | ((i & 3) << 4) | ((i >> 2) & 15)] & 15);
+ color_prom += 256;
+
+ /* bg chars (this is not the full story... there are four layers mixed */
+ /* using another PROM */
+ for (i = 0; i < 256; i++)
+ //colortable[i + 0x200] = 16 + (color_prom[(i & 0xc0) | ((i & 3) << 4) | ((i >> 2) & 15)] & 15);
+ colortable[i + 0x200] = *color_prom++ & 15;
+}
+
+
+
+/*************************************
+ *
+ * Video system startup
+ *
+ *************************************/
+
+VIDEO_START( fcombat )
+{
+ bgmap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32*8*2,32);
+ video_start_generic(machine);
+}
+
+
+
+/*************************************
+ *
+ * Video register I/O
+ *
+ *************************************/
+
+WRITE8_HANDLER( fcombat_videoreg_w )
+{
+ /* bit 0 = flip screen and joystick input multiplexor */
+ fcombat_cocktail_flip = data & 1;
+
+ /* bits 1-2 char lookup table bank */
+ char_palette = (data & 0x06) >> 1;
+
+ /* bits 3 char bank */
+ char_bank = (data & 0x08) >> 3;
+
+ /* bits 4-5 unused */
+
+ /* bits 6-7 sprite lookup table bank */
+ sprite_palette = 0;//(data & 0xc0) >> 6;
+ //popmessage("%08x",data);
+}
+
+
+
+VIDEO_UPDATE( fcombat )
+{
+ int sx, sy, offs, i;
+
+ /* draw background */
+ tilemap_set_scrolly( bgmap,0, fcombat_sh);
+ tilemap_set_scrollx( bgmap,0, fcombat_sv-24);
+
+tilemap_mark_all_tiles_dirty(bgmap);
+ tilemap_draw(bitmap,cliprect,bgmap,0,0);
+ //draw_background(bitmap, cliprect);
+
+ /* draw sprites */
+ for (i = 0; i < spriteram_size; i += 4)
+ {
+ int flags = spriteram[i + 0];
+ int y = spriteram[i + 1] ^ 255;
+ int code = spriteram[i + 2]+((flags&0x20)<<3);
+ int x = spriteram[i + 3] * 2 + 72;
+
+ int xflip = flags & 0x80;
+ int yflip = flags & 0x40;
+ int doubled =0;// flags & 0x10;
+ int wide = flags & 0x08;
+ int code2 = code;
+
+ int color = ((flags >> 1) & 0x03) | ((code >> 5) & 0x04) | (code & 0x08) | (sprite_palette * 16);
+ const gfx_element *gfx = machine->gfx[1];
+
+ if (fcombat_cocktail_flip)
+ {
+ x = 64*8 - gfx->width - x;
+ y = 32*8 - gfx->height - y;
+ if (wide) y -= gfx->height;
+ xflip = !xflip;
+ yflip = !yflip;
+ }
+
+ if (wide)
+ {
+ if (yflip)
+ code |= 0x10, code2 &= ~0x10;
+ else
+ code &= ~0x10, code2 |= 0x10;
+
+ drawgfx(bitmap, gfx, code2, color, xflip, yflip, x, y + gfx->height,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+
+ if(flags&0x10)
+ {
+
+
+
+ drawgfx(bitmap, gfx, code2+16, color, xflip, yflip, x, y + gfx->height,
+ cliprect, TRANSPARENCY_PEN, 0);
+ drawgfx(bitmap, gfx, code2+16*2, color, xflip, yflip, x, y + 2*gfx->height,
+ cliprect, TRANSPARENCY_PEN, 0);
+ drawgfx(bitmap, gfx, code2+16*3, color, xflip, yflip, x, y + 3*gfx->height,
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ }
+
+
+
+ drawgfx(bitmap, gfx, code, color, xflip, yflip, x, y,
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ if (doubled) i += 4;
+ }
+
+ /* draw the visible text layer */
+ for (sy = VISIBLE_Y_MIN/8; sy < VISIBLE_Y_MAX/8; sy++)
+ for (sx = VISIBLE_X_MIN/8; sx < VISIBLE_X_MAX/8; sx++)
+ {
+ int x = fcombat_cocktail_flip ? (63*8 - 8*sx) : 8*sx;
+ int y = fcombat_cocktail_flip ? (31*8 - 8*sy) : 8*sy;
+
+ offs = sx + sy * 64;
+ drawgfx(bitmap, machine->gfx[0],
+ videoram[offs] + 256 * char_bank,
+ ((videoram[offs] & 0xf0) >> 4) + char_palette * 16,
+ fcombat_cocktail_flip, fcombat_cocktail_flip, x, y,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/fgoal.c b/src/mame/video/fgoal.c
new file mode 100644
index 00000000000..f5839bc811e
--- /dev/null
+++ b/src/mame/video/fgoal.c
@@ -0,0 +1,131 @@
+/***************************************************************************
+
+ Taito Field Goal video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/fgoal.h"
+
+static mame_bitmap *fgbitmap;
+static mame_bitmap *bgbitmap;
+
+static UINT8 xpos;
+static UINT8 ypos;
+
+static int current_color;
+
+
+WRITE8_HANDLER( fgoal_color_w )
+{
+ current_color = data & 3;
+}
+
+
+WRITE8_HANDLER( fgoal_ypos_w )
+{
+ ypos = data;
+}
+
+
+WRITE8_HANDLER( fgoal_xpos_w )
+{
+ xpos = data;
+}
+
+
+VIDEO_START( fgoal )
+{
+ fgbitmap = auto_bitmap_alloc(256, 256, machine->screen[0].format);
+ bgbitmap = auto_bitmap_alloc(256, 256, machine->screen[0].format);
+}
+
+
+VIDEO_UPDATE( fgoal )
+{
+ const UINT8* VRAM = fgoal_video_ram;
+
+ int x;
+ int y;
+ int n;
+
+ /* draw color overlay foreground and background */
+
+ if (fgoal_player == 1 && (readinputport(1) & 0x40))
+ {
+ drawgfxzoom(fgbitmap, machine->gfx[0],
+ 0, (fgoal_player << 2) | current_color,
+ 1, 1,
+ 0, 16,
+ cliprect, TRANSPARENCY_NONE, 0,
+ 0x40000,
+ 0x40000);
+
+ drawgfxzoom(bgbitmap, machine->gfx[1],
+ 0, 0,
+ 1, 1,
+ 0, 16,
+ cliprect, TRANSPARENCY_NONE, 0,
+ 0x40000,
+ 0x40000);
+ }
+ else
+ {
+ drawgfxzoom(fgbitmap, machine->gfx[0],
+ 0, (fgoal_player << 2) | current_color,
+ 0, 0,
+ 0, 0,
+ cliprect, TRANSPARENCY_NONE, 0,
+ 0x40000,
+ 0x40000);
+
+ drawgfxzoom(bgbitmap, machine->gfx[1],
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ cliprect, TRANSPARENCY_NONE, 0,
+ 0x40000,
+ 0x40000);
+ }
+
+ /* the ball has a fixed color */
+
+ for (y = ypos; y < ypos + 8; y++)
+ {
+ for (x = xpos; x < xpos + 8; x++)
+ {
+ if (y < 256 && x < 256)
+ {
+ *BITMAP_ADDR16(fgbitmap, y, x) = 0x38;
+ }
+ }
+ }
+
+ /* draw bitmap layer */
+
+ for (y = 0; y < 256; y++)
+ {
+ UINT16* p = BITMAP_ADDR16(bitmap, y, 0);
+
+ const UINT16* FG = BITMAP_ADDR16(fgbitmap, y, 0);
+ const UINT16* BG = BITMAP_ADDR16(bgbitmap, y, 0);
+
+ for (x = 0; x < 256; x += 8)
+ {
+ UINT8 v = *VRAM++;
+
+ for (n = 0; n < 8; n++)
+ {
+ if (v & (1 << n))
+ {
+ p[x + n] = FG[x + n];
+ }
+ else
+ {
+ p[x + n] = BG[x + n];
+ }
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/finalizr.c b/src/mame/video/finalizr.c
new file mode 100644
index 00000000000..216748826cf
--- /dev/null
+++ b/src/mame/video/finalizr.c
@@ -0,0 +1,266 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+UINT8 *finalizr_scroll;
+UINT8 *finalizr_videoram2,*finalizr_colorram2;
+static int spriterambank,charbank;
+
+
+
+PALETTE_INIT( finalizr )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ /* red component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* green component */
+ bit0 = (color_prom[0] >> 4) & 0x01;
+ bit1 = (color_prom[0] >> 5) & 0x01;
+ bit2 = (color_prom[0] >> 6) & 0x01;
+ bit3 = (color_prom[0] >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* blue component */
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += machine->drv->total_colors;
+ /* color_prom now points to the beginning of the lookup tables */
+
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ {
+ if (*color_prom & 0x0f) COLOR(1,i) = *color_prom & 0x0f;
+ else COLOR(1,i) = 0;
+ color_prom++;
+ }
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ {
+ COLOR(0,i) = (*(color_prom++) & 0x0f) + 0x10;
+ }
+}
+
+VIDEO_START( finalizr )
+{
+ dirtybuffer = 0;
+ tmpbitmap = 0;
+
+ dirtybuffer = auto_malloc(videoram_size);
+ memset(dirtybuffer,1,videoram_size);
+
+ tmpbitmap = auto_bitmap_alloc(256,256,machine->screen[0].format);
+}
+
+
+
+WRITE8_HANDLER( finalizr_videoctrl_w )
+{
+ if (charbank != (data & 3))
+ {
+ charbank = data & 3;
+ memset(dirtybuffer,1,videoram_size);
+ }
+
+ spriterambank = data & 8;
+
+ /* other bits unknown */
+}
+
+
+
+VIDEO_UPDATE( finalizr )
+{
+ int offs;
+
+
+ /* for every character in the Video RAM, check if it has been modified */
+ /* since last time and update it accordingly. */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ if (dirtybuffer[offs])
+ {
+ int sx,sy;
+
+
+ dirtybuffer[offs] = 0;
+
+ sx = offs % 32;
+ sy = offs / 32;
+
+ drawgfx(tmpbitmap,machine->gfx[0],
+ videoram[offs] + ((colorram[offs] & 0xc0) << 2) + (charbank<<10),
+ (colorram[offs] & 0x0f),
+ colorram[offs] & 0x10,colorram[offs] & 0x20,
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+
+ /* copy the temporary bitmap to the screen */
+ {
+ int scroll;
+
+
+ scroll = -*finalizr_scroll + 16;
+
+ copyscrollbitmap(bitmap,tmpbitmap,1,&scroll,0,0,cliprect,TRANSPARENCY_NONE,0);
+ }
+
+
+ /* Draw the sprites. */
+ {
+ UINT8 *sr;
+
+
+ if (spriterambank != 0)
+ sr = spriteram_2;
+ else sr = spriteram;
+
+ for (offs = 0;offs < spriteram_size;offs += 5)
+ {
+ int sx,sy,flipx,flipy,code,color;
+
+
+ sx = 16 + sr[offs+3] - ((sr[offs+4] & 0x01) << 8);
+ sy = sr[offs+2];
+ flipx = sr[offs+4] & 0x20;
+ flipy = sr[offs+4] & 0x40;
+ code = sr[offs] + ((sr[offs+1] & 0x0f) << 8);
+ color = ((sr[offs+1] & 0xf0)>>4);
+
+// (sr[offs+4] & 0x02) is used, meaning unknown
+
+ switch (sr[offs+4] & 0x1c)
+ {
+ case 0x10: /* 32x32? */
+ case 0x14: /* ? */
+ case 0x18: /* ? */
+ case 0x1c: /* ? */
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ flipx?sx+16:sx,flipy?sy+16:sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[1],
+ code + 1,
+ color,
+ flipx,flipy,
+ flipx?sx:sx+16,flipy?sy+16:sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[1],
+ code + 2,
+ color,
+ flipx,flipy,
+ flipx?sx+16:sx,flipy?sy:sy+16,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[1],
+ code + 3,
+ color,
+ flipx,flipy,
+ flipx?sx:sx+16,flipy?sy:sy+16,
+ cliprect,TRANSPARENCY_PEN,0);
+ break;
+
+ case 0x00: /* 16x16 */
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ break;
+
+ case 0x04: /* 16x8 */
+ code = ((code & 0x3ff) << 2) | ((code & 0xc00) >> 10);
+ drawgfx(bitmap,machine->gfx[2],
+ code & ~1,
+ color,
+ flipx,flipy,
+ flipx?sx+8:sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[2],
+ code | 1,
+ color,
+ flipx,flipy,
+ flipx?sx:sx+8,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ break;
+
+ case 0x08: /* 8x16 */
+ code = ((code & 0x3ff) << 2) | ((code & 0xc00) >> 10);
+ drawgfx(bitmap,machine->gfx[2],
+ code & ~2,
+ color,
+ flipx,flipy,
+ sx,flipy?sy+8:sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[2],
+ code | 2,
+ color,
+ flipx,flipy,
+ sx,flipy?sy:sy+8,
+ cliprect,TRANSPARENCY_PEN,0);
+ break;
+
+ case 0x0c: /* 8x8 */
+ code = ((code & 0x3ff) << 2) | ((code & 0xc00) >> 10);
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ break;
+ }
+ }
+ }
+
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int sx,sy;
+
+
+ sx = offs % 32;
+ if (sx < 6)
+ {
+ if (sx >= 3) sx += 30;
+ sy = offs / 32;
+
+ drawgfx(bitmap,machine->gfx[0],
+ finalizr_videoram2[offs] + ((finalizr_colorram2[offs] & 0xc0) << 2),
+ (finalizr_colorram2[offs] & 0x0f),
+ finalizr_colorram2[offs] & 0x10,finalizr_colorram2[offs] & 0x20,
+ 8*sx,8*sy,
+ cliprect,TRANSPARENCY_NONE,0);
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/firetrap.c b/src/mame/video/firetrap.c
new file mode 100644
index 00000000000..47692280392
--- /dev/null
+++ b/src/mame/video/firetrap.c
@@ -0,0 +1,296 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+UINT8 *firetrap_bg1videoram;
+UINT8 *firetrap_bg2videoram;
+UINT8 *firetrap_fgvideoram;
+
+static tilemap *fg_tilemap, *bg1_tilemap, *bg2_tilemap;
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Fire Trap has one 256x8 and one 256x4 palette PROMs.
+ I don't know for sure how the palette PROMs are connected to the RGB
+ output, but it's probably the usual:
+
+ bit 7 -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 2.2kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ -- 1 kohm resistor -- RED
+ bit 0 -- 2.2kohm resistor -- RED
+
+ bit 3 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 1 kohm resistor -- BLUE
+ bit 0 -- 2.2kohm resistor -- BLUE
+
+***************************************************************************/
+
+PALETTE_INIT( firetrap )
+{
+ int i;
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ bit3 = (color_prom[i] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[i] >> 4) & 0x01;
+ bit1 = (color_prom[i] >> 5) & 0x01;
+ bit2 = (color_prom[i] >> 6) & 0x01;
+ bit3 = (color_prom[i] >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[i + machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[i + machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[i + machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[i + machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( get_fg_memory_offset )
+{
+ return (row ^ 0x1f) + (col << 5);
+}
+
+static TILEMAP_MAPPER( get_bg_memory_offset )
+{
+ return ((row & 0x0f) ^ 0x0f) | ((col & 0x0f) << 4) |
+ /* hole at bit 8 */
+ ((row & 0x10) << 5) | ((col & 0x10) << 6);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code, color;
+
+ code = firetrap_fgvideoram[tile_index];
+ color = firetrap_fgvideoram[tile_index + 0x400];
+ SET_TILE_INFO(
+ 0,
+ code | ((color & 0x01) << 8),
+ color >> 4,
+ 0);
+}
+
+INLINE void get_bg_tile_info(running_machine *machine, tile_data *tileinfo, int tile_index, UINT8 *bgvideoram, int gfx_region)
+{
+ int code, color;
+
+ code = bgvideoram[tile_index];
+ color = bgvideoram[tile_index + 0x100];
+ SET_TILE_INFO(
+ gfx_region,
+ code + ((color & 0x03) << 8),
+ (color & 0x30) >> 4,
+ TILE_FLIPXY((color & 0x0c) >> 2));
+}
+
+static TILE_GET_INFO( get_bg1_tile_info )
+{
+ get_bg_tile_info(machine, tileinfo, tile_index, firetrap_bg1videoram, 1);
+}
+
+static TILE_GET_INFO( get_bg2_tile_info )
+{
+ get_bg_tile_info(machine, tileinfo, tile_index, firetrap_bg2videoram, 2);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( firetrap )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info, get_fg_memory_offset,TILEMAP_TYPE_PEN, 8, 8,32,32);
+ bg1_tilemap = tilemap_create(get_bg1_tile_info,get_bg_memory_offset,TILEMAP_TYPE_PEN,16,16,32,32);
+ bg2_tilemap = tilemap_create(get_bg2_tile_info,get_bg_memory_offset,TILEMAP_TYPE_PEN, 16,16,32,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_transparent_pen(bg1_tilemap,0);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( firetrap_fgvideoram_w )
+{
+ firetrap_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( firetrap_bg1videoram_w )
+{
+ firetrap_bg1videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg1_tilemap,offset & 0x6ff);
+}
+
+WRITE8_HANDLER( firetrap_bg2videoram_w )
+{
+ firetrap_bg2videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg2_tilemap,offset & 0x6ff);
+}
+
+
+WRITE8_HANDLER( firetrap_bg1_scrollx_w )
+{
+ static UINT8 scroll[2];
+
+ scroll[offset] = data;
+ tilemap_set_scrollx(bg1_tilemap,0,scroll[0] | (scroll[1] << 8));
+}
+
+WRITE8_HANDLER( firetrap_bg1_scrolly_w )
+{
+ static UINT8 scroll[2];
+
+ scroll[offset] = data;
+ tilemap_set_scrolly(bg1_tilemap,0,-(scroll[0] | (scroll[1] << 8)));
+}
+
+WRITE8_HANDLER( firetrap_bg2_scrollx_w )
+{
+ static UINT8 scroll[2];
+
+ scroll[offset] = data;
+ tilemap_set_scrollx(bg2_tilemap,0,scroll[0] | (scroll[1] << 8));
+}
+
+WRITE8_HANDLER( firetrap_bg2_scrolly_w )
+{
+ static UINT8 scroll[2];
+
+ scroll[offset] = data;
+ tilemap_set_scrolly(bg2_tilemap,0,-(scroll[0] | (scroll[1] << 8)));
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+
+ for (offs = 0;offs < spriteram_size; offs += 4)
+ {
+ int sx,sy,flipx,flipy,code,color;
+
+
+ /* the meaning of bit 3 of [offs] is unknown */
+
+ sy = spriteram[offs];
+ sx = spriteram[offs + 2];
+ code = spriteram[offs + 3] + 4 * (spriteram[offs + 1] & 0xc0);
+ color = ((spriteram[offs + 1] & 0x08) >> 2) | (spriteram[offs + 1] & 0x01);
+ flipx = spriteram[offs + 1] & 0x04;
+ flipy = spriteram[offs + 1] & 0x02;
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if (spriteram[offs + 1] & 0x10) /* double width */
+ {
+ if (flip_screen) sy -= 16;
+
+ drawgfx(bitmap,machine->gfx[3],
+ code & ~1,
+ color,
+ flipx,flipy,
+ sx,flipy ? sy : sy + 16,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[3],
+ code | 1,
+ color,
+ flipx,flipy,
+ sx,flipy ? sy + 16 : sy,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ /* redraw with wraparound */
+ drawgfx(bitmap,machine->gfx[3],
+ code & ~1,
+ color,
+ flipx,flipy,
+ sx - 256,flipy ? sy : sy + 16,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[3],
+ code | 1,
+ color,
+ flipx,flipy,
+ sx - 256,flipy ? sy + 16 : sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ /* redraw with wraparound */
+ drawgfx(bitmap,machine->gfx[3],
+ code,
+ color,
+ flipx,flipy,
+ sx - 256,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( firetrap )
+{
+ tilemap_draw(bitmap,cliprect,bg2_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/firetrk.c b/src/mame/video/firetrk.c
new file mode 100644
index 00000000000..8e109baaab0
--- /dev/null
+++ b/src/mame/video/firetrk.c
@@ -0,0 +1,468 @@
+/***************************************************************************
+
+Atari Fire Truck + Super Bug + Monte Carlo video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "firetrk.h"
+
+UINT8* firetrk_alpha_num_ram;
+UINT8* firetrk_playfield_ram;
+
+int firetrk_skid[2];
+int firetrk_crash[2];
+
+static mame_bitmap *helper1;
+static mame_bitmap *helper2;
+
+static int blink;
+static int flash;
+static int drone_hpos;
+static int drone_vpos;
+
+static const rectangle playfield_window = { 0x02A, 0x115, 0x000, 0x0FF };
+
+struct sprite_data
+{
+ int layout;
+ int number;
+ int x;
+ int y;
+ int flipx;
+ int flipy;
+ int color;
+};
+
+static struct sprite_data car[2];
+
+static tilemap* tilemap1; /* for screen display */
+static tilemap* tilemap2; /* for collision detection */
+
+
+
+INLINE int arrow_code(int c)
+{
+ if (GAME_IS_FIRETRUCK)
+ {
+ return (c & 0x3F) >= 0x4 && (c & 0x3F) <= 0xB;
+ }
+ if (GAME_IS_SUPERBUG)
+ {
+ return (c & 0x3F) >= 0x8 && (c & 0x3F) <= 0xF;
+ }
+
+ return 0;
+}
+
+
+void firetrk_set_flash(int flag)
+{
+ tilemap_mark_all_tiles_dirty(tilemap1);
+
+ if (GAME_IS_FIRETRUCK || GAME_IS_SUPERBUG)
+ {
+ if (flag)
+ {
+ car[0].color = 1;
+ car[1].color = 1;
+ }
+ else
+ {
+ car[0].color = 0;
+ car[1].color = 0;
+ }
+ }
+
+ flash = flag;
+}
+
+
+void firetrk_set_blink(int flag)
+{
+ int offset;
+
+ for (offset = 0; offset < 0x100; offset++)
+ {
+ if (arrow_code(firetrk_playfield_ram[offset]))
+ {
+ tilemap_mark_tile_dirty(tilemap1, offset);
+ }
+ }
+
+ blink = flag;
+}
+
+
+static TILE_GET_INFO( get_tile_info1 )
+{
+ UINT8 code = firetrk_playfield_ram[tile_index];
+
+ int color = code >> 6;
+
+ if (blink && arrow_code(code))
+ {
+ color = 0;
+ }
+ if (flash)
+ {
+ color |= 4;
+ }
+
+ SET_TILE_INFO(1, code & 0x3f, color, 0);
+}
+
+
+static TILE_GET_INFO( get_tile_info2 )
+{
+ UINT8 code = firetrk_playfield_ram[tile_index];
+
+ int color = 0;
+
+ /* palette 1 for crash and palette 2 for skid */
+
+ if (GAME_IS_FIRETRUCK)
+ {
+ if ((code & 0x30) != 0x00 || (code & 0x0c) == 0x00)
+ {
+ color = 1; /* palette 0, 1 */
+ }
+ if ((code & 0x3c) == 0x0c)
+ {
+ color = 2; /* palette 0, 2 */
+ }
+ }
+
+ if (GAME_IS_SUPERBUG)
+ {
+ if ((code & 0x30) != 0x00)
+ {
+ color = 1; /* palette 0, 1 */
+ }
+ if ((code & 0x38) == 0x00)
+ {
+ color = 2; /* palette 0, 2 */
+ }
+ }
+
+ if (GAME_IS_MONTECARLO)
+ {
+ if ((code & 0xc0) == 0x40 || (code & 0xc0) == 0x80)
+ {
+ color = 2; /* palette 2, 1 */
+ }
+ if ((code & 0xc0) == 0xc0)
+ {
+ color = 1; /* palette 2, 0 */
+ }
+ if ((code & 0xc0) == 0x00)
+ {
+ color = 3; /* palette 2, 2 */
+ }
+ if ((code & 0x30) == 0x30)
+ {
+ color = 0; /* palette 0, 0 */
+ }
+ }
+
+ SET_TILE_INFO(2, code & 0x3f, color, 0);
+}
+
+
+WRITE8_HANDLER( firetrk_vert_w )
+{
+ tilemap_set_scrolly(tilemap1, 0, data);
+ tilemap_set_scrolly(tilemap2, 0, data);
+}
+
+
+WRITE8_HANDLER( firetrk_horz_w )
+{
+ tilemap_set_scrollx(tilemap1, 0, data - 37);
+ tilemap_set_scrollx(tilemap2, 0, data - 37);
+}
+
+
+WRITE8_HANDLER( firetrk_drone_hpos_w )
+{
+ drone_hpos = data;
+}
+
+
+WRITE8_HANDLER( firetrk_drone_vpos_w )
+{
+ drone_vpos = data;
+}
+
+
+WRITE8_HANDLER( firetrk_car_rot_w )
+{
+ if (GAME_IS_FIRETRUCK)
+ {
+ car[0].number = data & 0x03;
+
+ if (data & 0x10) /* swap xy */
+ {
+ car[0].layout = 4;
+ }
+ else
+ {
+ car[0].layout = 3;
+ }
+
+ car[0].flipx = data & 0x04;
+ car[0].flipy = data & 0x08;
+ }
+
+ if (GAME_IS_SUPERBUG)
+ {
+ car[0].number = (data & 0x03) ^ 3;
+
+ if (data & 0x10) /* swap xy */
+ {
+ car[0].layout = 4;
+ }
+ else
+ {
+ car[0].layout = 3;
+ }
+
+ car[0].flipx = data & 0x04;
+ car[0].flipy = data & 0x08;
+ }
+
+ if (GAME_IS_MONTECARLO)
+ {
+ car[0].number = data & 0x07;
+
+ if (data & 0x80)
+ {
+ car[1].color |= 2;
+ }
+ else
+ {
+ car[1].color &= ~2;
+ }
+
+ car[0].flipx = data & 0x10;
+ car[0].flipy = data & 0x08;
+ }
+}
+
+
+WRITE8_HANDLER( firetrk_drone_rot_w )
+{
+ car[1].number = data & 0x07;
+
+ if (GAME_IS_FIRETRUCK)
+ {
+ car[1].flipx = data & 0x08;
+ car[1].flipy = data & 0x10;
+ }
+
+ if (GAME_IS_MONTECARLO)
+ {
+ car[1].flipx = data & 0x10;
+ car[1].flipy = data & 0x08;
+
+ if (data & 0x80)
+ {
+ car[1].color |= 1;
+ }
+ else
+ {
+ car[1].color &= ~1;
+ }
+ }
+}
+
+
+WRITE8_HANDLER( firetrk_playfield_w )
+{
+ firetrk_playfield_ram[offset] = data;
+ tilemap_mark_tile_dirty(tilemap1, offset);
+ tilemap_mark_tile_dirty(tilemap2, offset);
+}
+
+
+VIDEO_START( firetrk )
+{
+ helper1 = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ helper2 = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ tilemap1 = tilemap_create(get_tile_info1, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 16, 16);
+ tilemap2 = tilemap_create(get_tile_info2, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 16, 16);
+
+ memset(&car[0], 0, sizeof (struct sprite_data));
+ memset(&car[1], 0, sizeof (struct sprite_data));
+
+ if (GAME_IS_FIRETRUCK)
+ {
+ car[0].layout = 3;
+ car[1].layout = 5;
+ }
+ if (GAME_IS_SUPERBUG)
+ {
+ car[0].layout = 3;
+ car[1].layout = 0;
+ }
+ if (GAME_IS_MONTECARLO)
+ {
+ car[0].layout = 3;
+ car[1].layout = 4;
+ }
+}
+
+
+static void calc_car_positions(void)
+{
+ car[0].x = 144;
+ car[0].y = 104;
+
+ if (GAME_IS_FIRETRUCK)
+ {
+ car[1].x = car[1].flipx ? drone_hpos - 63 : 192 - drone_hpos;
+ car[1].y = car[1].flipy ? drone_vpos - 63 : 192 - drone_vpos;
+
+ car[1].x += 36;
+ }
+
+ if (GAME_IS_MONTECARLO)
+ {
+ car[1].x = car[1].flipx ? drone_hpos - 31 : 224 - drone_hpos;
+ car[1].y = car[1].flipy ? drone_vpos - 31 : 224 - drone_vpos;
+
+ car[1].x += 34;
+ }
+}
+
+
+static void draw_text(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ const UINT8* p = firetrk_alpha_num_ram;
+
+ int i;
+
+ for (i = 0; i < 2; i++)
+ {
+ int x = 0;
+ int y = 0;
+
+ if (GAME_IS_SUPERBUG || GAME_IS_FIRETRUCK)
+ {
+ x = (i == 0) ? 296 : 8;
+ }
+ if (GAME_IS_MONTECARLO)
+ {
+ x = (i == 0) ? 24 : 16;
+ }
+
+ for (y = 0; y < 256; y += machine->gfx[0]->width)
+ {
+ drawgfx(bitmap, machine->gfx[0], *p++, 0, 0, 0,
+ x, y, cliprect, TRANSPARENCY_NONE, 0);
+ }
+ }
+}
+
+
+VIDEO_UPDATE( firetrk )
+{
+ int i;
+
+ tilemap_draw(bitmap, &playfield_window, tilemap1, 0, 0);
+
+ calc_car_positions();
+
+ for (i = 1; i >= 0; i--)
+ {
+ if (GAME_IS_SUPERBUG && i == 1)
+ {
+ continue;
+ }
+
+ drawgfx(bitmap,
+ machine->gfx[car[i].layout],
+ car[i].number,
+ car[i].color,
+ car[i].flipx,
+ car[i].flipy,
+ car[i].x,
+ car[i].y,
+ &playfield_window,
+ TRANSPARENCY_PEN, 0);
+ }
+
+ draw_text(machine, bitmap, cliprect);
+ return 0;
+}
+
+
+VIDEO_EOF( firetrk )
+{
+ int i;
+
+ tilemap_draw(helper1, &playfield_window, tilemap2, 0, 0);
+
+ calc_car_positions();
+
+ for (i = 1; i >= 0; i--)
+ {
+ int width = machine->gfx[car[i].layout]->width;
+ int height = machine->gfx[car[i].layout]->height;
+
+ int x;
+ int y;
+
+ if (GAME_IS_SUPERBUG && i == 1)
+ {
+ continue;
+ }
+
+ drawgfx(helper2,
+ machine->gfx[car[i].layout],
+ car[i].number,
+ 0,
+ car[i].flipx,
+ car[i].flipy,
+ car[i].x,
+ car[i].y,
+ &playfield_window,
+ TRANSPARENCY_NONE, 0);
+
+ for (y = car[i].y; y < car[i].y + height; y++)
+ {
+ for (x = car[i].x; x < car[i].x + width; x++)
+ {
+ pen_t a;
+ pen_t b;
+
+ if (x < playfield_window.min_x)
+ continue;
+ if (x > playfield_window.max_x)
+ continue;
+ if (y < playfield_window.min_y)
+ continue;
+ if (y > playfield_window.max_y)
+ continue;
+
+ a = *BITMAP_ADDR16(helper1, y, x);
+ b = *BITMAP_ADDR16(helper2, y, x);
+
+ if (b != 0 && a == 1)
+ {
+ firetrk_crash[i] = 1;
+ }
+ if (b != 0 && a == 2)
+ {
+ firetrk_skid[i] = 1;
+ }
+ }
+ }
+ }
+
+ if (blink)
+ {
+ firetrk_set_blink(0);
+ }
+}
diff --git a/src/mame/video/fitfight.c b/src/mame/video/fitfight.c
new file mode 100644
index 00000000000..501fc7880b8
--- /dev/null
+++ b/src/mame/video/fitfight.c
@@ -0,0 +1,167 @@
+/* Fit of Fighting Video Hardware */
+
+#include "driver.h"
+
+extern UINT16 *fitfight_spriteram;
+extern UINT16 *fof_100000, *fof_600000, *fof_700000, *fof_800000, *fof_900000, *fof_a00000;
+
+extern UINT16 *fof_bak_tileram;
+static tilemap *fof_bak_tilemap;
+extern UINT16 *fof_mid_tileram;
+static tilemap *fof_mid_tilemap;
+extern UINT16 *fof_txt_tileram;
+static tilemap *fof_txt_tilemap;
+
+extern char bbprot_kludge;
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int layer )
+{
+ const gfx_element *gfx = machine->gfx[3];
+ UINT16 *source = fitfight_spriteram;
+ UINT16 *finish = source + 0x800/2;
+
+ while( source<finish )
+ {
+ int xpos, ypos, number,xflip,yflip, end, colr, prio;
+
+ ypos = source[0];
+ xpos = source[3];
+ number = source[2];
+ xflip = (source[1] & 0x0001) ^ 0x0001;
+ yflip = (source[1] & 0x0002);
+ prio = (source[1] & 0x0400) >> 10;
+ colr = (source[1] & 0x00fc) >> 2;
+ if (bbprot_kludge==1) colr = (source[1] & 0x00f8) >> 3;
+ end = source[0] & 0x8000;
+
+ ypos = 0xff-ypos;
+
+ xpos -=38;//48;
+ ypos -=14;//16;
+
+ if (end) break;
+ if (prio == layer)
+ drawgfx(bitmap,gfx,number,colr,xflip,yflip,xpos,ypos,cliprect,TRANSPARENCY_PEN,0);
+
+ source+=4;
+ }
+}
+
+static TILE_GET_INFO( get_fof_bak_tile_info )
+{
+ int code = fof_bak_tileram[tile_index*2+1];
+ int colr = fof_bak_tileram[tile_index*2] & 0x1f;
+ int xflip = (fof_bak_tileram[tile_index*2] & 0x0020)>>5;
+ xflip ^= 1;
+
+ SET_TILE_INFO(2,code,colr,TILE_FLIPYX(xflip));
+}
+
+WRITE16_HANDLER( fof_bak_tileram_w )
+{
+ COMBINE_DATA(&fof_bak_tileram[offset]);
+ tilemap_mark_tile_dirty(fof_bak_tilemap,offset/2);
+}
+
+
+static TILE_GET_INFO( get_fof_mid_tile_info )
+{
+ int code = fof_mid_tileram[tile_index*2+1];
+ int colr = fof_mid_tileram[tile_index*2] & 0x1f;
+ int xflip = (fof_mid_tileram[tile_index*2] & 0x0020)>>5;
+ xflip ^= 1;
+
+ SET_TILE_INFO(1,code,colr,TILE_FLIPYX(xflip));
+}
+
+WRITE16_HANDLER( fof_mid_tileram_w )
+{
+ COMBINE_DATA(&fof_mid_tileram[offset]);
+
+ tilemap_mark_tile_dirty(fof_mid_tilemap,offset/2);
+}
+
+static TILE_GET_INFO( get_fof_txt_tile_info )
+{
+ int code = fof_txt_tileram[tile_index*2+1];
+ int colr = fof_txt_tileram[tile_index*2] & 0x1f;
+ int xflip = (fof_txt_tileram[tile_index*2] & 0x0020)>>5;
+ xflip ^= 1;
+
+ SET_TILE_INFO(0,code,colr,TILE_FLIPYX(xflip));
+}
+
+WRITE16_HANDLER( fof_txt_tileram_w )
+{
+ COMBINE_DATA(&fof_txt_tileram[offset]);
+ tilemap_mark_tile_dirty(fof_txt_tilemap,offset/2);
+}
+
+/* video start / update */
+
+VIDEO_START(fitfight)
+{
+ fof_bak_tilemap = tilemap_create(get_fof_bak_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,128, 32);
+ /* opaque */
+
+ fof_mid_tilemap = tilemap_create(get_fof_mid_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,128, 32);
+ tilemap_set_transparent_pen(fof_mid_tilemap,0);
+
+ fof_txt_tilemap = tilemap_create(get_fof_txt_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,128, 32);
+ tilemap_set_transparent_pen(fof_txt_tilemap,0);
+}
+
+VIDEO_UPDATE(fitfight)
+{
+ /* scroll isn't right */
+
+ int vblank;
+ int scrollbak,scrollmid;
+
+ vblank = (fof_700000[0] & 0x8000);
+
+ if (vblank > 0)
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ else {
+// if (input_code_pressed(KEYCODE_Q))
+// scrollbak = ((fof_a00000[0]&0xff00) >> 5) - ((fof_700000[0] & 0x0038) >> 3);
+// else if (input_code_pressed(KEYCODE_W))
+// scrollbak = ((fof_a00000[0]&0xff00) >> 5) + ((fof_700000[0] & 0x01c0) >> 6);
+// else if (input_code_pressed(KEYCODE_E))
+// scrollbak = ((fof_a00000[0]&0xff00) >> 5) - ((fof_700000[0] & 0x01c0) >> 6);
+// else if (input_code_pressed(KEYCODE_R))
+// scrollbak = ((fof_a00000[0]&0xff00) >> 5) + ((fof_700000[0] & 0x0038) >> 3);
+// else
+ scrollbak = ((fof_a00000[0]&0xff00) >> 5);
+ tilemap_set_scrollx(fof_bak_tilemap,0, scrollbak );
+ tilemap_set_scrolly(fof_bak_tilemap,0, fof_a00000[0]&0xff);
+ tilemap_draw(bitmap,cliprect,fof_bak_tilemap,0,0);
+
+ draw_sprites(machine,bitmap,cliprect,0);
+
+// if (input_code_pressed(KEYCODE_A))
+// scrollmid = ((fof_900000[0]&0xff00) >> 5) - ((fof_700000[0] & 0x01c0) >> 6);
+// else if (input_code_pressed(KEYCODE_S))
+// scrollmid = ((fof_900000[0]&0xff00) >> 5) + ((fof_700000[0] & 0x0038) >> 3);
+// else if (input_code_pressed(KEYCODE_D))
+// scrollmid = ((fof_900000[0]&0xff00) >> 5) - ((fof_700000[0] & 0x0038) >> 3);
+// else if (input_code_pressed(KEYCODE_F))
+// scrollmid = ((fof_900000[0]&0xff00) >> 5) + ((fof_700000[0] & 0x01c0) >> 6);
+// else
+ scrollmid = ((fof_900000[0]&0xff00) >> 5);
+ tilemap_set_scrollx(fof_mid_tilemap,0, scrollmid );
+ tilemap_set_scrolly(fof_mid_tilemap,0, fof_900000[0]&0xff);
+// if (!input_code_pressed(KEYCODE_F))
+ tilemap_draw(bitmap,cliprect,fof_mid_tilemap,0,0);
+
+ draw_sprites(machine,bitmap,cliprect,1);
+
+ tilemap_draw(bitmap,cliprect,fof_txt_tilemap,0,0);
+ }
+/* popmessage ("Regs %04x %04x %04x %04x %04x %04x",
+ fof_100000[0], fof_600000[0], fof_700000[0],
+ fof_800000[0], fof_900000[0],
+ fof_a00000[0] );
+*/
+ return 0;
+}
diff --git a/src/mame/video/flkatck.c b/src/mame/video/flkatck.c
new file mode 100644
index 00000000000..1f8ff2175ca
--- /dev/null
+++ b/src/mame/video/flkatck.c
@@ -0,0 +1,163 @@
+/***************************************************************************
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+static tilemap *k007121_tilemap[2];
+static rectangle k007121_clip[2];
+
+UINT8 *k007121_ram;
+
+int flkatck_irq_enabled;
+
+static int k007121_flip_screen = 0;
+
+/***************************************************************************
+
+ Callbacks for the K007121
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info_A )
+{
+ int attr = k007121_ram[tile_index];
+ int code = k007121_ram[tile_index+0x400];
+ int bit0 = (K007121_ctrlram[0][0x05] >> 0) & 0x03;
+ int bit1 = (K007121_ctrlram[0][0x05] >> 2) & 0x03;
+ int bit2 = (K007121_ctrlram[0][0x05] >> 4) & 0x03;
+ int bit3 = (K007121_ctrlram[0][0x05] >> 6) & 0x03;
+ int bank = ((attr & 0x80) >> 7) |
+ ((attr >> (bit0+2)) & 0x02) |
+ ((attr >> (bit1+1)) & 0x04) |
+ ((attr >> (bit2 )) & 0x08) |
+ ((attr >> (bit3-1)) & 0x10) |
+ ((K007121_ctrlram[0][0x03] & 0x01) << 5);
+ int mask = (K007121_ctrlram[0][0x04] & 0xf0) >> 4;
+
+ bank = (bank & ~(mask << 1)) | ((K007121_ctrlram[0][0x04] & mask) << 1);
+
+ if ((attr == 0x0d) && (!(K007121_ctrlram[0][0])) && (!(K007121_ctrlram[0][2])))
+ bank = 0; /* this allows the game to print text
+ in all banks selected by the k007121 */
+
+ SET_TILE_INFO(
+ 0,
+ code + 256*bank,
+ (attr & 0x0f) + 16,
+ (attr & 0x20) ? TILE_FLIPY : 0);
+}
+
+static TILE_GET_INFO( get_tile_info_B )
+{
+ int attr = k007121_ram[tile_index+0x800];
+ int code = k007121_ram[tile_index+0xc00];
+
+ SET_TILE_INFO(
+ 0,
+ code,
+ (attr & 0x0f) + 16,
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( flkatck )
+{
+ k007121_tilemap[0] = tilemap_create(get_tile_info_A,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ k007121_tilemap[1] = tilemap_create(get_tile_info_B,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ k007121_clip[0] = machine->screen[0].visarea;
+ k007121_clip[0].min_x += 40;
+
+ k007121_clip[1] = machine->screen[0].visarea;
+ k007121_clip[1].max_x = 39;
+ k007121_clip[1].min_x = 0;
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( flkatck_k007121_w )
+{
+ k007121_ram[offset] = data;
+ if (offset < 0x1000) /* tiles */
+ {
+ if (offset & 0x800) /* score */
+ tilemap_mark_tile_dirty(k007121_tilemap[1],offset & 0x3ff);
+ else
+ tilemap_mark_tile_dirty(k007121_tilemap[0],offset & 0x3ff);
+ }
+}
+
+WRITE8_HANDLER( flkatck_k007121_regs_w )
+{
+ switch (offset)
+ {
+ case 0x04: /* ROM bank select */
+ if (data != K007121_ctrlram[0][0x04])
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ break;
+
+ case 0x07: /* flip screen + IRQ control */
+ k007121_flip_screen = data & 0x08;
+ tilemap_set_flip(ALL_TILEMAPS, k007121_flip_screen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ flkatck_irq_enabled = data & 0x02;
+ break;
+ }
+
+ K007121_ctrl_0_w(offset,data);
+}
+
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+/***************************************************************************
+
+ Flack Attack sprites. Each sprite has 16 bytes!:
+
+
+***************************************************************************/
+
+VIDEO_UPDATE( flkatck )
+{
+ rectangle final_clip[2];
+
+#if 0
+popmessage("%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
+ K007121_ctrlram[0][0x00],K007121_ctrlram[0][0x01],K007121_ctrlram[0][0x02],K007121_ctrlram[0][0x03],K007121_ctrlram[0][0x04],K007121_ctrlram[0][0x05],K007121_ctrlram[0][0x06],K007121_ctrlram[0][0x07],
+ K007121_ctrlram[1][0x00],K007121_ctrlram[1][0x01],K007121_ctrlram[1][0x02],K007121_ctrlram[1][0x03],K007121_ctrlram[1][0x04],K007121_ctrlram[1][0x05],K007121_ctrlram[1][0x06],K007121_ctrlram[1][0x07]);
+#endif
+
+ /* set scroll registers */
+ tilemap_set_scrollx(k007121_tilemap[0],0,K007121_ctrlram[0][0x00] - 40);
+ tilemap_set_scrolly(k007121_tilemap[0],0,K007121_ctrlram[0][0x02]);
+
+ /* compute clipping */
+ final_clip[0] = k007121_clip[0];
+ final_clip[1] = k007121_clip[1];
+ sect_rect(&final_clip[0], cliprect);
+ sect_rect(&final_clip[1], cliprect);
+
+ /* draw the graphics */
+ tilemap_draw(bitmap,&final_clip[0],k007121_tilemap[0],0,0);
+ K007121_sprites_draw(machine,0,bitmap,cliprect,&k007121_ram[0x1000],0,40,0,-1);
+ tilemap_draw(bitmap,&final_clip[1],k007121_tilemap[1],0,0);
+ return 0;
+}
diff --git a/src/mame/video/flower.c b/src/mame/video/flower.c
new file mode 100644
index 00000000000..2d48e14e854
--- /dev/null
+++ b/src/mame/video/flower.c
@@ -0,0 +1,204 @@
+/* Flower Video Hardware */
+
+#include "driver.h"
+
+static tilemap *flower_bg0_tilemap, *flower_bg1_tilemap, *flower_text_tilemap, *flower_text_right_tilemap;
+UINT8 *flower_textram, *flower_bg0ram, *flower_bg1ram, *flower_bg0_scroll, *flower_bg1_scroll;
+
+
+PALETTE_INIT( flower )
+{
+ int i;
+
+ for (i=0; i<256; i++)
+ {
+ palette_set_color_rgb(machine, i, pal4bit(color_prom[i]), pal4bit(color_prom[i+0x100]), pal4bit(color_prom[i+0x200]));
+ colortable[i] = i;
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ const gfx_element *gfx = machine->gfx[1];
+ UINT8 *source = spriteram + 0x200;
+ UINT8 *finish = source - 0x200;
+
+ source -= 8;
+
+ while( source>=finish )
+ {
+ int xblock,yblock;
+ int sy = 256-32-source[0]+1;
+ int sx = (source[4]|(source[5]<<8))-55;
+ int code = source[1] & 0x3f;
+ int color = (source[6]>>4);
+
+ /*
+ Byte 0: Y
+ Byte 1:
+ 0x80 - FlipY
+ 0x40 - FlipX
+ 0x3f - Tile
+ Byte 2:
+ 0x08 - Tile MSB
+ 0x01 - Tile MSB
+ Byte 3:
+ 0x07 - X Zoom
+ 0x08 - X Size
+ 0x70 - Y Zoom
+ 0x80 - Y Size
+ Byte 4: X LSB
+ Byte 5: X MSB
+ Byte 6:
+ 0xf0 - Colour
+ */
+
+ int flipy = source[1] & 0x80;
+ int flipx = source[1] & 0x40;
+
+ int size = source[3];
+
+ int xsize = ((size & 0x08)>>3);
+ int ysize = ((size & 0x80)>>7);
+
+ xsize++;
+ ysize++;
+
+ if (ysize==2) sy -= 16;
+
+ code |= ((source[2] & 0x01) << 6);
+ code |= ((source[2] & 0x08) << 4);
+
+ if(flip_screen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+ sx = sx+16;
+ sy = 250-sy;
+
+ if (ysize==2) sy += 16;
+ }
+
+ for (xblock = 0; xblock<xsize; xblock++)
+ {
+ int xoffs=!flipx ? (xblock*8) : ((xsize-xblock-1)*8);
+ int zoomx=((size&7)+1)<<13;
+ int zoomy=((size&0x70)+0x10)<<9;
+ int xblocksizeinpixels=(zoomx*16)>>16;
+ int yblocksizeinpixels=(zoomy*16)>>16;
+
+ for (yblock = 0; yblock<ysize; yblock++)
+ {
+ int yoffs=!flipy ? yblock : (ysize-yblock-1);
+ int sxoffs=(16-xblocksizeinpixels)/2;
+ int syoffs=(16-yblocksizeinpixels)/2;
+ if (xblock) sxoffs+=xblocksizeinpixels;
+ if (yblock) syoffs+=yblocksizeinpixels;
+
+ drawgfxzoom(bitmap,gfx,
+ code+yoffs+xoffs,
+ color,
+ flipx,flipy,
+ sx+sxoffs,sy+syoffs,
+ cliprect,TRANSPARENCY_PEN,15,
+ zoomx,zoomy);
+ }
+ }
+ source -= 8;
+ }
+
+}
+
+static TILE_GET_INFO( get_bg0_tile_info )
+{
+ int code = flower_bg0ram[tile_index];
+ int color = flower_bg0ram[tile_index+0x100];
+ /* Todo - may be tile flip bits? */
+
+ SET_TILE_INFO(2, code, color>>4, 0);
+}
+
+static TILE_GET_INFO( get_bg1_tile_info )
+{
+ int code = flower_bg1ram[tile_index];
+ int color = flower_bg1ram[tile_index+0x100];
+ /* Todo - may be tile flip bits? */
+
+ SET_TILE_INFO(2, code, color>>4, 0);
+}
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ int code = flower_textram[tile_index];
+ int color = flower_textram[tile_index+0x400];
+ /* Todo - may be tile flip bits? */
+
+ SET_TILE_INFO(0, code, color>>2, 0);
+}
+
+VIDEO_START(flower)
+{
+ flower_bg0_tilemap = tilemap_create(get_bg0_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,16,16);
+ flower_bg1_tilemap = tilemap_create(get_bg1_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,16,16);
+ flower_text_tilemap = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+ flower_text_right_tilemap = tilemap_create(get_text_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 8, 8, 2,32);
+
+ tilemap_set_transparent_pen(flower_bg1_tilemap,15);
+ tilemap_set_transparent_pen(flower_text_tilemap,3);
+ tilemap_set_transparent_pen(flower_text_right_tilemap,3);
+
+ tilemap_set_scrolly(flower_text_tilemap, 0, 16);
+ tilemap_set_scrolly(flower_text_right_tilemap, 0, 16);
+}
+
+VIDEO_UPDATE( flower )
+{
+ rectangle myclip = *cliprect;
+
+ tilemap_set_scrolly(flower_bg0_tilemap,0, flower_bg0_scroll[0]+16);
+ tilemap_set_scrolly(flower_bg1_tilemap,0, flower_bg1_scroll[0]+16);
+
+ tilemap_draw(bitmap,cliprect,flower_bg0_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,flower_bg1_tilemap,0,0);
+
+ draw_sprites(machine,bitmap,cliprect);
+
+ if(flip_screen)
+ {
+ myclip.min_x = cliprect->min_x;
+ myclip.max_x = cliprect->min_x + 15;
+ }
+ else
+ {
+ myclip.min_x = cliprect->max_x - 15;
+ myclip.max_x = cliprect->max_x;
+ }
+
+ tilemap_draw(bitmap,cliprect,flower_text_tilemap,0,0);
+ tilemap_draw(bitmap,&myclip,flower_text_right_tilemap,0,0);
+ return 0;
+}
+
+WRITE8_HANDLER( flower_textram_w )
+{
+ flower_textram[offset] = data;
+ tilemap_mark_tile_dirty(flower_text_tilemap, offset);
+ tilemap_mark_all_tiles_dirty(flower_text_right_tilemap);
+}
+
+WRITE8_HANDLER( flower_bg0ram_w )
+{
+ flower_bg0ram[offset] = data;
+ tilemap_mark_tile_dirty(flower_bg0_tilemap, offset & 0x1ff);
+}
+
+WRITE8_HANDLER( flower_bg1ram_w )
+{
+ flower_bg1ram[offset] = data;
+ tilemap_mark_tile_dirty(flower_bg1_tilemap, offset & 0x1ff);
+}
+
+WRITE8_HANDLER( flower_flipscreen_w )
+{
+ flip_screen_set(data);
+}
diff --git a/src/mame/video/flstory.c b/src/mame/video/flstory.c
new file mode 100644
index 00000000000..71323c2bad5
--- /dev/null
+++ b/src/mame/video/flstory.c
@@ -0,0 +1,252 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+#include "driver.h"
+
+
+static tilemap *bg_tilemap;
+static int char_bank,palette_bank,flipscreen,gfxctrl;
+
+UINT8 *flstory_scrlram;
+
+
+static TILE_GET_INFO( get_tile_info )
+{
+ int code = videoram[tile_index*2];
+ int attr = videoram[tile_index*2+1];
+ int tile_number = code + ((attr & 0xc0) << 2) + 0x400 + 0x800 * char_bank;
+ int flags = TILE_FLIPYX((attr & 0x18) >> 3);
+ tileinfo->category = (attr & 0x20) >> 5;
+ tileinfo->group = (attr & 0x20) >> 5;
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ attr & 0x0f,
+ flags);
+}
+
+static TILE_GET_INFO( victnine_get_tile_info )
+{
+ int code = videoram[tile_index*2];
+ int attr = videoram[tile_index*2+1];
+ int tile_number = tile_number = ((attr & 0x38) << 5) + code;
+ int flags = ((attr & 0x40) ? TILE_FLIPX : 0) | ((attr & 0x80) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ attr & 0x07,
+ flags);
+}
+
+
+VIDEO_START( flstory )
+{
+ bg_tilemap = tilemap_create( get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+// tilemap_set_transparent_pen( bg_tilemap,15 );
+ tilemap_set_transmask(bg_tilemap,0,0x3fff,0xc000); /* split type 0 has pens 0-13 transparent in front half */
+ tilemap_set_transmask(bg_tilemap,1,0x8000,0x7fff); /* split type 1 has pen 15 transparent in front half */
+ tilemap_set_scroll_cols(bg_tilemap,32);
+
+ paletteram = auto_malloc(0x200);
+ paletteram_2 = auto_malloc(0x200);
+ video_start_generic(machine);
+}
+
+VIDEO_START( victnine )
+{
+ bg_tilemap = tilemap_create( victnine_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+ tilemap_set_scroll_cols(bg_tilemap,32);
+
+ paletteram = auto_malloc(0x200);
+ paletteram_2 = auto_malloc(0x200);
+ video_start_generic(machine);
+}
+
+WRITE8_HANDLER( flstory_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+WRITE8_HANDLER( flstory_palette_w )
+{
+ if (offset & 0x100)
+ paletteram_xxxxBBBBGGGGRRRR_split2_w((offset & 0xff) + (palette_bank << 8),data);
+ else
+ paletteram_xxxxBBBBGGGGRRRR_split1_w((offset & 0xff) + (palette_bank << 8),data);
+}
+
+READ8_HANDLER( flstory_palette_r )
+{
+ if (offset & 0x100)
+ return paletteram_2[ (offset & 0xff) + (palette_bank << 8) ];
+ else
+ return paletteram [ (offset & 0xff) + (palette_bank << 8) ];
+}
+
+WRITE8_HANDLER( flstory_gfxctrl_w )
+{
+ if (gfxctrl == data)
+ return;
+ gfxctrl = data;
+
+ flipscreen = (~data & 0x01);
+ if (char_bank != ((data & 0x10) >> 4))
+ {
+ char_bank = (data & 0x10) >> 4;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+ palette_bank = (data & 0x20) >> 5;
+
+ flip_screen_set(flipscreen);
+
+//popmessage("%04x: gfxctrl = %02x\n",activecpu_get_pc(),data);
+
+}
+
+WRITE8_HANDLER( victnine_gfxctrl_w )
+{
+ if (gfxctrl == data)
+ return;
+ gfxctrl = data;
+
+ palette_bank = (data & 0x20) >> 5;
+
+ if (data & 0x04)
+ {
+ flipscreen = (data & 0x01);
+ flip_screen_set(flipscreen);
+ }
+
+//popmessage("%04x: gfxctrl = %02x\n",activecpu_get_pc(),data);
+
+}
+
+#ifdef UNUSED_FUNCTION
+READ8_HANDLER( flstory_scrlram_r )
+{
+ return flstory_scrlram[offset];
+}
+#endif
+
+WRITE8_HANDLER( flstory_scrlram_w )
+{
+ flstory_scrlram[offset] = data;
+ tilemap_set_scrolly(bg_tilemap, offset, data );
+}
+
+
+static void flstory_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri)
+{
+ int i;
+
+ for (i = 0; i < 0x20; i++)
+ {
+ int pr = spriteram[spriteram_size-1 -i];
+ int offs = (pr & 0x1f) * 4;
+
+ if ((pr & 0x80) == pri)
+ {
+ int code,sx,sy,flipx,flipy;
+
+ code = spriteram[offs+2] + ((spriteram[offs+1] & 0x30) << 4);
+ sx = spriteram[offs+3];
+ sy = spriteram[offs+0];
+
+ if (flipscreen)
+ {
+ sx = (240 - sx) & 0xff ;
+ sy = sy - 1 ;
+ }
+ else
+ sy = 240 - sy - 1 ;
+
+ flipx = ((spriteram[offs+1]&0x40)>>6)^flipscreen;
+ flipy = ((spriteram[offs+1]&0x80)>>7)^flipscreen;
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ spriteram[offs+1] & 0x0f,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ /* wrap around */
+ if (sx > 240)
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ spriteram[offs+1] & 0x0f,
+ flipx,flipy,
+ sx-256,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+}
+
+VIDEO_UPDATE( flstory )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0|TILEMAP_DRAW_LAYER1,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,1|TILEMAP_DRAW_LAYER1,0);
+ flstory_draw_sprites(machine,bitmap,cliprect,0x00);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0|TILEMAP_DRAW_LAYER0,0);
+ flstory_draw_sprites(machine,bitmap,cliprect,0x80);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,1|TILEMAP_DRAW_LAYER0,0);
+ return 0;
+}
+
+static void victnine_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int i;
+
+ for (i = 0; i < 0x20; i++)
+ {
+ int pr = spriteram[spriteram_size-1 -i];
+ int offs = (pr & 0x1f) * 4;
+
+ //if ((pr & 0x80) == pri)
+ {
+ int code,sx,sy,flipx,flipy;
+
+ code = spriteram[offs+2] + ((spriteram[offs+1] & 0x20) << 3);
+ sx = spriteram[offs+3];
+ sy = spriteram[offs+0];
+
+ if (flipscreen)
+ {
+ sx = (240 - sx + 1) & 0xff ;
+ sy = sy + 1 ;
+ }
+ else
+ sy = 240 - sy + 1 ;
+
+ flipx = ((spriteram[offs+1]&0x40)>>6)^flipscreen;
+ flipy = ((spriteram[offs+1]&0x80)>>7)^flipscreen;
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ spriteram[offs+1] & 0x0f,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ /* wrap around */
+ if (sx > 240)
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ spriteram[offs+1] & 0x0f,
+ flipx,flipy,
+ sx-256,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+}
+
+VIDEO_UPDATE( victnine )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ victnine_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/flyball.c b/src/mame/video/flyball.c
new file mode 100644
index 00000000000..690d4d34025
--- /dev/null
+++ b/src/mame/video/flyball.c
@@ -0,0 +1,95 @@
+/***************************************************************************
+
+Atari Flyball video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap* flyball_tilemap;
+
+UINT8 flyball_pitcher_vert;
+UINT8 flyball_pitcher_horz;
+UINT8 flyball_pitcher_pic;
+UINT8 flyball_ball_vert;
+UINT8 flyball_ball_horz;
+
+UINT8* flyball_playfield_ram;
+
+
+static TILEMAP_MAPPER( flyball_get_memory_offset )
+{
+ if (col == 0)
+ {
+ col = num_cols;
+ }
+
+ return num_cols * (num_rows - row) - col;
+}
+
+
+static TILE_GET_INFO( flyball_get_tile_info )
+{
+ UINT8 data = flyball_playfield_ram[tile_index];
+
+ int flags =
+ ((data & 0x40) ? TILE_FLIPX : 0) |
+ ((data & 0x80) ? TILE_FLIPY : 0);
+
+ int code = data & 63;
+
+ if ((flags & TILE_FLIPX) && (flags & TILE_FLIPY))
+ {
+ code += 64;
+ }
+
+ SET_TILE_INFO(0, code, 0, flags);
+}
+
+
+VIDEO_START( flyball )
+{
+ flyball_tilemap = tilemap_create(flyball_get_tile_info,
+ flyball_get_memory_offset, TILEMAP_TYPE_PEN, 8, 16, 32, 16);
+}
+
+
+VIDEO_UPDATE( flyball )
+{
+ int pitcherx = flyball_pitcher_horz;
+ int pitchery = flyball_pitcher_vert - 31;
+
+ int ballx = flyball_ball_horz - 1;
+ int bally = flyball_ball_vert - 17;
+
+ int x;
+ int y;
+
+ tilemap_mark_all_tiles_dirty(flyball_tilemap);
+
+ /* draw playfield */
+
+ tilemap_draw(bitmap, cliprect, flyball_tilemap, 0, 0);
+
+ /* draw pitcher */
+
+ drawgfx(bitmap, machine->gfx[1], flyball_pitcher_pic ^ 0xf,
+ 0, 1, 0, pitcherx, pitchery, cliprect, TRANSPARENCY_PEN, 1);
+
+ /* draw ball */
+
+ for (y = bally; y < bally + 2; y++)
+ {
+ for (x = ballx; x < ballx + 2; x++)
+ {
+ if (x >= machine->screen[0].visarea.min_x &&
+ x <= machine->screen[0].visarea.max_x &&
+ y >= machine->screen[0].visarea.min_y &&
+ y <= machine->screen[0].visarea.max_y)
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[1];
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/foodf.c b/src/mame/video/foodf.c
new file mode 100644
index 00000000000..7c56c0727d8
--- /dev/null
+++ b/src/mame/video/foodf.c
@@ -0,0 +1,155 @@
+/***************************************************************************
+
+ Atari Food Fight hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "foodf.h"
+#include "video/resnet.h"
+
+
+static double rweights[3], gweights[3], bweights[2];
+static UINT8 playfield_flip;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data = atarigen_playfield[tile_index];
+ int code = (data & 0xff) | ((data >> 7) & 0x100);
+ int color = (data >> 8) & 0x3f;
+ SET_TILE_INFO(0, code, color, playfield_flip ? (TILE_FLIPX | TILE_FLIPY) : 0);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( foodf )
+{
+ static const int resistances[3] = { 1000, 470, 220 };
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8,8, 32,32);
+ tilemap_set_transparent_pen(atarigen_playfield_tilemap, 0);
+
+ /* adjust the playfield for the 8 pixel offset */
+ tilemap_set_scrollx(atarigen_playfield_tilemap, 0, -8);
+ playfield_flip = 0;
+ state_save_register_global(playfield_flip);
+
+ /* compute the color output resistor weights */
+ compute_resistor_weights(0, 255, -1.0,
+ 3, &resistances[0], rweights, 0, 0,
+ 3, &resistances[0], gweights, 0, 0,
+ 2, &resistances[1], bweights, 0, 0);
+}
+
+
+
+/*************************************
+ *
+ * Cocktail flip
+ *
+ *************************************/
+
+void foodf_set_flip(int flip)
+{
+ if (flip != playfield_flip)
+ {
+ playfield_flip = flip;
+ tilemap_mark_all_tiles_dirty(atarigen_playfield_tilemap);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM write
+ *
+ *************************************/
+
+WRITE16_HANDLER( foodf_paletteram_w )
+{
+ int newword, r, g, b, bit0, bit1, bit2;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ newword = paletteram16[offset];
+
+ /* only the bottom 8 bits are used */
+ /* red component */
+ bit0 = (newword >> 0) & 0x01;
+ bit1 = (newword >> 1) & 0x01;
+ bit2 = (newword >> 2) & 0x01;
+ r = combine_3_weights(rweights, bit0, bit1, bit2);
+
+ /* green component */
+ bit0 = (newword >> 3) & 0x01;
+ bit1 = (newword >> 4) & 0x01;
+ bit2 = (newword >> 5) & 0x01;
+ g = combine_3_weights(gweights, bit0, bit1, bit2);
+
+ /* blue component */
+ bit0 = (newword >> 6) & 0x01;
+ bit1 = (newword >> 7) & 0x01;
+ b = combine_2_weights(bweights, bit0, bit1);
+
+ palette_set_color(Machine, offset, MAKE_RGB(r, g, b));
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( foodf )
+{
+ int offs;
+
+ /* first draw the playfield opaquely */
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, TILEMAP_DRAW_OPAQUE, 0);
+
+ /* then draw the non-transparent parts with a priority of 1 */
+ fillbitmap(priority_bitmap, 0, 0);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 1);
+
+ /* draw the motion objects front-to-back */
+ for (offs = 0x80-2; offs >= 0x20; offs -= 2)
+ {
+ int data1 = spriteram16[offs];
+ int data2 = spriteram16[offs+1];
+
+ int pict = data1 & 0xff;
+ int color = (data1 >> 8) & 0x1f;
+ int xpos = (data2 >> 8) & 0xff;
+ int ypos = (0xff - data2 - 16) & 0xff;
+ int hflip = (data1 >> 15) & 1;
+ int vflip = (data1 >> 14) & 1;
+ int pri = (data1 >> 13) & 1;
+
+ pdrawgfx(bitmap, machine->gfx[1], pict, color, hflip, vflip,
+ xpos, ypos, cliprect, TRANSPARENCY_PEN, 0, pri * 2);
+
+ /* draw again with wraparound (needed to get the end of level animation right) */
+ pdrawgfx(bitmap, machine->gfx[1], pict, color, hflip, vflip,
+ xpos - 256, ypos, cliprect, TRANSPARENCY_PEN, 0, pri * 2);
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/freekick.c b/src/mame/video/freekick.c
new file mode 100644
index 00000000000..d0a146f2dd8
--- /dev/null
+++ b/src/mame/video/freekick.c
@@ -0,0 +1,157 @@
+/* Free Kick Video Hardware */
+
+#include "driver.h"
+
+static tilemap *freek_tilemap;
+UINT8 *freek_videoram;
+
+
+static TILE_GET_INFO( get_freek_tile_info )
+{
+ int tileno,palno;
+
+ tileno = freek_videoram[tile_index]+((freek_videoram[tile_index+0x400]&0xe0)<<3);
+ palno=freek_videoram[tile_index+0x400]&0x1f;
+ SET_TILE_INFO(0,tileno,palno,0);
+}
+
+
+
+VIDEO_START(freekick)
+{
+ freek_tilemap = tilemap_create(get_freek_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+}
+
+
+
+WRITE8_HANDLER( freek_videoram_w )
+{
+ freek_videoram[offset] = data;
+ tilemap_mark_tile_dirty(freek_tilemap,offset&0x3ff);
+}
+
+static void gigas_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int xpos = spriteram[offs + 3];
+ int ypos = spriteram[offs + 2];
+ int code = spriteram[offs + 0]|( (spriteram[offs + 1]&0x20) <<3 );
+
+ int flipx = 0;
+ int flipy = 0;
+ int color = spriteram[offs + 1] & 0x1f;
+
+ if (flip_screen_x)
+ {
+ xpos = 240 - xpos;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ ypos = 256 - ypos;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ xpos,240-ypos,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+static void pbillrd_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int xpos = spriteram[offs + 3];
+ int ypos = spriteram[offs + 2];
+ int code = spriteram[offs + 0];
+
+ int flipx = 0;//spriteram[offs + 0] & 0x80; //?? unused ?
+ int flipy = 0;//spriteram[offs + 0] & 0x40;
+ int color = spriteram[offs + 1] & 0x0f;
+
+ if (flip_screen_x)
+ {
+ xpos = 240 - xpos;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ ypos = 256 - ypos;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ xpos,240-ypos,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+
+static void freekick_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int xpos = spriteram[offs + 3];
+ int ypos = spriteram[offs + 0];
+ int code = spriteram[offs + 1]+ ((spriteram[offs + 2] & 0x20) << 3);
+
+ int flipx = spriteram[offs + 2] & 0x80; //?? unused ?
+ int flipy = spriteram[offs + 2] & 0x40;
+ int color = spriteram[offs + 2] & 0x1f;
+
+ if (flip_screen_x)
+ {
+ xpos = 240 - xpos;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ ypos = 256 - ypos;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ xpos,248-ypos,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE(gigas)
+{
+ tilemap_draw(bitmap,cliprect,freek_tilemap,0,0);
+ gigas_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE(pbillrd)
+{
+ tilemap_draw(bitmap,cliprect,freek_tilemap,0,0);
+ pbillrd_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE(freekick)
+{
+ tilemap_draw(bitmap,cliprect,freek_tilemap,0,0);
+ freekick_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/fromanc2.c b/src/mame/video/fromanc2.c
new file mode 100644
index 00000000000..732887d3a22
--- /dev/null
+++ b/src/mame/video/fromanc2.c
@@ -0,0 +1,487 @@
+/******************************************************************************
+
+ Video Hardware for Video System Mahjong series.
+
+ Driver by Takahiro Nogi <nogi@kt.rim.or.jp> 2001/02/04 -
+
+******************************************************************************/
+
+#include "driver.h"
+
+static int fromanc2_scrollx[2][4], fromanc2_scrolly[2][4];
+static int fromanc2_gfxbank[2][4];
+static UINT16 *fromanc2_paletteram[2];
+static UINT16 *fromanc2_videoram[2][4];
+static tilemap *fromanc2_tilemap[2][4];
+
+/******************************************************************************
+
+ Callbacks for the TileMap code
+
+******************************************************************************/
+
+INLINE void fromanc2_get_tile_info(running_machine *machine, tile_data *tileinfo, int tile_index, int vram, int layer)
+{
+ int tile, color;
+
+ tile = (fromanc2_videoram[vram][layer][tile_index] & 0x3fff) | (fromanc2_gfxbank[vram][layer] << 14);
+ color = ((fromanc2_videoram[vram][layer][tile_index] & 0xc000) >> 14) | (0x10 * vram);
+
+ SET_TILE_INFO(layer, tile, color, 0);
+}
+
+static TILE_GET_INFO( fromanc2_get_v0_l0_tile_info ) { fromanc2_get_tile_info(machine, tileinfo, tile_index, 0, 0); }
+static TILE_GET_INFO( fromanc2_get_v0_l1_tile_info ) { fromanc2_get_tile_info(machine, tileinfo, tile_index, 0, 1); }
+static TILE_GET_INFO( fromanc2_get_v0_l2_tile_info ) { fromanc2_get_tile_info(machine, tileinfo, tile_index, 0, 2); }
+static TILE_GET_INFO( fromanc2_get_v0_l3_tile_info ) { fromanc2_get_tile_info(machine, tileinfo, tile_index, 0, 3); }
+static TILE_GET_INFO( fromanc2_get_v1_l0_tile_info ) { fromanc2_get_tile_info(machine, tileinfo, tile_index, 1, 0); }
+static TILE_GET_INFO( fromanc2_get_v1_l1_tile_info ) { fromanc2_get_tile_info(machine, tileinfo, tile_index, 1, 1); }
+static TILE_GET_INFO( fromanc2_get_v1_l2_tile_info ) { fromanc2_get_tile_info(machine, tileinfo, tile_index, 1, 2); }
+static TILE_GET_INFO( fromanc2_get_v1_l3_tile_info ) { fromanc2_get_tile_info(machine, tileinfo, tile_index, 1, 3); }
+
+
+INLINE void fromancr_get_tile_info(running_machine *machine, tile_data *tileinfo, int tile_index, int vram, int layer)
+{
+ int tile, color;
+
+ tile = fromanc2_videoram[vram][layer][tile_index] | (fromanc2_gfxbank[vram][layer] << 16);
+ color = vram;
+
+ SET_TILE_INFO(layer, tile, color, 0);
+}
+
+static TILE_GET_INFO( fromancr_get_v0_l0_tile_info ) { fromancr_get_tile_info(machine, tileinfo, tile_index, 0, 0); }
+static TILE_GET_INFO( fromancr_get_v0_l1_tile_info ) { fromancr_get_tile_info(machine, tileinfo, tile_index, 0, 1); }
+static TILE_GET_INFO( fromancr_get_v0_l2_tile_info ) { fromancr_get_tile_info(machine, tileinfo, tile_index, 0, 2); }
+static TILE_GET_INFO( fromancr_get_v1_l0_tile_info ) { fromancr_get_tile_info(machine, tileinfo, tile_index, 1, 0); }
+static TILE_GET_INFO( fromancr_get_v1_l1_tile_info ) { fromancr_get_tile_info(machine, tileinfo, tile_index, 1, 1); }
+static TILE_GET_INFO( fromancr_get_v1_l2_tile_info ) { fromancr_get_tile_info(machine, tileinfo, tile_index, 1, 2); }
+
+
+/******************************************************************************
+
+ Memory handlers
+
+******************************************************************************/
+
+READ16_HANDLER( fromanc2_paletteram_0_r )
+{
+ return fromanc2_paletteram[0][offset];
+}
+
+READ16_HANDLER( fromanc2_paletteram_1_r )
+{
+ return fromanc2_paletteram[1][offset];
+}
+
+WRITE16_HANDLER( fromanc2_paletteram_0_w )
+{
+ UINT16 color;
+
+ COMBINE_DATA(&fromanc2_paletteram[0][offset]);
+
+ // GGGG_GRRR_RRBB_BBBx
+ color = ((offset & 0x0700) << 1) + (offset & 0x00ff);
+ palette_set_color_rgb(Machine, 0x000 + color, pal5bit(data >> 6), pal5bit(data >> 11), pal5bit(data >> 1));
+}
+
+WRITE16_HANDLER( fromanc2_paletteram_1_w )
+{
+ UINT16 color;
+
+ COMBINE_DATA(&fromanc2_paletteram[1][offset]);
+
+ // GGGG_GRRR_RRBB_BBBx
+ color = ((offset & 0x0700) << 1) + (offset & 0x00ff);
+ palette_set_color_rgb(Machine, 0x100 + color, pal5bit(data >> 6), pal5bit(data >> 11), pal5bit(data >> 1));
+}
+
+
+READ16_HANDLER( fromancr_paletteram_0_r )
+{
+ return fromanc2_paletteram[0][offset];
+}
+
+READ16_HANDLER( fromancr_paletteram_1_r )
+{
+ return fromanc2_paletteram[1][offset];
+}
+
+WRITE16_HANDLER( fromancr_paletteram_0_w )
+{
+ UINT16 color;
+
+ COMBINE_DATA(&fromanc2_paletteram[0][offset]);
+
+ // xGGG_GGRR_RRRB_BBBB
+ color = ((offset & 0x0700) << 1) + (offset & 0x00ff);
+ palette_set_color_rgb(Machine, 0x000 + color, pal5bit(data >> 5), pal5bit(data >> 10), pal5bit(data >> 0));
+}
+
+WRITE16_HANDLER( fromancr_paletteram_1_w )
+{
+ UINT16 color;
+
+ COMBINE_DATA(&fromanc2_paletteram[1][offset]);
+
+ // xGGG_GGRR_RRRB_BBBB
+ color = ((offset & 0x0700) << 1) + (offset & 0x00ff);
+ palette_set_color_rgb(Machine, 0x100 + color, pal5bit(data >> 5), pal5bit(data >> 10), pal5bit(data >> 0));
+}
+
+
+READ16_HANDLER( fromanc4_paletteram_0_r )
+{
+ return fromanc2_paletteram[0][offset];
+}
+
+READ16_HANDLER( fromanc4_paletteram_1_r )
+{
+ return fromanc2_paletteram[1][offset];
+}
+
+WRITE16_HANDLER( fromanc4_paletteram_0_w )
+{
+ UINT16 color;
+
+ COMBINE_DATA(&fromanc2_paletteram[0][offset]);
+
+ // xRRR_RRGG_GGGB_BBBB
+ color = ((offset & 0x0700) << 1) + (offset & 0x00ff);
+ palette_set_color_rgb(Machine, 0x000 + color, pal5bit(data >> 10), pal5bit(data >> 5), pal5bit(data >> 0));
+}
+
+WRITE16_HANDLER( fromanc4_paletteram_1_w )
+{
+ UINT16 color;
+
+ COMBINE_DATA(&fromanc2_paletteram[1][offset]);
+
+ // xRRR_RRGG_GGGB_BBBB
+ color = ((offset & 0x0700) << 1) + (offset & 0x00ff);
+ palette_set_color_rgb(Machine, 0x100 + color, pal5bit(data >> 10), pal5bit(data >> 5), pal5bit(data >> 0));
+}
+
+
+INLINE void fromanc2_dispvram_w(offs_t offset, UINT16 data, UINT16 mem_mask, int vram, int layer)
+{
+ layer += (offset < 0x1000) ? 0 : 1;
+
+ COMBINE_DATA(&fromanc2_videoram[vram][layer][offset & 0x0fff]);
+ tilemap_mark_tile_dirty(fromanc2_tilemap[vram][layer], offset & 0x0fff);
+}
+
+WRITE16_HANDLER( fromanc2_videoram_0_w ) { fromanc2_dispvram_w(offset, data, mem_mask, 0, 0); }
+WRITE16_HANDLER( fromanc2_videoram_1_w ) { fromanc2_dispvram_w(offset, data, mem_mask, 0, 2); }
+WRITE16_HANDLER( fromanc2_videoram_2_w ) { fromanc2_dispvram_w(offset, data, mem_mask, 1, 0); }
+WRITE16_HANDLER( fromanc2_videoram_3_w ) { fromanc2_dispvram_w(offset, data, mem_mask, 1, 2); }
+
+WRITE16_HANDLER( fromanc2_gfxreg_0_w )
+{
+ switch (offset) {
+ case 0x00: fromanc2_scrollx[0][0] = -(data - 0x000); break;
+ case 0x01: fromanc2_scrolly[0][0] = -(data - 0x000); break;
+ case 0x02: fromanc2_scrollx[0][1] = -(data - 0x004); break;
+ case 0x03: fromanc2_scrolly[0][1] = -(data - 0x000); break;
+ // offset 0x04 - 0x11 unknown
+ default: break;
+ }
+}
+
+WRITE16_HANDLER( fromanc2_gfxreg_1_w )
+{
+ switch (offset) {
+ case 0x00: fromanc2_scrollx[1][0] = -(data - 0x1be); break;
+ case 0x01: fromanc2_scrolly[1][0] = -(data - 0x1ef); break;
+ case 0x02: fromanc2_scrollx[1][1] = -(data - 0x1c2); break;
+ case 0x03: fromanc2_scrolly[1][1] = -(data - 0x1ef); break;
+ // offset 0x04 - 0x11 unknown
+ default: break;
+ }
+}
+
+WRITE16_HANDLER( fromanc2_gfxreg_2_w )
+{
+ switch (offset) {
+ case 0x00: fromanc2_scrollx[0][2] = -(data - 0x1c0); break;
+ case 0x01: fromanc2_scrolly[0][2] = -(data - 0x1ef); break;
+ case 0x02: fromanc2_scrollx[0][3] = -(data - 0x1c3); break;
+ case 0x03: fromanc2_scrolly[0][3] = -(data - 0x1ef); break;
+ // offset 0x04 - 0x11 unknown
+ default: break;
+ }
+}
+
+WRITE16_HANDLER( fromanc2_gfxreg_3_w )
+{
+ switch (offset) {
+ case 0x00: fromanc2_scrollx[1][2] = -(data - 0x1bf); break;
+ case 0x01: fromanc2_scrolly[1][2] = -(data - 0x1ef); break;
+ case 0x02: fromanc2_scrollx[1][3] = -(data - 0x1c3); break;
+ case 0x03: fromanc2_scrolly[1][3] = -(data - 0x1ef); break;
+ // offset 0x04 - 0x11 unknown
+ default: break;
+ }
+}
+
+WRITE16_HANDLER( fromanc2_gfxbank_0_w )
+{
+ fromanc2_gfxbank[0][0] = (data & 0x000f) >> 0;
+ fromanc2_gfxbank[0][1] = (data & 0x00f0) >> 4;
+ fromanc2_gfxbank[0][2] = (data & 0x0f00) >> 8;
+ fromanc2_gfxbank[0][3] = (data & 0xf000) >> 12;
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[0][0]);
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[0][1]);
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[0][2]);
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[0][3]);
+}
+
+WRITE16_HANDLER( fromanc2_gfxbank_1_w )
+{
+ fromanc2_gfxbank[1][0] = (data & 0x000f) >> 0;
+ fromanc2_gfxbank[1][1] = (data & 0x00f0) >> 4;
+ fromanc2_gfxbank[1][2] = (data & 0x0f00) >> 8;
+ fromanc2_gfxbank[1][3] = (data & 0xf000) >> 12;
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[1][0]);
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[1][1]);
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[1][2]);
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[1][3]);
+}
+
+
+INLINE void fromancr_vram_w(offs_t offset, UINT16 data, UINT16 mem_mask, int layer)
+{
+ int vram = (offset < 0x1000) ? 0 : 1;
+
+ COMBINE_DATA(&fromanc2_videoram[vram][layer][offset & 0x0fff]);
+ tilemap_mark_tile_dirty(fromanc2_tilemap[vram][layer], offset & 0x0fff);
+}
+
+WRITE16_HANDLER( fromancr_videoram_0_w ) { fromancr_vram_w(offset, data, mem_mask, 1); }
+WRITE16_HANDLER( fromancr_videoram_1_w ) { fromancr_vram_w(offset, data, mem_mask, 0); }
+WRITE16_HANDLER( fromancr_videoram_2_w ) { fromancr_vram_w(offset, data, mem_mask, 2); }
+
+WRITE16_HANDLER( fromancr_gfxreg_0_w )
+{
+ switch (offset) {
+ case 0x00: fromanc2_scrollx[0][0] = -(data - 0x1bf); break;
+ case 0x01: fromanc2_scrolly[0][0] = -(data - 0x1ef); break;
+ case 0x02: fromanc2_scrollx[1][0] = -(data - 0x1c3); break;
+ case 0x03: fromanc2_scrolly[1][0] = -(data - 0x1ef); break;
+ // offset 0x04 - 0x11 unknown
+ default: break;
+ }
+}
+
+WRITE16_HANDLER( fromancr_gfxreg_1_w )
+{
+ switch (offset) {
+ case 0x00: fromanc2_scrollx[0][1] = -(data - 0x000); break;
+ case 0x01: fromanc2_scrolly[0][1] = -(data - 0x000); break;
+ case 0x02: fromanc2_scrollx[1][1] = -(data - 0x004); break;
+ case 0x03: fromanc2_scrolly[1][1] = -(data - 0x000); break;
+ // offset 0x04 - 0x11 unknown
+ default: break;
+ }
+}
+
+void fromancr_gfxbank_w(int data)
+{
+ fromanc2_gfxbank[0][0] = (data & 0x0010) >> 4; // BG (1P)
+ fromanc2_gfxbank[0][1] = (data & 0xf000) >> 12; // FG (1P)
+ fromanc2_gfxbank[1][0] = (data & 0x0008) >> 3; // BG (2P)
+ fromanc2_gfxbank[1][1] = (data & 0x0f00) >> 8; // FG (2P)
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[0][0]);
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[0][1]);
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[1][0]);
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[1][1]);
+}
+
+
+INLINE void fromanc4_vram_w(offs_t offset, UINT16 data, UINT16 mem_mask, int layer)
+{
+ int vram = (offset < 0x4000) ? 0 : 1;
+
+ COMBINE_DATA(&fromanc2_videoram[vram][layer][offset & 0x3fff]);
+ tilemap_mark_tile_dirty(fromanc2_tilemap[vram][layer], offset & 0x3fff);
+}
+
+WRITE16_HANDLER( fromanc4_videoram_0_w ) { fromanc4_vram_w(offset, data, mem_mask, 2); }
+WRITE16_HANDLER( fromanc4_videoram_1_w ) { fromanc4_vram_w(offset, data, mem_mask, 1); }
+WRITE16_HANDLER( fromanc4_videoram_2_w ) { fromanc4_vram_w(offset, data, mem_mask, 0); }
+
+WRITE16_HANDLER( fromanc4_gfxreg_0_w )
+{
+ switch (offset) {
+ case 0x00: fromanc2_scrollx[0][2] = -(data - 0xfbb); break;
+ case 0x01: fromanc2_scrolly[0][2] = -(data - 0x1e4); break;
+ case 0x02: fromanc2_scrollx[1][2] = -(data - 0xfbb); break;
+ case 0x03: fromanc2_scrolly[1][2] = -(data - 0x1e4); break;
+ case 0x05: fromanc2_gfxbank[0][2] = (data & 0x000f) >> 0;
+ fromanc2_gfxbank[1][2] = (data & 0x0f00) >> 8;
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[0][2]);
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[1][2]);
+ break;
+ // offset 0x04, 0x06 - 0x11 unknown
+ default: break;
+ }
+}
+
+WRITE16_HANDLER( fromanc4_gfxreg_1_w )
+{
+ switch (offset) {
+ case 0x00: fromanc2_scrollx[0][1] = -(data - 0xfba); break;
+ case 0x01: fromanc2_scrolly[0][1] = -(data - 0x1e4); break;
+ case 0x02: fromanc2_scrollx[1][1] = -(data - 0xfba); break;
+ case 0x03: fromanc2_scrolly[1][1] = -(data - 0x1e4); break;
+ case 0x05: fromanc2_gfxbank[0][1] = (data & 0x000f) >> 0;
+ fromanc2_gfxbank[1][1] = (data & 0x0f00) >> 8;
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[0][1]);
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[1][1]);
+ break;
+ // offset 0x04, 0x06 - 0x11 unknown
+ default: break;
+ }
+}
+
+WRITE16_HANDLER( fromanc4_gfxreg_2_w )
+{
+ switch (offset) {
+ case 0x00: fromanc2_scrollx[0][0] = -(data - 0xfbb); break;
+ case 0x01: fromanc2_scrolly[0][0] = -(data - 0x1e4); break;
+ case 0x02: fromanc2_scrollx[1][0] = -(data - 0xfbb); break;
+ case 0x03: fromanc2_scrolly[1][0] = -(data - 0x1e4); break;
+ case 0x05: fromanc2_gfxbank[0][0] = (data & 0x000f) >> 0;
+ fromanc2_gfxbank[1][0] = (data & 0x0f00) >> 8;
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[0][0]);
+ tilemap_mark_all_tiles_dirty(fromanc2_tilemap[1][0]);
+ break;
+ // offset 0x04, 0x06 - 0x11 unknown
+ default: break;
+ }
+}
+
+
+/******************************************************************************
+
+ Start the video hardware emulation.
+
+******************************************************************************/
+
+VIDEO_START( fromanc2 )
+{
+ fromanc2_tilemap[0][0] = tilemap_create(fromanc2_get_v0_l0_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ fromanc2_tilemap[0][1] = tilemap_create(fromanc2_get_v0_l1_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ fromanc2_tilemap[0][2] = tilemap_create(fromanc2_get_v0_l2_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ fromanc2_tilemap[0][3] = tilemap_create(fromanc2_get_v0_l3_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ fromanc2_tilemap[1][0] = tilemap_create(fromanc2_get_v1_l0_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ fromanc2_tilemap[1][1] = tilemap_create(fromanc2_get_v1_l1_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ fromanc2_tilemap[1][2] = tilemap_create(fromanc2_get_v1_l2_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ fromanc2_tilemap[1][3] = tilemap_create(fromanc2_get_v1_l3_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+
+ fromanc2_videoram[0][0] = auto_malloc((64 * 64) * sizeof(UINT16));
+ fromanc2_videoram[0][1] = auto_malloc((64 * 64) * sizeof(UINT16));
+ fromanc2_videoram[0][2] = auto_malloc((64 * 64) * sizeof(UINT16));
+ fromanc2_videoram[0][3] = auto_malloc((64 * 64) * sizeof(UINT16));
+ fromanc2_videoram[1][0] = auto_malloc((64 * 64) * sizeof(UINT16));
+ fromanc2_videoram[1][1] = auto_malloc((64 * 64) * sizeof(UINT16));
+ fromanc2_videoram[1][2] = auto_malloc((64 * 64) * sizeof(UINT16));
+ fromanc2_videoram[1][3] = auto_malloc((64 * 64) * sizeof(UINT16));
+
+ fromanc2_paletteram[0] = auto_malloc(0x800 * 2);
+ fromanc2_paletteram[1] = auto_malloc(0x800 * 2);
+
+ tilemap_set_transparent_pen(fromanc2_tilemap[0][1], 0x000);
+ tilemap_set_transparent_pen(fromanc2_tilemap[0][2], 0x000);
+ tilemap_set_transparent_pen(fromanc2_tilemap[0][3], 0x000);
+ tilemap_set_transparent_pen(fromanc2_tilemap[1][1], 0x000);
+ tilemap_set_transparent_pen(fromanc2_tilemap[1][2], 0x000);
+ tilemap_set_transparent_pen(fromanc2_tilemap[1][3], 0x000);
+}
+
+VIDEO_START( fromancr )
+{
+ fromanc2_tilemap[0][0] = tilemap_create(fromancr_get_v0_l0_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ fromanc2_tilemap[0][1] = tilemap_create(fromancr_get_v0_l1_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ fromanc2_tilemap[0][2] = tilemap_create(fromancr_get_v0_l2_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ fromanc2_tilemap[0][3] = 0;
+ fromanc2_tilemap[1][0] = tilemap_create(fromancr_get_v1_l0_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ fromanc2_tilemap[1][1] = tilemap_create(fromancr_get_v1_l1_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ fromanc2_tilemap[1][2] = tilemap_create(fromancr_get_v1_l2_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ fromanc2_tilemap[1][3] = 0;
+
+ fromanc2_videoram[0][0] = auto_malloc((64 * 64) * sizeof(UINT16));
+ fromanc2_videoram[0][1] = auto_malloc((64 * 64) * sizeof(UINT16));
+ fromanc2_videoram[0][2] = auto_malloc((64 * 64) * sizeof(UINT16));
+ fromanc2_videoram[1][0] = auto_malloc((64 * 64) * sizeof(UINT16));
+ fromanc2_videoram[1][1] = auto_malloc((64 * 64) * sizeof(UINT16));
+ fromanc2_videoram[1][2] = auto_malloc((64 * 64) * sizeof(UINT16));
+
+ fromanc2_paletteram[0] = auto_malloc(0x800 * 2);
+ fromanc2_paletteram[1] = auto_malloc(0x800 * 2);
+
+ tilemap_set_transparent_pen(fromanc2_tilemap[0][1], 0x0ff);
+ tilemap_set_transparent_pen(fromanc2_tilemap[0][2], 0x0ff);
+ tilemap_set_transparent_pen(fromanc2_tilemap[1][1], 0x0ff);
+ tilemap_set_transparent_pen(fromanc2_tilemap[1][2], 0x0ff);
+}
+
+
+VIDEO_START( fromanc4 )
+{
+ fromanc2_tilemap[0][0] = tilemap_create(fromancr_get_v0_l0_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 256, 64);
+ fromanc2_tilemap[0][1] = tilemap_create(fromancr_get_v0_l1_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 256, 64);
+ fromanc2_tilemap[0][2] = tilemap_create(fromancr_get_v0_l2_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 256, 64);
+ fromanc2_tilemap[0][3] = 0;
+ fromanc2_tilemap[1][0] = tilemap_create(fromancr_get_v1_l0_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 256, 64);
+ fromanc2_tilemap[1][1] = tilemap_create(fromancr_get_v1_l1_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 256, 64);
+ fromanc2_tilemap[1][2] = tilemap_create(fromancr_get_v1_l2_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 256, 64);
+ fromanc2_tilemap[1][3] = 0;
+
+ fromanc2_videoram[0][0] = auto_malloc((256 * 64) * sizeof(UINT16));
+ fromanc2_videoram[0][1] = auto_malloc((256 * 64) * sizeof(UINT16));
+ fromanc2_videoram[0][2] = auto_malloc((256 * 64) * sizeof(UINT16));
+ fromanc2_videoram[1][0] = auto_malloc((256 * 64) * sizeof(UINT16));
+ fromanc2_videoram[1][1] = auto_malloc((256 * 64) * sizeof(UINT16));
+ fromanc2_videoram[1][2] = auto_malloc((256 * 64) * sizeof(UINT16));
+
+ fromanc2_paletteram[0] = auto_malloc(0x800 * 2);
+ fromanc2_paletteram[1] = auto_malloc(0x800 * 2);
+
+ tilemap_set_transparent_pen(fromanc2_tilemap[0][1], 0x000);
+ tilemap_set_transparent_pen(fromanc2_tilemap[0][2], 0x000);
+ tilemap_set_transparent_pen(fromanc2_tilemap[1][1], 0x000);
+ tilemap_set_transparent_pen(fromanc2_tilemap[1][2], 0x000);
+}
+
+/******************************************************************************
+
+ Display refresh
+
+******************************************************************************/
+
+VIDEO_UPDATE( fromanc2 )
+{
+ if (fromanc2_tilemap[screen][0]) {
+ tilemap_set_scrollx(fromanc2_tilemap[screen][0], 0, -fromanc2_scrollx[screen][0]);
+ tilemap_set_scrolly(fromanc2_tilemap[screen][0], 0, -fromanc2_scrolly[screen][0]);
+ tilemap_draw(bitmap,cliprect, fromanc2_tilemap[screen][0], 0, 0);
+ }
+ if (fromanc2_tilemap[screen][1]) {
+ tilemap_set_scrollx(fromanc2_tilemap[screen][1], 0, -fromanc2_scrollx[screen][1]);
+ tilemap_set_scrolly(fromanc2_tilemap[screen][1], 0, -fromanc2_scrolly[screen][1]);
+ tilemap_draw(bitmap,cliprect, fromanc2_tilemap[screen][1], 0, 0);
+ }
+ if (fromanc2_tilemap[screen][2]) {
+ tilemap_set_scrollx(fromanc2_tilemap[screen][2], 0, -fromanc2_scrollx[screen][2]);
+ tilemap_set_scrolly(fromanc2_tilemap[screen][2], 0, -fromanc2_scrolly[screen][2]);
+ tilemap_draw(bitmap,cliprect, fromanc2_tilemap[screen][2], 0, 0);
+ }
+ if (fromanc2_tilemap[screen][3]) {
+ tilemap_set_scrollx(fromanc2_tilemap[screen][3], 0, -fromanc2_scrollx[screen][3]);
+ tilemap_set_scrolly(fromanc2_tilemap[screen][3], 0, -fromanc2_scrolly[screen][3]);
+ tilemap_draw(bitmap,cliprect, fromanc2_tilemap[screen][3], 0, 0);
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/fromance.c b/src/mame/video/fromance.c
new file mode 100644
index 00000000000..06ae9541f5c
--- /dev/null
+++ b/src/mame/video/fromance.c
@@ -0,0 +1,471 @@
+/******************************************************************************
+
+ Video Hardware for Video System Mahjong series and Pipe Dream.
+
+ Driver by Takahiro Nogi <nogi@kt.rim.or.jp> 2001/02/04 -
+ and Bryan McPhail, Nicola Salmoria, Aaron Giles
+
+******************************************************************************/
+
+#include "driver.h"
+#include "fromance.h"
+
+
+static UINT8 selected_videoram;
+static UINT8 *local_videoram[2];
+
+static UINT8 selected_paletteram;
+static UINT8 *local_paletteram;
+
+static UINT32 scrollx[2], scrolly[2];
+static UINT8 gfxreg;
+static UINT8 flipscreen;
+static UINT32 scrolly_ofs;
+static UINT32 scrollx_ofs;
+
+static UINT8 crtc_register;
+static UINT8 crtc_data[0x10];
+static emu_timer *crtc_timer;
+
+static UINT8 flipscreen_old = -1;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+static TIMER_CALLBACK( crtc_interrupt_gen );
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+INLINE void get_fromance_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int layer)
+{
+ int tile = ((local_videoram[layer][0x0000 + tile_index] & 0x80) << 9) |
+ (local_videoram[layer][0x1000 + tile_index] << 8) |
+ local_videoram[layer][0x2000 + tile_index];
+ int color = local_videoram[layer][tile_index] & 0x7f;
+
+ SET_TILE_INFO(layer, tile, color, 0);
+}
+
+static TILE_GET_INFO( get_fromance_bg_tile_info ) { get_fromance_tile_info(machine,tileinfo,tile_index, 0); }
+static TILE_GET_INFO( get_fromance_fg_tile_info ) { get_fromance_tile_info(machine,tileinfo,tile_index, 1); }
+
+INLINE void get_nekkyoku_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int layer)
+{
+ int tile = (local_videoram[layer][0x0000 + tile_index] << 8) |
+ local_videoram[layer][0x1000 + tile_index];
+ int color = local_videoram[layer][tile_index + 0x2000] & 0x3f;
+
+ SET_TILE_INFO(layer, tile, color, 0);
+}
+
+static TILE_GET_INFO( get_nekkyoku_bg_tile_info ) { get_nekkyoku_tile_info(machine, tileinfo, tile_index, 0); }
+static TILE_GET_INFO( get_nekkyoku_fg_tile_info ) { get_nekkyoku_tile_info(machine, tileinfo, tile_index, 1); }
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( fromance )
+{
+ /* allocate tilemaps */
+ bg_tilemap = tilemap_create(get_fromance_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,4, 64,64);
+ fg_tilemap = tilemap_create(get_fromance_fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,4, 64,64);
+
+ /* allocate local videoram */
+ local_videoram[0] = auto_malloc(0x1000 * 3);
+ local_videoram[1] = auto_malloc(0x1000 * 3);
+
+ /* allocate local palette RAM */
+ local_paletteram = auto_malloc(0x800 * 2);
+
+ /* configure tilemaps */
+ tilemap_set_transparent_pen(fg_tilemap,15);
+
+ /* reset the timer */
+ crtc_timer = timer_alloc(crtc_interrupt_gen);
+
+ scrollx_ofs = 0x159;
+ scrolly_ofs = 0x10;
+
+ /* state save */
+ state_save_register_global(selected_videoram);
+ state_save_register_global_pointer(local_videoram[0], 0x1000 * 3);
+ state_save_register_global_pointer(local_videoram[1], 0x1000 * 3);
+ state_save_register_global(selected_paletteram);
+ state_save_register_global_array(scrollx);
+ state_save_register_global_array(scrolly);
+ state_save_register_global(gfxreg);
+ state_save_register_global(flipscreen);
+ state_save_register_global(flipscreen_old);
+ state_save_register_global(scrollx_ofs);
+ state_save_register_global(scrolly_ofs);
+ state_save_register_global(crtc_register);
+ state_save_register_global_array(crtc_data);
+ state_save_register_global_pointer(local_paletteram, 0x800 * 2);
+}
+
+VIDEO_START( nekkyoku )
+{
+ /* allocate tilemaps */
+ bg_tilemap = tilemap_create(get_nekkyoku_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,4, 64,64);
+ fg_tilemap = tilemap_create(get_nekkyoku_fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,4, 64,64);
+
+ /* allocate local videoram */
+ local_videoram[0] = auto_malloc(0x1000 * 3);
+ local_videoram[1] = auto_malloc(0x1000 * 3);
+
+ /* allocate local palette RAM */
+ local_paletteram = auto_malloc(0x800 * 2);
+
+ /* configure tilemaps */
+ tilemap_set_transparent_pen(fg_tilemap,15);
+
+ /* reset the timer */
+ crtc_timer = timer_alloc(crtc_interrupt_gen);
+
+ scrollx_ofs = 0x159;
+ scrolly_ofs = 0x10;
+
+ /* state save */
+ state_save_register_global(selected_videoram);
+ state_save_register_global_pointer(local_videoram[0], 0x1000 * 3);
+ state_save_register_global_pointer(local_videoram[1], 0x1000 * 3);
+ state_save_register_global(selected_paletteram);
+ state_save_register_global_array(scrollx);
+ state_save_register_global_array(scrolly);
+ state_save_register_global(gfxreg);
+ state_save_register_global(flipscreen);
+ state_save_register_global(flipscreen_old);
+ state_save_register_global(scrollx_ofs);
+ state_save_register_global(scrolly_ofs);
+ state_save_register_global(crtc_register);
+ state_save_register_global_array(crtc_data);
+ state_save_register_global_pointer(local_paletteram, 0x800 * 2);
+}
+
+VIDEO_START( pipedrm )
+{
+ video_start_fromance(machine);
+ scrolly_ofs = 0x00;
+}
+
+VIDEO_START( hatris )
+{
+ video_start_fromance(machine);
+ scrollx_ofs = 0xB9;
+ scrolly_ofs = 0x00;
+}
+
+/*************************************
+ *
+ * Graphics control register
+ *
+ *************************************/
+
+WRITE8_HANDLER( fromance_gfxreg_w )
+{
+
+ gfxreg = data;
+ flipscreen = (data & 0x01);
+ selected_videoram = (~data >> 1) & 1;
+ selected_paletteram = (data >> 6) & 1;
+
+ if (flipscreen != flipscreen_old)
+ {
+ flipscreen_old = flipscreen;
+ tilemap_set_flip(ALL_TILEMAPS, flipscreen ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Banked palette RAM
+ *
+ *************************************/
+
+READ8_HANDLER( fromance_paletteram_r )
+{
+ /* adjust for banking and read */
+ offset |= selected_paletteram << 11;
+ return local_paletteram[offset];
+}
+
+
+WRITE8_HANDLER( fromance_paletteram_w )
+{
+ int palword;
+
+ /* adjust for banking and modify */
+ offset |= selected_paletteram << 11;
+ local_paletteram[offset] = data;
+
+ /* compute R,G,B */
+ palword = (local_paletteram[offset | 1] << 8) | local_paletteram[offset & ~1];
+ palette_set_color_rgb(Machine, offset / 2, pal5bit(palword >> 10), pal5bit(palword >> 5), pal5bit(palword >> 0));
+}
+
+
+
+/*************************************
+ *
+ * Video RAM read/write
+ *
+ *************************************/
+
+READ8_HANDLER( fromance_videoram_r )
+{
+ return local_videoram[selected_videoram][offset];
+}
+
+
+WRITE8_HANDLER( fromance_videoram_w )
+{
+ local_videoram[selected_videoram][offset] = data;
+ tilemap_mark_tile_dirty(selected_videoram ? fg_tilemap : bg_tilemap, offset & 0x0fff);
+}
+
+
+
+/*************************************
+ *
+ * Scroll registers
+ *
+ *************************************/
+
+WRITE8_HANDLER( fromance_scroll_w )
+{
+ if (flipscreen)
+ {
+ switch (offset)
+ {
+ case 0:
+ scrollx[1] = (data + (((gfxreg & 0x08) >> 3) * 0x100) - scrollx_ofs);
+ break;
+ case 1:
+ scrolly[1] = (data + (((gfxreg & 0x04) >> 2) * 0x100) - scrolly_ofs); // - 0x10
+ break;
+ case 2:
+ scrollx[0] = (data + (((gfxreg & 0x20) >> 5) * 0x100) - scrollx_ofs);
+ break;
+ case 3:
+ scrolly[0] = (data + (((gfxreg & 0x10) >> 4) * 0x100) - scrolly_ofs);
+ break;
+ }
+ }
+ else
+ {
+ switch (offset)
+ {
+ case 0:
+ scrollx[1] = (data + (((gfxreg & 0x08) >> 3) * 0x100) - 0x1f7);
+ break;
+ case 1:
+ scrolly[1] = (data + (((gfxreg & 0x04) >> 2) * 0x100) - 0xf9);
+ break;
+ case 2:
+ scrollx[0] = (data + (((gfxreg & 0x20) >> 5) * 0x100) - 0x1f7);
+ break;
+ case 3:
+ scrolly[0] = (data + (((gfxreg & 0x10) >> 4) * 0x100) - 0xf9);
+ break;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Fake video controller
+ *
+ *************************************/
+
+static TIMER_CALLBACK( crtc_interrupt_gen )
+{
+ cpunum_set_input_line(1, 0, HOLD_LINE);
+ if (param != 0)
+ timer_adjust(crtc_timer, attotime_make(0, machine->screen[0].refresh / param), 0, attotime_make(0, machine->screen[0].refresh / param));
+}
+
+
+WRITE8_HANDLER( fromance_crtc_data_w )
+{
+ crtc_data[crtc_register] = data;
+
+ switch (crtc_register)
+ {
+ /* only register we know about.... */
+ case 0x0b:
+ timer_adjust(crtc_timer, video_screen_get_time_until_pos(0, Machine->screen[0].visarea.max_y + 1, 0), (data > 0x80) ? 2 : 1, attotime_zero);
+ break;
+
+ default:
+ logerror("CRTC register %02X = %02X\n", crtc_register, data & 0xff);
+ break;
+ }
+}
+
+
+WRITE8_HANDLER( fromance_crtc_register_w )
+{
+ crtc_register = data;
+}
+
+
+
+/*************************************
+ *
+ * Sprite routines (Pipe Dream)
+ *
+ *************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int draw_priority)
+{
+ static const UINT8 zoomtable[16] = { 0,7,14,20,25,30,34,38,42,46,49,52,54,57,59,61 };
+ int offs;
+
+ /* draw the sprites */
+ for (offs = 0; offs < spriteram_size; offs += 8)
+ {
+ int data2 = spriteram[offs + 4] | (spriteram[offs + 5] << 8);
+ int priority = (data2 >> 4) & 1;
+
+ /* turns out the sprites are the same as in aerofgt.c */
+ if ((data2 & 0x80) && priority == draw_priority)
+ {
+ int data0 = spriteram[offs + 0] | (spriteram[offs + 1] << 8);
+ int data1 = spriteram[offs + 2] | (spriteram[offs + 3] << 8);
+ int data3 = spriteram[offs + 6] | (spriteram[offs + 7] << 8);
+ int code = data3 & 0xfff;
+ int color = data2 & 0x0f;
+ int y = (data0 & 0x1ff) - 6;
+ int x = (data1 & 0x1ff) - 13;
+ int yzoom = (data0 >> 12) & 15;
+ int xzoom = (data1 >> 12) & 15;
+ int zoomed = (xzoom | yzoom);
+ int ytiles = ((data2 >> 12) & 7) + 1;
+ int xtiles = ((data2 >> 8) & 7) + 1;
+ int yflip = (data2 >> 15) & 1;
+ int xflip = (data2 >> 11) & 1;
+ int xt, yt;
+
+ /* compute the zoom factor -- stolen from aerofgt.c */
+ xzoom = 16 - zoomtable[xzoom] / 8;
+ yzoom = 16 - zoomtable[yzoom] / 8;
+
+ /* wrap around */
+ if (x > machine->screen[0].visarea.max_x) x -= 0x200;
+ if (y > machine->screen[0].visarea.max_y) y -= 0x200;
+
+ /* flip ? */
+ if (flipscreen)
+ {
+ y = machine->screen[0].visarea.max_y - y - 16 * ytiles - 4;
+ x = machine->screen[0].visarea.max_x - x - 16 * xtiles - 24;
+ xflip=!xflip;
+ yflip=!yflip;
+ }
+
+ /* normal case */
+ if (!xflip && !yflip)
+ {
+ for (yt = 0; yt < ytiles; yt++)
+ for (xt = 0; xt < xtiles; xt++, code++)
+ if (!zoomed)
+ drawgfx(bitmap, machine->gfx[2], code, color, 0, 0,
+ x + xt * 16, y + yt * 16, cliprect, TRANSPARENCY_PEN, 15);
+ else
+ drawgfxzoom(bitmap, machine->gfx[2], code, color, 0, 0,
+ x + xt * xzoom, y + yt * yzoom, cliprect, TRANSPARENCY_PEN, 15,
+ 0x1000 * xzoom, 0x1000 * yzoom);
+ }
+
+ /* xflipped case */
+ else if (xflip && !yflip)
+ {
+ for (yt = 0; yt < ytiles; yt++)
+ for (xt = 0; xt < xtiles; xt++, code++)
+ if (!zoomed)
+ drawgfx(bitmap, machine->gfx[2], code, color, 1, 0,
+ x + (xtiles - 1 - xt) * 16, y + yt * 16, cliprect, TRANSPARENCY_PEN, 15);
+ else
+ drawgfxzoom(bitmap, machine->gfx[2], code, color, 1, 0,
+ x + (xtiles - 1 - xt) * xzoom, y + yt * yzoom, cliprect, TRANSPARENCY_PEN, 15,
+ 0x1000 * xzoom, 0x1000 * yzoom);
+ }
+
+ /* yflipped case */
+ else if (!xflip && yflip)
+ {
+ for (yt = 0; yt < ytiles; yt++)
+ for (xt = 0; xt < xtiles; xt++, code++)
+ if (!zoomed)
+ drawgfx(bitmap, machine->gfx[2], code, color, 0, 1,
+ x + xt * 16, y + (ytiles - 1 - yt) * 16, cliprect, TRANSPARENCY_PEN, 15);
+ else
+ drawgfxzoom(bitmap, machine->gfx[2], code, color, 0, 1,
+ x + xt * xzoom, y + (ytiles - 1 - yt) * yzoom, cliprect, TRANSPARENCY_PEN, 15,
+ 0x1000 * xzoom, 0x1000 * yzoom);
+ }
+
+ /* x & yflipped case */
+ else
+ {
+ for (yt = 0; yt < ytiles; yt++)
+ for (xt = 0; xt < xtiles; xt++, code++)
+ if (!zoomed)
+ drawgfx(bitmap, machine->gfx[2], code, color, 1, 1,
+ x + (xtiles - 1 - xt) * 16, y + (ytiles - 1 - yt) * 16, cliprect, TRANSPARENCY_PEN, 15);
+ else
+ drawgfxzoom(bitmap, machine->gfx[2], code, color, 1, 1,
+ x + (xtiles - 1 - xt) * xzoom, y + (ytiles - 1 - yt) * yzoom, cliprect, TRANSPARENCY_PEN, 15,
+ 0x1000 * xzoom, 0x1000 * yzoom);
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main screen refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( fromance )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, scrollx[0]);
+ tilemap_set_scrolly(bg_tilemap, 0, scrolly[0]);
+ tilemap_set_scrollx(fg_tilemap, 0, scrollx[1]);
+ tilemap_set_scrolly(fg_tilemap, 0, scrolly[1]);
+
+ tilemap_draw(bitmap,cliprect, bg_tilemap, 0, 0);
+ tilemap_draw(bitmap,cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( pipedrm )
+{
+ /* there seems to be no logical mapping for the X scroll register -- maybe it's gone */
+ tilemap_set_scrolly(bg_tilemap, 0, scrolly[1]);
+ tilemap_set_scrolly(fg_tilemap, 0, scrolly[0]);
+
+ tilemap_draw(bitmap,cliprect, bg_tilemap, 0, 0);
+ tilemap_draw(bitmap,cliprect, fg_tilemap, 0, 0);
+
+ draw_sprites(machine,bitmap,cliprect, 0);
+ draw_sprites(machine,bitmap,cliprect, 1);
+ return 0;
+}
diff --git a/src/mame/video/funkybee.c b/src/mame/video/funkybee.c
new file mode 100644
index 00000000000..d03834983c9
--- /dev/null
+++ b/src/mame/video/funkybee.c
@@ -0,0 +1,175 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static int gfx_bank;
+static tilemap *bg_tilemap;
+
+PALETTE_INIT( funkybee )
+{
+ int i;
+
+
+ /* first, the character/sprite palette */
+ for (i = 0;i < 32;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( funkybee_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( funkybee_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( funkybee_gfx_bank_w )
+{
+ if (gfx_bank != (data & 0x01))
+ {
+ gfx_bank = data & 0x01;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( funkybee_scroll_w )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, flip_screen ? -data : data);
+}
+
+WRITE8_HANDLER( funkybee_flipscreen_w )
+{
+ flip_screen_set(data & 0x01);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + ((colorram[tile_index] & 0x80) << 1);
+ int color = colorram[tile_index] & 0x03;
+
+ SET_TILE_INFO(gfx_bank, code, color, 0);
+}
+
+static TILEMAP_MAPPER( funkybee_tilemap_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return 256 * row + col;
+}
+
+VIDEO_START( funkybee )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, funkybee_tilemap_scan,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0x0f; offs >= 0; offs--)
+ {
+ int offs2 = offs + 0x1e00;
+ int attr = videoram[offs2];
+ int code = (attr >> 2) | ((attr & 2) << 5);
+ int color = colorram[offs2 + 0x10];
+ int flipx = 0;
+ int flipy = attr & 0x01;
+ int sx = videoram[offs2 + 0x10];
+ int sy = 224 - colorram[offs2];
+
+ if (flip_screen)
+ {
+ sy += 32;
+ flipx = !flipx;
+ }
+
+ drawgfx(bitmap,machine->gfx[2+gfx_bank],
+ code, color,
+ flipx, flipy,
+ sx, sy,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+static void draw_columns(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0x1f;offs >= 0;offs--)
+ {
+ int code = videoram[0x1c00 + offs];
+ int color = colorram[0x1f10] & 0x03;
+ int sx = videoram[0x1f10];
+ int sy = offs * 8;
+
+ if (flip_screen)
+ {
+ sx = 248 - sx;
+ sy = 248 - sy;
+ }
+
+ drawgfx(bitmap,machine->gfx[gfx_bank],
+ code, color,
+ flip_screen, flip_screen,
+ sx, sy,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ code = videoram[0x1d00 + offs];
+ color = colorram[0x1f11] & 0x03;
+ sx = videoram[0x1f11];
+ sy = offs * 8;
+
+ if (flip_screen)
+ {
+ sx = 248 - sx;
+ sy = 248 - sy;
+ }
+
+ drawgfx(bitmap,machine->gfx[gfx_bank],
+ code, color,
+ flip_screen, flip_screen,
+ sx, sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( funkybee )
+{
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ draw_columns(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/funkyjet.c b/src/mame/video/funkyjet.c
new file mode 100644
index 00000000000..94f87f28c08
--- /dev/null
+++ b/src/mame/video/funkyjet.c
@@ -0,0 +1,90 @@
+/***************************************************************************
+
+ Funky Jet Video emulation - Bryan McPhail, mish@tendril.co.uk
+
+***************************************************************************/
+
+#include "driver.h"
+#include "deco16ic.h"
+
+/******************************************************************************/
+
+VIDEO_START( funkyjet )
+{
+ deco16_1_video_init();
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ sprite = spriteram16[offs+1] & 0x3fff;
+
+ y = spriteram16[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ x = spriteram16[offs+2];
+ colour = (x >>9) & 0x1f;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+ y = 240 - y;
+ x = 304 - x;
+
+ if (x>320) continue;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen)
+ {
+ y=240-y;
+ x=304-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ multi--;
+ }
+ }
+}
+
+VIDEO_UPDATE( funkyjet )
+{
+ flip_screen_set( deco16_pf12_control[0]&0x80 );
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+
+ fillbitmap(bitmap,machine->pens[768],cliprect);
+ deco16_tilemap_2_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/funworld.c b/src/mame/video/funworld.c
new file mode 100644
index 00000000000..9865c0958be
--- /dev/null
+++ b/src/mame/video/funworld.c
@@ -0,0 +1,128 @@
+/**********************************************************************************
+
+
+ FUNWORLD.
+
+
+ Original preliminary driver: Curt Coder, Peter Trauner.
+ Rewrite and aditional work: Roberto Fresca.
+
+
+ Games running in this hardware:
+
+ * Jolly Card (Austria), TAB-Austria, 1985.
+ * Jolly Card (Austria, encrypted), TAB-Austria, 1985.
+ * Jolly Card (Croatia), Soft Design, 1993.
+ * Jolly Card (Italia, encrypted), bootleg, 199?.
+ * Jolly Card (Austria, Fun World, bootleg), Inter Games, 1995.
+ * Big Deal (Hungary, set 1), Fun World, 1990.
+ * Big Deal (Hungary, set 2), Fun World, 1990.
+ * Jolly Card (Austria, Fun World), Fun World, 1990.
+ * Cuore 1 (Italia), C.M.C., 1996.
+ * Elephant Family (Italia, new), C.M.C., 1997.
+ * Elephant Family (Italia, old), C.M.C., 1996.
+ * Pool 10 (Italia, set 1), C.M.C., 1996.
+ * Pool 10 (Italia, set 2), C.M.C., 1996.
+ * Tortuga Family (Italia), C.M.C., 1997.
+ * Royal Card (Austria, set 1), TAB-Austria, 1991.
+ * Royal Card (Austria, set 2), TAB-Austria, 1991.
+ * Royal Card (Slovakia, encrypted), Evona Electronic, 1991.
+ * Magic Card II (Bulgaria, bootleg), Impera, 1996.
+ * Joker Card (Ver.A267BC, encrypted), Vesely Svet, 1993.
+ * Mongolfier New (Italia), bootleg, 199?.
+ * Soccer New (Italia), bootleg, 199?.
+ * Snooker 10 (Ver 1.11), Sandiy, 1998.
+ * Saloon (France, encrypted), unknown, 199?.
+
+
+***********************************************************************************/
+
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+
+PALETTE_INIT(funworld)
+{
+ int i;
+
+ /* RRRBBBGG */
+ if (color_prom == 0) return;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+WRITE8_HANDLER( funworld_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( funworld_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+/**** normal hardware limit ****
+ - bits -
+ 7654 3210
+ xxxx xx-- tiles color.
+ xxx- x-xx tiles color (title).
+ xxxx -xxx tiles color (background).
+*/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+// - bits -
+// 7654 3210
+// xxxx ---- tiles color.
+// ---- xxxx unused.
+
+ int offs = tile_index;
+ int attr = videoram[offs] + (colorram[offs] << 8);
+ int code = attr & 0xfff;
+ int color = colorram[offs] >> 4; // 4 bits for color.
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START(funworld)
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 4, 8, 96, 29);
+}
+
+VIDEO_START(magiccrd)
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 4, 8, 112, 34);
+}
+
+VIDEO_UPDATE(funworld)
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/funybubl.c b/src/mame/video/funybubl.c
new file mode 100644
index 00000000000..e6f6b3d4344
--- /dev/null
+++ b/src/mame/video/funybubl.c
@@ -0,0 +1,116 @@
+/* Funny Bubble Video hardware
+
+todo - convert to tilemap
+
+ */
+
+
+#include "driver.h"
+
+UINT8* funybubl_banked_videoram;
+UINT8 *funybubl_paletteram;
+
+
+WRITE8_HANDLER ( funybubl_paldatawrite )
+{
+ int colchanged ;
+
+ UINT32 coldat;
+
+ funybubl_paletteram[offset] = data;
+
+ colchanged = offset >> 2;
+
+ coldat = funybubl_paletteram[colchanged*4] | (funybubl_paletteram[colchanged*4+1] << 8) | (funybubl_paletteram[colchanged*4+2] << 16) | (funybubl_paletteram[colchanged*4+3] << 24);
+
+ palette_set_color_rgb(Machine,colchanged,pal6bit(coldat >> 12),pal6bit(coldat >> 0),pal6bit(coldat >> 6));
+}
+
+
+VIDEO_START(funybubl)
+{
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+
+
+ UINT8 *source = &funybubl_banked_videoram[0x2000-0x20];
+ UINT8 *finish = source - 0x1000;
+
+
+ while( source>finish )
+ {
+ int xpos, ypos, tile;
+
+ /* the sprites are in the sprite list twice
+ the first format (in comments) appears to be a buffer, if you use
+ this list you get garbage sprites in 2 player mode
+ the second format (used) seems correct
+
+ */
+/*
+ ypos = 0xff-source[1+0x10];
+ xpos = source[2+0x10];
+ tile = source[0+0x10] | ( (source[3+0x10] & 0x0f) <<8);
+ if (source[3+0x10] & 0x80) tile += 0x1000;
+ if (source[3+0x10] & 0x20) xpos += 0x100;
+ // bits 0x40 (not used?) and 0x10 (just set during transition period of x co-ord 0xff and 0x00) ...
+ xpos -= 8;
+ ypos -= 14;
+
+*/
+ ypos = source[2];
+ xpos = source[3];
+ tile = source[0] | ( (source[1] & 0x0f) <<8);
+ if (source[1] & 0x80) tile += 0x1000;
+ if (source[1] & 0x20) { if (xpos < 0xe0) xpos += 0x100; }
+ // bits 0x40 and 0x10 not used?...
+
+ drawgfx(bitmap,machine->gfx[1],tile,0,0,0,xpos,ypos,cliprect,TRANSPARENCY_PEN,255);
+
+ source -= 0x20;
+ }
+
+}
+
+
+VIDEO_UPDATE(funybubl)
+{
+ int x,y, offs;
+
+ offs = 0;
+
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+
+ /* tilemap .. convert it .. banking makes it slightly more annoying but still easy */
+ for (y = 0; y < 32; y++)
+ {
+ for (x = 0; x< 64; x++)
+ {
+ int data;
+
+ data = funybubl_banked_videoram[offs] | (funybubl_banked_videoram[offs+1] << 8);
+ drawgfx(bitmap,machine->gfx[0],data&0x7fff,(data&0x8000)?2:1,0,0,x*8,y*8,cliprect,TRANSPARENCY_PEN,0);
+ offs+=2;
+ }
+ }
+
+ draw_sprites(machine,bitmap,cliprect);
+
+/*
+ if ( input_code_pressed_once(KEYCODE_W) )
+ {
+ FILE *fp;
+
+ fp=fopen("funnybubsprites", "w+b");
+ if (fp)
+ {
+ fwrite(&funybubl_banked_videoram[0x1000], 0x1000, 1, fp);
+ fclose(fp);
+ }
+ }
+*/
+ return 0;
+}
diff --git a/src/mame/video/fuukifg2.c b/src/mame/video/fuukifg2.c
new file mode 100644
index 00000000000..a86f99aa31e
--- /dev/null
+++ b/src/mame/video/fuukifg2.c
@@ -0,0 +1,353 @@
+/***************************************************************************
+
+ -= Fuuki 16 Bit Games (FG-2) =-
+
+ driver by Luca Elia (l.elia@tin.it)
+ c.f. Fuuki FG-3
+
+
+ [ 4 Scrolling Layers ]
+
+ [ Layer 0 ] [ Layer 1 ] [ Layers 2&3 (double-buffered) ]
+
+ Tile Size: 16 x 16 x 4 16 x 16 x 8 8 x 8 x 4
+ Layer Size (tiles): 64 x 32 64 x 32 64 x 32
+
+ [ 1024? Zooming Sprites ]
+
+ Sprites are made of 16 x 16 x 4 tiles. Size can vary from 1 to 16
+ tiles both horizontally and vertically.
+ There is zooming (from full size to half size) and 4 levels of
+ priority (wrt layers)
+
+ * Note: the game does hardware assisted raster effects *
+
+***************************************************************************/
+
+#include "driver.h"
+
+/* Variables that driver has access to: */
+
+UINT16 *fuuki16_vram_0, *fuuki16_vram_1;
+UINT16 *fuuki16_vram_2, *fuuki16_vram_3;
+UINT16 *fuuki16_vregs, *fuuki16_priority, *fuuki16_unknown;
+
+
+/***************************************************************************
+
+
+ Tilemaps
+
+ Offset: Bits: Value:
+
+ 0.w Code
+
+ 2.w fedc ba98 ---- ----
+ ---- ---- 7--- ---- Flip Y
+ ---- ---- -6-- ---- Flip X
+ ---- ---- --54 3210 Color
+
+
+***************************************************************************/
+
+#define LAYER( _N_ ) \
+\
+static tilemap *tilemap_##_N_; \
+\
+static TILE_GET_INFO( get_tile_info_##_N_ ) \
+{ \
+ UINT16 code = fuuki16_vram_##_N_[ 2 * tile_index + 0 ]; \
+ UINT16 attr = fuuki16_vram_##_N_[ 2 * tile_index + 1 ]; \
+ SET_TILE_INFO(1 + _N_, code, attr & 0x3f,TILE_FLIPYX( (attr >> 6) & 3 )); \
+} \
+\
+WRITE16_HANDLER( fuuki16_vram_##_N_##_w ) \
+{ \
+ COMBINE_DATA(&fuuki16_vram_##_N_[offset]); \
+ tilemap_mark_tile_dirty(tilemap_##_N_,offset/2); \
+}
+
+LAYER( 0 )
+LAYER( 1 )
+LAYER( 2 )
+LAYER( 3 )
+
+
+/***************************************************************************
+
+
+ Video Hardware Init
+
+
+***************************************************************************/
+
+/* Not used atm, seems to be fine without clearing pens? */
+#if 0
+PALETTE_INIT( fuuki16 )
+{
+ int pen;
+
+ /* The game does not initialise the palette at startup. It should
+ be totally black */
+ for (pen = 0; pen < machine->drv->total_colors; pen++)
+ palette_set_color(machine,pen,MAKE_RGB(0,0,0));
+}
+#endif
+
+VIDEO_START( fuuki16 )
+{
+ tilemap_0 = tilemap_create( get_tile_info_0, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16, 16, 64,32);
+
+ tilemap_1 = tilemap_create( get_tile_info_1, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16, 16, 64,32);
+
+ tilemap_2 = tilemap_create( get_tile_info_2, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64,32);
+
+ tilemap_3 = tilemap_create( get_tile_info_3, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64,32);
+
+ tilemap_set_transparent_pen(tilemap_0,0x0f); // 4 bits
+ tilemap_set_transparent_pen(tilemap_1,0xff); // 8 bits
+ tilemap_set_transparent_pen(tilemap_2,0x0f); // 4 bits
+ tilemap_set_transparent_pen(tilemap_3,0x0f); // 4 bits
+
+ machine->gfx[2]->color_granularity=16; /* 256 colour tiles with palette selectable on 16 colour boundaries */
+}
+
+
+/***************************************************************************
+
+
+ Sprites Drawing
+
+ Offset: Bits: Value:
+
+ 0.w fedc ---- ---- ---- Number Of Tiles Along X - 1
+ ---- b--- ---- ---- Flip X
+ ---- -a-- ---- ---- 1 = Don't Draw This Sprite
+ ---- --98 7654 3210 X (Signed)
+
+ 2.w fedc ---- ---- ---- Number Of Tiles Along Y - 1
+ ---- b--- ---- ---- Flip Y
+ ---- -a-- ---- ----
+ ---- --98 7654 3210 Y (Signed)
+
+ 4.w fedc ---- ---- ---- Zoom X ($0 = Full Size, $F = Half Size)
+ ---- ba98 ---- ---- Zoom Y ""
+ ---- ---- 76-- ---- Priority
+ ---- ---- --54 3210 Color
+
+ 6.w Code
+
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ int max_x = machine->screen[0].visarea.max_x+1;
+ int max_y = machine->screen[0].visarea.max_y+1;
+
+ /* Draw them backwards, for pdrawgfx */
+ for ( offs = (spriteram_size-8)/2; offs >=0; offs -= 8/2 )
+ {
+ int x, y, xstart, ystart, xend, yend, xinc, yinc;
+ int xnum, ynum, xzoom, yzoom, flipx, flipy;
+ int pri_mask;
+
+ int sx = spriteram16[offs + 0];
+ int sy = spriteram16[offs + 1];
+ int attr = spriteram16[offs + 2];
+ int code = spriteram16[offs + 3];
+
+ if (sx & 0x400) continue;
+
+ flipx = sx & 0x0800;
+ flipy = sy & 0x0800;
+
+ xnum = ((sx >> 12) & 0xf) + 1;
+ ynum = ((sy >> 12) & 0xf) + 1;
+
+ xzoom = 16*8 - (8 * ((attr >> 12) & 0xf))/2;
+ yzoom = 16*8 - (8 * ((attr >> 8) & 0xf))/2;
+
+ switch( (attr >> 6) & 3 )
+ {
+ case 3: pri_mask = 0xf0|0xcc|0xaa; break; // behind all layers
+ case 2: pri_mask = 0xf0|0xcc; break; // behind fg + middle layer
+ case 1: pri_mask = 0xf0; break; // behind fg layer
+ case 0:
+ default: pri_mask = 0; // above all
+ }
+
+ sx = (sx & 0x1ff) - (sx & 0x200);
+ sy = (sy & 0x1ff) - (sy & 0x200);
+
+ if (flip_screen)
+ { flipx = !flipx; sx = max_x - sx - xnum * 16;
+ flipy = !flipy; sy = max_y - sy - ynum * 16; }
+
+ if (flipx) { xstart = xnum-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = xnum; xinc = +1; }
+
+ if (flipy) { ystart = ynum-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = ynum; yinc = +1; }
+
+ for (y = ystart; y != yend; y += yinc)
+ {
+ for (x = xstart; x != xend; x += xinc)
+ {
+ if (xzoom == (16*8) && yzoom == (16*8))
+ pdrawgfx( bitmap,machine->gfx[0],
+ code++,
+ attr & 0x3f,
+ flipx, flipy,
+ sx + x * 16, sy + y * 16,
+ cliprect,TRANSPARENCY_PEN,15,
+ pri_mask );
+ else
+ pdrawgfxzoom( bitmap,machine->gfx[0],
+ code++,
+ attr & 0x3f,
+ flipx, flipy,
+ sx + (x * xzoom) / 8, sy + (y * yzoom) / 8,
+ cliprect,TRANSPARENCY_PEN,15,
+ (0x10000/0x10/8) * (xzoom + 8),(0x10000/0x10/8) * (yzoom + 8), // nearest greater integer value to avoid holes
+ pri_mask );
+ }
+ }
+
+#ifdef MAME_DEBUG
+#if 0
+if (input_code_pressed(KEYCODE_X))
+{ /* Display some info on each sprite */
+ char buf[10];
+ sprintf(buf, "%Xx%X %X",xnum,ynum,(attr>>6)&3);
+ ui_draw_text(buf, sx, sy);
+}
+#endif
+#endif
+ }
+}
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+ Video Registers (fuuki16_vregs):
+
+ 00.w Layer 0 Scroll Y
+ 02.w Layer 0 Scroll X
+ 04.w Layer 1 Scroll Y
+ 06.w Layer 1 Scroll X
+ 08.w Layer 2 Scroll Y
+ 0a.w Layer 2 Scroll X
+ 0c.w Layers Y Offset
+ 0e.w Layers X Offset
+
+ 10-1a.w ? 0
+ 1c.w Trigger a level 5 irq on this raster line
+ 1e.w ? $3390/$3393 (Flip Screen Off/On), $0040 is buffer for tilemap 2 or 3
+
+ Priority Register (fuuki16_priority):
+
+ fedc ba98 7654 3---
+ ---- ---- ---- -210 Layer Order
+
+
+ Unknown Registers (fuuki16_unknown):
+
+ 00.w ? $0200/$0201 (Flip Screen Off/On)
+ 02.w ? $f300/$0330
+
+***************************************************************************/
+
+/* Wrapper to handle bg and bg2 ttogether */
+static void fuuki16_draw_layer(mame_bitmap *bitmap, const rectangle *cliprect, int i, int flag, int pri)
+{
+ int buffer = (fuuki16_vregs[0x1e/2] & 0x40);
+
+ switch( i )
+ {
+ case 2: if (buffer) tilemap_draw(bitmap,cliprect,tilemap_3,flag,pri);
+ else tilemap_draw(bitmap,cliprect,tilemap_2,flag,pri);
+ return;
+ case 1: tilemap_draw(bitmap,cliprect,tilemap_1,flag,pri);
+ return;
+ case 0: tilemap_draw(bitmap,cliprect,tilemap_0,flag,pri);
+ return;
+ }
+}
+
+VIDEO_UPDATE( fuuki16 )
+{
+ UINT16 layer0_scrollx, layer0_scrolly;
+ UINT16 layer1_scrollx, layer1_scrolly;
+ UINT16 layer2_scrollx, layer2_scrolly;
+ UINT16 scrollx_offs, scrolly_offs;
+
+ /*
+ It's not independant bits causing layers to switch, that wouldn't make sense with 3 bits.
+ See fuukifg3 for more justification
+ */
+
+ int tm_back, tm_middle, tm_front;
+ static const int pri_table[6][3] = {
+ { 0, 1, 2 },
+ { 0, 2, 1 },
+ { 1, 0, 2 },
+ { 1, 2, 0 },
+ { 2, 0, 1 },
+ { 2, 1, 0 }};
+
+ tm_front = pri_table[ fuuki16_priority[0] & 0x0f ][0];
+ tm_middle = pri_table[ fuuki16_priority[0] & 0x0f ][1];
+ tm_back = pri_table[ fuuki16_priority[0] & 0x0f ][2];
+
+ flip_screen_set(fuuki16_vregs[0x1e/2] & 1);
+
+ /* Layers scrolling */
+
+ scrolly_offs = fuuki16_vregs[0xc/2] - (flip_screen ? 0x103 : 0x1f3);
+ scrollx_offs = fuuki16_vregs[0xe/2] - (flip_screen ? 0x2a7 : 0x3f6);
+
+ layer0_scrolly = fuuki16_vregs[0x0/2] + scrolly_offs;
+ layer0_scrollx = fuuki16_vregs[0x2/2] + scrollx_offs;
+ layer1_scrolly = fuuki16_vregs[0x4/2] + scrolly_offs;
+ layer1_scrollx = fuuki16_vregs[0x6/2] + scrollx_offs;
+
+ layer2_scrolly = fuuki16_vregs[0x8/2];
+ layer2_scrollx = fuuki16_vregs[0xa/2];
+
+ tilemap_set_scrollx(tilemap_0, 0, layer0_scrollx);
+ tilemap_set_scrolly(tilemap_0, 0, layer0_scrolly);
+ tilemap_set_scrollx(tilemap_1, 0, layer1_scrollx);
+ tilemap_set_scrolly(tilemap_1, 0, layer1_scrolly);
+
+ tilemap_set_scrollx(tilemap_2, 0, layer2_scrollx + 0x10);
+ tilemap_set_scrolly(tilemap_2, 0, layer2_scrolly /*+ 0x02*/);
+ tilemap_set_scrollx(tilemap_3, 0, layer2_scrollx + 0x10);
+ tilemap_set_scrolly(tilemap_3, 0, layer2_scrolly /*+ 0x02*/);
+
+ /* The backmost tilemap decides the background color(s) but sprites can
+ go below the opaque pixels of that tilemap. We thus need to mark the
+ transparent pixels of this layer with a different priority value */
+// fuuki16_draw_layer(bitmap,cliprect, tm_back, TILEMAP_DRAW_OPAQUE, 0);
+
+ /* Actually, bg colour is simply the last pen i.e. 0x1fff -pjp */
+ fillbitmap(bitmap,(0x800*4)-1,cliprect);
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ fuuki16_draw_layer(bitmap,cliprect, tm_back, 0, 1);
+ fuuki16_draw_layer(bitmap,cliprect, tm_middle, 0, 2);
+ fuuki16_draw_layer(bitmap,cliprect, tm_front, 0, 4);
+
+ draw_sprites(machine, bitmap, cliprect);
+
+ return 0;
+}
diff --git a/src/mame/video/fuukifg3.c b/src/mame/video/fuukifg3.c
new file mode 100644
index 00000000000..16eef03d88f
--- /dev/null
+++ b/src/mame/video/fuukifg3.c
@@ -0,0 +1,388 @@
+/***************************************************************************
+
+ -= Fuuki 32 Bit Games (FG-3) =-
+
+ driver by Paul Priest and David Haywood
+ based on fuukifg2 by Luca Elia
+
+
+ [ 4 Scrolling Layers ]
+
+ [ Layer 0 ] [ Layer 1 ] [ Layers 2&3 (double-buffered) ]
+
+ Tile Size: 16 x 16 x 8 16 x 16 x 8 8 x 8 x 4
+ Layer Size (tiles): 64 x 32 64 x 32 64 x 32
+
+ [ 1024? Zooming Sprites ]
+
+ Sprites are made of 16 x 16 x 4 tiles. Size can vary from 1 to 16
+ tiles both horizontally and vertically.
+ There is zooming (from full size to half size) and 4 levels of
+ priority (wrt layers)
+
+ Per-line raster effects used on many stages
+ Sprites buffered by two frames
+ Tilebank buffered by 3 frames? Only 2 in attract
+ Sprite pens needs to be buffered by 3 frames? Or lazy programming? Probably 2
+
+***************************************************************************/
+
+#include "driver.h"
+
+/* Variables that driver has access to: */
+
+UINT32 *fuuki32_vram_0, *fuuki32_vram_1;
+UINT32 *fuuki32_vram_2, *fuuki32_vram_3;
+UINT32 *fuuki32_vregs, *fuuki32_priority, *fuuki32_tilebank;
+
+static UINT32 spr_buffered_tilebank[2];
+
+
+/***************************************************************************
+
+
+ Tilemaps
+
+ Offset: Bits: Value:
+
+ 0.w Code
+
+ 2.w fedc ba98 ---- ----
+ ---- ---- 7--- ---- Flip Y
+ ---- ---- -6-- ---- Flip X
+ ---- ---- --54 3210 Color
+
+
+***************************************************************************/
+
+#define LAYER_8BPP( _N_ ) \
+\
+static tilemap *tilemap_##_N_; \
+\
+static TILE_GET_INFO( get_tile_info_##_N_ ) \
+{ \
+ UINT16 code = (fuuki32_vram_##_N_[tile_index]&0xffff0000)>>16; \
+ UINT16 attr = (fuuki32_vram_##_N_[tile_index]&0x0000ffff); \
+ SET_TILE_INFO(1 + _N_, code, (attr & 0x3f)>>4,TILE_FLIPYX( (attr >> 6) & 3 )); \
+} \
+\
+WRITE32_HANDLER( fuuki32_vram_##_N_##_w ) \
+{ \
+ COMBINE_DATA(&fuuki32_vram_##_N_[offset]); \
+ tilemap_mark_tile_dirty(tilemap_##_N_,offset); \
+}
+
+#define LAYER_4BPP( _N_ ) \
+\
+static tilemap *tilemap_##_N_; \
+\
+static TILE_GET_INFO( get_tile_info_##_N_ ) \
+{ \
+ UINT16 code = (fuuki32_vram_##_N_[tile_index]&0xffff0000)>>16; \
+ UINT16 attr = (fuuki32_vram_##_N_[tile_index]&0x0000ffff); \
+ SET_TILE_INFO(1 + _N_, code, attr & 0x3f,TILE_FLIPYX( (attr >> 6) & 3 )); \
+} \
+\
+WRITE32_HANDLER( fuuki32_vram_##_N_##_w ) \
+{ \
+ COMBINE_DATA(&fuuki32_vram_##_N_[offset]); \
+ tilemap_mark_tile_dirty(tilemap_##_N_,offset); \
+}
+
+
+LAYER_8BPP( 0 )
+LAYER_8BPP( 1 )
+LAYER_4BPP( 2 )
+LAYER_4BPP( 3 )
+
+
+/***************************************************************************
+
+
+ Video Hardware Init
+
+
+***************************************************************************/
+
+VIDEO_START( fuuki32 )
+{
+ buffered_spriteram32 = auto_malloc(spriteram_size);
+ buffered_spriteram32_2 = auto_malloc(spriteram_size);
+
+ tilemap_0 = tilemap_create( get_tile_info_0, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16, 16, 64,32);
+
+ tilemap_1 = tilemap_create( get_tile_info_1, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16, 16, 64,32);
+
+ tilemap_2 = tilemap_create( get_tile_info_2, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64,32);
+
+ tilemap_3 = tilemap_create( get_tile_info_3, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64,32);
+
+ tilemap_set_transparent_pen(tilemap_0,0xff); // 8 bits
+ tilemap_set_transparent_pen(tilemap_1,0xff); // 8 bits
+ tilemap_set_transparent_pen(tilemap_2,0x0f); // 4 bits
+ tilemap_set_transparent_pen(tilemap_3,0x0f); // 4 bits
+
+ //machine->gfx[1]->color_granularity=16; /* 256 colour tiles with palette selectable on 16 colour boundaries */
+ //machine->gfx[2]->color_granularity=16;
+}
+
+
+/***************************************************************************
+
+
+ Sprites Drawing
+
+ Offset: Bits: Value:
+
+ 0.w fedc ---- ---- ---- Number Of Tiles Along X - 1
+ ---- b--- ---- ---- Flip X
+ ---- -a-- ---- ---- 1 = Don't Draw This Sprite
+ ---- --98 7654 3210 X (Signed)
+
+ 2.w fedc ---- ---- ---- Number Of Tiles Along Y - 1
+ ---- b--- ---- ---- Flip Y
+ ---- -a-- ---- ----
+ ---- --98 7654 3210 Y (Signed)
+
+ 4.w fedc ---- ---- ---- Zoom X ($0 = Full Size, $F = Half Size)
+ ---- ba98 ---- ---- Zoom Y ""
+ ---- ---- 76-- ---- Priority
+ ---- ---- --54 3210 Color
+
+ 6.w fe-- ---- ---- ---- Tile Bank
+ --dc ba98 7654 3210 Tile Code
+
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ int max_x = machine->screen[0].visarea.max_x+1;
+ int max_y = machine->screen[0].visarea.max_y+1;
+
+ UINT32 *src = buffered_spriteram32_2; /* Use spriteram buffered by 2 frames, need palette buffered by one frame? */
+
+ /* Draw them backwards, for pdrawgfx */
+ for ( offs = (spriteram_size-8)/4; offs >=0; offs -= 8/4 )
+ {
+ int x, y, xstart, ystart, xend, yend, xinc, yinc;
+ int xnum, ynum, xzoom, yzoom, flipx, flipy;
+ int pri_mask;
+
+ int sx = (src[offs + 0]& 0xffff0000)>>16;
+ int sy = (src[offs + 0]& 0x0000ffff);
+ int attr = (src[offs + 1]& 0xffff0000)>>16;
+ int code = (src[offs + 1]& 0x0000ffff);
+
+ int bank = (code & 0xc000) >> 14;
+ int bank_lookedup;
+
+ bank_lookedup = ((spr_buffered_tilebank[1] & 0xffff0000)>>(16+bank*4))&0xf;
+ code &= 0x3fff;
+ code += bank_lookedup * 0x4000;
+
+ if (sx & 0x400) continue;
+
+ flipx = sx & 0x0800;
+ flipy = sy & 0x0800;
+
+ xnum = ((sx >> 12) & 0xf) + 1;
+ ynum = ((sy >> 12) & 0xf) + 1;
+
+ xzoom = 16*8 - (8 * ((attr >> 12) & 0xf))/2;
+ yzoom = 16*8 - (8 * ((attr >> 8) & 0xf))/2;
+
+ switch( (attr >> 6) & 3 )
+ {
+ case 3: pri_mask = 0xf0|0xcc|0xaa; break; // behind all layers
+ case 2: pri_mask = 0xf0|0xcc; break; // behind fg + middle layer
+ case 1: pri_mask = 0xf0; break; // behind fg layer
+ case 0:
+ default: pri_mask = 0; // above all
+ }
+
+ sx = (sx & 0x1ff) - (sx & 0x200);
+ sy = (sy & 0x1ff) - (sy & 0x200);
+
+ if (flip_screen)
+ { flipx = !flipx; sx = max_x - sx - xnum * 16;
+ flipy = !flipy; sy = max_y - sy - ynum * 16; }
+
+ if (flipx) { xstart = xnum-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = xnum; xinc = +1; }
+
+ if (flipy) { ystart = ynum-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = ynum; yinc = +1; }
+
+#if 0
+ if(!( (input_code_pressed(KEYCODE_V) && (((attr >> 6)&3) == 0))
+ || (input_code_pressed(KEYCODE_B) && (((attr >> 6)&3) == 1))
+ || (input_code_pressed(KEYCODE_N) && (((attr >> 6)&3) == 2))
+ || (input_code_pressed(KEYCODE_M) && (((attr >> 6)&3) == 3))
+ ))
+#endif
+
+ for (y = ystart; y != yend; y += yinc)
+ {
+ for (x = xstart; x != xend; x += xinc)
+ {
+ if (xzoom == (16*8) && yzoom == (16*8))
+ pdrawgfx( bitmap,machine->gfx[0],
+ code++,
+ attr & 0x3f,
+ flipx, flipy,
+ sx + x * 16, sy + y * 16,
+ cliprect,TRANSPARENCY_PEN,15,
+ pri_mask );
+ else
+ pdrawgfxzoom( bitmap,machine->gfx[0],
+ code++,
+ attr & 0x3f,
+ flipx, flipy,
+ sx + (x * xzoom) / 8, sy + (y * yzoom) / 8,
+ cliprect,TRANSPARENCY_PEN,15,
+ (0x10000/0x10/8) * (xzoom + 8),(0x10000/0x10/8) * (yzoom + 8), // nearest greater integer value to avoid holes
+ pri_mask );
+ }
+ }
+
+#ifdef MAME_DEBUG
+#if 0
+if (input_code_pressed(KEYCODE_X))
+{ /* Display some info on each sprite */
+ char buf[10];
+ sprintf(buf, "%Xx%X %X",xnum,ynum,(attr>>6)&3);
+ ui_draw_text(buf, sx, sy);
+}
+#endif
+#endif
+ }
+}
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+ Video Registers (fuuki32_vregs):
+
+ 00.w Layer 0 Scroll Y
+ 02.w Layer 0 Scroll X
+ 04.w Layer 1 Scroll Y
+ 06.w Layer 1 Scroll X
+ 08.w Layer 2 Scroll Y
+ 0a.w Layer 2 Scroll X
+ 0c.w Layers Y Offset
+ 0e.w Layers X Offset
+
+ 10-1a.w ? 0
+ 1c.w Trigger a level 5 irq on this raster line
+ 1e.w ? $3390/$3393 (Flip Screen Off/On), $0040 is buffer for tilemap 2 or 3
+
+ Priority Register (fuuki32_priority):
+
+ fedc ba98 7654 3---
+ ---- ---- ---- -210 Layer Order
+
+
+ Unknown Registers ($de0000.l):
+
+ 00.w ? $0200/$0201 (Flip Screen Off/On)
+ 02.w ? $f300/$0330
+
+***************************************************************************/
+
+/* Wrapper to handle bg and bg2 ttogether */
+static void fuuki32_draw_layer(mame_bitmap *bitmap, const rectangle *cliprect, int i, int flag, int pri)
+{
+ int buffer = ((fuuki32_vregs[0x1e/4]&0x0000ffff) & 0x40);
+
+ switch( i )
+ {
+ case 2: if (buffer) tilemap_draw(bitmap,cliprect,tilemap_3,flag,pri);
+ else tilemap_draw(bitmap,cliprect,tilemap_2,flag,pri);
+ return;
+ case 1: tilemap_draw(bitmap,cliprect,tilemap_1,flag,pri);
+ return;
+ case 0: tilemap_draw(bitmap,cliprect,tilemap_0,flag,pri);
+ return;
+ }
+}
+
+VIDEO_UPDATE( fuuki32 )
+{
+ UINT16 layer0_scrollx, layer0_scrolly;
+ UINT16 layer1_scrollx, layer1_scrolly;
+ UINT16 layer2_scrollx, layer2_scrolly;
+ UINT16 scrollx_offs, scrolly_offs;
+
+ /*
+ It's not independant bits causing layers to switch, that wouldn't make sense with 3 bits.
+ */
+
+ int tm_back, tm_middle, tm_front;
+ static const int pri_table[6][3] = {
+ { 0, 1, 2 }, // Special moves 0>1, 0>2 (0,1,2 or 0,2,1)
+ { 0, 2, 1 }, // Two Levels - 0>1 (0,1,2 or 0,2,1 or 2,0,1)
+ { 1, 0, 2 }, // Most Levels - 2>1 1>0 2>0 (1,0,2)
+ { 1, 2, 0 }, // Not used?
+ { 2, 0, 1 }, // Title etc. - 0>1 (0,1,2 or 0,2,1 or 2,0,1)
+ { 2, 1, 0 }}; // Char Select, prison stage 1>0 (leaves 1,2,0 or 2,1,0)
+
+ tm_front = pri_table[ (fuuki32_priority[0]>>16) & 0x0f ][0];
+ tm_middle = pri_table[ (fuuki32_priority[0]>>16) & 0x0f ][1];
+ tm_back = pri_table[ (fuuki32_priority[0]>>16) & 0x0f ][2];
+
+ flip_screen_set((fuuki32_vregs[0x1e/4]&0x0000ffff) & 1);
+
+ /* Layers scrolling */
+
+ scrolly_offs = ((fuuki32_vregs[0xc/4]&0xffff0000)>>16) - (flip_screen ? 0x103 : 0x1f3);
+ scrollx_offs = (fuuki32_vregs[0xc/4]&0x0000ffff) - (flip_screen ? 0x2c7 : 0x3f6);
+
+ layer0_scrolly = ((fuuki32_vregs[0x0/4]&0xffff0000)>>16) + scrolly_offs;
+ layer0_scrollx = ((fuuki32_vregs[0x0/4]&0x0000ffff)) + scrollx_offs;
+ layer1_scrolly = ((fuuki32_vregs[0x4/4]&0xffff0000)>>16) + scrolly_offs;
+ layer1_scrollx = ((fuuki32_vregs[0x4/4]&0x0000ffff)) + scrollx_offs;
+
+ layer2_scrolly = ((fuuki32_vregs[0x8/4]&0xffff0000)>>16);
+ layer2_scrollx = ((fuuki32_vregs[0x8/4]&0x0000ffff));
+
+ tilemap_set_scrollx(tilemap_0, 0, layer0_scrollx);
+ tilemap_set_scrolly(tilemap_0, 0, layer0_scrolly);
+ tilemap_set_scrollx(tilemap_1, 0, layer1_scrollx);
+ tilemap_set_scrolly(tilemap_1, 0, layer1_scrolly);
+
+ tilemap_set_scrollx(tilemap_2, 0, layer2_scrollx);
+ tilemap_set_scrolly(tilemap_2, 0, layer2_scrolly);
+ tilemap_set_scrollx(tilemap_3, 0, layer2_scrollx);
+ tilemap_set_scrolly(tilemap_3, 0, layer2_scrolly);
+
+ /* The bg colour is the last pen i.e. 0x1fff */
+ fillbitmap(bitmap,(0x800*4)-1,cliprect);
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ fuuki32_draw_layer(bitmap,cliprect, tm_back, 0, 1);
+ fuuki32_draw_layer(bitmap,cliprect, tm_middle, 0, 2);
+ fuuki32_draw_layer(bitmap,cliprect, tm_front, 0, 4);
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_EOF( fuuki32 )
+{
+ /* Buffer sprites and tilebank by 2 frames */
+
+ spr_buffered_tilebank[1] = spr_buffered_tilebank[0];
+ spr_buffered_tilebank[0] = fuuki32_tilebank[0];
+ memcpy(buffered_spriteram32_2,buffered_spriteram32,spriteram_size);
+ memcpy(buffered_spriteram32,spriteram32,spriteram_size);
+}
diff --git a/src/mame/video/gaelco.c b/src/mame/video/gaelco.c
new file mode 100644
index 00000000000..34802995472
--- /dev/null
+++ b/src/mame/video/gaelco.c
@@ -0,0 +1,254 @@
+/***************************************************************************
+
+ Gaelco Type 1 Video Hardware
+
+ Functions to emulate the video hardware of the machine
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *gaelco_vregs;
+UINT16 *gaelco_videoram;
+UINT16 *gaelco_spriteram;
+
+tilemap *gaelco_tilemap[2];
+#define pant gaelco_tilemap
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/*
+ Tile format
+ -----------
+
+ Screen 0 & 1: (32*32, 16x16 tiles)
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- -------x | flip x
+ 0 | -------- ------x- | flip y
+ 0 | xxxxxxxx xxxxxx-- | code
+ 1 | -------- --xxxxxx | color
+ 1 | -------- xx------ | priority
+ 1 | xxxxxxxx -------- | not used
+*/
+
+static TILE_GET_INFO( get_tile_info_gaelco_screen0 )
+{
+ int data = gaelco_videoram[tile_index << 1];
+ int data2 = gaelco_videoram[(tile_index << 1) + 1];
+ int code = ((data & 0xfffc) >> 2);
+
+ tileinfo->category = (data2 >> 6) & 0x03;
+
+ SET_TILE_INFO(1, 0x4000 + code, data2 & 0x3f, TILE_FLIPYX(data & 0x03));
+}
+
+
+static TILE_GET_INFO( get_tile_info_gaelco_screen1 )
+{
+ int data = gaelco_videoram[(0x1000/2) + (tile_index << 1)];
+ int data2 = gaelco_videoram[(0x1000/2) + (tile_index << 1) + 1];
+ int code = ((data & 0xfffc) >> 2);
+
+ tileinfo->category = (data2 >> 6) & 0x03;
+
+ SET_TILE_INFO(1, 0x4000 + code, data2 & 0x3f, TILE_FLIPYX(data & 0x03));
+}
+
+/***************************************************************************
+
+ Memory Handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( gaelco_vram_w )
+{
+ COMBINE_DATA(&gaelco_videoram[offset]);
+ tilemap_mark_tile_dirty(pant[offset >> 11],((offset << 1) & 0x0fff) >> 2);
+}
+
+/***************************************************************************
+
+ Start/Stop the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( bigkarnk )
+{
+ pant[0] = tilemap_create(get_tile_info_gaelco_screen0,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ pant[1] = tilemap_create(get_tile_info_gaelco_screen1,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ tilemap_set_transmask(pant[0],0,0xff01,0x00ff); /* pens 1-7 opaque, pens 0, 8-15 transparent */
+ tilemap_set_transmask(pant[1],0,0xff01,0x00ff); /* pens 1-7 opaque, pens 0, 8-15 transparent */
+}
+
+VIDEO_START( maniacsq )
+{
+ pant[0] = tilemap_create(get_tile_info_gaelco_screen0,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ pant[1] = tilemap_create(get_tile_info_gaelco_screen1,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ tilemap_set_transparent_pen(pant[0],0);
+ tilemap_set_transparent_pen(pant[1],0);
+}
+
+
+/***************************************************************************
+
+ Sprites
+
+***************************************************************************/
+
+/*
+ Sprite Format
+ -------------
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- xxxxxxxx | y position
+ 0 | -----xxx -------- | not used
+ 0 | ----x--- -------- | sprite size
+ 0 | --xx---- -------- | sprite priority
+ 0 | -x------ -------- | flipx
+ 0 | x------- -------- | flipy
+ 1 | xxxxxxxx xxxxxxxx | not used
+ 2 | -------x xxxxxxxx | x position
+ 2 | -xxxxxx- -------- | sprite color
+ 3 | -------- ------xx | sprite code (8x8 cuadrant)
+ 3 | xxxxxxxx xxxxxx-- | sprite code
+*/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int i, x, y, ex, ey;
+ const gfx_element *gfx = machine->gfx[0];
+
+ static int x_offset[2] = {0x0,0x2};
+ static int y_offset[2] = {0x0,0x1};
+
+ for (i = 0x800 - 4 - 1; i >= 3; i -= 4){
+ int sx = gaelco_spriteram[i+2] & 0x01ff;
+ int sy = (240 - (gaelco_spriteram[i] & 0x00ff)) & 0x00ff;
+ int number = gaelco_spriteram[i+3];
+ int color = (gaelco_spriteram[i+2] & 0x7e00) >> 9;
+ int attr = (gaelco_spriteram[i] & 0xfe00) >> 9;
+ int priority = (gaelco_spriteram[i] & 0x3000) >> 12;
+
+ int xflip = attr & 0x20;
+ int yflip = attr & 0x40;
+ int spr_size, pri_mask;
+
+ /* palettes 0x38-0x3f are used for high priority sprites in Big Karnak */
+ if (color >= 0x38){
+ priority = 4;
+ }
+
+ switch( priority )
+ {
+ case 0: pri_mask = 0xff00; break;
+ case 1: pri_mask = 0xff00|0xf0f0; break;
+ case 2: pri_mask = 0xff00|0xf0f0|0xcccc; break;
+ case 3: pri_mask = 0xff00|0xf0f0|0xcccc|0xaaaa; break;
+ default:
+ case 4: pri_mask = 0; break;
+ }
+
+ if (attr & 0x04){
+ spr_size = 1;
+ }
+ else{
+ spr_size = 2;
+ number &= (~3);
+ }
+
+ for (y = 0; y < spr_size; y++){
+ for (x = 0; x < spr_size; x++){
+
+ ex = xflip ? (spr_size-1-x) : x;
+ ey = yflip ? (spr_size-1-y) : y;
+
+ pdrawgfx(bitmap,gfx,number + x_offset[ex] + y_offset[ey],
+ color,xflip,yflip,
+ sx-0x0f+x*8,sy+y*8,
+ cliprect,TRANSPARENCY_PEN,0,pri_mask);
+ }
+ }
+ }
+}
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( maniacsq )
+{
+ /* set scroll registers */
+ tilemap_set_scrolly(pant[0], 0, gaelco_vregs[0]);
+ tilemap_set_scrollx(pant[0], 0, gaelco_vregs[1]+4);
+ tilemap_set_scrolly(pant[1], 0, gaelco_vregs[2]);
+ tilemap_set_scrollx(pant[1], 0, gaelco_vregs[3]);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap( bitmap, machine->pens[0], cliprect );
+
+ tilemap_draw(bitmap,cliprect,pant[1],3,0);
+ tilemap_draw(bitmap,cliprect,pant[0],3,0);
+
+ tilemap_draw(bitmap,cliprect,pant[1],2,1);
+ tilemap_draw(bitmap,cliprect,pant[0],2,1);
+
+ tilemap_draw(bitmap,cliprect,pant[1],1,2);
+ tilemap_draw(bitmap,cliprect,pant[0],1,2);
+
+ tilemap_draw(bitmap,cliprect,pant[1],0,4);
+ tilemap_draw(bitmap,cliprect,pant[0],0,4);
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( bigkarnk )
+{
+ /* set scroll registers */
+ tilemap_set_scrolly(pant[0], 0, gaelco_vregs[0]);
+ tilemap_set_scrollx(pant[0], 0, gaelco_vregs[1]+4);
+ tilemap_set_scrolly(pant[1], 0, gaelco_vregs[2]);
+ tilemap_set_scrollx(pant[1], 0, gaelco_vregs[3]);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap( bitmap, machine->pens[0], cliprect );
+
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER1 | 3,0);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER1 | 3,0);
+
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER0 | 3,1);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER0 | 3,1);
+
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER1 | 2,1);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER1 | 2,1);
+
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER0 | 2,2);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER0 | 2,2);
+
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER1 | 1,2);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER1 | 1,2);
+
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER0 | 1,4);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER0 | 1,4);
+
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER1 | 0,4);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER1 | 0,4);
+
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER0 | 0,8);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER0 | 0,8);
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/gaelco2.c b/src/mame/video/gaelco2.c
new file mode 100644
index 00000000000..fb74193927c
--- /dev/null
+++ b/src/mame/video/gaelco2.c
@@ -0,0 +1,510 @@
+/***************************************************************************
+
+ Gaelco Type CG-1V/GAE1 Video Hardware
+
+ Functions to emulate the video hardware of the machine
+
+ CG-1V/GAE1 (Gaelco custom GFX & Sound chip):
+ The CG-1V works with 16x16, 5 bpp gfx.
+ It can handle:
+ * 2 1024x512 tilemaps with linescroll.
+ * 2 banks of 512 sprites (sprites can be grouped up to 16x16).
+ Sprites can make the background darker or brighter.
+
+ Memory map:
+ ===========
+ 0x000000-0x000fff Sprite bank #1 (1)
+ 0x001000-0x001fff Sprite bank #2 (1)
+ 0x002000-0x0023ff Linescroll tilemap #1 (2)
+ 0x002400-0x0027ff Linescroll tilemap #2 (2)
+ Linescroll entries are like this:
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ i | xxxxxx-- -------- | not used?
+ i | ------xx xxxxxxxx | line i x scroll register
+
+ 0x002800-0x002807 Scroll registers
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | xxxxxxx- -------- | not used?
+ 0 | -------x xxxxxxxx | tilemap #1 y scroll register
+ 1 | xxxxxx-- -------- | not used?
+ 1 | ------xx xxxxxxxx | tilemap #1 x scroll register
+ 2 | xxxxxxx- -------- | not used?
+ 2 | -------x xxxxxxxx | tilemap #2 y scroll register
+ 3 | xxxxxx-- -------- | not used?
+ 3 | ------xx xxxxxxxx | tilemap #2 x scroll register
+ 0x002890-0x0028ff Sound registers (3)
+ 0x000000-0x00ffff Video RAM
+ 0x010000-0x011fff Palette (xRRRRRGGGGGBBBBB)
+ 0x018004-0x018007 Video Registers
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | x------- -------- | tilemap #1 linescroll enable
+ 0 | -xxx---- -------- | not used?
+ 0 | ----xxx- -------- | tilemap #1 video RAM bank? (4, 5)
+ 0 | -------x -------- | not used?
+ 0 | -------- x------- | unknown
+ 0 | -------- -x------ | not used?
+ 0 | -------- --xx---- | visible area size? (=0,480x240;=1,384x240;=2,320x240)
+ 0 | -------- ----xxxx | not used?
+ 1 | x------- -------- | tilemap #2 linescroll enable
+ 1 | -xxx---- -------- | not used?
+ 1 | ----xxx- -------- | tilemap #2 video RAM bank? (4, 5)
+ 1 | -------x xxx----- | not used?
+ 1 | -------- ---x---- | sprite bank select
+ 1 | -------- ----xxxx | not used?
+ 0x018008-0x018009 Clear video int?
+
+Notes:
+ (1) See sprite format in the sprite section
+ (2) x scroll register is not taken into account when doing line scroll
+ (3) See sound/gaelco.c for the sound register layout
+ (4) tilemaps use the memory [0x2000*bank .. 0x2000*bank + 0x1fff]
+ (5) See tile format in the tilemap section
+
+Multi monitor notes:
+ Some games have two RGB outputs to allow two or four simultaneous
+ players linking two cabinets (World Rally 2, Touch & Go).
+
+ In 2 monitors mode, the hardware maps one tilemap to a monitor and the
+ other tilemap to the other monitor. The game palette is splitted, using
+ the first half for one monitor and the second half for the other monitor.
+ The sprite RAM has one bit that selects the sprite's target monitor. The
+ sound is splitted too, right channel for cabinet 1 and the left channel
+ for the other cabinet.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *gaelco2_vregs;
+static UINT16 *gaelco2_videoram;
+
+/* tilemaps */
+static tilemap *pant[2];
+
+static int dual_monitor;
+
+/***************************************************************************
+
+ Callbacks for the TileMap code (single monitor games)
+
+ Tile format
+ -----------
+
+ Screen 0 & 1: (1024*512, 16x16 tiles)
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- -----xxx | code (bits 18-16)
+ 0 | -------- --xxx--- | not used?
+ 0 | -------- -x------ | flip y
+ 0 | -------- x------- | flip x
+ 0 | -------x -------- | not used?
+ 0 | xxxxxxx- -------- | color
+ 1 | xxxxxxxx xxxxxxxx | code (bits 15-0)
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info_gaelco2_screen0 )
+{
+ int data = gaelco2_videoram[(((gaelco2_vregs[0] >> 9) & 0x07)*0x2000/2) + (tile_index << 1)];
+ int data2 = gaelco2_videoram[(((gaelco2_vregs[0] >> 9) & 0x07)*0x2000/2) + ((tile_index << 1) + 1)];
+ int code = ((data & 0x07) << 16) | (data2 & 0xffff);
+
+ SET_TILE_INFO(0, code, ((data >> 9) & 0x7f), TILE_FLIPXY((data >> 6) & 0x03));
+}
+
+static TILE_GET_INFO( get_tile_info_gaelco2_screen1 )
+{
+ int data = gaelco2_videoram[(((gaelco2_vregs[1] >> 9) & 0x07)*0x2000/2) + (tile_index << 1)];
+ int data2 = gaelco2_videoram[(((gaelco2_vregs[1] >> 9) & 0x07)*0x2000/2) + ((tile_index << 1) + 1)];
+ int code = ((data & 0x07) << 16) | (data2 & 0xffff);
+
+ SET_TILE_INFO(0, code, ((data >> 9) & 0x7f), TILE_FLIPXY((data >> 6) & 0x03));
+}
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code (dual monitor games)
+
+ Tile format
+ -----------
+
+ Screen 0 & 1: (1024*512, 16x16 tiles)
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- -----xxx | code (bits 18-16)
+ 0 | -------- --xxx--- | not used?
+ 0 | -------- -x------ | flip y
+ 0 | -------- x------- | flip x
+ 0 | -------x -------- | not used?
+ 0 | -xxxxxx- -------- | color
+ 0 | x------- -------- | unknown
+ 1 | xxxxxxxx xxxxxxxx | code (bits 15-0)
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info_gaelco2_screen0_dual )
+{
+ int data = gaelco2_videoram[(((gaelco2_vregs[0] >> 9) & 0x07)*0x2000/2) + (tile_index << 1)];
+ int data2 = gaelco2_videoram[(((gaelco2_vregs[0] >> 9) & 0x07)*0x2000/2) + ((tile_index << 1) + 1)];
+ int code = ((data & 0x07) << 16) | (data2 & 0xffff);
+
+ SET_TILE_INFO(0, code, ((data >> 9) & 0x3f), TILE_FLIPXY((data >> 6) & 0x03));
+}
+
+static TILE_GET_INFO( get_tile_info_gaelco2_screen1_dual )
+{
+ int data = gaelco2_videoram[(((gaelco2_vregs[1] >> 9) & 0x07)*0x2000/2) + (tile_index << 1)];
+ int data2 = gaelco2_videoram[(((gaelco2_vregs[1] >> 9) & 0x07)*0x2000/2) + ((tile_index << 1) + 1)];
+ int code = ((data & 0x07) << 16) | (data2 & 0xffff);
+
+ SET_TILE_INFO(0, code, 0x40 + ((data >> 9) & 0x3f), TILE_FLIPXY((data >> 6) & 0x03));
+}
+
+
+/***************************************************************************
+
+ Memory Handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( gaelco2_vram_w )
+{
+ int pant0_start = ((gaelco2_vregs[0] >> 9) & 0x07)*0x1000;
+ int pant0_end = pant0_start + 0x1000;
+ int pant1_start = ((gaelco2_vregs[1] >> 9) & 0x07)*0x1000;
+ int pant1_end = pant1_start + 0x1000;
+
+ COMBINE_DATA(&gaelco2_videoram[offset]);
+
+ /* tilemap 0 writes */
+ if ((offset >= pant0_start) && (offset < pant0_end)){
+ tilemap_mark_tile_dirty(pant[0], ((offset << 1) & 0x1fff) >> 2);
+ }
+
+ /* tilemap 1 writes */
+ if ((offset >= pant1_start) && (offset < pant1_end)){
+ tilemap_mark_tile_dirty(pant[1], ((offset << 1) & 0x1fff) >> 2);
+ }
+}
+
+/***************************************************************************
+
+ Palette (paletteram16_xRRRRRGGGGGBBBBB_word_w)
+
+ The game's palette uses colors 0-4095, but we need 15 aditional palettes
+ to handle shadows and highlights properly. After a color write to the
+ game's palette we update the other palettes with a darker/brighter color.
+
+ Sprites use last palette entry for shadows and highlights
+ (in order to make some pixels darker or brighter).
+
+ The sprite's pens define the color adjustment:
+
+ 0x00 -> Transparent
+ 0x01-0x07 -> Shadow level (0x01 = min, 0x07 = max)
+ 0x08-0x0f -> Highlight level (0x08 = max, 0x0f = min)
+ 0x10-0x1f -> not used?
+
+***************************************************************************/
+
+#define RGB_CHG 0x08
+#define ADJUST_COLOR(c) ((c < 0) ? 0 : ((c > 255) ? 255 : c))
+
+/* table used for color adjustment */
+static int pen_color_adjust[16] = {
+ +RGB_CHG*0, -RGB_CHG*1, -RGB_CHG*2, -RGB_CHG*3, -RGB_CHG*4, -RGB_CHG*5, -RGB_CHG*6, -RGB_CHG*7,
+ +RGB_CHG*8, +RGB_CHG*7, +RGB_CHG*6, +RGB_CHG*5, +RGB_CHG*4, +RGB_CHG*3, +RGB_CHG*2, +RGB_CHG*1
+};
+
+
+WRITE16_HANDLER( gaelco2_palette_w )
+{
+ int i, color, r, g, b, auxr, auxg, auxb;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ color = paletteram16[offset];
+
+ /* extract RGB components */
+ r = (color >> 10) & 0x1f;
+ g = (color >> 5) & 0x1f;
+ b = (color >> 0) & 0x1f;
+
+ r = pal5bit(r);
+ g = pal5bit(g);
+ b = pal5bit(b);
+
+ /* update game palette */
+ palette_set_color(Machine, 4096*0 + offset, MAKE_RGB(r, g, b));
+
+ /* update shadow/highligh palettes */
+ for (i = 1; i < 16; i++){
+ /* because the last palette entry is reserved for shadows and highlights, we
+ don't use it and that way we save some colors so the UI looks fine ;-) */
+ if ((offset >= 0xff0) && (offset <= 0xfff)) return;
+
+ auxr = ADJUST_COLOR(r + pen_color_adjust[i]);
+ auxg = ADJUST_COLOR(g + pen_color_adjust[i]);
+ auxb = ADJUST_COLOR(b + pen_color_adjust[i]);
+
+ palette_set_color(Machine, 4096*i + offset, MAKE_RGB(auxr, auxg, auxb));
+ }
+}
+
+/***************************************************************************
+
+ Start/Stop the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( gaelco2 )
+{
+ gaelco2_videoram = spriteram16;
+
+ /* create tilemaps */
+ pant[0] = tilemap_create(get_tile_info_gaelco2_screen0,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pant[1] = tilemap_create(get_tile_info_gaelco2_screen1,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+
+ /* set tilemap properties */
+ tilemap_set_transparent_pen(pant[0],0);
+ tilemap_set_transparent_pen(pant[1],0);
+
+ tilemap_set_scroll_rows(pant[0], 512);
+ tilemap_set_scroll_cols(pant[0], 1);
+ tilemap_set_scroll_rows(pant[1], 512);
+ tilemap_set_scroll_cols(pant[1], 1);
+
+ dual_monitor = 0;
+}
+
+VIDEO_START( gaelco2_dual )
+{
+ gaelco2_videoram = spriteram16;
+
+ /* create tilemaps */
+ pant[0] = tilemap_create(get_tile_info_gaelco2_screen0_dual,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pant[1] = tilemap_create(get_tile_info_gaelco2_screen1_dual,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+
+ /* set tilemap properties */
+ tilemap_set_transparent_pen(pant[0],0);
+ tilemap_set_transparent_pen(pant[1],0);
+
+ tilemap_set_scroll_rows(pant[0], 512);
+ tilemap_set_scroll_cols(pant[0], 1);
+ tilemap_set_scroll_rows(pant[1], 512);
+ tilemap_set_scroll_cols(pant[1], 1);
+
+ dual_monitor = 1;
+}
+
+/***************************************************************************
+
+ Sprite Format
+ -------------
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------x xxxxxxxx | sprite bank (sprite number bits 18-10)
+ 0 | xxxxxxx- -------- | sprite color (bits 6-0)
+ 1 | -------x xxxxxxxx | y position
+ 1 | ------x- -------- | sprite enable
+ 1 | -----x-- -------- | flipy
+ 1 | ----x--- -------- | flipx
+ 1 | xxxx---- -------- | sprite y size
+ 2 | ------xx xxxxxxxx | x position
+ 2 | ----xx-- -------- | not used?
+ 2 | xxxx---- -------- | sprite x size
+ 3 | xxxxxxxx xxxxxxxx | pointer to more sprite data
+
+ Each sprite entry has a pointer to more sprite data.
+ The length of data depends on the sprite size (xsize*ysize).
+ Each entry has the following format:
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | ----xxxx xxxxxxxx | sprite number offset (sprite number bits 11-0)
+ 0 | xxxx---- -------- | sprite color offset (bits 3-0)
+
+ In dual monitor games, the configuration is the same, but MSB of
+ word 0 is used to select target monitor for the sprite, and the
+ palette is splitted for each monitor.
+
+ Last sprite color entry is used for shadows/highlights
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int mask, int xoffs)
+{
+ int j, x, y, ex, ey, px, py;
+ const gfx_element *gfx = machine->gfx[0];
+
+ /* get sprite ram start and end offsets */
+ int start_offset = (gaelco2_vregs[1] & 0x10)*0x100;
+ int end_offset = start_offset + 0x1000;
+
+ /* sprite offset is based on the visible area */
+ int spr_x_adjust = (machine->screen[0].visarea.max_x - 320 + 1) - (511 - 320 - 1) - ((gaelco2_vregs[0] >> 4) & 0x01) + xoffs;
+
+ for (j = start_offset; j < end_offset; j += 8){
+ int data = buffered_spriteram16[(j/2) + 0];
+ int data2 = buffered_spriteram16[(j/2) + 1];
+ int data3 = buffered_spriteram16[(j/2) + 2];
+ int data4 = buffered_spriteram16[(j/2) + 3];
+
+ int sx = data3 & 0x3ff;
+ int sy = data2 & 0x1ff;
+
+ int xflip = data2 & 0x800;
+ int yflip = data2 & 0x400;
+
+ int xsize = ((data3 >> 12) & 0x0f) + 1;
+ int ysize = ((data2 >> 12) & 0x0f) + 1;
+
+ if (dual_monitor && ((data & 0x8000) != mask)) continue;
+
+ /* if it's enabled, draw it */
+ if ((data2 & 0x0200) != 0){
+ for (y = 0; y < ysize; y++){
+ for (x = 0; x < xsize; x++){
+ /* for each x,y of the sprite, fetch the sprite data */
+ int data5 = buffered_spriteram16[((data4/2) + (y*xsize + x)) & 0x7fff];
+ int number = ((data & 0x1ff) << 10) + (data5 & 0x0fff);
+ int color = ((data >> 9) & 0x7f) + ((data5 >> 12) & 0x0f);
+ int color_effect = dual_monitor ? ((color & 0x3f) == 0x3f) : (color == 0x7f);
+
+ ex = xflip ? (xsize - 1 - x) : x;
+ ey = yflip ? (ysize - 1 - y) : y;
+
+ /* normal sprite, pen 0 transparent */
+ if (color_effect == 0){
+ drawgfx(bitmap, gfx, number,
+ color, xflip, yflip,
+ ((sx + ex*16) & 0x3ff) + spr_x_adjust,
+ ((sy + ey*16) & 0x1ff),
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ } else { /* last palette entry is reserved for shadows and highlights */
+
+ /* get a pointer to the current sprite's gfx data */
+ UINT8 *gfx_src = gfx->gfxdata + (number % gfx->total_elements)*gfx->char_modulo;
+
+ for (py = 0; py < gfx->height; py++){
+ /* get a pointer to the current line in the screen bitmap */
+ int ypos = ((sy + ey*16 + py) & 0x1ff);
+ UINT16 *srcy = BITMAP_ADDR16(bitmap, ypos, 0);
+
+ int gfx_py = yflip ? (gfx->height - 1 - py) : py;
+
+ if ((ypos < cliprect->min_y) || (ypos > cliprect->max_y)) continue;
+
+ for (px = 0; px < gfx->width; px++){
+ /* get current pixel */
+ int xpos = (((sx + ex*16 + px) & 0x3ff) + spr_x_adjust) & 0x3ff;
+ UINT16 *pixel = srcy + xpos;
+ int src_color = *pixel;
+
+ int gfx_px = xflip ? (gfx->width - 1 - px) : px;
+
+ /* get asociated pen for the current sprite pixel */
+ int gfx_pen = gfx_src[gfx->line_modulo*gfx_py + gfx_px];
+
+ if ((gfx_pen == 0) || (gfx_pen >= 16)) continue;
+
+ if ((xpos < cliprect->min_x) || (xpos > cliprect->max_x)) continue;
+
+ /* make background color darker or brighter */
+ *pixel = src_color + 4096*gfx_pen;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( gaelco2 )
+{
+ int i;
+
+ /* read scroll values */
+ int scroll0x = gaelco2_videoram[0x2802/2] + 0x14;
+ int scroll1x = gaelco2_videoram[0x2806/2] + 0x10;
+ int scroll0y = gaelco2_videoram[0x2800/2] + 0x01;
+ int scroll1y = gaelco2_videoram[0x2804/2] + 0x01;
+
+ /* set y scroll registers */
+ tilemap_set_scrolly(pant[0], 0, scroll0y & 0x1ff);
+ tilemap_set_scrolly(pant[1], 0, scroll1y & 0x1ff);
+
+ /* set x linescroll registers */
+ for (i = 0; i < 512; i++){
+ tilemap_set_scrollx(pant[0], i & 0x1ff, (gaelco2_vregs[0] & 0x8000) ? (gaelco2_videoram[(0x2000/2) + i] + 0x14) & 0x3ff : scroll0x & 0x3ff);
+ tilemap_set_scrollx(pant[1], i & 0x1ff, (gaelco2_vregs[1] & 0x8000) ? (gaelco2_videoram[(0x2400/2) + i] + 0x10) & 0x3ff : scroll1x & 0x3ff);
+ }
+
+ /* draw screen */
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ tilemap_draw(bitmap, cliprect, pant[1], 0, 0);
+ tilemap_draw(bitmap, cliprect, pant[0], 0, 0);
+ draw_sprites(machine, bitmap, cliprect, 0, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( gaelco2_dual )
+{
+ int i;
+
+ /* read scroll values */
+ int scroll0x = gaelco2_videoram[0x2802/2] + 0x14;
+ int scroll1x = gaelco2_videoram[0x2806/2] + 0x10;
+ int scroll0y = gaelco2_videoram[0x2800/2] + 0x01;
+ int scroll1y = gaelco2_videoram[0x2804/2] + 0x01;
+
+ /* set y scroll registers */
+ tilemap_set_scrolly(pant[0], 0, scroll0y & 0x1ff);
+ tilemap_set_scrolly(pant[1], 0, scroll1y & 0x1ff);
+
+ /* set x linescroll registers */
+ for (i = 0; i < 512; i++){
+ tilemap_set_scrollx(pant[0], i & 0x1ff, (gaelco2_vregs[0] & 0x8000) ? (gaelco2_videoram[(0x2000/2) + i] + 0x14) & 0x3ff : scroll0x & 0x3ff);
+ tilemap_set_scrollx(pant[1], i & 0x1ff, (gaelco2_vregs[1] & 0x8000) ? (gaelco2_videoram[(0x2400/2) + i] + 0x10) & 0x3ff : scroll1x & 0x3ff);
+ }
+
+ /* draw screen */
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ if (screen==1)
+ {
+ /* monitor 2 output */
+ tilemap_draw(bitmap,cliprect,pant[1], 0, 0);
+ draw_sprites(machine,bitmap,cliprect, 0x8000, 0);
+ }
+ else if (screen==0)
+ {
+ /* monitor 1 output */
+ tilemap_draw(bitmap,cliprect,pant[0], 0, 0);
+ draw_sprites(machine,bitmap,cliprect, 0x0000, 0);
+ }
+
+ return 0;
+}
+
+
+VIDEO_EOF( gaelco2 )
+{
+ /* sprites are one frame ahead */
+ buffer_spriteram16_w(0, 0, 0);
+}
diff --git a/src/mame/video/gaelco3d.c b/src/mame/video/gaelco3d.c
new file mode 100644
index 00000000000..d346236242c
--- /dev/null
+++ b/src/mame/video/gaelco3d.c
@@ -0,0 +1,535 @@
+/*************************************************************************
+
+ Driver for Gaelco 3D games
+
+ driver by Aaron Giles
+
+**************************************************************************/
+
+#include "driver.h"
+#include "eminline.h"
+#include "gaelco3d.h"
+#include "video/rgbutil.h"
+#include "video/poly.h"
+
+UINT8 *gaelco3d_texture;
+UINT8 *gaelco3d_texmask;
+UINT32 gaelco3d_texture_size;
+UINT32 gaelco3d_texmask_size;
+
+
+#define MAX_POLYGONS 4096
+#define MAX_POLYDATA (MAX_POLYGONS * 21)
+#define MAX_VERTICES 32
+
+#define DISPLAY_TEXTURE 0
+#define LOG_POLYGONS 0
+#define DISPLAY_STATS 0
+
+#define IS_POLYEND(x) (((x) ^ ((x) >> 1)) & 0x4000)
+
+
+static mame_bitmap *screenbits;
+static mame_bitmap *zbuffer;
+static rgb_t *palette;
+static UINT32 *polydata_buffer;
+static UINT32 polydata_count;
+
+static int polygons;
+static int lastscan;
+static int video_changed;
+
+static poly_manager *poly;
+
+
+typedef struct _poly_extra_data poly_extra_data;
+struct _poly_extra_data
+{
+ UINT32 tex, color;
+ float ooz_dx, ooz_dy, ooz_base;
+ float uoz_dx, uoz_dy, uoz_base;
+ float voz_dx, voz_dy, voz_base;
+ float z0;
+};
+
+
+static void render_noz_noperspective(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid);
+static void render_normal(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid);
+static void render_alphablend(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid);
+
+
+
+/*************************************
+ *
+ * Video init
+ *
+ *************************************/
+
+static void gaelco3d_exit(running_machine *machine)
+{
+ poly_free(poly);
+}
+
+
+VIDEO_START( gaelco3d )
+{
+ poly = poly_alloc(2000, sizeof(poly_extra_data), 0);
+ add_exit_callback(machine, gaelco3d_exit);
+
+ screenbits = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ zbuffer = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+
+ palette = auto_malloc(32768 * sizeof(palette[0]));
+ polydata_buffer = auto_malloc(MAX_POLYDATA * sizeof(polydata_buffer[0]));
+
+ /* save states */
+
+ state_save_register_global_pointer(palette, 32768);
+ state_save_register_global_pointer(polydata_buffer, MAX_POLYDATA);
+ state_save_register_global(polydata_count);
+
+ state_save_register_global(polygons);
+ state_save_register_global(lastscan);
+
+ state_save_register_bitmap("video", 0, "screenbits", screenbits);
+ state_save_register_bitmap("video", 0, "zbuffer", zbuffer);
+}
+
+
+
+/*************************************
+ *
+ * TMS32031 floating point conversion
+ *
+ *************************************/
+
+typedef union int_double
+{
+ double d;
+ float f[2];
+ UINT32 i[2];
+} int_double;
+
+
+static float dsp_to_float(UINT32 val)
+{
+ INT32 _mantissa = val << 8;
+ INT8 _exponent = (INT32)val >> 24;
+ int_double id;
+
+ if (_mantissa == 0 && _exponent == -128)
+ return 0;
+ else if (_mantissa >= 0)
+ {
+ int exponent = (_exponent + 127) << 23;
+ id.i[0] = exponent + (_mantissa >> 8);
+ }
+ else
+ {
+ int exponent = (_exponent + 127) << 23;
+ INT32 man = -_mantissa;
+ id.i[0] = 0x80000000 + exponent + ((man >> 8) & 0x00ffffff);
+ }
+ return id.f[0];
+}
+
+
+/*************************************
+ *
+ * Polygon rendering
+ *
+ *************************************/
+
+/*
+ Polygon data stream format:
+
+ data[0] (float) = scale factor to map Z to fixed Z buffer value
+ data[1] (float) = dvoz/dy (change in v/z per Y)
+ data[2] (float) = dvoz/dx (change in v/z per X)
+ data[3] (float) = dooz/dy (change in 1/z per Y)
+ data[4] (float) = dooz/dx (change in 1/z per X)
+ data[5] (float) = duoz/dy (change in u/z per Y)
+ data[6] (float) = duoz/dx (change in u/z per X)
+ data[7] (float) = voz origin (value of v/z at coordinate (0,0))
+ data[8] (float) = ooz origin (value of 1/z at coordinate (0,0))
+ data[9] (float) = uoz origin (value of u/z at coordinate (0,0))
+ data[10] (int) = palette base (bits 14-8)
+ data[11] (int) = texture address
+ data[12] (int) = start point (bits 15-8 = X coordinate, bits 12-0 = Y coordinate)
+ data[13] (int) = next point (bits 15-8 = X coordinate, bits 12-0 = Y coordinate)
+ data[14] (int) = 16.16 dx/dy from previous point to this point
+ (repeat these two for each additional point in the fan)
+*/
+
+static void render_poly(UINT32 *polydata)
+{
+ float midx = Machine->screen[0].width / 2;
+ float midy = Machine->screen[0].height / 2;
+ float z0 = dsp_to_float(polydata[0]);
+ float voz_dy = dsp_to_float(polydata[1]) * 256.0f;
+ float voz_dx = dsp_to_float(polydata[2]) * 256.0f;
+ float ooz_dy = dsp_to_float(polydata[3]);
+ float ooz_dx = dsp_to_float(polydata[4]);
+ float uoz_dy = dsp_to_float(polydata[5]) * 256.0f;
+ float uoz_dx = dsp_to_float(polydata[6]) * 256.0f;
+ float voz_base = dsp_to_float(polydata[7]) * 256.0f - midx * voz_dx - midy * voz_dy;
+ float ooz_base = dsp_to_float(polydata[8]) - midx * ooz_dx - midy * ooz_dy;
+ float uoz_base = dsp_to_float(polydata[9]) * 256.0f - midx * uoz_dx - midy * uoz_dy;
+ poly_extra_data *extra = poly_get_extra_data(poly);
+ int color = (polydata[10] & 0x7f) << 8;
+ poly_vertex vert[MAX_VERTICES];
+ UINT32 data;
+ int vertnum;
+
+ if (LOG_POLYGONS)
+ {
+ int t;
+ logerror("poly: %12.2f %12.2f %12.2f %12.2f %12.2f %12.2f %12.2f %12.2f %12.2f %12.2f %08X %08X (%4d,%4d) %08X",
+ (double)dsp_to_float(polydata[0]),
+ (double)dsp_to_float(polydata[1]),
+ (double)dsp_to_float(polydata[2]),
+ (double)dsp_to_float(polydata[3]),
+ (double)dsp_to_float(polydata[4]),
+ (double)dsp_to_float(polydata[5]),
+ (double)dsp_to_float(polydata[6]),
+ (double)dsp_to_float(polydata[7]),
+ (double)dsp_to_float(polydata[8]),
+ (double)dsp_to_float(polydata[9]),
+ polydata[10],
+ polydata[11],
+ (INT16)(polydata[12] >> 16), (INT16)(polydata[12] << 2) >> 2, polydata[12]);
+
+ logerror(" (%4d,%4d) %08X %08X", (INT16)(polydata[13] >> 16), (INT16)(polydata[13] << 2) >> 2, polydata[13], polydata[14]);
+ for (t = 15; !IS_POLYEND(polydata[t - 2]); t += 2)
+ logerror(" (%4d,%4d) %08X %08X", (INT16)(polydata[t] >> 16), (INT16)(polydata[t] << 2) >> 2, polydata[t], polydata[t+1]);
+ logerror("\n");
+ }
+
+ /* fill in extra data */
+ extra->tex = polydata[11];
+ extra->color = color;
+ extra->ooz_dx = ooz_dx;
+ extra->ooz_dy = ooz_dy;
+ extra->ooz_base = ooz_base;
+ extra->uoz_dx = uoz_dx;
+ extra->uoz_dy = uoz_dy;
+ extra->uoz_base = uoz_base;
+ extra->voz_dx = voz_dx;
+ extra->voz_dy = voz_dy;
+ extra->voz_base = voz_base;
+ extra->z0 = z0;
+
+ /* extract vertices */
+ data = 0;
+ for (vertnum = 0; vertnum < ARRAY_LENGTH(vert) && !IS_POLYEND(data); vertnum++)
+ {
+ /* extract vertex data */
+ data = polydata[13 + vertnum * 2];
+ vert[vertnum].x = midx + (float)((INT32)data >> 16) + 0.5f;
+ vert[vertnum].y = midy + (float)((INT32)(data << 18) >> 18) + 0.5f;
+ }
+
+ /* if we have a valid number of verts, render them */
+ if (vertnum >= 3)
+ {
+ /* special case: no Z buffering and no perspective correction */
+ if (color != 0x7f00 && z0 < 0 && ooz_dx == 0 && ooz_dy == 0)
+ poly_render_triangle_fan(poly, screenbits, &Machine->screen[0].visarea, render_noz_noperspective, 0, vertnum, &vert[0]);
+
+ /* general case: non-alpha blended */
+ else if (color != 0x7f00)
+ poly_render_triangle_fan(poly, screenbits, &Machine->screen[0].visarea, render_normal, 0, vertnum, &vert[0]);
+
+ /* color 0x7f seems to be hard-coded as a 50% alpha blend */
+ else
+ poly_render_triangle_fan(poly, screenbits, &Machine->screen[0].visarea, render_alphablend, 0, vertnum, &vert[0]);
+
+ polygons += vertnum - 2;
+ }
+}
+
+
+
+static void render_noz_noperspective(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ mame_bitmap *bitmap = destbase;
+ float zbase = recip_approx(extra->ooz_base);
+ float uoz_step = extra->uoz_dx * zbase;
+ float voz_step = extra->voz_dx * zbase;
+ int zbufval = (int)(-extra->z0 * zbase);
+ offs_t endmask = gaelco3d_texture_size - 1;
+ const rgb_t *palsource = palette + extra->color;
+ UINT32 tex = extra->tex;
+ UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0);
+ UINT16 *zbuf = BITMAP_ADDR16(zbuffer, scanline, 0);
+ int startx = extent->startx;
+ float uoz = (extra->uoz_base + scanline * extra->uoz_dy + startx * extra->uoz_dx) * zbase;
+ float voz = (extra->voz_base + scanline * extra->voz_dy + startx * extra->voz_dx) * zbase;
+ int x;
+
+ for (x = startx; x < extent->stopx; x++)
+ {
+ int u = (int)uoz;
+ int v = (int)voz;
+ int pixeloffs = (tex + (v >> 8) * 4096 + (u >> 8)) & endmask;
+ if (pixeloffs >= gaelco3d_texmask_size || !gaelco3d_texmask[pixeloffs])
+ {
+ rgb_t rgb00 = palsource[gaelco3d_texture[pixeloffs]];
+ rgb_t rgb01 = palsource[gaelco3d_texture[(pixeloffs + 1) & endmask]];
+ rgb_t rgb10 = palsource[gaelco3d_texture[(pixeloffs + 4096) & endmask]];
+ rgb_t rgb11 = palsource[gaelco3d_texture[(pixeloffs + 4097) & endmask]];
+ rgb_t filtered = rgb_bilinear_filter(rgb00, rgb01, rgb10, rgb11, u, v);
+ dest[x] = (filtered & 0x1f) | ((filtered & 0x1ff800) >> 6);
+ zbuf[x] = zbufval;
+ }
+
+ /* advance texture params to the next pixel */
+ uoz += uoz_step;
+ voz += voz_step;
+ }
+}
+
+
+static void render_normal(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ mame_bitmap *bitmap = destbase;
+ float ooz_dx = extra->ooz_dx;
+ float uoz_dx = extra->uoz_dx;
+ float voz_dx = extra->voz_dx;
+ offs_t endmask = gaelco3d_texture_size - 1;
+ const rgb_t *palsource = palette + extra->color;
+ UINT32 tex = extra->tex;
+ float z0 = extra->z0;
+ UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0);
+ UINT16 *zbuf = BITMAP_ADDR16(zbuffer, scanline, 0);
+ int startx = extent->startx;
+ float ooz = extra->ooz_base + scanline * extra->ooz_dy + startx * ooz_dx;
+ float uoz = extra->uoz_base + scanline * extra->uoz_dy + startx * uoz_dx;
+ float voz = extra->voz_base + scanline * extra->voz_dy + startx * voz_dx;
+ int x;
+
+ for (x = startx; x < extent->stopx; x++)
+ {
+ if (ooz > 0)
+ {
+ /* compute Z and check the Z buffer value first */
+ float z = recip_approx(ooz);
+ int zbufval = (int)(z0 * z);
+ if (zbufval < zbuf[x])
+ {
+ int u = (int)(uoz * z);
+ int v = (int)(voz * z);
+ int pixeloffs = (tex + (v >> 8) * 4096 + (u >> 8)) & endmask;
+ if (pixeloffs >= gaelco3d_texmask_size || !gaelco3d_texmask[pixeloffs])
+ {
+ rgb_t rgb00 = palsource[gaelco3d_texture[pixeloffs]];
+ rgb_t rgb01 = palsource[gaelco3d_texture[(pixeloffs + 1) & endmask]];
+ rgb_t rgb10 = palsource[gaelco3d_texture[(pixeloffs + 4096) & endmask]];
+ rgb_t rgb11 = palsource[gaelco3d_texture[(pixeloffs + 4097) & endmask]];
+ rgb_t filtered = rgb_bilinear_filter(rgb00, rgb01, rgb10, rgb11, u, v);
+ dest[x] = (filtered & 0x1f) | ((filtered & 0x1ff800) >> 6);
+ zbuf[x] = (zbufval < 0) ? -zbufval : zbufval;
+ }
+ }
+ }
+
+ /* advance texture params to the next pixel */
+ ooz += ooz_dx;
+ uoz += uoz_dx;
+ voz += voz_dx;
+ }
+}
+
+
+static void render_alphablend(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ mame_bitmap *bitmap = destbase;
+ float ooz_dx = extra->ooz_dx;
+ float uoz_dx = extra->uoz_dx;
+ float voz_dx = extra->voz_dx;
+ offs_t endmask = gaelco3d_texture_size - 1;
+ const rgb_t *palsource = palette + extra->color;
+ UINT32 tex = extra->tex;
+ float z0 = extra->z0;
+ UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0);
+ UINT16 *zbuf = BITMAP_ADDR16(zbuffer, scanline, 0);
+ int startx = extent->startx;
+ float ooz = extra->ooz_base + extra->ooz_dy * scanline + startx * ooz_dx;
+ float uoz = extra->uoz_base + extra->uoz_dy * scanline + startx * uoz_dx;
+ float voz = extra->voz_base + extra->voz_dy * scanline + startx * voz_dx;
+ int x;
+
+ for (x = startx; x < extent->stopx; x++)
+ {
+ if (ooz > 0)
+ {
+ /* compute Z and check the Z buffer value first */
+ float z = recip_approx(ooz);
+ int zbufval = (int)(z0 * z);
+ if (zbufval < zbuf[x])
+ {
+ int u = (int)(uoz * z);
+ int v = (int)(voz * z);
+ int pixeloffs = (tex + (v >> 8) * 4096 + (u >> 8)) & endmask;
+ if (pixeloffs >= gaelco3d_texmask_size || !gaelco3d_texmask[pixeloffs])
+ {
+ rgb_t rgb00 = palsource[gaelco3d_texture[pixeloffs]];
+ rgb_t rgb01 = palsource[gaelco3d_texture[(pixeloffs + 1) & endmask]];
+ rgb_t rgb10 = palsource[gaelco3d_texture[(pixeloffs + 4096) & endmask]];
+ rgb_t rgb11 = palsource[gaelco3d_texture[(pixeloffs + 4097) & endmask]];
+ rgb_t filtered = rgb_bilinear_filter(rgb00, rgb01, rgb10, rgb11, u, v) >> 1;
+ dest[x] = ((filtered & 0x0f) | ((filtered & 0x0f7800) >> 6)) + ((dest[x] >> 1) & 0x3def);
+ zbuf[x] = (zbufval < 0) ? -zbufval : zbufval;
+ }
+ }
+ }
+
+ /* advance texture params to the next pixel */
+ ooz += ooz_dx;
+ uoz += uoz_dx;
+ voz += voz_dx;
+ }
+}
+
+
+/*************************************
+ *
+ * Scene rendering
+ *
+ *************************************/
+
+void gaelco3d_render(void)
+{
+ /* wait for any queued stuff to complete */
+ poly_wait(poly, "Time to render");
+
+#if DISPLAY_STATS
+{
+ int scan = video_screen_get_vpos(0);
+ popmessage("Polys = %4d Timeleft = %3d", polygons, (lastscan < scan) ? (scan - lastscan) : (scan + (lastscan - Machine->screen[0].visarea.max_y)));
+}
+#endif
+
+ polydata_count = 0;
+ polygons = 0;
+ lastscan = -1;
+}
+
+
+
+/*************************************
+ *
+ * Renderer access
+ *
+ *************************************/
+
+WRITE32_HANDLER( gaelco3d_render_w )
+{
+ /* append the data to our buffer */
+ polydata_buffer[polydata_count++] = data;
+ if (polydata_count >= MAX_POLYDATA)
+ fatalerror("Out of polygon buffer space!");
+
+ /* if we've accumulated a completed poly set of data, queue it */
+ if (!video_skip_this_frame())
+ {
+ if (polydata_count >= 18 && (polydata_count % 2) == 1 && IS_POLYEND(polydata_buffer[polydata_count - 2]))
+ {
+ render_poly(&polydata_buffer[0]);
+ polydata_count = 0;
+ }
+ video_changed = TRUE;
+ }
+
+#if DISPLAY_STATS
+ lastscan = video_screen_get_vpos(0);
+#endif
+}
+
+
+
+/*************************************
+ *
+ * Palette access
+ *
+ *************************************/
+
+WRITE16_HANDLER( gaelco3d_paletteram_w )
+{
+ poly_wait(poly, "Palette change");
+ COMBINE_DATA(&paletteram16[offset]);
+ palette[offset] = ((paletteram16[offset] & 0x7fe0) << 6) | (paletteram16[offset] & 0x1f);
+}
+
+
+WRITE32_HANDLER( gaelco3d_paletteram_020_w )
+{
+ poly_wait(poly, "Palette change");
+ COMBINE_DATA(&paletteram32[offset]);
+ palette[offset*2+0] = ((paletteram32[offset] & 0x7fe00000) >> 10) | ((paletteram32[offset] & 0x1f0000) >> 16);
+ palette[offset*2+1] = ((paletteram32[offset] & 0x7fe0) << 6) | (paletteram32[offset] & 0x1f);
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( gaelco3d )
+{
+ int x, y, ret;
+
+ if (DISPLAY_TEXTURE && (input_code_pressed(KEYCODE_Z) || input_code_pressed(KEYCODE_X)))
+ {
+ static int xv = 0, yv = 0x1000;
+ UINT8 *base = gaelco3d_texture;
+ int length = gaelco3d_texture_size;
+
+ if (input_code_pressed(KEYCODE_X))
+ {
+ base = gaelco3d_texmask;
+ length = gaelco3d_texmask_size;
+ }
+
+ if (input_code_pressed(KEYCODE_LEFT) && xv >= 4)
+ xv -= 4;
+ if (input_code_pressed(KEYCODE_RIGHT) && xv < 4096 - 4)
+ xv += 4;
+
+ if (input_code_pressed(KEYCODE_UP) && yv >= 4)
+ yv -= 4;
+ if (input_code_pressed(KEYCODE_DOWN) && yv < 0x40000)
+ yv += 4;
+
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ int offs = (yv + y - cliprect->min_y) * 4096 + xv + x - cliprect->min_x;
+ if (offs < length)
+ dest[x] = base[offs];
+ else
+ dest[x] = 0;
+ }
+ }
+ popmessage("(%04X,%04X)", xv, yv);
+ }
+ else
+ {
+ if (video_changed)
+ copybitmap(bitmap, screenbits, 0,1, 0,0, cliprect, TRANSPARENCY_NONE, 0);
+ ret = video_changed;
+ video_changed = FALSE;
+ }
+
+ logerror("---update---\n");
+ return (!ret);
+}
diff --git a/src/mame/video/gaiden.c b/src/mame/video/gaiden.c
new file mode 100644
index 00000000000..f005ce3f5d3
--- /dev/null
+++ b/src/mame/video/gaiden.c
@@ -0,0 +1,577 @@
+/***************************************************************************
+
+ Ninja Gaiden / Tecmo Knights Video Hardware
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *gaiden_videoram,*gaiden_videoram2,*gaiden_videoram3;
+int gaiden_sprite_sizey;
+//int raiga_alpha;
+
+static tilemap *text_layer,*foreground,*background;
+static mame_bitmap *sprite_bitmap, *tile_bitmap_bg, *tile_bitmap_fg;
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT16 *videoram1 = &gaiden_videoram3[0x0800];
+ UINT16 *videoram2 = gaiden_videoram3;
+ SET_TILE_INFO(
+ 1,
+ videoram1[tile_index] & 0x0fff,
+ (videoram2[tile_index] & 0xf0) >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT16 *videoram1 = &gaiden_videoram2[0x0800];
+ UINT16 *videoram2 = gaiden_videoram2;
+ SET_TILE_INFO(
+ 2,
+ videoram1[tile_index] & 0x0fff,
+ (videoram2[tile_index] & 0xf0) >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info_raiga )
+{
+ UINT16 *videoram1 = &gaiden_videoram2[0x0800];
+ UINT16 *videoram2 = gaiden_videoram2;
+
+ /* bit 3 controls blending */
+ tileinfo->category = (videoram2[tile_index] & 0x08) >> 3;
+
+ SET_TILE_INFO(
+ 2,
+ videoram1[tile_index] & 0x0fff,
+ ((videoram2[tile_index] & 0xf0) >> 4) | (tileinfo->category ? 0x80 : 0x00),
+ 0);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ UINT16 *videoram1 = &gaiden_videoram[0x0400];
+ UINT16 *videoram2 = gaiden_videoram;
+ SET_TILE_INFO(
+ 0,
+ videoram1[tile_index] & 0x07ff,
+ (videoram2[tile_index] & 0xf0) >> 4,
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( gaiden )
+{
+ /* set up tile layers */
+ background = tilemap_create(get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 64, 32);
+ foreground = tilemap_create(get_fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 64, 32);
+ text_layer = tilemap_create(get_tx_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(background, 0);
+ tilemap_set_transparent_pen(foreground, 0);
+ tilemap_set_transparent_pen(text_layer, 0);
+}
+
+VIDEO_START( raiga )
+{
+ /* set up tile layers */
+ tile_bitmap_bg = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+ tile_bitmap_fg = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+
+ background = tilemap_create(get_bg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ foreground = tilemap_create(get_fg_tile_info_raiga,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ text_layer = tilemap_create(get_tx_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+
+ tilemap_set_transparent_pen(background,0);
+ tilemap_set_transparent_pen(foreground,0);
+ tilemap_set_transparent_pen(text_layer,0);
+
+ /* set up sprites */
+ sprite_bitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+}
+
+VIDEO_START( drgnbowl )
+{
+ /* set up tile layers */
+ background = tilemap_create(get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 64, 32);
+ foreground = tilemap_create(get_fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 64, 32);
+ text_layer = tilemap_create(get_tx_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(foreground, 15);
+ tilemap_set_transparent_pen(text_layer, 15);
+
+ tilemap_set_scrolldx(background, -248, 248);
+ tilemap_set_scrolldx(foreground, -252, 252);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( gaiden_txscrollx_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrollx(text_layer, 0, scroll);
+}
+
+WRITE16_HANDLER( gaiden_txscrolly_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrolly(text_layer, 0, scroll);
+}
+
+WRITE16_HANDLER( gaiden_fgscrollx_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrollx(foreground, 0, scroll);
+}
+
+WRITE16_HANDLER( gaiden_fgscrolly_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrolly(foreground, 0, scroll);
+}
+
+WRITE16_HANDLER( gaiden_bgscrollx_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrollx(background, 0, scroll);
+}
+
+WRITE16_HANDLER( gaiden_bgscrolly_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrolly(background, 0, scroll);
+}
+
+WRITE16_HANDLER( gaiden_videoram3_w )
+{
+ COMBINE_DATA(&gaiden_videoram3[offset]);
+ tilemap_mark_tile_dirty(background,offset & 0x07ff);
+}
+
+WRITE16_HANDLER( gaiden_flip_w )
+{
+ if (ACCESSING_LSB)
+ flip_screen_set(data & 1);
+}
+
+
+READ16_HANDLER( gaiden_videoram3_r )
+{
+ return gaiden_videoram3[offset];
+}
+
+WRITE16_HANDLER( gaiden_videoram2_w )
+{
+ COMBINE_DATA(&gaiden_videoram2[offset]);
+ tilemap_mark_tile_dirty(foreground,offset & 0x07ff);
+}
+
+READ16_HANDLER( gaiden_videoram2_r )
+{
+ return gaiden_videoram2[offset];
+}
+
+WRITE16_HANDLER( gaiden_videoram_w )
+{
+ COMBINE_DATA(&gaiden_videoram[offset]);
+ tilemap_mark_tile_dirty(text_layer,offset & 0x03ff);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+/* mix & blend the paletted 16-bit tile and sprite bitmaps into an RGB 32-bit bitmap */
+static void blendbitmaps(running_machine *machine,
+ mame_bitmap *dest,mame_bitmap *src1,mame_bitmap *src2,mame_bitmap *src3,
+ int sx,int sy,const rectangle *clip)
+{
+ int ox;
+ int oy;
+ int ex;
+ int ey;
+
+ /* check bounds */
+ ox = sx;
+ oy = sy;
+
+ ex = sx + src1->width - 1;
+ if (sx < 0) sx = 0;
+ if (sx < clip->min_x) sx = clip->min_x;
+ if (ex >= dest->width) ex = dest->width - 1;
+ if (ex > clip->max_x) ex = clip->max_x;
+ if (sx > ex) return;
+
+ ey = sy + src1->height - 1;
+ if (sy < 0) sy = 0;
+ if (sy < clip->min_y) sy = clip->min_y;
+ if (ey >= dest->height) ey = dest->height - 1;
+ if (ey > clip->max_y) ey = clip->max_y;
+ if (sy > ey) return;
+
+ {
+ const pen_t *paldata = machine->pens;
+ UINT32 *end;
+
+ UINT16 *sd1 = src1->base; /* source data */
+ UINT16 *sd2 = src2->base;
+ UINT16 *sd3 = src3->base;
+
+ int sw = ex-sx+1; /* source width */
+ int sh = ey-sy+1; /* source height */
+ int sm = src1->rowpixels; /* source modulo */
+
+ UINT32 *dd = BITMAP_ADDR32(dest, sy, sx); /* dest data */
+ int dm = dest->rowpixels; /* dest modulo */
+
+ sd1 += (sx-ox);
+ sd1 += sm * (sy-oy);
+ sd2 += (sx-ox);
+ sd2 += sm * (sy-oy);
+ sd3 += (sx-ox);
+ sd3 += sm * (sy-oy);
+
+ sm -= sw;
+ dm -= sw;
+
+ while (sh)
+ {
+
+#define BLENDPIXEL(x) if (sd3[x]) { \
+ if (sd2[x]) { \
+ dd[x] = paldata[sd2[x] | 0x0400] + paldata[sd3[x]]; \
+ } else { \
+ dd[x] = paldata[sd1[x] | 0x0400] + paldata[sd3[x]]; \
+ } \
+ } else { \
+ if (sd2[x]) { \
+ if (sd2[x] & 0x0800) { \
+ dd[x] = paldata[sd1[x] | 0x0400] + paldata[sd2[x]]; \
+ } else { \
+ dd[x] = paldata[sd2[x]]; \
+ } \
+ } else { \
+ dd[x] = paldata[sd1[x]]; \
+ } \
+ }
+
+ end = dd + sw;
+ while (dd <= end - 8)
+ {
+ BLENDPIXEL(0);
+ BLENDPIXEL(1);
+ BLENDPIXEL(2);
+ BLENDPIXEL(3);
+ BLENDPIXEL(4);
+ BLENDPIXEL(5);
+ BLENDPIXEL(6);
+ BLENDPIXEL(7);
+ dd += 8;
+ sd1 += 8;
+ sd2 += 8;
+ sd3 += 8;
+ }
+ while (dd < end)
+ {
+ BLENDPIXEL(0);
+ dd++;
+ sd1++;
+ sd2++;
+ sd3++;
+ }
+ dd += dm;
+ sd1 += sm;
+ sd2 += sm;
+ sd3 += sm;
+ sh--;
+
+#undef BLENDPIXEL
+
+ }
+ }
+}
+
+/* sprite format:
+ *
+ * word bit usage
+ * --------+-fedcba9876543210-+----------------
+ * 0 | ---------------x | flip x
+ * | --------------x- | flip y
+ * | -------------x-- | enable
+ * | ----------x----- | blend
+ * | --------xx------ | sprite-tile priority
+ * 1 | xxxxxxxxxxxxxxxx | number
+ * 2 | --------xxxx---- | palette
+ * | --------------xx | size: 8x8, 16x16, 32x32, 64x64
+ * 3 | xxxxxxxxxxxxxxxx | y position
+ * 4 | xxxxxxxxxxxxxxxx | x position
+ * 5,6,7| | unused
+ */
+
+#define NUM_SPRITES 256
+
+static void gaiden_draw_sprites(running_machine *machine, mame_bitmap *bitmap_bg, mame_bitmap *bitmap_fg, mame_bitmap *bitmap_sp, const rectangle *cliprect)
+{
+ static const UINT8 layout[8][8] =
+ {
+ { 0, 1, 4, 5,16,17,20,21},
+ { 2, 3, 6, 7,18,19,22,23},
+ { 8, 9,12,13,24,25,28,29},
+ {10,11,14,15,26,27,30,31},
+ {32,33,36,37,48,49,52,53},
+ {34,35,38,39,50,51,54,55},
+ {40,41,44,45,56,57,60,61},
+ {42,43,46,47,58,59,62,63}
+ };
+
+ const gfx_element *gfx = machine->gfx[3];
+ mame_bitmap *bitmap = bitmap_bg;
+ const UINT16 *source = (NUM_SPRITES - 1) * 8 + spriteram16;
+ const UINT8 blend_support = (bitmap_fg && bitmap_sp);
+ int count = NUM_SPRITES;
+
+ /* draw all sprites from front to back */
+ while (count--)
+ {
+ UINT32 attributes = source[0];
+ UINT32 priority_mask;
+ int col,row;
+
+ if (attributes & 0x04)
+ {
+ UINT32 priority = (attributes >> 6) & 3;
+ UINT32 flipx = (attributes & 1);
+ UINT32 flipy = (attributes & 2);
+
+ UINT32 color = source[2];
+ UINT32 sizex = 1 << ((color >> 0) & 3); /* 1,2,4,8 */
+ UINT32 sizey = 1 << ((color >> gaiden_sprite_sizey) & 3); /* 1,2,4,8 */
+
+ /* raiga needs something like this */
+ UINT32 number = (source[1] & (sizex > 2 ? 0x7ff8 : 0x7ffc));
+
+ int ypos = source[3] & 0x01ff;
+ int xpos = source[4] & 0x01ff;
+
+ if (!blend_support && (attributes & 0x20) && (cpu_getcurrentframe() & 1))
+ goto skip_sprite;
+
+ color = (color >> 4) & 0x0f;
+
+ /* wraparound */
+ if (xpos >= 256)
+ xpos -= 512;
+ if (ypos >= 256)
+ ypos -= 512;
+
+ if (flip_screen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+
+ xpos = 256 - (8 * sizex) - xpos;
+ ypos = 256 - (8 * sizey) - ypos;
+
+ if (xpos <= -256)
+ xpos += 512;
+ if (ypos <= -256)
+ ypos += 512;
+ }
+
+ /* bg: 1; fg:2; text: 4 */
+ switch( priority )
+ {
+ default:
+ case 0x0: priority_mask = 0; break;
+ case 0x1: priority_mask = 0xf0; break; /* obscured by text layer */
+ case 0x2: priority_mask = 0xf0 | 0xcc; break; /* obscured by foreground */
+ case 0x3: priority_mask = 0xf0 | 0xcc | 0xaa; break; /* obscured by bg and fg */
+ }
+
+ /* blending */
+ if (blend_support && (attributes & 0x20))
+ {
+ color |= 0x80;
+
+ for (row = 0; row < sizey; row++)
+ {
+ for (col = 0; col < sizex; col++)
+ {
+ int sx = xpos + 8 * (flipx ? (sizex - 1 - col) : col);
+ int sy = ypos + 8 * (flipy ? (sizey - 1 - row) : row);
+
+ pdrawgfx(bitmap_sp, gfx,
+ number + layout[row][col],
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect, TRANSPARENCY_PEN, 0,
+ priority_mask);
+ }
+ }
+ }
+ else
+ {
+ if (blend_support)
+ bitmap = (priority >= 2) ? bitmap_bg : bitmap_fg;
+
+ for (row = 0; row < sizey; row++)
+ {
+ for (col = 0; col < sizex; col++)
+ {
+ int sx = xpos + 8 * (flipx ? (sizex - 1 - col) : col);
+ int sy = ypos + 8 * (flipy ? (sizey - 1 - row) : row);
+
+ pdrawgfx(bitmap, gfx,
+ number + layout[row][col],
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect, TRANSPARENCY_PEN, 0,
+ priority_mask);
+ }
+ }
+ }
+ }
+skip_sprite:
+ source -= 8;
+ }
+}
+
+
+/* sprite format:
+ *
+ * word bit usage
+ * --------+-fedcba9876543210-+----------------
+ * 0 | --------xxxxxxxx | sprite code (lower bits)
+ * | ---xxxxx-------- | unused ?
+ * 1 | --------xxxxxxxx | y position
+ * | ------x--------- | unused ?
+ * 2 | --------xxxxxxxx | x position
+ * | -------x-------- | unused ?
+ * 3 | -----------xxxxx | sprite code (upper bits)
+ * | ----------x----- | sprite-tile priority
+ * | ---------x------ | flip x
+ * | --------x------- | flip y
+ * 0x400 |-------------xxxx | color
+ * |---------x------- | x position (high bit)
+ */
+
+static void drgnbowl_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int i, code, color, x, y, flipx, flipy, priority_mask;
+
+ for( i = 0; i < 0x800/2; i += 4 )
+ {
+ code = (spriteram16[i + 0] & 0xff) | ((spriteram16[i + 3] & 0x1f) << 8);
+ y = 256 - (spriteram16[i + 1] & 0xff) - 12;
+ x = spriteram16[i + 2] & 0xff;
+ color = (spriteram16[(0x800/2) + i] & 0x0f);
+ flipx = spriteram16[i + 3] & 0x40;
+ flipy = spriteram16[i + 3] & 0x80;
+
+ if(spriteram16[(0x800/2) + i] & 0x80)
+ x -= 256;
+
+ x += 256;
+
+ if(spriteram16[i + 3] & 0x20)
+ priority_mask = 0xf0 | 0xcc; /* obscured by foreground */
+ else
+ priority_mask = 0;
+
+ pdrawgfx(bitmap,machine->gfx[3],
+ code,
+ color,flipx,flipy,x,y,
+ cliprect,
+ TRANSPARENCY_PEN,15,
+ priority_mask);
+
+ /* wrap x*/
+ pdrawgfx(bitmap,machine->gfx[3],
+ code,
+ color,flipx,flipy,x-512,y,
+ cliprect,
+ TRANSPARENCY_PEN,15,
+ priority_mask);
+
+ }
+}
+
+VIDEO_UPDATE( gaiden )
+{
+ fillbitmap(priority_bitmap, 0, cliprect);
+ fillbitmap(bitmap, machine->pens[0x200], cliprect);
+
+ tilemap_draw(bitmap, cliprect, background, 0, 1);
+ tilemap_draw(bitmap, cliprect, foreground, 0, 2);
+ tilemap_draw(bitmap, cliprect, text_layer, 0, 4);
+
+ gaiden_draw_sprites(machine, bitmap, NULL, NULL, cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( raiga )
+{
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ fillbitmap(tile_bitmap_bg, 0x200, cliprect);
+ fillbitmap(tile_bitmap_fg, 0, cliprect);
+ fillbitmap(sprite_bitmap, 0, cliprect);
+
+ /* draw tilemaps into a 16-bit bitmap */
+ tilemap_draw(tile_bitmap_bg, cliprect,background, 0, 1);
+ tilemap_draw(tile_bitmap_fg, cliprect,foreground, 0, 2);
+ /* draw the blended tiles at a lower priority
+ so sprites covered by them will still be drawn */
+ tilemap_draw(tile_bitmap_fg, cliprect,foreground, 1, 0);
+ tilemap_draw(tile_bitmap_fg, cliprect,text_layer, 0, 4);
+
+ /* draw sprites into a 16-bit bitmap */
+ gaiden_draw_sprites(machine, tile_bitmap_bg, tile_bitmap_fg, sprite_bitmap, cliprect);
+
+ /* mix & blend the tilemaps and sprites into a 32-bit bitmap */
+ blendbitmaps(machine, bitmap, tile_bitmap_bg, tile_bitmap_fg, sprite_bitmap, 0, 0, cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( drgnbowl )
+{
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ tilemap_draw(bitmap, cliprect, background, 0, 1);
+ tilemap_draw(bitmap, cliprect, foreground, 0, 2);
+ tilemap_draw(bitmap, cliprect, text_layer, 0, 4);
+ drgnbowl_draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/galaga.c b/src/mame/video/galaga.c
new file mode 100644
index 00000000000..08c580b7f2e
--- /dev/null
+++ b/src/mame/video/galaga.c
@@ -0,0 +1,610 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/galaga.h"
+
+
+#define MAX_STARS 252
+#define STARS_COLOR_BASE (64*4+64*4)
+
+UINT8 *galaga_videoram;
+UINT8 *galaga_ram1,*galaga_ram2,*galaga_ram3;
+UINT8 galaga_starcontrol[6];
+static UINT32 stars_scrollx,stars_scrolly;
+static colortable *galaga_colortable;
+
+static INT32 galaga_gfxbank; // used by catsbee
+
+static tilemap *tx_tilemap;
+
+/*
+Galaga star line and pixel locations pulled directly from
+a clocked stepping of the 05 starfield. The chip was clocked
+on a test rig with hblank and vblank simulated, each X & Y
+location of a star being recorded along with it's color value.
+
+Because the starfield begins generating stars at the point
+in time it's enabled the exact horiz location of the stars
+on Galaga depends on the length of time of the POST for the
+original board.
+
+Two control bits determine which of two sets are displayed
+set 0 or 1 and simultaneously 2 or 3.
+
+There are 63 stars in each set, 126 displayed at any one time
+
+*/
+
+struct star star_seed_tab[252]=
+{
+
+/* also shared by Bosconian */
+
+/* star set 0 */
+
+{0x0085,0x0006,0x35, 0x00},
+{0x008F,0x0008,0x30, 0x00},
+{0x00E5,0x001B,0x07, 0x00},
+{0x0022,0x001C,0x31, 0x00},
+{0x00E5,0x0025,0x1D, 0x00},
+{0x0015,0x0026,0x29, 0x00},
+{0x0080,0x002D,0x3B, 0x00},
+{0x0097,0x002E,0x1C, 0x00},
+{0x00BA,0x003B,0x05, 0x00},
+{0x0036,0x003D,0x36, 0x00},
+{0x0057,0x0044,0x09, 0x00},
+{0x00CF,0x0044,0x3D, 0x00},
+{0x0061,0x004E,0x27, 0x00},
+{0x0087,0x0064,0x1A, 0x00},
+{0x00D6,0x0064,0x17, 0x00},
+{0x000B,0x006C,0x3C, 0x00},
+{0x0006,0x006D,0x24, 0x00},
+{0x0018,0x006E,0x3A, 0x00},
+{0x00A9,0x0079,0x23, 0x00},
+{0x008A,0x007B,0x11, 0x00},
+{0x00D6,0x0080,0x0C, 0x00},
+{0x0067,0x0082,0x3F, 0x00},
+{0x0039,0x0083,0x38, 0x00},
+{0x0072,0x0083,0x14, 0x00},
+{0x00EC,0x0084,0x16, 0x00},
+{0x008E,0x0085,0x10, 0x00},
+{0x0020,0x0088,0x25, 0x00},
+{0x0095,0x008A,0x0F, 0x00},
+{0x000E,0x008D,0x00, 0x00},
+{0x0006,0x0091,0x2E, 0x00},
+{0x0007,0x0094,0x0D, 0x00},
+{0x00AE,0x0097,0x0B, 0x00},
+{0x0000,0x0098,0x2D, 0x00},
+{0x0086,0x009B,0x01, 0x00},
+{0x0058,0x00A1,0x34, 0x00},
+{0x00FE,0x00A1,0x3E, 0x00},
+{0x00A2,0x00A8,0x1F, 0x00},
+{0x0041,0x00AA,0x0A, 0x00},
+{0x003F,0x00AC,0x32, 0x00},
+{0x00DE,0x00AC,0x03, 0x00},
+{0x00D4,0x00B9,0x26, 0x00},
+{0x006D,0x00BB,0x1B, 0x00},
+{0x0062,0x00BD,0x39, 0x00},
+{0x00C9,0x00BE,0x18, 0x00},
+{0x006C,0x00C1,0x04, 0x00},
+{0x0059,0x00C3,0x21, 0x00},
+{0x0060,0x00CC,0x0E, 0x00},
+{0x0091,0x00CC,0x12, 0x00},
+{0x003F,0x00CF,0x06, 0x00},
+{0x00F7,0x00CF,0x22, 0x00},
+{0x0044,0x00D0,0x33, 0x00},
+{0x0034,0x00D2,0x08, 0x00},
+{0x00D3,0x00D9,0x20, 0x00},
+{0x0071,0x00DD,0x37, 0x00},
+{0x0073,0x00E1,0x2C, 0x00},
+{0x00B9,0x00E3,0x2F, 0x00},
+{0x00A9,0x00E4,0x13, 0x00},
+{0x00D3,0x00E7,0x19, 0x00},
+{0x0037,0x00ED,0x02, 0x00},
+{0x00BD,0x00F4,0x15, 0x00},
+{0x000F,0x00F6,0x28, 0x00},
+{0x004F,0x00F7,0x2B, 0x00},
+{0x00FB,0x00FF,0x2A, 0x00},
+
+/* star set 1 */
+
+{0x00FE,0x0004,0x3D, 0x01},
+{0x00C4,0x0006,0x10, 0x01},
+{0x001E,0x0007,0x2D, 0x01},
+{0x0083,0x000B,0x1F, 0x01},
+{0x002E,0x000D,0x3C, 0x01},
+{0x001F,0x000E,0x00, 0x01},
+{0x00D8,0x000E,0x2C, 0x01},
+{0x0003,0x000F,0x17, 0x01},
+{0x0095,0x0011,0x3F, 0x01},
+{0x006A,0x0017,0x35, 0x01},
+{0x00CC,0x0017,0x02, 0x01},
+{0x0000,0x0018,0x32, 0x01},
+{0x0092,0x001D,0x36, 0x01},
+{0x00E3,0x0021,0x04, 0x01},
+{0x002F,0x002D,0x37, 0x01},
+{0x00F0,0x002F,0x0C, 0x01},
+{0x009B,0x003E,0x06, 0x01},
+{0x00A4,0x004C,0x07, 0x01},
+{0x00EA,0x004D,0x13, 0x01},
+{0x0084,0x004E,0x21, 0x01},
+{0x0033,0x0052,0x0F, 0x01},
+{0x0070,0x0053,0x0E, 0x01},
+{0x0006,0x0059,0x08, 0x01},
+{0x0081,0x0060,0x28, 0x01},
+{0x0037,0x0061,0x29, 0x01},
+{0x008F,0x0067,0x2F, 0x01},
+{0x001B,0x006A,0x1D, 0x01},
+{0x00BF,0x007C,0x12, 0x01},
+{0x0051,0x007F,0x31, 0x01},
+{0x0061,0x0086,0x25, 0x01},
+{0x006A,0x008F,0x0D, 0x01},
+{0x006A,0x0091,0x19, 0x01},
+{0x0090,0x0092,0x05, 0x01},
+{0x003B,0x0096,0x24, 0x01},
+{0x008C,0x0097,0x0A, 0x01},
+{0x0006,0x0099,0x03, 0x01},
+{0x0038,0x0099,0x38, 0x01},
+{0x00A8,0x0099,0x18, 0x01},
+{0x0076,0x00A6,0x20, 0x01},
+{0x00AD,0x00A6,0x1C, 0x01},
+{0x00EC,0x00A6,0x1E, 0x01},
+{0x0086,0x00AC,0x15, 0x01},
+{0x0078,0x00AF,0x3E, 0x01},
+{0x007B,0x00B3,0x09, 0x01},
+{0x0027,0x00B8,0x39, 0x01},
+{0x0088,0x00C2,0x23, 0x01},
+{0x0044,0x00C3,0x3A, 0x01},
+{0x00CF,0x00C5,0x34, 0x01},
+{0x0035,0x00C9,0x30, 0x01},
+{0x006E,0x00D1,0x3B, 0x01},
+{0x00D6,0x00D7,0x16, 0x01},
+{0x003A,0x00D9,0x2B, 0x01},
+{0x00AB,0x00E0,0x11, 0x01},
+{0x00E0,0x00E2,0x1B, 0x01},
+{0x006F,0x00E6,0x0B, 0x01},
+{0x00B8,0x00E8,0x14, 0x01},
+{0x00D9,0x00E8,0x1A, 0x01},
+{0x00F9,0x00E8,0x22, 0x01},
+{0x0004,0x00F1,0x2E, 0x01},
+{0x0049,0x00F8,0x26, 0x01},
+{0x0010,0x00F9,0x01, 0x01},
+{0x0039,0x00FB,0x33, 0x01},
+{0x0028,0x00FC,0x27, 0x01},
+
+/* star set 2 */
+
+{0x00FA,0x0006,0x19, 0x02},
+{0x00E4,0x0007,0x2D, 0x02},
+{0x0072,0x000A,0x03, 0x02},
+{0x0084,0x001B,0x00, 0x02},
+{0x00BA,0x001D,0x29, 0x02},
+{0x00E3,0x0022,0x04, 0x02},
+{0x00D1,0x0026,0x2A, 0x02},
+{0x0089,0x0032,0x30, 0x02},
+{0x005B,0x0036,0x27, 0x02},
+{0x0084,0x003A,0x36, 0x02},
+{0x0053,0x003F,0x0D, 0x02},
+{0x0008,0x0040,0x1D, 0x02},
+{0x0055,0x0040,0x1A, 0x02},
+{0x00AA,0x0041,0x31, 0x02},
+{0x00FB,0x0041,0x2B, 0x02},
+{0x00BC,0x0046,0x16, 0x02},
+{0x0093,0x0052,0x39, 0x02},
+{0x00B9,0x0057,0x10, 0x02},
+{0x0054,0x0059,0x28, 0x02},
+{0x00E6,0x005A,0x01, 0x02},
+{0x00A7,0x005D,0x1B, 0x02},
+{0x002D,0x005E,0x35, 0x02},
+{0x0014,0x0062,0x21, 0x02},
+{0x0069,0x006D,0x1F, 0x02},
+{0x00CE,0x006F,0x0B, 0x02},
+{0x00DF,0x0075,0x2F, 0x02},
+{0x00CB,0x0077,0x12, 0x02},
+{0x004E,0x007C,0x23, 0x02},
+{0x004A,0x0084,0x0F, 0x02},
+{0x0012,0x0086,0x25, 0x02},
+{0x0068,0x008C,0x32, 0x02},
+{0x0003,0x0095,0x20, 0x02},
+{0x000A,0x009C,0x17, 0x02},
+{0x005B,0x00A3,0x08, 0x02},
+{0x005F,0x00A4,0x3E, 0x02},
+{0x0072,0x00A4,0x2E, 0x02},
+{0x00CC,0x00A6,0x06, 0x02},
+{0x008A,0x00AB,0x0C, 0x02},
+{0x00E0,0x00AD,0x26, 0x02},
+{0x00F3,0x00AF,0x0A, 0x02},
+{0x0075,0x00B4,0x13, 0x02},
+{0x0068,0x00B7,0x11, 0x02},
+{0x006D,0x00C2,0x2C, 0x02},
+{0x0076,0x00C3,0x14, 0x02},
+{0x00CF,0x00C4,0x1E, 0x02},
+{0x0004,0x00C5,0x1C, 0x02},
+{0x0013,0x00C6,0x3F, 0x02},
+{0x00B9,0x00C7,0x3C, 0x02},
+{0x0005,0x00D7,0x34, 0x02},
+{0x0095,0x00D7,0x3A, 0x02},
+{0x00FC,0x00D8,0x02, 0x02},
+{0x00E7,0x00DC,0x09, 0x02},
+{0x001D,0x00E1,0x05, 0x02},
+{0x0005,0x00E6,0x33, 0x02},
+{0x001C,0x00E9,0x3B, 0x02},
+{0x00A2,0x00ED,0x37, 0x02},
+{0x0028,0x00EE,0x07, 0x02},
+{0x00DD,0x00EF,0x18, 0x02},
+{0x006D,0x00F0,0x38, 0x02},
+{0x00A1,0x00F2,0x0E, 0x02},
+{0x0074,0x00F7,0x3D, 0x02},
+{0x0069,0x00F9,0x22, 0x02},
+{0x003F,0x00FF,0x24, 0x02},
+
+/* star set 3 */
+
+{0x0071,0x0010,0x34, 0x03},
+{0x00AF,0x0011,0x23, 0x03},
+{0x00A0,0x0014,0x26, 0x03},
+{0x0002,0x0017,0x02, 0x03},
+{0x004B,0x0019,0x31, 0x03},
+{0x0093,0x001C,0x0E, 0x03},
+{0x001B,0x001E,0x25, 0x03},
+{0x0032,0x0020,0x2E, 0x03},
+{0x00EE,0x0020,0x3A, 0x03},
+{0x0079,0x0022,0x2F, 0x03},
+{0x006C,0x0023,0x17, 0x03},
+{0x00BC,0x0025,0x11, 0x03},
+{0x0041,0x0029,0x30, 0x03},
+{0x001C,0x002E,0x32, 0x03},
+{0x00B9,0x0031,0x01, 0x03},
+{0x0083,0x0032,0x05, 0x03},
+{0x0095,0x003A,0x12, 0x03},
+{0x000D,0x003F,0x07, 0x03},
+{0x0020,0x0041,0x33, 0x03},
+{0x0092,0x0045,0x2C, 0x03},
+{0x00D4,0x0047,0x08, 0x03},
+{0x00A1,0x004B,0x2D, 0x03},
+{0x00D2,0x004B,0x3B, 0x03},
+{0x00D6,0x0052,0x24, 0x03},
+{0x009A,0x005F,0x1C, 0x03},
+{0x0016,0x0060,0x3D, 0x03},
+{0x001A,0x0063,0x1F, 0x03},
+{0x00CD,0x0066,0x28, 0x03},
+{0x00FF,0x0067,0x10, 0x03},
+{0x0035,0x0069,0x20, 0x03},
+{0x008F,0x006C,0x04, 0x03},
+{0x00CA,0x006C,0x2A, 0x03},
+{0x005A,0x0074,0x09, 0x03},
+{0x0060,0x0078,0x38, 0x03},
+{0x0072,0x0079,0x1E, 0x03},
+{0x0037,0x007F,0x29, 0x03},
+{0x0012,0x0080,0x14, 0x03},
+{0x0029,0x0082,0x2B, 0x03},
+{0x0084,0x0098,0x36, 0x03},
+{0x0032,0x0099,0x37, 0x03},
+{0x00BB,0x00A0,0x19, 0x03},
+{0x003E,0x00A3,0x3E, 0x03},
+{0x004A,0x00A6,0x1A, 0x03},
+{0x0029,0x00A7,0x21, 0x03},
+{0x009D,0x00B7,0x22, 0x03},
+{0x006C,0x00B9,0x15, 0x03},
+{0x000C,0x00C0,0x0A, 0x03},
+{0x00C2,0x00C3,0x0F, 0x03},
+{0x002F,0x00C9,0x0D, 0x03},
+{0x00D2,0x00CE,0x16, 0x03},
+{0x00F3,0x00CE,0x0B, 0x03},
+{0x0075,0x00CF,0x27, 0x03},
+{0x001A,0x00D5,0x35, 0x03},
+{0x0026,0x00D6,0x39, 0x03},
+{0x0080,0x00DA,0x3C, 0x03},
+{0x00A9,0x00DD,0x00, 0x03},
+{0x00BC,0x00EB,0x03, 0x03},
+{0x0032,0x00EF,0x1B, 0x03},
+{0x0067,0x00F0,0x3F, 0x03},
+{0x00EF,0x00F1,0x18, 0x03},
+{0x00A8,0x00F3,0x0C, 0x03},
+{0x00DE,0x00F9,0x1D, 0x03},
+{0x002C,0x00FA,0x13, 0x03}
+};
+
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs.
+
+ Galaga has one 32x8 palette PROM and two 256x4 color lookup table PROMs
+ (one for characters, one for sprites). Only the first 128 bytes of the
+ lookup tables seem to be used.
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+
+PALETTE_INIT( galaga )
+{
+ int i;
+
+ galaga_colortable = colortable_alloc(machine, 32+64);
+
+ /* core palette */
+ for (i = 0;i < 32;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ bit0 = ((*color_prom) >> 0) & 0x01;
+ bit1 = ((*color_prom) >> 1) & 0x01;
+ bit2 = ((*color_prom) >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = ((*color_prom) >> 3) & 0x01;
+ bit1 = ((*color_prom) >> 4) & 0x01;
+ bit2 = ((*color_prom) >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = 0;
+ bit1 = ((*color_prom) >> 6) & 0x01;
+ bit2 = ((*color_prom) >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ colortable_palette_set_color(galaga_colortable,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* palette for the stars */
+ for (i = 0;i < 64;i++)
+ {
+ int bits,r,g,b;
+ static const int map[4] = { 0x00, 0x47, 0x97 ,0xde };
+
+ bits = (i >> 0) & 0x03;
+ r = map[bits];
+ bits = (i >> 2) & 0x03;
+ g = map[bits];
+ bits = (i >> 4) & 0x03;
+ b = map[bits];
+
+ colortable_palette_set_color(galaga_colortable,32 + i,MAKE_RGB(r,g,b));
+ }
+
+ /* characters */
+ for (i = 0;i < 64*4;i++)
+ colortable_entry_set_value(galaga_colortable, i, (*(color_prom++) & 0x0f) + 0x10); /* chars */
+
+ /* sprites */
+ for (i = 0;i < 64*4;i++)
+ colortable_entry_set_value(galaga_colortable, 64*4+i, (*(color_prom++) & 0x0f));
+
+ /* now the stars */
+ for (i = 0;i < 64;i++)
+ colortable_entry_set_value(galaga_colortable, 64*4+64*4+i, 32 + i);
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/* convert from 32x32 to 36x28 */
+static TILEMAP_MAPPER( tilemap_scan )
+{
+ int offs;
+
+ row += 2;
+ col -= 2;
+ if (col & 0x20)
+ offs = row + ((col & 0x1f) << 5);
+ else
+ offs = col + (row << 5);
+
+ return offs;
+}
+
+
+static TILE_GET_INFO( get_tile_info )
+{
+ /* the hardware has two character sets, one normal and one x-flipped. When
+ screen is flipped, character y flip is done by the hardware inverting the
+ timing signals, while x flip is done by selecting the 2nd character set.
+ We reproduce this here, but since the tilemap system automatically flips
+ characters when screen is flipped, we have to flip them back. */
+ int color = galaga_videoram[tile_index + 0x400] & 0x3f;
+ SET_TILE_INFO(
+ 0,
+ (galaga_videoram[tile_index] & 0x7f) | (flip_screen ? 0x80 : 0) | (galaga_gfxbank << 8),
+ color,
+ flip_screen ? TILE_FLIPX : 0);
+ tileinfo->group = color;
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( galaga )
+{
+ tx_tilemap = tilemap_create(get_tile_info,tilemap_scan,TILEMAP_TYPE_PEN,8,8,36,28);
+ colortable_configure_tilemap_groups(galaga_colortable, tx_tilemap, machine->gfx[0], 0x1f);
+
+ galaga_gfxbank = 0;
+
+ spriteram = galaga_ram1 + 0x380;
+ spriteram_2 = galaga_ram2 + 0x380;
+ spriteram_3 = galaga_ram3 + 0x380;
+
+
+ state_save_register_global_array(galaga_starcontrol);
+ state_save_register_global(stars_scrollx);
+ state_save_register_global(stars_scrolly);
+ state_save_register_global(galaga_gfxbank);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ8_HANDLER( galaga_videoram_r )
+{
+ return galaga_videoram[offset];
+}
+
+WRITE8_HANDLER( galaga_videoram_w )
+{
+ galaga_videoram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( galaga_starcontrol_w )
+{
+ galaga_starcontrol[offset] = data & 1;
+}
+
+WRITE8_HANDLER ( gatsbee_bank_w )
+{
+ galaga_gfxbank = data & 0x1;
+ tilemap_mark_all_tiles_dirty(tx_tilemap);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+
+ for (offs = 0;offs < 0x80;offs += 2)
+ {
+ static int gfx_offs[2][2] =
+ {
+ { 0, 1 },
+ { 2, 3 }
+ };
+ int sprite = spriteram[offs] & 0x7f;
+ int color = spriteram[offs+1] & 0x3f;
+ int sx = spriteram_2[offs+1] - 40 + 0x100*(spriteram_3[offs+1] & 3);
+ int sy = 256 - spriteram_2[offs] + 1; // sprites are buffered and delayed by one scanline
+ int flipx = (spriteram_3[offs] & 0x01);
+ int flipy = (spriteram_3[offs] & 0x02) >> 1;
+ int sizex = (spriteram_3[offs] & 0x04) >> 2;
+ int sizey = (spriteram_3[offs] & 0x08) >> 3;
+ int x,y;
+
+ if (flip_screen)
+ {
+ flipx ^= 1;
+ flipy ^= 1;
+ }
+
+ sy -= 16 * sizey;
+ sy = (sy & 0xff) - 32; // fix wraparound
+
+ for (y = 0;y <= sizey;y++)
+ {
+ for (x = 0;x <= sizex;x++)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ sprite + gfx_offs[y ^ (sizey * flipy)][x ^ (sizex * flipx)],
+ color,
+ flipx,flipy,
+ sx + 16*x, sy + 16*y,
+ cliprect,TRANSPARENCY_PENS,
+ colortable_get_transpen_mask(galaga_colortable, machine->gfx[1], color, 0x0f));
+ }
+ }
+ }
+}
+
+
+static void draw_stars(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ /* draw the stars */
+
+ /* $a005 controls the stars ON/OFF */
+
+
+ if ( galaga_starcontrol[5] == 1 )
+ {
+ int star_cntr;
+ int set_a, set_b;
+
+ /* two sets of stars controlled by these bits */
+
+ set_a = galaga_starcontrol[3];
+ set_b = galaga_starcontrol[4] | 0x2;
+
+
+ for (star_cntr = 0;star_cntr < MAX_STARS ;star_cntr++)
+ {
+ int x,y;
+
+ if ( (set_a == star_seed_tab[star_cntr].set) || ( set_b == star_seed_tab[star_cntr].set) )
+ {
+
+ x = (star_seed_tab[star_cntr].x + stars_scrollx) % 256 + 16;
+ y = (112 + star_seed_tab[star_cntr].y + stars_scrolly) % 256;
+ /* 112 is a tweak to get alignment about perfect */
+
+
+
+ if (y >= machine->screen[0].visarea.min_y && y <= machine->screen[0].visarea.max_y)
+ *BITMAP_ADDR16(bitmap, y, x) = STARS_COLOR_BASE + star_seed_tab[ star_cntr ].col;
+ }
+
+ }
+ }
+}
+
+VIDEO_UPDATE( galaga )
+{
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ draw_stars(machine,bitmap,cliprect);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+
+
+VIDEO_EOF( galaga )
+{
+ /* this function is called by galaga_interrupt_1() */
+ int s0,s1,s2;
+ static const int speeds[8] = { -1, -2, -3, 0, 3, 2, 1, 0 };
+
+
+ s0 = galaga_starcontrol[0];
+ s1 = galaga_starcontrol[1];
+ s2 = galaga_starcontrol[2];
+
+ stars_scrollx += speeds[s0 + s1*2 + s2*4];
+}
+
+
diff --git a/src/mame/video/galaxian.c b/src/mame/video/galaxian.c
new file mode 100644
index 00000000000..c331bce0c15
--- /dev/null
+++ b/src/mame/video/galaxian.c
@@ -0,0 +1,2243 @@
+/***************************************************************************
+
+ Galaxian hardware family
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/galaxian.h"
+
+static rectangle _spritevisiblearea =
+{
+ 2*8+1, 32*8-1,
+ 2*8, 30*8-1
+};
+static rectangle _spritevisibleareaflipx =
+{
+ 0*8, 30*8-2,
+ 2*8, 30*8-1
+};
+
+static rectangle* spritevisiblearea;
+static rectangle* spritevisibleareaflipx;
+
+
+#define STARS_COLOR_BASE (memory_region_length(REGION_PROMS))
+#define BULLETS_COLOR_BASE (STARS_COLOR_BASE + 64)
+#define BACKGROUND_COLOR_BASE (BULLETS_COLOR_BASE + 2)
+
+
+UINT8 *galaxian_videoram;
+UINT8 *galaxian_spriteram;
+UINT8 *galaxian_spriteram2;
+UINT8 *galaxian_attributesram;
+UINT8 *galaxian_bulletsram;
+UINT8 *rockclim_videoram;
+size_t galaxian_spriteram_size;
+size_t galaxian_spriteram2_size;
+size_t galaxian_bulletsram_size;
+
+
+static TILE_GET_INFO( get_tile_info );
+static TILE_GET_INFO( rockclim_get_tile_info );
+static tilemap *bg_tilemap;
+static tilemap *rockclim_tilemap;
+static int mooncrst_gfxextend;
+static int spriteram2_present;
+static UINT8 gfxbank[5];
+static UINT8 flipscreen_x;
+static UINT8 flipscreen_y;
+static UINT8 color_mask;
+static tilemap *dambustr_tilemap2;
+static UINT8 *dambustr_videoram2;
+static void (*modify_charcode)(UINT16 *code,UINT8 x); /* function to call to do character banking */
+static void gmgalax_modify_charcode(UINT16 *code,UINT8 x);
+static void mooncrst_modify_charcode(UINT16 *code,UINT8 x);
+static void mooncrgx_modify_charcode(UINT16 *code,UINT8 x);
+static void moonqsr_modify_charcode(UINT16 *code,UINT8 x);
+static void mshuttle_modify_charcode(UINT16 *code,UINT8 x);
+static void pisces_modify_charcode(UINT16 *code,UINT8 x);
+static void mimonkey_modify_charcode(UINT16 *code,UINT8 x);
+static void batman2_modify_charcode(UINT16 *code,UINT8 x);
+static void mariner_modify_charcode(UINT16 *code,UINT8 x);
+static void jumpbug_modify_charcode(UINT16 *code,UINT8 x);
+static void dambustr_modify_charcode(UINT16 *code,UINT8 x);
+
+static void (*modify_spritecode)(UINT8 *spriteram,int*,int*,int*,int); /* function to call to do sprite banking */
+static void gmgalax_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs);
+static void mooncrst_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs);
+static void mooncrgx_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs);
+static void moonqsr_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs);
+static void mshuttle_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs);
+static void calipso_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs);
+static void pisces_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs);
+static void mimonkey_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs);
+static void batman2_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs);
+static void jumpbug_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs);
+static void dkongjrm_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs);
+static void ad2083_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs);
+static void dambustr_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs);
+
+static void (*modify_color)(UINT8 *color); /* function to call to do modify how the color codes map to the PROM */
+static void frogger_modify_color(UINT8 *color);
+static void gmgalax_modify_color(UINT8 *color);
+static void drivfrcg_modify_color(UINT8 *color);
+
+static void (*modify_ypos)(UINT8*); /* function to call to do modify how vertical positioning bits are connected */
+static void frogger_modify_ypos(UINT8 *sy);
+
+static TIMER_CALLBACK( stars_blink_callback );
+static TIMER_CALLBACK( stars_scroll_callback );
+
+static void (*tilemap_set_scroll)( tilemap *, int col, int value );
+
+/* star circuit */
+#define STAR_COUNT 252
+struct star
+{
+ int x,y,color;
+};
+static struct star stars[STAR_COUNT];
+static int stars_colors_start;
+ UINT8 galaxian_stars_on;
+static INT32 stars_scrollpos;
+static UINT8 stars_blink_state;
+static emu_timer *stars_blink_timer;
+static emu_timer *stars_scroll_timer;
+static UINT8 timer_adjusted;
+ void galaxian_init_stars(running_machine *machine, int colors_offset);
+static void (*draw_stars)(running_machine *, mame_bitmap *); /* function to call to draw the star layer */
+static void noop_draw_stars(running_machine *machine, mame_bitmap *bitmap);
+ void galaxian_draw_stars(running_machine *machine, mame_bitmap *bitmap);
+static void scramble_draw_stars(running_machine *machine, mame_bitmap *bitmap);
+static void rescue_draw_stars(running_machine *machine, mame_bitmap *bitmap);
+static void mariner_draw_stars(running_machine *machine, mame_bitmap *bitmap);
+static void jumpbug_draw_stars(running_machine *machine, mame_bitmap *bitmap);
+static void start_stars_blink_timer(double ra, double rb, double c);
+static void start_stars_scroll_timer(void);
+
+/* bullets circuit */
+static UINT8 darkplnt_bullet_color;
+static void (*draw_bullets)(running_machine *, mame_bitmap *,int,int,int); /* function to call to draw a bullet */
+static void galaxian_draw_bullets(running_machine *machine, mame_bitmap *bitmap, int offs, int x, int y);
+static void gteikob2_draw_bullets(running_machine *machine, mame_bitmap *bitmap, int offs, int x, int y);
+static void scramble_draw_bullets(running_machine *machine, mame_bitmap *bitmap, int offs, int x, int y);
+static void theend_draw_bullets(running_machine *machine, mame_bitmap *bitmap, int offs, int x, int y);
+static void darkplnt_draw_bullets(running_machine *machine, mame_bitmap *bitmap, int offs, int x, int y);
+static void dambustr_draw_bullets(running_machine *machine, mame_bitmap *bitmap, int offs, int x, int y);
+
+/* background circuit */
+static UINT8 background_enable;
+static UINT8 background_red, background_green, background_blue;
+static void (*draw_background)(running_machine *, mame_bitmap *); /* function to call to draw the background */
+static void galaxian_draw_background(running_machine *machine, mame_bitmap *bitmap);
+static void scramble_draw_background(running_machine *machine, mame_bitmap *bitmap);
+static void turtles_draw_background(running_machine *machine, mame_bitmap *bitmap);
+static void mariner_draw_background(running_machine *machine, mame_bitmap *bitmap);
+static void frogger_draw_background(running_machine *machine, mame_bitmap *bitmap);
+static void stratgyx_draw_background(running_machine *machine, mame_bitmap *bitmap);
+static void minefld_draw_background(running_machine *machine, mame_bitmap *bitmap);
+static void rescue_draw_background(running_machine *machine, mame_bitmap *bitmap);
+static void dambustr_draw_background(running_machine *machine, mame_bitmap *bitmap);
+
+static UINT16 rockclim_v;
+static UINT16 rockclim_h;
+static int dambustr_bg_split_line;
+static int dambustr_bg_color_1;
+static int dambustr_bg_color_2;
+static int dambustr_bg_priority;
+static int dambustr_char_bank;
+static mame_bitmap *dambustr_tmpbitmap;
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Galaxian has one 32 bytes palette PROM, connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+ The output of the background star generator is connected this way:
+
+ bit 5 -- 100 ohm resistor -- BLUE
+ -- 150 ohm resistor -- BLUE
+ -- 100 ohm resistor -- GREEN
+ -- 150 ohm resistor -- GREEN
+ -- 100 ohm resistor -- RED
+ bit 0 -- 150 ohm resistor -- RED
+
+ The blue background in Scramble and other games goes through a 390 ohm
+ resistor.
+
+ The bullet RGB outputs go through 100 ohm resistors.
+
+ The RGB outputs have a 470 ohm pull-down each.
+
+***************************************************************************/
+PALETTE_INIT( galaxian )
+{
+ int i;
+
+
+ /* first, the character/sprite palette */
+
+ for (i = 0;i < memory_region_length(REGION_PROMS);i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = BIT(*color_prom,0);
+ bit1 = BIT(*color_prom,1);
+ bit2 = BIT(*color_prom,2);
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = BIT(*color_prom,3);
+ bit1 = BIT(*color_prom,4);
+ bit2 = BIT(*color_prom,5);
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = BIT(*color_prom,6);
+ bit1 = BIT(*color_prom,7);
+ b = 0x4f * bit0 + 0xa8 * bit1;
+
+ palette_set_color_rgb(machine,i,r,g,b);
+ color_prom++;
+ }
+
+
+ galaxian_init_stars(machine, STARS_COLOR_BASE);
+
+
+ /* bullets - yellow and white */
+ palette_set_color(machine,BULLETS_COLOR_BASE+0,MAKE_RGB(0xef,0xef,0x00));
+ palette_set_color(machine,BULLETS_COLOR_BASE+1,MAKE_RGB(0xef,0xef,0xef));
+}
+
+PALETTE_INIT( scramble )
+{
+ palette_init_galaxian(machine, colortable, color_prom);
+
+
+ /* blue background - 390 ohm resistor */
+ palette_set_color(machine,BACKGROUND_COLOR_BASE,MAKE_RGB(0,0,0x56));
+}
+
+PALETTE_INIT( moonwar )
+{
+ palette_init_scramble(machine, colortable, color_prom);
+
+
+ /* wire mod to connect the bullet blue output to the 220 ohm resistor */
+ palette_set_color(machine,BULLETS_COLOR_BASE+0,MAKE_RGB(0xef,0xef,0x97));
+}
+
+PALETTE_INIT( turtles )
+{
+ int i;
+
+
+ palette_init_galaxian(machine, colortable, color_prom);
+
+
+ /* The background color generator is connected this way:
+
+ RED - 390 ohm resistor
+ GREEN - 470 ohm resistor
+ BLUE - 390 ohm resistor */
+
+ for (i = 0; i < 8; i++)
+ {
+ int r = BIT(i,0) * 0x55;
+ int g = BIT(i,1) * 0x47;
+ int b = BIT(i,2) * 0x55;
+
+ palette_set_color_rgb(machine,BACKGROUND_COLOR_BASE+i,r,g,b);
+ }
+}
+
+PALETTE_INIT( stratgyx )
+{
+ int i;
+
+
+ palette_init_galaxian(machine, colortable, color_prom);
+
+
+ /* The background color generator is connected this way:
+
+ RED - 270 ohm resistor
+ GREEN - 560 ohm resistor
+ BLUE - 470 ohm resistor */
+
+ for (i = 0; i < 8; i++)
+ {
+ int r = BIT(i,0) * 0x7c;
+ int g = BIT(i,1) * 0x3c;
+ int b = BIT(i,2) * 0x47;
+
+ palette_set_color_rgb(machine,BACKGROUND_COLOR_BASE+i,r,g,b);
+ }
+}
+
+PALETTE_INIT( frogger )
+{
+ palette_init_galaxian(machine, colortable, color_prom);
+
+
+ /* blue background - 470 ohm resistor */
+ palette_set_color(machine,BACKGROUND_COLOR_BASE,MAKE_RGB(0,0,0x47));
+}
+
+PALETTE_INIT( rockclim )
+{
+ int i;
+
+
+ /* first, the character/sprite palette */
+
+ for (i = 0;i < memory_region_length(REGION_PROMS);i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = BIT(*color_prom,0);
+ bit1 = BIT(*color_prom,1);
+ bit2 = BIT(*color_prom,2);
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = BIT(*color_prom,3);
+ bit1 = BIT(*color_prom,4);
+ bit2 = BIT(*color_prom,5);
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = BIT(*color_prom,6);
+ bit1 = BIT(*color_prom,7);
+ b = 0x4f * bit0 + 0xa8 * bit1;
+
+ palette_set_color_rgb(machine,i,r,g,b);
+ color_prom++;
+ }
+}
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Dark Planet has one 32 bytes palette PROM, connected to the RGB output this way:
+
+ bit 5 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 1 kohm resistor -- BLUE
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+ The bullet RGB outputs go through 100 ohm resistors.
+
+ The RGB outputs have a 470 ohm pull-down each.
+
+***************************************************************************/
+PALETTE_INIT( darkplnt )
+{
+ int i;
+
+
+ /* first, the character/sprite palette */
+
+ for (i = 0;i < 32;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = BIT(*color_prom,0);
+ bit1 = BIT(*color_prom,1);
+ bit2 = BIT(*color_prom,2);
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ g = 0x00;
+ /* blue component */
+ bit0 = BIT(*color_prom,3);
+ bit1 = BIT(*color_prom,4);
+ bit2 = BIT(*color_prom,5);
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color_rgb(machine,i,r,g,b);
+ color_prom++;
+ }
+
+
+ /* bullets - red and blue */
+ palette_set_color(machine,BULLETS_COLOR_BASE+0,MAKE_RGB(0xef,0x00,0x00));
+ palette_set_color(machine,BULLETS_COLOR_BASE+1,MAKE_RGB(0x00,0x00,0xef));
+}
+
+PALETTE_INIT( minefld )
+{
+ int i;
+
+
+ palette_init_galaxian(machine, colortable, color_prom);
+
+
+ /* set up background colors */
+
+ /* graduated blue */
+
+ for (i = 0; i < 128; i++)
+ {
+ int r = 0;
+ int g = i;
+ int b = i * 2;
+ palette_set_color_rgb(machine,BACKGROUND_COLOR_BASE+i,r,g,b);
+ }
+
+ /* graduated brown */
+
+ for (i = 0; i < 128; i++)
+ {
+ int r = i * 1.5;
+ int g = i * 0.75;
+ int b = i / 2;
+ palette_set_color_rgb(machine,BACKGROUND_COLOR_BASE+128+i,r,g,b);
+ }
+}
+
+PALETTE_INIT( rescue )
+{
+ int i;
+
+
+ palette_init_galaxian(machine, colortable, color_prom);
+
+
+ /* set up background colors */
+
+ /* graduated blue */
+
+ for (i = 0; i < 128; i++)
+ {
+ int r = 0;
+ int g = i;
+ int b = i * 2;
+ palette_set_color_rgb(machine,BACKGROUND_COLOR_BASE+i,r,g,b);
+ }
+}
+
+PALETTE_INIT( mariner )
+{
+ int i;
+
+
+ palette_init_galaxian(machine, colortable, color_prom);
+
+
+ /* set up background colors */
+
+ /* 16 shades of blue - the 4 bits are connected to the following resistors:
+
+ bit 0 -- 4.7 kohm resistor
+ -- 2.2 kohm resistor
+ -- 1 kohm resistor
+ bit 0 -- .47 kohm resistor */
+
+ for (i = 0; i < 16; i++)
+ {
+ int r,g,b;
+
+ r = 0;
+ g = 0;
+ b = 0x0e * BIT(i,0) + 0x1f * BIT(i,1) + 0x43 * BIT(i,2) + 0x8f * BIT(i,3);
+
+ palette_set_color_rgb(machine,BACKGROUND_COLOR_BASE+i,r,g,b);
+ }
+}
+
+
+PALETTE_INIT( dambustr )
+{
+ int i;
+
+ palette_init_galaxian(machine, colortable, color_prom);
+
+
+ /*
+ Assumption (not clear from the schematics):
+ The background color generator is connected this way:
+
+ RED - 470 ohm resistor
+ GREEN - 470 ohm resistor
+ BLUE - 470 ohm resistor */
+
+
+ for (i = 0; i < 8; i++)
+ {
+ int r = BIT(i,0) * 0x47;
+ int g = BIT(i,1) * 0x47;
+ int b = BIT(i,2) * 0x4f;
+ palette_set_color_rgb(machine,BACKGROUND_COLOR_BASE+i,r,g,b);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+static void state_save_register(void)
+{
+ state_save_register_global_array(gfxbank);
+ state_save_register_global(flipscreen_x);
+ state_save_register_global(flipscreen_y);
+
+ state_save_register_global(galaxian_stars_on);
+ state_save_register_global(stars_scrollpos);
+ state_save_register_global(stars_blink_state);
+
+ state_save_register_global(darkplnt_bullet_color);
+
+ state_save_register_global(background_enable);
+ state_save_register_global(background_red);
+ state_save_register_global(background_green);
+ state_save_register_global(background_blue);
+}
+
+static void video_start_common(running_machine *machine, tilemap_mapper_callback get_memory_offset)
+{
+ bg_tilemap = tilemap_create(get_tile_info,get_memory_offset,TILEMAP_TYPE_PEN,8,8,32,32);
+ tilemap_set_scrolldx(bg_tilemap, 0, -128);
+
+ tilemap_set_transparent_pen(bg_tilemap,0);
+
+
+ modify_charcode = 0;
+ modify_spritecode = 0;
+ modify_color = 0;
+ modify_ypos = 0;
+
+ mooncrst_gfxextend = 0;
+
+ draw_bullets = 0;
+
+ draw_background = galaxian_draw_background;
+ background_enable = 0;
+ background_blue = 0;
+ background_red = 0;
+ background_green = 0;
+
+ draw_stars = noop_draw_stars;
+
+ flipscreen_x = 0;
+ flipscreen_y = 0;
+
+ spriteram2_present = 0;
+
+ spritevisiblearea = &_spritevisiblearea;
+ spritevisibleareaflipx = &_spritevisibleareaflipx;
+
+ color_mask = (machine->gfx[0]->color_granularity == 4) ? 7 : 3;
+
+ state_save_register();
+}
+
+VIDEO_START( galaxian_plain )
+{
+ video_start_common(machine,tilemap_scan_rows);
+
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+ tilemap_set_scroll = tilemap_set_scrolly;
+}
+
+VIDEO_START( galaxian )
+{
+ video_start_galaxian_plain(machine);
+
+ draw_stars = galaxian_draw_stars;
+
+ draw_bullets = galaxian_draw_bullets;
+}
+
+VIDEO_START( gmgalax )
+{
+ video_start_galaxian(machine);
+
+ modify_charcode = gmgalax_modify_charcode;
+ modify_spritecode = gmgalax_modify_spritecode;
+ modify_color = gmgalax_modify_color;
+}
+
+VIDEO_START( mooncrst )
+{
+ video_start_galaxian(machine);
+
+ modify_charcode = mooncrst_modify_charcode;
+ modify_spritecode = mooncrst_modify_spritecode;
+}
+
+VIDEO_START( mooncrgx )
+{
+ video_start_galaxian(machine);
+
+ modify_charcode = mooncrgx_modify_charcode;
+ modify_spritecode = mooncrgx_modify_spritecode;
+}
+
+VIDEO_START( moonqsr )
+{
+ video_start_galaxian(machine);
+
+ modify_charcode = moonqsr_modify_charcode;
+ modify_spritecode = moonqsr_modify_spritecode;
+}
+
+VIDEO_START( mshuttle )
+{
+ video_start_galaxian(machine);
+
+ modify_charcode = mshuttle_modify_charcode;
+ modify_spritecode = mshuttle_modify_spritecode;
+}
+
+VIDEO_START( pisces )
+{
+ video_start_galaxian(machine);
+
+ modify_charcode = pisces_modify_charcode;
+ modify_spritecode = pisces_modify_spritecode;
+}
+
+VIDEO_START( gteikob2 )
+{
+ video_start_pisces(machine);
+
+ draw_bullets = gteikob2_draw_bullets;
+}
+
+VIDEO_START( batman2 )
+{
+ video_start_galaxian(machine);
+
+ modify_charcode = batman2_modify_charcode;
+ modify_spritecode = batman2_modify_spritecode;
+
+}
+
+VIDEO_START( scramble )
+{
+ video_start_galaxian_plain(machine);
+
+ draw_stars = scramble_draw_stars;
+
+ draw_bullets = scramble_draw_bullets;
+
+ draw_background = scramble_draw_background;
+}
+
+VIDEO_START( sfx )
+{
+ video_start_common(machine,tilemap_scan_cols);
+
+ tilemap_set_scroll_rows(bg_tilemap, 32);
+ tilemap_set_scroll = tilemap_set_scrollx;
+
+ draw_stars = scramble_draw_stars;
+
+ draw_bullets = scramble_draw_bullets;
+
+ draw_background = turtles_draw_background;
+}
+
+VIDEO_START( turtles )
+{
+ video_start_galaxian_plain(machine);
+
+ draw_background = turtles_draw_background;
+}
+
+VIDEO_START( theend )
+{
+ video_start_galaxian(machine);
+
+ draw_bullets = theend_draw_bullets;
+}
+
+VIDEO_START( darkplnt )
+{
+ video_start_galaxian_plain(machine);
+
+ draw_bullets = darkplnt_draw_bullets;
+}
+
+VIDEO_START( rescue )
+{
+ video_start_scramble(machine);
+
+ draw_stars = rescue_draw_stars;
+
+ draw_background = rescue_draw_background;
+}
+
+VIDEO_START( minefld )
+{
+ video_start_scramble(machine);
+
+ draw_stars = rescue_draw_stars;
+
+ draw_background = minefld_draw_background;
+}
+
+VIDEO_START( stratgyx )
+{
+ video_start_galaxian_plain(machine);
+
+ draw_background = stratgyx_draw_background;
+}
+
+VIDEO_START( ckongs )
+{
+ video_start_scramble(machine);
+
+ modify_spritecode = mshuttle_modify_spritecode;
+}
+
+VIDEO_START( calipso )
+{
+ video_start_galaxian_plain(machine);
+
+ draw_bullets = scramble_draw_bullets;
+
+ draw_background = scramble_draw_background;
+
+ modify_spritecode = calipso_modify_spritecode;
+}
+
+VIDEO_START( mariner )
+{
+ video_start_galaxian_plain(machine);
+
+ draw_stars = mariner_draw_stars;
+
+ draw_bullets = scramble_draw_bullets;
+
+ draw_background = mariner_draw_background;
+
+ modify_charcode = mariner_modify_charcode;
+}
+
+VIDEO_START( froggers )
+{
+ video_start_galaxian_plain(machine);
+
+ draw_background = frogger_draw_background;
+ modify_color = frogger_modify_color;
+}
+
+VIDEO_START( frogger )
+{
+ video_start_froggers(machine);
+
+ modify_ypos = frogger_modify_ypos;
+}
+
+VIDEO_START( jumpbug )
+{
+ video_start_scramble(machine);
+
+ draw_stars = jumpbug_draw_stars;
+
+ modify_charcode = jumpbug_modify_charcode;
+ modify_spritecode = jumpbug_modify_spritecode;
+}
+
+VIDEO_START( azurian )
+{
+ video_start_galaxian_plain(machine);
+
+ draw_stars = galaxian_draw_stars;
+ draw_bullets = scramble_draw_bullets; /* Shots are yellow like in Scramble */
+}
+
+VIDEO_START( mimonkey )
+{
+ video_start_scramble(machine);
+
+ modify_charcode = mimonkey_modify_charcode;
+ modify_spritecode = mimonkey_modify_spritecode;
+}
+
+VIDEO_START( dkongjrm )
+{
+ video_start_galaxian_plain(machine);
+
+ modify_charcode = pisces_modify_charcode;
+ modify_spritecode = dkongjrm_modify_spritecode;
+
+ spriteram2_present= 1;
+}
+
+VIDEO_START( newsin7 )
+{
+ video_start_scramble(machine);
+
+ spritevisiblearea = &_spritevisibleareaflipx;
+ spritevisibleareaflipx = &_spritevisiblearea;
+}
+
+VIDEO_START( scorpion )
+{
+ video_start_scramble(machine);
+
+ modify_spritecode = batman2_modify_spritecode;
+}
+
+static void rockclim_draw_background(running_machine *machine, mame_bitmap *bitmap)
+{
+ tilemap_draw(bitmap,0,rockclim_tilemap, 0,0);
+}
+
+static void rockclim_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
+{
+ if (gfxbank[2]) *code|=0x40;
+}
+
+VIDEO_START( rockclim )
+{
+ video_start_galaxian(machine);
+ rockclim_tilemap = tilemap_create(rockclim_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ draw_background = rockclim_draw_background;
+ modify_charcode = mooncrst_modify_charcode;
+ modify_spritecode = rockclim_modify_spritecode;
+ rockclim_v = rockclim_h = 0;
+ state_save_register_global(rockclim_v);
+ state_save_register_global(rockclim_h);
+}
+
+static TILE_GET_INFO( drivfrcg_get_tile_info )
+{
+ int code = galaxian_videoram[tile_index];
+ UINT8 x = tile_index & 0x1f;
+ UINT8 color = galaxian_attributesram[(x << 1) | 1] & 7;
+ UINT8 bank = galaxian_attributesram[(x << 1) | 1] & 0x30;
+
+ code |= (bank << 4);
+ color |= ((galaxian_attributesram[(x << 1) | 1] & 0x40) >> 3);
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( drivfrcg )
+{
+ bg_tilemap = tilemap_create(drivfrcg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(bg_tilemap,0);
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+ tilemap_set_scroll = tilemap_set_scrolly;
+
+ modify_charcode = 0;
+ modify_spritecode = mshuttle_modify_spritecode;
+ modify_color = drivfrcg_modify_color;
+ modify_ypos = 0;
+
+ mooncrst_gfxextend = 0;
+
+ draw_bullets = 0;
+
+ draw_background = galaxian_draw_background;
+ background_enable = 0;
+ background_blue = 0;
+ background_red = 0;
+ background_green = 0;
+
+ draw_stars = noop_draw_stars;
+
+ flipscreen_x = 0;
+ flipscreen_y = 0;
+
+ spriteram2_present = 0;
+
+ spritevisiblearea = &_spritevisiblearea;
+ spritevisibleareaflipx = &_spritevisibleareaflipx;
+
+ color_mask = 0xff;
+
+ state_save_register();
+}
+
+VIDEO_START( ad2083 )
+{
+ bg_tilemap = tilemap_create(drivfrcg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(bg_tilemap,0);
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+ tilemap_set_scroll = tilemap_set_scrolly;
+
+ modify_charcode = 0;
+ modify_spritecode = ad2083_modify_spritecode;
+ modify_color = 0;
+ modify_ypos = 0;
+
+ mooncrst_gfxextend = 0;
+
+ draw_bullets = scramble_draw_bullets;
+
+ draw_background = turtles_draw_background;
+ background_enable = 0;
+ background_blue = 0;
+ background_red = 0;
+ background_green = 0;
+
+ draw_stars = noop_draw_stars;
+
+ flipscreen_x = 0;
+ flipscreen_y = 0;
+
+ spriteram2_present = 0;
+
+ spritevisiblearea = &_spritevisiblearea;
+ spritevisibleareaflipx = &_spritevisibleareaflipx;
+
+ color_mask = 7;
+
+ state_save_register();
+}
+
+UINT8 *racknrol_tiles_bank;
+
+WRITE8_HANDLER( racknrol_tiles_bank_w )
+{
+ racknrol_tiles_bank[offset] = data;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+}
+
+static TILE_GET_INFO( racknrol_get_tile_info )
+{
+ int code = galaxian_videoram[tile_index];
+ UINT8 x = tile_index & 0x1f;
+ UINT8 color = galaxian_attributesram[(x << 1) | 1] & 7;
+ UINT8 bank = racknrol_tiles_bank[x] & 7;
+
+ code |= (bank << 8);
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( racknrol )
+{
+ bg_tilemap = tilemap_create(racknrol_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(bg_tilemap,0);
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+ tilemap_set_scroll = tilemap_set_scrolly;
+
+ modify_charcode = 0;
+ modify_spritecode = 0;
+ modify_color = 0;
+ modify_ypos = 0;
+
+ mooncrst_gfxextend = 0;
+
+ draw_bullets = 0;
+
+ draw_background = galaxian_draw_background;
+ background_enable = 0;
+ background_blue = 0;
+ background_red = 0;
+ background_green = 0;
+
+ draw_stars = noop_draw_stars;
+
+ flipscreen_x = 0;
+ flipscreen_y = 0;
+
+ spriteram2_present = 0;
+
+ spritevisiblearea = &_spritevisiblearea;
+ spritevisibleareaflipx = &_spritevisibleareaflipx;
+
+ color_mask = 0xff;
+
+ state_save_register();
+}
+
+VIDEO_START( bongo )
+{
+ video_start_galaxian_plain(machine);
+
+ modify_spritecode = batman2_modify_spritecode;
+}
+
+static TILE_GET_INFO( dambustr_get_tile_info2 )
+{
+ UINT8 x = tile_index & 0x1f;
+
+ UINT16 code = dambustr_videoram2[tile_index];
+ UINT8 color = galaxian_attributesram[(x << 1) | 1] & color_mask;
+
+ if (modify_charcode)
+ {
+ modify_charcode(&code, x);
+ }
+
+ if (modify_color)
+ {
+ modify_color(&color);
+ }
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( dambustr )
+{
+ video_start_galaxian(machine);
+
+ dambustr_bg_split_line = 0;
+ dambustr_bg_color_1 = 0;
+ dambustr_bg_color_2 = 0;
+ dambustr_bg_priority = 0;
+ dambustr_char_bank = 0;
+
+ draw_background = dambustr_draw_background;
+
+ modify_charcode = dambustr_modify_charcode;
+ modify_spritecode = dambustr_modify_spritecode;
+
+ draw_bullets = dambustr_draw_bullets;
+
+ /* allocate the temporary bitmap for the background priority */
+ dambustr_tmpbitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ /* make a copy of the tilemap to emulate background priority */
+ dambustr_videoram2 = auto_malloc(0x0400);
+ dambustr_tilemap2 = tilemap_create(dambustr_get_tile_info2,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(dambustr_tilemap2,0);
+}
+
+
+WRITE8_HANDLER( galaxian_videoram_w )
+{
+ galaxian_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+READ8_HANDLER( galaxian_videoram_r )
+{
+ return galaxian_videoram[offset];
+}
+
+
+WRITE8_HANDLER( galaxian_attributesram_w )
+{
+ if (galaxian_attributesram[offset] != data)
+ {
+ if (offset & 0x01)
+ {
+ /* color change */
+ int i;
+
+ for (i = offset >> 1; i < 0x0400; i += 32)
+ tilemap_mark_tile_dirty(bg_tilemap, i);
+ }
+ else
+ {
+ if (modify_ypos)
+ {
+ modify_ypos(&data);
+ }
+
+ tilemap_set_scroll(bg_tilemap, offset >> 1, data);
+ }
+
+ galaxian_attributesram[offset] = data;
+ }
+}
+
+
+WRITE8_HANDLER( galaxian_flip_screen_x_w )
+{
+ if (flipscreen_x != (data & 0x01))
+ {
+ flipscreen_x = data & 0x01;
+
+ tilemap_set_flip(bg_tilemap, (flipscreen_x ? TILEMAP_FLIPX : 0) | (flipscreen_y ? TILEMAP_FLIPY : 0));
+ }
+}
+
+WRITE8_HANDLER( galaxian_flip_screen_y_w )
+{
+ if (flipscreen_y != (data & 0x01))
+ {
+ flipscreen_y = data & 0x01;
+
+ tilemap_set_flip(bg_tilemap, (flipscreen_x ? TILEMAP_FLIPX : 0) | (flipscreen_y ? TILEMAP_FLIPY : 0));
+ }
+}
+
+
+WRITE8_HANDLER( gteikob2_flip_screen_x_w )
+{
+ galaxian_flip_screen_x_w(offset, ~data);
+}
+
+WRITE8_HANDLER( gteikob2_flip_screen_y_w )
+{
+ galaxian_flip_screen_y_w(offset, ~data);
+}
+
+
+WRITE8_HANDLER( hotshock_flip_screen_w )
+{
+ galaxian_flip_screen_x_w(offset, data);
+ galaxian_flip_screen_y_w(offset, data);
+}
+
+
+WRITE8_HANDLER( scramble_background_enable_w )
+{
+ background_enable = data & 0x01;
+}
+
+WRITE8_HANDLER( scramble_background_red_w )
+{
+ background_red = data & 0x01;
+}
+
+WRITE8_HANDLER( scramble_background_green_w )
+{
+ background_green = data & 0x01;
+}
+
+WRITE8_HANDLER( scramble_background_blue_w )
+{
+ background_blue = data & 0x01;
+}
+
+
+WRITE8_HANDLER( galaxian_stars_enable_w )
+{
+ galaxian_stars_on = data & 0x01;
+
+ if (!galaxian_stars_on)
+ {
+ stars_scrollpos = 0;
+ }
+}
+
+
+WRITE8_HANDLER( darkplnt_bullet_color_w )
+{
+ darkplnt_bullet_color = data & 0x01;
+}
+
+
+
+WRITE8_HANDLER( galaxian_gfxbank_w )
+{
+ if (gfxbank[offset] != data)
+ {
+ gfxbank[offset] = data;
+
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+WRITE8_HANDLER( rockclim_videoram_w )
+{
+ rockclim_videoram[offset] = data;
+ tilemap_mark_tile_dirty(rockclim_tilemap, offset);
+}
+
+WRITE8_HANDLER( rockclim_scroll_w )
+{
+ switch(offset&3)
+ {
+ case 0: rockclim_h=(rockclim_h&0xff00)|data;tilemap_set_scrollx(rockclim_tilemap , 0, rockclim_h );break;
+ case 1: rockclim_h=(rockclim_h&0xff)|(data<<8);tilemap_set_scrollx(rockclim_tilemap , 0, rockclim_h );break;
+ case 2: rockclim_v=(rockclim_v&0xff00)|data;tilemap_set_scrolly(rockclim_tilemap , 0, rockclim_v );break;
+ case 3: rockclim_v=(rockclim_v&0xff)|(data<<8);tilemap_set_scrolly(rockclim_tilemap , 0, rockclim_v );break;
+ }
+
+}
+
+
+READ8_HANDLER( rockclim_videoram_r )
+{
+ return rockclim_videoram[offset];
+}
+
+
+WRITE8_HANDLER( dambustr_bg_split_line_w )
+{
+ dambustr_bg_split_line = data;
+}
+
+
+WRITE8_HANDLER( dambustr_bg_color_w )
+{
+ dambustr_bg_color_1 = (BIT(data,2)<<2) | (BIT(data,1)<<1) | BIT(data,0);
+ dambustr_bg_color_2 = (BIT(data,6)<<2) | (BIT(data,5)<<1) | BIT(data,4);
+ dambustr_bg_priority = BIT(data,3);
+ dambustr_char_bank = BIT(data,7);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+}
+
+
+
+/* character banking functions */
+
+static void gmgalax_modify_charcode(UINT16 *code,UINT8 x)
+{
+ *code |= (gfxbank[0] << 9);
+}
+
+static void mooncrst_modify_charcode(UINT16 *code,UINT8 x)
+{
+ if (gfxbank[2] && ((*code & 0xc0) == 0x80))
+ {
+ *code = (*code & 0x3f) | (gfxbank[0] << 6) | (gfxbank[1] << 7) | 0x0100;
+ }
+}
+
+static void mooncrgx_modify_charcode(UINT16 *code,UINT8 x)
+{
+ if (gfxbank[2] && ((*code & 0xc0) == 0x80))
+ {
+ *code = (*code & 0x3f) | (gfxbank[1] << 6) | (gfxbank[0] << 7) | 0x0100;
+ }
+}
+
+static void moonqsr_modify_charcode(UINT16 *code,UINT8 x)
+{
+ *code |= ((galaxian_attributesram[(x << 1) | 1] & 0x20) << 3);
+}
+
+static void mshuttle_modify_charcode(UINT16 *code,UINT8 x)
+{
+ *code |= ((galaxian_attributesram[(x << 1) | 1] & 0x30) << 4);
+}
+
+static void pisces_modify_charcode(UINT16 *code,UINT8 x)
+{
+ *code |= (gfxbank[0] << 8);
+}
+
+static void mimonkey_modify_charcode(UINT16 *code,UINT8 x)
+{
+ *code |= (gfxbank[0] << 8) | (gfxbank[2] << 9);
+}
+
+static void batman2_modify_charcode(UINT16 *code,UINT8 x)
+{
+ if (*code & 0x80)
+ {
+ *code |= (gfxbank[0] << 8);
+ }
+}
+
+static void mariner_modify_charcode(UINT16 *code,UINT8 x)
+{
+ UINT8 *prom;
+
+
+ /* bit 0 of the PROM controls character banking */
+
+ prom = memory_region(REGION_USER2);
+
+ *code |= ((prom[x] & 0x01) << 8);
+}
+
+static void jumpbug_modify_charcode(UINT16 *code,UINT8 x)
+{
+ if (((*code & 0xc0) == 0x80) &&
+ (gfxbank[2] & 0x01))
+ {
+ *code += 128 + (( gfxbank[0] & 0x01) << 6) +
+ (( gfxbank[1] & 0x01) << 7) +
+ ((~gfxbank[4] & 0x01) << 8);
+ }
+}
+
+
+static void dambustr_modify_charcode(UINT16 *code,UINT8 x)
+{
+ if (dambustr_char_bank == 0) { // text mode
+ *code |= 0x0300;
+ }
+ else { // graphics mode
+ if (x == 28) // only line #28 stays in text mode
+ *code |= 0x0300;
+ else
+ *code &= 0x00ff;
+ };
+}
+
+
+
+/* sprite banking functions */
+
+static void gmgalax_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
+{
+ *code |= (gfxbank[0] << 7) | 0x40;
+}
+
+static void mooncrst_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
+{
+ if (gfxbank[2] && ((*code & 0x30) == 0x20))
+ {
+ *code = (*code & 0x0f) | (gfxbank[0] << 4) | (gfxbank[1] << 5) | 0x40;
+ }
+}
+
+static void mooncrgx_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
+{
+ if (gfxbank[2] && ((*code & 0x30) == 0x20))
+ {
+ *code = (*code & 0x0f) | (gfxbank[1] << 4) | (gfxbank[0] << 5) | 0x40;
+ }
+}
+
+static void moonqsr_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
+{
+ *code |= ((spriteram[offs + 2] & 0x20) << 1);
+}
+
+static void mshuttle_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
+{
+ *code |= ((spriteram[offs + 2] & 0x30) << 2);
+}
+
+static void calipso_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
+{
+ /* No flips */
+ *code = spriteram[offs + 1];
+ *flipx = 0;
+ *flipy = 0;
+}
+
+static void pisces_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
+{
+ *code |= (gfxbank[0] << 6);
+}
+
+static void mimonkey_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
+{
+ *code |= (gfxbank[0] << 6) | (gfxbank[2] << 7);
+}
+
+static void batman2_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
+{
+ /* only the upper 64 sprites are used */
+ *code |= 0x40;
+}
+
+static void jumpbug_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
+{
+ if (((*code & 0x30) == 0x20) &&
+ (gfxbank[2] & 0x01) != 0)
+ {
+ *code += 32 + (( gfxbank[0] & 0x01) << 4) +
+ (( gfxbank[1] & 0x01) << 5) +
+ ((~gfxbank[4] & 0x01) << 6);
+ }
+}
+
+static void dkongjrm_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
+{
+ /* No x flip */
+ *code = (spriteram[offs + 1] & 0x7f) | 0x80;
+ *flipx = 0;
+}
+
+static void ad2083_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
+{
+ /* No x flip */
+ *code = (spriteram[offs + 1] & 0x7f) | ((spriteram[offs + 2] & 0x30) << 2);
+ *flipx = 0;
+}
+
+static void dambustr_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
+{
+ *code += 0x40;
+}
+
+
+/* color PROM mapping functions */
+
+static void frogger_modify_color(UINT8 *color)
+{
+ *color = ((*color >> 1) & 0x03) | ((*color << 2) & 0x04);
+}
+
+static void gmgalax_modify_color(UINT8 *color)
+{
+ *color |= (gfxbank[0] << 3);
+}
+
+static void drivfrcg_modify_color(UINT8 *color)
+{
+ *color = ((*color & 0x40) >> 3) | (*color & 7);
+}
+
+/* y position mapping functions */
+
+static void frogger_modify_ypos(UINT8 *sy)
+{
+ *sy = (*sy << 4) | (*sy >> 4);
+}
+
+
+/* bullet drawing functions */
+
+static void galaxian_draw_bullets(running_machine *machine, mame_bitmap *bitmap, int offs, int x, int y)
+{
+ int i;
+
+
+ for (i = 0; i < 4; i++)
+ {
+ x--;
+
+ if (x >= machine->screen[0].visarea.min_x &&
+ x <= machine->screen[0].visarea.max_x)
+ {
+ int color;
+
+
+ /* yellow missile, white shells (this is the terminology on the schematics) */
+ color = ((offs == 7*4) ? BULLETS_COLOR_BASE : BULLETS_COLOR_BASE + 1);
+
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[color];
+ }
+ }
+}
+
+static void gteikob2_draw_bullets(running_machine *machine, mame_bitmap *bitmap, int offs, int x, int y)
+{
+ galaxian_draw_bullets(machine, bitmap, offs, 260 - x, y);
+}
+
+static void scramble_draw_bullets(running_machine *machine, mame_bitmap *bitmap, int offs, int x, int y)
+{
+ if (flipscreen_x) x++;
+
+ x = x - 6;
+
+ if (x >= machine->screen[0].visarea.min_x &&
+ x <= machine->screen[0].visarea.max_x)
+ {
+ /* yellow bullets */
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[BULLETS_COLOR_BASE];
+ }
+}
+
+static void darkplnt_draw_bullets(running_machine *machine, mame_bitmap *bitmap, int offs, int x, int y)
+{
+ if (flipscreen_x) x++;
+
+ x = x - 6;
+
+ if (x >= machine->screen[0].visarea.min_x &&
+ x <= machine->screen[0].visarea.max_x)
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[32 + darkplnt_bullet_color];
+ }
+}
+
+static void theend_draw_bullets(running_machine *machine, mame_bitmap *bitmap, int offs, int x, int y)
+{
+ int i;
+
+
+ /* same as Galaxian, but all bullets are yellow */
+ for (i = 0; i < 4; i++)
+ {
+ x--;
+
+ if (x >= machine->screen[0].visarea.min_x &&
+ x <= machine->screen[0].visarea.max_x)
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[BULLETS_COLOR_BASE];
+ }
+ }
+}
+
+static void dambustr_draw_bullets(running_machine *machine, mame_bitmap *bitmap, int offs, int x, int y)
+{
+ int i, color;
+
+ if (flip_screen_x) x++;
+
+ x = x - 6;
+
+ /* bullets are 2 pixels wide */
+ for (i = 0; i < 2; i++)
+ {
+ if (offs < 4*4)
+ {
+ color = BULLETS_COLOR_BASE;
+ y--;
+ }
+ else {
+ color = BULLETS_COLOR_BASE + 1;
+ x--;
+ }
+
+ if (x >= machine->screen[0].visarea.min_x &&
+ x <= machine->screen[0].visarea.max_x)
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[color];
+ }
+ }
+}
+
+
+
+/* background drawing functions */
+
+static void galaxian_draw_background(running_machine *machine, mame_bitmap *bitmap)
+{
+ /* plain black background */
+ fillbitmap(bitmap,machine->pens[0],&machine->screen[0].visarea);
+}
+
+static void scramble_draw_background(running_machine *machine, mame_bitmap *bitmap)
+{
+ if (background_enable)
+ {
+ fillbitmap(bitmap,machine->pens[BACKGROUND_COLOR_BASE],&machine->screen[0].visarea);
+ }
+ else
+ {
+ fillbitmap(bitmap,machine->pens[0],&machine->screen[0].visarea);
+ }
+}
+
+static void turtles_draw_background(running_machine *machine, mame_bitmap *bitmap)
+{
+ int color = (background_blue << 2) | (background_green << 1) | background_red;
+
+ fillbitmap(bitmap,machine->pens[BACKGROUND_COLOR_BASE + color],&machine->screen[0].visarea);
+}
+
+static void frogger_draw_background(running_machine *machine, mame_bitmap *bitmap)
+{
+ /* color split point verified on real machine */
+ if (flipscreen_x)
+ {
+ plot_box(bitmap, 0, 0, 128, 256, machine->pens[0]);
+ plot_box(bitmap, 128, 0, 128, 256, machine->pens[BACKGROUND_COLOR_BASE]);
+ }
+ else
+ {
+ plot_box(bitmap, 0, 0, 128, 256, machine->pens[BACKGROUND_COLOR_BASE]);
+ plot_box(bitmap, 128, 0, 128, 256, machine->pens[0]);
+ }
+}
+
+static void stratgyx_draw_background(running_machine *machine, mame_bitmap *bitmap)
+{
+ UINT8 x;
+ UINT8 *prom;
+
+
+ /* the background PROM is connected the following way:
+
+ bit 0 = 0 enables the blue gun if BCB is asserted
+ bit 1 = 0 enables the red gun if BCR is asserted and
+ the green gun if BCG is asserted
+ bits 2-7 are unconnected */
+
+ prom = memory_region(REGION_USER1);
+
+ for (x = 0; x < 32; x++)
+ {
+ int sx,color;
+
+
+ color = 0;
+
+ if ((~prom[x] & 0x02) && background_red) color |= 0x01;
+ if ((~prom[x] & 0x02) && background_green) color |= 0x02;
+ if ((~prom[x] & 0x01) && background_blue) color |= 0x04;
+
+ if (flipscreen_x)
+ {
+ sx = 8 * (31 - x);
+ }
+ else
+ {
+ sx = 8 * x;
+ }
+
+ plot_box(bitmap, sx, 0, 8, 256, machine->pens[BACKGROUND_COLOR_BASE + color]);
+ }
+}
+
+static void minefld_draw_background(running_machine *machine, mame_bitmap *bitmap)
+{
+ if (background_enable)
+ {
+ int x;
+
+
+ for (x = 0; x < 128; x++)
+ {
+ plot_box(bitmap, x, 0, 1, 256, machine->pens[BACKGROUND_COLOR_BASE + x]);
+ }
+
+ for (x = 0; x < 120; x++)
+ {
+ plot_box(bitmap, x + 128, 0, 1, 256, machine->pens[BACKGROUND_COLOR_BASE + x + 128]);
+ }
+
+ plot_box(bitmap, 248, 0, 16, 256, machine->pens[BACKGROUND_COLOR_BASE]);
+ }
+ else
+ {
+ fillbitmap(bitmap,machine->pens[0],&machine->screen[0].visarea);
+ }
+}
+
+static void rescue_draw_background(running_machine *machine, mame_bitmap *bitmap)
+{
+ if (background_enable)
+ {
+ int x;
+
+
+ for (x = 0; x < 128; x++)
+ {
+ plot_box(bitmap, x, 0, 1, 256, machine->pens[BACKGROUND_COLOR_BASE + x]);
+ }
+
+ for (x = 0; x < 120; x++)
+ {
+ plot_box(bitmap, x + 128, 0, 1, 256, machine->pens[BACKGROUND_COLOR_BASE + x + 8]);
+ }
+
+ plot_box(bitmap, 248, 0, 16, 256, machine->pens[BACKGROUND_COLOR_BASE]);
+ }
+ else
+ {
+ fillbitmap(bitmap,machine->pens[0],&machine->screen[0].visarea);
+ }
+}
+
+static void mariner_draw_background(running_machine *machine, mame_bitmap *bitmap)
+{
+ UINT8 x;
+ UINT8 *prom;
+
+
+ /* the background PROM contains the color codes for each 8 pixel
+ line (column) of the screen. The first 0x20 bytes for unflipped,
+ and the 2nd 0x20 bytes for flipped screen. */
+
+ prom = memory_region(REGION_USER1);
+
+ if (flipscreen_x)
+ {
+ for (x = 0; x < 32; x++)
+ {
+ int color;
+
+
+ if (x == 0)
+ color = 0;
+ else
+ color = prom[0x20 + x - 1];
+
+ plot_box(bitmap, 8 * (31 - x), 0, 8, 256, machine->pens[BACKGROUND_COLOR_BASE + color]);
+ }
+ }
+ else
+ {
+ for (x = 0; x < 32; x++)
+ {
+ int color;
+
+
+ if (x == 31)
+ color = 0;
+ else
+ color = prom[x + 1];
+
+ plot_box(bitmap, 8 * x, 0, 8, 256, machine->pens[BACKGROUND_COLOR_BASE + color]);
+ }
+ }
+}
+
+static void dambustr_draw_background(running_machine *machine, mame_bitmap *bitmap)
+{
+ int col1 = BACKGROUND_COLOR_BASE + dambustr_bg_color_1;
+ int col2 = BACKGROUND_COLOR_BASE + dambustr_bg_color_2;
+
+ if (flip_screen_x)
+ {
+ plot_box(bitmap, 0, 0, 256-dambustr_bg_split_line, 256, machine->pens[col2]);
+ plot_box(bitmap, 256-dambustr_bg_split_line, 0, dambustr_bg_split_line, 256, machine->pens[col1]);
+ }
+ else
+ {
+ plot_box(bitmap, 0, 0, 256-dambustr_bg_split_line, 256, machine->pens[col1]);
+ plot_box(bitmap, 256-dambustr_bg_split_line, 0, dambustr_bg_split_line, 256, machine->pens[col2]);
+ }
+
+}
+
+static void dambustr_draw_upper_background(mame_bitmap *bitmap)
+{
+ static rectangle clip = { 0, 0, 0, 0 };
+
+ if (flip_screen_x)
+ {
+ clip.min_x = 254 - dambustr_bg_split_line;
+ clip.max_x = dambustr_bg_split_line;
+ clip.min_y = 0;
+ clip.max_y = 255;
+ copybitmap(bitmap, dambustr_tmpbitmap, 0, 0, 0, 0, &clip, TRANSPARENCY_NONE, 0);
+ }
+ else
+ {
+ clip.min_x = 0;
+ clip.max_x = 254 - dambustr_bg_split_line;
+ clip.min_y = 0;
+ clip.max_y = 255;
+ copybitmap(bitmap, dambustr_tmpbitmap, 0, 0, 0, 0, &clip, TRANSPARENCY_NONE, 0);
+ }
+}
+
+
+
+/* star drawing functions */
+
+void galaxian_init_stars(running_machine *machine, int colors_offset)
+{
+ int i;
+ int total_stars;
+ UINT32 generator;
+ int x,y;
+
+
+ galaxian_stars_on = 0;
+ stars_blink_state = 0;
+ stars_blink_timer = timer_alloc(stars_blink_callback);
+ stars_scroll_timer = timer_alloc(stars_scroll_callback);
+ timer_adjusted = 0;
+ stars_colors_start = colors_offset;
+
+ for (i = 0;i < 64;i++)
+ {
+ int bits,r,g,b;
+ static const int map[4] = { 0x00, 0x88, 0xcc, 0xff };
+
+
+ bits = (i >> 0) & 0x03;
+ r = map[bits];
+ bits = (i >> 2) & 0x03;
+ g = map[bits];
+ bits = (i >> 4) & 0x03;
+ b = map[bits];
+ palette_set_color_rgb(machine,colors_offset+i,r,g,b);
+ }
+
+
+ /* precalculate the star background */
+
+ total_stars = 0;
+ generator = 0;
+
+ for (y = 0;y < 256;y++)
+ {
+ for (x = 0;x < 512;x++)
+ {
+ UINT32 bit0;
+
+
+ bit0 = ((~generator >> 16) & 0x01) ^ ((generator >> 4) & 0x01);
+
+ generator = (generator << 1) | bit0;
+
+ if (((~generator >> 16) & 0x01) && (generator & 0xff) == 0xff)
+ {
+ int color;
+
+
+ color = (~(generator >> 8)) & 0x3f;
+ if (color)
+ {
+ stars[total_stars].x = x;
+ stars[total_stars].y = y;
+ stars[total_stars].color = color;
+
+ total_stars++;
+ }
+ }
+ }
+ }
+
+ if (total_stars != STAR_COUNT)
+ {
+ fatalerror("total_stars = %d, STAR_COUNT = %d",total_stars,STAR_COUNT);
+ }
+}
+
+static void plot_star(running_machine *machine, mame_bitmap *bitmap, int x, int y, int color)
+{
+ if (y < machine->screen[0].visarea.min_y ||
+ y > machine->screen[0].visarea.max_y ||
+ x < machine->screen[0].visarea.min_x ||
+ x > machine->screen[0].visarea.max_x)
+ return;
+
+
+ if (flipscreen_x)
+ {
+ x = 255 - x;
+ }
+ if (flipscreen_y)
+ {
+ y = 255 - y;
+ }
+
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[stars_colors_start + color];
+}
+
+static void noop_draw_stars(running_machine *machine, mame_bitmap *bitmap)
+{
+}
+
+void galaxian_draw_stars(running_machine *machine, mame_bitmap *bitmap)
+{
+ int offs;
+
+
+ if (!timer_adjusted)
+ {
+ start_stars_scroll_timer();
+ timer_adjusted = 1;
+ }
+
+
+ for (offs = 0;offs < STAR_COUNT;offs++)
+ {
+ int x,y;
+
+
+ x = ((stars[offs].x + stars_scrollpos) & 0x01ff) >> 1;
+ y = ( stars[offs].y + ((stars_scrollpos + stars[offs].x) >> 9)) & 0xff;
+
+ if ((y & 0x01) ^ ((x >> 3) & 0x01))
+ {
+ plot_star(machine, bitmap, x, y, stars[offs].color);
+ }
+ }
+}
+
+void scramble_draw_stars(running_machine *machine, mame_bitmap *bitmap)
+{
+ int offs;
+
+
+ if (!timer_adjusted)
+ {
+ start_stars_blink_timer(100000, 10000, 0.00001);
+ timer_adjusted = 1;
+ }
+
+
+ for (offs = 0;offs < STAR_COUNT;offs++)
+ {
+ int x,y;
+
+
+ x = stars[offs].x >> 1;
+ y = stars[offs].y;
+
+ if ((y & 0x01) ^ ((x >> 3) & 0x01))
+ {
+ /* determine when to skip plotting */
+ switch (stars_blink_state & 0x03)
+ {
+ case 0:
+ if (!(stars[offs].color & 0x01)) continue;
+ break;
+ case 1:
+ if (!(stars[offs].color & 0x04)) continue;
+ break;
+ case 2:
+ if (!(stars[offs].y & 0x02)) continue;
+ break;
+ case 3:
+ /* always plot */
+ break;
+ }
+
+ plot_star(machine, bitmap, x, y, stars[offs].color);
+ }
+ }
+}
+
+static void rescue_draw_stars(running_machine *machine, mame_bitmap *bitmap)
+{
+ int offs;
+
+
+ /* same as Scramble, but only top (left) half of screen */
+
+ if (!timer_adjusted)
+ {
+ start_stars_blink_timer(100000, 10000, 0.00001);
+ timer_adjusted = 1;
+ }
+
+
+ for (offs = 0;offs < STAR_COUNT;offs++)
+ {
+ int x,y;
+
+
+ x = stars[offs].x >> 1;
+ y = stars[offs].y;
+
+ if ((x < 128) && ((y & 0x01) ^ ((x >> 3) & 0x01)))
+ {
+ /* determine when to skip plotting */
+ switch (stars_blink_state & 0x03)
+ {
+ case 0:
+ if (!(stars[offs].color & 0x01)) continue;
+ break;
+ case 1:
+ if (!(stars[offs].color & 0x04)) continue;
+ break;
+ case 2:
+ if (!(stars[offs].y & 0x02)) continue;
+ break;
+ case 3:
+ /* always plot */
+ break;
+ }
+
+ plot_star(machine, bitmap, x, y, stars[offs].color);
+ }
+ }
+}
+
+static void mariner_draw_stars(running_machine *machine, mame_bitmap *bitmap)
+{
+ int offs;
+ UINT8 *prom;
+
+
+ if (!timer_adjusted)
+ {
+ start_stars_scroll_timer();
+ timer_adjusted = 1;
+ }
+
+
+ /* bit 2 of the PROM controls star visibility */
+
+ prom = memory_region(REGION_USER2);
+
+ for (offs = 0;offs < STAR_COUNT;offs++)
+ {
+ int x,y;
+
+
+ x = ((stars[offs].x + -stars_scrollpos) & 0x01ff) >> 1;
+ y = ( stars[offs].y + ((-stars_scrollpos + stars[offs].x) >> 9)) & 0xff;
+
+ if ((y & 0x01) ^ ((x >> 3) & 0x01))
+ {
+ if (prom[(x/8 + 1) & 0x1f] & 0x04)
+ {
+ plot_star(machine, bitmap, x, y, stars[offs].color);
+ }
+ }
+ }
+}
+
+static void jumpbug_draw_stars(running_machine *machine, mame_bitmap *bitmap)
+{
+ int offs;
+
+
+ if (!timer_adjusted)
+ {
+ start_stars_blink_timer(100000, 10000, 0.00001);
+ start_stars_scroll_timer();
+ timer_adjusted = 1;
+ }
+
+
+ for (offs = 0;offs < STAR_COUNT;offs++)
+ {
+ int x,y;
+
+
+ x = stars[offs].x >> 1;
+ y = stars[offs].y;
+
+ /* determine when to skip plotting */
+ if ((y & 0x01) ^ ((x >> 3) & 0x01))
+ {
+ switch (stars_blink_state & 0x03)
+ {
+ case 0:
+ if (!(stars[offs].color & 0x01)) continue;
+ break;
+ case 1:
+ if (!(stars[offs].color & 0x04)) continue;
+ break;
+ case 2:
+ if (!(stars[offs].y & 0x02)) continue;
+ break;
+ case 3:
+ /* always plot */
+ break;
+ }
+
+ x = ((stars[offs].x + stars_scrollpos) & 0x01ff) >> 1;
+ y = ( stars[offs].y + ((stars_scrollpos + stars[offs].x) >> 9)) & 0xff;
+
+ /* no stars in the status area */
+ if (x >= 240) continue;
+
+ plot_star(machine, bitmap, x, y, stars[offs].color);
+ }
+ }
+}
+
+
+static TIMER_CALLBACK( stars_blink_callback )
+{
+ stars_blink_state++;
+}
+
+static void start_stars_blink_timer(double ra, double rb, double c)
+{
+ /* calculate the period using the formula given in the 555 datasheet */
+
+ int period_in_ms = 693 * (ra + 2.0 * rb) * c;
+
+ timer_adjust(stars_blink_timer, ATTOTIME_IN_MSEC(period_in_ms), 0, ATTOTIME_IN_MSEC(period_in_ms));
+}
+
+
+static TIMER_CALLBACK( stars_scroll_callback )
+{
+ if (galaxian_stars_on)
+ {
+ stars_scrollpos++;
+ }
+}
+
+static void start_stars_scroll_timer()
+{
+ timer_adjust(stars_scroll_timer, video_screen_get_frame_period(0), 0, video_screen_get_frame_period(0));
+}
+
+
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 x = tile_index & 0x1f;
+
+ UINT16 code = galaxian_videoram[tile_index];
+ UINT8 color = galaxian_attributesram[(x << 1) | 1] & color_mask;
+
+ if (modify_charcode)
+ {
+ modify_charcode(&code, x);
+ }
+
+ if (modify_color)
+ {
+ modify_color(&color);
+ }
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static TILE_GET_INFO( rockclim_get_tile_info )
+{
+ UINT16 code = rockclim_videoram[tile_index];
+ SET_TILE_INFO(2, code, 0, 0);
+}
+
+static void draw_bullets_common(running_machine *machine, mame_bitmap *bitmap)
+{
+ int offs;
+
+
+ for (offs = 0;offs < galaxian_bulletsram_size;offs += 4)
+ {
+ UINT8 sx,sy;
+
+ sy = 255 - galaxian_bulletsram[offs + 1];
+ sx = 255 - galaxian_bulletsram[offs + 3];
+
+ if (sy < machine->screen[0].visarea.min_y ||
+ sy > machine->screen[0].visarea.max_y)
+ continue;
+
+ if (flipscreen_y) sy = 255 - sy;
+
+ draw_bullets(machine, bitmap, offs, sx, sy);
+ }
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, UINT8 *spriteram, size_t spriteram_size)
+{
+ int offs;
+
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ UINT8 sx,sy,color;
+ int flipx,flipy,code;
+
+
+ sx = spriteram[offs + 3] + 1; /* the existence of +1 is supported by a LOT of games */
+ sy = spriteram[offs]; /* Anteater, Mariner, for example */
+ flipx = spriteram[offs + 1] & 0x40;
+ flipy = spriteram[offs + 1] & 0x80;
+ code = spriteram[offs + 1] & 0x3f;
+ color = spriteram[offs + 2] & color_mask;
+
+ if (modify_spritecode)
+ {
+ modify_spritecode(spriteram, &code, &flipx, &flipy, offs);
+ }
+
+ if (modify_color)
+ {
+ modify_color(&color);
+ }
+
+ if (modify_ypos)
+ {
+ modify_ypos(&sy);
+ }
+
+ if (flipscreen_x)
+ {
+ sx = 240 - sx;
+ flipx = !flipx;
+ }
+
+ if (flipscreen_y)
+ {
+ flipy = !flipy;
+ }
+ else
+ {
+ sy = 240 - sy;
+ }
+
+
+ /* In at least Amidar Turtles, sprites #0, #1 and #2 need to be moved */
+ /* down (left) one pixel to be positioned correctly. */
+ /* Note that the adjustment must be done AFTER handling flipscreen, thus */
+ /* proving that this is a hardware related "feature" */
+
+ if (offs < 3*4) sy++;
+
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,color,
+ flipx,flipy,
+ sx,sy,
+ flipscreen_x ? spritevisibleareaflipx : spritevisiblearea,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+VIDEO_UPDATE( galaxian )
+{
+ draw_background(machine, bitmap);
+
+
+ if (galaxian_stars_on)
+ {
+ draw_stars(machine, bitmap);
+ }
+
+
+ tilemap_draw(bitmap, 0, bg_tilemap, 0, 0);
+
+
+ if (draw_bullets)
+ {
+ draw_bullets_common(machine, bitmap);
+ }
+
+
+ draw_sprites(machine, bitmap, galaxian_spriteram, galaxian_spriteram_size);
+
+ if (spriteram2_present)
+ {
+ draw_sprites(machine, bitmap, galaxian_spriteram2, galaxian_spriteram2_size);
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( dambustr )
+{
+ int i, j;
+ UINT8 color;
+
+ draw_background(machine, bitmap);
+
+ if (galaxian_stars_on)
+ {
+ draw_stars(machine, bitmap);
+ }
+
+ /* save the background for drawing it again later, if background has priority over characters */
+ copybitmap(dambustr_tmpbitmap, bitmap, 0, 0, 0, 0, &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+
+ tilemap_draw(bitmap, 0, bg_tilemap, 0, 0);
+
+ if (draw_bullets)
+ {
+ draw_bullets_common(machine, bitmap);
+ }
+
+ draw_sprites(machine, bitmap, galaxian_spriteram, galaxian_spriteram_size);
+
+ if (dambustr_bg_priority)
+ {
+ /* draw the upper part of the background, as it has priority */
+ dambustr_draw_upper_background(bitmap);
+
+ /* only rows with color code > 3 are stronger than the background */
+ memset(dambustr_videoram2, 0x20, 0x0400);
+ for (i=0; i<32; i++) {
+ color = galaxian_attributesram[(i << 1) | 1] & color_mask;
+ if (color > 3) {
+ for (j=0; j<32; j++)
+ dambustr_videoram2[32*j+i] = galaxian_videoram[32*j+i];
+ };
+ };
+ tilemap_mark_all_tiles_dirty(dambustr_tilemap2);
+ tilemap_draw(bitmap, 0, dambustr_tilemap2, 0, 0);
+ };
+
+ return 0;
+}
+
diff --git a/src/mame/video/galivan.c b/src/mame/video/galivan.c
new file mode 100644
index 00000000000..8d711c56ddc
--- /dev/null
+++ b/src/mame/video/galivan.c
@@ -0,0 +1,443 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+d800-dbff foreground: char low bits (1 screen * 1024 chars/screen)
+dc00-dfff foreground attribute: 7 ?
+ 6543 color
+ 21 ?
+ 0 char hi bit
+
+
+e000-e0ff spriteram: 64 sprites (4 bytes/sprite)
+ offset : 0 1 2 3
+ meaning: ypos(lo) sprite(lo) attribute xpos(lo)
+ 7 flipy
+ 6 flipx
+ 5-2 color
+ 1 sprite(hi)
+ 0 xpos(hi)
+
+
+background: 0x4000 bytes of ROM: 76543210 tile code low bits
+ 0x4000 bytes of ROM: 7 ?
+ 6543 color
+ 2 ?
+ 10 tile code high bits
+
+***************************************************************************/
+
+#include "driver.h"
+
+static UINT8 scrollx[2], scrolly[2];
+
+/* Layers has only bits 5-6 active.
+ 6 selects background off/on
+ 5 controls sprite priority (active only on title screen,
+ not for scores or push start nor game)
+*/
+
+static UINT8 flipscreen;
+static UINT8 write_layers, layers;
+static UINT8 ninjemak_dispdisable;
+
+static tilemap *bg_tilemap, *tx_tilemap;
+
+static const UINT8 *spritepalettebank;
+
+/* Notes:
+ write_layers and layers are used in galivan/dangar but not ninjemak
+ ninjemak_dispdisable is used in ninjemak but not galivan/dangar
+ spritepalettebank is set at palette init and doesn't need to be saved
+*/
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+***************************************************************************/
+
+PALETTE_INIT( galivan )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the lookup tables */
+
+
+ /* characters use colors 0-127 */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = i;
+
+ /* I think that */
+ /* background tiles use colors 192-255 in four banks */
+ /* the bottom two bits of the color code select the palette bank for */
+ /* pens 0-7; the top two bits for pens 8-15. */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ {
+ if (i & 8) COLOR(1,i) = 192 + (i & 0x0f) + ((i & 0xc0) >> 2);
+ else COLOR(1,i) = 192 + (i & 0x0f) + ((i & 0x30) >> 0);
+ }
+
+
+ /* sprites use colors 128-191 in four banks */
+ /* The lookup table tells which colors to pick from the selected bank */
+ /* the bank is selected by another PROM and depends on the top 7 bits of */
+ /* the sprite code. The PROM selects the bank *separately* for pens 0-7 and */
+ /* 8-15 (like for tiles). */
+ for (i = 0;i < TOTAL_COLORS(2)/16;i++)
+ {
+ int j;
+
+ for (j = 0;j < 16;j++)
+ {
+ if (i & 8)
+ COLOR(2,i + j * (TOTAL_COLORS(2)/16)) = 128 + ((j & 0x0c) << 2) + (*color_prom & 0x0f);
+ else
+ COLOR(2,i + j * (TOTAL_COLORS(2)/16)) = 128 + ((j & 0x03) << 4) + (*color_prom & 0x0f);
+ }
+
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the sprite palette bank table */
+ spritepalettebank = color_prom; /* we'll need it at run time */
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 *BGROM = memory_region(REGION_GFX4);
+ int attr = BGROM[tile_index + 0x4000];
+ int code = BGROM[tile_index] | ((attr & 0x03) << 8);
+ SET_TILE_INFO(
+ 1,
+ code,
+ (attr & 0x78) >> 3, /* seems correct */
+ 0);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] | ((attr & 0x01) << 8);
+ SET_TILE_INFO(
+ 0,
+ code,
+ (attr & 0xe0) >> 5, /* not sure */
+ 0);
+ tileinfo->category = attr & 8 ? 0 : 1; /* seems correct */
+}
+
+static TILE_GET_INFO( ninjemak_get_bg_tile_info )
+{
+ UINT8 *BGROM = memory_region(REGION_GFX4);
+ int attr = BGROM[tile_index + 0x4000];
+ int code = BGROM[tile_index] | ((attr & 0x03) << 8);
+ SET_TILE_INFO(
+ 1,
+ code,
+ ((attr & 0x60) >> 3) | ((attr & 0x0c) >> 2), /* seems correct */
+ 0);
+}
+
+static TILE_GET_INFO( ninjemak_get_tx_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] | ((attr & 0x03) << 8);
+ SET_TILE_INFO(
+ 0,
+ code,
+ (attr & 0x1c) >> 2, /* seems correct ? */
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( galivan )
+{
+ /* configure ROM banking */
+ UINT8 *rombase = memory_region(REGION_CPU1);
+ memory_configure_bank(1, 0, 2, &rombase[0x10000], 0x2000);
+
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,128,128);
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(tx_tilemap,15);
+
+ /* register for saving */
+ state_save_register_global_array(scrollx);
+ state_save_register_global_array(scrolly);
+ state_save_register_global(flipscreen);
+ state_save_register_global(write_layers);
+ state_save_register_global(layers);
+}
+
+VIDEO_START( ninjemak )
+{
+ /* configure ROM banking */
+ UINT8 *rombase = memory_region(REGION_CPU1);
+ memory_configure_bank(1, 0, 4, &rombase[0x10000], 0x2000);
+
+ bg_tilemap = tilemap_create(ninjemak_get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 16,16,512,32);
+ tx_tilemap = tilemap_create(ninjemak_get_tx_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(tx_tilemap,15);
+
+ /* register for saving */
+ state_save_register_global_array(scrollx);
+ state_save_register_global_array(scrolly);
+ state_save_register_global(flipscreen);
+ state_save_register_global(ninjemak_dispdisable);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( galivan_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+WRITE8_HANDLER( galivan_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+/* Written through port 40 */
+WRITE8_HANDLER( galivan_gfxbank_w )
+{
+ /* bits 0 and 1 coin counters */
+ coin_counter_w(0,data & 1);
+ coin_counter_w(1,data & 2);
+
+ /* bit 2 flip screen */
+ flipscreen = data & 0x04;
+ tilemap_set_flip (bg_tilemap, flipscreen ? TILEMAP_FLIPX|TILEMAP_FLIPY : 0);
+ tilemap_set_flip (tx_tilemap, flipscreen ? TILEMAP_FLIPX|TILEMAP_FLIPY : 0);
+
+ /* bit 7 selects one of two ROM banks for c000-dfff */
+ memory_set_bank(1, (data & 0x80) >> 7);
+
+/* logerror("Address: %04X - port 40 = %02x\n",activecpu_get_pc(),data); */
+}
+
+WRITE8_HANDLER( ninjemak_gfxbank_w )
+{
+ /* bits 0 and 1 coin counters */
+ coin_counter_w(0,data & 1);
+ coin_counter_w(1,data & 2);
+
+ /* bit 2 flip screen */
+ flipscreen = data & 0x04;
+ tilemap_set_flip (bg_tilemap, flipscreen ? TILEMAP_FLIPX|TILEMAP_FLIPY : 0);
+ tilemap_set_flip (tx_tilemap, flipscreen ? TILEMAP_FLIPX|TILEMAP_FLIPY : 0);
+
+ /* bit 3 text bank flag ??? */
+ if (data & 0x08)
+ {
+ /* This is a temporary condition specification. */
+
+ int offs;
+
+logerror("%04x: write %02x to port 80\n",activecpu_get_pc(),data);
+
+ for (offs = 0; offs < videoram_size; offs++)
+ {
+ galivan_videoram_w(offs, 0x20);
+ }
+ for (offs = 0; offs < videoram_size; offs++)
+ {
+ galivan_colorram_w(offs, 0x03);
+ }
+ }
+
+ /* bit 4 background disable flag */
+ ninjemak_dispdisable = data & 0x10;
+
+ /* bit 5 sprite flag ??? */
+
+ /* bit 6, 7 ROM bank select */
+ memory_set_bank(1, (data & 0xc0) >> 6);
+
+#if 0
+ {
+ char mess[80];
+ int btz[8];
+ int offs;
+
+ for (offs = 0; offs < 8; offs++) btz[offs] = (((data >> offs) & 0x01) ? 1 : 0);
+
+ sprintf(mess, "BK:%01X%01X S:%01X B:%01X T:%01X FF:%01X C2:%01X C1:%01X", btz[7], btz[6], btz[5], btz[4], btz[3], btz[2], btz[1], btz[0]);
+ popmessage(mess);
+ }
+#endif
+}
+
+
+
+/* Written through port 41-42 */
+WRITE8_HANDLER( galivan_scrollx_w )
+{
+ if (offset == 1) {
+ if (data & 0x80)
+ write_layers = 1;
+ else if (write_layers) {
+ layers = data & 0x60;
+ write_layers = 0;
+ }
+ }
+ scrollx[offset] = data;
+}
+
+/* Written through port 43-44 */
+WRITE8_HANDLER( galivan_scrolly_w )
+{
+ scrolly[offset] = data;
+}
+
+
+WRITE8_HANDLER( ninjemak_scrollx_w )
+{
+ scrollx[offset] = data;
+}
+
+WRITE8_HANDLER( ninjemak_scrolly_w )
+{
+ scrolly[offset] = data;
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ /* draw the sprites */
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int code;
+ int attr = spriteram[offs+2];
+ int color = (attr & 0x3c) >> 2;
+ int flipx = attr & 0x40;
+ int flipy = attr & 0x80;
+ int sx,sy;
+
+ sx = (spriteram[offs+3] - 0x80) + 256 * (attr & 0x01);
+ sy = 240 - spriteram[offs];
+ if (flipscreen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+// code = spriteram[offs+1] + ((attr & 0x02) << 7);
+ code = spriteram[offs+1] + ((attr & 0x06) << 7); // for ninjemak, not sure ?
+
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ color + 16 * (spritepalettebank[code >> 2] & 0x0f),
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+
+VIDEO_UPDATE( galivan )
+{
+ tilemap_set_scrollx(bg_tilemap,0,scrollx[0] + 256 * (scrollx[1] & 0x07));
+ tilemap_set_scrolly(bg_tilemap,0,scrolly[0] + 256 * (scrolly[1] & 0x07));
+
+ if (layers & 0x40)
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ else
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ if (layers & 0x20) {
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,1,0);
+ draw_sprites(machine,bitmap,cliprect);
+ } else {
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,1,0);
+ }
+
+ return 0;
+}
+
+VIDEO_UPDATE( ninjemak )
+{
+ /* (scrollx[1] & 0x40) does something */
+ tilemap_set_scrollx(bg_tilemap,0,scrollx[0] + 256 * (scrollx[1] & 0x1f));
+ tilemap_set_scrolly(bg_tilemap,0,scrolly[0] + 256 * (scrolly[1] & 0xff));
+
+ if (ninjemak_dispdisable)
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ else
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ draw_sprites(machine,bitmap,cliprect);
+
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/galpani2.c b/src/mame/video/galpani2.c
new file mode 100644
index 00000000000..bfcf293ebdd
--- /dev/null
+++ b/src/mame/video/galpani2.c
@@ -0,0 +1,204 @@
+/***************************************************************************
+
+ -= Gal's Panic II =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+***************************************************************************/
+
+#include "driver.h"
+#include "kaneko16.h"
+
+/*
+304000:0040 0000 0100 0000-0000 0000 0000 0000 (Sprites regs)
+304010:16C0 0200 16C0 0200-16C0 0200 16C0 0200
+*/
+
+/***************************************************************************
+
+
+ Palettized Background Layers
+
+
+***************************************************************************/
+
+UINT16 *galpani2_bg8_0, *galpani2_bg8_1;
+UINT16 *galpani2_palette_0, *galpani2_palette_1;
+UINT16 *galpani2_bg8_regs_0, *galpani2_bg8_regs_1;
+UINT16 *galpani2_bg8_0_scrollx, *galpani2_bg8_1_scrollx;
+UINT16 *galpani2_bg8_0_scrolly, *galpani2_bg8_1_scrolly;
+
+static mame_bitmap *galpani2_bg8_bitmap_0, *galpani2_bg8_bitmap_1;
+
+#define galpani2_BG8_REGS_R( _n_ ) \
+READ16_HANDLER( galpani2_bg8_regs_##_n_##_r ) \
+{ \
+ switch (offset * 2) \
+ { \
+ case 0x16: return mame_rand(Machine) & 1; \
+ default: \
+ logerror("CPU #0 PC %06X : Warning, bg8 #%d screen reg %04X read\n",activecpu_get_pc(),_n_,offset*2); \
+ } \
+ return galpani2_bg8_regs_##_n_[offset]; \
+}
+
+/*
+ 000-3ff row? scroll
+ 400 ?
+ 800-bff col? scroll
+ c04 0003 flip, 0300 flip?
+ c1c/e 01ff scroll, 3000 ?
+*/
+#define galpani2_BG8_REGS_W( _n_ ) \
+WRITE16_HANDLER( galpani2_bg8_regs_##_n_##_w ) \
+{ \
+ COMBINE_DATA(&galpani2_bg8_regs_##_n_[offset]); \
+}
+
+#define galpani2_BG8_W( _n_ ) \
+WRITE16_HANDLER( galpani2_bg8_##_n_##_w ) \
+{ \
+ int x,y,pen; \
+ UINT16 newword = COMBINE_DATA(&galpani2_bg8_##_n_[offset]); \
+ pen = newword & 0xff; \
+ x = (offset % 512); /* 512 x 256 */ \
+ y = (offset / 512); \
+ *BITMAP_ADDR16(galpani2_bg8_bitmap_##_n_, y, x) = Machine->pens[0x4000 + pen]; \
+}
+
+#define galpani2_BG8_PALETTE_W( _n_ ) \
+WRITE16_HANDLER( galpani2_palette_##_n_##_w ) \
+{ \
+ UINT16 newword = COMBINE_DATA(&galpani2_palette_##_n_[offset]); \
+ palette_set_color_rgb( Machine, offset + 0x4000 + _n_ * 0x100, pal5bit(newword >> 5), pal5bit(newword >> 10), pal5bit(newword >> 0) ); \
+}
+
+galpani2_BG8_REGS_R( 0 )
+galpani2_BG8_REGS_R( 1 )
+
+galpani2_BG8_REGS_W( 0 )
+galpani2_BG8_REGS_W( 1 )
+
+galpani2_BG8_W( 0 )
+galpani2_BG8_W( 1 )
+
+galpani2_BG8_PALETTE_W( 0 )
+galpani2_BG8_PALETTE_W( 1 )
+
+
+/***************************************************************************
+
+
+ xRGB Background Layer
+
+
+***************************************************************************/
+
+UINT16 *galpani2_bg15;
+
+static mame_bitmap *galpani2_bg15_bitmap;
+
+/* 8 horizontal pages of 256x256 pixels? */
+WRITE16_HANDLER( galpani2_bg15_w )
+{
+ UINT16 newword = COMBINE_DATA(&galpani2_bg15[offset]);
+
+ int x = (offset % 256) + (offset / (256*256)) * 256 ;
+ int y = (offset / 256) % 256;
+
+ *BITMAP_ADDR16(galpani2_bg15_bitmap, y, x) = Machine->pens[0x4200 + (newword & 0x7fff)];
+}
+
+
+/***************************************************************************
+
+
+ Video Init Functions
+
+
+***************************************************************************/
+
+PALETTE_INIT( galpani2 )
+{
+ int i;
+ /* first $4200 colors are dynamic */
+
+ /* initialize 555 RGB lookup */
+ for (i = 0; i < 0x8000; i++)
+ palette_set_color_rgb(machine,0x4200+i,pal5bit(i >> 5),pal5bit(i >> 10),pal5bit(i >> 0));
+}
+
+VIDEO_START( galpani2 )
+{
+ galpani2_bg15_bitmap = auto_bitmap_alloc(256*8, 256, BITMAP_FORMAT_INDEXED16);
+ galpani2_bg8_bitmap_0 = auto_bitmap_alloc(512, 256, BITMAP_FORMAT_INDEXED16);
+ galpani2_bg8_bitmap_1 = auto_bitmap_alloc(512, 256, BITMAP_FORMAT_INDEXED16);
+
+ video_start_kaneko16_sprites(machine);
+}
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+VIDEO_UPDATE( galpani2 )
+{
+ int layers_ctrl = -1;
+
+ galpani2_mcu_run();
+
+#ifdef MAME_DEBUG
+if (input_code_pressed(KEYCODE_Z))
+{ int msk = 0;
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+ if (input_code_pressed(KEYCODE_E)) msk |= 4;
+ if (input_code_pressed(KEYCODE_A)) msk |= 8;
+ if (msk != 0) layers_ctrl &= msk; }
+#endif
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ if (layers_ctrl & 0x1)
+ {
+ int x = 0;
+ int y = 0;
+ copyscrollbitmap( bitmap, galpani2_bg15_bitmap,
+ 1, &x, 1, &y,
+ cliprect,TRANSPARENCY_PEN,machine->pens[0x4200 + 0]);
+ }
+
+/* test mode:
+ 304000:0040 0000 0100 0000-0000 0000 0000 0000 (Sprite regs)
+ 304010:16C0 0200 16C0 0200-16C0 0200 16C0 0200
+ 16c0/40 = 5b 200/40 = 8
+ scrollx = f5, on screen x should be 0 (f5+5b = 150) */
+
+ if (layers_ctrl & 0x2)
+ {
+ int x = - ( *galpani2_bg8_0_scrollx + 0x200 - 0x0f5 );
+ int y = - ( *galpani2_bg8_0_scrolly + 0x200 - 0x1be );
+ copyscrollbitmap( bitmap, galpani2_bg8_bitmap_0,
+ 1, &x, 1, &y,
+ cliprect,TRANSPARENCY_PEN,machine->pens[0x4000 + 0]);
+ }
+
+ if (layers_ctrl & 0x4)
+ {
+ int x = - ( *galpani2_bg8_1_scrollx + 0x200 - 0x0f5 );
+ int y = - ( *galpani2_bg8_1_scrolly + 0x200 - 0x1be );
+ copyscrollbitmap( bitmap, galpani2_bg8_bitmap_1,
+ 1, &x, 1, &y,
+ cliprect,TRANSPARENCY_PEN,machine->pens[0x4000 + 0]);
+ }
+
+ if (layers_ctrl & 0x8) kaneko16_draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/galpanic.c b/src/mame/video/galpanic.c
new file mode 100644
index 00000000000..6ee7f201356
--- /dev/null
+++ b/src/mame/video/galpanic.c
@@ -0,0 +1,136 @@
+#include "driver.h"
+#include "kan_pand.h"
+
+UINT16 *galpanic_bgvideoram,*galpanic_fgvideoram;
+size_t galpanic_fgvideoram_size;
+
+static mame_bitmap *sprites_bitmap;
+
+VIDEO_START( galpanic )
+{
+ tmpbitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ sprites_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ pandora_start(0,0, -16);
+}
+
+PALETTE_INIT( galpanic )
+{
+ int i;
+
+ /* first 1024 colors are dynamic */
+
+ /* initialize 555 RGB lookup */
+ for (i = 0;i < 32768;i++)
+ palette_set_color_rgb(machine,i+1024,pal5bit(i >> 5),pal5bit(i >> 10),pal5bit(i >> 0));
+}
+
+
+
+WRITE16_HANDLER( galpanic_bgvideoram_w )
+{
+ int sx,sy;
+
+
+ data = COMBINE_DATA(&galpanic_bgvideoram[offset]);
+
+ sy = offset / 256;
+ sx = offset % 256;
+
+ *BITMAP_ADDR16(tmpbitmap, sy, sx) = Machine->pens[1024 + (data >> 1)];
+}
+
+WRITE16_HANDLER( galpanic_paletteram_w )
+{
+ data = COMBINE_DATA(&paletteram16[offset]);
+ /* bit 0 seems to be a transparency flag for the front bitmap */
+ palette_set_color_rgb(Machine,offset,pal5bit(data >> 6),pal5bit(data >> 11),pal5bit(data >> 1));
+}
+
+
+static void comad_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+ int sx=0, sy=0;
+
+ for (offs = 0;offs < spriteram_size/2;offs += 4)
+ {
+ int code,color,flipx,flipy;
+
+ code = spriteram16[offs + 1] & 0x1fff;
+ color = (spriteram16[offs] & 0x003c) >> 2;
+ flipx = spriteram16[offs] & 0x0002;
+ flipy = spriteram16[offs] & 0x0001;
+
+ if((spriteram16[offs] & 0x6000) == 0x6000) /* Link bits */
+ {
+ sx += spriteram16[offs + 2] >> 6;
+ sy += spriteram16[offs + 3] >> 6;
+ }
+ else
+ {
+ sx = spriteram16[offs + 2] >> 6;
+ sy = spriteram16[offs + 3] >> 6;
+ }
+
+ sx = (sx&0x1ff) - (sx&0x200);
+ sy = (sy&0x1ff) - (sy&0x200);
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+static void draw_fgbitmap(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < galpanic_fgvideoram_size/2;offs++)
+ {
+ int sx,sy,color;
+
+ sx = offs % 256;
+ sy = offs / 256;
+ color = galpanic_fgvideoram[offs];
+ if (color)
+ *BITMAP_ADDR16(bitmap, sy, sx) = machine->pens[color];
+ }
+}
+
+VIDEO_UPDATE( galpanic )
+{
+ /* copy the temporary bitmap to the screen */
+ copybitmap(bitmap,tmpbitmap,0,0,0,0,cliprect,TRANSPARENCY_NONE,0);
+
+ draw_fgbitmap(machine, bitmap, cliprect);
+
+ pandora_update(machine,bitmap,cliprect);
+
+ return 0;
+}
+
+VIDEO_UPDATE( comad )
+{
+ /* copy the temporary bitmap to the screen */
+ copybitmap(bitmap,tmpbitmap,0,0,0,0,cliprect,TRANSPARENCY_NONE,0);
+
+ draw_fgbitmap(machine,bitmap,cliprect);
+
+
+// if(galpanic_clear_sprites)
+ {
+ fillbitmap(sprites_bitmap,0,cliprect);
+ comad_draw_sprites(machine,bitmap,cliprect);
+ }
+// else
+// {
+// /* keep sprites on the bitmap without clearing them */
+// comad_draw_sprites(machine,sprites_bitmap,0);
+// copybitmap(bitmap,sprites_bitmap,0,0,0,0,cliprect,TRANSPARENCY_PEN,0);
+// }
+ return 0;
+}
diff --git a/src/mame/video/galspnbl.c b/src/mame/video/galspnbl.c
new file mode 100644
index 00000000000..361ddd41f3c
--- /dev/null
+++ b/src/mame/video/galspnbl.c
@@ -0,0 +1,144 @@
+#include "driver.h"
+
+
+UINT16 *galspnbl_bgvideoram,*galspnbl_videoram,*galspnbl_colorram;
+static int screenscroll;
+
+
+
+PALETTE_INIT( galspnbl )
+{
+ int i;
+
+ /* initialize 555 RGB lookup */
+ for (i = 0;i < 32768;i++)
+ palette_set_color_rgb(machine,i+1024,pal5bit(i >> 5),pal5bit(i >> 10),pal5bit(i >> 0));
+}
+
+
+
+WRITE16_HANDLER( galspnbl_bgvideoram_w )
+{
+ int sx,sy;
+
+
+ data = COMBINE_DATA(&galspnbl_bgvideoram[offset]);
+
+ sx = offset % 512;
+ sy = offset / 512;
+
+ *BITMAP_ADDR16(tmpbitmap, sy, sx) = Machine->pens[1024 + (data >> 1)];
+}
+
+WRITE16_HANDLER( galspnbl_scroll_w )
+{
+ if (ACCESSING_LSB)
+ screenscroll = 4-(data & 0xff);
+}
+
+
+
+/* sprite format (see also Ninja Gaiden):
+ *
+ * word bit usage
+ * --------+-fedcba9876543210-+----------------
+ * 0 | ---------------x | flip x
+ * | --------------x- | flip y
+ * | -------------x-- | enable
+ * | ----------xx---- | priority?
+ * | ---------x------ | flicker?
+ * 1 | xxxxxxxxxxxxxxxx | code
+ * 2 | --------xxxx---- | color
+ * | --------------xx | size: 8x8, 16x16, 32x32, 64x64
+ * 3 | xxxxxxxxxxxxxxxx | y position
+ * 4 | xxxxxxxxxxxxxxxx | x position
+ * 5,6,7| | unused
+ */
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int offs;
+ static const UINT8 layout[8][8] =
+ {
+ {0,1,4,5,16,17,20,21},
+ {2,3,6,7,18,19,22,23},
+ {8,9,12,13,24,25,28,29},
+ {10,11,14,15,26,27,30,31},
+ {32,33,36,37,48,49,52,53},
+ {34,35,38,39,50,51,54,55},
+ {40,41,44,45,56,57,60,61},
+ {42,43,46,47,58,59,62,63}
+ };
+
+ for (offs = (spriteram_size-16)/2;offs >= 0;offs -= 8)
+ {
+ int sx,sy,code,color,size,attr,flipx,flipy;
+ int col,row;
+
+ attr = spriteram16[offs];
+ if ((attr & 0x0004) && ((attr & 0x0040) == 0 || (cpu_getcurrentframe() & 1))
+// && ((attr & 0x0030) >> 4) == priority)
+ && ((attr & 0x0020) >> 5) == priority)
+ {
+ code = spriteram16[offs+1];
+ color = spriteram16[offs+2];
+ size = 1 << (color & 0x0003); // 1,2,4,8
+ color = (color & 0x00f0) >> 4;
+ sx = spriteram16[offs+4] + screenscroll;
+ sy = spriteram16[offs+3];
+ flipx = attr & 0x0001;
+ flipy = attr & 0x0002;
+
+ for (row = 0;row < size;row++)
+ {
+ for (col = 0;col < size;col++)
+ {
+ int x = sx + 8*(flipx?(size-1-col):col);
+ int y = sy + 8*(flipy?(size-1-row):row);
+ drawgfx(bitmap,machine->gfx[1],
+ code + layout[row][col],
+ color,
+ flipx,flipy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( galspnbl )
+{
+ int offs;
+
+
+ /* copy the temporary bitmap to the screen */
+ copyscrollbitmap(bitmap,tmpbitmap,1,&screenscroll,0,0,cliprect,TRANSPARENCY_NONE,0);
+
+ draw_sprites(machine,bitmap,cliprect,0);
+
+ for (offs = 0;offs < 0x1000/2;offs++)
+ {
+ int sx,sy,code,attr,color;
+
+ code = galspnbl_videoram[offs];
+ attr = galspnbl_colorram[offs];
+ color = (attr & 0x00f0) >> 4;
+ sx = offs % 64;
+ sy = offs / 64;
+
+ /* What is this? A priority/half transparency marker? */
+ if (!(attr & 0x0008))
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ 0,0,
+ 16*sx + screenscroll,8*sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+
+ draw_sprites(machine,bitmap,cliprect,1);
+ return 0;
+}
diff --git a/src/mame/video/gaplus.c b/src/mame/video/gaplus.c
new file mode 100644
index 00000000000..abd71e31d30
--- /dev/null
+++ b/src/mame/video/gaplus.c
@@ -0,0 +1,415 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *gaplus_videoram;
+UINT8 *gaplus_spriteram;
+
+static tilemap *bg_tilemap;
+static colortable *gaplus_colortable;
+
+
+/***************************************************************************
+
+ Convert the color PROMs.
+
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+
+PALETTE_INIT( gaplus )
+{
+ int i;
+
+ /* allocate the colortable */
+ gaplus_colortable = colortable_alloc(machine, 256);
+
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ bit3 = (color_prom[i] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* green component */
+ bit0 = (color_prom[i + 0x100] >> 0) & 0x01;
+ bit1 = (color_prom[i + 0x100] >> 1) & 0x01;
+ bit2 = (color_prom[i + 0x100] >> 2) & 0x01;
+ bit3 = (color_prom[i + 0x100] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* blue component */
+ bit0 = (color_prom[i + 0x200] >> 0) & 0x01;
+ bit1 = (color_prom[i + 0x200] >> 1) & 0x01;
+ bit2 = (color_prom[i + 0x200] >> 2) & 0x01;
+ bit3 = (color_prom[i + 0x200] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ colortable_palette_set_color(gaplus_colortable,i,MAKE_RGB(r,g,b));
+ }
+
+ color_prom += 0x300;
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* characters use colors 0xf0-0xff */
+ for (i = 0;i < machine->gfx[0]->total_colors * machine->gfx[0]->color_granularity;i++)
+ colortable_entry_set_value(gaplus_colortable, machine->gfx[0]->color_base + i, 0xf0 + (*color_prom++ & 0x0f));
+
+ /* sprites */
+ for (i = 0;i < machine->gfx[1]->total_colors * machine->gfx[1]->color_granularity;i++)
+ {
+ colortable_entry_set_value(gaplus_colortable, machine->gfx[1]->color_base + i, (color_prom[0] & 0x0f) + ((color_prom[0x200] & 0x0f) << 4));
+ color_prom++;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/* convert from 32x32 to 36x28 */
+static TILEMAP_MAPPER( tilemap_scan )
+{
+ int offs;
+
+ row += 2;
+ col -= 2;
+ if (col & 0x20)
+ offs = row + ((col & 0x1f) << 5);
+ else
+ offs = col + (row << 5);
+
+ return offs;
+}
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 attr = gaplus_videoram[tile_index + 0x400];
+ tileinfo->category = (attr & 0x40) >> 6;
+ tileinfo->group = attr & 0x3f;
+ SET_TILE_INFO(
+ 0,
+ gaplus_videoram[tile_index] + ((attr & 0x80) << 1),
+ attr & 0x3f,
+ 0);
+}
+
+
+
+/***************************************************************************
+ Starfield information
+ There's 3 sets of stars planes at different speeds.
+
+ a000 ---> (bit 0 = 1) enable starfield.
+ (bit 0 = 0) disable starfield.
+ a001 ---> starfield plane 0 control
+ a002 ---> starfield plane 1 control
+ a003 ---> starfield plane 2 control
+***************************************************************************/
+
+#define MAX_STARS 250
+
+/* starfield speed constants (bigger = faster) */
+#define SPEED_1 0.5
+#define SPEED_2 1.0
+#define SPEED_3 2.0
+
+struct star {
+ float x,y;
+ int col,set;
+};
+static struct star stars[MAX_STARS];
+
+static UINT8 gaplus_starfield_control[4];
+static int total_stars;
+
+static void starfield_init(running_machine *machine)
+{
+ int generator = 0;
+ int x,y;
+ int set = 0;
+ int width, height;
+
+ width = machine->screen[0].width;
+ height = machine->screen[0].height;
+
+ total_stars = 0;
+
+ /* precalculate the star background */
+ /* this comes from the Galaxian hardware, Gaplus is probably different */
+
+ for ( y = 0;y < height; y++ ) {
+ for ( x = width*2 - 1; x >= 0; x--) {
+ int bit1,bit2;
+
+ generator <<= 1;
+ bit1 = (~generator >> 17) & 1;
+ bit2 = (generator >> 5) & 1;
+
+ if (bit1 ^ bit2) generator |= 1;
+
+ if ( ((~generator >> 16) & 1) && (generator & 0xff) == 0xff) {
+ int color;
+
+ color = (~(generator >> 8)) & 0x3f;
+ if ( color && total_stars < MAX_STARS ) {
+ stars[total_stars].x = x;
+ stars[total_stars].y = y;
+ stars[total_stars].col = machine->pens[color];
+ stars[total_stars].set = set++;
+
+ if ( set == 3 )
+ set = 0;
+
+ total_stars++;
+ }
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( gaplus )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan,TILEMAP_TYPE_PEN,8,8,36,28);
+
+ colortable_configure_tilemap_groups(gaplus_colortable, bg_tilemap, machine->gfx[0], 0xff);
+
+ spriteram = gaplus_spriteram + 0x780;
+ spriteram_2 = spriteram + 0x800;
+ spriteram_3 = spriteram_2 + 0x800;
+
+ starfield_init(machine);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ8_HANDLER( gaplus_videoram_r )
+{
+ return gaplus_videoram[offset];
+}
+
+WRITE8_HANDLER( gaplus_videoram_w )
+{
+ gaplus_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( gaplus_starfield_control_w )
+{
+ offset &= 3;
+ gaplus_starfield_control[offset] = data;
+}
+
+
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+static void starfield_render(running_machine *machine, mame_bitmap *bitmap)
+{
+ int i;
+ int width, height;
+
+ width = machine->screen[0].width;
+ height = machine->screen[0].height;
+
+ /* check if we're running */
+ if ( ( gaplus_starfield_control[0] & 1 ) == 0 )
+ return;
+
+ /* draw the starfields */
+ for ( i = 0; i < total_stars; i++ )
+ {
+ int x, y;
+
+ x = stars[i].x;
+ y = stars[i].y;
+
+ if ( x >=0 && x < width && y >= 0 && y < height )
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = stars[i].col;
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = 0;offs < 0x80;offs += 2)
+ {
+ /* is it on? */
+ if ((spriteram_3[offs+1] & 2) == 0)
+ {
+ static int gfx_offs[2][2] =
+ {
+ { 0, 1 },
+ { 2, 3 }
+ };
+ int sprite = spriteram[offs] | ((spriteram_3[offs] & 0x40) << 2);
+ int color = spriteram[offs+1] & 0x3f;
+ int sx = spriteram_2[offs+1] + 0x100 * (spriteram_3[offs+1] & 1) - 71;
+ int sy = 256 - spriteram_2[offs] - 8;
+ int flipx = (spriteram_3[offs] & 0x01);
+ int flipy = (spriteram_3[offs] & 0x02) >> 1;
+ int sizex = (spriteram_3[offs] & 0x08) >> 3;
+ int sizey = (spriteram_3[offs] & 0x20) >> 5;
+ int duplicate = spriteram_3[offs] & 0x80;
+ int x,y;
+
+ if (flip_screen)
+ {
+ flipx ^= 1;
+ flipy ^= 1;
+ }
+
+ sy -= 16 * sizey;
+ sy = (sy & 0xff) - 32; // fix wraparound
+
+ for (y = 0;y <= sizey;y++)
+ {
+ for (x = 0;x <= sizex;x++)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ sprite + (duplicate ? 0 : (gfx_offs[y ^ (sizey * flipy)][x ^ (sizex * flipx)])),
+ color,
+ flipx,flipy,
+ sx + 16*x,sy + 16*y,
+ cliprect,TRANSPARENCY_PENS,
+ colortable_get_transpen_mask(gaplus_colortable, machine->gfx[1], color, 0xff));
+ }
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( gaplus )
+{
+ /* flip screen control is embedded in RAM */
+ flip_screen_set(gaplus_spriteram[0x1f7f-0x800] & 1);
+
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ starfield_render(machine, bitmap);
+
+ /* draw the low priority characters */
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ draw_sprites(machine, bitmap, cliprect);
+
+ /* draw the high priority characters */
+ /* (I don't know if this feature is used by Gaplus, but it's shown in the schematics) */
+ tilemap_draw(bitmap,cliprect,bg_tilemap,1,0);
+ return 0;
+}
+
+
+VIDEO_EOF( gaplus ) /* update starfields */
+{
+ int i;
+ int width, height;
+
+ width = machine->screen[0].width;
+ height = machine->screen[0].height;
+
+ /* check if we're running */
+ if ( ( gaplus_starfield_control[0] & 1 ) == 0 )
+ return;
+
+ /* update the starfields */
+ for ( i = 0; i < total_stars; i++ ) {
+ switch( gaplus_starfield_control[stars[i].set + 1] ) {
+ case 0x87:
+ /* stand still */
+ break;
+
+ case 0x86:
+ /* scroll down (speed 1) */
+ stars[i].x += SPEED_1;
+ break;
+
+ case 0x85:
+ /* scroll down (speed 2) */
+ stars[i].x += SPEED_2;
+ break;
+
+ case 0x06:
+ /* scroll down (speed 3) */
+ stars[i].x += SPEED_3;
+ break;
+
+ case 0x80:
+ /* scroll up (speed 1) */
+ stars[i].x -= SPEED_1;
+ break;
+
+ case 0x82:
+ /* scroll up (speed 2) */
+ stars[i].x -= SPEED_2;
+ break;
+
+ case 0x81:
+ /* scroll up (speed 3) */
+ stars[i].x -= SPEED_3;
+ break;
+
+ case 0x9f:
+ /* scroll left (speed 2) */
+ stars[i].y += SPEED_2;
+ break;
+
+ case 0xaf:
+ /* scroll left (speed 1) */
+ stars[i].y += SPEED_1;
+ break;
+ }
+
+ /* wrap */
+ if ( stars[i].x < 0 )
+ stars[i].x = ( float )( width*2 ) + stars[i].x;
+
+ if ( stars[i].x >= ( float )( width*2 ) )
+ stars[i].x -= ( float )( width*2 );
+
+ if ( stars[i].y < 0 )
+ stars[i].y = ( float )( height ) + stars[i].y;
+
+ if ( stars[i].y >= ( float )( height ) )
+ stars[i].y -= ( float )( height );
+ }
+}
diff --git a/src/mame/video/gauntlet.c b/src/mame/video/gauntlet.c
new file mode 100644
index 00000000000..2a0cbc636de
--- /dev/null
+++ b/src/mame/video/gauntlet.c
@@ -0,0 +1,230 @@
+/***************************************************************************
+
+ Atari Gauntlet hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "gauntlet.h"
+
+
+
+/*************************************
+ *
+ * Globals we own
+ *
+ *************************************/
+
+UINT8 vindctr2_screen_refresh;
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static UINT8 playfield_tile_bank;
+static UINT8 playfield_color_bank;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha[tile_index];
+ int code = data & 0x3ff;
+ int color = ((data >> 10) & 0x0f) | ((data >> 9) & 0x20);
+ int opaque = data & 0x8000;
+ SET_TILE_INFO(1, code, color, opaque ? TILE_FORCE_LAYER0 : 0);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data = atarigen_playfield[tile_index];
+ int code = ((playfield_tile_bank * 0x1000) + (data & 0xfff)) ^ 0x800;
+ int color = 0x10 + (playfield_color_bank * 8) + ((data >> 12) & 7);
+ SET_TILE_INFO(0, code, color, (data >> 15) & 1);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( gauntlet )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 0, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 1, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 8, /* pixels per SLIP entry (0 for no-slip) */
+ 1, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x100, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0,0,0,0x03ff }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0x7fff,0,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0x000f,0,0 }}, /* mask for the color */
+ {{ 0,0xff80,0,0 }}, /* mask for the X position */
+ {{ 0,0,0xff80,0 }}, /* mask for the Y position */
+ {{ 0,0,0x0038,0 }}, /* mask for the width, in tiles*/
+ {{ 0,0,0x0007,0 }}, /* mask for the height, in tiles */
+ {{ 0,0,0x0040,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0 /* callback routine for special entries */
+ };
+
+ UINT16 *codelookup;
+ int i, size;
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8,8, 64,64);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ tilemap_set_transparent_pen(atarigen_alpha_tilemap, 0);
+
+ /* modify the motion object code lookup table to account for the code XOR */
+ codelookup = atarimo_get_code_lookup(0, &size);
+ for (i = 0; i < size; i++)
+ codelookup[i] ^= 0x800;
+
+ /* set up the base color for the playfield */
+ playfield_color_bank = vindctr2_screen_refresh ? 0 : 1;
+}
+
+
+
+/*************************************
+ *
+ * Horizontal scroll register
+ *
+ *************************************/
+
+WRITE16_HANDLER( gauntlet_xscroll_w )
+{
+ UINT16 oldxscroll = *atarigen_xscroll;
+ COMBINE_DATA(atarigen_xscroll);
+
+ /* if something changed, force a partial update */
+ if (*atarigen_xscroll != oldxscroll)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ /* adjust the scrolls */
+ tilemap_set_scrollx(atarigen_playfield_tilemap, 0, *atarigen_xscroll);
+ atarimo_set_xscroll(0, *atarigen_xscroll & 0x1ff);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Vertical scroll/PF bank register
+ *
+ *************************************/
+
+WRITE16_HANDLER( gauntlet_yscroll_w )
+{
+ UINT16 oldyscroll = *atarigen_yscroll;
+ COMBINE_DATA(atarigen_yscroll);
+
+ /* if something changed, force a partial update */
+ if (*atarigen_yscroll != oldyscroll)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ /* if the bank changed, mark all tiles dirty */
+ if (playfield_tile_bank != (*atarigen_yscroll & 3))
+ {
+ playfield_tile_bank = *atarigen_yscroll & 3;
+ tilemap_mark_all_tiles_dirty(atarigen_playfield_tilemap);
+ }
+
+ /* adjust the scrolls */
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, *atarigen_yscroll >> 7);
+ atarimo_set_yscroll(0, (*atarigen_yscroll >> 7) & 0x1ff);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( gauntlet )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* verified via schematics:
+
+ MO pen 1 clears PF color bit 0x80
+ */
+ if ((mo[x] & 0x0f) == 1)
+ {
+ /* Vindicators Part II has extra logic here for the bases */
+ if (!vindctr2_screen_refresh || (mo[x] & 0xf0) != 0)
+ pf[x] ^= 0x80;
+ }
+ else
+ pf[x] = mo[x];
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+
+ /* add the alpha on top */
+ tilemap_draw(bitmap, cliprect, atarigen_alpha_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/gberet.c b/src/mame/video/gberet.c
new file mode 100644
index 00000000000..479ad9e8eed
--- /dev/null
+++ b/src/mame/video/gberet.c
@@ -0,0 +1,212 @@
+#include "driver.h"
+
+
+UINT8 *gberet_scrollram;
+
+static int gberet_spritebank;
+
+static tilemap *bg_tilemap;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Green Beret has a 32 bytes palette PROM and two 256 bytes color lookup table
+ PROMs (one for sprites, one for characters).
+ The palette PROM is connected to the RGB output, this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+
+PALETTE_INIT( gberet )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ {
+ if (*color_prom & 0x0f) COLOR(1,i) = *color_prom & 0x0f;
+ else COLOR(1,i) = 0;
+ color_prom++;
+ }
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ {
+ COLOR(0,i) = (*(color_prom++) & 0x0f) + 0x10;
+ }
+}
+
+WRITE8_HANDLER( gberet_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( gberet_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( gberet_scroll_w )
+{
+ int scroll;
+
+ gberet_scrollram[offset] = data;
+
+ scroll = gberet_scrollram[offset & 0x1f] | (gberet_scrollram[offset | 0x20] << 8);
+ tilemap_set_scrollx(bg_tilemap, offset & 0x1f, scroll);
+}
+
+WRITE8_HANDLER( gberet_sprite_bank_w )
+{
+ gberet_spritebank = data;
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + ((attr & 0x40) << 2);
+ int color = attr & 0x0f;
+ int flags = TILE_FLIPYX((attr & 0x30) >> 4);
+
+ tileinfo->category = (attr & 0x80) >> 7;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( gberet )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_COLORTABLE, 8, 8, 64, 32);
+
+ tilemap_set_transparent_pen(bg_tilemap, 0x10);
+ tilemap_set_scroll_rows(bg_tilemap, 32);
+}
+
+static void gberet_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+ UINT8 *sr;
+
+ if (gberet_spritebank & 0x08)
+ sr = spriteram_2;
+ else
+ sr = spriteram;
+
+ for (offs = 0; offs < 0xc0; offs += 4)
+ {
+ if (sr[offs + 3])
+ {
+ int attr = sr[offs + 1];
+ int code = sr[offs+0] + ((attr & 0x40) << 2);
+ int color = attr & 0x0f;
+ int sx = sr[offs + 2] - 2 * (attr & 0x80);
+ int sy = sr[offs + 3];
+ int flipx = attr & 0x10;
+ int flipy = attr & 0x20;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy, sx, sy,
+ cliprect, TRANSPARENCY_COLOR, 0);
+ }
+ }
+}
+
+VIDEO_UPDATE( gberet )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_OPAQUE | 0, 0);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_OPAQUE | 1, 0);
+ gberet_draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ return 0;
+}
+
+/* Green Beret (bootleg) */
+
+WRITE8_HANDLER( gberetb_scroll_w )
+{
+ int scroll;
+
+ scroll = data;
+ if (offset) scroll |= 0x100;
+
+ for (offset = 6; offset < 29; offset++)
+ tilemap_set_scrollx(bg_tilemap, offset, scroll + 64-8);
+}
+
+static void gberetb_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = spriteram_size - 4; offs >= 0; offs -= 4)
+ {
+ if (spriteram[offs + 1])
+ {
+ int attr = spriteram[offs + 3];
+ int code = spriteram[offs] + ((attr & 0x40) << 2);
+ int color = attr & 0x0f;
+ int sx = spriteram[offs + 2] - 2 * (attr & 0x80);
+ int sy = 240 - spriteram[offs + 1];
+ int flipx = attr & 0x10;
+ int flipy = attr & 0x20;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy, sx, sy,
+ cliprect, TRANSPARENCY_COLOR, 0);
+ }
+ }
+}
+
+VIDEO_UPDATE( gberetb )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_OPAQUE | 0, 0);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_OPAQUE | 1, 0);
+ gberetb_draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/gbusters.c b/src/mame/video/gbusters.c
new file mode 100644
index 00000000000..3232d113483
--- /dev/null
+++ b/src/mame/video/gbusters.c
@@ -0,0 +1,77 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+
+int gbusters_priority;
+static int layer_colorbase[3],sprite_colorbase;
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void tile_callback(int layer,int bank,int *code,int *color,int *flags, int *priority)
+{
+ /* (color & 0x02) is flip y handled internally by the 052109 */
+ *code |= ((*color & 0x0d) << 8) | ((*color & 0x10) << 5) | (bank << 12);
+ *color = layer_colorbase[layer] + ((*color & 0xe0) >> 5);
+}
+
+/***************************************************************************
+
+ Callbacks for the K051960
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority,int *shadow)
+{
+ *priority = (*color & 0x30) >> 4;
+ *color = sprite_colorbase + (*color & 0x0f);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( gbusters )
+{
+ layer_colorbase[0] = 48;
+ layer_colorbase[1] = 0;
+ layer_colorbase[2] = 16;
+ sprite_colorbase = 32;
+
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,NORMAL_PLANE_ORDER,sprite_callback);
+}
+
+
+VIDEO_UPDATE( gbusters )
+{
+ K052109_tilemap_update();
+
+ /* sprite priority 3 = disable */
+ if (gbusters_priority)
+ {
+// K051960_sprites_draw(bitmap,cliprect,1,1); /* are these used? */
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],TILEMAP_DRAW_OPAQUE,0);
+ K051960_sprites_draw(bitmap,cliprect,2,2);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],0,0);
+ K051960_sprites_draw(bitmap,cliprect,0,0);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],0,0);
+ }
+ else
+ {
+// K051960_sprites_draw(bitmap,cliprect,1,1); /* are these used? */
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],TILEMAP_DRAW_OPAQUE,0);
+ K051960_sprites_draw(bitmap,cliprect,2,2);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],0,0);
+ K051960_sprites_draw(bitmap,cliprect,0,0);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],0,0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/gcpinbal.c b/src/mame/video/gcpinbal.c
new file mode 100644
index 00000000000..8e2c47e0f8e
--- /dev/null
+++ b/src/mame/video/gcpinbal.c
@@ -0,0 +1,356 @@
+#include "driver.h"
+#include "includes/gcpinbal.h"
+
+
+static tilemap *gcpinbal_tilemap[3];
+
+UINT16 *gcpinbal_tilemapram;
+UINT16 *gcpinbal_ioc_ram;
+
+//UINT16 *gcpinbal_ctrlram;
+//static UINT16 gcpinbal_ctrl_reg;
+
+static UINT16 gcpinbal_scrollx[3],gcpinbal_scrolly[3];
+
+static UINT16 bg0_gfxset = 0;
+static UINT16 bg1_gfxset = 0;
+
+
+
+/*******************************************************************/
+
+
+static TILE_GET_INFO( get_bg0_tile_info )
+{
+ UINT16 tilenum = gcpinbal_tilemapram[0 + tile_index*2];
+ UINT16 attr = gcpinbal_tilemapram[1 + tile_index*2];
+
+ SET_TILE_INFO(
+ 1,
+ (tilenum & 0xfff) + bg0_gfxset,
+ (attr & 0x1f),
+ TILE_FLIPYX( (attr & 0x300) >> 8));
+}
+
+static TILE_GET_INFO( get_bg1_tile_info )
+{
+ UINT16 tilenum = gcpinbal_tilemapram[0x800 + tile_index*2];
+ UINT16 attr = gcpinbal_tilemapram[0x801 + tile_index*2];
+
+ SET_TILE_INFO(
+ 1,
+ (tilenum & 0xfff) + 0x2000 + bg1_gfxset,
+ (attr & 0x1f) + 0x30,
+ TILE_FLIPYX( (attr & 0x300) >> 8));
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT16 tilenum = gcpinbal_tilemapram[0x1000 + tile_index];
+
+ SET_TILE_INFO(
+ 2,
+ (tilenum & 0xfff),
+ (tilenum >> 12) | 0x70,
+ 0);
+}
+
+#if 0
+static void dirty_tilemaps(void) // will be used for save states
+{
+ tilemap_mark_all_tiles_dirty(gcpinbal_tilemap[0]);
+ tilemap_mark_all_tiles_dirty(gcpinbal_tilemap[1]);
+ tilemap_mark_all_tiles_dirty(gcpinbal_tilemap[2]);
+}
+#endif
+
+static void gcpinbal_core_vh_start (void)
+{
+ int xoffs = 0;
+ int yoffs = 0;
+
+ gcpinbal_tilemap[0] = tilemap_create(get_bg0_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ gcpinbal_tilemap[1] = tilemap_create(get_bg1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ gcpinbal_tilemap[2] = tilemap_create(get_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ tilemap_set_transparent_pen( gcpinbal_tilemap[0],0 );
+ tilemap_set_transparent_pen( gcpinbal_tilemap[1],0 );
+ tilemap_set_transparent_pen( gcpinbal_tilemap[2],0 );
+
+ /* flipscreen n/a */
+ tilemap_set_scrolldx( gcpinbal_tilemap[0],-xoffs,0 );
+ tilemap_set_scrolldx( gcpinbal_tilemap[1],-xoffs,0 );
+ tilemap_set_scrolldx( gcpinbal_tilemap[2],-xoffs,0 );
+ tilemap_set_scrolldy( gcpinbal_tilemap[0],-yoffs,0 );
+ tilemap_set_scrolldy( gcpinbal_tilemap[1],-yoffs,0 );
+ tilemap_set_scrolldy( gcpinbal_tilemap[2],-yoffs,0 );
+}
+
+VIDEO_START( gcpinbal )
+{
+ gcpinbal_core_vh_start();
+}
+
+
+/******************************************************************
+ TILEMAP READ AND WRITE HANDLERS
+*******************************************************************/
+
+READ16_HANDLER( gcpinbal_tilemaps_word_r )
+{
+ return gcpinbal_tilemapram[offset];
+}
+
+WRITE16_HANDLER( gcpinbal_tilemaps_word_w )
+{
+ COMBINE_DATA(&gcpinbal_tilemapram[offset]);
+
+ if (offset<0x800) /* BG0 */
+ {
+ tilemap_mark_tile_dirty(gcpinbal_tilemap[0],offset/2);
+ }
+ else if ((offset<0x1000)) /* BG1 */
+ {
+ tilemap_mark_tile_dirty(gcpinbal_tilemap[1],(offset%0x800)/2);
+ }
+ else if ((offset<0x1800)) /* FG */
+ {
+ tilemap_mark_tile_dirty(gcpinbal_tilemap[2],(offset%0x800));
+ }
+}
+
+
+/*
+
+READ16_HANDLER( gcpinbal_ctrl_word_r )
+{
+ // ***** NOT HOOKED UP *****
+
+ return gcpinbal_piv_ctrlram[offset];
+}
+
+
+WRITE16_HANDLER( gcpinbal_ctrl_word_w )
+{
+ // ***** NOT HOOKED UP *****
+
+ COMBINE_DATA(&gcpinbal_piv_ctrlram[offset]);
+ data = gcpinbal_piv_ctrlram[offset];
+
+ switch (offset)
+ {
+ case 0x00:
+ gcpinbal_scrollx[0] = -data;
+ break;
+
+ case 0x01:
+ gcpinbal_scrollx[1] = -data;
+ break;
+
+ case 0x02:
+ gcpinbal_scrollx[2] = -data;
+ break;
+
+ case 0x03:
+ gcpinbal_scrolly[0] = data;
+ break;
+
+ case 0x04:
+ gcpinbal_scrolly[1] = data;
+ break;
+
+ case 0x05:
+ gcpinbal_scrolly[2] = data;
+ break;
+
+ case 0x06:
+ gcpinbal_ctrl_reg = data;
+ break;
+ }
+}
+
+*/
+
+
+/****************************************************************
+ SPRITE DRAW ROUTINE
+
+ Word | Bit(s) | Use
+ -----+-----------------+-----------------
+ 0 |........ xxxxxxxx| X lo
+ 1 |........ xxxxxxxx| X hi
+ 2 |........ xxxxxxxx| Y lo
+ 3 |........ xxxxxxxx| Y hi
+ 4 |........ x.......| Disable
+ 4 |........ ...x....| Flip Y
+ 4 |........ ....x...| 1 = Y chain, 0 = X chain
+ 4 |........ .....xxx| Chain size
+ 5 |........ ??xxxxxx| Tile (low)
+ 6 |........ xxxxxxxx| Tile (high)
+ 7 |........ ....xxxx| Color Bank
+
+ Modified table from Raine
+
+****************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int y_offs)
+{
+ int offs,chain_pos;
+ int x,y,curx,cury;
+ int priority=0;
+ UINT8 col,flipx,flipy,chain;
+ UINT16 code;
+
+ /* According to Raine, word in ioc_ram determines sprite/tile priority... */
+ priority = (gcpinbal_ioc_ram[0x68/2] & 0x8800) ? 0 : 1;
+
+ for (offs = spriteram_size/2-8;offs >= 0;offs -= 8)
+ {
+ code = ((spriteram16[offs+5])&0xff) + (((spriteram16[offs+6]) &0xff) << 8);
+ code &= 0x3fff;
+
+ if (!(spriteram16[offs+4] &0x80)) /* active sprite ? */
+ {
+ x = ((spriteram16[offs+0]) &0xff) + (((spriteram16[offs+1]) &0xff) << 8);
+ y = ((spriteram16[offs+2]) &0xff) + (((spriteram16[offs+3]) &0xff) << 8);
+
+ /* Treat coords as signed */
+ if (x & 0x8000) x -= 0x10000;
+ if (y & 0x8000) y -= 0x10000;
+
+ col = ((spriteram16[offs+7]) &0x0f) | 0x60;
+ chain = (spriteram16[offs+4]) &0x07;
+ flipy = (spriteram16[offs+4]) &0x10;
+ flipx = 0;
+
+ curx = x;
+ cury = y;
+
+ if (((spriteram16[offs+4]) &0x08) && flipy)
+ cury += (chain * 16);
+
+ for (chain_pos = chain;chain_pos >= 0;chain_pos--)
+ {
+ pdrawgfx(bitmap, machine->gfx[0],
+ code,
+ col,
+ flipx, flipy,
+ curx,cury,
+ cliprect,TRANSPARENCY_PEN,0,
+ priority ? 0xfc : 0xf0);
+
+ code++;
+
+ if ((spriteram16[offs+4]) &0x08) /* Y chain */
+ {
+ if (flipy) cury -= 16;
+ else cury += 16;
+ }
+ else /* X chain */
+ {
+ curx += 16;
+ }
+ }
+ }
+ }
+#if 0
+ if (rotate)
+ {
+ char buf[80];
+ sprintf(buf,"sprite rotate offs %04x ?",rotate);
+ popmessage(buf);
+ }
+#endif
+}
+
+
+
+
+/**************************************************************
+ SCREEN REFRESH
+**************************************************************/
+
+VIDEO_UPDATE( gcpinbal )
+{
+ static UINT16 tile_sets = 0;
+ int i;
+ UINT8 layer[3];
+
+#ifdef MAME_DEBUG
+ static UINT8 dislayer[4];
+#endif
+
+#ifdef MAME_DEBUG
+ if (input_code_pressed_once (KEYCODE_V))
+ {
+ dislayer[0] ^= 1;
+ popmessage("bg0: %01x",dislayer[0]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_B))
+ {
+ dislayer[1] ^= 1;
+ popmessage("bg1: %01x",dislayer[1]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_N))
+ {
+ dislayer[2] ^= 1;
+ popmessage("fg: %01x",dislayer[2]);
+ }
+#endif
+
+ gcpinbal_scrollx[0] = gcpinbal_ioc_ram[0x14/2];
+ gcpinbal_scrolly[0] = gcpinbal_ioc_ram[0x16/2];
+ gcpinbal_scrollx[1] = gcpinbal_ioc_ram[0x18/2];
+ gcpinbal_scrolly[1] = gcpinbal_ioc_ram[0x1a/2];
+ gcpinbal_scrollx[2] = gcpinbal_ioc_ram[0x1c/2];
+ gcpinbal_scrolly[2] = gcpinbal_ioc_ram[0x1e/2];
+
+ tile_sets = gcpinbal_ioc_ram[0x88/2];
+ bg0_gfxset = (tile_sets & 0x400) ? 0x1000 : 0;
+ bg1_gfxset = (tile_sets & 0x800) ? 0x1000 : 0;
+
+ for (i=0;i<3;i++)
+ {
+ tilemap_set_scrollx(gcpinbal_tilemap[i], 0, gcpinbal_scrollx[i]);
+ tilemap_set_scrolly(gcpinbal_tilemap[i], 0, gcpinbal_scrolly[i]);
+ }
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ layer[0] = 0;
+ layer[1] = 1;
+ layer[2] = 2;
+
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[0]]==0)
+#endif
+ tilemap_draw(bitmap,cliprect,gcpinbal_tilemap[layer[0]],TILEMAP_DRAW_OPAQUE,1);
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[1]]==0)
+#endif
+ tilemap_draw(bitmap,cliprect,gcpinbal_tilemap[layer[1]],0,2);
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[2]]==0)
+#endif
+ tilemap_draw(bitmap,cliprect,gcpinbal_tilemap[layer[2]],0,4);
+
+
+ draw_sprites(machine, bitmap,cliprect,16);
+
+#if 0
+ {
+// char buf[80];
+ sprintf(buf,"bg0_gfx: %04x bg1_gfx: %04x ",bg0_gfxset,bg1_gfxset);
+ popmessage(buf);
+ }
+#endif
+
+ return 0;
+}
+
diff --git a/src/mame/video/gdrawpkr.c b/src/mame/video/gdrawpkr.c
new file mode 100644
index 00000000000..525dd59b655
--- /dev/null
+++ b/src/mame/video/gdrawpkr.c
@@ -0,0 +1,90 @@
+/**********************************************************************************
+
+ GAMING DRAW POKER (CEI)
+ Driver by Roberto Fresca.
+
+ Video Hardware
+
+***********************************************************************************/
+
+#include "driver.h"
+static tilemap *bg_tilemap;
+
+WRITE8_HANDLER( gdrawpkr_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( gdrawpkr_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+/* - bits -
+ 7654 3210
+ --xx xx-- tiles color.
+ ---- --x- tiles bank.
+ xx-- ---x seems unused. */
+
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index];
+ int bank = (attr & 0x02) >> 1; /* bit 1 switch the gfx banks */
+ int color = (attr & 0x3c); /* bits 2-3-4-5 for color */
+
+ if (attr == 0x3a) /* Is the palette wrong? */
+ color = 0x3b; /* 0x3b is the best match */
+
+ SET_TILE_INFO(bank, code, color, 0);
+}
+
+VIDEO_START( gdrawpkr )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 31);
+}
+
+VIDEO_UPDATE( gdrawpkr )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ return 0;
+}
+
+PALETTE_INIT( gdrawpkr )
+{
+/* prom bits
+ 7654 3210
+ ---- ---x red component.
+ ---- --x- green component.
+ ---- -x-- blue component.
+ ---- x--- unknown, aparently unused.
+ xxxx ---- unused.
+*/
+ int i;
+
+ /* 00000BGR */
+ if (color_prom == 0) return;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ r = bit0 * 0xff;
+
+ /* green component */
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ g = bit1 * 0xff;
+
+ /* blue component */
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ b = bit2 * 0xff;
+
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ }
+}
diff --git a/src/mame/video/genesis.c b/src/mame/video/genesis.c
new file mode 100644
index 00000000000..440621a3b61
--- /dev/null
+++ b/src/mame/video/genesis.c
@@ -0,0 +1,1382 @@
+/***********************************************************************************************
+
+ Sega System C/C2 Driver
+ -----------------------
+ Version 0.54 - 02 Feb 2003
+ (for changes see drivers\segac2.c)
+
+***********************************************************************************************/
+
+#include "driver.h"
+#include "genesis.h"
+
+/* in video/segasyse.c */
+void megaplay_start_video_normal(running_machine *machine);
+void megaplay_update_video_normal(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect );
+
+static int genesis_screen_number;
+
+
+/******************************************************************************
+ Macros
+******************************************************************************/
+
+#define BITMAP_WIDTH 320
+#define BITMAP_HEIGHT 240
+
+#define VRAM_SIZE 0x10000
+#define VRAM_MASK (VRAM_SIZE - 1)
+#define VSRAM_SIZE 0x80
+#define VSRAM_MASK (VSRAM_SIZE - 1)
+#define CRAM_SIZE 0x40
+#define CRAM_MASK (CRAM_SIZE - 1)
+
+#define VDP_VRAM_BYTE(x) (vdp_vram[(x) & VRAM_MASK])
+#define VDP_VSRAM_BYTE(x) (vdp_vsram[(x) & VSRAM_MASK])
+#define VDP_VRAM_WORD(x) ((VDP_VRAM_BYTE(x) << 8) | VDP_VRAM_BYTE((x) + 1))
+#define VDP_VSRAM_WORD(x) ((VDP_VSRAM_BYTE(x) << 8) | VDP_VSRAM_BYTE((x) + 1))
+
+#ifdef LSB_FIRST
+#define EXTRACT_PIXEL(x,i) (((x) >> (((i) ^ 1) * 4)) & 0x0f)
+#else
+#define EXTRACT_PIXEL(x,i) (((x) >> (((i) ^ 7) * 4)) & 0x0f)
+#endif
+
+
+
+/******************************************************************************
+ Function Prototypes
+******************************************************************************/
+
+static int vdp_data_r(void);
+static void vdp_data_w(int data);
+static int vdp_control_r(void);
+static void vdp_control_w(int data);
+static void vdp_register_w(int data, int vblank);
+static void vdp_control_dma(int data);
+static void vdp_dma_68k(void);
+static void vdp_dma_fill(int);
+static void vdp_dma_copy(void);
+
+static void drawline(UINT16 *bitmap, int line, int bgfill);
+static void get_scroll_tiles(int line, int scrollnum, UINT32 scrollbase, UINT32 *tiles, int *offset);
+static void get_window_tiles(int line, UINT32 scrollbase, UINT32 *tiles);
+static void drawline_tiles(UINT32 *tiles, UINT16 *bmap, int pri, int offset, int lclip, int rclip);
+static void drawline_sprite(int line, UINT16 *bmap, int priority, UINT8 *spritebase);
+
+
+
+/******************************************************************************
+ Global variables
+******************************************************************************/
+
+/* EXTERNALLY ACCESSIBLE */
+ UINT16 genesis_bg_pal_lookup[4]; /* lookup table for background tiles */
+ UINT16 genesis_sp_pal_lookup[4]; /* lookup table for sprites */
+ UINT8 genesis_vdp_regs[32]; /* VDP registers */
+
+/* LOCAL */
+static UINT8 * vdp_vram; /* VDP video RAM */
+static UINT8 * vdp_vsram; /* VDP vertical scroll RAM */
+static UINT8 display_enable; /* is the display enabled? */
+static int genesis_palette_base; /* offset to use when doing palette writes */
+
+/* updates */
+static UINT16 * transparent_lookup; /* fast transparent mapping table */
+
+/* vram bases */
+static UINT32 vdp_scrollabase; /* base address of scroll A tiles */
+static UINT32 vdp_scrollbbase; /* base address of scroll B tiles */
+static UINT32 vdp_windowbase; /* base address of window tiles */
+static UINT32 vdp_spritebase; /* base address of sprite data */
+static UINT32 vdp_hscrollbase; /* base address of H scroll values */
+
+/* other vdp variables */
+static INT32 vdp_hscrollmask; /* mask for H scrolling */
+static UINT32 vdp_hscrollsize; /* size of active H scroll values */
+static UINT8 vdp_vscrollmode; /* current V scrolling mode */
+
+static UINT8 vdp_cmdpart; /* partial command flag */
+static UINT8 vdp_code; /* command code value */
+static UINT32 vdp_address; /* current I/O address */
+static UINT8 vdp_dmafill; /* DMA filling flag */
+static UINT8 scrollheight; /* height of the scroll area in tiles */
+static UINT8 scrollwidth; /* width of the scroll area in tiles */
+static UINT8 bgcol; /* current background color */
+static UINT8 window_down; /* window Y direction */
+static UINT32 window_vpos; /* window Y position */
+static UINT8 window_right; /* window X direction */
+static UINT32 window_hpos; /* window X position */
+static UINT8 window_width; /* window width */
+
+
+/******************************************************************************
+ Video Start / Stop Functions
+*******************************************************************************
+
+ Here we allocate memory used by the VDP and various other video related parts
+ of the System C/C2 hardware such as the Palette RAM. Here is what is needed
+
+ 64kb of VRAM (multi-purpose, storing tiles, tilemaps, hscroll data,
+ spritelist etc.)
+
+ 80bytes of VSRAM (used exclusively for storing Vertical Scroll values)
+
+******************************************************************************/
+
+
+static void start_genesis_vdp(int screen_number)
+{
+ static const UINT8 vdp_init[24] =
+ {
+ 0x04, 0x44, 0x30, 0x3C, 0x07, 0x6C, 0x00, 0x00,
+ 0x00, 0x00, 0xFF, 0x00, 0x01, 0x37, 0x00, 0x02,
+ 0x01, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x80,
+ };
+ int i;
+
+ genesis_screen_number = screen_number;
+
+ /* allocate memory for the VDP, the lookup table, and the buffer bitmap */
+ vdp_vram = auto_malloc(VRAM_SIZE);
+ vdp_vsram = auto_malloc(VSRAM_SIZE);
+ transparent_lookup = auto_malloc(0x1000 * sizeof(UINT16));
+
+ /* clear the VDP memory, prevents corrupt tile in Puyo Puyo 2 */
+ memset(vdp_vram, 0, VRAM_SIZE);
+ memset(vdp_vsram, 0, VSRAM_SIZE);
+
+ /* init transparency table */
+ for (i = 0; i < 0x1000; i++)
+ {
+ int orig_color = i & 0x7ff;
+ int half_bright = i & 0x800;
+
+ if (orig_color & 0x100)
+ transparent_lookup[i] = orig_color;
+ else if (half_bright)
+ transparent_lookup[i] = orig_color | 0x800;
+ else
+ transparent_lookup[i] = orig_color | 0x1000;
+ }
+
+ /* reset the palettes */
+ genesis_palette_base = 0;
+ genesis_bg_pal_lookup[0] = genesis_sp_pal_lookup[0] = 0x00;
+ genesis_bg_pal_lookup[1] = genesis_sp_pal_lookup[1] = 0x10;
+ genesis_bg_pal_lookup[2] = genesis_sp_pal_lookup[2] = 0x20;
+ genesis_bg_pal_lookup[3] = genesis_sp_pal_lookup[3] = 0x30;
+
+ /* reset VDP */
+ for (i = 0; i < 24; i++)
+ vdp_register_w(0x8000 | (i << 8) | vdp_init[i], 1);
+ vdp_cmdpart = 0;
+ vdp_code = 0;
+ vdp_address = 0;
+
+ /* Save State Stuff */
+ state_save_register_global_array(genesis_vdp_regs);
+ state_save_register_global_pointer(vdp_vram, 0x10000);
+ state_save_register_global_pointer(vdp_vsram, 0x80);
+ state_save_register_global_array(genesis_bg_pal_lookup);
+ state_save_register_global_array(genesis_sp_pal_lookup);
+ state_save_register_global(display_enable);
+ state_save_register_global(vdp_scrollabase);
+ state_save_register_global(vdp_scrollbbase);
+ state_save_register_global(vdp_windowbase);
+ state_save_register_global(vdp_spritebase);
+ state_save_register_global(vdp_hscrollbase);
+ state_save_register_global(vdp_hscrollmask);
+ state_save_register_global(vdp_hscrollsize);
+ state_save_register_global(vdp_vscrollmode);
+ state_save_register_global(vdp_cmdpart);
+ state_save_register_global(vdp_code);
+ state_save_register_global(vdp_address);
+ state_save_register_global(vdp_dmafill);
+ state_save_register_global(scrollheight);
+ state_save_register_global(scrollwidth);
+ state_save_register_global(bgcol);
+ state_save_register_global(window_down);
+ state_save_register_global(window_vpos);
+}
+
+VIDEO_START(genesis)
+{
+ start_genesis_vdp(0);
+}
+
+
+VIDEO_START( segac2 )
+{
+ start_genesis_vdp(0);
+
+ /* C2 has separate sprite/background palettes */
+ genesis_sp_pal_lookup[0] = 0x100;
+ genesis_sp_pal_lookup[1] = 0x110;
+ genesis_sp_pal_lookup[2] = 0x120;
+ genesis_sp_pal_lookup[3] = 0x130;
+}
+
+
+
+
+
+
+void start_system18_vdp(void)
+{
+ start_genesis_vdp(0);
+
+ genesis_palette_base = 0x1800;
+ genesis_bg_pal_lookup[0] = genesis_sp_pal_lookup[0] = 0x1800;
+ genesis_bg_pal_lookup[1] = genesis_sp_pal_lookup[1] = 0x1810;
+ genesis_bg_pal_lookup[2] = genesis_sp_pal_lookup[2] = 0x1820;
+ genesis_bg_pal_lookup[3] = genesis_sp_pal_lookup[3] = 0x1830;
+}
+
+
+
+/******************************************************************************
+ Screen Refresh Functions
+*******************************************************************************
+
+ These are responsible for the core drawing. The update_display function
+ can be called under several circumstances to cache all the currently
+ displayed lines before a significant palette or scrolling change is
+ set to occur. The actual refresh routine marks the accumulated palette
+ entries and then converts the raw pens in the cache bitmap to their
+ final remapped values.
+
+******************************************************************************/
+
+/* set the display enable bit */
+void segac2_enable_display(int enable)
+{
+ if (!video_screen_get_vblank(0))
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ display_enable = enable;
+}
+
+
+VIDEO_UPDATE( genesis )
+{
+ int y;
+
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ drawline(BITMAP_ADDR16(bitmap, y, 0), y, 0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( segac2 )
+{
+ if (!display_enable)
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ else
+ video_update_genesis(machine, screen, bitmap, cliprect);
+ return 0;
+}
+
+
+
+
+/* megaplay, draws either Genesis or SMS (single screen display) */
+
+/* core refresh: computes the final screen */
+VIDEO_UPDATE( megaplay )
+{
+ int y;
+
+
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ drawline(BITMAP_ADDR16(bitmap, y, 0), y, 0);
+
+ megaplay_update_video_normal(machine, bitmap, cliprect);
+
+ return 0;
+}
+
+void update_system18_vdp( mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int y;
+
+ /* generate the final screen */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ drawline(BITMAP_ADDR16(bitmap, y, 0), y, 0xffff);
+}
+
+/******************************************************************************
+ VDP Read & Write Handlers
+*******************************************************************************
+
+ The VDP is accessed via 8 & 16 bit reads / writes at the addresses 0xC00000 -
+ 0xC0001F. Different locations have different functions in the following
+ layout. (based on Information in Charles MacDonalds Document)
+
+ 0xC00000 - DATA port (8 or 16 bit, Read or Write)
+ 0xC00002 - mirror of above
+ 0xC00004 - CTRL port (8 or 16 bit, Read or Write)
+ 0xC00006 - mirror of above
+ 0xC00008 - HV counter (8 or 16 bit Read Only)
+ 0xC0000A - mirror of above
+ 0xC0000C - mirror of above
+ 0xC0000E - mirror of above
+ 0xC00010 - SN76489 (8 bit Write Only)
+ 0xC00012 - mirror of above
+ 0xC00014 - mirror of above
+ 0xC00016 - mirror of above
+
+ The SN76489 PSG Writes are intercepted before we get here and handled
+ directly.
+
+******************************************************************************/
+
+READ16_HANDLER( genesis_vdp_r )
+{
+ switch (offset)
+ {
+ case 0x00: /* Read Data */
+ case 0x01:
+ return vdp_data_r();
+
+ case 0x02: /* Status Register */
+ case 0x03:
+ return vdp_control_r();
+
+ case 0x04: /* HV counter */
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ {
+ int xpos = video_screen_get_hpos(0);
+ int ypos = video_screen_get_vpos(0);
+
+ /* adjust for the weird counting rules */
+ if (xpos > 0xe9) xpos -= (342 - 0x100);
+ if (ypos > 0xea) ypos -= (262 - 0x100);
+
+ /* kludge for ichidant: it sets the H counter to 160, then */
+ /* expects that a read from here will return 159 */
+ if (ypos > 0) ypos -= 2;
+ return (ypos << 8) | xpos;
+ }
+ }
+ return 0;
+}
+
+
+WRITE16_HANDLER( genesis_vdp_w )
+{
+ switch (offset)
+ {
+ case 0x00: /* Write data */
+ case 0x01:
+ if (mem_mask)
+ {
+ data &= ~mem_mask;
+ if (ACCESSING_MSB)
+ data |= data >> 8;
+ else
+ data |= data << 8;
+ }
+ vdp_data_w(data);
+ break;
+
+ case 0x02: /* Control Write */
+ case 0x03:
+ if (mem_mask)
+ {
+ data &= ~mem_mask;
+ if (ACCESSING_MSB)
+ data |= data >> 8;
+ else
+ data |= data << 8;
+ }
+ vdp_control_w(data);
+ break;
+
+ case 0x08: /* SN76489 Write */
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ if (ACCESSING_LSB && sndti_exists(SOUND_SN76496, 0))
+ SN76496_0_w(0, data & 0xff);
+ break;
+ }
+}
+
+
+
+/******************************************************************************
+ VDP DATA Reads / Writes (Accesses to 0xC00000 - 0xC00003)
+*******************************************************************************
+
+ The functions here are called by the read / write handlers for the VDP.
+ They deal with Data Reads and Writes to and from the VDP Chip.
+
+ Read / write mode is set by Writes to VDP Control, Can't Read when in
+ write mode or vice versa.
+
+******************************************************************************/
+
+/* Games needing Read to Work .. bloxeed (attract) .. puyo puyo .. probably more */
+static int vdp_data_r(void)
+{
+ int read = 0;
+
+ /* kill 2nd write pending flag */
+ vdp_cmdpart = 0;
+
+ /* which memory is based on the code */
+ switch (vdp_code & 0x0f)
+ {
+ case 0x00: /* VRAM read */
+ read = VDP_VRAM_WORD(vdp_address & ~1);
+ break;
+
+ case 0x04: /* VSRAM read */
+ read = VDP_VSRAM_WORD(vdp_address & ~1);
+ break;
+
+ default: /* Illegal read attempt */
+ logerror("%06x: VDP illegal read type %02x\n", activecpu_get_previouspc(), vdp_code);
+ read = 0x00;
+ break;
+ }
+
+ /* advance the address */
+ vdp_address += genesis_vdp_regs[15];
+ return read;
+}
+
+
+static void vdp_data_w(int data)
+{
+ /* kill 2nd write pending flag */
+ vdp_cmdpart = 0;
+
+ /* handle the fill case */
+ if (vdp_dmafill)
+ {
+ vdp_dma_fill(data);
+ vdp_dmafill = 0;
+ return;
+ }
+
+ /* which memory is based on the code */
+ switch (vdp_code & 0x0f)
+ {
+ case 0x01: /* VRAM write */
+
+ /* if the hscroll RAM is changing during screen refresh, force an update */
+ if (!video_screen_get_vblank(0) &&
+ vdp_address >= vdp_hscrollbase &&
+ vdp_address < vdp_hscrollbase + vdp_hscrollsize)
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ /* write to VRAM */
+ if (vdp_address & 1)
+ data = ((data & 0xff) << 8) | ((data >> 8) & 0xff);
+ VDP_VRAM_BYTE(vdp_address & ~1) = data >> 8;
+ VDP_VRAM_BYTE(vdp_address | 1) = data;
+ break;
+
+ case 0x03: /* Palette write */
+ {
+ int offset = (vdp_address/2) % CRAM_SIZE;
+ palette_set_color_rgb(Machine, offset + genesis_palette_base, pal3bit(data >> 1), pal3bit(data >> 5), pal3bit(data >> 9));
+ }
+ break;
+
+ case 0x05: /* VSRAM write */
+
+ /* if the vscroll RAM is changing during screen refresh, force an update */
+ if (!video_screen_get_vblank(0))
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ /* write to VSRAM */
+ if (vdp_address & 1)
+ data = ((data & 0xff) << 8) | ((data >> 8) & 0xff);
+ VDP_VSRAM_BYTE(vdp_address & ~1) = data >> 8;
+ VDP_VSRAM_BYTE(vdp_address | 1) = data;
+ break;
+
+ default: /* Illegal write attempt */
+ logerror("PC:%06x: VDP illegal write type %02x data %04x\n", activecpu_get_previouspc(), vdp_code, data);
+ break;
+ }
+
+ /* advance the address */
+ vdp_address += genesis_vdp_regs[15];
+}
+
+
+
+/******************************************************************************
+ VDP CTRL Reads / Writes (Accesses to 0xC00004 - 0xC00007)
+*******************************************************************************
+
+ A Read from the Control Port will return the Status Register Value.
+ 16-bits are used to report the VDP status
+ | 0 | 0 | 1 | 1 | 0 | 1 | FIFE | FIFF |
+ | VIP | SOF | SCL | ODD | VBLK | HBLK | DMA | PAL |
+
+ 0,1 = Set Values
+ FIFE = FIFO Empty
+ FIFF = FIFO Full
+ VIP = Vertical Interrupt Pending
+ SOF = Sprite Overflow (Not used in C2 afaik)
+ SCL = Sprite Collision (Not used in C2 afaik)
+ ODD = Odd Frame (Interlace Mode) (Not used in C2 afaik)
+ VBLK = In Vertical Blank
+ HBLK = In Horizontal Blank
+ DMA = DMA In Progress
+ PAL = Pal Mode Flag
+
+ Control Writes are used for setting VDP Registers, setting up DMA Transfers
+ etc.
+
+ A Write to the Control port can consist of 2 16-bit Words.
+ When the VDP _isn't_ expecting the 2nd part of a command the highest 2 bits
+ of the data written will determine what it is we want to do.
+ 10xxxxxx xxxxxxxx will cause a register to be set
+ anything else will trigger the 1st half of a 2 Part Mode Setting Command
+ If the VDP is already expecting the 2nd half of a command the data written
+ will be the 2nd half of the Mode setup.
+
+******************************************************************************/
+
+static int vdp_control_r(void)
+{
+ int status = 0x3600; // wwally needs fifo empty set
+
+ /* kill 2nd write pending flag */
+ vdp_cmdpart = 0;
+
+ /* set the VBLANK bit */
+ if (video_screen_get_vblank(0))
+ status |= 0x0008;
+
+ /* set the HBLANK bit */
+ if (video_screen_get_hblank(0))
+ status |= 0x0004;
+
+ return (status);
+}
+
+
+static void vdp_control_w(int data)
+{
+ /* case 1: we're not expecting the 2nd half of a command */
+ if (!vdp_cmdpart)
+ {
+ /* if 10xxxxxx xxxxxxxx this is a register setting command */
+ if ((data & 0xc000) == 0x8000)
+ vdp_register_w(data, video_screen_get_vblank(0));
+
+ /* otherwise this is the First part of a mode setting command */
+ else
+ {
+ vdp_code = (vdp_code & 0x3c) | ((data >> 14) & 0x03);
+ vdp_address = (vdp_address & 0xc000) | (data & 0x3fff);
+ vdp_cmdpart = 1;
+ }
+ }
+
+ /* case 2: this is the 2nd part of a mode setting command */
+ else
+ {
+ vdp_code = (vdp_code & 0x03) | ((data >> 2) & 0x3c);
+ vdp_address = (vdp_address & 0x3fff) | ((data << 14) & 0xc000);
+ vdp_cmdpart = 0;
+ vdp_control_dma(data);
+ }
+}
+
+
+static void vdp_register_w(int data, int vblank)
+{
+ int scrwidth = 0;
+ static const UINT8 is_important[32] = { 0,0,1,1,1,1,0,1,0,0,0,1,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+ UINT8 regnum = (data & 0x1f00) >> 8; /* ---R RRRR ---- ---- */
+ UINT8 regdat = (data & 0x00ff); /* ---- ---- DDDD DDDD */
+
+ genesis_vdp_regs[regnum] = regdat;
+
+ /* these are mostly important writes; force an update if they */
+ /* are written during a screen refresh */
+ if (!vblank && is_important[regnum])
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ /* For quite a few of the registers its a good idea to set a couple of variable based
+ upon the writes here */
+ switch (regnum)
+ {
+ case 0x01: /* video modes */
+ if (regdat & 8)
+ popmessage("Video height = 240!");
+ break;
+
+ case 0x02: /* Scroll A Name Table Base */
+ vdp_scrollabase = (regdat & 0x38) << 10;
+ break;
+
+ case 0x03: /* Window Name Table Base */
+ vdp_windowbase = (regdat & 0x3e) << 10;
+ break;
+
+ case 0x04: /* Scroll B Name Table Base */
+ vdp_scrollbbase = (regdat & 0x07) << 13;
+ break;
+
+ case 0x05: /* Sprite Table Base */
+ vdp_spritebase = (regdat & 0x7e) << 9;
+ break;
+
+ case 0x07: /* BG Colour */
+ bgcol = regdat & 0x3f;
+ break;
+
+ case 0x0b: /* Scroll Modes */
+ {
+ static const UINT16 mask_table[4] = { 0x000, 0x007, 0xff8, 0xfff };
+ vdp_vscrollmode = (regdat & 0x04) >> 2;
+
+ vdp_hscrollmask = mask_table[regdat & 3];
+ vdp_hscrollsize = 4 * ((vdp_hscrollmask < 224) ? (vdp_hscrollmask + 1) : 224);
+ break;
+ }
+
+ case 0x0c: /* video modes */
+ /* HDG: taken from mess/machine/genesis.c */
+ switch (regdat&0x81)
+ {
+ case 0x00: // 32 cell
+ scrwidth=32;
+ window_width=32;
+ break;
+ case 0x01: // 40 cell corrupted
+ scrwidth=40;
+ window_width=64;
+ break;
+ case 0x80: // illegal!
+ scrwidth=40;
+ window_width=64;
+ break;
+ case 0x81: // 40 cell
+ scrwidth=40;
+ window_width=64;
+ break;
+ }
+ {
+ screen_state *state = &Machine->screen[genesis_screen_number];
+ rectangle visarea = state->visarea;
+
+ /* this gets called from the init! */
+ visarea.max_x = scrwidth*8-1;
+ video_screen_configure(genesis_screen_number, scrwidth*8, state->height, &visarea, state->refresh);
+ }
+ break;
+
+ case 0x0d: /* HScroll Base */
+ vdp_hscrollbase = (regdat & 0x3f) << 10;
+ break;
+
+ case 0x10: /* Scroll Size */
+ {
+ static const UINT8 size_table[4] = { 32, 64, 128, 128 };
+ scrollwidth = size_table[regdat & 0x03];
+ scrollheight = size_table[(regdat & 0x30) >> 4];
+ break;
+ }
+
+ case 0x11: /* Window H Position .. Doesn't Matter for any of the C2 Games */
+ window_right = regdat & 0x80;
+ window_hpos = (regdat & 0x1f) << 4;
+ break;
+
+ case 0x12: /* Window V Position */
+ window_down = regdat & 0x80;
+ window_vpos = (regdat & 0x1f) << 3;
+ break;
+ }
+}
+
+
+static void vdp_control_dma(int data)
+{
+ if ((vdp_code & 0x20) && (genesis_vdp_regs[1] & 0x10))
+ {
+ switch(genesis_vdp_regs[23] & 0xc0)
+ {
+ case 0x00:
+ case 0x40: /* 68k -> VRAM Tranfser */
+ vdp_dma_68k();
+ break;
+
+ case 0x80: /* VRAM fill, can't be done here, requires data write */
+ vdp_dmafill = 1;
+ break;
+
+ case 0xC0: /* VRAM copy */
+ vdp_dma_copy();
+ break;
+ }
+ }
+}
+
+
+
+/******************************************************************************
+ DMA handling
+*******************************************************************************
+
+ These are currently Pretty much directly from the C2 emu
+
+******************************************************************************/
+
+static void vdp_dma_68k(void)
+{
+ int length = genesis_vdp_regs[19] | (genesis_vdp_regs[20] << 8);
+ int source = (genesis_vdp_regs[21] << 1) | (genesis_vdp_regs[22] << 9) | ((genesis_vdp_regs[23] & 0x7f) << 17);
+ int count;
+
+ /* length of 0 means 64k likely */
+ if (!length)
+ length = 0xffff;
+
+ /* handle the DMA */
+ for (count = 0; count < length; count++)
+ {
+ vdp_data_w(program_read_word(source));
+ source += 2;
+ }
+}
+
+
+static void vdp_dma_copy(void)
+{
+ int length = genesis_vdp_regs[19] | (genesis_vdp_regs[20] << 8);
+ int source = genesis_vdp_regs[21] | (genesis_vdp_regs[22] << 8);
+ int count;
+
+ /* length of 0 means 64k likely */
+ if (!length)
+ length = 0xffff;
+
+ /* handle the DMA */
+ for (count = 0; count < length; count++)
+ {
+ VDP_VRAM_BYTE(vdp_address) = VDP_VRAM_BYTE(source++);
+ vdp_address += genesis_vdp_regs[15];
+ }
+}
+
+
+static void vdp_dma_fill(int data)
+{
+ int length = genesis_vdp_regs[19] | (genesis_vdp_regs[20] << 8);
+ int count;
+
+ /* length of 0 means 64k likely */
+ if (!length)
+ length = 0xffff;
+
+ /* handle the fill */
+ VDP_VRAM_BYTE(vdp_address) = data;
+ data >>= 8;
+ for(count = 0; count < length; count++)
+ {
+ VDP_VRAM_BYTE(vdp_address ^ 1) = data;
+ vdp_address += genesis_vdp_regs[15];
+ }
+}
+
+
+
+/******************************************************************************
+ Scroll calculations
+*******************************************************************************
+
+ These special routines handle the transparency effects in sprites.
+
+******************************************************************************/
+
+/*** Useful Little Functions **************************************************/
+
+/* Note: We Expect plane = 0 for Scroll A, plane = 2 for Scroll B */
+INLINE int vdp_gethscroll(int plane, int line)
+{
+ line &= vdp_hscrollmask;
+ return 0x400 - (VDP_VRAM_WORD(vdp_hscrollbase + (4 * line) + plane) & 0x3ff);
+}
+
+
+/* Note: We expect plane = 0 for Scroll A, plane = 2 for Scroll B
+ A Column is 8 Pixels Wide */
+static int vdp_getvscroll(int plane, int column)
+{
+ UINT32 vsramoffset;
+
+ switch (vdp_vscrollmode)
+ {
+ case 0x00: /* Overall Scroll */
+ return VDP_VSRAM_WORD(plane) & 0x7ff;
+
+ case 0x01: /* Column Scroll */
+ if (column == 40) column = 39; /* Fix Minor Innacuracy Only affects PotoPoto */
+ vsramoffset = (4 * (column >> 1)) + plane;
+ return VDP_VSRAM_WORD(vsramoffset) & 0x7ff;
+ }
+ return 0;
+}
+
+
+
+/******************************************************************************
+ Drawing Functions
+*******************************************************************************
+
+ These are used by the Screen Refresh functions to do the actual rendering
+ of a screenline to the bitmap.
+
+ Draw Planes in Order
+ Scroll B Low
+ Scroll A Low / Window Low
+ Sprites Low
+ Scroll B High
+ Scroll A High / Window High
+ Sprites High
+
+ NOTE: Low Sprites _can_ overlap High sprites, however none of the C2
+ games do this ever so its safe to draw them in this order.
+
+******************************************************************************/
+
+static void drawline(UINT16 *bitmap, int line, int bgfill)
+{
+ int lowsprites, highsprites, link;
+ UINT32 scrolla_tiles[41], scrollb_tiles[41], window_tiles[41];
+ int scrolla_offset, scrollb_offset;
+ UINT8 *lowlist[81], *highlist[81];
+ int bgcolor = bgfill ? bgfill : genesis_bg_pal_lookup[0];
+ int window_lclip, window_rclip;
+ int scrolla_lclip, scrolla_rclip;
+ int column, sprite;
+
+ /* clear to the background color */
+ for (column = 0; column < BITMAP_WIDTH; column++)
+ bitmap[column] = bgcolor;
+
+ /* if display is disabled, stop */
+ if (!(genesis_vdp_regs[1] & 0x40))
+ return;
+
+ /* Sprites need to be Drawn in Reverse order .. may as well sort them here */
+ link = lowsprites = highsprites = 0;
+ for (sprite = 0; sprite < 80; sprite++)
+ {
+ UINT8 *spritebase = &VDP_VRAM_BYTE(vdp_spritebase + 8 * link);
+
+ /* sort into high/low priorities */
+ if (spritebase[4] & 0x0080)
+ highlist[++highsprites] = spritebase;
+ else
+ lowlist[++lowsprites] = spritebase;
+
+ /* get the link; if 0, stop processing */
+ link = spritebase[3] & 0x7F;
+ if (!link)
+ break;
+ }
+
+ /* get tiles for the B scroll layer */
+ get_scroll_tiles(line, 2, vdp_scrollbbase, scrollb_tiles, &scrollb_offset);
+
+ /* get tiles for the A scroll layer */
+ get_scroll_tiles(line, 0, vdp_scrollabase, scrolla_tiles, &scrolla_offset);
+
+ /* get tiles for the window layer */
+ get_window_tiles(line, vdp_windowbase, window_tiles);
+
+ /* compute the windowing for this line */
+ if ((window_down && line >= window_vpos) || (!window_down && line < window_vpos))
+ window_lclip = 0, window_rclip = BITMAP_WIDTH - 1;
+ else if (window_right)
+ window_lclip = window_hpos, window_rclip = BITMAP_WIDTH - 1;
+ else
+ window_lclip = 0, window_rclip = window_hpos - 1;
+
+ /* compute the clipping of the scroll A layer */
+ if (window_lclip == 0)
+ {
+ scrolla_lclip = window_rclip + 1;
+ scrolla_rclip = BITMAP_WIDTH - 1;
+ }
+ else
+ {
+ scrolla_lclip = 0;
+ scrolla_rclip = window_lclip - 1;
+ }
+
+ /* Scroll B Low */
+ drawline_tiles(scrollb_tiles, bitmap, 0, scrollb_offset, 0, BITMAP_WIDTH - 1);
+
+ /* Scroll A Low */
+ drawline_tiles(scrolla_tiles, bitmap, 0, scrolla_offset, scrolla_lclip, scrolla_rclip);
+
+ /* Window Low */
+ drawline_tiles(window_tiles, bitmap, 0, 0, window_lclip, window_rclip);
+
+ /* Sprites Low */
+ for (sprite = lowsprites; sprite > 0; sprite--)
+ drawline_sprite(line, bitmap, 0, lowlist[sprite]);
+
+ /* Scroll B High */
+ drawline_tiles(scrollb_tiles, bitmap, 1, scrollb_offset, 0, BITMAP_WIDTH - 1);
+
+ /* Scroll A High */
+ drawline_tiles(scrolla_tiles, bitmap, 1, scrolla_offset, scrolla_lclip, scrolla_rclip);
+
+ /* Window High */
+ drawline_tiles(window_tiles, bitmap, 1, 0, window_lclip, window_rclip);
+
+ /* Sprites High */
+ for (sprite = highsprites; sprite > 0; sprite--)
+ drawline_sprite(line, bitmap, 1, highlist[sprite]);
+}
+
+
+
+/******************************************************************************
+ Background rendering
+*******************************************************************************
+
+ This code handles all the scroll calculations and rendering of the
+ background layers.
+
+******************************************************************************/
+
+/* determine the tiles we will draw on a scrolling layer */
+static void get_scroll_tiles(int line, int scrollnum, UINT32 scrollbase, UINT32 *tiles, int *offset)
+{
+ int linehscroll = vdp_gethscroll(scrollnum, line);
+ int column;
+
+ /* adjust for partial tiles and then pre-divide hscroll to get the tile offset */
+ *offset = -(linehscroll % 8);
+ linehscroll /= 8;
+
+ /* loop over columns */
+ for (column = 0; column < 41; column++)
+ {
+ int columnvscroll = vdp_getvscroll(scrollnum, (column - (linehscroll & 1)) & 0x3f) + line;
+
+ /* determine the base of the tilemap row */
+ int temp = ((columnvscroll / 8) & (scrollheight - 1)) * scrollwidth;
+ int tilebase = scrollbase + 2 * temp;
+
+ /* offset into the tilemap based on the column */
+ temp = (linehscroll + column) & (scrollwidth - 1);
+ tilebase += 2 * temp;
+
+ /* get the tile info */
+ *tiles++ = ((columnvscroll % 8) << 16) | VDP_VRAM_WORD(tilebase);
+ }
+}
+
+
+/* determine the tiles we will draw on a non-scrolling window layer */
+static void get_window_tiles(int line, UINT32 scrollbase, UINT32 *tiles)
+{
+ int column;
+
+ /* loop over columns */
+ for (column = 0; column < 40; column++)
+ {
+ /* determine the base of the tilemap row */
+ int temp = (line / 8) * window_width + column;
+ int tilebase = scrollbase + 2 * temp;
+
+ /* get the tile info */
+ *tiles++ = ((line % 8) << 16) | VDP_VRAM_WORD(tilebase);
+ }
+}
+
+
+/* draw a line of tiles */
+static void drawline_tiles(UINT32 *tiles, UINT16 *bmap, int pri, int offset, int lclip, int rclip)
+{
+ /* adjust for the 8-pixel slop */
+ bmap += offset;
+ if (lclip > rclip)
+ return;
+
+ /* loop over columns */
+ for ( ; offset < BITMAP_WIDTH; offset += 8, bmap += 8)
+ {
+ UINT32 tile = *tiles++;
+
+ /* if the tile is the correct priority, draw it */
+ if (((tile >> 15) & 1) == pri && offset < BITMAP_WIDTH)
+ {
+ int colbase = genesis_bg_pal_lookup[(tile & 0x6000) >> 13];
+ UINT32 *tp = (UINT32 *)&VDP_VRAM_BYTE((tile & 0x7ff) * 32);
+ UINT32 mytile;
+ int col;
+
+ /* vertical flipping */
+ if (!(tile & 0x1000))
+ mytile = tp[tile >> 16];
+ else
+ mytile = tp[(tile >> 16) ^ 7];
+
+ /* skip if all-transparent */
+ if (!mytile)
+ continue;
+
+ /* non-clipped */
+ if (offset >= lclip && offset <= rclip - 7)
+ {
+ /* non-flipped */
+ if (!(tile & 0x0800))
+ {
+ col = EXTRACT_PIXEL(mytile, 0); if (col) bmap[0] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 1); if (col) bmap[1] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 2); if (col) bmap[2] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 3); if (col) bmap[3] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 4); if (col) bmap[4] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 5); if (col) bmap[5] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 6); if (col) bmap[6] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 7); if (col) bmap[7] = colbase + col;
+ }
+
+ /* horizontal flip */
+ else
+ {
+ col = EXTRACT_PIXEL(mytile, 7); if (col) bmap[0] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 6); if (col) bmap[1] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 5); if (col) bmap[2] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 4); if (col) bmap[3] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 3); if (col) bmap[4] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 2); if (col) bmap[5] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 1); if (col) bmap[6] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 0); if (col) bmap[7] = colbase + col;
+ }
+ }
+
+ /* clipped */
+ else if (offset >= lclip - 8 && offset <= rclip)
+ {
+ /* non-flipped */
+ if (!(tile & 0x0800))
+ {
+ col = EXTRACT_PIXEL(mytile, 0); if (col && (offset + 0) >= lclip && (offset + 0) <= rclip) bmap[0] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 1); if (col && (offset + 1) >= lclip && (offset + 1) <= rclip) bmap[1] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 2); if (col && (offset + 2) >= lclip && (offset + 2) <= rclip) bmap[2] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 3); if (col && (offset + 3) >= lclip && (offset + 3) <= rclip) bmap[3] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 4); if (col && (offset + 4) >= lclip && (offset + 4) <= rclip) bmap[4] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 5); if (col && (offset + 5) >= lclip && (offset + 5) <= rclip) bmap[5] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 6); if (col && (offset + 6) >= lclip && (offset + 6) <= rclip) bmap[6] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 7); if (col && (offset + 7) >= lclip && (offset + 7) <= rclip) bmap[7] = colbase + col;
+ }
+
+ /* horizontal flip */
+ else
+ {
+ col = EXTRACT_PIXEL(mytile, 7); if (col && (offset + 0) >= lclip && (offset + 0) <= rclip) bmap[0] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 6); if (col && (offset + 1) >= lclip && (offset + 1) <= rclip) bmap[1] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 5); if (col && (offset + 2) >= lclip && (offset + 2) <= rclip) bmap[2] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 4); if (col && (offset + 3) >= lclip && (offset + 3) <= rclip) bmap[3] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 3); if (col && (offset + 4) >= lclip && (offset + 4) <= rclip) bmap[4] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 2); if (col && (offset + 5) >= lclip && (offset + 5) <= rclip) bmap[5] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 1); if (col && (offset + 6) >= lclip && (offset + 6) <= rclip) bmap[6] = colbase + col;
+ col = EXTRACT_PIXEL(mytile, 0); if (col && (offset + 7) >= lclip && (offset + 7) <= rclip) bmap[7] = colbase + col;
+ }
+ }
+ }
+ }
+}
+
+
+
+/******************************************************************************
+ Sprite drawing
+*******************************************************************************
+
+ These special routines handle the transparency effects in sprites.
+
+******************************************************************************/
+
+/* draw a non-horizontally-flipped section of a sprite */
+INLINE void draw8pixs(UINT16 *bmap, int sxpos, int patno, int priority, int colbase, int patline)
+{
+ UINT32 tile = *(UINT32 *)&VDP_VRAM_BYTE(patno * 32 + 4 * patline);
+ int col;
+
+ /* skip if all-transparent */
+ if (!tile)
+ return;
+
+ /* non-transparent */
+ if ((colbase & 0x30) != 0x30 || !(genesis_vdp_regs[12] & 0x08))
+ {
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 0); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 1); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 2); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 3); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 4); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 5); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 6); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 7); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ }
+
+ /* transparent */
+ else
+ {
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 0); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 1); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 2); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 3); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 4); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 5); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 6); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 7); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ }
+}
+
+
+/* draw a horizontally-flipped section of a sprite */
+INLINE void draw8pixs_hflip(UINT16 *bmap, int sxpos, int patno, int priority, int colbase, int patline)
+{
+ UINT32 tile = *(UINT32 *)&VDP_VRAM_BYTE(patno * 32 + 4 * patline);
+ int col;
+
+ /* skip if all-transparent */
+ if (!tile)
+ return;
+
+ /* non-transparent */
+ if ((colbase & 0x30) != 0x30 || !(genesis_vdp_regs[12] & 0x08))
+ {
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 7); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 6); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 5); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 4); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 3); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 2); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 1); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 0); if (col) bmap[sxpos] = colbase + col; } sxpos++;
+ }
+
+ /* transparent */
+ else
+ {
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 7); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 6); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 5); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 4); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 3); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 2); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 1); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ if (sxpos>=0 && sxpos<BITMAP_WIDTH) { col = EXTRACT_PIXEL(tile, 0); if (col) { if (col < 0x0e) bmap[sxpos] = colbase + col; else bmap[sxpos] = transparent_lookup[((col & 1) << 11) | (bmap[sxpos] & 0x7ff)]; }} sxpos++;
+ }
+}
+
+
+static void drawline_sprite(int line, UINT16 *bmap, int priority, UINT8 *spritebase)
+{
+ int spriteypos = (((spritebase[0] & 0x01) << 8) | spritebase[1]) - 0x80;
+ int spritexpos = (((spritebase[6] & 0x01) << 8) | spritebase[7]) - 0x80;
+ int spriteheight = ((spritebase[2] & 0x03) + 1) * 8;
+ int spritewidth = (((spritebase[2] & 0x0c) >> 2) + 1) * 8;
+ int spriteattr, patno, patflip, patline, colbase, x;
+
+ /* skip if out of range */
+ if (line < spriteypos || line >= spriteypos + spriteheight)
+ return;
+ if (spritexpos + spritewidth < 0 || spritexpos >= BITMAP_WIDTH)
+ return;
+
+ /* extract the remaining data */
+ spriteattr = (spritebase[4] << 8) | spritebase[5];
+ patno = spriteattr & 0x07FF;
+ patflip = (spriteattr & 0x1800) >> 11;
+ patline = line - spriteypos;
+
+ /* determine the color base */
+ colbase = genesis_sp_pal_lookup[(spriteattr & 0x6000) >> 13];
+
+ /* adjust for the X position */
+ spritewidth >>= 3;
+ spriteheight >>= 3;
+
+ /* switch off the flip mode */
+ switch (patflip)
+ {
+ case 0x00: /* No Flip */
+ for (x = 0; x < spritewidth; x++)
+ {
+ if (spritexpos >= -7 && spritexpos < BITMAP_WIDTH)
+ draw8pixs(bmap, spritexpos, patno, priority, colbase, patline);
+ spritexpos += 8;
+ patno += spriteheight;
+ }
+ break;
+
+ case 0x01: /* Horizontal Flip */
+ patno += spriteheight * (spritewidth - 1);
+ for (x = 0; x < spritewidth; x++)
+ {
+ if (spritexpos >= -7 && spritexpos < BITMAP_WIDTH)
+ draw8pixs_hflip(bmap, spritexpos, patno, priority, colbase, patline);
+ spritexpos += 8;
+ patno -= spriteheight;
+ }
+ break;
+
+ case 0x02: /* Vertical Flip */
+ patline = 8 * spriteheight - patline - 1;
+ for (x = 0; x < spritewidth; x++)
+ {
+ if (spritexpos >= -7 && spritexpos < BITMAP_WIDTH)
+ draw8pixs(bmap, spritexpos, patno, priority, colbase, patline);
+ spritexpos += 8;
+ patno += spriteheight;
+ }
+ break;
+
+ case 0x03: /* Both Flip */
+ patno += spriteheight * (spritewidth - 1);
+ patline = 8 * spriteheight - patline - 1;
+ for (x = 0; x < spritewidth; x++)
+ {
+ if (spritexpos >= -7 && spritexpos < BITMAP_WIDTH)
+ draw8pixs_hflip(bmap, spritexpos, patno, priority, colbase, patline);
+ spritexpos += 8;
+ patno -= spriteheight;
+ }
+ break;
+ }
+}
+
+
+
+/******************************************************************************/
+/* General Information (Mainly Genesis Related */
+/******************************************************************************/
+/* Genesis VDP Registers (from sega2.doc)
+
+Reg# : | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Bit0 | General Function
+--------------------------------------------------------------------------------
+0x00 : | 0 | 0 | 0 | IE1 | 0 | 1 | M3 | 0 | Mode Set Register #1
+IE = Enabled H Interrupt (Lev 4), M3 = Enable HV Counter Read / Stopped
+0x01 : | 0 | DISP | IE0 | M1 | M2 | 1 | 0 | 0 | Mode Set Register #2
+DISP = Display Enable, IE0 = Enabled V Interrupt (Lev 6), M1 = DMA Enabled, M2 = 30 Cell Mode
+0x02 : | 0 | 0 | SA15 | SA14 | SA13 | 0 | 0 | 0 | Scroll A Base Address
+SA13-15 = Bits 13-15 of the Scroll A Name Table Base Address in VRAM
+0x03 : | 0 | 0 | WD15 | WD14 | WD13 | WD12 | WD11 | 0 | Window Base Address
+WD11-15 = Bits 11-15 of the Window Name Table Base Address in VRAM
+0x04 : | 0 | 0 | 0 | 0 | 0 | SB15 | SB14 | SB13 | Scroll B Base Address
+SB13-15 = Bits 13-15 of the Scroll B Name Table Base Address in VRAM
+0x05 : | 0 | AT15 | AT14 | AT13 | AT12 | AT11 | AT10 | AT9 | Sprite Table Base Address
+AT9=15 = Bits 9-15 of the Sprite Name Table Base Address in VRAM
+0x06 : | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Unused
+0x07 : | 0 | 0 | CPT1 | CPT0 | COL3 | COL2 | COL1 | COL0 | Background Colour Select
+CPT0-1 = Palette Number, COL = Colour in Palette
+0x08 : | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Unused
+0x09 : | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Unused
+0x0A : | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 | H-Interrupt Register
+BIT0-7 = Controls Level 4 Interrupt Timing
+0x0B : | 0 | 0 | 0 | 0 | IE2 | VSCR | HSCR | LSCR | Mode Set Register #3
+IE2 = Enable E Interrupt (Lev 2), VSCR = Vertical Scroll Mode, HSCR / LSCR = Horizontal Scroll Mode
+0x0C : | RS0 | 0 | 0 | 0 | S/TE | LSM1 | LSM0 | RS1 | Mode Set Register #4
+RS0 / RS1 = Cell Mode, S/TE = Shadow/Hilight Enable, LSM0 / LSM1 = Interlace Mode Setting
+0x0D : | 0 | 0 | HS15 | HS14 | HS13 | HS12 | HS11 | HS10 | HScroll Base Address
+HS10-15 = Bits 10-15 of the HScroll Name Table Base Address in VRAM
+0x0E : | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Unused
+0x0F : | INC7 | INC6 | INC5 | INC4 | INC3 | INC2 | INC1 | INC0 | Auto-Increment
+INC0-7 = Auto Increment Value (after VRam Access)
+0x10 : | 0 | 0 | VSZ1 | VSZ0 | 0 | 0 | HSZ1 | HSZ0 | Scroll Size
+VSZ0-1 = Vertical Plane Size, HSZ0-1 = Horizontal Plane Size
+0x11 : | RIGT | 0 | 0 | WHP5 | WHP4 | WHP3 | WHP2 | WHP1 | Window H Position
+RIGT = Window Right Side of Base Point, WHP1-5 = Bits1-5 of Window H Point
+0x12 : | DOWN | 0 | 0 | WVP4 | WVP3 | WVP2 | WVP1 | WVP0 | Window V Position
+DOWN = Window Below Base Point, WVP0-4 = Bits0-4 of Window V Point
+0x13 : | LG7 | LG6 | LG5 | LG4 | LG3 | LG2 | LG1 | LG0 | DMA Length Counter LOW
+0x14 : | LG15 | LG14 | LG13 | LG12 | LG11 | LG10 | LG9 | LG8 | DMA Length Counter HIGH
+LG0-15 = Bits 0-15 of DMA Length Counter
+0x15 : | SA8 | SA7 | SA6 | SA5 | SA4 | SA3 | SA2 | SA1 | DMA Source Address LOW
+0x16 : | SA16 | SA15 | SA14 | SA13 | SA12 | SA11 | SA10 | SA9 | DMA Source Address MID
+0x17 : | DMD1 | DMD0 | SA22 | SA21 | SA20 | SA19 | SA18 | S17 | DMA Source Address HIGH
+LG0-15 = Bits 1-22 of DMA Source Address
+DMD0-1 = DMA Mode
+
+Memory Layouts ...
+
+Scroll Name Table
+16-bits are used to Define a Tile in the Scroll Plane
+| PRI | CP1 | CP0 | VF | HF | PT10 | PT9 | PT8 |
+| PT7 | PT6 | PT5 | PT4 | PT3 | PT2 | PT1 | PT0 |
+PRI = Priority, CP = Colour Palette, VF = VFlip, HF = HFlip, PT0-9 = Tile # in VRAM
+
+HScroll Data (in VRAM)
+0x00 |
+0x01 / H Scroll of Plane A (Used in Overall, Cell & Line Modes)
+0x02 |
+0x03 / H Scroll of Plane B (Used in Overall, Cell & Line Modes)
+0x04 |
+0x05 / H Scroll of Plane A (Used in Line Mode)
+0x06 |
+0x07 / H Scroll of Plane B (Used in Line Mode)
+...
+0x20 |
+0x21 / H Scroll of Plane A (Used in Cell & Line Mode)
+0x22 |
+0x23 / H Scroll of Plane B (Used in Cell & Line Mode)
+etc.. That kinda thing :)
+Data is in Format ..
+| x | x | x | x | x | x | HS9 | HS8 |
+| HS7 | HS6 | HS5 | HS4 | HS3 | HS2 | HS1 | HS0 |
+HS = HScroll Amount for Overall / Cell / Line depending on Mode.
+
+VScroll Data (in VSRAM)
+0x00 |
+0x01 / V Scroll of Plane A (Used in Overall & Cell Modes)
+0x02 |
+0x03 / V Scroll of Plane B (Used in Overall & Cell Modes)
+0x04 |
+0x05 / V Scroll of Plane A (Used in Cell Mode)
+0x06 |
+0x07 / V Scroll of Plane B (Used in Cell Modes)
+etc..
+Data is in Format ..
+| x | x | x | x | x | VS10 | VS9 | VS8 |
+| VS7 | VS6 | VS5 | VS4 | VS3 | VS2 | VS1 | VS0 |
+VS = HScroll Amount for Overall / Cell / Line depending on Mode.
+
+Sprite Attributes Table (in VRAM)
+Each Sprite uses 64-bits of Information (8 bytes)
+| x | x | x | x | x | x | YP9 | YP8 |
+| YP7 | YP6 | YP5 | YP4 | YP3 | YP2 | YP1 | YP0 |
+| x | x | x | x | HS1 | HS0 | VS1 | VS0 |
+| x | LN6 | LN5 | LN4 | LN3 | LN2 | LN1 | LN0 |
+| PRI | CP1 | CP0 | VF | HF | PT10 | PT9 | PT8 |
+| PT7 | PT6 | PT5 | PT4 | PT3 | PT2 | PT1 | PT0 |
+| x | x | x | x | x | x | XP9 | XP8 |
+| XP7 | XP6 | XP5 | XP4 | XP3 | XP2 | XP1 | XP0 |
+YP = Y Position of Sprite
+HS = Horizontal Size (Blocks)
+VS = Vertical Size (Blocks)
+LN = Link Field
+PRI = Priority
+CP = Colour Palette
+VF = VFlip
+HF = HFlip
+PT = Pattern Number
+XP = X Position of Sprite
+
+
+
+*/
+
diff --git a/src/mame/video/gijoe.c b/src/mame/video/gijoe.c
new file mode 100644
index 00000000000..8f3fbeefc78
--- /dev/null
+++ b/src/mame/video/gijoe.c
@@ -0,0 +1,156 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+static int AVAC_bits[4], AVAC_occupancy[4];
+static int layer_colorbase[4], layer_pri[4];
+static int AVAC_vrc, sprite_colorbase;
+
+static void gijoe_sprite_callback(int *code, int *color, int *priority_mask)
+{
+ int pri, c = *color;
+
+ pri = (c & 0x03e0) >> 4;
+
+ if (pri <= layer_pri[3]) *priority_mask = 0; else
+ if (pri > layer_pri[3] && pri <= layer_pri[2]) *priority_mask = 0xff00; else
+ if (pri > layer_pri[2] && pri <= layer_pri[1]) *priority_mask = 0xff00|0xf0f0; else
+ if (pri > layer_pri[1] && pri <= layer_pri[0]) *priority_mask = 0xff00|0xf0f0|0xcccc; else
+ *priority_mask = 0xff00|0xf0f0|0xcccc|0xaaaa;
+
+ *color = sprite_colorbase | (c & 0x001f);
+}
+
+static void gijoe_tile_callback(int layer, int *code, int *color, int *flags)
+{
+ int tile = *code;
+
+ if (tile >= 0xf000 && tile <= 0xf4ff)
+ {
+ tile &= 0x0fff;
+ if (tile < 0x0310) { AVAC_occupancy[layer] |= 0x0f00; tile |= AVAC_bits[0]; } else
+ if (tile < 0x0470) { AVAC_occupancy[layer] |= 0xf000; tile |= AVAC_bits[1]; } else
+ { AVAC_occupancy[layer] |= 0x00f0; tile |= AVAC_bits[2]; }
+ *code = tile;
+ }
+
+ *color = (*color>>2 & 0x0f) | layer_colorbase[layer];
+}
+
+VIDEO_START( gijoe )
+{
+ int i;
+
+ K053251_vh_start();
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_4, 1, NULL, gijoe_tile_callback, 0);
+
+ K056832_linemap_enable(1);
+
+ K053247_vh_start(machine, REGION_GFX2, -37, 20, NORMAL_PLANE_ORDER, gijoe_sprite_callback);
+
+ for (i=0; i<4; i++) AVAC_occupancy[i] = 0;
+ AVAC_vrc = 0xffff;
+}
+
+/* useful function to sort the four tile layers by priority order */
+static void sortlayers(int *layer, int *pri)
+{
+#define SWAP(a,b) \
+ if (pri[a] <= pri[b]) \
+ { \
+ int t; \
+ t = pri[a]; pri[a] = pri[b]; pri[b] = t; \
+ t = layer[a]; layer[a] = layer[b]; layer[b] = t; \
+ }
+
+ SWAP(0, 1)
+ SWAP(0, 2)
+ SWAP(0, 3)
+ SWAP(1, 2)
+ SWAP(1, 3)
+ SWAP(2, 3)
+}
+
+VIDEO_UPDATE( gijoe )
+{
+ static const int K053251_CI[4] = { K053251_CI1, K053251_CI2, K053251_CI3, K053251_CI4 };
+ int layer[4];
+ int vrc_mode, vrc_new, colorbase_new, primode, dirty, i;
+ int mask = 0;
+
+ // update tile offsets
+ K056832_read_AVAC(&vrc_mode, &vrc_new);
+
+ if (vrc_mode)
+ {
+ for (dirty=0xf000; dirty; dirty>>=4) if ((AVAC_vrc & dirty) != (vrc_new & dirty)) mask |= dirty;
+
+ AVAC_vrc = vrc_new;
+ AVAC_bits[0] = vrc_new<<4 & 0xf000;
+ AVAC_bits[1] = vrc_new & 0xf000;
+ AVAC_bits[2] = vrc_new<<8 & 0xf000;
+ AVAC_bits[3] = vrc_new<<12 & 0xf000;
+ }
+ else
+ AVAC_bits[3] = AVAC_bits[2] = AVAC_bits[1] = AVAC_bits[0] = 0xf000;
+
+ // update color info and refresh tilemaps
+ sprite_colorbase = K053251_get_palette_index(K053251_CI0);
+
+ for (i=0; i<4; i++)
+ {
+ dirty = 0;
+
+ colorbase_new = K053251_get_palette_index(K053251_CI[i]);
+ if (layer_colorbase[i] != colorbase_new) { layer_colorbase[i] = colorbase_new; dirty = 1; }
+ if (AVAC_occupancy[i] & mask) dirty = 1;
+
+ if (dirty) { AVAC_occupancy[i] = 0; K056832_mark_plane_dirty(i); }
+ }
+
+ /*
+ Layer A is supposed to be a non-scrolling status display with static X-offset.
+ The weird thing is tilemap alignment only follows the 832 standard when 2 is
+ written to the layer's X-scroll register otherwise the chip expects totally
+ different alignment values.
+ */
+ if (K056832_read_register(0x14) == 2)
+ {
+ K056832_set_LayerOffset(0, 2, 0);
+ K056832_set_LayerOffset(1, 4, 0);
+ K056832_set_LayerOffset(2, 6, 0); // 7?
+ K056832_set_LayerOffset(3, 8, 0);
+ }
+ else
+ {
+ K056832_set_LayerOffset(0, 0, 0);
+ K056832_set_LayerOffset(1, 8, 0);
+ K056832_set_LayerOffset(2, 14, 0);
+ K056832_set_LayerOffset(3, 16, 0); // smaller?
+ }
+
+ // seems to switch the K053251 between different priority modes, detail unknown
+ primode = K053251_get_priority(K053251_CI1);
+
+ layer[0] = 0;
+ layer_pri[0] = 0; // not sure
+ layer[1] = 1;
+ layer_pri[1] = K053251_get_priority(K053251_CI2);
+ layer[2] = 2;
+ layer_pri[2] = K053251_get_priority(K053251_CI3);
+ layer[3] = 3;
+ layer_pri[3] = K053251_get_priority(K053251_CI4);
+
+ sortlayers(layer, layer_pri);
+
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ K056832_tilemap_draw(machine, bitmap,cliprect, layer[0], 0, 1);
+ K056832_tilemap_draw(machine, bitmap,cliprect, layer[1], 0, 2);
+ K056832_tilemap_draw(machine, bitmap,cliprect, layer[2], 0, 4);
+ K056832_tilemap_draw(machine, bitmap,cliprect, layer[3], 0, 8);
+
+ K053247_sprites_draw(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/ginganin.c b/src/mame/video/ginganin.c
new file mode 100644
index 00000000000..0bdd3328200
--- /dev/null
+++ b/src/mame/video/ginganin.c
@@ -0,0 +1,290 @@
+/**************************************************************************
+
+ Ginga NinkyouDen
+ (C) 1987 Jaleco
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z with:
+
+ Q shows background
+ W shows foreground
+ E shows frontmost (text) layer
+ A shows sprites
+
+ Keys can be used togheter!
+
+
+[Screen]
+ Visible Size: 256H x 240V
+ Dynamic Colors: 256 x 4
+ Color Space: 16R x 16G x 16B
+
+[Scrolling layers]
+ Format (all layers): Offset: 0x400 0x000
+ Bit: fedc---- -------- Color
+ ----ba98 76543210 Code
+
+ [Background]
+ Size: 8192 x 512 (static: stored in ROM)
+ Scrolling: X,Y (registers: $60006.w, $60004.w)
+ Tiles Size: 16 x 16
+ Tiles Number: $400
+ Colors: $300-$3ff
+
+ [Foreground]
+ Size: 4096 x 512
+ Scrolling: X,Y (registers: $60002.w, $60000.w)
+ Tiles Size: 16 x 16
+ Tiles Number: $400
+ Colors: $200-$2ff
+
+ [Frontmost]
+ Size: 256 x 256
+ Scrolling: -
+ Tiles Size: 8 x 8
+ Tiles Number: $200
+ Colors: $000-$0ff
+
+
+[Sprites]
+ On Screen: 256
+ In ROM: $a00
+ Colors: $100-$1ff
+ Format: See Below
+
+
+**************************************************************************/
+
+#include "driver.h"
+
+/* Variables only used here */
+static tilemap *bg_tilemap, *fg_tilemap, *tx_tilemap;
+static int layers_ctrl, flipscreen;
+
+/* Variables that driver has access to */
+UINT16 *ginganin_fgram16, *ginganin_txtram16, *ginganin_vregs16;
+
+/* Variables defined in drivers */
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+
+/* Background - Resides in ROM */
+
+#define BG_GFX (0)
+#define BG_NX (16*32)
+#define BG_NY (16*2)
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = memory_region(REGION_GFX5)[2*tile_index + 0] * 256 + memory_region(REGION_GFX5)[2*tile_index + 1];
+ SET_TILE_INFO(
+ BG_GFX,
+ code,
+ code >> 12,
+ 0);
+}
+
+
+/* Foreground - Resides in RAM */
+
+#define FG_GFX (1)
+#define FG_NX (16*16)
+#define FG_NY (16*2)
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT16 code = ginganin_fgram16[tile_index];
+ SET_TILE_INFO(
+ FG_GFX,
+ code,
+ code >> 12,
+ 0);
+}
+
+WRITE16_HANDLER( ginganin_fgram16_w )
+{
+ COMBINE_DATA(&ginganin_fgram16[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+
+/* Frontmost (text) Layer - Resides in RAM */
+
+#define TXT_GFX (2)
+#define TXT_NX (32)
+#define TXT_NY (32)
+
+static TILE_GET_INFO( get_txt_tile_info )
+{
+ UINT16 code = ginganin_txtram16[tile_index];
+ SET_TILE_INFO(
+ TXT_GFX,
+ code,
+ code >> 12,
+ 0);
+}
+
+WRITE16_HANDLER( ginganin_txtram16_w )
+{
+ COMBINE_DATA(&ginganin_txtram16[offset]);
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+
+VIDEO_START( ginganin )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,BG_NX,BG_NY);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,FG_NX,FG_NY);
+ tx_tilemap = tilemap_create(get_txt_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,TXT_NX,TXT_NY);
+
+ tilemap_set_transparent_pen(fg_tilemap,15);
+ tilemap_set_transparent_pen(tx_tilemap,15);
+}
+
+
+WRITE16_HANDLER( ginganin_vregs16_w )
+{
+ COMBINE_DATA(&ginganin_vregs16[offset]);
+ data = ginganin_vregs16[offset];
+
+ switch (offset)
+ {
+ case 0:
+ tilemap_set_scrolly(fg_tilemap, 0, data);
+ break;
+ case 1:
+ tilemap_set_scrollx(fg_tilemap, 0, data);
+ break;
+ case 2:
+ tilemap_set_scrolly(bg_tilemap, 0, data);
+ break;
+ case 3:
+ tilemap_set_scrollx(bg_tilemap, 0, data);
+ break;
+ case 4:
+ layers_ctrl = data;
+ break;
+/* case 5:
+ * break;
+ */
+ case 6:
+ flipscreen = !(data & 1);
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ break;
+ case 7:
+ soundlatch_w(0,data);
+ cpunum_set_input_line(1, INPUT_LINE_NMI, PULSE_LINE);
+ break;
+ default:
+ logerror("CPU #0 PC %06X : Warning, videoreg %04X <- %04X\n",activecpu_get_pc(),offset,data);
+ }
+}
+
+
+
+/* --------------------------[ Sprites Format ]----------------------------
+
+Offset: Values: Format:
+
+0000.w y position fedc ba9- ---- ---- unused
+ ---- ---8 ---- ---- subtract 256
+ ---- ---- 7654 3210 position
+
+0002.w x position See above
+
+0004.w code f--- ---- ---- ---- y flip
+ -e-- ---- ---- ---- x flip
+ --dc ---- ---- ---- unused?
+ ---- ba98 7654 3210 code
+
+0006.w colour fedc ---- ---- ---- colour code
+ ---- ba98 7654 3210 unused?
+
+------------------------------------------------------------------------ */
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+int offs;
+
+ for ( offs = 0 ; offs < (spriteram_size >> 1); offs += 4 )
+ {
+ int y = spriteram16[offs + 0];
+ int x = spriteram16[offs + 1];
+ int code = spriteram16[offs + 2];
+ int attr = spriteram16[offs + 3];
+ int flipx = code & 0x4000;
+ int flipy = code & 0x8000;
+
+ x = (x & 0xFF) - (x & 0x100);
+ y = (y & 0xFF) - (y & 0x100);
+
+ if (flipscreen)
+ {
+ x = 240 - x; y = 240 - y;
+ flipx = !flipx; flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[3],
+ code & 0x3fff,
+ attr >> 12,
+ flipx, flipy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,15);
+
+ }
+}
+
+
+VIDEO_UPDATE( ginganin )
+{
+ int layers_ctrl1;
+
+ layers_ctrl1 = layers_ctrl;
+
+#ifdef MAME_DEBUG
+if (input_code_pressed(KEYCODE_Z))
+{
+ int msk = 0;
+ static int posx,posy;
+
+ if (input_code_pressed(KEYCODE_Q)) { msk |= 0xfff1;}
+ if (input_code_pressed(KEYCODE_W)) { msk |= 0xfff2;}
+ if (input_code_pressed(KEYCODE_E)) { msk |= 0xfff4;}
+ if (input_code_pressed(KEYCODE_A)) { msk |= 0xfff8;}
+ if (msk != 0) layers_ctrl1 &= msk;
+
+#define SETSCROLL \
+ tilemap_set_scrollx(bg_tilemap, 0, posx); \
+ tilemap_set_scrolly(bg_tilemap, 0, posy); \
+ tilemap_set_scrollx(fg_tilemap, 0, posx); \
+ tilemap_set_scrolly(fg_tilemap, 0, posy); \
+ popmessage("B>%04X:%04X F>%04X:%04X",posx%(BG_NX*16),posy%(BG_NY*16),posx%(FG_NX*16),posy%(FG_NY*16));
+
+ if (input_code_pressed(KEYCODE_L)) { posx +=8; SETSCROLL }
+ if (input_code_pressed(KEYCODE_J)) { posx -=8; SETSCROLL }
+ if (input_code_pressed(KEYCODE_K)) { posy +=8; SETSCROLL }
+ if (input_code_pressed(KEYCODE_I)) { posy -=8; SETSCROLL }
+ if (input_code_pressed(KEYCODE_H)) { posx = posy = 0; SETSCROLL }
+
+}
+#endif
+
+
+ if (layers_ctrl1 & 1) tilemap_draw(bitmap,cliprect, bg_tilemap, 0,0);
+ else fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ if (layers_ctrl1 & 2) tilemap_draw(bitmap,cliprect, fg_tilemap, 0,0);
+ if (layers_ctrl1 & 8) draw_sprites(machine, bitmap,cliprect);
+ if (layers_ctrl1 & 4) tilemap_draw(bitmap,cliprect, tx_tilemap, 0,0);
+
+ return 0;
+}
+
diff --git a/src/mame/video/gladiatr.c b/src/mame/video/gladiatr.c
new file mode 100644
index 00000000000..410349750be
--- /dev/null
+++ b/src/mame/video/gladiatr.c
@@ -0,0 +1,309 @@
+/***************************************************************************
+
+ Video Hardware description for Taito Gladiator
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *gladiatr_videoram, *gladiatr_colorram, *gladiatr_textram;
+
+static int video_attributes;
+static int fg_scrollx, fg_scrolly, bg_scrollx, bg_scrolly;
+static int sprite_bank, sprite_buffer;
+
+
+static tilemap *fg_tilemap, *bg_tilemap;
+static int fg_tile_bank, bg_tile_bank;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( bg_get_tile_info )
+{
+ UINT8 attr = gladiatr_colorram[tile_index];
+
+ SET_TILE_INFO(
+ 1,
+ gladiatr_videoram[tile_index] + ((attr & 0x07) << 8) + (bg_tile_bank << 11),
+ (attr >> 3) ^ 0x1f,
+ 0);
+}
+
+static TILE_GET_INFO( fg_get_tile_info )
+{
+ SET_TILE_INFO(
+ 0,
+ gladiatr_textram[tile_index] + (fg_tile_bank << 8),
+ 0,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( ppking )
+{
+ bg_tilemap = tilemap_create(bg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,64);
+ fg_tilemap = tilemap_create(fg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,64);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ tilemap_set_scroll_cols(bg_tilemap, 0x10);
+
+ sprite_bank = 1;
+}
+
+VIDEO_START( gladiatr )
+{
+ bg_tilemap = tilemap_create(bg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ fg_tilemap = tilemap_create(fg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ tilemap_set_scrolldx(bg_tilemap, -0x30, 0x12f);
+ tilemap_set_scrolldx(fg_tilemap, -0x30, 0x12f);
+
+ sprite_bank = 2;
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( gladiatr_videoram_w )
+{
+ gladiatr_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( gladiatr_colorram_w )
+{
+ gladiatr_colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( gladiatr_textram_w )
+{
+ gladiatr_textram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE8_HANDLER( gladiatr_paletteram_w )
+{
+ int r,g,b;
+
+ paletteram[offset] = data;
+ offset &= 0x3ff;
+
+ r = (paletteram[offset] >> 0) & 0x0f;
+ g = (paletteram[offset] >> 4) & 0x0f;
+ b = (paletteram[offset + 0x400] >> 0) & 0x0f;
+
+ r = (r << 1) + ((paletteram[offset + 0x400] >> 4) & 0x01);
+ g = (g << 1) + ((paletteram[offset + 0x400] >> 5) & 0x01);
+ b = (b << 1) + ((paletteram[offset + 0x400] >> 6) & 0x01);
+
+ palette_set_color_rgb(Machine,offset,pal5bit(r),pal5bit(g),pal5bit(b));
+}
+
+
+WRITE8_HANDLER( gladiatr_spritebuffer_w )
+{
+ sprite_buffer = data & 1;
+}
+
+WRITE8_HANDLER( gladiatr_spritebank_w )
+{
+ sprite_bank = (data & 1) ? 4 : 2;
+}
+
+
+WRITE8_HANDLER( ppking_video_registers_w )
+{
+ switch (offset & 0x300)
+ {
+ case 0x000:
+ tilemap_set_scrolly(bg_tilemap, offset & 0x0f, 0x100-data);
+ break;
+ case 0x200:
+ if (data & 0x80)
+ fg_scrolly = data + 0x100;
+ else
+ fg_scrolly = data;
+ break;
+ case 0x300:
+ if (fg_tile_bank != (data & 0x03))
+ {
+ fg_tile_bank = data & 0x03;
+ tilemap_mark_all_tiles_dirty(fg_tilemap);
+ }
+ video_attributes = data;
+ break;
+ }
+
+//popmessage("%02x %02x",fg_scrolly, video_attributes);
+}
+
+WRITE8_HANDLER( gladiatr_video_registers_w )
+{
+ switch (offset)
+ {
+ case 0x000:
+ fg_scrolly = data;
+ break;
+ case 0x080:
+ if (fg_tile_bank != (data & 0x03))
+ {
+ fg_tile_bank = data & 0x03;
+ tilemap_mark_all_tiles_dirty(fg_tilemap);
+ }
+ if (bg_tile_bank != ((data & 0x10) >> 4))
+ {
+ bg_tile_bank = (data & 0x10) >> 4;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+ video_attributes = data;
+ break;
+ case 0x100:
+ fg_scrollx = data;
+ break;
+ case 0x200:
+ bg_scrolly = data;
+ break;
+ case 0x300:
+ bg_scrollx = data;
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x80;offs += 2)
+ {
+ static int tile_offset[2][2] =
+ {
+ {0x0,0x1},
+ {0x2,0x3},
+ };
+ UINT8 *src = &spriteram[offs + (sprite_buffer << 7)];
+ int attributes = src[0x800];
+ int size = (attributes & 0x10) >> 4;
+ int bank = (attributes & 0x01) + ((attributes & 0x02) ? sprite_bank : 0);
+ int tile_number = (src[0]+256*bank);
+ int sx = src[0x400+1] + 256*(src[0x801]&1) - 0x38;
+ int sy = 240 - src[0x400] - (size ? 16 : 0);
+ int xflip = attributes & 0x04;
+ int yflip = attributes & 0x08;
+ int color = src[1] & 0x1f;
+ int x,y;
+
+ if (flip_screen)
+ {
+ xflip = !xflip;
+ yflip = !yflip;
+ }
+
+ for (y = 0; y <= size; y++)
+ {
+ for (x = 0; x <= size; x++)
+ {
+ int ex = xflip ? (size - x) : x;
+ int ey = yflip ? (size - y) : y;
+
+ int t = tile_offset[ey][ex] + tile_number;
+
+ drawgfx(bitmap,machine->gfx[2],
+ t,
+ color,
+ xflip, yflip,
+ sx+x*16, sy+y*16,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+}
+
+
+
+VIDEO_UPDATE( ppking )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+
+ /* the fg layer just selects the upper palette bank on underlying pixels */
+ {
+ mame_bitmap *flagsbitmap;
+ int sx = cliprect->min_x;
+ int sy = cliprect->min_y;
+
+ tilemap_get_pixmap( fg_tilemap );
+ flagsbitmap = tilemap_get_flagsmap( fg_tilemap );
+
+ while( sy <= cliprect->max_y )
+ {
+ int x = sx;
+ int y = (sy + fg_scrolly) & 0x1ff;
+
+ UINT16 *dest = BITMAP_ADDR16(bitmap, sy, sx);
+ while( x <= cliprect->max_x )
+ {
+ if( *BITMAP_ADDR8(flagsbitmap, y, x)&TILEMAP_PIXEL_LAYER0 )
+ {
+ *dest += 512;
+ }
+ x++;
+ dest++;
+ } /* next x */
+ sy++;
+ } /* next y */
+ }
+ return 0;
+}
+
+VIDEO_UPDATE( gladiatr )
+{
+ if (video_attributes & 0x20)
+ {
+ int scroll;
+
+ scroll = bg_scrollx + ((video_attributes & 0x04) << 6);
+ tilemap_set_scrollx(bg_tilemap, 0, scroll ^ (flip_screen ? 0x0f : 0));
+ scroll = fg_scrollx + ((video_attributes & 0x08) << 5);
+ tilemap_set_scrollx(fg_tilemap, 0, scroll ^ (flip_screen ? 0x0f : 0));
+
+ // always 0 anyway
+ tilemap_set_scrolly(bg_tilemap, 0, bg_scrolly);
+ tilemap_set_scrolly(fg_tilemap, 0, fg_scrolly);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ }
+ else
+ fillbitmap( bitmap, get_black_pen(machine), cliprect );
+ return 0;
+}
diff --git a/src/mame/video/glass.c b/src/mame/video/glass.c
new file mode 100644
index 00000000000..55dad3acb8c
--- /dev/null
+++ b/src/mame/video/glass.c
@@ -0,0 +1,211 @@
+/***************************************************************************
+
+ Glass Video Hardware
+
+ Functions to emulate the video hardware of the machine
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *glass_spriteram;
+UINT16 *glass_vregs;
+UINT16 *glass_videoram;
+
+static tilemap *pant[2];
+static mame_bitmap *screen_bitmap;
+
+static int glass_blitter_serial_buffer[5];
+static int current_command = 0;
+int glass_current_bit = 0;
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/*
+ Tile format
+ -----------
+
+ Screen 0 & 1: (32*32, 16x16 tiles)
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | xxxxxxxx xxxxxxxx | code
+ 1 | -------- ---xxxxx | color (uses colors 0x200-0x3ff)
+ 1 | -------- --x----- | not used?
+ 1 | -------- -x------ | flip x
+ 1 | -------- x------- | flip y
+ 1 | xxxxxxxx -------- | not used
+*/
+
+static TILE_GET_INFO( get_tile_info_glass_screen0 )
+{
+ int data = glass_videoram[tile_index << 1];
+ int data2 = glass_videoram[(tile_index << 1) + 1];
+ int code = ((data & 0x03) << 14) | ((data & 0x0fffc) >> 2);
+
+ SET_TILE_INFO(0, code, 0x20 + (data2 & 0x1f), TILE_FLIPYX((data2 & 0xc0) >> 6));
+}
+
+
+static TILE_GET_INFO( get_tile_info_glass_screen1 )
+{
+ int data = glass_videoram[(0x1000/2) + (tile_index << 1)];
+ int data2 = glass_videoram[(0x1000/2) + (tile_index << 1) + 1];
+ int code = ((data & 0x03) << 14) | ((data & 0x0fffc) >> 2);
+
+ SET_TILE_INFO(0, code, 0x20 + (data2 & 0x1f), TILE_FLIPYX((data2 & 0xc0) >> 6));
+}
+
+/***************************************************************************
+
+ Blitter
+
+***************************************************************************/
+
+/*
+ The blitter is accessed writting 5 consecutive bits. The stream is: P0 P1 B2 B1 B0
+
+ if P0 is set, the hardware selects the first half of ROM H9 (girls)
+ if P1 is set, the hardware selects the second half of ROM H9 (boys)
+
+ B2B1B0 selects the picture (there are 8 pictures in each half of the ROM)
+*/
+
+WRITE16_HANDLER( glass_blitter_w )
+{
+ glass_blitter_serial_buffer[glass_current_bit] = data & 0x01;
+ glass_current_bit++;
+
+ if (glass_current_bit == 5){
+ current_command = (glass_blitter_serial_buffer[0] << 4) |
+ (glass_blitter_serial_buffer[1] << 3) |
+ (glass_blitter_serial_buffer[2] << 2) |
+ (glass_blitter_serial_buffer[3] << 1) |
+ (glass_blitter_serial_buffer[4] << 0);
+ glass_current_bit = 0;
+
+ /* fill the screen bitmap with the current picture */
+ {
+ int i, j;
+ UINT8 *gfx = (UINT8 *)memory_region(REGION_GFX3);
+
+ gfx = gfx + (current_command & 0x07)*0x10000 + (current_command & 0x08)*0x10000 + 0x140;
+
+ if ((current_command & 0x18) != 0){
+ for (j = 0; j < 200; j++){
+ for (i = 0; i < 320; i++){
+ int color = *gfx;
+ gfx++;
+ *BITMAP_ADDR16(screen_bitmap, j, i) = Machine->pens[color & 0xff];
+ }
+ }
+ } else {
+ fillbitmap(screen_bitmap, Machine->pens[0], 0);
+ }
+ }
+ }
+}
+
+/***************************************************************************
+
+ Memory Handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( glass_vram_w )
+{
+ COMBINE_DATA(&glass_videoram[offset]);
+ tilemap_mark_tile_dirty(pant[offset >> 11],((offset << 1) & 0x0fff) >> 2);
+}
+
+
+/***************************************************************************
+
+ Start/Stop the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( glass )
+{
+ pant[0] = tilemap_create(get_tile_info_glass_screen0,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ pant[1] = tilemap_create(get_tile_info_glass_screen1,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ screen_bitmap = auto_bitmap_alloc (320, 200, machine->screen[0].format);
+
+ tilemap_set_transparent_pen(pant[0],0);
+ tilemap_set_transparent_pen(pant[1],0);
+}
+
+
+/***************************************************************************
+
+ Sprites
+
+***************************************************************************/
+
+/*
+ Sprite Format
+ -------------
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- xxxxxxxx | y position
+ 0 | --xxxxxx -------- | not used?
+ 0 | -x------ -------- | flipx
+ 0 | x------- -------- | flipy
+ 1 | xxxxxxxx xxxxxxxx | not used?
+ 2 | -------x xxxxxxxx | x position
+ 2 | ---xxxx- -------- | sprite color (uses colors 0x100-0x1ff)
+ 2 | xx------ -------- | not used?
+ 3 | xxxxxxxx xxxxxxxx | sprite code
+*/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int i;
+ const gfx_element *gfx = machine->gfx[0];
+
+ for (i = 3; i < (0x1000 - 6)/2; i += 4){
+ int sx = glass_spriteram[i+2] & 0x01ff;
+ int sy = (240 - (glass_spriteram[i] & 0x00ff)) & 0x00ff;
+ int number = glass_spriteram[i+3];
+ int color = (glass_spriteram[i+2] & 0x1e00) >> 9;
+ int attr = (glass_spriteram[i] & 0xfe00) >> 9;
+
+ int xflip = attr & 0x20;
+ int yflip = attr & 0x40;
+
+ number = ((number & 0x03) << 14) | ((number & 0x0fffc) >> 2);
+
+ drawgfx(bitmap,gfx,number,
+ 0x10 + (color & 0x0f),xflip,yflip,
+ sx-0x0f,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+/***************************************************************************
+
+ Display Refresh
+
+****************************************************************************/
+
+VIDEO_UPDATE( glass )
+{
+ /* set scroll registers */
+ tilemap_set_scrolly(pant[0], 0, glass_vregs[0]);
+ tilemap_set_scrollx(pant[0], 0, glass_vregs[1] + 0x04);
+ tilemap_set_scrolly(pant[1], 0, glass_vregs[2]);
+ tilemap_set_scrollx(pant[1], 0, glass_vregs[3]);
+
+ /* draw layers + sprites */
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ copybitmap(bitmap,screen_bitmap,0,0,0x18,0x24,cliprect,TRANSPARENCY_NONE,0);
+ tilemap_draw(bitmap,cliprect,pant[1],0,0);
+ tilemap_draw(bitmap,cliprect,pant[0],0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/gng.c b/src/mame/video/gng.c
new file mode 100644
index 00000000000..fbe740a6afc
--- /dev/null
+++ b/src/mame/video/gng.c
@@ -0,0 +1,160 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *gng_fgvideoram;
+UINT8 *gng_bgvideoram;
+
+static tilemap *bg_tilemap,*fg_tilemap;
+
+static UINT8 scrollx[2];
+static UINT8 scrolly[2];
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 attr = gng_fgvideoram[tile_index + 0x400];
+ SET_TILE_INFO(
+ 0,
+ gng_fgvideoram[tile_index] + ((attr & 0xc0) << 2),
+ attr & 0x0f,
+ TILE_FLIPYX((attr & 0x30) >> 4));
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 attr = gng_bgvideoram[tile_index + 0x400];
+ SET_TILE_INFO(
+ 1,
+ gng_bgvideoram[tile_index] + ((attr & 0xc0) << 2),
+ attr & 0x07,
+ TILE_FLIPYX((attr & 0x30) >> 4));
+ tileinfo->group = (attr & 0x08) >> 3;
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( gng )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 16,16,32,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,3);
+
+ tilemap_set_transmask(bg_tilemap,0,0xff,0x00); /* split type 0 is totally transparent in front half */
+ tilemap_set_transmask(bg_tilemap,1,0x41,0xbe); /* split type 1 has pens 0 and 6 transparent in front half */
+
+ /* register to save state */
+ state_save_register_global_array(scrollx);
+ state_save_register_global_array(scrolly);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( gng_fgvideoram_w )
+{
+ gng_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( gng_bgvideoram_w )
+{
+ gng_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+}
+
+
+WRITE8_HANDLER( gng_bgscrollx_w )
+{
+ scrollx[offset] = data;
+ tilemap_set_scrollx( bg_tilemap, 0, scrollx[0] + 256 * scrollx[1] );
+}
+
+WRITE8_HANDLER( gng_bgscrolly_w )
+{
+ scrolly[offset] = data;
+ tilemap_set_scrolly( bg_tilemap, 0, scrolly[0] + 256 * scrolly[1] );
+}
+
+
+WRITE8_HANDLER( gng_flipscreen_w )
+{
+ flip_screen_set(~data & 1);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const gfx_element *gfx = machine->gfx[2];
+ int offs;
+
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ UINT8 attributes = buffered_spriteram[offs+1];
+ int sx = buffered_spriteram[offs + 3] - 0x100 * (attributes & 0x01);
+ int sy = buffered_spriteram[offs + 2];
+ int flipx = attributes & 0x04;
+ int flipy = attributes & 0x08;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,gfx,
+ buffered_spriteram[offs] + ((attributes<<2) & 0x300),
+ (attributes >> 4) & 3,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+VIDEO_UPDATE( gng )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1,0);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_EOF( gng )
+{
+ buffer_spriteram_w(0,0);
+}
diff --git a/src/mame/video/goal92.c b/src/mame/video/goal92.c
new file mode 100644
index 00000000000..38728c50b38
--- /dev/null
+++ b/src/mame/video/goal92.c
@@ -0,0 +1,187 @@
+/***************************************************************************
+
+ Goal '92 video hardware
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *goal92_back_data,*goal92_fore_data,*goal92_textram,*goal92_scrollram16;
+
+static tilemap *background_layer,*foreground_layer,*text_layer;
+
+static UINT16 fg_bank = 0;
+
+READ16_HANDLER( goal92_fg_bank_r )
+{
+ return fg_bank;
+}
+
+WRITE16_HANDLER( goal92_fg_bank_w )
+{
+ COMBINE_DATA(&fg_bank);
+
+ if(ACCESSING_LSB)
+ {
+ tilemap_mark_all_tiles_dirty(foreground_layer);
+ }
+}
+
+WRITE16_HANDLER( goal92_text_w )
+{
+ COMBINE_DATA(&goal92_textram[offset]);
+ tilemap_mark_tile_dirty(text_layer,offset);
+}
+
+WRITE16_HANDLER( goal92_background_w )
+{
+ COMBINE_DATA(&goal92_back_data[offset]);
+ tilemap_mark_tile_dirty(background_layer,offset);
+}
+
+WRITE16_HANDLER( goal92_foreground_w )
+{
+ COMBINE_DATA(&goal92_fore_data[offset]);
+ tilemap_mark_tile_dirty(foreground_layer,offset);
+}
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ int tile = goal92_textram[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile &= 0xfff;
+
+ tile |= 0xc000;
+
+ SET_TILE_INFO(1,tile,color,0);
+}
+
+static TILE_GET_INFO( get_back_tile_info )
+{
+ int tile=goal92_back_data[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile &= 0xfff;
+
+ SET_TILE_INFO(2,tile,color,0);
+}
+
+static TILE_GET_INFO( get_fore_tile_info )
+{
+ int tile=goal92_fore_data[tile_index];
+ int color=(tile>>12)&0xf;
+ int region;
+
+ tile &= 0xfff;
+
+ if(fg_bank & 0xff)
+ {
+ region = 3;
+ tile |= 0x1000;
+ }
+ else
+ {
+ region = 4;
+ tile |= 0x2000;
+ }
+
+ SET_TILE_INFO(region,tile,color,0);
+}
+
+static void draw_sprites(running_machine *machine,mame_bitmap *bitmap,const rectangle *cliprect,int pri)
+{
+ int offs,fx,fy,x,y,color,sprite;
+
+ for (offs = 3;offs <= 0x400-5;offs += 4)
+ {
+ UINT16 data = buffered_spriteram16[offs+2];
+
+ y = buffered_spriteram16[offs+0];
+
+ if (y & 0x8000)
+ break;
+
+ if (!(data & 0x8000))
+ continue;
+
+ sprite = buffered_spriteram16[offs+1];
+
+ if ((sprite>>14)!=pri)
+ continue;
+
+ x = buffered_spriteram16[offs+3];
+
+ sprite &= 0x1fff;
+
+ x &= 0x1ff;
+ y &= 0x1ff;
+
+ color = (data & 0x3f) + 0x40;
+ fx = (data & 0x4000) >> 14;
+ fy = 0;
+
+ x -= 320/4-16-1;
+
+ y = 256-(y+7);
+
+ drawgfx(bitmap,machine->gfx[0],
+ sprite,
+ color,fx,fy,x,y,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+
+VIDEO_START( goal92 )
+{
+ background_layer = tilemap_create(get_back_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ foreground_layer = tilemap_create(get_fore_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ text_layer = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,32);
+
+ buffered_spriteram16 = auto_malloc(0x400*2);
+
+ tilemap_set_transparent_pen(background_layer,15);
+ tilemap_set_transparent_pen(foreground_layer,15);
+ tilemap_set_transparent_pen(text_layer,15);
+}
+
+VIDEO_UPDATE( goal92 )
+{
+ tilemap_set_scrollx(background_layer, 0, goal92_scrollram16[0] + 60);
+ tilemap_set_scrolly(background_layer, 0, goal92_scrollram16[1] + 8);
+
+ if(fg_bank & 0xff)
+ {
+ tilemap_set_scrollx(foreground_layer, 0, goal92_scrollram16[0] + 60);
+ tilemap_set_scrolly(foreground_layer, 0, goal92_scrollram16[1] + 8);
+ }
+ else
+ {
+ tilemap_set_scrollx(foreground_layer, 0, goal92_scrollram16[2] + 60);
+ tilemap_set_scrolly(foreground_layer, 0, goal92_scrollram16[3] + 8);
+ }
+
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ tilemap_draw(bitmap,cliprect,background_layer,0,0);
+ draw_sprites(machine,bitmap,cliprect,2);
+
+ if(!(fg_bank & 0xff))
+ draw_sprites(machine,bitmap,cliprect,1);
+
+ tilemap_draw(bitmap,cliprect,foreground_layer,0,0);
+
+ if(fg_bank & 0xff)
+ draw_sprites(machine,bitmap,cliprect,1);
+
+ draw_sprites(machine,bitmap,cliprect,0);
+ draw_sprites(machine,bitmap,cliprect,3);
+ tilemap_draw(bitmap,cliprect,text_layer,0,0);
+ return 0;
+}
+
+VIDEO_EOF( goal92 )
+{
+ memcpy(buffered_spriteram16,spriteram16,0x400*2);
+}
diff --git a/src/mame/video/goindol.c b/src/mame/video/goindol.c
new file mode 100644
index 00000000000..5fa3914c396
--- /dev/null
+++ b/src/mame/video/goindol.c
@@ -0,0 +1,143 @@
+/***************************************************************************
+ Goindol
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *goindol_bg_videoram;
+UINT8 *goindol_fg_videoram;
+UINT8 *goindol_fg_scrollx;
+UINT8 *goindol_fg_scrolly;
+
+size_t goindol_fg_videoram_size;
+size_t goindol_bg_videoram_size;
+int goindol_char_bank;
+
+static tilemap *bg_tilemap,*fg_tilemap;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = goindol_fg_videoram[2*tile_index+1];
+ int attr = goindol_fg_videoram[2*tile_index];
+ SET_TILE_INFO(
+ 0,
+ code | ((attr & 0x7) << 8) | (goindol_char_bank << 11),
+ (attr & 0xf8) >> 3,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = goindol_bg_videoram[2*tile_index+1];
+ int attr = goindol_bg_videoram[2*tile_index];
+ SET_TILE_INFO(
+ 1,
+ code | ((attr & 0x7) << 8) | (goindol_char_bank << 11),
+ (attr & 0xf8) >> 3,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( goindol )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,32,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( goindol_fg_videoram_w )
+{
+ goindol_fg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset / 2);
+}
+
+WRITE8_HANDLER( goindol_bg_videoram_w )
+{
+ goindol_bg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset / 2);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int gfxbank, UINT8 *sprite_ram)
+{
+ int offs,sx,sy,tile,palette;
+
+ for (offs = 0 ;offs < spriteram_size; offs+=4)
+ {
+ sx = sprite_ram[offs];
+ sy = 240-sprite_ram[offs+1];
+
+ if (flip_screen)
+ {
+ sx = 248 - sx;
+ sy = 248 - sy;
+ }
+
+ if ((sprite_ram[offs+1] >> 3) && (sx < 248))
+ {
+ tile = ((sprite_ram[offs+3])+((sprite_ram[offs+2] & 7) << 8));
+ tile += tile;
+ palette = sprite_ram[offs+2] >> 3;
+
+ drawgfx(bitmap,machine->gfx[gfxbank],
+ tile,
+ palette,
+ flip_screen,flip_screen,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ drawgfx(bitmap,machine->gfx[gfxbank],
+ tile+1,
+ palette,
+ flip_screen,flip_screen,
+ sx,sy + (flip_screen ? -8 : 8),
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+ }
+}
+
+VIDEO_UPDATE( goindol )
+{
+ tilemap_set_scrollx(fg_tilemap,0,*goindol_fg_scrollx);
+ tilemap_set_scrolly(fg_tilemap,0,*goindol_fg_scrolly);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect,1,spriteram);
+ draw_sprites(machine,bitmap,cliprect,0,spriteram_2);
+ return 0;
+}
diff --git a/src/mame/video/goldstar.c b/src/mame/video/goldstar.c
new file mode 100644
index 00000000000..ee0017d4ff8
--- /dev/null
+++ b/src/mame/video/goldstar.c
@@ -0,0 +1,200 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+UINT8 *goldstar_video1, *goldstar_video2, *goldstar_video3;
+size_t goldstar_video_size;
+UINT8 *goldstar_scroll1, *goldstar_scroll2, *goldstar_scroll3;
+
+static UINT8 *dirtybuffer1, *dirtybuffer2, *dirtybuffer3;
+static mame_bitmap *tmpbitmap1, *tmpbitmap2, *tmpbitmap3;
+static int bgcolor;
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+VIDEO_START( goldstar )
+{
+// int i;
+
+ video_start_generic(machine);
+
+ dirtybuffer1 = auto_malloc(3 * goldstar_video_size * sizeof(UINT8));
+ dirtybuffer2 = dirtybuffer1 + goldstar_video_size;
+ dirtybuffer3 = dirtybuffer2 + goldstar_video_size;
+
+ /* the background area is half as high as the screen */
+ tmpbitmap1 = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ tmpbitmap2 = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ tmpbitmap3 = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ /* leave everything at the default, but map all foreground 0 pens as transparent */
+// for (i = 0;i < 16;i++) palette_used_colors[8 * i] = PALETTE_COLOR_TRANSPARENT;
+}
+
+
+
+
+WRITE8_HANDLER( goldstar_video1_w )
+{
+ if (goldstar_video1[offset] != data)
+ {
+ dirtybuffer1[offset] = 1;
+ goldstar_video1[offset] = data;
+ }
+}
+WRITE8_HANDLER( goldstar_video2_w )
+{
+ if (goldstar_video2[offset] != data)
+ {
+ dirtybuffer2[offset] = 1;
+ goldstar_video2[offset] = data;
+ }
+}
+WRITE8_HANDLER( goldstar_video3_w )
+{
+ if (goldstar_video3[offset] != data)
+ {
+ dirtybuffer3[offset] = 1;
+ goldstar_video3[offset] = data;
+ }
+}
+
+
+
+WRITE8_HANDLER( goldstar_fa00_w )
+{
+ /* bit 1 toggles continuously - might be irq enable or watchdog reset */
+
+ /* bit 2 selects background gfx color (I think) */
+ if (bgcolor != ((data & 0x04) >> 2))
+ {
+ bgcolor = (data & 0x04) >> 2;
+ memset(dirtybuffer1,1,goldstar_video_size);
+ memset(dirtybuffer2,1,goldstar_video_size);
+ memset(dirtybuffer3,1,goldstar_video_size);
+ }
+}
+
+
+
+static const rectangle visible1 = { 14*8, (14+48)*8-1, 4*8, (4+7)*8-1 };
+static const rectangle visible2 = { 14*8, (14+48)*8-1, 12*8, (12+7)*8-1 };
+static const rectangle visible3 = { 14*8, (14+48)*8-1, 20*8, (20+7)*8-1 };
+
+
+VIDEO_UPDATE( goldstar )
+{
+ int offs;
+
+
+// if (palette_recalc())
+ {
+ memset(dirtybuffer,1,videoram_size);
+ memset(dirtybuffer1,1,goldstar_video_size);
+ memset(dirtybuffer2,1,goldstar_video_size);
+ memset(dirtybuffer3,1,goldstar_video_size);
+ }
+
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ if (dirtybuffer[offs])
+ {
+ int sx,sy;
+
+
+ dirtybuffer[offs] = 0;
+
+ sx = offs % 64;
+ sy = offs / 64;
+
+ drawgfx(tmpbitmap,machine->gfx[0],
+ videoram[offs] + ((colorram[offs] & 0xf0) << 4),
+ colorram[offs] & 0x0f,
+ 0,0,
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ copybitmap(bitmap,tmpbitmap,0,0,0,0,cliprect,TRANSPARENCY_NONE,0);
+
+
+ for (offs = goldstar_video_size - 1;offs >= 0;offs--)
+ {
+ int sx = offs % 64;
+ int sy = offs / 64;
+
+
+ if (dirtybuffer1[offs])
+ {
+ dirtybuffer1[offs] = 0;
+
+ drawgfx(tmpbitmap1,machine->gfx[1],
+ goldstar_video1[offs],
+ bgcolor,
+ 0,0,
+ sx*8,sy*32,
+ 0,TRANSPARENCY_NONE,0);
+ }
+
+ if (dirtybuffer2[offs])
+ {
+ dirtybuffer2[offs] = 0;
+
+ drawgfx(tmpbitmap2,machine->gfx[1],
+ goldstar_video2[offs],
+ bgcolor,
+ 0,0,
+ sx*8,sy*32,
+ 0,TRANSPARENCY_NONE,0);
+ }
+
+ if (dirtybuffer3[offs])
+ {
+ dirtybuffer3[offs] = 0;
+
+ drawgfx(tmpbitmap3,machine->gfx[1],
+ goldstar_video3[offs],
+ bgcolor,
+ 0,0,
+ sx*8,sy*32,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ {
+ int i,scrolly[64];
+
+ for (i= 0;i < 64;i++)
+ scrolly[i] = -goldstar_scroll1[i];
+
+ copyscrollbitmap(bitmap,tmpbitmap1,0,0,64,scrolly,&visible1,TRANSPARENCY_NONE,0);
+ copybitmap(bitmap,tmpbitmap,0,0,0,0,&visible1,TRANSPARENCY_PEN,0);
+
+ for (i= 0;i < 64;i++)
+ scrolly[i] = -goldstar_scroll2[i];
+
+ copyscrollbitmap(bitmap,tmpbitmap2,0,0,64,scrolly,&visible2,TRANSPARENCY_NONE,0);
+ copybitmap(bitmap,tmpbitmap,0,0,0,0,&visible2,TRANSPARENCY_PEN,0);
+
+ for (i= 0;i < 64;i++)
+ scrolly[i] = -goldstar_scroll3[i];
+
+ copyscrollbitmap(bitmap,tmpbitmap3,0,0,64,scrolly,&visible3,TRANSPARENCY_NONE,0);
+ copybitmap(bitmap,tmpbitmap,0,0,0,0,&visible3,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/gomoku.c b/src/mame/video/gomoku.c
new file mode 100644
index 00000000000..043ac564215
--- /dev/null
+++ b/src/mame/video/gomoku.c
@@ -0,0 +1,235 @@
+/******************************************************************************
+
+ Gomoku Narabe Renju
+ (c)1981 Nihon Bussan Co.,Ltd.
+
+ Driver by Takahiro Nogi <nogi@kt.rim.or.jp> 1999/11/06 -
+ Updated to compile again by David Haywood 19th Oct 2002
+
+******************************************************************************/
+
+#include "driver.h"
+
+
+static int gomoku_flipscreen;
+static int gomoku_bg_dispsw;
+static tilemap *fg_tilemap;
+static mame_bitmap *gomoku_bg_bitmap;
+
+UINT8 *gomoku_videoram;
+UINT8 *gomoku_colorram;
+UINT8 *gomoku_bgram;
+
+
+/******************************************************************************
+
+ palette RAM
+
+******************************************************************************/
+
+PALETTE_INIT( gomoku )
+{
+ int i;
+ int bit0, bit1, bit2, r, g, b;
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i, MAKE_RGB(r, g, b));
+ color_prom++;
+ }
+}
+
+
+/******************************************************************************
+
+ Tilemap callbacks
+
+******************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = (gomoku_videoram[tile_index]);
+ int attr = (gomoku_colorram[tile_index]);
+ int color = (attr& 0x0f);
+ int flipyx = (attr & 0xc0) >> 6;
+
+ SET_TILE_INFO(
+ 0,
+ code,
+ color,
+ TILE_FLIPYX(flipyx));
+}
+
+WRITE8_HANDLER( gomoku_videoram_w )
+{
+ gomoku_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE8_HANDLER( gomoku_colorram_w )
+{
+ gomoku_colorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE8_HANDLER( gomoku_bgram_w )
+{
+ gomoku_bgram[offset] = data;
+}
+
+WRITE8_HANDLER( gomoku_flipscreen_w )
+{
+ gomoku_flipscreen = (data & 0x02) ? 0 : 1;
+}
+
+WRITE8_HANDLER( gomoku_bg_dispsw_w )
+{
+ gomoku_bg_dispsw = (data & 0x02) ? 0 : 1;
+}
+
+
+/******************************************************************************
+
+ Start the video hardware emulation
+
+******************************************************************************/
+
+VIDEO_START( gomoku )
+{
+ UINT8 *GOMOKU_BG_X = memory_region( REGION_USER1 );
+ UINT8 *GOMOKU_BG_Y = memory_region( REGION_USER2 );
+ UINT8 *GOMOKU_BG_D = memory_region( REGION_USER3 );
+ int x, y;
+ int bgdata;
+ int color;
+
+ gomoku_bg_bitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ /* make background bitmap */
+ fillbitmap(gomoku_bg_bitmap, 0x20, 0);
+
+ // board
+ for (y = 0; y < 256; y++)
+ {
+ for (x = 0; x < 256; x++)
+ {
+ bgdata = GOMOKU_BG_D[ GOMOKU_BG_X[x] + (GOMOKU_BG_Y[y] << 4) ];
+
+ color = 0x20; // outside frame (black)
+
+ if (bgdata & 0x01) color = 0x21; // board (brown)
+ if (bgdata & 0x02) color = 0x20; // frame line (while)
+
+ *BITMAP_ADDR16(gomoku_bg_bitmap, (255 - y - 1) & 0xff, (255 - x + 7) & 0xff) = color;
+ }
+ }
+}
+
+
+/******************************************************************************
+
+ Display refresh
+
+******************************************************************************/
+
+VIDEO_UPDATE( gomoku )
+{
+ UINT8 *GOMOKU_BG_X = memory_region( REGION_USER1 );
+ UINT8 *GOMOKU_BG_Y = memory_region( REGION_USER2 );
+ UINT8 *GOMOKU_BG_D = memory_region( REGION_USER3 );
+ int x, y;
+ int bgram;
+ int bgoffs;
+ int bgdata;
+ int color;
+
+ /* draw background layer */
+ if (gomoku_bg_dispsw)
+ {
+ /* copy bg bitmap */
+ copybitmap(bitmap, gomoku_bg_bitmap, 0, 0, 0, 0, cliprect, TRANSPARENCY_NONE, 0);
+
+ // stone
+ for (y = 0; y < 256; y++)
+ {
+ for (x = 0; x < 256; x++)
+ {
+ bgoffs = ((((255 - x - 2) / 14) | (((255 - y - 10) / 14) << 4)) & 0xff);
+
+ bgdata = GOMOKU_BG_D[ GOMOKU_BG_X[x] + (GOMOKU_BG_Y[y] << 4) ];
+ bgram = gomoku_bgram[bgoffs];
+
+ if (bgdata & 0x04)
+ {
+ if (bgram & 0x01)
+ {
+ color = 0x2f; // stone (black)
+ }
+ else if (bgram & 0x02)
+ {
+ color = 0x22; // stone (white)
+ }
+ else continue;
+ }
+ else continue;
+
+ *BITMAP_ADDR16(bitmap, (255 - y - 1) & 0xff, (255 - x + 7) & 0xff) = color;
+ }
+ }
+
+ // cursor
+ for (y = 0; y < 256; y++)
+ {
+ for (x = 0; x < 256; x++)
+ {
+ bgoffs = ((((255 - x - 2) / 14) | (((255 - y - 10) / 14) << 4)) & 0xff);
+
+ bgdata = GOMOKU_BG_D[ GOMOKU_BG_X[x] + (GOMOKU_BG_Y[y] << 4) ];
+ bgram = gomoku_bgram[bgoffs];
+
+ if (bgdata & 0x08)
+ {
+ if (bgram & 0x04)
+ {
+ color = 0x2f; // cursor (black)
+ }
+ else if (bgram & 0x08)
+ {
+ color = 0x22; // cursor (white)
+ }
+ else continue;
+ }
+ else continue;
+
+ *BITMAP_ADDR16(bitmap, (255 - y - 1) & 0xff, (255 - x + 7) & 0xff) = color;
+ }
+ }
+ }
+ else
+ {
+ fillbitmap(bitmap, 0x20, 0);
+ }
+
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/goodejan.c b/src/mame/video/goodejan.c
new file mode 100644
index 00000000000..c6814d9d88f
--- /dev/null
+++ b/src/mame/video/goodejan.c
@@ -0,0 +1,104 @@
+#include "driver.h"
+
+static tilemap *bg_tilemap, *tx_tilemap;
+UINT16 *goodejan_bgvram,*goodejan_txvram;
+
+WRITE16_HANDLER( goodejan_bgvram_w )
+{
+ COMBINE_DATA(&goodejan_bgvram[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE16_HANDLER( goodejan_txvram_w )
+{
+ COMBINE_DATA(&goodejan_txvram[offset]);
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+static TILE_GET_INFO( goodejan_bg_tile_info )
+{
+ int tile = goodejan_bgvram[tile_index]&0x0fff;
+ int color = (goodejan_bgvram[tile_index]&0xf000)>>12;
+
+ // WRONG!
+ if ((goodejan_bgvram[tile_index]&0x8000)==0x0000) tile+=0x1000;
+
+ SET_TILE_INFO(1, tile, color, 0);
+}
+
+static TILE_GET_INFO( goodejan_tx_tile_info )
+{
+ int tile = goodejan_txvram[tile_index];
+ int color = (tile >> 12) & 0x0f;
+ SET_TILE_INFO(2, (tile & 0xfff) + 0x3000, color, 0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int pri)
+{
+ int offs,fx,fy,x,y,color,sprite;
+ int dx,dy,ax,ay;
+
+ for (offs = 0x400-4;offs >= 0;offs -= 4)
+ {
+ if ((spriteram16[offs+0]&0x8000)!=0x8000) continue;
+ sprite = spriteram16[offs+1];
+ if ((sprite>>14)!=pri) continue;
+ sprite &= 0x1fff;
+
+ y = spriteram16[offs+3];//&0x1ff;
+ x = spriteram16[offs+2];//&0x1ff;
+
+ if (spriteram16[offs+2]&0x8000) x=0x10000-x;
+ if (spriteram16[offs+3]&0x8000) y=0x10000-y;
+
+ color = spriteram16[offs+0]&0x3f;
+ fx = spriteram16[offs+0]&0x40;
+ fy = 0; /* To do - probably 0x2000 */
+ dy = ((spriteram16[offs+0]&0x0380)>>7) + 1;
+ dx = ((spriteram16[offs+0]&0x1c00)>>10) + 1;
+
+ for (ax=0; ax<dx; ax++)
+ for (ay=0; ay<dy; ay++) {
+ if (!fx)
+ drawgfx(bitmap,machine->gfx[0],
+ sprite++,
+ color,fx,fy,x+ax*16,y+ay*16,
+ cliprect,TRANSPARENCY_PEN,15);
+ else
+ drawgfx(bitmap,machine->gfx[0],
+ sprite++,
+ color,fx,fy,x+(dx-1-ax)*16,y+ay*16,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+}
+
+
+WRITE16_HANDLER( goodejan_bg_scrollx_w )
+{
+ tilemap_set_scrollx(bg_tilemap,0, data);
+}
+
+WRITE16_HANDLER( goodejan_bg_scrolly_w )
+{
+ tilemap_set_scrolly(bg_tilemap,0, data);
+}
+
+VIDEO_START( goodejan )
+{
+ bg_tilemap = tilemap_create(goodejan_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,32,32);
+ tx_tilemap = tilemap_create(goodejan_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+ tilemap_set_transparent_pen(tx_tilemap,15);
+}
+
+VIDEO_UPDATE( goodejan )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect, 2);
+ draw_sprites(machine, bitmap,cliprect, 1);
+ draw_sprites(machine, bitmap,cliprect, 0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect, 3);
+
+ return 0;
+}
diff --git a/src/mame/video/gotcha.c b/src/mame/video/gotcha.c
new file mode 100644
index 00000000000..eaa63c1488c
--- /dev/null
+++ b/src/mame/video/gotcha.c
@@ -0,0 +1,135 @@
+#include "driver.h"
+
+
+UINT16 *gotcha_fgvideoram,*gotcha_bgvideoram;
+
+static tilemap *fg_tilemap,*bg_tilemap;
+static int banksel,gfxbank[4];
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( gotcha_tilemap_scan )
+{
+ return (col & 0x1f) | (row << 5) | ((col & 0x20) << 5);
+}
+
+INLINE void get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,UINT16 *vram,int color_offs)
+{
+ UINT16 data = vram[tile_index];
+ int code = (data & 0x3ff) | (gfxbank[(data & 0x0c00) >> 10] << 10);
+
+ SET_TILE_INFO(0,code,(data >> 12) + color_offs,0);
+}
+
+static TILE_GET_INFO( fg_get_tile_info ) { get_tile_info(machine,tileinfo,tile_index,gotcha_fgvideoram, 0); }
+static TILE_GET_INFO( bg_get_tile_info ) { get_tile_info(machine,tileinfo,tile_index,gotcha_bgvideoram,16); }
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( gotcha )
+{
+ fg_tilemap = tilemap_create(fg_get_tile_info,gotcha_tilemap_scan,TILEMAP_TYPE_PEN,16,16,64,32);
+ bg_tilemap = tilemap_create(bg_get_tile_info,gotcha_tilemap_scan,TILEMAP_TYPE_PEN, 16,16,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ tilemap_set_scrolldx(fg_tilemap,-1,0);
+ tilemap_set_scrolldx(bg_tilemap,-5,0);
+}
+
+
+WRITE16_HANDLER( gotcha_fgvideoram_w )
+{
+ COMBINE_DATA(&gotcha_fgvideoram[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE16_HANDLER( gotcha_bgvideoram_w )
+{
+ COMBINE_DATA(&gotcha_bgvideoram[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE16_HANDLER( gotcha_gfxbank_select_w )
+{
+ if (ACCESSING_MSB)
+ banksel = (data & 0x0300) >> 8;
+}
+
+WRITE16_HANDLER( gotcha_gfxbank_w )
+{
+ if (ACCESSING_MSB)
+ {
+ if (gfxbank[banksel] != ((data & 0x0f00) >> 8))
+ {
+ gfxbank[banksel] = (data & 0x0f00) >> 8;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+ }
+}
+
+WRITE16_HANDLER( gotcha_scroll_w )
+{
+ static UINT16 scroll[4];
+ COMBINE_DATA(&scroll[offset]);
+
+ switch (offset)
+ {
+ case 0: tilemap_set_scrollx(fg_tilemap,0,scroll[0]); break;
+ case 1: tilemap_set_scrolly(fg_tilemap,0,scroll[1]); break;
+ case 2: tilemap_set_scrollx(bg_tilemap,0,scroll[2]); break;
+ case 3: tilemap_set_scrolly(bg_tilemap,0,scroll[3]); break;
+ }
+}
+
+
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size/2;offs += 4)
+ {
+ int sx,sy,code,color,flipx,flipy,height,y;
+
+ sx = spriteram16[offs + 2];
+ sy = spriteram16[offs + 0];
+ code = spriteram16[offs + 1];
+ color = spriteram16[offs + 2] >> 9;
+ height = 1 << ((spriteram16[offs + 0] & 0x0600) >> 9);
+ flipx = spriteram16[offs + 0] & 0x2000;
+ flipy = spriteram16[offs + 0] & 0x4000;
+
+ for (y = 0;y < height;y++)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ code + (flipy ? height-1 - y : y),
+ color,
+ flipx,flipy,
+ 0x140-5 - ((sx + 0x10) & 0x1ff),0x100+1 - ((sy + 0x10 * (height - y)) & 0x1ff),
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+
+VIDEO_UPDATE( gotcha )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/gottlieb.c b/src/mame/video/gottlieb.c
new file mode 100644
index 00000000000..7282707de33
--- /dev/null
+++ b/src/mame/video/gottlieb.c
@@ -0,0 +1,221 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *gottlieb_charram;
+
+static int background_priority = 0;
+static int spritebank;
+
+static tilemap *bg_tilemap;
+static int swap_bg_ramrom;
+
+static UINT8 last_video_outputs;
+
+/***************************************************************************
+
+ Gottlieb games dosn't have a color PROM. They use 32 bytes of RAM to
+ dynamically create the palette. Each couple of bytes defines one
+ color (4 bits per pixel; the high 4 bits of the second byte are unused).
+
+ The RAM is conected to the RGB output this way:
+
+ bit 7 -- 240 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 2 kohm resistor -- GREEN
+ -- 240 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ -- 1 kohm resistor -- RED
+ bit 0 -- 2 kohm resistor -- RED
+
+ bit 7 -- unused
+ -- unused
+ -- unused
+ -- unused
+ -- 240 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 1 kohm resistor -- BLUE
+ bit 0 -- 2 kohm resistor -- BLUE
+
+***************************************************************************/
+WRITE8_HANDLER( gottlieb_paletteram_w )
+{
+ int bit0, bit1, bit2, bit3;
+ int r, g, b, val;
+
+ paletteram[offset] = data;
+
+ /* red component */
+
+ val = paletteram[offset | 1];
+
+ bit0 = (val >> 0) & 0x01;
+ bit1 = (val >> 1) & 0x01;
+ bit2 = (val >> 2) & 0x01;
+ bit3 = (val >> 3) & 0x01;
+
+ r = 0x10 * bit0 + 0x21 * bit1 + 0x46 * bit2 + 0x88 * bit3;
+
+ /* green component */
+
+ val = paletteram[offset & ~1];
+
+ bit0 = (val >> 4) & 0x01;
+ bit1 = (val >> 5) & 0x01;
+ bit2 = (val >> 6) & 0x01;
+ bit3 = (val >> 7) & 0x01;
+
+ g = 0x10 * bit0 + 0x21 * bit1 + 0x46 * bit2 + 0x88 * bit3;
+
+ /* blue component */
+
+ val = paletteram[offset & ~1];
+
+ bit0 = (val >> 0) & 0x01;
+ bit1 = (val >> 1) & 0x01;
+ bit2 = (val >> 2) & 0x01;
+ bit3 = (val >> 3) & 0x01;
+
+ b = 0x10 * bit0 + 0x21 * bit1 + 0x46 * bit2 + 0x88 * bit3;
+
+ palette_set_color(Machine, offset / 2, MAKE_RGB(r, g, b));
+}
+
+WRITE8_HANDLER( gottlieb_video_outputs_w )
+{
+ extern void gottlieb_knocker(void);
+
+ background_priority = data & 0x01;
+
+ if (flip_screen_x != (data & 0x02))
+ {
+ flip_screen_x_set(data & 0x02);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ if (flip_screen_y != (data & 0x04))
+ {
+ flip_screen_y_set(data & 0x04);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ /* in Q*Bert Qubes only, bit 4 controls the sprite bank */
+ spritebank = (data & 0x10) >> 4;
+
+ output_set_value("knocker0", (data >> 5) & 1);
+
+ last_video_outputs = data;
+}
+
+WRITE8_HANDLER( usvsthem_video_outputs_w )
+{
+ background_priority = data & 0x01;
+
+ /* in most games, bits 1 and 2 flip screen, however in the laser */
+ /* disc games they are different. */
+
+ /* bit 1 controls the sprite bank. */
+ spritebank = (data & 0x02) >> 1;
+
+ /* bit 2 video enable (0 = black screen) */
+
+ /* bit 3 genlock control (1 = show laserdisc image) */
+}
+
+WRITE8_HANDLER( gottlieb_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( gottlieb_charram_w )
+{
+ if (gottlieb_charram[offset] != data)
+ {
+ gottlieb_charram[offset] = data;
+
+ decodechar(Machine->gfx[0], offset / 32, gottlieb_charram,
+ Machine->drv->gfxdecodeinfo[0].gfxlayout);
+
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index];
+
+ SET_TILE_INFO(0, code^swap_bg_ramrom, 0, 0);
+}
+
+static void gottlieb_video_start_common(void)
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(bg_tilemap, 0);
+}
+
+VIDEO_START( gottlieb )
+{
+ swap_bg_ramrom = 0x00;
+ gottlieb_video_start_common();
+}
+
+VIDEO_START( vidvince )
+{
+ swap_bg_ramrom = 0x80;
+ gottlieb_video_start_common();
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0; offs < spriteram_size - 8; offs += 4) /* it seems there's something strange with sprites #62 and #63 */
+ {
+ /* coordinates hand tuned to make the position correct in Q*Bert Qubes start */
+ /* of level animation. */
+ int sx = (spriteram[offs + 1]) - 4;
+ int sy = (spriteram[offs]) - 13;
+ int code = (255 ^ spriteram[offs + 2]) + 256 * spritebank;
+
+ if (flip_screen_x) sx = 233 - sx;
+ if (flip_screen_y) sy = 244 - sy;
+
+ if (spriteram[offs] || spriteram[offs + 1]) /* needed to avoid garbage on screen */
+ drawgfx(bitmap, machine->gfx[1],
+ code, 0,
+ flip_screen_x, flip_screen_y,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( gottlieb )
+{
+ if (!background_priority)
+ {
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_OPAQUE, 0);
+ }
+ else
+ {
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+ }
+
+ draw_sprites(machine, bitmap, cliprect);
+
+ if (background_priority)
+ {
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/gotya.c b/src/mame/video/gotya.c
new file mode 100644
index 00000000000..c3642881980
--- /dev/null
+++ b/src/mame/video/gotya.c
@@ -0,0 +1,192 @@
+#include "driver.h"
+
+UINT8 *gotya_scroll;
+UINT8 *gotya_videoram2;
+
+static int scroll_bit_8;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ I'm using Pac Man resistor values
+
+***************************************************************************/
+PALETTE_INIT( gotya )
+{
+ int i;
+
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ /* red component */
+
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* green component */
+
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* blue component */
+
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+
+ color_prom++;
+ }
+
+ color_prom += 0x18;
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* character lookup table */
+ /* sprites use the same color lookup table as characters */
+
+ for (i = 0; i < TOTAL_COLORS(0); i++)
+ {
+ COLOR(0, i) = *(color_prom++) & 0x07;
+ }
+}
+
+WRITE8_HANDLER( gotya_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( gotya_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( gotya_video_control_w )
+{
+ /* bit 0 - scroll bit 8
+ bit 1 - flip screen
+ bit 2 - sound disable ??? */
+
+ scroll_bit_8 = data & 0x01;
+
+ if (flip_screen != (data & 0x02))
+ {
+ flip_screen_set(data & 0x02);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index];
+ int color = colorram[tile_index] & 0x0f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static TILEMAP_MAPPER( tilemap_scan_rows_thehand )
+{
+ /* logical (col,row) -> memory offset */
+ row = 31-row;
+ col = 63-col;
+ return ((row)*(num_cols>>1)) + (col&31) + ((col>>5)*0x400);
+}
+
+VIDEO_START( gotya )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows_thehand,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+}
+
+static void draw_status_row(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int sx, int col)
+{
+ int row;
+
+ if (flip_screen)
+ {
+ sx = 35 - sx;
+ }
+
+ for (row = 29; row >= 0; row--)
+ {
+ int sy;
+
+ if (flip_screen)
+ {
+ sy = row;
+ }
+ else
+ {
+ sy = 31 - row;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ gotya_videoram2[row * 32 + col],
+ gotya_videoram2[row * 32 + col + 0x10] & 0x0f,
+ flip_screen_x, flip_screen_y,
+ 8 * sx, 8 * sy,
+ cliprect,
+ TRANSPARENCY_NONE, 0);
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 2; offs < 0x0e; offs += 2)
+ {
+ int code = spriteram[offs + 0x01] >> 2;
+ int color = spriteram[offs + 0x11] & 0x0f;
+ int sx = 256 - spriteram[offs + 0x10] + (spriteram[offs + 0x01] & 0x01) * 256;
+ int sy = spriteram[offs + 0x00];
+
+ if (flip_screen)
+ {
+ sy = 240 - sy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code, color,
+ flip_screen_x, flip_screen_y,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+}
+
+static void draw_status(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ draw_status_row(machine, bitmap, cliprect, 0, 1);
+ draw_status_row(machine, bitmap, cliprect, 1, 0);
+ draw_status_row(machine, bitmap, cliprect, 2, 2); /* these two are blank, but I dont' know if the data comes */
+ draw_status_row(machine, bitmap, cliprect, 33, 13); /* from RAM or 'hardcoded' into the hardware. Likely the latter */
+ draw_status_row(machine, bitmap, cliprect, 35, 14);
+ draw_status_row(machine, bitmap, cliprect, 34, 15);
+}
+
+VIDEO_UPDATE( gotya )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, -(*gotya_scroll + (scroll_bit_8 * 256)) - 2 * 8);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ draw_status(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/gradius3.c b/src/mame/video/gradius3.c
new file mode 100644
index 00000000000..3321068698c
--- /dev/null
+++ b/src/mame/video/gradius3.c
@@ -0,0 +1,190 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+#define TOTAL_CHARS 0x1000
+#define TOTAL_SPRITES 0x4000
+
+UINT16 *gradius3_gfxram;
+int gradius3_priority;
+static int layer_colorbase[3],sprite_colorbase;
+static int dirtygfx;
+static UINT8 *dirtychar;
+
+
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void gradius3_tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ /* (color & 0x02) is flip y handled internally by the 052109 */
+ *code |= ((*color & 0x01) << 8) | ((*color & 0x1c) << 7);
+ *color = layer_colorbase[layer] + ((*color & 0xe0) >> 5);
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the K051960
+
+***************************************************************************/
+
+static void gradius3_sprite_callback(int *code,int *color,int *priority_mask,int *shadow)
+{
+ #define L0 0xaa
+ #define L1 0xcc
+ #define L2 0xf0
+ static int primask[2][4] =
+ {
+ { L0|L2, L0, L0|L2, L0|L1|L2 },
+ { L1|L2, L2, 0, L0|L1|L2 }
+ };
+ int pri = ((*color & 0x60) >> 5);
+ if (gradius3_priority == 0) *priority_mask = primask[0][pri];
+ else *priority_mask = primask[1][pri];
+
+ *code |= (*color & 0x01) << 13;
+ *color = sprite_colorbase + ((*color & 0x1e) >> 1);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( gradius3 )
+{
+ int i;
+ static const gfx_layout spritelayout =
+ {
+ 16,16,
+ TOTAL_SPRITES,
+ 4,
+ { 0, 1, 2, 3 },
+ { 2*4, 3*4, 0*4, 1*4, 6*4, 7*4, 4*4, 5*4,
+ 32*8+2*4, 32*8+3*4, 32*8+0*4, 32*8+1*4, 32*8+6*4, 32*8+7*4, 32*8+4*4, 32*8+5*4 },
+ { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32,
+ 64*8+0*32, 64*8+1*32, 64*8+2*32, 64*8+3*32, 64*8+4*32, 64*8+5*32, 64*8+6*32, 64*8+7*32 },
+ 128*8
+ };
+
+
+ layer_colorbase[0] = 0;
+ layer_colorbase[1] = 32;
+ layer_colorbase[2] = 48;
+ sprite_colorbase = 16;
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,gradius3_tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,REVERSE_PLANE_ORDER,gradius3_sprite_callback);
+
+ K052109_set_layer_offsets(2, -2, 0);
+ K051960_set_sprite_offsets(2, 0);
+
+ /* re-decode the sprites because the ROMs are connected to the custom IC differently
+ from how they are connected to the CPU. */
+ for (i = 0;i < TOTAL_SPRITES;i++)
+ decodechar(machine->gfx[1],i,memory_region(REGION_GFX2),&spritelayout);
+
+ dirtychar = auto_malloc(TOTAL_CHARS);
+ memset(dirtychar,1,TOTAL_CHARS);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ16_HANDLER( gradius3_gfxrom_r )
+{
+ UINT8 *gfxdata = memory_region(REGION_GFX2);
+
+ return (gfxdata[2*offset+1] << 8) | gfxdata[2*offset];
+}
+
+WRITE16_HANDLER( gradius3_gfxram_w )
+{
+ int oldword = gradius3_gfxram[offset];
+ COMBINE_DATA(&gradius3_gfxram[offset]);
+ if (oldword != gradius3_gfxram[offset])
+ {
+ dirtygfx = 1;
+ dirtychar[offset / 16] = 1;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( gradius3 )
+{
+ static const gfx_layout charlayout =
+ {
+ 8,8,
+ TOTAL_CHARS,
+ 4,
+ { 0, 1, 2, 3 },
+#ifdef LSB_FIRST
+ { 2*4, 3*4, 0*4, 1*4, 6*4, 7*4, 4*4, 5*4 },
+#else
+ { 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4 },
+#endif
+ { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 },
+ 32*8
+ };
+
+ /* TODO: this kludge enforces the char banks. For some reason, they don't work otherwise. */
+ K052109_w(0x1d80,0x10);
+ K052109_w(0x1f00,0x32);
+
+ if (dirtygfx)
+ {
+ int i;
+
+ dirtygfx = 0;
+
+ for (i = 0;i < TOTAL_CHARS;i++)
+ {
+ if (dirtychar[i])
+ {
+ dirtychar[i] = 0;
+ decodechar(machine->gfx[0],i,(UINT8 *)gradius3_gfxram,&charlayout);
+ }
+ }
+
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ K052109_tilemap_update();
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ if (gradius3_priority == 0)
+ {
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],TILEMAP_DRAW_OPAQUE,2);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],0,4);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],0,1);
+ }
+ else
+ {
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],TILEMAP_DRAW_OPAQUE,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],0,2);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],0,4);
+ }
+
+ K051960_sprites_draw(bitmap,cliprect,-1,-1);
+ return 0;
+}
diff --git a/src/mame/video/grchamp.c b/src/mame/video/grchamp.c
new file mode 100644
index 00000000000..9b06f6c495a
--- /dev/null
+++ b/src/mame/video/grchamp.c
@@ -0,0 +1,552 @@
+/* Video hardware for Taito Grand Champion */
+
+/* updated by Hans Andersson, dec 2005 */
+#include <math.h>
+#include "driver.h"
+#include "video/resnet.h"
+#include "includes/grchamp.h"
+
+#define FOG_SIZE 70
+
+
+
+#define RGB_MAX 191
+
+
+PALETTE_INIT( grchamp )
+{
+ static const int resistances[3] = { 100, 270, 470 };
+ double rweights[3], gweights[3], bweights[2];
+ grchamp_state *state = machine->driver_data;
+ int i;
+
+ /* compute the color output resistor weights */
+ compute_resistor_weights(0, RGB_MAX, -1.0,
+ 3, &resistances[0], rweights, 0, 100,
+ 3, &resistances[0], gweights, 0, 100,
+ 2, &resistances[0], bweights, 0, 100);
+
+ /* initialize the palette with these colors */
+ for (i = 0; i < 0x20; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 1;
+ bit1 = (color_prom[i] >> 1) & 1;
+ bit2 = (color_prom[i] >> 2) & 1;
+ r = combine_3_weights(rweights, bit0, bit1, bit2);
+
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 1;
+ bit1 = (color_prom[i] >> 4) & 1;
+ bit2 = (color_prom[i] >> 5) & 1;
+ g = combine_3_weights(gweights, bit0, bit1, bit2);
+
+ /* blue component */
+ bit0 = (color_prom[i] >> 6) & 1;
+ bit1 = (color_prom[i] >> 7) & 1;
+ b = combine_2_weights(bweights, bit0, bit1);
+
+ state->bgcolor[i] = MAKE_RGB(r, g, b);
+ }
+}
+
+
+WRITE8_HANDLER( grchamp_left_w )
+{
+ grchamp_state *state = Machine->driver_data;
+ state->leftram[offset] = data;
+ tilemap_mark_tile_dirty(state->left_tilemap, offset);
+}
+
+WRITE8_HANDLER( grchamp_center_w )
+{
+ grchamp_state *state = Machine->driver_data;
+ state->centerram[offset] = data;
+ tilemap_mark_tile_dirty(state->center_tilemap, offset);
+}
+
+WRITE8_HANDLER( grchamp_right_w )
+{
+ grchamp_state *state = Machine->driver_data;
+ state->rightram[offset] = data;
+ tilemap_mark_tile_dirty(state->right_tilemap, offset);
+}
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ grchamp_state *state = machine->driver_data;
+ SET_TILE_INFO(0, state->videoram[tile_index], 0, 0);
+}
+
+static TILE_GET_INFO( get_left_tile_info )
+{
+ grchamp_state *state = machine->driver_data;
+ SET_TILE_INFO(1, state->leftram[tile_index], 0, 0);
+}
+
+static TILE_GET_INFO( get_right_tile_info )
+{
+ grchamp_state *state = machine->driver_data;
+ SET_TILE_INFO(2, state->rightram[tile_index], 0, 0);
+}
+
+static TILE_GET_INFO( get_center_tile_info )
+{
+ grchamp_state *state = machine->driver_data;
+ SET_TILE_INFO(3, state->centerram[tile_index], 0, 0);
+}
+
+static TILEMAP_MAPPER( get_memory_offset )
+{
+ return (col % 32) + row * 32 + (col / 32) * 32*32;
+}
+
+
+VIDEO_START( grchamp )
+{
+ grchamp_state *state = machine->driver_data;
+
+ state->work_bitmap = auto_bitmap_alloc(32,32,machine->screen[0].format);
+
+ /* allocate tilemaps for each of the three sections */
+ state->text_tilemap = tilemap_create(get_text_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+ state->left_tilemap = tilemap_create(get_left_tile_info, get_memory_offset, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ state->right_tilemap = tilemap_create(get_right_tile_info, get_memory_offset, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ state->center_tilemap = tilemap_create(get_center_tile_info, get_memory_offset, TILEMAP_TYPE_PEN, 8,8, 64,32);
+}
+
+#if 0
+static int collision_check(running_machine *machine, grchamp_state *state, mame_bitmap *bitmap, int which )
+{
+ int bgcolor = machine->pens[0];
+ int sprite_transp = machine->pens[0x24];
+ const rectangle *clip = &machine->screen[0].visarea;
+ int y0 = 240 - state->cpu0_out[3];
+ int x0 = 256 - state->cpu0_out[2];
+ int x,y,sx,sy;
+ int pixel;
+ int result = 0;
+
+ if( which==0 )
+ {
+ /* draw the current player sprite into a work bitmap */
+ drawgfx( state->work_bitmap,
+ machine->gfx[4],
+ state->cpu0_out[4]&0xf,
+ 1, /* color */
+ 0,0,
+ 0,0,
+ 0,
+ TRANSPARENCY_NONE, 0 );
+ }
+
+ for( y = 0; y <32; y++ )
+ {
+ for( x = 0; x<32; x++ )
+ {
+ pixel = *BITMAP_ADDR16(state->work_bitmap, y, x);
+ if( pixel != sprite_transp ){
+ sx = x+x0;
+ sy = y+y0;
+ if( (sx >= clip->min_x) && (sx <= clip->max_x) &&
+ (sy >= clip->min_y) && (sy <= clip->max_y) )
+ {
+ // Collision check uses only 16 pens!
+ pixel = *BITMAP_ADDR16(bitmap, sy, sx) % 16;
+ if( pixel != bgcolor )
+ {
+ result = 1; /* flag collision */
+ /* wipe this pixel, so collision checks with the
+ ** next layer work */
+ *BITMAP_ADDR16(bitmap, sy, sx) = bgcolor;
+ }
+ }
+ }
+
+ }
+ }
+ return result?(1<<which):0;
+}
+
+static void draw_fog(grchamp_state *state, mame_bitmap *bitmap, const rectangle *cliprect, int fog)
+{
+ int x,y,offs;
+
+ // Emulation of analog fog effect
+ for (x = 0; x < 100; x++)
+ {
+ offs = 0x40;
+ if(x > (100-FOG_SIZE-1))
+ offs = 0x40*(x-(100-FOG_SIZE-1));
+ for(y=16;y<240;y++)
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = *BITMAP_ADDR16(bitmap, y, x) + offs;
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, grchamp_state *state, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const gfx_element *gfx = machine->gfx[5];
+ int bank = (state->cpu0_out[0] & 0x20) ? 0x40 : 0x00;
+ const UINT8 *source = state->spriteram + 0x40;
+ const UINT8 *finish = source + 0x40;
+
+ while (source < finish)
+ {
+ int sx = source[3];
+ int sy = 240-source[0];
+ int color = source[2];
+ int code = source[1];
+ drawgfx(bitmap, gfx,
+ bank + (code & 0x3f),
+ color,
+ code & 0x40,
+ code & 0x80,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ source += 4;
+ }
+}
+#endif
+
+
+static void draw_objects(running_machine *machine, grchamp_state *state, int y, UINT8 *objdata)
+{
+/*
+ CPU 5/7:
+
+ TOP-LEFT:
+ 2xLS163 counters
+ /CNTRLD loads HPOSI0-7
+ /CNTRCLR | /256H clears (i.e., cleared on /CNTRCLR only during HBLANK)
+ clocks on 6MHz
+
+ Output from counters is inverted if /256H = 1 (during visible area)
+
+ Becomes address in line buffer
+
+ TOP-CENTER: (POINT "A" == output from 74LS02 pin 13)
+ 0 during visible area (always)
+ 0 during HBLANK if:
+ 2xLS163 counters & 0xf8 == 0xf8 or
+ 2xLS163 counters & 0xf8 == 0x00
+ When 0, forces /RC0, /RC1, /RC2, /RV0, /RV1 to 1
+
+ When drawing (during HBLANK):
+ /RC0 = 0 iff (RAW0 | RAW1) & (prev /RC11) & (prev /RC22) & HPOSI0
+ /RC1 = 0 iff (RAW0 | RAW1) & (prev /RC00) & (prev /RC22) & HPOSI1
+ /RC2 = 0 iff (RAW0 | RAW1) & (prev /RC00) & (prev /RC11) & HPOSI2
+ /RV0 = RAW0 | (prev bit value & !(RAW0 | RAW1))
+ /RV1 = RAW1 | (prev bit value & !(RAW0 | RAW1))
+
+
+
+ /RC00 = (RAW0|RAW1) | DOUT(2)
+ /RC11 = (RAW0|RAW1) | DOUT(3)
+ /RC22 = (RAW0|RAW1) | DOUT(4)
+
+
+*/
+ const UINT8 *prom = memory_region(REGION_PROMS) + 0x20;
+ const gfx_element *gfx;
+ int change = (state->cpu0_out[0] & 0x20) << 3;
+ int num;
+
+ /* first clear to 0; this is done as the previous scanline was scanned */
+ memset(objdata, 0, 256);
+
+ /* now draw the sprites; this is done during HBLANK */
+ gfx = machine->gfx[4];
+ for (num = 0; num < 16; num++)
+ {
+ /*
+ Each sprite is 4 bytes. The logic reads one byte every 2H:
+ 5C,7D,5E,7F, 5C,5D,5E,5F, 58,79,5A,7B, 58,59,5A,5B,
+ 54,75,56,77, 54,55,56,57, 50,71,52,73, 50,51,52,53,
+ 4C,6D,4E,6F, 4C,4D,4E,4F, 48,69,4A,6B, 48,49,4A,4B,
+ 44,65,46,67, 44,45,46,47, 40,61,42,63, 40,41,42,43,
+ */
+ int dataoffs = ((~num & 0x0e) << 1) | ((~num & 0x01) << 5);
+
+ /* the first of the 4 bytes is the Y position; this is used to match the scanline */
+ /* we match this scanline if the sum & 0xf0 == 0 */
+ int sy = state->spriteram[0x40 + (dataoffs & ~0x20)];
+ int dy = sy + ~y;
+ if ((dy & 0xf0) == 0)
+ {
+ /* the second byte is: code is in bits 0-5, xflip in bit 6, yflip in bit 7 */
+ /* note that X flip is reversed (on purpose) */
+ int codeflip = state->spriteram[0x41 + dataoffs];
+ int code = (codeflip & 0x3f) + (change >> 2);
+ int yflip = (codeflip & 0x80) ? 0x0f : 0x00;
+ int xflip = (codeflip & 0x40) ? 0x0f : 0x00;
+ const UINT8 *src = gfx->gfxdata + code * gfx->char_modulo + ((dy ^ yflip) & 15) * gfx->line_modulo;
+
+ /* the third byte is: color in bits 0-2 */
+ int color = (state->spriteram[0x42 + (dataoffs & ~0x20)] & 0x07) << 2;
+
+ /* the fourth byte is the X position */
+ int sx = state->spriteram[0x43 + dataoffs];
+ int x;
+
+ /* draw 16 pixels */
+ for (x = 0; x < 16; x++)
+ {
+ int dx = ~(x + sx) & 0xff;
+
+ /* the line buffer circuit clips between $08 and $F8 */
+ if (dx >= 0x08 && dx < 0xf8)
+ {
+ int pix = src[x ^ xflip];
+
+ /* only non-zero pixels are written */
+ if (pix != 0)
+ objdata[dx] = pix | color;
+ }
+ }
+ }
+ }
+
+ /* finally draw the text characters; this is done as we read out the object buffers */
+ gfx = machine->gfx[0];
+ for (num = 0; num < 32; num++)
+ {
+ /*
+ The logic reads one byte every 4H, 64 bytes total:
+ 3E,3F,3C,3D, 3A,3B,38,39, 36,37,34,35, 32,33,30,31,
+ 2E,2F,2C,2D, 2A,2B,28,29, 26,27,24,25, 22,23,20,21,
+ 1E,1F,1C,1D, 1A,1B,18,19, 16,17,14,15, 12,13,10,11,
+ 0E,0F,0C,0D, 0A,0B,08,09, 06,07,04,05, 02,03,00,01
+ */
+ int hprime = num ^ 0x1f;
+ int dataoffs = hprime << 1;
+ int sy = state->spriteram[0x00 + dataoffs];
+ int dy = sy + ~y;
+ int color = (state->spriteram[0x01 + dataoffs] & 0x07) << 2;
+ int code = state->videoram[hprime | ((dy & 0xf8) << 2)] + change;
+ const UINT8 *src = gfx->gfxdata + code * gfx->char_modulo + (dy & 7) * gfx->line_modulo;
+ int x;
+
+ /* draw 8 pixels */
+ for (x = 0; x < 8; x++)
+ {
+ int pix = src[x ^ 7];
+
+ /* look up the final result in the PROM */
+ /* bit 4 = CHARAC (we add this in) */
+ /* bit 3 = /OBJECT */
+ /* bit 2 = /RADA */
+ /* bit 1 = /GREENA */
+ /* bit 0 = /BLUEA */
+
+ /* if non-zero pixels, just OR in the color */
+ if (pix != 0)
+ objdata[num * 8 + x] = (prom[pix | color] ^ 0x0f) | 0x10;
+
+ /* otherwise, fetch the sprite data */
+ else
+ objdata[num * 8 + x] = prom[objdata[num * 8 + x]] ^ 0x0f;
+ }
+ }
+}
+
+
+VIDEO_UPDATE( grchamp )
+{
+ static const rgb_t objpix_lookup[8] =
+ {
+ MAKE_RGB(0,0,0),
+ MAKE_RGB(0,0,RGB_MAX),
+ MAKE_RGB(0,RGB_MAX,0),
+ MAKE_RGB(0,RGB_MAX,RGB_MAX),
+ MAKE_RGB(RGB_MAX,0,0),
+ MAKE_RGB(RGB_MAX,0,RGB_MAX),
+ MAKE_RGB(RGB_MAX,RGB_MAX,0),
+ MAKE_RGB(RGB_MAX,RGB_MAX,RGB_MAX)
+ };
+
+ grchamp_state *state = machine->driver_data;
+ const UINT8 *amedata = memory_region(REGION_GFX5);
+ const UINT8 *headdata = memory_region(REGION_GFX6);
+ const UINT8 *pldata = memory_region(REGION_GFX7);
+ mame_bitmap *lpixmap = tilemap_get_pixmap(state->left_tilemap);
+ mame_bitmap *rpixmap = tilemap_get_pixmap(state->right_tilemap);
+ mame_bitmap *cpixmap = tilemap_get_pixmap(state->center_tilemap);
+ int lrxscroll, cxscroll, lyscroll, ryscroll, cyscroll;
+ int bgcolor = state->cpu1_out[3] & 0x10;
+ int amebase = state->cpu0_out[4] >> 4;
+ int plbase = state->cpu0_out[4] & 0x0f;
+ int cxmask;
+ int x, y;
+
+ /* ensure that the tilemaps are the same size */
+ assert(lpixmap->width == rpixmap->width && lpixmap->width == cpixmap->width);
+ assert(lpixmap->height == rpixmap->height && lpixmap->height == cpixmap->height);
+
+ /* extract background scroll values; left and right share the same X scroll */
+ lrxscroll = state->cpu1_out[0] + (state->cpu1_out[1] & 1) * 256;
+ lyscroll = state->cpu1_out[2];
+ ryscroll = state->cpu1_out[7];
+ cxscroll = state->cpu1_out[9] + (state->cpu1_out[10] & 1) * 256;
+ cyscroll = state->cpu1_out[11];
+
+ /* determine the center background mask, controlled by attribute bit 0x20 */
+ cxmask = (state->cpu1_out[3] & 0x20) ? 0xff : 0x1ff;
+
+ /* iterate over scanlines */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ /* select either left or right tilemaps based on Y */
+ mame_bitmap *lrpixmap = (y < 128) ? lpixmap : rpixmap;
+ int lryscroll = (y < 128) ? lyscroll : ryscroll;
+
+ /* get source/dest pointers */
+ /* the Y counter starts counting when VBLANK goes to 0, which is at Y=16 */
+ UINT16 *lrsrc = (UINT16 *)lrpixmap->base + ((lryscroll + y - 16) & 0xff) * lrpixmap->rowpixels;
+ UINT16 *csrc = (UINT16 *)cpixmap->base + ((cyscroll + y - 16) & 0xff) * cpixmap->rowpixels;
+ UINT32 *dest = (UINT32 *)bitmap->base + y * bitmap->rowpixels;
+ UINT8 objdata[256];
+
+ /* draw the objects for this scanline */
+ draw_objects(machine, state, y, objdata);
+
+ /* iterate over columns */
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ rgb_t finalpix;
+ int headbit = 0;
+ int kill = 0;
+ int mydh, mydv;
+ int objpix;
+ int mvid;
+
+ /* the X counter starts counting when HSYNC goes to 0 */
+ /* HYSYNC is high from X=304 through X=336; this means it has */
+ /* been counting from 336 through 384 before HBLANK is low */
+ mvid = csrc[(cxscroll + x + (384-336)) & cxmask];
+ if ((mvid & 0x0f) == 0)
+ mvid = lrsrc[(lrxscroll + x + (384-336)) & 0x1ff];
+
+ /* objdata contains the REDA/GREENA/BLUEA states */
+ objpix = objdata[x];
+
+ /* if the headlamp is visible, determine that now */
+ mydh = (state->cpu0_out[2] - x) & 0xff;
+ mydv = (state->cpu0_out[3] - (y - 16)) & 0xff;
+ if ((state->cpu0_out[0] & 0x10) && (mydh & 0xc0) == 0xc0 && ((mydv ^ (mydv >> 1)) & 0x40) == 0)
+ {
+ int bits = headdata[((mydh & 0x38) >> 3) |
+ ((mydv & 0x3f) << 3) |
+ ((~mydv & 0x40) << 3) |
+ ((state->cpu0_out[0] & 0x10) << 6)];
+ headbit = (bits >> (~mydh & 0x07)) & 0x01;
+ }
+
+ /* if the headlamp is on and we're not in the headlamp area, */
+ /* and this isn't a character pixel, the /KILL switch is set */
+ if ((state->cpu0_out[0] & 0x10) && !headbit && !(objpix & 0x10))
+ {
+ kill = 1;
+ objpix &= ~7;
+ }
+
+ /* if the player car is visible, compute its pixels */
+ /* the H and V counters work like the tilemaps, offset by the same amount */
+ if ((mydv & 0xe0) == 0 && (mydh & 0xe0) == 0)
+ {
+ int bits = pldata[(mydh >> 2) | (mydv << 3) | (plbase << 8)] >> (~mydh & 0x03);
+ if (bits & 0x01)
+ {
+ objpix |= 4; /* MYCAR(A) */
+
+ /* handle collision detection between MYCARRED and MVID/OBJECT */
+
+ /* skip if the state is being held clear, or if we already have a collision */
+ if ((state->cpu0_out[0] & 0x02) && !(state->collide & 0x1000))
+ {
+ if (objpix & 0x08)
+ {
+mame_printf_debug("Collide car/object @ (%d,%d)\n", x, y);
+ state->collide = 0x1000 | 0x2000/* guess */ | ((~y & 0x80) << 3) | ((~y & 0xf8) << 2) | ((~x & 0xf8) >> 3);
+}
+ else if ((mvid & 0x0f) != 0)
+ {
+mame_printf_debug("Collide car/bg @ (%d,%d)\n", x, y);
+ state->collide = 0x1000 | 0x4000/* guess */ | ((~y & 0x80) << 3) | ((~y & 0xf8) << 2) | ((~x & 0xf8) >> 3);
+}
+ }
+ }
+ if (bits & 0x10)
+ objpix |= 3; /* MYCAR(B) */
+ }
+
+ /* if rain is enabled, it ORs against the bits */
+ if (amebase != 0)
+ {
+ int effx = (state->cpu0_out[8] + x) & 0x0f;
+ int effy = (state->cpu0_out[7] - y) & 0x0f;
+ if ((amedata[(amebase << 5) | (effy << 1) | (effx >> 3)] >> (effx & 0x07)) & 0x01)
+ objpix |= 7;
+ }
+
+ /* if the radar is on, it ORs against the bits */
+ if (y >= 192 && (state->cpu0_out[0] & 0x80))
+ {
+ if ((state->radarram[((~y & 0x3e) << 4) | ((~x & 0xf8) >> 3)] >> (x & 0x07)) & 0x01)
+ objpix |= 7;
+ }
+
+ /* handle collision detection between MVID and OBJECT */
+ if (!(state->collide & 0x1000) && (objpix & 0x08) && (mvid & 0x0f) != 0)
+ {
+mame_printf_debug("Collide bg/object @ (%d,%d)\n", x, y);
+ state->collide = 0x1000 | 0x8000 | ((~y & 0x80) << 3) | ((~y & 0xf8) << 2) | ((~x & 0xf8) >> 3);
+ }
+
+ /*
+
+ OBJECT LAYER:
+
+ R = REDA | MYRADAR | MYCAR(A) | RADARVID | AMEOUT
+ G = GREENA | MYCAR(B) | RADARVID | AMEOUT
+ B = BLUEA | MYCAR(B) | RADARVID | AMEOUT
+
+ if (R | G | B) display object,
+ else display background
+ */
+
+
+ /* still to do:
+ collision detection
+ myradar
+ fog
+ real headlamp effect
+ */
+
+ /* if the object data is non-zero, it gets priority */
+ if ((objpix & 7) != 0)
+ finalpix = objpix_lookup[objpix & 7];
+
+ /* otherwise, it's the background, unless it's been KILL'ed */
+ else if (!kill)
+ finalpix = state->bgcolor[mvid | bgcolor];
+
+ /* in which case it's black */
+ else
+ finalpix = MAKE_RGB(0,0,0);
+
+ /* if the headlamp is visible, adjust the brightness */
+ if (headbit)
+ finalpix += MAKE_RGB(64,64,64);
+
+ dest[x] = finalpix;
+ }
+ }
+
+
+ return 0;
+}
diff --git a/src/mame/video/gridlee.c b/src/mame/video/gridlee.c
new file mode 100644
index 00000000000..8a708a83775
--- /dev/null
+++ b/src/mame/video/gridlee.c
@@ -0,0 +1,212 @@
+/***************************************************************************
+
+ Videa Gridlee hardware
+
+ driver by Aaron Giles
+
+ Based on the Bally/Sente SAC system
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/gridlee.h"
+#include "includes/balsente.h"
+
+
+/*************************************
+ *
+ * Globals
+ *
+ *************************************/
+
+UINT8 gridlee_cocktail_flip;
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static UINT8 *local_videoram;
+
+static UINT8 palettebank_vis;
+
+
+
+/*************************************
+ *
+ * Color PROM conversion
+ *
+ *************************************/
+
+PALETTE_INIT( gridlee )
+{
+ int i;
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ palette_set_color_rgb(machine,i,pal4bit(color_prom[0x0000]),pal4bit(color_prom[0x0800]),pal4bit(color_prom[0x1000]));
+ color_prom++;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( gridlee )
+{
+ /* allocate a local copy of video RAM */
+ local_videoram = auto_malloc(256 * 256);
+ memset(local_videoram, 0, 256 * 256);
+
+ /* reset the palette */
+ palettebank_vis = 0;
+}
+
+
+
+/*************************************
+ *
+ * Cocktail flip
+ *
+ *************************************/
+
+WRITE8_HANDLER( gridlee_cocktail_flip_w )
+{
+ gridlee_cocktail_flip = data & 1;
+}
+
+
+
+/*************************************
+ *
+ * Video RAM write
+ *
+ *************************************/
+
+WRITE8_HANDLER( gridlee_videoram_w )
+{
+ videoram[offset] = data;
+
+ /* expand the two pixel values into two bytes */
+ local_videoram[offset * 2 + 0] = data >> 4;
+ local_videoram[offset * 2 + 1] = data & 15;
+}
+
+
+
+/*************************************
+ *
+ * Palette banking
+ *
+ *************************************/
+
+WRITE8_HANDLER( gridlee_palette_select_w )
+{
+ /* update the scanline palette */
+ if (palettebank_vis != (data & 0x3f))
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1 + BALSENTE_VBEND);
+ palettebank_vis = data & 0x3f;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main screen refresh
+ *
+ *************************************/
+
+/* all the BALSENTE_VBEND adjustments are needed because the hardware has a seperate counting chain
+ to address the video memory instead of using the video chain directly */
+
+VIDEO_UPDATE( gridlee )
+{
+ const pen_t *pens = &machine->pens[palettebank_vis * 32];
+ int x, y, i;
+
+ /* draw scanlines from the VRAM directly */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ /* non-flipped: draw directly from the bitmap */
+ if (!gridlee_cocktail_flip)
+ draw_scanline8(bitmap, 0, y, 256, &local_videoram[(y - BALSENTE_VBEND) * 256], pens + 16, -1);
+
+ /* flipped: x-flip the scanline into a temp buffer and draw that */
+ else
+ {
+ int srcy = BALSENTE_VBSTART - 1 - y;
+ UINT8 temp[256];
+ int xx;
+
+ for (xx = 0; xx < 256; xx++)
+ temp[xx] = local_videoram[srcy * 256 + 255 - xx];
+ draw_scanline8(bitmap, 0, y, 256, temp, pens + 16, -1);
+ }
+ }
+
+ /* draw the sprite images */
+ for (i = 0; i < 32; i++)
+ {
+ UINT8 *sprite = spriteram + i * 4;
+ UINT8 *src;
+ int image = sprite[0];
+ int ypos = sprite[2] + 17 + BALSENTE_VBEND;
+ int xpos = sprite[3];
+
+ /* get a pointer to the source image */
+ src = &memory_region(REGION_GFX1)[64 * image];
+
+ /* loop over y */
+ for (y = 0; y < 16; y++, ypos = (ypos + 1) & 255)
+ {
+ int currxor = 0;
+
+ /* adjust for flip */
+ if (gridlee_cocktail_flip)
+ {
+ ypos = 271 - ypos;
+ currxor = 0xff;
+ }
+
+ if (ypos >= (16 + BALSENTE_VBEND) && ypos >= cliprect->min_y && ypos <= cliprect->max_y)
+ {
+ int currx = xpos;
+
+ /* loop over x */
+ for (x = 0; x < 4; x++)
+ {
+ int ipixel = *src++;
+ int left = ipixel >> 4;
+ int right = ipixel & 0x0f;
+
+ /* left pixel */
+ if (left && currx >= 0 && currx < 256)
+ *BITMAP_ADDR16(bitmap, ypos, currx ^ currxor) = pens[left];
+ currx++;
+
+ /* right pixel */
+ if (right && currx >= 0 && currx < 256)
+ *BITMAP_ADDR16(bitmap, ypos, currx ^ currxor) = pens[right];
+ currx++;
+ }
+ }
+ else
+ src += 4;
+
+ /* de-adjust for flip */
+ if (gridlee_cocktail_flip)
+ ypos = 271 - ypos;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/groundfx.c b/src/mame/video/groundfx.c
new file mode 100644
index 00000000000..e4a5ede7110
--- /dev/null
+++ b/src/mame/video/groundfx.c
@@ -0,0 +1,283 @@
+#include "driver.h"
+#include "video/taitoic.h"
+
+#define TC0100SCN_GFX_NUM 2
+#define TC0480SCP_GFX_NUM 1
+
+UINT16 groundfx_rotate_ctrl[8];
+
+struct tempsprite
+{
+ int gfx;
+ int code,color;
+ int flipx,flipy;
+ int x,y;
+ int zoomx,zoomy;
+ int pri;
+};
+static struct tempsprite *spritelist;
+static rectangle hack_cliprect;
+
+/******************************************************************/
+
+VIDEO_START( groundfx )
+{
+ spritelist = auto_malloc(0x4000 * sizeof(*spritelist));
+
+ TC0100SCN_vh_start(machine,1,TC0100SCN_GFX_NUM,50,8,0,0,0,0,0);
+ TC0480SCP_vh_start(machine,TC0480SCP_GFX_NUM,0,0x24,0,-1,0,0,0,0);
+
+ /* Hack */
+ hack_cliprect.min_x=69;
+ hack_cliprect.max_x=250;
+ hack_cliprect.min_y=24 + 5;
+ hack_cliprect.max_y=24 + 44;
+}
+
+/***************************************************************
+ SPRITE DRAW ROUTINES
+
+We draw a series of small tiles ("chunks") together to
+create each big sprite. The spritemap rom provides the lookup
+table for this. The game hardware looks up 16x16 sprite chunks
+from the spritemap rom, creating a 64x64 sprite like this:
+
+ 0 1 2 3
+ 4 5 6 7
+ 8 9 10 11
+ 12 13 14 15
+
+(where the number is the word offset into the spritemap rom).
+It can also create 32x32 sprites.
+
+NB: unused portions of the spritemap rom contain hex FF's.
+It is a useful coding check to warn in the log if these
+are being accessed. [They can be inadvertently while
+spriteram is being tested, take no notice of that.]
+
+Heavy use is made of sprite zooming.
+
+ ***
+
+ Sprite table layout (4 long words per entry)
+
+ ------------------------------------------
+ 0 | ........ x....... ........ ........ | Flip X
+ 0 | ........ .xxxxxxx ........ ........ | ZoomX
+ 0 | ........ ........ .xxxxxxx xxxxxxxx | Sprite Tile
+ | |
+ 2 | ........ ....xx.. ........ ........ | Sprite/tile priority [*]
+ 2 | ........ ......xx xxxxxx.. ........ | Palette bank
+ 2 | ........ ........ ......xx xxxxxxxx | X position
+ | |
+ 3 | ........ .....x.. ........ ........ | Sprite size (0=32x32, 1=64x64)
+ 3 | ........ ......x. ........ ........ | Flip Y
+ 3 | ........ .......x xxxxxx.. ........ | ZoomY
+ 3 | ........ ........ ......xx xxxxxxxx | Y position
+ ------------------------------------------
+
+ [* 00=over BG0, 01=BG1, 10=BG2, 11=BG3 ]
+ [or 00=over BG1, 01=BG2, 10=BG3, 11=BG3 ]
+
+***************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int do_hack,int x_offs,int y_offs)
+{
+ UINT16 *spritemap = (UINT16 *)memory_region(REGION_USER1);
+ int offs, data, tilenum, color, flipx, flipy;
+ int x, y, priority, dblsize, curx, cury;
+ int sprites_flipscreen = 0;
+ int zoomx, zoomy, zx, zy;
+ int sprite_chunk,map_offset,code,j,k,px,py;
+ int dimension,total_chunks,bad_chunks;
+ static const int primasks[4] = {0xffff, 0xfffc, 0xfff0, 0xff00 };
+
+ /* pdrawgfx() needs us to draw sprites front to back, so we have to build a list
+ while processing sprite ram and then draw them all at the end */
+ struct tempsprite *sprite_ptr = spritelist;
+
+ for (offs = (spriteram_size/4-4);offs >= 0;offs -= 4)
+ {
+ data = spriteram32[offs+0];
+ flipx = (data & 0x00800000) >> 23;
+ zoomx = (data & 0x007f0000) >> 16;
+ tilenum = (data & 0x00007fff);
+
+ data = spriteram32[offs+2];
+ priority = (data & 0x000c0000) >> 18;
+ color = (data & 0x0003fc00) >> 10;
+ x = (data & 0x000003ff);
+
+ data = spriteram32[offs+3];
+ dblsize = (data & 0x00040000) >> 18;
+ flipy = (data & 0x00020000) >> 17;
+ zoomy = (data & 0x0001fc00) >> 10;
+ y = (data & 0x000003ff);
+
+// color |= (0x100 + (priority << 6)); /* priority bits select color bank */
+ color /= 2; /* as sprites are 5bpp */
+ flipy = !flipy;
+ y = (-y &0x3ff);
+
+ if (!tilenum) continue;
+
+ flipy = !flipy;
+ zoomx += 1;
+ zoomy += 1;
+
+ y += y_offs;
+
+ /* treat coords as signed */
+ if (x>0x340) x -= 0x400;
+ if (y>0x340) y -= 0x400;
+
+ x -= x_offs;
+
+ bad_chunks = 0;
+ dimension = ((dblsize*2) + 2); // 2 or 4
+ total_chunks = ((dblsize*3) + 1) << 2; // 4 or 16
+ map_offset = tilenum << 2;
+
+ {
+ for (sprite_chunk=0;sprite_chunk<total_chunks;sprite_chunk++)
+ {
+ j = sprite_chunk / dimension; /* rows */
+ k = sprite_chunk % dimension; /* chunks per row */
+
+ px = k;
+ py = j;
+ /* pick tiles back to front for x and y flips */
+ if (flipx) px = dimension-1-k;
+ if (flipy) py = dimension-1-j;
+
+ code = spritemap[map_offset + px + (py<<(dblsize+1))];
+
+ if (code==0xffff)
+ {
+ bad_chunks += 1;
+ continue;
+ }
+
+ curx = x + ((k*zoomx)/dimension);
+ cury = y + ((j*zoomy)/dimension);
+
+ zx= x + (((k+1)*zoomx)/dimension) - curx;
+ zy= y + (((j+1)*zoomy)/dimension) - cury;
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 320 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ sprite_ptr->gfx = 0;
+ sprite_ptr->code = code;
+ sprite_ptr->color = color;
+ sprite_ptr->flipx = !flipx;
+ sprite_ptr->flipy = flipy;
+ sprite_ptr->x = curx;
+ sprite_ptr->y = cury;
+ sprite_ptr->zoomx = zx << 12;
+ sprite_ptr->zoomy = zy << 12;
+ sprite_ptr->pri = priority;
+ sprite_ptr++;
+ }
+ }
+ }
+
+ /* this happens only if primsks != NULL */
+ while (sprite_ptr != spritelist)
+ {
+ const rectangle *clipper;
+
+ sprite_ptr--;
+
+ if (do_hack && sprite_ptr->pri==1 && sprite_ptr->y<100)
+ clipper=&hack_cliprect;
+ else
+ clipper=cliprect;
+
+ pdrawgfxzoom(bitmap,machine->gfx[sprite_ptr->gfx],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ clipper,TRANSPARENCY_PEN,0,
+ sprite_ptr->zoomx,sprite_ptr->zoomy,
+ primasks[sprite_ptr->pri]);
+ }
+}
+
+/**************************************************************
+ SCREEN REFRESH
+**************************************************************/
+
+VIDEO_UPDATE( groundfx )
+{
+ UINT8 layer[5];
+ UINT8 pivlayer[3];
+ UINT16 priority;
+
+ TC0100SCN_tilemap_update(machine);
+ TC0480SCP_tilemap_update(machine);
+
+ priority = TC0480SCP_get_bg_priority();
+
+ layer[0] = (priority &0xf000) >> 12; /* tells us which bg layer is bottom */
+ layer[1] = (priority &0x0f00) >> 8;
+ layer[2] = (priority &0x00f0) >> 4;
+ layer[3] = (priority &0x000f) >> 0; /* tells us which is top */
+ layer[4] = 4; /* text layer always over bg layers */
+
+ pivlayer[0] = TC0100SCN_bottomlayer(0);
+ pivlayer[1] = pivlayer[0]^1;
+ pivlayer[2] = 2;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect); /* wrong color? */
+
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,pivlayer[0],0,0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,pivlayer[1],0,0);
+
+ /* BIG HACK!
+
+ The rear view mirror is a big priority trick - the text
+ layer of TC0100SCN is used as a stencil to display
+ the bottom layer of TC0480SCP and a particular sprite
+ priority. These never appear outside of the stencil.
+
+ I'm not sure how the game turns this effect on/off
+ (the 480 layer is used normally in the frontend
+ of the game).
+
+ I haven't implemented it properly yet, instead I'm
+ doing a hacky cliprect around the rearview and drawing
+ it's contents the usual way.
+
+ */
+ if (TC0100SCN_long_r(0x4090/4,0) || TC0480SCP_long_r(0x20/4,0)==0x240866) { /* Anything in text layer - really stupid hack */
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[1],0,2);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[2],0,4);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[3],0,8);
+// TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,pivlayer[2],0,0);
+ if (TC0480SCP_long_r(0x20/4,0)!=0x240866) /* Stupid hack for start of race */
+ TC0480SCP_tilemap_draw(bitmap,&hack_cliprect,layer[0],0,0);
+ draw_sprites(machine,bitmap,cliprect,1,44,-574);
+ } else {
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[0],0,1);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[1],0,2);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[2],0,4);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[3],0,8);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,pivlayer[2],0,0);
+ draw_sprites(machine,bitmap,cliprect,0,44,-574);
+ }
+
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[4],0,0); /* TC0480SCP text layer */
+ return 0;
+}
diff --git a/src/mame/video/gstriker.c b/src/mame/video/gstriker.c
new file mode 100644
index 00000000000..c0d888b61f7
--- /dev/null
+++ b/src/mame/video/gstriker.c
@@ -0,0 +1,609 @@
+
+#include "driver.h"
+#include "gstriker.h"
+
+/* imports from driver file */
+extern UINT16 *gs_videoram3;
+extern UINT16 *gs_mixer_regs;
+extern UINT16 *gstriker_lineram;
+
+
+/*** VS920A (score tilemap) **********************************************/
+
+/*
+
+ VS920A - (Very) Simple tilemap chip
+ -----------------------------------
+
+- 1 Plane
+- Tiles 8x8, 4bpp
+- Map 64x64
+- No scrolling or other effects (at least in gstriker)
+
+
+ Videoram format:
+ ----------------
+
+pppp tttt tttt tttt
+
+t=tile, p=palette
+
+*/
+
+sVS920A VS920A[MAX_VS920A];
+static sVS920A* VS920A_cur_chip;
+
+static TILE_GET_INFO( VS920A_get_tile_info )
+{
+ int data;
+ int tileno, pal;
+
+ data = VS920A_cur_chip->vram[tile_index];
+
+ tileno = data & 0xFFF;
+ pal = (data >> 12) & 0xF;
+
+ SET_TILE_INFO(VS920A_cur_chip->gfx_region, tileno, VS920A_cur_chip->pal_base + pal, 0);
+}
+
+WRITE16_HANDLER( VS920A_0_vram_w )
+{
+ COMBINE_DATA(&VS920A[0].vram[offset]);
+ tilemap_mark_tile_dirty(VS920A[0].tmap, offset);
+}
+
+WRITE16_HANDLER( VS920A_1_vram_w )
+{
+ COMBINE_DATA(&VS920A[1].vram[offset]);
+ tilemap_mark_tile_dirty(VS920A[1].tmap, offset);
+}
+
+static void VS920A_init(int numchips)
+{
+ int i;
+
+ if (numchips > MAX_VS920A)
+ numchips = MAX_VS920A;
+
+ for (i=0;i<numchips;i++)
+ {
+ VS920A[i].tmap = tilemap_create(VS920A_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_transparent_pen(VS920A[i].tmap, 0);
+ }
+}
+
+static tilemap* VS920A_get_tilemap(int numchip)
+{
+ return VS920A[numchip].tmap;
+}
+
+static void VS920A_set_pal_base(int numchip, int pal_base)
+{
+ VS920A[numchip].pal_base = pal_base;
+}
+
+static void VS920A_set_gfx_region(int numchip, int gfx_region)
+{
+ VS920A[numchip].gfx_region = gfx_region;
+}
+
+static void VS920A_draw(int numchip, mame_bitmap* screen, const rectangle* cliprect, int priority)
+{
+ VS920A_cur_chip = &VS920A[numchip];
+
+ tilemap_draw(screen, cliprect, VS920A_cur_chip->tmap, 0, priority);
+}
+
+
+
+/*** Fujitsu MB60553 (screen tilemap) **********************************************/
+
+/*
+
+ Fujitsu MB60553 - Tilemap chip
+ ------------------------------
+
+- 1 Plane
+- Tiles 16x16, 4bpp
+- Map 64x64
+- Scrolling
+- Indexed banking (8 banks)
+- Surely another effect like roz/tilezoom, yet to be implemented
+
+
+ Videoram format
+ ---------------
+
+pppp bbbt tttt tttt
+
+t=tile, b=bank, p=palette
+
+
+ Registers
+ ---------
+
+0 - Scroll X
+Fixed point 12.4 (seems wrong)
+
+1 - Scroll Y
+Fixed point 12.4 (seems wrong)
+
+2 - ????
+
+3 - ????
+
+4 - Tilebank #0/#1 ---a aaaa ---b bbbb
+5 - Tilebank #2/#3 ---a aaaa ---b bbbb
+6 - Tilebank #4/#5 ---a aaaa ---b bbbb
+7 - Tilebank #6/#7 ---a aaaa ---b bbbb
+
+Indexed tilebank. Each bank is 0x200 tiles wide. Notice that within each register, the bank with the lower
+index is in the MSB. gstriker uses 5 bits for banking, but the chips could be able to do more.
+
+*/
+
+tMB60553 MB60553[MAX_MB60553];
+
+static tMB60553 *MB60553_cur_chip;
+
+static TILE_GET_INFO( MB60553_get_tile_info )
+{
+ int data, bankno;
+ int tileno, pal;
+
+ data = MB60553_cur_chip->vram[tile_index];
+
+ tileno = data & 0x1FF;
+ pal = (data >> 12) & 0xF;
+ bankno = (data >> 9) & 0x7;
+
+ SET_TILE_INFO(MB60553->gfx_region, tileno + MB60553_cur_chip->bank[bankno] * 0x200, pal + MB60553->pal_base, 0);
+}
+
+static void MB60553_reg_written(int numchip, int num_reg)
+{
+ tMB60553* cur = &MB60553[numchip];
+
+ switch (num_reg)
+ {
+ case 0:
+ tilemap_set_scrollx(cur->tmap, 0, cur->regs[0]>>4);
+ break;
+
+ case 1:
+ tilemap_set_scrolly(cur->tmap, 0, cur->regs[1]>>4);
+ break;
+
+ case 2:
+ mame_printf_debug("MB60553_reg chip %d, reg 2 %04x\n",numchip, cur->regs[2]);
+ break;
+
+ case 3:
+ mame_printf_debug("MB60553_reg chip %d, reg 3 %04x\n",numchip, cur->regs[3]);
+ break;
+
+ case 4:
+ cur->bank[0] = (cur->regs[4] >> 8) & 0x1F;
+ cur->bank[1] = (cur->regs[4] >> 0) & 0x1F;
+ tilemap_mark_all_tiles_dirty(cur->tmap);
+ break;
+
+ case 5:
+ cur->bank[2] = (cur->regs[5] >> 8) & 0x1F;
+ cur->bank[3] = (cur->regs[5] >> 0) & 0x1F;
+ tilemap_mark_all_tiles_dirty(cur->tmap);
+ break;
+
+ case 6:
+ cur->bank[4] = (cur->regs[6] >> 8) & 0x1F;
+ cur->bank[5] = (cur->regs[6] >> 0) & 0x1F;
+ tilemap_mark_all_tiles_dirty(cur->tmap);
+ break;
+
+ case 7:
+ cur->bank[6] = (cur->regs[7] >> 8) & 0x1F;
+ cur->bank[7] = (cur->regs[7] >> 0) & 0x1F;
+ tilemap_mark_all_tiles_dirty(cur->tmap);
+ break;
+ }
+}
+
+/* twc94 has the tilemap made of 2 pages .. it needs this */
+static TILEMAP_MAPPER( twc94_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (row*64) + (col&63) + ((col&64)<<6);
+}
+
+static void MB60553_init(int numchips)
+{
+ int i;
+
+ if (numchips > MAX_MB60553)
+ numchips = MAX_MB60553;
+
+ for (i=0;i<numchips;i++)
+ {
+ MB60553[i].tmap = tilemap_create(MB60553_get_tile_info,twc94_scan,TILEMAP_TYPE_PEN, 16,16,128,64);
+
+ tilemap_set_transparent_pen(MB60553[i].tmap, 0);
+ }
+}
+
+static void MB60553_set_pal_base(int numchip, int pal_base)
+{
+ MB60553[numchip].pal_base = pal_base;
+}
+
+static void MB60553_set_gfx_region(int numchip, int gfx_region)
+{
+ MB60553[numchip].gfx_region = gfx_region;
+}
+
+/* THIS IS STILL WRONG! */
+static void MB60553_draw(running_machine *machine, int numchip, mame_bitmap* screen, const rectangle* cliprect, int priority)
+{
+ int line;
+ rectangle clip;
+ MB60553_cur_chip = &MB60553[numchip];
+
+
+
+
+ clip.min_x = machine->screen[0].visarea.min_x;
+ clip.max_x = machine->screen[0].visarea.max_x;
+ clip.min_y = machine->screen[0].visarea.min_y;
+ clip.max_y = machine->screen[0].visarea.max_y;
+
+ for (line = 0; line < 224;line++)
+ {
+// int scrollx;
+// int scrolly;
+
+ UINT32 startx,starty;
+
+ UINT32 incxx,incyy;
+
+ startx = MB60553_cur_chip->regs[0];
+ starty = MB60553_cur_chip->regs[1];
+
+ startx += (24<<4); // maybe not..
+
+ startx -= gstriker_lineram[(line)*8+7]/2;
+
+ incxx = gstriker_lineram[(line)*8+0]<<4;
+ incyy = gstriker_lineram[(line)*8+3]<<4;
+
+ clip.min_y = clip.max_y = line;
+
+ tilemap_draw_roz(screen,&clip,MB60553_cur_chip->tmap,startx<<12,starty<<12,
+ incxx,0,0,incyy,
+ 1,
+ 0,priority);
+
+ }
+
+
+
+}
+
+static tilemap* MB60553_get_tilemap(int numchip)
+{
+ return MB60553[numchip].tmap;
+}
+
+
+WRITE16_HANDLER(MB60553_0_regs_w)
+{
+ UINT16 oldreg = MB60553[0].regs[offset];
+
+ COMBINE_DATA(&MB60553[0].regs[offset]);
+
+ if (MB60553[0].regs[offset] != oldreg)
+ MB60553_reg_written(0, offset);
+}
+
+WRITE16_HANDLER(MB60553_1_regs_w)
+{
+ UINT16 oldreg = MB60553[1].regs[offset];
+
+ COMBINE_DATA(&MB60553[1].regs[offset]);
+
+ if (MB60553[1].regs[offset] != oldreg)
+ MB60553_reg_written(1, offset);
+}
+
+WRITE16_HANDLER(MB60553_0_vram_w)
+{
+ COMBINE_DATA(&MB60553[0].vram[offset]);
+
+ tilemap_mark_tile_dirty(MB60553[0].tmap, offset);
+}
+
+WRITE16_HANDLER(MB60553_1_vram_w)
+{
+ COMBINE_DATA(&MB60553[1].vram[offset]);
+
+ tilemap_mark_tile_dirty(MB60553[1].tmap, offset);
+}
+
+
+
+/*** Fujitsu CG10103 **********************************************/
+
+/*
+ Fujitsu CG10103 sprite generator
+ --------------------------------
+
+- Tile based
+- 16x16 4bpp tiles
+- Up to 7x7 in each block
+- 5 bit of palette selection for the mixer
+- Scaling (x/y)
+- Flipping
+- Indipendent sorting list
+- 1 bit of priority for the mixer
+
+Note that this chip can be connected to a VS9210 which adds a level of indirection for
+tile numbers. Basically, the VS9210 indirects the tile number through a table in its attached
+memory, before accessing the ROMs.
+
+
+ Sorting list format (VideoRAM offset 0)
+ ---------------------------------------
+
+?e-- ---f ssss ssss
+
+e=end of list
+f=sprite present in this position
+s=sprite index
+?=used together with 'e' almost always
+
+
+ Sprite format (VideoRAM offset 0x400)
+ -------------------------------------
+
+0: nnnn jjjy yyyy yyyy
+1: mmmm iiix xxxx xxxx
+2: fFpc cccc ---- ---t
+3: tttt tttt tttt tttt
+
+t=tile, x=posx, y=posy, i=blockx, j=blocky
+c=color, m=zoomx, n=zoomy, p=priority
+
+The zoom (scaling) is probably non-linear, it would require a hand-made table unless we find the correct
+formula. I'd probably try 1/x. I'm almost sure that it scales between full size (value=0) and half size
+(value=0xF) but I couldn't get much more than that from a soccer game.
+
+
+TODO:
+Priorities should be right, but they probably need to be orthogonal with the mixer priorities.
+Zoom factor is not correct, the scale is probably non-linear
+Horizontal wrapping is just a hack. The chip probably calculates if it needs to draw the sprite at the
+ normal position, or wrapped along X/Y.
+Abstracts the VS9210
+
+*/
+
+tCG10103 CG10103[MAX_CG10103];
+static tCG10103* CG10103_cur_chip;
+
+static void CG10103_draw_sprite(running_machine *machine, mame_bitmap* screen, const rectangle* cliprect, UINT16* spr, int drawpri)
+{
+ int ypos = spr[0] & 0x1FF;
+ int xpos = (spr[1] & 0x1FF);
+ UINT32 tile = (spr[3] & 0xFFFF) | ((spr[2] & 1) << 16);
+ int ynum = (spr[0] >> 9) & 0x7;
+ int xnum = (spr[1] >> 9) & 0x7;
+ int color = (spr[2] >> 8) & 0x1F;
+ int flipx = (spr[2] >> 14) & 1;
+ int flipy = (spr[2] >> 15) & 1;
+ int yzoom = (spr[0] >> 12) & 0xF;
+ int xzoom = (spr[1] >> 12) & 0xF;
+ int pri = (spr[2] >> 13) & 1;
+ int x, y;
+ int xstep, ystep;
+ int xfact, yfact;
+
+ // Check if we want to draw this sprite now
+ if (pri != drawpri)
+ return;
+
+ // Convert in fixed point to handle the scaling
+ xpos <<= 16;
+ ypos <<= 16;
+
+ xnum++;
+ ynum++;
+ xstep = ystep = 16;
+
+ // Linear scale, surely wrong
+ xfact = 0x10000 - ((0x8000 * xzoom) / 15);
+ yfact = 0x10000 - ((0x8000 * yzoom) / 15);
+
+ xstep *= xfact;
+ ystep *= yfact;
+
+ // Handle flipping
+ if (flipy)
+ {
+ ypos += (ynum-1) * ystep;
+ ystep = -ystep;
+ }
+
+ if (flipx)
+ {
+ xpos += (xnum-1) * xstep;
+ xstep = -xstep;
+ }
+
+ // @@@ Add here optional connection to the VS9210 for extra level of tile number indirection
+#if 0
+ if (CG10103_cur_chip->connected_vs9210)
+ {
+ // ...
+ }
+#endif
+
+ // Draw the block
+ for (y=0;y<ynum;y++)
+ {
+ int xp = xpos;
+
+ for (x=0;x<xnum;x++)
+ {
+ // Hack to handle horizontal wrapping
+ drawgfxzoom(screen, machine->gfx[CG10103_cur_chip->gfx_region], tile, color+CG10103_cur_chip->pal_base, flipx, flipy, xp>>16, ypos>>16, cliprect, TRANSPARENCY_PEN, 0x0, xfact, yfact);
+ drawgfxzoom(screen, machine->gfx[CG10103_cur_chip->gfx_region], tile, color+CG10103_cur_chip->pal_base, flipx, flipy, (xp>>16) - 0x200, ypos>>16, cliprect, TRANSPARENCY_PEN, 0x0, xfact, yfact);
+ xp += xstep;
+ tile++;
+ }
+
+ ypos += ystep;
+ }
+}
+
+
+static void CG10103_draw(running_machine *machine, int numchip, mame_bitmap* screen, const rectangle* cliprect, int priority)
+{
+ UINT16* splist;
+ int i;
+
+ CG10103_cur_chip = &CG10103[numchip];
+
+ splist = CG10103_cur_chip->vram;
+
+ // Parse the sorting list
+ for (i=0;i<0x400;i++)
+ {
+ UINT16 cmd = *splist++;
+
+ // End of list
+ if (cmd & 0x4000)
+ break;
+
+ // Normal sprite here
+ if (cmd & 0x100)
+ {
+ // Extract sprite index
+ int num = cmd & 0xFF;
+
+ // Draw the sprite
+ CG10103_draw_sprite(machine, screen, cliprect, CG10103_cur_chip->vram + 0x400 + num*4, priority);
+ }
+ }
+}
+
+static void CG10103_init(int numchips)
+{
+ int i;
+
+ if (numchips > MAX_CG10103)
+ numchips = MAX_CG10103;
+
+ for (i=0;i<numchips;i++)
+ {
+ // No initalization required, as for now. I'll keep the init function in case we later
+ // need something
+ }
+}
+
+static void CG10103_set_pal_base(int numchip, int pal_base)
+{
+ CG10103[numchip].pal_base = pal_base;
+}
+
+static void CG10103_set_gfx_region(int numchip, int gfx_region)
+{
+ CG10103[numchip].gfx_region = gfx_region;
+}
+
+
+
+/*** VIDEO UPDATE/START **********************************************/
+
+
+#ifdef UNUSED_FUNCTION
+WRITE16_HANDLER( gsx_videoram3_w )
+{
+ // This memory appears to be empty in gstriker
+ gs_videoram3[offset] = data;
+}
+#endif
+
+
+VIDEO_UPDATE(gstriker)
+{
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ // Sandwitched screen/sprite0/score/sprite1. Surely wrong, probably
+ // needs sprite orthogonality
+ MB60553_draw(machine, 0, bitmap,cliprect, 0);
+
+ CG10103_draw(machine, 0, bitmap, cliprect, 0);
+
+ VS920A_draw(0, bitmap, cliprect, 0);
+
+ CG10103_draw(machine, 0, bitmap, cliprect, 1);
+
+#if 0
+ popmessage("%04x %04x %04x %04x %04x %04x %04x %04x",
+ (UINT16)MB60553[0].regs[0], (UINT16)MB60553[0].regs[1], (UINT16)MB60553[0].regs[2], (UINT16)MB60553[0].regs[3],
+ (UINT16)MB60553[0].regs[4], (UINT16)MB60553[0].regs[5], (UINT16)MB60553[0].regs[6], (UINT16)MB60553[0].regs[7]
+ );
+#endif
+
+#if 0
+ popmessage("%04x %04x %04x %04x %04x %04x %04x %04x",
+ (UINT16)gs_mixer_regs[8], (UINT16)gs_mixer_regs[9], (UINT16)gs_mixer_regs[10], (UINT16)gs_mixer_regs[11],
+ (UINT16)gs_mixer_regs[12], (UINT16)gs_mixer_regs[13], (UINT16)gs_mixer_regs[14], (UINT16)gs_mixer_regs[15]
+ );
+#endif
+ return 0;
+}
+
+VIDEO_START(gstriker)
+{
+ // Palette bases are hardcoded, but should be probably extracted from the mixer registers
+
+ // Initalize the chip for the score plane
+ VS920A_init(1);
+ VS920A_set_gfx_region(0, 0);
+ VS920A_set_pal_base(0, 0x30);
+ tilemap_set_transparent_pen(VS920A_get_tilemap(0), 0xf);
+
+ // Initalize the chip for the screen plane
+ MB60553_init(1);
+ MB60553_set_gfx_region(0, 1);
+ MB60553_set_pal_base(0, 0);
+ tilemap_set_transparent_pen(MB60553_get_tilemap(0), 0xf);
+
+ // Initialize the sprite generator
+ CG10103_init(1);
+ CG10103_set_gfx_region(0, 2);
+ CG10103_set_pal_base(0, 0x10);
+}
+
+VIDEO_START(twrldc94)
+{
+ // Palette bases are hardcoded, but should be probably extracted from the mixer registers
+
+ // Initalize the chip for the score plane
+ VS920A_init(1);
+ VS920A_set_gfx_region(0, 0);
+ VS920A_set_pal_base(0, 0x40);
+ tilemap_set_transparent_pen(VS920A_get_tilemap(0), 0xf);
+
+ // Initalize the chip for the screen plane
+ MB60553_init(1);
+ MB60553_set_gfx_region(0, 1);
+ MB60553_set_pal_base(0, 0x50);
+ tilemap_set_transparent_pen(MB60553_get_tilemap(0), 0xf);
+
+ // Initialize the sprite generator
+ CG10103_init(1);
+ CG10103_set_gfx_region(0, 2);
+ CG10103_set_pal_base(0, 0x60);
+}
+
diff --git a/src/mame/video/gsword.c b/src/mame/video/gsword.c
new file mode 100644
index 00000000000..36a633df1e5
--- /dev/null
+++ b/src/mame/video/gsword.c
@@ -0,0 +1,220 @@
+/***************************************************************************
+ Great Swordsman
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+size_t gsword_spritexy_size;
+
+//UINT8 *gsword_scrolly_ram;
+UINT8 *gsword_spritexy_ram;
+UINT8 *gsword_spritetile_ram;
+UINT8 *gsword_spriteattrib_ram;
+
+static int charbank, charpalbank, flipscreen;
+
+static tilemap *bg_tilemap;
+
+PALETTE_INIT( josvolly )
+{
+ int i;
+
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ /* red component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* green component */
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* blue component */
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the sprite lookup table */
+
+ /* characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = i;
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = 0x80 + (BITSWAP8( color_prom[i], 7,6,5,4, 0,1,2,3) & 0xf);
+}
+
+PALETTE_INIT( gsword )
+{
+ int i;
+
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[256+i] >> 0) & 1;
+ bit1 = (color_prom[256+i] >> 1) & 1;
+ bit2 = (color_prom[256+i] >> 2) & 1;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[256+i] >> 3) & 1;
+ bit1 = (color_prom[i] >> 0) & 1;
+ bit2 = (color_prom[i] >> 1) & 1;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 2) & 1;
+ bit2 = (color_prom[i] >> 3) & 1;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ color_prom += 2*256;
+ /* color_prom now points to the beginning of the sprite lookup table */
+
+ /* characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = i;
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = 0x80 + (BITSWAP8( color_prom[i], 7,6,5,4, 0,1,2,3) & 0xf);
+}
+
+WRITE8_HANDLER( gsword_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( gsword_charbank_w )
+{
+ if (charbank != data)
+ {
+ charbank = data;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( gsword_videoctrl_w )
+{
+ if (data & 0x8f)
+ {
+ popmessage("videoctrl %02x",data);
+ }
+
+ /* bits 5-6 are char palette bank */
+
+ if (charpalbank != ((data & 0x60) >> 5))
+ {
+ charpalbank = (data & 0x60) >> 5;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ /* bit 4 is flip screen */
+
+ if (flipscreen != (data & 0x10))
+ {
+ flipscreen = data & 0x10;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ /* bit 0 could be used but unknown */
+
+ /* other bits unused */
+}
+
+WRITE8_HANDLER( gsword_scroll_w )
+{
+ tilemap_set_scrolly(bg_tilemap, 0, data);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + ((charbank & 0x03) << 8);
+ int color = ((code & 0x3c0) >> 6) + 16 * charpalbank;
+ int flags = flipscreen ? (TILE_FLIPX | TILE_FLIPY) : 0;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( gsword )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 64);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0; offs < gsword_spritexy_size - 1; offs+=2)
+ {
+ int sx,sy,flipx,flipy,spritebank,tile;
+
+ if (gsword_spritexy_ram[offs]!=0xf1)
+ {
+ spritebank = 0;
+ tile = gsword_spritetile_ram[offs];
+ sy = 241-gsword_spritexy_ram[offs];
+ sx = gsword_spritexy_ram[offs+1]-56;
+ flipx = gsword_spriteattrib_ram[offs] & 0x02;
+ flipy = gsword_spriteattrib_ram[offs] & 0x01;
+
+ // Adjust sprites that should be far far right!
+ if (sx<0) sx+=256;
+
+ // Adjuste for 32x32 tiles(#128-256)
+ if (tile > 127)
+ {
+ spritebank = 1;
+ tile -= 128;
+ sy-=16;
+ }
+ if (flipscreen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+ drawgfx(bitmap,machine->gfx[1+spritebank],
+ tile,
+ gsword_spritetile_ram[offs+1] & 0x3f,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_COLOR, 0x8f);
+ }
+ }
+}
+
+VIDEO_UPDATE( gsword )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/gtia.c b/src/mame/video/gtia.c
new file mode 100644
index 00000000000..1ac255bd66c
--- /dev/null
+++ b/src/mame/video/gtia.c
@@ -0,0 +1,1135 @@
+/***************************************************************************
+
+ Atari 400/800
+
+ GTIA graphics television interface adapter
+
+ Juergen Buchmueller, June 1998
+
+***************************************************************************/
+
+#include "driver.h"
+#include "cpu/m6502/m6502.h"
+#include "includes/atari.h"
+#include "video/gtia.h"
+
+gtia_struct gtia;
+
+#define P0 0x01
+#define P1 0x02
+#define P2 0x04
+#define P3 0x08
+#define M0 0x10
+#define M1 0x20
+#define M2 0x40
+#define M3 0x80
+
+#define CHECK_GRACTL 0
+#define VERBOSE 0
+
+static void gtia_reset(running_machine *machine);
+static void gtia_state(void);
+static void gtia_state_postload(void);
+
+/**********************************************
+ * split a color into hue and luminance values
+ **********************************************/
+#define SPLIT_HUE_LUM(data,hue,lum) \
+ hue = (data & HUE); lum = (data & LUM)
+
+/**********************************************
+ * set both color clocks equal for one color
+ **********************************************/
+#define SETCOL_B(o,d) \
+ antic.color_lookup[o] = (Machine->remapped_colortable[d] << 8) | Machine->remapped_colortable[d]
+
+/**********************************************
+ * set left color clock for one color
+ **********************************************/
+#define SETCOL_L(o,d) \
+ *((UINT8*)&antic.color_lookup[o] + 0) = Machine->remapped_colortable[d]
+
+/**********************************************
+ * set right color clock for one color
+ **********************************************/
+#define SETCOL_R(o,d) \
+ *((UINT8*)&antic.color_lookup[o] + 1) = Machine->remapped_colortable[d]
+
+
+
+/*************************************
+ *
+ * Initialization/Reset
+ *
+ *************************************/
+
+void gtia_init(const gtia_interface *intf)
+{
+ memset(&gtia, 0, sizeof(gtia));
+ gtia.intf = *intf;
+
+ add_reset_callback(Machine, gtia_reset);
+
+ /* state saves */
+ gtia_state();
+}
+
+
+
+static void gtia_state(void)
+{
+ state_save_register_global(gtia.r.m0pf);
+ state_save_register_global(gtia.r.m1pf);
+ state_save_register_global(gtia.r.m2pf);
+ state_save_register_global(gtia.r.m3pf);
+ state_save_register_global(gtia.r.p0pf);
+ state_save_register_global(gtia.r.p1pf);
+ state_save_register_global(gtia.r.p2pf);
+ state_save_register_global(gtia.r.p3pf);
+ state_save_register_global(gtia.r.m0pl);
+ state_save_register_global(gtia.r.m1pl);
+ state_save_register_global(gtia.r.m2pl);
+ state_save_register_global(gtia.r.m3pl);
+ state_save_register_global(gtia.r.p0pl);
+ state_save_register_global(gtia.r.p1pl);
+ state_save_register_global(gtia.r.p2pl);
+ state_save_register_global(gtia.r.p3pl);
+ state_save_register_global_array(gtia.r.but);
+ state_save_register_global(gtia.r.pal);
+ state_save_register_global(gtia.r.gtia15);
+ state_save_register_global(gtia.r.gtia16);
+ state_save_register_global(gtia.r.gtia17);
+ state_save_register_global(gtia.r.gtia18);
+ state_save_register_global(gtia.r.gtia19);
+ state_save_register_global(gtia.r.gtia1a);
+ state_save_register_global(gtia.r.gtia1b);
+ state_save_register_global(gtia.r.gtia1c);
+ state_save_register_global(gtia.r.gtia1d);
+ state_save_register_global(gtia.r.gtia1e);
+ state_save_register_global(gtia.r.cons);
+ state_save_register_global(gtia.w.hposp0);
+ state_save_register_global(gtia.w.hposp1);
+ state_save_register_global(gtia.w.hposp2);
+ state_save_register_global(gtia.w.hposp3);
+ state_save_register_global(gtia.w.hposm0);
+ state_save_register_global(gtia.w.hposm1);
+ state_save_register_global(gtia.w.hposm2);
+ state_save_register_global(gtia.w.hposm3);
+ state_save_register_global(gtia.w.sizep0);
+ state_save_register_global(gtia.w.sizep1);
+ state_save_register_global(gtia.w.sizep2);
+ state_save_register_global(gtia.w.sizep3);
+ state_save_register_global(gtia.w.sizem);
+ state_save_register_global_array(gtia.w.grafp0);
+ state_save_register_global_array(gtia.w.grafp1);
+ state_save_register_global_array(gtia.w.grafp2);
+ state_save_register_global_array(gtia.w.grafp3);
+ state_save_register_global_array(gtia.w.grafm);
+ state_save_register_global(gtia.w.colpm0);
+ state_save_register_global(gtia.w.colpm1);
+ state_save_register_global(gtia.w.colpm2);
+ state_save_register_global(gtia.w.colpm3);
+ state_save_register_global(gtia.w.colpf0);
+ state_save_register_global(gtia.w.colpf1);
+ state_save_register_global(gtia.w.colpf2);
+ state_save_register_global(gtia.w.colpf3);
+ state_save_register_global(gtia.w.colbk);
+ state_save_register_global(gtia.w.prior);
+ state_save_register_global(gtia.w.vdelay);
+ state_save_register_global(gtia.w.gractl);
+ state_save_register_global(gtia.w.hitclr);
+ state_save_register_global(gtia.w.cons);
+ state_save_register_func_postload(gtia_state_postload);
+}
+
+
+
+static int is_ntsc(void)
+{
+ return ATTOSECONDS_TO_HZ(Machine->screen[0].refresh) > 55;
+}
+
+
+
+static void gtia_reset(running_machine *machine)
+{
+ int i;
+ /* reset the GTIA read/write/helper registers */
+ for (i = 0; i < 32; i++)
+ atari_gtia_w(i,0);
+ memset(&gtia.r, 0, sizeof(gtia.r));
+ if (is_ntsc())
+ gtia.r.pal = 0xff;
+ else
+ gtia.r.pal = 0xf1;
+ gtia.r.gtia15 = 0xff;
+ gtia.r.gtia16 = 0xff;
+ gtia.r.gtia17 = 0xff;
+ gtia.r.gtia18 = 0xff;
+ gtia.r.gtia19 = 0xff;
+ gtia.r.gtia1a = 0xff;
+ gtia.r.gtia1b = 0xff;
+ gtia.r.gtia1c = 0xff;
+ gtia.r.gtia1d = 0xff;
+ gtia.r.gtia1e = 0xff;
+ gtia.r.cons = 0x07; /* console keys */
+ SETCOL_B(ILL,0x3e); /* bright red */
+ SETCOL_B(EOR,0xff); /* yellow */
+}
+
+
+
+/**************************************************************
+ *
+ * Read GTIA hardware registers
+ *
+ **************************************************************/
+
+READ8_HANDLER( atari_gtia_r )
+{
+ switch (offset & 31)
+ {
+ case 0: return gtia.r.m0pf;
+ case 1: return gtia.r.m1pf;
+ case 2: return gtia.r.m2pf;
+ case 3: return gtia.r.m3pf;
+ case 4: return gtia.r.p0pf;
+ case 5: return gtia.r.p1pf;
+ case 6: return gtia.r.p2pf;
+ case 7: return gtia.r.p3pf;
+ case 8: return gtia.r.m0pl;
+ case 9: return gtia.r.m1pl;
+ case 10: return gtia.r.m2pl;
+ case 11: return gtia.r.m3pl;
+ case 12: return gtia.r.p0pl;
+ case 13: return gtia.r.p1pl;
+ case 14: return gtia.r.p2pl;
+ case 15: return gtia.r.p3pl;
+
+ case 16: return gtia.r.but[0];
+ case 17: return gtia.r.but[1];
+ case 18: return gtia.r.but[2];
+ case 19: return gtia.r.but[3];
+
+ case 20: return gtia.r.pal;
+
+ case 21: return gtia.r.gtia15;
+ case 22: return gtia.r.gtia16;
+ case 23: return gtia.r.gtia17;
+ case 24: return gtia.r.gtia18;
+ case 25: return gtia.r.gtia19;
+ case 26: return gtia.r.gtia1a;
+ case 27: return gtia.r.gtia1b;
+ case 28: return gtia.r.gtia1c;
+ case 29: return gtia.r.gtia1d;
+ case 30: return gtia.r.gtia1e;
+
+ case 31:
+ gtia.r.cons = gtia.intf.console_read ? (gtia.intf.console_read() & 0x0F) : 0x00;
+ return gtia.r.cons;
+ }
+ return 0xff;
+}
+
+
+
+static void recalc_p0(void)
+{
+ if (
+#if CHECK_GRACTL
+ (gtia.w.gractl & GTIA_PLAYER) == 0 ||
+#endif
+ gtia.w.grafp0[gtia.h.vdelay_p0] == 0 || gtia.w.hposp0 >= 224 )
+ {
+ gtia.h.grafp0 = 0;
+ gtia.h.usedp &= ~0x10;
+ }
+ else
+ {
+ gtia.h.grafp0 = gtia.w.grafp0[gtia.h.vdelay_p0];
+ gtia.h.usedp |= 0x10;
+ }
+}
+
+static void recalc_p1(void)
+{
+ if (
+#if CHECK_GRACTL
+ (gtia.w.gractl & GTIA_PLAYER) == 0 ||
+#endif
+ gtia.w.grafp1[gtia.h.vdelay_p1] == 0 || gtia.w.hposp1 >= 224 )
+ {
+ gtia.h.grafp1 = 0;
+ gtia.h.usedp &= ~0x20;
+ }
+ else
+ {
+ gtia.h.grafp1 = gtia.w.grafp1[gtia.h.vdelay_p1];
+ gtia.h.usedp |= 0x20;
+ }
+}
+
+static void recalc_p2(void)
+{
+ if (
+#if CHECK_GRACTL
+ (gtia.w.gractl & GTIA_PLAYER) == 0 ||
+#endif
+ gtia.w.grafp2[gtia.h.vdelay_p2] == 0 || gtia.w.hposp2 >= 224 )
+ {
+ gtia.h.grafp2 = 0;
+ gtia.h.usedp &= ~0x40;
+ }
+ else
+ {
+ gtia.h.grafp2 = gtia.w.grafp2[gtia.h.vdelay_p2];
+ gtia.h.usedp |= 0x40;
+ }
+}
+
+static void recalc_p3(void)
+{
+ if (
+#if CHECK_GRACTL
+ (gtia.w.gractl & GTIA_PLAYER) == 0 ||
+#endif
+ gtia.w.grafp3[gtia.h.vdelay_p3] == 0 || gtia.w.hposp3 >= 224 )
+ {
+ gtia.h.grafp3 = 0;
+ gtia.h.usedp &= ~0x80;
+ }
+ else
+ {
+ gtia.h.grafp3 = gtia.w.grafp3[gtia.h.vdelay_p3];
+ gtia.h.usedp |= 0x80;
+ }
+}
+
+static void recalc_m0(void)
+{
+ if (
+#if CHECK_GRACTL
+ (gtia.w.gractl & GTIA_MISSILE) == 0 ||
+#endif
+ (gtia.w.grafm[gtia.h.vdelay_m0] & 0x03) == 0 || gtia.w.hposm0 >= 224 )
+ {
+ gtia.h.grafm0 = 0;
+ gtia.h.usedm0 = 0;
+ }
+ else
+ {
+ gtia.h.grafm0 = (gtia.w.grafm[gtia.h.vdelay_m0] << 6) & 0xc0;
+ gtia.h.usedm0 = (gtia.w.prior & 0x10) ? 0x08 : 0x10;
+ }
+}
+
+static void recalc_m1(void)
+{
+ if (
+#if CHECK_GRACTL
+ (gtia.w.gractl & GTIA_MISSILE) == 0 ||
+#endif
+ (gtia.w.grafm[gtia.h.vdelay_m1] & 0x0c) == 0 || gtia.w.hposm1 >= 224 )
+ {
+ gtia.h.grafm1 = 0;
+ gtia.h.usedm1 = 0;
+ }
+ else
+ {
+ gtia.h.grafm1 = (gtia.w.grafm[gtia.h.vdelay_m1] << 4) & 0xc0;
+ gtia.h.usedm1 = (gtia.w.prior & 0x10) ? 0x08 : 0x20;
+ }
+}
+
+static void recalc_m2(void)
+{
+ if (
+#if CHECK_GRACTL
+ (gtia.w.gractl & GTIA_MISSILE) == 0 ||
+#endif
+ (gtia.w.grafm[gtia.h.vdelay_m2] & 0x30) == 0 || gtia.w.hposm2 >= 224 )
+ {
+ gtia.h.grafm2 = 0;
+ gtia.h.usedm2 = 0;
+ }
+ else
+ {
+ gtia.h.grafm2 = (gtia.w.grafm[gtia.h.vdelay_m2] << 2) & 0xc0;
+ gtia.h.usedm2 = (gtia.w.prior & 0x10) ? 0x08 : 0x40;
+ }
+}
+
+static void recalc_m3(void)
+{
+ if (
+#if CHECK_GRACTL
+ (gtia.w.gractl & GTIA_MISSILE) == 0 ||
+#endif
+ (gtia.w.grafm[gtia.h.vdelay_m3] & 0xc0) == 0 || gtia.w.hposm3 >= 224)
+ {
+ gtia.h.grafm3 = 0;
+ gtia.h.usedm3 = 0;
+ }
+ else
+ {
+ gtia.h.grafm3 = (gtia.w.grafm[gtia.h.vdelay_m3] << 0) & 0xc0;
+ gtia.h.usedm3 = (gtia.w.prior & 0x10) ? 0x08 : 0x80;
+ }
+}
+
+
+
+WRITE8_HANDLER( atari_gtia_w )
+{
+ /* used for mixing hue/lum of different colors */
+ static UINT8 lumpm0=0,lumpm1=0,lumpm2=0,lumpm3=0,lumpm4=0;
+ static UINT8 lumpf1=0,lumpf2=0,lumbk= 0;
+ static UINT8 huepm0=0,huepm1=0,huepm2=0,huepm3=0,huepm4=0;
+ static UINT8 huepf1=0,huepf2=0,huebk= 0;
+
+ switch (offset & 31)
+ {
+ case 0:
+ gtia.w.hposp0 = data;
+ recalc_p0();
+ break;
+ case 1:
+ gtia.w.hposp1 = data;
+ recalc_p1();
+ break;
+ case 2:
+ gtia.w.hposp2 = data;
+ recalc_p2();
+ break;
+ case 3:
+ gtia.w.hposp3 = data;
+ recalc_p3();
+ break;
+
+ case 4:
+ gtia.w.hposm0 = data;
+ recalc_m0();
+ break;
+ case 5:
+ gtia.w.hposm1 = data;
+ recalc_m1();
+ break;
+ case 6:
+ gtia.w.hposm2 = data;
+ recalc_m2();
+ break;
+ case 7:
+ gtia.w.hposm3 = data;
+ recalc_m3();
+ break;
+
+ case 8:
+ data &= 3;
+ gtia.w.sizep0 = data;
+ recalc_p0();
+ break;
+ case 9:
+ data &= 3;
+ gtia.w.sizep1 = data;
+ recalc_p1();
+ break;
+ case 10:
+ data &= 3;
+ gtia.w.sizep2 = data;
+ recalc_p2();
+ break;
+ case 11:
+ data &= 3;
+ gtia.w.sizep3 = data;
+ recalc_p3();
+ break;
+
+ case 12:
+ data &= 3;
+ gtia.w.sizem = data;
+ recalc_m0();
+ recalc_m1();
+ recalc_m2();
+ recalc_m3();
+ break;
+
+ case 13:
+ gtia.w.grafp0[0] = data;
+ recalc_p0();
+ break;
+ case 14:
+ gtia.w.grafp1[0] = data;
+ recalc_p1();
+ break;
+ case 15:
+ gtia.w.grafp2[0] = data;
+ recalc_p2();
+ break;
+ case 16:
+ gtia.w.grafp3[0] = data;
+ recalc_p3();
+ break;
+
+ case 17:
+ gtia.w.grafm[0] = data;
+ recalc_m0();
+ recalc_m1();
+ recalc_m2();
+ recalc_m3();
+ break;
+
+ case 18: /* color for player/missile #0 */
+ if (data == gtia.w.colpm0)
+ break;
+ gtia.w.colpm0 = data;
+ if (VERBOSE)
+ logerror("atari colpm0 $%02x\n", data);
+
+ SETCOL_B(PL0,data); /* set player 0 color */
+ SETCOL_B(MI0,data); /* set missile 0 color */
+ SETCOL_B(GT2,data); /* set GTIA mode 2 color 0 */
+ SETCOL_B(P000,data); /* set player 0 both pixels 0 */
+ SETCOL_L(P001,data); /* set player 0 left pixel 0 */
+ SETCOL_R(P010,data); /* set player 0 right pixel 0 */
+ SPLIT_HUE_LUM(data,huepm0,lumpm0);
+ data = huepm0 | lumpf1;
+ SETCOL_R(P001,data); /* set player 0 right pixel 1 */
+ SETCOL_L(P010,data); /* set player 0 left pixel 1 */
+ SETCOL_B(P011,data); /* set player 0 both pixels 1 */
+ break;
+
+ case 19: /* color for player/missile #1 */
+ if (data == gtia.w.colpm1)
+ break;
+ gtia.w.colpm1 = data;
+ if (VERBOSE)
+ logerror("atari colpm1 $%02x\n", data);
+
+ SETCOL_B(PL1,data); /* set player color 1 */
+ SETCOL_B(MI1,data); /* set missile color 1 */
+ SETCOL_B(GT2+1,data); /* set GTIA mode 2 color 1 */
+ SETCOL_B(P100,data); /* set player 1 both pixels 0 */
+ SETCOL_L(P101,data); /* set player 1 left pixel 0 */
+ SETCOL_R(P110,data); /* set player 1 right pixel 0 */
+ SPLIT_HUE_LUM(data,huepm1,lumpm1);
+ data = huepm1 | lumpf1;
+ SETCOL_R(P101,data); /* set player 1 right pixel 1 */
+ SETCOL_L(P110,data); /* set player 1 left pixel 1 */
+ SETCOL_B(P111,data); /* set player 1 both pixels 1 */
+ break;
+
+ case 20: /* color for player/missile #2 */
+ if (data == gtia.w.colpm2)
+ break;
+ gtia.w.colpm2 = data;
+ if (VERBOSE)
+ logerror("atari colpm2 $%02x\n", data);
+
+ SETCOL_B(PL2,data); /* set player 2 color */
+ SETCOL_B(MI2,data); /* set missile 2 color */
+ SETCOL_B(GT2+2,data); /* set GTIA mode 2 color 2 */
+ SETCOL_B(P200,data); /* set player 2 both pixels 0 */
+ SETCOL_L(P201,data); /* set player 2 left pixel 0 */
+ SETCOL_R(P210,data); /* set player 2 right pixel 0 */
+ SPLIT_HUE_LUM(data,huepm2,lumpm2);
+ data = huepm2 | lumpf1;
+ SETCOL_R(P201,data); /* set player 2 right pixel 1 */
+ SETCOL_L(P210,data); /* set player 2 left pixel 1 */
+ SETCOL_B(P211,data); /* set player 2 both pixels 1 */
+ break;
+
+ case 21: /* color for player/missile #3 */
+ if (data == gtia.w.colpm3)
+ break;
+ gtia.w.colpm3 = data;
+ if (VERBOSE)
+ logerror("atari colpm3 $%02x\n", data);
+
+ SETCOL_B(PL3,data); /* set player 3 color */
+ SETCOL_B(MI3,data); /* set missile 3 color */
+ SETCOL_B(GT2+3,data); /* set GTIA mode 2 color 3 */
+ SETCOL_B(P300,data); /* set player 3 both pixels 0 */
+ SETCOL_L(P301,data); /* set player 3 left pixel 0 */
+ SETCOL_R(P310,data); /* set player 3 right pixel 0 */
+ SPLIT_HUE_LUM(data,huepm3,lumpm3);
+ data = huepm3 | lumpf1;
+ SETCOL_R(P301,data); /* set player 3 right pixel 1 */
+ SETCOL_L(P310,data); /* set player 3 left pixel 1 */
+ SETCOL_B(P311,data); /* set player 3 both pixels 1 */
+ break;
+
+ case 22: /* playfield color #0 */
+ if (data == gtia.w.colpf0)
+ break;
+ gtia.w.colpf0 = data;
+ if (VERBOSE)
+ logerror("atari colpf0 $%02x\n", data);
+
+ SETCOL_B(PF0,data); /* set playfield 0 color */
+ SETCOL_B(GT2+4,data); /* set GTIA mode 2 color 4 */
+ break;
+
+ case 23: /* playfield color #1 */
+ if (data == gtia.w.colpf1)
+ break;
+ gtia.w.colpf1 = data;
+ if (VERBOSE)
+ logerror("atari colpf1 $%02x\n", data);
+
+ SETCOL_B(PF1,data); /* set playfield 1 color */
+ SETCOL_B(GT2+5,data); /* set GTIA mode 2 color 5 */
+ SPLIT_HUE_LUM(data,huepf1,lumpf1);
+ data = huepf2 | lumpf1;
+ SETCOL_R(T01,data); /* set text mode right pixel 1 */
+ SETCOL_L(T10,data); /* set text mode left pixel 1 */
+ SETCOL_B(T11,data); /* set text mode both pixels 1 */
+ data = huebk | lumpf1;
+ SETCOL_R(G01,data); /* set graphics mode right pixel 1 */
+ SETCOL_L(G10,data); /* set graphics mode left pixel 1 */
+ SETCOL_B(G11,data); /* set graphics mode both pixels 1 */
+ data = huepm0 | lumpf1;
+ SETCOL_R(P001,data); /* set player 0 right pixel 1 */
+ SETCOL_L(P010,data); /* set player 0 left pixel 1 */
+ SETCOL_B(P011,data); /* set player 0 both pixels 1 */
+ data = huepm1 | lumpf1;
+ SETCOL_R(P101,data); /* set player 1 right pixel 1 */
+ SETCOL_L(P110,data); /* set player 1 left pixel 1 */
+ SETCOL_B(P111,data); /* set player 1 both pixels 1 */
+ data = huepm2 | lumpf1;
+ SETCOL_R(P201,data); /* set player 2 right pixel 1 */
+ SETCOL_L(P210,data); /* set player 2 left pixel 1 */
+ SETCOL_B(P211,data); /* set player 2 both pixels 1 */
+ data = huepm3 | lumpf1;
+ SETCOL_R(P301,data); /* set player 3 right pixel 1 */
+ SETCOL_L(P310,data); /* set player 3 left pixel 1 */
+ SETCOL_B(P311,data); /* set player 3 both pixels 1 */
+ data = huepm4 | lumpf1;
+ SETCOL_R(P401,data); /* set missiles right pixel 1 */
+ SETCOL_L(P410,data); /* set missiles left pixel 1 */
+ SETCOL_B(P411,data); /* set missiles both pixels 1 */
+ break;
+
+ case 24: /* playfield color #2 */
+ if (data == gtia.w.colpf2)
+ break;
+ gtia.w.colpf2 = data;
+ if (VERBOSE)
+ logerror("atari colpf2 $%02x\n", data);
+
+ SETCOL_B(PF2,data); /* set playfield color 2 */
+ SETCOL_B(GT2+6,data); /* set GTIA mode 2 color 6 */
+ SETCOL_B(T00,data); /* set text mode both pixels 0 */
+ SETCOL_L(T01,data); /* set text mode left pixel 0 */
+ SETCOL_R(T10,data); /* set text mode right pixel 0 */
+ SPLIT_HUE_LUM(data,huepf2,lumpf2);
+ data = huepf2 | lumpf1;
+ SETCOL_R(T01,data); /* set text mode right pixel 1 */
+ SETCOL_L(T10,data); /* set text mode left pixel 1 */
+ SETCOL_B(T11,data); /* set text mode both pixels 1 */
+ break;
+
+ case 25: /* playfield color #3 */
+ if (data == gtia.w.colpf3)
+ break;
+ gtia.w.colpf3 = data;
+ if (VERBOSE)
+ logerror("atari colpf3 $%02x\n", data);
+
+ SETCOL_B(PF3,data); /* set playfield color 3 */
+ SETCOL_B(GT2+7,data); /* set GTIA mode 2 color 7 */
+ SETCOL_B(P400,data); /* set p/m xor mode both pixels 0 */
+ SETCOL_L(P401,data); /* set p/m xor mode left pixel 0 */
+ SETCOL_R(P410,data); /* set p/m xor mode right pixel 0 */
+ SPLIT_HUE_LUM(data,huepm4,lumpm4);
+ data = huepm4 | lumpf1;
+ SETCOL_R(P401,data); /* set p/m xor mode right pixel 1 */
+ SETCOL_L(P410,data); /* set p/m xor mode left pixel 1 */
+ SETCOL_B(P411,data); /* set p/m xor mode both pixels 1 */
+ break;
+
+ case 26: /* playfield background */
+ if (data == gtia.w.colbk)
+ break;
+ gtia.w.colbk = data;
+ if (VERBOSE)
+ logerror("atari colbk $%02x\n", data);
+
+ SETCOL_B(PBK,data); /* set background color */
+ SETCOL_B(GT2+8,data); /* set GTIA mode 2 color 8 */
+ SETCOL_B(GT2+9,data); /* set GTIA mode 2 color 9 */
+ SETCOL_B(GT2+10,data); /* set GTIA mode 2 color 10 */
+ SETCOL_B(GT2+11,data); /* set GTIA mode 2 color 11 */
+ SETCOL_B(GT2+12,data); /* set GTIA mode 2 color 12 */
+ SETCOL_B(GT2+13,data); /* set GTIA mode 2 color 13 */
+ SETCOL_B(GT2+14,data); /* set GTIA mode 2 color 14 */
+ SETCOL_B(GT2+15,data); /* set GTIA mode 2 color 15 */
+ SETCOL_B(G00,data); /* set 2 color graphics both pixels 0 */
+ SETCOL_L(G01,data); /* set 2 color graphics left pixel 0 */
+ SETCOL_R(G10,data); /* set 2 color graphics right pixel 0 */
+ SPLIT_HUE_LUM(data,huebk,lumbk);
+ data = huebk | lumpf1;
+ SETCOL_R(G01,data); /* set 2 color graphics right pixel 1 */
+ SETCOL_L(G10,data); /* set 2 color graphics left pixel 1 */
+ SETCOL_B(G11,data); /* set 2 color graphics both pixels 1 */
+ SETCOL_B(GT1+ 0,(data&HUE)+(0x00&LUM)); /* set GTIA mode 1 HUE + LUM 0..15 */
+ SETCOL_B(GT1+ 1,(data&HUE)+(0x11&LUM));
+ SETCOL_B(GT1+ 2,(data&HUE)+(0x22&LUM));
+ SETCOL_B(GT1+ 3,(data&HUE)+(0x33&LUM));
+ SETCOL_B(GT1+ 4,(data&HUE)+(0x44&LUM));
+ SETCOL_B(GT1+ 5,(data&HUE)+(0x55&LUM));
+ SETCOL_B(GT1+ 6,(data&HUE)+(0x66&LUM));
+ SETCOL_B(GT1+ 7,(data&HUE)+(0x77&LUM));
+ SETCOL_B(GT1+ 8,(data&HUE)+(0x88&LUM));
+ SETCOL_B(GT1+ 9,(data&HUE)+(0x99&LUM));
+ SETCOL_B(GT1+10,(data&HUE)+(0xaa&LUM));
+ SETCOL_B(GT1+11,(data&HUE)+(0xbb&LUM));
+ SETCOL_B(GT1+12,(data&HUE)+(0xcc&LUM));
+ SETCOL_B(GT1+13,(data&HUE)+(0xdd&LUM));
+ SETCOL_B(GT1+14,(data&HUE)+(0xee&LUM));
+ SETCOL_B(GT1+15,(data&HUE)+(0xff&LUM));
+ SETCOL_B(GT3+ 0,(data&LUM)+(0x00&HUE)); /* set GTIA mode 3 LUM + HUE 0..15 */
+ SETCOL_B(GT3+ 1,(data&LUM)+(0x11&HUE));
+ SETCOL_B(GT3+ 2,(data&LUM)+(0x22&HUE));
+ SETCOL_B(GT3+ 3,(data&LUM)+(0x33&HUE));
+ SETCOL_B(GT3+ 4,(data&LUM)+(0x44&HUE));
+ SETCOL_B(GT3+ 5,(data&LUM)+(0x55&HUE));
+ SETCOL_B(GT3+ 6,(data&LUM)+(0x66&HUE));
+ SETCOL_B(GT3+ 7,(data&LUM)+(0x77&HUE));
+ SETCOL_B(GT3+ 8,(data&LUM)+(0x88&HUE));
+ SETCOL_B(GT3+ 9,(data&LUM)+(0x99&HUE));
+ SETCOL_B(GT3+10,(data&LUM)+(0xaa&HUE));
+ SETCOL_B(GT3+11,(data&LUM)+(0xbb&HUE));
+ SETCOL_B(GT3+12,(data&LUM)+(0xcc&HUE));
+ SETCOL_B(GT3+13,(data&LUM)+(0xdd&HUE));
+ SETCOL_B(GT3+14,(data&LUM)+(0xee&HUE));
+ SETCOL_B(GT3+15,(data&LUM)+(0xff&HUE));
+ break;
+
+ case 27:
+ gtia.w.prior = data;
+ recalc_m0();
+ recalc_m1();
+ recalc_m2();
+ recalc_m3();
+ break;
+
+ case 28: /* delay until vertical retrace */
+ gtia.w.vdelay = data;
+ gtia.h.vdelay_m0 = (data >> 0) & 1;
+ gtia.h.vdelay_m1 = (data >> 1) & 1;
+ gtia.h.vdelay_m2 = (data >> 2) & 1;
+ gtia.h.vdelay_m3 = (data >> 3) & 1;
+ gtia.h.vdelay_p0 = (data >> 4) & 1;
+ gtia.h.vdelay_p1 = (data >> 5) & 1;
+ gtia.h.vdelay_p2 = (data >> 6) & 1;
+ gtia.h.vdelay_p3 = (data >> 7) & 1;
+ break;
+
+ case 29:
+ gtia.w.gractl = data;
+ recalc_p0();
+ recalc_p1();
+ recalc_p2();
+ recalc_p3();
+ recalc_m0();
+ recalc_m1();
+ recalc_m2();
+ recalc_m3();
+ break;
+
+ case 30: /* clear collisions */
+ gtia.r.m0pf = gtia.r.m1pf = gtia.r.m2pf = gtia.r.m3pf =
+ gtia.r.p0pf = gtia.r.p1pf = gtia.r.p2pf = gtia.r.p3pf =
+ gtia.r.m0pl = gtia.r.m1pl = gtia.r.m2pl = gtia.r.m3pl =
+ gtia.r.p0pl = gtia.r.p1pl = gtia.r.p2pl = gtia.r.p3pl = 0;
+ gtia.w.hitclr = data;
+ break;
+
+ case 31: /* write console (speaker) */
+ if (data == gtia.w.cons)
+ break;
+ gtia.w.cons = data;
+ if (gtia.intf.console_write)
+ gtia.intf.console_write(gtia.w.cons);
+ break;
+ }
+}
+
+
+
+static void gtia_state_postload(void)
+{
+ recalc_p0();
+ recalc_p1();
+ recalc_p2();
+ recalc_p3();
+ recalc_m0();
+ recalc_m1();
+ recalc_m2();
+ recalc_m3();
+}
+
+
+
+static const UINT8 pf_collision[256] = {
+ 0,1,2,0,4,0,0,0,8,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
+
+static const int pf_prioindex[256] = {
+/* PBK PF0 PF1 PF2 PF3 */
+/* */ 0x000,0x100,0x100,0x000,0x200,0x000,0x000,0x000,0x200,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* */ 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* */ 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* */ 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* T00 */ 0x400,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* T01 */ 0x500,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* T10 */ 0x600,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* T11 */ 0x700,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* G00 */ 0x400,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* G01 */ 0x500,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* G10 */ 0x600,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* G11 */ 0x700,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* GT1 */ 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* GT2 */ 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* GT3 */ 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
+/* */ 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000
+};
+
+#define RENDER_PLAYER(player,color) \
+static void render_##player##_w1(UINT8 *dst) \
+{ \
+ if( gtia.h.graf##player & 0x80 ) \
+ dst[0] |= color; \
+ if( gtia.h.graf##player & 0x40 ) \
+ dst[1] |= color; \
+ if( gtia.h.graf##player & 0x20 ) \
+ dst[2] |= color; \
+ if( gtia.h.graf##player & 0x10 ) \
+ dst[3] |= color; \
+ if( gtia.h.graf##player & 0x08 ) \
+ dst[4] |= color; \
+ if( gtia.h.graf##player & 0x04 ) \
+ dst[5] |= color; \
+ if( gtia.h.graf##player & 0x02 ) \
+ dst[6] |= color; \
+ if( gtia.h.graf##player & 0x01 ) \
+ dst[7] |= color; \
+} \
+static void render_##player##_w2(UINT8 *dst) \
+{ \
+ if( gtia.h.graf##player & 0x80 ) \
+ { \
+ dst[ 0] |= color; \
+ dst[ 1] |= color; \
+ } \
+ if( gtia.h.graf##player & 0x40 ) \
+ { \
+ dst[ 2] |= color; \
+ dst[ 3] |= color; \
+ } \
+ if( gtia.h.graf##player & 0x20 ) \
+ { \
+ dst[ 4] |= color; \
+ dst[ 5] |= color; \
+ } \
+ if( gtia.h.graf##player & 0x10 ) \
+ { \
+ dst[ 6] |= color; \
+ dst[ 7] |= color; \
+ } \
+ if( gtia.h.graf##player & 0x08 ) \
+ { \
+ dst[ 8] |= color; \
+ dst[ 9] |= color; \
+ } \
+ if( gtia.h.graf##player & 0x04 ) \
+ { \
+ dst[10] |= color; \
+ dst[11] |= color; \
+ } \
+ if( gtia.h.graf##player & 0x02 ) \
+ { \
+ dst[12] |= color; \
+ dst[13] |= color; \
+ } \
+ if( gtia.h.graf##player & 0x01 ) \
+ { \
+ dst[14] |= color; \
+ dst[15] |= color; \
+ } \
+} \
+static void render_##player##_w4(UINT8 *dst) \
+{ \
+ if( gtia.h.graf##player & 0x80 ) \
+ { \
+ dst[ 0] |= color; \
+ dst[ 1] |= color; \
+ dst[ 2] |= color; \
+ dst[ 3] |= color; \
+ } \
+ if( gtia.h.graf##player & 0x40 ) \
+ { \
+ dst[ 4] |= color; \
+ dst[ 5] |= color; \
+ dst[ 6] |= color; \
+ dst[ 7] |= color; \
+ } \
+ if( gtia.h.graf##player & 0x20 ) \
+ { \
+ dst[ 8] |= color; \
+ dst[ 9] |= color; \
+ dst[10] |= color; \
+ dst[11] |= color; \
+ } \
+ if( gtia.h.graf##player & 0x10 ) \
+ { \
+ dst[12] |= color; \
+ dst[13] |= color; \
+ dst[14] |= color; \
+ dst[15] |= color; \
+ } \
+ if( gtia.h.graf##player & 0x08 ) \
+ { \
+ dst[16] |= color; \
+ dst[17] |= color; \
+ dst[18] |= color; \
+ dst[19] |= color; \
+ } \
+ if( gtia.h.graf##player & 0x04 ) \
+ { \
+ dst[20] |= color; \
+ dst[21] |= color; \
+ dst[22] |= color; \
+ dst[23] |= color; \
+ } \
+ if( gtia.h.graf##player & 0x02 ) \
+ { \
+ dst[24] |= color; \
+ dst[25] |= color; \
+ dst[26] |= color; \
+ dst[27] |= color; \
+ } \
+ if( gtia.h.graf##player & 0x01 ) \
+ { \
+ dst[28] |= color; \
+ dst[29] |= color; \
+ dst[30] |= color; \
+ dst[31] |= color; \
+ } \
+} \
+static void (*render_##player[4])(UINT8 *dst)={ \
+ render_##player##_w1, \
+ render_##player##_w2, \
+ render_##player##_w2, \
+ render_##player##_w4 \
+}
+
+#define RENDER_MISSILE(missile,color) \
+static void render_##missile##_w1(UINT8 *dst) \
+{ \
+ if( gtia.h.graf##missile & 0x80 ) \
+ dst[0] |= color; \
+ if( gtia.h.graf##missile & 0x40 ) \
+ dst[1] |= color; \
+} \
+static void render_##missile##_w2(UINT8 *dst) \
+{ \
+ if( gtia.h.graf##missile & 0x80 ) \
+ { \
+ dst[ 0] |= color; \
+ dst[ 1] |= color; \
+ } \
+ if( gtia.h.graf##missile & 0x40 ) \
+ { \
+ dst[ 2] |= color; \
+ dst[ 3] |= color; \
+ } \
+} \
+static void render_##missile##_w4(UINT8 *dst) \
+{ \
+ if( gtia.h.graf##missile & 0x80 ) \
+ { \
+ dst[ 0] |= color; \
+ dst[ 1] |= color; \
+ dst[ 2] |= color; \
+ dst[ 3] |= color; \
+ } \
+ if( gtia.h.graf##missile & 0x40 ) \
+ { \
+ dst[ 4] |= color; \
+ dst[ 5] |= color; \
+ dst[ 6] |= color; \
+ dst[ 7] |= color; \
+ } \
+} \
+static void (*render_##missile[4])(UINT8 *dst) = { \
+ render_##missile##_w1, \
+ render_##missile##_w2, \
+ render_##missile##_w2, \
+ render_##missile##_w4 \
+}
+
+RENDER_PLAYER(p0,P0);
+RENDER_PLAYER(p1,P1);
+RENDER_PLAYER(p2,P2);
+RENDER_PLAYER(p3,P3);
+RENDER_MISSILE(m0,M0);
+RENDER_MISSILE(m1,M1);
+RENDER_MISSILE(m2,M2);
+RENDER_MISSILE(m3,M3);
+
+
+void gtia_render(VIDEO *video)
+{
+ int x;
+ UINT8 *prio = antic.prio_table[gtia.w.prior & 0x3f];
+ UINT8 *src, *dst;
+
+ if( antic.scanline < VBL_END || antic.scanline >= 256 )
+ return;
+
+ if( gtia.h.grafp0 )
+ (*render_p0[gtia.w.sizep0])(&antic.pmbits[gtia.w.hposp0]);
+
+ if( gtia.h.grafp1 )
+ (*render_p1[gtia.w.sizep1])(&antic.pmbits[gtia.w.hposp1]);
+
+ if( gtia.h.grafp2 )
+ (*render_p2[gtia.w.sizep2])(&antic.pmbits[gtia.w.hposp2]);
+
+ if( gtia.h.grafp3 )
+ (*render_p3[gtia.w.sizep3])(&antic.pmbits[gtia.w.hposp3]);
+
+ if( gtia.h.grafm0 )
+ (*render_m0[gtia.w.sizem])(&antic.pmbits[gtia.w.hposm0]);
+
+ if( gtia.h.grafm1 )
+ (*render_m1[gtia.w.sizem])(&antic.pmbits[gtia.w.hposm1]);
+
+ if( gtia.h.grafm2 )
+ (*render_m2[gtia.w.sizem])(&antic.pmbits[gtia.w.hposm2]);
+
+ if( gtia.h.grafm3 )
+ (*render_m3[gtia.w.sizem])(&antic.pmbits[gtia.w.hposm3]);
+
+ src = antic.pmbits + PMOFFSET;
+ dst = antic.cclock + PMOFFSET - antic.hscrol_old;
+
+ for( x = 0; x < HWIDTH*4; x++, src++, dst++ )
+ {
+ UINT8 pm, pc, pf;
+ if( !*src )
+ continue;
+ /* get the player/missile combination bits and reset the buffer */
+ pm = *src;
+ *src = 0;
+ /* get the current playfield color */
+ pc = *dst;
+ pf = pf_collision[pc];
+ if (pm&P0) { gtia.r.p0pf |= pf; gtia.r.p0pl |= pm&( P1|P2|P3); }
+ if (pm&P1) { gtia.r.p1pf |= pf; gtia.r.p1pl |= pm&(P0| P2|P3); }
+ if (pm&P2) { gtia.r.p2pf |= pf; gtia.r.p2pl |= pm&(P0|P1| P3); }
+ if (pm&P3) { gtia.r.p3pf |= pf; gtia.r.p3pl |= pm&(P0|P1|P2 ); }
+ if (pm&M0) { gtia.r.m0pf |= pf; gtia.r.m0pl |= pm&(P0|P1|P2|P3); }
+ if (pm&M1) { gtia.r.m1pf |= pf; gtia.r.m1pl |= pm&(P0|P1|P2|P3); }
+ if (pm&M2) { gtia.r.m2pf |= pf; gtia.r.m2pl |= pm&(P0|P1|P2|P3); }
+ if (pm&M3) { gtia.r.m3pf |= pf; gtia.r.m3pl |= pm&(P0|P1|P2|P3); }
+ /* color with higher priority? change playfield */
+ pc = prio[pf_prioindex[pc] | pm];
+ if (pc) *dst = pc;
+ }
+ /* copy player/missile graphics in case of vdelay */
+ gtia.w.grafp0[1] = gtia.w.grafp0[0];
+ gtia.w.grafp1[1] = gtia.w.grafp1[0];
+ gtia.w.grafp2[1] = gtia.w.grafp2[0];
+ gtia.w.grafp3[1] = gtia.w.grafp3[0];
+ gtia.w.grafm[1] = gtia.w.grafm[0];
+}
+
+/************* ANTIC mode 0F : GTIA mode 1 ********************
+ * graphics mode 8x1:16 (32/40/48 byte per line)
+ ***************************************************************/
+#define GTIA1(s) COPY4(dst, antic.pf_gtia1[video->data[s]])
+
+void gtia_mode_1_32(VIDEO *video)
+{
+ PREPARE_GFXG1(32);
+ REP32(GTIA1);
+ POST_GFX(32);
+}
+void gtia_mode_1_40(VIDEO *video)
+{
+ PREPARE_GFXG1(40);
+ REP40(GTIA1);
+ POST_GFX(40);
+}
+void gtia_mode_1_48(VIDEO *video)
+{
+ PREPARE_GFXG1(48);
+ REP48(GTIA1);
+ POST_GFX(48);
+}
+
+/************* ANTIC mode 0F : GTIA mode 2 ********************
+ * graphics mode 8x1:16 (32/40/48 byte per line)
+ ***************************************************************/
+#define GTIA2(s) COPY4(dst, antic.pf_gtia2[video->data[s]])
+
+void gtia_mode_2_32(VIDEO *video)
+{
+ PREPARE_GFXG2(32);
+ REP32(GTIA2);
+ POST_GFX(32);
+}
+void gtia_mode_2_40(VIDEO *video)
+{
+ PREPARE_GFXG2(40);
+ REP40(GTIA2);
+ POST_GFX(40);
+}
+void gtia_mode_2_48(VIDEO *video)
+{
+ PREPARE_GFXG2(48);
+ REP48(GTIA2);
+ POST_GFX(48);
+}
+
+/************* ANTIC mode 0F : GTIA mode 3 ********************
+ * graphics mode 8x1:16 (32/40/48 byte per line)
+ ***************************************************************/
+#define GTIA3(s) COPY4(dst, antic.pf_gtia3[video->data[s]])
+
+void gtia_mode_3_32(VIDEO *video)
+{
+ PREPARE_GFXG3(32);
+ REP32(GTIA3);
+ POST_GFX(32);
+}
+void gtia_mode_3_40(VIDEO *video)
+{
+ PREPARE_GFXG3(40);
+ REP40(GTIA3);
+ POST_GFX(40);
+}
+void gtia_mode_3_48(VIDEO *video)
+{
+ PREPARE_GFXG3(48);
+ REP48(GTIA3);
+ POST_GFX(48);
+}
+
diff --git a/src/mame/video/gtia.h b/src/mame/video/gtia.h
new file mode 100644
index 00000000000..8b4b58611b5
--- /dev/null
+++ b/src/mame/video/gtia.h
@@ -0,0 +1,156 @@
+/***************************************************************************
+
+ Atari 400/800
+
+ GTIA graphics television interface adapter
+
+ Juergen Buchmueller, June 1998
+
+***************************************************************************/
+
+#ifndef __GTIA_H__
+#define __GTIA_H__
+
+#include "includes/atari.h"
+
+typedef struct _gtia_interface gtia_interface;
+struct _gtia_interface
+{
+ UINT8 (*console_read)(void);
+ void (*console_write)(UINT8 data);
+};
+
+
+
+
+/* reading registers */
+typedef struct _gtia_readregs gtia_readregs;
+struct _gtia_readregs
+{
+ UINT8 m0pf; /* d000 missile 0 playfield collisions */
+ UINT8 m1pf; /* d001 missile 1 playfield collisions */
+ UINT8 m2pf; /* d002 missile 2 playfield collisions */
+ UINT8 m3pf; /* d003 missile 3 playfield collisions */
+ UINT8 p0pf; /* d004 player 0 playfield collisions */
+ UINT8 p1pf; /* d005 player 1 playfield collisions */
+ UINT8 p2pf; /* d006 player 2 playfield collisions */
+ UINT8 p3pf; /* d007 player 3 playfield collisions */
+ UINT8 m0pl; /* d008 missile 0 player collisions */
+ UINT8 m1pl; /* d009 missile 1 player collisions */
+ UINT8 m2pl; /* d00a missile 2 player collisions */
+ UINT8 m3pl; /* d00b missile 3 player collisions */
+ UINT8 p0pl; /* d00c player 0 player collisions */
+ UINT8 p1pl; /* d00d player 1 player collisions */
+ UINT8 p2pl; /* d00e player 2 player collisions */
+ UINT8 p3pl; /* d00f player 3 player collisions */
+ UINT8 but[4]; /* d010-d013 button stick 0-3 */
+ UINT8 pal; /* d014 PAL/NTSC config (D3,2,1 0=PAL, 1=NTSC */
+ UINT8 gtia15; /* d015 nothing */
+ UINT8 gtia16; /* d016 nothing */
+ UINT8 gtia17; /* d017 nothing */
+ UINT8 gtia18; /* d018 nothing */
+ UINT8 gtia19; /* d019 nothing */
+ UINT8 gtia1a; /* d01a nothing */
+ UINT8 gtia1b; /* d01b nothing */
+ UINT8 gtia1c; /* d01c nothing */
+ UINT8 gtia1d; /* d01d nothing */
+ UINT8 gtia1e; /* d01e nothing */
+ UINT8 cons; /* d01f console keys */
+};
+
+/* writing registers */
+typedef struct _gtia_writeregs gtia_writeregs;
+struct _gtia_writeregs
+{
+ UINT8 hposp0; /* d000 player 0 horz position */
+ UINT8 hposp1; /* d001 player 1 horz position */
+ UINT8 hposp2; /* d002 player 2 horz position */
+ UINT8 hposp3; /* d003 player 3 horz position */
+ UINT8 hposm0; /* d004 missile 0 horz position */
+ UINT8 hposm1; /* d005 missile 1 horz position */
+ UINT8 hposm2; /* d006 missile 2 horz position */
+ UINT8 hposm3; /* d007 missile 3 horz position */
+ UINT8 sizep0; /* d008 size player 0 */
+ UINT8 sizep1; /* d009 size player 1 */
+ UINT8 sizep2; /* d00a size player 2 */
+ UINT8 sizep3; /* d00b size player 3 */
+ UINT8 sizem; /* d00c size missiles */
+ UINT8 grafp0[2]; /* d00d graphics data for player 0 */
+ UINT8 grafp1[2]; /* d00e graphics data for player 1 */
+ UINT8 grafp2[2]; /* d00f graphics data for player 2 */
+ UINT8 grafp3[2]; /* d010 graphics data for player 3 */
+ UINT8 grafm[2]; /* d011 graphics data for missiles */
+ UINT8 colpm0; /* d012 color for player/missile 0 */
+ UINT8 colpm1; /* d013 color for player/missile 1 */
+ UINT8 colpm2; /* d014 color for player/missile 2 */
+ UINT8 colpm3; /* d015 color for player/missile 3 */
+ UINT8 colpf0; /* d016 playfield color 0 */
+ UINT8 colpf1; /* d017 playfield color 1 */
+ UINT8 colpf2; /* d018 playfield color 2 */
+ UINT8 colpf3; /* d019 playfield color 3 */
+ UINT8 colbk; /* d01a background playfield */
+ UINT8 prior; /* d01b priority select */
+ UINT8 vdelay; /* d01c delay until vertical retrace */
+ UINT8 gractl; /* d01d graphics control */
+ UINT8 hitclr; /* d01e clear collisions */
+ UINT8 cons; /* d01f write console (speaker) */
+};
+
+/* helpers */
+typedef struct _gtia_helpervars gtia_helpervars;
+struct _gtia_helpervars
+{
+ UINT8 grafp0; /* optimized graphics data player 0 */
+ UINT8 grafp1; /* optimized graphics data player 1 */
+ UINT8 grafp2; /* optimized graphics data player 2 */
+ UINT8 grafp3; /* optimized graphics data player 3 */
+ UINT8 grafm0; /* optimized graphics data missile 0 */
+ UINT8 grafm1; /* optimized graphics data missile 1 */
+ UINT8 grafm2; /* optimized graphics data missile 2 */
+ UINT8 grafm3; /* optimized graphics data missile 3 */
+ UINT32 hitclr_frames;/* frames gone since last hitclr */
+ UINT8 sizem; /* optimized size missiles */
+ UINT8 usedp; /* mask for used player colors */
+ UINT8 usedm0; /* mask for used missile 0 color */
+ UINT8 usedm1; /* mask for used missile 1 color */
+ UINT8 usedm2; /* mask for used missile 2 color */
+ UINT8 usedm3; /* mask for used missile 3 color */
+ UINT8 vdelay_m0; /* vertical delay for missile 0 */
+ UINT8 vdelay_m1; /* vertical delay for missile 1 */
+ UINT8 vdelay_m2; /* vertical delay for missile 2 */
+ UINT8 vdelay_m3; /* vertical delay for missile 3 */
+ UINT8 vdelay_p0; /* vertical delay for player 0 */
+ UINT8 vdelay_p1; /* vertical delay for player 1 */
+ UINT8 vdelay_p2; /* vertical delay for player 2 */
+ UINT8 vdelay_p3; /* vertical delay for player 3 */
+};
+
+typedef struct _gtia_struct gtia_struct;
+struct _gtia_struct
+{
+ gtia_interface intf;
+ gtia_readregs r; /* read registers */
+ gtia_writeregs w; /* write registers */
+ gtia_helpervars h; /* helper variables */
+};
+
+
+
+extern gtia_struct gtia;
+
+void gtia_init(const gtia_interface *intf);
+READ8_HANDLER( atari_gtia_r );
+WRITE8_HANDLER( atari_gtia_w );
+
+void gtia_mode_1_32(VIDEO *video);
+void gtia_mode_1_40(VIDEO *video);
+void gtia_mode_1_48(VIDEO *video);
+void gtia_mode_2_32(VIDEO *video);
+void gtia_mode_2_40(VIDEO *video);
+void gtia_mode_2_48(VIDEO *video);
+void gtia_mode_3_32(VIDEO *video);
+void gtia_mode_3_40(VIDEO *video);
+void gtia_mode_3_48(VIDEO *video);
+void gtia_render(VIDEO *video);
+
+#endif /* __GTIA_H__ */
diff --git a/src/mame/video/gticlub.c b/src/mame/video/gticlub.c
new file mode 100644
index 00000000000..4a03ccaa576
--- /dev/null
+++ b/src/mame/video/gticlub.c
@@ -0,0 +1,1033 @@
+#include "driver.h"
+#include "cpu/sharc/sharc.h"
+#include "machine/konppc.h"
+#include "video/poly.h"
+#include "gticlub.h"
+
+
+typedef struct _poly_extra_data poly_extra_data;
+struct _poly_extra_data
+{
+ UINT32 color;
+ int texture_x, texture_y;
+ int texture_page;
+ int texture_palette;
+ int texture_mirror_x;
+ int texture_mirror_y;
+};
+
+
+// defined in drivers/nwk-tr.c
+int K001604_vh_start(running_machine *machine, int chip);
+void K001604_tile_update(running_machine *machine, int chip);
+void K001604_draw_front_layer(int chip, mame_bitmap *bitmap, const rectangle *cliprect);
+void K001604_draw_back_layer(int chip, mame_bitmap *bitmap, const rectangle *cliprect);
+
+extern UINT8 gticlub_led_reg0;
+extern UINT8 gticlub_led_reg1;
+
+static poly_manager *poly;
+
+
+
+/*****************************************************************************/
+/* Konami K001006 Custom 3D Texel Renderer chip (KS10081) */
+
+#define MAX_K001006_CHIPS 2
+
+static UINT16 K001006_pal_ram[MAX_K001006_CHIPS][0x800];
+static UINT16 K001006_unknown_ram[MAX_K001006_CHIPS][0x1000];
+static UINT32 K001006_addr[MAX_K001006_CHIPS] = { 0, 0 };
+static int K001006_device_sel[MAX_K001006_CHIPS] = { 0, 0 };
+
+static UINT32 K001006_palette[MAX_K001006_CHIPS][0x800];
+
+static UINT32 K001006_r(int chip, int offset, UINT32 mem_mask)
+{
+ if (offset == 1)
+ {
+ switch (K001006_device_sel[chip])
+ {
+ case 0x0b: // CG Board ROM read
+ {
+ UINT16 *rom = (UINT16*)memory_region(REGION_GFX1);
+ return rom[K001006_addr[chip] / 2] << 16;
+ }
+ case 0x0d: // Palette RAM read
+ {
+ UINT32 addr = K001006_addr[chip];
+
+ K001006_addr[chip] += 2;
+ return K001006_pal_ram[chip][addr>>1];
+ }
+ case 0x0f: // Unknown RAM read
+ {
+ return K001006_unknown_ram[chip][K001006_addr[chip]++];
+ }
+ default:
+ {
+ fatalerror("K001006_r chip %d, unknown device %02X", chip, K001006_device_sel[chip]);
+ }
+ }
+ }
+ return 0;
+}
+
+static void K001006_w(int chip, int offset, UINT32 data, UINT32 mem_mask)
+{
+ if (offset == 0)
+ {
+ COMBINE_DATA(&K001006_addr[chip]);
+ }
+ else if (offset == 1)
+ {
+ switch (K001006_device_sel[chip])
+ {
+ case 0xd: // Palette RAM write
+ {
+ int r, g, b, a;
+ UINT32 index = K001006_addr[chip];
+
+ K001006_pal_ram[chip][index>>1] = data & 0xffff;
+
+ a = (data & 0x8000) ? 0x00 : 0xff;
+ b = ((data >> 10) & 0x1f) << 3;
+ g = ((data >> 5) & 0x1f) << 3;
+ r = ((data >> 0) & 0x1f) << 3;
+ b |= (b >> 5);
+ g |= (g >> 5);
+ r |= (r >> 5);
+ K001006_palette[chip][index>>1] = MAKE_ARGB(a, r, g, b);
+
+ K001006_addr[chip] += 2;
+ break;
+ }
+ case 0xf: // Unknown RAM write
+ {
+ // mame_printf_debug("Unknown RAM %08X = %04X\n", K001006_addr[chip], data & 0xffff);
+ K001006_unknown_ram[chip][K001006_addr[chip]++] = data & 0xffff;
+ break;
+ }
+ default:
+ {
+ mame_printf_debug("K001006_w: chip %d, device %02X, write %04X to %08X\n", chip, K001006_device_sel[chip], data & 0xffff, K001006_addr[0]++);
+ }
+ }
+ }
+ else if (offset == 2)
+ {
+ if (!(mem_mask & 0xffff0000))
+ {
+ K001006_device_sel[chip] = (data >> 16) & 0xf;
+ }
+ }
+}
+
+READ32_HANDLER(K001006_0_r)
+{
+ return K001006_r(0, offset, mem_mask);
+}
+
+WRITE32_HANDLER(K001006_0_w)
+{
+ K001006_w(0, offset, data, mem_mask);
+}
+
+READ32_HANDLER(K001006_1_r)
+{
+ return K001006_r(1, offset, mem_mask);
+}
+
+WRITE32_HANDLER(K001006_1_w)
+{
+ K001006_w(1, offset, data, mem_mask);
+}
+
+
+/*****************************************************************************/
+/* Konami K001005 Custom 3D Pixel Renderer chip (KS10071) */
+
+static const int decode_x_gti[8] = { 0, 16, 2, 18, 4, 20, 6, 22 };
+static const int decode_y_gti[16] = { 0, 8, 32, 40, 1, 9, 33, 41, 64, 72, 96, 104, 65, 73, 97, 105 };
+
+static const int decode_x_zr107[8] = { 0, 16, 1, 17, 2, 18, 3, 19 };
+static const int decode_y_zr107[16] = { 0, 8, 32, 40, 4, 12, 36, 44, 64, 72, 96, 104, 68, 76, 100, 108 };
+
+UINT32 K001005_status = 0;
+static mame_bitmap *K001005_bitmap[2];
+static mame_bitmap *K001005_zbuffer;
+static rectangle K001005_cliprect;
+
+static void render_polygons(void);
+
+static UINT8 *K001005_texture;
+
+static UINT16 *K001005_ram[2];
+static int K001005_ram_ptr = 0;
+static UINT32 *K001005_fifo;
+static int K001005_fifo_read_ptr = 0;
+static int K001005_fifo_write_ptr = 0;
+
+static UINT32 *K001005_3d_fifo;
+static int K001005_3d_fifo_ptr = 0;
+
+static int tex_mirror_table[4][128];
+
+static int K001005_bitmap_page = 0;
+
+void K001005_swap_buffers(void);
+
+void K001005_init(void)
+{
+ int i;
+ K001005_bitmap[0] = auto_bitmap_alloc(Machine->screen[0].width, Machine->screen[0].height, Machine->screen[0].format);
+ K001005_bitmap[1] = auto_bitmap_alloc(Machine->screen[0].width, Machine->screen[0].height, Machine->screen[0].format);
+
+ K001005_zbuffer = auto_bitmap_alloc(Machine->screen[0].width, Machine->screen[0].height, BITMAP_FORMAT_INDEXED32);
+
+ K001005_texture = auto_malloc(0x800000);
+
+ K001005_ram[0] = auto_malloc(0x140000 * sizeof(UINT16));
+ K001005_ram[1] = auto_malloc(0x140000 * sizeof(UINT16));
+
+ K001005_fifo = auto_malloc(0x800 * sizeof(UINT32));
+
+ K001005_3d_fifo = auto_malloc(0x10000 * sizeof(UINT32));
+
+ for (i=0; i < 128; i++)
+ {
+ tex_mirror_table[0][i] = i & 0x3f;
+ tex_mirror_table[1][i] = i & 0x3f;
+ tex_mirror_table[2][i] = ((i & 0x3f) >= 0x20) ? (0x1f - (i & 0x1f)) : i & 0x1f;
+ tex_mirror_table[3][i] = ((i & 0x7f) >= 0x40) ? (0x3f - (i & 0x3f)) : i & 0x3f;
+ }
+}
+
+// rearranges the texture data to a more practical order
+void K001005_preprocess_texture_data(UINT8 *rom, int length, int gticlub)
+{
+ int index;
+ int i, x, y;
+ UINT8 temp[0x40000];
+
+ const int *decode_x;
+ const int *decode_y;
+
+ if (gticlub)
+ {
+ decode_x = decode_x_gti;
+ decode_y = decode_y_gti;
+ }
+ else
+ {
+ decode_x = decode_x_zr107;
+ decode_y = decode_y_zr107;
+ }
+
+ for (index=0; index < length; index += 0x40000)
+ {
+ int offset = index;
+
+ memset(temp, 0, 0x40000);
+
+ for (i=0; i < 0x800; i++)
+ {
+ int tx = ((i & 0x400) >> 5) | ((i & 0x100) >> 4) | ((i & 0x40) >> 3) | ((i & 0x10) >> 2) | ((i & 0x4) >> 1) | (i & 0x1);
+ int ty = ((i & 0x200) >> 5) | ((i & 0x80) >> 4) | ((i & 0x20) >> 3) | ((i & 0x8) >> 2) | ((i & 0x2) >> 1);
+
+ tx <<= 3;
+ ty <<= 4;
+
+ for (y=0; y < 16; y++)
+ {
+ for (x=0; x < 8; x++)
+ {
+ UINT8 pixel = rom[offset + decode_y[y] + decode_x[x]];
+
+ temp[((ty+y) * 512) + (tx+x)] = pixel;
+ }
+ }
+
+ offset += 128;
+ }
+
+ memcpy(&rom[index], temp, 0x40000);
+ }
+}
+
+READ32_HANDLER( K001005_r )
+{
+ switch(offset)
+ {
+ case 0x000: // FIFO read, high 16 bits
+ {
+ UINT16 value = K001005_fifo[K001005_fifo_read_ptr] >> 16;
+ // mame_printf_debug("FIFO_r0: %08X\n", K001005_fifo_ptr);
+ return value;
+ }
+
+ case 0x001: // FIFO read, low 16 bits
+ {
+ UINT16 value = K001005_fifo[K001005_fifo_read_ptr] & 0xffff;
+ // mame_printf_debug("FIFO_r1: %08X\n", K001005_fifo_ptr);
+
+ if (K001005_status != 1 && K001005_status != 2)
+ {
+ if (K001005_fifo_read_ptr < 0x3ff)
+ {
+ //cpunum_set_input_line(2, SHARC_INPUT_FLAG1, CLEAR_LINE);
+ cpuintrf_push_context(2);
+ sharc_set_flag_input(1, CLEAR_LINE);
+ cpuintrf_pop_context();
+ }
+ else
+ {
+ //cpunum_set_input_line(2, SHARC_INPUT_FLAG1, ASSERT_LINE);
+ cpuintrf_push_context(2);
+ sharc_set_flag_input(1, ASSERT_LINE);
+ cpuintrf_pop_context();
+ }
+ }
+ else
+ {
+ //cpunum_set_input_line(2, SHARC_INPUT_FLAG1, ASSERT_LINE);
+ cpuintrf_push_context(2);
+ sharc_set_flag_input(1, ASSERT_LINE);
+ cpuintrf_pop_context();
+ }
+
+ K001005_fifo_read_ptr++;
+ K001005_fifo_read_ptr &= 0x7ff;
+ return value;
+ }
+
+ case 0x11b: // status ?
+ return 0x8002;
+
+ case 0x11c: // slave status ?
+ return 0x8000;
+
+ case 0x11f:
+ if (K001005_ram_ptr >= 0x400000)
+ {
+ return K001005_ram[1][(K001005_ram_ptr++) & 0x3fffff];
+ }
+ else
+ {
+ return K001005_ram[0][(K001005_ram_ptr++) & 0x3fffff];
+ }
+
+ default:
+ mame_printf_debug("K001005_r: %08X, %08X at %08X\n", offset, mem_mask, activecpu_get_pc());
+ break;
+ }
+ return 0;
+}
+
+WRITE32_HANDLER( K001005_w )
+{
+ switch(offset)
+ {
+ case 0x000: // FIFO write
+ {
+ if (K001005_status != 1 && K001005_status != 2)
+ {
+ if (K001005_fifo_write_ptr < 0x400)
+ {
+ //cpunum_set_input_line(2, SHARC_INPUT_FLAG1, ASSERT_LINE);
+ cpuintrf_push_context(2);
+ sharc_set_flag_input(1, ASSERT_LINE);
+ cpuintrf_pop_context();
+ }
+ else
+ {
+ //cpunum_set_input_line(2, SHARC_INPUT_FLAG1, CLEAR_LINE);
+ cpuintrf_push_context(2);
+ sharc_set_flag_input(1, CLEAR_LINE);
+ cpuintrf_pop_context();
+ }
+ }
+ else
+ {
+ //cpunum_set_input_line(2, SHARC_INPUT_FLAG1, ASSERT_LINE);
+ cpuintrf_push_context(2);
+ sharc_set_flag_input(1, ASSERT_LINE);
+ cpuintrf_pop_context();
+ }
+
+ // mame_printf_debug("K001005 FIFO write: %08X at %08X\n", data, activecpu_get_pc());
+ K001005_fifo[K001005_fifo_write_ptr] = data;
+ K001005_fifo_write_ptr++;
+ K001005_fifo_write_ptr &= 0x7ff;
+
+ K001005_3d_fifo[K001005_3d_fifo_ptr++] = data;
+
+ // !!! HACK to get past the FIFO B test (GTI Club & Thunder Hurricane) !!!
+ if (activecpu_get_pc() == 0x201ee)
+ {
+ // This is used to make the SHARC timeout
+ cpu_spinuntil_trigger(10000);
+ }
+ // !!! HACK to get past the FIFO B test (Winding Heat & Midnight Run) !!!
+ if (activecpu_get_pc() == 0x201e6)
+ {
+ // This is used to make the SHARC timeout
+ cpu_spinuntil_trigger(10000);
+ }
+
+ break;
+ }
+
+ case 0x100: break;
+
+ // case 0x10a: poly_r = data & 0xff; break;
+ // case 0x10b: poly_g = data & 0xff; break;
+ // case 0x10c: poly_b = data & 0xff; break;
+
+ case 0x11a:
+ K001005_status = data;
+ K001005_fifo_write_ptr = 0;
+ K001005_fifo_read_ptr = 0;
+
+ if (data == 2 && K001005_3d_fifo_ptr > 0)
+ {
+ K001005_swap_buffers();
+ render_polygons();
+ poly_wait(poly, "render_polygons");
+ K001005_3d_fifo_ptr = 0;
+ }
+ break;
+
+ case 0x11d:
+ K001005_fifo_write_ptr = 0;
+ K001005_fifo_read_ptr = 0;
+ break;
+
+ case 0x11e:
+ K001005_ram_ptr = data;
+ break;
+
+ case 0x11f:
+ if (K001005_ram_ptr >= 0x400000)
+ {
+ K001005_ram[1][(K001005_ram_ptr++) & 0x3fffff] = data & 0xffff;
+ }
+ else
+ {
+ K001005_ram[0][(K001005_ram_ptr++) & 0x3fffff] = data & 0xffff;
+ }
+ break;
+
+ default:
+ //mame_printf_debug("K001005_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, activecpu_get_pc());
+ break;
+ }
+
+}
+
+static void draw_scanline(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ mame_bitmap *destmap = dest;
+ float z = extent->param[0].start;
+ float dz = extent->param[0].dpdx;
+ UINT32 *fb = BITMAP_ADDR32(destmap, scanline, 0);
+ UINT32 *zb = BITMAP_ADDR32(K001005_zbuffer, scanline, 0);
+ UINT32 color = extra->color;
+ int x;
+
+ for (x = extent->startx; x < extent->stopx; x++)
+ {
+ UINT32 iz = (UINT32)z >> 16;
+
+ if (iz <= zb[x])
+ {
+ if (color & 0xff000000)
+ {
+ fb[x] = color;
+ zb[x] = iz;
+ }
+ }
+
+ z += dz;
+ }
+}
+
+static void draw_scanline_tex(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ mame_bitmap *destmap = dest;
+ UINT8 *texrom = memory_region(REGION_GFX1) + (extra->texture_page * 0x40000);
+ int pal_chip = (extra->texture_palette & 0x8) ? 1 : 0;
+ int palette_index = (extra->texture_palette & 0x7) * 256;
+ float z = extent->param[0].start;
+ float u = extent->param[1].start;
+ float v = extent->param[2].start;
+ float w = extent->param[3].start;
+ float dz = extent->param[0].dpdx;
+ float du = extent->param[1].dpdx;
+ float dv = extent->param[2].dpdx;
+ float dw = extent->param[3].dpdx;
+ int texture_mirror_x = extra->texture_mirror_x;
+ int texture_mirror_y = extra->texture_mirror_y;
+ int texture_x = extra->texture_x;
+ int texture_y = extra->texture_y;
+ int x;
+
+ UINT32 *fb = BITMAP_ADDR32(destmap, scanline, 0);
+ UINT32 *zb = BITMAP_ADDR32(K001005_zbuffer, scanline, 0);
+
+ for (x = extent->startx; x < extent->stopx; x++)
+ {
+ UINT32 iz = (UINT32)z >> 16;
+ //int iu = u >> 16;
+ //int iv = v >> 16;
+
+ if (iz < zb[x])
+ {
+ float oow = 1.0f / w;
+ UINT32 color;
+ int iu, iv;
+ int iiv, iiu, texel;
+
+ iu = u * oow;
+ iv = v * oow;
+
+ iiu = texture_x + tex_mirror_table[texture_mirror_x][(iu >> 4) & 0x7f];
+ iiv = texture_y + tex_mirror_table[texture_mirror_y][(iv >> 4) & 0x7f];
+ texel = texrom[((iiv & 0x1ff) * 512) + (iiu & 0x1ff)];
+ color = K001006_palette[pal_chip][palette_index + texel];
+
+ if (color & 0xff000000)
+ {
+ fb[x] = color;
+ zb[x] = iz;
+ }
+ }
+
+ u += du;
+ v += dv;
+ z += dz;
+ w += dw;
+ }
+}
+
+static poly_vertex prev_v[4];
+static int prev_poly_type;
+
+static void render_polygons(void)
+{
+ int i, j;
+
+// mame_printf_debug("K001005_fifo_ptr = %08X\n", K001005_3d_fifo_ptr);
+
+ for (i=0; i < K001005_3d_fifo_ptr; i++)
+ {
+ if (K001005_3d_fifo[i] == 0x80000003)
+ {
+ poly_extra_data *extra = poly_get_extra_data(poly);
+ poly_vertex v[4];
+ int r, g, b, a;
+ UINT32 color;
+ int index = i;
+
+ ++index;
+
+ for (j=0; j < 4; j++)
+ {
+ int x, y;
+
+ x = ((K001005_3d_fifo[index] >> 0) & 0x3fff);
+ y = ((K001005_3d_fifo[index] >> 16) & 0x1fff);
+ x |= ((x & 0x2000) ? 0xffffc000 : 0);
+ y |= ((y & 0x1000) ? 0xffffe000 : 0);
+ ++index;
+
+ v[j].x = ((float)(x) / 16.0f) + 256.0f;
+ v[j].y = ((float)(-y) / 16.0f) + 192.0f;
+ v[j].p[0] = 0; /* ??? */
+ }
+
+ ++index;
+
+ r = (K001005_3d_fifo[index] >> 0) & 0xff;
+ g = (K001005_3d_fifo[index] >> 8) & 0xff;
+ b = (K001005_3d_fifo[index] >> 16) & 0xff;
+ a = (K001005_3d_fifo[index] >> 24) & 0xff;
+ color = (a << 24) | (r << 16) | (g << 8) | (b);
+ ++index;
+
+ extra->color = color;
+ poly_render_triangle(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline, 1, &v[0], &v[1], &v[2]);
+ poly_render_triangle(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline, 1, &v[0], &v[2], &v[3]);
+// poly_render_polygon(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline, 1, 4, v);
+
+ i = index - 1;
+ }
+ else if (K001005_3d_fifo[i] == 0x800000ae || K001005_3d_fifo[i] == 0x8000008e ||
+ K001005_3d_fifo[i] == 0x80000096 || K001005_3d_fifo[i] == 0x800000b6 ||
+ K001005_3d_fifo[i] == 0x8000002e || K001005_3d_fifo[i] == 0x8000000e ||
+ K001005_3d_fifo[i] == 0x80000016 || K001005_3d_fifo[i] == 0x80000036 ||
+ K001005_3d_fifo[i] == 0x800000aa || K001005_3d_fifo[i] == 0x800000a8 ||
+ K001005_3d_fifo[i] == 0x800000b2)
+ {
+ // 0x00: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Command
+ //
+ // 0x01: xxxx---- -------- -------- -------- Texture palette
+ // 0x01: -------- -------x xxxx---- -------- Texture page
+ // 0x01: -------- -------- ----x-x- x-x-x-x- Texture X / 8
+ // 0x01: -------- -------- -----x-x -x-x-x-x Texture Y / 8
+
+ poly_extra_data *extra = poly_get_extra_data(poly);
+ poly_vertex v[4];
+ int tx, ty;
+ UINT32 color = 0;
+ UINT32 header;
+ UINT32 command;
+ int num_verts = 0;
+ int index = i;
+ int poly_type = 0;
+
+ command = K001005_3d_fifo[index++];
+ header = K001005_3d_fifo[index++];
+
+ for (j=0; j < 4; j++)
+ {
+ INT16 u2, v2;
+ int x, y, z;
+ int end = 0;
+
+ x = ((K001005_3d_fifo[index] >> 0) & 0x3fff);
+ y = ((K001005_3d_fifo[index] >> 16) & 0x1fff);
+ x |= ((x & 0x2000) ? 0xffffc000 : 0);
+ y |= ((y & 0x1000) ? 0xffffe000 : 0);
+
+ poly_type = K001005_3d_fifo[index] & 0x4000;
+ end = K001005_3d_fifo[index] & 0x8000;
+ ++index;
+
+ z = K001005_3d_fifo[index];
+ ++index;
+
+ if (end)
+ {
+ color = K001005_3d_fifo[index];
+ ++index;
+
+ u2 = (K001005_3d_fifo[index] >> 16) & 0xffff;
+ v2 = (K001005_3d_fifo[index] >> 0) & 0xffff;
+ ++index;
+ }
+ else
+ {
+ u2 = (K001005_3d_fifo[index] >> 16) & 0xffff;
+ v2 = (K001005_3d_fifo[index] >> 0) & 0xffff;
+ ++index;
+ }
+
+ v[j].x = ((float)(x) / 16.0f) + 256.0f;
+ v[j].y = ((float)(-y) / 16.0f) + 192.0f;
+ v[j].p[0] = *(float*)(&z);
+ v[j].p[3] = 1.0f / v[j].p[0];
+ v[j].p[1] = u2 * v[j].p[3];
+ v[j].p[2] = v2 * v[j].p[3];
+
+ ++num_verts;
+
+ if (end)
+ break;
+ }
+
+ ty = ((header & 0x400) >> 5) |
+ ((header & 0x100) >> 4) |
+ ((header & 0x040) >> 3) |
+ ((header & 0x010) >> 2) |
+ ((header & 0x004) >> 1) |
+ ((header & 0x001) >> 0);
+
+ tx = ((header & 0x800) >> 6) |
+ ((header & 0x200) >> 5) |
+ ((header & 0x080) >> 4) |
+ ((header & 0x020) >> 3) |
+ ((header & 0x008) >> 2) |
+ ((header & 0x002) >> 1);
+
+ extra->texture_x = tx * 8;
+ extra->texture_y = ty * 8;
+
+ extra->texture_page = (header >> 12) & 0x1f;
+ extra->texture_palette = (header >> 28) & 0xf;
+
+ extra->texture_mirror_x = ((command & 0x10) ? 0x2 : 0) | ((header & 0x00400000) ? 0x1 : 0);
+ extra->texture_mirror_y = ((command & 0x10) ? 0x2 : 0) | ((header & 0x00400000) ? 0x1 : 0);
+
+ extra->color = color;
+
+ if (num_verts < 3)
+ {
+ poly_render_triangle(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline_tex, 4, &prev_v[2], &v[0], &v[1]);
+ if (prev_poly_type)
+ poly_render_triangle(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline_tex, 4, &prev_v[2], &prev_v[3], &v[0]);
+// if (prev_poly_type)
+// poly_render_quad(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline_tex, 4, &prev_v[2], &prev_v[3], &v[0], &v[1]);
+// else
+// poly_render_triangle(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline_tex, 4, &prev_v[2], &v[0], &v[1]);
+
+ memcpy(&prev_v[0], &prev_v[2], sizeof(poly_vertex));
+ memcpy(&prev_v[1], &prev_v[3], sizeof(poly_vertex));
+ memcpy(&prev_v[2], &v[0], sizeof(poly_vertex));
+ memcpy(&prev_v[3], &v[1], sizeof(poly_vertex));
+ }
+ else
+ {
+ poly_render_triangle(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline_tex, 4, &v[0], &v[1], &v[2]);
+ if (num_verts > 3)
+ poly_render_triangle(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline_tex, 4, &v[2], &v[3], &v[0]);
+// poly_render_polygon(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline_tex, 4, num_verts, v);
+
+ memcpy(prev_v, v, sizeof(poly_vertex) * 4);
+ }
+
+ prev_poly_type = poly_type;
+
+ while ((K001005_3d_fifo[index] & 0xffffff00) != 0x80000000 && index < K001005_3d_fifo_ptr)
+ {
+ poly_extra_data *extra = poly_get_extra_data(poly);
+ int new_verts = 0;
+
+ if (poly_type)
+ {
+ memcpy(&v[0], &prev_v[2], sizeof(poly_vertex));
+ memcpy(&v[1], &prev_v[3], sizeof(poly_vertex));
+ }
+ else
+ {
+ memcpy(&v[0], &prev_v[1], sizeof(poly_vertex));
+ memcpy(&v[1], &prev_v[2], sizeof(poly_vertex));
+ }
+
+ for (j=2; j < 4; j++)
+ {
+ INT16 u2, v2;
+ int x, y, z;
+ int end = 0;
+
+ x = ((K001005_3d_fifo[index] >> 0) & 0x3fff);
+ y = ((K001005_3d_fifo[index] >> 16) & 0x1fff);
+ x |= ((x & 0x2000) ? 0xffffc000 : 0);
+ y |= ((y & 0x1000) ? 0xffffe000 : 0);
+
+ poly_type = K001005_3d_fifo[index] & 0x4000;
+ end = K001005_3d_fifo[index] & 0x8000;
+ ++index;
+
+ z = K001005_3d_fifo[index];
+ ++index;
+
+ if (end)
+ {
+ color = K001005_3d_fifo[index];
+ ++index;
+
+ u2 = (K001005_3d_fifo[index] >> 16) & 0xffff;
+ v2 = (K001005_3d_fifo[index] >> 0) & 0xffff;
+ ++index;
+ }
+ else
+ {
+ u2 = (K001005_3d_fifo[index] >> 16) & 0xffff;
+ v2 = (K001005_3d_fifo[index] >> 0) & 0xffff;
+ ++index;
+ }
+
+ v[j].x = ((float)(x) / 16.0f) + 256.0f;
+ v[j].y = ((float)(-y) / 16.0f) + 192.0f;
+ v[j].p[0] = *(float*)(&z);
+ v[j].p[3] = 1.0f / v[j].p[0];
+ v[j].p[1] = u2 * v[j].p[3];
+ v[j].p[2] = v2 * v[j].p[3];
+
+ ++new_verts;
+
+ if (end)
+ break;
+ }
+
+ extra->texture_x = tx * 8;
+ extra->texture_y = ty * 8;
+
+ extra->texture_page = (header >> 12) & 0x1f;
+ extra->texture_palette = (header >> 28) & 0xf;
+
+ extra->texture_mirror_x = ((command & 0x10) ? 0x2 : 0) | ((header & 0x00400000) ? 0x1 : 0);
+ extra->texture_mirror_y = ((command & 0x10) ? 0x2 : 0) | ((header & 0x00400000) ? 0x1 : 0);
+
+ extra->color = color;
+
+ poly_render_triangle(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline_tex, 4, &v[0], &v[1], &v[2]);
+ if (new_verts > 1)
+ poly_render_triangle(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline_tex, 4, &v[2], &v[3], &v[0]);
+// poly_render_polygon(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline_tex, 4, new_verts + 2, v);
+
+ memcpy(prev_v, v, sizeof(poly_vertex) * 4);
+ };
+
+ i = index - 1;
+ }
+ else if (K001005_3d_fifo[i] == 0x80000006 || K001005_3d_fifo[i] == 0x80000026 ||
+ K001005_3d_fifo[i] == 0x80000020 || K001005_3d_fifo[i] == 0x80000022)
+ {
+ poly_extra_data *extra = poly_get_extra_data(poly);
+ poly_vertex v[4];
+ int r, g, b, a;
+ UINT32 color;
+ int num_verts = 0;
+ int index = i;
+ int poly_type = 0;
+
+ ++index;
+
+ for (j=0; j < 4; j++)
+ {
+ int x, y, z;
+ int end = 0;
+
+ x = ((K001005_3d_fifo[index] >> 0) & 0x3fff);
+ y = ((K001005_3d_fifo[index] >> 16) & 0x1fff);
+ x |= ((x & 0x2000) ? 0xffffc000 : 0);
+ y |= ((y & 0x1000) ? 0xffffe000 : 0);
+
+ poly_type = K001005_3d_fifo[index] & 0x4000;
+ end = K001005_3d_fifo[index] & 0x8000;
+ ++index;
+
+ z = K001005_3d_fifo[index];
+ ++index;
+
+ v[j].x = ((float)(x) / 16.0f) + 256.0f;
+ v[j].y = ((float)(-y) / 16.0f) + 192.0f;
+ v[j].p[0] = *(float*)(&z);
+
+ ++num_verts;
+
+ if (end)
+ break;
+ }
+
+ r = (K001005_3d_fifo[index] >> 0) & 0xff;
+ g = (K001005_3d_fifo[index] >> 8) & 0xff;
+ b = (K001005_3d_fifo[index] >> 16) & 0xff;
+ a = (K001005_3d_fifo[index] >> 24) & 0xff;
+ color = (a << 24) | (r << 16) | (g << 8) | (b);
+ index++;
+
+ extra->color = color;
+
+ poly_render_triangle(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline, 1, &v[0], &v[1], &v[2]);
+ if (num_verts > 3)
+ poly_render_triangle(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline, 1, &v[2], &v[3], &v[0]);
+// poly_render_polygon(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline, 1, num_verts, v);
+
+ memcpy(prev_v, v, sizeof(poly_vertex) * 4);
+
+ while ((K001005_3d_fifo[index] & 0xffffff00) != 0x80000000 && index < K001005_3d_fifo_ptr)
+ {
+ poly_extra_data *extra = poly_get_extra_data(poly);
+ int new_verts = 0;
+
+ if (poly_type)
+ {
+ memcpy(&v[0], &prev_v[2], sizeof(poly_vertex));
+ memcpy(&v[1], &prev_v[3], sizeof(poly_vertex));
+ }
+ else
+ {
+ memcpy(&v[0], &prev_v[1], sizeof(poly_vertex));
+ memcpy(&v[1], &prev_v[2], sizeof(poly_vertex));
+ }
+
+ for (j=2; j < 4; j++)
+ {
+ int x, y, z;
+ int end = 0;
+
+ x = ((K001005_3d_fifo[index] >> 0) & 0x3fff);
+ y = ((K001005_3d_fifo[index] >> 16) & 0x1fff);
+ x |= ((x & 0x2000) ? 0xffffc000 : 0);
+ y |= ((y & 0x1000) ? 0xffffe000 : 0);
+
+ poly_type = K001005_3d_fifo[index] & 0x4000;
+ end = K001005_3d_fifo[index] & 0x8000;
+ ++index;
+
+ z = K001005_3d_fifo[index];
+ ++index;
+
+ v[j].x = ((float)(x) / 16.0f) + 256.0f;
+ v[j].y = ((float)(-y) / 16.0f) + 192.0f;
+ v[j].p[0] = *(float*)(&z);
+
+ ++new_verts;
+
+ if (end)
+ break;
+ }
+
+ r = (K001005_3d_fifo[index] >> 0) & 0xff;
+ g = (K001005_3d_fifo[index] >> 8) & 0xff;
+ b = (K001005_3d_fifo[index] >> 16) & 0xff;
+ a = (K001005_3d_fifo[index] >> 24) & 0xff;
+ color = (a << 24) | (r << 16) | (g << 8) | (b);
+ index++;
+
+ extra->color = color;
+
+ poly_render_triangle(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline, 1, &v[0], &v[1], &v[2]);
+ if (new_verts > 1)
+ poly_render_triangle(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline, 1, &v[0], &v[2], &v[3]);
+// poly_render_polygon(poly, K001005_bitmap[K001005_bitmap_page], &Machine->screen[0].visarea, draw_scanline, 1, new_verts + 2, v);
+
+ memcpy(prev_v, v, sizeof(poly_vertex) * 4);
+ };
+
+ i = index - 1;
+ }
+ else if (K001005_3d_fifo[i] == 0x80000000)
+ {
+
+ }
+ else if ((K001005_3d_fifo[i] & 0xffffff00) == 0x80000000)
+ {
+ /*
+ mame_printf_debug("Unknown polygon type %08X:\n", K001005_3d_fifo[i]);
+ for (j=0; j < 0x20; j++)
+ {
+ mame_printf_debug(" %02X: %08X\n", j, K001005_3d_fifo[i+1+j]);
+ }
+ mame_printf_debug("\n");
+ */
+ }
+ }
+}
+
+void K001005_draw(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int i, j;
+
+ memcpy(&K001005_cliprect, cliprect, sizeof(rectangle));
+
+ for (j=cliprect->min_y; j <= cliprect->max_y; j++)
+ {
+ UINT32 *bmp = BITMAP_ADDR32(bitmap, j, 0);
+ UINT32 *src = BITMAP_ADDR32(K001005_bitmap[K001005_bitmap_page^1], j, 0);
+
+ for (i=cliprect->min_x; i <= cliprect->max_x; i++)
+ {
+ if (src[i] & 0xff000000)
+ {
+ bmp[i] = src[i];
+ }
+ }
+ }
+}
+
+void K001005_swap_buffers(void)
+{
+ K001005_bitmap_page ^= 1;
+
+ //if (K001005_status == 2)
+ {
+ fillbitmap(K001005_bitmap[K001005_bitmap_page], Machine->remapped_colortable[0], &K001005_cliprect);
+ fillbitmap(K001005_zbuffer, 0xffffffff, &K001005_cliprect);
+ }
+}
+
+
+
+static void gticlub_exit(running_machine *machine)
+{
+ poly_free(poly);
+}
+
+VIDEO_START( gticlub )
+{
+ poly = poly_alloc(4000, sizeof(poly_extra_data), POLYFLAG_ALLOW_QUADS);
+ add_exit_callback(machine, gticlub_exit);
+
+ K001005_init();
+ K001604_vh_start(machine, 0);
+}
+
+static int tick = 0;
+static int debug_tex_page = 0;
+static int debug_tex_palette = 0;
+
+VIDEO_UPDATE( gticlub )
+{
+ K001604_tile_update(machine, 0);
+ K001604_draw_back_layer(0, bitmap, cliprect);
+
+ K001005_draw(bitmap, cliprect);
+
+ K001604_draw_front_layer(0, bitmap, cliprect);
+
+ tick++;
+ if( tick >= 5 ) {
+ tick = 0;
+
+ if( input_code_pressed(KEYCODE_O) )
+ debug_tex_page++;
+
+ if( input_code_pressed(KEYCODE_I) )
+ debug_tex_page--;
+
+ if (input_code_pressed(KEYCODE_U))
+ debug_tex_palette++;
+ if (input_code_pressed(KEYCODE_Y))
+ debug_tex_palette--;
+
+ if (debug_tex_page < 0)
+ debug_tex_page = 32;
+ if (debug_tex_page > 32)
+ debug_tex_page = 0;
+
+ if (debug_tex_palette < 0)
+ debug_tex_palette = 15;
+ if (debug_tex_palette > 15)
+ debug_tex_palette = 0;
+ }
+
+ /*
+ if (debug_tex_page > 0)
+ {
+ char string[200];
+ int x,y;
+ int index = (debug_tex_page - 1) * 0x40000;
+ int pal = debug_tex_palette & 7;
+ int tp = (debug_tex_palette >> 3) & 1;
+ UINT8 *rom = memory_region(REGION_GFX1);
+
+ for (y=0; y < 384; y++)
+ {
+ for (x=0; x < 512; x++)
+ {
+ UINT8 pixel = rom[index + (y*512) + x];
+ *BITMAP_ADDR32(bitmap, y, x) = K001006_palette[tp][(pal * 256) + pixel];
+ }
+ }
+
+ sprintf(string, "Texture page %d\nPalette %d", debug_tex_page, debug_tex_palette);
+ //popmessage("%s", string);
+ }
+ */
+
+ draw_7segment_led(bitmap, 3, 3, gticlub_led_reg0);
+ draw_7segment_led(bitmap, 9, 3, gticlub_led_reg1);
+
+ //cpunum_set_input_line(2, SHARC_INPUT_FLAG1, ASSERT_LINE);
+ cpuintrf_push_context(2);
+ sharc_set_flag_input(1, ASSERT_LINE);
+ cpuintrf_pop_context();
+ return 0;
+}
+
diff --git a/src/mame/video/gticlub.h b/src/mame/video/gticlub.h
new file mode 100644
index 00000000000..fb7c428a39a
--- /dev/null
+++ b/src/mame/video/gticlub.h
@@ -0,0 +1,12 @@
+void K001005_draw(mame_bitmap *bitmap, const rectangle *cliprect);
+void K001005_swap_buffers(void);
+void K001005_init(void);
+void K001005_preprocess_texture_data(UINT8 *rom, int length, int gticlub);
+
+READ32_HANDLER(K001005_r);
+WRITE32_HANDLER(K001005_w);
+
+READ32_HANDLER(K001006_0_r);
+WRITE32_HANDLER(K001006_0_w);
+READ32_HANDLER(K001006_1_r);
+WRITE32_HANDLER(K001006_1_w);
diff --git a/src/mame/video/gumbo.c b/src/mame/video/gumbo.c
new file mode 100644
index 00000000000..a16a31126db
--- /dev/null
+++ b/src/mame/video/gumbo.c
@@ -0,0 +1,51 @@
+/* Gumbo video */
+
+#include "driver.h"
+
+extern UINT16 *gumbo_bg_videoram;
+extern UINT16 *gumbo_fg_videoram;
+
+static tilemap *gumbo_bg_tilemap;
+static tilemap *gumbo_fg_tilemap;
+
+WRITE16_HANDLER( gumbo_bg_videoram_w )
+{
+ COMBINE_DATA(&gumbo_bg_videoram[offset]);
+ tilemap_mark_tile_dirty(gumbo_bg_tilemap,offset);
+}
+
+static TILE_GET_INFO( get_gumbo_bg_tile_info )
+{
+ int tileno;
+ tileno = gumbo_bg_videoram[tile_index];
+ SET_TILE_INFO(0,tileno,0,0);
+}
+
+
+WRITE16_HANDLER( gumbo_fg_videoram_w )
+{
+ COMBINE_DATA(&gumbo_fg_videoram[offset]);
+ tilemap_mark_tile_dirty(gumbo_fg_tilemap,offset);
+}
+
+static TILE_GET_INFO( get_gumbo_fg_tile_info )
+{
+ int tileno;
+ tileno = gumbo_fg_videoram[tile_index];
+ SET_TILE_INFO(1,tileno,1,0);
+}
+
+
+VIDEO_START( gumbo )
+{
+ gumbo_bg_tilemap = tilemap_create(get_gumbo_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8, 64,32);
+ gumbo_fg_tilemap = tilemap_create(get_gumbo_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 4, 4,128,64);
+ tilemap_set_transparent_pen(gumbo_fg_tilemap,0xff);
+}
+
+VIDEO_UPDATE( gumbo )
+{
+ tilemap_draw(bitmap,cliprect,gumbo_bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,gumbo_fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/gunbustr.c b/src/mame/video/gunbustr.c
new file mode 100644
index 00000000000..a706839c99d
--- /dev/null
+++ b/src/mame/video/gunbustr.c
@@ -0,0 +1,254 @@
+#include "driver.h"
+#include "video/taitoic.h"
+
+#define TC0480SCP_GFX_NUM 1
+
+struct tempsprite
+{
+ int gfx;
+ int code,color;
+ int flipx,flipy;
+ int x,y;
+ int zoomx,zoomy;
+ int primask;
+};
+static struct tempsprite *spritelist;
+
+/************************************************************/
+
+VIDEO_START( gunbustr )
+{
+ spritelist = auto_malloc(0x4000 * sizeof(*spritelist));
+
+ TC0480SCP_vh_start(machine,TC0480SCP_GFX_NUM,0,0x20,0x07,-1,-1,-1,0,0);
+}
+
+/************************************************************
+ SPRITE DRAW ROUTINES
+
+We draw a series of small tiles ("chunks") together to
+create each big sprite. The spritemap rom provides the lookup
+table for this. The game hardware looks up 16x16 sprite chunks
+from the spritemap rom, creating a 64x64 sprite like this:
+
+ 0 1 2 3
+ 4 5 6 7
+ 8 9 10 11
+ 12 13 14 15
+
+(where the number is the word offset into the spritemap rom).
+It can also create 32x32 sprites.
+
+NB: unused portions of the spritemap rom contain hex FF's.
+It is a useful coding check to warn in the log if these
+are being accessed. [They can be inadvertently while
+spriteram is being tested, take no notice of that.]
+
+Heavy use is made of sprite zooming.
+
+ ***
+
+ Sprite table layout (4 long words per entry)
+
+ ------------------------------------------
+ 0 | ........ x....... ........ ........ | Flip X
+ 0 | ........ .xxxxxxx ........ ........ | ZoomX
+ 0 | ........ ........ .xxxxxxx xxxxxxxx | Sprite Tile
+ | |
+ 2 | ........ ....xx.. ........ ........ | Sprite/tile priority [*]
+ 2 | ........ ......xx xxxxxx.. ........ | Palette bank
+ 2 | ........ ........ ......xx xxxxxxxx | X position
+ | |
+ 3 | ........ .....x.. ........ ........ | Sprite size (0=32x32, 1=64x64)
+ 3 | ........ ......x. ........ ........ | Flip Y
+ 3 | ........ .......x xxxxxx.. ........ | ZoomY
+ 3 | ........ ........ ......xx xxxxxxxx | Y position
+ ------------------------------------------
+
+ [* 00=over BG1; 01=BG2; 10=BG3; 11=over text ???]
+
+********************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,const int *primasks,int x_offs,int y_offs)
+{
+ UINT16 *spritemap = (UINT16 *)memory_region(REGION_USER1);
+ int offs, data, tilenum, color, flipx, flipy;
+ int x, y, priority, dblsize, curx, cury;
+ int sprites_flipscreen = 0;
+ int zoomx, zoomy, zx, zy;
+ int sprite_chunk,map_offset,code,j,k,px,py;
+ int dimension,total_chunks,bad_chunks;
+
+ /* pdrawgfx() needs us to draw sprites front to back, so we have to build a list
+ while processing sprite ram and then draw them all at the end */
+ struct tempsprite *sprite_ptr = spritelist;
+
+ for (offs = (spriteram_size/4-4);offs >= 0;offs -= 4)
+ {
+ data = spriteram32[offs+0];
+ flipx = (data & 0x00800000) >> 23;
+ zoomx = (data & 0x007f0000) >> 16;
+ tilenum = (data & 0x00007fff);
+
+ data = spriteram32[offs+2];
+ priority = (data & 0x000c0000) >> 18;
+ color = (data & 0x0003fc00) >> 10;
+ x = (data & 0x000003ff);
+
+ data = spriteram32[offs+3];
+ dblsize = (data & 0x00040000) >> 18;
+ flipy = (data & 0x00020000) >> 17;
+ zoomy = (data & 0x0001fc00) >> 10;
+ y = (data & 0x000003ff);
+
+ color |= 0x80;
+
+ if (!tilenum) continue;
+
+ flipy = !flipy;
+ zoomx += 1;
+ zoomy += 1;
+
+ y += y_offs;
+
+ /* treat coords as signed */
+ if (x>0x340) x -= 0x400;
+ if (y>0x340) y -= 0x400;
+
+ x -= x_offs;
+
+ bad_chunks = 0;
+ dimension = ((dblsize*2) + 2); // 2 or 4
+ total_chunks = ((dblsize*3) + 1) << 2; // 4 or 16
+ map_offset = tilenum << 2;
+
+ {
+ for (sprite_chunk=0;sprite_chunk<total_chunks;sprite_chunk++)
+ {
+ j = sprite_chunk / dimension; /* rows */
+ k = sprite_chunk % dimension; /* chunks per row */
+
+ px = k;
+ py = j;
+ /* pick tiles back to front for x and y flips */
+ if (flipx) px = dimension-1-k;
+ if (flipy) py = dimension-1-j;
+
+ code = spritemap[map_offset + px + (py<<(dblsize+1))];
+
+ if (code==0xffff)
+ {
+ bad_chunks += 1;
+ continue;
+ }
+
+ curx = x + ((k*zoomx)/dimension);
+ cury = y + ((j*zoomy)/dimension);
+
+ zx= x + (((k+1)*zoomx)/dimension) - curx;
+ zy= y + (((j+1)*zoomy)/dimension) - cury;
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 320 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ sprite_ptr->gfx = 0;
+ sprite_ptr->code = code;
+ sprite_ptr->color = color;
+ sprite_ptr->flipx = !flipx;
+ sprite_ptr->flipy = flipy;
+ sprite_ptr->x = curx;
+ sprite_ptr->y = cury;
+ sprite_ptr->zoomx = zx << 12;
+ sprite_ptr->zoomy = zy << 12;
+
+ if (primasks)
+ {
+ sprite_ptr->primask = primasks[priority];
+
+ sprite_ptr++;
+ }
+ else
+ {
+ drawgfxzoom(bitmap,machine->gfx[sprite_ptr->gfx],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,TRANSPARENCY_PEN,0,
+ sprite_ptr->zoomx,sprite_ptr->zoomy);
+ }
+ }
+ }
+
+ if (bad_chunks)
+logerror("Sprite number %04x had %02x invalid chunks\n",tilenum,bad_chunks);
+ }
+
+ /* this happens only if primsks != NULL */
+ while (sprite_ptr != spritelist)
+ {
+ sprite_ptr--;
+
+ pdrawgfxzoom(bitmap,machine->gfx[sprite_ptr->gfx],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,TRANSPARENCY_PEN,0,
+ sprite_ptr->zoomx,sprite_ptr->zoomy,
+ sprite_ptr->primask);
+ }
+}
+
+
+
+/**************************************************************
+ SCREEN REFRESH
+**************************************************************/
+
+VIDEO_UPDATE( gunbustr )
+{
+ UINT8 layer[5];
+ UINT16 priority;
+ static const int primasks[4] = {0xfffc, 0xfff0, 0xff00, 0x0};
+
+ TC0480SCP_tilemap_update(machine);
+
+ priority = TC0480SCP_get_bg_priority();
+ layer[0] = (priority &0xf000) >> 12; /* tells us which bg layer is bottom */
+ layer[1] = (priority &0x0f00) >> 8;
+ layer[2] = (priority &0x00f0) >> 4;
+ layer[3] = (priority &0x000f) >> 0; /* tells us which is top */
+ layer[4] = 4; /* text layer always over bg layers */
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* We have to assume 2nd to bottom layer is always underneath
+ sprites as pdrawgfx cannot yet cope with more than 4 layers */
+
+#ifdef MAME_DEBUG
+ if (!input_code_pressed (KEYCODE_Z)) TC0480SCP_tilemap_draw(bitmap,cliprect,layer[0],TILEMAP_DRAW_OPAQUE,0);
+ if (!input_code_pressed (KEYCODE_X)) TC0480SCP_tilemap_draw(bitmap,cliprect,layer[1],0,1);
+ if (!input_code_pressed (KEYCODE_C)) TC0480SCP_tilemap_draw(bitmap,cliprect,layer[2],0,2);
+ if (!input_code_pressed (KEYCODE_V)) TC0480SCP_tilemap_draw(bitmap,cliprect,layer[3],0,4);
+ if (!input_code_pressed (KEYCODE_B)) TC0480SCP_tilemap_draw(bitmap,cliprect,layer[4],0,8);
+ if (!input_code_pressed (KEYCODE_N)) draw_sprites(machine,bitmap,cliprect,primasks,48,-116);
+#else
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[0],TILEMAP_DRAW_OPAQUE,0);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[1],0,1);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[2],0,2);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[3],0,4);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[4],0,8); /* text layer */
+ draw_sprites(machine,bitmap,cliprect,primasks,48,-116);
+#endif
+ return 0;
+}
diff --git a/src/mame/video/gundealr.c b/src/mame/video/gundealr.c
new file mode 100644
index 00000000000..40916d82f9b
--- /dev/null
+++ b/src/mame/video/gundealr.c
@@ -0,0 +1,143 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+UINT8 *gundealr_bg_videoram,*gundealr_fg_videoram;
+
+static tilemap *bg_tilemap,*fg_tilemap;
+static int flipscreen;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 attr = gundealr_bg_videoram[2*tile_index+1];
+ SET_TILE_INFO(
+ 0,
+ gundealr_bg_videoram[2*tile_index] + ((attr & 0x07) << 8),
+ (attr & 0xf0) >> 4,
+ 0);
+}
+
+static TILEMAP_MAPPER( gundealr_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (row & 0x0f) + ((col & 0x3f) << 4) + ((row & 0x10) << 6);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 attr = gundealr_fg_videoram[2*tile_index+1];
+ SET_TILE_INFO(
+ 1,
+ gundealr_fg_videoram[2*tile_index] + ((attr & 0x03) << 8),
+ (attr & 0xf0) >> 4,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( gundealr )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 8, 8,32,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,gundealr_scan, TILEMAP_TYPE_PEN,16,16,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,15);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( gundealr_bg_videoram_w )
+{
+ gundealr_bg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+WRITE8_HANDLER( gundealr_fg_videoram_w )
+{
+ gundealr_fg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset/2);
+}
+
+WRITE8_HANDLER( gundealr_paletteram_w )
+{
+ int r,g,b,val;
+
+
+ paletteram[offset] = data;
+
+ val = paletteram[offset & ~1];
+ r = (val >> 4) & 0x0f;
+ g = (val >> 0) & 0x0f;
+
+ val = paletteram[offset | 1];
+ b = (val >> 4) & 0x0f;
+ /* TODO: the bottom 4 bits are used as well, but I'm not sure about the meaning */
+
+ palette_set_color_rgb(Machine,offset / 2,pal4bit(r),pal4bit(g),pal4bit(b));
+}
+
+WRITE8_HANDLER( gundealr_fg_scroll_w )
+{
+ static UINT8 scroll[4];
+
+ scroll[offset] = data;
+ tilemap_set_scrollx(fg_tilemap,0,scroll[1] | ((scroll[0] & 0x03) << 8));
+ tilemap_set_scrolly(fg_tilemap,0,scroll[3] | ((scroll[2] & 0x03) << 8));
+}
+
+WRITE8_HANDLER( yamyam_fg_scroll_w )
+{
+ static UINT8 scroll[4];
+
+ scroll[offset] = data;
+ tilemap_set_scrollx(fg_tilemap,0,scroll[0] | ((scroll[1] & 0x03) << 8));
+ tilemap_set_scrolly(fg_tilemap,0,scroll[2] | ((scroll[3] & 0x03) << 8));
+}
+
+WRITE8_HANDLER( gundealr_flipscreen_w )
+{
+ flipscreen = data;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( gundealr )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/gunsmoke.c b/src/mame/video/gunsmoke.c
new file mode 100644
index 00000000000..79ec0530b2a
--- /dev/null
+++ b/src/mame/video/gunsmoke.c
@@ -0,0 +1,216 @@
+#include "driver.h"
+
+#define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+#define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+UINT8 *gunsmoke_scrollx;
+UINT8 *gunsmoke_scrolly;
+
+static UINT8 chon, objon, bgon;
+static UINT8 sprite3bank;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Gunsmoke has three 256x4 palette PROMs (one per gun) and a lot ;-) of
+ 256x4 lookup table PROMs.
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+PALETTE_INIT( gunsmoke )
+{
+ int i;
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int bit0, bit1, bit2, bit3, r, g, b;
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ color_prom++;
+ }
+
+ color_prom += 2 * machine->drv->total_colors;
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* characters use colors 64-79 */
+ for (i = 0; i < TOTAL_COLORS(0); i++)
+ COLOR(0, i) = *(color_prom++) + 64;
+ color_prom += 128; /* skip the bottom half of the PROM - not used */
+
+ /* background tiles use colors 0-63 */
+ for (i = 0; i < TOTAL_COLORS(1); i++)
+ {
+ COLOR(1, i) = color_prom[0] + 16 * (color_prom[256] & 0x03);
+ color_prom++;
+ }
+ color_prom += TOTAL_COLORS(1);
+
+ /* sprites use colors 128-255 */
+ for (i = 0; i < TOTAL_COLORS(2); i++)
+ {
+ COLOR(2, i) = color_prom[0] + 16 * (color_prom[256] & 0x07) + 128;
+ color_prom++;
+ }
+ color_prom += TOTAL_COLORS(2);
+}
+
+WRITE8_HANDLER( gunsmoke_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( gunsmoke_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( gunsmoke_c804_w )
+{
+ /* bits 0 and 1 are for coin counters */
+ coin_counter_w(1, data & 0x01);
+ coin_counter_w(0, data & 0x02);
+
+ /* bits 2 and 3 select the ROM bank */
+ memory_set_bank(1, (data & 0x0c) >> 2);
+
+ /* bit 5 resets the sound CPU? - we ignore it */
+
+ /* bit 6 flips screen */
+ flip_screen_set(data & 0x40);
+
+ /* bit 7 enables characters? */
+ chon = data & 0x80;
+}
+
+WRITE8_HANDLER( gunsmoke_d806_w )
+{
+ /* bits 0-2 select the sprite 3 bank */
+ sprite3bank = data & 0x07;
+
+ /* bit 4 enables bg 1? */
+ bgon = data & 0x10;
+
+ /* bit 5 enables sprites? */
+ objon = data & 0x20;
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 *tilerom = memory_region(REGION_GFX4);
+
+ int offs = tile_index * 2;
+ int attr = tilerom[offs + 1];
+ int code = tilerom[offs] + ((attr & 0x01) << 8);
+ int color = (attr & 0x3c) >> 2;
+ int flags = TILE_FLIPYX((attr & 0xc0) >> 6);
+
+ SET_TILE_INFO(1, code, color, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + ((attr & 0xe0) << 2);
+ int color = attr & 0x1f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( gunsmoke )
+{
+ /* configure ROM banking */
+ UINT8 *rombase = memory_region(REGION_CPU1);
+ memory_configure_bank(1, 0, 4, &rombase[0x10000], 0x4000);
+
+ /* create tilemaps */
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 32, 32, 2048, 8);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_COLORTABLE, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0x4f);
+
+ /* register for saving */
+ state_save_register_global(chon);
+ state_save_register_global(objon);
+ state_save_register_global(bgon);
+ state_save_register_global(sprite3bank);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 32; offs >= 0; offs -= 32)
+ {
+ int attr = spriteram[offs + 1];
+ int bank = (attr & 0xc0) >> 6;
+ int code = spriteram[offs];
+ int color = attr & 0x0f;
+ int flipx = 0;
+ int flipy = attr & 0x10;
+ int sx = spriteram[offs + 3] - ((attr & 0x20) << 3);
+ int sy = spriteram[offs + 2];
+
+ if (bank == 3) bank += sprite3bank;
+ code += 256 * bank;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[2], code, color, flipx, flipy,
+ sx, sy, cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( gunsmoke )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, gunsmoke_scrollx[0] + 256 * gunsmoke_scrollx[1]);
+ tilemap_set_scrolly(bg_tilemap, 0, gunsmoke_scrolly[0]);
+
+ if (bgon)
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ else
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ if (objon) draw_sprites(machine, bitmap, cliprect);
+ if (chon) tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/gyruss.c b/src/mame/video/gyruss.c
new file mode 100644
index 00000000000..7018f8b86df
--- /dev/null
+++ b/src/mame/video/gyruss.c
@@ -0,0 +1,218 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+static UINT8 flipscreen;
+
+/*
+sprites are multiplexed, so we have to buffer the spriteram
+scanline by scanline.
+*/
+static UINT8 *sprite_mux_buffer;
+static UINT32 scanline;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Gyruss has one 32x8 palette PROM and two 256x4 lookup table PROMs
+ (one for characters, one for sprites).
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( gyruss )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the sprite lookup table */
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = *(color_prom++) & 0x0f;
+
+ /* characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = (*(color_prom++) & 0x0f) + 0x10;
+}
+
+
+
+VIDEO_START( gyruss )
+{
+ sprite_mux_buffer = auto_malloc(256 * spriteram_size);
+
+ state_save_register_global(flipscreen);
+ state_save_register_global(scanline);
+ state_save_register_global_pointer(sprite_mux_buffer,256*spriteram_size);
+}
+
+
+
+WRITE8_HANDLER( gyruss_flipscreen_w )
+{
+ flipscreen = data & 1;
+}
+
+
+
+/* Return the current video scan line */
+READ8_HANDLER( gyruss_scanline_r )
+{
+ return scanline;
+}
+
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap)
+{
+ rectangle clip = machine->screen[0].visarea;
+ int offs;
+ int line;
+
+
+ for (line = 0;line < 256;line++)
+ {
+ UINT8 *sr;
+
+ sr = sprite_mux_buffer + line * spriteram_size;
+ clip.min_y = clip.max_y = line;
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int sx,sy;
+
+ sx = sr[offs];
+ sy = 241 - sr[offs + 3];
+ if (sy > line-16 && sy <= line)
+ {
+ drawgfx(bitmap,machine->gfx[1 + (sr[offs + 1] & 1)],
+ sr[offs + 1]/2 + 4*(sr[offs + 2] & 0x20),
+ sr[offs + 2] & 0x0f,
+ !(sr[offs + 2] & 0x40),sr[offs + 2] & 0x80,
+ sx,sy,
+ &clip,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( gyruss )
+{
+ int offs;
+
+
+ /* for every character in the Video RAM, check if it has been modified */
+ /* since last time and update it accordingly. */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int sx,sy,flipx,flipy;
+
+ sx = offs % 32;
+ sy = offs / 32;
+ flipx = colorram[offs] & 0x40;
+ flipy = colorram[offs] & 0x80;
+ if (flipscreen)
+ {
+ sx = 31 - sx;
+ sy = 31 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ videoram[offs] + 8 * (colorram[offs] & 0x20),
+ colorram[offs] & 0x0f,
+ flipx,flipy,
+ 8*sx,8*sy,
+ cliprect,TRANSPARENCY_NONE,0);
+ }
+
+
+ draw_sprites(machine, bitmap);
+
+
+ /* redraw the characters which have priority over sprites */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int sx,sy,flipx,flipy;
+
+
+ sx = offs % 32;
+ sy = offs / 32;
+ flipx = colorram[offs] & 0x40;
+ flipy = colorram[offs] & 0x80;
+ if (flipscreen)
+ {
+ sx = 31 - sx;
+ sy = 31 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if ((colorram[offs] & 0x10) != 0)
+ drawgfx(bitmap,machine->gfx[0],
+ videoram[offs] + 8 * (colorram[offs] & 0x20),
+ colorram[offs] & 0x0f,
+ flipx,flipy,
+ 8*sx,8*sy,
+ cliprect,TRANSPARENCY_NONE,0);
+ }
+ return 0;
+}
+
+
+INTERRUPT_GEN( gyruss_6809_interrupt )
+{
+ scanline = 255 - cpu_getiloops();
+
+ memcpy(sprite_mux_buffer + scanline * spriteram_size,spriteram,spriteram_size);
+
+ if (scanline == 255)
+ irq0_line_hold();
+}
diff --git a/src/mame/video/hanaawas.c b/src/mame/video/hanaawas.c
new file mode 100644
index 00000000000..a4dbfae008d
--- /dev/null
+++ b/src/mame/video/hanaawas.c
@@ -0,0 +1,118 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+***************************************************************************/
+
+PALETTE_INIT( hanaawas )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 0x10;
+ /* color_prom now points to the beginning of the lookup table */
+
+
+ /* character lookup table. The 1bpp tiles really only use colors 0-0x0f and the
+ 3bpp ones 0x10-0x1f */
+
+ for (i = 0;i < TOTAL_COLORS(0)/8 ;i++)
+ {
+ COLOR(0,i*8+0) = color_prom[i*4+0x00] & 0x0f;
+ COLOR(0,i*8+1) = color_prom[i*4+0x01] & 0x0f;
+ COLOR(0,i*8+2) = color_prom[i*4+0x02] & 0x0f;
+ COLOR(0,i*8+3) = color_prom[i*4+0x03] & 0x0f;
+ COLOR(0,i*8+4) = color_prom[i*4+0x80] & 0x0f;
+ COLOR(0,i*8+5) = color_prom[i*4+0x81] & 0x0f;
+ COLOR(0,i*8+6) = color_prom[i*4+0x82] & 0x0f;
+ COLOR(0,i*8+7) = color_prom[i*4+0x83] & 0x0f;
+ }
+}
+
+WRITE8_HANDLER( hanaawas_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( hanaawas_colorram_w )
+{
+ colorram[offset] = data;
+
+ /* dirty both current and next offsets */
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+ tilemap_mark_tile_dirty(bg_tilemap, (offset + (flip_screen ? -1 : 1)) & 0x03ff);
+}
+
+WRITE8_HANDLER( hanaawas_portB_w )
+{
+ /* bit 7 is flip screen */
+ if (flip_screen != (~data & 0x80))
+ {
+ flip_screen_set(~data & 0x80);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ /* the color is determined by the current color byte, but the bank is via the previous one!!! */
+ int offset = (tile_index + (flip_screen ? 1 : -1)) & 0x3ff;
+ int attr = colorram[offset];
+ int gfxbank = (attr & 0x40) >> 6;
+ int code = videoram[tile_index] + ((attr & 0x20) << 3);
+ int color = colorram[tile_index] & 0x1f;
+
+ SET_TILE_INFO(gfxbank, code, color, 0);
+}
+
+VIDEO_START( hanaawas )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+VIDEO_UPDATE( hanaawas )
+{
+ tilemap_draw(bitmap, &machine->screen[0].visarea, bg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/harddriv.c b/src/mame/video/harddriv.c
new file mode 100644
index 00000000000..e3d5914b8c7
--- /dev/null
+++ b/src/mame/video/harddriv.c
@@ -0,0 +1,489 @@
+/***************************************************************************
+
+ Hard Drivin' video hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "cpu/tms34010/tms34010.h"
+#include "cpu/tms34010/34010ops.h"
+#include "harddriv.h"
+
+
+
+/*************************************
+ *
+ * Constants and macros
+ *
+ *************************************/
+
+#define DISPLAY_SPEEDUPS 0
+
+#ifdef LSB_FIRST
+#define MASK(n) (0x000000ffUL << ((n) * 8))
+#else
+#define MASK(n) (0xff000000UL >> (((n) ^ 1) * 8))
+#endif
+
+
+/*************************************
+ *
+ * External definitions
+ *
+ *************************************/
+
+/* externally accessible */
+UINT8 hdgsp_multisync;
+UINT8 *hdgsp_vram;
+UINT16 *hdgsp_control_lo;
+UINT16 *hdgsp_control_hi;
+UINT16 *hdgsp_paletteram_lo;
+UINT16 *hdgsp_paletteram_hi;
+size_t hdgsp_vram_size;
+
+
+
+/*************************************
+ *
+ * Static globals
+ *
+ *************************************/
+
+static offs_t vram_mask;
+
+static UINT8 shiftreg_enable;
+
+static UINT32 *mask_table;
+static UINT8 *gsp_shiftreg_source;
+
+static offs_t gfx_offset;
+static offs_t gfx_rowbytes;
+static INT8 gfx_finescroll;
+static UINT8 gfx_palettebank;
+
+
+
+/*************************************
+ *
+ * Start/stop routines
+ *
+ *************************************/
+
+VIDEO_START( harddriv )
+{
+ UINT32 *destmask, mask;
+ int i;
+
+ shiftreg_enable = 0;
+
+ gfx_offset = 0;
+ gfx_rowbytes = 0;
+ gfx_finescroll = 0;
+ gfx_palettebank = 0;
+
+ /* allocate the mask table */
+ mask_table = auto_malloc(sizeof(UINT32) * 4 * 65536);
+
+ /* fill in the mask table */
+ destmask = mask_table;
+ for (i = 0; i < 65536; i++)
+ if (hdgsp_multisync)
+ {
+ mask = 0;
+ if (i & 0x0001) mask |= MASK(0);
+ if (i & 0x0004) mask |= MASK(1);
+ if (i & 0x0010) mask |= MASK(2);
+ if (i & 0x0040) mask |= MASK(3);
+ *destmask++ = mask;
+
+ mask = 0;
+ if (i & 0x0100) mask |= MASK(0);
+ if (i & 0x0400) mask |= MASK(1);
+ if (i & 0x1000) mask |= MASK(2);
+ if (i & 0x4000) mask |= MASK(3);
+ *destmask++ = mask;
+ }
+ else
+ {
+ mask = 0;
+ if (i & 0x0001) mask |= MASK(0);
+ if (i & 0x0002) mask |= MASK(1);
+ if (i & 0x0004) mask |= MASK(2);
+ if (i & 0x0008) mask |= MASK(3);
+ *destmask++ = mask;
+
+ mask = 0;
+ if (i & 0x0010) mask |= MASK(0);
+ if (i & 0x0020) mask |= MASK(1);
+ if (i & 0x0040) mask |= MASK(2);
+ if (i & 0x0080) mask |= MASK(3);
+ *destmask++ = mask;
+
+ mask = 0;
+ if (i & 0x0100) mask |= MASK(0);
+ if (i & 0x0200) mask |= MASK(1);
+ if (i & 0x0400) mask |= MASK(2);
+ if (i & 0x0800) mask |= MASK(3);
+ *destmask++ = mask;
+
+ mask = 0;
+ if (i & 0x1000) mask |= MASK(0);
+ if (i & 0x2000) mask |= MASK(1);
+ if (i & 0x4000) mask |= MASK(2);
+ if (i & 0x8000) mask |= MASK(3);
+ *destmask++ = mask;
+ }
+
+ /* init VRAM pointers */
+ vram_mask = hdgsp_vram_size - 1;
+}
+
+
+
+/*************************************
+ *
+ * Shift register access
+ *
+ *************************************/
+
+void hdgsp_write_to_shiftreg(UINT32 address, UINT16 *shiftreg)
+{
+ /* access to the 1bpp/2bpp area */
+ if (address >= 0x02000000 && address <= 0x020fffff)
+ {
+ address -= 0x02000000;
+ address >>= hdgsp_multisync;
+ address &= vram_mask;
+ address &= ~((512*8 >> hdgsp_multisync) - 1);
+ gsp_shiftreg_source = &hdgsp_vram[address];
+ }
+
+ /* access to normal VRAM area */
+ else if (address >= 0xff800000 && address <= 0xffffffff)
+ {
+ address -= 0xff800000;
+ address /= 8;
+ address &= vram_mask;
+ address &= ~511;
+ gsp_shiftreg_source = &hdgsp_vram[address];
+ }
+ else
+ logerror("Unknown shiftreg write %08X\n", address);
+}
+
+
+void hdgsp_read_from_shiftreg(UINT32 address, UINT16 *shiftreg)
+{
+ if (!shiftreg_enable)
+ return;
+
+ /* access to the 1bpp/2bpp area */
+ if (address >= 0x02000000 && address <= 0x020fffff)
+ {
+ address -= 0x02000000;
+ address >>= hdgsp_multisync;
+ address &= vram_mask;
+ address &= ~((512*8 >> hdgsp_multisync) - 1);
+ memmove(&hdgsp_vram[address], gsp_shiftreg_source, 512*8 >> hdgsp_multisync);
+ }
+
+ /* access to normal VRAM area */
+ else if (address >= 0xff800000 && address <= 0xffffffff)
+ {
+ address -= 0xff800000;
+ address /= 8;
+ address &= vram_mask;
+ address &= ~511;
+ memmove(&hdgsp_vram[address], gsp_shiftreg_source, 512);
+ }
+ else
+ logerror("Unknown shiftreg read %08X\n", address);
+}
+
+
+
+/*************************************
+ *
+ * Palette bank updating
+ *
+ *************************************/
+
+static void update_palette_bank(int newbank)
+{
+ if (gfx_palettebank != newbank)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ gfx_palettebank = newbank;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video control registers (lo)
+ *
+ *************************************/
+
+READ16_HANDLER( hdgsp_control_lo_r )
+{
+ return hdgsp_control_lo[offset];
+}
+
+
+WRITE16_HANDLER( hdgsp_control_lo_w )
+{
+ int oldword = hdgsp_control_lo[offset];
+ int newword;
+
+ COMBINE_DATA(&hdgsp_control_lo[offset]);
+ newword = hdgsp_control_lo[offset];
+
+ if (oldword != newword && offset != 0)
+ logerror("GSP:hdgsp_control_lo(%X)=%04X\n", offset, newword);
+}
+
+
+
+/*************************************
+ *
+ * Video control registers (hi)
+ *
+ *************************************/
+
+READ16_HANDLER( hdgsp_control_hi_r )
+{
+ return hdgsp_control_hi[offset];
+}
+
+
+WRITE16_HANDLER( hdgsp_control_hi_w )
+{
+ int val = (offset >> 3) & 1;
+
+ int oldword = hdgsp_control_hi[offset];
+ int newword;
+
+ COMBINE_DATA(&hdgsp_control_hi[offset]);
+ newword = hdgsp_control_hi[offset];
+
+ switch (offset & 7)
+ {
+ case 0x00:
+ shiftreg_enable = val;
+ break;
+
+ case 0x01:
+ data = data & (15 >> hdgsp_multisync);
+ if (gfx_finescroll != data)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+ gfx_finescroll = data;
+ }
+ break;
+
+ case 0x02:
+ update_palette_bank((gfx_palettebank & ~1) | val);
+ break;
+
+ case 0x03:
+ update_palette_bank((gfx_palettebank & ~2) | (val << 1));
+ break;
+
+ case 0x04:
+ if (Machine->drv->total_colors >= 256 * 8)
+ update_palette_bank((gfx_palettebank & ~4) | (val << 2));
+ break;
+
+ case 0x07:
+ /* LED */
+ break;
+
+ default:
+ if (oldword != newword)
+ logerror("GSP:hdgsp_control_hi_w(%X)=%04X\n", offset, newword);
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video RAM expanders
+ *
+ *************************************/
+
+READ16_HANDLER( hdgsp_vram_2bpp_r )
+{
+ return 0;
+}
+
+
+WRITE16_HANDLER( hdgsp_vram_1bpp_w )
+{
+ UINT32 *dest = (UINT32 *)&hdgsp_vram[offset * 16];
+ UINT32 *mask = &mask_table[data * 4];
+ UINT32 color = hdgsp_control_lo[0] & 0xff;
+ UINT32 curmask;
+
+ color |= color << 8;
+ color |= color << 16;
+
+ curmask = *mask++;
+ *dest = (*dest & ~curmask) | (color & curmask);
+ dest++;
+
+ curmask = *mask++;
+ *dest = (*dest & ~curmask) | (color & curmask);
+ dest++;
+
+ curmask = *mask++;
+ *dest = (*dest & ~curmask) | (color & curmask);
+ dest++;
+
+ curmask = *mask++;
+ *dest = (*dest & ~curmask) | (color & curmask);
+ dest++;
+}
+
+
+WRITE16_HANDLER( hdgsp_vram_2bpp_w )
+{
+ UINT32 *dest = (UINT32 *)&hdgsp_vram[offset * 8];
+ UINT32 *mask = &mask_table[data * 2];
+ UINT32 color = hdgsp_control_lo[0];
+ UINT32 curmask;
+
+ color |= color << 16;
+
+ curmask = *mask++;
+ *dest = (*dest & ~curmask) | (color & curmask);
+ dest++;
+
+ curmask = *mask++;
+ *dest = (*dest & ~curmask) | (color & curmask);
+ dest++;
+}
+
+
+
+/*************************************
+ *
+ * Palette registers (lo)
+ *
+ *************************************/
+
+INLINE void gsp_palette_change(int offset)
+{
+ int red = (hdgsp_paletteram_lo[offset] >> 8) & 0xff;
+ int green = hdgsp_paletteram_lo[offset] & 0xff;
+ int blue = hdgsp_paletteram_hi[offset] & 0xff;
+ palette_set_color(Machine, offset, MAKE_RGB(red, green, blue));
+}
+
+
+READ16_HANDLER( hdgsp_paletteram_lo_r )
+{
+ /* note that the palette is only accessed via the first 256 entries */
+ /* others are selected via the palette bank */
+ offset = gfx_palettebank * 0x100 + (offset & 0xff);
+
+ return hdgsp_paletteram_lo[offset];
+}
+
+
+WRITE16_HANDLER( hdgsp_paletteram_lo_w )
+{
+ /* note that the palette is only accessed via the first 256 entries */
+ /* others are selected via the palette bank */
+ offset = gfx_palettebank * 0x100 + (offset & 0xff);
+
+ COMBINE_DATA(&hdgsp_paletteram_lo[offset]);
+ gsp_palette_change(offset);
+}
+
+
+
+/*************************************
+ *
+ * Palette registers (hi)
+ *
+ *************************************/
+
+READ16_HANDLER( hdgsp_paletteram_hi_r )
+{
+ /* note that the palette is only accessed via the first 256 entries */
+ /* others are selected via the palette bank */
+ offset = gfx_palettebank * 0x100 + (offset & 0xff);
+
+ return hdgsp_paletteram_hi[offset];
+}
+
+
+WRITE16_HANDLER( hdgsp_paletteram_hi_w )
+{
+ /* note that the palette is only accessed via the first 256 entries */
+ /* others are selected via the palette bank */
+ offset = gfx_palettebank * 0x100 + (offset & 0xff);
+
+ COMBINE_DATA(&hdgsp_paletteram_hi[offset]);
+ gsp_palette_change(offset);
+}
+
+
+
+/*************************************
+ *
+ * Core refresh routine
+ *
+ *************************************/
+
+static void display_speedups(void)
+{
+#if DISPLAY_SPEEDUPS
+ char temp[200];
+ sprintf(temp, "GSP:%d/%d/%d/%d",
+ gsp_speedup_count[0], gsp_speedup_count[1],
+ gsp_speedup_count[2], gsp_speedup_count[3]);
+ ui_draw_text(temp, 0, 0);
+ sprintf(temp, "MSP:%d/%d/%d/%d",
+ msp_speedup_count[0], msp_speedup_count[1],
+ msp_speedup_count[2], msp_speedup_count[3]);
+ ui_draw_text(temp, 0, 10);
+ sprintf(temp, "ADSP:%d/%d/%d/%d",
+ adsp_speedup_count[0], adsp_speedup_count[1],
+ adsp_speedup_count[2], adsp_speedup_count[3]);
+ ui_draw_text(temp, 0, 20);
+#endif
+}
+
+
+void harddriv_scanline_driver(running_machine *machine, int screen, mame_bitmap *bitmap, int scanline, const tms34010_display_params *params)
+{
+ UINT8 *vram_base = &hdgsp_vram[(params->rowaddr << 12) & vram_mask];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0);
+ int coladdr = (params->yoffset << 9) + ((params->coladdr & 0xff) << 4) - 15 + (gfx_finescroll & 0x0f);
+ int x;
+
+ for (x = params->heblnk; x < params->hsblnk; x++)
+ dest[x] = gfx_palettebank * 256 + vram_base[BYTE_XOR_LE(coladdr++ & 0xfff)];
+
+ if (scanline == machine->screen[screen].visarea.max_y)
+ display_speedups();
+}
+
+
+void harddriv_scanline_multisync(running_machine *machine, int screen, mame_bitmap *bitmap, int scanline, const tms34010_display_params *params)
+{
+ UINT8 *vram_base = &hdgsp_vram[(params->rowaddr << 11) & vram_mask];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0);
+ int coladdr = (params->yoffset << 9) + ((params->coladdr & 0xff) << 3) - 7 + (gfx_finescroll & 0x07);
+ int x;
+
+ for (x = params->heblnk; x < params->hsblnk; x++)
+ dest[x] = gfx_palettebank * 256 + vram_base[BYTE_XOR_LE(coladdr++ & 0x7ff)];
+
+ if (scanline == machine->screen[screen].visarea.max_y)
+ display_speedups();
+}
diff --git a/src/mame/video/hcastle.c b/src/mame/video/hcastle.c
new file mode 100644
index 00000000000..b06e133b735
--- /dev/null
+++ b/src/mame/video/hcastle.c
@@ -0,0 +1,231 @@
+/***************************************************************************
+
+ Haunted Castle video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+UINT8 *hcastle_pf1_videoram,*hcastle_pf2_videoram;
+static int gfx_bank;
+
+static tilemap *fg_tilemap,*bg_tilemap;
+static int pf2_bankbase,pf1_bankbase;
+
+
+PALETTE_INIT( hcastle )
+{
+ int i,chip,pal,clut;
+
+ for (chip = 0;chip < 2;chip++)
+ {
+ for (pal = 0;pal < 8;pal++)
+ {
+ clut = (pal & 1) + 2 * chip;
+ for (i = 0;i < 256;i++)
+ {
+ if ((pal & 1) == 0) /* sprites */
+ {
+ if (color_prom[256 * clut + i] == 0)
+ *(colortable++) = 0;
+ else
+ *(colortable++) = 16 * pal + color_prom[256 * clut + i];
+ }
+ else
+ *(colortable++) = 16 * pal + color_prom[256 * clut + i];
+ }
+ }
+ }
+}
+
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( tilemap_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x20) << 6); /* skip 0x400 */
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int bit0 = (K007121_ctrlram[0][0x05] >> 0) & 0x03;
+ int bit1 = (K007121_ctrlram[0][0x05] >> 2) & 0x03;
+ int bit2 = (K007121_ctrlram[0][0x05] >> 4) & 0x03;
+ int bit3 = (K007121_ctrlram[0][0x05] >> 6) & 0x03;
+ int attr = hcastle_pf1_videoram[tile_index];
+ int tile = hcastle_pf1_videoram[tile_index + 0x400];
+ int color = attr & 0x7;
+ int bank = ((attr & 0x80) >> 7) |
+ ((attr >> (bit0+2)) & 0x02) |
+ ((attr >> (bit1+1)) & 0x04) |
+ ((attr >> (bit2 )) & 0x08) |
+ ((attr >> (bit3-1)) & 0x10);
+
+ SET_TILE_INFO(
+ 0,
+ tile + bank*0x100 + pf1_bankbase,
+ ((K007121_ctrlram[0][6]&0x30)*2+16) + color,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int bit0 = (K007121_ctrlram[1][0x05] >> 0) & 0x03;
+ int bit1 = (K007121_ctrlram[1][0x05] >> 2) & 0x03;
+ int bit2 = (K007121_ctrlram[1][0x05] >> 4) & 0x03;
+ int bit3 = (K007121_ctrlram[1][0x05] >> 6) & 0x03;
+ int attr = hcastle_pf2_videoram[tile_index];
+ int tile = hcastle_pf2_videoram[tile_index + 0x400];
+ int color = attr & 0x7;
+ int bank = ((attr & 0x80) >> 7) |
+ ((attr >> (bit0+2)) & 0x02) |
+ ((attr >> (bit1+1)) & 0x04) |
+ ((attr >> (bit2 )) & 0x08) |
+ ((attr >> (bit3-1)) & 0x10);
+
+ SET_TILE_INFO(
+ 1,
+ tile + bank*0x100 + pf2_bankbase,
+ ((K007121_ctrlram[1][6]&0x30)*2+16) + color,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( hcastle )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan,TILEMAP_TYPE_PEN,8,8,64,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan,TILEMAP_TYPE_PEN, 8,8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( hcastle_pf1_video_w )
+{
+ hcastle_pf1_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0xbff);
+}
+
+WRITE8_HANDLER( hcastle_pf2_video_w )
+{
+ hcastle_pf2_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0xbff);
+}
+
+WRITE8_HANDLER( hcastle_gfxbank_w )
+{
+ gfx_bank = data;
+}
+
+READ8_HANDLER( hcastle_gfxbank_r )
+{
+ return gfx_bank;
+}
+
+WRITE8_HANDLER( hcastle_pf1_control_w )
+{
+ if (offset==3)
+ {
+ if ((data&0x8)==0)
+ buffer_spriteram(spriteram+0x800,0x800);
+ else
+ buffer_spriteram(spriteram,0x800);
+ }
+ else if (offset == 7)
+ {
+ tilemap_set_flip(fg_tilemap, (data & 0x08) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ }
+ K007121_ctrl_0_w(offset,data);
+}
+
+WRITE8_HANDLER( hcastle_pf2_control_w )
+{
+ if (offset==3)
+ {
+ if ((data&0x8)==0)
+ buffer_spriteram_2(spriteram_2+0x800,0x800);
+ else
+ buffer_spriteram_2(spriteram_2,0x800);
+ }
+ else if (offset == 7)
+ {
+ tilemap_set_flip(bg_tilemap, (data & 0x08) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ }
+ K007121_ctrl_1_w(offset,data);
+}
+
+/*****************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8 *sbank, int bank )
+{
+ int bank_base = (bank == 0) ? 0x4000 * (gfx_bank & 1) : 0;
+ K007121_sprites_draw(machine,bank,bitmap,cliprect,sbank,(K007121_ctrlram[bank][6]&0x30)*2,0,bank_base,-1);
+}
+
+/*****************************************************************************/
+
+VIDEO_UPDATE( hcastle )
+{
+ static int old_pf1,old_pf2;
+
+
+ pf1_bankbase = 0x0000;
+ pf2_bankbase = 0x4000 * ((gfx_bank & 2) >> 1);
+
+ if (K007121_ctrlram[0][3] & 0x01) pf1_bankbase += 0x2000;
+ if (K007121_ctrlram[1][3] & 0x01) pf2_bankbase += 0x2000;
+
+ if (pf1_bankbase != old_pf1)
+ tilemap_mark_all_tiles_dirty(fg_tilemap);
+
+ if (pf2_bankbase != old_pf2)
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+
+ old_pf1 = pf1_bankbase;
+ old_pf2 = pf2_bankbase;
+
+ tilemap_set_scrolly(bg_tilemap,0,K007121_ctrlram[1][2]);
+ tilemap_set_scrollx(bg_tilemap,0,((K007121_ctrlram[1][1]<<8)+K007121_ctrlram[1][0]));
+ tilemap_set_scrolly(fg_tilemap,0,K007121_ctrlram[0][2]);
+ tilemap_set_scrollx(fg_tilemap,0,((K007121_ctrlram[0][1]<<8)+K007121_ctrlram[0][0]));
+
+// /* Sprite priority */
+// if (K007121_ctrlram[0][3]&0x20)
+ if ((gfx_bank & 0x04) == 0)
+ {
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites( machine,bitmap,cliprect, buffered_spriteram, 0 );
+ draw_sprites( machine,bitmap,cliprect, buffered_spriteram_2, 1 );
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ }
+ else
+ {
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ draw_sprites( machine,bitmap,cliprect, buffered_spriteram, 0 );
+ draw_sprites( machine,bitmap,cliprect, buffered_spriteram_2, 1 );
+ }
+ return 0;
+}
diff --git a/src/mame/video/hexa.c b/src/mame/video/hexa.c
new file mode 100644
index 00000000000..d93bd653b81
--- /dev/null
+++ b/src/mame/video/hexa.c
@@ -0,0 +1,75 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static int charbank;
+static tilemap *bg_tilemap;
+
+WRITE8_HANDLER( hexa_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+WRITE8_HANDLER( hexa_d008_w )
+{
+ UINT8 *RAM = memory_region(REGION_CPU1);
+ int bankaddress;
+
+ /* bit 0 = flipx (or y?) */
+ if (flip_screen_x != (data & 0x01))
+ {
+ flip_screen_x_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ /* bit 1 = flipy (or x?) */
+ if (flip_screen_y != (data & 0x02))
+ {
+ flip_screen_y_set(data & 0x02);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ /* bit 2 - 3 unknown */
+
+ /* bit 4 could be the ROM bank selector for 8000-bfff (not sure) */
+ bankaddress = 0x10000 + ((data & 0x10) >> 4) * 0x4000;
+ memory_set_bankptr(1, &RAM[bankaddress]);
+
+ /* bit 5 = char bank */
+ if (charbank != ((data & 0x20) >> 5))
+ {
+ charbank = (data & 0x20) >> 5;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ /* bit 6 - 7 unknown */
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int offs = tile_index * 2;
+ int tile = videoram[offs + 1] + ((videoram[offs] & 0x07) << 8) + (charbank << 11);
+ int color = (videoram[offs] & 0xf8) >> 3;
+
+ SET_TILE_INFO(0, tile, color, 0);
+}
+
+VIDEO_START( hexa )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+
+VIDEO_UPDATE( hexa )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/hexion.c b/src/mame/video/hexion.c
new file mode 100644
index 00000000000..92b151a084d
--- /dev/null
+++ b/src/mame/video/hexion.c
@@ -0,0 +1,168 @@
+#include "driver.h"
+
+
+static UINT8 *vram[2],*unkram;
+static int bankctrl,rambank,pmcbank,gfxrom_select;
+static tilemap *bg_tilemap[2];
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+INLINE void get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,UINT8 *ram)
+{
+ tile_index *= 4;
+ SET_TILE_INFO(
+ 0,
+ ram[tile_index] + ((ram[tile_index+1] & 0x3f) << 8),
+ ram[tile_index+2] & 0x0f,
+ 0);
+}
+
+static TILE_GET_INFO( get_tile_info0 )
+{
+ get_tile_info(machine,tileinfo,tile_index,vram[0]);
+}
+
+static TILE_GET_INFO( get_tile_info1 )
+{
+ get_tile_info(machine,tileinfo,tile_index,vram[1]);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( hexion )
+{
+ bg_tilemap[0] = tilemap_create(get_tile_info0,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ bg_tilemap[1] = tilemap_create(get_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,32);
+
+ tilemap_set_transparent_pen(bg_tilemap[0],0);
+ tilemap_set_scrollx(bg_tilemap[1],0,-4);
+ tilemap_set_scrolly(bg_tilemap[1],0,4);
+
+ vram[0] = memory_region(REGION_CPU1) + 0x30000;
+ vram[1] = vram[0] + 0x2000;
+ unkram = vram[1] + 0x2000;
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( hexion_bankswitch_w )
+{
+ UINT8 *rom = memory_region(REGION_CPU1) + 0x10000;
+
+ /* bits 0-3 select ROM bank */
+ memory_set_bankptr(1,rom + 0x2000 * (data & 0x0f));
+
+ /* does bit 6 trigger the 052591? */
+ if (data & 0x40)
+ {
+ int bank = unkram[0]&1;
+ memset(vram[bank],unkram[1],0x2000);
+ tilemap_mark_all_tiles_dirty(bg_tilemap[bank]);
+ }
+ /* bit 7 = PMC-BK */
+ pmcbank = (data & 0x80) >> 7;
+
+ /* other bits unknown */
+if (data & 0x30)
+ popmessage("bankswitch %02x",data&0xf0);
+
+//logerror("%04x: bankswitch_w %02x\n",activecpu_get_pc(),data);
+}
+
+READ8_HANDLER( hexion_bankedram_r )
+{
+ if (gfxrom_select && offset < 0x1000)
+ {
+ return memory_region(REGION_GFX1)[((gfxrom_select & 0x7f) << 12) + offset];
+ }
+ else if (bankctrl == 0)
+ {
+ return vram[rambank][offset];
+ }
+ else if (bankctrl == 2 && offset < 0x800)
+ {
+ return unkram[offset];
+ }
+ else
+ {
+//logerror("%04x: bankedram_r offset %04x, bankctrl = %02x\n",activecpu_get_pc(),offset,bankctrl);
+ return 0;
+ }
+}
+
+WRITE8_HANDLER( hexion_bankedram_w )
+{
+ if (bankctrl == 3 && offset == 0 && (data & 0xfe) == 0)
+ {
+//logerror("%04x: bankedram_w offset %04x, data %02x, bankctrl = %02x\n",activecpu_get_pc(),offset,data,bankctrl);
+ rambank = data & 1;
+ }
+ else if (bankctrl == 0)
+ {
+ if (pmcbank)
+ {
+//logerror("%04x: bankedram_w offset %04x, data %02x, bankctrl = %02x\n",activecpu_get_pc(),offset,data,bankctrl);
+ vram[rambank][offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap[rambank],offset/4);
+ }
+ else
+ logerror("%04x pmc internal ram %04x = %02x\n",activecpu_get_pc(),offset,data);
+ }
+ else if (bankctrl == 2 && offset < 0x800)
+ {
+ if (pmcbank)
+ {
+//logerror("%04x: unkram_w offset %04x, data %02x, bankctrl = %02x\n",activecpu_get_pc(),offset,data,bankctrl);
+ unkram[offset] = data;
+ }
+ else
+ logerror("%04x pmc internal ram %04x = %02x\n",activecpu_get_pc(),offset,data);
+ }
+ else
+logerror("%04x: bankedram_w offset %04x, data %02x, bankctrl = %02x\n",activecpu_get_pc(),offset,data,bankctrl);
+}
+
+WRITE8_HANDLER( hexion_bankctrl_w )
+{
+//logerror("%04x: bankctrl_w %02x\n",activecpu_get_pc(),data);
+ bankctrl = data;
+}
+
+WRITE8_HANDLER( hexion_gfxrom_select_w )
+{
+//logerror("%04x: gfxrom_select_w %02x\n",activecpu_get_pc(),data);
+ gfxrom_select = data;
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( hexion )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap[1],0,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap[0],0,0);
+ return 0;
+}
diff --git a/src/mame/video/higemaru.c b/src/mame/video/higemaru.c
new file mode 100644
index 00000000000..4a023da49af
--- /dev/null
+++ b/src/mame/video/higemaru.c
@@ -0,0 +1,140 @@
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+WRITE8_HANDLER( higemaru_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( higemaru_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+***************************************************************************/
+PALETTE_INIT( higemaru )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* characters use colors 0-15 */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = *(color_prom++) & 0x0f;
+
+ color_prom += 128; /* the bottom half of the PROM doesn't seem to be used */
+
+ /* sprites use colors 16-31 */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = (*(color_prom++) & 0x0f) + 0x10;
+}
+
+WRITE8_HANDLER( higemaru_c800_w )
+{
+ if (data & 0x7c) logerror("c800 = %02x\n",data);
+
+ /* bits 0 and 1 are coin counters */
+ coin_counter_w(0,data & 2);
+ coin_counter_w(1,data & 1);
+
+ /* bit 7 flips screen */
+ if (flip_screen != (data & 0x80))
+ {
+ flip_screen_set(data & 0x80);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + ((colorram[tile_index] & 0x80) << 1);
+ int color = colorram[tile_index] & 0x1f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( higemaru )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 16;offs >= 0;offs -= 16)
+ {
+ int code,col,sx,sy,flipx,flipy;
+
+ code = spriteram[offs] & 0x7f;
+ col = spriteram[offs + 4] & 0x0f;
+ sx = spriteram[offs + 12];
+ sy = spriteram[offs + 8];
+ flipx = spriteram[offs + 4] & 0x10;
+ flipy = spriteram[offs + 4] & 0x20;
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ col,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+
+ /* draw again with wraparound */
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ col,
+ flipx,flipy,
+ sx - 256,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+VIDEO_UPDATE( higemaru )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/hnayayoi.c b/src/mame/video/hnayayoi.c
new file mode 100644
index 00000000000..bdb9eccb074
--- /dev/null
+++ b/src/mame/video/hnayayoi.c
@@ -0,0 +1,274 @@
+/***************************************************************************
+
+First version of the Dynax blitter.
+
+Can handle up to 8 256x256 bitmaps; in the games supported, every pair of
+bitmaps is interleaved horizontally to form 4 higher res 512x256 layer.
+
+The blitter reads compressed data from ROM and copies it to the bitmap RAM.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+static UINT8 *pixmap[8];
+static int palbank;
+static int total_pixmaps;
+
+
+static void common_vh_start(int num_pixmaps)
+{
+ int i;
+
+ total_pixmaps = num_pixmaps;
+
+ for (i = 0;i < 8;i++)
+ {
+ if (i < total_pixmaps)
+ {
+ pixmap[i] = auto_malloc(256*256);
+ }
+ else
+ pixmap[i] = NULL;
+ }
+}
+
+VIDEO_START( hnayayoi )
+{
+ common_vh_start(4); /* 4 bitmaps -> 2 layers */
+}
+
+VIDEO_START( untoucha )
+{
+ common_vh_start(8); /* 8 bitmaps -> 4 layers */
+}
+
+
+
+/***************************************************************************
+
+Blitter support
+
+three parameters:
+blit_layer: mask of the bitmaps to write to (can write to multiple bitmaps
+ at the same time)
+blit_dest: position in the destination bitmap where to start blitting
+blit_src: address of source data in the gfx ROM
+
+additional parameters specify the palette base, but this is handled while rendering
+the screen, not during blitting (games change the palette base without redrawing
+the screen).
+
+It is not known whether the palette base control registers are part of the blitter
+hardware or latched somewhere else. Since they are mapped in memory immediately
+before the bitter parameters, they probably are part of the blitter, but I'm
+handling them separately anyway.
+
+
+The format of the blitter data stored in ROM is very simple:
+
+7654 ---- Pen to draw with
+---- 3210 Command
+
+Commands:
+
+0 Stop
+1-b Draw 1-b pixels along X.
+c Followed by 1 byte (N): draw N pixels along X.
+d Followed by 2 bytes (X,N): move on the line to pixel (start+X), draw N pixels
+ along X.
+e Followed by 1 byte (N): set blit_layer = N. Used to draw interleaved graphics
+ with a single blitter run.
+f Move to next line.
+
+At the end of the blit, blit_src is left pointing to the next data in the gfx ROM.
+This is used to draw interleaved graphics with two blitter runs without having to set
+up blit_src for the second call.
+
+***************************************************************************/
+
+static UINT8 blit_layer;
+static UINT16 blit_dest;
+static UINT32 blit_src;
+
+WRITE8_HANDLER( dynax_blitter_rev1_param_w )
+{
+ switch (offset)
+ {
+ case 0: blit_dest = (blit_dest & 0xff00) | (data << 0); break;
+ case 1: blit_dest = (blit_dest & 0x00ff) | (data << 8); break;
+ case 2: blit_layer = data; break;
+ case 3: blit_src = (blit_src & 0xffff00) | (data << 0); break;
+ case 4: blit_src = (blit_src & 0xff00ff) | (data << 8); break;
+ case 5: blit_src = (blit_src & 0x00ffff) | (data <<16); break;
+ }
+}
+
+static void copy_pixel(int x,int y,int pen)
+{
+ if (x >= 0 && x <= 255 && y >= 0 && y <= 255)
+ {
+ int i;
+
+ for (i = 0;i < 8;i++)
+ {
+ if ((~blit_layer & (1 << i)) && (pixmap[i]))
+ pixmap[i][256*y+x] = pen;
+ }
+ }
+}
+
+WRITE8_HANDLER( dynax_blitter_rev1_start_w )
+{
+ UINT8 *rom = memory_region(REGION_GFX1);
+ int romlen = memory_region_length(REGION_GFX1);
+ int sx = blit_dest & 0xff;
+ int sy = blit_dest >> 8;
+ int x,y;
+
+ x = sx;
+ y = sy;
+ while (blit_src < romlen)
+ {
+ int cmd = rom[blit_src] & 0x0f;
+ int pen = rom[blit_src] >> 4;
+
+ blit_src++;
+
+ switch (cmd)
+ {
+ case 0xf:
+ y++;
+ x = sx;
+ break;
+
+ case 0xe:
+ if (blit_src >= romlen)
+ {
+ popmessage("GFXROM OVER %06x",blit_src);
+ return;
+ }
+ x = sx;
+ blit_layer = rom[blit_src++];
+ break;
+
+ case 0xd:
+ if (blit_src >= romlen)
+ {
+ popmessage("GFXROM OVER %06x",blit_src);
+ return;
+ }
+ x = sx + rom[blit_src++];
+ /* fall through into next case */
+
+ case 0xc:
+ if (blit_src >= romlen)
+ {
+ popmessage("GFXROM OVER %06x",blit_src);
+ return;
+ }
+ cmd = rom[blit_src++];
+ /* fall through into next case */
+
+ case 0xb:
+ case 0xa:
+ case 0x9:
+ case 0x8:
+ case 0x7:
+ case 0x6:
+ case 0x5:
+ case 0x4:
+ case 0x3:
+ case 0x2:
+ case 0x1:
+ while (cmd--)
+ copy_pixel(x++,y,pen);
+ break;
+
+ case 0x0:
+ return;
+ }
+ }
+
+ popmessage("GFXROM OVER %06x",blit_src);
+}
+
+WRITE8_HANDLER( dynax_blitter_rev1_clear_w )
+{
+ int pen = data >> 4;
+ int i;
+
+ for (i = 0;i < 8;i++)
+ {
+ if ((~blit_layer & (1 << i)) && (pixmap[i]))
+ memset(pixmap[i] + blit_dest, pen, 0x10000 - blit_dest);
+ }
+}
+
+
+WRITE8_HANDLER( hnayayoi_palbank_w )
+{
+ offset *= 8;
+ palbank = (palbank & (0xff00 >> offset)) | (data << offset);
+}
+
+
+static void draw_layer_interleaved(mame_bitmap *bitmap, const rectangle *cliprect,
+ int left_pixmap, int right_pixmap, int palbase, int transp)
+{
+ int county,countx,pen,offs;
+ UINT8 *src1 = pixmap[left_pixmap];
+ UINT8 *src2 = pixmap[right_pixmap];
+ UINT16 *dstbase = (UINT16 *)bitmap->base;
+
+ palbase *= 16;
+ offs = 0;
+
+ for (county = 255; county >= 0; county--, dstbase += bitmap->rowpixels)
+ {
+ UINT16 *dst = dstbase;
+
+ if (transp)
+ {
+ for (countx = 255; countx >= 0; countx--, dst += 2)
+ {
+ pen = *(src1++);
+ if (pen) *dst = palbase + pen;
+ pen = *(src2++);
+ if (pen) *(dst+1) = palbase + pen;
+ }
+ }
+ else
+ {
+ for (countx = 255; countx >= 0; countx--, dst += 2)
+ {
+ *dst = palbase + *(src1++);
+ *(dst+1) = palbase + *(src2++);
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( hnayayoi )
+{
+ int col0 = (palbank >> 0) & 0x0f;
+ int col1 = (palbank >> 4) & 0x0f;
+ int col2 = (palbank >> 8) & 0x0f;
+ int col3 = (palbank >> 12) & 0x0f;
+
+ if (total_pixmaps == 4)
+ {
+ draw_layer_interleaved(bitmap,cliprect,3,2,col1,0);
+ draw_layer_interleaved(bitmap,cliprect,1,0,col0,1);
+ }
+ else /* total_pixmaps == 8 */
+ {
+ draw_layer_interleaved(bitmap,cliprect,7,6,col3,0);
+ draw_layer_interleaved(bitmap,cliprect,5,4,col2,1);
+ draw_layer_interleaved(bitmap,cliprect,3,2,col1,1);
+ draw_layer_interleaved(bitmap,cliprect,1,0,col0,1);
+ }
+ return 0;
+}
diff --git a/src/mame/video/hng64.c b/src/mame/video/hng64.c
new file mode 100644
index 00000000000..8a0af6c22ce
--- /dev/null
+++ b/src/mame/video/hng64.c
@@ -0,0 +1,2083 @@
+#include "driver.h"
+
+#include <math.h>
+
+
+// !!! I'm sure this isn't right !!!
+UINT32 hng64_dls[2][0x81] ;
+
+static int frameCount = 0 ;
+
+UINT32* hng64_videoram;
+tilemap *hng64_tilemap0;
+tilemap *hng64_tilemap1;
+tilemap *hng64_tilemap2;
+tilemap *hng64_tilemap3;
+
+UINT32 *hng64_spriteram;
+UINT32 *hng64_videoregs;
+
+UINT32 *hng64_tcram ;
+
+/* HAAAACK to make the floor 'work' */
+UINT32 hng64_hackTilemap3, hng64_hackTm3Count, hng64_rowScrollOffset ;
+
+
+static void matmul4( float *product, const float *a, const float *b ) ;
+static void vecmatmul4( float *product, const float *a, const float *b) ;
+//static float vecDotProduct( const float *a, const float *b) ;
+//static void normalize(float* x) ;
+
+// 3d helpers
+static float uToF(UINT16 input) ;
+static void SetIdentity(float *matrix) ;
+
+
+//static void plot(INT32 x, INT32 y, INT32 color, mame_bitmap *bitmap) ;
+//static void drawline2d(INT32 x0, INT32 y0, INT32 x1, INT32 y1, INT32 color, mame_bitmap *bitmap) ;
+
+static float *depthBuffer ;
+static struct polygon *polys ;
+
+//static int tilemap2Offset = 0x10000 ;
+
+
+#define WORD_AT(BUFFER,OFFSET) ( (BUFFER[OFFSET] << 8) | BUFFER[OFFSET+1] )
+
+
+/*
+ * Sprite Format
+ * ------------------
+ *
+ * UINT32 | Bytes | Use
+ * -------+-76543210-+----------------
+ * 0 | xxxx---- | y position
+ * 0 | ----xxxx | x position
+ * 1 | xxxx---- | y zoom
+ * 1 | ----xxxx | x zoom
+ * 2 | ------x- | x chain
+ * 2 | -------x | y chain
+ * 2 | xxxx---- | end of sprite list - though it surely contains more info !
+ * 2 | ----oo-- | not used ??
+ * 3 | --xx---- | palette entry
+ * 3 | --x----- | (bit 0x8) - maybe a graphics bank selector
+ * 3 | oo--oooo | not used ?
+ * 4 | --xxxxxx | tile number
+ * 4 | --x----- | (bit 0x2) - x flip
+ * 4 | --x----- | (bit 0x1) - y flip
+ * 4 | oo------ | not used ??
+ * 5 | oooooooo | not used ??
+ * 6 | oooooooo | not used ??
+ * 7 | oooooooo | not used ??
+ */
+
+/* xxxx---- | I think this part of UINT32 2 is interesting as more than just a list end marker (AJG)
+ */
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const gfx_element *gfx;
+ UINT32 *source = hng64_spriteram;
+ UINT32 *finish = hng64_spriteram + 0xb000/4;
+
+ /* find end of list? */
+ while( source<finish)
+ {
+ int endlist;
+
+ endlist=(source[2]&0xffff0000)>>16;
+ if (endlist == 0x07ff) break;
+ source+=8;
+ }
+
+// for (int iii = 0; iii < 0x0f; iii++)
+// mame_printf_debug("%.8x ", hng64_videoregs[iii]) ;
+
+// mame_printf_debug("\n") ;
+
+ finish = hng64_spriteram;
+
+ /* draw backwards .. */
+ while( source>finish )
+ {
+ int xpos, ypos, tileno,chainx,chainy,xflip;
+ int xdrw,ydrw,pal,xinc,yinc,yflip;
+ UINT32 zoomx,zoomy;
+ float foomX, foomY;
+ source-=8;
+
+ ypos = (source[0]&0xffff0000)>>16;
+ xpos = (source[0]&0x0000ffff)>>0;
+ tileno=(source[4]&0x00ffffff);
+ chainx=(source[2]&0x000000f0)>>4;
+ chainy=(source[2]&0x0000000f);
+
+ zoomy = (source[1]&0xffff0000)>>16;
+ zoomx = (source[1]&0x0000ffff)>>0;
+
+ pal =(source[3]&0x00ff0000)>>16;
+ xflip=(source[4]&0x02000000)>>25;
+ yflip=(source[4]&0x01000000)>>24;
+
+ if(xpos&0x8000) xpos -=0x10000;
+ if(ypos&0x8000) ypos -=0x10000;
+
+
+// if (!(source[4] == 0x00000000 || source[4] == 0x000000aa))
+// mame_printf_debug("unknown : %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x \n", source[0], source[1], source[2], source[3],
+// source[4], source[5], source[6], source[7]) ;
+
+ /* Calculate the zoom */
+ /* First, prevent any possible divide by zero errors */
+ if(!zoomx) zoomx=0x1000;
+ if(!zoomy) zoomy=0x1000;
+
+ foomX = (float)(0x1000) / (float)zoomx ;
+ foomY = (float)(0x1000) / (float)zoomy ;
+
+ zoomx = ((int)foomX) << 16 ;
+ zoomy = ((int)foomY) << 16 ;
+
+ zoomx += (int)((foomX - floor(foomX)) * (float)0x10000) ;
+ zoomy += (int)((foomY - floor(foomY)) * (float)0x10000) ;
+
+
+ if (source[3]&0x00800000) // maybe ..
+ {
+ gfx= machine->gfx[4];
+ }
+ else
+ {
+ gfx= machine->gfx[5];
+ tileno>>=1;
+
+ // Just a big hack to make the top and bottom tiles in the intro not crash (a pal value of 0x70 is bad)
+ // Is there a problem with draw_sprites? Doubtful...
+ if (source[2] == 0x00080000)
+ pal >>=4;
+ }
+
+ // Accomodate for chaining and flipping
+ if(xflip)
+ {
+ xinc=-(int)(16.0f*foomX);
+ xpos-=xinc*chainx;
+ }
+ else
+ {
+ xinc=(int)(16.0f*foomX);
+ }
+
+ if(yflip)
+ {
+ yinc=-(int)(16.0f*foomY);
+ ypos-=yinc*chainy;
+ }
+ else
+ {
+ yinc=(int)(16.0f*foomY);
+ }
+
+
+// if (((source[2] & 0xffff0000) >> 16) == 0x0001)
+// {
+// usrintf_showmessage("T %.8x %.8x %.8x %.8x %.8x", source[0], source[1], source[2], source[3], source[4]) ;
+// // usrintf_showmessage("T %.8x %.8x %.8x %.8x %.8x", source[0], source[1], source[2], source[3], source[4]) ;
+// }
+
+ for(ydrw=0;ydrw<=chainy;ydrw++)
+ {
+ for(xdrw=0;xdrw<=chainx;xdrw++)
+ {
+ drawgfxzoom(bitmap,gfx,tileno,pal,xflip,yflip,xpos+(xinc*xdrw),ypos+(yinc*ydrw),cliprect,TRANSPARENCY_PEN,0,zoomx,zoomy/*0x10000*/);
+ tileno++;
+ }
+ }
+ }
+}
+
+
+/* Transition_Control Memory Region Map
+ * ------------------------------
+ *
+ * UINT32 | Bytes | Use
+ * -------+-76543210-+----------
+ * 0 | |
+ * 1 | |
+ * 2 | |
+ * 3 | |
+ * 4 | |
+ * 5 | |
+ * 6 | --xxxxxx | I popped into Buriki and saw some of these values changing to the same as 7. hmmmm...
+ * 7 | --xxxxxx | Almost certainly RGB darkening
+ * 8 | |
+ * 9 | |
+ * 10 | --xxxxxx | Almost certainly RGB brightening
+ * 11 | xxxxxxxx | Unknown - looks like an ARGB value - it seems to change when the scene changes
+ * 12 | |
+ * 13 | |
+ * 14 | |
+ * 15 | |
+ *
+ * Various bits change depending on what is happening in the scene.
+ * These bits may set which 'layer' is affected by the blending.
+ * Or maybe they adjust the scale of the lightening and darkening...
+ * Or maybe it switches from fading by scaling to fading using absolute addition and subtraction...
+ * Or maybe they set transition type (there seems to be a cute scaling-squares transition in there somewhere)...
+ */
+static void transition_control(running_machine *machine, mame_bitmap *bitmap)
+{
+ int i, j ;
+
+// float colorScaleR, colorScaleG, colorScaleB ;
+// float finR, finG, finB ;
+ INT32 finR, finG, finB ;
+
+ INT32 darkR, darkG, darkB ;
+ INT32 brigR, brigG, brigB ;
+
+ // If either of the fading memory regions is non-zero...
+ if (hng64_tcram[0x00000007] != 0x00000000 || hng64_tcram[0x0000000a] != 0x00000000)
+ {
+ darkR = (INT32)( hng64_tcram[0x00000007] & 0xff) ;
+ darkG = (INT32)((hng64_tcram[0x00000007] >> 8) & 0xff) ;
+ darkB = (INT32)((hng64_tcram[0x00000007] >> 16) & 0xff) ;
+
+ brigR = (INT32)( hng64_tcram[0x0000000a] & 0xff) ;
+ brigG = (INT32)((hng64_tcram[0x0000000a] >> 8) & 0xff) ;
+ brigB = (INT32)((hng64_tcram[0x0000000a] >> 16) & 0xff) ;
+
+ for (i = machine->screen[0].visarea.min_x; i < machine->screen[0].visarea.max_x; i++)
+ {
+ for (j = machine->screen[0].visarea.min_y; j < machine->screen[0].visarea.max_y; j++)
+ {
+ UINT32* thePixel = BITMAP_ADDR32(bitmap, j, i);
+
+ finR = (INT32)RGB_RED(*thePixel) ;
+ finG = (INT32)RGB_GREEN(*thePixel) ;
+ finB = (INT32)RGB_BLUE(*thePixel) ;
+
+ /*
+ // Apply the darkening pass (0x07)...
+ colorScaleR = 1.0f - (float)( hng64_tcram[0x00000007] & 0xff) / 255.0f ;
+ colorScaleG = 1.0f - (float)((hng64_tcram[0x00000007] >> 8) & 0xff) / 255.0f ;
+ colorScaleB = 1.0f - (float)((hng64_tcram[0x00000007] >> 16) & 0xff) / 255.0f ;
+
+ finR = ((float)RGB_RED(*thePixel) * colorScaleR) ;
+ finG = ((float)RGB_GREEN(*thePixel) * colorScaleG) ;
+ finB = ((float)RGB_BLUE(*thePixel) * colorScaleB) ;
+
+
+ // Apply the lightening pass (0x0a)...
+ colorScaleR = 1.0f + (float)( hng64_tcram[0x0000000a] & 0xff) / 255.0f ;
+ colorScaleG = 1.0f + (float)((hng64_tcram[0x0000000a] >> 8) & 0xff) / 255.0f ;
+ colorScaleB = 1.0f + (float)((hng64_tcram[0x0000000a] >> 16) & 0xff) / 255.0f ;
+
+ finR *= colorScaleR ;
+ finG *= colorScaleG ;
+ finB *= colorScaleB ;
+
+
+ // Clamp
+ if (finR > 255.0f) finR = 255.0f ;
+ if (finG > 255.0f) finG = 255.0f ;
+ if (finB > 255.0f) finB = 255.0f ;
+ */
+
+
+ // Subtractive fading
+ if (hng64_tcram[0x00000007] != 0x00000000)
+ {
+ finR -= darkR ;
+ finG -= darkG ;
+ finB -= darkB ;
+ }
+
+ // Additive fading
+ if (hng64_tcram[0x0000000a] != 0x00000000)
+ {
+ finR += brigR ;
+ finG += brigG ;
+ finB += brigB ;
+ }
+
+ // Clamp the high end
+ if (finR > 255) finR = 255 ;
+ if (finG > 255) finG = 255 ;
+ if (finB > 255) finB = 255 ;
+
+ // Clamp the low end
+ if (finR < 0) finR = 0 ;
+ if (finG < 0) finG = 0 ;
+ if (finB < 0) finB = 0 ;
+
+ *thePixel = MAKE_ARGB(255, (UINT8)finR, (UINT8)finG, (UINT8)finB) ;
+ }
+ }
+ }
+}
+
+
+/*
+ * 3d 'Sprite' Format
+ * ------------------
+ *
+ * (documented below)
+ *
+ */
+
+#define MAX_ONSCREEN_POLYS (10000)
+
+struct polyVert
+{
+ float worldCoords[4] ; // World space coordinates (X Y Z 1.0)
+
+ float texCoords[4] ; // Texture coordinates (U V 0 1.0) -> OpenGL style...
+
+ float normal[4] ; // Normal (X Y Z 1.0)
+ float clipCoords[4] ; // Homogeneous screen space coordinates (X Y Z W)
+
+ float light[3] ; // The intensity of the illumination at this point
+} ;
+
+struct polygon
+{
+ int n ; // Number of sides
+ struct polyVert vert[10] ; // Vertices (maximum number per polygon is 10 -> 3+6)
+
+ float faceNormal[4] ; // Normal of the face overall - for calculating visibility and flat-shading...
+ int visible ; // Polygon visibility in scene
+
+ INT8 texIndex ; // Which texture to draw from (0x00-0x0f)
+ INT8 texType ; // How to index into the texture
+ UINT8 palIndex ; // Which palette to use when rasterizing
+} ;
+
+
+static void PerformFrustumClip(struct polygon *p) ;
+
+//static void DrawWireframe(struct polygon *p, mame_bitmap *bitmap) ;
+static void DrawShaded(running_machine *machine, struct polygon *p, mame_bitmap *bitmap) ;
+
+
+static void draw3d(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int i,j,k,l,m ;
+
+ float projectionMatrix[16] ;
+ float modelViewMatrix[16] ;
+ float cameraMatrix[16] ;
+ float objectMatrix[16] ;
+
+ int paletteState = 0x00 ;
+
+ UINT32 numPolys = 0 ;
+
+ struct polygon lastPoly = { 0 } ;
+
+ // Set some matrices to the identity...
+ SetIdentity(projectionMatrix) ;
+ SetIdentity(modelViewMatrix) ;
+ SetIdentity(cameraMatrix) ;
+ SetIdentity(objectMatrix) ;
+
+ // Display list 2 comes after display list 1. Go figure.
+ for (j = 1; j >= 0; j--)
+ {
+ UINT32 *workingList = hng64_dls[j] ;
+
+ for (i = 0; i < 0x80; i += 0x08)
+ {
+ float left, right, top, bottom, near_, far_ ;
+ UINT8 *threeDRoms ;
+ UINT8 *threeDPointer ;
+ UINT32 threeDOffset ;
+ UINT32 size[4] ;
+ UINT32 address[4] ;
+ UINT32 megaOffset ;
+ float eyeCoords[4] ; // objectCoords transformed by the modelViewMatrix
+ // float clipCoords[4] ; // eyeCoords transformed by the projectionMatrix
+ float ndCoords[4] ; // normalized device coordinates/clipCoordinates (x/w, y/w, z/w)
+ float windowCoords[4] ; // mapped ndCoordinates to screen space
+ float cullRay[4] ;
+
+ // Debug...
+// mame_printf_debug("Element %.2d (%d) : %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", i/0x08, j,
+// (UINT32)hng64_dls[j][i+0], (UINT32)hng64_dls[j][i+1], (UINT32)hng64_dls[j][i+2], (UINT32)hng64_dls[j][i+3],
+// (UINT32)hng64_dls[j][i+4], (UINT32)hng64_dls[j][i+5], (UINT32)hng64_dls[j][i+6], (UINT32)hng64_dls[j][i+7]) ;
+
+ // Depending on what the initial flags are, do sumthin'...
+ switch((workingList[i+0] & 0xffff0000) >> 16)
+ {
+ case 0x0012:
+ // UNKNOWN - seems an awful lot parameters for a projection matrix though...
+
+ ;
+
+ // It changes when 'How to play' is on the screen... not too much, but if this is right, the aspect
+ // ratio is different...
+
+ // Heisted from GLFrustum - 6 parameters...
+ left = uToF( workingList[i+5] & 0x0000ffff) ;
+ right = uToF((workingList[i+5] & 0xffff0000) >> 16) ;
+ top = uToF((workingList[i+6] & 0xffff0000) >> 16) ;
+ bottom = uToF( workingList[i+6] & 0x0000ffff) ;
+ near_ = uToF((workingList[i+3] & 0xffff0000) >> 16) ;
+ far_ = uToF( workingList[i+3] & 0x0000ffff) ;
+
+ // It's almost .always. these values in fatfurwa...
+ // 0.070313 0.000000 [0] (scaled by 128)
+ // 0.000000 10.000000 [1]
+ // 0.000000 0.500000 [2]
+ // 2.000000 11.062500 [3]
+ // 10.000000 11.000000 [4]
+ // 1.000000 -1.000000 [5]
+ // 0.875000 -0.875000 [6]
+ // 0.000000 0.000000 [7]
+
+ projectionMatrix[0] = (2.0f*near_)/(right-left) ;
+ projectionMatrix[1] = 0.0f ;
+ projectionMatrix[2] = 0.0f ;
+ projectionMatrix[3] = 0.0f ;
+
+ projectionMatrix[4] = 0.0f ;
+ projectionMatrix[5] = (2.0f*near_)/(top-bottom) ;
+ projectionMatrix[6] = 0.0f ;
+ projectionMatrix[7] = 0.0f ;
+
+ projectionMatrix[8] = (right+left)/(right-left) ;
+ projectionMatrix[9] = (top+bottom)/(top-bottom) ;
+ projectionMatrix[10] = -((far_+near_)/(far_-near_)) ;
+ projectionMatrix[11] = -1.0f ;
+
+ projectionMatrix[12] = 0.0f ;
+ projectionMatrix[13] = 0.0f ;
+ projectionMatrix[14] = -((2.0f*far_*near_)/(far_-near_)) ;
+ projectionMatrix[15] = 0.0f ;
+
+ /*
+ int xxx ;
+ for (xxx = 0; xxx < 16; xxx++)
+ mame_printf_debug("%f ", projectionMatrix[xxx]) ;
+ mame_printf_debug("\n") ;
+
+ mame_printf_debug("Vars : %f %f %f %f %f %f\n", left, right, top, bottom, near, far) ;
+ mame_printf_debug("Camera : %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
+ uToF((workingList[i+0] & 0xffff0000) >> 16)*128, uToF( workingList[i+0] & 0x0000ffff)*128,
+ uToF((workingList[i+1] & 0xffff0000) >> 16)*128, uToF( workingList[i+1] & 0x0000ffff)*128,
+
+ uToF((workingList[i+2] & 0xffff0000) >> 16)*128, uToF( workingList[i+2] & 0x0000ffff)*128,
+ uToF((workingList[i+3] & 0xffff0000) >> 16)*128, uToF( workingList[i+3] & 0x0000ffff)*128,
+
+ uToF((workingList[i+4] & 0xffff0000) >> 16)*128, uToF( workingList[i+4] & 0x0000ffff)*128,
+ uToF((workingList[i+5] & 0xffff0000) >> 16)*128, uToF( workingList[i+5] & 0x0000ffff)*128,
+
+ uToF((workingList[i+6] & 0xffff0000) >> 16)*128, uToF( workingList[i+6] & 0x0000ffff)*128,
+ uToF((workingList[i+7] & 0xffff0000) >> 16)*128, uToF( workingList[i+7] & 0x0000ffff)*128) ;
+ */
+
+ break ;
+
+ case 0x0001:
+ // CAMERA TRANSFORMATION MATRIX
+ cameraMatrix[0] = uToF( workingList[i+0] & 0x0000ffff) ;
+ cameraMatrix[4] = uToF((workingList[i+1] & 0xffff0000) >> 16) ;
+ cameraMatrix[8] = uToF( workingList[i+1] & 0x0000ffff) ;
+ cameraMatrix[3] = 0.0f ;
+
+ cameraMatrix[1] = uToF((workingList[i+2] & 0xffff0000) >> 16) ;
+ cameraMatrix[5] = uToF( workingList[i+2] & 0x0000ffff) ;
+ cameraMatrix[9] = uToF((workingList[i+3] & 0xffff0000) >> 16) ;
+ cameraMatrix[7] = 0.0f ;
+
+ cameraMatrix[2] = uToF( workingList[i+3] & 0x0000ffff) ;
+ cameraMatrix[6] = uToF((workingList[i+4] & 0xffff0000) >> 16) ;
+ cameraMatrix[10] = uToF( workingList[i+4] & 0x0000ffff) ;
+ cameraMatrix[11] = 0.0f ;
+
+ cameraMatrix[12] = uToF((workingList[i+5] & 0xffff0000) >> 16) ;
+ cameraMatrix[13] = uToF( workingList[i+5] & 0x0000ffff) ;
+ cameraMatrix[14] = uToF((workingList[i+6] & 0xffff0000) >> 16) ;
+ cameraMatrix[15] = 1.0f ;
+ break ;
+
+ case 0x0010:
+ // UNKNOWN - light maybe
+ break ;
+
+ case 0x0011:
+ // Model Flags?
+ // 00110000 00000000 00000100 01000100 0400-0000 00007fff 00000000 00000020
+ // ---- pal ---- -------- -------- -------- not used (known)
+ paletteState = (workingList[i+4] & 0xff000000) >> 24 ;
+
+ break ;
+
+ case 0x0100:
+ // GEOMETRY
+ ;
+
+ threeDRoms = memory_region(REGION_GFX4) ;
+
+ /////////////////////////
+ // GET THE HEADER INFO //
+ /////////////////////////
+
+ // 3d ROM Offset
+ // !!! This might be more than just 20 bits...
+ threeDOffset = workingList[i+1] & 0x000fffff ;
+ threeDOffset = (threeDOffset<<1) * 3 ;
+
+ threeDPointer = &threeDRoms[threeDOffset] ;
+
+
+ // 66 byte versus 48 byte chunk flag
+ // WRONG ! I think it's something to do with lighting...
+ // it's 0 for the 66-byte lit globe in the character select and 0 for something in terry's hand...
+ // if (workingList[i+0] & 0x00000010)
+
+
+ //////////////////////////////////////////
+ // GET THE OBJECT TRANSFORMATION MATRIX //
+ //////////////////////////////////////////
+
+ objectMatrix[8 ] = uToF( workingList[i+3] & 0x0000ffff) ;
+ objectMatrix[4 ] = uToF((workingList[i+4] & 0xffff0000) >> 16) ;
+ objectMatrix[0 ] = uToF( workingList[i+4] & 0x0000ffff) ;
+ objectMatrix[3] = 0.0f ;
+
+ objectMatrix[9 ] = uToF((workingList[i+5] & 0xffff0000) >> 16) ;
+ objectMatrix[5 ] = uToF( workingList[i+5] & 0x0000ffff) ;
+ objectMatrix[1 ] = uToF((workingList[i+6] & 0xffff0000) >> 16) ;
+ objectMatrix[7] = 0.0f ;
+
+ objectMatrix[10] = uToF( workingList[i+6] & 0x0000ffff) ;
+ objectMatrix[6 ] = uToF((workingList[i+7] & 0xffff0000) >> 16) ;
+ objectMatrix[2 ] = uToF( workingList[i+7] & 0x0000ffff) ;
+ objectMatrix[11] = 0.0f ;
+
+ objectMatrix[12] = uToF((workingList[i+2] & 0xffff0000) >> 16) ;
+ objectMatrix[13] = uToF( workingList[i+2] & 0x0000ffff) ;
+ objectMatrix[14] = uToF((workingList[i+3] & 0xffff0000) >> 16) ;
+ objectMatrix[15] = 1.0f ;
+
+
+
+ //////////////////////////////////////////////////////////
+ // EXTRACT DATA FROM THE ADDRESS POINTED TO IN THE FILE //
+ //////////////////////////////////////////////////////////
+
+ // Okay, there are 4 hunks per address. They all seem good too...
+
+ // First tell me how many 'chunks' are at each address...
+ size[0] = WORD_AT( threeDPointer, ( 6<<1) ) ;
+ size[1] = WORD_AT( threeDPointer, ( 7<<1) ) ;
+ size[2] = WORD_AT( threeDPointer, ( 9<<1) ) ;
+ size[3] = WORD_AT( threeDPointer, (10<<1) ) ;
+
+ megaOffset = ( WORD_AT(threeDRoms, (threeDOffset + 4)) ) << 16 ;
+ address[0] = megaOffset | WORD_AT(threeDPointer, (0<<1)) ;
+ address[1] = megaOffset | WORD_AT(threeDPointer, (1<<1)) ;
+ address[2] = megaOffset | WORD_AT(threeDPointer, (3<<1)) ;
+ address[3] = megaOffset | WORD_AT(threeDPointer, (4<<1)) ;
+
+ // DEBUG
+ // mame_printf_debug("%.5x %.3x %.5x %.3x %.5x %.3x %.5x %.3x\n", address[0], size[0], address[1], size[1], address[2], size[2], address[3], size[3]) ;
+ // !! END DEBUG !!
+
+
+
+ ////////////////////////////////////
+ // A FEW 'GLOBAL' TRANSFORMATIONS //
+ ////////////////////////////////////
+
+ // Now perform the world transformations...
+ // !! Can eliminate this step with a matrix stack (maybe necessary?) !!
+ SetIdentity(modelViewMatrix) ;
+ matmul4(modelViewMatrix, modelViewMatrix, cameraMatrix) ;
+ matmul4(modelViewMatrix, modelViewMatrix, objectMatrix) ;
+
+ for (k = 0; k < 4; k++) // For all 4 chunks
+ {
+ threeDPointer = &threeDRoms[(address[k]<<1) * 3] ;
+
+ for (l = 0; l < size[k]; l++)
+ {
+ ////////////////////////////////////////////
+ // GATHER A SINGLE TRIANGLE'S INFORMATION //
+ ////////////////////////////////////////////
+
+ UINT8 triangleType = threeDPointer[1] ;
+
+ UINT8 numVertices = 3 ;
+ UINT8 chunkLength = 0 ;
+
+ // Some chunks only have 1 vertex (they act as a vertex fan)
+ if (triangleType == 0x97 ||
+ triangleType == 0x87 ||
+ triangleType == 0xd7 ||
+ triangleType == 0x96)
+ numVertices = 1 ;
+
+ // Get which texture this polygon refers to...
+ // In fatfur it's 0xc for the smooth-shaded earth - maybe this is for all things with alpha - check the hair at some point...
+ // 0x9 for the untextured buildings
+ // 0xd for the 'explosion' of the HNG64
+ // and 0x8 everywhere else...
+ // they're 0x8 in the buriki intro too (those are 66-byte chunks!)
+ polys[numPolys].texType = ((threeDPointer[2] & 0xf0) >> 4);
+
+ if (polys[numPolys].texType == 0x8 || polys[numPolys].texType == 0xc) // || polys[numPolys].texType == 0x9
+ polys[numPolys].texIndex = threeDPointer[3] & 0x0f ;
+ else
+ polys[numPolys].texIndex = -1 ;
+
+ // Set the polygon's palette
+ polys[numPolys].palIndex = paletteState ;
+
+ for (m = 0; m < numVertices; m++) // For all vertices of the chunk
+ {
+ switch(triangleType)
+ {
+ // 42 byte chunk
+ case 0x04:
+ case 0x0e:
+ polys[numPolys].vert[m].worldCoords[0] = uToF(WORD_AT(threeDPointer, ((3<<1) + (6<<1)*m)) ) ;
+ polys[numPolys].vert[m].worldCoords[1] = uToF(WORD_AT(threeDPointer, ((4<<1) + (6<<1)*m)) ) ;
+ polys[numPolys].vert[m].worldCoords[2] = uToF(WORD_AT(threeDPointer, ((5<<1) + (6<<1)*m)) ) ;
+ polys[numPolys].vert[m].worldCoords[3] = 1.0f ;
+ polys[numPolys].n = 3 ;
+
+ // !! What is the first coordinate here (6) - maybe denotes size of chunk? !!
+ polys[numPolys].vert[m].texCoords[0] = uToF(WORD_AT(threeDPointer, ((7<<1) + (6<<1)*m)) ) ;
+ polys[numPolys].vert[m].texCoords[1] = uToF(WORD_AT(threeDPointer, ((8<<1) + (6<<1)*m)) ) ;
+ polys[numPolys].vert[m].texCoords[2] = 0.0f ;
+ polys[numPolys].vert[m].texCoords[3] = 1.0f ;
+
+ polys[numPolys].vert[m].normal[0] = uToF(WORD_AT(threeDPointer, (21<<1) )) ;
+ polys[numPolys].vert[m].normal[1] = uToF(WORD_AT(threeDPointer, (22<<1) )) ;
+ polys[numPolys].vert[m].normal[2] = uToF(WORD_AT(threeDPointer, (23<<1) )) ;
+ polys[numPolys].vert[m].normal[3] = 0.0f ;
+
+ // !!! DUMB !!!
+ polys[numPolys].vert[m].light[0] = polys[numPolys].vert[m].texCoords[0] * 255.0f ;
+ polys[numPolys].vert[m].light[1] = polys[numPolys].vert[m].texCoords[1] * 255.0f ;
+ polys[numPolys].vert[m].light[2] = polys[numPolys].vert[m].texCoords[2] * 255.0f ;
+
+ // Redundantly called, but it works...
+ polys[numPolys].faceNormal[0] = polys[numPolys].vert[m].normal[0] ;
+ polys[numPolys].faceNormal[1] = polys[numPolys].vert[m].normal[1] ;
+ polys[numPolys].faceNormal[2] = polys[numPolys].vert[m].normal[2] ;
+ polys[numPolys].faceNormal[3] = 0.0f ;
+
+ chunkLength = (24<<1) ;
+ break ;
+
+ // 66 byte chunk
+ case 0x05:
+ case 0x0f:
+ polys[numPolys].vert[m].worldCoords[0] = uToF(WORD_AT(threeDPointer, ((3<<1) + (9<<1)*m)) ) ;
+ polys[numPolys].vert[m].worldCoords[1] = uToF(WORD_AT(threeDPointer, ((4<<1) + (9<<1)*m)) ) ;
+ polys[numPolys].vert[m].worldCoords[2] = uToF(WORD_AT(threeDPointer, ((5<<1) + (9<<1)*m)) ) ;
+ polys[numPolys].vert[m].worldCoords[3] = 1.0f ;
+ polys[numPolys].n = 3 ;
+
+ // !! See above - (6) - why? !!
+ polys[numPolys].vert[m].texCoords[0] = uToF(WORD_AT(threeDPointer, ((7<<1) + (9<<1)*m)) ) ;
+ polys[numPolys].vert[m].texCoords[1] = uToF(WORD_AT(threeDPointer, ((8<<1) + (9<<1)*m)) ) ;
+ polys[numPolys].vert[m].texCoords[2] = 0.0f ;
+ polys[numPolys].vert[m].texCoords[3] = 1.0f ;
+
+ polys[numPolys].vert[m].normal[0] = uToF(WORD_AT(threeDPointer, ((9<<1) + (9<<1)*m)) ) ;
+ polys[numPolys].vert[m].normal[1] = uToF(WORD_AT(threeDPointer, ((10<<1) + (9<<1)*m)) ) ;
+ polys[numPolys].vert[m].normal[2] = uToF(WORD_AT(threeDPointer, ((11<<1) + (9<<1)*m)) ) ;
+ polys[numPolys].vert[m].normal[3] = 0.0f ;
+
+ // !!! DUMB !!!
+ polys[numPolys].vert[m].light[0] = polys[numPolys].vert[m].texCoords[0] * 255.0f ;
+ polys[numPolys].vert[m].light[1] = polys[numPolys].vert[m].texCoords[1] * 255.0f ;
+ polys[numPolys].vert[m].light[2] = polys[numPolys].vert[m].texCoords[2] * 255.0f ;
+
+ // Redundantly called, but it works...
+ polys[numPolys].faceNormal[0] = uToF(WORD_AT(threeDPointer, (30<<1) )) ;
+ polys[numPolys].faceNormal[1] = uToF(WORD_AT(threeDPointer, (31<<1) )) ;
+ polys[numPolys].faceNormal[2] = uToF(WORD_AT(threeDPointer, (32<<1) )) ;
+ polys[numPolys].faceNormal[3] = 0.0f ;
+
+ chunkLength = (33<<1) ;
+ break ;
+
+ // 30 byte chunk
+ case 0x97:
+ case 0x87:
+ case 0xd7:
+
+ // Copy over the proper vertices from the previous triangle...
+ memcpy(&polys[numPolys].vert[1], &lastPoly.vert[0], sizeof(struct polyVert)) ;
+ memcpy(&polys[numPolys].vert[2], &lastPoly.vert[2], sizeof(struct polyVert)) ;
+
+ // Fill in the appropriate data...
+ polys[numPolys].vert[0].worldCoords[0] = uToF(WORD_AT(threeDPointer, (3<<1) )) ;
+ polys[numPolys].vert[0].worldCoords[1] = uToF(WORD_AT(threeDPointer, (4<<1) )) ;
+ polys[numPolys].vert[0].worldCoords[2] = uToF(WORD_AT(threeDPointer, (5<<1) )) ;
+ polys[numPolys].vert[0].worldCoords[3] = 1.0f ;
+ polys[numPolys].n = 3 ;
+
+ // !! See above - (6) - why? !!
+ polys[numPolys].vert[0].texCoords[0] = uToF(WORD_AT(threeDPointer, (7<<1) )) ;
+ polys[numPolys].vert[0].texCoords[1] = uToF(WORD_AT(threeDPointer, (8<<1) )) ;
+ polys[numPolys].vert[0].texCoords[2] = 0.0f ;
+ polys[numPolys].vert[0].texCoords[3] = 1.0f ;
+
+ polys[numPolys].vert[0].normal[0] = uToF(WORD_AT(threeDPointer, (9<<1) )) ;
+ polys[numPolys].vert[0].normal[1] = uToF(WORD_AT(threeDPointer, (10<<1) )) ;
+ polys[numPolys].vert[0].normal[2] = uToF(WORD_AT(threeDPointer, (11<<1) )) ;
+ polys[numPolys].vert[0].normal[3] = 0.0f ;
+
+ polys[numPolys].vert[0].light[0] = polys[numPolys].vert[0].texCoords[0] * 255.0f ;
+ polys[numPolys].vert[0].light[1] = polys[numPolys].vert[0].texCoords[1] * 255.0f ;
+ polys[numPolys].vert[0].light[2] = polys[numPolys].vert[0].texCoords[2] * 255.0f ;
+
+ polys[numPolys].faceNormal[0] = uToF(WORD_AT(threeDPointer, (12<<1) )) ;
+ polys[numPolys].faceNormal[1] = uToF(WORD_AT(threeDPointer, (13<<1) )) ;
+ polys[numPolys].faceNormal[2] = uToF(WORD_AT(threeDPointer, (14<<1) )) ;
+ polys[numPolys].faceNormal[3] = 0.0f ;
+
+ chunkLength = (15<<1) ;
+ break ;
+
+ // 18 byte chunk
+ case 0x96:
+
+ // Copy over the proper vertices from the previous triangle...
+ memcpy(&polys[numPolys].vert[1], &lastPoly.vert[0], sizeof(struct polyVert)) ;
+ memcpy(&polys[numPolys].vert[2], &lastPoly.vert[2], sizeof(struct polyVert)) ;
+
+ // !!! Too lazy to have finished this yet !!!
+
+ polys[numPolys].vert[0].worldCoords[0] = uToF(WORD_AT(threeDPointer, (3<<1))) ;
+ polys[numPolys].vert[0].worldCoords[1] = uToF(WORD_AT(threeDPointer, (4<<1))) ;
+ polys[numPolys].vert[0].worldCoords[2] = uToF(WORD_AT(threeDPointer, (5<<1))) ;
+ polys[numPolys].vert[0].worldCoords[3] = 1.0f ;
+ polys[numPolys].n = 3 ;
+
+ // !! See above - (6) - why? !!
+ polys[numPolys].vert[0].texCoords[0] = uToF(WORD_AT(threeDPointer, (7<<1))) ;
+ polys[numPolys].vert[0].texCoords[1] = uToF(WORD_AT(threeDPointer, (8<<1))) ;
+ polys[numPolys].vert[0].texCoords[2] = 0.0f ;
+ polys[numPolys].vert[0].texCoords[3] = 1.0f ;
+
+ // !!! DUMB !!!
+ polys[numPolys].vert[0].light[0] = polys[numPolys].vert[0].texCoords[0] * 255.0f ;
+ polys[numPolys].vert[0].light[1] = polys[numPolys].vert[0].texCoords[1] * 255.0f ;
+ polys[numPolys].vert[0].light[2] = polys[numPolys].vert[0].texCoords[2] * 255.0f ;
+
+ // This normal could be right, but I'm not entirely sure - there is no normal in the 18 bytes!
+ polys[numPolys].vert[0].normal[0] = lastPoly.faceNormal[0] ;
+ polys[numPolys].vert[0].normal[1] = lastPoly.faceNormal[1] ;
+ polys[numPolys].vert[0].normal[2] = lastPoly.faceNormal[2] ;
+ polys[numPolys].vert[0].normal[3] = lastPoly.faceNormal[3] ;
+
+ polys[numPolys].faceNormal[0] = lastPoly.faceNormal[0] ;
+ polys[numPolys].faceNormal[1] = lastPoly.faceNormal[1] ;
+ polys[numPolys].faceNormal[2] = lastPoly.faceNormal[2] ;
+ polys[numPolys].faceNormal[3] = lastPoly.faceNormal[3] ;
+
+ chunkLength = (9<<1) ;
+ break ;
+
+ default:
+ mame_printf_debug("UNKNOWN geometry CHUNK TYPE : %x\n", triangleType) ;
+ break ;
+ }
+ }
+
+ polys[numPolys].visible = 1 ;
+
+ memcpy(&lastPoly, &polys[numPolys], sizeof(struct polygon)) ;
+
+
+
+
+ // THE HNG64 HARDWARE DOES NOT SEEM TO BACKFACE CULL //
+
+ ///////////////////
+ // BACKFACE CULL //
+ ///////////////////
+/*
+ float cullRay[4] ;
+ float cullNorm[4] ;
+
+ // Cast a ray out of the camera towards the polygon's point in eyespace.
+ vecmatmul4(cullRay, modelViewMatrix, polys[numPolys].vert[0].worldCoords) ;
+ normalize(cullRay) ;
+ // Dot product that with the normal to see if you're negative...
+ vecmatmul4(cullNorm, modelViewMatrix, polys[numPolys].faceNormal) ;
+
+ float result = vecDotProduct(cullRay, cullNorm) ;
+
+ if (result < 0.0f)
+ polys[numPolys].visible = 1 ;
+ else
+ polys[numPolys].visible = 0 ;
+*/
+
+ ////////////////////////////
+ // BEHIND-THE-CAMERA CULL //
+ ////////////////////////////
+ vecmatmul4(cullRay, modelViewMatrix, polys[numPolys].vert[0].worldCoords) ;
+
+ if (cullRay[2] > 0.0f) // Camera is pointing down -Z
+ {
+ polys[numPolys].visible = 0 ;
+ }
+
+
+ //////////////////////////////////////////////////////////
+ // TRANSFORM THE TRIANGLE INTO HOMOGENEOUS SCREEN SPACE //
+ //////////////////////////////////////////////////////////
+
+ if (polys[numPolys].visible)
+ {
+ for (m = 0; m < polys[numPolys].n; m++)
+ {
+ // Transform and project the vertex into pre-divided homogeneous coordinates...
+ vecmatmul4(eyeCoords, modelViewMatrix, polys[numPolys].vert[m].worldCoords) ;
+ vecmatmul4(polys[numPolys].vert[m].clipCoords, projectionMatrix, eyeCoords) ;
+ }
+
+ if (polys[numPolys].visible)
+ {
+ // Clip the triangles to the view frustum...
+ PerformFrustumClip(&polys[numPolys]) ;
+
+ for (m = 0; m < polys[numPolys].n; m++)
+ {
+ // Convert into normalized device coordinates...
+ ndCoords[0] = polys[numPolys].vert[m].clipCoords[0] / polys[numPolys].vert[m].clipCoords[3] ;
+ ndCoords[1] = polys[numPolys].vert[m].clipCoords[1] / polys[numPolys].vert[m].clipCoords[3] ;
+ ndCoords[2] = polys[numPolys].vert[m].clipCoords[2] / polys[numPolys].vert[m].clipCoords[3] ;
+ ndCoords[3] = polys[numPolys].vert[m].clipCoords[3] ;
+
+ // Final pixel values are garnered here :
+ windowCoords[0] = (ndCoords[0]+1.0f) * ((float)(machine->screen[0].visarea.max_x) / 2.0f) + 0.0f ;
+ windowCoords[1] = (ndCoords[1]+1.0f) * ((float)(machine->screen[0].visarea.max_y) / 2.0f) + 0.0f ;
+ windowCoords[2] = (ndCoords[2]+1.0f) * 0.5f ;
+
+ windowCoords[1] = (float)machine->screen[0].visarea.max_y - windowCoords[1] ; // Flip Y
+
+ // Store the points in a list for later use...
+ polys[numPolys].vert[m].clipCoords[0] = windowCoords[0] ;
+ polys[numPolys].vert[m].clipCoords[1] = windowCoords[1] ;
+ polys[numPolys].vert[m].clipCoords[2] = windowCoords[2] ;
+ polys[numPolys].vert[m].clipCoords[3] = ndCoords[3] ;
+ }
+ }
+ }
+
+
+/*
+ // DEBUG
+ if (chunkLength == (9 << 1))
+ {
+ mame_printf_debug("Chunk : ") ;
+ for (int ajg = 0; ajg < chunkLength; ajg+=2)
+ mame_printf_debug("%.2x%.2x ", threeDPointer[ajg], threeDPointer[ajg+1]) ;
+ mame_printf_debug("\n") ;
+ }
+ // END DEBUG
+*/
+
+ // Advance to the next polygon chunk...
+ threeDPointer += chunkLength ;
+
+ numPolys++ ; // Add one more to the display list...
+ }
+ }
+
+ break ;
+
+ default:
+ break ;
+ }
+ }
+
+ // Don't forget about this !!!
+ //mame_printf_debug(" %.8x\n\n", (UINT32)hng64_dls[j][0x80]) ;
+
+ }
+
+
+ /////////////////////////////////////////////////
+ // FINALLY RENDER THE TRIANGLES INTO THE FRAME //
+ /////////////////////////////////////////////////
+
+ // Reset the depth buffer...
+ for (i = 0; i < (machine->screen[0].visarea.max_x)*(machine->screen[0].visarea.max_y); i++)
+ depthBuffer[i] = 100.0f ;
+
+ for (i = 0; i < numPolys; i++)
+ {
+ if (polys[i].visible)
+ {
+ //DrawWireframe(&polys[i], bitmap) ;
+ DrawShaded(machine, &polys[i], bitmap) ;
+ }
+ }
+
+ // usrintf_showmessage("%d", numPolys) ;
+
+ // Clear each of the display list buffers after drawing...
+ for (i = 0; i < 0x81; i++)
+ {
+ hng64_dls[0][i] = 0 ;
+ hng64_dls[1][i] = 0 ;
+ }
+}
+
+
+/* 8x8 tiles, 4bpp layer */
+static TILE_GET_INFO( get_hng64_tile0_info )
+{
+ int tileno,pal;
+ tileno = hng64_videoram[tile_index];
+ pal = hng64_videoram[tile_index]>>24;
+ SET_TILE_INFO((tileno&1)?0:1,(tileno&0x3fffff)>>1,pal,TILE_FLIPYX((tileno&0xc00000)>>22));
+}
+
+/* 16x16 tiles, 8bpp layer */
+static TILE_GET_INFO( get_hng64_tile1_info )
+{
+ int tileno,pal;
+ tileno = hng64_videoram[tile_index+(0x10000/4)];
+ pal = hng64_videoram[tile_index+(0x10000/4)]>>24;
+
+ SET_TILE_INFO(3,(tileno&0x3fffff)>>3,pal>>4, TILE_FLIPYX((tileno&0xc00000)>>22) );
+}
+
+/* 16x16 tiles, 8bpp layer */
+static TILE_GET_INFO( get_hng64_tile2_info )
+{
+ int tileno,pal;
+ tileno = hng64_videoram[tile_index+(0x20000/4)];
+ pal = hng64_videoram[tile_index+(0x20000/4)]>>24;
+ SET_TILE_INFO(3,(tileno&0x3fffff)>>3,pal>>4,TILE_FLIPYX((tileno&0xc00000)>>22));
+}
+
+/* 16x16 tiles, 8bpp layer */
+static TILE_GET_INFO( get_hng64_tile3_info )
+{
+ int tileno,pal;
+ tileno = hng64_videoram[tile_index+(0x30000/4)];
+ pal = hng64_videoram[tile_index+(0x30000/4)]>>24;
+ SET_TILE_INFO(3,(tileno&0x3fffff)>>3,pal>>4,TILE_FLIPYX((tileno&0xc00000)>>22));
+}
+
+
+
+/* Tilemaps zoom, and probably rotate.. they can have linescroll/lineselect,
+looks like the zoom center can move too..
+not sure how these features are enabled up yet */
+
+static int gatherPixelsForLine(mame_bitmap *tilemapBitmap,
+ INT32 startX, INT32 startY, INT32 endX, INT32 endY,
+ UINT16 *penList)
+{
+ int retVal = 0 ;
+
+ // !! BRESENHAM'S AGAIN - I REALLY SHOULD GENERALIZE THIS !!
+
+#define SWAP(a,b) tmpswap = a; a = b; b = tmpswap;
+
+ INT32 i;
+ INT32 steep = 1;
+ INT32 sx, sy; /* step positive or negative (1 or -1) */
+ INT32 dx, dy; /* delta (difference in X and Y between points) */
+ INT32 e;
+
+ /*
+ * inline swap. On some architectures, the XOR trick may be faster
+ */
+ INT32 tmpswap;
+
+ /*
+ * optimize for vertical and horizontal lines here
+ */
+
+ dx = abs(endX - startX);
+ sx = ((endX - startX) > 0) ? 1 : -1;
+ dy = abs(endY - startY);
+ sy = ((endY - startY) > 0) ? 1 : -1;
+
+ if (dy > dx)
+ {
+ steep = 0;
+ SWAP(startX, startY);
+ SWAP(dx, dy);
+ SWAP(sx, sy);
+ }
+
+ e = (dy << 1) - dx;
+
+ for (i = 0; i < dx; i++)
+ {
+ if (steep)
+ {
+ penList[retVal] = *BITMAP_ADDR16(tilemapBitmap, startY, startX);
+ retVal++ ;
+ }
+ else
+ {
+ penList[retVal] = *BITMAP_ADDR16(tilemapBitmap, startX, startY) ;
+ retVal++ ;
+ }
+ while (e >= 0)
+ {
+ startY += sy;
+ e -= (dx << 1);
+ }
+
+ startX += sx;
+ e += (dy << 1);
+ }
+#undef SWAP
+
+
+ return retVal ;
+}
+
+static void plotTilemap3Line(running_machine *machine,
+ mame_bitmap *tilemapBitmap,
+ INT32 startX, INT32 startY, INT32 endX, INT32 endY,
+ INT32 screenY, mame_bitmap *bitmap)
+{
+ int i ;
+
+ int numPix ;
+ UINT16 penList[0x1000] ; // 4k of pixels to be safe
+
+ float pixStride, pixOffset ;
+
+// mame_printf_debug("(%d,%d) (%d,%d)\n", startX, startY, endX, endY) ;
+
+ // CLAMP - BUT I'M PRETTY SURE THIS ISN'T QUITE RIGHT !!! ???
+ startX += 1024 ; if (startX < 0) startX = 0 ; else if (startX >= 2048) startX = 2048-1 ;
+ startY += 1024 ; if (startY < 0) startY = 0 ; else if (startY >= 2048) startY = 2048-1 ;
+ endX += 1024 ; if (endX < 0) endX = 0 ; else if (endX >= 2048) endX = 2048-1 ;
+ endY += 1024 ; if (endY < 0) endY = 0 ; else if (endY >= 2048) endY = 2048-1 ;
+
+ numPix = gatherPixelsForLine(tilemapBitmap, startX, startY, endX, endY, penList) ;
+
+ pixStride = (float)numPix / (float)(machine->screen[0].visarea.max_x-1) ;
+ pixOffset = 0 ;
+
+ if (numPix == 0)
+ penList[0] = *BITMAP_ADDR16(tilemapBitmap, 1024, 1024);
+
+// mame_printf_debug("numpix %d ps %f po %f s(%d,%d) e(%d,%d)\n", numPix, pixStride, pixOffset, startX, startY, endX, endY) ;
+
+ // Draw out the screen's line...
+ for (i = machine->screen[0].visarea.min_x; i < machine->screen[0].visarea.max_x; i++)
+ {
+ // Nearest-neighbor interpolation for now (but i doubt it does linear)
+ UINT16 tmPen = penList[(int)pixOffset] ;
+
+ *BITMAP_ADDR32(bitmap, screenY, i) = palette_get_color(machine, tmPen) | 0xff000000;
+
+ pixOffset += pixStride ;
+ }
+}
+
+static void hng64_drawtilemap3(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int i ;
+
+ mame_bitmap *srcbitmap = tilemap_get_pixmap( hng64_tilemap3 );
+
+// usrintf_showmessage("%d", hng64_hackTm3Count) ;
+
+ if (hng64_hackTm3Count/4 < Machine->screen[0].visarea.max_y)
+ {
+ for (i = 0; i < hng64_hackTm3Count/4; i++)
+ {
+ UINT32 address = hng64_rowScrollOffset + 0xbf0 ;
+ address -= (i * 0x10) ;
+ address /= 4 ;
+ //mame_printf_debug("nums : %.4x %.4x %.4x %.4x\n", (INT16)((hng64_videoram[address+0x0]&0xffff0000) >> 16),
+ // (INT16)((hng64_videoram[address+0x1]&0xffff0000) >> 16),
+ // (INT16)((hng64_videoram[address+0x2]&0xffff0000) >> 16),
+ // (INT16)((hng64_videoram[address+0x3]&0xffff0000) >> 16)) ;
+
+ plotTilemap3Line(machine, srcbitmap,
+ (INT16)((hng64_videoram[address+0x0]&0xffff0000) >> 16),
+ (INT16)((hng64_videoram[address+0x2]&0xffff0000) >> 16),
+ (INT16)((hng64_videoram[address+0x1]&0xffff0000) >> 16),
+ (INT16)((hng64_videoram[address+0x3]&0xffff0000) >> 16),
+ (machine->screen[0].visarea.max_y-1)-i,
+ bitmap) ;
+ }
+ }
+
+ // Maybe the scrollbase should be used instead of my hacky hng64_rowScrollOffset :)?
+// scrollbase = (hng64_videoregs[0x05]&0x00003fff)>>0;
+
+// xscroll = hng64_videoram[(0x40000+(scrollbase<<4))/4]>>16;
+// yscroll = hng64_videoram[(0x40008+(scrollbase<<4))/4]>>16;
+// xzoom = hng64_videoram[(0x40010+(scrollbase<<4))/4]>>16;
+// yzoom = hng64_videoram[(0x4000c+(scrollbase<<4))/4]>>16;
+// xzoom = xzoom-xscroll;
+// yzoom = yzoom-yscroll;
+// xzoom &=0xffff;
+// yzoom &=0xffff;
+
+// xscroll <<=16;
+// yscroll <<=16;
+// xzoom <<=8;
+// yzoom <<=8;
+
+// tilemap_set_scrollx(hng64_tilemap3,0, xscroll);
+// tilemap_set_scrolly(hng64_tilemap3,0, yscroll);
+
+// tilemap_draw(bitmap,cliprect,hng64_tilemap3,0,0);
+
+// tilemap_draw_roz(bitmap,cliprect,hng64_tilemap3,xscroll,yscroll,
+// xzoom,0,0,yzoom,
+// 1,
+// 0,0);
+}
+
+static void hng64_drawtilemap2( mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int scrollbase,xscroll,yscroll,xzoom,yzoom;
+
+ scrollbase = (hng64_videoregs[0x05]&0x3fff0000)>>16;
+ xscroll = (INT16)(hng64_videoram[(0x40000+(scrollbase<<4))/4]>>16);
+ // ??? = (INT16)(hng64_videoram[(0x40004+(scrollbase<<4))/4]>>16);
+ yscroll = (INT16)(hng64_videoram[(0x40008+(scrollbase<<4))/4]>>16);
+ yzoom = (INT16)(hng64_videoram[(0x4000c+(scrollbase<<4))/4]>>16);
+ xzoom = (INT16)(hng64_videoram[(0x40010+(scrollbase<<4))/4]>>16);
+ // ??? = (INT16)(hng64_videoram[(0x40014+(scrollbase<<4))/4]>>16);
+ // ??? = (INT16)(hng64_videoram[(0x40018+(scrollbase<<4))/4]>>16);
+ // ??? = (INT16)(hng64_videoram[(0x4001c+(scrollbase<<4))/4]>>16);
+ xzoom = xzoom-xscroll;
+ yzoom = yzoom-yscroll;
+ xzoom &=0xffff;
+ yzoom &=0xffff;
+
+ xscroll <<=16;
+ yscroll <<=16;
+ xzoom <<=8;
+ yzoom <<=8;
+
+ tilemap_draw_roz(bitmap,cliprect,hng64_tilemap2,xscroll,yscroll,
+ xzoom,0,0,yzoom,
+ 1,
+ 0,0);
+}
+
+static void hng64_drawtilemap1( mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int scrollbase,xscroll,yscroll,xzoom,yzoom;
+
+ scrollbase = (hng64_videoregs[0x04]&0x00003fff)>>0;
+ xscroll = (INT16)(hng64_videoram[(0x40000+(scrollbase<<4))/4]>>16);
+ // ??? = (INT16)(hng64_videoram[(0x40004+(scrollbase<<4))/4]>>16);
+ yscroll = (INT16)(hng64_videoram[(0x40008+(scrollbase<<4))/4]>>16);
+ xzoom = (INT16)(hng64_videoram[(0x40010+(scrollbase<<4))/4]>>16);
+ yzoom = (INT16)(hng64_videoram[(0x4000c+(scrollbase<<4))/4]>>16);
+ // ??? = (INT16)(hng64_videoram[(0x40014+(scrollbase<<4))/4]>>16);
+ // ??? = (INT16)(hng64_videoram[(0x40018+(scrollbase<<4))/4]>>16);
+ // ??? = (INT16)(hng64_videoram[(0x4001c+(scrollbase<<4))/4]>>16);
+ xzoom = xzoom-xscroll;
+ yzoom = yzoom-yscroll;
+ xzoom &=0xffff;
+ yzoom &=0xffff;
+
+ xscroll <<=16;
+ yscroll <<=16;
+ xzoom <<=8;
+ yzoom <<=8;
+
+ tilemap_draw_roz(bitmap,cliprect,hng64_tilemap1,xscroll,yscroll,
+ xzoom,0,0,yzoom,
+ 1,
+ 0,0);
+}
+
+
+
+/*
+ * Video Regs Format
+ * ------------------
+ *
+ * UINT32 | Bytes | Use
+ * -------+-76543210-+----------------
+ * 0 | oooooooo | unknown - always seems to be 04060000 (fatfurwa) and 00060000 (buriki)
+ * 1 | xxxx---- | looks like it's 0001 most (all) of the time - turns off in buriki intro
+ * 1 | ----oooo | unknown - always seems to be 0000 (fatfurwa)
+ * 2 | oooooooo | unknown - likes to change sometimes though... (looks like bit-flags)
+ * 3 | oooooooo | unknown - change a lot - maybe mixer flags?
+ * 4 | xxxx---- | tilemap0 offset into tilemap RAM?
+ * 4 | ----xxxx | tilemap1 offset into tilemap RAM
+ * 5 | xxxx---- | tilemap3 offset into tilemap RAM
+ * 5 | ----xxxx | tilemap4 offset into tilemap RAM?
+ * 6 | oooooooo | unknown - always seems to be 000001ff (fatfurwa)
+ * 7 | oooooooo | unknown - always seems to be 000001ff (fatfurwa)
+ * 8 | oooooooo | unknown - always seems to be 80008000 (fatfurwa)
+ * 9 | oooooooo | unknown - always seems to be 00000000 (fatfurwa)
+ * a | oooooooo | unknown - always seems to be 00000000 (fatfurwa)
+ * b | oooooooo | unknown - 00000000 in intro - 00007ff8 when fight is going on (looks like &'ing it with 0x3fff is a good thing to do - tilemap stuff?)
+ * c | xxxxxxxx | I'm almost positive this is some form of offset to produce animations in Tilemap1 - or maybe all tilemaps?
+ * - 00xxx000 are used in fatfurwa during fights
+ * - 00000?xx are used in buriki during the intro
+ * d | oooooooo | not used ??
+ * e | oooooooo | not used ??
+ */
+
+
+VIDEO_UPDATE( hng64 )
+{
+ fillbitmap(bitmap, get_black_pen(machine), 0);
+
+ // Debug
+// for (int iii = 0; iii < 0x0f; iii++)
+// mame_printf_debug("%.8x ", hng64_videoregs[iii]) ;
+// mame_printf_debug("\n") ;
+// usrintf_showmessage("%.8x %.8x %.8x %.8x", hng64_videoregs[0x1], hng64_videoregs[0x3], hng64_videoregs[0xb], hng64_videoregs[0xc]) ;
+
+ // I think there's something to this, but I'm not doing it right...
+ // Interestingly enough, this turns the bootup screen blue :)
+ /*
+ if (hng64_videoregs[0xc] != tilemap2Offset)
+ {
+ tilemap2Offset = hng64_videoregs[0xc] ;
+
+ tilemap_dispose(hng64_tilemap1) ;
+ hng64_tilemap1 = tilemap_create(get_hng64_tile2_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16, 128,128); // 128x128x4 = 0x10000
+ }
+ */
+
+ // Rowscroll variables...
+ // usrintf_showmessage("%.8x %.8x x %.8x %.8x", hng64_videoram[0x00057bf0/4], hng64_videoram[0x00057bf4/4], hng64_videoram[0x00057bf8/4], hng64_videoram[0x00057bfc/4]) ;
+
+ // All of this priority stuff is probably done with some funky layer mixing chip -
+ // (there are neato alpha effects on a real board, etc)
+ hng64_drawtilemap2(bitmap,cliprect);
+ hng64_drawtilemap1(bitmap,cliprect);
+ hng64_drawtilemap3(machine, bitmap,cliprect); // Draw the ground last...
+
+ // !!! This tilemap has the same flags as the 'previous' three, but they're not used in fatfurwa !!!
+ // (in other words, we should make a similar hng64_drawtilemap0() function for this tilemap)
+ tilemap_draw(bitmap,cliprect,hng64_tilemap0,0,0);
+
+ draw_sprites(machine, bitmap,cliprect);
+
+ // 3d really shouldn't be last, but you don't see some cool stuff right now if it's put before sprites :)...
+ draw3d(machine, bitmap, cliprect);
+
+ /* hack to enable 2nd cpu when key is pressed */
+// if ( input_code_pressed_once(KEYCODE_L) )
+// {
+// cpunum_set_input_line(1, INPUT_LINE_HALT, CLEAR_LINE);
+// cpunum_set_input_line(1, INPUT_LINE_RESET, CLEAR_LINE);
+// }
+
+ /* AJG */
+ // if(input_code_pressed(KEYCODE_D))
+
+ transition_control(machine, bitmap) ;
+
+// mame_printf_debug("FRAME DONE %d\n", frameCount) ;
+ frameCount++ ;
+
+ hng64_hackTilemap3 = hng64_rowScrollOffset = hng64_hackTm3Count = 0 ;
+ return 0;
+}
+
+VIDEO_START( hng64 )
+{
+ hng64_tilemap0 = tilemap_create(get_hng64_tile0_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 128,128); /* 128x128x4 = 0x10000 */
+ hng64_tilemap1 = tilemap_create(get_hng64_tile1_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 128,128); /* 128x128x4 = 0x10000 */
+ hng64_tilemap2 = tilemap_create(get_hng64_tile2_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 128,128); /* 128x128x4 = 0x10000 */
+ hng64_tilemap3 = tilemap_create(get_hng64_tile3_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 128,128); /* 128x128x4 = 0x10000 */
+ tilemap_set_transparent_pen(hng64_tilemap0,0);
+ tilemap_set_transparent_pen(hng64_tilemap1,0);
+ tilemap_set_transparent_pen(hng64_tilemap2,0);
+ tilemap_set_transparent_pen(hng64_tilemap3,0);
+
+ // 3d Buffer Allocation
+ depthBuffer = (float*)auto_malloc((machine->screen[0].visarea.max_x)*(machine->screen[0].visarea.max_y)*sizeof(float)) ;
+
+ // The general display list of polygons in the scene...
+ // !! This really should be a dynamic array !!
+ polys = auto_malloc(MAX_ONSCREEN_POLYS * sizeof(struct polygon)) ;
+}
+
+///////////////
+// UTILITIES //
+///////////////
+
+/* 4x4 matrix multiplication */
+static void matmul4( float *product, const float *a, const float *b )
+{
+ int i;
+ for (i = 0; i < 4; i++)
+ {
+ const float ai0 = a[0 + i] ;
+ const float ai1 = a[4 + i] ;
+ const float ai2 = a[8 + i] ;
+ const float ai3 = a[12 + i] ;
+
+ product[0 + i] = ai0 * b[0 ] + ai1 * b[1 ] + ai2 * b[2 ] + ai3 * b[3 ] ;
+ product[4 + i] = ai0 * b[4 ] + ai1 * b[5 ] + ai2 * b[6 ] + ai3 * b[7 ] ;
+ product[8 + i] = ai0 * b[8 ] + ai1 * b[9 ] + ai2 * b[10] + ai3 * b[11] ;
+ product[12 + i] = ai0 * b[12] + ai1 * b[13] + ai2 * b[14] + ai3 * b[15] ;
+ }
+}
+
+/* vector by 4x4 matrix multiply */
+static void vecmatmul4( float *product, const float *a, const float *b)
+{
+ const float bi0 = b[0] ;
+ const float bi1 = b[1] ;
+ const float bi2 = b[2] ;
+ const float bi3 = b[3] ;
+
+ product[0] = bi0 * a[0] + bi1 * a[4] + bi2 * a[8 ] + bi3 * a[12];
+ product[1] = bi0 * a[1] + bi1 * a[5] + bi2 * a[9 ] + bi3 * a[13];
+ product[2] = bi0 * a[2] + bi1 * a[6] + bi2 * a[10] + bi3 * a[14];
+ product[3] = bi0 * a[3] + bi1 * a[7] + bi2 * a[11] + bi3 * a[15];
+}
+
+#ifdef UNUSED_FUNCTION
+static float vecDotProduct( const float *a, const float *b)
+{
+ return ((a[0]*b[0]) + (a[1]*b[1]) + (a[2]*b[2])) ;
+}
+#endif
+
+static void SetIdentity(float *matrix)
+{
+ int i ;
+
+ for (i = 0; i < 16; i++)
+ {
+ matrix[i] = 0.0f ;
+ }
+
+ matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1.0f ;
+}
+
+static float uToF(UINT16 input)
+{
+ float retVal ;
+
+ retVal = (float)((INT16)input) / 32768.0f ;
+
+/*
+ if ((INT16)input < 0)
+ retVal = (float)((INT16)input) / 32768.0f ;
+ else
+ retVal = (float)((INT16)input) / 32767.0f ;
+*/
+
+ return retVal ;
+}
+
+#ifdef UNUSED_FUNCTION
+static void normalize(float* x)
+{
+ double l2 = (x[0]*x[0]) + (x[1]*x[1]) + (x[2]*x[2]);
+ double l=sqrt(l2) ;
+
+ x[0] = (float)(x[0] / l) ;
+ x[1] = (float)(x[1] / l) ;
+ x[2] = (float)(x[2] / l) ;
+}
+#endif
+
+
+
+///////////////////////////
+// POLYGON CLIPPING CODE //
+///////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////////
+// The remainder of the code in this file is heavily //
+// influenced by, and sometimes copied verbatim from Andrew Zaferakis' SoftGL //
+// rasterizing system. http://www.cs.unc.edu/~andrewz/comp236/ //
+// //
+// Andrew granted permission for its use in MAME in October of 2004. //
+///////////////////////////////////////////////////////////////////////////////////
+
+// Refer to the clipping planes as numbers
+#define HNG64_LEFT 0
+#define HNG64_RIGHT 1
+#define HNG64_TOP 2
+#define HNG64_BOTTOM 3
+#define HNG64_NEAR 4
+#define HNG64_FAR 5
+
+
+static int Inside(struct polyVert *v, int plane)
+{
+ switch(plane)
+ {
+ case HNG64_LEFT:
+ return (v->clipCoords[0] >= -v->clipCoords[3]) ? 1 : 0 ;
+ case HNG64_RIGHT:
+ return (v->clipCoords[0] <= v->clipCoords[3]) ? 1 : 0 ;
+
+ case HNG64_TOP:
+ return (v->clipCoords[1] <= v->clipCoords[3]) ? 1 : 0 ;
+ case HNG64_BOTTOM:
+ return (v->clipCoords[1] >= -v->clipCoords[3]) ? 1 : 0 ;
+
+ case HNG64_NEAR:
+ return (v->clipCoords[2] <= v->clipCoords[3]) ? 1 : 0;
+ return 1 ;
+ case HNG64_FAR:
+ return (v->clipCoords[2] >= -v->clipCoords[3]) ? 1 : 0;
+ return 1 ;
+ }
+
+ return 0 ;
+}
+
+static void Intersect(struct polyVert *input0, struct polyVert *input1, struct polyVert *output, int plane)
+{
+ float t = 0.0f ;
+
+ float *Iv0 = input0->clipCoords ;
+ float *Iv1 = input1->clipCoords ;
+ float *Ov = output->clipCoords ;
+
+ float *It0 = input0->texCoords ;
+ float *It1 = input1->texCoords ;
+ float *Ot = output->texCoords ;
+
+ float *Il0 = input0->light ;
+ float *Il1 = input1->light ;
+ float *Ol = output->light ;
+
+ switch(plane)
+ {
+ case HNG64_LEFT:
+ t = (Iv0[0]+Iv0[3]) / (-Iv1[3]+Iv0[3]-Iv1[0]+Iv0[0]);
+ break;
+ case HNG64_RIGHT:
+ t = (Iv0[0]-Iv0[3]) / (Iv1[3]-Iv0[3]-Iv1[0]+Iv0[0]);
+ break;
+ case HNG64_TOP:
+ t = (Iv0[1]-Iv0[3]) / (Iv1[3]-Iv0[3]-Iv1[1]+Iv0[1]);
+ break;
+ case HNG64_BOTTOM:
+ t = (Iv0[1]+Iv0[3]) / (-Iv1[3]+Iv0[3]-Iv1[1]+Iv0[1]);
+ break;
+ case HNG64_NEAR:
+ t = (Iv0[2]-Iv0[3]) / (Iv1[3]-Iv0[3]-Iv1[2]+Iv0[2]);
+ break;
+ case HNG64_FAR:
+ t = (Iv0[2]+Iv0[3]) / (-Iv1[3]+Iv0[3]-Iv1[2]+Iv0[2]);
+ break;
+ }
+
+ Ov[0] = Iv0[0] + (Iv1[0] - Iv0[0]) * t ;
+ Ov[1] = Iv0[1] + (Iv1[1] - Iv0[1]) * t ;
+ Ov[2] = Iv0[2] + (Iv1[2] - Iv0[2]) * t ;
+ Ov[3] = Iv0[3] + (Iv1[3] - Iv0[3]) * t ;
+
+ Ot[0] = It0[0] + (It1[0] - It0[0]) * t ;
+ Ot[1] = It0[1] + (It1[1] - It0[1]) * t ;
+ Ot[2] = It0[2] + (It1[2] - It0[2]) * t ;
+ Ot[3] = It0[3] + (It1[3] - It0[3]) * t ;
+
+ Ol[0] = Il0[0] + (Il1[0] - Il0[0]) * t ;
+ Ol[1] = Il0[1] + (Il1[1] - Il0[1]) * t ;
+ Ol[2] = Il0[2] + (Il1[2] - Il0[2]) * t ;
+}
+
+
+
+static void PerformFrustumClip(struct polygon *p)
+{
+ int i, j ;
+ int k ;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Clip against the volumes defined by the homogeneous clip coordinates //
+ //////////////////////////////////////////////////////////////////////////
+
+ struct polygon temp ;
+
+ struct polyVert *v0 ;
+ struct polyVert *v1 ;
+ struct polyVert *tv ;
+
+ temp.n = 0;
+
+ // Skip near and far clipping planes ?
+ for (j = 0; j <= HNG64_BOTTOM; j++)
+ {
+ for (i = 0; i < p->n; i++)
+ {
+ k = (i+1) % p->n; // Index of next vertex
+
+ v0 = &p->vert[i] ;
+ v1 = &p->vert[k] ;
+
+ tv = &temp.vert[temp.n] ;
+
+ if (Inside(v0, j) && Inside(v1, j)) // Edge is completely inside the volume...
+ {
+ memcpy(tv, v1, sizeof(struct polyVert)) ;
+ temp.n++;
+ }
+
+ else if (Inside(v0, j) && !Inside(v1, j)) // Edge goes from in to out...
+ {
+ Intersect(v0, v1, tv, j) ;
+ temp.n++;
+ }
+
+ else if (!Inside(v0, j) && Inside(v1, j)) // Edge goes from out to in...
+ {
+ Intersect(v0, v1, tv, j) ;
+ memcpy(&temp.vert[temp.n+1], v1, sizeof(struct polyVert)) ;
+ temp.n+=2;
+ }
+ }
+
+ p->n = temp.n;
+
+ for (i = 0; i < temp.n; i++)
+ {
+ memcpy(&p->vert[i], &temp.vert[i], sizeof(struct polyVert)) ;
+ }
+
+ temp.n = 0 ;
+ }
+}
+
+
+//////////////////////////////
+// POLYGON RASTERIZING CODE //
+//////////////////////////////
+
+/////////////////////////
+// wireframe rendering //
+/////////////////////////
+
+#ifdef UNUSED_FUNCTION
+static void plot(INT32 x, INT32 y, INT32 color, mame_bitmap *bitmap)
+{
+ *BITMAP_ADDR32(bitmap, y, x) = MAKE_ARGB((UINT8)255, (UINT8)color, (UINT8)color, (UINT8)color) ;
+}
+
+// Stolen from http://en.wikipedia.org/wiki/Bresenham's_line_algorithm (no copyright denoted) - the non-optimized version
+static void drawline2d(INT32 x0, INT32 y0, INT32 x1, INT32 y1, INT32 color, mame_bitmap *bitmap)
+{
+#define SWAP(a,b) tmpswap = a; a = b; b = tmpswap;
+
+ INT32 i;
+ INT32 steep = 1;
+ INT32 sx, sy; /* step positive or negative (1 or -1) */
+ INT32 dx, dy; /* delta (difference in X and Y between points) */
+ INT32 e;
+
+ /*
+ * inline swap. On some architectures, the XOR trick may be faster
+ */
+ INT32 tmpswap;
+
+ /*
+ * optimize for vertical and horizontal lines here
+ */
+
+ dx = abs(x1 - x0);
+ sx = ((x1 - x0) > 0) ? 1 : -1;
+ dy = abs(y1 - y0);
+ sy = ((y1 - y0) > 0) ? 1 : -1;
+
+ if (dy > dx)
+ {
+ steep = 0;
+ SWAP(x0, y0);
+ SWAP(dx, dy);
+ SWAP(sx, sy);
+ }
+
+ e = (dy << 1) - dx;
+
+ for (i = 0; i < dx; i++)
+ {
+ if (steep)
+ {
+ plot(x0,y0,color, bitmap);
+ }
+ else
+ {
+ plot(y0,x0,color, bitmap);
+ }
+ while (e >= 0)
+ {
+ y0 += sy;
+ e -= (dx << 1);
+ }
+
+ x0 += sx;
+ e += (dy << 1);
+ }
+#undef SWAP
+}
+
+
+static void DrawWireframe(struct polygon *p, mame_bitmap *bitmap)
+{
+ int j;
+ for (j = 0; j < p->n; j++)
+ {
+ // mame_printf_debug("now drawing : %f %f %f, %f %f %f\n", p->vert[j].clipCoords[0], p->vert[j].clipCoords[1], p->vert[j].clipCoords[2], p->vert[(j+1)%p->n].clipCoords[0], p->vert[(j+1)%p->n].clipCoords[1], p->vert[(j+1)%p->n].clipCoords[2]) ;
+ // mame_printf_debug("%f %f %f %f\n", p->vert[j].clipCoords[0], p->vert[j].clipCoords[1], p->vert[(j+1)%p->n].clipCoords[0], p->vert[(j+1)%p->n].clipCoords[1]) ;
+ drawline2d(p->vert[j].clipCoords[0], p->vert[j].clipCoords[1], p->vert[(j+1)%p->n].clipCoords[0], p->vert[(j+1)%p->n].clipCoords[1], 255, bitmap) ;
+ }
+
+ // SHOWS THE CLIPPING //
+ /*
+ for (int j = 1; j < p->n-1; j++)
+ {
+ drawline2d(p->vert[0].clipCoords[0], p->vert[0].clipCoords[1], p->vert[j].clipCoords[0], p->vert[j].clipCoords[1], 255, bitmap) ;
+ drawline2d(p->vert[j].clipCoords[0], p->vert[j].clipCoords[1], p->vert[j+1].clipCoords[0], p->vert[j+1].clipCoords[1], 255, bitmap) ;
+ drawline2d(p->vert[j+1].clipCoords[0], p->vert[j+1].clipCoords[1], p->vert[0].clipCoords[0], p->vert[0].clipCoords[1], 255, bitmap) ;
+ }
+ */
+}
+#endif
+
+
+///////////////////////
+// polygon rendering //
+///////////////////////
+
+static void RasterizeTriangle_SMOOTH_TEX_PC(running_machine *machine, mame_bitmap *Color,
+ float A[4], float B[4], float C[4],
+ float Ca[3], float Cb[3], float Cc[3], // PER-VERTEX RGB COLORS
+ float Ta[2], float Tb[2], float Tc[2], // PER-VERTEX (S,T) TEX-COORDS
+ int Wrapping, int Filtering, int Function) ;
+
+static void DrawShaded(running_machine *machine, struct polygon *p, mame_bitmap *bitmap)
+{
+ // The perspective-correct texture divide...
+ // !!! There is a very good chance the HNG64 hardware does not do perspective-correct texture-mapping !!!
+ int j;
+ for (j = 0; j < p->n; j++)
+ {
+ p->vert[j].clipCoords[3] = 1.0f / p->vert[j].clipCoords[3] ;
+ p->vert[j].light[0] = p->vert[j].light[0] * p->vert[j].clipCoords[3] ;
+ p->vert[j].light[1] = p->vert[j].light[1] * p->vert[j].clipCoords[3] ;
+ p->vert[j].light[2] = p->vert[j].light[2] * p->vert[j].clipCoords[3] ;
+ p->vert[j].texCoords[0] = p->vert[j].texCoords[0] * p->vert[j].clipCoords[3] ;
+ p->vert[j].texCoords[1] = p->vert[j].texCoords[1] * p->vert[j].clipCoords[3] ;
+ }
+
+ for (j = 1; j < p->n-1; j++)
+ {
+ RasterizeTriangle_SMOOTH_TEX_PC(machine, bitmap,
+ p->vert[0].clipCoords, p->vert[j].clipCoords, p->vert[j+1].clipCoords,
+ p->vert[0].light, p->vert[j].light, p->vert[j+1].light,
+ p->vert[0].texCoords, p->vert[j].texCoords, p->vert[j+1].texCoords,
+ p->texType, p->palIndex, p->texIndex) ;
+
+ }
+}
+
+
+/*********************************************************************/
+/** FillSmoothTexPCHorizontalLine **/
+/** Input: Color Buffer (framebuffer), depth buffer, width and **/
+/** height of framebuffer, starting, and ending values **/
+/** for x and y, constant y. Fills horizontally with **/
+/** z,r,g,b interpolation. **/
+/** **/
+/** Output: none **/
+/*********************************************************************/
+INLINE void FillSmoothTexPCHorizontalLine(running_machine *machine, mame_bitmap *Color,
+ int Wrapping, int Filtering, int Function,
+ int x_start, int x_end, int y, float z_start, float z_delta,
+ float w_start, float w_delta, float r_start, float r_delta,
+ float g_start, float g_delta, float b_start, float b_delta,
+ float s_start, float s_delta, float t_start, float t_delta)
+{
+ float *dp = &(depthBuffer[y*machine->screen[0].visarea.max_x+x_start]);
+
+ const UINT8 *gfx = memory_region(REGION_GFX3);
+ const UINT8 *textureOffset ;
+ UINT8 paletteEntry ;
+ float t_coord, s_coord ;
+
+ if (Function >= 0) textureOffset = &gfx[Function * 1024 * 1024] ;
+ else textureOffset = 0x00 ;
+
+
+ for ( ; x_start <= x_end; x_start++)
+ {
+ if (z_start < (*dp))
+ {
+ // MULTIPLY BACK THROUGH BY W
+ t_coord = t_start / w_start;
+ s_coord = s_start / w_start;
+
+ // GET THE TEXTURE INDEX
+ if (Function >= 0)
+ {
+ if (Wrapping == 0x8 || Wrapping == 0xc)
+ paletteEntry = textureOffset[(((int)(s_coord*1024.0f))*1024 + (int)(t_coord*1024.0f))] ;
+ else
+ paletteEntry = textureOffset[(((int)(s_coord*512.0f))*1024 + (int)(t_coord*512.0f))] ;
+
+ // Naieve Alpha Implementation (?) - don't draw if you're at texture index 0...
+ if (paletteEntry != 0)
+ {
+ // Greyscale texture - for Buriki...
+ // *BITMAP_ADDR32(Color, y, x_start) = MAKE_ARGB(255, (UINT8)paletteEntry, (UINT8)paletteEntry, (UINT8)paletteEntry) ;
+
+ *BITMAP_ADDR32(Color, y, x_start) = machine->pens[(128*(Filtering))+paletteEntry] ;
+ *dp = z_start ;
+ }
+ }
+ else
+ {
+ *BITMAP_ADDR32(Color, y, x_start) = MAKE_ARGB(255, (UINT8)(r_start/w_start), (UINT8)(g_start/w_start), (UINT8)(b_start/w_start)) ;
+ *dp = z_start;
+ }
+ }
+ dp++;
+ z_start += z_delta;
+ w_start += w_delta;
+ r_start += r_delta;
+ g_start += g_delta;
+ b_start += b_delta;
+ s_start += s_delta;
+ t_start += t_delta;
+ }
+}
+
+//----------------------------------------------------------------------------
+// Given 3D triangle ABC in screen space with clipped coordinates within the following
+// bounds: x in [0,W], y in [0,H], z in [0,1]. The origin for (x,y) is in the bottom
+// left corner of the pixel grid. z=0 is the near plane and z=1 is the far plane,
+// so lesser values are closer. The coordinates of the pixels are evenly spaced
+// in x and y 1 units apart starting at the bottom-left pixel with coords
+// (0.5,0.5). In other words, the pixel sample point is in the center of the
+// rectangular grid cell containing the pixel sample. The framebuffer has
+// dimensions width x height (WxH). The Color buffer is a 1D array (row-major
+// order) with 3 unsigned chars per pixel (24-bit color). The Depth buffer is
+// a 1D array (also row-major order) with a float value per pixel
+// For a pixel location (x,y) we can obtain
+// the Color and Depth array locations as: Color[(((int)y)*W+((int)x))*3]
+// (for the red value, green is offset +1, and blue is offset +2 and
+// Depth[((int)y)*W+((int)x)]. Fills the pixels contained in the triangle
+// with the global current color and the properly linearly interpolated depth
+// value (performs Z-buffer depth test before writing new pixel).
+// Pixel samples that lie inside the triangle edges are filled with
+// a bias towards the minimum values (samples that lie exactly on a triangle
+// edge are filled only for minimum x values along a horizontal span and for
+// minimum y values, samples lying on max values are not filled).
+// Per-vertex colors are RGB floating point triplets in [0.0,255.0]. The vertices
+// include their w-components for use in linearly interpolating perspectively
+// correct color (RGB) and texture-coords (st) across the face of the triangle.
+// A texture image of RGB floating point triplets of size TWxWH is also given.
+// Texture colors are normalized RGB values in [0,1].
+// clamp and repeat wrapping modes : Wrapping={0,1}
+// nearest and bilinear filtering: Filtering={0,1}
+// replace and modulate application modes: Function={0,1}
+//---------------------------------------------------------------------------
+static void RasterizeTriangle_SMOOTH_TEX_PC(running_machine *machine, mame_bitmap *Color,
+ float A[4], float B[4], float C[4],
+ float Ca[3], float Cb[3], float Cc[3], // PER-VERTEX RGB COLORS
+ float Ta[2], float Tb[2], float Tc[2], // PER-VERTEX (S,T) TEX-COORDS
+ int Wrapping, int Filtering, int Function)
+{
+ // Get our order of points by increasing y-coord
+ float *p_min = ((A[1] <= B[1]) && (A[1] <= C[1])) ? A : ((B[1] <= A[1]) && (B[1] <= C[1])) ? B : C;
+ float *p_max = ((A[1] >= B[1]) && (A[1] >= C[1])) ? A : ((B[1] >= A[1]) && (B[1] >= C[1])) ? B : C;
+ float *p_mid = ((A != p_min) && (A != p_max)) ? A : ((B != p_min) && (B != p_max)) ? B : C;
+
+ // Perspectively correct color interpolation, interpolate r/w, g/w, b/w, then divide by 1/w at each pixel (A[3] = 1/w)
+ float ca[3], cb[3], cc[3];
+ float ta[2], tb[2], tc[2];
+
+ float *c_min;
+ float *c_mid;
+ float *c_max;
+
+ // We must keep the tex coords straight with the point ordering
+ float *t_min;
+ float *t_mid;
+ float *t_max;
+
+ // Find out control points for y, this divides the triangle into upper and lower
+ int y_min;
+ int y_max;
+ int y_mid;
+
+ // Compute the slopes of each line, and color this is used to determine the interpolation
+ float x1_slope;
+ float x2_slope;
+ float z1_slope;
+ float z2_slope;
+ float w1_slope;
+ float w2_slope;
+ float r1_slope;
+ float r2_slope;
+ float g1_slope;
+ float g2_slope;
+ float b1_slope;
+ float b2_slope;
+ float s1_slope;
+ float s2_slope;
+ float t1_slope;
+ float t2_slope;
+
+ // Compute the t values used in the equation Ax = Ax + (Bx - Ax)*t
+ // We only need one t, because it is only used to compute the start.
+ // Create storage for the interpolated x and z values for both lines
+ // also for the RGB interpolation
+ float t;
+ float x1_interp;
+ float z1_interp;
+ float w1_interp;
+ float r1_interp;
+ float g1_interp;
+ float b1_interp;
+ float s1_interp;
+ float t1_interp;
+
+ float x2_interp;
+ float z2_interp;
+ float w2_interp;
+ float r2_interp;
+ float g2_interp;
+ float b2_interp;
+ float s2_interp;
+ float t2_interp;
+
+ // Create storage for the horizontal interpolation of z and RGB color and its starting points
+ // This is used to fill the triangle horizontally
+ int x_start, x_end;
+ float z_interp_x, z_delta_x;
+ float w_interp_x, w_delta_x;
+ float r_interp_x, r_delta_x;
+ float g_interp_x, g_delta_x;
+ float b_interp_x, b_delta_x;
+ float s_interp_x, s_delta_x;
+ float t_interp_x, t_delta_x;
+
+ ca[0] = Ca[0]; ca[1] = Ca[1]; ca[2] = Ca[2];
+ cb[0] = Cb[0]; cb[1] = Cb[1]; cb[2] = Cb[2];
+ cc[0] = Cc[0]; cc[1] = Cc[1]; cc[2] = Cc[2];
+
+ // Perspectively correct tex interpolation, interpolate s/w, t/w, then divide by 1/w at each pixel (A[3] = 1/w)
+ ta[0] = Ta[0]; ta[1] = Ta[1];
+ tb[0] = Tb[0]; tb[1] = Tb[1];
+ tc[0] = Tc[0]; tc[1] = Tc[1];
+
+ // We must keep the colors straight with the point ordering
+ c_min = (p_min == A) ? ca : (p_min == B) ? cb : cc;
+ c_mid = (p_mid == A) ? ca : (p_mid == B) ? cb : cc;
+ c_max = (p_max == A) ? ca : (p_max == B) ? cb : cc;
+
+ // We must keep the tex coords straight with the point ordering
+ t_min = (p_min == A) ? ta : (p_min == B) ? tb : tc;
+ t_mid = (p_mid == A) ? ta : (p_mid == B) ? tb : tc;
+ t_max = (p_max == A) ? ta : (p_max == B) ? tb : tc;
+
+ // Find out control points for y, this divides the triangle into upper and lower
+ y_min = (((int)p_min[1]) + 0.5 >= p_min[1]) ? p_min[1] : ((int)p_min[1]) + 1;
+ y_max = (((int)p_max[1]) + 0.5 < p_max[1]) ? p_max[1] : ((int)p_max[1]) - 1;
+ y_mid = (((int)p_mid[1]) + 0.5 >= p_mid[1]) ? p_mid[1] : ((int)p_mid[1]) + 1;
+
+ // Compute the slopes of each line, and color this is used to determine the interpolation
+ x1_slope = (p_max[0] - p_min[0]) / (p_max[1] - p_min[1]);
+ x2_slope = (p_mid[0] - p_min[0]) / (p_mid[1] - p_min[1]);
+ z1_slope = (p_max[2] - p_min[2]) / (p_max[1] - p_min[1]);
+ z2_slope = (p_mid[2] - p_min[2]) / (p_mid[1] - p_min[1]);
+ w1_slope = (p_max[3] - p_min[3]) / (p_max[1] - p_min[1]);
+ w2_slope = (p_mid[3] - p_min[3]) / (p_mid[1] - p_min[1]);
+ r1_slope = (c_max[0] - c_min[0]) / (p_max[1] - p_min[1]);
+ r2_slope = (c_mid[0] - c_min[0]) / (p_mid[1] - p_min[1]);
+ g1_slope = (c_max[1] - c_min[1]) / (p_max[1] - p_min[1]);
+ g2_slope = (c_mid[1] - c_min[1]) / (p_mid[1] - p_min[1]);
+ b1_slope = (c_max[2] - c_min[2]) / (p_max[1] - p_min[1]);
+ b2_slope = (c_mid[2] - c_min[2]) / (p_mid[1] - p_min[1]);
+ s1_slope = (t_max[0] - t_min[0]) / (p_max[1] - p_min[1]);
+ s2_slope = (t_mid[0] - t_min[0]) / (p_mid[1] - p_min[1]);
+ t1_slope = (t_max[1] - t_min[1]) / (p_max[1] - p_min[1]);
+ t2_slope = (t_mid[1] - t_min[1]) / (p_mid[1] - p_min[1]);
+
+ // Compute the t values used in the equation Ax = Ax + (Bx - Ax)*t
+ // We only need one t, because it is only used to compute the start.
+ // Create storage for the interpolated x and z values for both lines
+ // also for the RGB interpolation
+ t = (((float)y_min) + 0.5 - p_min[1]) / (p_max[1] - p_min[1]);
+ x1_interp = p_min[0] + (p_max[0] - p_min[0]) * t;
+ z1_interp = p_min[2] + (p_max[2] - p_min[2]) * t;
+ w1_interp = p_min[3] + (p_max[3] - p_min[3]) * t;
+ r1_interp = c_min[0] + (c_max[0] - c_min[0]) * t;
+ g1_interp = c_min[1] + (c_max[1] - c_min[1]) * t;
+ b1_interp = c_min[2] + (c_max[2] - c_min[2]) * t;
+ s1_interp = t_min[0] + (t_max[0] - t_min[0]) * t;
+ t1_interp = t_min[1] + (t_max[1] - t_min[1]) * t;
+
+ t = (((float)y_min) + 0.5 - p_min[1]) / (p_mid[1] - p_min[1]);
+ x2_interp = p_min[0] + (p_mid[0] - p_min[0]) * t;
+ z2_interp = p_min[2] + (p_mid[2] - p_min[2]) * t;
+ w2_interp = p_min[3] + (p_mid[3] - p_min[3]) * t;
+ r2_interp = c_min[0] + (c_mid[0] - c_min[0]) * t;
+ g2_interp = c_min[1] + (c_mid[1] - c_min[1]) * t;
+ b2_interp = c_min[2] + (c_mid[2] - c_min[2]) * t;
+ s2_interp = t_min[0] + (t_mid[0] - t_min[0]) * t;
+ t2_interp = t_min[1] + (t_mid[1] - t_min[1]) * t;
+
+ // First work on the bottom half of the triangle
+ // I'm using y_min as the incrementer because it saves space and we don't need it anymore
+ for ( ; y_min < y_mid; y_min++) {
+
+ // We always want to fill left to right, so we have 2 main cases
+ // Compute the integer starting and ending points and the appropriate z by
+ // interpolating. Remember the pixels are in the middle of the grid, i.e. (0.5,0.5,0.5)
+ if (x1_interp < x2_interp) {
+ x_start = ((((int)x1_interp) + 0.5) >= x1_interp) ? x1_interp : ((int)x1_interp) + 1;
+ x_end = ((((int)x2_interp) + 0.5) < x2_interp) ? x2_interp : ((int)x2_interp) - 1;
+ z_delta_x = (z2_interp - z1_interp) / (x2_interp - x1_interp);
+ w_delta_x = (w2_interp - w1_interp) / (x2_interp - x1_interp);
+ r_delta_x = (r2_interp - r1_interp) / (x2_interp - x1_interp);
+ g_delta_x = (g2_interp - g1_interp) / (x2_interp - x1_interp);
+ b_delta_x = (b2_interp - b1_interp) / (x2_interp - x1_interp);
+ s_delta_x = (s2_interp - s1_interp) / (x2_interp - x1_interp);
+ t_delta_x = (t2_interp - t1_interp) / (x2_interp - x1_interp);
+ t = (x_start + 0.5 - x1_interp) / (x2_interp - x1_interp);
+ z_interp_x = z1_interp + (z2_interp - z1_interp) * t;
+ w_interp_x = w1_interp + (w2_interp - w1_interp) * t;
+ r_interp_x = r1_interp + (r2_interp - r1_interp) * t;
+ g_interp_x = g1_interp + (g2_interp - g1_interp) * t;
+ b_interp_x = b1_interp + (b2_interp - b1_interp) * t;
+ s_interp_x = s1_interp + (s2_interp - s1_interp) * t;
+ t_interp_x = t1_interp + (t2_interp - t1_interp) * t;
+
+ } else {
+ x_start = ((((int)x2_interp) + 0.5) >= x2_interp) ? x2_interp : ((int)x2_interp) + 1;
+ x_end = ((((int)x1_interp) + 0.5) < x1_interp) ? x1_interp : ((int)x1_interp) - 1;
+ z_delta_x = (z1_interp - z2_interp) / (x1_interp - x2_interp);
+ w_delta_x = (w1_interp - w2_interp) / (x1_interp - x2_interp);
+ r_delta_x = (r1_interp - r2_interp) / (x1_interp - x2_interp);
+ g_delta_x = (g1_interp - g2_interp) / (x1_interp - x2_interp);
+ b_delta_x = (b1_interp - b2_interp) / (x1_interp - x2_interp);
+ s_delta_x = (s1_interp - s2_interp) / (x1_interp - x2_interp);
+ t_delta_x = (t1_interp - t2_interp) / (x1_interp - x2_interp);
+ t = (x_start + 0.5 - x2_interp) / (x1_interp - x2_interp);
+ z_interp_x = z2_interp + (z1_interp - z2_interp) * t;
+ w_interp_x = w2_interp + (w1_interp - w2_interp) * t;
+ r_interp_x = r2_interp + (r1_interp - r2_interp) * t;
+ g_interp_x = g2_interp + (g1_interp - g2_interp) * t;
+ b_interp_x = b2_interp + (b1_interp - b2_interp) * t;
+ s_interp_x = s2_interp + (s1_interp - s2_interp) * t;
+ t_interp_x = t2_interp + (t1_interp - t2_interp) * t;
+ }
+
+ // Pass the horizontal line to the filler, this could be put in the routine
+ // then interpolate for the next values of x and z
+ FillSmoothTexPCHorizontalLine(machine, Color, Wrapping, Filtering, Function,
+ x_start, x_end, y_min, z_interp_x, z_delta_x, w_interp_x, w_delta_x,
+ r_interp_x, r_delta_x, g_interp_x, g_delta_x, b_interp_x, b_delta_x,
+ s_interp_x, s_delta_x, t_interp_x, t_delta_x);
+ x1_interp += x1_slope; z1_interp += z1_slope;
+ x2_interp += x2_slope; z2_interp += z2_slope;
+ r1_interp += r1_slope; r2_interp += r2_slope;
+ g1_interp += g1_slope; g2_interp += g2_slope;
+ b1_interp += b1_slope; b2_interp += b2_slope;
+ w1_interp += w1_slope; w2_interp += w2_slope;
+ s1_interp += s1_slope; s2_interp += s2_slope;
+ t1_interp += t1_slope; t2_interp += t2_slope;
+ }
+
+ // Now do the same thing for the top half of the triangle.
+ // We only need to recompute the x2 line because it changes at the midpoint
+ x2_slope = (p_max[0] - p_mid[0]) / (p_max[1] - p_mid[1]);
+ z2_slope = (p_max[2] - p_mid[2]) / (p_max[1] - p_mid[1]);
+ w2_slope = (p_max[3] - p_mid[3]) / (p_max[1] - p_mid[1]);
+ r2_slope = (c_max[0] - c_mid[0]) / (p_max[1] - p_mid[1]);
+ g2_slope = (c_max[1] - c_mid[1]) / (p_max[1] - p_mid[1]);
+ b2_slope = (c_max[2] - c_mid[2]) / (p_max[1] - p_mid[1]);
+ s2_slope = (t_max[0] - t_mid[0]) / (p_max[1] - p_mid[1]);
+ t2_slope = (t_max[1] - t_mid[1]) / (p_max[1] - p_mid[1]);
+
+ t = (((float)y_mid) + 0.5 - p_mid[1]) / (p_max[1] - p_mid[1]);
+ x2_interp = p_mid[0] + (p_max[0] - p_mid[0]) * t;
+ z2_interp = p_mid[2] + (p_max[2] - p_mid[2]) * t;
+ w2_interp = p_mid[3] + (p_max[3] - p_mid[3]) * t;
+ r2_interp = c_mid[0] + (c_max[0] - c_mid[0]) * t;
+ g2_interp = c_mid[1] + (c_max[1] - c_mid[1]) * t;
+ b2_interp = c_mid[2] + (c_max[2] - c_mid[2]) * t;
+ s2_interp = t_mid[0] + (t_max[0] - t_mid[0]) * t;
+ t2_interp = t_mid[1] + (t_max[1] - t_mid[1]) * t;
+
+ // We've seen this loop before haven't we?
+ // I'm using y_mid as the incrementer because it saves space and we don't need it anymore
+ for ( ; y_mid <= y_max; y_mid++) {
+
+ if (x1_interp < x2_interp) {
+ x_start = ((((int)x1_interp) + 0.5) >= x1_interp) ? x1_interp : ((int)x1_interp) + 1;
+ x_end = ((((int)x2_interp) + 0.5) < x2_interp) ? x2_interp : ((int)x2_interp) - 1;
+ z_delta_x = (z2_interp - z1_interp) / (x2_interp - x1_interp);
+ w_delta_x = (w2_interp - w1_interp) / (x2_interp - x1_interp);
+ r_delta_x = (r2_interp - r1_interp) / (x2_interp - x1_interp);
+ g_delta_x = (g2_interp - g1_interp) / (x2_interp - x1_interp);
+ b_delta_x = (b2_interp - b1_interp) / (x2_interp - x1_interp);
+ s_delta_x = (s2_interp - s1_interp) / (x2_interp - x1_interp);
+ t_delta_x = (t2_interp - t1_interp) / (x2_interp - x1_interp);
+ t = (x_start + 0.5 - x1_interp) / (x2_interp - x1_interp);
+ z_interp_x = z1_interp + (z2_interp - z1_interp) * t;
+ w_interp_x = w1_interp + (w2_interp - w1_interp) * t;
+ r_interp_x = r1_interp + (r2_interp - r1_interp) * t;
+ g_interp_x = g1_interp + (g2_interp - g1_interp) * t;
+ b_interp_x = b1_interp + (b2_interp - b1_interp) * t;
+ s_interp_x = s1_interp + (s2_interp - s1_interp) * t;
+ t_interp_x = t1_interp + (t2_interp - t1_interp) * t;
+
+ } else {
+ x_start = ((((int)x2_interp) + 0.5) >= x2_interp) ? x2_interp : ((int)x2_interp) + 1;
+ x_end = ((((int)x1_interp) + 0.5) < x1_interp) ? x1_interp : ((int)x1_interp) - 1;
+ z_delta_x = (z1_interp - z2_interp) / (x1_interp - x2_interp);
+ w_delta_x = (w1_interp - w2_interp) / (x1_interp - x2_interp);
+ r_delta_x = (r1_interp - r2_interp) / (x1_interp - x2_interp);
+ g_delta_x = (g1_interp - g2_interp) / (x1_interp - x2_interp);
+ b_delta_x = (b1_interp - b2_interp) / (x1_interp - x2_interp);
+ s_delta_x = (s1_interp - s2_interp) / (x1_interp - x2_interp);
+ t_delta_x = (t1_interp - t2_interp) / (x1_interp - x2_interp);
+ t = (x_start + 0.5 - x2_interp) / (x1_interp - x2_interp);
+ z_interp_x = z2_interp + (z1_interp - z2_interp) * t;
+ w_interp_x = w2_interp + (w1_interp - w2_interp) * t;
+ r_interp_x = r2_interp + (r1_interp - r2_interp) * t;
+ g_interp_x = g2_interp + (g1_interp - g2_interp) * t;
+ b_interp_x = b2_interp + (b1_interp - b2_interp) * t;
+ s_interp_x = s2_interp + (s1_interp - s2_interp) * t;
+ t_interp_x = t2_interp + (t1_interp - t2_interp) * t;
+ }
+
+ // Pass the horizontal line to the filler, this could be put in the routine
+ // then interpolate for the next values of x and z
+ FillSmoothTexPCHorizontalLine(machine, Color, Wrapping, Filtering, Function,
+ x_start, x_end, y_mid, z_interp_x, z_delta_x, w_interp_x, w_delta_x,
+ r_interp_x, r_delta_x, g_interp_x, g_delta_x, b_interp_x, b_delta_x,
+ s_interp_x, s_delta_x, t_interp_x, t_delta_x);
+ x1_interp += x1_slope; z1_interp += z1_slope;
+ x2_interp += x2_slope; z2_interp += z2_slope;
+ r1_interp += r1_slope; r2_interp += r2_slope;
+ g1_interp += g1_slope; g2_interp += g2_slope;
+ b1_interp += b1_slope; b2_interp += b2_slope;
+ w1_interp += w1_slope; w2_interp += w2_slope;
+ s1_interp += s1_slope; s2_interp += s2_slope;
+ t1_interp += t1_slope; t2_interp += t2_slope;
+ }
+}
diff --git a/src/mame/video/holeland.c b/src/mame/video/holeland.c
new file mode 100644
index 00000000000..89f595cfd75
--- /dev/null
+++ b/src/mame/video/holeland.c
@@ -0,0 +1,196 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static int palette_offset;
+static tilemap *bg_tilemap;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( holeland_get_tile_info )
+{
+ int attr = colorram[tile_index];
+ int tile_number = videoram[tile_index] | ((attr & 0x03) << 8);
+
+/*if (input_code_pressed(KEYCODE_Q) && (attr & 0x10)) tile_number = rand(); */
+/*if (input_code_pressed(KEYCODE_W) && (attr & 0x20)) tile_number = rand(); */
+/*if (input_code_pressed(KEYCODE_E) && (attr & 0x40)) tile_number = rand(); */
+/*if (input_code_pressed(KEYCODE_R) && (attr & 0x80)) tile_number = rand(); */
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ palette_offset + ((attr >> 4) & 0x0f),
+ TILE_FLIPYX((attr >> 2) & 0x03));
+ tileinfo->group = (attr >> 4) & 1;
+}
+
+static TILE_GET_INFO( crzrally_get_tile_info )
+{
+ int attr = colorram[tile_index];
+ int tile_number = videoram[tile_index] | ((attr & 0x03) << 8);
+
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ palette_offset + ((attr >> 4) & 0x0f),
+ TILE_FLIPYX((attr >> 2) & 0x03));
+ tileinfo->group = (attr >> 4) & 1;
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( holeland )
+{
+ bg_tilemap = tilemap_create(holeland_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ tilemap_set_transmask(bg_tilemap,0,0xff,0x00); /* split type 0 is totally transparent in front half */
+ tilemap_set_transmask(bg_tilemap,1,0x01,0xfe); /* split type 1 has pen 0? transparent in front half */
+}
+
+VIDEO_START( crzrally )
+{
+ bg_tilemap = tilemap_create(crzrally_get_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32,32);
+}
+
+WRITE8_HANDLER( holeland_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty( bg_tilemap, offset );
+}
+
+WRITE8_HANDLER( holeland_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty( bg_tilemap, offset );
+}
+
+WRITE8_HANDLER( holeland_pal_offs_w )
+{
+ static int po[2];
+ if ((data & 1) != po[offset])
+ {
+ po[offset] = data & 1;
+ palette_offset = (po[0] + (po[1] << 1)) << 4;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( holeland_scroll_w )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, data);
+}
+
+WRITE8_HANDLER( holeland_flipscreen_w )
+{
+ if (offset) flip_screen_y_set(data);
+ else flip_screen_x_set(data);
+}
+
+
+static void holeland_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs,code,sx,sy,color,flipx, flipy;
+
+ /* Weird, sprites entries don't start on DWORD boundary */
+ for (offs = 3;offs < spriteram_size - 1;offs += 4)
+ {
+ sy = 236 - spriteram[offs];
+ sx = spriteram[offs+2];
+
+ /* Bit 7 unknown */
+ code = spriteram[offs+1] & 0x7f;
+ color = palette_offset + (spriteram[offs+3] >> 4);
+
+ /* Bit 0, 1 unknown */
+ flipx = spriteram[offs+3] & 0x04;
+ flipy = spriteram[offs+3] & 0x08;
+
+ if (flip_screen_x)
+ {
+ flipx = !flipx;
+ sx = 240 - sx;
+ }
+
+ if (flip_screen_y)
+ {
+ flipy = !flipy;
+ sy = 240 - sy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ 2*sx,2*sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+static void crzrally_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs,code,sx,sy,color,flipx, flipy;
+
+ /* Weird, sprites entries don't start on DWORD boundary */
+ for (offs = 3;offs < spriteram_size - 1;offs += 4)
+ {
+ sy = 236 - spriteram[offs];
+ sx = spriteram[offs+2];
+
+ code = spriteram[offs+1] + ((spriteram[offs+3] & 0x01) << 8);
+ color = (spriteram[offs+3] >> 4) + ((spriteram[offs+3] & 0x01) << 4);
+
+ /* Bit 1 unknown */
+ flipx = spriteram[offs+3] & 0x04;
+ flipy = spriteram[offs+3] & 0x08;
+
+ if (flip_screen_x)
+ {
+ flipx = !flipx;
+ sx = 240 - sx;
+ }
+
+ if (flip_screen_y)
+ {
+ flipy = !flipy;
+ sy = 240 - sy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( holeland )
+{
+/*tilemap_mark_all_tiles_dirty(bg_tilemap); */
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1,0);
+ holeland_draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( crzrally )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ crzrally_draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/homedata.c b/src/mame/video/homedata.c
new file mode 100644
index 00000000000..9eaa5519684
--- /dev/null
+++ b/src/mame/video/homedata.c
@@ -0,0 +1,882 @@
+#include "driver.h"
+#include "cpu/m6809/m6809.h"
+#include "homedata.h"
+
+
+UINT8 *homedata_vreg; /* pointer to RAM associated with 0x7ffx */
+UINT8 reikaids_which;
+int homedata_visible_page;
+int homedata_priority;
+static int homedata_flipscreen;
+
+static UINT8 reikaids_gfx_bank[2];
+static UINT8 pteacher_gfx_bank;
+static UINT8 blitter_bank;
+static int blitter_param_count;
+static UINT8 blitter_param[4]; /* buffers last 4 writes to 0x8006 */
+
+static tilemap *bg_tilemap[2][4];
+
+
+/*
+ video control registers:
+ 0 xxxxxxxx unknown
+ 1 x------- flip screen
+ -xxxxxxx unknown
+ 2 xxxxxxxx unknown
+ 3 xxxxxxxx related to visible area?
+ 4 ----xxxx fine horiz scroll (sub-character, 8 or 12 pixels)
+ xxxx---- unknown
+ 5 xxxxxxxx related to visible area?
+ 6 xxxxxxxx related to visible area?
+ 7 xxxxxxxx unknown
+ 8 xxxxxxxx unknown
+ 9 xxxxxxxx unknown
+ a xxxxxxxx unknown
+ b xxxxxx-- horiz scroll (character resolution)
+ c xxxxxxxx might be bg layer horiz scroll (always 0 here but used by the older games)
+ d xxxxxxxx might be fg layer horiz scroll (always 0 here but always 4 in the older games)
+ */
+
+
+/***************************************************************************
+
+ Blitter
+
+ This is probably work done by the GX61A01 custom chip found on all boards,
+ however the way it works is not exactly the same in all games.
+
+***************************************************************************/
+
+static void mrokumei_handleblit( int rom_base )
+{
+ int i;
+ int DestParam;
+ int SourceAddr;
+ int DestAddr;
+ int BaseAddr;
+ int opcode,data,NumTiles;
+ UINT8 *pBlitData = memory_region(REGION_USER1) + rom_base;
+
+ DestParam =
+ blitter_param[(blitter_param_count-4)&3]*256+
+ blitter_param[(blitter_param_count-3)&3];
+
+ SourceAddr =
+ blitter_param[(blitter_param_count-2)&3]*256+
+ blitter_param[(blitter_param_count-1)&3];
+
+ /* xxx-.----.----.---- not used?
+ * ---x.----.----.---- layer
+ * ----.xxxx.xxxx.xxxx addr
+ */
+ BaseAddr= (DestParam&0x1000);
+ DestAddr= (DestParam&0x0fff);
+
+// logerror( "[blit bank %02x src %04x dst %04x]\n",blitter_bank,SourceAddr,DestParam);
+
+ if( homedata_visible_page == 0 )
+ {
+ BaseAddr += 0x2000;
+ }
+
+ for(;;)
+ {
+ opcode = pBlitData[SourceAddr++];
+ /* 00xxxxxx RLE incrementing
+ * 01xxxxxx Raw Run
+ * 1xxxxxxx RLE constant data
+ */
+ if( opcode == 0x00 )
+ {
+ /* end-of-graphic */
+ goto finish;
+ }
+ data = pBlitData[SourceAddr++];
+
+ if (opcode&0x80)
+ NumTiles = 0x80-(opcode&0x7f);
+ else
+ NumTiles = 0x40-(opcode&0x3f);
+
+ for( i=0; i<NumTiles; i++ )
+ {
+ if( i!=0 )
+ {
+ switch( opcode&0xc0 )
+ {
+ case 0x40: // Raw Run
+ data = pBlitData[SourceAddr++];
+ break;
+
+ case 0x00: // RLE incrementing
+ data++;
+ break;
+ }
+ } /* i!=0 */
+
+ if (data) /* 00 is a nop */
+ mrokumei_videoram_w( BaseAddr + DestAddr, data );
+
+ if (homedata_vreg[1] & 0x80) /* flip screen */
+ {
+ DestAddr-=2;
+ if (DestAddr < 0) goto finish;
+ }
+ else
+ {
+ DestAddr+=2;
+ if (DestAddr >= 0x1000) goto finish;
+ }
+ } /* for( i=0; i<NumTiles; i++ ) */
+ } /* for(;;) */
+
+finish:
+ cpunum_set_input_line(0,M6809_FIRQ_LINE,HOLD_LINE);
+}
+
+static void reikaids_handleblit( int rom_base )
+{
+ int i;
+ UINT16 DestParam;
+ int flipx;
+ int SourceAddr, BaseAddr;
+ int DestAddr;
+ UINT8 *pBlitData = memory_region(REGION_USER1) + rom_base;
+
+ int opcode,data,NumTiles;
+
+ DestParam =
+ blitter_param[(blitter_param_count-4)&3]*256+
+ blitter_param[(blitter_param_count-3)&3];
+
+ SourceAddr =
+ blitter_param[(blitter_param_count-2)&3]*256+
+ blitter_param[(blitter_param_count-1)&3];
+
+ /* x---.----.----.---- flipx
+ * -x--.----.----.---- select: attr/tile
+ * --*x.xxxx.*xxx.xxxx addr
+ */
+ BaseAddr= (DestParam&0x4000);
+ DestAddr= (DestParam&0x3fff);
+ flipx = (DestParam&0x8000);
+
+// logerror( "[blit %02x %04x %04x]\n",blitter_bank,SourceAddr,DestParam);
+
+ if( homedata_visible_page == 0 )
+ {
+ BaseAddr += 0x2000<<2;
+ }
+
+ for(;;)
+ {
+ opcode = pBlitData[SourceAddr++];
+ /* 00xxxxxx Raw Run
+ * 01xxxxxx RLE incrementing
+ * 1xxxxxxx RLE constant data
+ */
+ if( opcode == 0x00 )
+ {
+ /* end-of-graphic */
+ goto finish;
+ }
+
+ data = pBlitData[SourceAddr++];
+
+ if( (opcode&0xc0)==0x80 )
+ NumTiles = 0x80 - (opcode&0x7f);
+ else
+ NumTiles = 0x40 - (opcode&0x3f);
+
+ for( i=0; i<NumTiles; i++ )
+ {
+ if( i!=0 )
+ {
+ switch( opcode&0xc0 )
+ {
+ case 0x00: // Raw Run
+ data = pBlitData[SourceAddr++];
+ break;
+
+ case 0x40: // RLE incrementing
+ data++;
+ break;
+ }
+ } /* i!=0 */
+
+ if (data) /* 00 is a nop */
+ {
+ int addr = BaseAddr + (DestAddr & 0x3fff);
+ int dat = data;
+
+ if ((addr & 0x2080) == 0)
+ {
+ addr = ((addr & 0xc000) >> 2) | ((addr & 0x1f00) >> 1) | (addr & 0x7f);
+
+ if( flipx )
+ {
+ if ((BaseAddr & 0x4000) == 0) dat |= 0x80;
+ addr ^= 0x007c;
+ }
+
+ reikaids_videoram_w( addr, dat );
+ }
+ }
+
+ if (homedata_vreg[1] & 0x80) /* flip screen */
+ DestAddr-=4;
+ else
+ DestAddr+=4;
+ } /* for( i=0; i<NumTiles; i++ ) */
+ }
+
+finish:
+ cpunum_set_input_line(0,M6809_FIRQ_LINE,HOLD_LINE);
+}
+
+static void pteacher_handleblit( int rom_base )
+{
+ int i;
+ int DestParam;
+ int SourceAddr;
+ int DestAddr, BaseAddr;
+ int opcode,data,NumTiles;
+ UINT8 *pBlitData = memory_region(REGION_USER1) + rom_base;
+
+ DestParam =
+ blitter_param[(blitter_param_count-4)&3]*256+
+ blitter_param[(blitter_param_count-3)&3];
+
+ SourceAddr =
+ blitter_param[(blitter_param_count-2)&3]*256+
+ blitter_param[(blitter_param_count-1)&3];
+
+ /* x---.----.----.---- not used?
+ * -x--.----.----.---- layer (0..1)
+ * --*x.xxxx.*xxx.xxxx addr
+ */
+ BaseAddr= (DestParam&0x4000);
+ DestAddr= (DestParam&0x3fff);
+
+// logerror( "[blit %02x %04x %04x]->%d\n",blitter_bank,SourceAddr,DestParam,homedata_visible_page);
+
+ if( homedata_visible_page == 0 )
+ {
+ BaseAddr += 0x2000<<2;
+ }
+
+ for(;;)
+ {
+ opcode = pBlitData[SourceAddr++];
+ /* 00xxxxxx Raw Run
+ * 01xxxxxx RLE incrementing
+ * 1xxxxxxx RLE constant data
+ */
+ if( opcode == 0x00 )
+ {
+ /* end-of-graphic */
+ goto finish;
+ }
+ data = pBlitData[SourceAddr++];
+
+ if (opcode & 0x80)
+ NumTiles = 0x80-(opcode&0x7f);
+ else
+ NumTiles = 0x40-(opcode&0x3f);
+
+ for( i=0; i<NumTiles; i++ )
+ {
+ if( i!=0 )
+ {
+ switch( opcode&0xc0 )
+ {
+ case 0x00: // Raw Run
+ data = pBlitData[SourceAddr++];
+ break;
+
+ case 0x40: // RLE incrementing
+ data++;
+ break;
+ }
+ } /* i!=0 */
+
+ if (data) /* 00 is a nop */
+ {
+ int addr = BaseAddr + (DestAddr & 0x3fff);
+
+ if ((addr & 0x2080) == 0)
+ {
+ addr = ((addr & 0xc000) >> 2) | ((addr & 0x1f00) >> 1) | (addr & 0x7f);
+ pteacher_videoram_w( addr, data );
+ }
+ }
+
+ if (homedata_vreg[1] & 0x80) /* flip screen */
+ DestAddr-=2;
+ else
+ DestAddr+=2;
+ } /* for( i=0; i<NumTiles; i++ ) */
+ } /* for(;;) */
+
+finish:
+ cpunum_set_input_line(0,M6809_FIRQ_LINE,HOLD_LINE);
+}
+
+
+
+
+/***************************************************************************
+
+ Palette setup
+
+***************************************************************************/
+
+PALETTE_INIT( mrokumei )
+{
+ int i;
+
+ /* initialize 555 RGB palette */
+ for (i = 0; i < 0x8000; i++)
+ {
+ int r,g,b;
+ int color = color_prom[i*2] * 256 + color_prom[i*2+1];
+ /* xxxx--------x--- red
+ * ----xxxx-----x-- green
+ * --------xxxx--x- blue
+ * ---------------x unused
+ */
+ r = ((color >> 11) & 0x1e) | ((color >> 3) & 1);
+ g = ((color >> 7) & 0x1e) | ((color >> 2) & 1);
+ b = ((color >> 3) & 0x1e) | ((color >> 1) & 1);
+
+ palette_set_color_rgb(machine,i,pal5bit(r),pal5bit(g),pal5bit(b));
+ }
+}
+
+PALETTE_INIT( reikaids )
+{
+ int i;
+
+ /* initialize 555 RGB palette */
+ for (i = 0; i < 0x8000; i++)
+ {
+ int r,g,b;
+ int color = color_prom[i*2] * 256 + color_prom[i*2+1];
+ /* xxxx--------x--- green
+ * ----xxxx-----x-- red
+ * --------xxxx--x- blue
+ * ---------------x unused
+ */
+ g = ((color >> 11) & 0x1e) | ((color >> 3) & 1);
+ r = ((color >> 7) & 0x1e) | ((color >> 2) & 1);
+ b = ((color >> 3) & 0x1e) | ((color >> 1) & 1);
+
+ palette_set_color_rgb(machine,i,pal5bit(r),pal5bit(g),pal5bit(b));
+ }
+}
+
+PALETTE_INIT( pteacher )
+{
+ int i;
+
+ /* initialize 555 RGB palette */
+ for (i = 0; i < 0x8000; i++)
+ {
+ int r,g,b;
+ int color = color_prom[i*2] * 256 + color_prom[i*2+1];
+ /* xxxxx----------- green
+ * -----xxxxx------ red
+ * ----------xxxxx- blue
+ * ---------------x unused
+ */
+ g = ((color >> 11) & 0x1f);
+ r = ((color >> 6) & 0x1f);
+ b = ((color >> 1) & 0x1f);
+
+ palette_set_color_rgb(machine,i,pal5bit(r),pal5bit(g),pal5bit(b));
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+INLINE void mrokumei_info0( running_machine *machine, tile_data *tileinfo, int tile_index, int page, int gfxbank )
+{
+ int addr = tile_index * 2 + 0x2000 * page;
+ int attr = videoram[addr];
+ int code = videoram[addr + 1] + ((attr & 0x03) << 8) + (gfxbank << 10);
+ int color = (attr >> 2) + (gfxbank << 6);
+
+ SET_TILE_INFO( 0, code, color, homedata_flipscreen );
+}
+INLINE void mrokumei_info1( running_machine *machine, tile_data *tileinfo, int tile_index, int page, int gfxbank )
+{
+ int addr = tile_index * 2 + 0x1000 + 0x2000 * page;
+ int attr = videoram[addr];
+ int code = videoram[addr + 1] + ((attr & 0x07) << 8) + (gfxbank << 11);
+ int color = (attr >> 3) + ((gfxbank & 3) << 6);
+
+ SET_TILE_INFO( 1, code, color, homedata_flipscreen );
+}
+
+static TILE_GET_INFO( mrokumei_get_info0_0 ) { mrokumei_info0( machine, tileinfo, tile_index, 0, blitter_bank & 0x03 ); }
+static TILE_GET_INFO( mrokumei_get_info1_0 ) { mrokumei_info0( machine, tileinfo, tile_index, 1, blitter_bank & 0x03 ); }
+static TILE_GET_INFO( mrokumei_get_info0_1 ) { mrokumei_info1( machine, tileinfo, tile_index, 0, (blitter_bank & 0x38) >> 3 ); }
+static TILE_GET_INFO( mrokumei_get_info1_1 ) { mrokumei_info1( machine, tileinfo, tile_index, 1, (blitter_bank & 0x38) >> 3 ); }
+
+
+INLINE void reikaids_info( running_machine *machine, tile_data *tileinfo, int tile_index, int page, int layer, int gfxbank )
+{
+ int addr = tile_index * 4 + layer + 0x2000 * page;
+ int attr = videoram[addr];
+ int code = videoram[addr + 0x1000] + ((attr & 0x03) << 8) + (gfxbank << 10);
+ int color = (attr & 0x7c) >> 2;
+ int flags = homedata_flipscreen;
+
+ if (attr & 0x80) flags ^= TILE_FLIPX;
+
+ SET_TILE_INFO( layer, code, color, flags );
+}
+
+ /* reikaids_gfx_bank[0]:
+ * -xxx.x--- layer#1
+ * ----.-xxx layer#3
+ *
+ * reikaids_gfx_bank[1]:
+ * xxxx.x--- layer#0
+ * ----.-xxx layer#2
+ */
+static TILE_GET_INFO( reikaids_get_info0_0 ) { reikaids_info( machine, tileinfo, tile_index, 0, 0, (reikaids_gfx_bank[1]>>3)); }
+static TILE_GET_INFO( reikaids_get_info1_0 ) { reikaids_info( machine, tileinfo, tile_index, 1, 0, (reikaids_gfx_bank[1]>>3)); }
+static TILE_GET_INFO( reikaids_get_info0_1 ) { reikaids_info( machine, tileinfo, tile_index, 0, 1, ((reikaids_gfx_bank[0]&0x78)>>3)); }
+static TILE_GET_INFO( reikaids_get_info1_1 ) { reikaids_info( machine, tileinfo, tile_index, 1, 1, ((reikaids_gfx_bank[0]&0x78)>>3)); }
+static TILE_GET_INFO( reikaids_get_info0_2 ) { reikaids_info( machine, tileinfo, tile_index, 0, 2, (reikaids_gfx_bank[1]&0x7)); }
+static TILE_GET_INFO( reikaids_get_info1_2 ) { reikaids_info( machine, tileinfo, tile_index, 1, 2, (reikaids_gfx_bank[1]&0x7)); }
+static TILE_GET_INFO( reikaids_get_info0_3 ) { reikaids_info( machine, tileinfo, tile_index, 0, 3, (reikaids_gfx_bank[0]&0x7)); }
+static TILE_GET_INFO( reikaids_get_info1_3 ) { reikaids_info( machine, tileinfo, tile_index, 1, 3, (reikaids_gfx_bank[0]&0x7)); }
+
+
+INLINE void pteacher_info( running_machine *machine, tile_data *tileinfo, int tile_index, int page, int layer, int gfxbank )
+{
+ int addr = tile_index * 2 + 0x1000 * layer + 0x2000 * page;
+ int attr = videoram[addr];
+ int code = videoram[addr + 1] + ((attr & 0x07) << 8) + (gfxbank << 11);
+ int color = (attr >> 3) + ((gfxbank & 1) << 5);
+
+ SET_TILE_INFO( layer, code, color, homedata_flipscreen );
+}
+
+static TILE_GET_INFO( pteacher_get_info0_0 ) { pteacher_info( machine, tileinfo, tile_index, 0, 0, pteacher_gfx_bank & 0x0f ); }
+static TILE_GET_INFO( pteacher_get_info1_0 ) { pteacher_info( machine, tileinfo, tile_index, 1, 0, pteacher_gfx_bank & 0x0f ); }
+static TILE_GET_INFO( pteacher_get_info0_1 ) { pteacher_info( machine, tileinfo, tile_index, 0, 1, pteacher_gfx_bank >> 4 ); }
+static TILE_GET_INFO( pteacher_get_info1_1 ) { pteacher_info( machine, tileinfo, tile_index, 1, 1, pteacher_gfx_bank >> 4 ); }
+
+
+INLINE void lemnangl_info( running_machine *machine, tile_data *tileinfo, int tile_index, int page, int layer, int gfxset, int gfxbank )
+{
+ int addr = tile_index * 2 + 0x1000 * layer + 0x2000 * page;
+ int attr = videoram[addr];
+ int code = videoram[addr + 1] + ((attr & 0x07) << 8) + (gfxbank << 11);
+ int color = 16 * (attr >> 3) + gfxbank;
+
+ SET_TILE_INFO( 2*layer + gfxset, code, color, homedata_flipscreen );
+}
+
+static TILE_GET_INFO( lemnangl_get_info0_0 ) { lemnangl_info( machine, tileinfo, tile_index, 0, 0, blitter_bank & 1, pteacher_gfx_bank & 0x0f ); }
+static TILE_GET_INFO( lemnangl_get_info1_0 ) { lemnangl_info( machine, tileinfo, tile_index, 1, 0, blitter_bank & 1, pteacher_gfx_bank & 0x0f ); }
+static TILE_GET_INFO( lemnangl_get_info0_1 ) { lemnangl_info( machine, tileinfo, tile_index, 0, 1, (blitter_bank & 2) >> 1, pteacher_gfx_bank >> 4 ); }
+static TILE_GET_INFO( lemnangl_get_info1_1 ) { lemnangl_info( machine, tileinfo, tile_index, 1, 1, (blitter_bank & 2) >> 1, pteacher_gfx_bank >> 4 ); }
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( mrokumei )
+{
+ bg_tilemap[0][0] = tilemap_create( mrokumei_get_info0_0, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64,32 );
+ bg_tilemap[0][1] = tilemap_create( mrokumei_get_info0_1, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64,32 );
+ bg_tilemap[1][0] = tilemap_create( mrokumei_get_info1_0, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64,32 );
+ bg_tilemap[1][1] = tilemap_create( mrokumei_get_info1_1, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64,32 );
+
+ tilemap_set_transparent_pen(bg_tilemap[0][1],0);
+ tilemap_set_transparent_pen(bg_tilemap[1][1],0);
+}
+
+VIDEO_START( reikaids )
+{
+ bg_tilemap[0][0] = tilemap_create( reikaids_get_info0_0, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32 );
+ bg_tilemap[0][1] = tilemap_create( reikaids_get_info0_1, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32 );
+ bg_tilemap[0][2] = tilemap_create( reikaids_get_info0_2, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32 );
+ bg_tilemap[0][3] = tilemap_create( reikaids_get_info0_3, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32 );
+ bg_tilemap[1][0] = tilemap_create( reikaids_get_info1_0, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32 );
+ bg_tilemap[1][1] = tilemap_create( reikaids_get_info1_1, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32 );
+ bg_tilemap[1][2] = tilemap_create( reikaids_get_info1_2, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32 );
+ bg_tilemap[1][3] = tilemap_create( reikaids_get_info1_3, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32 );
+
+ tilemap_set_transparent_pen(bg_tilemap[0][0],0xff);
+ tilemap_set_transparent_pen(bg_tilemap[0][1],0xff);
+ tilemap_set_transparent_pen(bg_tilemap[0][2],0xff);
+ tilemap_set_transparent_pen(bg_tilemap[0][3],0xff);
+ tilemap_set_transparent_pen(bg_tilemap[1][0],0xff);
+ tilemap_set_transparent_pen(bg_tilemap[1][1],0xff);
+ tilemap_set_transparent_pen(bg_tilemap[1][2],0xff);
+ tilemap_set_transparent_pen(bg_tilemap[1][3],0xff);
+}
+
+VIDEO_START( pteacher )
+{
+ bg_tilemap[0][0] = tilemap_create( pteacher_get_info0_0, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64,32 );
+ bg_tilemap[0][1] = tilemap_create( pteacher_get_info0_1, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64,32 );
+ bg_tilemap[1][0] = tilemap_create( pteacher_get_info1_0, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64,32 );
+ bg_tilemap[1][1] = tilemap_create( pteacher_get_info1_1, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64,32 );
+
+ tilemap_set_transparent_pen(bg_tilemap[0][1],0xff);
+ tilemap_set_transparent_pen(bg_tilemap[1][1],0xff);
+}
+
+VIDEO_START( lemnangl )
+{
+ bg_tilemap[0][0] = tilemap_create( lemnangl_get_info0_0, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64,32 );
+ bg_tilemap[0][1] = tilemap_create( lemnangl_get_info0_1, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64,32 );
+ bg_tilemap[1][0] = tilemap_create( lemnangl_get_info1_0, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64,32 );
+ bg_tilemap[1][1] = tilemap_create( lemnangl_get_info1_1, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64,32 );
+
+ tilemap_set_transparent_pen(bg_tilemap[0][1],0x0f);
+ tilemap_set_transparent_pen(bg_tilemap[1][1],0x0f);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( mrokumei_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty( bg_tilemap[(offset & 0x2000) >> 13][(offset & 0x1000) >> 12], (offset & 0xffe) >> 1 );
+}
+
+WRITE8_HANDLER( reikaids_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty( bg_tilemap[(offset & 0x2000) >> 13][offset & 3], (offset & 0xffc) >> 2 );
+}
+
+WRITE8_HANDLER( pteacher_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty( bg_tilemap[(offset & 0x2000) >> 13][(offset & 0x1000) >> 12], (offset & 0xffe) >> 1 );
+}
+
+WRITE8_HANDLER( reikaids_gfx_bank_w )
+{
+
+//logerror( "%04x: [setbank %02x]\n",activecpu_get_pc(),data);
+
+ if (reikaids_gfx_bank[reikaids_which] != data)
+ {
+ reikaids_gfx_bank[reikaids_which] = data;
+ tilemap_mark_all_tiles_dirty( ALL_TILEMAPS );
+ }
+
+ reikaids_which ^= 1;
+}
+
+WRITE8_HANDLER( pteacher_gfx_bank_w )
+{
+// logerror( "%04x: gfxbank:=%02x\n", activecpu_get_pc(), data );
+ if (pteacher_gfx_bank != data)
+ {
+ pteacher_gfx_bank = data;
+ tilemap_mark_all_tiles_dirty( ALL_TILEMAPS );
+ }
+}
+
+WRITE8_HANDLER( homedata_blitter_param_w )
+{
+//logerror("%04x: blitter_param_w %02x\n",activecpu_get_pc(),data);
+ blitter_param[blitter_param_count] = data;
+ blitter_param_count++;
+ blitter_param_count&=3;
+}
+
+WRITE8_HANDLER( mrokumei_blitter_bank_w )
+{
+ /* --xxx--- layer 1 gfx bank
+ -----x-- blitter ROM bank
+ ------xx layer 0 gfx bank
+ */
+
+ if ((blitter_bank ^ data) & 0x3b)
+ tilemap_mark_all_tiles_dirty( ALL_TILEMAPS);
+
+ blitter_bank = data;
+}
+
+WRITE8_HANDLER( reikaids_blitter_bank_w )
+{
+ /* xxx----- priority control
+ ----x--- target page? what's this for?
+ ------xx blitter ROM bank
+ */
+ blitter_bank = data;
+}
+
+WRITE8_HANDLER( pteacher_blitter_bank_w )
+{
+ /* xxx----- blitter ROM bank
+ -----x-- pixel clock (normal/slow)
+ ------x- layer #1 gfx charset (lemnangl only)
+ -------x layer #0 gfx charset (lemnangl only)
+ */
+
+ if ((blitter_bank ^ data) & 0x03)
+ tilemap_mark_all_tiles_dirty( ALL_TILEMAPS);
+
+ blitter_bank = data;
+}
+
+WRITE8_HANDLER( mrokumei_blitter_start_w )
+{
+ if (data & 0x80) mrokumei_handleblit(((blitter_bank & 0x04) >> 2) * 0x10000);
+
+ /* bit 0 = bank switch; used by hourouki to access the
+ optional service mode ROM (not available in current dump) */
+}
+
+WRITE8_HANDLER( reikaids_blitter_start_w )
+{
+ reikaids_handleblit((blitter_bank & 3) * 0x10000);
+}
+
+WRITE8_HANDLER( pteacher_blitter_start_w )
+{
+ pteacher_handleblit((blitter_bank >> 5) * 0x10000 & (memory_region_length(REGION_USER1) - 1));
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( mrokumei )
+{
+ int flags,width;
+
+ /* blank screen */
+ if (homedata_vreg[0x3] == 0xc1 && homedata_vreg[0x4] == 0xc0 && homedata_vreg[0x5] == 0xff)
+ {
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ return 0;
+ }
+
+ flags = (homedata_vreg[1] & 0x80) ? (TILE_FLIPX | TILE_FLIPY) : 0;
+ if (flags != homedata_flipscreen)
+ {
+ homedata_flipscreen = flags;
+ tilemap_mark_all_tiles_dirty( ALL_TILEMAPS );
+ }
+
+ switch (homedata_vreg[0x3])
+ {
+ case 0xb7: width = 54; break; // mjclinic
+ case 0xae: width = 52; break; // mrokumei
+ case 0x9f: width = 49; break; // hourouki, mhgaiden, mjhokite
+ case 0x96: width = 49; break; // mjclinic
+ default:
+ if (homedata_vreg[0x3])
+ popmessage("unknown video control %02x %02x %02x %02x",
+ homedata_vreg[0x3],
+ homedata_vreg[0x4],
+ homedata_vreg[0x5],
+ homedata_vreg[0x6]);
+ width = 54;
+ break;
+ }
+ video_screen_set_visarea(0, 0*8, width*8-1, 2*8, 30*8-1);
+
+ tilemap_set_scrollx(bg_tilemap[homedata_visible_page][0],0,homedata_vreg[0xc] << 1);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap[homedata_visible_page][0], 0, 0);
+ tilemap_draw(bitmap, cliprect, bg_tilemap[homedata_visible_page][1], 0, 0);
+ return 0;
+}
+/*
+VIDEO_UPDATE( reikaids )
+{
+ int flags;
+ static int pritable[8][4] =
+ {
+ { 3,1,0,2 },
+ { 1,3,0,2 },
+ { 0,3,1,2 },
+ { 0,1,3,2 },
+ { 3,0,1,2 },
+ { 1,0,3,2 },
+ { 2,3,1,0 }, // (bg color should be taken from 1)
+ { 3,1,2,0 }, // (bg color should be taken from 1)
+ };
+ int pri,i;
+
+
+ flags = (homedata_vreg[1] & 0x80) ? (TILE_FLIPX | TILE_FLIPY) : 0;
+ if (flags != homedata_flipscreen)
+ {
+ homedata_flipscreen = flags;
+ tilemap_mark_all_tiles_dirty( ALL_TILEMAPS );
+ }
+
+
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ pri = (blitter_bank & 0x70) >> 4;
+ for (i = 0;i < 4;i++)
+ tilemap_draw(bitmap, cliprect, bg_tilemap[homedata_visible_page][pritable[pri][3-i]], 0, 0);
+ return 0;
+}
+
+*/
+VIDEO_UPDATE( reikaids )
+{
+ int flags;
+ static int pritable[2][8][4] = /* table of priorities derived from the PROM */
+ {
+ {
+ { 3,1,0,2 },
+ { 1,3,0,2 },
+ { 0,3,1,2 },
+ { 0,1,3,2 },
+ { 3,0,1,2 },
+ { 1,0,3,2 },
+ { 2,3,1,0 }, // (bg color should be taken from 1)
+ { 3,1,2,0 } // (bg color should be taken from 1)
+ },
+ {
+ {2,3,0,1},
+ {2,0,3,1},
+ {3,0,2,1},
+ {0,3,2,1},
+ {3,0,1,2},
+ {2,1,3,0},
+ {0,2,3,1},
+ {3,2,0,1}
+ },
+ };
+
+ int pri,i;
+
+ flags = (homedata_vreg[1] & 0x80) ? (TILE_FLIPX | TILE_FLIPY) : 0;
+ if (flags != homedata_flipscreen)
+ {
+ homedata_flipscreen = flags;
+ tilemap_mark_all_tiles_dirty( ALL_TILEMAPS );
+ }
+
+
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ pri = (blitter_bank & 0x70) >> 4;
+ for (i = 0;i < 4;i++)
+ tilemap_draw(bitmap, cliprect, bg_tilemap[homedata_visible_page][pritable[homedata_priority][pri][3-i]], 0, 0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( pteacher )
+{
+ int flags,scroll_low,scroll_high;
+
+
+ /* blank screen */
+ if (homedata_vreg[0x3] == 0xc1 && homedata_vreg[0x4] == 0xc0 && homedata_vreg[0x5] == 0xff)
+ {
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ return 0;
+ }
+
+ flags = (homedata_vreg[1] & 0x80) ? (TILE_FLIPX | TILE_FLIPY) : 0;
+ if (flags != homedata_flipscreen)
+ {
+ homedata_flipscreen = flags;
+ tilemap_mark_all_tiles_dirty( ALL_TILEMAPS );
+ }
+
+ /* bit 2 of blitter_bank stretches characters horizontally by 3/2,
+ so they look as if they were 12x8 instead of 8x8.
+
+ However, the visible area can be further reduced by fudging with the video
+ registers, but I haven't figured out how they work exactly.
+ In most games it's like this (note that register 4 controls fine
+ scrolling):
+
+ width 3 4 5 6
+ 33*8 = a6 00 ef db (mjikaga)
+ 35*8 = bc 0b ef f0
+ 51*8 = a6 07 ef db (mjikaga)
+ 54*8 = bc 07 ef e8
+
+ but in mjkinjas it's
+ 42*8 = f0 ae df cc
+
+ note that mjkinjas has a 11MHz xtal instead of the 9MHz of all the others:
+ the two things are probably related, in fact 35 * 11 / 9 = 42.7777777.
+
+ and it also seems that
+ blanked = c1 c0 ff --
+ */
+
+ if (blitter_bank & 0x04)
+ {
+ if (homedata_vreg[0x4] == 0xae || homedata_vreg[0x4] == 0xb8)
+ {
+ /* kludge for mjkinjas */
+ video_screen_set_visarea(0, 0*8, 42*8-1, 2*8, 30*8-1);
+ scroll_low = 0;
+ }
+ else
+ {
+ if (homedata_vreg[0x3] == 0xa6)
+ video_screen_set_visarea(0, 0*8, 33*8-1, 2*8, 30*8-1);
+ else
+ video_screen_set_visarea(0, 0*8, 35*8-1, 2*8, 30*8-1);
+ scroll_low = (11 - (homedata_vreg[0x4] & 0x0f)) * 8 / 12;
+ }
+ }
+ else
+ {
+ if (homedata_vreg[0x3] == 0xa6)
+ video_screen_set_visarea(0, 0*8, 51*8-1, 2*8, 30*8-1);
+ else
+ video_screen_set_visarea(0, 0*8, 54*8-1, 2*8, 30*8-1);
+ scroll_low = 7 - (homedata_vreg[0x4] & 0x0f);
+ }
+ scroll_high = homedata_vreg[0xb] >> 2;
+
+ tilemap_set_scrollx(bg_tilemap[homedata_visible_page][0],0,scroll_high*8 + scroll_low);
+ tilemap_set_scrollx(bg_tilemap[homedata_visible_page][1],0,scroll_high*8 + scroll_low);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap[homedata_visible_page][0], 0, 0);
+ tilemap_draw(bitmap, cliprect, bg_tilemap[homedata_visible_page][1], 0, 0);
+ return 0;
+}
+
+
+VIDEO_EOF( homedata )
+{
+ homedata_visible_page ^= 1;
+}
diff --git a/src/mame/video/homerun.c b/src/mame/video/homerun.c
new file mode 100644
index 00000000000..b71cc09c1b2
--- /dev/null
+++ b/src/mame/video/homerun.c
@@ -0,0 +1,114 @@
+#include "driver.h"
+
+static int homerun_gfx_ctrl;
+static int homerun_gc_up,homerun_gc_down;
+int homerun_xpa,homerun_xpb,homerun_xpc;
+
+static tilemap *homerun_tilemap;
+UINT8 *homerun_videoram;
+
+#define half_screen 116
+
+WRITE8_HANDLER(homerun_banking_w)
+{
+ if(video_screen_get_vpos(0)>half_screen)
+ homerun_gc_down=data&3;
+ else
+ homerun_gc_up=data&3;
+
+ tilemap_mark_all_tiles_dirty(homerun_tilemap);
+
+ data>>=5;
+ if(!data)
+ memory_set_bankptr(1, memory_region(REGION_CPU1) );
+ else
+ memory_set_bankptr(1, memory_region(REGION_CPU1) + 0x10000 + (((data-1)&0x7)*0x4000 ));
+}
+
+WRITE8_HANDLER( homerun_videoram_w )
+{
+ homerun_videoram[offset]=data;
+ tilemap_mark_tile_dirty(homerun_tilemap,offset&0xfff);
+}
+
+WRITE8_HANDLER(homerun_color_w)
+{
+ int r,g,b;
+ int bit0,bit1,bit2;
+ bit0 = (data >> 0) & 0x01;
+ bit1 = (data >> 1) & 0x01;
+ bit2 = (data >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = (data >> 3) & 0x01;
+ bit1 = (data >> 4) & 0x01;
+ bit2 = (data >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = 0;
+ bit1 = (data >> 6) & 0x01;
+ bit2 = (data >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ palette_set_color(Machine,offset,MAKE_RGB(r,g,b));
+}
+
+static TILE_GET_INFO( get_homerun_tile_info )
+{
+ int tileno,palno;
+ tileno = (homerun_videoram[tile_index])+((homerun_videoram[tile_index+0x1000]&0x38)<<5)+ ((homerun_gfx_ctrl&1)<<11);
+ palno=(homerun_videoram[tile_index+0x1000]&0x7);
+ SET_TILE_INFO(0,tileno,palno,0);
+}
+
+
+
+VIDEO_START(homerun)
+{
+ homerun_tilemap = tilemap_create(get_homerun_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,64);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+ for (offs = spriteram_size-4; offs >=0; offs -= 4)
+ {
+ int code,color,sx,sy,flipx,flipy;
+ sx = spriteram[offs+3];
+ sy = spriteram[offs+0]-16;
+ code = (spriteram[offs+1] ) +((spriteram[offs+2]&0x8)<<5 )+(homerun_gfx_ctrl<<9);
+ color = (spriteram[offs+2] & 0x7)+8 ;
+ flipx=(spriteram[offs+2] & 0x40) ;
+ flipy=(spriteram[offs+2] & 0x80) ;
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE(homerun)
+{
+ rectangle myclip=*cliprect;
+
+ /* upper part */
+
+ tilemap_set_scrollx(homerun_tilemap, 0, homerun_xpc+((homerun_xpa&2)<<7) );
+ tilemap_set_scrolly(homerun_tilemap, 0, homerun_xpb+((homerun_xpa&1)<<8) );
+ myclip.max_y/=2;
+ homerun_gfx_ctrl=homerun_gc_up;
+ tilemap_draw(bitmap,&myclip,homerun_tilemap,0,0);
+ draw_sprites(machine, bitmap,&myclip);
+
+ /* lower part */
+
+ myclip.min_y+=myclip.max_y;
+ myclip.max_y*=2;
+ homerun_gfx_ctrl=homerun_gc_down;
+ tilemap_draw(bitmap,&myclip,homerun_tilemap,0,0);
+ draw_sprites(machine, bitmap,&myclip);
+
+ homerun_gc_down=homerun_gc_up;
+ return 0;
+}
+
+
diff --git a/src/mame/video/hyhoo.c b/src/mame/video/hyhoo.c
new file mode 100644
index 00000000000..3f569c2e1d6
--- /dev/null
+++ b/src/mame/video/hyhoo.c
@@ -0,0 +1,247 @@
+/******************************************************************************
+
+ Video Hardware for Nichibutsu Mahjong series.
+
+ Driver by Takahiro Nogi <nogi@kt.rim.or.jp> 2000/01/28 -
+
+******************************************************************************/
+
+#include "driver.h"
+#include "nb1413m3.h"
+
+
+UINT8 *hyhoo_clut;
+
+static int blitter_destx, blitter_desty;
+static int blitter_sizex, blitter_sizey;
+static int blitter_src_addr;
+static int blitter_direction_x, blitter_direction_y;
+static int hyhoo_gfxrom;
+static int hyhoo_dispflag;
+static int hyhoo_highcolorflag;
+static int hyhoo_flipscreen;
+
+static mame_bitmap *hyhoo_tmpbitmap;
+static void hyhoo_gfxdraw(void);
+
+
+WRITE8_HANDLER( hyhoo_blitter_w )
+{
+ switch (offset)
+ {
+ case 0x00: blitter_src_addr = (blitter_src_addr & 0xff00) | data;
+ nb1413m3_gfxradr_l_w(0, data); break;
+ case 0x01: blitter_src_addr = (blitter_src_addr & 0x00ff) | (data << 8);
+ nb1413m3_gfxradr_h_w(0, data); break;
+ case 0x02: blitter_destx = data; break;
+ case 0x03: blitter_desty = data; break;
+ case 0x04: blitter_sizex = data; break;
+ case 0x05: blitter_sizey = data;
+ /* writing here also starts the blit */
+ hyhoo_gfxdraw();
+ break;
+ case 0x06: blitter_direction_x = (data >> 0) & 0x01;
+ blitter_direction_y = (data >> 1) & 0x01;
+ hyhoo_flipscreen = (~data >> 2) & 0x01;
+ hyhoo_dispflag = (~data >> 3) & 0x01;
+ break;
+ case 0x07: break;
+ }
+}
+
+
+WRITE8_HANDLER( hyhoo_romsel_w )
+{
+ hyhoo_gfxrom = (((data & 0xc0) >> 4) + (data & 0x03));
+ hyhoo_highcolorflag = data;
+ nb1413m3_gfxrombank_w(0, data);
+
+ if ((0x20000 * hyhoo_gfxrom) > (memory_region_length(REGION_GFX1) - 1))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM BANK OVER!!");
+#endif
+ hyhoo_gfxrom &= (memory_region_length(REGION_GFX1) / 0x20000 - 1);
+ }
+}
+
+
+static TIMER_CALLBACK( blitter_timer_callback )
+{
+ nb1413m3_busyflag = 1;
+}
+
+void hyhoo_gfxdraw(void)
+{
+ UINT8 *GFX = memory_region(REGION_GFX1);
+
+ int x, y;
+ int dx1, dx2, dy;
+ int startx, starty;
+ int sizex, sizey;
+ int skipx, skipy;
+ int ctrx, ctry;
+ int gfxaddr;
+ UINT8 color, color1, color2;
+ int r, g, b;
+ pen_t pen;
+
+ nb1413m3_busyctr = 0;
+
+ hyhoo_gfxrom |= ((nb1413m3_sndrombank1 & 0x02) << 3);
+
+ startx = blitter_destx + blitter_sizex;
+ starty = blitter_desty + blitter_sizey;
+
+ if (blitter_direction_x)
+ {
+ sizex = blitter_sizex ^ 0xff;
+ skipx = 1;
+ }
+ else
+ {
+ sizex = blitter_sizex;
+ skipx = -1;
+ }
+
+ if (blitter_direction_y)
+ {
+ sizey = blitter_sizey ^ 0xff;
+ skipy = 1;
+ }
+ else
+ {
+ sizey = blitter_sizey;
+ skipy = -1;
+ }
+
+ gfxaddr = (hyhoo_gfxrom << 17) + (blitter_src_addr << 1);
+
+ for (y = starty, ctry = sizey; ctry >= 0; y += skipy, ctry--)
+ {
+ for (x = startx, ctrx = sizex; ctrx >= 0; x += skipx, ctrx--)
+ {
+ if ((gfxaddr > (memory_region_length(REGION_GFX1) - 1)))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM ADDRESS OVER!!");
+#endif
+ gfxaddr = 0;
+ }
+
+ color = GFX[gfxaddr++];
+
+ dx1 = (2 * x + 0) & 0x1ff;
+ dx2 = (2 * x + 1) & 0x1ff;
+ dy = y & 0xff;
+
+ if (hyhoo_highcolorflag & 0x04)
+ {
+ // direct mode
+
+ if (color != 0xff)
+ {
+ if (hyhoo_highcolorflag & 0x20)
+ {
+ /* least significant bits */
+
+ // src xxxxxxxx_bbbggrrr
+ // dst xxbbbxxx_ggxxxrrr
+
+ r = ((color & 0x07) >> 0) & 0x07;
+ g = ((color & 0x18) >> 3) & 0x03;
+ b = ((color & 0xe0) >> 5) & 0x07;
+
+ pen = MAKE_RGB(pal6bit(r), pal5bit(g), pal5bit(b));
+
+ *BITMAP_ADDR32(hyhoo_tmpbitmap, dy, dx1) = *BITMAP_ADDR32(hyhoo_tmpbitmap, dy, dx1) | pen;
+ *BITMAP_ADDR32(hyhoo_tmpbitmap, dy, dx2) = *BITMAP_ADDR32(hyhoo_tmpbitmap, dy, dx2) | pen;
+ }
+ else
+ {
+ /* most significant bits */
+
+ // src xxxxxxxx_bbgggrrr
+ // dst bbxxxggg_xxrrrxxx
+
+ r = ((color & 0x07) >> 0) & 0x07;
+ g = ((color & 0x38) >> 3) & 0x07;
+ b = ((color & 0xc0) >> 6) & 0x03;
+
+ pen = MAKE_RGB(pal6bit(r << 3), pal5bit(g << 2), pal5bit(b << 3));
+
+ *BITMAP_ADDR32(hyhoo_tmpbitmap, dy, dx1) = pen;
+ *BITMAP_ADDR32(hyhoo_tmpbitmap, dy, dx2) = pen;
+ }
+ }
+ }
+ else
+ {
+ // lookup table mode
+
+ if (blitter_direction_x)
+ {
+ // flip
+ color1 = (color & 0x0f) >> 0;
+ color2 = (color & 0xf0) >> 4;
+ }
+ else
+ {
+ // normal
+ color1 = (color & 0xf0) >> 4;
+ color2 = (color & 0x0f) >> 0;
+ }
+
+ if (hyhoo_clut[color1])
+ {
+ // src xxxxxxxx_bbgggrrr
+ // dst bbxxxggg_xxrrrxxx
+
+ r = ((~hyhoo_clut[color1] & 0x07) >> 0) & 0x07;
+ g = ((~hyhoo_clut[color1] & 0x38) >> 3) & 0x07;
+ b = ((~hyhoo_clut[color1] & 0xc0) >> 6) & 0x03;
+
+ pen = MAKE_RGB(pal6bit(r << 3), pal5bit(g << 2), pal5bit(b << 3));
+
+ *BITMAP_ADDR32(hyhoo_tmpbitmap, dy, dx1) = pen;
+ }
+
+ if (hyhoo_clut[color2])
+ {
+ // src xxxxxxxx_bbgggrrr
+ // dst bbxxxggg_xxrrrxxx
+
+ r = ((~hyhoo_clut[color2] & 0x07) >> 0) & 0x07;
+ g = ((~hyhoo_clut[color2] & 0x38) >> 3) & 0x07;
+ b = ((~hyhoo_clut[color2] & 0xc0) >> 6) & 0x03;
+
+ pen = MAKE_RGB(pal6bit(r << 3), pal5bit(g << 2), pal5bit(b << 3));
+
+ *BITMAP_ADDR32(hyhoo_tmpbitmap, dy, dx2) = pen;
+ }
+ }
+
+ nb1413m3_busyctr++;
+ }
+ }
+
+ nb1413m3_busyflag = 0;
+ timer_set(attotime_mul(ATTOTIME_IN_HZ(400000), nb1413m3_busyctr), 0, blitter_timer_callback);
+}
+
+
+VIDEO_START( hyhoo )
+{
+ hyhoo_tmpbitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+}
+
+
+VIDEO_UPDATE( hyhoo )
+{
+ if (hyhoo_dispflag)
+ copybitmap(bitmap, hyhoo_tmpbitmap, hyhoo_flipscreen, hyhoo_flipscreen, 0, 0, cliprect, TRANSPARENCY_NONE, 0);
+ else
+ fillbitmap(bitmap, RGB_BLACK, cliprect);
+
+ return 0;
+}
diff --git a/src/mame/video/hyperspt.c b/src/mame/video/hyperspt.c
new file mode 100644
index 00000000000..8cc753be1fb
--- /dev/null
+++ b/src/mame/video/hyperspt.c
@@ -0,0 +1,189 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *hyperspt_scroll;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Hyper Sports has one 32x8 palette PROM and two 256x4 lookup table PROMs
+ (one for characters, one for sprites).
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( hyperspt )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = *(color_prom++) & 0x0f;
+
+ /* characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = (*(color_prom++) & 0x0f) + 0x10;
+}
+
+WRITE8_HANDLER( hyperspt_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( hyperspt_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( hyperspt_flipscreen_w )
+{
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + ((colorram[tile_index] & 0x80) << 1) + ((colorram[tile_index] & 0x40) << 3);
+ int color = colorram[tile_index] & 0x0f;
+ int flags = ((colorram[tile_index] & 0x10) ? TILE_FLIPX : 0) | ((colorram[tile_index] & 0x20) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( hyperspt )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ tilemap_set_scroll_rows(bg_tilemap, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int sx = spriteram[offs + 3];
+ int sy = 240 - spriteram[offs + 1];
+ int flipx = ~spriteram[offs] & 0x40;
+ int flipy = spriteram[offs] & 0x80;
+
+ if (flip_screen)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ /* Note that this adjustment must be done AFTER handling flip_screen, thus */
+ /* proving that this is a hardware related "feature" */
+
+ sy += 1;
+
+ drawgfx(bitmap,machine->gfx[1],
+ spriteram[offs + 2] + 8 * (spriteram[offs] & 0x20),
+ spriteram[offs] & 0x0f,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_COLOR, 0);
+
+ /* redraw with wraparound */
+
+ drawgfx(bitmap,machine->gfx[1],
+ spriteram[offs + 2] + 8 * (spriteram[offs] & 0x20),
+ spriteram[offs] & 0x0f,
+ flipx, flipy,
+ sx - 256, sy,
+ cliprect,
+ TRANSPARENCY_COLOR, 0);
+ }
+}
+
+VIDEO_UPDATE( hyperspt )
+{
+ int row;
+
+ for (row = 0; row < 32; row++)
+ {
+ int scrollx = hyperspt_scroll[row * 2] + (hyperspt_scroll[(row * 2) + 1] & 0x01) * 256;
+ if (flip_screen) scrollx = -scrollx;
+ tilemap_set_scrollx(bg_tilemap, row, scrollx);
+ }
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
+
+/* Road Fighter */
+
+static TILE_GET_INFO( roadf_get_bg_tile_info )
+{
+ int code = videoram[tile_index] + ((colorram[tile_index] & 0x80) << 1) + ((colorram[tile_index] & 0x60) << 4);
+ int color = colorram[tile_index] & 0x0f;
+ int flags = (colorram[tile_index] & 0x10) ? TILE_FLIPX : 0;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( roadf )
+{
+ bg_tilemap = tilemap_create(roadf_get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ tilemap_set_scroll_rows(bg_tilemap, 32);
+}
diff --git a/src/mame/video/hyprduel.c b/src/mame/video/hyprduel.c
new file mode 100644
index 00000000000..06cc91527e5
--- /dev/null
+++ b/src/mame/video/hyprduel.c
@@ -0,0 +1,680 @@
+
+/* based on driver from video/metro.c by Luca Elia */
+/* modified by Eisuke Watanabe */
+
+/***************************************************************************
+
+ -= Metro Games =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z with:
+
+ Q Shows Layer 0
+ W Shows Layer 1
+ E Shows Layer 2
+ A Shows Sprites
+
+ Keys can be used together!
+
+
+ [ 3 Scrolling Layers ]
+
+ There is memory for a huge layer, but the actual tilemap
+ is a smaller window (of fixed size) carved from anywhere
+ inside that layer.
+
+ Tile Size: 8 x 8 x 4
+ (later games can switch to 8 x 8 x 8, 16 x 16 x 4/8 at run time)
+
+ Big Layer Size: 2048 x 2048 (8x8 tiles) or 4096 x 4096 (16x16 tiles)
+
+ Tilemap Window Size: 512 x 256 (8x8 tiles) or 1024 x 512 (16x16 tiles)
+
+ The tile codes in memory do not map directly to tiles. They
+ are indexes into a table (with 0x200 entries) that defines
+ a virtual set of tiles for the 3 layers. Each entry in that
+ table adds 16 tiles to the set of available tiles, and decides
+ their color code.
+
+ Tile code with their msbit set are different as they mean:
+ draw a tile filled with a single color (0-1ff)
+
+
+ [ 512 Zooming Sprites ]
+
+ The sprites are NOT tile based: the "tile" size can vary from
+ 8 to 64 (independently for width and height) with an 8 pixel
+ granularity. The "tile" address is a multiple of 8x8 pixels.
+
+ Each sprite can be shrinked to ~1/4 or enlarged to ~32x following
+ an exponential curve of sizes (with one zoom value for both width
+ and height)
+
+***************************************************************************/
+
+#include "driver.h"
+
+#define RASTER_LINES 262
+#define FIRST_VISIBLE_LINE 0
+#define LAST_VISIBLE_LINE 223
+
+/* Variables that driver has access to: */
+
+UINT16 *hyprduel_videoregs;
+UINT16 *hyprduel_screenctrl;
+UINT16 *hyprduel_tiletable;
+size_t hyprduel_tiletable_size;
+UINT16 *hyprduel_vram_0,*hyprduel_vram_1,*hyprduel_vram_2;
+UINT16 *hyprduel_window;
+
+UINT16 hyprduel_scrollx[3][RASTER_LINES+1];
+UINT16 hyprduel_scrolly[3][RASTER_LINES+1];
+
+static UINT16 *hypr_tiletable_old;
+static UINT8 *dirtyindex;
+
+
+/***************************************************************************
+ Palette GGGGGRRRRRBBBBBx
+***************************************************************************/
+
+WRITE16_HANDLER( hyprduel_paletteram_w )
+{
+ data = COMBINE_DATA(&paletteram16[offset]);
+ /* We need the ^0xff because we had to invert the pens in the gfx */
+ palette_set_color_rgb(Machine,offset^0xff,pal5bit(data >> 6),pal5bit(data >> 11),pal5bit(data >> 1));
+}
+
+
+/***************************************************************************
+ Tilemaps: Tiles Set & Window
+
+ Each entry in the Tiles Set RAM uses 2 words to specify a starting
+ tile code and a color code. This adds 16 consecutive tiles with
+ that color code to the set of available tiles.
+
+ Offset: Bits: Value:
+
+ 0.w fedc ---- ---- ----
+ ---- ba98 7654 ---- Color Code
+ ---- ---- ---- 3210 Code High Bits
+
+ 2.w Code Low Bits
+***************************************************************************/
+
+
+/***************************************************************************
+ Tilemaps: Rendering
+***************************************************************************/
+
+static tilemap *bg_tilemap[3];
+static UINT8 *empty_tiles;
+
+/* A 2048 x 2048 virtual tilemap */
+
+#define BIG_NX (0x100)
+#define BIG_NY (0x100)
+
+/* A smaller 512 x 256 window defines the actual tilemap */
+
+#define WIN_NX (0x40)
+#define WIN_NY (0x20)
+//#define WIN_NX (0x40+1)
+//#define WIN_NY (0x20+1)
+
+
+/* 8x8x4 tiles only */
+INLINE void get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int layer,UINT16 *vram)
+{
+ UINT16 code;
+ int table_index;
+ UINT32 tile;
+
+ /* The actual tile index depends on the window */
+ tile_index = ((tile_index / WIN_NX + hyprduel_window[layer * 2 + 0] / 8) % BIG_NY) * BIG_NX +
+ ((tile_index % WIN_NX + hyprduel_window[layer * 2 + 1] / 8) % BIG_NX);
+
+ /* Fetch the code */
+ code = vram[ tile_index ];
+
+ /* Use it as an index into the tiles set table */
+ table_index = ( (code & 0x1ff0) >> 4 ) * 2;
+ tile = (hyprduel_tiletable[table_index + 0] << 16 ) +
+ hyprduel_tiletable[table_index + 1];
+
+ if (code & 0x8000) /* Special: draw a tile of a single color (i.e. not from the gfx ROMs) */
+ {
+ int _code = code & 0x000f;
+ tileinfo->pen_data = empty_tiles + _code*16*16;
+ tileinfo->palette_base = ((code & 0x0ff0) ^ 0x0f0) + 0x1000;
+ tileinfo->flags = 0;
+ }
+ else
+ SET_TILE_INFO(
+ 0,
+ (tile & 0xfffff) + (code & 0xf),
+ (((tile & 0x0ff00000) >> 20) ^ 0x0f) + 0x100,
+ TILE_FLIPXY((code & 0x6000) >> 13));
+}
+
+
+/* 8x8x4 or 8x8x8 tiles. It's the tile's color that decides: if its low 4
+ bits are high ($f,$1f,$2f etc) the tile is 8bpp, otherwise it's 4bpp */
+INLINE void get_tile_info_8bit(running_machine *machine,tile_data *tileinfo,int tile_index,int layer,UINT16 *vram)
+{
+ UINT16 code;
+ int table_index;
+ UINT32 tile;
+
+ /* The actual tile index depends on the window */
+ tile_index = ((tile_index / WIN_NX + hyprduel_window[layer * 2 + 0] / 8) % BIG_NY) * BIG_NX +
+ ((tile_index % WIN_NX + hyprduel_window[layer * 2 + 1] / 8) % BIG_NX);
+
+ /* Fetch the code */
+ code = vram[ tile_index ];
+
+ /* Use it as an index into the tiles set table */
+ table_index = ( (code & 0x1ff0) >> 4 ) * 2;
+ tile = (hyprduel_tiletable[table_index + 0] << 16 ) +
+ hyprduel_tiletable[table_index + 1];
+
+ if (code & 0x8000) /* Special: draw a tile of a single color (i.e. not from the gfx ROMs) */
+ {
+ int _code = code & 0x000f;
+ tileinfo->pen_data = empty_tiles + _code*16*16;
+ tileinfo->palette_base = ((code & 0x0ff0) ^ 0x0f0) + 0x1000;
+ tileinfo->flags = 0;
+ }
+ else if ((tile & 0x00f00000)==0x00f00000) /* draw tile as 8bpp */
+ SET_TILE_INFO(
+ 1,
+ (tile & 0xfffff) + 2*(code & 0xf),
+ ((tile & 0x0f000000) >> 24) + 0x10,
+ TILE_FLIPXY((code & 0x6000) >> 13));
+ else
+ SET_TILE_INFO(
+ 0,
+ (tile & 0xfffff) + (code & 0xf),
+ (((tile & 0x0ff00000) >> 20) ^ 0x0f) + 0x100,
+ TILE_FLIPXY((code & 0x6000) >> 13));
+}
+
+/* 16x16x4 or 16x16x8 tiles. It's the tile's color that decides: if its low 4
+ bits are high ($f,$1f,$2f etc) the tile is 8bpp, otherwise it's 4bpp */
+INLINE void get_tile_info_16x16_8bit(running_machine *machine,tile_data *tileinfo,int tile_index,int layer,UINT16 *vram)
+{
+ UINT16 code;
+ int table_index;
+ UINT32 tile;
+
+ /* The actual tile index depends on the window */
+ tile_index = ((tile_index / WIN_NX + hyprduel_window[layer * 2 + 0] / 8) % BIG_NY) * BIG_NX +
+ ((tile_index % WIN_NX + hyprduel_window[layer * 2 + 1] / 8) % BIG_NX);
+
+ /* Fetch the code */
+ code = vram[ tile_index ];
+
+ /* Use it as an index into the tiles set table */
+ table_index = ( (code & 0x1ff0) >> 4 ) * 2;
+ tile = (hyprduel_tiletable[table_index + 0] << 16 ) +
+ hyprduel_tiletable[table_index + 1];
+
+ if (code & 0x8000) /* Special: draw a tile of a single color (i.e. not from the gfx ROMs) */
+ {
+ int _code = code & 0x000f;
+ tileinfo->pen_data = empty_tiles + _code*16*16;
+ tileinfo->palette_base = ((code & 0x0ff0) ^ 0x0f0) + 0x1000;
+ tileinfo->flags = 0;
+ }
+ else if ((tile & 0x00f00000)==0x00f00000) /* draw tile as 8bpp */
+ SET_TILE_INFO(
+ 3,
+ (tile & 0xfffff) + 8*(code & 0xf),
+ ((tile & 0x0f000000) >> 24) + 0x10,
+ TILE_FLIPXY((code & 0x6000) >> 13));
+ else
+ SET_TILE_INFO(
+ 2,
+ (tile & 0xfffff) + 4*(code & 0xf),
+ (((tile & 0x0ff00000) >> 20) ^ 0x0f) + 0x100,
+ TILE_FLIPXY((code & 0x6000) >> 13));
+}
+
+
+INLINE void hyprduel_vram_w(offs_t offset,UINT16 data,UINT16 mem_mask,int layer,UINT16 *vram)
+{
+ COMBINE_DATA(&vram[offset]);
+
+ {
+ /* Account for the window */
+ int col = (offset % BIG_NX) - ((hyprduel_window[layer * 2 + 1] / 8) % BIG_NX);
+ int row = (offset / BIG_NX) - ((hyprduel_window[layer * 2 + 0] / 8) % BIG_NY);
+ if (col < -(BIG_NX-WIN_NX)) col += (BIG_NX-WIN_NX) + WIN_NX;
+ if (row < -(BIG_NY-WIN_NY)) row += (BIG_NY-WIN_NY) + WIN_NY;
+ if ( (col >= 0) && (col < WIN_NX) &&
+ (row >= 0) && (row < WIN_NY) )
+ {
+ tilemap_mark_tile_dirty(bg_tilemap[layer], row * WIN_NX + col );
+ }
+ }
+}
+
+
+
+static TILE_GET_INFO( get_tile_info_0_8bit ) { get_tile_info_8bit(machine,tileinfo,tile_index,0,hyprduel_vram_0); }
+static TILE_GET_INFO( get_tile_info_1_8bit ) { get_tile_info_8bit(machine,tileinfo,tile_index,1,hyprduel_vram_1); }
+static TILE_GET_INFO( get_tile_info_2_8bit ) { get_tile_info_8bit(machine,tileinfo,tile_index,2,hyprduel_vram_2); }
+
+WRITE16_HANDLER( hyprduel_vram_0_w ) { hyprduel_vram_w(offset,data,mem_mask,0,hyprduel_vram_0); }
+WRITE16_HANDLER( hyprduel_vram_1_w ) { hyprduel_vram_w(offset,data,mem_mask,1,hyprduel_vram_1); }
+WRITE16_HANDLER( hyprduel_vram_2_w ) { hyprduel_vram_w(offset,data,mem_mask,2,hyprduel_vram_2); }
+
+
+/* Dirty the relevant tilemap when its window changes */
+WRITE16_HANDLER( hyprduel_window_w )
+{
+ UINT16 olddata = hyprduel_window[offset];
+ UINT16 newdata = COMBINE_DATA( &hyprduel_window[offset] );
+ if ( newdata != olddata )
+ {
+ offset /= 2;
+ tilemap_mark_all_tiles_dirty(bg_tilemap[offset]);
+ }
+}
+
+
+/***************************************************************************
+ Video Init Routines
+***************************************************************************/
+
+/*
+ Sprites are not tile based, so we decode their graphics at runtime.
+
+ We can't do it at startup because drawgfx requires the tiles to be
+ pre-rotated to support vertical games, and that, in turn, requires
+ the tile's sizes to be known at startup - which we don't!
+*/
+
+static int hyprduel_sprite_xoffs, hyprduel_sprite_yoffs;
+
+
+static void alloc_empty_tiles(void)
+{
+ int code,i;
+
+ empty_tiles = auto_malloc(16*16*16);
+
+ for (code = 0;code < 0x10;code++)
+ for (i = 0;i < 16*16;i++)
+ empty_tiles[16*16*code + i] = code ^ 0x0f;
+}
+
+VIDEO_START( hyprduel_14220 )
+{
+ alloc_empty_tiles();
+ hypr_tiletable_old = auto_malloc(hyprduel_tiletable_size);
+ dirtyindex = auto_malloc(hyprduel_tiletable_size/4);
+
+ bg_tilemap[0] = tilemap_create(get_tile_info_0_8bit,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,WIN_NX,WIN_NY);
+ bg_tilemap[1] = tilemap_create(get_tile_info_1_8bit,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,WIN_NX,WIN_NY);
+ bg_tilemap[2] = tilemap_create(get_tile_info_2_8bit,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,WIN_NX,WIN_NY);
+
+ tilemap_set_transparent_pen(bg_tilemap[0],0);
+ tilemap_set_transparent_pen(bg_tilemap[1],0);
+ tilemap_set_transparent_pen(bg_tilemap[2],0);
+
+ tilemap_set_scrolldx(bg_tilemap[0], 0, 0);
+ tilemap_set_scrolldx(bg_tilemap[1], 0, 0);
+ tilemap_set_scrolldx(bg_tilemap[2], 0, 0);
+}
+
+/***************************************************************************
+
+ Video Registers
+
+
+ Offset: Bits: Value:
+
+ 0.w Number Of Sprites To Draw
+ 2.w f--- ---- ---- ---- Disabled Sprites Layer Priority
+ -edc ---- ---- ----
+ ---- ba-- ---- ---- Sprites Masked Layer
+ ---- --98 ---- ---- Sprites Priority
+ ---- ---- 765- ----
+ ---- ---- ---4 3210 Sprites Masked Number
+ 4.w Sprites Y Offset
+ 6.w Sprites X Offset
+ 8.w Sprites Color Codes Start
+
+ -
+
+ 10.w fedc ba98 76-- ----
+ ---- ---- --54 ---- Layer 2 Priority (3 backmost, 0 frontmost)
+ ---- ---- ---- 32-- Layer 1 Priority
+ ---- ---- ---- --10 Layer 0 Priority
+
+ 12.w Backround Color
+
+***************************************************************************/
+
+
+
+/***************************************************************************
+
+ Sprites Drawing
+
+
+ Offset: Bits: Value:
+
+ 0.w fedc b--- ---- ---- Priority (0 = Max)
+ ---- -a98 7654 3210 X
+
+ 2.w fedc ba-- ---- ---- Zoom (Both X & Y)
+ ---- --98 7654 3210 Y
+
+ 4.w f--- ---- ---- ---- Flip X
+ -e-- ---- ---- ---- Flip Y
+ --dc b--- ---- ---- Size X *
+ ---- -a98 ---- ---- Size Y *
+ ---- ---- 7654 ---- Color
+ ---- ---- ---- 3210 Code High Bits **
+
+ 6.w Code Low Bits **
+
+* 8 pixel increments
+** 8x8 pixel increments
+***************************************************************************/
+
+/* Draw sprites */
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const int region = REGION_GFX1;
+
+ UINT8 *base_gfx = memory_region(region);
+ UINT8 *gfx_max = base_gfx + memory_region_length(region);
+
+ int max_x = machine->screen[0].width;
+ int max_y = machine->screen[0].height;
+
+ int max_sprites = spriteram_size / 8;
+ int sprites = hyprduel_videoregs[0x00/2] % max_sprites;
+
+ int color_start = ((hyprduel_videoregs[0x08/2] & 0xf) << 4 ) + 0x100;
+
+ int i, pri;
+ static const int primask[4] = { 0x0000, 0xff00, 0xff00|0xf0f0, 0xff00|0xf0f0|0xcccc };
+
+ for (i=0; i<0x20; i++)
+ {
+ UINT16 *src = spriteram16 + (sprites - 1) * (8/2);
+ UINT16 *end = spriteram16;
+
+ for ( ; src >= end; src -= 8/2 )
+ {
+ int x,y, attr,code,color,flipx,flipy, zoom, curr_pri,width,height;
+ UINT8 *gfxdata;
+
+ /* Exponential zoom table extracted from daitoride */
+ static const int zoomtable[0x40] =
+ { 0xAAC,0x800,0x668,0x554,0x494,0x400,0x390,0x334,
+ 0x2E8,0x2AC,0x278,0x248,0x224,0x200,0x1E0,0x1C8,
+ 0x1B0,0x198,0x188,0x174,0x164,0x154,0x148,0x13C,
+ 0x130,0x124,0x11C,0x110,0x108,0x100,0x0F8,0x0F0,
+ 0x0EC,0x0E4,0x0DC,0x0D8,0x0D4,0x0CC,0x0C8,0x0C4,
+ 0x0C0,0x0BC,0x0B8,0x0B4,0x0B0,0x0AC,0x0A8,0x0A4,
+ 0x0A0,0x09C,0x098,0x094,0x090,0x08C,0x088,0x080,
+ 0x078,0x070,0x068,0x060,0x058,0x050,0x048,0x040 };
+
+ x = src[ 0 ];
+ curr_pri = (x & 0xf800) >> 11;
+ if ((curr_pri == 0x1f) || (curr_pri != i)) continue;
+
+ pri = (hyprduel_videoregs[0x02/2] & 0x0300) >> 8;
+
+ if (!(hyprduel_videoregs[0x02/2] & 0x8000))
+ {
+ if (curr_pri > (hyprduel_videoregs[0x02/2] & 0x1f))
+ pri = (hyprduel_videoregs[0x02/2] & 0x0c00) >> 10;
+ }
+
+ y = src[ 1 ];
+ attr = src[ 2 ];
+ code = src[ 3 ];
+
+ flipx = attr & 0x8000;
+ flipy = attr & 0x4000;
+ color = (attr & 0xf0) >> 4;
+
+ zoom = zoomtable[(y & 0xfc00) >> 10] << (16-8);
+
+ x = (x & 0x07ff) - hyprduel_sprite_xoffs;
+ y = (y & 0x03ff) - hyprduel_sprite_yoffs +2;
+
+ width = (( (attr >> 11) & 0x7 ) + 1 ) * 8;
+ height = (( (attr >> 8) & 0x7 ) + 1 ) * 8;
+
+ gfxdata = base_gfx + (8*8*4/8) * (((attr & 0x000f) << 16) + code);
+
+ if (flip_screen)
+ {
+ flipx = !flipx; x = max_x - x - width;
+ flipy = !flipy; y = max_y - y - height;
+ }
+
+ if (color == 0xf) /* 8bpp */
+ {
+ /* prepare GfxElement on the fly */
+ gfx_element gfx;
+ gfx.width = width;
+ gfx.height = height;
+ gfx.total_elements = 1;
+ gfx.color_depth = 256;
+ gfx.color_granularity = 256;
+ gfx.color_base = 0;
+ gfx.total_colors = 0x20;
+ gfx.pen_usage = NULL;
+ gfx.gfxdata = gfxdata;
+ gfx.line_modulo = width;
+ gfx.char_modulo = 0; /* doesn't matter */
+ gfx.flags = 0;
+
+ /* Bounds checking */
+ if ( (gfxdata + width * height - 1) >= gfx_max )
+ continue;
+
+ pdrawgfxzoom( bitmap,&gfx,
+ 0,
+ color_start >> 4,
+ flipx, flipy,
+ x, y,
+ cliprect, TRANSPARENCY_PEN, 0,
+ zoom, zoom,
+ primask[pri]);
+ }
+ else
+ {
+ /* prepare GfxElement on the fly */
+ gfx_element gfx;
+ gfx.width = width;
+ gfx.height = height;
+ gfx.total_elements = 1;
+ gfx.color_depth = 16;
+ gfx.color_granularity = 16;
+ gfx.color_base = 0;
+ gfx.total_colors = 0x200;
+ gfx.pen_usage = NULL;
+ gfx.gfxdata = gfxdata;
+ gfx.line_modulo = width/2;
+ gfx.char_modulo = 0; /* doesn't matter */
+ gfx.flags = GFX_ELEMENT_PACKED;
+
+ /* Bounds checking */
+ if ( (gfxdata + width/2 * height - 1) >= gfx_max )
+ continue;
+
+ pdrawgfxzoom( bitmap,&gfx,
+ 0,
+ (color ^ 0x0f) + color_start,
+ flipx, flipy,
+ x, y,
+ cliprect, TRANSPARENCY_PEN, 0,
+ zoom, zoom,
+ primask[pri]);
+ }
+#if 0
+{ /* Display priority + zoom on each sprite */
+ char buf[80];
+ sprintf(buf, "%02X %02X",((src[ 0 ] & 0xf800) >> 11)^0x1f,((src[ 1 ] & 0xfc00) >> 10) );
+ ui_draw_text(buf, x, y);
+}
+#endif
+ }
+ }
+}
+
+
+/***************************************************************************
+ Screen Drawing
+***************************************************************************/
+
+/* Draw all the layers that match the given priority */
+static void draw_layers(mame_bitmap *bitmap, const rectangle *cliprect, int pri, int layers_ctrl)
+{
+ UINT16 layers_pri = hyprduel_videoregs[0x10/2];
+ int layer;
+ int offs;
+ rectangle clip;
+
+ clip.min_x = 0;
+ clip.max_x = 319;
+
+ /* Draw all the layers with priority == pri */
+ for (layer = 2; layer >= 0; layer--) // tilemap[2] below?
+ {
+ if ( pri == ((layers_pri >> (layer*2)) & 3) )
+ {
+ /* Scroll and Window values */
+ UINT16 wx = hyprduel_window[layer * 2 + 1];
+ UINT16 wy = hyprduel_window[layer * 2 + 0];
+ wx = wx - (wx & 7);
+ wy = wy - (wy & 7);
+
+ if (layers_ctrl & (1<<layer))
+ {
+ for (offs = cliprect->min_y; offs <= cliprect->max_y; offs++)
+ {
+ clip.min_y = offs;
+ clip.max_y = offs;
+
+ tilemap_set_scrollx(bg_tilemap[layer], 0, hyprduel_scrollx[layer][offs+RASTER_LINES-(LAST_VISIBLE_LINE+1)] - wx);
+ tilemap_set_scrolly(bg_tilemap[layer], 0, hyprduel_scrolly[layer][offs+RASTER_LINES-(LAST_VISIBLE_LINE+1)] - wy);
+ tilemap_draw(bitmap,&clip,bg_tilemap[layer], 0, 1<<(3-pri));
+ }
+ }
+ }
+ }
+}
+
+
+/* Dirty tilemaps when the tiles set changes */
+static void dirty_tiles(int layer,UINT16 *vram)
+{
+ int col,row;
+
+ for (row = 0;row < WIN_NY;row++)
+ {
+ for (col = 0;col < WIN_NX;col++)
+ {
+ int offset = (col + hyprduel_window[layer * 2 + 1] / 8) % BIG_NX +
+ ((row + hyprduel_window[layer * 2 + 0] / 8) % BIG_NY) * BIG_NX;
+ UINT16 code = vram[offset];
+
+ if (!(code & 0x8000) && dirtyindex[(code & 0x1ff0) >> 4])
+ tilemap_mark_tile_dirty(bg_tilemap[layer], row * WIN_NX + col );
+ }
+ }
+}
+
+
+VIDEO_UPDATE( hyprduel )
+{
+ int i,pri,layers_ctrl = -1;
+ UINT16 screenctrl = *hyprduel_screenctrl;
+
+ {
+ int dirty = 0;
+
+ memset(dirtyindex,0,hyprduel_tiletable_size/4);
+ for (i = 0;i < hyprduel_tiletable_size/4;i++)
+ {
+ UINT32 tile_new = (hyprduel_tiletable[2*i + 0] << 16 ) + hyprduel_tiletable[2*i + 1];
+ UINT32 tile_old = (hypr_tiletable_old[2*i + 0] << 16 ) + hypr_tiletable_old[2*i + 1];
+
+ if ((tile_new ^ tile_old) & 0x0fffffff)
+ {
+ dirtyindex[i] = 1;
+ dirty = 1;
+ }
+ }
+ memcpy(hypr_tiletable_old,hyprduel_tiletable,hyprduel_tiletable_size);
+
+ if (dirty)
+ {
+ dirty_tiles(0,hyprduel_vram_0);
+ dirty_tiles(1,hyprduel_vram_1);
+ dirty_tiles(2,hyprduel_vram_2);
+ }
+ }
+
+ hyprduel_sprite_xoffs = hyprduel_videoregs[0x06/2] - machine->screen[0].width / 2;
+ hyprduel_sprite_yoffs = hyprduel_videoregs[0x04/2] - machine->screen[0].height / 2;
+
+ /* The background color is selected by a register */
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[((hyprduel_videoregs[0x12/2] & 0x0fff) ^ 0x0ff) + 0x1000],cliprect);
+
+ /* Screen Control Register:
+
+ f--- ---- ---- ---- ?
+ -edc b--- ---- ----
+ ---- -a98 ---- ---- ? Leds
+ ---- ---- 7--- ---- 16x16 Tiles (Layer 2)
+ ---- ---- -6-- ---- 16x16 Tiles (Layer 1)
+ ---- ---- --5- ---- 16x16 Tiles (Layer 0)
+ ---- ---- ---4 32--
+ ---- ---- ---- --1- ? Blank Screen
+ ---- ---- ---- ---0 Flip Screen */
+ if (screenctrl & 2) return 0;
+ flip_screen_set(screenctrl & 1);
+
+ /* If the game supports 16x16 tiles, make sure that the
+ 16x16 and 8x8 tilemaps of a given layer are not simultaneously
+ enabled! */
+
+#if 0
+if (input_code_pressed(KEYCODE_Z))
+{ int msk = 0;
+ if (input_code_pressed(KEYCODE_Q)) msk |= 0x01;
+ if (input_code_pressed(KEYCODE_W)) msk |= 0x02;
+ if (input_code_pressed(KEYCODE_E)) msk |= 0x04;
+ if (input_code_pressed(KEYCODE_A)) msk |= 0x08;
+ if (msk != 0)
+ { fillbitmap(bitmap,0,cliprect);
+ layers_ctrl &= msk; }
+
+ popmessage("%x-%x-%x:%04x %04x %04x",
+ hyprduel_videoregs[0x10/2]&3,(hyprduel_videoregs[0x10/2]&0xc)>>2,(hyprduel_videoregs[0x10/2]&0x30)>>4,
+ hyprduel_videoregs[0x02/2],hyprduel_videoregs[0x08/2],
+ *hyprduel_screenctrl);}
+#endif
+
+ for (pri=3; pri>=0; pri--)
+ draw_layers(bitmap,cliprect,pri,layers_ctrl);
+
+ if (layers_ctrl & 0x08)
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/ikki.c b/src/mame/video/ikki.c
new file mode 100644
index 00000000000..855811609ef
--- /dev/null
+++ b/src/mame/video/ikki.c
@@ -0,0 +1,201 @@
+/******************************************************************************
+
+Ikki (c) 1985 Sun Electronics
+
+Video hardware driver by Uki
+
+ 20/Jun/2001 -
+
+******************************************************************************/
+
+#include "driver.h"
+
+static UINT8 ikki_flipscreen, ikki_scroll[2];
+
+PALETTE_INIT( ikki )
+{
+ int i;
+
+ for (i = 0; i<256; i++)
+ {
+ palette_set_color_rgb(machine,i,pal4bit(color_prom[0]),pal4bit(color_prom[256]),pal4bit(color_prom[2*256]));
+
+ color_prom++;
+ }
+
+ /* 256th color is not drawn on screen */
+ /* this is used for special transparent function */
+ palette_set_color(machine,256,MAKE_RGB(0,0,1));
+
+ color_prom += 2*256;
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* sprites lookup table */
+ for (i=0; i<512; i++)
+ {
+ int d = 255-*(color_prom++);
+ if ( ((i % 8) == 7) && (d == 0) )
+ *(colortable++) = 256; /* special transparent */
+ else
+ *(colortable++) = d; /* normal color */
+ }
+
+ /* bg lookup table */
+ for (i=0; i<512; i++)
+ *(colortable++) = *(color_prom++);
+
+}
+
+WRITE8_HANDLER( ikki_scroll_w )
+{
+ ikki_scroll[offset] = data;
+}
+
+WRITE8_HANDLER( ikki_scrn_ctrl_w )
+{
+ ikki_flipscreen = (data >> 2) & 1;
+}
+
+VIDEO_UPDATE( ikki )
+{
+
+ int offs,chr,col,px,py,f,bank,d;
+ UINT8 *VIDEOATTR = memory_region( REGION_USER1 );
+
+ f = ikki_flipscreen;
+
+ /* draw bg layer */
+
+ for (offs=0; offs<(videoram_size/2); offs++)
+ {
+ int sx,sy;
+
+ sx = offs / 32;
+ sy = offs % 32;
+
+ py = sy*8;
+ px = sx*8;
+
+ d = VIDEOATTR[ sx ];
+
+ switch (d)
+ {
+ case 0x02: /* scroll area */
+ px = sx*8 - ikki_scroll[1];
+ if (px<0)
+ px=px+8*22;
+ py = (sy*8 + ~ikki_scroll[0]) & 0xff;
+ break;
+
+ case 0x03: /* non-scroll area */
+ break;
+
+ case 0x00: /* sprite disable? */
+ break;
+
+ case 0x0d: /* sprite disable? */
+ break;
+
+ case 0x0b: /* non-scroll area (?) */
+ break;
+
+ case 0x0e: /* unknown */
+ break;
+ }
+
+ if (f != 0)
+ {
+ px = 248-px;
+ py = 248-py;
+ }
+
+ col = videoram[offs*2];
+ bank = (col & 0xe0) << 3;
+ col = ((col & 0x1f)<<0) | ((col & 0x80) >> 2);
+
+ drawgfx(bitmap,machine->gfx[0],
+ videoram[offs*2+1] + bank,
+ col,
+ f,f,
+ px,py,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ }
+
+/* draw sprites */
+
+ fillbitmap(tmpbitmap, machine->pens[256], 0);
+
+ /* c060 - c0ff */
+ for (offs=0x00; offs<0x800; offs +=4)
+ {
+ chr = spriteram[offs+1] >> 1 ;
+ col = spriteram[offs+2];
+
+ px = spriteram[offs+3];
+ py = spriteram[offs+0];
+
+ chr += (col & 0x80);
+ col = (col & 0x3f) >> 0 ;
+
+ if (f==0)
+ py = 224-py;
+ else
+ px = 240-px;
+
+ px = px & 0xff;
+ py = py & 0xff;
+
+ if (px>248)
+ px = px-256;
+ if (py>240)
+ py = py-256;
+
+ drawgfx(tmpbitmap,machine->gfx[1],
+ chr,
+ col,
+ f,f,
+ px,py,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+ }
+
+ copybitmap(bitmap,tmpbitmap,0,0,0,0,&machine->screen[0].visarea,TRANSPARENCY_COLOR,256);
+
+
+ /* mask sprites */
+
+ for (offs=0; offs<(videoram_size/2); offs++)
+ {
+ int sx,sy;
+
+ sx = offs / 32;
+ sy = offs % 32;
+
+ d = VIDEOATTR[ sx ];
+
+ if ( (d == 0) || (d == 0x0d) )
+ {
+ py = sy*8;
+ px = sx*8;
+
+ if (f != 0)
+ {
+ px = 248-px;
+ py = 248-py;
+ }
+
+ col = videoram[offs*2];
+ bank = (col & 0xe0) << 3;
+ col = ((col & 0x1f)<<0) | ((col & 0x80) >> 2);
+
+ drawgfx(bitmap,machine->gfx[0],
+ videoram[offs*2+1] + bank,
+ col,
+ f,f,
+ px,py,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/inufuku.c b/src/mame/video/inufuku.c
new file mode 100644
index 00000000000..c17c84d9087
--- /dev/null
+++ b/src/mame/video/inufuku.c
@@ -0,0 +1,263 @@
+/******************************************************************************
+
+ Video Hardware for Video System Games.
+
+ Quiz & Variety Sukusuku Inufuku
+ (c)1998 Video System Co.,Ltd.
+
+ Driver by Takahiro Nogi <nogi@kt.rim.or.jp> 2003/08/09 -
+
+ based on other Video System drivers
+
+******************************************************************************/
+
+#include "driver.h"
+
+
+extern UINT16 *inufuku_spriteram1;
+extern UINT16 *inufuku_spriteram2;
+extern size_t inufuku_spriteram1_size;
+
+extern UINT16 *inufuku_bg_videoram;
+extern UINT16 *inufuku_bg_rasterram;
+extern UINT16 *inufuku_text_videoram;
+
+static int inufuku_bg_scrollx, inufuku_bg_scrolly;
+static int inufuku_text_scrollx, inufuku_text_scrolly;
+static int inufuku_bg_raster;
+static int inufuku_bg_palettebank;
+static int inufuku_text_palettebank;
+
+static tilemap *inufuku_bg_tilemap;
+static tilemap *inufuku_text_tilemap;
+
+
+/******************************************************************************
+
+ Memory handlers
+
+******************************************************************************/
+
+WRITE16_HANDLER( inufuku_palettereg_w )
+{
+ switch (offset) {
+ case 0x02: inufuku_bg_palettebank = (data & 0xf000) >> 12;
+ tilemap_mark_all_tiles_dirty(inufuku_bg_tilemap);
+ break;
+ case 0x03: inufuku_text_palettebank = (data & 0xf000) >> 12;
+ tilemap_mark_all_tiles_dirty(inufuku_text_tilemap);
+ break;
+ }
+}
+
+WRITE16_HANDLER( inufuku_scrollreg_w )
+{
+ switch (offset) {
+ case 0x00: inufuku_bg_scrollx = data + 1; break;
+ case 0x01: inufuku_bg_scrolly = data + 0; break;
+ case 0x02: inufuku_text_scrollx = data - 3; break;
+ case 0x03: inufuku_text_scrolly = data + 1; break;
+ case 0x04: inufuku_bg_raster = (data & 0x0200) ? 0 : 1; break;
+ }
+}
+
+
+/******************************************************************************
+
+ Sprite routines
+
+******************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = (inufuku_spriteram1_size / 16) - 1; offs >= 0; offs--) {
+
+ if ((inufuku_spriteram1[offs] & 0x8000) == 0x0000) {
+
+ int attr_start;
+ int map_start;
+ int ox, oy, x, y, xsize, ysize, zoomx, zoomy, flipx, flipy, color;
+ int priority, priority_mask;
+
+ attr_start = 4 * (inufuku_spriteram1[offs] & 0x03ff);
+
+ /*
+ attr_start + 0x0000
+ ---- ---x xxxx xxxx oy
+ ---- xxx- ---- ---- ysize
+ xxxx ---- ---- ---- zoomy
+
+ attr_start + 0x0001
+ ---- ---x xxxx xxxx ox
+ ---- xxx- ---- ---- xsize
+ xxxx ---- ---- ---- zoomx
+
+ attr_start + 0x0002
+ -x-- ---- ---- ---- flipx
+ x--- ---- ---- ---- flipy
+ --xx xxxx ---- ---- color
+ --xx ---- ---- ---- priority?
+ ---- ---- xxxx xxxx unused?
+
+ attr_start + 0x0003
+ -xxx xxxx xxxx xxxx map start
+ x--- ---- ---- ---- unused?
+ */
+
+ ox = (inufuku_spriteram1[attr_start + 1] & 0x01ff) + 0;
+ xsize = (inufuku_spriteram1[attr_start + 1] & 0x0e00) >> 9;
+ zoomx = (inufuku_spriteram1[attr_start + 1] & 0xf000) >> 12;
+ oy = (inufuku_spriteram1[attr_start + 0] & 0x01ff) + 1;
+ ysize = (inufuku_spriteram1[attr_start + 0] & 0x0e00) >> 9;
+ zoomy = (inufuku_spriteram1[attr_start + 0] & 0xf000) >> 12;
+ flipx = inufuku_spriteram1[attr_start + 2] & 0x4000;
+ flipy = inufuku_spriteram1[attr_start + 2] & 0x8000;
+ color = (inufuku_spriteram1[attr_start + 2] & 0x3f00) >> 8;
+ priority = (inufuku_spriteram1[attr_start + 2] & 0x3000) >> 12;
+ map_start = (inufuku_spriteram1[attr_start + 3] & 0x7fff) << 1;
+
+ switch (priority) {
+ default:
+ case 0: priority_mask = 0x00; break;
+ case 3: priority_mask = 0xfe; break;
+ case 2: priority_mask = 0xfc; break;
+ case 1: priority_mask = 0xf0; break;
+ }
+
+ ox += (xsize * zoomx + 2) / 4;
+ oy += (ysize * zoomy + 2) / 4;
+
+ zoomx = 32 - zoomx;
+ zoomy = 32 - zoomy;
+
+ for (y = 0; y <= ysize; y++) {
+ int sx, sy;
+
+ if (flipy)
+ sy = (oy + zoomy * (ysize - y) / 2 + 16) & 0x1ff;
+ else
+ sy = (oy + zoomy * y / 2 + 16) & 0x1ff;
+
+ for (x = 0; x <= xsize; x++) {
+ int code;
+
+ if (flipx)
+ sx = (ox + zoomx * (xsize - x) / 2 + 16) & 0x1ff;
+ else
+ sx = (ox + zoomx * x / 2 + 16) & 0x1ff;
+
+ code = ((inufuku_spriteram2[map_start] & 0x0007) << 16) + inufuku_spriteram2[map_start + 1];
+
+ pdrawgfxzoom(bitmap, machine->gfx[2],
+ code,
+ color,
+ flipx, flipy,
+ sx - 16, sy - 16,
+ cliprect, TRANSPARENCY_PEN, 15,
+ zoomx << 11, zoomy << 11,
+ priority_mask);
+
+ map_start += 2;
+ }
+ }
+ }
+ }
+}
+
+
+/******************************************************************************
+
+ Tilemap callbacks
+
+******************************************************************************/
+
+static TILE_GET_INFO( get_inufuku_bg_tile_info )
+{
+ SET_TILE_INFO(
+ 0,
+ inufuku_bg_videoram[tile_index],
+ inufuku_bg_palettebank,
+ 0);
+}
+
+static TILE_GET_INFO( get_inufuku_text_tile_info )
+{
+ SET_TILE_INFO(
+ 1,
+ inufuku_text_videoram[tile_index],
+ inufuku_text_palettebank,
+ 0);
+}
+
+READ16_HANDLER( inufuku_bg_videoram_r )
+{
+ return inufuku_bg_videoram[offset];
+}
+
+WRITE16_HANDLER( inufuku_bg_videoram_w )
+{
+ COMBINE_DATA(&inufuku_bg_videoram[offset]);
+ tilemap_mark_tile_dirty(inufuku_bg_tilemap, offset);
+}
+
+READ16_HANDLER( inufuku_text_videoram_r )
+{
+ return inufuku_text_videoram[offset];
+}
+
+WRITE16_HANDLER( inufuku_text_videoram_w )
+{
+ COMBINE_DATA(&inufuku_text_videoram[offset]);
+ tilemap_mark_tile_dirty(inufuku_text_tilemap, offset);
+}
+
+
+/******************************************************************************
+
+ Start the video hardware emulation
+
+******************************************************************************/
+
+VIDEO_START( inufuku )
+{
+ inufuku_bg_tilemap = tilemap_create(get_inufuku_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ inufuku_text_tilemap = tilemap_create(get_inufuku_text_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+
+ tilemap_set_transparent_pen(inufuku_bg_tilemap, 255);
+ tilemap_set_transparent_pen(inufuku_text_tilemap, 255);
+}
+
+
+/******************************************************************************
+
+ Display refresh
+
+******************************************************************************/
+
+VIDEO_UPDATE( inufuku )
+{
+ int i;
+
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ fillbitmap(priority_bitmap, 0, NULL);
+
+ if (inufuku_bg_raster) {
+ tilemap_set_scroll_rows(inufuku_bg_tilemap, 512);
+ for (i = 0; i < 256; i++) tilemap_set_scrollx(inufuku_bg_tilemap, (inufuku_bg_scrolly + i) & 0x1ff, inufuku_bg_rasterram[i]);
+ }
+ else {
+ tilemap_set_scroll_rows(inufuku_bg_tilemap, 1);
+ tilemap_set_scrollx(inufuku_bg_tilemap, 0, inufuku_bg_scrollx);
+ }
+ tilemap_set_scrolly(inufuku_bg_tilemap, 0, inufuku_bg_scrolly);
+ tilemap_draw(bitmap, cliprect, inufuku_bg_tilemap, 0, 0);
+
+ tilemap_set_scrollx(inufuku_text_tilemap, 0, inufuku_text_scrollx);
+ tilemap_set_scrolly(inufuku_text_tilemap, 0, inufuku_text_scrolly);
+ tilemap_draw(bitmap, cliprect, inufuku_text_tilemap, 0, 4);
+
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/iqblock.c b/src/mame/video/iqblock.c
new file mode 100644
index 00000000000..c70b8aab076
--- /dev/null
+++ b/src/mame/video/iqblock.c
@@ -0,0 +1,103 @@
+#include "driver.h"
+#include "iqblock.h"
+
+
+UINT8 *iqblock_bgvideoram;
+//UINT8 *iqblock_fgscroll;
+UINT8 *iqblock_fgvideoram;
+int iqblock_videoenable;
+int iqblock_video_type;
+
+static tilemap *bg_tilemap,*fg_tilemap;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = iqblock_bgvideoram[tile_index] + (iqblock_bgvideoram[tile_index + 0x800] << 8);
+ SET_TILE_INFO(
+ 0,
+ code &(iqblock_video_type ? 0x1fff : 0x3fff),
+ iqblock_video_type? (2*(code >> 13)+1) : (4*(code >> 14)+3),
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = iqblock_fgvideoram[tile_index];
+ SET_TILE_INFO(
+ 1,
+ code & 0x7f,
+ (code & 0x80) ? 3 : 0,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( iqblock )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,32,64, 8);
+
+ tilemap_set_transparent_pen(bg_tilemap,0);
+ tilemap_set_scroll_cols(fg_tilemap,64);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( iqblock_fgvideoram_w )
+{
+ iqblock_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE8_HANDLER( iqblock_bgvideoram_w )
+{
+ iqblock_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x7ff);
+}
+
+READ8_HANDLER( iqblock_bgvideoram_r )
+{
+ return iqblock_bgvideoram[offset];
+}
+
+WRITE8_HANDLER( iqblock_fgscroll_w )
+{
+ tilemap_set_scrolly(fg_tilemap,offset,data);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( iqblock )
+{
+ if (!iqblock_videoenable) return 0;
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ return 0;
+}
+
diff --git a/src/mame/video/irobot.c b/src/mame/video/irobot.c
new file mode 100644
index 00000000000..a9006cb7adb
--- /dev/null
+++ b/src/mame/video/irobot.c
@@ -0,0 +1,390 @@
+/***************************************************************************
+
+ Atari I, Robot hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "irobot.h"
+
+#define BITMAP_WIDTH 256
+static UINT8 *polybitmap1,*polybitmap2;
+
+static int ir_xmin, ir_ymin, ir_xmax, ir_ymax; /* clipping area */
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ 5 bits from polygon ram address the palette ram
+
+ Output of color RAM
+ bit 8 -- inverter -- 1K ohm resistor -- RED
+ bit 7 -- inverter -- 2.2K ohm resistor -- RED
+ -- inverter -- 1K ohm resistor -- GREEN
+ -- inverter -- 2.2K ohm resistor -- GREEN
+ -- inverter -- 1K ohm resistor -- BLUE
+ -- inverter -- 2.2K ohm resistor -- BLUE
+ -- inverter -- 2.2K ohm resistor -- INT
+ -- inverter -- 4.7K ohm resistor -- INT
+ bit 0 -- inverter -- 9.1K ohm resistor -- INT
+
+ Alphanumeric colors are generated by ROM .125, it's outputs are connected
+ to bits 1..8 as above. The inputs are:
+
+ A0..1 - Character color
+ A2 - Character image (1=pixel on/0=off)
+ A3..4 - Alphamap 0,1 (appears that only Alphamap1 is used, it is set by
+ the processor)
+
+***************************************************************************/
+
+PALETTE_INIT( irobot )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ /* Convert the color prom for the text palette */
+ for (i = 0;i < 32;i++)
+ {
+ int r,g,b;
+ int bits,intensity;
+ UINT32 color;
+
+ color = *color_prom;
+ intensity = color & 0x03;
+ bits = (color >> 6) & 0x03;
+ r = 28 * bits * intensity;
+ bits = (color >> 4) & 0x03;
+ g = 28 * bits * intensity;
+ bits = (color >> 2) & 0x03;
+ b = 28 * bits * intensity;
+ palette_set_color(machine,i+64,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* polygons */
+ for (i = 0;i < 64;i++)
+ colortable[i] = i;
+
+ /* text */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ {
+ COLOR(0,i) = ((i & 0x18) | ((i & 0x01) << 2) | ((i & 0x06) >> 1)) + 64;
+ }
+}
+
+
+WRITE8_HANDLER( irobot_paletteram_w )
+{
+ int r,g,b;
+ int bits,intensity;
+ UINT32 color;
+
+ color = ((data << 1) | (offset & 0x01)) ^ 0x1ff;
+ intensity = color & 0x07;
+ bits = (color >> 3) & 0x03;
+ b = 12 * bits * intensity;
+ bits = (color >> 5) & 0x03;
+ g = 12 * bits * intensity;
+ bits = (color >> 7) & 0x03;
+ r = 12 * bits * intensity;
+ palette_set_color(Machine,(offset >> 1) & 0x3F,MAKE_RGB(r,g,b));
+}
+
+
+static void _irobot_poly_clear(running_machine *machine, UINT8 *bitmap_base)
+{
+ memset(bitmap_base, 0, BITMAP_WIDTH * machine->screen[0].height);
+}
+
+void irobot_poly_clear(void)
+{
+ UINT8 *bitmap_base = irobot_bufsel ? polybitmap2 : polybitmap1;
+ _irobot_poly_clear(Machine, bitmap_base);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+VIDEO_START( irobot )
+{
+ /* Setup 2 bitmaps for the polygon generator */
+ polybitmap1 = auto_malloc(BITMAP_WIDTH * machine->screen[0].height);
+ polybitmap2 = auto_malloc(BITMAP_WIDTH * machine->screen[0].height);
+
+ /* clear the bitmaps so we start with valid palette look-up values for drawing */
+ _irobot_poly_clear(machine, polybitmap1);
+ _irobot_poly_clear(machine, polybitmap2);
+
+ /* Set clipping */
+ ir_xmin = ir_ymin = 0;
+ ir_xmax = machine->screen[0].width;
+ ir_ymax = machine->screen[0].height;
+}
+
+
+/***************************************************************************
+
+ Polygon Generator (Preliminary information)
+ The polygon communication ram works as follows (each location is a 16-bit word):
+
+ 0000-xxxx: Object pointer table
+ bits 00..10: Address of object data
+ bits 12..15: Object type
+ 0x4 = Polygon
+ 0x8 = Point
+ 0xC = Vector
+ (0xFFFF means end of table)
+
+ Point Object:
+ Word 0, bits 0..15: X Position (0xFFFF = end of point objects)
+ Word 1, bits 7..15: Y Position
+ bits 0..5: Color
+
+ Vector Object:
+ Word 0, bits 7..15: Ending Y (0xFFFF = end of line objects)
+ Word 1, bits 7..15: Starting Y
+ bits 0..5: Color
+ Word 2: Slope
+ Word 3, bits 0..15: Starting X
+
+ Polygon Object:
+ Word 0, bits 0..10: Pointer to second slope list
+ Word 1, bits 0..15: Starting X first vector
+ Word 2, bits 0..15: Starting X second vector
+ Word 3, bits 0..5: Color
+ bits 7..15: Initial Y value
+
+ Slope Lists: (one starts at Word 4, other starts at pointer in Word 0)
+ Word 0, Slope (0xFFFF = side done)
+ Word 1, bits 7..15: Ending Y of vector
+
+ Each side is a continous set of vectors. Both sides are drawn at
+ the same time and the space between them is filled in.
+
+***************************************************************************/
+
+#define draw_pixel(x,y,c) polybitmap[(y) * BITMAP_WIDTH + (x)] = (c)
+#define fill_hline(x1,x2,y,c) memset(&polybitmap[(y) * BITMAP_WIDTH + (x1)], (c), (x2) - (x1) + 1)
+
+
+/*
+ Line draw routine
+ modified from a routine written by Andrew Caldwell
+ */
+
+static void draw_line (UINT8 *polybitmap, int x1, int y1, int x2, int y2, int col)
+{
+ int dx,dy,sx,sy,cx,cy;
+
+ dx = abs(x1-x2);
+ dy = abs(y1-y2);
+ sx = (x1 <= x2) ? 1: -1;
+ sy = (y1 <= y2) ? 1: -1;
+ cx = dx/2;
+ cy = dy/2;
+
+ if (dx>=dy)
+ {
+ for (;;)
+ {
+ if (x1 >= ir_xmin && x1 < ir_xmax && y1 >= ir_ymin && y1 < ir_ymax)
+ draw_pixel (x1, y1, col);
+ if (x1 == x2) break;
+ x1 += sx;
+ cx -= dy;
+ if (cx < 0)
+ {
+ y1 += sy;
+ cx += dx;
+ }
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ if (x1 >= ir_xmin && x1 < ir_xmax && y1 >= ir_ymin && y1 < ir_ymax)
+ draw_pixel (x1, y1, col);
+ if (y1 == y2) break;
+ y1 += sy;
+ cy -= dx;
+ if (cy < 0)
+ {
+ x1 += sx;
+ cy += dy;
+ }
+ }
+ }
+}
+
+
+#define ROUND_TO_PIXEL(x) ((x >> 7) - 128)
+
+void irobot_run_video(void)
+{
+ UINT8 *polybitmap;
+ UINT16 *combase16 = (UINT16 *)irobot_combase;
+ int sx,sy,ex,ey,sx2,ey2;
+ int color;
+ UINT32 d1;
+ int lpnt,spnt,spnt2;
+ int shp;
+ INT32 word1,word2;
+
+ logerror("Starting Polygon Generator, Clear=%d\n",irobot_vg_clear);
+
+ if (irobot_bufsel)
+ polybitmap = polybitmap2;
+ else
+ polybitmap = polybitmap1;
+
+ lpnt=0;
+ while (lpnt < 0x7FF)
+ {
+ d1 = combase16[lpnt++];
+ if (d1 == 0xFFFF) break;
+ spnt = d1 & 0x07FF;
+ shp = (d1 & 0xF000) >> 12;
+
+ /* Pixel */
+ if (shp == 0x8)
+ {
+ while (spnt < 0x7FF)
+ {
+ sx = combase16[spnt];
+ if (sx == 0xFFFF) break;
+ sy = combase16[spnt+1];
+ color = sy & 0x3F;
+ sx = ROUND_TO_PIXEL(sx);
+ sy = ROUND_TO_PIXEL(sy);
+ if (sx >= ir_xmin && sx < ir_xmax && sy >= ir_ymin && sy < ir_ymax)
+ draw_pixel(sx,sy,color);
+ spnt+=2;
+ }//while object
+ }//if point
+
+ /* Line */
+ if (shp == 0xC)
+ {
+ while (spnt < 0x7FF)
+ {
+ ey = combase16[spnt];
+ if (ey == 0xFFFF) break;
+ ey = ROUND_TO_PIXEL(ey);
+ sy = combase16[spnt+1];
+ color = sy & 0x3F;
+ sy = ROUND_TO_PIXEL(sy);
+ sx = combase16[spnt+3];
+ word1 = (INT16)combase16[spnt+2];
+ ex = sx + word1 * (ey - sy + 1);
+ draw_line(polybitmap, ROUND_TO_PIXEL(sx),sy,ROUND_TO_PIXEL(ex),ey,color);
+ spnt+=4;
+ }//while object
+ }//if line
+
+ /* Polygon */
+ if (shp == 0x4)
+ {
+ spnt2 = combase16[spnt] & 0x7FF;
+
+ sx = combase16[spnt+1];
+ sx2 = combase16[spnt+2];
+ sy = combase16[spnt+3];
+ color = sy & 0x3F;
+ sy = ROUND_TO_PIXEL(sy);
+ spnt+=4;
+
+ word1 = (INT16)combase16[spnt];
+ ey = combase16[spnt+1];
+ if (word1 != -1 || ey != 0xFFFF)
+ {
+ ey = ROUND_TO_PIXEL(ey);
+ spnt+=2;
+
+ // sx += word1;
+
+ word2 = (INT16)combase16[spnt2];
+ ey2 = ROUND_TO_PIXEL(combase16[spnt2+1]);
+ spnt2+=2;
+
+ // sx2 += word2;
+
+ while(1)
+ {
+ if (sy >= ir_ymin && sy < ir_ymax)
+ {
+ int x1 = ROUND_TO_PIXEL(sx);
+ int x2 = ROUND_TO_PIXEL(sx2);
+ int temp;
+
+ if (x1 > x2) temp = x1, x1 = x2, x2 = temp;
+ if (x1 < ir_xmin) x1 = ir_xmin;
+ if (x2 >= ir_xmax) x2 = ir_xmax - 1;
+ if (x1 < x2)
+ fill_hline(x1 + 1, x2, sy, color);
+ }
+ sy++;
+
+ if (sy > ey)
+ {
+ word1 = (INT16)combase16[spnt];
+ ey = combase16[spnt+1];
+ if (word1 == -1 && ey == 0xFFFF)
+ break;
+ ey = ROUND_TO_PIXEL(ey);
+ spnt+=2;
+ }
+ else
+ sx += word1;
+
+ if (sy > ey2)
+ {
+ word2 = (INT16)combase16[spnt2];
+ ey2 = ROUND_TO_PIXEL(combase16[spnt2+1]);
+ spnt2+=2;
+ }
+ else
+ sx2 += word2;
+
+ } //while polygon
+ }//if at least 2 sides
+ } //if polygon
+ } //while object
+}
+
+
+
+VIDEO_UPDATE( irobot )
+{
+ UINT8 *bitmap_base = irobot_bufsel ? polybitmap1 : polybitmap2;
+ int x, y, offs;
+
+ /* copy the polygon bitmap */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ draw_scanline8(bitmap, 0, y, BITMAP_WIDTH, &bitmap_base[y * BITMAP_WIDTH], machine->pens, -1);
+
+ /* redraw the non-zero characters in the alpha layer */
+ for (y = offs = 0; y < 32; y++)
+ for (x = 0; x < 32; x++, offs++)
+ if (videoram[offs] != 0)
+ {
+ int code = videoram[offs] & 0x3f;
+ int color = ((videoram[offs] & 0xC0) >> 6) | (irobot_alphamap >> 3);
+ int transp=color + 64;
+
+ drawgfx(bitmap,machine->gfx[0],
+ code, color,
+ 0,0,
+ 8*x,8*y,
+ cliprect,TRANSPARENCY_COLOR,transp);
+ }
+ return 0;
+}
diff --git a/src/mame/video/ironhors.c b/src/mame/video/ironhors.c
new file mode 100644
index 00000000000..8824025bdc4
--- /dev/null
+++ b/src/mame/video/ironhors.c
@@ -0,0 +1,262 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *ironhors_scroll;
+static int palettebank, charbank, spriterambank;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Iron Horse has three 256x4 palette PROMs (one per gun) and two 256x4
+ lookup table PROMs (one for characters, one for sprites).
+ I don't know for sure how the palette PROMs are connected to the RGB
+ output, but it's probably the usual:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+PALETTE_INIT( ironhors )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the character lookup table */
+
+
+ /* there are eight 32 colors palette banks; sprites use colors 0-15 and */
+ /* characters 16-31 of each bank. */
+ for (i = 0;i < TOTAL_COLORS(0)/8;i++)
+ {
+ int j;
+
+
+ for (j = 0;j < 8;j++)
+ COLOR(0,i + j * TOTAL_COLORS(0)/8) = (*color_prom & 0x0f) + 32 * j + 16;
+
+ color_prom++;
+ }
+
+ for (i = 0;i < TOTAL_COLORS(1)/8;i++)
+ {
+ int j;
+
+
+ for (j = 0;j < 8;j++)
+ COLOR(1,i + j * TOTAL_COLORS(1)/8) = (*color_prom & 0x0f) + 32 * j;
+
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( ironhors_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( ironhors_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( ironhors_charbank_w )
+{
+ if (charbank != (data & 0x03))
+ {
+ charbank = data & 0x03;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ spriterambank = data & 0x08;
+
+ /* other bits unknown */
+}
+
+WRITE8_HANDLER( ironhors_palettebank_w )
+{
+ if (palettebank != (data & 0x07))
+ {
+ palettebank = data & 0x07;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ coin_counter_w(0, data & 0x10);
+ coin_counter_w(1, data & 0x20);
+
+ /* bit 6 unknown - set after game over */
+
+ if (data & 0x88) popmessage("ironhors_palettebank_w %02x",data);
+}
+
+WRITE8_HANDLER( ironhors_flipscreen_w )
+{
+ if (flip_screen != (~data & 0x08))
+ {
+ flip_screen_set(~data & 0x08);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ /* other bits are used too, but unknown */
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + ((colorram[tile_index] & 0x40) << 2) +
+ ((colorram[tile_index] & 0x20) << 4) + (charbank << 10);
+ int color = (colorram[tile_index] & 0x0f) + 16 * palettebank;
+ int flags = ((colorram[tile_index] & 0x10) ? TILE_FLIPX : 0) |
+ ((colorram[tile_index] & 0x20) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( ironhors )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_scroll_rows(bg_tilemap, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+ UINT8 *sr;
+
+ if (spriterambank != 0)
+ sr = spriteram;
+ else
+ sr = spriteram_2;
+
+ for (offs = 0;offs < spriteram_size;offs += 5)
+ {
+ int sx = sr[offs+3];
+ int sy = sr[offs+2];
+ int flipx = sr[offs+4] & 0x20;
+ int flipy = sr[offs+4] & 0x40;
+ int code = (sr[offs] << 2) + ((sr[offs+1] & 0x03) << 10) + ((sr[offs+1] & 0x0c) >> 2);
+ int color = ((sr[offs+1] & 0xf0)>>4) + 16 * palettebank;
+ // int mod = flip_screen ? -8 : 8;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ switch (sr[offs+4] & 0x0c)
+ {
+ case 0x00: /* 16x16 */
+ drawgfx(bitmap,machine->gfx[1],
+ code/4,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ break;
+
+ case 0x04: /* 16x8 */
+ {
+ if (flip_screen) sy += 8; // this fixes the train wheels' position
+
+ drawgfx(bitmap,machine->gfx[2],
+ code & ~1,
+ color,
+ flipx,flipy,
+ flipx?sx+8:sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[2],
+ code | 1,
+ color,
+ flipx,flipy,
+ flipx?sx:sx+8,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ break;
+
+ case 0x08: /* 8x16 */
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ code & ~2,
+ color,
+ flipx,flipy,
+ sx,flipy?sy+8:sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[2],
+ code | 2,
+ color,
+ flipx,flipy,
+ sx,flipy?sy:sy+8,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ break;
+
+ case 0x0c: /* 8x8 */
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ break;
+ }
+ }
+}
+
+VIDEO_UPDATE( ironhors )
+{
+ int row;
+
+ for (row = 0; row < 32; row++)
+ tilemap_set_scrollx(bg_tilemap, row, ironhors_scroll[row]);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/itech32.c b/src/mame/video/itech32.c
new file mode 100644
index 00000000000..4e00bae7b32
--- /dev/null
+++ b/src/mame/video/itech32.c
@@ -0,0 +1,1486 @@
+/***************************************************************************
+
+ Incredible Technologies/Strata system
+ (32-bit blitter variant)
+
+***************************************************************************/
+
+#include "driver.h"
+#include "profiler.h"
+#include "cpu/m68000/m68000.h"
+#include "itech32.h"
+
+
+/*************************************
+ *
+ * Debugging
+ *
+ *************************************/
+
+#define BLIT_LOGGING 0
+
+
+
+/*************************************
+ *
+ * Blitter constants
+ *
+ *************************************/
+
+#define VIDEO_UNKNOWN00 itech32_video[0x00/2] /* $0087 at startup */
+#define VIDEO_STATUS itech32_video[0x00/2]
+#define VIDEO_INTSTATE itech32_video[0x02/2]
+#define VIDEO_INTACK itech32_video[0x02/2]
+#define VIDEO_TRANSFER itech32_video[0x04/2]
+#define VIDEO_TRANSFER_FLAGS itech32_video[0x06/2] /* $5080 at startup (kept at $1512) */
+#define VIDEO_COMMAND itech32_video[0x08/2] /* $0005 at startup */
+#define VIDEO_INTENABLE itech32_video[0x0a/2] /* $0144 at startup (kept at $1514) */
+#define VIDEO_TRANSFER_HEIGHT itech32_video[0x0c/2]
+#define VIDEO_TRANSFER_WIDTH itech32_video[0x0e/2]
+#define VIDEO_TRANSFER_ADDRLO itech32_video[0x10/2]
+#define VIDEO_TRANSFER_X itech32_video[0x12/2]
+#define VIDEO_TRANSFER_Y itech32_video[0x14/2]
+#define VIDEO_SRC_YSTEP itech32_video[0x16/2] /* $0011 at startup */
+#define VIDEO_SRC_XSTEP itech32_video[0x18/2]
+#define VIDEO_DST_XSTEP itech32_video[0x1a/2]
+#define VIDEO_DST_YSTEP itech32_video[0x1c/2]
+#define VIDEO_YSTEP_PER_X itech32_video[0x1e/2]
+#define VIDEO_XSTEP_PER_Y itech32_video[0x20/2]
+#define VIDEO_UNKNOWN22 itech32_video[0x22/2] /* $0033 at startup */
+#define VIDEO_LEFTCLIP itech32_video[0x24/2]
+#define VIDEO_RIGHTCLIP itech32_video[0x26/2]
+#define VIDEO_TOPCLIP itech32_video[0x28/2]
+#define VIDEO_BOTTOMCLIP itech32_video[0x2a/2]
+#define VIDEO_INTSCANLINE itech32_video[0x2c/2] /* $00ef at startup */
+#define VIDEO_TRANSFER_ADDRHI itech32_video[0x2e/2] /* $0000 at startup */
+
+#define VIDEO_UNKNOWN30 itech32_video[0x30/2] /* $0040 at startup */
+#define VIDEO_VTOTAL itech32_video[0x32/2] /* $0106 at startup */
+#define VIDEO_VSYNC itech32_video[0x34/2] /* $0101 at startup */
+#define VIDEO_VBLANK_START itech32_video[0x36/2] /* $00f3 at startup */
+#define VIDEO_VBLANK_END itech32_video[0x38/2] /* $0003 at startup */
+#define VIDEO_HTOTAL itech32_video[0x3a/2] /* $01fc at startup */
+#define VIDEO_HSYNC itech32_video[0x3c/2] /* $01e4 at startup */
+#define VIDEO_HBLANK_START itech32_video[0x3e/2] /* $01b2 at startup */
+#define VIDEO_HBLANK_END itech32_video[0x40/2] /* $0032 at startup */
+#define VIDEO_UNKNOWN42 itech32_video[0x42/2] /* $0015 at startup */
+#define VIDEO_DISPLAY_YORIGIN1 itech32_video[0x44/2] /* $0000 at startup */
+#define VIDEO_DISPLAY_YORIGIN2 itech32_video[0x46/2] /* $0000 at startup */
+#define VIDEO_DISPLAY_YSCROLL2 itech32_video[0x48/2] /* $0000 at startup */
+#define VIDEO_UNKNOWN4a itech32_video[0x4a/2] /* $0000 at startup */
+#define VIDEO_DISPLAY_XORIGIN1 itech32_video[0x4c/2] /* $0000 at startup */
+#define VIDEO_DISPLAY_XORIGIN2 itech32_video[0x4e/2] /* $0000 at startup */
+#define VIDEO_DISPLAY_XSCROLL2 itech32_video[0x50/2] /* $0000 at startup */
+#define VIDEO_UNKNOWN52 itech32_video[0x52/2] /* $0000 at startup */
+#define VIDEO_UNKNOWN54 itech32_video[0x54/2] /* $0080 at startup */
+#define VIDEO_UNKNOWN56 itech32_video[0x56/2] /* $00c0 at startup */
+#define VIDEO_UNKNOWN58 itech32_video[0x58/2] /* $01c0 at startup */
+#define VIDEO_UNKNOWN5a itech32_video[0x5a/2] /* $01c0 at startup */
+#define VIDEO_UNKNOWN5c itech32_video[0x5c/2] /* $01cf at startup */
+#define VIDEO_UNKNOWN5e itech32_video[0x5e/2] /* $01cf at startup */
+#define VIDEO_UNKNOWN60 itech32_video[0x60/2] /* $01e3 at startup */
+#define VIDEO_UNKNOWN62 itech32_video[0x62/2] /* $01cf at startup */
+#define VIDEO_UNKNOWN64 itech32_video[0x64/2] /* $01ff at startup */
+#define VIDEO_UNKNOWN66 itech32_video[0x66/2] /* $0183 at startup */
+#define VIDEO_UNKNOWN68 itech32_video[0x68/2] /* $01ff at startup */
+#define VIDEO_UNKNOWN6a itech32_video[0x6a/2] /* $000f at startup */
+#define VIDEO_UNKNOWN6c itech32_video[0x6c/2] /* $018f at startup */
+#define VIDEO_UNKNOWN6e itech32_video[0x6e/2] /* $01ff at startup */
+#define VIDEO_UNKNOWN70 itech32_video[0x70/2] /* $000f at startup */
+#define VIDEO_UNKNOWN72 itech32_video[0x72/2] /* $000f at startup */
+#define VIDEO_UNKNOWN74 itech32_video[0x74/2] /* $01ff at startup */
+#define VIDEO_UNKNOWN76 itech32_video[0x76/2] /* $01ff at startup */
+#define VIDEO_UNKNOWN78 itech32_video[0x78/2] /* $01ff at startup */
+#define VIDEO_UNKNOWN7a itech32_video[0x7a/2] /* $01ff at startup */
+#define VIDEO_UNKNOWN7c itech32_video[0x7c/2] /* $0820 at startup */
+#define VIDEO_UNKNOWN7e itech32_video[0x7e/2] /* $0100 at startup */
+
+#define VIDEO_STARTSTEP itech32_video[0x80/2] /* drivedge only? */
+#define VIDEO_LEFTSTEPLO itech32_video[0x82/2] /* drivedge only? */
+#define VIDEO_LEFTSTEPHI itech32_video[0x84/2] /* drivedge only? */
+#define VIDEO_RIGHTSTEPLO itech32_video[0x86/2] /* drivedge only? */
+#define VIDEO_RIGHTSTEPHI itech32_video[0x88/2] /* drivedge only? */
+
+#define VIDEOINT_SCANLINE 0x0004
+#define VIDEOINT_BLITTER 0x0040
+
+#define XFERFLAG_TRANSPARENT 0x0001
+#define XFERFLAG_XFLIP 0x0002
+#define XFERFLAG_YFLIP 0x0004
+#define XFERFLAG_DSTXSCALE 0x0008
+#define XFERFLAG_DYDXSIGN 0x0010
+#define XFERFLAG_DXDYSIGN 0x0020
+#define XFERFLAG_UNKNOWN8 0x0100
+#define XFERFLAG_CLIP 0x0400
+#define XFERFLAG_UNKNOWN15 0x8000
+
+#define XFERFLAG_KNOWNFLAGS (XFERFLAG_TRANSPARENT | XFERFLAG_XFLIP | XFERFLAG_YFLIP | XFERFLAG_DSTXSCALE | XFERFLAG_DYDXSIGN | XFERFLAG_DXDYSIGN | XFERFLAG_CLIP)
+
+#define VRAM_WIDTH 512
+
+
+
+/*************************************
+ *
+ * Global variables
+ *
+ *************************************/
+
+UINT16 *itech32_video;
+UINT32 *drivedge_zbuf_control;
+UINT8 itech32_planes;
+UINT16 itech32_vram_height;
+
+static UINT16 xfer_xcount, xfer_ycount;
+static UINT16 xfer_xcur, xfer_ycur;
+
+static rectangle clip_rect, scaled_clip_rect;
+static rectangle clip_save;
+
+static emu_timer *scanline_timer;
+
+static UINT8 *grom_base;
+static UINT32 grom_size;
+static UINT32 grom_bank;
+static UINT32 grom_bank_mask;
+
+static UINT16 color_latch[2];
+static UINT8 enable_latch[2];
+
+static UINT16 *videoplane[2];
+static UINT32 vram_mask;
+static UINT32 vram_xmask, vram_ymask;
+
+static int is_drivedge;
+
+static TIMER_CALLBACK( scanline_interrupt );
+
+
+
+/*************************************
+ *
+ * Macros and inlines
+ *
+ *************************************/
+
+#define ADJUSTED_HEIGHT(x) ((((x) >> 1) & 0x100) | ((x) & 0xff))
+
+INLINE offs_t compute_safe_address(int x, int y)
+{
+ return ((y & vram_ymask) * 512) + (x & vram_xmask);
+}
+
+INLINE void disable_clipping(void)
+{
+ clip_save = clip_rect;
+
+ clip_rect.min_x = clip_rect.min_y = 0;
+ clip_rect.max_x = clip_rect.max_y = 0xfff;
+
+ scaled_clip_rect.min_x = scaled_clip_rect.min_y = 0;
+ scaled_clip_rect.max_x = scaled_clip_rect.max_y = 0xfff << 8;
+}
+
+INLINE void enable_clipping(void)
+{
+ clip_rect = clip_save;
+
+ scaled_clip_rect.min_x = clip_rect.min_x << 8;
+ scaled_clip_rect.max_x = clip_rect.max_x << 8;
+ scaled_clip_rect.min_y = clip_rect.min_y << 8;
+ scaled_clip_rect.max_y = clip_rect.max_y << 8;
+}
+
+
+
+/*************************************
+ *
+ * Video start
+ *
+ *************************************/
+
+VIDEO_START( itech32 )
+{
+ int i;
+
+ /* allocate memory */
+ videoram16 = auto_malloc(VRAM_WIDTH * (itech32_vram_height + 16) * 2 * 2);
+ memset(videoram16, 0xff, VRAM_WIDTH * (itech32_vram_height + 16) * 2 * 2);
+
+ /* videoplane[0] is the foreground; videoplane[1] is the background */
+ videoplane[0] = &videoram16[0 * VRAM_WIDTH * (itech32_vram_height + 16) + 8 * VRAM_WIDTH];
+ videoplane[1] = &videoram16[1 * VRAM_WIDTH * (itech32_vram_height + 16) + 8 * VRAM_WIDTH];
+
+ /* set the masks */
+ vram_mask = VRAM_WIDTH * itech32_vram_height - 1;
+ vram_xmask = VRAM_WIDTH - 1;
+ vram_ymask = itech32_vram_height - 1;
+
+ /* clear the planes initially */
+ for (i = 0; i < VRAM_WIDTH * itech32_vram_height; i++)
+ videoplane[0][i] = videoplane[1][i] = 0xff;
+
+ /* fetch the GROM base */
+ grom_base = memory_region(REGION_GFX1);
+ grom_size = memory_region_length(REGION_GFX1);
+ grom_bank = 0;
+ grom_bank_mask = grom_size >> 24;
+ if (grom_bank_mask == 2)
+ grom_bank_mask = 3;
+
+ /* reset statics */
+ memset(itech32_video, 0, 0x80);
+
+ scanline_timer = timer_alloc(scanline_interrupt);
+ enable_latch[0] = 1;
+ enable_latch[1] = (itech32_planes > 1) ? 1 : 0;
+
+ is_drivedge = 0;
+}
+
+
+
+/*************************************
+ *
+ * Latches
+ *
+ *************************************/
+
+WRITE16_HANDLER( timekill_colora_w )
+{
+ if (ACCESSING_LSB)
+ {
+ enable_latch[0] = (~data >> 5) & 1;
+ enable_latch[1] = (~data >> 7) & 1;
+ color_latch[0] = (data & 0x0f) << 8;
+ }
+}
+
+
+WRITE16_HANDLER( timekill_colorbc_w )
+{
+ if (ACCESSING_LSB)
+ color_latch[1] = ((data & 0xf0) << 4) | 0x1000;
+}
+
+
+WRITE16_HANDLER( timekill_intensity_w )
+{
+ if (ACCESSING_LSB)
+ {
+ double intensity = (double)(data & 0xff) / (double)0x60;
+ int i;
+ for (i = 0; i < 8192; i++)
+ palette_set_brightness(Machine, i, intensity);
+ }
+}
+
+
+WRITE16_HANDLER( bloodstm_color1_w )
+{
+ if (ACCESSING_LSB)
+ color_latch[0] = (data & 0x7f) << 8;
+}
+
+
+WRITE16_HANDLER( bloodstm_color2_w )
+{
+ if (ACCESSING_LSB)
+ color_latch[1] = (data & 0x7f) << 8;
+}
+
+
+WRITE16_HANDLER( bloodstm_plane_w )
+{
+ if (ACCESSING_LSB)
+ {
+ enable_latch[0] = (~data >> 1) & 1;
+ enable_latch[1] = (~data >> 2) & 1;
+ }
+}
+
+
+WRITE32_HANDLER( drivedge_color0_w )
+{
+ if (!(mem_mask & 0x00ff0000))
+ color_latch[0] = ((data >> 16) & 0x7f) << 8;
+}
+
+
+WRITE32_HANDLER( itech020_color1_w )
+{
+ if (ACCESSING_LSB32)
+ color_latch[1] = (data & 0x7f) << 8;
+}
+
+
+WRITE32_HANDLER( itech020_color2_w )
+{
+ if (ACCESSING_LSB32)
+ color_latch[0] = (data & 0x7f) << 8;
+}
+
+
+WRITE32_HANDLER( itech020_plane_w )
+{
+ if (!(mem_mask & 0x0000ff00))
+ {
+ enable_latch[0] = (~data >> 9) & 1;
+ enable_latch[1] = (~data >> 10) & 1;
+ grom_bank = ((data >> 14) & grom_bank_mask) << 24;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Palette I/O
+ *
+ *************************************/
+
+WRITE16_HANDLER( timekill_paletteram_w )
+{
+ int r, g, b;
+
+ COMBINE_DATA(&paletteram16[offset]);
+
+ r = paletteram16[offset & ~1] & 0xff;
+ g = paletteram16[offset & ~1] >> 8;
+ b = paletteram16[offset | 1] >> 8;
+
+ palette_set_color(Machine, offset / 2, MAKE_RGB(r, g, b));
+}
+
+
+WRITE16_HANDLER( bloodstm_paletteram_w )
+{
+ int r, g, b;
+
+ /* in test mode, the LSB is used; in game mode, the MSB is used */
+ if (!ACCESSING_LSB && (offset & 1))
+ data >>= 8, mem_mask >>= 8;
+ COMBINE_DATA(&paletteram16[offset]);
+
+ r = paletteram16[offset & ~1] & 0xff;
+ g = paletteram16[offset & ~1] >> 8;
+ b = paletteram16[offset | 1] & 0xff;
+
+ palette_set_color(Machine, offset / 2, MAKE_RGB(r, g, b));
+}
+
+
+WRITE32_HANDLER( drivedge_paletteram_w )
+{
+ int r, g, b;
+
+ COMBINE_DATA(&paletteram32[offset]);
+
+ r = paletteram32[offset] & 0xff;
+ g = (paletteram32[offset] >> 8) & 0xff;
+ b = (paletteram32[offset] >> 16) & 0xff;
+
+ palette_set_color(Machine, offset, MAKE_RGB(r, g, b));
+}
+
+
+WRITE32_HANDLER( itech020_paletteram_w )
+{
+ int r, g, b;
+
+ COMBINE_DATA(&paletteram32[offset]);
+
+ r = (paletteram32[offset] >> 16) & 0xff;
+ g = (paletteram32[offset] >> 8) & 0xff;
+ b = paletteram32[offset] & 0xff;
+
+ palette_set_color(Machine, offset, MAKE_RGB(r, g, b));
+}
+
+
+
+/*************************************
+ *
+ * Debugging
+ *
+ *************************************/
+
+static void logblit(const char *tag)
+{
+ if (!input_code_pressed(KEYCODE_L))
+ return;
+ if (is_drivedge && VIDEO_TRANSFER_FLAGS == 0x5490)
+ {
+ /* polygon drawing */
+ logerror("%s: e=%d%d f=%04x s=(%03x-%03x,%03x) w=%03x h=%03x b=%02x%04x c=%02x%02x ss=%04x,%04x ds=%04x,%04x ls=%04x%04x rs=%04x%04x u80=%04x", tag,
+ enable_latch[0], enable_latch[1],
+ VIDEO_TRANSFER_FLAGS,
+ VIDEO_TRANSFER_X, VIDEO_RIGHTCLIP, VIDEO_TRANSFER_Y, VIDEO_TRANSFER_WIDTH, VIDEO_TRANSFER_HEIGHT,
+ VIDEO_TRANSFER_ADDRHI, VIDEO_TRANSFER_ADDRLO,
+ color_latch[0] >> 8, color_latch[1] >> 8,
+ VIDEO_SRC_XSTEP, VIDEO_SRC_YSTEP,
+ VIDEO_DST_XSTEP, VIDEO_DST_YSTEP,
+ VIDEO_LEFTSTEPHI, VIDEO_LEFTSTEPLO, VIDEO_RIGHTSTEPHI, VIDEO_RIGHTSTEPLO,
+ VIDEO_STARTSTEP);
+ }
+
+ else if (itech32_video[0x16/2] == 0x100 && itech32_video[0x18/2] == 0x100 &&
+ itech32_video[0x1a/2] == 0x000 && itech32_video[0x1c/2] == 0x100 &&
+ itech32_video[0x1e/2] == 0x000 && itech32_video[0x20/2] == 0x000)
+ {
+ logerror("%s: e=%d%d f=%04x c=%02x%02x %02x%04x -> (%03x,%03x) %3dx%3dc=(%03x,%03x)-(%03x,%03x)", tag,
+ enable_latch[0], enable_latch[1],
+ VIDEO_TRANSFER_FLAGS,
+ color_latch[0] >> 8, color_latch[1] >> 8,
+ VIDEO_TRANSFER_ADDRHI, VIDEO_TRANSFER_ADDRLO,
+ VIDEO_TRANSFER_X, VIDEO_TRANSFER_Y,
+ VIDEO_TRANSFER_WIDTH, ADJUSTED_HEIGHT(VIDEO_TRANSFER_HEIGHT),
+ VIDEO_LEFTCLIP, VIDEO_TOPCLIP, VIDEO_RIGHTCLIP, VIDEO_BOTTOMCLIP);
+ }
+ else
+ {
+ logerror("%s: e=%d%d f=%04x c=%02x%02x %02x%04x -> (%03x,%03x) %3dx%3d c=(%03x,%03x)-(%03x,%03x) s=%04x %04x %04x %04x %04x %04x", tag,
+ enable_latch[0], enable_latch[1],
+ VIDEO_TRANSFER_FLAGS,
+ color_latch[0] >> 8, color_latch[1] >> 8,
+ VIDEO_TRANSFER_ADDRHI, VIDEO_TRANSFER_ADDRLO,
+ VIDEO_TRANSFER_X, VIDEO_TRANSFER_Y,
+ VIDEO_TRANSFER_WIDTH, ADJUSTED_HEIGHT(VIDEO_TRANSFER_HEIGHT),
+ VIDEO_LEFTCLIP, VIDEO_TOPCLIP, VIDEO_RIGHTCLIP, VIDEO_BOTTOMCLIP,
+ itech32_video[0x16/2], itech32_video[0x18/2], itech32_video[0x1a/2],
+ itech32_video[0x1c/2], itech32_video[0x1e/2], itech32_video[0x20/2]);
+ }
+ if (is_drivedge) logerror(" v0=%08x v1=%08x v2=%08x v3=%08x", drivedge_zbuf_control[0], drivedge_zbuf_control[1], drivedge_zbuf_control[2], drivedge_zbuf_control[3]);
+ logerror("\n");
+}
+
+
+
+/*************************************
+ *
+ * Video interrupts
+ *
+ *************************************/
+
+static void update_interrupts(int fast)
+{
+ int scanline_state = 0, blitter_state = 0;
+
+ if (VIDEO_INTSTATE & VIDEO_INTENABLE & VIDEOINT_SCANLINE)
+ scanline_state = 1;
+ if (VIDEO_INTSTATE & VIDEO_INTENABLE & VIDEOINT_BLITTER)
+ blitter_state = 1;
+
+ itech32_update_interrupts(-1, blitter_state, scanline_state);
+}
+
+
+static TIMER_CALLBACK( scanline_interrupt )
+{
+ /* set timer for next frame */
+ timer_adjust(scanline_timer, video_screen_get_time_until_pos(0, VIDEO_INTSCANLINE, 0), 0, attotime_zero);
+
+ /* set the interrupt bit in the status reg */
+ logerror("-------------- (DISPLAY INT @ %d) ----------------\n", video_screen_get_vpos(0));
+ VIDEO_INTSTATE |= VIDEOINT_SCANLINE;
+
+ /* update the interrupt state */
+ update_interrupts(0);
+}
+
+
+
+/*************************************
+ *
+ * Uncompressed blitter functions
+ *
+ *************************************/
+
+static void draw_raw(UINT16 *base, UINT16 color)
+{
+ UINT8 *src = &grom_base[(grom_bank | ((VIDEO_TRANSFER_ADDRHI & 0xff) << 16) | VIDEO_TRANSFER_ADDRLO) % grom_size];
+ int transparent_pen = (VIDEO_TRANSFER_FLAGS & XFERFLAG_TRANSPARENT) ? 0xff : -1;
+ int width = VIDEO_TRANSFER_WIDTH << 8;
+ int height = ADJUSTED_HEIGHT(VIDEO_TRANSFER_HEIGHT) << 8;
+ int xsrcstep = VIDEO_SRC_XSTEP;
+ int ysrcstep = VIDEO_SRC_YSTEP;
+ int sx, sy = (VIDEO_TRANSFER_Y & 0xfff) << 8;
+ int startx = (VIDEO_TRANSFER_X & 0xfff) << 8;
+ int xdststep = 0x100;
+ int ydststep = VIDEO_DST_YSTEP;
+ int x, y;
+
+ /* adjust for (lack of) clipping */
+ if (!(VIDEO_TRANSFER_FLAGS & XFERFLAG_CLIP))
+ disable_clipping();
+
+ /* adjust for scaling */
+ if (VIDEO_TRANSFER_FLAGS & XFERFLAG_DSTXSCALE)
+ xdststep = VIDEO_DST_XSTEP;
+
+ /* adjust for flipping */
+ if (VIDEO_TRANSFER_FLAGS & XFERFLAG_XFLIP)
+ xdststep = -xdststep;
+ if (VIDEO_TRANSFER_FLAGS & XFERFLAG_YFLIP)
+ ydststep = -ydststep;
+
+ /* loop over Y in src pixels */
+ for (y = 0; y < height; y += ysrcstep, sy += ydststep)
+ {
+ UINT8 *rowsrc = &src[(y >> 8) * (width >> 8)];
+
+ /* simpler case: VIDEO_YSTEP_PER_X is zero */
+ if (VIDEO_YSTEP_PER_X == 0)
+ {
+ /* clip in the Y direction */
+ if (sy >= scaled_clip_rect.min_y && sy < scaled_clip_rect.max_y)
+ {
+ UINT32 dstoffs;
+
+ /* direction matters here */
+ sx = startx;
+ if (xdststep > 0)
+ {
+ /* skip left pixels */
+ for (x = 0; x < width && sx < scaled_clip_rect.min_x; x += xsrcstep, sx += xdststep) ;
+
+ /* compute the address */
+ dstoffs = compute_safe_address(sx >> 8, sy >> 8) - (sx >> 8);
+
+ /* render middle pixels */
+ for ( ; x < width && sx < scaled_clip_rect.max_x; x += xsrcstep, sx += xdststep)
+ {
+ int pixel = rowsrc[x >> 8];
+ if (pixel != transparent_pen)
+ base[(dstoffs + (sx >> 8)) & vram_mask] = pixel | color;
+ }
+ }
+ else
+ {
+ /* skip right pixels */
+ for (x = 0; x < width && sx >= scaled_clip_rect.max_x; x += xsrcstep, sx += xdststep) ;
+
+ /* compute the address */
+ dstoffs = compute_safe_address(sx >> 8, sy >> 8) - (sx >> 8);
+
+ /* render middle pixels */
+ for ( ; x < width && sx >= scaled_clip_rect.min_x; x += xsrcstep, sx += xdststep)
+ {
+ int pixel = rowsrc[x >> 8];
+ if (pixel != transparent_pen)
+ base[(dstoffs + (sx >> 8)) & vram_mask] = pixel | color;
+ }
+ }
+ }
+ }
+
+ /* slow case: VIDEO_YSTEP_PER_X is non-zero */
+ else
+ {
+ int ystep = (VIDEO_TRANSFER_FLAGS & XFERFLAG_DYDXSIGN) ? -VIDEO_YSTEP_PER_X : VIDEO_YSTEP_PER_X;
+ int ty = sy;
+
+ /* render all pixels */
+ sx = startx;
+ for (x = 0; x < width && sx < scaled_clip_rect.max_x; x += xsrcstep, sx += xdststep, ty += ystep)
+ if (ty >= scaled_clip_rect.min_y && ty < scaled_clip_rect.max_y &&
+ sx >= scaled_clip_rect.min_x && sx < scaled_clip_rect.max_x)
+ {
+ int pixel = rowsrc[x >> 8];
+ if (pixel != transparent_pen)
+ base[compute_safe_address(sx >> 8, ty >> 8)] = pixel | color;
+ }
+ }
+
+ /* apply skew */
+ if (VIDEO_TRANSFER_FLAGS & XFERFLAG_DXDYSIGN)
+ startx += VIDEO_XSTEP_PER_Y;
+ else
+ startx -= VIDEO_XSTEP_PER_Y;
+ }
+
+ /* restore cliprects */
+ if (!(VIDEO_TRANSFER_FLAGS & XFERFLAG_CLIP))
+ enable_clipping();
+}
+
+
+static void draw_raw_drivedge(UINT16 *base, UINT16 *zbase, UINT16 color)
+{
+ UINT8 *src = &grom_base[(grom_bank | ((VIDEO_TRANSFER_ADDRHI & 0xff) << 16) | VIDEO_TRANSFER_ADDRLO) % grom_size];
+ int transparent_pen = (VIDEO_TRANSFER_FLAGS & XFERFLAG_TRANSPARENT) ? 0xff : -1;
+ int width = VIDEO_TRANSFER_WIDTH << 8;
+ int height = ADJUSTED_HEIGHT(VIDEO_TRANSFER_HEIGHT) << 8;
+ int xsrcstep = VIDEO_SRC_XSTEP;
+ int ysrcstep = VIDEO_SRC_YSTEP;
+ int sx, sy = ((VIDEO_TRANSFER_Y & 0xfff) << 8) + 0x80;
+ int startx = ((VIDEO_TRANSFER_X & 0xfff) << 8) + 0x80;
+ int xdststep = 0x100;
+ int ydststep = VIDEO_DST_YSTEP;
+ INT32 z0 = drivedge_zbuf_control[2] & 0x7ff00;
+ INT32 zmatch = (drivedge_zbuf_control[2] & 0x1f) << 11;
+ INT32 srcdelta = 0;
+ int x, y;
+
+ /* adjust for (lack of) clipping */
+ if (!(VIDEO_TRANSFER_FLAGS & XFERFLAG_CLIP))
+ disable_clipping();
+
+ /* adjust for scaling */
+ if (VIDEO_TRANSFER_FLAGS & XFERFLAG_DSTXSCALE)
+ xdststep = VIDEO_DST_XSTEP;
+
+ /* adjust for flipping */
+ if (VIDEO_TRANSFER_FLAGS & XFERFLAG_XFLIP)
+ xdststep = -xdststep;
+ if (VIDEO_TRANSFER_FLAGS & XFERFLAG_YFLIP)
+ ydststep = -ydststep;
+
+ /* loop over Y in src pixels */
+ for (y = 0; y < height; y += ysrcstep, sy += ydststep)
+ {
+ UINT8 *rowsrc = src + (srcdelta >> 8);
+
+ /* in the polygon case, we don't factor in the Y */
+ if (VIDEO_TRANSFER_FLAGS != 0x5490)
+ rowsrc += (y >> 8) * (width >> 8);
+ else
+ width = 1000 << 8;
+
+ /* simpler case: VIDEO_YSTEP_PER_X is zero */
+ if (VIDEO_YSTEP_PER_X == 0)
+ {
+ /* clip in the Y direction */
+ if (sy >= scaled_clip_rect.min_y && sy < scaled_clip_rect.max_y)
+ {
+ UINT32 dstoffs, zbufoffs;
+ INT32 z = z0;
+
+ /* direction matters here */
+ sx = startx;
+ if (xdststep > 0)
+ {
+ /* skip left pixels */
+ for (x = 0; x < width && sx < scaled_clip_rect.min_x; x += xsrcstep, sx += xdststep)
+ z += (INT32)drivedge_zbuf_control[0];
+
+ /* compute the address */
+ dstoffs = compute_safe_address(sx >> 8, sy >> 8) - (sx >> 8);
+ zbufoffs = compute_safe_address(sx >> 8, sy >> 8) - (sx >> 8);
+
+ /* render middle pixels */
+ if (drivedge_zbuf_control[3] & 0x8000)
+ {
+ for ( ; x < width && sx < scaled_clip_rect.max_x; x += xsrcstep, sx += xdststep)
+ {
+ int pixel = rowsrc[x >> 8];
+ if (pixel != transparent_pen)
+ {
+ base[(dstoffs + (sx >> 8)) & vram_mask] = pixel | color;
+ zbase[(zbufoffs + (sx >> 8)) & vram_mask] = (z >> 8) | zmatch;
+ }
+ z += (INT32)drivedge_zbuf_control[0];
+ }
+ }
+ else if (drivedge_zbuf_control[3] & 0x4000)
+ {
+ for ( ; x < width && sx < scaled_clip_rect.max_x; x += xsrcstep, sx += xdststep)
+ {
+ int pixel = rowsrc[x >> 8];
+ if (pixel != transparent_pen && zmatch == (zbase[(zbufoffs + (sx >> 8)) & vram_mask] & (0x1f << 11)))
+ base[(dstoffs + (sx >> 8)) & vram_mask] = pixel | color;
+ z += (INT32)drivedge_zbuf_control[0];
+ }
+ }
+ else
+ {
+ for ( ; x < width && sx < scaled_clip_rect.max_x; x += xsrcstep, sx += xdststep)
+ {
+ int pixel = rowsrc[x >> 8];
+ if (pixel != transparent_pen && ((z >> 8) <= (zbase[(zbufoffs + (sx >> 8)) & vram_mask] & 0x7ff)))
+ {
+ base[(dstoffs + (sx >> 8)) & vram_mask] = pixel | color;
+ zbase[(zbufoffs + (sx >> 8)) & vram_mask] = (z >> 8) | zmatch;
+ }
+ z += (INT32)drivedge_zbuf_control[0];
+ }
+ }
+ }
+ else
+ {
+ /* skip right pixels */
+ for (x = 0; x < width && sx >= scaled_clip_rect.max_x; x += xsrcstep, sx += xdststep)
+ z += (INT32)drivedge_zbuf_control[0];
+
+ /* compute the address */
+ dstoffs = compute_safe_address(sx >> 8, sy >> 8) - (sx >> 8);
+ zbufoffs = compute_safe_address(sx >> 8, sy >> 8) - (sx >> 8);
+
+ /* render middle pixels */
+ if (drivedge_zbuf_control[3] & 0x8000)
+ {
+ for ( ; x < width && sx >= scaled_clip_rect.min_x; x += xsrcstep, sx += xdststep)
+ {
+ int pixel = rowsrc[x >> 8];
+ if (pixel != transparent_pen)
+ {
+ base[(dstoffs + (sx >> 8)) & vram_mask] = pixel | color;
+ zbase[(zbufoffs + (sx >> 8)) & vram_mask] = (z >> 8) | zmatch;
+ }
+ z += (INT32)drivedge_zbuf_control[0];
+ }
+ }
+ else if (drivedge_zbuf_control[3] & 0x4000)
+ {
+ for ( ; x < width && sx >= scaled_clip_rect.min_x; x += xsrcstep, sx += xdststep)
+ {
+ int pixel = rowsrc[x >> 8];
+ if (pixel != transparent_pen && zmatch == (zbase[(zbufoffs + (sx >> 8)) & vram_mask] & (0x1f << 11)))
+ base[(dstoffs + (sx >> 8)) & vram_mask] = pixel | color;
+ z += (INT32)drivedge_zbuf_control[0];
+ }
+ }
+ else
+ {
+ for ( ; x < width && sx >= scaled_clip_rect.min_x; x += xsrcstep, sx += xdststep)
+ {
+ int pixel = rowsrc[x >> 8];
+ if (pixel != transparent_pen && ((z >> 8) <= (zbase[(zbufoffs + (sx >> 8)) & vram_mask] & 0x7ff)))
+ {
+ base[(dstoffs + (sx >> 8)) & vram_mask] = pixel | color;
+ zbase[(zbufoffs + (sx >> 8)) & vram_mask] = (z >> 8) | zmatch;
+ }
+ z += (INT32)drivedge_zbuf_control[0];
+ }
+ }
+ }
+ }
+ }
+
+ /* slow case: VIDEO_YSTEP_PER_X is non-zero */
+ else
+ {
+ int ystep = (VIDEO_TRANSFER_FLAGS & XFERFLAG_DYDXSIGN) ? -VIDEO_YSTEP_PER_X : VIDEO_YSTEP_PER_X;
+ int ty = sy;
+ INT32 z = z0;
+
+ /* render all pixels */
+ sx = startx;
+ if (drivedge_zbuf_control[3] & 0x8000)
+ {
+ for (x = 0; x < width && sx < scaled_clip_rect.max_x; x += xsrcstep, sx += xdststep, ty += ystep)
+ if (ty >= scaled_clip_rect.min_y && ty < scaled_clip_rect.max_y &&
+ sx >= scaled_clip_rect.min_x && sx < scaled_clip_rect.max_x)
+ {
+ int pixel = rowsrc[x >> 8];
+ if (pixel != transparent_pen)
+ {
+ base[compute_safe_address(sx >> 8, ty >> 8)] = pixel | color;
+ zbase[compute_safe_address(sx >> 8, ty >> 8)] = (z >> 8) | zmatch;
+ }
+ z += (INT32)drivedge_zbuf_control[0];
+ }
+ }
+ else if (drivedge_zbuf_control[3] & 0x4000)
+ {
+ for (x = 0; x < width && sx < scaled_clip_rect.max_x; x += xsrcstep, sx += xdststep, ty += ystep)
+ if (ty >= scaled_clip_rect.min_y && ty < scaled_clip_rect.max_y &&
+ sx >= scaled_clip_rect.min_x && sx < scaled_clip_rect.max_x)
+ {
+ int pixel = rowsrc[x >> 8];
+ UINT16 *zbuf = &zbase[compute_safe_address(sx >> 8, ty >> 8)];
+ if (pixel != transparent_pen && zmatch == (*zbuf & (0x1f << 11)))
+ {
+ base[compute_safe_address(sx >> 8, ty >> 8)] = pixel | color;
+ *zbuf = (z >> 8) | zmatch;
+ }
+ z += (INT32)drivedge_zbuf_control[0];
+ }
+ }
+ else
+ {
+ for (x = 0; x < width && sx < scaled_clip_rect.max_x; x += xsrcstep, sx += xdststep, ty += ystep)
+ if (ty >= scaled_clip_rect.min_y && ty < scaled_clip_rect.max_y &&
+ sx >= scaled_clip_rect.min_x && sx < scaled_clip_rect.max_x)
+ {
+ int pixel = rowsrc[x >> 8];
+ UINT16 *zbuf = &zbase[compute_safe_address(sx >> 8, ty >> 8)];
+ if (pixel != transparent_pen && ((z >> 8) <= (*zbuf & 0x7ff)))
+ {
+ base[compute_safe_address(sx >> 8, ty >> 8)] = pixel | color;
+ *zbuf = (z >> 8) | zmatch;
+ }
+ z += (INT32)drivedge_zbuf_control[0];
+ }
+ }
+ }
+
+ /* apply skew */
+ if (VIDEO_TRANSFER_FLAGS & XFERFLAG_DXDYSIGN)
+ startx += VIDEO_XSTEP_PER_Y;
+ else
+ startx -= VIDEO_XSTEP_PER_Y;
+
+ /* update the per-scanline parameters */
+ if (VIDEO_TRANSFER_FLAGS == 0x5490)
+ {
+ startx += (INT32)((VIDEO_LEFTSTEPHI << 16) | VIDEO_LEFTSTEPLO);
+ scaled_clip_rect.max_x += (INT32)((VIDEO_RIGHTSTEPHI << 16) | VIDEO_RIGHTSTEPLO);
+ srcdelta += (INT16)VIDEO_STARTSTEP;
+ }
+ z0 += (INT32)drivedge_zbuf_control[1];
+ }
+
+ /* restore cliprects */
+ if (!(VIDEO_TRANSFER_FLAGS & XFERFLAG_CLIP))
+ enable_clipping();
+
+ /* reflect the final values into registers */
+ VIDEO_TRANSFER_X = (VIDEO_TRANSFER_X & ~0xfff) | (startx >> 8);
+ VIDEO_RIGHTCLIP = (VIDEO_RIGHTCLIP & ~0xfff) | (scaled_clip_rect.max_x >> 8);
+ VIDEO_TRANSFER_Y = (VIDEO_TRANSFER_Y & ~0xfff) | ((VIDEO_TRANSFER_Y + (y >> 8)) & 0xfff);
+ VIDEO_TRANSFER_ADDRLO += srcdelta >> 8;
+
+ drivedge_zbuf_control[2] = (drivedge_zbuf_control[2] & ~0x7ff00) | (z0 & 0x7ff00);
+}
+
+
+
+/*************************************
+ *
+ * Compressed blitter macros
+ *
+ *************************************/
+
+#define GET_NEXT_RUN(xleft, count, innercount, src) \
+do { \
+ /* load next RLE chunk if needed */ \
+ if (!count) \
+ { \
+ count = *src++; \
+ val = (count & 0x80) ? -1 : *src++; \
+ count &= 0x7f; \
+ } \
+ \
+ /* determine how much to bite off */ \
+ innercount = (xleft > count) ? count : xleft; \
+ count -= innercount; \
+ xleft -= innercount; \
+} while (0)
+
+
+#define SKIP_RLE(skip, xleft, count, innercount, src)\
+do { \
+ /* scan RLE until done */ \
+ for (xleft = skip; xleft > 0; ) \
+ { \
+ /* load next RLE chunk if needed */ \
+ GET_NEXT_RUN(xleft, count, innercount, src);\
+ \
+ /* skip past the data */ \
+ if (val == -1) src += innercount; \
+ } \
+} while (0)
+
+
+
+/*************************************
+ *
+ * Fast compressed blitter functions
+ *
+ *************************************/
+
+INLINE void draw_rle_fast(UINT16 *base, UINT16 color)
+{
+ UINT8 *src = &grom_base[(grom_bank | ((VIDEO_TRANSFER_ADDRHI & 0xff) << 16) | VIDEO_TRANSFER_ADDRLO) % grom_size];
+ int transparent_pen = (VIDEO_TRANSFER_FLAGS & XFERFLAG_TRANSPARENT) ? 0xff : -1;
+ int width = VIDEO_TRANSFER_WIDTH;
+ int height = ADJUSTED_HEIGHT(VIDEO_TRANSFER_HEIGHT);
+ int sx = VIDEO_TRANSFER_X & 0xfff;
+ int sy = (VIDEO_TRANSFER_Y & 0xfff) << 8;
+ int xleft, y, count = 0, val = 0, innercount;
+ int ydststep = VIDEO_DST_YSTEP;
+ int lclip, rclip;
+
+ /* determine clipping */
+ lclip = clip_rect.min_x - sx;
+ if (lclip < 0) lclip = 0;
+ rclip = sx + width - clip_rect.max_x;
+ if (rclip < 0) rclip = 0;
+ width -= lclip + rclip;
+ sx += lclip;
+
+ /* adjust for flipping */
+ if (VIDEO_TRANSFER_FLAGS & XFERFLAG_YFLIP)
+ ydststep = -ydststep;
+
+ /* loop over Y in src pixels */
+ for (y = 0; y < height; y++, sy += ydststep)
+ {
+ UINT32 dstoffs;
+
+ /* clip in the Y direction */
+ if (sy < scaled_clip_rect.min_y || sy >= scaled_clip_rect.max_y)
+ {
+ SKIP_RLE(width + lclip + rclip, xleft, count, innercount, src);
+ continue;
+ }
+
+ /* compute the address */
+ dstoffs = compute_safe_address(sx, sy >> 8);
+
+ /* left clip */
+ SKIP_RLE(lclip, xleft, count, innercount, src);
+
+ /* loop until gone */
+ for (xleft = width; xleft > 0; )
+ {
+ /* load next RLE chunk if needed */
+ GET_NEXT_RUN(xleft, count, innercount, src);
+
+ /* run of literals */
+ if (val == -1)
+ while (innercount--)
+ {
+ int pixel = *src++;
+ if (pixel != transparent_pen)
+ base[dstoffs & vram_mask] = color | pixel;
+ dstoffs++;
+ }
+
+ /* run of non-transparent repeats */
+ else if (val != transparent_pen)
+ {
+ val |= color;
+ while (innercount--)
+ base[dstoffs++ & vram_mask] = val;
+ }
+
+ /* run of transparent repeats */
+ else
+ dstoffs += innercount;
+ }
+
+ /* right clip */
+ SKIP_RLE(rclip, xleft, count, innercount, src);
+ }
+}
+
+
+INLINE void draw_rle_fast_xflip(UINT16 *base, UINT16 color)
+{
+ UINT8 *src = &grom_base[(grom_bank | ((VIDEO_TRANSFER_ADDRHI & 0xff) << 16) | VIDEO_TRANSFER_ADDRLO) % grom_size];
+ int transparent_pen = (VIDEO_TRANSFER_FLAGS & XFERFLAG_TRANSPARENT) ? 0xff : -1;
+ int width = VIDEO_TRANSFER_WIDTH;
+ int height = ADJUSTED_HEIGHT(VIDEO_TRANSFER_HEIGHT);
+ int sx = VIDEO_TRANSFER_X & 0xfff;
+ int sy = (VIDEO_TRANSFER_Y & 0xfff) << 8;
+ int xleft, y, count = 0, val = 0, innercount;
+ int ydststep = VIDEO_DST_YSTEP;
+ int lclip, rclip;
+
+ /* determine clipping */
+ lclip = sx - clip_rect.max_x;
+ if (lclip < 0) lclip = 0;
+ rclip = clip_rect.min_x - (sx - width);
+ if (rclip < 0) rclip = 0;
+ width -= lclip + rclip;
+ sx -= lclip;
+
+ /* adjust for flipping */
+ if (VIDEO_TRANSFER_FLAGS & XFERFLAG_YFLIP)
+ ydststep = -ydststep;
+
+ /* loop over Y in src pixels */
+ for (y = 0; y < height; y++, sy += ydststep)
+ {
+ UINT32 dstoffs;
+
+ /* clip in the Y direction */
+ if (sy < scaled_clip_rect.min_y || sy >= scaled_clip_rect.max_y)
+ {
+ SKIP_RLE(width + lclip + rclip, xleft, count, innercount, src);
+ continue;
+ }
+
+ /* compute the address */
+ dstoffs = compute_safe_address(sx, sy >> 8);
+
+ /* left clip */
+ SKIP_RLE(lclip, xleft, count, innercount, src);
+
+ /* loop until gone */
+ for (xleft = width; xleft > 0; )
+ {
+ /* load next RLE chunk if needed */
+ GET_NEXT_RUN(xleft, count, innercount, src);
+
+ /* run of literals */
+ if (val == -1)
+ while (innercount--)
+ {
+ int pixel = *src++;
+ if (pixel != transparent_pen)
+ base[dstoffs & vram_mask] = color | pixel;
+ dstoffs--;
+ }
+
+ /* run of non-transparent repeats */
+ else if (val != transparent_pen)
+ {
+ val |= color;
+ while (innercount--)
+ base[dstoffs-- & vram_mask] = val;
+ }
+
+ /* run of transparent repeats */
+ else
+ dstoffs -= innercount;
+ }
+
+ /* right clip */
+ SKIP_RLE(rclip, xleft, count, innercount, src);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Slow compressed blitter functions
+ *
+ *************************************/
+
+INLINE void draw_rle_slow(UINT16 *base, UINT16 color)
+{
+ UINT8 *src = &grom_base[(grom_bank | ((VIDEO_TRANSFER_ADDRHI & 0xff) << 16) | VIDEO_TRANSFER_ADDRLO) % grom_size];
+ int transparent_pen = (VIDEO_TRANSFER_FLAGS & XFERFLAG_TRANSPARENT) ? 0xff : -1;
+ int width = VIDEO_TRANSFER_WIDTH;
+ int height = ADJUSTED_HEIGHT(VIDEO_TRANSFER_HEIGHT);
+ int sx, sy = (VIDEO_TRANSFER_Y & 0xfff) << 8;
+ int xleft, y, count = 0, val = 0, innercount;
+ int xdststep = 0x100;
+ int ydststep = VIDEO_DST_YSTEP;
+ int startx = (VIDEO_TRANSFER_X & 0xfff) << 8;
+
+ /* adjust for scaling */
+ if (VIDEO_TRANSFER_FLAGS & XFERFLAG_DSTXSCALE)
+ xdststep = VIDEO_DST_XSTEP;
+
+ /* adjust for flipping */
+ if (VIDEO_TRANSFER_FLAGS & XFERFLAG_XFLIP)
+ xdststep = -xdststep;
+ if (VIDEO_TRANSFER_FLAGS & XFERFLAG_YFLIP)
+ ydststep = -ydststep;
+
+ /* loop over Y in src pixels */
+ for (y = 0; y < height; y++, sy += ydststep)
+ {
+ UINT32 dstoffs;
+
+ /* clip in the Y direction */
+ if (sy < scaled_clip_rect.min_y || sy >= scaled_clip_rect.max_y)
+ {
+ SKIP_RLE(width, xleft, count, innercount, src);
+ continue;
+ }
+
+ /* compute the address */
+ sx = startx;
+ dstoffs = compute_safe_address(clip_rect.min_x, sy >> 8) - clip_rect.min_x;
+
+ /* loop until gone */
+ for (xleft = width; xleft > 0; )
+ {
+ /* load next RLE chunk if needed */
+ GET_NEXT_RUN(xleft, count, innercount, src);
+
+ /* run of literals */
+ if (val == -1)
+ for ( ; innercount--; sx += xdststep)
+ {
+ int pixel = *src++;
+ if (pixel != transparent_pen)
+ if (sx >= scaled_clip_rect.min_x && sx < scaled_clip_rect.max_x)
+ base[(dstoffs + (sx >> 8)) & vram_mask] = color | pixel;
+ }
+
+ /* run of non-transparent repeats */
+ else if (val != transparent_pen)
+ {
+ val |= color;
+ for ( ; innercount--; sx += xdststep)
+ if (sx >= scaled_clip_rect.min_x && sx < scaled_clip_rect.max_x)
+ base[(dstoffs + (sx >> 8)) & vram_mask] = val;
+ }
+
+ /* run of transparent repeats */
+ else
+ sx += xdststep * innercount;
+ }
+
+ /* apply skew */
+ if (VIDEO_TRANSFER_FLAGS & XFERFLAG_DXDYSIGN)
+ startx += VIDEO_XSTEP_PER_Y;
+ else
+ startx -= VIDEO_XSTEP_PER_Y;
+ }
+}
+
+
+
+static void draw_rle(UINT16 *base, UINT16 color)
+{
+ /* adjust for (lack of) clipping */
+ if (!(VIDEO_TRANSFER_FLAGS & XFERFLAG_CLIP))
+ disable_clipping();
+
+ /* if we have an X scale, draw it slow */
+ if (((VIDEO_TRANSFER_FLAGS & XFERFLAG_DSTXSCALE) && VIDEO_DST_XSTEP != 0x100) || VIDEO_XSTEP_PER_Y)
+ draw_rle_slow(base, color);
+
+ /* else draw it fast */
+ else if (VIDEO_TRANSFER_FLAGS & XFERFLAG_XFLIP)
+ draw_rle_fast_xflip(base, color);
+ else
+ draw_rle_fast(base, color);
+
+ /* restore cliprects */
+ if (!(VIDEO_TRANSFER_FLAGS & XFERFLAG_CLIP))
+ enable_clipping();
+}
+
+
+
+/*************************************
+ *
+ * Shift register manipulation
+ *
+ *************************************/
+
+static void shiftreg_clear(UINT16 *base, UINT16 *zbase)
+{
+ int ydir = (VIDEO_TRANSFER_FLAGS & XFERFLAG_YFLIP) ? -1 : 1;
+ int height = ADJUSTED_HEIGHT(VIDEO_TRANSFER_HEIGHT);
+ int sx = VIDEO_TRANSFER_X & 0xfff;
+ int sy = VIDEO_TRANSFER_Y & 0xfff;
+ UINT16 *src;
+ int y;
+
+ /* first line is the source */
+ src = &base[compute_safe_address(sx, sy)];
+ sy += ydir;
+
+ /* loop over height */
+ for (y = 1; y < height; y++)
+ {
+ memcpy(&base[compute_safe_address(sx, sy)], src, 512*2);
+ if (zbase)
+ {
+ UINT16 zval = ((drivedge_zbuf_control[2] >> 8) & 0x7ff) | ((drivedge_zbuf_control[2] & 0x1f) << 11);
+ UINT16 *dst = &zbase[compute_safe_address(sx, sy)];
+ int x;
+ for (x = 0; x < 512; x++)
+ *dst++ = zval;
+ }
+ sy += ydir;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video commands
+ *
+ *************************************/
+
+static void handle_video_command(void)
+{
+ /* only 6 known commands */
+ switch (VIDEO_COMMAND)
+ {
+ /* command 1: blit raw data */
+ case 1:
+ profiler_mark(PROFILER_USER1);
+ if (BLIT_LOGGING) logblit("Blit Raw");
+
+ if (is_drivedge)
+ {
+ if (enable_latch[0]) draw_raw_drivedge(videoplane[0], videoplane[1], color_latch[0]);
+ }
+ else
+ {
+ if (enable_latch[0]) draw_raw(videoplane[0], color_latch[0]);
+ if (enable_latch[1]) draw_raw(videoplane[1], color_latch[1]);
+ }
+
+ profiler_mark(PROFILER_END);
+ break;
+
+ /* command 2: blit RLE-compressed data */
+ case 2:
+ profiler_mark(PROFILER_USER2);
+ if (BLIT_LOGGING) logblit("Blit RLE");
+
+ if (enable_latch[0]) draw_rle(videoplane[0], color_latch[0]);
+ if (enable_latch[1]) draw_rle(videoplane[1], color_latch[1]);
+
+ profiler_mark(PROFILER_END);
+ break;
+
+ /* command 3: set up raw data transfer */
+ case 3:
+ if (BLIT_LOGGING) logblit("Raw Xfer");
+ xfer_xcount = VIDEO_TRANSFER_WIDTH;
+ xfer_ycount = ADJUSTED_HEIGHT(VIDEO_TRANSFER_HEIGHT);
+ xfer_xcur = VIDEO_TRANSFER_X & 0xfff;
+ xfer_ycur = VIDEO_TRANSFER_Y & 0xfff;
+ break;
+
+ /* command 4: flush? */
+ case 4:
+ break;
+
+ /* command 5: reset? */
+ case 5:
+ break;
+
+ /* command 6: perform shift register copy */
+ case 6:
+ profiler_mark(PROFILER_USER3);
+ if (BLIT_LOGGING) logblit("ShiftReg");
+
+ if (is_drivedge)
+ {
+ if (enable_latch[0]) shiftreg_clear(videoplane[0], videoplane[1]);
+ }
+ else
+ {
+ if (enable_latch[0]) shiftreg_clear(videoplane[0], NULL);
+ if (enable_latch[1]) shiftreg_clear(videoplane[1], NULL);
+ }
+
+ profiler_mark(PROFILER_END);
+ break;
+
+ default:
+ if (BLIT_LOGGING) logerror("Unknown blit command %d\n", VIDEO_COMMAND);
+ break;
+ }
+
+ /* tell the processor we're done */
+ VIDEO_INTSTATE |= VIDEOINT_BLITTER;
+ update_interrupts(1);
+}
+
+
+
+/*************************************
+ *
+ * Video I/O
+ *
+ *************************************/
+
+WRITE16_HANDLER( itech32_video_w )
+{
+ rectangle visarea;
+
+ int old = itech32_video[offset];
+ COMBINE_DATA(&itech32_video[offset]);
+
+ switch (offset)
+ {
+ case 0x02/2: /* VIDEO_INTACK */
+ VIDEO_INTSTATE = old & ~data;
+ update_interrupts(1);
+ break;
+
+ case 0x04/2: /* VIDEO_TRANSFER */
+ if (VIDEO_COMMAND == 3 && xfer_ycount)
+ {
+ offs_t addr = compute_safe_address(xfer_xcur, xfer_ycur);
+ if (enable_latch[0])
+ {
+ VIDEO_TRANSFER = videoplane[0][addr];
+ videoplane[0][addr] = (data & 0xff) | color_latch[0];
+ }
+ if (enable_latch[1])
+ {
+ VIDEO_TRANSFER = videoplane[1][addr];
+ videoplane[1][addr] = (data & 0xff) | color_latch[1];
+ }
+ if (--xfer_xcount)
+ xfer_xcur++;
+ else if (--xfer_ycount)
+ xfer_xcur = VIDEO_TRANSFER_X, xfer_xcount = VIDEO_TRANSFER_WIDTH, xfer_ycur++;
+ }
+ break;
+
+ case 0x08/2: /* VIDEO_COMMAND */
+ handle_video_command();
+ break;
+
+ case 0x0a/2: /* VIDEO_INTENABLE */
+ update_interrupts(1);
+ break;
+
+ case 0x24/2: /* VIDEO_LEFTCLIP */
+ clip_rect.min_x = VIDEO_LEFTCLIP;
+ scaled_clip_rect.min_x = VIDEO_LEFTCLIP << 8;
+ break;
+
+ case 0x26/2: /* VIDEO_RIGHTCLIP */
+ clip_rect.max_x = VIDEO_RIGHTCLIP;
+ scaled_clip_rect.max_x = VIDEO_RIGHTCLIP << 8;
+ break;
+
+ case 0x28/2: /* VIDEO_TOPCLIP */
+ clip_rect.min_y = VIDEO_TOPCLIP;
+ scaled_clip_rect.min_y = VIDEO_TOPCLIP << 8;
+ break;
+
+ case 0x2a/2: /* VIDEO_BOTTOMCLIP */
+ clip_rect.max_y = VIDEO_BOTTOMCLIP;
+ scaled_clip_rect.max_y = VIDEO_BOTTOMCLIP << 8;
+ break;
+
+ case 0x2c/2: /* VIDEO_INTSCANLINE */
+ timer_adjust(scanline_timer, video_screen_get_time_until_pos(0, VIDEO_INTSCANLINE, 0), 0, attotime_zero);
+ break;
+
+ case 0x32/2: /* VIDEO_VTOTAL */
+ case 0x36/2: /* VIDEO_VBLANK_START */
+ case 0x38/2: /* VIDEO_VBLANK_END */
+ case 0x3a/2: /* VIDEO_HTOTAL */
+ case 0x3e/2: /* VIDEO_HBLANK_START */
+ case 0x40/2: /* VIDEO_HBLANK_END */
+ /* do some sanity checks first */
+ if ((VIDEO_HTOTAL > 0) && (VIDEO_VTOTAL > 0) &&
+ (VIDEO_VBLANK_START != VIDEO_VBLANK_END) &&
+ (VIDEO_HBLANK_START != VIDEO_HBLANK_END) &&
+ (VIDEO_HBLANK_START < VIDEO_HTOTAL) &&
+ (VIDEO_HBLANK_END < VIDEO_HTOTAL) &&
+ (VIDEO_VBLANK_START < VIDEO_VTOTAL) &&
+ (VIDEO_VBLANK_END < VIDEO_VTOTAL))
+ {
+ visarea.min_x = visarea.min_y = 0;
+
+ if (VIDEO_HBLANK_START > VIDEO_HBLANK_END)
+ visarea.max_x = VIDEO_HBLANK_START - VIDEO_HBLANK_END - 1;
+ else
+ visarea.max_x = VIDEO_HTOTAL - VIDEO_HBLANK_END + VIDEO_HBLANK_START - 1;
+
+ if (VIDEO_VBLANK_START > VIDEO_VBLANK_END)
+ visarea.max_y = VIDEO_VBLANK_START - VIDEO_VBLANK_END - 1;
+ else
+ visarea.max_y = VIDEO_VTOTAL - VIDEO_VBLANK_END + VIDEO_VBLANK_START - 1;
+
+ logerror("Configure Screen: HTOTAL: %x HBSTART: %x HBEND: %x VTOTAL: %x VBSTART: %x VBEND: %x\n",
+ VIDEO_HTOTAL, VIDEO_HBLANK_START, VIDEO_HBLANK_END, VIDEO_VTOTAL, VIDEO_VBLANK_START, VIDEO_VBLANK_END);
+ video_screen_configure(0, VIDEO_HTOTAL, VIDEO_VTOTAL, &visarea, Machine->screen[0].refresh);
+ }
+ break;
+ }
+}
+
+
+READ16_HANDLER( itech32_video_r )
+{
+ if (offset == 0)
+ {
+ return (itech32_video[offset] & ~0x08) | 0x04 | 0x01;
+ }
+ else if (offset == 3)
+ {
+ return 0xef;/*video_screen_get_vpos(0) - 1;*/
+ }
+
+ return itech32_video[offset];
+}
+
+
+
+/*************************************
+ *
+ * Alternate video I/O
+ *
+ *************************************/
+
+WRITE16_HANDLER( bloodstm_video_w )
+{
+ itech32_video_w(offset / 2, data, mem_mask);
+}
+
+
+READ16_HANDLER( bloodstm_video_r )
+{
+ return itech32_video_r(offset / 2,0);
+}
+
+
+WRITE32_HANDLER( itech020_video_w )
+{
+ if (ACCESSING_MSW32)
+ itech32_video_w(offset, data >> 16, mem_mask >> 16);
+ else
+ itech32_video_w(offset, data, mem_mask);
+}
+
+
+WRITE32_HANDLER( drivedge_zbuf_control_w )
+{
+ COMBINE_DATA(&drivedge_zbuf_control[offset]);
+ is_drivedge = 1;
+}
+
+
+READ32_HANDLER( itech020_video_r )
+{
+ int result = itech32_video_r(offset,0);
+ return (result << 16) | result;
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( itech32 )
+{
+ int y;
+
+ /* loop over height */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *src1 = &videoplane[0][compute_safe_address(VIDEO_DISPLAY_XORIGIN1, VIDEO_DISPLAY_YORIGIN1 + y)];
+
+ /* handle multi-plane case */
+ if (itech32_planes > 1)
+ {
+ UINT16 *src2 = &videoplane[1][compute_safe_address(VIDEO_DISPLAY_XORIGIN2 + VIDEO_DISPLAY_XSCROLL2, VIDEO_DISPLAY_YORIGIN2 + VIDEO_DISPLAY_YSCROLL2 + y)];
+ UINT16 scanline[384];
+ int x;
+
+ /* blend the pixels in the scanline; color xxFF is transparent */
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ UINT16 pixel = src1[x];
+ if ((pixel & 0xff) == 0xff)
+ pixel = src2[x];
+ scanline[x] = pixel;
+ }
+
+ /* draw from the buffer */
+ draw_scanline16(bitmap, cliprect->min_x, y, cliprect->max_x - cliprect->min_x + 1, &scanline[cliprect->min_x], machine->pens, -1);
+ }
+
+ /* otherwise, draw directly from VRAM */
+ else
+ draw_scanline16(bitmap, cliprect->min_x, y, cliprect->max_x - cliprect->min_x + 1, &src1[cliprect->min_x], machine->pens, -1);
+ }
+ return 0;
+}
diff --git a/src/mame/video/itech8.c b/src/mame/video/itech8.c
new file mode 100644
index 00000000000..9f90fb8ad33
--- /dev/null
+++ b/src/mame/video/itech8.c
@@ -0,0 +1,670 @@
+/***************************************************************************
+
+ Incredible Technologies/Strata system
+ (8-bit blitter variant)
+
+****************************************************************************
+
+ The games run in one of two modes, either 4bpp mode with a latched
+ palette nibble, or straight 8bpp.
+
+ arligntn: 4bpp mode, dp = 00/80, draw to 0xxxx/2xxxx
+ hstennis: 4bpp mode, dp = 00/80, draw to 0xxxx/2xxxx
+ neckneck: 4bpp mode, dp = 00/80, draw to 0xxxx/2xxxx
+ ninclown: 4bpp mode, dp = 00/80, draw to 0xxxx/2xxxx
+ peggle: 4bpp mode, dp = 00/80, draw to 0xxxx/2xxxx
+ rimrockn: 4bpp mode, dp = 00/80, draw to 0xxxx/2xxxx
+
+ dynobop: 8bpp mode, dp = 00/FF, draw to 2xxxx/0xxxx
+ pokrdice: 8bpp mode, dp = 00/FF, draw to 2xxxx/0xxxx
+ slikshot: 8bpp mode, dp = 00/FF, draw to 2xxxx/0xxxx
+
+ gtg: 8bpp mode, dp = C0
+ stratab: 8bpp mode, dp = C0, always draws to 2xxxx
+ wfortune: 8bpp mode, dp = C0, always draws to 2xxxx
+
+****************************************************************************
+
+ 8-bit blitter data format:
+
+ +00 hhhhhhhh MSB of 16-bit source address
+ +01 llllllll LSB of 16-bit source address
+ +02 ---t---- Transparent: when set, don't write 0 nibbles
+ ----r--- RLE: when set, source data is RLE compressed
+ -----y-- Y-flip: when set, draw up instead of down
+ ------x- X-flip: when set, draw right instead of left
+ -------s Shift: when set, offset drawing by one nibble
+ +03 s------- Blit status: when set, blit is in progress
+ +03 -------- Blit start: a write here starts the blit
+ +04 wwwwwwww Width of blit, in bytes
+ +05 hhhhhhhh Height of blit, in rows
+ +06 mmmmmmmm Blit mask, applied to each source pixel
+ +07 ?------- Set by ninclown at startup
+ -4------ Set by games that use 4bpp latched output
+ --?----- Set by gtg, gtg2, peggle, pokrdice, stratab
+ ---l---- Video status LED
+ ----?--- Set by gtg2, ninclown, peggle, stratab
+ ------?- Set by arligntn, neckneck, gtg, gtg2, ninclown, peggle, pokrdice, rimrockn, stratab
+ +08 xxxxxxxx Number of pixels to skip before drawing each row
+ +09 yyyyyyyy Number of rows to draw (the first height - y rows are skipped)
+ +0A eeeeeeee Number of pixels to skip at the end of each row
+ +0B ssssssss Number of rows to skip at the end of drawing
+
+****************************************************************************
+
+ Blitter timing
+
+ Times are in 2MHz NOPs (@ 2 cycles/NOP) after issuing a blit start
+ command:
+
+ 1x1 = 1-2 1x 1 = 1-2
+ 2x1 = 2 1x 2 = 2
+ 3x1 = 2 1x 3 = 2
+ 4x1 = 2 1x 4 = 2
+ 5x1 = 3 1x 5 = 3
+ 6x1 = 3 1x 6 = 3
+ 7x1 = 3-4 1x 7 = 3
+ 8x1 = 4 1x 8 = 4
+ 9x1 = 4 1x 9 = 4
+ 10x1 = 4 1x 10 = 4-5
+ 11x1 = 5 1x 11 = 5
+ 12x1 = 5 1x 12 = 5
+ 13x1 = 5-6 1x 13 = 5
+ 14x1 = 6 1x 14 = 6
+ 15x1 = 6 1x 15 = 6
+ 16x1 = 6-7 1x 16 = 6
+ 24x1 = 9-10 1x 24 = 9
+ 32x1 = 12 1x 32 = 12
+ 48x1 = 17 1x 48 = 17
+ 64x1 = 23 1x 64 = 22
+ 96x1 = 33 1x 96 = 33
+ 128x1 = 44 1x128 = 44
+ 192x1 = 65 1x192 = 65
+ 240x1 = 81-82 1x240 = 81-82
+
+ Times are not affected by transparency or RLE settings at all.
+ Times are slightly variable in nature in my tests (within 1 NOP).
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/tms34061.h"
+#include "video/tlc34076.h"
+#include "cpu/m6809/m6809.h"
+#include "itech8.h"
+
+
+/*************************************
+ *
+ * Debugging
+ *
+ *************************************/
+
+#define FULL_LOGGING 0
+#define BLIT_LOGGING 0
+
+
+
+/*************************************
+ *
+ * Blitter constants
+ *
+ *************************************/
+
+#define BLITTER_ADDRHI blitter_data[0]
+#define BLITTER_ADDRLO blitter_data[1]
+#define BLITTER_FLAGS blitter_data[2]
+#define BLITTER_STATUS blitter_data[3]
+#define BLITTER_WIDTH blitter_data[4]
+#define BLITTER_HEIGHT blitter_data[5]
+#define BLITTER_MASK blitter_data[6]
+#define BLITTER_OUTPUT blitter_data[7]
+#define BLITTER_XSTART blitter_data[8]
+#define BLITTER_YCOUNT blitter_data[9]
+#define BLITTER_XSTOP blitter_data[10]
+#define BLITTER_YSKIP blitter_data[11]
+
+#define BLITFLAG_SHIFT 0x01
+#define BLITFLAG_XFLIP 0x02
+#define BLITFLAG_YFLIP 0x04
+#define BLITFLAG_RLE 0x08
+#define BLITFLAG_TRANSPARENT 0x10
+
+
+
+/*************************************
+ *
+ * Global variables
+ *
+ *************************************/
+
+UINT8 *itech8_grom_bank;
+
+static UINT8 blitter_data[16];
+static UINT8 blit_in_progress;
+
+static UINT8 page_select;
+
+static offs_t fetch_offset;
+static UINT8 fetch_rle_count;
+static UINT8 fetch_rle_value;
+static UINT8 fetch_rle_literal;
+
+static struct tms34061_display tms_state;
+static UINT8 *grom_base;
+static UINT32 grom_size;
+
+
+
+/*************************************
+ *
+ * TMS34061 interfacing
+ *
+ *************************************/
+
+static void generate_interrupt(int state)
+{
+ itech8_update_interrupts(-1, state, -1);
+
+ if (FULL_LOGGING && state) logerror("------------ DISPLAY INT (%d) --------------\n", video_screen_get_vpos(0));
+}
+
+
+static struct tms34061_interface tms34061intf =
+{
+ 0, /* the screen we are acting on */
+ 8, /* VRAM address is (row << rowshift) | col */
+ 0x40000, /* size of video RAM */
+ generate_interrupt /* interrupt gen callback */
+};
+
+
+
+/*************************************
+ *
+ * Video start
+ *
+ *************************************/
+
+VIDEO_START( itech8 )
+{
+ /* initialize TMS34061 emulation */
+ tms34061_start(&tms34061intf);
+
+ /* get the TMS34061 display state */
+ tms34061_get_display_state(&tms_state);
+
+ /* reset statics */
+ page_select = 0xc0;
+
+ /* fetch the GROM base */
+ grom_base = memory_region(REGION_GFX1);
+ grom_size = memory_region_length(REGION_GFX1);
+}
+
+
+
+/*************************************
+ *
+ * Palette I/O
+ *
+ *************************************/
+
+WRITE8_HANDLER( itech8_palette_w )
+{
+ tlc34076_w(offset/2, data);
+}
+
+
+
+/*************************************
+ *
+ * Paging control
+ *
+ *************************************/
+
+WRITE8_HANDLER( itech8_page_w )
+{
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ logerror("%04x:display_page = %02X (%d)\n", activecpu_get_pc(), data, video_screen_get_vpos(0));
+ page_select = data;
+}
+
+
+
+
+/*************************************
+ *
+ * Blitter data fetchers
+ *
+ *************************************/
+
+INLINE UINT8 fetch_next_raw(void)
+{
+ return grom_base[fetch_offset++ % grom_size];
+}
+
+
+INLINE void consume_raw(int count)
+{
+ fetch_offset += count;
+}
+
+
+INLINE UINT8 fetch_next_rle(void)
+{
+ if (fetch_rle_count == 0)
+ {
+ fetch_rle_count = grom_base[fetch_offset++ % grom_size];
+ fetch_rle_literal = fetch_rle_count & 0x80;
+ fetch_rle_count &= 0x7f;
+
+ if (!fetch_rle_literal)
+ fetch_rle_value = grom_base[fetch_offset++ % grom_size];
+ }
+
+ fetch_rle_count--;
+ if (fetch_rle_literal)
+ fetch_rle_value = grom_base[fetch_offset++ % grom_size];
+
+ return fetch_rle_value;
+}
+
+
+INLINE void consume_rle(int count)
+{
+ while (count)
+ {
+ int num_to_consume;
+
+ if (fetch_rle_count == 0)
+ {
+ fetch_rle_count = grom_base[fetch_offset++ % grom_size];
+ fetch_rle_literal = fetch_rle_count & 0x80;
+ fetch_rle_count &= 0x7f;
+
+ if (!fetch_rle_literal)
+ fetch_rle_value = grom_base[fetch_offset++ % grom_size];
+ }
+
+ num_to_consume = (count < fetch_rle_count) ? count : fetch_rle_count;
+ count -= num_to_consume;
+
+ fetch_rle_count -= num_to_consume;
+ if (fetch_rle_literal)
+ fetch_offset += num_to_consume;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Core blitter
+ *
+ *************************************/
+
+static void perform_blit(void)
+{
+ offs_t addr = tms_state.regs[TMS34061_XYADDRESS] | ((tms_state.regs[TMS34061_XYOFFSET] & 0x300) << 8);
+ UINT8 shift = (BLITTER_FLAGS & BLITFLAG_SHIFT) ? 4 : 0;
+ int transparent = (BLITTER_FLAGS & BLITFLAG_TRANSPARENT);
+ int ydir = (BLITTER_FLAGS & BLITFLAG_YFLIP) ? -1 : 1;
+ int xdir = (BLITTER_FLAGS & BLITFLAG_XFLIP) ? -1 : 1;
+ int xflip = (BLITTER_FLAGS & BLITFLAG_XFLIP);
+ int rle = (BLITTER_FLAGS & BLITFLAG_RLE);
+ int color = tms34061_latch_r(0);
+ int width = BLITTER_WIDTH;
+ int height = BLITTER_HEIGHT;
+ UINT8 transmaskhi, transmasklo;
+ UINT8 mask = BLITTER_MASK;
+ UINT8 skip[3];
+ int x, y;
+
+ /* debugging */
+ if (FULL_LOGGING)
+ logerror("Blit: scan=%d src=%06x @ (%05x) for %dx%d ... flags=%02x\n",
+ video_screen_get_vpos(0),
+ (*itech8_grom_bank << 16) | (BLITTER_ADDRHI << 8) | BLITTER_ADDRLO,
+ tms_state.regs[TMS34061_XYADDRESS] | ((tms_state.regs[TMS34061_XYOFFSET] & 0x300) << 8),
+ BLITTER_WIDTH, BLITTER_HEIGHT, BLITTER_FLAGS);
+
+ /* initialize the fetcher */
+ fetch_offset = (*itech8_grom_bank << 16) | (BLITTER_ADDRHI << 8) | BLITTER_ADDRLO;
+ fetch_rle_count = 0;
+
+ /* RLE starts with a couple of extra 0's */
+ if (rle)
+ fetch_offset += 2;
+
+ /* select 4-bit versus 8-bit transparency */
+ if (BLITTER_OUTPUT & 0x40)
+ transmaskhi = 0xf0, transmasklo = 0x0f;
+ else
+ transmaskhi = transmasklo = 0xff;
+
+ /* compute horiz skip counts */
+ skip[0] = BLITTER_XSTART;
+ skip[1] = (width <= BLITTER_XSTOP) ? 0 : width - 1 - BLITTER_XSTOP;
+ if (xdir == -1) { int temp = skip[0]; skip[0] = skip[1]; skip[1] = temp; }
+ width -= skip[0] + skip[1];
+
+ /* compute vertical skip counts */
+ if (ydir == 1)
+ {
+ skip[2] = (height <= BLITTER_YCOUNT) ? 0 : height - BLITTER_YCOUNT;
+ if (BLITTER_YSKIP > 1) height -= BLITTER_YSKIP - 1;
+ }
+ else
+ {
+ skip[2] = (height <= BLITTER_YSKIP) ? 0 : height - BLITTER_YSKIP;
+ if (BLITTER_YCOUNT > 1) height -= BLITTER_YCOUNT - 1;
+ }
+
+ /* skip top */
+ for (y = 0; y < skip[2]; y++)
+ {
+ /* skip src and dest */
+ addr += xdir * (width + skip[0] + skip[1]);
+ if (rle)
+ consume_rle(width + skip[0] + skip[1]);
+ else
+ consume_raw(width + skip[0] + skip[1]);
+
+ /* back up one and reverse directions */
+ addr -= xdir;
+ addr += ydir * 256;
+ addr &= 0x3ffff;
+ xdir = -xdir;
+ }
+
+ /* loop over height */
+ for (y = skip[2]; y < height; y++)
+ {
+ /* skip left */
+ addr += xdir * skip[y & 1];
+ if (rle)
+ consume_rle(skip[y & 1]);
+ else
+ consume_raw(skip[y & 1]);
+
+ /* loop over width */
+ for (x = 0; x < width; x++)
+ {
+ UINT8 pix = rle ? fetch_next_rle() : fetch_next_raw();
+
+ /* swap pixels for X flip in 4bpp mode */
+ if (xflip && transmaskhi != 0xff)
+ pix = (pix >> 4) | (pix << 4);
+
+ /* draw upper pixel */
+ if (!transparent || (pix & transmaskhi))
+ {
+ tms_state.vram[addr] = (tms_state.vram[addr] & (0x0f << shift)) | ((pix & mask & 0xf0) >> shift);
+ tms_state.latchram[addr] = (tms_state.latchram[addr] & (0x0f << shift)) | ((color & 0xf0) >> shift);
+ }
+
+ /* draw lower pixel */
+ if (!transparent || (pix & transmasklo))
+ {
+ offs_t addr1 = addr + shift/4;
+ tms_state.vram[addr1] = (tms_state.vram[addr1] & (0xf0 >> shift)) | ((pix & mask & 0x0f) << shift);
+ tms_state.latchram[addr1] = (tms_state.latchram[addr1] & (0xf0 >> shift)) | ((color & 0x0f) << shift);
+ }
+
+ /* advance to the next byte */
+ addr += xdir;
+ }
+
+ /* skip right */
+ addr += xdir * skip[~y & 1];
+ if (rle)
+ consume_rle(skip[~y & 1]);
+ else
+ consume_raw(skip[~y & 1]);
+
+ /* back up one and reverse directions */
+ addr -= xdir;
+ addr += ydir * 256;
+ addr &= 0x3ffff;
+ xdir = -xdir;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Blitter finished callback
+ *
+ *************************************/
+
+static TIMER_CALLBACK( blitter_done )
+{
+ /* turn off blitting and generate an interrupt */
+ blit_in_progress = 0;
+ itech8_update_interrupts(-1, -1, 1);
+
+ if (FULL_LOGGING) logerror("------------ BLIT DONE (%d) --------------\n", video_screen_get_vpos(0));
+}
+
+
+
+/*************************************
+ *
+ * Blitter I/O
+ *
+ *************************************/
+
+READ8_HANDLER( itech8_blitter_r )
+{
+ int result = blitter_data[offset / 2];
+
+ /* debugging */
+ if (FULL_LOGGING) logerror("%04x:blitter_r(%02x)\n", activecpu_get_previouspc(), offset / 2);
+
+ /* low bit seems to be ignored */
+ offset /= 2;
+
+ /* a read from offset 3 clears the interrupt and returns the status */
+ if (offset == 3)
+ {
+ itech8_update_interrupts(-1, -1, 0);
+ if (blit_in_progress)
+ result |= 0x80;
+ else
+ result &= 0x7f;
+ }
+
+ /* a read from offsets 12-15 return input port values */
+ if (offset >= 12 && offset <= 15)
+ result = readinputport(3 + offset - 12);
+
+ return result;
+}
+
+
+WRITE8_HANDLER( itech8_blitter_w )
+{
+ /* low bit seems to be ignored */
+ offset /= 2;
+ blitter_data[offset] = data;
+
+ /* a write to offset 3 starts things going */
+ if (offset == 3)
+ {
+ /* log to the blitter file */
+ if (BLIT_LOGGING)
+ {
+ logerror("Blit: XY=%1X%04X SRC=%02X%02X%02X SIZE=%3dx%3d FLAGS=%02x",
+ (tms_state.regs[TMS34061_XYOFFSET] >> 8) & 0x0f, tms_state.regs[TMS34061_XYADDRESS],
+ *itech8_grom_bank, blitter_data[0], blitter_data[1],
+ blitter_data[4], blitter_data[5],
+ blitter_data[2]);
+ logerror(" %02X %02X %02X [%02X] %02X %02X %02X [%02X]-%02X %02X %02X %02X [%02X %02X %02X %02X]\n",
+ blitter_data[0], blitter_data[1],
+ blitter_data[2], blitter_data[3],
+ blitter_data[4], blitter_data[5],
+ blitter_data[6], blitter_data[7],
+ blitter_data[8], blitter_data[9],
+ blitter_data[10], blitter_data[11],
+ blitter_data[12], blitter_data[13],
+ blitter_data[14], blitter_data[15]);
+ }
+
+ /* perform the blit */
+ perform_blit();
+ blit_in_progress = 1;
+
+ /* set a timer to go off when we're done */
+ timer_set(attotime_mul(ATTOTIME_IN_HZ(12000000/4), BLITTER_WIDTH * BLITTER_HEIGHT + 12), 0, blitter_done);
+ }
+
+ /* debugging */
+ if (FULL_LOGGING) logerror("%04x:blitter_w(%02x)=%02x\n", activecpu_get_previouspc(), offset, data);
+}
+
+
+
+/*************************************
+ *
+ * TMS34061 I/O
+ *
+ *************************************/
+
+WRITE8_HANDLER( itech8_tms34061_w )
+{
+ int func = (offset >> 9) & 7;
+ int col = offset & 0xff;
+
+ /* Column address (CA0-CA8) is hooked up the A0-A7, with A1 being inverted
+ during register access. CA8 is ignored */
+ if (func == 0 || func == 2)
+ col ^= 2;
+
+ /* Row address (RA0-RA8) is not dependent on the offset */
+ tms34061_w(col, 0xff, func, data);
+}
+
+
+READ8_HANDLER( itech8_tms34061_r )
+{
+ int func = (offset >> 9) & 7;
+ int col = offset & 0xff;
+
+ /* Column address (CA0-CA8) is hooked up the A0-A7, with A1 being inverted
+ during register access. CA8 is ignored */
+ if (func == 0 || func == 2)
+ col ^= 2;
+
+ /* Row address (RA0-RA8) is not dependent on the offset */
+ return tms34061_r(col, 0xff, func);
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( itech8_2layer )
+{
+ UINT32 page_offset;
+ int x, y;
+
+ /* first get the current display state */
+ tms34061_get_display_state(&tms_state);
+
+ /* if we're blanked, just fill with black */
+ if (tms_state.blanked)
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* there are two layers: */
+ /* top layer @ 0x00000 is only 4bpp, colors come from the first 16 palettes */
+ /* bottom layer @ 0x20000 is full 8bpp */
+ page_offset = tms_state.dispstart & 0x0ffff;
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT8 *base0 = &tms_state.vram[(0x00000 + page_offset + y * 256) & 0x3ffff];
+ UINT8 *base2 = &tms_state.vram[(0x20000 + page_offset + y * 256) & 0x3ffff];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ int pix0 = base0[x] & 0x0f;
+ dest[x] = pix0 ? pix0 : base2[x];
+ }
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( itech8_2page )
+{
+ UINT32 page_offset;
+ int x, y;
+
+ /* first get the current display state */
+ tms34061_get_display_state(&tms_state);
+
+ /* if we're blanked, just fill with black */
+ if (tms_state.blanked)
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* there are two pages, each of which is a full 8bpp */
+ /* page index is selected by the top bit of the page_select register */
+ page_offset = ((page_select & 0x80) << 10) | (tms_state.dispstart & 0x0ffff);
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT8 *base = &tms_state.vram[(page_offset + y * 256) & 0x3ffff];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ dest[x] = base[x];
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( itech8_2page_large )
+{
+ UINT32 page_offset;
+ int x, y;
+
+ /* first get the current display state */
+ tms34061_get_display_state(&tms_state);
+
+ /* if we're blanked, just fill with black */
+ if (tms_state.blanked)
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* there are two pages, each of which is a full 8bpp */
+ /* the low 4 bits come from the bitmap directly */
+ /* the upper 4 bits were latched on each write into a separate bitmap */
+ /* page index is selected by the top bit of the page_select register */
+ page_offset = ((~page_select & 0x80) << 10) | (tms_state.dispstart & 0x0ffff);
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT8 *base = &tms_state.vram[(page_offset + y * 256) & 0x3ffff];
+ UINT8 *latch = &tms_state.latchram[(page_offset + y * 256) & 0x3ffff];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+
+ for (x = cliprect->min_x & ~1; x <= cliprect->max_x; x += 2)
+ {
+ dest[x + 0] = (latch[x/2] & 0xf0) | (base[x/2] >> 4);
+ dest[x + 1] = ((latch[x/2] << 4) & 0xf0) | (base[x/2] & 0x0f);
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/jack.c b/src/mame/video/jack.c
new file mode 100644
index 00000000000..e1718aa8649
--- /dev/null
+++ b/src/mame/video/jack.c
@@ -0,0 +1,179 @@
+/***************************************************************************
+
+ video/jack.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+WRITE8_HANDLER( jack_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( jack_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( jack_paletteram_w )
+{
+ /* RGB output is inverted */
+ paletteram_BBGGGRRR_w(offset,~data);
+}
+
+READ8_HANDLER( jack_flipscreen_r )
+{
+ flip_screen_set(offset);
+ return 0;
+}
+
+WRITE8_HANDLER( jack_flipscreen_w )
+{
+ flip_screen_set(offset);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + ((colorram[tile_index] & 0x18) << 5);
+ int color = colorram[tile_index] & 0x07;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static UINT32 tilemap_scan_cols_flipy( UINT32 col, UINT32 row, UINT32 num_cols, UINT32 num_rows )
+{
+ /* logical (col,row) -> memory offset */
+ return (col * num_rows) + (num_rows - 1 - row);
+}
+
+VIDEO_START( jack )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols_flipy, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void jack_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int sx,sy,num, color,flipx,flipy;
+
+ sx = spriteram[offs + 1];
+ sy = spriteram[offs];
+ num = spriteram[offs + 2] + ((spriteram[offs + 3] & 0x08) << 5);
+ color = spriteram[offs + 3] & 0x07;
+ flipx = (spriteram[offs + 3] & 0x80);
+ flipy = (spriteram[offs + 3] & 0x40);
+
+ if (flip_screen)
+ {
+ sx = 248 - sx;
+ sy = 248 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ num,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( jack )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ jack_draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
+
+/*
+ Joinem has a bit different video hardware with proms based palette,
+ 3bpp gfx and different banking / colors bits
+*/
+
+PALETTE_INIT( joinem )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+static TILE_GET_INFO( joinem_get_bg_tile_info )
+{
+ int code = videoram[tile_index] + ((colorram[tile_index] & 0x03) << 8);
+ int color = (colorram[tile_index] & 0x38) >> 3;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( joinem )
+{
+ bg_tilemap = tilemap_create(joinem_get_bg_tile_info, tilemap_scan_cols_flipy, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void joinem_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int sx,sy,num, color,flipx,flipy;
+
+ sx = spriteram[offs + 1];
+ sy = spriteram[offs];
+ num = spriteram[offs + 2] + ((spriteram[offs + 3] & 0x01) << 8);
+ color = (spriteram[offs + 3] & 0x38) >> 3;
+ flipx = (spriteram[offs + 3] & 0x80);
+ flipy = (spriteram[offs + 3] & 0x40);
+
+ if (flip_screen)
+ {
+ sx = 248 - sx;
+ sy = 248 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ num,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( joinem )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ joinem_draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/jackal.c b/src/mame/video/jackal.c
new file mode 100644
index 00000000000..066d6d5f151
--- /dev/null
+++ b/src/mame/video/jackal.c
@@ -0,0 +1,217 @@
+/***************************************************************************
+
+ video.c
+
+ Written by Kenneth Lin (kenneth_lin@ai.vancouver.bc.ca)
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static UINT8 *jackal_scrollram;
+UINT8 *jackal_videoctrl;
+
+static tilemap *bg_tilemap;
+
+
+PALETTE_INIT( jackal )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ {
+ COLOR(0,i) = (i & 0xff) + 256;
+ /* this is surely wrong - is there a PROM missing? */
+ if (i & 0x0f)
+ COLOR(0,i) |= i/256;
+ }
+
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ {
+ COLOR(1,i) = (*color_prom & 0x0f);
+ color_prom++;
+ }
+
+ for (i = 0;i < TOTAL_COLORS(3);i++)
+ {
+ COLOR(3,i) = (*color_prom & 0x0f) + 16;
+ color_prom++;
+ }
+}
+
+void jackal_mark_tile_dirty(int offset)
+{
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 *RAM = memory_region(REGION_CPU1);
+
+ int attr = RAM[0x2000 + tile_index];
+ int code = RAM[0x2400 + tile_index] + ((attr & 0xc0) << 2) + ((attr & 0x30) << 6);
+ int color = attr & 0x0f;
+ int flags = ((attr & 0x10) ? TILE_FLIPX : 0) | ((attr & 0x20) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( jackal )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_background( mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ UINT8 *RAM = memory_region(REGION_CPU1);
+ int i;
+
+ jackal_scrollram = &RAM[0x0020];
+
+ tilemap_set_scroll_rows(bg_tilemap, 1);
+ tilemap_set_scroll_cols(bg_tilemap, 1);
+
+ tilemap_set_scrolly(bg_tilemap, 0, jackal_videoctrl[0]);
+ tilemap_set_scrollx(bg_tilemap, 0, jackal_videoctrl[1]);
+
+ if (jackal_videoctrl[2] & 0x02)
+ {
+ if (jackal_videoctrl[2] & 0x08)
+ {
+ tilemap_set_scroll_rows(bg_tilemap, 32);
+
+ for (i = 0; i < 32; i++)
+ {
+ tilemap_set_scrollx(bg_tilemap, i, jackal_scrollram[i]);
+ }
+ }
+
+ if (jackal_videoctrl[2] & 0x04)
+ {
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+
+ for (i = 0; i < 32; i++)
+ {
+ tilemap_set_scrolly(bg_tilemap, i, jackal_scrollram[i]);
+ }
+ }
+ }
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+}
+
+#define DRAW_SPRITE(bank, code, sx, sy) drawgfx(bitmap, machine->gfx[bank], code, color, flipx, flipy, sx, sy, cliprect, TRANSPARENCY_PEN, 0);
+
+static void draw_sprites_region(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, const UINT8 *sram, int length, int bank )
+{
+ int offs;
+
+ for (offs = 0; offs < length; offs += 5)
+ {
+ int sn1 = sram[offs];
+ int sn2 = sram[offs+1];
+ int sy = sram[offs+2];
+ int sx = sram[offs+3];
+ int attr = sram[offs+4];
+ int flipx = attr & 0x20;
+ int flipy = attr & 0x40;
+ int color = ((sn2 & 0xf0) >> 4);
+
+ if (attr & 0x01) sx = sx - 256;
+ if (sy > 0xf0) sy = sy - 256;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if (attr & 0xC) // half-size sprite
+ {
+ int spritenum = sn1*4 + ((sn2 & (8+4)) >> 2) + ((sn2 & (2+1)) << 10);
+ int mod = -8;
+
+ if (flip_screen)
+ {
+ sx += 8;
+ sy -= 8;
+ mod = 8;
+ }
+
+ if ((attr & 0x0C) == 0x0C)
+ {
+ if (flip_screen) sy += 16;
+ DRAW_SPRITE(bank + 1, spritenum, sx, sy)
+ }
+
+ if ((attr & 0x0C) == 0x08)
+ {
+ sy += 8;
+ DRAW_SPRITE(bank + 1, spritenum, sx, sy)
+ DRAW_SPRITE(bank + 1, spritenum - 2, sx, sy + mod)
+ }
+
+ if ((attr & 0x0C) == 0x04)
+ {
+ DRAW_SPRITE(bank + 1, spritenum, sx, sy)
+ DRAW_SPRITE(bank + 1, spritenum + 1, sx + mod, sy)
+ }
+ }
+ else
+ {
+ int spritenum = sn1 + ((sn2 & 0x03) << 8);
+
+ if (attr & 0x10)
+ {
+ if (flip_screen)
+ {
+ sx -= 16;
+ sy -= 16;
+ }
+
+ DRAW_SPRITE(bank, spritenum, flipx ? sx+16 : sx, flipy ? sy+16 : sy)
+ DRAW_SPRITE(bank, spritenum + 1, flipx ? sx : sx+16, flipy ? sy+16 : sy)
+ DRAW_SPRITE(bank, spritenum + 2, flipx ? sx+16 : sx, flipy ? sy : sy+16)
+ DRAW_SPRITE(bank, spritenum + 3, flipx ? sx : sx+16, flipy ? sy : sy+16)
+ }
+ else
+ {
+ DRAW_SPRITE(bank, spritenum, sx, sy)
+ }
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ UINT8 *RAM = memory_region(REGION_CPU1);
+ UINT8 *sr, *ss;
+
+ if (jackal_videoctrl[0x03] & 0x08)
+ {
+ sr = &RAM[0x03800]; // Sprite 2
+ ss = &RAM[0x13800]; // Additional Sprite 2
+ }
+ else
+ {
+ sr = &RAM[0x03000]; // Sprite 1
+ ss = &RAM[0x13000]; // Additional Sprite 1
+ }
+
+ draw_sprites_region(machine, bitmap, cliprect, ss, 0x0f5, 3);
+ draw_sprites_region(machine, bitmap, cliprect, sr, 0x500, 1);
+}
+
+VIDEO_UPDATE( jackal )
+{
+ draw_background(bitmap, cliprect);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/jagblit.c b/src/mame/video/jagblit.c
new file mode 100644
index 00000000000..ff7cbb40fcf
--- /dev/null
+++ b/src/mame/video/jagblit.c
@@ -0,0 +1,480 @@
+/***************************************************************************
+
+ Atari Jaguar blitter
+
+****************************************************************************
+
+ How to use this module:
+
+ #define FUNCNAME -- name of the function to be generated
+ #define COMMAND -- blitter command bits for blitter
+ #define A1FIXED -- fixed A1 flag bits for blitter
+ #define A2FIXED -- fixed A2 flag bits for blitter
+ #include "jagblit.c"
+
+****************************************************************************/
+
+
+#ifndef FUNCNAME
+#error jagblit.c -- requires FUNCNAME to be predefined
+#endif
+
+#ifndef COMMAND
+#error jagblit.c -- requires COMMAND to be predefined
+#endif
+
+#ifndef A1FIXED
+#error jagblit.c -- requires A1FIXED to be predefined
+#endif
+
+#ifndef A2FIXED
+#error jagblit.c -- requires A2FIXED to be predefined
+#endif
+
+#ifndef PIXEL_SHIFT_1
+#define PIXEL_SHIFT_1(a) ((~a##_x >> 16) & 7)
+#define PIXEL_OFFSET_1(a) BYTE4_XOR_BE(((UINT32)a##_y >> 16) * a##_width / 8 + (((UINT32)a##_x >> 19) & ~7) * (1 + a##_pitch) + (((UINT32)a##_x >> 19) & 7))
+#define ZDATA_OFFSET_1(a) 0 /* huh? */
+#define READ_RDATA_1(r,a,p) ((p) ? (((((UINT8 *)&blitter_regs[r])[BYTE4_XOR_BE(((UINT32)a##_x >> 19) & 7)]) >> PIXEL_SHIFT_1(a)) & 0x01) : (blitter_regs[r] & 0x01))
+#define READ_PIXEL_1(a) (((((UINT8 *)a##_base_mem)[PIXEL_OFFSET_1(a)]) >> PIXEL_SHIFT_1(a)) & 0x01)
+#define READ_ZDATA_1(a) 0 /* huh? */
+#define WRITE_PIXEL_1(a,d) do { UINT8 *pix = &((UINT8 *)a##_base_mem)[PIXEL_OFFSET_1(a)]; *pix = (*pix & ~(0x01 << PIXEL_SHIFT_1(a))) | ((d) << PIXEL_SHIFT_1(a)); } while (0)
+#define WRITE_ZDATA_1(a,d) /* huh? */
+
+#define PIXEL_SHIFT_2(a) ((~a##_x >> 15) & 6)
+#define PIXEL_OFFSET_2(a) BYTE4_XOR_BE(((UINT32)a##_y >> 16) * a##_width / 4 + (((UINT32)a##_x >> 18) & ~7) * (1 + a##_pitch) + (((UINT32)a##_x >> 18) & 7))
+#define ZDATA_OFFSET_2(a) 0 /* huh? */
+#define READ_RDATA_2(r,a,p) ((p) ? (((((UINT8 *)&blitter_regs[r])[BYTE4_XOR_BE(((UINT32)a##_x >> 18) & 7)]) >> PIXEL_SHIFT_2(a)) & 0x03) : (blitter_regs[r] & 0x03))
+#define READ_PIXEL_2(a) (((((UINT8 *)a##_base_mem)[PIXEL_OFFSET_2(a)]) >> PIXEL_SHIFT_2(a)) & 0x03)
+#define READ_ZDATA_2(a) 0 /* huh? */
+#define WRITE_PIXEL_2(a,d) do { UINT8 *pix = &((UINT8 *)a##_base_mem)[PIXEL_OFFSET_2(a)]; *pix = (*pix & ~(0x03 << PIXEL_SHIFT_2(a))) | ((d) << PIXEL_SHIFT_2(a)); } while (0)
+#define WRITE_ZDATA_2(a,d) /* huh? */
+
+#define PIXEL_SHIFT_4(a) ((~a##_x >> 14) & 4)
+#define PIXEL_OFFSET_4(a) BYTE4_XOR_BE(((UINT32)a##_y >> 16) * a##_width / 2 + (((UINT32)a##_x >> 17) & ~7) * (1 + a##_pitch) + (((UINT32)a##_x >> 17) & 7))
+#define ZDATA_OFFSET_4(a) 0 /* huh? */
+#define READ_RDATA_4(r,a,p) ((p) ? (((((UINT8 *)&blitter_regs[r])[BYTE4_XOR_BE(((UINT32)a##_x >> 17) & 7)]) >> PIXEL_SHIFT_4(a)) & 0x0f) : (blitter_regs[r] & 0x0f))
+#define READ_PIXEL_4(a) (((((UINT8 *)a##_base_mem)[PIXEL_OFFSET_4(a)]) >> PIXEL_SHIFT_4(a)) & 0x0f)
+#define READ_ZDATA_4(a) 0 /* huh? */
+#define WRITE_PIXEL_4(a,d) do { UINT8 *pix = &((UINT8 *)a##_base_mem)[PIXEL_OFFSET_4(a)]; *pix = (*pix & ~(0x0f << PIXEL_SHIFT_4(a))) | ((d) << PIXEL_SHIFT_4(a)); } while (0)
+#define WRITE_ZDATA_4(a,d) /* huh? */
+
+#define PIXEL_OFFSET_8(a) BYTE4_XOR_BE(((UINT32)a##_y >> 16) * a##_width + (((UINT32)a##_x >> 16) & ~7) * (1 + a##_pitch) + (((UINT32)a##_x >> 16) & 7))
+#define ZDATA_OFFSET_8(a) (PIXEL_OFFSET_8(a) + a##_zoffs * 8)
+#define READ_RDATA_8(r,a,p) ((p) ? (((UINT8 *)&blitter_regs[r])[BYTE4_XOR_BE(((UINT32)a##_x >> 16) & 7)]) : (blitter_regs[r] & 0xff))
+#define READ_PIXEL_8(a) (((UINT8 *)a##_base_mem)[PIXEL_OFFSET_8(a)])
+#define READ_ZDATA_8(a) (((UINT8 *)a##_base_mem)[ZDATA_OFFSET_8(a)])
+#define WRITE_PIXEL_8(a,d) do { ((UINT8 *)a##_base_mem)[PIXEL_OFFSET_8(a)] = (d); } while (0)
+#define WRITE_ZDATA_8(a,d) do { ((UINT8 *)a##_base_mem)[ZDATA_OFFSET_8(a)] = (d); } while (0)
+
+#define PIXEL_OFFSET_16(a) BYTE_XOR_BE(((UINT32)a##_y >> 16) * a##_width + (((UINT32)a##_x >> 16) & ~3) * (1 + a##_pitch) + (((UINT32)a##_x >> 16) & 3))
+#define ZDATA_OFFSET_16(a) (PIXEL_OFFSET_16(a) + a##_zoffs * 4)
+#define READ_RDATA_16(r,a,p) ((p) ? (((UINT16 *)&blitter_regs[r])[BYTE_XOR_BE(((UINT32)a##_x >> 16) & 3)]) : (blitter_regs[r] & 0xffff))
+#define READ_PIXEL_16(a) (((UINT16 *)a##_base_mem)[PIXEL_OFFSET_16(a)])
+#define READ_ZDATA_16(a) (((UINT16 *)a##_base_mem)[ZDATA_OFFSET_16(a)])
+#define WRITE_PIXEL_16(a,d) do { ((UINT16 *)a##_base_mem)[PIXEL_OFFSET_16(a)] = (d); } while (0)
+#define WRITE_ZDATA_16(a,d) do { ((UINT16 *)a##_base_mem)[ZDATA_OFFSET_16(a)] = (d); } while (0)
+
+#define PIXEL_OFFSET_32(a) (((UINT32)a##_y >> 16) * a##_width + (((UINT32)a##_x >> 16) & ~1) * (1 + a##_pitch) + (((UINT32)a##_x >> 16) & 1))
+#define ZDATA_OFFSET_32(a) (PIXEL_OFFSET_32(a) + a##_zoffs * 2)
+#define READ_RDATA_32(r,a,p) ((p) ? (blitter_regs[r + (((UINT32)a##_x >> 16) & 1)]) : blitter_regs[r])
+#define READ_PIXEL_32(a) (((UINT32 *)a##_base_mem)[PIXEL_OFFSET_32(a)])
+#define READ_ZDATA_32(a) (((UINT32 *)a##_base_mem)[ZDATA_OFFSET_32(a)])
+#define WRITE_PIXEL_32(a,d) do { ((UINT32 *)a##_base_mem)[PIXEL_OFFSET_32(a)] = (d); } while (0)
+#define WRITE_ZDATA_32(a,d) do { ((UINT32 *)a##_base_mem)[ZDATA_OFFSET_32(a)] = (d); } while (0)
+
+#define READ_RDATA(r,a,f,p) \
+ ((((f) & 0x38) == (0 << 3)) ? (READ_RDATA_1(r,a,p)) : \
+ (((f) & 0x38) == (1 << 3)) ? (READ_RDATA_2(r,a,p)) : \
+ (((f) & 0x38) == (2 << 3)) ? (READ_RDATA_4(r,a,p)) : \
+ (((f) & 0x38) == (3 << 3)) ? (READ_RDATA_8(r,a,p)) : \
+ (((f) & 0x38) == (4 << 3)) ? (READ_RDATA_16(r,a,p)) : \
+ (((f) & 0x38) == (5 << 3)) ? (READ_RDATA_32(r,a,p)) : 0)
+
+#define READ_PIXEL(a,f) \
+ ((((f) & 0x38) == (0 << 3)) ? (READ_PIXEL_1(a)) : \
+ (((f) & 0x38) == (1 << 3)) ? (READ_PIXEL_2(a)) : \
+ (((f) & 0x38) == (2 << 3)) ? (READ_PIXEL_4(a)) : \
+ (((f) & 0x38) == (3 << 3)) ? (READ_PIXEL_8(a)) : \
+ (((f) & 0x38) == (4 << 3)) ? (READ_PIXEL_16(a)) : \
+ (((f) & 0x38) == (5 << 3)) ? (READ_PIXEL_32(a)) : 0)
+
+#define READ_ZDATA(a,f) \
+ ((((f) & 0x38) == (0 << 3)) ? (READ_ZDATA_1(a)) : \
+ (((f) & 0x38) == (1 << 3)) ? (READ_ZDATA_2(a)) : \
+ (((f) & 0x38) == (2 << 3)) ? (READ_ZDATA_4(a)) : \
+ (((f) & 0x38) == (3 << 3)) ? (READ_ZDATA_8(a)) : \
+ (((f) & 0x38) == (4 << 3)) ? (READ_ZDATA_16(a)) : \
+ (((f) & 0x38) == (5 << 3)) ? (READ_ZDATA_32(a)) : 0)
+
+#define WRITE_PIXEL(a,f,d) \
+ do \
+ { \
+ if (((f) & 0x38) == (0 << 3)) WRITE_PIXEL_1(a,d); \
+ else if (((f) & 0x38) == (1 << 3)) WRITE_PIXEL_2(a,d); \
+ else if (((f) & 0x38) == (2 << 3)) WRITE_PIXEL_4(a,d); \
+ else if (((f) & 0x38) == (3 << 3)) WRITE_PIXEL_8(a,d); \
+ else if (((f) & 0x38) == (4 << 3)) WRITE_PIXEL_16(a,d); \
+ else if (((f) & 0x38) == (5 << 3)) WRITE_PIXEL_32(a,d); \
+ } while (0)
+
+#define WRITE_ZDATA(a,f,d) \
+ do \
+ { \
+ if (((f) & 0x38) == (0 << 3)) WRITE_ZDATA_1(a,d); \
+ else if (((f) & 0x38) == (1 << 3)) WRITE_ZDATA_2(a,d); \
+ else if (((f) & 0x38) == (2 << 3)) WRITE_ZDATA_4(a,d); \
+ else if (((f) & 0x38) == (3 << 3)) WRITE_ZDATA_8(a,d); \
+ else if (((f) & 0x38) == (4 << 3)) WRITE_ZDATA_16(a,d); \
+ else if (((f) & 0x38) == (5 << 3)) WRITE_ZDATA_32(a,d); \
+ } while (0)
+#endif
+
+static void FUNCNAME(UINT32 command, UINT32 a1flags, UINT32 a2flags)
+{
+ UINT32 a1_base = blitter_regs[A1_BASE];
+ INT32 a1_pitch = (A1FIXED & 3) ^ ((A1FIXED & 2) >> 1);
+ INT32 a1_zoffs = (A1FIXED >> 6) & 7;
+ INT32 a1_width = ((4 | ((a1flags >> 9) & 3)) << ((a1flags >> 11) & 15)) >> 2;
+ INT32 a1_xadd = (A1FIXED >> 16) & 0x03;
+ INT32 a1_yadd = (A1FIXED >> 18) & 0x01;
+ INT32 a1_x = (blitter_regs[A1_PIXEL] << 16) | (blitter_regs[A1_FPIXEL] & 0xffff);
+ INT32 a1_y = (blitter_regs[A1_PIXEL] & 0xffff0000) | (blitter_regs[A1_FPIXEL] >> 16);
+ INT32 a1_xstep = 0;
+ INT32 a1_ystep = 0;
+ UINT32 a1_xmask = 0xffffffff;
+ UINT32 a1_ymask = 0xffffffff;
+
+ UINT32 a2_base = blitter_regs[A2_BASE];
+ INT32 a2_pitch = (A2FIXED & 3) ^ ((A2FIXED & 2) >> 1);
+ INT32 a2_zoffs = (A2FIXED >> 6) & 7;
+ INT32 a2_width = ((4 | ((a2flags >> 9) & 3)) << ((a2flags >> 11) & 15)) >> 2;
+ INT32 a2_xadd = (A2FIXED >> 16) & 0x03;
+ INT32 a2_yadd = (A2FIXED >> 18) & 0x01;
+ INT32 a2_x = (blitter_regs[A2_PIXEL] << 16);
+ INT32 a2_y = (blitter_regs[A2_PIXEL] & 0xffff0000);
+ INT32 a2_xstep = 0;
+ INT32 a2_ystep = 0;
+ UINT32 a2_xmask = 0xffffffff;
+ UINT32 a2_ymask = 0xffffffff;
+
+ int inner_count = blitter_regs[B_COUNT] & 0xffff;
+ int outer_count = blitter_regs[B_COUNT] >> 16;
+ int inner, outer;
+
+ UINT8 a1_phrase_mode = 0;
+ UINT8 a2_phrase_mode = 0;
+
+ void *a1_base_mem = get_jaguar_memory(a1_base);
+ void *a2_base_mem = get_jaguar_memory(a2_base);
+
+ void *asrc_base_mem = (COMMAND & 0x00000800) ? a1_base_mem : a2_base_mem;
+ UINT32 asrcflags = (COMMAND & 0x00000800) ? A1FIXED : A2FIXED;
+ INT32 asrc_x = (COMMAND & 0x00000800) ? a1_x : a2_x;
+ INT32 asrc_y = (COMMAND & 0x00000800) ? a1_y : a2_y;
+ INT32 asrc_width = (COMMAND & 0x00000800) ? a1_width : a2_width;
+ INT32 asrc_pitch = (COMMAND & 0x00000800) ? a1_pitch : a2_pitch;
+ INT32 asrc_zoffs = (COMMAND & 0x00000800) ? a1_zoffs : a2_zoffs;
+ UINT8 asrc_phrase_mode;
+ INT32 asrc_xadd, asrc_xstep, asrc_yadd, asrc_ystep;
+ UINT32 asrc_xmask, asrc_ymask;
+
+ void *adest_base_mem = (COMMAND & 0x00000800) ? a2_base_mem : a1_base_mem;
+ UINT32 adestflags = (COMMAND & 0x00000800) ? A2FIXED : A1FIXED;
+ INT32 adest_x = (COMMAND & 0x00000800) ? a2_x : a1_x;
+ INT32 adest_y = (COMMAND & 0x00000800) ? a2_y : a1_y;
+ INT32 adest_width = (COMMAND & 0x00000800) ? a2_width : a1_width;
+ INT32 adest_pitch = (COMMAND & 0x00000800) ? a2_pitch : a1_pitch;
+ INT32 adest_zoffs = (COMMAND & 0x00000800) ? a2_zoffs : a1_zoffs;
+ UINT8 adest_phrase_mode;
+ INT32 adest_xadd, adest_xstep, adest_yadd, adest_ystep;
+ UINT32 adest_xmask, adest_ymask;
+
+ /* don't blit if pointer bad */
+ if (!a1_base_mem || !a2_base_mem)
+ {
+#if LOG_BAD_BLITS
+ logerror("%08X:Blit!\n", activecpu_get_previouspc());
+ logerror(" a1_base = %08X\n", a1_base);
+ logerror(" a2_base = %08X\n", a2_base);
+#endif
+ return;
+ }
+
+ /* determine actual xadd/yadd for A1 */
+ a1_yadd <<= 16;
+ if (A1FIXED & 0x00100000)
+ a1_yadd = -a1_yadd;
+
+ a1_phrase_mode = (a1_xadd == 0);
+ if (a1_xadd == 3)
+ {
+ a1_xadd = (blitter_regs[A1_INC] << 16) | (blitter_regs[A1_FINC] & 0xffff);
+ a1_yadd = (blitter_regs[A1_INC] & 0xffff0000) | (blitter_regs[A1_FINC] >> 16);
+ }
+ else if (a1_xadd == 2)
+ a1_xadd = 0;
+ else
+ a1_xadd = 1 << 16;
+ if (A1FIXED & 0x00080000)
+ a1_xadd = -a1_xadd;
+
+ /* determine actual xadd/yadd for A2 */
+ a2_yadd <<= 16;
+ if (A2FIXED & 0x00100000)
+ a2_yadd = -a2_yadd;
+
+ a2_phrase_mode = (a2_xadd == 0);
+ if (a2_xadd == 2)
+ a2_xadd = 0;
+ else
+ a2_xadd = 1 << 16;
+ if (A2FIXED & 0x00080000)
+ a2_xadd = -a2_xadd;
+
+ /* set up the A2 mask */
+ if (A2FIXED & 0x00008000)
+ {
+ a2_xmask = (blitter_regs[A2_MASK] << 16) | 0xffff;
+ a2_ymask = (blitter_regs[A2_MASK] & 0xffff) | 0xffff;
+ }
+
+ /* modify outer loop steps based on command */
+ if (command & 0x00000100)
+ {
+ a1_xstep = blitter_regs[A1_FSTEP] & 0xffff;
+ a1_ystep = blitter_regs[A1_FSTEP] >> 16;
+ }
+ if (command & 0x00000200)
+ {
+ a1_xstep += blitter_regs[A1_STEP] << 16;
+ a1_ystep += blitter_regs[A1_STEP] & 0xffff0000;
+ }
+ if (command & 0x00000400)
+ {
+ a2_xstep = blitter_regs[A2_STEP] << 16;
+ a2_ystep = blitter_regs[A2_STEP] & 0xffff0000;
+ }
+
+ asrc_phrase_mode = (COMMAND & 0x00000800) ? a1_phrase_mode : a2_phrase_mode;
+ asrc_xstep = (COMMAND & 0x00000800) ? a1_xstep : a2_xstep;
+ asrc_ystep = (COMMAND & 0x00000800) ? a1_ystep : a2_ystep;
+ asrc_xadd = (COMMAND & 0x00000800) ? a1_xadd : a2_xadd;
+ asrc_yadd = (COMMAND & 0x00000800) ? a1_yadd : a2_yadd;
+ asrc_xmask = (COMMAND & 0x00000800) ? a1_xmask : a2_xmask;
+ asrc_ymask = (COMMAND & 0x00000800) ? a1_ymask : a2_ymask;
+
+ adest_phrase_mode = (COMMAND & 0x00000800) ? a2_phrase_mode : a1_phrase_mode;
+ adest_xstep = (COMMAND & 0x00000800) ? a2_xstep : a1_xstep;
+ adest_ystep = (COMMAND & 0x00000800) ? a2_ystep : a1_ystep;
+ adest_xadd = (COMMAND & 0x00000800) ? a2_xadd : a1_xadd;
+ adest_yadd = (COMMAND & 0x00000800) ? a2_yadd : a1_yadd;
+ adest_xmask = (COMMAND & 0x00000800) ? a2_xmask : a1_xmask;
+ adest_ymask = (COMMAND & 0x00000800) ? a2_ymask : a1_ymask;
+
+#if LOG_BLITS
+ logerror("%08X:Blit!\n", activecpu_get_previouspc());
+ logerror(" a1_base = %08X\n", a1_base);
+ logerror(" a1_pitch = %d\n", a1_pitch);
+ logerror(" a1_psize = %d\n", 1 << ((A1FIXED >> 3) & 7));
+ logerror(" a1_width = %d\n", a1_width);
+ logerror(" a1_xadd = %f (phrase=%d)\n", (float)a1_xadd / 65536.0, a1_phrase_mode);
+ logerror(" a1_yadd = %f\n", (float)a1_yadd / 65536.0);
+ logerror(" a1_xstep = %f\n", (float)a1_xstep / 65536.0);
+ logerror(" a1_ystep = %f\n", (float)a1_ystep / 65536.0);
+ logerror(" a1_x = %f\n", (float)a1_x / 65536.0);
+ logerror(" a1_y = %f\n", (float)a1_y / 65536.0);
+
+ logerror(" a2_base = %08X\n", a2_base);
+ logerror(" a2_pitch = %d\n", a2_pitch);
+ logerror(" a2_psize = %d\n", 1 << ((A2FIXED >> 3) & 7));
+ logerror(" a2_width = %d\n", a2_width);
+ logerror(" a2_xadd = %f (phrase=%d)\n", (float)a2_xadd / 65536.0, a2_phrase_mode);
+ logerror(" a2_yadd = %f\n", (float)a2_yadd / 65536.0);
+ logerror(" a2_xstep = %f\n", (float)a2_xstep / 65536.0);
+ logerror(" a2_ystep = %f\n", (float)a2_ystep / 65536.0);
+ logerror(" a2_x = %f\n", (float)a2_x / 65536.0);
+ logerror(" a2_y = %f\n", (float)a2_y / 65536.0);
+
+ logerror(" count = %d x %d\n", inner_count, outer_count);
+ logerror(" command = %08X\n", COMMAND);
+#endif
+
+#if LOG_UNHANDLED_BLITS
+ /* check for unhandled command bits */
+ if (COMMAND & 0x24003000)
+ logerror("Blitter unhandled: these command bits: %08X\n", COMMAND & 0x24003000);
+#endif /* LOG_UNHANDLED_BLITS */
+
+ /* top of the outer loop */
+ outer = outer_count;
+ while (outer--)
+ {
+ /* top of the inner loop */
+ inner = inner_count;
+ while (inner--)
+ {
+ UINT32 srcdata;
+ UINT32 srczdata = 0;
+ UINT32 dstdata;
+ UINT32 dstzdata = 0;
+ UINT32 writedata = 0;
+ int inhibit = 0;
+
+ /* load src data and Z */
+ if (COMMAND & 0x00000001)
+ {
+ srcdata = READ_PIXEL(asrc, asrcflags);
+ if (COMMAND & 0x00000002)
+ srczdata = READ_ZDATA(asrc, asrcflags);
+ else if (COMMAND & 0x001c020)
+ srczdata = READ_RDATA(B_SRCZ1_H, asrc, asrcflags, asrc_phrase_mode);
+ }
+ else
+ {
+ srcdata = READ_RDATA(B_SRCD_H, asrc, asrcflags, asrc_phrase_mode);
+ if (COMMAND & 0x001c020)
+ srczdata = READ_RDATA(B_SRCZ1_H, asrc, asrcflags, asrc_phrase_mode);
+ }
+
+ /* load dst data and Z */
+ if (COMMAND & 0x00000008)
+ {
+ dstdata = READ_PIXEL(adest, adestflags);
+ if (COMMAND & 0x00000010)
+ dstzdata = READ_ZDATA(adest, adestflags);
+ else
+ dstzdata = READ_RDATA(B_DSTZ_H, adest, adestflags, adest_phrase_mode);
+ }
+ else
+ {
+ dstdata = READ_RDATA(B_DSTD_H, adest, adestflags, adest_phrase_mode);
+ if (COMMAND & 0x00000010)
+ dstzdata = READ_RDATA(B_DSTZ_H, adest, adestflags, adest_phrase_mode);
+ }
+
+ /* handle clipping */
+ if (COMMAND & 0x00000040)
+ {
+ if (adest_x < 0 || adest_y < 0 ||
+ (adest_x >> 16) >= (blitter_regs[A1_CLIP] & 0x7fff) ||
+ (adest_y >> 16) >= ((blitter_regs[A1_CLIP] >> 16) & 0x7fff))
+ inhibit = 1;
+ }
+
+ /* apply Z comparator */
+ if (COMMAND & 0x00040000)
+ if (srczdata < dstzdata) inhibit = 1;
+ if (COMMAND & 0x00080000)
+ if (srczdata == dstzdata) inhibit = 1;
+ if (COMMAND & 0x00100000)
+ if (srczdata > dstzdata) inhibit = 1;
+
+ /* apply data comparator */
+ if (COMMAND & 0x08000000)
+ {
+ if (!(COMMAND & 0x02000000))
+ {
+ if (srcdata == READ_RDATA(B_PATD_H, asrc, asrcflags, asrc_phrase_mode))
+ inhibit = 1;
+ }
+ else
+ {
+ if (dstdata == READ_RDATA(B_PATD_H, adest, adestflags, adest_phrase_mode))
+ inhibit = 1;
+ }
+ }
+
+ /* compute the write data and store */
+ if (!inhibit)
+ {
+ /* handle patterns/additive/LFU */
+ if (COMMAND & 0x00010000)
+ writedata = READ_RDATA(B_PATD_H, adest, adestflags, adest_phrase_mode);
+ else if (COMMAND & 0x00020000)
+ {
+ writedata = (srcdata & 0xff) + (dstdata & 0xff);
+ if (!(COMMAND & 0x00004000) && writedata > 0xff)
+ writedata = 0xff;
+ writedata |= (srcdata & 0xf00) + (dstdata & 0xf00);
+ if (!(COMMAND & 0x00008000) && writedata > 0xfff)
+ writedata = 0xfff;
+ writedata |= (srcdata & 0xf000) + (dstdata & 0xf000);
+ }
+ else
+ {
+ if (COMMAND & 0x00200000)
+ writedata |= ~srcdata & ~dstdata;
+ if (COMMAND & 0x00400000)
+ writedata |= ~srcdata & dstdata;
+ if (COMMAND & 0x00800000)
+ writedata |= srcdata & ~dstdata;
+ if (COMMAND & 0x01000000)
+ writedata |= srcdata & dstdata;
+ }
+
+ /* handle source shading */
+ if (COMMAND & 0x40000000)
+ {
+ int intensity = srcdata & 0x00ff;
+ intensity += (INT8) (blitter_regs[B_Z3] >> 16);
+ if (intensity < 0)
+ intensity = 0;
+ else if (intensity > 0xff)
+ intensity = 0xff;
+ writedata = (srcdata & 0xff00) | intensity;
+ }
+ }
+ else
+ writedata = dstdata;
+
+ if (adest_phrase_mode || (command & 0x10000000) || !inhibit)
+ {
+ /* write to the destination */
+ WRITE_PIXEL(adest, adestflags, writedata);
+ if (COMMAND & 0x00000020)
+ WRITE_ZDATA(adest, adestflags, srczdata);
+ }
+
+ /* update X/Y */
+ asrc_x = (asrc_x + asrc_xadd) & asrc_xmask;
+ asrc_y = (asrc_y + asrc_yadd) & asrc_ymask;
+ adest_x = (adest_x + adest_xadd) & adest_xmask;
+ adest_y = (adest_y + adest_yadd) & adest_ymask;
+ }
+
+ /* adjust for phrase mode */
+ if (asrc_phrase_mode)
+ {
+ if (asrc_xadd > 0)
+ asrc_x += 3 << 16;
+ else
+ asrc_x -= 3 << 16;
+ asrc_x &= ~(3 << 16);
+ }
+ if (adest_phrase_mode)
+ {
+ if (adest_xadd > 0)
+ adest_x += 3 << 16;
+ else
+ adest_x -= 3 << 16;
+ adest_x &= ~(3 << 16);
+ }
+
+ /* update for outer loop */
+ asrc_x += asrc_xstep;
+ asrc_y += asrc_ystep;
+ adest_x += adest_xstep;
+ adest_y += adest_ystep;
+ }
+
+ /* write values back to registers */
+ a1_x = (COMMAND & 0x00000800) ? asrc_x : adest_x;
+ a1_y = (COMMAND & 0x00000800) ? asrc_y : adest_y;
+ a2_x = (COMMAND & 0x00000800) ? adest_x : asrc_x;
+ a2_y = (COMMAND & 0x00000800) ? adest_y : asrc_y;
+
+ blitter_regs[A1_PIXEL] = (a1_y & 0xffff0000) | ((a1_x >> 16) & 0xffff);
+ blitter_regs[A1_FPIXEL] = (a1_y << 16) | (a1_x & 0xffff);
+ blitter_regs[A2_PIXEL] = (a2_y & 0xffff0000) | ((a2_x >> 16) & 0xffff);
+}
diff --git a/src/mame/video/jagblit.h b/src/mame/video/jagblit.h
new file mode 100644
index 00000000000..7c64772db99
--- /dev/null
+++ b/src/mame/video/jagblit.h
@@ -0,0 +1,139 @@
+/***************************************************************************
+
+ Atari Jaguar blitter
+
+****************************************************************************
+
+ ------------------------------------------------------------
+ BLITTER REGISTERS
+ ------------------------------------------------------------
+ F02200-F022FF R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Blitter registers
+ F02200 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_BASE - A1 base register
+ F02204 W -------- ---xxxxx -xxxxxxx xxxxx-xx A1_FLAGS - A1 flags register
+ W -------- ---x---- -------- -------- (YSIGNSUB - invert sign of Y delta)
+ W -------- ----x--- -------- -------- (XSIGNSUB - invert sign of X delta)
+ W -------- -----x-- -------- -------- (Y add control)
+ W -------- ------xx -------- -------- (X add control)
+ W -------- -------- -xxxxxx- -------- (width in 6-bit floating point)
+ W -------- -------- -------x xx------ (ZOFFS1-6 - Z data offset)
+ W -------- -------- -------- --xxx--- (PIXEL - pixel size)
+ W -------- -------- -------- ------xx (PITCH1-4 - data phrase pitch)
+ F02208 W -xxxxxxx xxxxxxxx -xxxxxxx xxxxxxxx A1_CLIP - A1 clipping size
+ W -xxxxxxx xxxxxxxx -------- -------- (height)
+ W -------- -------- -xxxxxxx xxxxxxxx (width)
+ F0220C R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_PIXEL - A1 pixel pointer
+ R/W xxxxxxxx xxxxxxxx -------- -------- (Y pixel value)
+ R/W -------- -------- xxxxxxxx xxxxxxxx (X pixel value)
+ F02210 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_STEP - A1 step value
+ W xxxxxxxx xxxxxxxx -------- -------- (Y step value)
+ W -------- -------- xxxxxxxx xxxxxxxx (X step value)
+ F02214 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_FSTEP - A1 step fraction value
+ W xxxxxxxx xxxxxxxx -------- -------- (Y step fraction value)
+ W -------- -------- xxxxxxxx xxxxxxxx (X step fraction value)
+ F02218 R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_FPIXEL - A1 pixel pointer fraction
+ R/W xxxxxxxx xxxxxxxx -------- -------- (Y pixel fraction value)
+ R/W -------- -------- xxxxxxxx xxxxxxxx (X pixel fraction value)
+ F0221C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_INC - A1 increment
+ W xxxxxxxx xxxxxxxx -------- -------- (Y increment)
+ W -------- -------- xxxxxxxx xxxxxxxx (X increment)
+ F02220 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_FINC - A1 increment fraction
+ W xxxxxxxx xxxxxxxx -------- -------- (Y increment fraction)
+ W -------- -------- xxxxxxxx xxxxxxxx (X increment fraction)
+ F02224 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_BASE - A2 base register
+ F02228 W -------- ---xxxxx -xxxxxxx xxxxx-xx A2_FLAGS - A2 flags register
+ W -------- ---x---- -------- -------- (YSIGNSUB - invert sign of Y delta)
+ W -------- ----x--- -------- -------- (XSIGNSUB - invert sign of X delta)
+ W -------- -----x-- -------- -------- (Y add control)
+ W -------- ------xx -------- -------- (X add control)
+ W -------- -------- -xxxxxx- -------- (width in 6-bit floating point)
+ W -------- -------- -------x xx------ (ZOFFS1-6 - Z data offset)
+ W -------- -------- -------- --xxx--- (PIXEL - pixel size)
+ W -------- -------- -------- ------xx (PITCH1-4 - data phrase pitch)
+ F0222C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_MASK - A2 window mask
+ F02230 R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_PIXEL - A2 pixel pointer
+ R/W xxxxxxxx xxxxxxxx -------- -------- (Y pixel value)
+ R/W -------- -------- xxxxxxxx xxxxxxxx (X pixel value)
+ F02234 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_STEP - A2 step value
+ W xxxxxxxx xxxxxxxx -------- -------- (Y step value)
+ W -------- -------- xxxxxxxx xxxxxxxx (X step value)
+ F02238 W -xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_CMD - command register
+ W -x------ -------- -------- -------- (SRCSHADE - modify source intensity)
+ W --x----- -------- -------- -------- (BUSHI - hi priority bus)
+ W ---x---- -------- -------- -------- (BKGWREN - writeback destination)
+ W ----x--- -------- -------- -------- (DCOMPEN - write inhibit from data comparator)
+ W -----x-- -------- -------- -------- (BCOMPEN - write inhibit from bit coparator)
+ W ------x- -------- -------- -------- (CMPDST - compare dest instead of src)
+ W -------x xxx----- -------- -------- (logical operation)
+ W -------- ---xxx-- -------- -------- (ZMODE - Z comparator mode)
+ W -------- ------x- -------- -------- (ADDDSEL - select sum of src & dst)
+ W -------- -------x -------- -------- (PATDSEL - select pattern data)
+ W -------- -------- x------- -------- (TOPNEN - enable carry into top intensity nibble)
+ W -------- -------- -x------ -------- (TOPBEN - enable carry into top intensity byte)
+ W -------- -------- --x----- -------- (ZBUFF - enable Z updates in inner loop)
+ W -------- -------- ---x---- -------- (GOURD - enable gouraud shading in inner loop)
+ W -------- -------- ----x--- -------- (DSTA2 - reverses A2/A1 roles)
+ W -------- -------- -----x-- -------- (UPDA2 - add A2 step to A2 in outer loop)
+ W -------- -------- ------x- -------- (UPDA1 - add A1 step to A1 in outer loop)
+ W -------- -------- -------x -------- (UPDA1F - add A1 fraction step to A1 in outer loop)
+ W -------- -------- -------- x------- (diagnostic use)
+ W -------- -------- -------- -x------ (CLIP_A1 - clip A1 to window)
+ W -------- -------- -------- --x----- (DSTWRZ - enable dest Z write in inner loop)
+ W -------- -------- -------- ---x---- (DSTENZ - enable dest Z read in inner loop)
+ W -------- -------- -------- ----x--- (DSTEN - enables dest data read in inner loop)
+ W -------- -------- -------- -----x-- (SRCENX - enable extra src read at start of inner)
+ W -------- -------- -------- ------x- (SRCENZ - enables source Z read in inner loop)
+ W -------- -------- -------- -------x (SRCEN - enables source data read in inner loop)
+ F02238 R xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_CMD - status register
+ R xxxxxxxx xxxxxxxx -------- -------- (inner count)
+ R -------- -------- xxxxxxxx xxxxxx-- (diagnostics)
+ R -------- -------- -------- ------x- (STOPPED - when stopped in collision detect)
+ R -------- -------- -------- -------x (IDLE - when idle)
+ F0223C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_COUNT - counters register
+ W xxxxxxxx xxxxxxxx -------- -------- (outer loop count)
+ W -------- -------- xxxxxxxx xxxxxxxx (inner loop count)
+ F02240-F02247 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_SRCD - source data register
+ F02248-F0224F W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_DSTD - destination data register
+ F02250-F02257 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_DSTZ - destination Z register
+ F02258-F0225F W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_SRCZ1 - source Z register 1
+ F02260-F02267 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_SRCZ2 - source Z register 2
+ F02268-F0226F W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_PATD - pattern data register
+ F02270 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_IINC - intensity increment
+ F02274 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_ZINC - Z increment
+ F02278 W -------- -------- -------- -----xxx B_STOP - collision control
+ W -------- -------- -------- -----x-- (STOPEN - enable blitter collision stops)
+ W -------- -------- -------- ------x- (ABORT - abort after stop)
+ W -------- -------- -------- -------x (RESUME - resume after stop)
+ F0227C W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I3 - intensity 3
+ F02280 W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I2 - intensity 2
+ F02284 W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I1 - intensity 1
+ F02288 W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I0 - intensity 0
+ F0228C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z3 - Z3
+ F02290 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z2 - Z2
+ F02294 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z1 - Z1
+ F02298 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z0 - Z0
+
+****************************************************************************/
+
+/* mask for flags that are always handled dynamically or ignored */
+#define DYNAMIC_COMMAND_MASK 0x00000704
+#define DYNAMIC_FLAGS_MASK 0xffe0fe04
+
+#define STATIC_COMMAND_MASK (~DYNAMIC_COMMAND_MASK)
+#define STATIC_FLAGS_MASK (~DYNAMIC_FLAGS_MASK)
+
+
+/* blitter registers */
+enum
+{
+ A1_BASE, A1_FLAGS, A1_CLIP, A1_PIXEL,
+ A1_STEP, A1_FSTEP, A1_FPIXEL, A1_INC,
+ A1_FINC, A2_BASE, A2_FLAGS, A2_MASK,
+ A2_PIXEL, A2_STEP, B_CMD, B_COUNT,
+ B_SRCD_H, B_SRCD_L, B_DSTD_H, B_DSTD_L,
+ B_DSTZ_H, B_DSTZ_L, B_SRCZ1_H, B_SRCZ1_L,
+ B_SRCZ2_H, B_SRCZ2_L, B_PATD_H, B_PATD_L,
+ B_IINC, B_ZINC, B_STOP, B_I3,
+ B_I2, B_I1, B_I0, B_Z3,
+ B_Z2, B_Z1, B_Z0,
+ BLITTER_REGS
+};
diff --git a/src/mame/video/jagobj.c b/src/mame/video/jagobj.c
new file mode 100644
index 00000000000..56facd66336
--- /dev/null
+++ b/src/mame/video/jagobj.c
@@ -0,0 +1,986 @@
+/***************************************************************************
+
+ Atari Jaguar object processor
+
+****************************************************************************/
+
+#ifndef INCLUDE_OBJECT_PROCESSOR
+#error jagobj.c is not directly compilable!
+#endif
+
+
+#define LOG_OBJECTS 0
+
+
+static UINT16 scanline[360];
+static UINT16 *clutbase;
+static UINT8 *blend_y, *blend_cc;
+
+
+
+/*************************************
+ *
+ * Object processor init
+ *
+ *************************************/
+
+void jagobj_init(void)
+{
+ int i;
+
+ /* allocate memory for tables */
+ blend_y = auto_malloc(256 * 256);
+ blend_cc = auto_malloc(256 * 256);
+
+ /* fill tables */
+ for (i = 0; i < 256 * 256; i++)
+ {
+ int y = (i >> 8) & 0xff;
+ int dy = (INT8)i;
+ int c1 = (i >> 8) & 0x0f;
+ int dc1 = (INT8)(i << 4) >> 4;
+ int c2 = (i >> 12) & 0x0f;
+ int dc2 = (INT8)(i & 0xf0) >> 4;
+
+ y += dy;
+ if (y < 0) y = 0;
+ else if (y > 0xff) y = 0xff;
+ blend_y[i] = y;
+
+ c1 += dc1;
+ if (c1 < 0) c1 = 0;
+ else if (c1 > 0x0f) c1 = 0x0f;
+ c2 += dc2;
+ if (c2 < 0) c2 = 0;
+ else if (c2 > 0x0f) c2 = 0x0f;
+ blend_cc[i] = (c2 << 4) | c1;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Blending function
+ *
+ *************************************/
+
+#define BLEND(dst, src) \
+ (dst) = (blend_cc[((dst) & 0xff00) | (((src) >> 8) & 0xff)] << 8) | blend_y[(((dst) & 0xff) << 8) | ((src) & 0xff)];
+
+
+
+/*************************************
+ *
+ * 4bpp bitmap renderers
+ *
+ *************************************/
+
+INLINE void bitmap_4_draw(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos, UINT8 flags, INT32 dxpos)
+{
+ if (firstpix & 7)
+ {
+ UINT32 pixsrc = src[firstpix / 8];
+ while (firstpix & 7)
+ {
+ int pix = (pixsrc >> (4 * (~firstpix & 7))) & 0x0f;
+ if ((!(flags & 4) || pix) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = clutbase[BYTE_XOR_BE(pix)];
+ else
+ BLEND(scanline[xpos], clutbase[BYTE_XOR_BE(pix)]);
+ }
+ xpos += dxpos;
+ firstpix++;
+ }
+ }
+
+ firstpix /= 8;
+ iwidth /= 8;
+ iwidth -= firstpix;
+
+ while (iwidth-- > 0)
+ {
+ UINT32 pix = src[firstpix++];
+ if (!(flags & 4) || pix)
+ {
+ if ((!(flags & 4) || (pix & 0xf0000000)) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = clutbase[BYTE_XOR_BE(pix >> 28)];
+ else
+ BLEND(scanline[xpos], clutbase[BYTE_XOR_BE(pix >> 28)]);
+ }
+ xpos += dxpos;
+
+ if ((!(flags & 4) || (pix & 0x0f000000)) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = clutbase[BYTE_XOR_BE((pix >> 24) & 0x0f)];
+ else
+ BLEND(scanline[xpos], clutbase[BYTE_XOR_BE((pix >> 24) & 0x0f)]);
+ }
+ xpos += dxpos;
+
+ if ((!(flags & 4) || (pix & 0x00f00000)) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = clutbase[BYTE_XOR_BE((pix >> 20) & 0x0f)];
+ else
+ BLEND(scanline[xpos], clutbase[BYTE_XOR_BE((pix >> 20) & 0x0f)]);
+ }
+ xpos += dxpos;
+
+ if ((!(flags & 4) || (pix & 0x000f0000)) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = clutbase[BYTE_XOR_BE((pix >> 16) & 0x0f)];
+ else
+ BLEND(scanline[xpos], clutbase[BYTE_XOR_BE((pix >> 16) & 0x0f)]);
+ }
+ xpos += dxpos;
+
+ if ((!(flags & 4) || (pix & 0x0000f000)) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = clutbase[BYTE_XOR_BE((pix >> 12) & 0x0f)];
+ else
+ BLEND(scanline[xpos], clutbase[BYTE_XOR_BE((pix >> 12) & 0x0f)]);
+ }
+ xpos += dxpos;
+
+ if ((!(flags & 4) || (pix & 0x00000f00)) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = clutbase[BYTE_XOR_BE((pix >> 8) & 0x0f)];
+ else
+ BLEND(scanline[xpos], clutbase[BYTE_XOR_BE((pix >> 8) & 0x0f)]);
+ }
+ xpos += dxpos;
+
+ if ((!(flags & 4) || (pix & 0x000000f0)) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = clutbase[BYTE_XOR_BE((pix >> 4) & 0x0f)];
+ else
+ BLEND(scanline[xpos], clutbase[BYTE_XOR_BE((pix >> 4) & 0x0f)]);
+ }
+ xpos += dxpos;
+
+ if ((!(flags & 4) || (pix & 0x0000000f)) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = clutbase[BYTE_XOR_BE(pix & 0x0f)];
+ else
+ BLEND(scanline[xpos], clutbase[BYTE_XOR_BE(pix & 0x0f)]);
+ }
+ xpos += dxpos;
+ }
+ else
+ xpos += 8 * dxpos;
+ }
+}
+
+static void bitmap_4_0(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_4_draw(firstpix, iwidth, src, xpos, 0, 1);
+}
+
+static void bitmap_4_1(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_4_draw(firstpix, iwidth, src, xpos, 1, -1);
+}
+
+static void bitmap_4_2(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_4_draw(firstpix, iwidth, src, xpos, 2, 1);
+}
+
+static void bitmap_4_3(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_4_draw(firstpix, iwidth, src, xpos, 3, -1);
+}
+
+static void bitmap_4_4(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_4_draw(firstpix, iwidth, src, xpos, 4, 1);
+}
+
+static void bitmap_4_5(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_4_draw(firstpix, iwidth, src, xpos, 5, -1);
+}
+
+static void bitmap_4_6(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_4_draw(firstpix, iwidth, src, xpos, 6, 1);
+}
+
+static void bitmap_4_7(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_4_draw(firstpix, iwidth, src, xpos, 7, -1);
+}
+
+static void (*bitmap4[8])(INT32, INT32, UINT32 *, INT32) =
+{
+ bitmap_4_0,
+ bitmap_4_1,
+ bitmap_4_2,
+ bitmap_4_3,
+ bitmap_4_4,
+ bitmap_4_5,
+ bitmap_4_6,
+ bitmap_4_7
+};
+
+
+
+/*************************************
+ *
+ * 8bpp bitmap renderers
+ *
+ *************************************/
+
+INLINE void bitmap_8_draw(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos, UINT8 flags, INT32 dxpos)
+{
+ if (firstpix & 3)
+ {
+ UINT32 pixsrc = src[firstpix / 4];
+ while (firstpix & 3)
+ {
+ UINT8 pix = pixsrc >> (8 * (~firstpix & 3));
+ if ((!(flags & 4) || pix) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = clutbase[BYTE_XOR_BE(pix)];
+ else
+ BLEND(scanline[xpos], clutbase[BYTE_XOR_BE(pix)]);
+ }
+ xpos += dxpos;
+ firstpix++;
+ }
+ }
+
+ firstpix /= 4;
+ iwidth /= 4;
+ iwidth -= firstpix;
+
+ while (iwidth-- > 0)
+ {
+ UINT32 pix = src[firstpix++];
+ if (!(flags & 4) || pix)
+ {
+ if ((!(flags & 4) || (pix & 0xff000000)) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = clutbase[BYTE_XOR_BE(pix >> 24)];
+ else
+ BLEND(scanline[xpos], clutbase[BYTE_XOR_BE(pix >> 24)]);
+ }
+ xpos += dxpos;
+
+ if ((!(flags & 4) || (pix & 0x00ff0000)) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = clutbase[BYTE_XOR_BE((pix >> 16) & 0xff)];
+ else
+ BLEND(scanline[xpos], clutbase[BYTE_XOR_BE((pix >> 16) & 0xff)]);
+ }
+ xpos += dxpos;
+
+ if ((!(flags & 4) || (pix & 0x0000ff00)) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = clutbase[BYTE_XOR_BE((pix >> 8) & 0xff)];
+ else
+ BLEND(scanline[xpos], clutbase[BYTE_XOR_BE((pix >> 8) & 0xff)]);
+ }
+ xpos += dxpos;
+
+ if ((!(flags & 4) || (pix & 0x000000ff)) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = clutbase[BYTE_XOR_BE(pix & 0xff)];
+ else
+ BLEND(scanline[xpos], clutbase[BYTE_XOR_BE(pix & 0xff)]);
+ }
+ xpos += dxpos;
+ }
+ else
+ xpos += 4 * dxpos;
+ }
+}
+
+static void bitmap_8_0(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_8_draw(firstpix, iwidth, src, xpos, 0, 1);
+}
+
+static void bitmap_8_1(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_8_draw(firstpix, iwidth, src, xpos, 1, -1);
+}
+
+static void bitmap_8_2(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_8_draw(firstpix, iwidth, src, xpos, 2, 1);
+}
+
+static void bitmap_8_3(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_8_draw(firstpix, iwidth, src, xpos, 3, -1);
+}
+
+static void bitmap_8_4(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_8_draw(firstpix, iwidth, src, xpos, 4, 1);
+}
+
+static void bitmap_8_5(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_8_draw(firstpix, iwidth, src, xpos, 5, -1);
+}
+
+static void bitmap_8_6(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_8_draw(firstpix, iwidth, src, xpos, 6, 1);
+}
+
+static void bitmap_8_7(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_8_draw(firstpix, iwidth, src, xpos, 7, -1);
+}
+
+static void (*bitmap8[8])(INT32, INT32, UINT32 *, INT32) =
+{
+ bitmap_8_0,
+ bitmap_8_1,
+ bitmap_8_2,
+ bitmap_8_3,
+ bitmap_8_4,
+ bitmap_8_5,
+ bitmap_8_6,
+ bitmap_8_7
+};
+
+
+
+/*************************************
+ *
+ * 16bpp bitmap renderers
+ *
+ *************************************/
+
+INLINE void bitmap_16_draw(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos, UINT8 flags, INT32 dxpos)
+{
+ if (firstpix & 1)
+ {
+ UINT16 pix = src[firstpix / 2];
+ if ((!(flags & 4) || pix) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = pix;
+ else
+ BLEND(scanline[xpos], pix);
+ }
+ xpos += dxpos;
+ }
+
+ firstpix /= 2;
+ iwidth /= 2;
+ iwidth -= firstpix;
+
+ while (iwidth-- > 0)
+ {
+ UINT32 pix = src[firstpix++];
+ if (!(flags & 4) || pix)
+ {
+ if ((!(flags & 4) || (pix >> 16)) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = pix >> 16;
+ else
+ BLEND(scanline[xpos], pix >> 16);
+ }
+ xpos += dxpos;
+
+ if ((!(flags & 4) || (pix & 0xffff)) && (UINT32)xpos < 360)
+ {
+ if (!(flags & 2))
+ scanline[xpos] = pix;
+ else
+ BLEND(scanline[xpos], pix);
+ }
+ xpos += dxpos;
+ }
+ else
+ xpos += 2 * dxpos;
+ }
+}
+
+static void bitmap_16_0(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_16_draw(firstpix, iwidth, src, xpos, 0, 1);
+}
+
+static void bitmap_16_1(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_16_draw(firstpix, iwidth, src, xpos, 1, -1);
+}
+
+static void bitmap_16_2(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_16_draw(firstpix, iwidth, src, xpos, 2, 1);
+}
+
+static void bitmap_16_3(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_16_draw(firstpix, iwidth, src, xpos, 3, -1);
+}
+
+static void bitmap_16_4(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_16_draw(firstpix, iwidth, src, xpos, 4, 1);
+}
+
+static void bitmap_16_5(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_16_draw(firstpix, iwidth, src, xpos, 5, -1);
+}
+
+static void bitmap_16_6(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_16_draw(firstpix, iwidth, src, xpos, 6, 1);
+}
+
+static void bitmap_16_7(INT32 firstpix, INT32 iwidth, UINT32 *src, INT32 xpos)
+{
+ bitmap_16_draw(firstpix, iwidth, src, xpos, 7, -1);
+}
+
+static void (*bitmap16[8])(INT32, INT32, UINT32 *, INT32) =
+{
+ bitmap_16_0,
+ bitmap_16_1,
+ bitmap_16_2,
+ bitmap_16_3,
+ bitmap_16_4,
+ bitmap_16_5,
+ bitmap_16_6,
+ bitmap_16_7
+};
+
+
+
+INLINE UINT8 lookup_pixel(const UINT32 *src, int i, int pitch, int depth)
+{
+ int ppl = 32 / depth;
+ UINT32 data = src[((i & ppl) / ppl) + ((i / (ppl*2)) * 2 * pitch)];
+ UINT8 pix = (data >> ((~i & (ppl-1)) * depth)) & ((1 << depth) - 1);
+ return pix;
+}
+
+
+
+/*************************************
+ *
+ * Standard bitmap processor
+ *
+ *************************************/
+
+static UINT32 *process_bitmap(UINT32 *objdata, int vc, int logit)
+{
+ /* extract minimal data */
+ UINT32 upper = objdata[0];
+ UINT32 lower = objdata[1];
+ UINT32 ypos = (lower >> 3) & 0x7ff;
+ UINT32 height = (lower >> 14) & 0x3ff;
+ UINT32 link = (lower >> 24) | ((upper & 0x7ff) << 8);
+ UINT32 data = (upper >> 11);
+ UINT32 *src = (UINT32 *)get_jaguar_memory(data << 3);
+
+ if (logit)
+ {
+ /* second phrase */
+ UINT32 upper2 = objdata[2];
+ UINT32 lower2 = objdata[3];
+
+ /* extract data */
+ INT32 xpos = (INT32)(lower2 << 20) >> 20;
+ UINT8 depth = 1 << ((lower2 >> 12) & 7);
+ UINT8 pitch = (lower2 >> 15) & 7;
+ UINT32 dwidth = (lower2 >> 18) & 0x3ff;
+ INT32 iwidth = (lower2 >> 28) | ((upper2 & 0x3f) << 4);
+ UINT8 _index = (upper2 >> 6) & 0x3f;
+ UINT8 flags = (upper2 >> 13) & 0x0f;
+ UINT8 firstpix = (upper2 >> 17) & 0x3f;
+
+ logerror(" ypos=%X height=%X link=%06X data=%06X\n", ypos, height, link << 3, data << 3);
+ logerror(" xpos=%X depth=%X pitch=%X dwidth=%X iwidth=%X index=%X flags=%X firstpix=%X\n", xpos, depth, pitch, dwidth, iwidth, _index, flags, firstpix);
+ }
+
+ /* only render if valid */
+ if (vc >= ypos && height > 0 && src)
+ {
+ /* second phrase */
+ UINT32 upper2 = objdata[2];
+ UINT32 lower2 = objdata[3];
+
+ /* extract data */
+ INT32 xpos = (INT32)(lower2 << 20) >> 20;
+ UINT8 depthlog = (lower2 >> 12) & 7;
+ UINT8 pitch = (lower2 >> 15) & 7;
+ UINT32 dwidth = (lower2 >> 18) & 0x3ff;
+ UINT32 iwidth = ((lower2 >> 28) | ((upper2 & 0x3f) << 4)) << (6 - depthlog);
+ UINT8 _index = (upper2 >> 5) & 0xfe;
+ UINT8 flags = (upper2 >> 13) & 0x0f;
+ UINT8 firstpix = ((upper2 >> 17) & 0x1f) >> depthlog;
+ int i, dxpos = (flags & 1) ? -1 : 1;
+
+ /* preadjust for firstpix */
+ xpos += firstpix * dxpos;
+
+ /* switch off the depth */
+ switch (depthlog)
+ {
+ /* 1bpp case */
+ case 0:
+ {
+ UINT16 *clut = (UINT16 *)jaguar_gpu_clut;
+ clut += _index & 0xfe;
+
+ /* non-blending */
+ if (!(flags & 2))
+ {
+ for (i = firstpix; i < iwidth; i++)
+ {
+ UINT8 pix = lookup_pixel(src, i, pitch, 1);
+
+ if (xpos >= 0 && xpos < 360 && (pix || !(flags & 4)))
+ scanline[xpos] = clut[BYTE_XOR_BE(pix)];
+ xpos += dxpos;
+ }
+ }
+
+ /* blending */
+ else
+ {
+ for (i = firstpix; i < iwidth; i++)
+ {
+ UINT8 pix = lookup_pixel(src, i, pitch, 1);
+
+ if (xpos >= 0 && xpos < 360 && (pix || !(flags & 4)))
+ BLEND(scanline[xpos], clut[BYTE_XOR_BE(pix)]);
+ xpos += dxpos;
+ }
+ }
+ break;
+ }
+
+ /* 2bpp case */
+ case 1:
+ {
+ UINT16 *clut = (UINT16 *)jaguar_gpu_clut;
+ clut += _index & 0xfc;
+
+ /* non-blending */
+ if (!(flags & 2))
+ {
+ for (i = firstpix; i < iwidth; i++)
+ {
+ UINT8 pix = lookup_pixel(src, i, pitch, 2);
+
+ if (xpos >= 0 && xpos < 360 && (pix || !(flags & 4)))
+ scanline[xpos] = clut[BYTE_XOR_BE(pix)];
+ xpos += dxpos;
+ }
+ }
+
+ /* blending */
+ else
+ {
+ for (i = firstpix; i < iwidth; i++)
+ {
+ UINT8 pix = lookup_pixel(src, i, pitch, 2);
+
+ if (xpos >= 0 && xpos < 360 && (pix || !(flags & 4)))
+ BLEND(scanline[xpos], clut[BYTE_XOR_BE(pix)]);
+ xpos += dxpos;
+ }
+ }
+ break;
+ }
+
+ /* 4bpp case */
+ case 2:
+ /* only handle pitch=1 for now */
+ if (pitch != 1)
+ logerror("Unhandled pitch = %d\n", pitch);
+
+ clutbase = (UINT16 *)jaguar_gpu_clut + (_index & 0xf0);
+ (*bitmap4[flags & 7])(firstpix, iwidth, src, xpos);
+ break;
+
+ /* 8bpp case */
+ case 3:
+ /* only handle pitch=1 for now */
+ if (pitch != 1)
+ logerror("Unhandled pitch = %d\n", pitch);
+
+ clutbase = (UINT16 *)jaguar_gpu_clut;
+ (*bitmap8[flags & 7])(firstpix, iwidth, src, xpos);
+ break;
+
+ /* 16bpp case */
+ case 4:
+ /* only handle pitch=1 for now */
+ if (pitch != 1)
+ logerror("Unhandled pitch = %d\n", pitch);
+
+ (*bitmap16[flags & 7])(firstpix, iwidth, src, xpos);
+ break;
+
+ default:
+ fprintf(stderr, "Unhandled bitmap source depth = %d\n", depthlog);
+ break;
+ }
+
+ /* decrement the height and add to the source data offset */
+ objdata[0] = upper + (dwidth << 11);
+ objdata[1] = lower - (1 << 14);
+ }
+
+ return (UINT32 *)get_jaguar_memory(link << 3);
+}
+
+
+
+/*************************************
+ *
+ * Scaled bitmap object processor
+ *
+ *************************************/
+
+static UINT32 *process_scaled_bitmap(UINT32 *objdata, int vc, int logit)
+{
+ /* extract data */
+ UINT32 upper = objdata[0];
+ UINT32 lower = objdata[1];
+ UINT32 ypos = (lower >> 3) & 0x7ff;
+ UINT32 height = (lower >> 14) & 0x3ff;
+ UINT32 link = (lower >> 24) | ((upper & 0x7ff) << 8);
+ UINT32 data = (upper >> 11);
+ UINT32 *src = (UINT32 *)get_jaguar_memory(data << 3);
+
+ /* third phrase */
+ UINT32 lower3 = objdata[5];
+ INT32 remainder = (lower3 >> 16) & 0xff;
+
+ if (logit)
+ {
+ /* second phrase */
+ UINT32 upper2 = objdata[2];
+ UINT32 lower2 = objdata[3];
+
+ /* extract data */
+ INT32 xpos = (INT32)(lower2 << 20) >> 20;
+ UINT8 depth = 1 << ((lower2 >> 12) & 7);
+ UINT8 pitch = (lower2 >> 15) & 7;
+ UINT32 dwidth = (lower2 >> 18) & 0x3ff;
+ INT32 iwidth = (lower2 >> 28) | ((upper2 & 0x3f) << 4);
+ UINT8 _index = (upper2 >> 6) & 0x3f;
+ UINT8 flags = (upper2 >> 13) & 0x0f;
+ UINT8 firstpix = (upper2 >> 17) & 0x3f;
+
+ INT32 hscale = lower3 & 0xff;
+ INT32 vscale = (lower3 >> 8) & 0xff;
+
+ logerror(" ypos=%X height=%X link=%06X data=%06X\n", ypos, height, link << 3, data << 3);
+ logerror(" xpos=%X depth=%X pitch=%X dwidth=%X iwidth=%X index=%X flags=%X firstpix=%X\n", xpos, depth, pitch, dwidth, iwidth, _index, flags, firstpix);
+ logerror(" hscale=%X vscale=%X remainder=%X\n", hscale, vscale, remainder);
+ }
+
+ /* only render if valid */
+ if (vc >= ypos && (height > 0 || remainder > 0) && src)
+ {
+ /* second phrase */
+ UINT32 upper2 = objdata[2];
+ UINT32 lower2 = objdata[3];
+
+ /* extract data */
+ INT32 xpos = (INT32)(lower2 << 20) >> 20;
+ UINT8 depthlog = (lower2 >> 12) & 7;
+ UINT8 pitch = (lower2 >> 15) & 7;
+ UINT32 dwidth = (lower2 >> 18) & 0x3ff;
+ INT32 iwidth = ((lower2 >> 28) | ((upper2 & 0x3f) << 4)) << (6 - depthlog);
+ UINT8 _index = (upper2 >> 5) & 0xfe;
+ UINT8 flags = (upper2 >> 13) & 0x0f;
+ UINT8 firstpix = ((upper2 >> 17) & 0x1f) >> depthlog;
+
+ INT32 hscale = lower3 & 0xff;
+ INT32 vscale = (lower3 >> 8) & 0xff;
+ INT32 xleft = hscale;
+ int dxpos = (flags & 1) ? -1 : 1;
+ int xpix = firstpix, yinc;
+
+ /* only handle pitch=0 for now */
+ if (pitch != 1)
+ logerror("Unhandled pitch = %d\n", pitch);
+ if (flags & 2)
+ {
+ mame_printf_debug("Unhandled blend mode in scaled bitmap case\n");
+ logerror("Unhandled blend mode in scaled bitmap case\n");
+ }
+
+ /* preadjust for firstpix */
+ xpos += firstpix * dxpos;
+
+ /* ignore hscale = 0 */
+ if (hscale != 0)
+ {
+ /* switch off the depth */
+ switch (depthlog)
+ {
+ case 2:
+ {
+ UINT16 *clut = (UINT16 *)jaguar_gpu_clut;
+ clut += _index & 0xf0;
+
+ /* render in phrases */
+ while (xpix < iwidth)
+ {
+ UINT16 pix = (src[xpix / 8] >> ((~xpix & 7) * 4)) & 0x0f;
+
+ while (xleft > 0)
+ {
+ if (xpos >= 0 && xpos < 360 && (pix || !(flags & 4)))
+ scanline[xpos] = clut[BYTE_XOR_BE(pix)];
+ xpos += dxpos;
+ xleft -= 0x20;
+ }
+ while (xleft <= 0)
+ xleft += hscale, xpix++;
+ }
+ break;
+ }
+
+ case 3:
+ {
+ UINT16 *clut = (UINT16 *)jaguar_gpu_clut;
+
+ /* render in phrases */
+ while (xpix < iwidth)
+ {
+ UINT16 pix = (src[xpix / 4] >> ((~xpix & 3) * 8)) & 0xff;
+
+ while (xleft > 0)
+ {
+ if (xpos >= 0 && xpos < 360 && (pix || !(flags & 4)))
+ scanline[xpos] = clut[BYTE_XOR_BE(pix)];
+ xpos += dxpos;
+ xleft -= 0x20;
+ }
+ while (xleft <= 0)
+ xleft += hscale, xpix++;
+ }
+ break;
+ }
+
+ case 4:
+ while (xpix < iwidth)
+ {
+ UINT16 pix = src[xpix / 2] >> ((~xpix & 1) * 16);
+
+ while (xleft > 0)
+ {
+ if (xpos >= 0 && xpos < 360 && (pix || !(flags & 4)))
+ scanline[xpos] = pix;
+ xpos += dxpos;
+ xleft -= 0x20;
+ }
+ while (xleft <= 0)
+ xleft += hscale, xpix++;
+ }
+ break;
+
+ default:
+ fprintf(stderr, "Unhandled scaled bitmap source depth = %d\n", depthlog);
+ break;
+ }
+ }
+
+ /* handle Y scale */
+ remainder -= 0x20;
+ yinc = 0;
+ while (remainder <= 0 && vscale != 0)
+ remainder += vscale, yinc++;
+ if (yinc > height)
+ yinc = height, remainder = 0;
+
+ /* decrement the height and add to the source data offset */
+ objdata[0] = upper + yinc * (dwidth << 11);
+ objdata[1] = lower - yinc * (1 << 14);
+ objdata[5] = (lower3 & ~0xff0000) | ((remainder & 0xff) << 16);
+ }
+
+ return (UINT32 *)get_jaguar_memory(link << 3);
+}
+
+
+
+/*************************************
+ *
+ * Brach object processor
+ *
+ *************************************/
+
+static UINT32 *process_branch(UINT32 *objdata, int vc, int logit)
+{
+ UINT32 upper = objdata[0];
+ UINT32 lower = objdata[1];
+ UINT32 ypos = (lower >> 3) & 0x7ff;
+ UINT32 cc = (lower >> 14) & 7;
+ UINT32 link = (lower >> 24) | ((upper & 0x7ff) << 8);
+ int taken = 0;
+
+#ifndef MESS
+ if ((ypos & 1) && ypos != 0x7ff)
+ fprintf(stderr, " branch cc=%d ypos=%X link=%06X - \n", cc, ypos, link << 3);
+#endif
+
+ switch (cc)
+ {
+ /* 0: branch if ypos == vc or ypos == 0x7ff */
+ case 0:
+ if (logit) logerror(" branch if %X == vc or %X == 0x7ff to %06X\n", ypos, ypos, link << 3);
+ taken = (ypos == vc) || (ypos == 0x7ff);
+ break;
+
+ /* 1: branch if ypos > vc */
+ case 1:
+ if (logit) logerror(" branch if %X > vc to %06X\n", ypos, link << 3);
+ taken = (ypos > vc);
+ break;
+
+ /* 2: branch if ypos < vc */
+ case 2:
+ if (logit) logerror(" branch if %X < vc to %06X\n", ypos, link << 3);
+ taken = (ypos < vc);
+ break;
+
+ /* 3: branch if object processor flag is set */
+ case 3:
+ if (logit) logerror(" branch if object flag set to %06X\n", link << 3);
+ fprintf(stderr, "Unhandled branch!\n");
+ link = 0, taken = 1;
+ break;
+
+ /* 4: branch on second half of display line */
+ case 4:
+ if (logit) logerror(" branch if second half of line to %06X\n", link << 3);
+ taken = (vc & 1);
+ break;
+
+ default:
+ fprintf(stderr, "Invalid branch!\n");
+ link = 0, taken = 1;
+ break;
+ }
+
+ /* handle the branch */
+ return taken ? (UINT32 *)get_jaguar_memory(link << 3) : (objdata + 2);
+}
+
+
+
+/*************************************
+ *
+ * Process object list
+ *
+ *************************************/
+
+static void process_object_list(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT32 *objdata;
+ int y, x, pass;
+ int logit;
+
+ /* loop over all scanlines */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ /* erase the scanline first */
+ for (x = 0; x < 336; x++)
+ scanline[x] = gpu_regs[BG];
+
+#if LOG_OBJECTS
+ logit = (y == cliprect->min_y);
+#else
+ logit = 0;
+#endif
+
+ /* two passes per scanline */
+ for (pass = 0; pass < 1; pass++)
+ {
+ int vc = y * 2 + pass + gpu_regs[VBE];
+ int done = 0, count = 0;
+
+ /* fetch the object pointer */
+ objdata = (UINT32 *)get_jaguar_memory((gpu_regs[OLP_H] << 16) | gpu_regs[OLP_L]);
+ while (!done && objdata && count++ < 100)
+ {
+ /* the low 3 bits determine the command */
+ switch (objdata[1] & 7)
+ {
+ /* bitmap object */
+ case 0:
+ if (logit)
+ logerror("bitmap = %08X-%08X %08X-%08X\n", objdata[0], objdata[1], objdata[2], objdata[3]);
+ objdata = process_bitmap(objdata, vc, logit);
+ break;
+
+ /* scaled bitmap object */
+ case 1:
+ if (logit)
+ logerror("scaled = %08X-%08X %08X-%08X %08X-%08X\n", objdata[0], objdata[1], objdata[2], objdata[3], objdata[4], objdata[5]);
+ objdata = process_scaled_bitmap(objdata, vc, logit);
+ break;
+
+ /* branch */
+ case 3:
+ if (logit)
+ logerror("branch = %08X-%08X\n", objdata[0], objdata[1]);
+ objdata = process_branch(objdata, vc, logit);
+ break;
+
+ /* stop */
+ case 4:
+ {
+ int interrupt = (objdata[1] >> 3) & 1;
+ done = 1;
+
+ if (logit)
+ logerror("stop = %08X-%08X\n", objdata[0], objdata[1]);
+ if (interrupt)
+ {
+#ifndef MESS
+ fprintf(stderr, "stop int=%d\n", interrupt);
+#endif
+ cpu_irq_state |= 4;
+ update_cpu_irq();
+ }
+ break;
+ }
+
+ default:
+ fprintf(stderr, "%08X %08X\n", objdata[0], objdata[1]);
+ done = 1;
+ break;
+ }
+ }
+ }
+
+ /* render this scanline */
+ draw_scanline16(bitmap, 0, y, 336, scanline, pen_table, -1);
+ }
+}
diff --git a/src/mame/video/jaguar.c b/src/mame/video/jaguar.c
new file mode 100644
index 00000000000..e4ea4b5aa88
--- /dev/null
+++ b/src/mame/video/jaguar.c
@@ -0,0 +1,881 @@
+/***************************************************************************
+
+ Atari Jaguar hardware
+
+****************************************************************************
+
+ ------------------------------------------------------------
+ TOM REGISTERS
+ ------------------------------------------------------------
+ F00000-F0FFFF R/W xxxxxxxx xxxxxxxx Internal Registers
+ F00000 R/W -x-xx--- xxxxxxxx MEMCON1 - memory config reg 1
+ -x------ -------- (CPU32 - is the CPU 32bits?)
+ ---xx--- -------- (IOSPEED - external I/O clock cycles)
+ -------- x------- (FASTROM - reduces ROM clock cycles)
+ -------- -xx----- (DRAMSPEED - sets RAM clock cycles)
+ -------- ---xx--- (ROMSPEED - sets ROM clock cycles)
+ -------- -----xx- (ROMWIDTH - sets width of ROM: 8,16,32,64 bits)
+ -------- -------x (ROMHI - controls ROM mapping)
+ F00002 R/W --xxxxxx xxxxxxxx MEMCON2 - memory config reg 2
+ --x----- -------- (HILO - image display bit order)
+ ---x---- -------- (BIGEND - big endian addressing?)
+ ----xxxx -------- (REFRATE - DRAM refresh rate)
+ -------- xx------ (DWIDTH1 - DRAM1 width: 8,16,32,64 bits)
+ -------- --xx---- (COLS1 - DRAM1 columns: 256,512,1024,2048)
+ -------- ----xx-- (DWIDTH0 - DRAM0 width: 8,16,32,64 bits)
+ -------- ------xx (COLS0 - DRAM0 columns: 256,512,1024,2048)
+ F00004 R/W -----xxx xxxxxxxx HC - horizontal count
+ -----x-- -------- (which half of the display)
+ ------xx xxxxxxxx (10-bit counter)
+ F00006 R/W ----xxxx xxxxxxxx VC - vertical count
+ ----x--- -------- (which field is being generated)
+ -----xxx xxxxxxxx (11-bit counter)
+ F00008 R -----xxx xxxxxxxx LPH - light pen horizontal position
+ F0000A R -----xxx xxxxxxxx LPV - light pen vertical position
+ F00010-F00017 R xxxxxxxx xxxxxxxx OB - current object code from the graphics processor
+ F00020-F00023 W xxxxxxxx xxxxxxxx OLP - start of the object list
+ F00026 W -------- -------x OBF - object processor flag
+ F00028 W ----xxxx xxxxxxxx VMODE - video mode
+ W ----xxx- -------- (PWIDTH1-8 - width of pixel in video clock cycles)
+ W -------x -------- (VARMOD - enable variable color resolution)
+ W -------- x------- (BGEN - clear line buffere to BG color)
+ W -------- -x------ (CSYNC - enable composite sync on VSYNC)
+ W -------- --x----- (BINC - local border color if INCEN)
+ W -------- ---x---- (INCEN - encrustation enable)
+ W -------- ----x--- (GENLOCK - enable genlock)
+ W -------- -----xx- (MODE - CRY16,RGB24,DIRECT16,RGB16)
+ W -------- -------x (VIDEN - enables video)
+ F0002A W xxxxxxxx xxxxxxxx BORD1 - border color (red/green)
+ F0002C W -------- xxxxxxxx BORD2 - border color (blue)
+ F0002E W ------xx xxxxxxxx HP - horizontal period
+ F00030 W -----xxx xxxxxxxx HBB - horizontal blanking begin
+ F00032 W -----xxx xxxxxxxx HBE - horizontal blanking end
+ F00034 W -----xxx xxxxxxxx HSYNC - horizontal sync
+ F00036 W ------xx xxxxxxxx HVS - horizontal vertical sync
+ F00038 W -----xxx xxxxxxxx HDB1 - horizontal display begin 1
+ F0003A W -----xxx xxxxxxxx HDB2 - horizontal display begin 2
+ F0003C W -----xxx xxxxxxxx HDE - horizontal display end
+ F0003E W -----xxx xxxxxxxx VP - vertical period
+ F00040 W -----xxx xxxxxxxx VBB - vertical blanking begin
+ F00042 W -----xxx xxxxxxxx VBE - vertical blanking end
+ F00044 W -----xxx xxxxxxxx VS - vertical sync
+ F00046 W -----xxx xxxxxxxx VDB - vertical display begin
+ F00048 W -----xxx xxxxxxxx VDE - vertical display end
+ F0004A W -----xxx xxxxxxxx VEB - vertical equalization begin
+ F0004C W -----xxx xxxxxxxx VEE - vertical equalization end
+ F0004E W -----xxx xxxxxxxx VI - vertical interrupt
+ F00050 W xxxxxxxx xxxxxxxx PIT0 - programmable interrupt timer 0
+ F00052 W xxxxxxxx xxxxxxxx PIT1 - programmable interrupt timer 1
+ F00054 W ------xx xxxxxxxx HEQ - horizontal equalization end
+ F00058 W xxxxxxxx xxxxxxxx BG - background color
+ F000E0 R/W ---xxxxx ---xxxxx INT1 - CPU interrupt control register
+ ---x---- -------- (C_JERCLR - clear pending Jerry ints)
+ ----x--- -------- (C_PITCLR - clear pending PIT ints)
+ -----x-- -------- (C_OPCLR - clear pending object processor ints)
+ ------x- -------- (C_GPUCLR - clear pending graphics processor ints)
+ -------x -------- (C_VIDCLR - clear pending video timebase ints)
+ -------- ---x---- (C_JERENA - enable Jerry ints)
+ -------- ----x--- (C_PITENA - enable PIT ints)
+ -------- -----x-- (C_OPENA - enable object processor ints)
+ -------- ------x- (C_GPUENA - enable graphics processor ints)
+ -------- -------x (C_VIDENA - enable video timebase ints)
+ F000E2 W -------- -------- INT2 - CPU interrupt resume register
+ F00400-F005FF R/W xxxxxxxx xxxxxxxx CLUT - color lookup table A
+ F00600-F007FF R/W xxxxxxxx xxxxxxxx CLUT - color lookup table B
+ F00800-F00D9F R/W xxxxxxxx xxxxxxxx LBUF - line buffer A
+ F01000-F0159F R/W xxxxxxxx xxxxxxxx LBUF - line buffer B
+ F01800-F01D9F R/W xxxxxxxx xxxxxxxx LBUF - line buffer currently selected
+ ------------------------------------------------------------
+ F02000-F021FF R/W xxxxxxxx xxxxxxxx GPU control registers
+ F02100 R/W xxxxxxxx xxxxxxxx G_FLAGS - GPU flags register
+ R/W x------- -------- (DMAEN - DMA enable)
+ R/W -x------ -------- (REGPAGE - register page)
+ W --x----- -------- (G_BLITCLR - clear blitter interrupt)
+ W ---x---- -------- (G_OPCLR - clear object processor int)
+ W ----x--- -------- (G_PITCLR - clear PIT interrupt)
+ W -----x-- -------- (G_JERCLR - clear Jerry interrupt)
+ W ------x- -------- (G_CPUCLR - clear CPU interrupt)
+ R/W -------x -------- (G_BLITENA - enable blitter interrupt)
+ R/W -------- x------- (G_OPENA - enable object processor int)
+ R/W -------- -x------ (G_PITENA - enable PIT interrupt)
+ R/W -------- --x----- (G_JERENA - enable Jerry interrupt)
+ R/W -------- ---x---- (G_CPUENA - enable CPU interrupt)
+ R/W -------- ----x--- (IMASK - interrupt mask)
+ R/W -------- -----x-- (NEGA_FLAG - ALU negative)
+ R/W -------- ------x- (CARRY_FLAG - ALU carry)
+ R/W -------- -------x (ZERO_FLAG - ALU zero)
+ F02104 W -------- ----xxxx G_MTXC - matrix control register
+ W -------- ----x--- (MATCOL - column/row major)
+ W -------- -----xxx (MATRIX3-15 - matrix width)
+ F02108 W ----xxxx xxxxxx-- G_MTXA - matrix address register
+ F0210C W -------- -----xxx G_END - data organization register
+ W -------- -----x-- (BIG_INST - big endian instruction fetch)
+ W -------- ------x- (BIG_PIX - big endian pixels)
+ W -------- -------x (BIG_IO - big endian I/O)
+ F02110 R/W xxxxxxxx xxxxxxxx G_PC - GPU program counter
+ F02114 R/W xxxxxxxx xx-xxxxx G_CTRL - GPU control/status register
+ R xxxx---- -------- (VERSION - GPU version code)
+ R/W ----x--- -------- (BUS_HOG - hog the bus!)
+ R/W -----x-- -------- (G_BLITLAT - blitter interrupt latch)
+ R/W ------x- -------- (G_OPLAT - object processor int latch)
+ R/W -------x -------- (G_PITLAT - PIT interrupt latch)
+ R/W -------- x------- (G_JERLAT - Jerry interrupt latch)
+ R/W -------- -x------ (G_CPULAT - CPU interrupt latch)
+ R/W -------- ---x---- (SINGLE_GO - single step one instruction)
+ R/W -------- ----x--- (SINGLE_STEP - single step mode)
+ R/W -------- -----x-- (FORCEINT0 - cause interrupt 0 on GPU)
+ R/W -------- ------x- (CPUINT - send GPU interrupt to CPU)
+ R/W -------- -------x (GPUGO - enable GPU execution)
+ F02118-F0211B R/W xxxxxxxx xxxxxxxx G_HIDATA - high data register
+ F0211C-F0211F R xxxxxxxx xxxxxxxx G_REMAIN - divide unit remainder
+ F0211C W -------- -------x G_DIVCTRL - divide unit control
+ W -------- -------x (DIV_OFFSET - 1=16.16 divide, 0=32-bit divide)
+ ------------------------------------------------------------
+
+****************************************************************************/
+
+#include "driver.h"
+#include "profiler.h"
+#include "machine/atarigen.h"
+#include "cpu/mips/r3000.h"
+#include "cpu/m68000/m68000.h"
+#include "includes/jaguar.h"
+#include "jagblit.h"
+
+
+#define LOG_BLITS 0
+#define LOG_BAD_BLITS 0
+#define LOG_BLITTER_STATS 0
+#define LOG_BLITTER_WRITE 0
+#define LOG_UNHANDLED_BLITS 0
+
+
+// interrupts to main CPU:
+// 0 = video (on the VI scanline)
+// 1 = GPU (write from GPU coprocessor)
+// 2 = object (stop object interrupt in display list)
+// 3 = timer (from the PIT)
+// 4 = jerry
+
+
+/* GPU registers */
+enum
+{
+ MEMCON1, MEMCON2, HC, VC,
+ LPH, LPV, GPU0, GPU1,
+ OB_HH, OB_HL, OB_LH, OB_LL,
+ GPU2, GPU3, GPU4, GPU5,
+ OLP_L, OLP_H, GPU6, OBF,
+ VMODE, BORD1, BORD2, HP,
+ HBB, HBE, HSYNC, HVS,
+ HDB1, HDB2, HDE, VP,
+ VBB, VBE, VS, VDB,
+ VDE, VEB, VEE, VI,
+ PIT0, PIT1, HEQ, GPU7,
+ BG,
+ INT1 = 0xe0/2,
+ INT2,
+ GPU_REGS
+};
+
+
+
+/*************************************
+ *
+ * Local variables
+ *
+ *************************************/
+
+/* blitter variables */
+static UINT32 blitter_regs[BLITTER_REGS];
+static UINT16 gpu_regs[GPU_REGS];
+
+static emu_timer *vi_timer;
+static UINT8 cpu_irq_state;
+
+static pen_t *pen_table;
+
+
+
+/*************************************
+ *
+ * Prototypes
+ *
+ *************************************/
+
+/* from jagobj.c */
+static void jagobj_init(void);
+static void process_object_list(mame_bitmap *bitmap, const rectangle *cliprect);
+
+/* from jagblit.c */
+static void generic_blitter(UINT32 command, UINT32 a1flags, UINT32 a2flags);
+static void blitter_09800001_010020_010020(UINT32 command, UINT32 a1flags, UINT32 a2flags);
+static void blitter_09800009_000020_000020(UINT32 command, UINT32 a1flags, UINT32 a2flags);
+static void blitter_01800009_000028_000028(UINT32 command, UINT32 a1flags, UINT32 a2flags);
+static void blitter_01800001_000018_000018(UINT32 command, UINT32 a1flags, UINT32 a2flags);
+static void blitter_01c00001_000018_000018(UINT32 command, UINT32 a1flags, UINT32 a2flags);
+
+#ifdef MESS
+static void blitter_00010000_xxxxxx_xxxxxx(UINT32 command, UINT32 a1flags, UINT32 a2flags);
+static void blitter_01800001_xxxxxx_xxxxxx(UINT32 command, UINT32 a1flags, UINT32 a2flags);
+static void blitter_x1800x01_xxxxxx_xxxxxx(UINT32 command, UINT32 a1flags, UINT32 a2flags);
+#endif
+
+
+
+/*************************************
+ *
+ * Compute X/Y coordinates
+ *
+ *************************************/
+
+INLINE void get_crosshair_xy(int player, int *x, int *y)
+{
+ *x = ((readinputport(3 + player * 2) & 0xff) * Machine->screen[0].width) >> 8;
+ *y = ((readinputport(4 + player * 2) & 0xff) * Machine->screen[0].height) >> 8;
+}
+
+
+
+/*************************************
+ *
+ * GPU optimization control
+ *
+ *************************************/
+
+void jaguar_gpu_suspend(void)
+{
+ cpunum_suspend(1, SUSPEND_REASON_SPIN, 1);
+}
+
+
+void jaguar_gpu_resume(void)
+{
+ cpunum_resume(1, SUSPEND_REASON_SPIN);
+}
+
+
+
+/*************************************
+ *
+ * Main CPU interrupts
+ *
+ *************************************/
+
+static void update_cpu_irq(void)
+{
+ if (cpu_irq_state & gpu_regs[INT1] & 0x1f)
+ cpunum_set_input_line(0, cojag_is_r3000 ? R3000_IRQ4 : MC68000_IRQ_6, ASSERT_LINE);
+ else
+ cpunum_set_input_line(0, cojag_is_r3000 ? R3000_IRQ4 : MC68000_IRQ_6, CLEAR_LINE);
+}
+
+
+static TIMER_CALLBACK( vi_callback )
+{
+ int scanline = param;
+
+ cpu_irq_state |= 1;
+ update_cpu_irq();
+ timer_adjust(vi_timer, video_screen_get_time_until_pos(0, scanline, 0), scanline, attotime_zero);
+}
+
+
+void jaguar_gpu_cpu_int(void)
+{
+ cpu_irq_state |= 2;
+ update_cpu_irq();
+}
+
+
+void jaguar_dsp_cpu_int(void)
+{
+ cpu_irq_state |= 16;
+ update_cpu_irq();
+}
+
+
+
+/*************************************
+ *
+ * Palette init
+ *
+ *************************************/
+
+static void jaguar_set_palette(UINT16 vmode)
+{
+ static const UINT8 red_lookup[256] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 19, 0,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 64, 43, 21, 0,
+ 102,102,102,102,102,102,102,102,102,102,102, 95, 71, 47, 23, 0,
+ 135,135,135,135,135,135,135,135,135,135,130,104, 78, 52, 26, 0,
+ 169,169,169,169,169,169,169,169,169,170,141,113, 85, 56, 28, 0,
+ 203,203,203,203,203,203,203,203,203,183,153,122, 91, 61, 30, 0,
+ 237,237,237,237,237,237,237,237,230,197,164,131, 98, 65, 32, 0,
+ 255,255,255,255,255,255,255,255,247,214,181,148,115, 82, 49, 17,
+ 255,255,255,255,255,255,255,255,255,235,204,173,143,112, 81, 51,
+ 255,255,255,255,255,255,255,255,255,255,227,198,170,141,113, 85,
+ 255,255,255,255,255,255,255,255,255,255,249,223,197,171,145,119,
+ 255,255,255,255,255,255,255,255,255,255,255,248,224,200,177,153,
+ 255,255,255,255,255,255,255,255,255,255,255,255,252,230,208,187,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,240,221,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
+ };
+
+ static const UINT8 grn_lookup[256] =
+ {
+ 0, 17, 34, 51, 68, 85,102,119,136,153,170,187,204,221,238,255,
+ 0, 19, 38, 57, 77, 96,115,134,154,173,182,211,231,250,255,255,
+ 0, 21, 43, 64, 86,107,129,150,172,193,215,236,255,255,255,255,
+ 0, 23, 47, 71, 96,119,142,166,190,214,238,255,255,255,255,255,
+ 0, 26, 52, 78,104,130,156,182,208,234,255,255,255,255,255,255,
+ 0, 28, 56, 85,113,141,170,198,226,255,255,255,255,255,255,255,
+ 0, 30, 61, 91,122,153,183,214,244,255,255,255,255,255,255,255,
+ 0, 32, 65, 98,131,164,197,230,255,255,255,255,255,255,255,255,
+ 0, 32, 65, 98,131,164,197,230,255,255,255,255,255,255,255,255,
+ 0, 30, 61, 91,122,153,183,214,244,255,255,255,255,255,255,255,
+ 0, 28, 56, 85,113,141,170,198,226,255,255,255,255,255,255,255,
+ 0, 26, 52, 78,104,130,156,182,208,234,255,255,255,255,255,255,
+ 0, 23, 47, 71, 96,119,142,166,190,214,238,255,255,255,255,255,
+ 0, 21, 43, 64, 86,107,129,150,172,193,215,236,255,255,255,255,
+ 0, 19, 38, 57, 77, 96,115,134,154,173,182,211,231,250,255,255,
+ 0, 17, 34, 51, 68, 85,102,119,136,153,170,187,204,221,238,255
+ };
+
+ static const UINT8 blu_lookup[256] =
+ {
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,240,221,
+ 255,255,255,255,255,255,255,255,255,255,255,255,252,230,208,187,
+ 255,255,255,255,255,255,255,255,255,255,255,248,224,200,177,153,
+ 255,255,255,255,255,255,255,255,255,255,249,223,197,171,145,119,
+ 255,255,255,255,255,255,255,255,255,255,227,198,170,141,113, 85,
+ 255,255,255,255,255,255,255,255,255,235,204,173,143,112, 81, 51,
+ 255,255,255,255,255,255,255,255,247,214,181,148,115, 82, 49, 17,
+ 237,237,237,237,237,237,237,237,230,197,164,131, 98, 65, 32, 0,
+ 203,203,203,203,203,203,203,203,203,183,153,122, 91, 61, 30, 0,
+ 169,169,169,169,169,169,169,169,169,170,141,113, 85, 56, 28, 0,
+ 135,135,135,135,135,135,135,135,135,135,130,104, 78, 52, 26, 0,
+ 102,102,102,102,102,102,102,102,102,102,102, 95, 71, 47, 23, 0,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 64, 43, 21, 0,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 19, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ int i, colors = 0;
+
+ /* switch off the mode */
+ switch (vmode & 0x106)
+ {
+ /* YCC full */
+ case 0x000:
+ {
+ /* set color 0 to black */
+ palette_set_color(Machine, colors++, MAKE_RGB(0, 0, 0));
+
+ /* due to the way YCC colorspace maps onto RGB, there are multiple entries for black */
+ /* take advantage of this so we don't have to use all 64k colors */
+ for (i = 0; i < 65536; i++)
+ {
+ UINT8 r = (red_lookup[i >> 8] * (i & 0xff)) >> 8;
+ UINT8 g = (grn_lookup[i >> 8] * (i & 0xff)) >> 8;
+ UINT8 b = (blu_lookup[i >> 8] * (i & 0xff)) >> 8;
+
+ if (r == 0 && g == 0 && b == 0)
+ pen_table[i] = 0;
+ else
+ {
+ pen_table[i] = colors;
+ palette_set_color(Machine, colors++, MAKE_RGB(r, g, b));
+ }
+ }
+ break;
+ }
+
+ /* YCC/RGB VARMOD */
+ case 0x100:
+ case 0x107:
+ {
+ /* set color 0 to black */
+ palette_set_color(Machine, colors++, MAKE_RGB(0, 0, 0));
+
+ /* due to the way YCC colorspace maps onto RGB, there are multiple entries for black */
+ /* take advantage of this so we don't have to use all 64k colors */
+ for (i = 0; i < 65536; i++)
+ {
+ UINT8 r = (red_lookup[i >> 8] * (i & 0xff)) >> 8;
+ UINT8 g = (grn_lookup[i >> 8] * (i & 0xff)) >> 8;
+ UINT8 b = (blu_lookup[i >> 8] * (i & 0xff)) >> 8;
+
+ /* if the low bit is set, treat it as 5-5-5 RGB instead */
+ if (i & 1)
+ {
+ r = (i >> 11) & 31;
+ g = (i >> 1) & 31;
+ b = (i >> 6) & 31;
+ r = (r << 3) | (r >> 2);
+ g = (g << 3) | (g >> 2);
+ b = (b << 3) | (b >> 2);
+ }
+
+ if (r == 0 && g == 0 && b == 0)
+ pen_table[i] = 0;
+ else
+ {
+ pen_table[i] = colors;
+ palette_set_color(Machine, colors++, MAKE_RGB(r, g, b));
+ }
+ }
+ break;
+ }
+
+ /* RGB full */
+ case 0x006:
+ {
+ /* we cheat a little here to squeeze into 65534 colors */
+ palette_set_color(Machine, colors++, MAKE_RGB(0, 0, 0));
+ palette_set_color(Machine, colors++, MAKE_RGB(0, 8, 0));
+ palette_set_color(Machine, colors++, MAKE_RGB(0, 16, 0));
+ pen_table[0] = 0;
+ pen_table[1] = 1;
+ pen_table[2] = 1;
+ pen_table[3] = 2;
+ pen_table[4] = 2;
+
+ /* map the remaining colors normally */
+ for (i = 5; i < 65536; i++)
+ {
+ pen_table[i] = colors;
+ palette_set_color_rgb(Machine, colors++, pal5bit(i >> 11), pal6bit(i >> 0), pal5bit(i >> 6));
+ }
+ break;
+ }
+
+ /* others */
+ default:
+ logerror("Can't handle mode %X\n", vmode);
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Fast memory accessors
+ *
+ *************************************/
+
+static UINT8 *get_jaguar_memory(UINT32 offset)
+{
+ return memory_get_read_ptr(1, ADDRESS_SPACE_PROGRAM, offset);
+}
+
+
+
+/*************************************
+ *
+ * 32-bit access to the blitter
+ *
+ *************************************/
+
+static void blitter_run(void)
+{
+ UINT32 command = blitter_regs[B_CMD] & STATIC_COMMAND_MASK;
+ UINT32 a1flags = blitter_regs[A1_FLAGS] & STATIC_FLAGS_MASK;
+ UINT32 a2flags = blitter_regs[A2_FLAGS] & STATIC_FLAGS_MASK;
+
+ profiler_mark(PROFILER_USER1);
+
+ if (a1flags == a2flags)
+ {
+ if (command == 0x09800001 && a1flags == 0x010020)
+ {
+ blitter_09800001_010020_010020(blitter_regs[B_CMD], blitter_regs[A1_FLAGS], blitter_regs[A2_FLAGS]);
+ return;
+ }
+ if (command == 0x09800009 && a1flags == 0x000020)
+ {
+ blitter_09800009_000020_000020(blitter_regs[B_CMD], blitter_regs[A1_FLAGS], blitter_regs[A2_FLAGS]);
+ return;
+ }
+ if (command == 0x01800009 && a1flags == 0x000028)
+ {
+ blitter_01800009_000028_000028(blitter_regs[B_CMD], blitter_regs[A1_FLAGS], blitter_regs[A2_FLAGS]);
+ return;
+ }
+
+ if (command == 0x01800001 && a1flags == 0x000018)
+ {
+ blitter_01800001_000018_000018(blitter_regs[B_CMD], blitter_regs[A1_FLAGS], blitter_regs[A2_FLAGS]);
+ return;
+ }
+
+ if (command == 0x01c00001 && a1flags == 0x000018)
+ {
+ blitter_01c00001_000018_000018(blitter_regs[B_CMD], blitter_regs[A1_FLAGS], blitter_regs[A2_FLAGS]);
+ return;
+ }
+ }
+
+#ifdef MESS
+ if (command == 0x00010000)
+ {
+ blitter_00010000_xxxxxx_xxxxxx(blitter_regs[B_CMD], blitter_regs[A1_FLAGS], blitter_regs[A2_FLAGS]);
+ return;
+ }
+
+ if (command == 0x01800001)
+ {
+ blitter_01800001_xxxxxx_xxxxxx(blitter_regs[B_CMD], blitter_regs[A1_FLAGS], blitter_regs[A2_FLAGS]);
+ return;
+ }
+
+ if ((command & 0x0ffff0ff) == 0x01800001)
+ {
+ blitter_x1800x01_xxxxxx_xxxxxx(blitter_regs[B_CMD], blitter_regs[A1_FLAGS], blitter_regs[A2_FLAGS]);
+ return;
+ }
+#endif
+
+
+#if LOG_BLITTER_STATS
+{
+static UINT32 blitter_stats[1000][4];
+static UINT64 blitter_pixels[1000];
+static int blitter_count = 0;
+static int reps = 0;
+int i;
+for (i = 0; i < blitter_count; i++)
+ if (blitter_stats[i][0] == (blitter_regs[B_CMD] & STATIC_COMMAND_MASK) &&
+ blitter_stats[i][1] == (blitter_regs[A1_FLAGS] & STATIC_FLAGS_MASK) &&
+ blitter_stats[i][2] == (blitter_regs[A2_FLAGS] & STATIC_FLAGS_MASK))
+ break;
+if (i == blitter_count)
+{
+ blitter_stats[i][0] = blitter_regs[B_CMD] & STATIC_COMMAND_MASK;
+ blitter_stats[i][1] = blitter_regs[A1_FLAGS] & STATIC_FLAGS_MASK;
+ blitter_stats[i][2] = blitter_regs[A2_FLAGS] & STATIC_FLAGS_MASK;
+ blitter_stats[i][3] = 0;
+ blitter_pixels[i] = 0;
+ blitter_count++;
+}
+blitter_stats[i][3]++;
+blitter_pixels[i] += (blitter_regs[B_COUNT] & 0xffff) * (blitter_regs[B_COUNT] >> 16);
+if (++reps % 100 == 99)
+{
+ mame_printf_debug("---\nBlitter stats:\n");
+ for (i = 0; i < blitter_count; i++)
+ mame_printf_debug(" CMD=%08X A1=%08X A2=%08X %6d times, %08X%08X pixels\n",
+ blitter_stats[i][0], blitter_stats[i][1], blitter_stats[i][2],
+ blitter_stats[i][3], (UINT32)(blitter_pixels[i] >> 32), (UINT32)(blitter_pixels[i]));
+ mame_printf_debug("---\n");
+}
+}
+#endif
+
+ generic_blitter(blitter_regs[B_CMD], blitter_regs[A1_FLAGS], blitter_regs[A2_FLAGS]);
+ profiler_mark(PROFILER_END);
+}
+
+
+READ32_HANDLER( jaguar_blitter_r )
+{
+ switch (offset)
+ {
+ case B_CMD: /* B_CMD */
+ return 0x00000001;
+
+ default:
+ logerror("%08X:Blitter read register @ F022%02X\n", activecpu_get_previouspc(), offset * 4);
+ return 0;
+ }
+}
+
+
+WRITE32_HANDLER( jaguar_blitter_w )
+{
+ COMBINE_DATA(&blitter_regs[offset]);
+ if (offset == B_CMD)
+ blitter_run();
+
+#if LOG_BLITTER_WRITE
+ logerror("%08X:Blitter write register @ F022%02X = %08X\n", activecpu_get_previouspc(), offset * 4, data);
+#endif
+}
+
+
+
+/*************************************
+ *
+ * 16-bit TOM register access
+ *
+ *************************************/
+
+READ16_HANDLER( jaguar_tom_regs_r )
+{
+ if (offset != INT1 && offset != INT2 && offset != HC && offset != VC)
+ logerror("%08X:TOM read register @ F00%03X\n", activecpu_get_previouspc(), offset * 2);
+
+ switch (offset)
+ {
+ case INT1:
+ return cpu_irq_state;
+
+ case HC:
+ return video_screen_get_hpos(0) % (Machine->screen[0].width / 2);
+
+ case VC:
+ return video_screen_get_vpos(0) * 2 + gpu_regs[VBE];
+
+ }
+
+ return gpu_regs[offset];
+}
+
+
+WRITE16_HANDLER( jaguar_tom_regs_w )
+{
+ int scanline;
+
+ if (offset < GPU_REGS)
+ {
+ COMBINE_DATA(&gpu_regs[offset]);
+
+ switch (offset)
+ {
+ case VI:
+ scanline = (gpu_regs[VI] - gpu_regs[VBE]) / 2;
+ timer_adjust(vi_timer, video_screen_get_time_until_pos(0, scanline, 0), scanline, attotime_zero);
+ break;
+
+ case INT1:
+ cpu_irq_state &= ~(gpu_regs[INT1] >> 8);
+ update_cpu_irq();
+ break;
+
+ case VMODE:
+ jaguar_set_palette(gpu_regs[VMODE]);
+ break;
+ }
+ }
+
+ if (offset != INT2 && offset != VI)
+ logerror("%08X:TOM write register @ F00%03X = %04X\n", activecpu_get_previouspc(), offset * 2, data);
+}
+
+
+
+/*************************************
+ *
+ * 32-bit TOM register access
+ *
+ *************************************/
+
+READ32_HANDLER( jaguar_tom_regs32_r )
+{
+ return (jaguar_tom_regs_r(offset * 2, 0) << 16) | jaguar_tom_regs_r(offset * 2 + 1, 0);
+}
+
+
+WRITE32_HANDLER( jaguar_tom_regs32_w )
+{
+ if (ACCESSING_MSW32)
+ jaguar_tom_regs_w(offset * 2, data >> 16, mem_mask >> 16);
+ if (ACCESSING_LSW32)
+ jaguar_tom_regs_w(offset * 2 + 1, data, mem_mask);
+}
+
+
+
+/*************************************
+ *
+ * Gun input
+ *
+ *************************************/
+
+READ32_HANDLER( cojag_gun_input_r )
+{
+ int beamx, beamy;
+
+ switch (offset)
+ {
+ case 0:
+ get_crosshair_xy(1, &beamx, &beamy);
+ beamx += 52;
+ beamy += 17;
+ return (beamy << 16) | (beamx ^ 0x1ff);
+
+ case 1:
+ get_crosshair_xy(0, &beamx, &beamy);
+ beamx += 52;
+ beamy += 17;
+ return (beamy << 16) | (beamx ^ 0x1ff);
+
+ case 2:
+ return readinputport(7) << 16;
+ }
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( cojag )
+{
+ jagobj_init();
+
+ pen_table = auto_malloc(65536 * sizeof(pen_t));
+
+ vi_timer = timer_alloc(vi_callback);
+
+ state_save_register_global_pointer(pen_table, 65536);
+ state_save_register_global_array(blitter_regs);
+ state_save_register_global_array(gpu_regs);
+ state_save_register_global(cpu_irq_state);
+ state_save_register_func_postload(update_cpu_irq);
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( cojag )
+{
+ /* if not enabled, just blank */
+ if (!(gpu_regs[VMODE] & 1))
+ {
+ fillbitmap(bitmap, 0, cliprect);
+ return 0;
+ }
+
+ /* render the object list */
+ process_object_list(bitmap, cliprect);
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Object processor
+ *
+ *************************************/
+
+#define INCLUDE_OBJECT_PROCESSOR
+#include "jagobj.c"
+
+
+
+/*************************************
+ *
+ * Blitter macros
+ *
+ *************************************/
+
+/* generic blitters */
+#define FUNCNAME generic_blitter
+#define COMMAND command
+#define A1FIXED a1flags
+#define A2FIXED a2flags
+#include "jagblit.c"
+#undef A2FIXED
+#undef A1FIXED
+#undef COMMAND
+#undef FUNCNAME
+
+/* optimized common blitters */
+#define FUNCNAME blitter_09800001_010020_010020
+#define COMMAND 0x09800001
+#define A1FIXED 0x010020
+#define A2FIXED 0x010020
+#include "jagblit.c"
+#undef A2FIXED
+#undef A1FIXED
+#undef COMMAND
+#undef FUNCNAME
+
+#define FUNCNAME blitter_09800009_000020_000020
+#define COMMAND 0x09800009
+#define A1FIXED 0x000020
+#define A2FIXED 0x000020
+#include "jagblit.c"
+#undef A2FIXED
+#undef A1FIXED
+#undef COMMAND
+#undef FUNCNAME
+
+#define FUNCNAME blitter_01800009_000028_000028
+#define COMMAND 0x01800009
+#define A1FIXED 0x000028
+#define A2FIXED 0x000028
+#include "jagblit.c"
+#undef A2FIXED
+#undef A1FIXED
+#undef COMMAND
+#undef FUNCNAME
+
+#define FUNCNAME blitter_01800001_000018_000018
+#define COMMAND 0x01800001
+#define A1FIXED 0x000018
+#define A2FIXED 0x000018
+#include "jagblit.c"
+#undef A2FIXED
+#undef A1FIXED
+#undef COMMAND
+#undef FUNCNAME
+
+#define FUNCNAME blitter_01c00001_000018_000018
+#define COMMAND 0x01c00001
+#define A1FIXED 0x000018
+#define A2FIXED 0x000018
+#include "jagblit.c"
+#undef A2FIXED
+#undef A1FIXED
+#undef COMMAND
+#undef FUNCNAME
+
+#ifdef MESS
+
+#define FUNCNAME blitter_00010000_xxxxxx_xxxxxx
+#define COMMAND 0x00010000
+#define A1FIXED a1flags
+#define A2FIXED a2flags
+#include "jagblit.c"
+#undef A2FIXED
+#undef A1FIXED
+#undef COMMAND
+#undef FUNCNAME
+
+#define FUNCNAME blitter_01800001_xxxxxx_xxxxxx
+#define COMMAND 0x01800001
+#define A1FIXED a1flags
+#define A2FIXED a2flags
+#include "jagblit.c"
+#undef A2FIXED
+#undef A1FIXED
+#undef COMMAND
+#undef FUNCNAME
+
+#define FUNCNAME blitter_x1800x01_xxxxxx_xxxxxx
+#define COMMAND ((command & 0xf0000f00) | 0x01800001)
+#define A1FIXED a1flags
+#define A2FIXED a2flags
+#include "jagblit.c"
+#undef A2FIXED
+#undef A1FIXED
+#undef COMMAND
+#undef FUNCNAME
+
+#endif /* MESS */
diff --git a/src/mame/video/jailbrek.c b/src/mame/video/jailbrek.c
new file mode 100644
index 00000000000..12bc0b468a3
--- /dev/null
+++ b/src/mame/video/jailbrek.c
@@ -0,0 +1,136 @@
+#include "driver.h"
+
+UINT8 *jailbrek_scroll_x;
+UINT8 *jailbrek_scroll_dir;
+
+static tilemap *bg_tilemap;
+
+PALETTE_INIT( jailbrek )
+{
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+ int i;
+
+ for ( i = 0; i < machine->drv->total_colors; i++ )
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[0] >> 4) & 0x01;
+ bit1 = (color_prom[0] >> 5) & 0x01;
+ bit2 = (color_prom[0] >> 6) & 0x01;
+ bit3 = (color_prom[0] >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += machine->drv->total_colors;
+
+ for ( i = 0; i < TOTAL_COLORS(0); i++ )
+ COLOR(0,i) = ( *color_prom++ ) + 0x10;
+
+ for ( i = 0; i < TOTAL_COLORS(1); i++ )
+ COLOR(1,i) = *color_prom++;
+}
+
+WRITE8_HANDLER( jailbrek_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( jailbrek_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + ((attr & 0xc0) << 2);
+ int color = attr & 0x0f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( jailbrek )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int i;
+
+ for (i = 0; i < spriteram_size; i += 4)
+ {
+ int attr = spriteram[i + 1]; // attributes = ?tyxcccc
+ int code = spriteram[i] + ((attr & 0x40) << 2);
+ int color = attr & 0x0f;
+ int flipx = attr & 0x10;
+ int flipy = attr & 0x20;
+ int sx = spriteram[i + 2] - ((attr & 0x80) << 1);
+ int sy = spriteram[i + 3];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy,
+ sx, sy, cliprect, TRANSPARENCY_COLOR, 0);
+ }
+}
+
+VIDEO_UPDATE( jailbrek )
+{
+ int i;
+
+ // added support for vertical scrolling (credits). 23/1/2002 -BR
+ // bit 2 appears to be horizontal/vertical scroll control
+ if (jailbrek_scroll_dir[0] & 0x04)
+ {
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+ tilemap_set_scroll_rows(bg_tilemap, 1);
+ tilemap_set_scrollx(bg_tilemap, 0, 0);
+
+ for (i = 0; i < 32; i++)
+ {
+ tilemap_set_scrolly(bg_tilemap, i, ((jailbrek_scroll_x[i + 32] << 8) + jailbrek_scroll_x[i]));
+ }
+ }
+ else
+ {
+ tilemap_set_scroll_rows(bg_tilemap, 32);
+ tilemap_set_scroll_cols(bg_tilemap, 1);
+ tilemap_set_scrolly(bg_tilemap, 0, 0);
+
+ for (i = 0; i < 32; i++)
+ {
+ tilemap_set_scrollx(bg_tilemap, i, ((jailbrek_scroll_x[i + 32] << 8) + jailbrek_scroll_x[i]));
+ }
+ }
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/jalblend.c b/src/mame/video/jalblend.c
new file mode 100644
index 00000000000..d5afd148e92
--- /dev/null
+++ b/src/mame/video/jalblend.c
@@ -0,0 +1,180 @@
+/***************************************************************************
+
+ Jaleco color blend emulation
+
+****************************************************************************
+
+ This implements the behaviour of color blending/alpha hardware
+ found in a small set of machines from the late 80's.
+
+ Thus far, Psychic 5, Argus, and Valtric are presumed to use it.
+
+****************************************************************************/
+
+
+/* each palette entry contains a fourth 'alpha' value */
+static UINT8 *jal_blend_table;
+
+/*
+ * 'Alpha' Format
+ * ------------------
+ *
+ * Bytes | Use
+ * -76543210-+----------------
+ * xxxx---- | unknown - maybe special background?
+ * ----x--- | unknown - same as above
+ * -----x-- | red add/subtract
+ * ------x- | green add/subtract
+ * -------x | blue add/subtract
+ */
+
+/* basically an add/subtract function with clamping */
+static rgb_t jal_blend_func(rgb_t dest, rgb_t addMe, UINT8 alpha)
+{
+ int r = (float)RGB_RED (addMe) ;
+ int g = (float)RGB_GREEN(addMe) ;
+ int b = (float)RGB_BLUE (addMe) ;
+
+ int rd = (float)RGB_RED (dest) ;
+ int gd = (float)RGB_GREEN(dest) ;
+ int bd = (float)RGB_BLUE (dest) ;
+
+ int finalR, finalG, finalB ;
+
+ int subR = (alpha & 0x04) >> 2 ;
+ int subG = (alpha & 0x02) >> 1 ;
+ int subB = (alpha & 0x01) ;
+
+ if (subR) finalR = rd - r ;
+ else finalR = rd + r ;
+ if (finalR < 0) finalR = 0 ;
+ else if (finalR > 255) finalR = 255 ;
+
+
+ if (subG) finalG = gd - g ;
+ else finalG = gd + g ;
+ if (finalG < 0) finalG = 0 ;
+ else if (finalG > 255) finalG = 255 ;
+
+
+ if (subB) finalB = bd - b ;
+ else finalB = bd + b ;
+ if (finalB < 0) finalB = 0 ;
+ else if (finalB > 255) finalB = 255 ;
+
+ return MAKE_RGB((UINT8)finalR,(UINT8)finalG,(UINT8)finalB) ;
+}
+
+static void jal_blend_drawgfx( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ UINT32 code,UINT32 color,int flipx,int flipy,int offsx,int offsy,
+ const rectangle *clip,int transparency,int transparent_color)
+{
+ /* drawgfx(dest_bmp, gfx, code, color, flipx, flipy, offsx, offsy, clip, TRANSPARENCY_PEN, 15); */
+
+ int xstart, ystart, xend, yend, xinc, yinc;
+ int xtile, ytile ;
+ int code_offset = 0;
+
+ int wide = 1 ;
+ int high = 1 ;
+
+ if (flipx) { xstart = wide-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = wide; xinc = +1; }
+
+ if (flipy) { ystart = high-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = high; yinc = +1; }
+
+ /* Start drawing */
+ if( gfx )
+ {
+ for (ytile = ystart; ytile != yend; ytile += yinc )
+ {
+ for (xtile = xstart; xtile != xend; xtile += xinc )
+ {
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+ const UINT8 *alpha = &jal_blend_table[gfx->color_granularity * (color % gfx->total_colors)];
+ int source_base = ((code + code_offset++) % gfx->total_elements) * gfx->height;
+
+ int x_index_base, y_index, sx, sy, ex, ey;
+
+ if (flipx) { x_index_base = gfx->width-1; }
+ else { x_index_base = 0; }
+
+ if (flipy) { y_index = gfx->height-1; }
+ else { y_index = 0; }
+
+ /* start coordinates */
+ sx = offsx + xtile*gfx->width;
+ sy = offsy + ytile*gfx->height;
+
+ /* end coordinates */
+ ex = sx + gfx->width;
+ ey = sy + gfx->height;
+
+ if( clip )
+ {
+ if( sx < clip->min_x)
+ { /* clip left */
+ int pixels = clip->min_x-sx;
+ sx += pixels;
+ x_index_base += xinc*pixels;
+ }
+ if( sy < clip->min_y )
+ { /* clip top */
+ int pixels = clip->min_y-sy;
+ sy += pixels;
+ y_index += yinc*pixels;
+ }
+ /* NS 980211 - fixed incorrect clipping */
+ if( ex > clip->max_x+1 )
+ { /* clip right */
+ int pixels = ex-clip->max_x-1;
+ ex -= pixels;
+ }
+ if( ey > clip->max_y+1 )
+ { /* clip bottom */
+ int pixels = ey-clip->max_y-1;
+ ey -= pixels;
+ }
+ }
+
+ if( ex>sx )
+ { /* skip if inner loop doesn't draw anything */
+ int y;
+
+ /* taken from case 7: TRANSPARENCY_ALPHARANGE */
+ UINT8 *source = gfx->gfxdata + (source_base + y_index)*gfx->line_modulo + x_index_base;
+ UINT32 *dest = (UINT32 *)dest_bmp->base + sy*dest_bmp->rowpixels + sx;
+ int src_modulo = yinc*gfx->line_modulo - xinc*(ex-sx);
+ int dst_modulo = dest_bmp->rowpixels - (ex-sx);
+
+ for( y=sy; y<ey; y++ )
+ {
+ int x;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = *source;
+ if( c != transparent_color )
+ {
+ if( alpha[c] == 0x00 )
+ {
+ /* Skip the costly alpha step altogether */
+ *dest = pal[c];
+ }
+ else
+ {
+ /* Comp with clamp */
+ *dest = jal_blend_func(*dest, pal[c], alpha[c]) ;
+ }
+ }
+ dest++;
+ source += xinc;
+ }
+ dest += dst_modulo;
+ source += src_modulo;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/mame/video/jcross.c b/src/mame/video/jcross.c
new file mode 100644
index 00000000000..001af5f256c
--- /dev/null
+++ b/src/mame/video/jcross.c
@@ -0,0 +1,194 @@
+#include "driver.h"
+#include "cpu/z80/z80.h"
+
+static int flipscreen;
+static tilemap *bg_tilemap, *tx_tilemap;
+static UINT8 fg_color, old_fg_color;
+
+extern UINT8 *jcr_textram;
+
+
+int jcross_vregs[5];
+
+WRITE8_HANDLER( jcross_palettebank_w )
+{
+ fg_color = data&0xf;
+}
+
+
+static void stuff_palette( running_machine *machine, int source_index, int dest_index, int num_colors )
+{
+ UINT8 *color_prom = memory_region(REGION_PROMS) + source_index;
+ int i;
+ for( i=0; i<num_colors; i++ )
+ {
+ int bit0=0,bit1,bit2,bit3;
+ int red, green, blue;
+
+ bit0 = (color_prom[0x800] >> 2) & 0x01; // ?
+ bit1 = (color_prom[0x000] >> 1) & 0x01;
+ bit2 = (color_prom[0x000] >> 2) & 0x01;
+ bit3 = (color_prom[0x000] >> 3) & 0x01;
+ red = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[0x800] >> 1) & 0x01; // ?
+ bit1 = (color_prom[0x400] >> 2) & 0x01;
+ bit2 = (color_prom[0x400] >> 3) & 0x01;
+ bit3 = (color_prom[0x000] >> 0) & 0x01;
+ green = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[0x800] >> 0) & 0x01; // ?
+ bit1 = (color_prom[0x800] >> 3) & 0x01; // ?
+ bit2 = (color_prom[0x400] >> 0) & 0x01;
+ bit3 = (color_prom[0x400] >> 1) & 0x01;
+ blue = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color( machine, dest_index++, MAKE_RGB(red, green, blue) );
+ color_prom++;
+ }
+}
+
+static void update_palette(running_machine *machine, int type )
+{
+ if( fg_color!=old_fg_color )
+ {
+ stuff_palette(machine, 128+16*(fg_color&0x7), (0x10+type)*16, 16 );
+ old_fg_color = fg_color;
+ }
+}
+
+WRITE8_HANDLER( jcross_background_ram_w )
+{
+ videoram[offset]=data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( jcross_text_ram_w )
+{
+ jcr_textram[offset]=data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+
+static TILE_GET_INFO( get_bg_tilemap_info )
+{
+ SET_TILE_INFO(
+ 1,
+ videoram[tile_index],
+ 0,
+ 0);
+}
+
+static TILE_GET_INFO( get_tx_tilemap_info )
+{
+ int tile_number = jcr_textram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ 0,
+ 0);
+}
+
+VIDEO_START( jcross )
+{
+ flipscreen = -1; old_fg_color = -1;
+
+ stuff_palette( machine, 0, 0, 16*8 );
+ stuff_palette( machine, 16*8*3, 16*8, 16*8 );
+
+ bg_tilemap = tilemap_create(get_bg_tilemap_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,64,64);
+ tx_tilemap = tilemap_create(get_tx_tilemap_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(tx_tilemap,0xf);
+ tilemap_set_scrolldx( bg_tilemap, 16, 22 );
+}
+
+/***************************************************************************
+**
+** Screen Refresh
+**
+***************************************************************************/
+
+static void draw_status(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ const UINT8 *base = jcr_textram + 0x400;
+ const gfx_element *gfx = machine->gfx[0];
+ int row;
+ for( row=0; row<4; row++ )
+ {
+ int sy,sx = (row&1)*8;
+ const UINT8 *source = base + (row&1)*32;
+ if( row>1 )
+ sx+=256+16;
+ else
+ source+=30*32;
+
+ for( sy=0; sy<256; sy+=8 )
+ {
+ int tile_number = *source++;
+ drawgfx( bitmap, gfx,
+ tile_number, tile_number>>5,
+ 0,0,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_NONE, 0xf );
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int scrollx, int scrolly )
+{
+ const gfx_element *gfx = machine->gfx[3];
+ const UINT8 *source, *finish;
+ source = spriteram;
+ finish = spriteram + 0x64;
+
+ while( source<finish )
+ {
+ int attributes = source[3];
+ int tile_number = source[1];
+ int sy = source[0] + ((attributes&0x10)?256:0);
+ int sx = source[2] + ((attributes&0x80)?256:0);
+ int color = attributes&0xf;
+ int flipy = (attributes&0x20);
+ int flipx = 0;
+
+ sy=(sy-scrolly)&0x1ff;
+ sx=(sx-scrollx)&0x1ff;
+
+ drawgfx( bitmap,gfx,
+ tile_number,
+ color,
+ flipx, flipy,
+ (256-sx)&0x1ff,sy-16,
+ cliprect,TRANSPARENCY_PEN,7);
+
+ source+=4;
+ }
+}
+
+
+VIDEO_UPDATE( jcross )
+{
+ int scroll_attributes = jcross_vregs[0];
+ int sprite_scrolly = jcross_vregs[1];
+ int sprite_scrollx = jcross_vregs[2];
+ int bg_scrolly = jcross_vregs[3];
+ int bg_scrollx = jcross_vregs[4];
+
+ if( scroll_attributes & 1 ) sprite_scrollx += 256;
+ if( scroll_attributes & 2 ) bg_scrollx += 256;
+
+ if( scroll_attributes & 8 ) sprite_scrolly += 256;
+ if( scroll_attributes & 0x10 ) bg_scrolly += 256;
+ update_palette(machine, 1);
+
+
+ tilemap_set_scrollx( bg_tilemap, 0, bg_scrollx );
+ tilemap_set_scrolly( bg_tilemap, 0, bg_scrolly );
+ tilemap_draw( bitmap,cliprect,bg_tilemap,0 ,0);
+ draw_sprites( machine, bitmap,cliprect, sprite_scrollx+23, sprite_scrolly+1 );
+ tilemap_draw( bitmap,cliprect,tx_tilemap,0 ,0);
+ draw_status( machine, bitmap,cliprect );
+ return 0;
+}
diff --git a/src/mame/video/jedi.c b/src/mame/video/jedi.c
new file mode 100644
index 00000000000..b50fa026c06
--- /dev/null
+++ b/src/mame/video/jedi.c
@@ -0,0 +1,394 @@
+/***************************************************************************
+
+ Atari Return of the Jedi hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "jedi.h"
+
+
+/* globals */
+UINT8 *jedi_backgroundram;
+size_t jedi_backgroundram_size;
+UINT8 *jedi_PIXIRAM;
+
+
+/* local variables */
+static UINT32 jedi_vscroll;
+static UINT32 jedi_hscroll;
+static UINT32 jedi_alpha_bank;
+static UINT8 video_off, smooth_table;
+static UINT8 *fgdirty, *bgdirty;
+static mame_bitmap *fgbitmap, *mobitmap, *bgbitmap, *bgexbitmap;
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+static void jedi_postload(void)
+{
+ memset(fgdirty, 1, videoram_size);
+ memset(bgdirty, 1, jedi_backgroundram_size);
+}
+
+
+VIDEO_START( jedi )
+{
+ /* allocate dirty buffer for the foreground characters */
+ fgdirty = dirtybuffer = auto_malloc(videoram_size);
+ memset(fgdirty, 1, videoram_size);
+
+ /* allocate an 8bpp bitmap for the raw foreground characters */
+ fgbitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ /* allocate an 8bpp bitmap for the motion objects */
+ mobitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ fillbitmap(mobitmap, 0, &machine->screen[0].visarea);
+
+ /* allocate dirty buffer for the background characters */
+ bgdirty = auto_malloc(jedi_backgroundram_size);
+ memset(bgdirty, 1, jedi_backgroundram_size);
+
+ /* the background area is 256x256, doubled by the hardware*/
+ bgbitmap = auto_bitmap_alloc(256, 256, machine->screen[0].format);
+
+ /* the expanded background area is 512x512 */
+ bgexbitmap = auto_bitmap_alloc(512, 512, machine->screen[0].format);
+
+ /* reserve color 1024 for black (disabled display) */
+ palette_set_color(machine, 1024, MAKE_RGB(0, 0, 0));
+
+ /* register for saving */
+ state_save_register_global(jedi_vscroll);
+ state_save_register_global(jedi_hscroll);
+ state_save_register_global(jedi_alpha_bank);
+ state_save_register_global(video_off);
+ state_save_register_global(smooth_table);
+ state_save_register_func_postload(jedi_postload);
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM
+ *
+ *************************************
+ *
+ * Color RAM format
+ * Color RAM is 1024x12
+ *
+ * RAM address: A0..A3 = Playfield color code
+ * A4..A7 = Motion object color code
+ * A8..A9 = Alphanumeric color code
+ *
+ * RAM data:
+ * 0..2 = Blue
+ * 3..5 = Green
+ * 6..8 = Blue
+ * 9..11 = Intensity
+ *
+ * Output resistor values:
+ * bit 0 = 22K
+ * bit 1 = 10K
+ * bit 2 = 4.7K
+ *
+ *************************************/
+
+WRITE8_HANDLER( jedi_paletteram_w )
+{
+ int r, g, b, bits, intensity;
+ UINT32 color;
+
+ paletteram[offset] = data;
+ color = paletteram[offset & 0x3FF] | (paletteram[offset | 0x400] << 8);
+
+ intensity = (color >> 9) & 7;
+ bits = (color >> 6) & 7;
+ r = 5 * bits * intensity;
+ bits = (color >> 3) & 7;
+ g = 5 * bits * intensity;
+ bits = (color >> 0) & 7;
+ b = 5 * bits * intensity;
+
+ palette_set_color(Machine, offset & 0x3ff, MAKE_RGB(r, g, b));
+}
+
+
+
+/*************************************
+ *
+ * Background access
+ *
+ *************************************/
+
+WRITE8_HANDLER( jedi_backgroundram_w )
+{
+ if (jedi_backgroundram[offset] != data)
+ {
+ bgdirty[offset] = 1;
+ jedi_backgroundram[offset] = data;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Foreground banking
+ *
+ *************************************/
+
+WRITE8_HANDLER( jedi_alpha_banksel_w )
+{
+ if (jedi_alpha_bank != 2 * (data & 0x80))
+ {
+ jedi_alpha_bank = 2 * (data & 0x80);
+ memset(fgdirty, 1, videoram_size);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Scroll offsets
+ *
+ *************************************/
+
+WRITE8_HANDLER( jedi_vscroll_w )
+{
+ jedi_vscroll = data | (offset << 8);
+}
+
+
+WRITE8_HANDLER( jedi_hscroll_w )
+{
+ jedi_hscroll = data | (offset << 8);
+}
+
+
+
+/*************************************
+ *
+ * Video control
+ *
+ *************************************/
+
+WRITE8_HANDLER( jedi_video_off_w )
+{
+ video_off = data;
+}
+
+
+WRITE8_HANDLER( jedi_PIXIRAM_w )
+{
+ smooth_table = data & 0x03;
+ memset(bgdirty, 1, jedi_backgroundram_size);
+}
+
+
+
+/*************************************
+ *
+ * Background smoothing
+ *
+ *************************************/
+
+static void update_smoothing(int bgtilerow, int first, int last)
+{
+ UINT8 *prom = memory_region(REGION_PROMS) + smooth_table * 0x100;
+ UINT8 bgscan[2][256];
+ UINT8 *bgcurr = bgscan[0], *bglast = bgscan[1];
+ int xstart, xstop, x, y;
+
+ /*
+ smoothing notes:
+ * even scanlines blend the previous (Y-1) and current (Y) line
+ * odd scanlines are just taken from the current line (Y)
+ * therefore, if we modify source scanlines 8-15, we must update dest scanlines 16-32
+
+ * even pixels are just taken from the current pixel (X)
+ * odd pixels blend the current (X) and next (X+1) pixels
+ * therefore, if we modify source pixels 8-15, we must update dest pixels 15-31
+ */
+
+ /* compute x start/stop in destination coordinates */
+ xstart = first * 16 - 1;
+ xstop = last * 16 + 15;
+
+ /* extract the previous bg scanline */
+ extract_scanline8(bgbitmap, 0, ((bgtilerow * 16 - 1) & 0x1ff) / 2, 256, bgcurr);
+
+ /* loop over height */
+ for (y = 0; y <= 16; y++)
+ {
+ int curry = (bgtilerow * 16 + y) & 0x1ff;
+
+ /* swap background buffers */
+ UINT8 *bgtemp = bgcurr;
+ bgcurr = bglast;
+ bglast = bgtemp;
+
+ /* extract current bg scanline */
+ extract_scanline8(bgbitmap, 0, curry / 2, 256, bgcurr);
+
+ /* loop over columns */
+ for (x = xstart; x <= xstop; x++)
+ {
+ int tr = bglast[((x + 1) & 0x1ff) / 2];
+ int br = bgcurr[((x + 1) & 0x1ff) / 2];
+
+ /* smooth pixels */
+ if (x & 1)
+ {
+ int tl = bglast[(x & 0x1ff) / 2];
+ int bl = bgcurr[(x & 0x1ff) / 2];
+ int mixt = prom[16 * tl + tr];
+ int mixb = prom[16 * bl + br];
+ *BITMAP_ADDR16(bgexbitmap, curry, x & 0x1ff) = prom[0x400 + 16 * mixt + mixb];
+ }
+ else
+ *BITMAP_ADDR16(bgexbitmap, curry, x & 0x1ff) = prom[0x400 + 16 * tr + br];
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Core video refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( jedi )
+{
+ int bgexdirty[32][2];
+ int offs;
+
+
+ /* if no video, clear it all to black */
+ if (video_off)
+ {
+ fillbitmap(bitmap, machine->pens[1024], &machine->screen[0].visarea);
+ return 0;
+ }
+
+ /* Return of the Jedi has a peculiar playfield/motion object priority system. That */
+ /* is, there is no priority system ;-) The color of the pixel which appears on */
+ /* screen depends on all three of the foreground, background and motion objects. The */
+ /* 1024 colors palette is appropriately set up by the program to "emulate" a */
+ /* priority system, but it can also be used to display completely different */
+ /* colors (see the palette test in service mode) */
+
+ /* update foreground bitmap as a raw bitmap*/
+ for (offs = videoram_size - 1; offs >= 0; offs--)
+ if (fgdirty[offs])
+ {
+ int sx = offs % 64;
+ int sy = offs / 64;
+
+ fgdirty[offs] = 0;
+
+ drawgfx(fgbitmap, machine->gfx[0], videoram[offs] + jedi_alpha_bank,
+ 0, 0, 0, 8*sx, 8*sy, &machine->screen[0].visarea, TRANSPARENCY_NONE_RAW, 0);
+ }
+
+ /* reset the expanded dirty array */
+ for (offs = 0; offs < 32; offs++)
+ bgexdirty[offs][0] = bgexdirty[offs][1] = -1;
+
+ /* update background bitmap as a raw bitmap */
+ for (offs = jedi_backgroundram_size / 2 - 1; offs >= 0; offs--)
+ if (bgdirty[offs] || bgdirty[offs + 0x400])
+ {
+ int sx = offs % 32;
+ int sy = offs / 32;
+ int code = (jedi_backgroundram[offs] & 0xFF);
+ int bank = (jedi_backgroundram[offs + 0x400] & 0x0F);
+
+ /* shuffle the bank bits in */
+ code |= (bank & 0x01) << 8;
+ code |= (bank & 0x08) << 6;
+ code |= (bank & 0x02) << 9;
+
+ bgdirty[offs] = bgdirty[offs + 0x400] = 0;
+
+ /* update expanded dirty status (assumes we go right-to-left) */
+ if (bgexdirty[sy][1] == -1)
+ bgexdirty[sy][1] = sx;
+ bgexdirty[sy][0] = sx;
+
+ drawgfx(bgbitmap, machine->gfx[1], code,
+ 0, bank & 0x04, 0, 8*sx, 8*sy, 0, TRANSPARENCY_NONE_RAW, 0);
+ }
+
+ /* update smoothed version of background */
+ for (offs = 0; offs < 32; offs++)
+ if (bgexdirty[offs][1] != -1)
+ update_smoothing(offs, bgexdirty[offs][0], bgexdirty[offs][1]);
+
+ /* draw the motion objects */
+ for (offs = 0; offs < 0x30; offs++)
+ {
+ /* coordinates adjustments made to match screenshot */
+ int x = spriteram[offs + 0x100] + ((spriteram[offs + 0x40] & 0x01) << 8) - 2;
+ int y = 240 - spriteram[offs + 0x80] + 1;
+ int flipx = spriteram[offs + 0x40] & 0x10;
+ int flipy = spriteram[offs + 0x40] & 0x20;
+ int tall = spriteram[offs + 0x40] & 0x08;
+ int code, bank;
+
+ /* shuffle the bank bits in */
+ bank = ((spriteram[offs + 0x40] & 0x02) >> 1);
+ bank |= ((spriteram[offs + 0x40] & 0x40) >> 5);
+ bank |= (spriteram[offs + 0x40] & 0x04);
+ code = spriteram[offs] + (bank * 256);
+
+ /* adjust for double-height */
+ if (tall)
+ code |= 1;
+
+ /* draw motion object */
+ drawgfx(mobitmap, machine->gfx[2], code,
+ 0, flipx, flipy, x, y, &machine->screen[0].visarea, TRANSPARENCY_PEN_RAW, 0);
+
+ /* handle double-height */
+ if (tall)
+ drawgfx(mobitmap, machine->gfx[2], code - 1,
+ 0, flipx, flipy, x, y - 16, &machine->screen[0].visarea, TRANSPARENCY_PEN_RAW, 0);
+ }
+
+ /* compose the three layers */
+ {
+ int xscroll = -jedi_hscroll;
+ int yscroll = -jedi_vscroll;
+ copyscrollbitmap(bitmap, bgexbitmap, 1, &xscroll, 1, &yscroll, &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ copybitmap(bitmap, mobitmap, 0, 0, 0, 0, &machine->screen[0].visarea, TRANSPARENCY_BLEND_RAW, 4);
+ copybitmap(bitmap, fgbitmap, 0, 0, 0, 0, &machine->screen[0].visarea, TRANSPARENCY_BLEND, 8);
+ }
+
+ /* erase the motion objects */
+ for (offs = 0; offs < 0x30; offs++)
+ {
+ /* coordinates adjustments made to match screenshot */
+ int x = spriteram[offs + 0x100] + ((spriteram[offs + 0x40] & 0x01) << 8) - 2;
+ int y = 240 - spriteram[offs + 0x80] + 1;
+ int tall = spriteram[offs + 0x40] & 0x08;
+ rectangle bounds;
+
+ /* compute the bounds */
+ bounds.min_x = x;
+ bounds.max_x = x + 15;
+ bounds.min_y = tall ? (y - 16) : y;
+ bounds.max_y = y + (tall ? 31 : 15);
+ fillbitmap(mobitmap, 0, &bounds);
+ }
+ return 0;
+}
diff --git a/src/mame/video/jpmimpct.c b/src/mame/video/jpmimpct.c
new file mode 100644
index 00000000000..ae29710bc9d
--- /dev/null
+++ b/src/mame/video/jpmimpct.c
@@ -0,0 +1,151 @@
+/***************************************************************************
+
+ JPM IMPACT with Video hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "cpu/tms34010/tms34010.h"
+#include "jpmimpct.h"
+
+
+UINT16 *tms_vram;
+
+
+/*************************************
+ *
+ * Brooktree Bt477 RAMDAC
+ *
+ *************************************/
+
+static struct
+{
+ UINT8 address;
+ UINT8 addr_cnt;
+ UINT8 pixmask;
+ UINT8 command;
+ rgb_t color;
+} bt477;
+
+
+/*
+ * 0 0 0 Address register (RAM write mode)
+ * 0 0 1 Color palette RAMs
+ * 0 1 0 Pixel read mask register
+ * 0 1 1 Address register (RAM read mode)
+ * 1 0 0 Address register (overlay write mode)
+ * 1 1 1 Address register (overlay read mode)
+ * 1 0 1 Overlay register
+ * 1 1 0 Command register
+ */
+
+WRITE16_HANDLER( bt477_w )
+{
+ UINT8 val = data & 0xff;
+
+ switch (offset)
+ {
+ case 0x0:
+ {
+ bt477.address = val;
+ bt477.addr_cnt = 0;
+ break;
+ }
+ case 0x1:
+ {
+ UINT8 *addr_cnt = &bt477.addr_cnt;
+ rgb_t *color = &bt477.color;
+
+ color[*addr_cnt] = val;
+
+ if (++*addr_cnt == 3)
+ {
+ palette_set_color(Machine, bt477.address, MAKE_RGB(color[0], color[1], color[2]));
+ *addr_cnt = 0;
+
+ /* Address register increments */
+ bt477.address++;
+ }
+ break;
+ }
+ case 0x2:
+ {
+ bt477.pixmask = val;
+ break;
+ }
+ case 0x6:
+ {
+ bt477.command = val;
+ break;
+ }
+ default:
+ {
+ popmessage("Bt477: Unhandled write access (offset:%x, data:%x)", offset, val);
+ }
+ }
+}
+
+READ16_HANDLER( bt477_r )
+{
+ popmessage("Bt477: Unhandled read access (offset:%x)", offset);
+ return 0;
+}
+
+
+/*************************************
+ *
+ * VRAM shift register callbacks
+ *
+ *************************************/
+
+void jpmimpct_to_shiftreg(UINT32 address, UINT16 *shiftreg)
+{
+ memcpy(shiftreg, &tms_vram[TOWORD(address)], 512 * sizeof(UINT16));
+}
+
+void jpmimpct_from_shiftreg(UINT32 address, UINT16 *shiftreg)
+{
+ memcpy(&tms_vram[TOWORD(address)], shiftreg, 512 * sizeof(UINT16));
+}
+
+
+/*************************************
+ *
+ * Main video refresh
+ *
+ *************************************/
+
+void jpmimpct_scanline_update(running_machine *machine, int screen, mame_bitmap *bitmap, int scanline, const tms34010_display_params *params)
+{
+ UINT16 *vram = &tms_vram[(params->rowaddr << 8) & 0x3ff00];
+ UINT32 *dest = BITMAP_ADDR32(bitmap, scanline, 0);
+ int coladdr = params->coladdr;
+ int x;
+
+ for (x = params->heblnk; x < params->hsblnk; x += 2)
+ {
+ UINT16 pixels = vram[coladdr++ & 0xff];
+ dest[x + 0] = machine->pens[pixels & 0xff];
+ dest[x + 1] = machine->pens[pixels >> 8];
+ }
+}
+
+
+/*************************************
+ *
+ * Video emulation start
+ *
+ *************************************/
+
+VIDEO_START( jpmimpct )
+{
+ memset(&bt477, 0, sizeof(bt477));
+
+ state_save_register_global(bt477.address);
+ state_save_register_global(bt477.addr_cnt);
+ state_save_register_global(bt477.pixmask);
+ state_save_register_global(bt477.command);
+ state_save_register_global(bt477.color);
+
+ video_start_generic_bitmapped(machine);
+}
diff --git a/src/mame/video/kan_panb.c b/src/mame/video/kan_panb.c
new file mode 100644
index 00000000000..b6575a6d19d
--- /dev/null
+++ b/src/mame/video/kan_panb.c
@@ -0,0 +1,275 @@
+/* bootlegs of Kaneko Pandora chip, with modifications */
+
+#include "driver.h"
+#include "kan_panb.h"
+
+VIDEO_UPDATE( honeydol )
+{
+ int sx=0, sy=0, x=0, y=0, offs;
+ /* sprites clip on left / right edges when scrolling, but it seems correct,
+ no extra sprite attribute bits are set during this time, the sprite co-ordinates
+ are simply set to 0 */
+
+ /* not standard snowbros video */
+
+ fillbitmap(bitmap,0xf0,&machine->screen[0].visarea);
+
+ for (offs = 0x0000/2;offs < 0x2000/2;offs += 8)
+ {
+ int dx,dy,tilecolour,attr,flipx,flipy,tile;
+
+ /* 8bpp gfx */
+ dx = (spriteram16[offs+4]>>8) & 0xff;
+ dy = (spriteram16[offs+5]>>8) & 0xff;
+ tilecolour = (spriteram16[offs+3]>>8)&3;
+ attr = spriteram16[offs+7]>>8;
+ flipx = attr & 0x80;
+ flipy = (attr & 0x40) << 1;
+ tile = ((attr & 0x3f)<<8) + ((spriteram16[offs+6]>>8) & 0xff);
+
+ x = dx;
+ y = dy;
+
+ if (flip_screen)
+ {
+ sx = 240 - x;
+ sy = 240 - y;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+ else
+ {
+ sx = x;
+ sy = y;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ tile,
+ tilecolour,
+ flipx, flipy,
+ sx,sy,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+
+ /* second list interleaved with first (4bpp) ??? */
+ dx = spriteram16[offs+4] & 0xff;
+ dy = spriteram16[offs+5] & 0xff;
+ tilecolour = spriteram16[offs+3];
+ attr = spriteram16[offs+7];
+ flipx = attr & 0x80;
+ flipy = (attr & 0x40) << 1;
+ tile = ((attr & 0x3f) << 8) + (spriteram16[offs+6] & 0xff);
+
+ x = dx;
+ y = dy;
+
+ if (flip_screen)
+ {
+ sx = 240 - x;
+ sy = 240 - y;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+ else
+ {
+ sx = x;
+ sy = y;
+ }
+
+ tilecolour = (tilecolour&0x03f0) >> 4;
+ tilecolour ^=0x3f; // unusual, but correct..
+
+ drawgfx(bitmap,machine->gfx[0],
+ tile,
+ tilecolour,
+ flipx, flipy,
+ sx,sy,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( twinadv )
+{
+ int sx=0, sy=0, x=0, y=0, offs;
+ /* sprites clip on left / right edges when scrolling, but it seems correct,
+ no extra sprite attribute bits are set during this time, the sprite co-ordinates
+ are simply set to 0 */
+
+ /* not standard snowbros video */
+
+ fillbitmap(bitmap,0xf0,&machine->screen[0].visarea);
+
+ for (offs = 0x0000/2;offs < 0x2000/2;offs += 8)
+ {
+ int dx,dy,tilecolour,attr,flipx,flipy,tile;
+
+ /* Similar to Honey Doll, but no 8bpp list / gfx */
+
+ dx = spriteram16[offs+4] & 0xff;
+ dy = spriteram16[offs+5] & 0xff;
+ tilecolour = spriteram16[offs+3];
+ attr = spriteram16[offs+7];
+ flipx = attr & 0x80;
+ flipy = (attr & 0x40) << 1;
+ tile = ((attr & 0x3f) << 8) + (spriteram16[offs+6] & 0xff);
+
+ x = dx;
+ y = dy;
+
+ if (flip_screen)
+ {
+ sx = 240 - x;
+ sy = 240 - y;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+ else
+ {
+ sx = x;
+ sy = y;
+ }
+
+ tilecolour = (tilecolour&0x00f0) >> 4;
+ tilecolour ^=0xf; // unusual, but correct..
+
+ drawgfx(bitmap,machine->gfx[0],
+ tile,
+ tilecolour,
+ flipx, flipy,
+ sx,sy,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( wintbob )
+{
+ int offs;
+
+ fillbitmap(bitmap,get_black_pen(machine),&machine->screen[0].visarea);
+
+ for (offs = 0;offs < spriteram_size/2;offs += 8)
+ {
+ int xpos = spriteram16[offs] & 0xff;
+ int ypos = spriteram16[offs+4] & 0xff;
+/* int unk1 = spriteram16[offs+1] & 0x01;*/ /* Unknown .. Set for the Bottom Left part of Sprites */
+ int disbl = spriteram16[offs+1] & 0x02;
+/* int unk2 = spriteram16[offs+1] & 0x04;*/ /* Unknown .. Set for most things */
+ int wrapr = spriteram16[offs+1] & 0x08;
+ int colr = (spriteram16[offs+1] & 0xf0) >> 4;
+ int tilen = (spriteram16[offs+2] << 8) + (spriteram16[offs+3] & 0xff);
+ int flipx = spriteram16[offs+2] & 0x80;
+ int flipy = (spriteram16[offs+2] & 0x40) << 1;
+
+ if (wrapr == 8) xpos -= 256;
+
+ if (flip_screen)
+ {
+ xpos = 240 - xpos;
+ ypos = 240 - ypos;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if ((xpos > -16) && (ypos > 0) && (xpos < 256) && (ypos < 240) && (disbl !=2))
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ tilen,
+ colr,
+ flipx, flipy,
+ xpos,ypos,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( snowbro3 )
+{
+
+ int sx=0, sy=0, x=0, y=0, offs;
+
+ /*
+ * Sprite Tile Format
+ * ------------------
+ *
+ * Byte | Bit(s) | Use
+ * -----+-76543210-+----------------
+ * 0-5 | -------- | ?
+ * 6 | -------- | ?
+ * 7 | xxxx.... | Palette Bank
+ * 7 | .......x | XPos - Sign Bit
+ * 9 | xxxxxxxx | XPos
+ * 7 | ......x. | YPos - Sign Bit
+ * B | xxxxxxxx | YPos
+ * 7 | .....x.. | Use Relative offsets
+ * C | -------- | ?
+ * D | xxxxxxxx | Sprite Number (low 8 bits)
+ * E | -------- | ?
+ * F | ....xxxx | Sprite Number (high 4 bits)
+ * F | x....... | Flip Sprite Y-Axis
+ * F | .x...... | Flip Sprite X-Axis
+ */
+
+ /* This clears & redraws the entire screen each pass */
+
+ fillbitmap(bitmap,get_black_pen(machine),&machine->screen[0].visarea);
+
+ for (offs = 0;offs < spriteram_size/2;offs += 8)
+ {
+ gfx_element *gfx = machine->gfx[0];
+ int dx = spriteram16[offs+4] & 0xff;
+ int dy = spriteram16[offs+5] & 0xff;
+ int tilecolour = spriteram16[offs+3];
+ int attr = spriteram16[offs+7];
+ int flipx = attr & 0x80;
+ int flipy = (attr & 0x40) << 1;
+ int tile = ((attr & 0xff) << 8) + (spriteram16[offs+6] & 0xff);
+
+ if (tilecolour & 1) dx = -1 - (dx ^ 0xff);
+ if (tilecolour & 2) dy = -1 - (dy ^ 0xff);
+ if (tilecolour & 4)
+ {
+ x += dx;
+ y += dy;
+ }
+ else
+ {
+ x = dx;
+ y = dy;
+ }
+
+ if (x > 511) x &= 0x1ff;
+ if (y > 511) y &= 0x1ff;
+
+ if (flip_screen)
+ {
+ sx = 240 - x;
+ sy = 240 - y;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+ else
+ {
+ sx = x;
+ sy = y;
+ }
+
+ if (offs < 0x800) /* i guess this is the right way */
+ {
+ gfx = machine->gfx[1];
+ tilecolour = 0x10;
+ }
+
+ drawgfx(bitmap,gfx,
+ tile,
+ (tilecolour & 0xf0) >> 4,
+ flipx, flipy,
+ sx,sy,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/kan_panb.h b/src/mame/video/kan_panb.h
new file mode 100644
index 00000000000..88e99818459
--- /dev/null
+++ b/src/mame/video/kan_panb.h
@@ -0,0 +1,4 @@
+VIDEO_UPDATE( honeydol );
+VIDEO_UPDATE( twinadv );
+VIDEO_UPDATE( wintbob );
+VIDEO_UPDATE( snowbro3 );
diff --git a/src/mame/video/kan_pand.c b/src/mame/video/kan_pand.c
new file mode 100644
index 00000000000..1d563634163
--- /dev/null
+++ b/src/mame/video/kan_pand.c
@@ -0,0 +1,258 @@
+/* kan_pand.c Kaneko Pandora Sprite Chip
+ GFX processor - PX79C480FP-3 (KANEKO, Pandora-Chip)
+
+ This emulates the Kaneko Pandora Sprite Chip
+ which is found on several Kaneko boards.
+
+ there several bootleg variants of this chip,
+ these are emulated in kan_panb.c instead.
+
+ Original Games using this Chip
+
+ Snow Bros
+ Air Buster
+ DJ Boy
+ Heavy Unit
+ Sand Scorpian
+ Gals Panic (1st release)
+
+ The SemiCom games are also using this because
+ their bootleg chip appears to function in an
+ identical way.
+
+ Rendering appears to be done to a framebuffer
+ and the video system can be instructed not to
+ clear this, allowing for 'sprite trail' effects
+ as used by Air Buster.
+
+ The chip appears to be an 8-bit chip, and
+ when used on 16-bit CPUs only the MSB or LSB
+ of the data lines are connected. Address Lines
+ also appear to be swapped around on one of the
+ hookups.
+
+ to use this in a driver you must hook functions to
+ VIDEO_START (allocates ram used by chip)
+ VIDEO_UPDATE (copies framebuffer to screen)
+ and
+ VIDEO_EOF (renders the sprites to the framebuffer)
+
+ spriteram should be accessed only with the
+ pandora_spriteram_r / pandora_spriteram_w or
+ pandora_spriteram_LSB_r / pandora_spriteram_LSB_w
+ handlers, depending on the CPU being used with it.
+
+*/
+
+#include "driver.h"
+#include "kan_pand.h"
+
+static UINT8* pandora_spriteram;
+static UINT8 pandora_region;
+static mame_bitmap *pandora_sprites_bitmap; /* bitmap to render sprites to, Pandora seems to be frame'buffered' */
+static int pandora_clear_bitmap;
+static int pandora_xoffset, pandora_yoffset;
+
+void pandora_set_clear_bitmap(int clear)
+{
+ pandora_clear_bitmap = clear;
+}
+
+void pandora_update(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ if (!pandora_sprites_bitmap)
+ {
+ printf("ERROR: pandora_update with no pandora_sprites_bitmap\n");
+ return;
+ }
+
+ copybitmap(bitmap,pandora_sprites_bitmap,0,0,0,0,cliprect,TRANSPARENCY_PEN,0);
+}
+
+
+static void pandora_draw(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+
+ int sx=0, sy=0, x=0, y=0, offs;
+
+
+ /*
+ * Sprite Tile Format
+ * ------------------
+ *
+ * Byte | Bit(s) | Use
+ * -----+-76543210-+----------------
+ * 0-2 | -------- | unused
+ * 3 | xxxx.... | Palette Bank
+ * 3 | .......x | XPos - Sign Bit
+ * 3 | ......x. | YPos - Sign Bit
+ * 3 | .....x.. | Use Relative offsets
+ * 4 | xxxxxxxx | XPos
+ * 5 | xxxxxxxx | YPos
+ * 6 | xxxxxxxx | Sprite Number (low 8 bits)
+ * 7 | ....xxxx | Sprite Number (high 4 bits)
+ * 7 | x....... | Flip Sprite Y-Axis
+ * 7 | .x...... | Flip Sprite X-Axis
+ */
+
+ for (offs = 0;offs < 0x1000;offs += 8)
+ {
+ int dx = pandora_spriteram[offs+4];
+ int dy = pandora_spriteram[offs+5];
+ int tilecolour = pandora_spriteram[offs+3];
+ int attr = pandora_spriteram[offs+7];
+ int flipx = attr & 0x80;
+ int flipy = (attr & 0x40) << 1;
+ int tile = ((attr & 0x3f) << 8) + (pandora_spriteram[offs+6] & 0xff);
+
+ if (tilecolour & 1) dx |= 0x100;
+ if (tilecolour & 2) dy |= 0x100;
+
+ if (tilecolour & 4)
+ {
+ x += dx;
+ y += dy;
+ }
+ else
+ {
+ x = dx;
+ y = dy;
+ }
+
+ if (flip_screen)
+ {
+ sx = 240 - x;
+ sy = 240 - y;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+ else
+ {
+ sx = x;
+ sy = y;
+ }
+
+ /* global offset */
+ sx+=pandora_xoffset;
+ sy+=pandora_yoffset;
+
+ sx &=0x1ff;
+ sy &=0x1ff;
+
+ if (sx&0x100) sx-=0x200;
+ if (sy&0x100) sy-=0x200;
+
+ drawgfx(bitmap,machine->gfx[pandora_region],
+ tile,
+ (tilecolour & 0xf0) >> 4,
+ flipx, flipy,
+ sx,sy,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+}
+
+void pandora_eof(running_machine *machine)
+{
+ rectangle clip;
+
+ /* draw top of screen */
+ clip.min_x = machine->screen[0].visarea.min_x;
+ clip.max_x = machine->screen[0].visarea.max_x;
+ clip.min_y = machine->screen[0].visarea.min_y;
+ clip.max_y = machine->screen[0].visarea.max_y;
+
+ if (!pandora_spriteram)
+ {
+ printf("ERROR: pandora_eof with no pandora_spriteram\n");
+ return;
+ }
+
+ // the games can disable the clearing of the sprite bitmap, to leave sprite trails
+ if (pandora_clear_bitmap) fillbitmap(pandora_sprites_bitmap,0,&clip);
+
+ pandora_draw(machine, pandora_sprites_bitmap, &clip);
+}
+
+void pandora_start(UINT8 region, int x, int y)
+{
+ pandora_region = region;
+ pandora_xoffset = x;
+ pandora_yoffset = y;
+ pandora_spriteram = auto_malloc(0x1000);
+ memset(pandora_spriteram,0x00, 0x1000);
+
+ pandora_sprites_bitmap = auto_bitmap_alloc(Machine->screen[0].width,Machine->screen[0].height,Machine->screen[0].format);
+ pandora_clear_bitmap = 1;
+}
+
+
+WRITE8_HANDLER ( pandora_spriteram_w )
+{
+ // it's either hooked up oddly on this, or on the 16-bit games
+ // either way, we swap the address lines so that the spriteram is in the same format
+ offset = BITSWAP16(offset, 15,14,13,12, 11, 7,6,5,4,3,2,1,0, 10,9,8 );
+
+ if (!pandora_spriteram)
+ {
+ printf("ERROR: pandora_spriteram_w with no pandora_spriteram\n");
+ return;
+ }
+
+ if (offset>=0x1000)
+ {
+ logerror("pandora_spriteram_w write past spriteram, offset %04x %02x\n",offset,data);
+ return;
+ }
+ pandora_spriteram[offset] = data;
+}
+
+READ8_HANDLER( pandora_spriteram_r )
+{
+ // it's either hooked up oddly on this, or ont the 16-bit games
+ // either way, we swap the address lines so that the spriteram is in the same format
+ offset = BITSWAP16(offset, 15,14,13,12, 11, 7,6,5,4,3,2,1,0, 10,9,8 );
+
+ if (!pandora_spriteram)
+ {
+ printf("ERROR: pandora_spriteram_r with no pandora_spriteram\n");
+ return 0x00;
+ }
+
+ if (offset>=0x1000)
+ {
+ logerror("pandora_spriteram_r read past spriteram, offset %04x\n",offset );
+ return 0x00;
+ }
+ return pandora_spriteram[offset];
+}
+
+/* I don't know if this MSB/LSB mirroring is correct, or if there is twice as much ram, with half of it unused */
+WRITE16_HANDLER( pandora_spriteram_LSB_w )
+{
+ if (!pandora_spriteram)
+ {
+ printf("ERROR: pandora_spriteram_LSB_w with no pandora_spriteram\n");
+ return;
+ }
+
+ if (ACCESSING_MSB)
+ {
+ pandora_spriteram[offset] = (data>>8)&0xff;
+ }
+
+ if (ACCESSING_LSB)
+ {
+ pandora_spriteram[offset] = data&0xff;
+ }
+}
+
+READ16_HANDLER( pandora_spriteram_LSB_r )
+{
+ if (!pandora_spriteram)
+ {
+ printf("ERROR: pandora_spriteram_LSB_r with no pandora_spriteram\n");
+ return 0x0000;
+ }
+
+ return pandora_spriteram[offset]|(pandora_spriteram[offset]<<8);
+}
diff --git a/src/mame/video/kan_pand.h b/src/mame/video/kan_pand.h
new file mode 100644
index 00000000000..696292e86ef
--- /dev/null
+++ b/src/mame/video/kan_pand.h
@@ -0,0 +1,11 @@
+/* kan_pand.h */
+
+void pandora_start(UINT8 region, int x, int y);
+void pandora_update(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect);
+void pandora_eof(running_machine *machine);
+void pandora_set_clear_bitmap(int clear);
+
+WRITE8_HANDLER ( pandora_spriteram_w );
+READ8_HANDLER( pandora_spriteram_r );
+WRITE16_HANDLER( pandora_spriteram_LSB_w );
+READ16_HANDLER( pandora_spriteram_LSB_r );
diff --git a/src/mame/video/kaneko16.c b/src/mame/video/kaneko16.c
new file mode 100644
index 00000000000..c389ed8299d
--- /dev/null
+++ b/src/mame/video/kaneko16.c
@@ -0,0 +1,1057 @@
+/***************************************************************************
+
+ -= Kaneko 16 Bit Games =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+ [ 1 High Color Layer ]
+
+ In ROM (Optional)
+
+ [ Scrolling Layers ]
+
+ Each VIEW2 chip generates 2 layers. Up to 2 chips are used
+ (4 layers)
+
+ Layer Size: 512 x 512
+ Tiles: 16 x 16 x 4
+
+ Line scroll is supported by the chip: each layer has RAM
+ for 512 horizontal scroll offsets (one per tilemap line)
+ that are added to the global scroll values.
+ See e.g. blazeon (2nd demo level), mgcrystl, sandscrp.
+
+ [ 1024 Sprites ]
+
+ Sprites are 16 x 16 x 4 in the older games, 16 x 16 x 8 in
+ gtmr & gtmr2.
+ Sprites types 0 and 2 can also have a simple effect keeping
+ sprites on the screen
+
+
+**************************************************************************/
+
+#include "driver.h"
+#include "kaneko16.h"
+#include "kan_pand.h"
+
+UINT16 kaneko16_disp_enable = 1; // default enabled for games not using it
+
+
+static tilemap *kaneko16_tmap_0, *kaneko16_tmap_1;
+static tilemap *kaneko16_tmap_2, *kaneko16_tmap_3;
+UINT16 *kaneko16_vram_0, *kaneko16_vram_1, *kaneko16_layers_0_regs;
+UINT16 *kaneko16_vscroll_0, *kaneko16_vscroll_1;
+UINT16 *kaneko16_vram_2, *kaneko16_vram_3, *kaneko16_layers_1_regs;
+UINT16 *kaneko16_vscroll_2, *kaneko16_vscroll_3;
+
+UINT16* galsnew_bg_pixram;
+UINT16* galsnew_fg_pixram;
+
+int kaneko16_sprite_type;
+int kaneko16_keep_sprites = 0; // default disabled for games not using it
+UINT16 kaneko16_sprite_xoffs, kaneko16_sprite_flipx;
+UINT16 kaneko16_sprite_yoffs, kaneko16_sprite_flipy;
+UINT16 *kaneko16_sprites_regs;
+
+
+UINT16 *kaneko16_bg15_select, *kaneko16_bg15_reg;
+static mame_bitmap *kaneko16_bg15_bitmap;
+static mame_bitmap *sprites_bitmap; /* bitmap used for to keep sprites on screen (mgcrystl 1st boss) */
+
+struct tempsprite
+{
+ int code,color;
+ int x,y;
+ int xoffs,yoffs;
+ int flipx,flipy;
+ int priority;
+};
+
+static struct
+{
+ struct tempsprite *first_sprite;
+} spritelist;
+
+
+kaneko16_priority_t kaneko16_priority;
+
+
+WRITE16_HANDLER( kaneko16_display_enable )
+{
+ COMBINE_DATA(&kaneko16_disp_enable);
+}
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+ [ Tiles Format ]
+
+Offset:
+
+0000.w fedc b--- ---- ---- unused?
+ ---- -a9- ---- ---- High Priority (vs Sprites)
+ ---- ---8 ---- ---- High Priority (vs Tiles)
+ ---- ---- 7654 32-- Color
+ ---- ---- ---- --1- Flip X
+ ---- ---- ---- ---0 Flip Y
+
+0002.w Code
+
+***************************************************************************/
+
+#define KANEKO16_LAYER(_N_) \
+static TILE_GET_INFO( get_tile_info_##_N_ ) \
+{ \
+ UINT16 code_hi = kaneko16_vram_##_N_[ 2 * tile_index + 0]; \
+ UINT16 code_lo = kaneko16_vram_##_N_[ 2 * tile_index + 1]; \
+ SET_TILE_INFO(1 + _N_/2, code_lo, (code_hi >> 2) & 0x3f, TILE_FLIPXY( code_hi & 3 )); \
+ tileinfo->category = (code_hi >> 8) & 7; \
+} \
+\
+WRITE16_HANDLER( kaneko16_vram_##_N_##_w ) \
+{ \
+ COMBINE_DATA(&kaneko16_vram_##_N_[offset]); \
+ tilemap_mark_tile_dirty(kaneko16_tmap_##_N_, offset/2); \
+}
+
+
+KANEKO16_LAYER(0)
+KANEKO16_LAYER(1)
+KANEKO16_LAYER(2)
+KANEKO16_LAYER(3)
+
+VIDEO_START( kaneko16_sprites )
+{
+ /* 0x400 sprites max */
+ spritelist.first_sprite = (struct tempsprite *)auto_malloc(0x400 * sizeof(spritelist.first_sprite[0]));
+}
+
+VIDEO_START( kaneko16_1xVIEW2 )
+{
+ video_start_kaneko16_sprites(machine);
+
+ kaneko16_tmap_0 = tilemap_create( get_tile_info_0, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 0x20,0x20 );
+ kaneko16_tmap_1 = tilemap_create( get_tile_info_1, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 0x20,0x20 );
+
+ kaneko16_tmap_2 = 0;
+
+ kaneko16_tmap_3 = 0;
+
+ sprites_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ {
+ int dx, xdim = machine->screen[0].width;
+ int dy, ydim = machine->screen[0].height;
+
+ switch (xdim)
+ {
+ case 320: dx = 0x33; break;
+ case 256: dx = 0x5b; break;
+ default: dx = 0;
+ }
+ switch (machine->screen[0].visarea.max_y - machine->screen[0].visarea.min_y + 1)
+ {
+ case 240- 8: dy = +0x08; break; /* blazeon */
+ case 240-16: dy = -0x08; break; /* berlwall, bakubrk */
+ default: dy = 0;
+ }
+
+ tilemap_set_scrolldx( kaneko16_tmap_0, -dx, xdim + dx -1 );
+ tilemap_set_scrolldx( kaneko16_tmap_1, -(dx+2), xdim + (dx + 2) - 1 );
+
+ tilemap_set_scrolldy( kaneko16_tmap_0, -dy, ydim + dy -1 );
+ tilemap_set_scrolldy( kaneko16_tmap_1, -dy, ydim + dy -1 );
+
+ tilemap_set_transparent_pen(kaneko16_tmap_0, 0);
+ tilemap_set_transparent_pen(kaneko16_tmap_1, 0);
+
+ tilemap_set_scroll_rows(kaneko16_tmap_0, 0x200); // Line Scroll
+ tilemap_set_scroll_rows(kaneko16_tmap_1, 0x200);
+ }
+}
+
+VIDEO_START( kaneko16_2xVIEW2 )
+{
+ video_start_kaneko16_1xVIEW2(machine);
+
+ kaneko16_tmap_2 = tilemap_create( get_tile_info_2, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 0x20,0x20 );
+ kaneko16_tmap_3 = tilemap_create( get_tile_info_3, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 0x20,0x20 );
+
+ {
+ int dx, xdim = machine->screen[0].width;
+ int dy, ydim = machine->screen[0].height;
+
+ switch (xdim)
+ {
+ case 320: dx = 0x33; break;
+ case 256: dx = 0x5b; break;
+ default: dx = 0;
+ }
+ switch (machine->screen[0].visarea.max_y - machine->screen[0].visarea.min_y + 1)
+ {
+ case 240- 8: dy = +0x08; break;
+ case 240-16: dy = -0x08; break;
+ default: dy = 0;
+ }
+
+ tilemap_set_scrolldx( kaneko16_tmap_2, -dx, xdim + dx -1 );
+ tilemap_set_scrolldx( kaneko16_tmap_3, -(dx+2), xdim + (dx + 2) - 1 );
+
+ tilemap_set_scrolldy( kaneko16_tmap_2, -dy, ydim + dy -1 );
+ tilemap_set_scrolldy( kaneko16_tmap_3, -dy, ydim + dy -1 );
+
+ tilemap_set_transparent_pen(kaneko16_tmap_2, 0);
+ tilemap_set_transparent_pen(kaneko16_tmap_3, 0);
+
+ tilemap_set_scroll_rows(kaneko16_tmap_2, 0x200); // Line Scroll
+ tilemap_set_scroll_rows(kaneko16_tmap_3, 0x200);
+ }
+}
+
+VIDEO_START( sandscrp_1xVIEW2 )
+{
+ video_start_kaneko16_1xVIEW2(machine);
+ pandora_start(0,0,0);
+
+ tilemap_set_scrolldy( kaneko16_tmap_0, 0, 256 - 1 );
+ tilemap_set_scrolldy( kaneko16_tmap_1, 0, 256 - 1 );
+}
+
+
+
+/* Berlwall and Gals Panic have an additional hi-color layers */
+
+PALETTE_INIT( berlwall )
+{
+ int i;
+
+ /* first 2048 colors are dynamic */
+
+ /* initialize 555 RGB lookup */
+ for (i = 0; i < 32768; i++)
+ palette_set_color_rgb(machine,2048 + i,pal5bit(i >> 5),pal5bit(i >> 10),pal5bit(i >> 0));
+}
+
+VIDEO_START( berlwall )
+{
+ int sx, x,y;
+ UINT8 *RAM = memory_region(REGION_GFX3);
+
+ /* Render the hi-color static backgrounds held in the ROMs */
+
+ kaneko16_bg15_bitmap = auto_bitmap_alloc(256 * 32, 256 * 1, BITMAP_FORMAT_INDEXED16);
+
+/*
+ 8aba is used as background color
+ 8aba/2 = 455d = 10001 01010 11101 = $11 $0a $1d
+*/
+
+ for (sx = 0 ; sx < 32 ; sx++) // horizontal screens
+ for (x = 0 ; x < 256 ; x++) // horizontal pixels
+ for (y = 0 ; y < 256 ; y++) // vertical pixels
+ {
+ int addr = sx * (256 * 256) + x + y * 256;
+ int data = RAM[addr * 2 + 0] * 256 + RAM[addr * 2 + 1];
+ int r,g,b;
+
+ r = (data & 0x07c0) >> 6;
+ g = (data & 0xf800) >> 11;
+ b = (data & 0x003e) >> 1;
+
+ /* apply a simple decryption */
+ r ^= 0x09;
+
+ if (~g & 0x08) g ^= 0x10;
+ g = (g - 1) & 0x1f; /* decrease with wraparound */
+
+ b ^= 0x03;
+ if (~b & 0x08) b ^= 0x10;
+ b = (b + 2) & 0x1f; /* increase with wraparound */
+
+ /* kludge to fix the rollercoaster picture */
+ if ((r & 0x10) && (b & 0x10))
+ g = (g - 1) & 0x1f; /* decrease with wraparound */
+
+ *BITMAP_ADDR16(kaneko16_bg15_bitmap, y, sx * 256 + x) = machine->pens[2048 + ((g << 10) | (r << 5) | b)];
+ }
+
+ video_start_kaneko16_1xVIEW2(machine);
+}
+
+VIDEO_START( galsnew )
+{
+ video_start_kaneko16_1xVIEW2(machine);
+}
+
+/***************************************************************************
+
+ Sprites Drawing
+
+ Sprite data is layed out in RAM in different ways for different games
+ (type 0,1,2,etc.). This basically involves the bits in the attribute
+ word to be shuffled around and/or the words being in different order.
+
+ Each sprite is always stuffed in 4 words. There may be some extra
+ padding words though (e.g. type 2 sprites are like type 0 but the
+ data is held in the last 8 bytes of every 16). Examples are:
+
+ Type 0: shogwarr, blazeon, bakubrkr.
+ Type 1: gtmr.
+ Type 2: berlwall
+
+Offset: Format: Value:
+
+0000.w Attribute (type 0 & 2)
+
+ f--- ---- ---- ---- Multisprite: Use Latched Code + 1
+ -e-- ---- ---- ---- Multisprite: Use Latched Color (And Flip?)
+ --d- ---- ---- ---- Multisprite: Use Latched X,Y As Offsets
+ ---c ba-- ---- ----
+ ---- --9- ---- ---- High Priority (vs FG Tiles Of High Priority)
+ ---- ---8 ---- ---- High Priority (vs BG Tiles Of High Priority)
+ ---- ---- 7654 32-- Color
+ ---- ---- ---- --1- X Flip
+ ---- ---- ---- ---0 Y Flip
+
+ Attribute (type 1)
+
+ f--- ---- ---- ---- Multisprite: Use Latched Code + 1
+ -e-- ---- ---- ---- Multisprite: Use Latched Color (And Flip?)
+ --d- ---- ---- ---- Multisprite: Use Latched X,Y As Offsets
+ ---c ba-- ---- ----
+ ---- --9- ---- ---- X Flip
+ ---- ---8 ---- ---- Y Flip
+ ---- ---- 7--- ---- High Priority (vs FG Tiles Of High Priority)
+ ---- ---- -6-- ---- High Priority (vs BG Tiles Of High Priority)
+ ---- ---- --54 3210 Color
+
+0002.w Code
+0004.w X Position << 6
+0006.w Y Position << 6
+
+***************************************************************************/
+
+#define USE_LATCHED_XY 1
+#define USE_LATCHED_CODE 2
+#define USE_LATCHED_COLOR 4
+
+static int kaneko16_parse_sprite_type012(running_machine *machine, int i, struct tempsprite *s)
+{
+ int attr, xoffs, offs;
+
+ if (kaneko16_sprite_type == 2) offs = i * 16/2 + 0x8/2;
+ else offs = i * 8/2;
+
+ if (offs >= (spriteram_size/2)) return -1;
+
+ attr = spriteram16[offs + 0];
+ s->code = spriteram16[offs + 1];
+ s->x = spriteram16[offs + 2];
+ s->y = spriteram16[offs + 3];
+
+ if (kaneko16_sprite_type == 1)
+ {
+ s->color = (attr & 0x003f);
+ s->priority = (attr & 0x00c0) >> 6;
+ s->flipy = (attr & 0x0100);
+ s->flipx = (attr & 0x0200);
+ s->code += (s->y & 1) << 16; // bloodwar
+ }
+ else
+ {
+ s->flipy = (attr & 0x0001);
+ s->flipx = (attr & 0x0002);
+ s->color = (attr & 0x00fc) >> 2;
+ s->priority = (attr & 0x0300) >> 8;
+ }
+ xoffs = (attr & 0x1800) >> 11;
+ s->yoffs = kaneko16_sprites_regs[0x10/2 + xoffs*2 + 1];
+ s->xoffs = kaneko16_sprites_regs[0x10/2 + xoffs*2 + 0];
+
+if (kaneko16_sprite_flipy)
+{
+ s->yoffs -= kaneko16_sprites_regs[0x2/2];
+ s->yoffs -= machine->screen[0].visarea.min_y<<6;
+}
+else
+{
+ s->yoffs -= kaneko16_sprites_regs[0x2/2];
+ s->yoffs += machine->screen[0].visarea.min_y<<6;
+}
+
+ return ( (attr & 0x2000) ? USE_LATCHED_XY : 0 ) |
+ ( (attr & 0x4000) ? USE_LATCHED_COLOR : 0 ) |
+ ( (attr & 0x8000) ? USE_LATCHED_CODE : 0 ) ;
+}
+
+// custom function to draw a single sprite. needed to keep correct sprites - sprites and sprites - tilemaps priorities
+static void kaneko16_draw_sprites_custom(mame_bitmap *dest_bmp,const gfx_element *gfx,
+ UINT32 code,UINT32 color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int priority)
+{
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+ UINT8 *source_base = gfx->gfxdata + (code % gfx->total_elements) * gfx->char_modulo;
+
+ int sprite_screen_height = ((1<<16)*gfx->height+0x8000)>>16;
+ int sprite_screen_width = ((1<<16)*gfx->width+0x8000)>>16;
+
+ if (sprite_screen_width && sprite_screen_height)
+ {
+ /* compute sprite increment per screen pixel */
+ int dx = (gfx->width<<16)/sprite_screen_width;
+ int dy = (gfx->height<<16)/sprite_screen_height;
+
+ int ex = sx+sprite_screen_width;
+ int ey = sy+sprite_screen_height;
+
+ int x_index_base;
+ int y_index;
+
+ if( flipx )
+ {
+ x_index_base = (sprite_screen_width-1)*dx;
+ dx = -dx;
+ }
+ else
+ {
+ x_index_base = 0;
+ }
+
+ if( flipy )
+ {
+ y_index = (sprite_screen_height-1)*dy;
+ dy = -dy;
+ }
+ else
+ {
+ y_index = 0;
+ }
+
+ if( clip )
+ {
+ if( sx < clip->min_x)
+ { /* clip left */
+ int pixels = clip->min_x-sx;
+ sx += pixels;
+ x_index_base += pixels*dx;
+ }
+ if( sy < clip->min_y )
+ { /* clip top */
+ int pixels = clip->min_y-sy;
+ sy += pixels;
+ y_index += pixels*dy;
+ }
+ /* NS 980211 - fixed incorrect clipping */
+ if( ex > clip->max_x+1 )
+ { /* clip right */
+ int pixels = ex-clip->max_x-1;
+ ex -= pixels;
+ }
+ if( ey > clip->max_y+1 )
+ { /* clip bottom */
+ int pixels = ey-clip->max_y-1;
+ ey -= pixels;
+ }
+ }
+
+ if( ex>sx )
+ { /* skip if inner loop doesn't draw anything */
+ int y;
+
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT16 *dest = BITMAP_ADDR16(dest_bmp, y, 0);
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if( c != 0 )
+ {
+ if (pri[x] < priority)
+ dest[x] = pal[c];
+ pri[x] = 0xff; // mark it "already drawn"
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+}
+
+/* Build a list of sprites to display & draw them */
+
+void kaneko16_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /* Sprites *must* be parsed from the first in RAM to the last,
+ because of the multisprite feature. But they *must* be drawn
+ from the last in RAM (frontmost) to the firtst in order to
+ cope with priorities using pdrawgfx.
+
+ Hence we parse them from first to last and put the result
+ in a temp buffer, then draw the buffer's contents from last
+ to first. */
+
+ int max = (machine->screen[0].width > 0x100) ? (0x200<<6) : (0x100<<6);
+
+ int i = 0;
+ struct tempsprite *s = spritelist.first_sprite;
+
+ /* These values are latched from the last sprite. */
+ int x = 0;
+ int y = 0;
+ int code = 0;
+ int color = 0;
+ int priority = 0;
+ int xoffs = 0;
+ int yoffs = 0;
+ int flipx = 0;
+ int flipy = 0;
+
+ while (1)
+ {
+ int flags;
+
+ switch( kaneko16_sprite_type )
+ {
+ case 0:
+ case 1:
+ case 2: flags = kaneko16_parse_sprite_type012(machine, i,s); break;
+ default: flags = -1;
+ }
+
+ if (flags == -1) // End of Sprites
+ break;
+
+ if (flags & USE_LATCHED_CODE)
+ s->code = ++code; // Use the latched code + 1 ..
+ else
+ code = s->code; // .. or latch this value
+
+ if (flags & USE_LATCHED_COLOR)
+ {
+ s->color = color;
+ s->priority = priority;
+ s->xoffs = xoffs;
+ s->yoffs = yoffs;
+ s->flipx = flipx;
+ s->flipy = flipy;
+ }
+ else
+ {
+ color = s->color;
+ priority = s->priority;
+ xoffs = s->xoffs;
+ yoffs = s->yoffs;
+ flipx = s->flipx;
+ flipy = s->flipy;
+ }
+
+ if (flags & USE_LATCHED_XY)
+ {
+ s->x += x;
+ s->y += y;
+ }
+ // Always latch the latest result
+ x = s->x;
+ y = s->y;
+
+ /* We can now buffer this sprite */
+
+ s->x = s->xoffs + s->x;
+ s->y = s->yoffs + s->y;
+
+ s->x += kaneko16_sprite_xoffs;
+ s->y += kaneko16_sprite_yoffs;
+
+ if (kaneko16_sprite_flipx) { s->x = max - s->x - (16<<6); s->flipx = !s->flipx; }
+ if (kaneko16_sprite_flipy) { s->y = max - s->y - (16<<6); s->flipy = !s->flipy; }
+
+ s->x = ( (s->x & 0x7fc0) - (s->x & 0x8000) ) / 0x40;
+ s->y = ( (s->y & 0x7fc0) - (s->y & 0x8000) ) / 0x40;
+
+ i++;
+ s++;
+ }
+
+
+ /* Let's finally draw the sprites we buffered, in reverse order
+ (for pdrawgfx) */
+
+ for (s--; s >= spritelist.first_sprite; s--)
+ {
+ int curr_pri = s->priority;
+
+ UINT32 primask = kaneko16_priority.sprite[curr_pri];
+
+ kaneko16_draw_sprites_custom( bitmap,machine->gfx[0],
+ s->code,
+ s->color,
+ s->flipx, s->flipy,
+ s->x, s->y,
+ cliprect,
+ primask );
+ }
+}
+
+
+
+/***************************************************************************
+
+
+ Sprites Registers
+
+ Offset: Format: Value:
+
+ 0000.w f--- ---- ---- ---- Sprites Disable?? (see blazeon)
+ -edc ba98 7654 3---
+ ---- ---- ---- -2-- Keep sprites on screen (only sprites types 0 and 2)
+ ---- ---- ---- --1- Flip X
+ ---- ---- ---- ---0 Flip Y
+
+ 0002.w Y Offset << 6 (Global)
+
+
+ 0004..000e.w ?
+
+
+ 0010.w X Offset << 6 #0
+ 0012.w Y Offset << 6 #0
+
+ 0014.w X Offset << 6 #1
+ 0016.w Y Offset << 6 #1
+
+ 0018.w X Offset << 6 #2
+ 001a.w Y Offset << 6 #2
+
+ 001c.w X Offset << 6 #3
+ 001e.w Y Offset << 6 #3
+
+***************************************************************************/
+
+/*
+[gtmr]
+
+Initial self test:
+600000: 4BC0 94C0 4C40 94C0-0404 0002 0000 0000 (Layers 1 regs)
+680000: 4BC0 94C0 4C40 94C0-1C1C 0002 0000 0000 (Layers 2 regs)
+Race start:
+600000: DC00 7D00 DC80 7D00-0404 0002 0000 0000 (Layers 1 regs)
+680000: DC00 7D00 DC80 7D00-1C1C 0002 0000 0000 (Layers 2 regs)
+
+[gtmr]
+700000: 0040 0000 0001 0180-0000 0000 0000 0000 (Sprites regs)
+700010: 0040 0000 0040 0000-0040 0000 2840 1E00 ; 1,0 .. a1,78
+ ; a0*2=screenx/2
+ ; 78*2=screeny/2
+FLIP ON:
+700000: 0043 FFC0 0001 0180-0000 0000 0000 0000 (Sprites regs)
+700010: 2FC0 4400 2FC0 4400-2FC0 4400 57C0 6200 ; bf,110 .. 15f,188
+ ; 15f-bf=a0! 188-110=78!
+
+[berlwall]
+600000: 48CC 03C0 0001 0100-0000 0000 0000 0000 (Sprites regs)
+600010: 0000 0000 0000 0000-0000 0000 0000 0000
+FLIP ON:
+600000: 48CF FC00 0001 0100-0000 0000 0000 0000 (Sprites regs)
+600010: 0000 0000 0000 0000-0000 0000 0000 0000
+
+[mgcrystl]
+900000: 4FCC 0000 0040 00C0-xxxx 0001 0001 0001 (Sprites regs)
+900010: 0000 FC40 A000 9C40-1E00 1A40 0000 FC40
+FLIP ON:
+900000: 4FCF 0000 0040 00C0-xxxx 0001 0001 0001 (Sprites regs)
+900010: 0000 0400 A000 A400-1E00 2200 0000 0400 ; +1f<<6 on y
+*/
+
+READ16_HANDLER( kaneko16_sprites_regs_r )
+{
+ return kaneko16_sprites_regs[offset];
+}
+
+WRITE16_HANDLER( kaneko16_sprites_regs_w )
+{
+ UINT16 new_data;
+
+ COMBINE_DATA(&kaneko16_sprites_regs[offset]);
+ new_data = kaneko16_sprites_regs[offset];
+
+ switch (offset)
+ {
+ case 0:
+ if (ACCESSING_LSB)
+ {
+ kaneko16_sprite_flipx = new_data & 2;
+ kaneko16_sprite_flipy = new_data & 1;
+
+ if(kaneko16_sprite_type == 0 || kaneko16_sprite_type == 2)
+ kaneko16_keep_sprites = ~new_data & 4;
+ }
+
+ break;
+ }
+
+// logerror("CPU #0 PC %06X : Warning, sprites reg %04X <- %04X\n",activecpu_get_pc(),offset*2,data);
+}
+
+
+/***************************************************************************
+
+ Layers Registers
+
+
+ Offset: Format: Value:
+
+ 0000.w FG Scroll X
+ 0002.w FG Scroll Y
+
+ 0004.w BG Scroll X
+ 0006.w BG Scroll Y
+
+ 0008.w Layers Control
+
+ fed- ---- ---- ----
+ ---c ---- ---- ---- BG Disable
+ ---- b--- ---- ---- Line Scroll (Always 1 in berlwall & bakubrkr)
+ ---- -a-- ---- ---- ? Always 1 in gtmr & bakubrkr ?
+ ---- --9- ---- ---- BG Flip X
+ ---- ---8 ---- ---- BG Flip Y
+
+ ---- ---- 765- ----
+ ---- ---- ---4 ---- FG Disable
+ ---- ---- ---- 3--- Line Scroll (Always 1 in berlwall & bakubrkr)
+ ---- ---- ---- -2-- ? Always 1 in gtmr & bakubrkr ?
+ ---- ---- ---- --1- FG Flip X
+ ---- ---- ---- ---0 FG Flip Y
+
+ 000a.w ? always 0x0002 ?
+
+There are more!
+
+***************************************************************************/
+
+/* [gtmr]
+
+ car select screen scroll values:
+ Flipscreen off:
+ $6x0000: $72c0 ; $fbc0 ; 7340 ; 0
+ $72c0/$40 = $1cb = $200-$35 / $7340/$40 = $1cd = $1cb+2
+
+ $fbc0/$40 = -$11
+
+ Flipscreen on:
+ $6x0000: $5d00 ; $3780 ; $5c80 ; $3bc0
+ $5d00/$40 = $174 = $200-$8c / $5c80/$40 = $172 = $174-2
+
+ $3780/$40 = $de / $3bc0/$40 = $ef
+
+*/
+
+WRITE16_HANDLER( kaneko16_layers_0_regs_w )
+{
+ COMBINE_DATA(&kaneko16_layers_0_regs[offset]);
+}
+
+WRITE16_HANDLER( kaneko16_layers_1_regs_w )
+{
+ COMBINE_DATA(&kaneko16_layers_1_regs[offset]);
+}
+
+
+
+
+/* Select the high color background image (out of 32 in the ROMs) */
+READ16_HANDLER( kaneko16_bg15_select_r )
+{
+ return kaneko16_bg15_select[0];
+}
+WRITE16_HANDLER( kaneko16_bg15_select_w )
+{
+ COMBINE_DATA(&kaneko16_bg15_select[0]);
+}
+
+/* ? */
+READ16_HANDLER( kaneko16_bg15_reg_r )
+{
+ return kaneko16_bg15_reg[0];
+}
+WRITE16_HANDLER( kaneko16_bg15_reg_w )
+{
+ COMBINE_DATA(&kaneko16_bg15_reg[0]);
+}
+
+
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+static void kaneko16_prepare_first_tilemap_chip(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /* Set Up FIRST Tilemap chip */
+ int layers_flip_0;
+ UINT16 layer0_scrollx, layer0_scrolly;
+ UINT16 layer1_scrollx, layer1_scrolly;
+ int i;
+
+ layers_flip_0 = kaneko16_layers_0_regs[ 4 ];
+
+ /* Enable layers */
+ tilemap_set_enable(kaneko16_tmap_0, ~layers_flip_0 & 0x1000);
+ tilemap_set_enable(kaneko16_tmap_1, ~layers_flip_0 & 0x0010);
+
+ /* Flip layers */
+ tilemap_set_flip(kaneko16_tmap_0, ((layers_flip_0 & 0x0100) ? TILEMAP_FLIPY : 0) |
+ ((layers_flip_0 & 0x0200) ? TILEMAP_FLIPX : 0) );
+ tilemap_set_flip(kaneko16_tmap_1, ((layers_flip_0 & 0x0100) ? TILEMAP_FLIPY : 0) |
+ ((layers_flip_0 & 0x0200) ? TILEMAP_FLIPX : 0) );
+
+ /* Scroll layers */
+ layer0_scrollx = kaneko16_layers_0_regs[ 2 ];
+ layer0_scrolly = kaneko16_layers_0_regs[ 3 ] >> 6;
+ layer1_scrollx = kaneko16_layers_0_regs[ 0 ];
+ layer1_scrolly = kaneko16_layers_0_regs[ 1 ] >> 6;
+
+ tilemap_set_scrolly(kaneko16_tmap_0,0,layer0_scrolly);
+ tilemap_set_scrolly(kaneko16_tmap_1,0,layer1_scrolly);
+
+ for (i=0; i<0x200; i++)
+ {
+ UINT16 scroll;
+ scroll = (layers_flip_0 & 0x0800) ? kaneko16_vscroll_0[i] : 0;
+ tilemap_set_scrollx(kaneko16_tmap_0,i,(layer0_scrollx + scroll) >> 6 );
+ scroll = (layers_flip_0 & 0x0008) ? kaneko16_vscroll_1[i] : 0;
+ tilemap_set_scrollx(kaneko16_tmap_1,i,(layer1_scrollx + scroll) >> 6 );
+ }
+
+}
+
+static void kaneko16_prepare_second_tilemap_chip(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /* Set Up SECOND Tilemap chip */
+ int layers_flip_1 = 0;
+ UINT16 layer0_scrollx, layer0_scrolly;
+ UINT16 layer1_scrollx, layer1_scrolly;
+ int i;
+
+ if (kaneko16_tmap_2)
+ {
+ layers_flip_1 = kaneko16_layers_1_regs[ 4 ];
+
+ tilemap_set_enable(kaneko16_tmap_2, ~layers_flip_1 & 0x1000);
+ tilemap_set_enable(kaneko16_tmap_3, ~layers_flip_1 & 0x0010);
+
+ tilemap_set_flip(kaneko16_tmap_2, ((layers_flip_1 & 0x0100) ? TILEMAP_FLIPY : 0) |
+ ((layers_flip_1 & 0x0200) ? TILEMAP_FLIPX : 0) );
+ tilemap_set_flip(kaneko16_tmap_3, ((layers_flip_1 & 0x0100) ? TILEMAP_FLIPY : 0) |
+ ((layers_flip_1 & 0x0200) ? TILEMAP_FLIPX : 0) );
+
+ layer0_scrollx = kaneko16_layers_1_regs[ 2 ];
+ layer0_scrolly = kaneko16_layers_1_regs[ 3 ] >> 6;
+ layer1_scrollx = kaneko16_layers_1_regs[ 0 ];
+ layer1_scrolly = kaneko16_layers_1_regs[ 1 ] >> 6;
+
+ tilemap_set_scrolly(kaneko16_tmap_2,0,layer0_scrolly);
+ tilemap_set_scrolly(kaneko16_tmap_3,0,layer1_scrolly);
+
+ for (i=0; i<0x200; i++)
+ {
+ UINT16 scroll;
+ scroll = (layers_flip_1 & 0x0800) ? kaneko16_vscroll_2[i] : 0;
+ tilemap_set_scrollx(kaneko16_tmap_2,i,(layer0_scrollx + scroll) >> 6 );
+ scroll = (layers_flip_1 & 0x0008) ? kaneko16_vscroll_3[i] : 0;
+ tilemap_set_scrollx(kaneko16_tmap_3,i,(layer1_scrollx + scroll) >> 6 );
+ }
+ }
+}
+
+static void kaneko16_render_first_tilemap_chip(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri)
+{
+ tilemap_draw_primask(bitmap,cliprect, kaneko16_tmap_0, pri, pri, 0);
+ tilemap_draw_primask(bitmap,cliprect, kaneko16_tmap_1, pri, pri, 0);
+}
+
+static void kaneko16_render_second_tilemap_chip(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri)
+{
+ if (kaneko16_tmap_2)
+ {
+ tilemap_draw_primask(bitmap,cliprect, kaneko16_tmap_2, pri, kaneko16_priority.VIEW2_2_pri ? pri : 0, 0);
+ tilemap_draw_primask(bitmap,cliprect, kaneko16_tmap_3, pri, kaneko16_priority.VIEW2_2_pri ? pri : 0, 0);
+ }
+}
+
+static void kaneko16_render_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /* Sprites last (rendered with pdrawgfx, so they can slip
+ in between the layers) */
+
+ if(kaneko16_keep_sprites)
+ {
+ /* keep sprites on screen */
+ kaneko16_draw_sprites(machine,sprites_bitmap,cliprect);
+ copybitmap(bitmap,sprites_bitmap,0,0,0,0,cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ fillbitmap(sprites_bitmap,machine->pens[0],cliprect);
+ kaneko16_draw_sprites(machine,bitmap,cliprect);
+ }
+}
+
+static void kaneko16_render_15bpp_bitmap(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ if (kaneko16_bg15_bitmap)
+ {
+ int select = kaneko16_bg15_select[ 0 ];
+// int reg = kaneko16_bg15_reg[ 0 ];
+ int flip = select & 0x20;
+ int sx, sy;
+
+ if (flip) select ^= 0x1f;
+
+ sx = (select & 0x1f) * 256;
+ sy = 0;
+
+ copybitmap(
+ bitmap, kaneko16_bg15_bitmap,
+ flip, flip,
+ -sx, -sy,
+ cliprect, TRANSPARENCY_NONE,0 );
+
+// flag = 0;
+ }
+}
+
+static void kaneko16_fill_bitmap(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ if(kaneko16_sprite_type == 1)
+ fillbitmap(bitmap,machine->pens[0x7f00],cliprect);
+ else
+ /* Fill the bitmap with pen 0. This is wrong, but will work most of
+ the times. To do it right, each pixel should be drawn with pen 0
+ of the bottomost tile that covers it (which is pretty tricky to do) */
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+}
+
+static void kaneko16_video_update_common(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int i;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ kaneko16_prepare_first_tilemap_chip(machine, bitmap, cliprect);
+ kaneko16_prepare_second_tilemap_chip(machine, bitmap, cliprect);
+
+ for ( i = 0; i < 8; i++ )
+ {
+ kaneko16_render_first_tilemap_chip(machine,bitmap,cliprect,i);
+ kaneko16_render_second_tilemap_chip(machine,bitmap,cliprect,i);
+ }
+}
+
+VIDEO_UPDATE(berlwall)
+{
+ // berlwall uses a 15bpp bitmap as a bg, not a solid fill
+ kaneko16_render_15bpp_bitmap(machine,bitmap,cliprect);
+
+ // if the display is disabled, do nothing?
+ if (!kaneko16_disp_enable) return 0;
+
+ kaneko16_video_update_common(machine,bitmap,cliprect);
+ kaneko16_render_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+
+
+VIDEO_UPDATE( kaneko16 )
+{
+ kaneko16_fill_bitmap(machine,bitmap,cliprect);
+
+ // if the display is disabled, do nothing?
+ if (!kaneko16_disp_enable) return 0;
+
+ kaneko16_video_update_common(machine,bitmap,cliprect);
+ kaneko16_render_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( galsnew )
+{
+// kaneko16_fill_bitmap(machine,bitmap,cliprect);
+ int y,x;
+ int count;
+
+
+ count = 0;
+ for (y=0;y<256;y++)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+
+ for (x=0;x<256;x++)
+ {
+ UINT16 dat = (galsnew_fg_pixram[count] & 0xfffe)>>1;
+ dat+=2048;
+ dest[x] = machine->pens[dat];
+ count++;
+ }
+ }
+
+ count = 0;
+ for (y=0;y<256;y++)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+
+ for (x=0;x<256;x++)
+ {
+ UINT16 dat = (galsnew_bg_pixram[count]);
+ //dat &=0x3ff;
+ if (dat)
+ {
+ dest[x] = machine->pens[dat];
+ }
+ count++;
+ }
+ }
+
+
+ // if the display is disabled, do nothing?
+ if (!kaneko16_disp_enable) return 0;
+
+ kaneko16_video_update_common(machine,bitmap,cliprect);
+
+ kaneko16_render_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+
+VIDEO_UPDATE( sandscrp )
+{
+ kaneko16_fill_bitmap(machine,bitmap,cliprect);
+
+ // if the display is disabled, do nothing?
+ if (!kaneko16_disp_enable) return 0;
+
+ kaneko16_video_update_common(machine,bitmap,cliprect);
+
+ // copy sprite bitmap to screen
+ pandora_update(machine,bitmap,cliprect);
+ return 0;
+}
+
+
diff --git a/src/mame/video/kangaroo.c b/src/mame/video/kangaroo.c
new file mode 100644
index 00000000000..0edb4c61c2c
--- /dev/null
+++ b/src/mame/video/kangaroo.c
@@ -0,0 +1,308 @@
+/***************************************************************************
+
+ Sun Electronics Kangaroo hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "kangaroo.h"
+
+
+UINT8 *kangaroo_video_control;
+UINT8 *kangaroo_bank_select;
+UINT8 *kangaroo_blitter;
+UINT8 *kangaroo_scroll;
+
+static int screen_flipped;
+static mame_bitmap *tmpbitmap2;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Kangaroo doesn't have color PROMs, the playfield data is directly converted
+ into colors: 1 bit per gun, therefore only 8 possible colors, but there is
+ also a global mask register which controls intensities of the three guns,
+ separately for foreground and background. The fourth bit in the video RAM
+ data disables this mask, making the color display at full intensity
+ regardless of the mask value.
+ Actually the mask doesn't directly control intensity. The guns are rapidly
+ turned on and off at a subpixel rate, relying on the monitor to blend the
+ colors into a more or less uniform half intensity color.
+
+ We use three groups of 8 pens: the first is fixed and contains the 8
+ possible colors; the other two are dynamically modified when the mask
+ register is written to, one is for the background, the other for sprites.
+
+***************************************************************************/
+
+PALETTE_INIT( kangaroo )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ palette_set_color_rgb(machine,i,pal1bit(i >> 2),pal1bit(i >> 1),pal1bit(i >> 0));
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( kangaroo )
+{
+ tmpbitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ tmpbitmap2 = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ videoram = auto_malloc(machine->screen[0].width*machine->screen[0].height);
+}
+
+
+
+WRITE8_HANDLER( kangaroo_video_control_w )
+{
+ /* A & B bitmap control latch (A=playfield B=motion)
+ bit 5 FLIP A
+ bit 4 FLIP B
+ bit 3 EN A
+ bit 2 EN B
+ bit 1 PRI A
+ bit 0 PRI B */
+
+ if ((*kangaroo_video_control & 0x30) != (data & 0x30))
+ {
+ screen_flipped = 1;
+ }
+
+ *kangaroo_video_control = data;
+}
+
+
+WRITE8_HANDLER( kangaroo_bank_select_w )
+{
+ UINT8 *RAM = memory_region(REGION_GFX1);
+
+
+ /* this is a VERY crude way to handle the banked ROMs - but it's */
+ /* correct enough to pass the self test */
+ if (data & 0x05)
+ memory_set_bankptr(1,&RAM[0x0000]);
+ else
+ memory_set_bankptr(1,&RAM[0x2000]);
+
+ *kangaroo_bank_select = data;
+}
+
+
+
+WRITE8_HANDLER( kangaroo_color_mask_w )
+{
+ int i;
+
+
+ /* color mask for A plane */
+ for (i = 0;i < 8;i++)
+ {
+ int r,g,b;
+
+
+ r = ((i & 4) >> 2) * ((data & 0x20) ? 0xff : 0x7f);
+ g = ((i & 2) >> 1) * ((data & 0x10) ? 0xff : 0x7f);
+ b = ((i & 1) >> 0) * ((data & 0x08) ? 0xff : 0x7f);
+
+ palette_set_color(Machine,8+i,MAKE_RGB(r,g,b));
+ }
+
+ /* color mask for B plane */
+ for (i = 0;i < 8;i++)
+ {
+ int r,g,b;
+
+
+ r = ((i & 4) >> 2) * ((data & 0x04) ? 0xff : 0x7f);
+ g = ((i & 2) >> 1) * ((data & 0x02) ? 0xff : 0x7f);
+ b = ((i & 1) >> 0) * ((data & 0x01) ? 0xff : 0x7f);
+
+ palette_set_color(Machine,16+i,MAKE_RGB(r,g,b));
+ }
+}
+
+
+
+WRITE8_HANDLER( kangaroo_blitter_w )
+{
+ kangaroo_blitter[offset] = data;
+
+ if (offset == 5) /* trigger DMA */
+ {
+ int src,dest;
+ int x,y,xb,yb,old_bank_select,new_bank_select;
+
+ src = kangaroo_blitter[0] + 256 * kangaroo_blitter[1];
+ dest = kangaroo_blitter[2] + 256 * kangaroo_blitter[3];
+
+ xb = kangaroo_blitter[5];
+ yb = kangaroo_blitter[4];
+
+ old_bank_select = new_bank_select = *kangaroo_bank_select;
+
+ if (new_bank_select & 0x0c) new_bank_select |= 0x0c;
+ if (new_bank_select & 0x03) new_bank_select |= 0x03;
+ kangaroo_bank_select_w(0, new_bank_select & 0x05);
+
+ for (x = 0;x <= xb;x++)
+ {
+ for (y = 0;y <= yb;y++)
+ {
+ program_write_byte(dest++, program_read_byte(src++));
+ }
+
+ dest = dest - (yb + 1) + 256;
+ }
+
+ src = kangaroo_blitter[0] + 256 * kangaroo_blitter[1];
+ dest = kangaroo_blitter[2] + 256 * kangaroo_blitter[3];
+
+ kangaroo_bank_select_w(0, new_bank_select & 0x0a);
+
+ for (x = 0;x <= xb;x++)
+ {
+ for (y = 0;y <= yb;y++)
+ {
+ program_write_byte(dest++, program_read_byte(src++));
+ }
+
+ dest = dest - (yb + 1) + 256;
+ }
+
+ kangaroo_bank_select_w(0, old_bank_select);
+ }
+}
+
+
+
+INLINE void kangaroo_plot_pixel(mame_bitmap *bitmap, int x, int y, int col, int color_base, int flip)
+{
+ if (flip)
+ {
+ x = bitmap->width - 1 - x;
+ y = bitmap->height - 1 - y;
+ }
+
+ *BITMAP_ADDR16(bitmap, y, x) = Machine->pens[((col & 0x08) ? 0 : color_base) + (col & 0x07)];
+}
+
+INLINE void kangaroo_redraw_4pixels(int x, int y)
+{
+ int offs, flipA, flipB;
+
+
+ offs = y * 256 + x;
+
+ flipA = *kangaroo_video_control & 0x20;
+ flipB = *kangaroo_video_control & 0x10;
+
+ kangaroo_plot_pixel(tmpbitmap , x , y, videoram[offs ] & 0x0f, 8, flipA);
+ kangaroo_plot_pixel(tmpbitmap , x+1, y, videoram[offs+1] & 0x0f, 8, flipA);
+ kangaroo_plot_pixel(tmpbitmap , x+2, y, videoram[offs+2] & 0x0f, 8, flipA);
+ kangaroo_plot_pixel(tmpbitmap , x+3, y, videoram[offs+3] & 0x0f, 8, flipA);
+ kangaroo_plot_pixel(tmpbitmap2, x , y, videoram[offs ] >> 4, 16, flipB);
+ kangaroo_plot_pixel(tmpbitmap2, x+1, y, videoram[offs+1] >> 4, 16, flipB);
+ kangaroo_plot_pixel(tmpbitmap2, x+2, y, videoram[offs+2] >> 4, 16, flipB);
+ kangaroo_plot_pixel(tmpbitmap2, x+3, y, videoram[offs+3] >> 4, 16, flipB);
+}
+
+WRITE8_HANDLER( kangaroo_videoram_w )
+{
+ int a_Z_R,a_G_B,b_Z_R,b_G_B;
+ int sx, sy, offs;
+
+ a_Z_R = *kangaroo_bank_select & 0x01;
+ a_G_B = *kangaroo_bank_select & 0x02;
+ b_Z_R = *kangaroo_bank_select & 0x04;
+ b_G_B = *kangaroo_bank_select & 0x08;
+
+
+ sx = (offset / 256) * 4;
+ sy = offset % 256;
+ offs = sy * 256 + sx;
+
+ if (a_G_B)
+ {
+ videoram[offs ] = (videoram[offs ] & 0xfc) | ((data & 0x10) >> 3) | ((data & 0x01) >> 0);
+ videoram[offs+1] = (videoram[offs+1] & 0xfc) | ((data & 0x20) >> 4) | ((data & 0x02) >> 1);
+ videoram[offs+2] = (videoram[offs+2] & 0xfc) | ((data & 0x40) >> 5) | ((data & 0x04) >> 2);
+ videoram[offs+3] = (videoram[offs+3] & 0xfc) | ((data & 0x80) >> 6) | ((data & 0x08) >> 3);
+ }
+
+ if (a_Z_R)
+ {
+ videoram[offs ] = (videoram[offs ] & 0xf3) | ((data & 0x10) >> 1) | ((data & 0x01) << 2);
+ videoram[offs+1] = (videoram[offs+1] & 0xf3) | ((data & 0x20) >> 2) | ((data & 0x02) << 1);
+ videoram[offs+2] = (videoram[offs+2] & 0xf3) | ((data & 0x40) >> 3) | ((data & 0x04) >> 0);
+ videoram[offs+3] = (videoram[offs+3] & 0xf3) | ((data & 0x80) >> 4) | ((data & 0x08) >> 1);
+ }
+
+ if (b_G_B)
+ {
+ videoram[offs ] = (videoram[offs ] & 0xcf) | ((data & 0x10) << 1) | ((data & 0x01) << 4);
+ videoram[offs+1] = (videoram[offs+1] & 0xcf) | ((data & 0x20) >> 0) | ((data & 0x02) << 3);
+ videoram[offs+2] = (videoram[offs+2] & 0xcf) | ((data & 0x40) >> 1) | ((data & 0x04) << 2);
+ videoram[offs+3] = (videoram[offs+3] & 0xcf) | ((data & 0x80) >> 2) | ((data & 0x08) << 1);
+ }
+
+ if (b_Z_R)
+ {
+ videoram[offs ] = (videoram[offs ] & 0x3f) | ((data & 0x10) << 3) | ((data & 0x01) << 6);
+ videoram[offs+1] = (videoram[offs+1] & 0x3f) | ((data & 0x20) << 2) | ((data & 0x02) << 5);
+ videoram[offs+2] = (videoram[offs+2] & 0x3f) | ((data & 0x40) << 1) | ((data & 0x04) << 4);
+ videoram[offs+3] = (videoram[offs+3] & 0x3f) | ((data & 0x80) << 0) | ((data & 0x08) << 3);
+ }
+
+ kangaroo_redraw_4pixels(sx, sy);
+}
+
+
+
+VIDEO_UPDATE( kangaroo )
+{
+ int scrollx, scrolly;
+
+ if (screen_flipped)
+ {
+ int x, y;
+
+ /* redraw bitmap */
+ for (x = 0; x < 256; x+=4)
+ {
+ for (y = 0; y < 256; y++)
+ {
+ kangaroo_redraw_4pixels(x, y);
+ }
+ }
+
+ screen_flipped = 0;
+ }
+
+
+ scrollx = kangaroo_scroll[1];
+ scrolly = kangaroo_scroll[0];
+
+ if (*kangaroo_bank_select & 0x01)
+ {
+ /* Plane B is primary */
+ copybitmap(bitmap,tmpbitmap2,0,0,0,0,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ copyscrollbitmap(bitmap,tmpbitmap,1,&scrollx,1,&scrolly,&machine->screen[0].visarea,TRANSPARENCY_COLOR,8);
+ }
+ else
+ {
+ /* Plane A is primary */
+ copyscrollbitmap(bitmap,tmpbitmap,1,&scrollx,1,&scrolly,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ copybitmap(bitmap,tmpbitmap2,0,0,0,0,&machine->screen[0].visarea,TRANSPARENCY_COLOR,16);
+ }
+ return 0;
+}
diff --git a/src/mame/video/karnov.c b/src/mame/video/karnov.c
new file mode 100644
index 00000000000..74abf4f7760
--- /dev/null
+++ b/src/mame/video/karnov.c
@@ -0,0 +1,261 @@
+/*******************************************************************************
+
+ Karnov - Bryan McPhail, mish@tendril.co.uk
+
+*******************************************************************************/
+
+#include "driver.h"
+
+static UINT8 *dirty_f;
+static mame_bitmap *bitmap_f;
+UINT16 karnov_scroll[2], *karnov_pf_data;
+static tilemap *fix_tilemap;
+static int flipscreen;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Karnov has two 1024x8 palette PROM.
+ I don't know the exact values of the resistors between the RAM and the
+ RGB output. I assumed these values (the same as Commando)
+
+ bit 7 -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 2.2kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ -- 1 kohm resistor -- RED
+ bit 0 -- 2.2kohm resistor -- RED
+
+ bit 7 -- unused
+ -- unused
+ -- unused
+ -- unused
+ -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 1 kohm resistor -- BLUE
+ bit 0 -- 2.2kohm resistor -- BLUE
+
+***************************************************************************/
+PALETTE_INIT( karnov )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[0] >> 4) & 0x01;
+ bit1 = (color_prom[0] >> 5) & 0x01;
+ bit2 = (color_prom[0] >> 6) & 0x01;
+ bit3 = (color_prom[0] >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+void karnov_flipscreen_w(int data)
+{
+ static int last_flip;
+ flipscreen=data;
+ if (flipscreen!=last_flip)
+ memset(dirty_f,1,0x800);
+ last_flip=flipscreen;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+}
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int my,mx,offs,color,tile,fx,fy;
+ int scrollx=karnov_scroll[0];
+ int scrolly=karnov_scroll[1];
+
+ if (flipscreen) fx=fy=1; else fx=fy=0;
+
+ /* 1st area is stored along X-axis... */
+ mx=-1; my=0;
+ for (offs = 0;offs < 0x400; offs ++) {
+ mx++;
+ if (mx==32) {mx=0; my++;}
+
+ if (!dirty_f[offs]) continue; else dirty_f[offs]=0;
+
+ tile=karnov_pf_data[offs];
+ color = tile >> 12;
+ tile = tile&0x7ff;
+ if (flipscreen)
+ drawgfx(bitmap_f,machine->gfx[1],tile,
+ color, fx, fy, 496-16*mx,496-16*my,
+ 0,TRANSPARENCY_NONE,0);
+ else
+ drawgfx(bitmap_f,machine->gfx[1],tile,
+ color, fx, fy, 16*mx,16*my,
+ 0,TRANSPARENCY_NONE,0);
+ }
+
+ /* 2nd area is stored along Y-axis... */
+ mx=0; my=-1;
+ for (offs = 0x400 ;offs < 0x800; offs ++) {
+ my++;
+ if (my==32) {my=0; mx++;}
+
+ if (!dirty_f[offs]) continue; else dirty_f[offs]=0;
+
+ tile=karnov_pf_data[offs];
+ color = tile >> 12;
+ tile=tile&0x7ff;
+
+ if (flipscreen)
+ drawgfx(bitmap_f,machine->gfx[1],tile,
+ color, fx, fy, 496-16*mx,496-16*my,
+ 0,TRANSPARENCY_NONE,0);
+ else
+ drawgfx(bitmap_f,machine->gfx[1],tile,
+ color, fx, fy, 16*mx,16*my,
+ 0,TRANSPARENCY_NONE,0);
+ }
+
+ if (!flipscreen) {
+ scrolly=-scrolly;
+ scrollx=-scrollx;
+ } else {
+ scrolly=scrolly+256;
+ scrollx=scrollx+256;
+ }
+ copyscrollbitmap(bitmap,bitmap_f,1,&scrollx,1,&scrolly,cliprect,TRANSPARENCY_NONE,0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs <0x800;offs += 4) {
+ int x,y,sprite,sprite2,colour,fx,fy,extra;
+
+ y=buffered_spriteram16[offs];
+ if (!(y&0x8000)) continue;
+
+ y=y&0x1ff;
+ sprite=buffered_spriteram16[offs+3];
+ colour=sprite>>12;
+ sprite=sprite&0xfff;
+ x=buffered_spriteram16[offs+2]&0x1ff;
+
+ fx=buffered_spriteram16[offs+1];
+ if ((fx&0x10)) extra=1; else extra=0;
+ fy=fx&0x2;
+ fx=fx&0x4;
+
+ if (extra) y=y+16;
+
+ /* Convert the co-ords..*/
+ x=(x+16)%0x200;
+ y=(y+16)%0x200;
+ x=256 - x;
+ y=256 - y;
+ if (flipscreen) {
+ y=240-y;
+ x=240-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ if (extra) y=y-16;
+ }
+
+ /* Y Flip determines order of multi-sprite */
+ if (extra && fy) {
+ sprite2=sprite;
+ sprite++;
+ }
+ else sprite2=sprite+1;
+
+ drawgfx(bitmap,machine->gfx[2],
+ sprite,
+ colour,fx,fy,x,y,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ /* 1 more sprite drawn underneath */
+ if (extra)
+ drawgfx(bitmap,machine->gfx[2],
+ sprite2,
+ colour,fx,fy,x,y+16,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( karnov )
+{
+ draw_background(machine,bitmap,cliprect);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,fix_tilemap,0,0);
+ return 0;
+}
+
+/******************************************************************************/
+
+static TILE_GET_INFO( get_fix_tile_info )
+{
+ int tile=videoram16[tile_index];
+ SET_TILE_INFO(
+ 0,
+ tile&0xfff,
+ tile>>14,
+ 0);
+}
+
+WRITE16_HANDLER( karnov_videoram_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty(fix_tilemap,offset);
+}
+
+WRITE16_HANDLER( karnov_playfield_w )
+{
+ COMBINE_DATA(&karnov_pf_data[offset]);
+ dirty_f[offset] = 1;
+}
+
+/******************************************************************************/
+
+VIDEO_START( karnov )
+{
+ /* Allocate bitmaps */
+ bitmap_f = auto_bitmap_alloc(512,512,machine->screen[0].format);
+
+ dirty_f=auto_malloc(0x800);
+ memset(dirty_f,1,0x800);
+
+ fix_tilemap=tilemap_create(get_fix_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(fix_tilemap,0);
+}
+
+VIDEO_START( wndrplnt )
+{
+ /* Allocate bitmaps */
+ bitmap_f = auto_bitmap_alloc(512,512,machine->screen[0].format);
+
+ dirty_f=auto_malloc(0x800);
+ memset(dirty_f,1,0x800);
+
+ fix_tilemap=tilemap_create(get_fix_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(fix_tilemap,0);
+}
+
+/******************************************************************************/
diff --git a/src/mame/video/kchamp.c b/src/mame/video/kchamp.c
new file mode 100644
index 00000000000..6714580dde2
--- /dev/null
+++ b/src/mame/video/kchamp.c
@@ -0,0 +1,139 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+PALETTE_INIT( kchamp )
+{
+ int i, red, green, blue;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ red = color_prom[i];
+ green = color_prom[machine->drv->total_colors+i];
+ blue = color_prom[2*machine->drv->total_colors+i];
+
+ palette_set_color_rgb(machine,i,pal4bit(red),pal4bit(green),pal4bit(blue));
+
+ *(colortable++) = i;
+ }
+}
+
+WRITE8_HANDLER( kchamp_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( kchamp_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( kchamp_flipscreen_w )
+{
+ flip_screen_set(data & 0x01);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + ((colorram[tile_index] & 7) << 8);
+ int color = (colorram[tile_index] >> 3) & 0x1f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( kchamp )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+/*
+ Sprites
+ -------
+ Offset Encoding
+ 0 YYYYYYYY
+ 1 TTTTTTTT
+ 2 FGGTCCCC
+ 3 XXXXXXXX
+*/
+
+static void kchamp_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0; offs < 0x100; offs += 4)
+ {
+ int attr = spriteram[offs + 2];
+ int bank = 1 + ((attr & 0x60) >> 5);
+ int code = spriteram[offs + 1] + ((attr & 0x10) << 4);
+ int color = attr & 0x0f;
+ int flipx = 0;
+ int flipy = attr & 0x80;
+ int sx = spriteram[offs + 3] - 8;
+ int sy = 247 - spriteram[offs];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[bank], code, color, flipx, flipy, sx, sy,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+static void kchampvs_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0; offs < 0x100; offs += 4)
+ {
+ int attr = spriteram[offs + 2];
+ int bank = 1 + ((attr & 0x60) >> 5);
+ int code = spriteram[offs + 1] + ((attr & 0x10) << 4);
+ int color = attr & 0x0f;
+ int flipx = 0;
+ int flipy = attr & 0x80;
+ int sx = spriteram[offs + 3];
+ int sy = 240 - spriteram[offs];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[bank], code, color, flipx, flipy, sx, sy,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+
+VIDEO_UPDATE( kchamp )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ kchamp_draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( kchampvs )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ kchampvs_draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/kickgoal.c b/src/mame/video/kickgoal.c
new file mode 100644
index 00000000000..e3ed91cc423
--- /dev/null
+++ b/src/mame/video/kickgoal.c
@@ -0,0 +1,257 @@
+/* Kick Goal - video */
+
+#include "driver.h"
+
+extern UINT16 *kickgoal_fgram, *kickgoal_bgram, *kickgoal_bg2ram, *kickgoal_scrram;
+static tilemap *kickgoal_fgtm, *kickgoal_bgtm, *kickgoal_bg2tm;
+
+/* FG */
+static TILE_GET_INFO( get_kickgoal_fg_tile_info )
+{
+ int tileno = kickgoal_fgram[tile_index*2] & 0x0fff;
+ int color = kickgoal_fgram[tile_index*2+1] & 0x000f;
+
+ SET_TILE_INFO(0,tileno + 0x7000,color + 0x00,0);
+}
+
+/* BG */
+static TILE_GET_INFO( get_kickgoal_bg_tile_info )
+{
+ int tileno = kickgoal_bgram[tile_index*2] & 0x0fff;
+ int color = kickgoal_bgram[tile_index*2+1] & 0x000f;
+
+ SET_TILE_INFO(1,tileno + 0x1000,color + 0x10,0);
+}
+
+/* BG 2 */
+static TILE_GET_INFO( get_kickgoal_bg2_tile_info )
+{
+ int tileno = kickgoal_bg2ram[tile_index*2] & 0x07ff;
+ int color = kickgoal_bg2ram[tile_index*2+1] & 0x000f;
+ int flipx = kickgoal_bg2ram[tile_index*2+1] & 0x0020;
+
+ SET_TILE_INFO(2,tileno + 0x800,color + 0x20,flipx ? TILE_FLIPX : 0);
+}
+
+
+static TILEMAP_MAPPER( tilemap_scan_kicksbg )
+{
+ /* logical (col,row) -> memory offset */
+ return col*8 + (row & 0x7) + ((row & 0x3c) >> 3) * 0x200;
+}
+
+static TILEMAP_MAPPER( tilemap_scan_kicksbg2 )
+{
+ /* logical (col,row) -> memory offset */
+ return col*16 + (row & 0xf) + ((row & 0x70) >> 4) * 0x400;
+}
+
+static TILEMAP_MAPPER( tilemap_scan_kicksfg )
+{
+ /* logical (col,row) -> memory offset */
+ return col*32 + (row & 0x1f) + ((row & 0x20) >> 5) * 0x800;
+}
+
+
+VIDEO_START( kickgoal )
+{
+ kickgoal_fgtm = tilemap_create(get_kickgoal_fg_tile_info,tilemap_scan_kicksfg,TILEMAP_TYPE_PEN, 8, 16,64,64);
+ tilemap_set_transparent_pen(kickgoal_fgtm,15);
+ kickgoal_bgtm = tilemap_create(get_kickgoal_bg_tile_info,tilemap_scan_kicksbg,TILEMAP_TYPE_PEN, 16, 32,64,64);
+ tilemap_set_transparent_pen(kickgoal_bgtm,15);
+ kickgoal_bg2tm = tilemap_create(get_kickgoal_bg2_tile_info,tilemap_scan_kicksbg2,TILEMAP_TYPE_PEN, 32, 64,64,64);
+}
+
+
+
+WRITE16_HANDLER( kickgoal_fgram_w )
+{
+ kickgoal_fgram[offset] = data;
+ tilemap_mark_tile_dirty(kickgoal_fgtm,offset/2);
+}
+
+WRITE16_HANDLER( kickgoal_bgram_w )
+{
+ kickgoal_bgram[offset] = data;
+ tilemap_mark_tile_dirty(kickgoal_bgtm,offset/2);
+}
+
+WRITE16_HANDLER( kickgoal_bg2ram_w )
+{
+ kickgoal_bg2ram[offset] = data;
+ tilemap_mark_tile_dirty(kickgoal_bg2tm,offset/2);
+}
+
+
+
+static void kickgoal_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ const gfx_element *gfx = machine->gfx[1];
+ int offs;
+
+ for (offs = 0;offs < spriteram_size/2;offs += 4)
+ {
+ int xpos = spriteram16[offs+3];
+ int ypos = spriteram16[offs+0] & 0x00ff;
+ int tileno = spriteram16[offs+2] & 0x0fff;
+ int flipx = spriteram16[offs+1] & 0x0020;
+ int color = spriteram16[offs+1] & 0x000f;
+
+ if (spriteram16[offs+0] & 0x0100) break;
+
+ ypos *= 2;
+
+ ypos = 0x200-ypos;
+
+ drawgfx(bitmap,gfx,
+ tileno,
+ 0x30 + color,
+ flipx,0,
+ xpos-16+4,ypos-32,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+
+VIDEO_UPDATE( kickgoal )
+{
+ /* set scroll */
+ tilemap_set_scrollx( kickgoal_fgtm, 0, kickgoal_scrram[0] );
+ tilemap_set_scrolly( kickgoal_fgtm, 0, kickgoal_scrram[1]*2 );
+ tilemap_set_scrollx( kickgoal_bgtm, 0, kickgoal_scrram[2] );
+ tilemap_set_scrolly( kickgoal_bgtm, 0, kickgoal_scrram[3]*2 );
+ tilemap_set_scrollx( kickgoal_bg2tm, 0, kickgoal_scrram[4] );
+ tilemap_set_scrolly( kickgoal_bg2tm, 0, kickgoal_scrram[5]*2 );
+
+ /* draw */
+ tilemap_draw(bitmap,cliprect,kickgoal_bg2tm,0,0);
+ tilemap_draw(bitmap,cliprect,kickgoal_bgtm,0,0);
+
+ kickgoal_draw_sprites(machine,bitmap,cliprect);
+
+ tilemap_draw(bitmap,cliprect,kickgoal_fgtm,0,0);
+
+ /*
+ popmessage ("Regs %04x %04x %04x %04x %04x %04x %04x %04x",
+ kickgoal_scrram[0],
+ kickgoal_scrram[1],
+ kickgoal_scrram[2],
+ kickgoal_scrram[3],
+ kickgoal_scrram[4],
+ kickgoal_scrram[5],
+ kickgoal_scrram[6],
+ kickgoal_scrram[7]);
+ */
+ return 0;
+}
+
+/* Holywood Action */
+
+/* FG */
+static TILE_GET_INFO( get_actionhw_fg_tile_info )
+{
+ int tileno = kickgoal_fgram[tile_index*2] & 0x0fff;
+ int color = kickgoal_fgram[tile_index*2+1] & 0x000f;
+
+ SET_TILE_INFO(0,tileno + 0x7000*2,color + 0x00,0);
+}
+
+/* BG */
+static TILE_GET_INFO( get_actionhw_bg_tile_info )
+{
+ int tileno = kickgoal_bgram[tile_index*2] & 0x1fff;
+ int color = kickgoal_bgram[tile_index*2+1] & 0x000f;
+ int flipx = kickgoal_bgram[tile_index*2+1] & 0x0020;
+ int flipy = kickgoal_bgram[tile_index*2+1] & 0x0040;
+
+ SET_TILE_INFO(1,tileno + 0x0000,color + 0x10,(flipx ? TILE_FLIPX : 0) | (flipy ? TILE_FLIPY : 0));
+}
+
+/* BG 2 */
+static TILE_GET_INFO( get_actionhw_bg2_tile_info )
+{
+ int tileno = kickgoal_bg2ram[tile_index*2] & 0x1fff;
+ int color = kickgoal_bg2ram[tile_index*2+1] & 0x000f;
+ int flipx = kickgoal_bg2ram[tile_index*2+1] & 0x0020;
+ int flipy = kickgoal_bg2ram[tile_index*2+1] & 0x0040;
+
+ SET_TILE_INFO(1,tileno + 0x2000,color + 0x20,(flipx ? TILE_FLIPX : 0) | (flipy ? TILE_FLIPY : 0));
+}
+
+
+static TILEMAP_MAPPER( tilemap_scan_actionhwbg2 )
+{
+ /* logical (col,row) -> memory offset */
+ return col*16 + (row & 0xf) + ((row & 0x70) >> 4) * 0x400;
+}
+
+static TILEMAP_MAPPER( tilemap_scan_actionhwbg )
+{
+ /* logical (col,row) -> memory offset */
+ return col*16 + (row & 0xf) + ((row & 0x70) >> 4) * 0x400;
+}
+
+static TILEMAP_MAPPER( tilemap_scan_actionhwfg )
+{
+ /* logical (col,row) -> memory offset */
+ return col*32 + (row & 0x1f) + ((row & 0x20) >> 5) * 0x800;
+}
+
+
+VIDEO_START( actionhw )
+{
+ kickgoal_fgtm = tilemap_create(get_actionhw_fg_tile_info,tilemap_scan_actionhwfg,TILEMAP_TYPE_PEN, 8, 8,64,64);
+ kickgoal_bgtm = tilemap_create(get_actionhw_bg_tile_info,tilemap_scan_actionhwbg,TILEMAP_TYPE_PEN, 16,16,64,64);
+ kickgoal_bg2tm = tilemap_create(get_actionhw_bg2_tile_info,tilemap_scan_actionhwbg2,TILEMAP_TYPE_PEN, 16,16,64,64);
+
+ tilemap_set_transparent_pen(kickgoal_fgtm,15);
+ tilemap_set_transparent_pen(kickgoal_bgtm,15);
+}
+
+
+static void actionhw_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ const gfx_element *gfx = machine->gfx[1];
+ int offs;
+
+ for (offs = 0;offs < spriteram_size/2;offs += 4)
+ {
+ int xpos = spriteram16[offs+3];
+ int ypos = spriteram16[offs+0] & 0x00ff;
+ int tileno = spriteram16[offs+2] & 0x3fff;
+ int flipx = spriteram16[offs+1] & 0x0020;
+ int color = spriteram16[offs+1] & 0x000f;
+
+ if (spriteram16[offs+0] & 0x0100) break;
+
+ ypos = 0x110-ypos;
+
+ drawgfx(bitmap,gfx,
+ tileno+0x4000,
+ 0x30 + color,
+ flipx,0,
+ xpos-16+4,ypos-32,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+
+VIDEO_UPDATE( actionhw )
+{
+ /* set scroll */
+ tilemap_set_scrollx( kickgoal_fgtm, 0, kickgoal_scrram[0] );
+ tilemap_set_scrolly( kickgoal_fgtm, 0, kickgoal_scrram[1] );
+ tilemap_set_scrollx( kickgoal_bgtm, 0, kickgoal_scrram[2] );
+ tilemap_set_scrolly( kickgoal_bgtm, 0, kickgoal_scrram[3] );
+ tilemap_set_scrollx( kickgoal_bg2tm, 0, kickgoal_scrram[4] );
+ tilemap_set_scrolly( kickgoal_bg2tm, 0, kickgoal_scrram[5] );
+
+ /* draw */
+ tilemap_draw(bitmap,cliprect,kickgoal_bg2tm,0,0);
+ tilemap_draw(bitmap,cliprect,kickgoal_bgtm,0,0);
+
+ actionhw_draw_sprites(machine,bitmap,cliprect);
+
+ tilemap_draw(bitmap,cliprect,kickgoal_fgtm,0,0);
+ return 0;
+}
diff --git a/src/mame/video/kingobox.c b/src/mame/video/kingobox.c
new file mode 100644
index 00000000000..c466d093902
--- /dev/null
+++ b/src/mame/video/kingobox.c
@@ -0,0 +1,297 @@
+#include "driver.h"
+
+UINT8 *kingofb_videoram2;
+UINT8 *kingofb_colorram2;
+UINT8 *kingofb_scroll_y;
+
+extern int kingofb_nmi_enable;
+
+static int palette_bank;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ King of Boxer has three 256x4 palette PROMs, connected to the RGB output
+ this way:
+
+ bit 3 -- 180 ohm resistor -- RED/GREEN/BLUE
+ -- 360 ohm resistor -- RED/GREEN/BLUE
+ -- 750 ohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 1.5kohm resistor -- RED/GREEN/BLUE
+
+ The foreground color code directly goes to the RGB output, this way:
+
+ bit 5 -- 51 ohm resistor -- RED
+ bit 4 -- 51 ohm resistor -- GREEN
+ bit 3 -- 51 ohm resistor -- BLUE
+
+***************************************************************************/
+PALETTE_INIT( kingofb )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ /* red component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x10 * bit0 + 0x21 * bit1 + 0x45 * bit2 + 0x89 * bit3;
+ /* green component */
+ bit0 = (color_prom[256] >> 0) & 0x01;
+ bit1 = (color_prom[256] >> 1) & 0x01;
+ bit2 = (color_prom[256] >> 2) & 0x01;
+ bit3 = (color_prom[256] >> 3) & 0x01;
+ g = 0x10 * bit0 + 0x21 * bit1 + 0x45 * bit2 + 0x89 * bit3;
+ /* blue component */
+ bit0 = (color_prom[2*256] >> 0) & 0x01;
+ bit1 = (color_prom[2*256] >> 1) & 0x01;
+ bit2 = (color_prom[2*256] >> 2) & 0x01;
+ bit3 = (color_prom[2*256] >> 3) & 0x01;
+ b = 0x10 * bit0 + 0x21 * bit1 + 0x45 * bit2 + 0x89 * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+
+ /* the foreground chars directly map to primary colors */
+ for (i = 0;i < 8;i++)
+ palette_set_color_rgb(machine,i+256,pal1bit(i >> 2),pal1bit(i >> 1),pal1bit(i >> 0));
+
+ for (i = 0;i < TOTAL_COLORS(0)/2;i++)
+ {
+ COLOR(0,2*i+0) = 0; /* transparent */
+ COLOR(0,2*i+1) = 256 + i;
+ }
+}
+
+
+/* Ring King has one 256x8 PROM instead of two 256x4 */
+PALETTE_INIT( ringking )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ /* red component */
+ bit0 = (color_prom[0] >> 4) & 0x01;
+ bit1 = (color_prom[0] >> 5) & 0x01;
+ bit2 = (color_prom[0] >> 6) & 0x01;
+ bit3 = (color_prom[0] >> 7) & 0x01;
+ r = 0x10 * bit0 + 0x21 * bit1 + 0x45 * bit2 + 0x89 * bit3;
+ /* green component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ g = 0x10 * bit0 + 0x21 * bit1 + 0x45 * bit2 + 0x89 * bit3;
+ /* blue component */
+ bit0 = (color_prom[256] >> 0) & 0x01;
+ bit1 = (color_prom[256] >> 1) & 0x01;
+ bit2 = (color_prom[256] >> 2) & 0x01;
+ bit3 = (color_prom[256] >> 3) & 0x01;
+ b = 0x10 * bit0 + 0x21 * bit1 + 0x45 * bit2 + 0x89 * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+
+ /* the foreground chars directly map to primary colors */
+ for (i = 0;i < 8;i++)
+ palette_set_color_rgb(machine,i+256,pal1bit(i >> 2),pal1bit(i >> 1),pal1bit(i >> 0));
+
+ for (i = 0;i < TOTAL_COLORS(0)/2;i++)
+ {
+ COLOR(0,2*i+0) = 0; /* transparent */
+ COLOR(0,2*i+1) = 256 + i;
+ }
+}
+
+WRITE8_HANDLER( kingofb_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( kingofb_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( kingofb_videoram2_w )
+{
+ kingofb_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( kingofb_colorram2_w )
+{
+ kingofb_colorram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( kingofb_f800_w )
+{
+ kingofb_nmi_enable = data & 0x20;
+
+ if (palette_bank != ((data & 0x18) >> 3))
+ {
+ palette_bank = (data & 0x18) >> 3;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ if (flip_screen != (data & 0x80))
+ {
+ flip_screen_set(data & 0x80);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int bank = ((attr & 0x04) >> 2) + 2;
+ int code = (tile_index / 16) ? videoram[tile_index] + ((attr & 0x03) << 8) : 0;
+ int color = ((attr & 0x70) >> 4) + 8 * palette_bank;
+
+ SET_TILE_INFO(bank, code, color, 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = kingofb_colorram2[tile_index];
+ int bank = (attr & 0x02) >> 1;
+ int code = kingofb_videoram2[tile_index] + ((attr & 0x01) << 8);
+ int color = (attr & 0x38) >> 3;
+
+ SET_TILE_INFO(bank, code, color, 0);
+}
+
+VIDEO_START( kingofb )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols_flip_y,
+ TILEMAP_TYPE_PEN, 16, 16, 16, 16);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols_flip_y,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+static void kingofb_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 4; offs >= 0; offs -= 4)
+ {
+ int bank = (spriteram[offs + 3] & 0x04) >> 2;
+ int code = spriteram[offs + 2] + ((spriteram[offs + 3] & 0x03) << 8);
+ int color = ((spriteram[offs + 3] & 0x70) >> 4) + 8 * palette_bank;
+ int flipx = 0;
+ int flipy = spriteram[offs + 3] & 0x80;
+ int sx = spriteram[offs+1];
+ int sy = spriteram[offs];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[2 + bank],
+ code, color,
+ flipx, flipy,
+ sx, sy,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( kingofb )
+{
+ tilemap_set_scrolly(bg_tilemap, 0, -(*kingofb_scroll_y));
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ kingofb_draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
+
+/* Ring King */
+
+static TILE_GET_INFO( ringking_get_bg_tile_info )
+{
+ int code = (tile_index / 16) ? videoram[tile_index] : 0;
+ int color = ((colorram[tile_index] & 0x70) >> 4) + 8 * palette_bank;
+
+ SET_TILE_INFO(4, code, color, 0);
+}
+
+VIDEO_START( ringking )
+{
+ bg_tilemap = tilemap_create(ringking_get_bg_tile_info, tilemap_scan_cols_flip_y,
+ TILEMAP_TYPE_PEN, 16, 16, 16, 16);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols_flip_y,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+static void ringking_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0; offs < spriteram_size; offs += 4)
+ {
+ int bank = (spriteram[offs + 1] & 0x04) >> 2;
+ int code = spriteram[offs + 3] + ((spriteram[offs + 1] & 0x03) << 8);
+ int color = ((spriteram[offs + 1] & 0x70) >> 4) + 8 * palette_bank;
+ int flipx = 0;
+ int flipy = ( spriteram[offs + 1] & 0x80 ) ? 0 : 1;
+ int sx = spriteram[offs+2];
+ int sy = spriteram[offs];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[2 + bank],
+ code, color,
+ flipx, flipy,
+ sx, sy,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( ringking )
+{
+ tilemap_set_scrolly(bg_tilemap, 0, -(*kingofb_scroll_y));
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ ringking_draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/klax.c b/src/mame/video/klax.c
new file mode 100644
index 00000000000..a4d0b595014
--- /dev/null
+++ b/src/mame/video/klax.c
@@ -0,0 +1,133 @@
+/***************************************************************************
+
+ Atari Klax hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "klax.h"
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data1 = atarigen_playfield[tile_index];
+ UINT16 data2 = atarigen_playfield_upper[tile_index] >> 8;
+ int code = data1 & 0x1fff;
+ int color = data2 & 0x0f;
+ SET_TILE_INFO(0, code, color, (data1 >> 15) & 1);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( klax )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 1, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 8, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x000, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0x00ff,0,0,0 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0,0x0fff,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0x000f,0 }}, /* mask for the color */
+ {{ 0,0,0xff80,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xff80 }}, /* mask for the Y position */
+ {{ 0,0,0,0x0070 }}, /* mask for the width, in tiles*/
+ {{ 0,0,0,0x0007 }}, /* mask for the height, in tiles */
+ {{ 0,0,0,0x0008 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0 /* callback routine for special entries */
+ };
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8,8, 64,32);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+}
+
+
+
+/*************************************
+ *
+ * Latch write handler
+ *
+ *************************************/
+
+WRITE16_HANDLER( klax_latch_w )
+{
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( klax )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* verified from schematics:
+
+ PFPRI if (PFS7-4 == 0 || LBPIX3-0 == 0)
+ */
+ if ((pf[x] & 0xf0) != 0xf0)
+ pf[x] = mo[x];
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/kncljoe.c b/src/mame/video/kncljoe.c
new file mode 100644
index 00000000000..e9a583c0a85
--- /dev/null
+++ b/src/mame/video/kncljoe.c
@@ -0,0 +1,260 @@
+/***************************************************************************
+
+Knuckle Joe - (c) 1985 Taito Corporation
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+static int tile_bank,sprite_bank;
+static int flipscreen;
+
+UINT8 *kncljoe_scrollregs;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+***************************************************************************/
+
+PALETTE_INIT( kncljoe )
+{
+ int i;
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < 128;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[0x100] >> 0) & 0x01;
+ bit1 = (color_prom[0x100] >> 1) & 0x01;
+ bit2 = (color_prom[0x100] >> 2) & 0x01;
+ bit3 = (color_prom[0x100] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[0x200] >> 0) & 0x01;
+ bit1 = (color_prom[0x200] >> 1) & 0x01;
+ bit2 = (color_prom[0x200] >> 2) & 0x01;
+ bit3 = (color_prom[0x200] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 2*256 + 128; /* bottom half is not used */
+
+ for (i = 0;i < 16;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i+128,MAKE_RGB(r,g,b));
+ color_prom ++;
+ }
+
+ color_prom += 16; /* bottom half is not used */
+
+ /* sprite lookup table */
+ for (i = 0;i < 128;i++)
+ {
+ COLOR(1,i) = 128 + (*(color_prom++) & 0x0f);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = videoram[2*tile_index+1];
+ int code = videoram[2*tile_index] + ((attr & 0xc0) << 2) + (tile_bank << 10);
+
+ SET_TILE_INFO(
+ 0,
+ code,
+ attr & 0xf,
+ TILE_FLIPXY((attr & 0x30) >> 4));
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( kncljoe )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_scroll_rows(bg_tilemap,4);
+
+ tile_bank = sprite_bank = flipscreen = 0;
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( kncljoe_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+WRITE8_HANDLER( kncljoe_control_w )
+{
+ int i;
+
+ switch(offset)
+ {
+ /*
+ 0x01 screen flip
+ 0x02 coin counter#1
+ 0x04 sprite bank
+ 0x10 character bank
+ 0x20 coin counter#2
+
+ reset when IN0 - Coin 1 goes low (active)
+ set after IN0 - Coin 1 goes high AND the credit has been added
+ */
+ case 0:
+ flipscreen = data & 0x01;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? TILEMAP_FLIPX : TILEMAP_FLIPY);
+
+ coin_counter_w(0,data & 0x02);
+ coin_counter_w(1,data & 0x20);
+
+ i = (data & 0x10) >> 4;
+ if (tile_bank != i)
+ {
+ tile_bank = i;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ i = (data & 0x04) >> 2;
+ if (sprite_bank != i)
+ {
+ sprite_bank = i;
+ memset(memory_region(REGION_CPU1)+0xf100, 0, 0x180);
+ }
+ break;
+ case 1:
+ // ???
+ break;
+ case 2:
+ // ???
+ break;
+ }
+}
+
+WRITE8_HANDLER( kncljoe_scroll_w )
+{
+ int scrollx;
+
+ kncljoe_scrollregs[offset] = data;
+ scrollx = kncljoe_scrollregs[0] | kncljoe_scrollregs[1]<<8;
+ tilemap_set_scrollx(bg_tilemap,0,scrollx);
+ tilemap_set_scrollx(bg_tilemap,1,scrollx);
+ tilemap_set_scrollx(bg_tilemap,2,scrollx);
+ tilemap_set_scrollx(bg_tilemap,3,0);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ rectangle clip = *cliprect;
+ const gfx_element *gfx = machine->gfx[1 + sprite_bank];
+ int i, j;
+ static const int pribase[4]={0x0180, 0x0080, 0x0100, 0x0000};
+
+ /* score covers sprites */
+ if (flipscreen)
+ {
+ if (clip.max_y > machine->screen[0].visarea.max_y - 64)
+ clip.max_y = machine->screen[0].visarea.max_y - 64;
+ }
+ else
+ {
+ if (clip.min_y < machine->screen[0].visarea.min_y + 64)
+ clip.min_y = machine->screen[0].visarea.min_y + 64;
+ }
+
+ for (i=0; i<4; i++)
+ for (j=0x7c; j>=0; j-=4)
+ {
+ int offs = pribase[i] + j;
+ int sy = spriteram[offs];
+ int sx = spriteram[offs+3];
+ int code = spriteram[offs+2];
+ int attr = spriteram[offs+1];
+ int flipx = attr & 0x40;
+ int flipy = !(attr & 0x80);
+ int color = attr & 0x0f;
+
+ if (attr & 0x10) code += 512;
+ if (attr & 0x20) code += 256;
+
+ if (flipscreen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+ sx = 240 - sx;
+ sy = 240 - sy;
+ }
+
+ if (sx >= 256-8) sx -= 256;
+
+ drawgfx(bitmap,gfx,
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ &clip,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( kncljoe )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/konamigx.c b/src/mame/video/konamigx.c
new file mode 100644
index 00000000000..45f1fd140be
--- /dev/null
+++ b/src/mame/video/konamigx.c
@@ -0,0 +1,498 @@
+#define VERBOSE 0
+
+/*
+ * video/konamigx.c - Konami GX video hardware (here there be dragons)
+ *
+ */
+
+#include "driver.h"
+#include "video/konamiic.h"
+#include "machine/konamigx.h"
+
+static int layer_colorbase[4];
+static INT32 gx_tilebanks[8], gx_oldbanks[8];
+static int gx_tilemode, gx_rozenable, psac_colorbase, last_psac_colorbase;
+static tilemap *gx_psac_tilemap, *gx_psac_tilemap2;
+extern UINT32 *gx_psacram, *gx_subpaletteram32;
+
+static void (*game_tile_callback)(int layer, int *code, int *color, int *flags);
+
+/* Run and Gun 2 / Rushing Heroes */
+static TILE_GET_INFO( get_gx_psac_tile_info )
+{
+ int tileno, colour, flipx;
+ UINT16 *map16 = (UINT16 *)gx_psacram;
+
+ tileno = map16[tile_index*2+1] & 0x3fff;
+ colour = (psac_colorbase << 4);
+ flipx = 0;
+
+ SET_TILE_INFO(0, tileno, colour, TILE_FLIPYX(flipx));
+}
+
+/* Soccer Superstars (tile and flip bits now TRUSTED) */
+static TILE_GET_INFO( get_gx_psac3_tile_info )
+{
+ int tileno, colour, flip;
+ UINT8 *tmap = memory_region(REGION_GFX4);
+
+ tileno = tmap[tile_index*2] | ((tmap[(tile_index*2)+1] & 0x0f)<<8);
+ colour = (psac_colorbase << 8);
+
+ flip = 0;
+ if (tmap[(tile_index*2)+1] & 0x20) flip |= TILE_FLIPX;
+ if (tmap[(tile_index*2)+1] & 0x10) flip |= TILE_FLIPY;
+
+ SET_TILE_INFO(0, tileno, colour, flip);
+}
+
+/* PSAC4 */
+/* these tilemaps are weird in both format and content, one of them
+ doesn't really look like it should be displayed? */
+static TILE_GET_INFO( get_gx_psac1a_tile_info )
+{
+ int tileno, colour, flipx,flipy;
+ int flip;
+ flip=0;
+ colour = 0;
+
+ tileno = (gx_psacram[tile_index*2] & 0x00003fff)>>0;
+ flipx = (gx_psacram[tile_index*2+1] & 0x00800000)>>23;
+ flipy = (gx_psacram[tile_index*2+1] & 0x00400000)>>22;
+
+ if (flipx) flip |= TILE_FLIPX;
+ if (flipy) flip |= TILE_FLIPY;
+
+ SET_TILE_INFO(1, tileno, colour, flip);
+}
+
+static TILE_GET_INFO( get_gx_psac1b_tile_info )
+{
+ int tileno, colour, flipx,flipy;
+ int flip;
+ flip=0;
+
+ colour = 0;
+ tileno = (gx_psacram[tile_index*2+1] & 0x00003fff)>>0;
+ flipx = (gx_psacram[tile_index*2+1] & 0x00200000)>>21;
+ flipy = (gx_psacram[tile_index*2+1] & 0x00100000)>>20;
+
+ if (flipx) flip |= TILE_FLIPX;
+ if (flipy) flip |= TILE_FLIPY;
+
+ SET_TILE_INFO(0, tileno, colour, flip);
+}
+
+static void konamigx_type2_tile_callback(int layer, int *code, int *color, int *flags)
+{
+ int d = *code;
+
+ *code = (gx_tilebanks[(d & 0xe000)>>13]<<13) + (d & 0x1fff);
+ K055555GX_decode_vmixcolor(layer, color);
+}
+
+static void konamigx_alpha_tile_callback(int layer, int *code, int *color, int *flags)
+{
+ int mixcode;
+ int d = *code;
+
+ mixcode = K055555GX_decode_vmixcolor(layer, color);
+
+ if (mixcode < 0)
+ *code = (gx_tilebanks[(d & 0xe000)>>13]<<13) + (d & 0x1fff);
+ else
+ {
+ /* save mixcode and mark tile alpha (unimplemented) */
+ *code = 0;
+
+ #if VERBOSE
+ popmessage("skipped alpha tile(layer=%d mix=%d)", layer, mixcode);
+ #endif
+ }
+}
+
+/*
+> bits 8-13 are the low priority bits
+> i.e. pri 0-5
+> pri 6-7 can be either 1, bits 14,15 or bits 16,17
+> contro.bit 2 being 0 forces the 1
+> when control.bit 2 is 1, control.bit 3 selects between the two
+> 0 selects 16,17
+> that gives you the entire 8 bits of the sprite priority
+> ok, lemme see if I've got this. bit2 = 0 means the top bits are 11, bit2=1 means the top bits are bits 14/15 (of the whatever word?) else
++16+17?
+> bit3=1 for the second
+
+ * 6 | ---------xxxxxxx | "color", but depends on external connections
+
+
+> there are 8 color lines entering the 5x5
+> that means the palette is 4 bits, not 5 as you currently have
+> the bits 4-9 are the low priority bits
+> bits 10/11 or 12/13 are the two high priority bits, depending on the control word
+> and bits 14/15 are the shadow bits
+> mix0/1 and brit0/1 come from elsewhere
+> they come from the '673 all right, but not from word 6
+> and in fact the top address bits are highly suspect
+> only 18 of the address bits go to the roms
+> the next 2 go to cai0/1 and the next 4 to bk0-3
+> (the '246 indexes the roms, the '673 reads the result)
+> the roms are 64 bits wide
+> so, well, the top bits of the code are suspicious
+*/
+
+static void _gxcommoninitnosprites(void)
+{
+ int i;
+
+ K054338_vh_start();
+ K055555_vh_start();
+
+ konamigx_mixer_init(0);
+
+ for (i = 0; i < 8; i++)
+ {
+ gx_tilebanks[i] = gx_oldbanks[i] = 0;
+ }
+
+ state_save_register_global_array(gx_tilebanks);
+
+ gx_tilemode = 0;
+
+ // Documented relative offsets of non-flipped games are (-2, 0, 2, 3),(0, 0, 0, 0).
+ // (+ve values move layers to the right and -ve values move layers to the left)
+ // In most cases only a constant is needed to add to the X offsets to yield correct
+ // displacement. This should be done by the CCU but the CRT timings have not been
+ // figured out.
+ K056832_set_LayerOffset(0, -2, 0);
+ K056832_set_LayerOffset(1, 0, 0);
+ K056832_set_LayerOffset(2, 2, 0);
+ K056832_set_LayerOffset(3, 3, 0);
+}
+
+static void _gxcommoninit(running_machine *machine)
+{
+ // (+ve values move objects to the right and -ve values move objects to the left)
+ K055673_vh_start(machine, REGION_GFX2, K055673_LAYOUT_GX, -26, -23, konamigx_type2_sprite_callback);
+
+ gx_rozenable = 0;
+
+ _gxcommoninitnosprites();
+}
+
+
+VIDEO_START(konamigx_5bpp)
+{
+ if (!strcmp(machine->gamedrv->name,"sexyparo"))
+ game_tile_callback = konamigx_alpha_tile_callback;
+ else
+ game_tile_callback = konamigx_type2_tile_callback;
+
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_5, 0, NULL, game_tile_callback, 0);
+
+ _gxcommoninit(machine);
+
+ /* here are some hand tuned per game scroll offsets to go with the per game visible areas,
+ i see no better way of doing this for now... */
+
+ if (!strcmp(machine->gamedrv->name,"tbyahhoo"))
+ {
+ K056832_set_UpdateMode(1);
+ gx_tilemode = 1;
+ } else
+
+ if (!strcmp(machine->gamedrv->name,"puzldama"))
+ {
+ K053247GP_set_SpriteOffset(-46, -23);
+ konamigx_mixer_primode(5);
+ } else
+
+ if (!strcmp(machine->gamedrv->name,"daiskiss"))
+ {
+ konamigx_mixer_primode(4);
+ } else
+
+ if (!strcmp(machine->gamedrv->name,"gokuparo") || !strcmp(machine->gamedrv->name,"fantjour"))
+ {
+ K053247GP_set_SpriteOffset(-46, -23);
+ } else
+
+ if (!strcmp(machine->gamedrv->name,"sexyparo"))
+ {
+ K053247GP_set_SpriteOffset(-42, -23);
+ }
+}
+
+VIDEO_START(winspike)
+{
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_8, 0, NULL, konamigx_alpha_tile_callback, 0);
+ K055673_vh_start(machine, REGION_GFX2, K055673_LAYOUT_LE2, -53, -23, konamigx_type2_sprite_callback);
+
+ _gxcommoninitnosprites();
+}
+
+VIDEO_START(dragoonj)
+{
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_5, 1, NULL, konamigx_type2_tile_callback, 0);
+ K055673_vh_start(machine, REGION_GFX2, K055673_LAYOUT_RNG, -53, -23, konamigx_dragoonj_sprite_callback);
+
+ _gxcommoninitnosprites();
+
+ K056832_set_LayerOffset(0, -2+1, 0);
+ K056832_set_LayerOffset(1, 0+1, 0);
+ K056832_set_LayerOffset(2, 2+1, 0);
+ K056832_set_LayerOffset(3, 3+1, 0);
+}
+
+VIDEO_START(le2)
+{
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_8, 1, NULL, konamigx_type2_tile_callback, 0);
+ K055673_vh_start(machine, REGION_GFX2, K055673_LAYOUT_LE2, -46, -23, konamigx_le2_sprite_callback);
+
+ _gxcommoninitnosprites();
+
+ konamigx_mixer_primode(-1); // swapped layer B and C priorities?
+}
+
+VIDEO_START(konamigx_6bpp)
+{
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_6, 0, NULL, konamigx_type2_tile_callback, 0);
+
+ _gxcommoninit(machine);
+
+ if (!strcmp(machine->gamedrv->name,"tokkae") || !strcmp(machine->gamedrv->name,"tkmmpzdm"))
+ {
+ K053247GP_set_SpriteOffset(-46, -23);
+ konamigx_mixer_primode(5);
+ }
+}
+
+VIDEO_START(konamigx_type3)
+{
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_6, 0, NULL, konamigx_type2_tile_callback, 0);
+
+ _gxcommoninit(machine);
+
+ gx_psac_tilemap = tilemap_create(get_gx_psac3_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 256, 1024);
+ gx_rozenable = 1;
+
+ K053936_wraparound_enable(0, 1);
+ K053936GP_set_offset(0, 0, 0);
+}
+
+VIDEO_START(konamigx_type4)
+{
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_8, 0, NULL, konamigx_type2_tile_callback, 0);
+
+ _gxcommoninit(machine);
+
+ gx_psac_tilemap = tilemap_create(get_gx_psac_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 128, 128);
+ gx_rozenable = 1;
+
+ K053936_wraparound_enable(0, 0);
+ K053936GP_set_offset(0, 0, 0);
+}
+
+VIDEO_START(konamigx_6bpp_2)
+{
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_6, 1, NULL, konamigx_type2_tile_callback, 0);
+
+ if (!strcmp(machine->gamedrv->name,"salmndr2"))
+ {
+ K055673_vh_start(machine, REGION_GFX2, K055673_LAYOUT_GX6, -48, -23, konamigx_salmndr2_sprite_callback);
+
+ _gxcommoninitnosprites();
+ }
+ else
+ {
+ _gxcommoninit(machine);
+ }
+}
+
+VIDEO_START(opengolf)
+{
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_5, 0, NULL, konamigx_type2_tile_callback, 0);
+ K055673_vh_start(machine, REGION_GFX2, K055673_LAYOUT_GX6, -53, -23, konamigx_type2_sprite_callback);
+
+ _gxcommoninitnosprites();
+
+ K056832_set_LayerOffset(0, -2+1, 0);
+ K056832_set_LayerOffset(1, 0+1, 0);
+ K056832_set_LayerOffset(2, 2+1, 0);
+ K056832_set_LayerOffset(3, 3+1, 0);
+
+ gx_psac_tilemap = tilemap_create(get_gx_psac1a_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 128, 128);
+ gx_psac_tilemap2 = tilemap_create(get_gx_psac1b_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 128, 128);
+ tilemap_set_transparent_pen(gx_psac_tilemap, 0);
+ tilemap_set_transparent_pen(gx_psac_tilemap2, 0);
+
+ gx_rozenable = 0;
+}
+
+VIDEO_START(racinfrc)
+{
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_6, 0, NULL, konamigx_type2_tile_callback, 0);
+ K055673_vh_start(machine, REGION_GFX2, K055673_LAYOUT_GX, -53, -23, konamigx_type2_sprite_callback);
+
+ _gxcommoninitnosprites();
+
+ K056832_set_LayerOffset(0, -2+1, 0);
+ K056832_set_LayerOffset(1, 0+1, 0);
+ K056832_set_LayerOffset(2, 2+1, 0);
+ K056832_set_LayerOffset(3, 3+1, 0);
+
+ gx_psac_tilemap = tilemap_create(get_gx_psac1a_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 128, 128);
+ gx_psac_tilemap2 = tilemap_create(get_gx_psac1b_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 128, 128);
+ tilemap_set_transparent_pen(gx_psac_tilemap, 0);
+ tilemap_set_transparent_pen(gx_psac_tilemap2, 0);
+
+ gx_rozenable = 0;
+}
+
+VIDEO_UPDATE(konamigx)
+{
+ int i, newbank, newbase, dirty, unchained;
+
+ /* if any banks are different from last render, we need to flush the planes */
+ for (dirty = 0, i = 0; i < 8; i++)
+ {
+ newbank = gx_tilebanks[i];
+ if (gx_oldbanks[i] != newbank) { gx_oldbanks[i] = newbank; dirty = 1; }
+ }
+
+ if (gx_tilemode == 0)
+ {
+ // driver approximates tile update in mode 0 for speed
+ unchained = K056832_get_LayerAssociation();
+ for (i=0; i<4; i++)
+ {
+ newbase = K055555_get_palette_index(i)<<6;
+ if (layer_colorbase[i] != newbase)
+ {
+ layer_colorbase[i] = newbase;
+
+ if (unchained)
+ K056832_mark_plane_dirty(i);
+ else
+ dirty = 1;
+ }
+ }
+ }
+ else
+ {
+ // K056832 does all the tracking in mode 1 for accuracy (Twinbee needs this)
+ }
+
+ // sub2 is PSAC colorbase on GX
+ if (gx_rozenable)
+ {
+ last_psac_colorbase = psac_colorbase;
+ psac_colorbase = K055555_get_palette_index(6);
+
+ if (psac_colorbase != last_psac_colorbase)
+ {
+ tilemap_mark_all_tiles_dirty(gx_psac_tilemap);
+ if (gx_rozenable == 3)
+ {
+ tilemap_mark_all_tiles_dirty(gx_psac_tilemap2);
+ }
+ }
+ }
+
+ if (dirty) K056832_MarkAllTilemapsDirty();
+
+ if (gx_rozenable)
+ konamigx_mixer(machine, bitmap, cliprect, 0, 0, gx_psac_tilemap, GXSUB_8BPP, 0);
+ else
+ konamigx_mixer(machine, bitmap, cliprect, 0, 0, 0, 0, 0);
+
+ return 0;
+}
+
+
+WRITE32_HANDLER( konamigx_palette_w )
+{
+ int r,g,b;
+
+ COMBINE_DATA(&paletteram32[offset]);
+
+ r = (paletteram32[offset] >>16) & 0xff;
+ g = (paletteram32[offset] >> 8) & 0xff;
+ b = (paletteram32[offset] >> 0) & 0xff;
+
+ palette_set_color(Machine,offset,MAKE_RGB(r,g,b));
+}
+
+WRITE32_HANDLER( konamigx_palette2_w )
+{
+ int r,g,b;
+
+ COMBINE_DATA(&gx_subpaletteram32[offset]);
+
+ offset += (0x8000/4);
+
+ COMBINE_DATA(&paletteram32[offset]);
+
+ r = (paletteram32[offset] >>16) & 0xff;
+ g = (paletteram32[offset] >> 8) & 0xff;
+ b = (paletteram32[offset] >> 0) & 0xff;
+
+ palette_set_color(Machine,offset,MAKE_RGB(r,g,b));
+}
+
+// main monitor for type 3
+WRITE32_HANDLER( konamigx_555_palette_w )
+{
+ COMBINE_DATA(&paletteram32[offset]);
+
+ paletteram16 = (UINT16 *)paletteram32;
+ if (ACCESSING_MSW32)
+ paletteram16_xRRRRRGGGGGBBBBB_word_w(offset*2, data >> 16, mem_mask >> 16);
+ if (ACCESSING_LSW32)
+ paletteram16_xRRRRRGGGGGBBBBB_word_w(offset*2+1, data, mem_mask);
+}
+
+// sub monitor for type 3
+WRITE32_HANDLER( konamigx_555_palette2_w )
+{
+ COMBINE_DATA(&gx_subpaletteram32[offset]);
+
+ offset += (0x4000/4);
+
+ COMBINE_DATA(&paletteram32[offset]);
+
+ paletteram16 = (UINT16 *)paletteram32;
+ if (ACCESSING_MSW32)
+ paletteram16_xRRRRRGGGGGBBBBB_word_w(offset*2, data >> 16, mem_mask >> 16);
+ if (ACCESSING_LSW32)
+ paletteram16_xRRRRRGGGGGBBBBB_word_w(offset*2+1, data, mem_mask);
+}
+
+WRITE32_HANDLER( konamigx_tilebank_w )
+{
+ if (!(mem_mask & 0xff000000))
+ gx_tilebanks[offset*4] = (data>>24)&0xff;
+ if (!(mem_mask & 0xff0000))
+ gx_tilebanks[offset*4+1] = (data>>16)&0xff;
+ if (!(mem_mask & 0xff00))
+ gx_tilebanks[offset*4+2] = (data>>8)&0xff;
+ if (!(mem_mask & 0xff))
+ gx_tilebanks[offset*4+3] = data&0xff;
+}
+
+// type 1 RAM-based PSAC tilemap
+WRITE32_HANDLER(konamigx_t1_psacmap_w)
+{
+ COMBINE_DATA(&gx_psacram[offset]);
+ tilemap_mark_tile_dirty(gx_psac_tilemap, offset/2);
+ tilemap_mark_tile_dirty(gx_psac_tilemap2, offset/2);
+}
+
+// type 4 RAM-based PSAC tilemap
+WRITE32_HANDLER( konamigx_t4_psacmap_w )
+{
+ COMBINE_DATA(&gx_psacram[offset]);
+
+ tilemap_mark_tile_dirty(gx_psac_tilemap, offset);
+}
+
diff --git a/src/mame/video/konamiic.c b/src/mame/video/konamiic.c
new file mode 100644
index 00000000000..7c784dd5448
--- /dev/null
+++ b/src/mame/video/konamiic.c
@@ -0,0 +1,8340 @@
+#define VERBOSE 0
+
+/***************************************************************************
+
+TODO:
+- It seems shadows can both affect underlying sprites and not. This is currently
+ hardcoded in the drivers; there might be a control bit somewhere.
+ Games requiring shadows to affect sprites behind them:
+ - Surprise Attack (dark glass walls in level 3)
+ - 88 Games (angle indicator in the long jump event).
+ - Sunset Riders (bull's eye in the saloon cutscene)
+ Games requiring shadows to NOT affect sprites behind them:
+ - Asterix (Asterix's shadow would be over his feet otherwise)
+ - X-Men is dubious, see enemies halfway through level 1 coming from above with
+ boulders over their heads.
+
+- scrollcontrol = 30 in Golfing Greats (leader board)
+
+- detatwin: sprites are left on screen during attract mode
+
+
+ Emulated
+ |
+ board #|year CPU tiles sprites priority palette other
+ -----|---- ------- ------------- ------------- ------ ------ ----------------
+Hyper Crash GX401 1985 GX400
+Twinbee GX412*1985 68000 GX400
+Yie Ar Kung Fu GX407*1985 6809
+Gradius / Nemesis GX456*1985 68000 GX400
+Shao-lins Road GX477*1985 6809
+Jail Break GX507*1986 KONAMI-1 005849 PROMs
+Finalizer GX523*1985 KONAMI-1 005885 PROMs
+Konami's Ping Pong GX555*1985 Z80
+Iron Horse GX560*1986 6809 005885 PROMs
+Konami GT GX561*1985 68000 GX400
+Green Beret GX577*1985 Z80 005849 PROMs
+Galactic Warriors GX578*1985 68000 GX400
+Salamander GX587*1986 68000 GX400
+WEC Le Mans 24 GX602*1986 2x68000
+BAW / Black Panther GX604*1987 68000 GX400 007593
+Combat School / GX611*1987 6309 007121(x2) 007327
+ Boot Camp
+Rock 'n Rage / GX620*1986 6309 007342 007420 007327
+ Koi no Hotrock
+Mr Kabuki/Mr Goemon GX621*1986 Z80 005849
+Jackal GX631*1986 6809? 005885(x2)
+Contra / Gryzor GX633*1987 6809? 007121(x2) 007593
+Flak Attack GX669*1987 6309 007121 007327 007452
+Devil World / Dark GX687*1987 2x68000 TWIN16
+ Adventure / Majuu no Oukoku
+Double Dribble GX690*1986 3x6809 005885(x2) 007327 007452
+Kitten Kaboodle / GX712*1988 GX400 007593 051550
+ Nyan Nyan Panic
+Chequered Flag GX717*1988 052001 051960 051937(x2) 051316(x2) (roz) 051733 (protection)
+Fast Lane GX752*1987 6309 007121 051733 (protection) 007801
+Hot Chase GX763*1988 2x68000 051316(x3) (roz) 007634 007635 007558 007557
+Rack 'Em Up / GX765*1987 6309 007342 007420 007327 007324
+ The Hustler
+Haunted Castle GX768*1988 052001 007121(x2) 007327
+Ajax / Typhoon GX770*1987 6309+ 052109 051962 051960 051937 PROM 007327 051316 (roz)
+ 052001
+Labyrinth Runner / GX771*1987 6309 007121 007593 051733 (protection) 051550
+ Trick Trap
+Super Contra GX775*1988 052001 052109 051962 051960 051937 PROM 007327
+Battlantis GX777*1987 6309 007342 007420 007327 007324
+Vulcan Venture / GX785*1988 2x68000 TWIN16
+ Gradius 2
+City Bomber GX787*1987 68000 GX400 007593 051550
+Over Drive GX789*1990 2x68000 053247 053246 053251 051316(x2) (roz) 053249 053250(x2) (road) 053252(*)
+Hyper Crash GX790 1987
+Blades of Steel GX797*1987 6309 007342 007420 007327 051733 (protection)
+The Main Event GX799*1988 6309 052109 051962 051960 051937 PROM
+Missing in Action GX808*1989 68000 052109 051962 051960 051937 PROM
+Missing in Action J GX808*1989 2x68000 TWIN16
+Crime Fighters GX821*1989 052526 052109 051962 051960 051937 PROM
+Special Project Y GX857*1989 6309 052109 051962 051960 051937 PROM 052591 (protection)
+'88 Games GX861*1988 052001 052109 051962 051960 051937 PROM 051316 (roz)
+Final Round / GX870*1988 1x68000 TWIN16?
+ Hard Puncher
+Thunder Cross GX873*1988 052001 052109 051962 051960 051937 PROM 007327 052591 (protection)
+Aliens GX875*1990 052526 052109 051962 051960 051937 PROM
+Gang Busters GX878*1988 052526 052109 051962 051960 051937 PROM
+Devastators GX890*1988 6309 052109 051962 051960 051937 PROM 007324 051733 (protection)
+Bottom of the Ninth GX891*1989 6809 052109 051962 051960 051937 PROM 051316 (roz)
+Cue Brick GX903*1989 68000 052109 051962 051960 051937 PROM
+Cue Brick GX903*1989 2x68000 TWIN16
+Punk Shot GX907*1990 68000 052109 051962 051960 051937 053251
+Ultraman GX910*1991 68000 ------ ------ 051960 051937 PROM 051316(x3) (roz) 051550
+Surprise Attack GX911*1990 053248 052109 051962 053245 053244 053251
+Lightning Fighters /GX939*1990 68000 052109 051962 053245 053244 053251
+ Trigon
+Gradius 3 GX945*1989 2x68000 052109 051962 051960 051937 PROM
+Parodius GX955*1990 053248 052109 051962 053245 053244 053251
+TMNT GX963*1989 68000 052109 051962 051960 051937 PROM
+Block Hole GX973*1989 052526 052109 051962 051960 051937 PROM
+Escape Kids GX975*1991 053248 052109 051962 053247 053246 053251 053252(*)
+Rollergames GX999*1991 053248 ------ ------ 053245 053244 051316 (roz) 053252(*)
+Bells & Whistles / GX060*1991 68000 052109 051962 053245 053244 053251 054000 (collision)
+ Detana!! Twin Bee
+Golfing Greats GX061*1991 68000 052109 051962 053245 053244 053251 053936 (roz+)
+TMNT 2 GX063*1991 68000 052109 051962 053245 053244 053251 053990 (protection) 051550
+Sunset Riders GX064*1991 68000 052109 051962 053245 053244 053251 054358
+X-Men GX065*1992 68000 052109 051962 053247 053246 053251 054539 (sound)
+XEXEX GX067*1991 68000 054157 054156 053247 053246 053251 053250?("road") 054338 (alpha blending) 054539 (sound)
+Asterix GX068*1992 68000 054157 054156 053245 053244 053251 054358
+G.I. Joe GX069*1992 68000 054157 054156 053247 053246 053251 054539 (sound)
+The Simpsons GX072*1991 053248 052109 051962 053247 053246 053251
+Thunder Cross 2 GX073*1991 68000 052109 051962 051960 051937 053251 054000 (collision)
+Vendetta / GX081*1991 053248 052109 051962 053247 053246 053251 054000 (collision)
+ Crime Fighters 2
+Premier Soccer GX101*1993 68000 052109 051962 053245 053244 053251 053936 (roz+) 054986
+Hexion GX122*1992 Z80 052591 (protection) 053252(*)
+Entapous / GX123*1993 68000 054157 054156 055673 053246 055555 053252(*) 054000 053936 (roz+)
+ Gaiapolis
+Mystic Warrior GX128*1993 68000 054157 054156 055673 053246 055555 054338 (alpha blending) 053252(*) 054539(x2) (sound)
+Cowboys of Moo Mesa GX151*1992 68000 054157 054156 053247 053246 053251 053252(*) 054338 (alpha blending) 053990 (protection)
+Violent Storm GX168*1993 68000 054157 054156 055673 053246 055555 054338 (alpha blending) 055550 054539(x2) (sound)
+Monster Maulers / GX170*1993 68000 054157 054156 055673 053246 055555 053252(*) 055550 054338 (alpha blending) 054539 (sound) 053936 (roz+)
+ Ultimate Battler Dadandarn
+Bucky 'O Hare GX173*1992 68000 054157 054156 053247 053246 053251 054338 (alpha blending) 054539 (sound)
+Potrio GX174 1992
+Lethal Enforcers GX191*1992 6309 054157(x2) 054156 053245 053244(x2) 054000 054539 (sound)
+Metamorphic Force GX224*1993 68000 054157 054157 055673 053246 055555
+Martial Champion GX234*1993 68000 054157 054156 055673 053246 055555 053252(*) 054338 (alpha blending) 053990 054539 (sound)
+Run and Gun GX247*1993 68000 (TTL tilemap) 055673 053246 053253(x2) 053252(*) 053936 (roz+) 054539(x2) (sound)
+Quiz Gakumon no GX248*1993 68000 052109 051962 053245 053244 053251 053990 (protection) 051550 - same board as TMNT2
+ Susume
+Polygonet Commander GX305+1993 68020 (TTL tilemap) XC56156-40(3D DSP) 054009(x2) 054010(x2) 054539 (sound)
+System GX (ver 1) GX300*1993 68020 056832 054156 055673 053246 055555 054338 (alpha blending) 054539(x2) (sound) 053252(*) 053936 (optional on ROM board, roz+)
+System GX (ver 2) GX300*1995 68020 056832 058143 055673 058142 055555 058144 (alpha blending) 058141 (sound) 053252(*) 053936 (optional on ROM board, roz+)
+Beatmania DJ Main GX858+1996 68020 056832 058143 056766 055555 058144 (alpha blending) 058141 (sound) 053252(*)
+Tail to Nose *1989 68000 V-System 051316 (roz)
+F-1 Grand Prix *1991 2x68000 V-System 053936 (roz+)
+F-1 Grand Prix Part II *1992 2x68000 V-System 053936 (roz+)
+Lethal Crash Race *1993 68000 V-System 053936 (roz+)
+Super Slams *1995 68000 V-System 053936 (roz+)
+Blazing Tornado *1991 68000 Metro 053936 (roz+)
+Dragonball Z 2 *1994 68000 054157 054156 053247 053246 053251(x2) 053936(x2) (roz+) 053252(*)
+
+
+Notes:
+* 053252 seems to be just a timing/interrupt controller (see Vendetta schematics).
+
+- Old games use 051961 instead of 052109, it is an earlier version functionally
+ equivalent (maybe 052109 had bugs fixed). The list always shows 052109 because
+ the two are exchangeable and 052109's are found also on original boards whose
+ schematics show a 051961.
+
+- Starting with the version 2 System GX mainboard, the following chip substitutions took place.
+ All "new" chips are equivalent to their older counterparts, but are in a smaller package (and
+ presumably are made on a smaller process). The exception is the 058141, which is equivalent
+ to 2 54539s (and yet takes less board space than even 1).
+
+ 058141 = 054539 (x2) (2 sound chips in one)
+ 058142 = 053246 (sprites)
+ 058143 = 054156 (tiles)
+ 058144 = 054338 (alpha blending)
+
+
+
+Status of the ROM tests in the emulated games:
+
+Chequered Flag pass
+Ajax / Typhoon pass
+Super Contra pass
+Over Drive fails 16..20 (053250)
+The Main Event pass
+Missing in Action pass
+Crime Fighters pass
+Special Project Y pass
+Konami 88 pass
+Thunder Cross pass
+Aliens pass
+Gang Busters pass
+Devastators pass
+Bottom of the Ninth pass
+Punk Shot pass
+Surprise Attack fails D05-6 (052109) because it uses mirror addresses to
+ select banks, and supporting those addresses breaks the
+ normal game ;-(
+Lightning Fighters pass
+Gradius 3 pass
+Parodius pass
+TMNT pass
+Block Hole pass
+Escape Kids pass
+Rollergames pass
+Bells & Whistles pass
+Golfing Greats pass
+TMNT 2 pass
+Sunset Riders pass
+X-Men pass
+The Simpsons pass
+Thunder Cross 2 pass
+Xexex pass
+Asterix pass
+GiJoe pass
+Vendetta pass
+Premier Soccer fails 16D 18D 18F (053936)
+Hexion pass
+Run and Gun fails 36M (053936) 2U 2Y 5U 5Y (sprites)
+Quiz Gakumon no Susume pass
+Dragonball Z 2 fails
+
+
+THE FOLLOWING INFORMATION IS PRELIMINARY AND INACCURATE. DON'T RELY ON IT.
+
+
+005885
+------
+Some games use two of these in pair. Jackal even puts together the two 4bpp
+tilemaps to form a single 8bpp one.
+It manages sprites and 32x32 or 64x32 tilemap (only Double Dribble uses the
+64x32 one).
+The chip also generates clock and interrupt signals suitable for a 6809.
+It uses 0x2000 bytes of RAM for the tilemaps and sprites, and an additional
+0x100 bytes, maybe for scroll RAM and line buffers. The maximum addressable
+ROM is 0x20000 bytes (addressed 16 bits at a time). Tile and sprite data both
+come from the same ROM space. Double Dribble and Jackal have external circuitry
+to extend the limits and use separated addressing spaces for sprites and tiles.
+All games use external circuitry to reuse one or both the tile flip attributes
+as an additional address bit.
+Two 256x4 lookup PROMs are also used to increase the color combinations.
+All tilemap / sprite priority handling is done internally and the chip exports
+5 bits of color code, composed of 1 bit indicating tile or sprite, and 4 bits
+of ROM data remapped through the PROM.
+
+inputs:
+- address lines (A0-A13)
+- data lines (DB0-DB7)
+- misc interface stuff
+- data from the gfx ROMs (RDL0-RDL7, RDU0-RDU7)
+- data from the tile lookup PROMs (VCD0-VCD3)
+- data from the sprite lookup PROMs (OCD0-OCD3)
+
+outputs:
+- address lines for tilemap RAM (AX0-AX12)
+- data lines for tilemap RAM (VO0-VO7)
+- address lines for the small RAM (FA0-FA7)
+- data lines for the small RAM (FD0-FD7)
+- address lines for the gfx ROMs (R0-R15)
+- address lines for the tile lookup PROMs (VCF0-VCF3, VCB0-VCB3)
+- address lines for the sprite lookup PROMs (OCB0-OCB3, OCF0-OCF3)
+- NNMI, NIRQ, NFIR, NCPE, NCPQ, NEQ for the main CPU
+- misc interface stuff
+- color code to be output on screen (COL0-COL4)
+
+
+control registers
+000: scroll y
+001: scroll x (low 8 bits)
+002: -------x scroll x (high bit)
+ ----xxx- row/colscroll control
+ 000 = solid scroll (finalizr, ddribble bg)
+ 100 = solid scroll (jackal)
+ 001 = ? (ddribble fg)
+ 011 = colscroll (jackal high scores)
+ 101 = rowscroll (ironhors, jackal map)
+003: ------xx high bits of the tile code
+ -----x-- unknown (finalizr)
+ ----x--- selects sprite buffer (and makes a copy to a private buffer?)
+ --x----- unknown (ironhors)
+ -x------ unknown (ironhors)
+ x------- unknown (ironhors, jackal)
+004: -------x nmi enable
+ ------x- irq enable
+ -----x-- firq enable
+ ----x--- flip screen
+
+
+
+007121
+------
+This is an interesting beast. It is an evolution of the 005885, with more
+features. Many games use two of these in pair.
+It manages sprites and two 32x32 tilemaps. The tilemaps can be joined to form
+a single 64x32 one, or one of them can be moved to the side of screen, giving
+a high score display suitable for vertical games.
+The chip also generates clock and interrupt signals suitable for a 6809.
+It uses 0x2000 bytes of RAM for the tilemaps and sprites, and an additional
+0x100 bytes, maybe for scroll RAM and line buffers. The maximum addressable
+ROM is 0x80000 bytes (addressed 16 bits at a time). Tile and sprite data both
+come from the same ROM space.
+Two 256x4 lookup PROMs are also used to increase the color combinations.
+All tilemap / sprite priority handling is done internally and the chip exports
+7 bits of color code, composed of 2 bits of palette bank, 1 bit indicating tile
+or sprite, and 4 bits of ROM data remapped through the PROM.
+
+inputs:
+- address lines (A0-A13)
+- data lines (DB0-DB7)
+- misc interface stuff
+- data from the gfx ROMs (RDL0-RDL7, RDU0-RDU7)
+- data from the tile lookup PROMs (VCD0-VCD3)
+- data from the sprite lookup PROMs (OCD0-OCD3)
+
+outputs:
+- address lines for tilemap RAM (AX0-AX12)
+- data lines for tilemap RAM (VO0-VO7)
+- address lines for the small RAM (FA0-FA7)
+- data lines for the small RAM (FD0-FD7)
+- address lines for the gfx ROMs (R0-R17)
+- address lines for the tile lookup PROMs (VCF0-VCF3, VCB0-VCB3)
+- address lines for the sprite lookup PROMs (OCB0-OCB3, OCF0-OCF3)
+- NNMI, NIRQ, NFIR, NE, NQ for the main CPU
+- misc interface stuff
+- color code to be output on screen (COA0-COA6)
+
+
+control registers
+000: scroll x (low 8 bits)
+001: -------x scroll x (high bit)
+ ------x- enable rowscroll? (combasc)
+ ----x--- this probably selects an alternate screen layout used in combat
+ school where tilemap #2 is overlayed on front and doesn't scroll.
+ The 32 lines of the front layer can be individually turned on or
+ off using the second 32 bytes of scroll RAM.
+002: scroll y
+003: -------x bit 13 of the tile code
+ ------x- unknown (contra)
+ -----x-- might be sprite / tilemap priority (0 = sprites have priority)
+ (combat school, contra, haunted castle(0/1), labyrunr)
+ ----x--- selects sprite buffer (and makes a copy to a private buffer?)
+ ---x---- screen layout selector:
+ when this is set, 5 columns are added on the left of the screen
+ (that means 5 rows at the top for vertical games), and the
+ rightmost 2 columns are chopped away.
+ Tilemap #2 is used to display the 5 additional columns on the
+ left. The rest of tilemap #2 is not used and can be used as work
+ RAM by the program.
+ The visible area becomes 280x224.
+ Note that labyrunr changes this at runtime, setting it during
+ gameplay and resetting it on the title screen and crosshatch.
+ --x----- might be sprite / tilemap priority (0 = sprites have priority)
+ (combat school, contra, haunted castle(0/1), labyrunr)
+ -x------ Chops away the leftmost and rightmost columns, switching the
+ visible area from 256 to 240 pixels. This is used by combasc on
+ the scrolling stages, and by labyrunr on the title screen.
+ At first I thought that this enabled an extra bank of 0x40
+ sprites, needed by combasc, but labyrunr proves that this is not
+ the case
+ x------- unknown (contra)
+004: ----xxxx bits 9-12 of the tile code. Only the bits enabled by the following
+ mask are actually used, and replace the ones selected by register
+ 005.
+ xxxx---- mask enabling the above bits
+005: selects where in the attribute byte to pick bits 9-12 of the tile code,
+ output to pins R12-R15. The bit of the attribute byte to use is the
+ specified bit (0-3) + 3, that is one of bits 3-6. Bit 7 is hardcoded as
+ bit 8 of the code. Bits 0-2 are used for the color, however note that
+ some games use bit 3 as well (see below).
+ ------xx attribute bit to use for tile code bit 9
+ ----xx-- attribute bit to use for tile code bit 10
+ --xx---- attribute bit to use for tile code bit 11
+ xx------ attribute bit to use for tile code bit 12
+006: ----xxxx select additional effect for bits 3-6 of the tile attribute (the
+ same ones indexed by register 005). Note that an attribute bit
+ can therefore be used at the same time to be BOTH a tile code bit
+ and an additional effect.
+ -------x bit 3 of attribute is bit 3 of color (combasc, fastlane, flkatck)
+ ------x- bit 4 of attribute is tile flip X (assumption - no game uses this)
+ -----x-- bit 5 of attribute is tile flip Y (flkatck)
+ ----x--- bit 6 of attribute is tile priority over sprites (combasc, hcastle,
+ labyrunr)
+ Note that hcastle sets this bit for layer 0, and bit 6 of the
+ attribute is also used as bit 12 of the tile code, however that
+ bit is ALWAYS set throughout the game.
+ combasc uses the bit in the "graduation" scene during attract mode,
+ to place soldiers behind the stand.
+ Use in labyrunr has not been investigated yet.
+ --xx---- palette bank (both tiles and sprites, see contra)
+007: -------x nmi enable
+ ------x- irq enable
+ -----x-- firq enable
+ ----x--- flip screen
+ ---x---- unknown (contra, labyrunr)
+
+
+
+007342
+------
+The 007342 manages 2 64x32 scrolling tilemaps with 8x8 characters, and
+optionally generates timing clocks and interrupt signals. It uses 0x2000
+bytes of RAM, plus 0x0200 bytes for scrolling, and a variable amount of ROM.
+It cannot read the ROMs.
+
+control registers
+000: ------x- INT control
+ ---x---- flip screen (TODO: doesn't work with thehustl)
+001: Used for banking in Rock'n'Rage
+002: -------x MSB of x scroll 1
+ ------x- MSB of x scroll 2
+ ---xxx-- layer 1 row/column scroll control
+ 000 = disabled
+ 010 = unknown (bladestl shootout between periods)
+ 011 = 32 columns (Blades of Steel)
+ 101 = 256 rows (Battlantis, Rock 'n Rage)
+ x------- enable sprite wraparound from bottom to top (see Blades of Steel
+ high score table)
+003: x scroll 1
+004: y scroll 1
+005: x scroll 2
+006: y scroll 2
+007: not used
+
+
+007420
+------
+Sprite generator. 8 bytes per sprite with zoom. It uses 0x200 bytes of RAM,
+and a variable amount of ROM. Nothing is known about its external interface.
+
+
+
+052109/051962
+-------------
+These work in pair.
+The 052109 manages 3 64x32 scrolling tilemaps with 8x8 characters, and
+optionally generates timing clocks and interrupt signals. It uses 0x4000
+bytes of RAM, and a variable amount of ROM. It cannot read the ROMs:
+instead, it exports 21 bits (16 from the tilemap RAM + 3 for the character
+raster line + 2 additional ones for ROM banking) and these are externally
+used to generate the address of the required data on the ROM; the output of
+the ROMs is sent to the 051962, along with a color code. In theory you could
+have any combination of bits in the tilemap RAM, as long as they add to 16.
+In practice, all the games supported so far standardize on the same format
+which uses 3 bits for the color code and 13 bits for the character code.
+The 051962 multiplexes the data of the three layers and converts it into
+palette indexes and transparency bits which will be mixed later in the video
+chain.
+Priority is handled externally: these chips only generate the tilemaps, they
+don't mix them.
+Both chips are interfaced with the main CPU. When the RMRD pin is asserted,
+the CPU can read the gfx ROM data. This is done by telling the 052109 which
+dword to read (this is a combination of some banking registers, and the CPU
+address lines), and then reading it from the 051962.
+
+052109 inputs:
+- address lines (AB0-AB15, AB13-AB15 seem to have a different function)
+- data lines (DB0-DB7)
+- misc interface stuff
+
+052109 outputs:
+- address lines for the private RAM (RA0-RA12)
+- data lines for the private RAM (VD0-VD15)
+- NMI, IRQ, FIRQ for the main CPU
+- misc interface stuff
+- ROM bank selector (CAB1-CAB2)
+- character "code" (VC0-VC10)
+- character "color" (COL0-COL7); used foc color but also bank switching and tile
+ flipping. Exact meaning depends on externl connections. All evidence indicates
+ that COL2 and COL3 select the tile bank, and are replaced with the low 2 bits
+ from the bank register. The top 2 bits of the register go to CAB1-CAB2.
+ However, this DOES NOT WORK with Gradius III. "color" seems to pass through
+ unaltered.
+- layer A horizontal scroll (ZA1H-ZA4H)
+- layer B horizontal scroll (ZB1H-ZB4H)
+- ????? (BEN)
+
+051962 inputs:
+- gfx data from the ROMs (VC0-VC31)
+- color code (COL0-COL7); only COL4-COL7 seem to really be used for color; COL0
+ is tile flip X.
+- layer A horizontal scroll (ZA1H-ZA4H)
+- layer B horizontal scroll (ZB1H-ZB4H)
+- let main CPU read the gfx ROMs (RMRD)
+- address lines to be used with RMRD (AB0-AB1)
+- data lines to be used with RMRD (DB0-DB7)
+- ????? (BEN)
+- misc interface stuff
+
+051962 outputs:
+- FIX layer palette index (DFI0-DFI7)
+- FIX layer transparency (NFIC)
+- A layer palette index (DSA0-DSAD); DSAA-DSAD seem to be unused
+- A layer transparency (NSAC)
+- B layer palette index (DSB0-DSBD); DSBA-DSBD seem to be unused
+- B layer transparency (NSBC)
+- misc interface stuff
+
+
+052109 memory layout:
+0000-07ff: layer FIX tilemap (attributes)
+0800-0fff: layer A tilemap (attributes)
+1000-1fff: layer B tilemap (attributes)
+180c-1833: A y scroll
+1a00-1bff: A x scroll
+1c00 : ?
+1c80 : row/column scroll control
+ ------xx layer A row scroll
+ 00 = disabled
+ 01 = disabled? (gradius3, vendetta)
+ 10 = 32 lines
+ 11 = 256 lines
+ -----x-- layer A column scroll
+ 0 = disabled
+ 1 = 64 (actually 40) columns
+ ---xx--- layer B row scroll
+ --x----- layer B column scroll
+ surpratk sets this register to 70 during the second boss. There is
+ nothing obviously wrong so it's not clear what should happen.
+ glfgreat sets it to 30 when showing the leader board
+1d00 : bits 0 & 1 might enable NMI and FIRQ, not sure
+ : bit 2 = IRQ enable
+1d80 : ROM bank selector bits 0-3 = bank 0 bits 4-7 = bank 1
+1e00 : ROM subbank selector for ROM testing
+1e80 : bit 0 = flip screen (applies to tilemaps only, not sprites)
+ : bit 1 = set by crimfght, mainevt, surpratk, xmen, mia, punkshot, thndrx2, spy
+ : it seems to enable tile flip X, however flip X is handled by the
+ : 051962 and it is not hardwired to a specific tile attribute.
+ : Note that xmen, punkshot and thndrx2 set the bit but the current
+ : drivers don't use flip X and seem to work fine.
+ : bit 2 = enables tile flip Y when bit 1 of the tile attribute is set
+1f00 : ROM bank selector bits 0-3 = bank 2 bits 4-7 = bank 3
+2000-27ff: layer FIX tilemap (code)
+2800-2fff: layer A tilemap (code)
+3000-37ff: layer B tilemap (code)
+3800-3807: nothing here, so the chip can share address space with a 051937
+380c-3833: B y scroll
+3a00-3bff: B x scroll
+3c00-3fff: nothing here, so the chip can share address space with a 051960
+3d80 : mirror of 1d80, but ONLY during ROM test (surpratk)
+3e00 : mirror of 1e00, but ONLY during ROM test (surpratk)
+3f00 : mirror of 1f00, but ONLY during ROM test (surpratk)
+EXTRA ADDRESSING SPACE USED BY X-MEN:
+4000-47ff: layer FIX tilemap (code high bits)
+4800-4fff: layer A tilemap (code high bits)
+5000-57ff: layer B tilemap (code high bits)
+
+The main CPU doesn't have direct acces to the RAM used by the 052109, it has
+to through the chip.
+
+
+
+054156/054157
+054156/056832
+-------------
+
+[Except for tilemap sizes, all numbers are in hex]
+
+These work in pairs. Similar in principle to the 052109/051962, they
+manage 4 64x32 or 64x64 tilemaps. They also handle linescroll on each
+layer, and optional tile banking. They use 4000 to 10000 bytes of
+RAM, organized in 1000 or 2000 bytes banks.
+
+The 56832 is a complete superset of the 54157 and supports higher color
+depths (the 156/157 combo only goes to 5 bpp, the 156/832 combo goes to 8bpp).
+
+These chips work in a fairly unusual way. There are 4, 8, or 16 pages of VRAM, arranged
+conceptually in a 4x4 2 dimensional grid. Each page is a complete 64x32 tile tilemap.
+
+The 4 physical tilemaps A, B, C, and, D are made up of these pages "glued together".
+Each physical tilemap has an X and Y position in the 4x4 page grid indicating where
+the page making up it's upper left corner is, as well as a width and height in pages.
+If two tilemaps try to use the same page, the higher-letter one wins and the lower-letter
+one is disabled completely. E.g. A > B > C > D, so if A and B both try to use the
+same page only A will be displayed. Some games rely on this behavior to implicitly
+disable tilemaps which otherwise should be displayed.
+
+Tile encoding 2 bytes/tile (banks of 1000 bytes):
+ pppx bbcc cccc cccc
+ p = color palette
+ x = flip x
+ b = tile bank (0..3)
+ c = tile code (0..3ff)
+
+
+Tile encoding 4 bytes/tile (banks of 2000 bytes):
+ ---- ---- pppp --yx cccc cccc cccc cccc
+ p = color palette
+ x = flip x
+ y = flip y
+ b = tile bank (0..3)
+ c = tile code (0..3ff)
+
+
+Communication with these ics go through 4 memory zones:
+ 1000/2000 bytes: access to the currently selected ram bank
+ 2000 bytes: readonly access the the currently select tile
+ rom bank for rom checksumming
+ 40 bytes: writeonly access to the first register bank
+ 8 bytes: writeonly access to the second register bank
+
+One of the register banks is probably on the 054156, and the other on
+the 054157.
+
+First register bank map (offsets in bytes, '-' means unused):
+00 ---- ---- ??yx ????
+ flip control
+
+02 ---- ---- ???? ????
+ unknown
+
+04 ---- ---- ???? ????
+ unknown (bit 1 may be bank count selection, 0 in xexex, 1 everywhere
+ else)
+
+06 ---- ---- ???? ???e
+ enable irq
+
+08 ---- ---- ???? ????
+ unknown
+
+0a ---- ---- 3322 1100
+ linescroll control, each pair of bits indicates the mode for the
+ corresponding layer:
+ 0: per-line linescroll
+ 1: unused/unknown
+ 2: per-8 lines linescroll
+ 3: no linescroll
+
+0c ---- ---- ???? ????
+ unknown (bit 1 may be bank size selection, 1 in asterix, 0 everywhere
+ else)
+
+0e ---- ---- ---- ----
+
+10-13 ---- ---- ---y y-hh
+ layer Y position in the VRAM grid and height in pages
+
+14-17 ---- ---- ---x x-ww
+ layer X position in the VRAM grid and width in pages
+18-1f ---- ---- ???? ????
+
+20-27 yyyy yyyy yyyy yyyy
+ scroll y position for each layer
+
+28-2f xxxx xxxx xxxx xxxx
+ scroll x position for each layer
+
+30 ---- ---- ---b b--b
+ linescroll ram bank selection
+
+32 ---- ---- ---b b--b
+ cpu-accessible ram bank selection
+
+34 bbbb bbbb bbbb bbbb
+ rom bank selection for checksumming (each bank is 0x2000 bytes)
+
+36 ---- ---- ---- bbbb
+ secondary rom bank selection for checksumming when tile banking is
+ used
+
+38 3333 2222 1111 0000
+ tile banking look up table. 4 bits are looked up here for the two
+ bits in the tile data.
+
+3a ???? ???? ???? ????
+ unknown
+
+3c ???? ???? ???? ????
+ unknown
+
+3e ---- ---- ---- ----
+
+
+Second register bank map:
+00 ---- ---- ???? ????
+ unknown
+
+02-07 are copies of the 02-07 registers from the first bank.
+
+
+ Linescroll:
+
+The linescroll is controlled by the register 0b, and uses the data in
+the ram bank pointed by register 31. The data for tilemap <n> starts
+at offset 400*n in the bank for 1000 bytes ram banks, and 800*n+2 for
+2000 bytes ram banks. The scrolling information is a vector of half
+words separated by 1 word padding for 2000 bytes banks.
+
+This is a source-oriented linescroll, i.e. the first word is
+associated to the first one of the tilemap, not matter what the
+current scrolly position is.
+
+In per-line mode, each word indicates the horizontal scroll of the
+associated line. Global scrollx is ignored.
+
+In per-8 lines mode, each word associated to a line multiple of 8
+indicates the horizontal scroll for that line and the 7 following
+ones. The other 7 words are ignored. Global scrollx is ignored.
+
+
+
+051960/051937
+-------------
+Sprite generators. Designed to work in pair. The 051960 manages the sprite
+list and produces and address that is fed to the gfx ROMs. The data from the
+ROMs is sent to the 051937, along with color code and other stuff from the
+051960. The 051937 outputs up to 12 bits of palette index, plus "shadow" and
+transparency information.
+Both chips are interfaced to the main CPU, through 8-bit data buses and 11
+bits of address space. The 051937 sits in the range 000-007, while the 051960
+in the range 400-7ff (all RAM). The main CPU can read the gfx ROM data though
+the 051937 data bus, while the 051960 provides the address lines.
+The 051960 is designed to directly address 1MB of ROM space, since it produces
+18 address lines that go to two 16-bit wide ROMs (the 051937 has a 32-bit data
+bus to the ROMs). However, the addressing space can be increased by using one
+or more of the "color attribute" bits of the sprites as bank selectors.
+Moreover a few games store the gfx data in the ROMs in a format different from
+the one expected by the 051960, and use external logic to reorder the address
+lines.
+The 051960 can also genenrate IRQ, FIRQ and NMI signals.
+
+memory map:
+000-007 is for the 051937, but also seen by the 051960
+400-7ff is 051960 only
+000 R bit 0 = unknown, looks like a status flag or something
+ aliens waits for it to be 0 before starting to copy sprite data
+ thndrx2 needs it to pulse for the startup checks to succeed
+000 W bit 0 = irq enable/acknowledge?
+ bit 2 = nmi enable?
+ bit 3 = flip screen (applies to sprites only, not tilemaps)
+ bit 4 = unknown, used by Devastators, TMNT, Aliens, Chequered Flag, maybe others
+ aliens sets it just after checking bit 0, and before copying
+ the sprite data
+ bit 5 = enable gfx ROM reading
+001 W Devastators sets bit 1, function unknown.
+ Ultraman sets the register to 0x0f.
+ None of the other games I tested seem to set this register to other than 0.
+002-003 W selects the portion of the gfx ROMs to be read.
+004 W Aliens uses this to select the ROM bank to be read, but Punk Shot
+ and TMNT don't, they use another bit of the registers above. Many
+ other games write to this register before testing.
+ It is possible that bits 2-7 of 003 go to OC0-OC5, and bits 0-1 of
+ 004 go to OC6-OC7.
+004-007 R reads data from the gfx ROMs (32 bits in total). The address of the
+ data is determined by the register above and by the last address
+ accessed on the 051960; plus bank switch bits for larger ROMs.
+ It seems that the data can also be read directly from the 051960
+ address space: 88 Games does this. First it reads 004 and discards
+ the result, then it reads from the 051960 the data at the address
+ it wants. The normal order is the opposite, read from the 051960 at
+ the address you want, discard the result, and fetch the data from
+ 004-007.
+400-7ff RW sprite RAM, 8 bytes per sprite
+
+
+
+053245/053244
+-------------
+Sprite generators. The 053245 has a 16-bit data bus to the main CPU.
+The sprites are buffered, a write to 006 activates to copy between the
+main ram and the buffer.
+
+053244 memory map (but the 053245 sees and processes them too):
+000-001 W global X offset
+002-003 W global Y offset
+004 W unknown
+005 W bit 0 = flip screen X
+ bit 1 = flip screen Y
+ bit 2 = unknown, used by Parodius
+ bit 4 = enable gfx ROM reading
+ bit 5 = unknown, used by Rollergames
+006 RW accessing this register copies the sprite ram to the internal buffer
+007 W unknown
+008-009 W low 16 bits of the ROM address to read
+00a-00b W high bits of the ROM address to read. 3 bits for most games, 1 for asterix
+00c-00f R reads data from the gfx ROMs (32 bits in total). The address of the
+ data is determined by the registers above; plus bank switch bits for
+ larger ROMs.
+
+
+
+053247/053246
+-------------
+Sprite generators. Nothing is known about their external interface.
+The sprite RAM format is very similar to the 053245.
+
+053246 memory map (but the 053247 sees and processes them too):
+000-001 W global X offset
+002-003 W global Y offset
+004 W low 8 bits of the ROM address to read
+005 W bit 0 = flip screen X
+ bit 1 = flip screen Y
+ bit 2 = unknown
+ bit 4 = interrupt enable
+ bit 5 = unknown
+006-007 W high 16 bits of the ROM address to read
+
+???-??? R reads data from the gfx ROMs (16 bits in total). The address of the
+ data is determined by the registers above
+
+
+
+051316
+------
+Manages a 32x32 tilemap (16x16 tiles, 512x512 pixels) which can be zoomed,
+distorted and rotated.
+It uses two internal 24 bit counters which are incremented while scanning the
+picture. The coordinates of the pixel in the tilemap that has to be drawn to
+the current beam position are the counters / (2^11).
+The chip doesn't directly generate the color information for the pixel, it
+just generates a 24 bit address (whose top 16 bits are the contents of the
+tilemap RAM), and a "visible" signal. It's up to external circuitry to convert
+the address into a pixel color. Most games seem to use 4bpp graphics, but Ajax
+uses 7bpp.
+If the value in the internal counters is out of the visible range (0..511), it
+is truncated and the corresponding address is still generated, but the "visible"
+signal is not asserted. The external circuitry might ignore that signal and
+still generate the pixel, therefore making the tilemap a continuous playfield
+that wraps around instead of a large sprite.
+
+control registers
+000-001 X counter starting value / 256
+002-003 amount to add to the X counter after each horizontal pixel
+004-005 amount to add to the X counter after each line (0 = no rotation)
+006-007 Y counter starting value / 256
+008-009 amount to add to the Y counter after each horizontal pixel (0 = no rotation)
+00a-00b amount to add to the Y counter after each line
+00c-00d ROM bank to read, used during ROM testing
+00e bit 0 = enable ROM reading (active low). This only makes the chip output the
+ requested address: the ROM is actually read externally, not through
+ the chip's data bus.
+ bit 1 = unknown
+ bit 2 = unknown
+00f unused
+
+
+
+053936
+------
+Evolution of the 051316. The data bus is 16-bit instead of 8-bit.
+When used in "simple" mode it can generate the same effects of the 051316, but it
+doesn't have internal tilemap RAM, so it just generates a couple of X/Y coordinates
+indicating the pixel to display at each moment. Therefore, the tilemap and tile
+sizes are not fixed.
+The important addition over the 051316 is 512x4 words of internal RAM used to control
+rotation and zoom scanline by scanline instead that on the whole screen, allowing for
+effects like linescroll (Super Slams) or 3D rotation of the tilemap (Golfing Greats,
+Premier Soccer).
+
+control registers
+000 X counter starting value / 256
+001 Y counter starting value / 256
+002 ["simple" mode only] amount to add to the X counter after each line (0 = no rotation)
+003 ["simple" mode only] amount to add to the Y counter after each line
+004 ["simple" mode only] amount to add to the X counter after each horizontal pixel
+005 ["simple" mode only] amount to add to the Y counter after each horizontal pixel (0 = no rotation)
+006 x------- -------- when set, register (line*4)+2 must be multiplied by 256
+ -x------ -------- when set, registers 002 and 003 must be multiplied by 256
+ --xxxxxx -------- clipping for the generated address? usually 3F, Premier Soccer
+ sets it to 07 before penalty kicks
+ -------- x------- when set, register (line*4)+3 must be multiplied by 256
+ -------- -x------ when set, registers 004 and 005 must be multiplied by 256
+ -------- --xxxxxx clipping for the generated address? usually 3F, Premier Soccer
+ sets it to 0F before penalty kicks
+007 -------- -x------ enable "super" mode
+ -------- --x----- unknown (enable address clipping from register 006?)
+ -------- ---x---- unknown
+ -------- ------x- (not sure) enable clipping with registers 008-00b
+008 min x screen coordinate to draw to (only when enabled by register 7)
+009 max x screen coordinate to draw to (only when enabled by register 7)
+00a min y screen coordinate to draw to (only when enabled by register 7)
+00b max y screen coordinate to draw to (only when enabled by register 7)
+00c unknown
+00d unknown
+00e unknown
+00f unknown
+
+additional control from extra RAM:
+(line*4)+0 X counter starting value / 256 (add to register 000)
+(line*4)+1 Y counter starting value / 256 (add to register 001)
+(line*4)+2 amount to add to the X counter after each horizontal pixel
+(line*4)+3 amount to add to the Y counter after each horizontal pixel
+
+
+
+053251
+------
+Priority encoder.
+
+The chip has inputs for 5 layers (CI0-CI4); only 4 are used (CI1-CI4)
+CI0-CI2 are 9(=5+4) bits inputs, CI3-CI4 8(=4+4) bits
+
+The input connctions change from game to game. E.g. in Simpsons,
+CI0 = grounded (background color)
+CI1 = sprites
+CI2 = FIX
+CI3 = A
+CI4 = B
+
+in lgtnfght:
+CI0 = grounded
+CI1 = sprites
+CI2 = FIX
+CI3 = B
+CI4 = A
+
+there are three 6 bit priority inputs, PR0-PR2
+
+simpsons:
+PR0 = 111111
+PR1 = xxxxx0 x bits coming from the sprite attributes
+PR2 = 111111
+
+lgtnfght:
+PR0 = 111111
+PR1 = 1xx000 x bits coming from the sprite attributes
+PR2 = 111111
+
+also two shadow inputs, SDI0 and SDI1 (from the sprite attributes)
+
+the chip outputs the 11 bit palette index, CO0-CO10, and two shadow bits.
+
+16 internal registers; registers are 6 bits wide (input is D0-D5)
+For the most part, their meaning is unknown
+All registers are write only.
+There must be a way to enable/disable the three external PR inputs.
+Some games initialize the priorities of the sprite & background layers,
+others don't. It isn't clear whether the data written to those registers is
+actually used, since the priority is taken from the external ports.
+
+ 0 priority of CI0 (higher = lower priority)
+ punkshot: unused?
+ lgtnfght: unused?
+ simpsons: 3f = 111111
+ xmen: 05 = 000101 default value
+ xmen: 09 = 001001 used to swap CI0 and CI2
+ 1 priority of CI1 (higher = lower priority)
+ punkshot: 28 = 101000
+ lgtnfght: unused?
+ simpsons: unused?
+ xmen: 02 = 000010
+ 2 priority of CI2 (higher = lower priority)
+ punkshot: 24 = 100100
+ lgtnfght: 24 = 100100
+ simpsons: 04 = 000100
+ xmen: 09 = 001001 default value
+ xmen: 05 = 000101 used to swap CI0 and CI2
+ 3 priority of CI3 (higher = lower priority)
+ punkshot: 34 = 110100
+ lgtnfght: 34 = 110100
+ simpsons: 28 = 101000
+ xmen: 00 = 000000
+ 4 priority of CI4 (higher = lower priority)
+ punkshot: 2c = 101100 default value
+ punkshot: 3c = 111100 used to swap CI3 and CI4
+ punkshot: 26 = 100110 used to swap CI1 and CI4
+ lgtnfght: 2c = 101100
+ simpsons: 18 = 011000
+ xmen: fe = 111110
+ 5 unknown
+ punkshot: unused?
+ lgtnfght: 2a = 101010
+ simpsons: unused?
+ xmen: unused?
+ 6 unknown
+ punkshot: 26 = 100110
+ lgtnfght: 30 = 110000
+ simpsons: 17 = 010111
+ xmen: 03 = 000011 (written after initial tests)
+ 7 unknown
+ punkshot: unused?
+ lgtnfght: unused?
+ simpsons: 27 = 100111
+ xmen: 07 = 000111 (written after initial tests)
+ 8 unknown
+ punkshot: unused?
+ lgtnfght: unused?
+ simpsons: 37 = 110111
+ xmen: ff = 111111 (written after initial tests)
+ 9 ----xx CI0 palette index base (CO9-CO10)
+ --xx-- CI1 palette index base (CO9-CO10)
+ xx---- CI2 palette index base (CO9-CO10)
+10 ---xxx CI3 palette index base (CO8-CO10)
+ xxx--- CI4 palette index base (CO8-CO10)
+11 unknown
+ punkshot: 00 = 000000
+ lgtnfght: 00 = 000000
+ simpsons: 00 = 000000
+ xmen: 00 = 000000 (written after initial tests)
+12 unknown
+ punkshot: 04 = 000100
+ lgtnfght: 04 = 000100
+ simpsons: 05 = 000101
+ xmen: 05 = 000101
+13 unused
+14 unused
+15 unused
+
+
+054000
+------
+Sort of a protection device, used for collision detection.
+It is passed a few parameters, and returns a boolean telling if collision
+happened. It has no access to gfx data, it only does arithmetical operations
+on the parameters.
+
+Memory map:
+00 unused
+01-03 W A center X
+04 W unknown, needed by thndrx2 to pass the startup check, we use a hack
+05 unused
+06 W A semiaxis X
+07 W A semiaxis Y
+08 unused
+09-0b W A center Y
+0c W unknown, needed by thndrx2 to pass the startup check, we use a hack
+0d unused
+0e W B semiaxis X
+0f W B semiaxis Y
+10 unused
+11-13 W B center Y
+14 unused
+15-17 W B center X
+18 R 0 = collision, 1 = no collision
+
+
+051733
+------
+Sort of a protection device, used for collision detection, and for
+arithmetical operations.
+It is passed a few parameters, and returns the result.
+
+Memory map(preliminary):
+------------------------
+00-01 W operand 1
+02-03 W operand 2
+04-05 W operand 3
+
+00-01 R operand 1 / operand 2
+02-03 R operand 1 % operand 2?
+04-05 R sqrt(operand 3<<16)
+
+06-07 W distance for collision check
+08-09 W Y pos of obj1
+0a-0b W X pos of obj1
+0c-0d W Y pos of obj2
+0e-0f W X pos of obj2
+13 W unknown
+
+07 R collision (0x80 = no, 0x00 = yes)
+0a-0b R unknown (chequered flag), might just read back X pos
+0e-0f R unknown (chequered flag), might just read back X pos
+
+Other addresses are unknown or unused.
+
+Fast Lane:
+----------
+$9def:
+This routine is called only after a collision.
+(R) 0x0006: unknown. Only bits 0-3 are used.
+
+Blades of Steel:
+----------------
+$ac2f:
+(R) 0x2f86: unknown. Only uses bit 0.
+
+$a5de:
+writes to 0x2f84-0x2f85, waits a little, and then reads from 0x2f84.
+
+$7af3:
+(R) 0x2f86: unknown. Only uses bit 0.
+
+
+Devastators:
+------------
+$6ce8:
+reads from 0x0006, and only uses bit 1.
+
+
+K055550
+-------
+
+Protection chip which performs a memset() operation.
+
+Used in Violent Storm and Ultimate Battler to clear VRAM between scenes, among
+other things. May also perform other functions since Violent Storm still isn't
+happy...
+
+Has word-wide registers as follows:
+
+0: Count of units to transfer. The write here triggers the transfer.
+1-6: Unknown
+7: Destination address, MSW
+8: Destination address, LSW
+9: Unknown
+10: Size of transfer units, MSW
+11: Size of transfer units, LSW
+12: Unknown
+13: Value to fill destination region with
+14-15: Unknown
+
+
+K055555
+-------
+
+Priority encoder. Always found in conjunction with K054338, but the reverse
+isn't true. The 55555 has 8 inputs: "A", "B", "C", and "D" intended for a 156/157
+type tilemap chip, "OBJ" intended for a '246 type sprite chip, and "SUB1-SUB3"
+which can be used for 3 additional layers.
+
+When used in combintion with a K054338, each input can be chosen to participate
+in shadow/highlight operations, R/G/B alpha blending, and R/G/B brightness control.
+Per-tile priority is supported for tilemap planes A and B.
+
+There are also 3 shadow priority registers. When these are enabled, layers and
+sprites with a priority greater than or equal to them become a shadow, and either
+then gets drawn as a shadow/highlight or not at all (I'm not sure what selects
+this yet. Dadandarn relies on this mechanism to hide the 53936 plane when
+it doesn't want it visible).
+
+It also appears that brightness control and alpha blend can be decided per-tile
+and per-sprite, although this is not certain.
+
+Additionally the 55555 can provide a gradient background with one palette entry
+per scanline. This is fairly rarely used, but does turn up in Gokujou Parodius as
+well as the Sexy Parodius title screen.
+
+Lots of byte-wise registers. A partial map:
+
+0: Palette index(?) for the gradient background
+1: related to tilemap brightness control
+2-5: COLSEL for various inputs (?)
+6: COLCHG ON
+7-18: priority levels (VA1/VA2/VAC/VB1/VB2/VBC/VC/VD/OBJ/S1/S2/S3)
+19-22: INPRI for OBJ/S1/S2/S3
+23-32: palette bases (VA/VB/VC/VD/OBJ/S1/S2/S3)
+37: shadow 1 priority
+38: shadow 2 priority
+39: shadow 3 priority
+40: shadow/highlight master enable
+41: master shadow/highlight priority
+42: VBRI: enables brightness control for each VRAM layer (bits: x x x x D B C A)
+43: OSBRI: enables brightness control for OBJ and SUB layers, depending for OBJ on attr bits
+44: OSBRI_ON: not quite sure
+45: input enables. bits as follows: (MSB) S3 S2 S1 OB VD VC VB VA (LSB)
+
+
+K054338
+-------
+Color combiner engine. Designed for use with the 55555, but also found in games
+without one.
+
+Registers (word-wise):
+
+0: first 8 bits unknown, second 8 bits are the R component of the background color
+1: G and B components (8 bits each) of the background color
+2-4: shadow 1 R/G/B (16 bits per component. In shadow mode, determines a blend
+ value between total blackness and the original color. In highlight mode,
+ determines a blend value between total whiteness and the original color.
+ The hardware clamps at black or white as necessary: see the Graphics Test
+ in many System GX games).
+5-7: shadow 2 R/G/B
+8-10: shadow 3 R/G/B
+11-12: brightness R/G/B (external circuit such as the 55555 decides which layers
+ this applies to)
+13-14: alpha blend R/G/B (external circuit such as the 55555 decides which layers
+ this applies to)
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+/*
+ This recursive function doesn't use additional memory
+ (it could be easily converted into an iterative one).
+ It's called shuffle because it mimics the shuffling of a deck of cards.
+*/
+static void shuffle(UINT16 *buf,int len)
+{
+ int i;
+ UINT16 t;
+
+ if (len == 2) return;
+
+ if (len % 4) fatalerror("shuffle() - not modulo 4"); /* must not happen */
+
+ len /= 2;
+
+ for (i = 0;i < len/2;i++)
+ {
+ t = buf[len/2 + i];
+ buf[len/2 + i] = buf[len + i];
+ buf[len + i] = t;
+ }
+
+ shuffle(buf,len);
+ shuffle(buf + len,len);
+}
+
+
+/* helper function to join two 16-bit ROMs and form a 32-bit data stream */
+void konami_rom_deinterleave_2(int mem_region)
+{
+ shuffle((UINT16 *)memory_region(mem_region),memory_region_length(mem_region)/2);
+}
+
+/* hacked version of rom_deinterleave_2_half for Lethal Enforcers */
+void konami_rom_deinterleave_2_half(int mem_region)
+{
+ UINT8 *rgn = memory_region(mem_region);
+
+ shuffle((UINT16 *)rgn,memory_region_length(mem_region)/4);
+ shuffle((UINT16 *)(rgn+memory_region_length(mem_region)/2),memory_region_length(mem_region)/4);
+}
+
+/* helper function to join four 16-bit ROMs and form a 64-bit data stream */
+void konami_rom_deinterleave_4(int mem_region)
+{
+ konami_rom_deinterleave_2(mem_region);
+ konami_rom_deinterleave_2(mem_region);
+}
+
+
+
+
+
+
+/***************************************************************************/
+/* */
+/* 007121 */
+/* */
+/***************************************************************************/
+
+/*static*/ UINT8 K007121_ctrlram[MAX_K007121][8];
+/*static*/ int K007121_flipscreen[MAX_K007121];
+
+
+void K007121_ctrl_w(int chip,int offset,int data)
+{
+ switch (offset)
+ {
+ case 6:
+/* palette bank change */
+if ((K007121_ctrlram[chip][offset] & 0x30) != (data & 0x30))
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ break;
+ case 7:
+ K007121_flipscreen[chip] = data & 0x08;
+ break;
+ }
+
+ K007121_ctrlram[chip][offset] = data;
+}
+
+WRITE8_HANDLER( K007121_ctrl_0_w )
+{
+ K007121_ctrl_w(0,offset,data);
+}
+
+WRITE8_HANDLER( K007121_ctrl_1_w )
+{
+ K007121_ctrl_w(1,offset,data);
+}
+
+
+/*
+ * Sprite Format
+ * ------------------
+ *
+ * There are 0x40 sprites, each one using 5 bytes. However the number of
+ * sprites can be increased to 0x80 with a control register (Combat School
+ * sets it on and off during the game).
+ *
+ * Byte | Bit(s) | Use
+ * -----+-76543210-+----------------
+ * 0 | xxxxxxxx | sprite code
+ * 1 | xxxx---- | color
+ * 1 | ----xx-- | sprite code low 2 bits for 16x8/8x8 sprites
+ * 1 | ------xx | sprite code bank bits 1/0
+ * 2 | xxxxxxxx | y position
+ * 3 | xxxxxxxx | x position (low 8 bits)
+ * 4 | xx------ | sprite code bank bits 3/2
+ * 4 | --x----- | flip y
+ * 4 | ---x---- | flip x
+ * 4 | ----xxx- | sprite size 000=16x16 001=16x8 010=8x16 011=8x8 100=32x32
+ * 4 | -------x | x position (high bit)
+ *
+ * Flack Attack uses a different, "wider" layout with 32 bytes per sprite,
+ * mapped as follows, and the priority order is reversed. Maybe it is a
+ * compatibility mode with an older custom IC. It is not known how this
+ * alternate layout is selected.
+ *
+ * 0 -> e
+ * 1 -> f
+ * 2 -> 6
+ * 3 -> 4
+ * 4 -> 8
+ *
+ */
+
+void K007121_sprites_draw(running_machine *machine, int chip,mame_bitmap *bitmap,const rectangle *cliprect,
+ const UINT8 *source,int base_color,int global_x_offset,int bank_base,
+ UINT32 pri_mask)
+{
+ const gfx_element *gfx = machine->gfx[chip];
+ int flipscreen = K007121_flipscreen[chip];
+ int i,num,inc,offs[5],trans;
+ int is_flakatck = K007121_ctrlram[chip][0x06] & 0x04; /* WRONG!!!! */
+
+#if 0
+popmessage("%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
+ K007121_ctrlram[0][0x00],K007121_ctrlram[0][0x01],K007121_ctrlram[0][0x02],K007121_ctrlram[0][0x03],K007121_ctrlram[0][0x04],K007121_ctrlram[0][0x05],K007121_ctrlram[0][0x06],K007121_ctrlram[0][0x07],
+ K007121_ctrlram[1][0x00],K007121_ctrlram[1][0x01],K007121_ctrlram[1][0x02],K007121_ctrlram[1][0x03],K007121_ctrlram[1][0x04],K007121_ctrlram[1][0x05],K007121_ctrlram[1][0x06],K007121_ctrlram[1][0x07]);
+
+if (input_code_pressed(KEYCODE_D))
+{
+ FILE *fp;
+ fp=fopen(chip?"SPRITE1.DMP":"SPRITE0.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(source, 0x800, 1, fp);
+ popmessage("saved");
+ fclose(fp);
+ }
+}
+#endif
+
+ if (is_flakatck)
+ {
+ num = 0x40;
+ inc = -0x20;
+ source += 0x3f*0x20;
+ offs[0] = 0x0e;
+ offs[1] = 0x0f;
+ offs[2] = 0x06;
+ offs[3] = 0x04;
+ offs[4] = 0x08;
+ /* Flak Attack doesn't use a lookup PROM, it maps the color code directly */
+ /* to a palette entry */
+ trans = TRANSPARENCY_PEN;
+ }
+ else /* all others */
+ {
+ //num = (K007121_ctrlram[chip][0x03] & 0x40) ? 0x80 : 0x40; /* WRONG!!! (needed by combasc) */
+ num = 0x40; // Combasc writes 70 sprites to VRAM at peak but the chip only processes the first 64.
+
+ inc = 5;
+ offs[0] = 0x00;
+ offs[1] = 0x01;
+ offs[2] = 0x02;
+ offs[3] = 0x03;
+ offs[4] = 0x04;
+ trans = TRANSPARENCY_COLOR;
+ /* when using priority buffer, draw front to back */
+ if (pri_mask != -1)
+ {
+ source += (num-1)*inc;
+ inc = -inc;
+ }
+ }
+
+ for (i = 0;i < num;i++)
+ {
+ int number = source[offs[0]]; /* sprite number */
+ int sprite_bank = source[offs[1]] & 0x0f; /* sprite bank */
+ int sx = source[offs[3]]; /* vertical position */
+ int sy = source[offs[2]]; /* horizontal position */
+ int attr = source[offs[4]]; /* attributes */
+ int xflip = source[offs[4]] & 0x10; /* flip x */
+ int yflip = source[offs[4]] & 0x20; /* flip y */
+ int color = base_color + ((source[offs[1]] & 0xf0) >> 4);
+ int width,height;
+ static int x_offset[4] = {0x0,0x1,0x4,0x5};
+ static int y_offset[4] = {0x0,0x2,0x8,0xa};
+ int x,y, ex, ey;
+
+ if (attr & 0x01) sx -= 256;
+ if (sy >= 240) sy -= 256;
+
+ number += ((sprite_bank & 0x3) << 8) + ((attr & 0xc0) << 4);
+ number = number << 2;
+ number += (sprite_bank >> 2) & 3;
+
+ if (!is_flakatck || source[0x00]) /* Flak Attack needs this */
+ {
+ number += bank_base;
+
+ switch( attr&0xe )
+ {
+ case 0x06: width = height = 1; break;
+ case 0x04: width = 1; height = 2; number &= (~2); break;
+ case 0x02: width = 2; height = 1; number &= (~1); break;
+ case 0x00: width = height = 2; number &= (~3); break;
+ case 0x08: width = height = 4; number &= (~3); break;
+ default: width = 1; height = 1;
+// logerror("Unknown sprite size %02x\n",attr&0xe);
+// popmessage("Unknown sprite size %02x\n",attr&0xe);
+ }
+
+ for (y = 0;y < height;y++)
+ {
+ for (x = 0;x < width;x++)
+ {
+ ex = xflip ? (width-1-x) : x;
+ ey = yflip ? (height-1-y) : y;
+
+ if (flipscreen)
+ {
+ if (pri_mask != -1)
+ pdrawgfx(bitmap,gfx,
+ number + x_offset[ex] + y_offset[ey],
+ color,
+ !xflip,!yflip,
+ 248-(sx+x*8),248-(sy+y*8),
+ cliprect,trans,0,
+ pri_mask);
+ else
+ drawgfx(bitmap,gfx,
+ number + x_offset[ex] + y_offset[ey],
+ color,
+ !xflip,!yflip,
+ 248-(sx+x*8),248-(sy+y*8),
+ cliprect,trans,0);
+ }
+ else
+ {
+ if (pri_mask != -1)
+ pdrawgfx(bitmap,gfx,
+ number + x_offset[ex] + y_offset[ey],
+ color,
+ xflip,yflip,
+ global_x_offset+sx+x*8,sy+y*8,
+ cliprect,trans,0,
+ pri_mask);
+ else
+ drawgfx(bitmap,gfx,
+ number + x_offset[ex] + y_offset[ey],
+ color,
+ xflip,yflip,
+ global_x_offset+sx+x*8,sy+y*8,
+ cliprect,trans,0);
+ }
+ }
+ }
+ }
+
+ source += inc;
+ }
+}
+
+
+
+/***************************************************************************/
+/* */
+/* 007342 */
+/* */
+/***************************************************************************/
+
+static UINT8 *K007342_ram,*K007342_scroll_ram;
+static int K007342_gfxnum;
+static int K007342_int_enabled;
+static int K007342_flipscreen;
+static int K007342_scrollx[2];
+static int K007342_scrolly[2];
+static UINT8 *K007342_videoram_0,*K007342_colorram_0;
+static UINT8 *K007342_videoram_1,*K007342_colorram_1;
+static int K007342_regs[8];
+static void (*K007342_callback)(int tmap, int bank, int *code, int *color, int *flags);
+static tilemap *K007342_tilemap[2];
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/*
+ data format:
+ video RAM xxxxxxxx tile number (bits 0-7)
+ color RAM x------- tiles with priority over the sprites
+ color RAM -x------ depends on external conections
+ color RAM --x----- flip Y
+ color RAM ---x---- flip X
+ color RAM ----xxxx depends on external connections (usually color and banking)
+*/
+
+static TILEMAP_MAPPER( K007342_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x20) << 5);
+}
+
+INLINE void K007342_get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int layer,UINT8 *cram,UINT8 *vram)
+{
+ int color, code, flags;
+
+ color = cram[tile_index];
+ code = vram[tile_index];
+ flags = TILE_FLIPYX((color & 0x30) >> 4);
+
+ tileinfo->category = (color & 0x80) >> 7;
+
+ (*K007342_callback)(layer, K007342_regs[1], &code, &color, &flags);
+
+ SET_TILE_INFO(
+ K007342_gfxnum,
+ code,
+ color,
+ flags);
+}
+
+static TILE_GET_INFO( K007342_get_tile_info0 ) { K007342_get_tile_info(machine,tileinfo,tile_index,0,K007342_colorram_0,K007342_videoram_0); }
+static TILE_GET_INFO( K007342_get_tile_info1 ) { K007342_get_tile_info(machine,tileinfo,tile_index,1,K007342_colorram_1,K007342_videoram_1); }
+
+
+
+void K007342_vh_start(int gfx_index, void (*callback)(int tmap, int bank, int *code, int *color, int *flags))
+{
+ K007342_gfxnum = gfx_index;
+ K007342_callback = callback;
+
+ K007342_tilemap[0] = tilemap_create(K007342_get_tile_info0,K007342_scan,TILEMAP_TYPE_PEN,8,8,64,32);
+ K007342_tilemap[1] = tilemap_create(K007342_get_tile_info1,K007342_scan,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ K007342_ram = auto_malloc(0x2000);
+ K007342_scroll_ram = auto_malloc(0x0200);
+
+ memset(K007342_ram,0,0x2000);
+
+ K007342_colorram_0 = &K007342_ram[0x0000];
+ K007342_colorram_1 = &K007342_ram[0x1000];
+ K007342_videoram_0 = &K007342_ram[0x0800];
+ K007342_videoram_1 = &K007342_ram[0x1800];
+
+ tilemap_set_transparent_pen(K007342_tilemap[0],0);
+ tilemap_set_transparent_pen(K007342_tilemap[1],0);
+}
+
+READ8_HANDLER( K007342_r )
+{
+ return K007342_ram[offset];
+}
+
+WRITE8_HANDLER( K007342_w )
+{
+ K007342_ram[offset] = data;
+ if (offset < 0x1000)
+ { /* layer 0 */
+ tilemap_mark_tile_dirty(K007342_tilemap[0],offset & 0x7ff);
+ }
+ else
+ { /* layer 1 */
+ tilemap_mark_tile_dirty(K007342_tilemap[1],offset & 0x7ff);
+ }
+}
+
+READ8_HANDLER( K007342_scroll_r )
+{
+ return K007342_scroll_ram[offset];
+}
+
+WRITE8_HANDLER( K007342_scroll_w )
+{
+ K007342_scroll_ram[offset] = data;
+}
+
+WRITE8_HANDLER( K007342_vreg_w )
+{
+ switch(offset)
+ {
+ case 0x00:
+ /* bit 1: INT control */
+ K007342_int_enabled = data & 0x02;
+ K007342_flipscreen = data & 0x10;
+ tilemap_set_flip(K007342_tilemap[0],K007342_flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ tilemap_set_flip(K007342_tilemap[1],K007342_flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ break;
+ case 0x01: /* used for banking in Rock'n'Rage */
+ if (data != K007342_regs[1])
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ case 0x02:
+ K007342_scrollx[0] = (K007342_scrollx[0] & 0xff) | ((data & 0x01) << 8);
+ K007342_scrollx[1] = (K007342_scrollx[1] & 0xff) | ((data & 0x02) << 7);
+ break;
+ case 0x03: /* scroll x (register 0) */
+ K007342_scrollx[0] = (K007342_scrollx[0] & 0x100) | data;
+ break;
+ case 0x04: /* scroll y (register 0) */
+ K007342_scrolly[0] = data;
+ break;
+ case 0x05: /* scroll x (register 1) */
+ K007342_scrollx[1] = (K007342_scrollx[1] & 0x100) | data;
+ break;
+ case 0x06: /* scroll y (register 1) */
+ K007342_scrolly[1] = data;
+ case 0x07: /* unused */
+ break;
+ }
+ K007342_regs[offset] = data;
+}
+
+void K007342_tilemap_update(void)
+{
+ int offs;
+
+
+ /* update scroll */
+ switch (K007342_regs[2] & 0x1c)
+ {
+ case 0x00:
+ case 0x08: /* unknown, blades of steel shootout between periods */
+ tilemap_set_scroll_rows(K007342_tilemap[0],1);
+ tilemap_set_scroll_cols(K007342_tilemap[0],1);
+ tilemap_set_scrollx(K007342_tilemap[0],0,K007342_scrollx[0]);
+ tilemap_set_scrolly(K007342_tilemap[0],0,K007342_scrolly[0]);
+ break;
+
+ case 0x0c: /* 32 columns */
+ tilemap_set_scroll_rows(K007342_tilemap[0],1);
+ tilemap_set_scroll_cols(K007342_tilemap[0],512);
+ tilemap_set_scrollx(K007342_tilemap[0],0,K007342_scrollx[0]);
+ for (offs = 0;offs < 256;offs++)
+ tilemap_set_scrolly(K007342_tilemap[0],(offs + K007342_scrollx[0]) & 0x1ff,
+ K007342_scroll_ram[2*(offs/8)] + 256 * K007342_scroll_ram[2*(offs/8)+1]);
+ break;
+
+ case 0x14: /* 256 rows */
+ tilemap_set_scroll_rows(K007342_tilemap[0],256);
+ tilemap_set_scroll_cols(K007342_tilemap[0],1);
+ tilemap_set_scrolly(K007342_tilemap[0],0,K007342_scrolly[0]);
+ for (offs = 0;offs < 256;offs++)
+ tilemap_set_scrollx(K007342_tilemap[0],(offs + K007342_scrolly[0]) & 0xff,
+ K007342_scroll_ram[2*offs] + 256 * K007342_scroll_ram[2*offs+1]);
+ break;
+
+ default:
+// popmessage("unknown scroll ctrl %02x",K007342_regs[2] & 0x1c);
+ break;
+ }
+
+ tilemap_set_scrollx(K007342_tilemap[1],0,K007342_scrollx[1]);
+ tilemap_set_scrolly(K007342_tilemap[1],0,K007342_scrolly[1]);
+
+#if 0
+ {
+ static int current_layer = 0;
+
+ if (input_code_pressed_once(KEYCODE_Z)) current_layer = !current_layer;
+ tilemap_set_enable(K007342_tilemap[current_layer], 1);
+ tilemap_set_enable(K007342_tilemap[!current_layer], 0);
+
+ popmessage("regs:%02x %02x %02x %02x-%02x %02x %02x %02x:%02x",
+ K007342_regs[0], K007342_regs[1], K007342_regs[2], K007342_regs[3],
+ K007342_regs[4], K007342_regs[5], K007342_regs[6], K007342_regs[7],
+ current_layer);
+ }
+#endif
+}
+
+void K007342_tilemap_set_enable(int tmap, int enable)
+{
+ tilemap_set_enable(K007342_tilemap[tmap], enable);
+}
+
+void K007342_tilemap_draw(mame_bitmap *bitmap,const rectangle *cliprect,int num,int flags,UINT32 priority)
+{
+ tilemap_draw(bitmap,cliprect,K007342_tilemap[num],flags,priority);
+}
+
+int K007342_is_INT_enabled(void)
+{
+ return K007342_int_enabled;
+}
+
+
+
+/***************************************************************************/
+/* */
+/* 007420 */
+/* */
+/***************************************************************************/
+
+static gfx_element *K007420_gfx;
+static void (*K007420_callback)(int *code,int *color);
+static UINT8 *K007420_ram;
+static int K007420_banklimit;
+
+void K007420_vh_start(running_machine *machine, int gfxnum, void (*callback)(int *code,int *color))
+{
+ K007420_gfx = machine->gfx[gfxnum];
+ K007420_callback = callback;
+ K007420_ram = auto_malloc(0x200);
+
+ memset(K007420_ram,0,0x200);
+
+ K007420_banklimit = -1;
+}
+
+READ8_HANDLER( K007420_r )
+{
+ return K007420_ram[offset];
+}
+
+WRITE8_HANDLER( K007420_w )
+{
+ K007420_ram[offset] = data;
+}
+
+/*
+ * Sprite Format
+ * ------------------
+ *
+ * Byte | Bit(s) | Use
+ * -----+-76543210-+----------------
+ * 0 | xxxxxxxx | y position
+ * 1 | xxxxxxxx | sprite code (low 8 bits)
+ * 2 | xxxxxxxx | depends on external conections. Usually banking
+ * 3 | xxxxxxxx | x position (low 8 bits)
+ * 4 | x------- | x position (high bit)
+ * 4 | -xxx---- | sprite size 000=16x16 001=8x16 010=16x8 011=8x8 100=32x32
+ * 4 | ----x--- | flip y
+ * 4 | -----x-- | flip x
+ * 4 | ------xx | zoom (bits 8 & 9)
+ * 5 | xxxxxxxx | zoom (low 8 bits) 0x080 = normal, < 0x80 enlarge, > 0x80 reduce
+ * 6 | xxxxxxxx | unused
+ * 7 | xxxxxxxx | unused
+ */
+
+void K007420_sprites_draw(mame_bitmap *bitmap,const rectangle *cliprect)
+{
+#define K007420_SPRITERAM_SIZE 0x200
+ int offs;
+ int codemask = K007420_banklimit;
+ int bankmask = ~K007420_banklimit;
+
+ for (offs = K007420_SPRITERAM_SIZE - 8; offs >= 0; offs -= 8)
+ {
+ int ox,oy,code,color,flipx,flipy,zoom,w,h,x,y,bank;
+ static int xoffset[4] = { 0, 1, 4, 5 };
+ static int yoffset[4] = { 0, 2, 8, 10 };
+
+ code = K007420_ram[offs+1];
+ color = K007420_ram[offs+2];
+ ox = K007420_ram[offs+3] - ((K007420_ram[offs+4] & 0x80) << 1);
+ oy = 256 - K007420_ram[offs+0];
+ flipx = K007420_ram[offs+4] & 0x04;
+ flipy = K007420_ram[offs+4] & 0x08;
+
+ (*K007420_callback)(&code,&color);
+
+ bank = code & bankmask;
+ code &= codemask;
+
+ /* 0x080 = normal scale, 0x040 = double size, 0x100 half size */
+ zoom = K007420_ram[offs+5] | ((K007420_ram[offs+4] & 0x03) << 8);
+ if (!zoom) continue;
+ zoom = 0x10000 * 128 / zoom;
+
+ switch (K007420_ram[offs+4] & 0x70)
+ {
+ case 0x30: w = h = 1; break;
+ case 0x20: w = 2; h = 1; code &= (~1); break;
+ case 0x10: w = 1; h = 2; code &= (~2); break;
+ case 0x00: w = h = 2; code &= (~3); break;
+ case 0x40: w = h = 4; code &= (~3); break;
+ default: w = 1; h = 1;
+//logerror("Unknown sprite size %02x\n",(K007420_ram[offs+4] & 0x70)>>4);
+ }
+
+ if (K007342_flipscreen)
+ {
+ ox = 256 - ox - ((zoom * w + (1<<12)) >> 13);
+ oy = 256 - oy - ((zoom * h + (1<<12)) >> 13);
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if (zoom == 0x10000)
+ {
+ int sx,sy;
+
+ for (y = 0;y < h;y++)
+ {
+ sy = oy + 8 * y;
+
+ for (x = 0;x < w;x++)
+ {
+ int c = code;
+
+ sx = ox + 8 * x;
+ if (flipx) c += xoffset[(w-1-x)];
+ else c += xoffset[x];
+ if (flipy) c += yoffset[(h-1-y)];
+ else c += yoffset[y];
+
+ if (c & bankmask) continue; else c += bank;
+
+ drawgfx(bitmap,K007420_gfx,
+ c,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ if (K007342_regs[2] & 0x80)
+ drawgfx(bitmap,K007420_gfx,
+ c,
+ color,
+ flipx,flipy,
+ sx,sy-256,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+ else
+ {
+ int sx,sy,zw,zh;
+ for (y = 0;y < h;y++)
+ {
+ sy = oy + ((zoom * y + (1<<12)) >> 13);
+ zh = (oy + ((zoom * (y+1) + (1<<12)) >> 13)) - sy;
+
+ for (x = 0;x < w;x++)
+ {
+ int c = code;
+
+ sx = ox + ((zoom * x + (1<<12)) >> 13);
+ zw = (ox + ((zoom * (x+1) + (1<<12)) >> 13)) - sx;
+ if (flipx) c += xoffset[(w-1-x)];
+ else c += xoffset[x];
+ if (flipy) c += yoffset[(h-1-y)];
+ else c += yoffset[y];
+
+ if (c & bankmask) continue; else c += bank;
+
+ drawgfxzoom(bitmap,K007420_gfx,
+ c,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0,
+ (zw << 16) / 8,(zh << 16) / 8);
+
+ if (K007342_regs[2] & 0x80)
+ drawgfxzoom(bitmap,K007420_gfx,
+ c,
+ color,
+ flipx,flipy,
+ sx,sy-256,
+ cliprect,TRANSPARENCY_PEN,0,
+ (zw << 16) / 8,(zh << 16) / 8);
+ }
+ }
+ }
+ }
+#if 0
+ {
+ static int current_sprite = 0;
+
+ if (input_code_pressed_once(KEYCODE_Z)) current_sprite = (current_sprite+1) & ((K007420_SPRITERAM_SIZE/8)-1);
+ if (input_code_pressed_once(KEYCODE_X)) current_sprite = (current_sprite-1) & ((K007420_SPRITERAM_SIZE/8)-1);
+
+ popmessage("%02x:%02x %02x %02x %02x %02x %02x %02x %02x", current_sprite,
+ K007420_ram[(current_sprite*8)+0], K007420_ram[(current_sprite*8)+1],
+ K007420_ram[(current_sprite*8)+2], K007420_ram[(current_sprite*8)+3],
+ K007420_ram[(current_sprite*8)+4], K007420_ram[(current_sprite*8)+5],
+ K007420_ram[(current_sprite*8)+6], K007420_ram[(current_sprite*8)+7]);
+ }
+#endif
+}
+
+void K007420_set_banklimit(int limit)
+{
+ K007420_banklimit = limit;
+}
+
+
+
+/***************************************************************************/
+/* */
+/* 052109 */
+/* */
+/***************************************************************************/
+
+static int K052109_memory_region;
+static int K052109_gfxnum;
+static void (*K052109_callback)(int tmap,int bank,int *code,int *color,int *flags,int *priority);
+static UINT8 *K052109_ram;
+static UINT8 *K052109_videoram_F,*K052109_videoram2_F,*K052109_colorram_F;
+static UINT8 *K052109_videoram_A,*K052109_videoram2_A,*K052109_colorram_A;
+static UINT8 *K052109_videoram_B,*K052109_videoram2_B,*K052109_colorram_B;
+static UINT8 K052109_charrombank[4];
+static UINT8 has_extra_video_ram;
+static INT32 K052109_RMRD_line;
+static int K052109_tileflip_enable;
+static UINT8 K052109_irq_enabled;
+static INT32 K052109_dx[3], K052109_dy[3];
+static UINT8 K052109_romsubbank,K052109_scrollctrl;
+tilemap *K052109_tilemap[3];
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/*
+ data format:
+ video RAM xxxxxxxx tile number (low 8 bits)
+ color RAM xxxx---- depends on external connections (usually color and banking)
+ color RAM ----xx-- bank select (0-3): these bits are replaced with the 2
+ bottom bits of the bank register before being placed on
+ the output pins. The other two bits of the bank register are
+ placed on the CAB1 and CAB2 output pins.
+ color RAM ------xx depends on external connections (usually banking, flip)
+*/
+
+INLINE void K052109_get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int layer,UINT8 *cram,UINT8 *vram1,UINT8 *vram2)
+{
+ int flipy = 0;
+ int code = vram1[tile_index] + 256 * vram2[tile_index];
+ int color = cram[tile_index];
+ int flags = 0;
+ int priority = 0;
+ int bank = K052109_charrombank[(color & 0x0c) >> 2];
+if (has_extra_video_ram) bank = (color & 0x0c) >> 2; /* kludge for X-Men */
+ color = (color & 0xf3) | ((bank & 0x03) << 2);
+ bank >>= 2;
+
+ flipy = color & 0x02;
+
+ (*K052109_callback)(layer,bank,&code,&color,&flags,&priority);
+
+ /* if the callback set flip X but it is not enabled, turn it off */
+ if (!(K052109_tileflip_enable & 1)) flags &= ~TILE_FLIPX;
+
+ /* if flip Y is enabled and the attribute but is set, turn it on */
+ if (flipy && (K052109_tileflip_enable & 2)) flags |= TILE_FLIPY;
+
+ SET_TILE_INFO(
+ K052109_gfxnum,
+ code,
+ color,
+ flags);
+
+ tileinfo->category = priority;
+}
+
+static TILE_GET_INFO( K052109_get_tile_info0 ) { K052109_get_tile_info(machine,tileinfo,tile_index,0,K052109_colorram_F,K052109_videoram_F,K052109_videoram2_F); }
+static TILE_GET_INFO( K052109_get_tile_info1 ) { K052109_get_tile_info(machine,tileinfo,tile_index,1,K052109_colorram_A,K052109_videoram_A,K052109_videoram2_A); }
+static TILE_GET_INFO( K052109_get_tile_info2 ) { K052109_get_tile_info(machine,tileinfo,tile_index,2,K052109_colorram_B,K052109_videoram_B,K052109_videoram2_B); }
+
+
+static void K052109_tileflip_reset(void)
+{
+ int data = K052109_ram[0x1e80];
+ tilemap_set_flip(K052109_tilemap[0],(data & 1) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ tilemap_set_flip(K052109_tilemap[1],(data & 1) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ tilemap_set_flip(K052109_tilemap[2],(data & 1) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ K052109_tileflip_enable = ((data & 0x06) >> 1);
+}
+
+
+void K052109_vh_start(running_machine *machine,int gfx_memory_region,int plane0,int plane1,int plane2,int plane3,
+ void (*callback)(int tmap,int bank,int *code,int *color,int *flags,int *priority))
+{
+ int gfx_index, i;
+ static gfx_layout charlayout =
+ {
+ 8,8,
+ 0, /* filled in later */
+ 4,
+ { 0, 0, 0, 0 }, /* filled in later */
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 },
+ 32*8
+ };
+
+
+ /* find first empty slot to decode gfx */
+ for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
+ if (machine->gfx[gfx_index] == 0)
+ break;
+ assert(gfx_index != MAX_GFX_ELEMENTS);
+
+ /* tweak the structure for the number of tiles we have */
+ charlayout.total = memory_region_length(gfx_memory_region) / 32;
+ charlayout.planeoffset[0] = plane3 * 8;
+ charlayout.planeoffset[1] = plane2 * 8;
+ charlayout.planeoffset[2] = plane1 * 8;
+ charlayout.planeoffset[3] = plane0 * 8;
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&charlayout);
+ decodegfx(machine->gfx[gfx_index], memory_region(gfx_memory_region), 0, machine->gfx[gfx_index]->total_elements);
+
+ /* set the color information */
+ if (machine->drv->color_table_len)
+ machine->gfx[gfx_index]->total_colors = machine->drv->color_table_len / 16;
+ else
+ machine->gfx[gfx_index]->total_colors = machine->drv->total_colors / 16;
+
+ K052109_memory_region = gfx_memory_region;
+ K052109_gfxnum = gfx_index;
+ K052109_callback = callback;
+ K052109_RMRD_line = CLEAR_LINE;
+ K052109_irq_enabled = 0;
+
+ has_extra_video_ram = 0;
+
+ K052109_tilemap[0] = tilemap_create(K052109_get_tile_info0,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ K052109_tilemap[1] = tilemap_create(K052109_get_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ K052109_tilemap[2] = tilemap_create(K052109_get_tile_info2,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ K052109_ram = auto_malloc(0x6000);
+
+ memset(K052109_ram,0,0x6000);
+
+ K052109_colorram_F = &K052109_ram[0x0000];
+ K052109_colorram_A = &K052109_ram[0x0800];
+ K052109_colorram_B = &K052109_ram[0x1000];
+ K052109_videoram_F = &K052109_ram[0x2000];
+ K052109_videoram_A = &K052109_ram[0x2800];
+ K052109_videoram_B = &K052109_ram[0x3000];
+ K052109_videoram2_F = &K052109_ram[0x4000];
+ K052109_videoram2_A = &K052109_ram[0x4800];
+ K052109_videoram2_B = &K052109_ram[0x5000];
+
+ tilemap_set_transparent_pen(K052109_tilemap[0],0);
+ tilemap_set_transparent_pen(K052109_tilemap[1],0);
+ tilemap_set_transparent_pen(K052109_tilemap[2],0);
+
+ for (i = 0; i < 3; i++)
+ {
+ K052109_dx[i] = K052109_dy[i] = 0;
+ }
+
+ state_save_register_global_pointer(K052109_ram, 0x6000);
+ state_save_register_global(K052109_RMRD_line);
+ state_save_register_global(K052109_romsubbank);
+ state_save_register_global(K052109_scrollctrl);
+ state_save_register_global(K052109_irq_enabled);
+ state_save_register_global_array(K052109_charrombank);
+ state_save_register_global_array(K052109_dx);
+ state_save_register_global_array(K052109_dy);
+ state_save_register_global(has_extra_video_ram);
+
+ state_save_register_func_postload(K052109_tileflip_reset);
+}
+
+
+
+READ8_HANDLER( K052109_r )
+{
+ if (K052109_RMRD_line == CLEAR_LINE)
+ {
+ if ((offset & 0x1fff) >= 0x1800)
+ {
+ if (offset >= 0x180c && offset < 0x1834)
+ { /* A y scroll */ }
+ else if (offset >= 0x1a00 && offset < 0x1c00)
+ { /* A x scroll */ }
+ else if (offset == 0x1d00)
+ { /* read for bitwise operations before writing */ }
+ else if (offset >= 0x380c && offset < 0x3834)
+ { /* B y scroll */ }
+ else if (offset >= 0x3a00 && offset < 0x3c00)
+ { /* B x scroll */ }
+// else
+//logerror("%04x: read from unknown 052109 address %04x\n",activecpu_get_pc(),offset);
+ }
+
+ return K052109_ram[offset];
+ }
+ else /* Punk Shot and TMNT read from 0000-1fff, Aliens from 2000-3fff */
+ {
+ int code = (offset & 0x1fff) >> 5;
+ int color = K052109_romsubbank;
+ int flags = 0;
+ int priority = 0;
+ int bank = K052109_charrombank[(color & 0x0c) >> 2] >> 2; /* discard low bits (TMNT) */
+ int addr;
+
+if (has_extra_video_ram) code |= color << 8; /* kludge for X-Men */
+else
+ (*K052109_callback)(0,bank,&code,&color,&flags,&priority);
+
+ addr = (code << 5) + (offset & 0x1f);
+ addr &= memory_region_length(K052109_memory_region)-1;
+
+// popmessage("%04x: off%04x sub%02x (bnk%x) adr%06x",activecpu_get_pc(),offset,K052109_romsubbank,bank,addr);
+
+ return memory_region(K052109_memory_region)[addr];
+ }
+}
+
+WRITE8_HANDLER( K052109_w )
+{
+ if ((offset & 0x1fff) < 0x1800) /* tilemap RAM */
+ {
+ if (offset >= 0x4000) has_extra_video_ram = 1; /* kludge for X-Men */
+ K052109_ram[offset] = data;
+ tilemap_mark_tile_dirty(K052109_tilemap[(offset & 0x1800) >> 11],offset & 0x7ff);
+ }
+ else /* control registers */
+ {
+ K052109_ram[offset] = data;
+
+ if (offset >= 0x180c && offset < 0x1834)
+ { /* A y scroll */ }
+ else if (offset >= 0x1a00 && offset < 0x1c00)
+ { /* A x scroll */ }
+ else if (offset == 0x1c80)
+ {
+ if (K052109_scrollctrl != data)
+ {
+//popmessage("scrollcontrol = %02x",data);
+//logerror("%04x: rowscrollcontrol = %02x\n",activecpu_get_pc(),data);
+ K052109_scrollctrl = data;
+ }
+ }
+ else if (offset == 0x1d00)
+ {
+//logerror("%04x: 052109 register 1d00 = %02x\n",activecpu_get_pc(),data);
+ /* bit 2 = irq enable */
+ /* the custom chip can also generate NMI and FIRQ, for use with a 6809 */
+ K052109_irq_enabled = data & 0x04;
+ }
+ else if (offset == 0x1d80)
+ {
+ int dirty = 0;
+
+ if (K052109_charrombank[0] != (data & 0x0f)) dirty |= 1;
+ if (K052109_charrombank[1] != ((data >> 4) & 0x0f)) dirty |= 2;
+ if (dirty)
+ {
+ int i;
+
+ K052109_charrombank[0] = data & 0x0f;
+ K052109_charrombank[1] = (data >> 4) & 0x0f;
+
+ for (i = 0;i < 0x1800;i++)
+ {
+ int bank = (K052109_ram[i]&0x0c) >> 2;
+ if ((bank == 0 && (dirty & 1)) || (bank == 1 && dirty & 2))
+ {
+ tilemap_mark_tile_dirty(K052109_tilemap[(i & 0x1800) >> 11],i & 0x7ff);
+ }
+ }
+ }
+ }
+ else if (offset == 0x1e00)
+ {
+//logerror("%04x: 052109 register 1e00 = %02x\n",activecpu_get_pc(),data);
+ K052109_romsubbank = data;
+ }
+ else if (offset == 0x1e80)
+ {
+//if ((data & 0xfe)) logerror("%04x: 052109 register 1e80 = %02x\n",activecpu_get_pc(),data);
+ tilemap_set_flip(K052109_tilemap[0],(data & 1) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ tilemap_set_flip(K052109_tilemap[1],(data & 1) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ tilemap_set_flip(K052109_tilemap[2],(data & 1) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ if (K052109_tileflip_enable != ((data & 0x06) >> 1))
+ {
+ K052109_tileflip_enable = ((data & 0x06) >> 1);
+
+ tilemap_mark_all_tiles_dirty(K052109_tilemap[0]);
+ tilemap_mark_all_tiles_dirty(K052109_tilemap[1]);
+ tilemap_mark_all_tiles_dirty(K052109_tilemap[2]);
+ }
+ }
+ else if (offset == 0x1f00)
+ {
+ int dirty = 0;
+
+ if (K052109_charrombank[2] != (data & 0x0f)) dirty |= 1;
+ if (K052109_charrombank[3] != ((data >> 4) & 0x0f)) dirty |= 2;
+ if (dirty)
+ {
+ int i;
+
+ K052109_charrombank[2] = data & 0x0f;
+ K052109_charrombank[3] = (data >> 4) & 0x0f;
+
+ for (i = 0;i < 0x1800;i++)
+ {
+ int bank = (K052109_ram[i] & 0x0c) >> 2;
+ if ((bank == 2 && (dirty & 1)) || (bank == 3 && dirty & 2))
+ tilemap_mark_tile_dirty(K052109_tilemap[(i & 0x1800) >> 11],i & 0x7ff);
+ }
+ }
+ }
+ else if (offset >= 0x380c && offset < 0x3834)
+ { /* B y scroll */ }
+ else if (offset >= 0x3a00 && offset < 0x3c00)
+ { /* B x scroll */ }
+// else
+//logerror("%04x: write %02x to unknown 052109 address %04x\n",activecpu_get_pc(),data,offset);
+ }
+}
+
+READ16_HANDLER( K052109_word_r )
+{
+ return K052109_r(offset + 0x2000) | (K052109_r(offset) << 8);
+}
+
+WRITE16_HANDLER( K052109_word_w )
+{
+ if (ACCESSING_MSB)
+ K052109_w(offset,(data >> 8) & 0xff);
+ if (ACCESSING_LSB)
+ K052109_w(offset + 0x2000,data & 0xff);
+}
+
+READ16_HANDLER(K052109_lsb_r)
+{
+ return K052109_r(offset);
+}
+
+WRITE16_HANDLER(K052109_lsb_w)
+{
+ if(ACCESSING_LSB)
+ K052109_w(offset, data & 0xff);
+}
+
+void K052109_set_RMRD_line(int state)
+{
+ K052109_RMRD_line = state;
+}
+
+
+void K052109_tilemap_update(void)
+{
+#if 0
+{
+popmessage("%x %x %x %x",
+ K052109_charrombank[0],
+ K052109_charrombank[1],
+ K052109_charrombank[2],
+ K052109_charrombank[3]);
+}
+#endif
+ if ((K052109_scrollctrl & 0x03) == 0x02)
+ {
+ int xscroll,yscroll,offs;
+ UINT8 *scrollram = &K052109_ram[0x1a00];
+
+
+ tilemap_set_scroll_rows(K052109_tilemap[1],256);
+ tilemap_set_scroll_cols(K052109_tilemap[1],1);
+ yscroll = K052109_ram[0x180c];
+ tilemap_set_scrolly(K052109_tilemap[1],0,yscroll+K052109_dy[1]);
+ for (offs = 0;offs < 256;offs++)
+ {
+ xscroll = scrollram[2*(offs&0xfff8)+0] + 256 * scrollram[2*(offs&0xfff8)+1];
+ xscroll -= 6;
+ tilemap_set_scrollx(K052109_tilemap[1],(offs+yscroll)&0xff,xscroll+K052109_dx[1]);
+ }
+ }
+ else if ((K052109_scrollctrl & 0x03) == 0x03)
+ {
+ int xscroll,yscroll,offs;
+ UINT8 *scrollram = &K052109_ram[0x1a00];
+
+
+ tilemap_set_scroll_rows(K052109_tilemap[1],256);
+ tilemap_set_scroll_cols(K052109_tilemap[1],1);
+ yscroll = K052109_ram[0x180c];
+ tilemap_set_scrolly(K052109_tilemap[1],0,yscroll+K052109_dy[1]);
+ for (offs = 0;offs < 256;offs++)
+ {
+ xscroll = scrollram[2*offs+0] + 256 * scrollram[2*offs+1];
+ xscroll -= 6;
+ tilemap_set_scrollx(K052109_tilemap[1],(offs+yscroll)&0xff,xscroll+K052109_dx[1]);
+ }
+ }
+ else if ((K052109_scrollctrl & 0x04) == 0x04)
+ {
+ int xscroll,yscroll,offs;
+ UINT8 *scrollram = &K052109_ram[0x1800];
+
+
+ tilemap_set_scroll_rows(K052109_tilemap[1],1);
+ tilemap_set_scroll_cols(K052109_tilemap[1],512);
+ xscroll = K052109_ram[0x1a00] + 256 * K052109_ram[0x1a01];
+ xscroll -= 6;
+ tilemap_set_scrollx(K052109_tilemap[1],0,xscroll+K052109_dx[1]);
+ for (offs = 0;offs < 512;offs++)
+ {
+ yscroll = scrollram[offs/8];
+ tilemap_set_scrolly(K052109_tilemap[1],(offs+xscroll)&0x1ff,yscroll+K052109_dy[1]);
+ }
+ }
+ else
+ {
+ int xscroll,yscroll;
+ UINT8 *scrollram = &K052109_ram[0x1a00];
+
+
+ tilemap_set_scroll_rows(K052109_tilemap[1],1);
+ tilemap_set_scroll_cols(K052109_tilemap[1],1);
+ xscroll = scrollram[0] + 256 * scrollram[1];
+ xscroll -= 6;
+ yscroll = K052109_ram[0x180c];
+ tilemap_set_scrollx(K052109_tilemap[1],0,xscroll+K052109_dx[1]);
+ tilemap_set_scrolly(K052109_tilemap[1],0,yscroll+K052109_dy[1]);
+ }
+
+ if ((K052109_scrollctrl & 0x18) == 0x10)
+ {
+ int xscroll,yscroll,offs;
+ UINT8 *scrollram = &K052109_ram[0x3a00];
+
+
+ tilemap_set_scroll_rows(K052109_tilemap[2],256);
+ tilemap_set_scroll_cols(K052109_tilemap[2],1);
+ yscroll = K052109_ram[0x380c];
+ tilemap_set_scrolly(K052109_tilemap[2],0,yscroll+K052109_dy[2]);
+ for (offs = 0;offs < 256;offs++)
+ {
+ xscroll = scrollram[2*(offs&0xfff8)+0] + 256 * scrollram[2*(offs&0xfff8)+1];
+ xscroll -= 6;
+ tilemap_set_scrollx(K052109_tilemap[2],(offs+yscroll)&0xff,xscroll+K052109_dx[2]);
+ }
+ }
+ else if ((K052109_scrollctrl & 0x18) == 0x18)
+ {
+ int xscroll,yscroll,offs;
+ UINT8 *scrollram = &K052109_ram[0x3a00];
+
+
+ tilemap_set_scroll_rows(K052109_tilemap[2],256);
+ tilemap_set_scroll_cols(K052109_tilemap[2],1);
+ yscroll = K052109_ram[0x380c];
+ tilemap_set_scrolly(K052109_tilemap[2],0,yscroll+K052109_dy[2]);
+ for (offs = 0;offs < 256;offs++)
+ {
+ xscroll = scrollram[2*offs+0] + 256 * scrollram[2*offs+1];
+ xscroll -= 6;
+ tilemap_set_scrollx(K052109_tilemap[2],(offs+yscroll)&0xff,xscroll+K052109_dx[2]);
+ }
+ }
+ else if ((K052109_scrollctrl & 0x20) == 0x20)
+ {
+ int xscroll,yscroll,offs;
+ UINT8 *scrollram = &K052109_ram[0x3800];
+
+
+ tilemap_set_scroll_rows(K052109_tilemap[2],1);
+ tilemap_set_scroll_cols(K052109_tilemap[2],512);
+ xscroll = K052109_ram[0x3a00] + 256 * K052109_ram[0x3a01];
+ xscroll -= 6;
+ tilemap_set_scrollx(K052109_tilemap[2],0,xscroll+K052109_dx[2]);
+ for (offs = 0;offs < 512;offs++)
+ {
+ yscroll = scrollram[offs/8];
+ tilemap_set_scrolly(K052109_tilemap[2],(offs+xscroll)&0x1ff,yscroll+K052109_dy[2]);
+ }
+ }
+ else
+ {
+ int xscroll,yscroll;
+ UINT8 *scrollram = &K052109_ram[0x3a00];
+
+
+ tilemap_set_scroll_rows(K052109_tilemap[2],1);
+ tilemap_set_scroll_cols(K052109_tilemap[2],1);
+ xscroll = scrollram[0] + 256 * scrollram[1];
+ xscroll -= 6;
+ yscroll = K052109_ram[0x380c];
+ tilemap_set_scrollx(K052109_tilemap[2],0,xscroll+K052109_dx[2]);
+ tilemap_set_scrolly(K052109_tilemap[2],0,yscroll+K052109_dy[2]);
+ }
+
+#if 0
+if ((K052109_scrollctrl & 0x03) == 0x01 ||
+ (K052109_scrollctrl & 0x18) == 0x08 ||
+ ((K052109_scrollctrl & 0x04) && (K052109_scrollctrl & 0x03)) ||
+ ((K052109_scrollctrl & 0x20) && (K052109_scrollctrl & 0x18)) ||
+ (K052109_scrollctrl & 0xc0) != 0)
+ popmessage("scrollcontrol = %02x",K052109_scrollctrl);
+
+if (input_code_pressed(KEYCODE_F))
+{
+ FILE *fp;
+ fp=fopen("TILE.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(K052109_ram, 0x6000, 1, fp);
+ popmessage("saved");
+ fclose(fp);
+ }
+}
+#endif
+}
+
+int K052109_is_IRQ_enabled(void)
+{
+ return K052109_irq_enabled;
+}
+
+void K052109_set_layer_offsets(int layer, int dx, int dy)
+{
+ K052109_dx[layer] = dx;
+ K052109_dy[layer] = dy;
+}
+
+
+/***************************************************************************/
+/* */
+/* 051960 */
+/* */
+/***************************************************************************/
+
+static int K051960_memory_region;
+static gfx_element *K051960_gfx;
+static void (*K051960_callback)(int *code,int *color,int *priority,int *shadow);
+static int K051960_romoffset;
+static int K051960_spriteflip,K051960_readroms;
+static UINT8 K051960_spriterombank[3];
+static UINT8 *K051960_ram;
+static int K051960_dx, K051960_dy;
+static int K051960_irq_enabled, K051960_nmi_enabled;
+
+
+void K051960_vh_start(running_machine *machine,int gfx_memory_region,int plane0,int plane1,int plane2,int plane3,
+ void (*callback)(int *code,int *color,int *priority,int *shadow))
+{
+ int gfx_index,i;
+ static gfx_layout spritelayout =
+ {
+ 16,16,
+ 0, /* filled in later */
+ 4,
+ { 0, 0, 0, 0 }, /* filled in later */
+ { 0, 1, 2, 3, 4, 5, 6, 7,
+ 8*32+0, 8*32+1, 8*32+2, 8*32+3, 8*32+4, 8*32+5, 8*32+6, 8*32+7 },
+ { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32,
+ 16*32, 17*32, 18*32, 19*32, 20*32, 21*32, 22*32, 23*32 },
+ 128*8
+ };
+
+
+ /* find first empty slot to decode gfx */
+ for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
+ if (machine->gfx[gfx_index] == 0)
+ break;
+
+ assert(gfx_index != MAX_GFX_ELEMENTS);
+
+ /* tweak the structure for the number of tiles we have */
+ spritelayout.total = memory_region_length(gfx_memory_region) / 128;
+ spritelayout.planeoffset[0] = plane0 * 8;
+ spritelayout.planeoffset[1] = plane1 * 8;
+ spritelayout.planeoffset[2] = plane2 * 8;
+ spritelayout.planeoffset[3] = plane3 * 8;
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&spritelayout);
+ decodegfx(machine->gfx[gfx_index], memory_region(gfx_memory_region), 0, machine->gfx[gfx_index]->total_elements);
+
+ /* set the color information */
+ if (machine->drv->color_table_len)
+ machine->gfx[gfx_index]->total_colors = machine->drv->color_table_len / 16;
+ else
+ machine->gfx[gfx_index]->total_colors = machine->drv->total_colors / 16;
+
+#if VERBOSE
+ if (!(machine->drv->video_attributes & VIDEO_HAS_SHADOWS))
+ popmessage("driver should use VIDEO_HAS_SHADOWS");
+#endif
+
+ /* prepare shadow draw table */
+ gfx_drawmode_table[0] = DRAWMODE_NONE;
+ for (i = 1;i < 15;i++)
+ gfx_drawmode_table[i] = DRAWMODE_SOURCE;
+ gfx_drawmode_table[15] = DRAWMODE_SHADOW;
+
+ K051960_dx = K051960_dy = 0;
+
+ K051960_memory_region = gfx_memory_region;
+ K051960_gfx = machine->gfx[gfx_index];
+ K051960_callback = callback;
+ K051960_ram = auto_malloc(0x400);
+ memset(K051960_ram,0,0x400);
+}
+
+
+static int K051960_fetchromdata(int byte)
+{
+ int code,color,pri,shadow,off1,addr;
+
+
+ addr = K051960_romoffset + (K051960_spriterombank[0] << 8) +
+ ((K051960_spriterombank[1] & 0x03) << 16);
+ code = (addr & 0x3ffe0) >> 5;
+ off1 = addr & 0x1f;
+ color = ((K051960_spriterombank[1] & 0xfc) >> 2) + ((K051960_spriterombank[2] & 0x03) << 6);
+ pri = 0;
+ shadow = color & 0x80;
+ (*K051960_callback)(&code,&color,&pri,&shadow);
+
+ addr = (code << 7) | (off1 << 2) | byte;
+ addr &= memory_region_length(K051960_memory_region)-1;
+
+// popmessage("%04x: addr %06x",activecpu_get_pc(),addr);
+
+ return memory_region(K051960_memory_region)[addr];
+}
+
+READ8_HANDLER( K051960_r )
+{
+ if (K051960_readroms)
+ {
+ /* the 051960 remembers the last address read and uses it when reading the sprite ROMs */
+ K051960_romoffset = (offset & 0x3fc) >> 2;
+ return K051960_fetchromdata(offset & 3); /* only 88 Games reads the ROMs from here */
+ }
+ else
+ return K051960_ram[offset];
+}
+
+WRITE8_HANDLER( K051960_w )
+{
+ K051960_ram[offset] = data;
+}
+
+READ16_HANDLER( K051960_word_r )
+{
+ return K051960_r(offset*2 + 1) | (K051960_r(offset*2) << 8);
+}
+
+WRITE16_HANDLER( K051960_word_w )
+{
+ if (ACCESSING_MSB)
+ K051960_w(offset*2,(data >> 8) & 0xff);
+ if (ACCESSING_LSB)
+ K051960_w(offset*2 + 1,data & 0xff);
+}
+
+READ8_HANDLER( K051937_r )
+{
+ if (K051960_readroms && offset >= 4 && offset < 8)
+ {
+ return K051960_fetchromdata(offset & 3);
+ }
+ else
+ {
+ if (offset == 0)
+ {
+ static int counter;
+
+ /* some games need bit 0 to pulse */
+ return (counter++) & 1;
+ }
+//logerror("%04x: read unknown 051937 address %x\n",activecpu_get_pc(),offset);
+ return 0;
+ }
+}
+
+WRITE8_HANDLER( K051937_w )
+{
+ if (offset == 0)
+ {
+
+//if (data & 0xc2) popmessage("051937 reg 00 = %02x",data);
+
+ /* bit 0 is IRQ enable */
+ K051960_irq_enabled = (data & 0x01);
+
+ /* bit 1: probably FIRQ enable */
+
+ /* bit 2 is NMI enable */
+ K051960_nmi_enabled = (data & 0x04);
+
+ /* bit 3 = flip screen */
+ K051960_spriteflip = data & 0x08;
+
+ /* bit 4 used by Devastators and TMNT, unknown */
+
+ /* bit 5 = enable gfx ROM reading */
+ K051960_readroms = data & 0x20;
+//logerror("%04x: write %02x to 051937 address %x\n",activecpu_get_pc(),data,offset);
+ }
+ else if (offset == 1)
+ {
+// popmessage("%04x: write %02x to 051937 address %x",activecpu_get_pc(),data,offset);
+//logerror("%04x: write %02x to unknown 051937 address %x\n",activecpu_get_pc(),data,offset);
+ }
+ else if (offset >= 2 && offset < 5)
+ {
+ K051960_spriterombank[offset - 2] = data;
+ }
+ else
+ {
+// popmessage("%04x: write %02x to 051937 address %x",activecpu_get_pc(),data,offset);
+//logerror("%04x: write %02x to unknown 051937 address %x\n",activecpu_get_pc(),data,offset);
+ }
+}
+
+READ16_HANDLER( K051937_word_r )
+{
+ return K051937_r(offset*2 + 1) | (K051937_r(offset*2) << 8);
+}
+
+WRITE16_HANDLER( K051937_word_w )
+{
+ if (ACCESSING_MSB)
+ K051937_w(offset*2,(data >> 8) & 0xff);
+ if (ACCESSING_LSB)
+ K051937_w(offset*2 + 1,data & 0xff);
+}
+
+
+/*
+ * Sprite Format
+ * ------------------
+ *
+ * Byte | Bit(s) | Use
+ * -----+-76543210-+----------------
+ * 0 | x------- | active (show this sprite)
+ * 0 | -xxxxxxx | priority order
+ * 1 | xxx----- | sprite size (see below)
+ * 1 | ---xxxxx | sprite code (high 5 bits)
+ * 2 | xxxxxxxx | sprite code (low 8 bits)
+ * 3 | xxxxxxxx | "color", but depends on external connections (see below)
+ * 4 | xxxxxx-- | zoom y (0 = normal, >0 = shrink)
+ * 4 | ------x- | flip y
+ * 4 | -------x | y position (high bit)
+ * 5 | xxxxxxxx | y position (low 8 bits)
+ * 6 | xxxxxx-- | zoom x (0 = normal, >0 = shrink)
+ * 6 | ------x- | flip x
+ * 6 | -------x | x position (high bit)
+ * 7 | xxxxxxxx | x position (low 8 bits)
+ *
+ * Example of "color" field for Punk Shot:
+ * 3 | x------- | shadow
+ * 3 | -xx----- | priority
+ * 3 | ---x---- | use second gfx ROM bank
+ * 3 | ----xxxx | color code
+ *
+ * shadow enables transparent shadows. Note that it applies to pen 0x0f ONLY.
+ * The rest of the sprite remains normal.
+ * Note that Aliens also uses the shadow bit to select the second sprite bank.
+ */
+
+void K051960_sprites_draw(mame_bitmap *bitmap,const rectangle *cliprect,int min_priority,int max_priority)
+{
+#define NUM_SPRITES 128
+ int offs,pri_code;
+ int sortedlist[NUM_SPRITES];
+
+ for (offs = 0;offs < NUM_SPRITES;offs++)
+ sortedlist[offs] = -1;
+
+ /* prebuild a sorted table */
+ for (offs = 0;offs < 0x400;offs += 8)
+ {
+ if (K051960_ram[offs] & 0x80)
+ {
+ if (max_priority == -1) /* draw front to back when using priority buffer */
+ sortedlist[(K051960_ram[offs] & 0x7f) ^ 0x7f] = offs;
+ else
+ sortedlist[K051960_ram[offs] & 0x7f] = offs;
+ }
+ }
+
+ for (pri_code = 0;pri_code < NUM_SPRITES;pri_code++)
+ {
+ int ox,oy,code,color,pri,shadow,size,w,h,x,y,flipx,flipy,zoomx,zoomy;
+ /* sprites can be grouped up to 8x8. The draw order is
+ 0 1 4 5 16 17 20 21
+ 2 3 6 7 18 19 22 23
+ 8 9 12 13 24 25 28 29
+ 10 11 14 15 26 27 30 31
+ 32 33 36 37 48 49 52 53
+ 34 35 38 39 50 51 54 55
+ 40 41 44 45 56 57 60 61
+ 42 43 46 47 58 59 62 63
+ */
+ static int xoffset[8] = { 0, 1, 4, 5, 16, 17, 20, 21 };
+ static int yoffset[8] = { 0, 2, 8, 10, 32, 34, 40, 42 };
+ static int width[8] = { 1, 2, 1, 2, 4, 2, 4, 8 };
+ static int height[8] = { 1, 1, 2, 2, 2, 4, 4, 8 };
+
+
+ offs = sortedlist[pri_code];
+ if (offs == -1) continue;
+
+ code = K051960_ram[offs+2] + ((K051960_ram[offs+1] & 0x1f) << 8);
+ color = K051960_ram[offs+3] & 0xff;
+ pri = 0;
+ shadow = color & 0x80;
+ (*K051960_callback)(&code,&color,&pri,&shadow);
+
+ if (max_priority != -1)
+ if (pri < min_priority || pri > max_priority) continue;
+
+ size = (K051960_ram[offs+1] & 0xe0) >> 5;
+ w = width[size];
+ h = height[size];
+
+ if (w >= 2) code &= ~0x01;
+ if (h >= 2) code &= ~0x02;
+ if (w >= 4) code &= ~0x04;
+ if (h >= 4) code &= ~0x08;
+ if (w >= 8) code &= ~0x10;
+ if (h >= 8) code &= ~0x20;
+
+ ox = (256 * K051960_ram[offs+6] + K051960_ram[offs+7]) & 0x01ff;
+ oy = 256 - ((256 * K051960_ram[offs+4] + K051960_ram[offs+5]) & 0x01ff);
+ ox += K051960_dx;
+ oy += K051960_dy;
+ flipx = K051960_ram[offs+6] & 0x02;
+ flipy = K051960_ram[offs+4] & 0x02;
+ zoomx = (K051960_ram[offs+6] & 0xfc) >> 2;
+ zoomy = (K051960_ram[offs+4] & 0xfc) >> 2;
+ zoomx = 0x10000 / 128 * (128 - zoomx);
+ zoomy = 0x10000 / 128 * (128 - zoomy);
+
+ if (K051960_spriteflip)
+ {
+ ox = 512 - (zoomx * w >> 12) - ox;
+ oy = 256 - (zoomy * h >> 12) - oy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if (zoomx == 0x10000 && zoomy == 0x10000)
+ {
+ int sx,sy;
+
+ for (y = 0;y < h;y++)
+ {
+ sy = oy + 16 * y;
+
+ for (x = 0;x < w;x++)
+ {
+ int c = code;
+
+ sx = ox + 16 * x;
+ if (flipx) c += xoffset[(w-1-x)];
+ else c += xoffset[x];
+ if (flipy) c += yoffset[(h-1-y)];
+ else c += yoffset[y];
+
+ if (max_priority == -1)
+ pdrawgfx(bitmap,K051960_gfx,
+ c,
+ color,
+ flipx,flipy,
+ sx & 0x1ff,sy,
+ cliprect,shadow ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,0,pri);
+ else
+ drawgfx(bitmap,K051960_gfx,
+ c,
+ color,
+ flipx,flipy,
+ sx & 0x1ff,sy,
+ cliprect,shadow ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+ else
+ {
+ int sx,sy,zw,zh;
+
+ for (y = 0;y < h;y++)
+ {
+ sy = oy + ((zoomy * y + (1<<11)) >> 12);
+ zh = (oy + ((zoomy * (y+1) + (1<<11)) >> 12)) - sy;
+
+ for (x = 0;x < w;x++)
+ {
+ int c = code;
+
+ sx = ox + ((zoomx * x + (1<<11)) >> 12);
+ zw = (ox + ((zoomx * (x+1) + (1<<11)) >> 12)) - sx;
+ if (flipx) c += xoffset[(w-1-x)];
+ else c += xoffset[x];
+ if (flipy) c += yoffset[(h-1-y)];
+ else c += yoffset[y];
+
+ if (max_priority == -1)
+ pdrawgfxzoom(bitmap,K051960_gfx,
+ c,
+ color,
+ flipx,flipy,
+ sx & 0x1ff,sy,
+ cliprect,shadow ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,0,
+ (zw << 16) / 16,(zh << 16) / 16,pri);
+ else
+ drawgfxzoom(bitmap,K051960_gfx,
+ c,
+ color,
+ flipx,flipy,
+ sx & 0x1ff,sy,
+ cliprect,shadow ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,0,
+ (zw << 16) / 16,(zh << 16) / 16);
+ }
+ }
+ }
+ }
+#if 0
+if (input_code_pressed(KEYCODE_D))
+{
+ FILE *fp;
+ fp=fopen("SPRITE.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(K051960_ram, 0x400, 1, fp);
+ popmessage("saved");
+ fclose(fp);
+ }
+}
+#endif
+#undef NUM_SPRITES
+}
+
+int K051960_is_IRQ_enabled(void)
+{
+ return K051960_irq_enabled;
+}
+
+int K051960_is_NMI_enabled(void)
+{
+ return K051960_nmi_enabled;
+}
+
+void K051960_set_sprite_offsets(int dx, int dy)
+{
+ K051960_dx = dx;
+ K051960_dy = dy;
+}
+
+
+
+
+READ8_HANDLER( K052109_051960_r )
+{
+ if (K052109_RMRD_line == CLEAR_LINE)
+ {
+ if (offset >= 0x3800 && offset < 0x3808)
+ return K051937_r(offset - 0x3800);
+ else if (offset < 0x3c00)
+ return K052109_r(offset);
+ else
+ return K051960_r(offset - 0x3c00);
+ }
+ else return K052109_r(offset);
+}
+
+WRITE8_HANDLER( K052109_051960_w )
+{
+ if (offset >= 0x3800 && offset < 0x3808)
+ K051937_w(offset - 0x3800,data);
+ else if (offset < 0x3c00)
+ K052109_w(offset,data);
+ else
+ K051960_w(offset - 0x3c00,data);
+}
+
+
+
+/***************************************************************************/
+/* */
+/* 05324x Family Sprite Generators */
+/* */
+/***************************************************************************/
+
+static int K05324x_z_rejection = -1;
+
+/*
+ In a K053247+K055555 setup objects with Z-code 0x00 should be ignored
+ when PRFLIP is cleared, while objects with Z-code 0xff should be
+ ignored when PRFLIP is set.
+
+ These behaviors can also be seen in older K053245(6)+K053251 setups.
+ Bucky'O Hare, The Simpsons and Sunset Riders rely on their implications
+ to prepare and retire sprites. They probably apply to many other Konami
+ games but it's hard to tell because most artifacts have been filtered
+ by exclusion sort.
+
+ A driver may call K05324x_set_z_rejection() to set which zcode to ignore.
+ Parameter:
+ -1 = accept all(default)
+ 0x00-0xff = zcode to ignore
+*/
+void K05324x_set_z_rejection(int zcode)
+{
+ K05324x_z_rejection = zcode;
+}
+
+
+
+/***************************************************************************/
+/* */
+/* 053245 */
+/* */
+/***************************************************************************/
+
+#define MAX_K053245_CHIPS 2
+
+static int K053245_memory_region[MAX_K053245_CHIPS];
+static gfx_element *K053245_gfx[MAX_K053245_CHIPS];
+static void (*K053245_callback[MAX_K053245_CHIPS])(int *code,int *color,int *priority);
+static int K053244_rombank[MAX_K053245_CHIPS];
+static int K053245_ramsize[MAX_K053245_CHIPS];
+static UINT16 *K053245_ram[MAX_K053245_CHIPS], *K053245_buffer[MAX_K053245_CHIPS];
+static UINT8 K053244_regs[MAX_K053245_CHIPS][0x10];
+static int K053245_dx[MAX_K053245_CHIPS], K053245_dy[MAX_K053245_CHIPS];
+
+void K053245_vh_start(running_machine *machine,int chip, int gfx_memory_region,int plane0,int plane1,int plane2,int plane3,
+ void (*callback)(int *code,int *color,int *priority))
+{
+ int gfx_index,i;
+ static gfx_layout spritelayout =
+ {
+ 16,16,
+ 0, /* filled in later */
+ 4,
+ { 0, 0, 0, 0 }, /* filled in later */
+ { 0, 1, 2, 3, 4, 5, 6, 7,
+ 8*32+0, 8*32+1, 8*32+2, 8*32+3, 8*32+4, 8*32+5, 8*32+6, 8*32+7 },
+ { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32,
+ 16*32, 17*32, 18*32, 19*32, 20*32, 21*32, 22*32, 23*32 },
+ 128*8
+ };
+
+ assert_always(chip<MAX_K053245_CHIPS, "K053245_vh_start chip >= MAX_K053245_CHIPS");
+
+ K053245_memory_region[chip]=2;
+
+
+
+ /* find first empty slot to decode gfx */
+ for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
+ if (machine->gfx[gfx_index] == 0)
+ break;
+ assert(gfx_index != MAX_GFX_ELEMENTS);
+
+ /* tweak the structure for the number of tiles we have */
+ spritelayout.total = memory_region_length(gfx_memory_region) / 128;
+ spritelayout.planeoffset[0] = plane3 * 8;
+ spritelayout.planeoffset[1] = plane2 * 8;
+ spritelayout.planeoffset[2] = plane1 * 8;
+ spritelayout.planeoffset[3] = plane0 * 8;
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&spritelayout);
+ decodegfx(machine->gfx[gfx_index], memory_region(gfx_memory_region), 0, machine->gfx[gfx_index]->total_elements);
+
+ /* set the color information */
+ if (machine->drv->color_table_len)
+ machine->gfx[gfx_index]->total_colors = machine->drv->color_table_len / 16;
+ else
+ machine->gfx[gfx_index]->total_colors = machine->drv->total_colors / 16;
+
+#if VERBOSE
+ if (!(machine->drv->video_attributes & VIDEO_HAS_SHADOWS))
+ popmessage("driver should use VIDEO_HAS_SHADOWS");
+#endif
+
+ /* prepare shadow draw table */
+ gfx_drawmode_table[0] = DRAWMODE_NONE;
+ for (i = 1;i < 15;i++)
+ gfx_drawmode_table[i] = DRAWMODE_SOURCE;
+ gfx_drawmode_table[15] = DRAWMODE_SHADOW;
+ K05324x_z_rejection = -1;
+ K053245_memory_region[chip] = gfx_memory_region;
+ K053245_gfx[chip] = machine->gfx[gfx_index];
+ K053245_callback[chip] = callback;
+ K053244_rombank[chip] = 0;
+ K053245_ramsize[chip] = 0x800;
+ K053245_ram[chip] = auto_malloc(K053245_ramsize[chip]);
+ K053245_dx[chip] = K053245_dy[chip] = 0;
+
+ K053245_buffer[chip] = auto_malloc(K053245_ramsize[chip]);
+
+ memset(K053245_ram[chip],0,K053245_ramsize[chip]);
+ memset(K053245_buffer[chip],0,K053245_ramsize[chip]);
+}
+
+void K053245_set_SpriteOffset(int chip,int offsx, int offsy)
+{
+ K053245_dx[chip] = offsx;
+ K053245_dy[chip] = offsy;
+}
+
+READ16_HANDLER( K053245_word_r )
+{
+ return K053245_ram[0][offset];
+}
+
+WRITE16_HANDLER( K053245_word_w )
+{
+ COMBINE_DATA(K053245_ram[0]+offset);
+}
+
+READ8_HANDLER( K053245_r )
+{
+ if(offset & 1)
+ return K053245_ram[0][offset>>1] & 0xff;
+ else
+ return (K053245_ram[0][offset>>1]>>8) & 0xff;
+}
+
+
+static void K053245_chip_w(int chip,int offset,int data)
+{
+ if(offset & 1)
+ K053245_ram[chip][offset>>1] = (K053245_ram[chip][offset>>1] & 0xff00) | data;
+ else
+ K053245_ram[chip][offset>>1] = (K053245_ram[chip][offset>>1] & 0x00ff) | (data<<8);
+}
+
+WRITE8_HANDLER( K053245_w )
+{
+ K053245_chip_w(0,offset,data);
+}
+
+/* 2nd chip */
+WRITE8_HANDLER( K053245_1_w )
+{
+ K053245_chip_w(1,offset,data);
+}
+
+void K053245_clear_buffer(int chip)
+{
+ int i, e;
+ for (e=K053245_ramsize[chip]/2, i=0; i<e; i+=8) K053245_buffer[chip][i] = 0;
+}
+
+INLINE void K053245_update_buffer( int chip )
+{
+ memcpy(K053245_buffer[chip], K053245_ram[chip], K053245_ramsize[chip]);
+}
+
+static UINT8 K053244_chip_r (int chip, int offset)
+{
+ if ((K053244_regs[chip][5] & 0x10) && offset >= 0x0c && offset < 0x10)
+ {
+ int addr;
+
+ addr = (K053244_rombank[chip] << 19) | ((K053244_regs[chip][11] & 0x7) << 18)
+ | (K053244_regs[chip][8] << 10) | (K053244_regs[chip][9] << 2)
+ | ((offset & 3) ^ 1);
+ addr &= memory_region_length(K053245_memory_region[chip])-1;
+
+// popmessage("%04x: offset %02x addr %06x",activecpu_get_pc(),offset&3,addr);
+
+ return memory_region(K053245_memory_region[chip])[addr];
+ }
+ else if (offset == 0x06)
+ {
+ K053245_update_buffer(chip);
+ return 0;
+ }
+ else
+ {
+//logerror("%04x: read from unknown 053244 address %x\n",activecpu_get_pc(),offset);
+ return 0;
+ }
+}
+
+READ8_HANDLER( K053244_r )
+{
+ return K053244_chip_r(0,offset);
+}
+
+static void K053244_chip_w(int chip, int offset, int data)
+{
+ K053244_regs[chip][offset] = data;
+
+ switch(offset) {
+ case 0x05: {
+// if (data & 0xc8)
+// popmessage("053244 reg 05 = %02x",data);
+ /* bit 2 = unknown, Parodius uses it */
+ /* bit 5 = unknown, Rollergames uses it */
+// logerror("%04x: write %02x to 053244 address 5\n",activecpu_get_pc(),data);
+ break;
+ }
+ case 0x06:
+ K053245_update_buffer(chip);
+ break;
+ }
+}
+
+WRITE8_HANDLER( K053244_w )
+{
+ K053244_chip_w(0,offset,data);
+}
+
+/* 2nd chip */
+WRITE8_HANDLER( K053244_1_w )
+{
+ K053244_chip_w(1,offset,data);
+}
+
+
+READ16_HANDLER( K053244_lsb_r )
+{
+ return K053244_r(offset);
+}
+
+WRITE16_HANDLER( K053244_lsb_w )
+{
+ if (ACCESSING_LSB)
+ K053244_w(offset, data & 0xff);
+}
+
+READ16_HANDLER( K053244_word_r )
+{
+ return (K053244_r(offset*2)<<8)|K053244_r(offset*2+1);
+}
+
+WRITE16_HANDLER( K053244_word_w )
+{
+ if (ACCESSING_MSB)
+ K053244_w(offset*2, (data >> 8) & 0xff);
+ if (ACCESSING_LSB)
+ K053244_w(offset*2+1, data & 0xff);
+}
+
+void K053244_bankselect(int chip, int bank)
+{
+ K053244_rombank[chip] = bank;
+}
+
+/*
+ * Sprite Format
+ * ------------------
+ *
+ * Word | Bit(s) | Use
+ * -----+-fedcba9876543210-+----------------
+ * 0 | x--------------- | active (show this sprite)
+ * 0 | -x-------------- | maintain aspect ratio (when set, zoom y acts on both axis)
+ * 0 | --x------------- | flip y
+ * 0 | ---x------------ | flip x
+ * 0 | ----xxxx-------- | sprite size (see below)
+ * 0 | ---------xxxxxxx | priority order
+ * 1 | --xxxxxxxxxxxxxx | sprite code. We use an additional bit in TMNT2, but this is
+ * probably not accurate (protection related so we can't verify)
+ * 2 | ------xxxxxxxxxx | y position
+ * 3 | ------xxxxxxxxxx | x position
+ * 4 | xxxxxxxxxxxxxxxx | zoom y (0x40 = normal, <0x40 = enlarge, >0x40 = reduce)
+ * 5 | xxxxxxxxxxxxxxxx | zoom x (0x40 = normal, <0x40 = enlarge, >0x40 = reduce)
+ * 6 | ------x--------- | mirror y (top half is drawn as mirror image of the bottom)
+ * 6 | -------x-------- | mirror x (right half is drawn as mirror image of the left)
+ * 6 | --------x------- | shadow
+ * 6 | ---------xxxxxxx | "color", but depends on external connections
+ * 7 | ---------------- |
+ *
+ * shadow enables transparent shadows. Note that it applies to pen 0x0f ONLY.
+ * The rest of the sprite remains normal.
+ */
+
+void K053245_sprites_draw(int chip, mame_bitmap *bitmap,const rectangle *cliprect) //*
+{
+#define NUM_SPRITES 128
+ int offs,pri_code,i;
+ int sortedlist[NUM_SPRITES];
+ int flipscreenX, flipscreenY, spriteoffsX, spriteoffsY;
+
+ flipscreenX = K053244_regs[chip][5] & 0x01;
+ flipscreenY = K053244_regs[chip][5] & 0x02;
+ spriteoffsX = (K053244_regs[chip][0] << 8) | K053244_regs[chip][1];
+ spriteoffsY = (K053244_regs[chip][2] << 8) | K053244_regs[chip][3];
+
+ for (offs = 0;offs < NUM_SPRITES;offs++)
+ sortedlist[offs] = -1;
+
+ /* prebuild a sorted table */
+ for (i=K053245_ramsize[chip]/2, offs=0; offs<i; offs+=8)
+ {
+ pri_code = K053245_buffer[chip][offs];
+ if (pri_code & 0x8000)
+ {
+ pri_code &= 0x007f;
+
+ if (offs && pri_code == K05324x_z_rejection) continue;
+
+ if (sortedlist[pri_code] == -1) sortedlist[pri_code] = offs;
+ }
+ }
+
+ for (pri_code = NUM_SPRITES-1;pri_code >= 0;pri_code--)
+ {
+ int ox,oy,color,code,size,w,h,x,y,flipx,flipy,mirrorx,mirrory,shadow,zoomx,zoomy,pri;
+
+ offs = sortedlist[pri_code];
+ if (offs == -1) continue;
+
+ /* the following changes the sprite draw order from
+ 0 1 4 5 16 17 20 21
+ 2 3 6 7 18 19 22 23
+ 8 9 12 13 24 25 28 29
+ 10 11 14 15 26 27 30 31
+ 32 33 36 37 48 49 52 53
+ 34 35 38 39 50 51 54 55
+ 40 41 44 45 56 57 60 61
+ 42 43 46 47 58 59 62 63
+
+ to
+
+ 0 1 2 3 4 5 6 7
+ 8 9 10 11 12 13 14 15
+ 16 17 18 19 20 21 22 23
+ 24 25 26 27 28 29 30 31
+ 32 33 34 35 36 37 38 39
+ 40 41 42 43 44 45 46 47
+ 48 49 50 51 52 53 54 55
+ 56 57 58 59 60 61 62 63
+ */
+
+ /* NOTE: from the schematics, it looks like the top 2 bits should be ignored */
+ /* (there are not output pins for them), and probably taken from the "color" */
+ /* field to do bank switching. However this applies only to TMNT2, with its */
+ /* protection mcu creating the sprite table, so we don't know where to fetch */
+ /* the bits from. */
+ code = K053245_buffer[chip][offs+1];
+ code = ((code & 0xffe1) + ((code & 0x0010) >> 2) + ((code & 0x0008) << 1)
+ + ((code & 0x0004) >> 1) + ((code & 0x0002) << 2));
+ color = K053245_buffer[chip][offs+6] & 0x00ff;
+ pri = 0;
+
+ (*K053245_callback[chip])(&code,&color,&pri);
+
+ size = (K053245_buffer[chip][offs] & 0x0f00) >> 8;
+
+ w = 1 << (size & 0x03);
+ h = 1 << ((size >> 2) & 0x03);
+
+ /* zoom control:
+ 0x40 = normal scale
+ <0x40 enlarge (0x20 = double size)
+ >0x40 reduce (0x80 = half size)
+ */
+ zoomy = K053245_buffer[chip][offs+4];
+ if (zoomy > 0x2000) continue;
+ if (zoomy) zoomy = (0x400000+zoomy/2) / zoomy;
+ else zoomy = 2 * 0x400000;
+ if ((K053245_buffer[chip][offs] & 0x4000) == 0)
+ {
+ zoomx = K053245_buffer[chip][offs+5];
+ if (zoomx > 0x2000) continue;
+ if (zoomx) zoomx = (0x400000+zoomx/2) / zoomx;
+ else zoomx = 2 * 0x400000;
+// else zoomx = zoomy; /* workaround for TMNT2 */
+ }
+ else zoomx = zoomy;
+
+ ox = K053245_buffer[chip][offs+3] + spriteoffsX;
+ oy = K053245_buffer[chip][offs+2];
+
+ ox += K053245_dx[chip];
+ oy += K053245_dy[chip];
+
+ flipx = K053245_buffer[chip][offs] & 0x1000;
+ flipy = K053245_buffer[chip][offs] & 0x2000;
+ mirrorx = K053245_buffer[chip][offs+6] & 0x0100;
+ if (mirrorx) flipx = 0; // documented and confirmed
+ mirrory = K053245_buffer[chip][offs+6] & 0x0200;
+ shadow = K053245_buffer[chip][offs+6] & 0x0080;
+
+ if (flipscreenX)
+ {
+ ox = 512 - ox;
+ if (!mirrorx) flipx = !flipx;
+ }
+ if (flipscreenY)
+ {
+ oy = -oy;
+ if (!mirrory) flipy = !flipy;
+ }
+
+ ox = (ox + 0x5d) & 0x3ff;
+ if (ox >= 768) ox -= 1024;
+ oy = (-(oy + spriteoffsY + 0x07)) & 0x3ff;
+ if (oy >= 640) oy -= 1024;
+
+ /* the coordinates given are for the *center* of the sprite */
+ ox -= (zoomx * w) >> 13;
+ oy -= (zoomy * h) >> 13;
+
+ for (y = 0;y < h;y++)
+ {
+ int sx,sy,zw,zh;
+
+ sy = oy + ((zoomy * y + (1<<11)) >> 12);
+ zh = (oy + ((zoomy * (y+1) + (1<<11)) >> 12)) - sy;
+
+ for (x = 0;x < w;x++)
+ {
+ int c,fx,fy;
+
+ sx = ox + ((zoomx * x + (1<<11)) >> 12);
+ zw = (ox + ((zoomx * (x+1) + (1<<11)) >> 12)) - sx;
+ c = code;
+ if (mirrorx)
+ {
+ if ((flipx == 0) ^ (2*x < w))
+ {
+ /* mirror left/right */
+ c += (w-x-1);
+ fx = 1;
+ }
+ else
+ {
+ c += x;
+ fx = 0;
+ }
+ }
+ else
+ {
+ if (flipx) c += w-1-x;
+ else c += x;
+ fx = flipx;
+ }
+ if (mirrory)
+ {
+ if ((flipy == 0) ^ (2*y >= h))
+ {
+ /* mirror top/bottom */
+ c += 8*(h-y-1);
+ fy = 1;
+ }
+ else
+ {
+ c += 8*y;
+ fy = 0;
+ }
+ }
+ else
+ {
+ if (flipy) c += 8*(h-1-y);
+ else c += 8*y;
+ fy = flipy;
+ }
+
+ /* the sprite can start at any point in the 8x8 grid, but it must stay */
+ /* in a 64 entries window, wrapping around at the edges. The animation */
+ /* at the end of the saloon level in Sunset Riders breaks otherwise. */
+ c = (c & 0x3f) | (code & ~0x3f);
+
+ if (zoomx == 0x10000 && zoomy == 0x10000)
+ {
+ pdrawgfx(bitmap,K053245_gfx[chip],
+ c,
+ color,
+ fx,fy,
+ sx,sy,
+ cliprect,shadow ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,0,pri);
+ }
+ else
+ {
+ pdrawgfxzoom(bitmap,K053245_gfx[chip],
+ c,
+ color,
+ fx,fy,
+ sx,sy,
+ cliprect,shadow ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,0,
+ (zw << 16) / 16,(zh << 16) / 16,pri);
+
+ }
+ }
+ }
+ }
+#if 0
+if (input_code_pressed(KEYCODE_D))
+{
+ FILE *fp;
+ fp=fopen("SPRITE.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(K053245_buffer, 0x800, 1, fp);
+ popmessage("saved");
+ fclose(fp);
+ }
+}
+#endif
+#undef NUM_SPRITES
+}
+
+/* Lethal Enforcers has 2 of these chips hooked up in parallel to give 6bpp gfx.. lets cheat a
+ bit and make emulating it a little less messy by using a custom function instead */
+void K053245_sprites_draw_lethal(running_machine *machine,int chip, mame_bitmap *bitmap,const rectangle *cliprect) //*
+{
+#define NUM_SPRITES 128
+ int offs,pri_code,i;
+ int sortedlist[NUM_SPRITES];
+ int flipscreenX, flipscreenY, spriteoffsX, spriteoffsY;
+
+ flipscreenX = K053244_regs[chip][5] & 0x01;
+ flipscreenY = K053244_regs[chip][5] & 0x02;
+ spriteoffsX = (K053244_regs[chip][0] << 8) | K053244_regs[chip][1];
+ spriteoffsY = (K053244_regs[chip][2] << 8) | K053244_regs[chip][3];
+
+ for (offs = 0;offs < NUM_SPRITES;offs++)
+ sortedlist[offs] = -1;
+
+ /* prebuild a sorted table */
+ for (i=K053245_ramsize[chip]/2, offs=0; offs<i; offs+=8)
+ {
+ pri_code = K053245_buffer[chip][offs];
+ if (pri_code & 0x8000)
+ {
+ pri_code &= 0x007f;
+
+ if (offs && pri_code == K05324x_z_rejection) continue;
+
+ if (sortedlist[pri_code] == -1) sortedlist[pri_code] = offs;
+ }
+ }
+
+ for (pri_code = NUM_SPRITES-1;pri_code >= 0;pri_code--)
+ {
+ int ox,oy,color,code,size,w,h,x,y,flipx,flipy,mirrorx,mirrory,shadow,zoomx,zoomy,pri;
+
+ offs = sortedlist[pri_code];
+ if (offs == -1) continue;
+
+ /* the following changes the sprite draw order from
+ 0 1 4 5 16 17 20 21
+ 2 3 6 7 18 19 22 23
+ 8 9 12 13 24 25 28 29
+ 10 11 14 15 26 27 30 31
+ 32 33 36 37 48 49 52 53
+ 34 35 38 39 50 51 54 55
+ 40 41 44 45 56 57 60 61
+ 42 43 46 47 58 59 62 63
+
+ to
+
+ 0 1 2 3 4 5 6 7
+ 8 9 10 11 12 13 14 15
+ 16 17 18 19 20 21 22 23
+ 24 25 26 27 28 29 30 31
+ 32 33 34 35 36 37 38 39
+ 40 41 42 43 44 45 46 47
+ 48 49 50 51 52 53 54 55
+ 56 57 58 59 60 61 62 63
+ */
+
+ /* NOTE: from the schematics, it looks like the top 2 bits should be ignored */
+ /* (there are not output pins for them), and probably taken from the "color" */
+ /* field to do bank switching. However this applies only to TMNT2, with its */
+ /* protection mcu creating the sprite table, so we don't know where to fetch */
+ /* the bits from. */
+ code = K053245_buffer[chip][offs+1];
+ code = ((code & 0xffe1) + ((code & 0x0010) >> 2) + ((code & 0x0008) << 1)
+ + ((code & 0x0004) >> 1) + ((code & 0x0002) << 2));
+ color = K053245_buffer[chip][offs+6] & 0x00ff;
+ pri = 0;
+
+ (*K053245_callback[chip])(&code,&color,&pri);
+
+ size = (K053245_buffer[chip][offs] & 0x0f00) >> 8;
+
+ w = 1 << (size & 0x03);
+ h = 1 << ((size >> 2) & 0x03);
+
+ /* zoom control:
+ 0x40 = normal scale
+ <0x40 enlarge (0x20 = double size)
+ >0x40 reduce (0x80 = half size)
+ */
+ zoomy = K053245_buffer[chip][offs+4];
+ if (zoomy > 0x2000) continue;
+ if (zoomy) zoomy = (0x400000+zoomy/2) / zoomy;
+ else zoomy = 2 * 0x400000;
+ if ((K053245_buffer[chip][offs] & 0x4000) == 0)
+ {
+ zoomx = K053245_buffer[chip][offs+5];
+ if (zoomx > 0x2000) continue;
+ if (zoomx) zoomx = (0x400000+zoomx/2) / zoomx;
+ else zoomx = 2 * 0x400000;
+// else zoomx = zoomy; /* workaround for TMNT2 */
+ }
+ else zoomx = zoomy;
+
+ ox = K053245_buffer[chip][offs+3] + spriteoffsX;
+ oy = K053245_buffer[chip][offs+2];
+
+ ox += K053245_dx[chip];
+ oy += K053245_dy[chip];
+
+ flipx = K053245_buffer[chip][offs] & 0x1000;
+ flipy = K053245_buffer[chip][offs] & 0x2000;
+ mirrorx = K053245_buffer[chip][offs+6] & 0x0100;
+ if (mirrorx) flipx = 0; // documented and confirmed
+ mirrory = K053245_buffer[chip][offs+6] & 0x0200;
+ shadow = K053245_buffer[chip][offs+6] & 0x0080;
+
+ if (flipscreenX)
+ {
+ ox = 512 - ox;
+ if (!mirrorx) flipx = !flipx;
+ }
+ if (flipscreenY)
+ {
+ oy = -oy;
+ if (!mirrory) flipy = !flipy;
+ }
+
+ ox = (ox + 0x5d) & 0x3ff;
+ if (ox >= 768) ox -= 1024;
+ oy = (-(oy + spriteoffsY + 0x07)) & 0x3ff;
+ if (oy >= 640) oy -= 1024;
+
+ /* the coordinates given are for the *center* of the sprite */
+ ox -= (zoomx * w) >> 13;
+ oy -= (zoomy * h) >> 13;
+
+ for (y = 0;y < h;y++)
+ {
+ int sx,sy,zw,zh;
+
+ sy = oy + ((zoomy * y + (1<<11)) >> 12);
+ zh = (oy + ((zoomy * (y+1) + (1<<11)) >> 12)) - sy;
+
+ for (x = 0;x < w;x++)
+ {
+ int c,fx,fy;
+
+ sx = ox + ((zoomx * x + (1<<11)) >> 12);
+ zw = (ox + ((zoomx * (x+1) + (1<<11)) >> 12)) - sx;
+ c = code;
+ if (mirrorx)
+ {
+ if ((flipx == 0) ^ (2*x < w))
+ {
+ /* mirror left/right */
+ c += (w-x-1);
+ fx = 1;
+ }
+ else
+ {
+ c += x;
+ fx = 0;
+ }
+ }
+ else
+ {
+ if (flipx) c += w-1-x;
+ else c += x;
+ fx = flipx;
+ }
+ if (mirrory)
+ {
+ if ((flipy == 0) ^ (2*y >= h))
+ {
+ /* mirror top/bottom */
+ c += 8*(h-y-1);
+ fy = 1;
+ }
+ else
+ {
+ c += 8*y;
+ fy = 0;
+ }
+ }
+ else
+ {
+ if (flipy) c += 8*(h-1-y);
+ else c += 8*y;
+ fy = flipy;
+ }
+
+ /* the sprite can start at any point in the 8x8 grid, but it must stay */
+ /* in a 64 entries window, wrapping around at the edges. The animation */
+ /* at the end of the saloon level in Sunset Riders breaks otherwise. */
+ c = (c & 0x3f) | (code & ~0x3f);
+
+ if (zoomx == 0x10000 && zoomy == 0x10000)
+ {
+ pdrawgfx(bitmap,machine->gfx[0], /* hardcoded to 0 (decoded 6bpp gfx) for le */
+ c,
+ color,
+ fx,fy,
+ sx,sy,
+ cliprect,shadow ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,0,pri);
+ }
+ else
+ {
+ pdrawgfxzoom(bitmap,machine->gfx[0], /* hardcoded to 0 (decoded 6bpp gfx) for le */
+ c,
+ color,
+ fx,fy,
+ sx,sy,
+ cliprect,shadow ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,0,
+ (zw << 16) / 16,(zh << 16) / 16,pri);
+
+ }
+ }
+ }
+ }
+#if 0
+if (input_code_pressed(KEYCODE_D))
+{
+ FILE *fp;
+ fp=fopen("SPRITE.DMP", "w+b");
+ if (fp)
+ {
+ fwrite(K053245_buffer, 0x800, 1, fp);
+ popmessage("saved");
+ fclose(fp);
+ }
+}
+#endif
+#undef NUM_SPRITES
+}
+
+
+/***************************************************************************/
+/* */
+/* 053246/053247 */
+/* */
+/***************************************************************************/
+
+static int K053247_memory_region, K053247_dx, K053247_dy, K053247_wraparound;
+static UINT8 K053246_regs[8];
+static UINT16 K053247_regs[16];
+static UINT16 *K053247_ram=0;
+static gfx_element *K053247_gfx;
+static void (*K053247_callback)(int *code,int *color,int *priority);
+static UINT8 K053246_OBJCHA_line;
+
+void K053247_export_config(UINT16 **ram, gfx_element **gfx, void (**callback)(int *, int *, int *), int *dx, int *dy)
+{
+ if(ram)
+ *ram = K053247_ram;
+ if(gfx)
+ *gfx = K053247_gfx;
+ if(callback)
+ *callback = K053247_callback;
+ if(dx)
+ *dx = K053247_dx;
+ if(dy)
+ *dy = K053247_dy;
+}
+
+int K053246_read_register(int regnum) { return(K053246_regs[regnum]); }
+int K053247_read_register(int regnum) { return(K053247_regs[regnum]); }
+
+void K053247_set_SpriteOffset(int offsx, int offsy)
+{
+ K053247_dx = offsx;
+ K053247_dy = offsy;
+}
+
+void K053247_wraparound_enable(int status)
+{
+ K053247_wraparound = status;
+}
+
+void K053247_vh_start(running_machine *machine, int gfx_memory_region, int dx, int dy, int plane0,int plane1,int plane2,int plane3,
+ void (*callback)(int *code,int *color,int *priority))
+{
+ int gfx_index,i;
+ static gfx_layout spritelayout =
+ {
+ 16,16,
+ 0, /* filled in later */
+ 4,
+ { 0, 0, 0, 0 }, /* filled in later */
+ { 2*4, 3*4, 0*4, 1*4, 6*4, 7*4, 4*4, 5*4,
+ 10*4, 11*4, 8*4, 9*4, 14*4, 15*4, 12*4, 13*4 },
+ { 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64,
+ 8*64, 9*64, 10*64, 11*64, 12*64, 13*64, 14*64, 15*64 },
+ 128*8
+ };
+
+
+ /* find first empty slot to decode gfx */
+ for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
+ if (machine->gfx[gfx_index] == 0)
+ break;
+ assert(gfx_index != MAX_GFX_ELEMENTS);
+
+ /* tweak the structure for the number of tiles we have */
+ spritelayout.total = memory_region_length(gfx_memory_region) / 128;
+ spritelayout.planeoffset[0] = plane0;
+ spritelayout.planeoffset[1] = plane1;
+ spritelayout.planeoffset[2] = plane2;
+ spritelayout.planeoffset[3] = plane3;
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&spritelayout);
+ decodegfx(machine->gfx[gfx_index], memory_region(gfx_memory_region), 0, machine->gfx[gfx_index]->total_elements);
+
+ /* set the color information */
+ if (machine->drv->color_table_len)
+ machine->gfx[gfx_index]->total_colors = machine->drv->color_table_len / 16;
+ else
+ machine->gfx[gfx_index]->total_colors = machine->drv->total_colors / 16;
+
+#if VERBOSE
+ if (machine->screen[0].format == BITMAP_FORMAT_RGB32)
+ {
+ if ((machine->drv->video_attributes & (VIDEO_HAS_SHADOWS|VIDEO_HAS_HIGHLIGHTS)) != VIDEO_HAS_SHADOWS+VIDEO_HAS_HIGHLIGHTS)
+ popmessage("driver missing SHADOWS or HIGHLIGHTS flag");
+ }
+ else
+ {
+ if (!(machine->drv->video_attributes & VIDEO_HAS_SHADOWS))
+ popmessage("driver should use VIDEO_HAS_SHADOWS");
+ }
+#endif
+
+ /* prepare shadow draw table */
+ gfx_drawmode_table[0] = DRAWMODE_NONE;
+ for (i = 1;i < 15;i++)
+ gfx_drawmode_table[i] = DRAWMODE_SOURCE;
+ gfx_drawmode_table[15] = DRAWMODE_SHADOW;
+
+ K053247_dx = dx;
+ K053247_dy = dy;
+ K053247_wraparound = 1;
+ K05324x_z_rejection = -1;
+ K053247_memory_region = gfx_memory_region;
+ K053247_gfx = machine->gfx[gfx_index];
+ K053247_callback = callback;
+ K053246_OBJCHA_line = CLEAR_LINE;
+ K053247_ram = auto_malloc(0x1000);
+
+ memset(K053247_ram, 0, 0x1000);
+ memset(K053246_regs, 0, 8);
+ memset(K053247_regs, 0, 32);
+
+ state_save_register_global_pointer(K053247_ram, 0x800);
+ state_save_register_global_array(K053246_regs);
+ state_save_register_global_array(K053247_regs);
+ state_save_register_global(K053246_OBJCHA_line);
+}
+
+/* K055673 used with the 54246 in PreGX/Run and Gun/System GX games */
+void K055673_vh_start(running_machine *machine, int gfx_memory_region, int layout, int dx, int dy, void (*callback)(int *code,int *color,int *priority))
+{
+ int gfx_index;
+
+ static gfx_layout spritelayout = /* System GX sprite layout */
+ {
+ 16,16,
+ 32768, /* filled in later */
+ 5,
+ { 32, 24, 16, 8, 0 },
+ { 0, 1, 2, 3, 4, 5, 6, 7, 40, 41, 42, 43, 44, 45, 46, 47 },
+ { 0, 10*8, 10*8*2, 10*8*3, 10*8*4, 10*8*5, 10*8*6, 10*8*7, 10*8*8,
+ 10*8*9, 10*8*10, 10*8*11, 10*8*12, 10*8*13, 10*8*14, 10*8*15 },
+ 16*16*5
+ };
+ static gfx_layout spritelayout2 = /* Run and Gun sprite layout */
+ {
+ 16,16,
+ 32768, /* filled in later */
+ 4,
+ { 24, 16, 8, 0 },
+ { 0, 1, 2, 3, 4, 5, 6, 7, 32, 33, 34, 35, 36, 37, 38, 39 },
+ { 0, 64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960 },
+ 16*16*4
+ };
+ static gfx_layout spritelayout3 = /* Lethal Enforcers II sprite layout */
+ {
+ 16,16,
+ 32768, /* filled in later */
+ 8,
+ { 8*1,8*0,8*3,8*2,8*5,8*4,8*7,8*6 },
+ { 0,1,2,3,4,5,6,7,64+0,64+1,64+2,64+3,64+4,64+5,64+6,64+7 },
+ { 128*0, 128*1, 128*2, 128*3, 128*4, 128*5, 128*6, 128*7,
+ 128*8, 128*9, 128*10, 128*11, 128*12, 128*13, 128*14, 128*15 },
+ 128*16
+ };
+ static gfx_layout spritelayout4 = /* System GX 6bpp sprite layout */
+ {
+ 16,16,
+ 32768, /* filled in later */
+ 6,
+ { 40, 32, 24, 16, 8, 0 },
+ { 0, 1, 2, 3, 4, 5, 6, 7, 48, 49, 50, 51, 52, 53, 54, 55 },
+ { 0, 12*8, 12*8*2, 12*8*3, 12*8*4, 12*8*5, 12*8*6, 12*8*7, 12*8*8,
+ 12*8*9, 12*8*10, 12*8*11, 12*8*12, 12*8*13, 12*8*14, 12*8*15 },
+ 16*16*6
+ };
+ UINT8 *s1, *s2, *d;
+ long i, c;
+ UINT16 *K055673_rom;
+
+ /* find first empty slot to decode gfx */
+ for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
+ if (machine->gfx[gfx_index] == 0)
+ break;
+ assert(gfx_index != MAX_GFX_ELEMENTS);
+
+ switch(layout) {
+ case K055673_LAYOUT_GX:
+ {
+ int size4 = (memory_region_length(gfx_memory_region)/(1024*1024))/5;
+ size4 *= 4*1024*1024;
+ /* set the # of tiles based on the 4bpp section */
+ spritelayout.total = size4 / 128;
+ K055673_rom = auto_malloc(size4 * 5);
+ d = (UINT8 *)K055673_rom;
+ // now combine the graphics together to form 5bpp
+ s1 = memory_region(gfx_memory_region); // 4bpp area
+ s2 = s1 + (size4); // 1bpp area
+ for (i = 0; i < size4; i+= 4)
+ {
+ *d++ = *s1++;
+ *d++ = *s1++;
+ *d++ = *s1++;
+ *d++ = *s1++;
+ *d++ = *s2++;
+ }
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&spritelayout);
+ decodegfx(machine->gfx[gfx_index], (UINT8 *)K055673_rom, 0, machine->gfx[gfx_index]->total_elements);
+ break;
+ }
+ case K055673_LAYOUT_RNG:
+ K055673_rom = (UINT16 *)memory_region(gfx_memory_region);
+ spritelayout2.total = memory_region_length(gfx_memory_region) / (16*16/2);
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&spritelayout2);
+ decodegfx(machine->gfx[gfx_index], (UINT8 *)K055673_rom, 0, machine->gfx[gfx_index]->total_elements);
+ break;
+ case K055673_LAYOUT_LE2:
+ K055673_rom = (UINT16 *)memory_region(gfx_memory_region);
+ spritelayout3.total = memory_region_length(gfx_memory_region) / (16*16);
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&spritelayout3);
+ decodegfx(machine->gfx[gfx_index], (UINT8 *)K055673_rom, 0, machine->gfx[gfx_index]->total_elements);
+ break;
+ case K055673_LAYOUT_GX6:
+ K055673_rom = (UINT16 *)memory_region(gfx_memory_region);
+ spritelayout4.total = memory_region_length(gfx_memory_region) / (16*16*6/8);
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&spritelayout4);
+ decodegfx(machine->gfx[gfx_index], (UINT8 *)K055673_rom, 0, machine->gfx[gfx_index]->total_elements);
+ break;
+ }
+
+ assert(machine->gfx[gfx_index]);
+
+ /* set the color information */
+ if (machine->drv->color_table_len)
+ machine->gfx[gfx_index]->total_colors = machine->drv->color_table_len / 16;
+ else
+ machine->gfx[gfx_index]->total_colors = machine->drv->total_colors / 16;
+
+#if VERBOSE
+ if (!(machine->drv->video_attributes & VIDEO_HAS_SHADOWS))
+ popmessage("driver should use VIDEO_HAS_SHADOWS");
+#endif
+
+ /* prepare shadow draw table */
+ c = machine->gfx[gfx_index]->color_granularity-1;
+ gfx_drawmode_table[0] = DRAWMODE_NONE;
+ for (i = 1;i < c;i++)
+ gfx_drawmode_table[i] = DRAWMODE_SOURCE;
+ gfx_drawmode_table[c] = DRAWMODE_SHADOW;
+
+ K053247_dx = dx;
+ K053247_dy = dy;
+ K053247_wraparound = 1;
+ K05324x_z_rejection = -1;
+ K053247_memory_region = gfx_memory_region;
+ K053247_gfx = machine->gfx[gfx_index];
+ K053247_callback = callback;
+ K053246_OBJCHA_line = CLEAR_LINE;
+ K053247_ram = auto_malloc(0x1000);
+
+ memset(K053247_ram, 0, 0x1000);
+ memset(K053246_regs, 0, 8);
+ memset(K053247_regs, 0, 32);
+
+ state_save_register_global_pointer(K053247_ram, 0x800);
+ state_save_register_global_array(K053246_regs);
+ state_save_register_global_array(K053247_regs);
+ state_save_register_global(K053246_OBJCHA_line);
+}
+
+WRITE16_HANDLER( K053247_reg_word_w ) // write-only OBJSET2 registers (see p.43 table 6.1)
+{
+ COMBINE_DATA(K053247_regs + offset);
+}
+
+WRITE32_HANDLER( K053247_reg_long_w )
+{
+ offset <<= 1;
+ COMBINE_DATA(K053247_regs + offset + 1);
+ mem_mask >>= 16;
+ data >>= 16;
+ COMBINE_DATA(K053247_regs + offset);
+}
+
+READ16_HANDLER( K053247_word_r )
+{
+ return K053247_ram[offset];
+}
+
+WRITE16_HANDLER( K053247_word_w )
+{
+ COMBINE_DATA(K053247_ram + offset);
+}
+
+READ32_HANDLER( K053247_long_r )
+{
+ return K053247_ram[offset*2+1] | (K053247_ram[offset*2]<<16);
+}
+
+WRITE32_HANDLER( K053247_long_w )
+{
+ offset <<= 1;
+ COMBINE_DATA(K053247_ram + offset + 1);
+ mem_mask >>= 16;
+ data >>= 16;
+ COMBINE_DATA(K053247_ram + offset);
+}
+
+READ8_HANDLER( K053247_r )
+{
+ int offs = offset >> 1;
+
+ if (offset & 1)
+ return(K053247_ram[offs] & 0xff);
+ else
+ return(K053247_ram[offs] >> 8);
+}
+
+WRITE8_HANDLER( K053247_w )
+{
+ int offs = offset >> 1;
+
+ if (offset & 1)
+ K053247_ram[offs] = (K053247_ram[offs] & 0xff00) | data;
+ else
+ K053247_ram[offs] = (K053247_ram[offs] & 0x00ff) | (data<<8);
+}
+
+// Mystic Warriors hardware games support a non-OBJCHA based ROM readback
+// write the address to the 246 as usual, but there's a completely separate ROM
+// window that works without needing an OBJCHA line.
+// in this window, +0 = 32 bits from one set of ROMs, and +8 = 32 bits from another set
+READ16_HANDLER( K055673_rom_word_r ) // 5bpp
+{
+ UINT8 *ROM8 = (UINT8 *)memory_region(K053247_memory_region);
+ UINT16 *ROM = (UINT16 *)memory_region(K053247_memory_region);
+ int size4 = (memory_region_length(K053247_memory_region)/(1024*1024))/5;
+ int romofs;
+
+ size4 *= 4*1024*1024; // get offset to 5th bit
+ ROM8 += size4;
+
+ romofs = K053246_regs[6]<<16 | K053246_regs[7]<<8 | K053246_regs[4];
+
+ switch (offset)
+ {
+ case 0: // 20k / 36u
+ return ROM[romofs+2];
+ break;
+ case 1: // 17k / 36y
+ return ROM[romofs+3];
+ break;
+ case 2: // 10k / 32y
+ case 3:
+ romofs /= 2;
+ return ROM8[romofs+1];
+ break;
+ case 4: // 22k / 34u
+ return ROM[romofs];
+ break;
+ case 5: // 19k / 34y
+ return ROM[romofs+1];
+ break;
+ case 6: // 12k / 29y
+ case 7:
+ romofs /= 2;
+ return ROM8[romofs];
+ break;
+ default:
+#if VERBOSE
+ logerror("55673_rom_word_r: Unknown read offset %x\n", offset);
+#endif
+ break;
+ }
+
+ return 0;
+}
+
+READ16_HANDLER( K055673_GX6bpp_rom_word_r )
+{
+ UINT16 *ROM = (UINT16 *)memory_region(K053247_memory_region);
+ int romofs;
+
+ romofs = K053246_regs[6]<<16 | K053246_regs[7]<<8 | K053246_regs[4];
+
+ romofs /= 4; // romofs increments 4 at a time
+ romofs *= 12/2; // each increment of romofs = 12 new bytes (6 new words)
+
+ switch (offset)
+ {
+ case 0:
+ return ROM[romofs+3];
+ break;
+ case 1:
+ return ROM[romofs+4];
+ break;
+ case 2:
+ case 3:
+ return ROM[romofs+5];
+ break;
+ case 4:
+ return ROM[romofs];
+ break;
+ case 5:
+ return ROM[romofs+1];
+ break;
+ case 6:
+ case 7:
+ return ROM[romofs+2];
+ break;
+ default:
+#if VERBOSE
+ logerror("55673_rom_word_r: Unknown read offset %x (PC=%x)\n", offset, activecpu_get_pc());
+#endif
+ break;
+ }
+
+ return 0;
+}
+
+READ8_HANDLER( K053246_r )
+{
+ if (K053246_OBJCHA_line == ASSERT_LINE)
+ {
+ int addr;
+
+ addr = (K053246_regs[6] << 17) | (K053246_regs[7] << 9) | (K053246_regs[4] << 1) | ((offset & 1) ^ 1);
+ addr &= memory_region_length(K053247_memory_region)-1;
+#if VERBOSE
+ popmessage("%04x: offset %02x addr %06x",activecpu_get_pc(),offset,addr);
+#endif
+ return memory_region(K053247_memory_region)[addr];
+ }
+ else
+ {
+#if VERBOSE
+logerror("%04x: read from unknown 053246 address %x\n",activecpu_get_pc(),offset);
+#endif
+ return 0;
+ }
+}
+
+WRITE8_HANDLER( K053246_w )
+{
+ K053246_regs[offset] = data;
+}
+
+READ16_HANDLER( K053246_word_r )
+{
+ offset <<= 1;
+ return K053246_r(offset + 1) | (K053246_r(offset) << 8);
+}
+
+WRITE16_HANDLER( K053246_word_w )
+{
+ if (ACCESSING_MSB)
+ K053246_w(offset<<1,(data >> 8) & 0xff);
+ if (ACCESSING_LSB)
+ K053246_w((offset<<1) + 1,data & 0xff);
+}
+
+READ32_HANDLER( K053246_long_r )
+{
+ offset <<= 1;
+ return (K053246_word_r(offset+1, 0xffff) | K053246_word_r(offset, 0xffff)<<16);
+}
+
+WRITE32_HANDLER( K053246_long_w )
+{
+ offset <<= 1;
+ K053246_word_w(offset, data>>16, mem_mask >> 16);
+ K053246_word_w(offset+1, data, mem_mask);
+}
+
+void K053246_set_OBJCHA_line(int state)
+{
+ K053246_OBJCHA_line = state;
+}
+
+int K053246_is_IRQ_enabled(void)
+{
+ // This bit enables obj DMA rather than obj IRQ even though the two functions usually coincide.
+ return K053246_regs[5] & 0x10;
+}
+
+/*
+ * Sprite Format
+ * ------------------
+ *
+ * Word | Bit(s) | Use
+ * -----+-fedcba9876543210-+----------------
+ * 0 | x--------------- | active (show this sprite)
+ * 0 | -x-------------- | maintain aspect ratio (when set, zoom y acts on both axis)
+ * 0 | --x------------- | flip y
+ * 0 | ---x------------ | flip x
+ * 0 | ----xxxx-------- | sprite size (see below)
+ * 0 | --------xxxxxxxx | zcode
+ * 1 | xxxxxxxxxxxxxxxx | sprite code
+ * 2 | ------xxxxxxxxxx | y position
+ * 3 | ------xxxxxxxxxx | x position
+ * 4 | xxxxxxxxxxxxxxxx | zoom y (0x40 = normal, <0x40 = enlarge, >0x40 = reduce)
+ * 5 | xxxxxxxxxxxxxxxx | zoom x (0x40 = normal, <0x40 = enlarge, >0x40 = reduce)
+ * 6 | x--------------- | mirror y (top half is drawn as mirror image of the bottom)
+ * 6 | -x-------------- | mirror x (right half is drawn as mirror image of the left)
+ * 6 | --xx------------ | reserved (sprites with these two bits set don't seem to be graphics data at all)
+ * 6 | ----xx---------- | shadow code: 0=off, 0x400=preset1, 0x800=preset2, 0xc00=preset3
+ * 6 | ------xx-------- | effect code: flicker, upper palette, full shadow...etc. (game dependent)
+ * 6 | --------xxxxxxxx | "color", but depends on external connections (implies priority)
+ * 7 | xxxxxxxxxxxxxxxx | game dependent
+ *
+ * shadow enables transparent shadows. Note that it applies to the last sprite pen ONLY.
+ * The rest of the sprite remains normal.
+ */
+
+void K053247_sprites_draw(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect) //*
+{
+#define NUM_SPRITES 256
+
+ /* sprites can be grouped up to 8x8. The draw order is
+ 0 1 4 5 16 17 20 21
+ 2 3 6 7 18 19 22 23
+ 8 9 12 13 24 25 28 29
+ 10 11 14 15 26 27 30 31
+ 32 33 36 37 48 49 52 53
+ 34 35 38 39 50 51 54 55
+ 40 41 44 45 56 57 60 61
+ 42 43 46 47 58 59 62 63
+ */
+ static int xoffset[8] = { 0, 1, 4, 5, 16, 17, 20, 21 };
+ static int yoffset[8] = { 0, 2, 8, 10, 32, 34, 40, 42 };
+
+ int sortedlist[NUM_SPRITES];
+ int offs,zcode;
+ int ox,oy,color,code,size,w,h,x,y,xa,ya,flipx,flipy,mirrorx,mirrory,shadow,zoomx,zoomy,primask;
+ int shdmask,nozoom,count,temp;
+
+ int flipscreenx = K053246_regs[5] & 0x01;
+ int flipscreeny = K053246_regs[5] & 0x02;
+ int offx = (short)((K053246_regs[0] << 8) | K053246_regs[1]);
+ int offy = (short)((K053246_regs[2] << 8) | K053246_regs[3]);
+
+ int solidpens = K053247_gfx->color_granularity - 1;
+ int screen_width = machine->screen[0].width;
+
+ /*
+ safeguard older drivers missing any of the following video attributes:
+
+ VIDEO_HAS_SHADOWS | VIDEO_HAS_HIGHLIGHTS
+ */
+ if (machine->drv->video_attributes & VIDEO_HAS_SHADOWS)
+ {
+ if (bitmap->bpp == 32 && (machine->drv->video_attributes & VIDEO_HAS_HIGHLIGHTS))
+ shdmask = 3; // enable all shadows and highlights
+ else
+ shdmask = 0; // enable default shadows
+ }
+ else
+ shdmask = -1; // disable everything
+
+ /*
+ The K053247 does not draw pixels on top of those with equal or smaller Z-values
+ regardless of priority. Embedded shadows inherit Z-values from their host sprites
+ but do not assume host priorities unless explicitly told. In other words shadows
+ can have priorities different from that of normal pens in the same sprite,
+ in addition to the ability of masking themselves from specific layers or pixels
+ on the other sprites.
+
+ In front-to-back rendering, sprites cannot sandwich between alpha blended layers
+ or the draw code will have to figure out the percentage opacities of what is on
+ top and beneath each sprite pixel and blend the target accordingly. The process
+ is overly demanding for realtime software and is thus another shortcoming of
+ pdrawgfx and pixel based mixers. Even mahjong games with straight forward video
+ subsystems are feeling the impact by which the girls cannot appear under
+ translucent dialogue boxes.
+
+ These are a small part of the K053247's feature set but many games expect them
+ to be the minimum compliances. The specification will undoubtedly require
+ redesigning the priority system from the ground up. Drawgfx.c and tilemap.c must
+ also undergo heavy facelifts but in the end the changes could hurt simpler games
+ more than they help complex systems; therefore the new engine should remain
+ completely stand alone and self-contained. Implementation details are being
+ hammered down but too early to make propositions.
+ */
+
+ // Prebuild a sorted table by descending Z-order.
+ zcode = K05324x_z_rejection;
+ offs = count = 0;
+
+ if (zcode == -1)
+ {
+ for (; offs<0x800; offs+=8)
+ if (K053247_ram[offs] & 0x8000) sortedlist[count++] = offs;
+ }
+ else
+ {
+ for (; offs<0x800; offs+=8)
+ if ((K053247_ram[offs] & 0x8000) && ((K053247_ram[offs] & 0xff) != zcode)) sortedlist[count++] = offs;
+ }
+
+ w = count;
+ count--;
+ h = count;
+
+ if (!(K053247_regs[0xc/2] & 0x10))
+ {
+ // sort objects in decending order(smaller z closer) when OPSET PRI is clear
+ for (y=0; y<h; y++)
+ {
+ offs = sortedlist[y];
+ zcode = K053247_ram[offs] & 0xff;
+ for (x=y+1; x<w; x++)
+ {
+ temp = sortedlist[x];
+ code = K053247_ram[temp] & 0xff;
+ if (zcode <= code) { zcode = code; sortedlist[x] = offs; sortedlist[y] = offs = temp; }
+ }
+ }
+ }
+ else
+ {
+ // sort objects in ascending order(bigger z closer) when OPSET PRI is set
+ for (y=0; y<h; y++)
+ {
+ offs = sortedlist[y];
+ zcode = K053247_ram[offs] & 0xff;
+ for (x=y+1; x<w; x++)
+ {
+ temp = sortedlist[x];
+ code = K053247_ram[temp] & 0xff;
+ if (zcode >= code) { zcode = code; sortedlist[x] = offs; sortedlist[y] = offs = temp; }
+ }
+ }
+ }
+
+ for (; count>=0; count--)
+ {
+ offs = sortedlist[count];
+
+ code = K053247_ram[offs+1];
+ shadow = color = K053247_ram[offs+6];
+ primask = 0;
+
+ (*K053247_callback)(&code,&color,&primask);
+
+ temp = K053247_ram[offs];
+
+ size = (temp & 0x0f00) >> 8;
+ w = 1 << (size & 0x03);
+ h = 1 << ((size >> 2) & 0x03);
+
+ /* the sprite can start at any point in the 8x8 grid. We have to */
+ /* adjust the offsets to draw it correctly. Simpsons does this all the time. */
+ xa = 0;
+ ya = 0;
+ if (code & 0x01) xa += 1;
+ if (code & 0x02) ya += 1;
+ if (code & 0x04) xa += 2;
+ if (code & 0x08) ya += 2;
+ if (code & 0x10) xa += 4;
+ if (code & 0x20) ya += 4;
+ code &= ~0x3f;
+
+ oy = (short)K053247_ram[offs+2];
+ ox = (short)K053247_ram[offs+3];
+
+ if (K053247_wraparound)
+ {
+ offx &= 0x3ff;
+ offy &= 0x3ff;
+ oy &= 0x3ff;
+ ox &= 0x3ff;
+ }
+
+ /* zoom control:
+ 0x40 = normal scale
+ <0x40 enlarge (0x20 = double size)
+ >0x40 reduce (0x80 = half size)
+ */
+ y = zoomy = K053247_ram[offs+4] & 0x3ff;
+ if (zoomy) zoomy = (0x400000+(zoomy>>1)) / zoomy; else zoomy = 0x800000;
+ if (!(temp & 0x4000))
+ {
+ x = zoomx = K053247_ram[offs+5] & 0x3ff;
+ if (zoomx) zoomx = (0x400000+(zoomx>>1)) / zoomx;
+ else zoomx = 0x800000;
+ }
+ else { zoomx = zoomy; x = y; }
+
+// ************************************************************************************
+// for Escape Kids (GX975)
+// ************************************************************************************
+// Escape Kids use 053246 #5 register's UNKNOWN Bit #5, #3 and #2.
+// Bit #5, #3, #2 always set "1".
+// Maybe, Bit #5 or #3 or #2 or combination means "FIX SPRITE WIDTH TO HALF" ?????
+// Below 7 lines supports this 053246's(???) function.
+// Don't rely on it, Please. But, Escape Kids works correctly!
+// ************************************************************************************
+ if ( K053246_regs[5] & 0x08 ) // Check only "Bit #3 is '1'?" (NOTE: good guess)
+ {
+ zoomx >>= 1; // Fix sprite width to HALF size
+ ox = (ox >> 1) + 1; // Fix sprite draw position
+ if (flipscreenx) ox += screen_width;
+ nozoom = 0;
+ }
+ else
+ nozoom = (x == 0x40 && y == 0x40);
+
+ flipx = temp & 0x1000;
+ flipy = temp & 0x2000;
+ mirrorx = shadow & 0x4000;
+ if (mirrorx) flipx = 0; // documented and confirmed
+ mirrory = shadow & 0x8000;
+
+ if (color == -1)
+ {
+ // drop the entire sprite to shadow unconditionally
+ if (shdmask < 0) continue;
+ color = 0;
+ shadow = -1;
+ for (temp=1; temp<solidpens; temp++) gfx_drawmode_table[temp] = DRAWMODE_SHADOW;
+ palette_set_shadow_mode(machine, 0);
+ }
+ else
+ {
+ if (shdmask >= 0)
+ {
+ shadow = (color & K053247_CUSTOMSHADOW) ? (color>>K053247_SHDSHIFT) : (shadow>>10);
+ if (shadow &= 3) palette_set_shadow_mode(machine, (shadow-1) & shdmask);
+ }
+ else
+ shadow = 0;
+ }
+
+ color &= 0xffff; // strip attribute flags
+
+ if (flipscreenx)
+ {
+ ox = -ox;
+ if (!mirrorx) flipx = !flipx;
+ }
+ if (flipscreeny)
+ {
+ oy = -oy;
+ if (!mirrory) flipy = !flipy;
+ }
+
+ // apply wrapping and global offsets
+ if (K053247_wraparound)
+ {
+ ox = ( ox - offx) & 0x3ff;
+ oy = (-oy - offy) & 0x3ff;
+ if (ox >= 0x300) ox -= 0x400;
+ if (oy >= 0x280) oy -= 0x400;
+ }
+ else
+ {
+ ox = ox - offx;
+ oy = -oy - offy;
+ }
+ ox += K053247_dx;
+ oy -= K053247_dy;
+
+ // apply global and display window offsets
+
+ /* the coordinates given are for the *center* of the sprite */
+ ox -= (zoomx * w) >> 13;
+ oy -= (zoomy * h) >> 13;
+
+ for (y = 0;y < h;y++)
+ {
+ int sx,sy,zw,zh;
+
+ sy = oy + ((zoomy * y + (1<<11)) >> 12);
+ zh = (oy + ((zoomy * (y+1) + (1<<11)) >> 12)) - sy;
+
+ for (x = 0;x < w;x++)
+ {
+ int c,fx,fy;
+
+ sx = ox + ((zoomx * x + (1<<11)) >> 12);
+ zw = (ox + ((zoomx * (x+1) + (1<<11)) >> 12)) - sx;
+ c = code;
+ if (mirrorx)
+ {
+ if ((flipx == 0) ^ ((x<<1) < w))
+ {
+ /* mirror left/right */
+ c += xoffset[(w-1-x+xa)&7];
+ fx = 1;
+ }
+ else
+ {
+ c += xoffset[(x+xa)&7];
+ fx = 0;
+ }
+ }
+ else
+ {
+ if (flipx) c += xoffset[(w-1-x+xa)&7];
+ else c += xoffset[(x+xa)&7];
+ fx = flipx;
+ }
+ if (mirrory)
+ {
+ if ((flipy == 0) ^ ((y<<1) >= h))
+ {
+ /* mirror top/bottom */
+ c += yoffset[(h-1-y+ya)&7];
+ fy = 1;
+ }
+ else
+ {
+ c += yoffset[(y+ya)&7];
+ fy = 0;
+ }
+ }
+ else
+ {
+ if (flipy) c += yoffset[(h-1-y+ya)&7];
+ else c += yoffset[(y+ya)&7];
+ fy = flipy;
+ }
+
+ if (nozoom)
+ {
+ pdrawgfx(bitmap,K053247_gfx,
+ c,
+ color,
+ fx,fy,
+ sx,sy,
+ cliprect,shadow ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,0,primask);
+ }
+ else
+ {
+ pdrawgfxzoom(bitmap,K053247_gfx,
+ c,
+ color,
+ fx,fy,
+ sx,sy,
+ cliprect,shadow ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,0,
+ (zw << 16) >> 4,(zh << 16) >> 4,primask);
+ }
+
+ if (mirrory && h == 1) /* Simpsons shadows */
+ {
+ if (nozoom)
+ {
+ pdrawgfx(bitmap,K053247_gfx,
+ c,
+ color,
+ fx,!fy,
+ sx,sy,
+ cliprect,shadow ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,0,primask);
+ }
+ else
+ {
+ pdrawgfxzoom(bitmap,K053247_gfx,
+ c,
+ color,
+ fx,!fy,
+ sx,sy,
+ cliprect,shadow ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,0,
+ (zw << 16) >> 4,(zh << 16) >> 4,primask);
+ }
+ }
+ } // end of X loop
+ } // end of Y loop
+
+ // reset drawmode_table
+ if (shadow == -1) for (temp=1; temp<solidpens; temp++) gfx_drawmode_table[temp] = DRAWMODE_SOURCE;
+
+ } // end of sprite-list loop
+#undef NUM_SPRITES
+}
+
+
+
+/***************************************************************************/
+/* */
+/* 051316 */
+/* */
+/***************************************************************************/
+
+#define MAX_K051316 3
+
+static int K051316_memory_region[MAX_K051316];
+static int K051316_gfxnum[MAX_K051316];
+static int K051316_wraparound[MAX_K051316];
+static int K051316_offset[MAX_K051316][2];
+static int K051316_bpp[MAX_K051316];
+static void (*K051316_callback[MAX_K051316])(int *code,int *color,int *flags);
+static UINT8 *K051316_ram[MAX_K051316];
+static UINT8 K051316_ctrlram[MAX_K051316][16];
+static tilemap *K051316_tilemap[MAX_K051316];
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+INLINE void K051316_get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int chip)
+{
+ int code = K051316_ram[chip][tile_index];
+ int color = K051316_ram[chip][tile_index + 0x400];
+ int flags = 0;
+
+ (*K051316_callback[chip])(&code,&color,&flags);
+
+ SET_TILE_INFO(
+ K051316_gfxnum[chip],
+ code,
+ color,
+ flags);
+}
+
+static TILE_GET_INFO( K051316_get_tile_info0 ) { K051316_get_tile_info(machine,tileinfo,tile_index,0); }
+static TILE_GET_INFO( K051316_get_tile_info1 ) { K051316_get_tile_info(machine,tileinfo,tile_index,1); }
+static TILE_GET_INFO( K051316_get_tile_info2 ) { K051316_get_tile_info(machine,tileinfo,tile_index,2); }
+
+
+static void K051316_vh_start(running_machine *machine,int chip, int gfx_memory_region,int bpp,
+ int pen_is_mask,int transparent_pen,
+ void (*callback)(int *code,int *color,int *flags))
+{
+ int gfx_index;
+ static tile_get_info_callback get_tile_info[3] = { K051316_get_tile_info0,K051316_get_tile_info1,K051316_get_tile_info2 };
+
+ /* find first empty slot to decode gfx */
+ for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
+ if (machine->gfx[gfx_index] == 0)
+ break;
+ assert(gfx_index != MAX_GFX_ELEMENTS);
+
+ assert((bpp == 4) || (bpp == 7) || (bpp == 8));
+
+ if (bpp == 4)
+ {
+ static gfx_layout charlayout =
+ {
+ 16,16,
+ 0, /* filled in later */
+ 4,
+ { 0, 1, 2, 3 },
+ { 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4,
+ 8*4, 9*4, 10*4, 11*4, 12*4, 13*4, 14*4, 15*4 },
+ { 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64,
+ 8*64, 9*64, 10*64, 11*64, 12*64, 13*64, 14*64, 15*64 },
+ 128*8
+ };
+
+
+ /* tweak the structure for the number of tiles we have */
+ charlayout.total = memory_region_length(gfx_memory_region) / 128;
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&charlayout);
+ decodegfx(machine->gfx[gfx_index], memory_region(gfx_memory_region), 0, machine->gfx[gfx_index]->total_elements);
+ }
+ else
+ {
+ static gfx_layout charlayout =
+ {
+ 16,16,
+ 0, /* filled in later */
+ 0, /* filled in later */
+ { 0 }, /* filled in later */
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8,
+ 8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8 },
+ { 0*128, 1*128, 2*128, 3*128, 4*128, 5*128, 6*128, 7*128,
+ 8*128, 9*128, 10*128, 11*128, 12*128, 13*128, 14*128, 15*128 },
+ 256*8
+ };
+ int i;
+
+
+ /* tweak the structure for the number of tiles we have */
+ charlayout.total = memory_region_length(gfx_memory_region) / 256;
+ charlayout.planes = bpp;
+ if (bpp == 7) for (i = 0;i < 7;i++) charlayout.planeoffset[i] = i+1;
+ else for (i = 0;i < 8;i++) charlayout.planeoffset[i] = i;
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&charlayout);
+ decodegfx(machine->gfx[gfx_index], memory_region(gfx_memory_region), 0, machine->gfx[gfx_index]->total_elements);
+ }
+
+ assert(machine->gfx[gfx_index]);
+
+ /* set the color information */
+ if (machine->drv->color_table_len)
+ machine->gfx[gfx_index]->total_colors = machine->drv->color_table_len / (1 << bpp);
+ else
+ machine->gfx[gfx_index]->total_colors = machine->drv->total_colors / (1 << bpp);
+
+ K051316_memory_region[chip] = gfx_memory_region;
+ K051316_gfxnum[chip] = gfx_index;
+ K051316_bpp[chip] = bpp;
+ K051316_callback[chip] = callback;
+
+ K051316_tilemap[chip] = tilemap_create(get_tile_info[chip],tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ K051316_ram[chip] = auto_malloc(0x800);
+
+ if (!pen_is_mask)
+ tilemap_set_transparent_pen(K051316_tilemap[chip],transparent_pen);
+ else
+ {
+ tilemap_map_pens_to_layer(K051316_tilemap[chip], 0, 0, 0, TILEMAP_PIXEL_LAYER1);
+ tilemap_map_pens_to_layer(K051316_tilemap[chip], 0, transparent_pen, transparent_pen, TILEMAP_PIXEL_LAYER0);
+ }
+
+ K051316_wraparound[chip] = 0; /* default = no wraparound */
+ K051316_offset[chip][0] = K051316_offset[chip][1] = 0;
+}
+
+void K051316_vh_start_0(running_machine *machine,int gfx_memory_region,int bpp,
+ int pen_is_mask,int transparent_pen,
+ void (*callback)(int *code,int *color,int *flags))
+{
+ K051316_vh_start(machine,0,gfx_memory_region,bpp,pen_is_mask,transparent_pen,callback);
+}
+
+void K051316_vh_start_1(running_machine *machine,int gfx_memory_region,int bpp,
+ int pen_is_mask,int transparent_pen,
+ void (*callback)(int *code,int *color,int *flags))
+{
+ K051316_vh_start(machine,1,gfx_memory_region,bpp,pen_is_mask,transparent_pen,callback);
+}
+
+void K051316_vh_start_2(running_machine *machine,int gfx_memory_region,int bpp,
+ int pen_is_mask,int transparent_pen,
+ void (*callback)(int *code,int *color,int *flags))
+{
+ K051316_vh_start(machine,2,gfx_memory_region,bpp,pen_is_mask,transparent_pen,callback);
+}
+
+
+static int K051316_r(int chip, int offset)
+{
+ return K051316_ram[chip][offset];
+}
+
+READ8_HANDLER( K051316_0_r )
+{
+ return K051316_r(0, offset);
+}
+
+READ8_HANDLER( K051316_1_r )
+{
+ return K051316_r(1, offset);
+}
+
+READ8_HANDLER( K051316_2_r )
+{
+ return K051316_r(2, offset);
+}
+
+
+static void K051316_w(int chip,int offset,int data)
+{
+ K051316_ram[chip][offset] = data;
+ tilemap_mark_tile_dirty(K051316_tilemap[chip],offset & 0x3ff);
+}
+
+WRITE8_HANDLER( K051316_0_w )
+{
+ K051316_w(0,offset,data);
+}
+
+WRITE8_HANDLER( K051316_1_w )
+{
+ K051316_w(1,offset,data);
+}
+
+WRITE8_HANDLER( K051316_2_w )
+{
+ K051316_w(2,offset,data);
+}
+
+
+static int K051316_rom_r(int chip, int offset)
+{
+ if ((K051316_ctrlram[chip][0x0e] & 0x01) == 0)
+ {
+ int addr;
+
+ addr = offset + (K051316_ctrlram[chip][0x0c] << 11) + (K051316_ctrlram[chip][0x0d] << 19);
+ if (K051316_bpp[chip] <= 4) addr /= 2;
+ addr &= memory_region_length(K051316_memory_region[chip])-1;
+
+// popmessage("%04x: offset %04x addr %04x",activecpu_get_pc(),offset,addr);
+
+ return memory_region(K051316_memory_region[chip])[addr];
+ }
+ else
+ {
+//logerror("%04x: read 051316 ROM offset %04x but reg 0x0c bit 0 not clear\n",activecpu_get_pc(),offset);
+ return 0;
+ }
+}
+
+READ8_HANDLER( K051316_rom_0_r )
+{
+ return K051316_rom_r(0,offset);
+}
+
+READ8_HANDLER( K051316_rom_1_r )
+{
+ return K051316_rom_r(1,offset);
+}
+
+READ8_HANDLER( K051316_rom_2_r )
+{
+ return K051316_rom_r(2,offset);
+}
+
+
+
+static void K051316_ctrl_w(int chip,int offset,int data)
+{
+ K051316_ctrlram[chip][offset] = data;
+//if (offset >= 0x0c) logerror("%04x: write %02x to 051316 reg %x\n",activecpu_get_pc(),data,offset);
+}
+
+WRITE8_HANDLER( K051316_ctrl_0_w )
+{
+ K051316_ctrl_w(0,offset,data);
+}
+
+WRITE8_HANDLER( K051316_ctrl_1_w )
+{
+ K051316_ctrl_w(1,offset,data);
+}
+
+WRITE8_HANDLER( K051316_ctrl_2_w )
+{
+ K051316_ctrl_w(2,offset,data);
+}
+
+void K051316_wraparound_enable(int chip, int status)
+{
+ K051316_wraparound[chip] = status;
+}
+
+void K051316_set_offset(int chip, int xoffs, int yoffs)
+{
+ K051316_offset[chip][0] = xoffs;
+ K051316_offset[chip][1] = yoffs;
+}
+
+
+static void K051316_zoom_draw(int chip, mame_bitmap *bitmap,const rectangle *cliprect,int flags,UINT32 priority)
+{
+ UINT32 startx,starty;
+ int incxx,incxy,incyx,incyy;
+
+ startx = 256 * ((INT16)(256 * K051316_ctrlram[chip][0x00] + K051316_ctrlram[chip][0x01]));
+ incxx = (INT16)(256 * K051316_ctrlram[chip][0x02] + K051316_ctrlram[chip][0x03]);
+ incyx = (INT16)(256 * K051316_ctrlram[chip][0x04] + K051316_ctrlram[chip][0x05]);
+ starty = 256 * ((INT16)(256 * K051316_ctrlram[chip][0x06] + K051316_ctrlram[chip][0x07]));
+ incxy = (INT16)(256 * K051316_ctrlram[chip][0x08] + K051316_ctrlram[chip][0x09]);
+ incyy = (INT16)(256 * K051316_ctrlram[chip][0x0a] + K051316_ctrlram[chip][0x0b]);
+
+ startx -= (16 + K051316_offset[chip][1]) * incyx;
+ starty -= (16 + K051316_offset[chip][1]) * incyy;
+
+ startx -= (89 + K051316_offset[chip][0]) * incxx;
+ starty -= (89 + K051316_offset[chip][0]) * incxy;
+
+ tilemap_draw_roz(bitmap,cliprect,K051316_tilemap[chip],startx << 5,starty << 5,
+ incxx << 5,incxy << 5,incyx << 5,incyy << 5,
+ K051316_wraparound[chip],
+ flags,priority);
+
+#if 0
+ popmessage("%02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x",
+ K051316_ctrlram[chip][0x00],
+ K051316_ctrlram[chip][0x01],
+ K051316_ctrlram[chip][0x02],
+ K051316_ctrlram[chip][0x03],
+ K051316_ctrlram[chip][0x04],
+ K051316_ctrlram[chip][0x05],
+ K051316_ctrlram[chip][0x06],
+ K051316_ctrlram[chip][0x07],
+ K051316_ctrlram[chip][0x08],
+ K051316_ctrlram[chip][0x09],
+ K051316_ctrlram[chip][0x0a],
+ K051316_ctrlram[chip][0x0b],
+ K051316_ctrlram[chip][0x0c], /* bank for ROM testing */
+ K051316_ctrlram[chip][0x0d],
+ K051316_ctrlram[chip][0x0e], /* 0 = test ROMs */
+ K051316_ctrlram[chip][0x0f]);
+#endif
+}
+
+void K051316_zoom_draw_0(mame_bitmap *bitmap,const rectangle *cliprect,int flags,UINT32 priority)
+{
+ K051316_zoom_draw(0,bitmap,cliprect,flags,priority);
+}
+
+void K051316_zoom_draw_1(mame_bitmap *bitmap,const rectangle *cliprect,int flags,UINT32 priority)
+{
+ K051316_zoom_draw(1,bitmap,cliprect,flags,priority);
+}
+
+void K051316_zoom_draw_2(mame_bitmap *bitmap,const rectangle *cliprect,int flags,UINT32 priority)
+{
+ K051316_zoom_draw(2,bitmap,cliprect,flags,priority);
+}
+
+
+
+/***************************************************************************/
+/* */
+/* 053936 */
+/* */
+/***************************************************************************/
+
+#define K053936_MAX_CHIPS 2
+
+UINT16 *K053936_0_ctrl,*K053936_0_linectrl;
+UINT16 *K053936_1_ctrl,*K053936_1_linectrl;
+static int K053936_offset[K053936_MAX_CHIPS][2];
+static int K053936_wraparound[K053936_MAX_CHIPS];
+
+
+static void K053936_zoom_draw(int chip,UINT16 *ctrl,UINT16 *linectrl,mame_bitmap *bitmap,const rectangle *cliprect,tilemap *tmap,int flags,UINT32 priority)
+{
+ if (ctrl[0x07] & 0x0040) /* "super" mode */
+ {
+ UINT32 startx,starty;
+ int incxx,incxy;
+ rectangle my_clip;
+ int y,maxy;
+
+ if ((ctrl[0x07] & 0x0002) && ctrl[0x09]) /* wrong, but fixes glfgreat */
+ {
+ my_clip.min_x = ctrl[0x08] + K053936_offset[chip][0]+2;
+ my_clip.max_x = ctrl[0x09] + K053936_offset[chip][0]+2 - 1;
+ if (my_clip.min_x < cliprect->min_x)
+ my_clip.min_x = cliprect->min_x;
+ if (my_clip.max_x > cliprect->max_x)
+ my_clip.max_x = cliprect->max_x;
+
+ y = ctrl[0x0a] + K053936_offset[chip][1]-2;
+ if (y < cliprect->min_y)
+ y = cliprect->min_y;
+ maxy = ctrl[0x0b] + K053936_offset[chip][1]-2 - 1;
+ if (maxy > cliprect->max_y)
+ maxy = cliprect->max_y;
+ }
+ else
+ {
+ my_clip.min_x = cliprect->min_x;
+ my_clip.max_x = cliprect->max_x;
+
+ y = cliprect->min_y;
+ maxy = cliprect->max_y;
+ }
+
+ while (y <= maxy)
+ {
+ UINT16 *lineaddr = linectrl + 4*((y - K053936_offset[chip][1]) & 0x1ff);
+ my_clip.min_y = my_clip.max_y = y;
+
+ startx = 256 * (INT16)(lineaddr[0] + ctrl[0x00]);
+ starty = 256 * (INT16)(lineaddr[1] + ctrl[0x01]);
+ incxx = (INT16)(lineaddr[2]);
+ incxy = (INT16)(lineaddr[3]);
+
+ if (ctrl[0x06] & 0x8000) incxx *= 256;
+ if (ctrl[0x06] & 0x0080) incxy *= 256;
+
+ startx -= K053936_offset[chip][0] * incxx;
+ starty -= K053936_offset[chip][0] * incxy;
+
+ tilemap_draw_roz(bitmap,&my_clip,tmap,startx << 5,starty << 5,
+ incxx << 5,incxy << 5,0,0,
+ K053936_wraparound[chip],
+ flags,priority);
+
+ y++;
+ }
+ }
+ else /* "simple" mode */
+ {
+ UINT32 startx,starty;
+ int incxx,incxy,incyx,incyy;
+
+ startx = 256 * (INT16)(ctrl[0x00]);
+ starty = 256 * (INT16)(ctrl[0x01]);
+ incyx = (INT16)(ctrl[0x02]);
+ incyy = (INT16)(ctrl[0x03]);
+ incxx = (INT16)(ctrl[0x04]);
+ incxy = (INT16)(ctrl[0x05]);
+
+ if (ctrl[0x06] & 0x4000) { incyx *= 256; incyy *= 256; }
+ if (ctrl[0x06] & 0x0040) { incxx *= 256; incxy *= 256; }
+
+ startx -= K053936_offset[chip][1] * incyx;
+ starty -= K053936_offset[chip][1] * incyy;
+
+ startx -= K053936_offset[chip][0] * incxx;
+ starty -= K053936_offset[chip][0] * incxy;
+
+ tilemap_draw_roz(bitmap,cliprect,tmap,startx << 5,starty << 5,
+ incxx << 5,incxy << 5,incyx << 5,incyy << 5,
+ K053936_wraparound[chip],
+ flags,priority);
+ }
+
+#if 0
+if (input_code_pressed(KEYCODE_D))
+ popmessage("%04x %04x %04x %04x\n%04x %04x %04x %04x\n%04x %04x %04x %04x\n%04x %04x %04x %04x",
+ ctrl[0x00],
+ ctrl[0x01],
+ ctrl[0x02],
+ ctrl[0x03],
+ ctrl[0x04],
+ ctrl[0x05],
+ ctrl[0x06],
+ ctrl[0x07],
+ ctrl[0x08],
+ ctrl[0x09],
+ ctrl[0x0a],
+ ctrl[0x0b],
+ ctrl[0x0c],
+ ctrl[0x0d],
+ ctrl[0x0e],
+ ctrl[0x0f]);
+#endif
+}
+
+
+void K053936_0_zoom_draw(mame_bitmap *bitmap,const rectangle *cliprect,tilemap *tmap,int flags,UINT32 priority)
+{
+ K053936_zoom_draw(0,K053936_0_ctrl,K053936_0_linectrl,bitmap,cliprect,tmap,flags,priority);
+}
+
+void K053936_1_zoom_draw(mame_bitmap *bitmap,const rectangle *cliprect,tilemap *tmap,int flags,UINT32 priority)
+{
+ K053936_zoom_draw(1,K053936_1_ctrl,K053936_1_linectrl,bitmap,cliprect,tmap,flags,priority);
+}
+
+
+void K053936_wraparound_enable(int chip, int status)
+{
+ K053936_wraparound[chip] = status;
+}
+
+
+void K053936_set_offset(int chip, int xoffs, int yoffs)
+{
+ K053936_offset[chip][0] = xoffs;
+ K053936_offset[chip][1] = yoffs;
+}
+
+
+
+/***************************************************************************/
+/* */
+/* 053251 */
+/* */
+/***************************************************************************/
+
+static UINT8 K053251_ram[16];
+static int K053251_palette_index[5];
+static tilemap *K053251_tilemaps[5];
+static int K053251_tilemaps_set;
+
+static void K053251_reset_indexes(void)
+{
+ K053251_palette_index[0] = 32 * ((K053251_ram[9] >> 0) & 0x03);
+ K053251_palette_index[1] = 32 * ((K053251_ram[9] >> 2) & 0x03);
+ K053251_palette_index[2] = 32 * ((K053251_ram[9] >> 4) & 0x03);
+ K053251_palette_index[3] = 16 * ((K053251_ram[10] >> 0) & 0x07);
+ K053251_palette_index[4] = 16 * ((K053251_ram[10] >> 3) & 0x07);
+}
+
+void K053251_vh_start(void)
+{
+ K053251_set_tilemaps(NULL,NULL,NULL,NULL,NULL);
+
+ state_save_register_global_array(K053251_ram);
+ state_save_register_func_postload(K053251_reset_indexes);
+}
+
+void K053251_set_tilemaps(tilemap *ci0,tilemap *ci1,tilemap *ci2,tilemap *ci3,tilemap *ci4)
+{
+ K053251_tilemaps[0] = ci0;
+ K053251_tilemaps[1] = ci1;
+ K053251_tilemaps[2] = ci2;
+ K053251_tilemaps[3] = ci3;
+ K053251_tilemaps[4] = ci4;
+
+ K053251_tilemaps_set = (ci0 || ci1 || ci2 || ci3 || ci4) ? 1 : 0;
+}
+
+WRITE8_HANDLER( K053251_w )
+{
+ int i,newind;
+
+ data &= 0x3f;
+
+ if (K053251_ram[offset] != data)
+ {
+ K053251_ram[offset] = data;
+ if (offset == 9)
+ {
+ /* palette base index */
+ for (i = 0;i < 3;i++)
+ {
+ newind = 32 * ((data >> 2*i) & 0x03);
+ if (K053251_palette_index[i] != newind)
+ {
+ K053251_palette_index[i] = newind;
+ if (K053251_tilemaps[i])
+ tilemap_mark_all_tiles_dirty(K053251_tilemaps[i]);
+
+ }
+ }
+
+ if (!K053251_tilemaps_set)
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+ else if (offset == 10)
+ {
+ /* palette base index */
+ for (i = 0;i < 2;i++)
+ {
+ newind = 16 * ((data >> 3*i) & 0x07);
+ if (K053251_palette_index[3+i] != newind)
+ {
+ K053251_palette_index[3+i] = newind;
+ if (K053251_tilemaps[3+i])
+ tilemap_mark_all_tiles_dirty(K053251_tilemaps[3+i]);
+
+ }
+ }
+
+ if (!K053251_tilemaps_set)
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+ }
+}
+
+WRITE16_HANDLER( K053251_lsb_w )
+{
+ if (ACCESSING_LSB)
+ K053251_w(offset, data & 0xff);
+}
+
+WRITE16_HANDLER( K053251_msb_w )
+{
+ if (ACCESSING_MSB)
+ K053251_w(offset, (data >> 8) & 0xff);
+}
+
+int K053251_get_priority(int ci)
+{
+ return K053251_ram[ci];
+}
+
+int K053251_get_palette_index(int ci)
+{
+ return K053251_palette_index[ci];
+}
+
+
+
+/***************************************************************************/
+/* */
+/* 054000 */
+/* */
+/***************************************************************************/
+
+static UINT8 K054000_ram[0x20];
+
+WRITE8_HANDLER( K054000_w )
+{
+//logerror("%04x: write %02x to 054000 address %02x\n",activecpu_get_pc(),data,offset);
+
+ K054000_ram[offset] = data;
+}
+
+READ8_HANDLER( K054000_r )
+{
+ int Acx,Acy,Aax,Aay;
+ int Bcx,Bcy,Bax,Bay;
+
+//logerror("%04x: read 054000 address %02x\n",activecpu_get_pc(),offset);
+
+ if (offset != 0x18) return 0;
+
+ Acx = (K054000_ram[0x01] << 16) | (K054000_ram[0x02] << 8) | K054000_ram[0x03];
+ Acy = (K054000_ram[0x09] << 16) | (K054000_ram[0x0a] << 8) | K054000_ram[0x0b];
+/* TODO: this is a hack to make thndrx2 pass the startup check. It is certainly wrong. */
+if (K054000_ram[0x04] == 0xff) Acx+=3;
+if (K054000_ram[0x0c] == 0xff) Acy+=3;
+ Aax = K054000_ram[0x06] + 1;
+ Aay = K054000_ram[0x07] + 1;
+
+ Bcx = (K054000_ram[0x15] << 16) | (K054000_ram[0x16] << 8) | K054000_ram[0x17];
+ Bcy = (K054000_ram[0x11] << 16) | (K054000_ram[0x12] << 8) | K054000_ram[0x13];
+ Bax = K054000_ram[0x0e] + 1;
+ Bay = K054000_ram[0x0f] + 1;
+
+ if (Acx + Aax < Bcx - Bax)
+ return 1;
+
+ if (Bcx + Bax < Acx - Aax)
+ return 1;
+
+ if (Acy + Aay < Bcy - Bay)
+ return 1;
+
+ if (Bcy + Bay < Acy - Aay)
+ return 1;
+
+ return 0;
+}
+
+READ16_HANDLER( K054000_lsb_r )
+{
+ return K054000_r(offset);
+}
+
+WRITE16_HANDLER( K054000_lsb_w )
+{
+ if (ACCESSING_LSB)
+ K054000_w(offset, data & 0xff);
+}
+
+
+
+/***************************************************************************/
+/* */
+/* 051733 */
+/* */
+/***************************************************************************/
+
+static UINT8 K051733_ram[0x20];
+
+WRITE8_HANDLER( K051733_w )
+{
+//logerror("%04x: write %02x to 051733 address %02x\n",activecpu_get_pc(),data,offset);
+
+ K051733_ram[offset] = data;
+}
+
+
+static int int_sqrt(UINT32 op)
+{
+ UINT32 i,step;
+
+ i = 0x8000;
+ step = 0x4000;
+ while (step)
+ {
+ if (i*i == op) return i;
+ else if (i*i > op) i -= step;
+ else i += step;
+ step >>= 1;
+ }
+ return i;
+}
+
+READ8_HANDLER( K051733_r )
+{
+ int op1 = (K051733_ram[0x00] << 8) | K051733_ram[0x01];
+ int op2 = (K051733_ram[0x02] << 8) | K051733_ram[0x03];
+ int op3 = (K051733_ram[0x04] << 8) | K051733_ram[0x05];
+
+ int rad = (K051733_ram[0x06] << 8) | K051733_ram[0x07];
+ int yobj1c = (K051733_ram[0x08] << 8) | K051733_ram[0x09];
+ int xobj1c = (K051733_ram[0x0a] << 8) | K051733_ram[0x0b];
+ int yobj2c = (K051733_ram[0x0c] << 8) | K051733_ram[0x0d];
+ int xobj2c = (K051733_ram[0x0e] << 8) | K051733_ram[0x0f];
+
+//logerror("%04x: read 051733 address %02x\n",activecpu_get_pc(),offset);
+
+ switch(offset){
+ case 0x00:
+ if (op2) return (op1 / op2) >> 8;
+ else return 0xff;
+ case 0x01:
+ if (op2) return (op1 / op2) & 0xff;
+ else return 0xff;
+
+ /* this is completely unverified */
+ case 0x02:
+ if (op2) return (op1 % op2) >> 8;
+ else return 0xff;
+ case 0x03:
+ if (op2) return (op1 % op2) & 0xff;
+ else return 0xff;
+
+ case 0x04:
+ return int_sqrt(op3<<16) >> 8;
+
+ case 0x05:
+ return int_sqrt(op3<<16) & 0xff;
+
+ case 0x07:{
+ if (xobj1c + rad < xobj2c)
+ return 0x80;
+
+ if (xobj2c + rad < xobj1c)
+ return 0x80;
+
+ if (yobj1c + rad < yobj2c)
+ return 0x80;
+
+ if (yobj2c + rad < yobj1c)
+ return 0x80;
+
+ return 0;
+ }
+ case 0x0e:
+ return ~K051733_ram[offset];
+ case 0x0f:
+ return ~K051733_ram[offset];
+ default:
+ return K051733_ram[offset];
+ }
+}
+
+/***************************************************************************/
+/* */
+/* 054157 / 056832 */
+/* */
+/***************************************************************************/
+
+#define K056832_PAGE_COLS 64
+#define K056832_PAGE_ROWS 32
+#define K056832_PAGE_HEIGHT (K056832_PAGE_ROWS*8)
+#define K056832_PAGE_WIDTH (K056832_PAGE_COLS*8)
+#define K056832_PAGE_COUNT 16
+
+static tilemap *K056832_tilemap[K056832_PAGE_COUNT];
+static mame_bitmap *K056832_pixmap[K056832_PAGE_COUNT];
+
+static UINT16 K056832_regs[0x20]; // 157/832 regs group 1
+static UINT16 K056832_regsb[4]; // 157/832 regs group 2, board dependent
+
+static UINT8 *K056832_rombase; // pointer to tile gfx data
+static UINT16 *K056832_videoram;
+static int K056832_NumGfxBanks; // depends on size of graphics ROMs
+static int K056832_CurGfxBank; // cached info for K056832_regs[0x1a]
+static int K056832_gfxnum; // graphics element index for unpacked tiles
+static int K056832_memory_region; // memory region for tile gfx data
+static int K056832_bpp;
+
+// ROM readback involves reading 2 halves of a word
+// from the same location in a row. Reading the
+// RAM window resets this state so you get the first half.
+static int K056832_rom_half;
+
+// locally cached values
+static int K056832_LayerAssociatedWithPage[K056832_PAGE_COUNT];
+static int K056832_LayerOffset[4][2];
+static int K056832_LSRAMPage[4][2];
+static INT32 K056832_X[4]; // 0..3 left
+static INT32 K056832_Y[4]; // 0..3 top
+static INT32 K056832_W[4]; // 0..3 width -> 1..4 pages
+static INT32 K056832_H[4]; // 0..3 height -> 1..4 pages
+static INT32 K056832_dx[4]; // scroll
+static INT32 K056832_dy[4]; // scroll
+static UINT32 K056832_LineDirty[K056832_PAGE_COUNT][8];
+static UINT8 K056832_AllLinesDirty[K056832_PAGE_COUNT];
+static UINT8 K056832_PageTileMode[K056832_PAGE_COUNT];
+static UINT8 K056832_LayerTileMode[4];
+static int K056832_DefaultLayerAssociation;
+static int K056832_LayerAssociation;
+static int K056832_ActiveLayer;
+static int K056832_SelectedPage;
+static int K056832_SelectedPagex4096;
+static int K056832_UpdateMode;
+static int K056832_linemap_enabled;
+static int K056832_use_ext_linescroll;
+static int K056832_uses_tile_banks, K056832_cur_tile_bank;
+
+static int K056832_djmain_hack;
+
+#define K056832_mark_line_dirty(P,L) if (L<0x100) K056832_LineDirty[P][L>>5] |= 1<<(L&0x1f)
+#define K056832_mark_all_lines_dirty(P) K056832_AllLinesDirty[P] = 1
+
+static void K056832_mark_page_dirty(int page)
+{
+ if (K056832_PageTileMode[page])
+ tilemap_mark_all_tiles_dirty(K056832_tilemap[page]);
+ else
+ K056832_mark_all_lines_dirty(page);
+}
+
+void K056832_mark_plane_dirty(int layer)
+{
+ int tilemode, i;
+
+ tilemode = K056832_LayerTileMode[layer];
+
+ for (i=0; i<K056832_PAGE_COUNT; i++)
+ {
+ if (K056832_LayerAssociatedWithPage[i] == layer)
+ {
+ K056832_PageTileMode[i] = tilemode;
+ K056832_mark_page_dirty(i);
+ }
+ }
+}
+
+void K056832_MarkAllTilemapsDirty(void)
+{
+ int i;
+
+ for (i=0; i<K056832_PAGE_COUNT; i++)
+ {
+ if (K056832_LayerAssociatedWithPage[i] != -1)
+ {
+ K056832_PageTileMode[i] = K056832_LayerTileMode[K056832_LayerAssociatedWithPage[i]];
+ K056832_mark_page_dirty(i);
+ }
+ }
+}
+
+static void K056832_UpdatePageLayout(void)
+{
+ int layer, rowstart, rowspan, colstart, colspan, r, c, pageIndex, setlayer;
+
+ // enable layer association by default
+ K056832_LayerAssociation = K056832_DefaultLayerAssociation;
+
+ // disable association if a layer grabs the entire 4x4 map (happens in Twinbee and Dadandarn)
+ for (layer=0; layer<4; layer++)
+ {
+ if (!K056832_Y[layer] && !K056832_X[layer] && K056832_H[layer]==3 && K056832_W[layer]==3)
+ {
+ K056832_LayerAssociation = 0;
+ break;
+ }
+ }
+
+ // disable all tilemaps
+ for (pageIndex=0; pageIndex<K056832_PAGE_COUNT; pageIndex++)
+ {
+ K056832_LayerAssociatedWithPage[pageIndex] = -1;
+ }
+
+ // enable associated tilemaps
+ for (layer=0; layer<4; layer++)
+ {
+ rowstart = K056832_Y[layer];
+ colstart = K056832_X[layer];
+ rowspan = K056832_H[layer]+1;
+ colspan = K056832_W[layer]+1;
+
+ setlayer = (K056832_LayerAssociation) ? layer : K056832_ActiveLayer;
+
+ for (r=0; r<rowspan; r++)
+ {
+ for (c=0; c<colspan; c++)
+ {
+ pageIndex = (((rowstart + r) & 3) << 2) + ((colstart + c) & 3);
+if (!K056832_djmain_hack || K056832_LayerAssociatedWithPage[pageIndex] == -1) //*
+ K056832_LayerAssociatedWithPage[pageIndex] = setlayer;
+ }
+ }
+ }
+
+ // refresh associated tilemaps
+ K056832_MarkAllTilemapsDirty();
+}
+
+int K056832_get_lookup(int bits)
+{
+ int res;
+
+ res = (K056832_regs[0x1c] >> (bits << 2)) & 0x0f;
+
+ if (K056832_uses_tile_banks) /* Asterix */
+ res |= K056832_cur_tile_bank << 4;
+
+ return res;
+}
+
+static void (*K056832_callback)(int layer, int *code, int *color, int *flags);
+
+INLINE void K056832_get_tile_info( running_machine *machine, tile_data *tileinfo, int tile_index, int pageIndex )
+{
+ static struct K056832_SHIFTMASKS
+ {
+ int flips, palm1, pals2, palm2;
+ }
+ K056832_shiftmasks[4] = {{6,0x3f,0,0x00},{4,0x0f,2,0x30},{2,0x03,2,0x3c},{0,0x00,2,0x3f}};
+
+ struct K056832_SHIFTMASKS *smptr;
+ int layer, flip, fbits, attr, code, color, flags;
+ UINT16 *pMem;
+
+ pMem = &K056832_videoram[(pageIndex<<12)+(tile_index<<1)];
+
+ if (K056832_LayerAssociation)
+ {
+ layer = K056832_LayerAssociatedWithPage[pageIndex];
+ if (layer == -1) layer = 0; // use layer 0's palette info for unmapped pages
+ }
+ else
+ layer = K056832_ActiveLayer;
+
+ fbits = K056832_regs[3]>>6 & 3;
+ flip = K056832_regs[1]>>(layer<<1) & 0x3; // tile-flip override (see p.20 3.2.2 "REG2")
+ smptr = &K056832_shiftmasks[fbits];
+ attr = pMem[0];
+ code = pMem[1];
+
+ // normalize the flip/palette flags
+ // see the tables on pages 4 and 10 of the Pt. 2-3 "VRAM" manual
+ // for a description of these bits "FBIT0" and "FBIT1"
+ flip &= attr>>smptr->flips & 3;
+ color = (attr & smptr->palm1) | (attr>>smptr->pals2 & smptr->palm2);
+ flags = TILE_FLIPYX(flip);
+
+ (*K056832_callback)(layer, &code, &color, &flags);
+
+ SET_TILE_INFO(K056832_gfxnum,
+ code,
+ color,
+ flags);
+}
+
+static TILE_GET_INFO( K056832_get_tile_info0 ) { K056832_get_tile_info(machine,tileinfo,tile_index,0x0); }
+static TILE_GET_INFO( K056832_get_tile_info1 ) { K056832_get_tile_info(machine,tileinfo,tile_index,0x1); }
+static TILE_GET_INFO( K056832_get_tile_info2 ) { K056832_get_tile_info(machine,tileinfo,tile_index,0x2); }
+static TILE_GET_INFO( K056832_get_tile_info3 ) { K056832_get_tile_info(machine,tileinfo,tile_index,0x3); }
+static TILE_GET_INFO( K056832_get_tile_info4 ) { K056832_get_tile_info(machine,tileinfo,tile_index,0x4); }
+static TILE_GET_INFO( K056832_get_tile_info5 ) { K056832_get_tile_info(machine,tileinfo,tile_index,0x5); }
+static TILE_GET_INFO( K056832_get_tile_info6 ) { K056832_get_tile_info(machine,tileinfo,tile_index,0x6); }
+static TILE_GET_INFO( K056832_get_tile_info7 ) { K056832_get_tile_info(machine,tileinfo,tile_index,0x7); }
+static TILE_GET_INFO( K056832_get_tile_info8 ) { K056832_get_tile_info(machine,tileinfo,tile_index,0x8); }
+static TILE_GET_INFO( K056832_get_tile_info9 ) { K056832_get_tile_info(machine,tileinfo,tile_index,0x9); }
+static TILE_GET_INFO( K056832_get_tile_infoa ) { K056832_get_tile_info(machine,tileinfo,tile_index,0xa); }
+static TILE_GET_INFO( K056832_get_tile_infob ) { K056832_get_tile_info(machine,tileinfo,tile_index,0xb); }
+static TILE_GET_INFO( K056832_get_tile_infoc ) { K056832_get_tile_info(machine,tileinfo,tile_index,0xc); }
+static TILE_GET_INFO( K056832_get_tile_infod ) { K056832_get_tile_info(machine,tileinfo,tile_index,0xd); }
+static TILE_GET_INFO( K056832_get_tile_infoe ) { K056832_get_tile_info(machine,tileinfo,tile_index,0xe); }
+static TILE_GET_INFO( K056832_get_tile_infof ) { K056832_get_tile_info(machine,tileinfo,tile_index,0xf); }
+
+static void K056832_change_rambank(void)
+{
+ /* ------xx page col
+ * ---xx--- page row
+ */
+ int bank = K056832_regs[0x19];
+
+ if (K056832_regs[0] & 0x02) // external linescroll enable
+ {
+ K056832_SelectedPage = K056832_PAGE_COUNT;
+ }
+ else
+ {
+ K056832_SelectedPage = ((bank>>1)&0xc)|(bank&3);
+ }
+ K056832_SelectedPagex4096 = K056832_SelectedPage << 12;
+
+ // refresh associated tilemaps
+ K056832_MarkAllTilemapsDirty();
+}
+
+int K056832_get_current_rambank(void)
+{
+ int bank = K056832_regs[0x19];
+
+ return ((bank>>1)&0xc)|(bank&3);
+}
+
+static void K056832_change_rombank(void)
+{
+ int bank;
+
+ if (K056832_uses_tile_banks) /* Asterix */
+ {
+ bank = (K056832_regs[0x1a] >> 8) | (K056832_regs[0x1b] << 4) | (K056832_cur_tile_bank << 6);
+ }
+ else
+ {
+ bank = K056832_regs[0x1a] | (K056832_regs[0x1b] << 16);
+ }
+
+ K056832_CurGfxBank = bank % K056832_NumGfxBanks;
+}
+
+void K056832_set_tile_bank(int bank)
+{
+ K056832_uses_tile_banks = 1;
+
+ if (K056832_cur_tile_bank != bank)
+ {
+ K056832_cur_tile_bank = bank;
+
+ K056832_mark_plane_dirty(0);
+ K056832_mark_plane_dirty(1);
+ K056832_mark_plane_dirty(2);
+ K056832_mark_plane_dirty(3);
+ }
+
+ K056832_change_rombank();
+}
+
+void K056832_vh_start(running_machine *machine, int gfx_memory_region, int bpp, int big,
+ int (*scrolld)[4][2],
+ void (*callback)(int layer, int *code, int *color, int *flags),
+ int djmain_hack)
+{
+ tilemap *tmap;
+ int gfx_index;
+ int i;
+ gfx_layout charlayout8 =
+ {
+ 8, 8,
+ 0, /* filled in later */
+ 8,
+ { 8*7,8*3,8*5,8*1,8*6,8*2,8*4,8*0 },
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ { 0, 8*8, 8*8*2, 8*8*3, 8*8*4, 8*8*5, 8*8*6, 8*8*7 },
+ 8*8*8
+ };
+ gfx_layout charlayout8le =
+ {
+ 8, 8,
+ 0,
+ 8,
+// { 0, 1, 2, 3, 0+(0x200000*8), 1+(0x200000*8), 2+(0x200000*8), 3+(0x200000*8) },
+ { 0+(0x200000*8), 1+(0x200000*8), 2+(0x200000*8), 3+(0x200000*8), 0, 1, 2, 3 },
+ { 2*4, 3*4, 0*4, 1*4, 6*4, 7*4, 4*4, 5*4 },
+ { 0*8*4, 1*8*4, 2*8*4, 3*8*4, 4*8*4, 5*8*4, 6*8*4, 7*8*4 },
+ 8*8*4
+ };
+ gfx_layout charlayout6 =
+ {
+ 8, 8,
+ 0, /* filled in later */
+ 6,
+ { 40, 32, 24, 8, 16, 0 },
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ { 0, 6*8, 6*8*2, 6*8*3, 6*8*4, 6*8*5, 6*8*6, 6*8*7 },
+ 8*8*6
+ };
+ gfx_layout charlayout5 =
+ {
+ 8, 8,
+ 0, /* filled in later */
+ 5,
+ { 32, 24, 8, 16, 0 },
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ { 0, 5*8, 5*8*2, 5*8*3, 5*8*4, 5*8*5, 5*8*6, 5*8*7 },
+ 8*8*5
+ };
+ gfx_layout charlayout4 =
+ {
+ 8, 8,
+ 0,
+ 4,
+ { 0, 1, 2, 3 },
+ { 2*4, 3*4, 0*4, 1*4, 6*4, 7*4, 4*4, 5*4 },
+ { 0*8*4, 1*8*4, 2*8*4, 3*8*4, 4*8*4, 5*8*4, 6*8*4, 7*8*4 },
+ 8*8*4
+ };
+ static gfx_layout charlayout4dj =
+ {
+ 8, 8,
+ 0, /* filled in later */
+ 4,
+ { 8*3,8*1,8*2,8*0 },
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ { 0, 8*4, 8*4*2, 8*4*3, 8*4*4, 8*4*5, 8*4*6, 8*4*7 },
+ 8*8*4
+ };
+
+ K056832_bpp = bpp;
+
+ /* find first empty slot to decode gfx */
+ for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
+ {
+ if (machine->gfx[gfx_index] == 0) break;
+ }
+ assert(gfx_index != MAX_GFX_ELEMENTS);
+
+ /* handle the various graphics formats */
+ i = (big) ? 8 : 16;
+
+ switch (bpp)
+ {
+ case K056832_BPP_4:
+ charlayout4.total = memory_region_length(gfx_memory_region) / (i*4);
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&charlayout4);
+ decodegfx(machine->gfx[gfx_index], memory_region(gfx_memory_region), 0, machine->gfx[gfx_index]->total_elements);
+ break;
+
+ case K056832_BPP_5:
+ /* tweak the structure for the number of tiles we have */
+ charlayout5.total = memory_region_length(gfx_memory_region) / (i*5);
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&charlayout5);
+ decodegfx(machine->gfx[gfx_index], memory_region(gfx_memory_region), 0, machine->gfx[gfx_index]->total_elements);
+ break;
+
+ case K056832_BPP_6:
+ /* tweak the structure for the number of tiles we have */
+ charlayout6.total = memory_region_length(gfx_memory_region) / (i*6);
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&charlayout6);
+ decodegfx(machine->gfx[gfx_index], memory_region(gfx_memory_region), 0, machine->gfx[gfx_index]->total_elements);
+ break;
+
+ case K056832_BPP_8:
+ /* tweak the structure for the number of tiles we have */
+ charlayout8.total = memory_region_length(gfx_memory_region) / (i*8);
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&charlayout8);
+ decodegfx(machine->gfx[gfx_index], memory_region(gfx_memory_region), 0, machine->gfx[gfx_index]->total_elements);
+ break;
+
+ case K056832_BPP_8LE:
+ /* tweak the structure for the number of tiles we have */
+ charlayout8le.total = memory_region_length(gfx_memory_region) / (i*8);
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&charlayout8le);
+ decodegfx(machine->gfx[gfx_index], memory_region(gfx_memory_region), 0, machine->gfx[gfx_index]->total_elements);
+ break;
+
+ case K056832_BPP_4dj:
+ charlayout4dj.total = memory_region_length(gfx_memory_region) / (i*4);
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&charlayout4dj);
+ decodegfx(machine->gfx[gfx_index], memory_region(gfx_memory_region), 0, machine->gfx[gfx_index]->total_elements);
+ break;
+ }
+
+ /* make sure the decode went OK */
+ assert(machine->gfx[gfx_index]);
+
+ /* set the color information */
+ if (machine->drv->color_table_len)
+ machine->gfx[gfx_index]->total_colors = machine->drv->color_table_len / 16;
+ else
+ machine->gfx[gfx_index]->total_colors = machine->drv->total_colors / 16;
+ machine->gfx[gfx_index]->color_granularity = 16; /* override */
+
+ K056832_memory_region = gfx_memory_region;
+ K056832_gfxnum = gfx_index;
+ K056832_callback = callback;
+
+ K056832_rombase = memory_region(gfx_memory_region);
+ K056832_NumGfxBanks = memory_region_length(gfx_memory_region) / 0x2000;
+ K056832_CurGfxBank = 0;
+ K056832_use_ext_linescroll = 0;
+ K056832_uses_tile_banks = 0;
+
+ K056832_djmain_hack = djmain_hack;
+
+ for (i=0; i<4; i++)
+ {
+ K056832_LayerOffset[i][0] = 0;
+ K056832_LayerOffset[i][1] = 0;
+ K056832_LSRAMPage[i][0] = i;
+ K056832_LSRAMPage[i][1] = i << 11;
+ K056832_X[i] = 0;
+ K056832_Y[i] = 0;
+ K056832_W[i] = 0;
+ K056832_H[i] = 0;
+ K056832_dx[i] = 0;
+ K056832_dy[i] = 0;
+ K056832_LayerTileMode[i] = 1;
+ }
+
+ K056832_DefaultLayerAssociation = 1;
+ K056832_ActiveLayer = 0;
+ K056832_UpdateMode = 0;
+ K056832_linemap_enabled = 0;
+
+ memset(K056832_LineDirty, 0, sizeof(UINT32) * K056832_PAGE_COUNT * 8);
+
+ for (i=0; i<K056832_PAGE_COUNT; i++)
+ {
+ K056832_AllLinesDirty[i] = 0;
+ K056832_PageTileMode[i] = 1;
+ }
+
+ K056832_videoram = auto_malloc(0x2000 * (K056832_PAGE_COUNT+1));
+
+ K056832_tilemap[0x0] = tilemap_create(K056832_get_tile_info0, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0x1] = tilemap_create(K056832_get_tile_info1, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0x2] = tilemap_create(K056832_get_tile_info2, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0x3] = tilemap_create(K056832_get_tile_info3, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0x4] = tilemap_create(K056832_get_tile_info4, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0x5] = tilemap_create(K056832_get_tile_info5, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0x6] = tilemap_create(K056832_get_tile_info6, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0x7] = tilemap_create(K056832_get_tile_info7, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0x8] = tilemap_create(K056832_get_tile_info8, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0x9] = tilemap_create(K056832_get_tile_info9, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0xa] = tilemap_create(K056832_get_tile_infoa, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0xb] = tilemap_create(K056832_get_tile_infob, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0xc] = tilemap_create(K056832_get_tile_infoc, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0xd] = tilemap_create(K056832_get_tile_infod, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0xe] = tilemap_create(K056832_get_tile_infoe, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ K056832_tilemap[0xf] = tilemap_create(K056832_get_tile_infof, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ for (i=0; i<K056832_PAGE_COUNT; i++)
+ {
+ tmap = K056832_tilemap[i];
+
+ K056832_pixmap[i] = tilemap_get_pixmap(tmap);
+
+ tilemap_set_transparent_pen(tmap, 0);
+ }
+
+ memset(K056832_videoram, 0x00, 0x20000);
+ memset(K056832_regs, 0x00, sizeof(K056832_regs) );
+ memset(K056832_regsb, 0x00, sizeof(K056832_regsb) );
+
+ K056832_UpdatePageLayout();
+
+ K056832_change_rambank();
+ K056832_change_rombank();
+
+ state_save_register_global_pointer(K056832_videoram, 0x10000);
+ state_save_register_global_array(K056832_regs);
+ state_save_register_global_array(K056832_regsb);
+ state_save_register_global_array(K056832_X);
+ state_save_register_global_array(K056832_Y);
+ state_save_register_global_array(K056832_W);
+ state_save_register_global_array(K056832_H);
+ state_save_register_global_array(K056832_dx);
+ state_save_register_global_array(K056832_dy);
+ state_save_register_global_array(K056832_LayerTileMode);
+
+ state_save_register_func_postload(K056832_UpdatePageLayout);
+ state_save_register_func_postload(K056832_change_rambank);
+ state_save_register_func_postload(K056832_change_rombank);
+}
+
+/* call if a game uses external linescroll */
+void K056832_SetExtLinescroll(void)
+{
+ K056832_use_ext_linescroll = 1;
+}
+
+/* generic helper routine for ROM checksumming */
+static int K056832_rom_read_b(int offset, int blksize, int blksize2, int zerosec)
+{
+ UINT8 *rombase;
+ int base, ret;
+
+ rombase = (UINT8 *)memory_region(K056832_memory_region);
+
+ if ((K056832_rom_half) && (zerosec))
+ {
+ return 0;
+ }
+
+ // add in the bank offset
+ offset += (K056832_CurGfxBank * 0x2000);
+
+ // figure out the base of the ROM block
+ base = (offset / blksize) * blksize2;
+
+ // get the starting offset of the proper word inside the block
+ base += (offset % blksize) * 2;
+
+ if (K056832_rom_half)
+ {
+ ret = rombase[base+1];
+ }
+ else
+ {
+ ret = rombase[base];
+ K056832_rom_half = 1;
+ }
+
+ return ret;
+}
+
+READ16_HANDLER( K056832_5bpp_rom_word_r )
+{
+ if (mem_mask == 0x00ff)
+ {
+ return K056832_rom_read_b(offset*2, 4, 5, 0)<<8;
+ }
+ else if (mem_mask == 0xff00)
+ {
+ return K056832_rom_read_b(offset*2+1, 4, 5, 0)<<16;
+ }
+ else
+ {
+#if VERBOSE
+ logerror("Non-byte read of tilemap ROM, PC=%x (mask=%x)\n", activecpu_get_pc(), mem_mask);
+#endif
+ }
+ return 0;
+}
+
+READ32_HANDLER( K056832_5bpp_rom_long_r )
+{
+ if (mem_mask == 0x00ffffff)
+ {
+ return K056832_rom_read_b(offset*4, 4, 5, 0)<<24;
+ }
+ else if (mem_mask == 0xff00ffff)
+ {
+ return K056832_rom_read_b(offset*4+1, 4, 5, 0)<<16;
+ }
+ else if (mem_mask == 0xffff00ff)
+ {
+ return K056832_rom_read_b(offset*4+2, 4, 5, 0)<<8;
+ }
+ else if (mem_mask == 0xffffff00)
+ {
+ return K056832_rom_read_b(offset*4+3, 4, 5, 1);
+ }
+ else
+ {
+#if VERBOSE
+ logerror("Non-byte read of tilemap ROM, PC=%x (mask=%x)\n", activecpu_get_pc(), mem_mask);
+#endif
+ }
+ return 0;
+}
+
+READ32_HANDLER( K056832_6bpp_rom_long_r )
+{
+ if (mem_mask == 0x00ffffff)
+ {
+ return K056832_rom_read_b(offset*4, 4, 6, 0)<<24;
+ }
+ else if (mem_mask == 0xff00ffff)
+ {
+ return K056832_rom_read_b(offset*4+1, 4, 6, 0)<<16;
+ }
+ else if (mem_mask == 0xffff00ff)
+ {
+ return K056832_rom_read_b(offset*4+2, 4, 6, 0)<<8;
+ }
+ else if (mem_mask == 0xffffff00)
+ {
+ return K056832_rom_read_b(offset*4+3, 4, 6, 0);
+ }
+ else
+ {
+#if VERBOSE
+ logerror("Non-byte read of tilemap ROM, PC=%x (mask=%x)\n", activecpu_get_pc(), mem_mask);
+#endif
+ }
+ return 0;
+}
+
+READ16_HANDLER( K056832_rom_word_r )
+{
+ int ofs16, ofs8;
+ UINT8 *rombase;
+ int ret;
+
+ ofs16 = (offset / 8)*5;
+ ofs8 = (offset / 4)*5;
+
+ ofs16 += (K056832_CurGfxBank*5*1024);
+ ofs8 += (K056832_CurGfxBank*10*1024);
+
+ if (!K056832_rombase)
+ {
+ K056832_rombase = memory_region(K056832_memory_region);
+ }
+ rombase = (UINT8 *)K056832_rombase;
+
+ ret = (rombase[ofs8+4]<<8);
+ if ((offset % 8) >= 4)
+ {
+ ret |= (rombase[ofs16+1]<<24) | (rombase[ofs16+3]<<16);
+ }
+ else
+ {
+ ret |= (rombase[ofs16]<<24) | (rombase[ofs16+2]<<16);
+ }
+
+ return ret;
+}
+
+// data is arranged like this:
+// 0000 1111 22 0000 1111 22
+READ16_HANDLER( K056832_mw_rom_word_r )
+{
+ int bank = 10240*K056832_CurGfxBank;
+ int addr;
+
+ if (!K056832_rombase)
+ {
+ K056832_rombase = memory_region(K056832_memory_region);
+ }
+
+ if (K056832_regsb[2] & 0x8)
+ {
+ // we want only the 2s
+ int bit;
+ int res, temp;
+
+ bit = offset % 4;
+ addr = (offset / 4) * 5;
+
+ temp = K056832_rombase[addr+4+bank];
+
+ switch (bit)
+ {
+ default:
+ case 0:
+ res = (temp & 0x80) << 5;
+ res |= ((temp & 0x40) >> 2);
+ break;
+
+ case 1:
+ res = (temp & 0x20) << 7;
+ res |= (temp & 0x10);
+ break;
+
+ case 2:
+ res = (temp & 0x08) << 9;
+ res |= ((temp & 0x04) << 2);
+ break;
+
+ case 3:
+ res = (temp & 0x02) << 11;
+ res |= ((temp & 0x01) << 4);
+ break;
+ }
+
+ return res;
+ }
+ else
+ {
+ // we want only the 0s and 1s.
+
+ addr = (offset>>1) * 5;
+
+ if (offset & 1)
+ {
+ addr += 2;
+ }
+
+ addr += bank;
+
+ return K056832_rombase[addr+1] | (K056832_rombase[addr] << 8);
+ }
+
+ return 0;
+}
+
+READ16_HANDLER( K056832_bishi_rom_word_r )
+{
+ int addr = 0x4000*K056832_CurGfxBank+offset;
+
+ if (!K056832_rombase)
+ {
+ K056832_rombase = memory_region(K056832_memory_region);
+ }
+
+ return K056832_rombase[addr+2] | (K056832_rombase[addr] << 8);
+}
+
+READ16_HANDLER( K056832_rom_word_8000_r )
+{
+ int addr = 0x8000*K056832_CurGfxBank + 2*offset;
+
+ if (!K056832_rombase)
+ {
+ K056832_rombase = memory_region(K056832_memory_region);
+ }
+
+ return K056832_rombase[addr+2] | (K056832_rombase[addr] << 8);
+}
+
+READ16_HANDLER( K056832_old_rom_word_r )
+{
+ int addr = 0x2000*K056832_CurGfxBank + (2*offset);
+
+ if (!K056832_rombase)
+ {
+ K056832_rombase = memory_region(K056832_memory_region);
+ }
+
+ return K056832_rombase[addr+1] | (K056832_rombase[addr] << 8);
+}
+
+READ32_HANDLER( K056832_rom_long_r )
+{
+ offset <<= 1;
+ return (K056832_rom_word_r(offset+1, 0xffff) | (K056832_rom_word_r(offset, 0xffff)<<16));
+}
+
+/* only one page is mapped to videoram at a time through a window */
+READ16_HANDLER( K056832_ram_word_r )
+{
+ // reading from tile RAM resets the ROM readback "half" offset
+ K056832_rom_half = 0;
+
+ return K056832_videoram[K056832_SelectedPagex4096+offset];
+}
+
+READ16_HANDLER( K056832_ram_half_word_r )
+{
+ return K056832_videoram[K056832_SelectedPagex4096+(((offset << 1) & 0xffe) | ((offset >> 11) ^ 1))];
+}
+
+READ32_HANDLER( K056832_ram_long_r )
+{
+ UINT16 *pMem = &K056832_videoram[K056832_SelectedPagex4096+offset*2];
+
+ // reading from tile RAM resets the ROM readback "half" offset
+ K056832_rom_half = 0;
+
+ return(pMem[0]<<16 | pMem[1]);
+}
+
+/* special 8-bit handlers for Lethal Enforcers */
+READ8_HANDLER( K056832_ram_code_lo_r )
+{
+ UINT16 *adr = &K056832_videoram[K056832_SelectedPagex4096+(offset*2)+1];
+
+ return *adr & 0xff;
+}
+
+READ8_HANDLER( K056832_ram_code_hi_r )
+{
+ UINT16 *adr = &K056832_videoram[K056832_SelectedPagex4096+(offset*2)+1];
+
+ return *adr>>8;
+}
+
+READ8_HANDLER( K056832_ram_attr_lo_r )
+{
+ UINT16 *adr = &K056832_videoram[K056832_SelectedPagex4096+(offset*2)];
+
+ return *adr & 0xff;
+}
+
+READ8_HANDLER( K056832_ram_attr_hi_r )
+{
+ UINT16 *adr = &K056832_videoram[K056832_SelectedPagex4096+(offset*2)];
+
+ return *adr>>8;
+}
+
+WRITE8_HANDLER( K056832_ram_code_lo_w )
+{
+ UINT16 *adr = &K056832_videoram[K056832_SelectedPagex4096+(offset*2)+1];
+
+ *adr &= 0xff00;
+ *adr |= data;
+
+ if (!(K056832_regs[0] & 0x02)) // external linescroll enable
+ {
+ if (K056832_PageTileMode[K056832_SelectedPage])
+ tilemap_mark_tile_dirty(K056832_tilemap[K056832_SelectedPage], offset);
+ else
+ K056832_mark_line_dirty(K056832_SelectedPage, offset);
+ }
+}
+
+WRITE8_HANDLER( K056832_ram_code_hi_w )
+{
+ UINT16 *adr = &K056832_videoram[K056832_SelectedPagex4096+(offset*2)+1];
+
+ *adr &= 0x00ff;
+ *adr |= data<<8;
+
+ if (!(K056832_regs[0] & 0x02)) // external linescroll enable
+ {
+ if (K056832_PageTileMode[K056832_SelectedPage])
+ tilemap_mark_tile_dirty(K056832_tilemap[K056832_SelectedPage], offset);
+ else
+ K056832_mark_line_dirty(K056832_SelectedPage, offset);
+ }
+}
+
+WRITE8_HANDLER( K056832_ram_attr_lo_w )
+{
+ UINT16 *adr = &K056832_videoram[K056832_SelectedPagex4096+(offset*2)];
+
+ *adr &= 0xff00;
+ *adr |= data;
+
+ if (!(K056832_regs[0] & 0x02)) // external linescroll enable
+ {
+ if (K056832_PageTileMode[K056832_SelectedPage])
+ tilemap_mark_tile_dirty(K056832_tilemap[K056832_SelectedPage], offset);
+ else
+ K056832_mark_line_dirty(K056832_SelectedPage, offset);
+ }
+}
+
+WRITE8_HANDLER( K056832_ram_attr_hi_w )
+{
+ UINT16 *adr = &K056832_videoram[K056832_SelectedPagex4096+(offset*2)];
+
+ *adr &= 0x00ff;
+ *adr |= data<<8;
+
+ if (!(K056832_regs[0] & 0x02)) // external linescroll enable
+ {
+ if (K056832_PageTileMode[K056832_SelectedPage])
+ tilemap_mark_tile_dirty(K056832_tilemap[K056832_SelectedPage], offset);
+ else
+ K056832_mark_line_dirty(K056832_SelectedPage, offset);
+ }
+}
+
+WRITE16_HANDLER( K056832_ram_word_w )
+{
+ UINT16 *tile_ptr;
+ UINT16 old_mask, old_data;
+
+ tile_ptr = &K056832_videoram[K056832_SelectedPagex4096+offset];
+ old_mask = mem_mask;
+ mem_mask = ~mem_mask;
+ old_data = *tile_ptr;
+ data = (data & mem_mask) | (old_data & old_mask);
+
+ if(data != old_data)
+ {
+ offset >>= 1;
+ *tile_ptr = data;
+
+ if (K056832_PageTileMode[K056832_SelectedPage])
+ tilemap_mark_tile_dirty(K056832_tilemap[K056832_SelectedPage], offset);
+ else
+ K056832_mark_line_dirty(K056832_SelectedPage, offset);
+ }
+}
+
+WRITE16_HANDLER( K056832_ram_half_word_w )
+{
+ UINT16 *adr = &K056832_videoram[K056832_SelectedPagex4096+(((offset << 1) & 0xffe) | 1)];
+ UINT16 old = *adr;
+
+ COMBINE_DATA(adr);
+ if(*adr != old)
+ {
+ int dofs = (((offset << 1) & 0xffe) | 1);
+
+ dofs >>= 1;
+
+ if (K056832_PageTileMode[K056832_SelectedPage])
+ tilemap_mark_tile_dirty(K056832_tilemap[K056832_SelectedPage], dofs);
+ else
+ K056832_mark_line_dirty(K056832_SelectedPage, dofs);
+ }
+}
+
+WRITE32_HANDLER( K056832_ram_long_w )
+{
+ UINT16 *tile_ptr;
+ UINT32 old_mask, old_data;
+
+ tile_ptr = &K056832_videoram[K056832_SelectedPagex4096+offset*2];
+ old_mask = mem_mask;
+ mem_mask = ~mem_mask;
+ old_data = (UINT32)tile_ptr[0]<<16 | (UINT32)tile_ptr[1];
+ data = (data & mem_mask) | (old_data & old_mask);
+
+ if (data != old_data)
+ {
+ tile_ptr[0] = data>>16;
+ tile_ptr[1] = data;
+
+ if (K056832_PageTileMode[K056832_SelectedPage])
+ tilemap_mark_tile_dirty(K056832_tilemap[K056832_SelectedPage], offset);
+ else
+ K056832_mark_line_dirty(K056832_SelectedPage, offset);
+ }
+}
+
+WRITE16_HANDLER( K056832_word_w )
+{
+ int layer, flip, mask, i;
+ UINT32 old_data, new_data;
+
+ old_data = K056832_regs[offset];
+ COMBINE_DATA(&K056832_regs[offset]);
+ new_data = K056832_regs[offset];
+
+ if (new_data != old_data)
+ {
+ switch(offset)
+ {
+ /* -x-- ---- dotclock select: 0=8Mhz, 1=6Mhz (not used by GX)
+ * --x- ---- screen flip y
+ * ---x ---- screen flip x
+ * ---- --x- external linescroll RAM page enable
+ */
+ case 0x00/2:
+ if ((new_data & 0x30) != (old_data & 0x30))
+ {
+ flip = 0;
+ if (new_data & 0x20) flip |= TILEMAP_FLIPY;
+ if (new_data & 0x10) flip |= TILEMAP_FLIPX;
+ for (i=0; i<K056832_PAGE_COUNT; i++)
+ {
+ tilemap_set_flip(K056832_tilemap[i], flip);
+ }
+ }
+
+ if ((new_data & 0x02) != (old_data & 0x02))
+ {
+ K056832_change_rambank();
+ }
+ break;
+
+ /* -------- -----xxx external irqlines enable (not used by GX)
+ * -------- xx------ tilemap attribute config (FBIT0 and FBIT1)
+ */
+ //case 0x06/2: break;
+
+ // -------- ----DCBA tile mode: 0=512x1, 1=8x8
+ // -------- DCBA---- synchronous scroll: 0=off, 1=on
+ case 0x08/2:
+ for (layer=0; layer<4; layer++)
+ {
+ mask = 1<<layer;
+ i = new_data & mask;
+ if (i != (old_data & mask))
+ {
+ K056832_LayerTileMode[layer] = i;
+ K056832_mark_plane_dirty(layer);
+ }
+ }
+ break;
+
+ /* -------- ------xx layer A linescroll config
+ * -------- ----xx-- layer B linescroll config
+ * -------- --xx---- layer C linescroll config
+ * -------- xx------ layer D linescroll config
+ *
+ * 0: linescroll
+ * 2: rowscroll
+ * 3: xy scroll
+ */
+ //case 0x0a/2: break;
+
+ case 0x32/2:
+ K056832_change_rambank();
+ break;
+
+ case 0x34/2: /* ROM bank select for checksum */
+ case 0x36/2: /* secondary ROM bank select for use with tile banking */
+ K056832_change_rombank();
+ break;
+
+ // extended tile address
+ //case 0x38/2: break;
+
+ // 12 bit (signed) horizontal offset if global HFLIP enabled
+ //case 0x3a/2: break;
+
+ // 11 bit (signed) vertical offset if global VFLIP enabled
+ //case 0x3c/2: break;
+
+ default:
+ layer = offset & 3;
+
+ if (offset >= 0x10/2 && offset <= 0x16/2)
+ {
+ K056832_Y[layer] = (new_data&0x18)>>3;
+ K056832_H[layer] = (new_data&0x3);
+ K056832_ActiveLayer = layer;
+ K056832_UpdatePageLayout();
+ } else
+
+ if (offset >= 0x18/2 && offset <= 0x1e/2)
+ {
+ K056832_X[layer] = (new_data&0x18)>>3;
+ K056832_W[layer] = (new_data&0x03);
+ K056832_ActiveLayer = layer;
+ K056832_UpdatePageLayout();
+ } else
+
+ if (offset >= 0x20/2 && offset <= 0x26/2)
+ {
+ K056832_dy[layer] = (INT16)new_data;
+ } else
+
+ if (offset >= 0x28/2 && offset <= 0x2e/2)
+ {
+ K056832_dx[layer] = (INT16)new_data;
+ }
+ break;
+ }
+ }
+}
+
+WRITE32_HANDLER( K056832_long_w )
+{
+ // GX does access of all 3 widths (8/16/32) so we can't do the
+ // if (ACCESSING_xxx) trick. in particular, 8-bit writes
+ // are used to the tilemap bank register.
+ offset <<= 1;
+ K056832_word_w(offset, data>>16, mem_mask >> 16);
+ K056832_word_w(offset+1, data, mem_mask);
+}
+
+WRITE16_HANDLER( K056832_b_word_w )
+{
+ COMBINE_DATA( &K056832_regsb[offset] );
+}
+
+WRITE8_HANDLER( K056832_w )
+{
+ if (offset & 1)
+ {
+ K056832_word_w((offset>>1), data, 0xff00);
+ }
+ else
+ {
+ K056832_word_w((offset>>1), data<<8, 0x00ff);
+ }
+}
+
+WRITE8_HANDLER( K056832_b_w )
+{
+ if (offset & 1)
+ {
+ K056832_b_word_w((offset>>1), data, 0xff00);
+ }
+ else
+ {
+ K056832_b_word_w((offset>>1), data<<8, 0x00ff);
+ }
+}
+
+WRITE32_HANDLER( K056832_b_long_w )
+{
+ if (ACCESSING_MSW32)
+ {
+ K056832_b_word_w(offset<<1, data>>16, mem_mask >> 16);
+ }
+ if (ACCESSING_LSW32)
+ {
+ K056832_b_word_w((offset<<1)+1, data, mem_mask);
+ }
+}
+
+static int K056832_update_linemap(running_machine *machine, mame_bitmap *bitmap, int page, int flags)
+{
+#define LINE_WIDTH 512
+
+#define DRAW_PIX(N) \
+ if ((pen = src_ptr[N])) \
+ { pen += basepen; xpr_ptr[count+N] = TILEMAP_PIXEL_LAYER0; dst_ptr[count+N] = pen; } else \
+ { xpr_ptr[count+N] = 0; }
+
+ rectangle zerorect;
+ tilemap *tmap;
+ mame_bitmap *pixmap, *xprmap;
+ UINT8 *xprdata;
+ const gfx_element *src_gfx;
+
+ UINT32 *dirty;
+ int all_dirty, line;
+ int offs, mask;
+
+ const pen_t *pal_ptr;
+ const UINT8 *src_base, *src_ptr;
+ UINT8 *xpr_ptr;
+ UINT16 *dst_ptr;
+ UINT16 pen, basepen;
+ int count, src_pitch, src_modulo;
+ int dst_pitch;
+
+ UINT8 code_transparent, code_opaque;
+
+ if (K056832_PageTileMode[page]) return(0);
+ if (!K056832_linemap_enabled) return(1);
+
+ tmap = K056832_tilemap[page];
+ pixmap = K056832_pixmap[page];
+ xprmap = tilemap_get_flagsmap(tmap);
+ xprdata = tilemap_get_tile_flags(tmap);
+
+ dirty = K056832_LineDirty[page];
+ all_dirty = K056832_AllLinesDirty[page];
+
+ if (all_dirty)
+ {
+ dirty[7]=dirty[6]=dirty[5]=dirty[4]=dirty[3]=dirty[2]=dirty[1]=dirty[0] = 0;
+ K056832_AllLinesDirty[page] = 0;
+
+ // force tilemap into a clean, static state
+ // *really ugly but it minimizes alteration to tilemap.c
+ memset (&zerorect, 0, sizeof(rectangle)); // zero dimension
+ tilemap_draw(bitmap, &zerorect, tmap, 0, 0); // dummy call to reset tile_dirty_map
+ fillbitmap(xprmap, 0, 0); // reset pixel transparency_bitmap;
+ memset(xprdata, TILEMAP_PIXEL_LAYER0, 0x800); // reset tile transparency_data;
+ }
+ else
+ {
+ if (!(dirty[0]|dirty[1]|dirty[2]|dirty[3]|dirty[4]|dirty[5]|dirty[6]|dirty[7])) return(0);
+ }
+
+ pal_ptr = machine->remapped_colortable;
+ src_gfx = machine->gfx[K056832_gfxnum];
+ src_base = src_gfx->gfxdata;
+ src_pitch = src_gfx->line_modulo;
+ src_modulo = src_gfx->char_modulo;
+ xpr_ptr = (UINT8*)xprmap->base + LINE_WIDTH;
+ dst_ptr = (UINT16*)pixmap->base + LINE_WIDTH;
+ dst_pitch = pixmap->rowpixels;
+
+ for (line=0; line<256; xpr_ptr+=dst_pitch, dst_ptr+=dst_pitch, line++)
+ {
+ tile_data *tileinfo = {0};
+ if (!all_dirty)
+ {
+ offs = line >> 5;
+ mask = 1 << (line & 0x1f);
+ if (!(dirty[offs] & mask)) continue;
+ dirty[offs] ^= mask;
+ }
+
+ K056832_get_tile_info(machine, tileinfo, line, page);
+ src_ptr = tileinfo->pen_data;//src_base + ((tileinfo->tile_number & ~7) << 6);
+ basepen = tileinfo->palette_base;
+ code_transparent = tileinfo->category;
+ code_opaque = code_transparent | TILEMAP_PIXEL_LAYER0;
+ count = -LINE_WIDTH;
+
+ do
+ {
+ DRAW_PIX(0)
+ DRAW_PIX(1)
+ DRAW_PIX(2)
+ DRAW_PIX(3)
+ DRAW_PIX(4)
+ DRAW_PIX(5)
+ DRAW_PIX(6)
+ DRAW_PIX(7)
+
+ src_ptr += 8;
+ }
+ while (count += 8);
+ }
+
+ return(0);
+
+#undef LINE_WIDTH
+#undef DRAW_PIX
+}
+
+void K056832_tilemap_draw(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int layer, int flags, UINT32 priority)
+{
+ static int last_colorbase[K056832_PAGE_COUNT];
+
+ UINT32 last_dx, last_visible, new_colorbase, last_active;
+ int sx, sy, ay, tx, ty, width, height;
+ int clipw, clipx, cliph, clipy, clipmaxy;
+ int line_height, line_endy, line_starty, line_y;
+ int sdat_start, sdat_walk, sdat_adv, sdat_wrapmask, sdat_offs;
+ int pageIndex, flipx, flipy, corr, r, c;
+ int cminy, cmaxy, cminx, cmaxx;
+ int dminy, dmaxy, dminx, dmaxx;
+ rectangle drawrect;
+ tilemap *tmap;
+ UINT16 *pScrollData;
+ UINT16 ram16[2];
+
+ int rowstart = K056832_Y[layer];
+ int colstart = K056832_X[layer];
+ int rowspan = K056832_H[layer]+1;
+ int colspan = K056832_W[layer]+1;
+ int dy = K056832_dy[layer];
+ int dx = K056832_dx[layer];
+ int scrollbank = ((K056832_regs[0x18]>>1) & 0xc) | (K056832_regs[0x18] & 3);
+ int scrollmode = K056832_regs[0x05]>>(K056832_LSRAMPage[layer][0]<<1) & 3;
+
+ if (K056832_use_ext_linescroll)
+ {
+ scrollbank = K056832_PAGE_COUNT;
+ }
+
+ height = rowspan * K056832_PAGE_HEIGHT;
+ width = colspan * K056832_PAGE_WIDTH;
+
+ cminx = cliprect->min_x;
+ cmaxx = cliprect->max_x;
+ cminy = cliprect->min_y;
+ cmaxy = cliprect->max_y;
+
+ // flip correction registers
+ if ((flipy = K056832_regs[0] & 0x20))
+ {
+ corr = K056832_regs[0x3c/2];
+ if (corr & 0x400)
+ corr |= 0xfffff800;
+ } else corr = 0;
+ dy += corr;
+ ay = (unsigned)(dy - K056832_LayerOffset[layer][1]) % height;
+
+ if ((flipx = K056832_regs[0] & 0x10))
+ {
+ corr = K056832_regs[0x3a/2];
+ if (corr & 0x800)
+ corr |= 0xfffff000;
+ } else corr = 0;
+ corr -= K056832_LayerOffset[layer][0];
+
+ if (scrollmode == 0 && (flags & TILE_LINE_DISABLED))
+ {
+ scrollmode = 3;
+ flags &= ~TILE_LINE_DISABLED;
+ }
+
+ switch( scrollmode )
+ {
+ case 0: // linescroll
+ pScrollData = &K056832_videoram[scrollbank<<12] + (K056832_LSRAMPage[layer][1]>>1);
+ line_height = 1;
+ sdat_wrapmask = 0x3ff;
+ sdat_adv = 2;
+ break;
+ case 2: // rowscroll
+
+ pScrollData = &K056832_videoram[scrollbank<<12] + (K056832_LSRAMPage[layer][1]>>1);
+ line_height = 8;
+ sdat_wrapmask = 0x3ff;
+ sdat_adv = 16;
+ break;
+ default: // xyscroll
+ pScrollData = ram16;
+ line_height = K056832_PAGE_HEIGHT;
+ sdat_wrapmask = 0;
+ sdat_adv = 0;
+ ram16[0] = 0;
+ ram16[1] = dx;
+ }
+ if (flipy) sdat_adv = -sdat_adv;
+
+ last_active = K056832_ActiveLayer;
+ new_colorbase = (K056832_UpdateMode) ? K055555_get_palette_index(layer) : 0;
+
+ for (r=0; r<rowspan; r++)
+ {
+ if (rowspan > 1)
+ {
+ sy = ay;
+ ty = r * K056832_PAGE_HEIGHT;
+
+ if (!flipy)
+ {
+ // handle bottom-edge wraparoundness and cull off-screen tilemaps
+ if ((r == 0) && (sy > height - K056832_PAGE_HEIGHT)) sy -= height;
+ if ((sy + K056832_PAGE_HEIGHT <= ty) || (sy - K056832_PAGE_HEIGHT >= ty)) continue;
+
+ // switch frame of reference and clip y
+ if ((ty -= sy) >= 0)
+ {
+ cliph = K056832_PAGE_HEIGHT - ty;
+ clipy = line_starty = ty;
+ line_endy = K056832_PAGE_HEIGHT;
+ sdat_start = 0;
+ }
+ else
+ {
+ cliph = K056832_PAGE_HEIGHT + ty;
+ ty = -ty;
+ clipy = line_starty = 0;
+ line_endy = cliph;
+ sdat_start = ty;
+ if (scrollmode == 2) { sdat_start &= ~7; line_starty -= ty & 7; }
+ }
+ }
+ else
+ {
+ ty += K056832_PAGE_HEIGHT;
+
+ // handle top-edge wraparoundness and cull off-screen tilemaps
+ if ((r == rowspan-1) && (sy < K056832_PAGE_HEIGHT)) sy += height;
+ if ((sy + K056832_PAGE_HEIGHT <= ty) || (sy - K056832_PAGE_HEIGHT >= ty)) continue;
+
+ // switch frame of reference and clip y
+ if ((ty -= sy) <= 0)
+ {
+ cliph = K056832_PAGE_HEIGHT + ty;
+ clipy = line_starty = -ty;
+ line_endy = K056832_PAGE_HEIGHT;
+ sdat_start = K056832_PAGE_HEIGHT-1;
+ if (scrollmode == 2) sdat_start &= ~7;
+ }
+ else
+ {
+ cliph = K056832_PAGE_HEIGHT - ty;
+ clipy = line_starty = 0;
+ line_endy = cliph;
+ sdat_start = cliph-1;
+ if (scrollmode == 2) { sdat_start &= ~7; line_starty -= ty & 7; }
+ }
+ }
+ }
+ else
+ {
+ cliph = line_endy = K056832_PAGE_HEIGHT;
+ clipy = line_starty = 0;
+
+ if (!flipy)
+ sdat_start = dy;
+ else
+ /*
+ doesn't work with Metamorphic Force and Martial Champion (software Y-flipped) but
+ LE2U (naturally Y-flipped) seems to expect this condition as an override.
+
+ sdat_start = K056832_PAGE_HEIGHT-1 -dy;
+ */
+ sdat_start = K056832_PAGE_HEIGHT-1;
+
+ if (scrollmode == 2) { sdat_start &= ~7; line_starty -= dy & 7; }
+ }
+
+ sdat_start += r * K056832_PAGE_HEIGHT;
+ sdat_start <<= 1;
+
+ clipmaxy = clipy + cliph - 1;
+
+ for (c=0; c<colspan; c++)
+ {
+ pageIndex = (((rowstart + r) & 3) << 2) + ((colstart + c) & 3);
+
+ if (K056832_LayerAssociation)
+ {
+ if (K056832_LayerAssociatedWithPage[pageIndex] != layer) continue;
+ }
+ else
+ {
+ if (K056832_LayerAssociatedWithPage[pageIndex] == -1) continue;
+ K056832_ActiveLayer = layer;
+ }
+
+ if (K056832_UpdateMode)
+ {
+ if (last_colorbase[pageIndex] != new_colorbase)
+ {
+ last_colorbase[pageIndex] = new_colorbase;
+ K056832_mark_page_dirty(pageIndex);
+ }
+ }
+ else
+ if (!pageIndex) K056832_ActiveLayer = 0;
+
+ if (K056832_update_linemap(machine, bitmap, pageIndex, flags)) continue;
+
+ tmap = K056832_tilemap[pageIndex];
+ tilemap_set_scrolly(tmap, 0, ay);
+
+ last_dx = 0x100000;
+ last_visible = 0;
+
+ for (sdat_walk=sdat_start, line_y=line_starty; line_y<line_endy; sdat_walk+=sdat_adv, line_y+=line_height)
+ {
+ dminy = line_y;
+ dmaxy = line_y + line_height - 1;
+
+ if (dminy < clipy) dminy = clipy;
+ if (dmaxy > clipmaxy) dmaxy = clipmaxy;
+ if (dminy > cmaxy || dmaxy < cminy) continue;
+
+ sdat_offs = sdat_walk & sdat_wrapmask;
+
+ drawrect.min_y = (dminy < cminy ) ? cminy : dminy;
+ drawrect.max_y = (dmaxy > cmaxy ) ? cmaxy : dmaxy;
+
+ dx = ((int)pScrollData[sdat_offs]<<16 | (int)pScrollData[sdat_offs+1]) + corr;
+
+ if (last_dx == dx) { if (last_visible) goto LINE_SHORTCIRCUIT; continue; }
+ last_dx = dx;
+
+ if (colspan > 1)
+ {
+ //sx = (unsigned)dx % width;
+ sx = (unsigned)dx & (width-1);
+
+ //tx = c * K056832_PAGE_WIDTH;
+ tx = c << 9;
+
+ if (!flipx)
+ {
+ // handle right-edge wraparoundness and cull off-screen tilemaps
+ if ((c == 0) && (sx > width - K056832_PAGE_WIDTH)) sx -= width;
+ if ((sx + K056832_PAGE_WIDTH <= tx) || (sx - K056832_PAGE_WIDTH >= tx))
+ { last_visible = 0; continue; }
+
+ // switch frame of reference and clip x
+ if ((tx -= sx) <= 0) { clipw = K056832_PAGE_WIDTH + tx; clipx = 0; }
+ else { clipw = K056832_PAGE_WIDTH - tx; clipx = tx; }
+ }
+ else
+ {
+ tx += K056832_PAGE_WIDTH;
+
+ // handle left-edge wraparoundness and cull off-screen tilemaps
+ if ((c == colspan-1) && (sx < K056832_PAGE_WIDTH)) sx += width;
+ if ((sx + K056832_PAGE_WIDTH <= tx) || (sx - K056832_PAGE_WIDTH >= tx))
+ { last_visible = 0; continue; }
+
+ // switch frame of reference and clip y
+ if ((tx -= sx) >= 0) { clipw = K056832_PAGE_WIDTH - tx; clipx = 0; }
+ else { clipw = K056832_PAGE_WIDTH + tx; clipx = -tx; }
+ }
+ }
+ else { clipw = K056832_PAGE_WIDTH; clipx = 0; }
+
+ last_visible = 1;
+
+ dminx = clipx;
+ dmaxx = clipx + clipw - 1;
+
+ drawrect.min_x = (dminx < cminx ) ? cminx : dminx;
+ drawrect.max_x = (dmaxx > cmaxx ) ? cmaxx : dmaxx;
+
+ tilemap_set_scrollx(tmap, 0, dx);
+
+ LINE_SHORTCIRCUIT:
+ tilemap_draw(bitmap, &drawrect, tmap, flags, priority);
+
+ } // end of line loop
+ } // end of column loop
+ } // end of row loop
+
+ K056832_ActiveLayer = last_active;
+
+} // end of function
+
+void K056832_tilemap_draw_dj(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int layer, int flags, UINT32 priority) //*
+{
+ static int last_colorbase[K056832_PAGE_COUNT];
+
+ UINT32 last_dx, last_visible, new_colorbase, last_active;
+ int sx, sy, ay, tx, ty, width, height;
+ int clipw, clipx, cliph, clipy, clipmaxy;
+ int line_height, line_endy, line_starty, line_y;
+ int sdat_start, sdat_walk, sdat_adv, sdat_wrapmask, sdat_offs;
+ int pageIndex, flipx, flipy, corr, r, c;
+ int cminy, cmaxy, cminx, cmaxx;
+ int dminy, dmaxy, dminx, dmaxx;
+ rectangle drawrect;
+ tilemap *tmap;
+ UINT16 *pScrollData;
+ UINT16 ram16[2];
+
+ int rowstart = K056832_Y[layer];
+ int colstart = K056832_X[layer];
+ int rowspan = K056832_H[layer]+1;
+ int colspan = K056832_W[layer]+1;
+ int dy = K056832_dy[layer];
+ int dx = K056832_dx[layer];
+ int scrollbank = ((K056832_regs[0x18]>>1) & 0xc) | (K056832_regs[0x18] & 3);
+ int scrollmode = K056832_regs[0x05]>>(K056832_LSRAMPage[layer][0]<<1) & 3;
+ int need_wrap = -1;
+
+ height = rowspan * K056832_PAGE_HEIGHT;
+ width = colspan * K056832_PAGE_WIDTH;
+
+ cminx = cliprect->min_x;
+ cmaxx = cliprect->max_x;
+ cminy = cliprect->min_y;
+ cmaxy = cliprect->max_y;
+
+ // flip correction registers
+ if ((flipy = K056832_regs[0] & 0x20))
+ {
+ corr = K056832_regs[0x3c/2];
+ if (corr & 0x400)
+ corr |= 0xfffff800;
+ } else corr = 0;
+ dy += corr;
+ ay = (unsigned)(dy - K056832_LayerOffset[layer][1]) % height;
+
+ if ((flipx = K056832_regs[0] & 0x10))
+ {
+ corr = K056832_regs[0x3a/2];
+ if (corr & 0x800)
+ corr |= 0xfffff000;
+ } else corr = 0;
+ corr -= K056832_LayerOffset[layer][0];
+
+ if (scrollmode == 0 && (flags & TILE_LINE_DISABLED))
+ {
+ scrollmode = 3;
+ flags &= ~TILE_LINE_DISABLED;
+ }
+
+ switch( scrollmode )
+ {
+ case 0: // linescroll
+ pScrollData = &K056832_videoram[scrollbank<<12] + (K056832_LSRAMPage[layer][1]>>1);
+ line_height = 1;
+ sdat_wrapmask = 0x3ff;
+ sdat_adv = 2;
+ break;
+ case 2: // rowscroll
+ pScrollData = &K056832_videoram[scrollbank<<12] + (K056832_LSRAMPage[layer][1]>>1);
+ line_height = 8;
+ sdat_wrapmask = 0x3ff;
+ sdat_adv = 16;
+ break;
+ default: // xyscroll
+ pScrollData = ram16;
+ line_height = K056832_PAGE_HEIGHT;
+ sdat_wrapmask = 0;
+ sdat_adv = 0;
+ ram16[0] = 0;
+ ram16[1] = dx;
+ }
+ if (flipy) sdat_adv = -sdat_adv;
+
+ last_active = K056832_ActiveLayer;
+ new_colorbase = (K056832_UpdateMode) ? K055555_get_palette_index(layer) : 0;
+
+ for (r=0; r<=rowspan; r++)
+ {
+ sy = ay;
+ if (r == rowspan)
+ {
+ if (need_wrap < 0)
+ continue;
+
+ ty = need_wrap * K056832_PAGE_HEIGHT;
+ }
+ else
+ {
+ ty = r * K056832_PAGE_HEIGHT;
+ }
+
+ // cull off-screen tilemaps
+ if ((sy + height <= ty) || (sy - height >= ty)) continue;
+
+ // switch frame of reference
+ ty -= sy;
+
+ // handle top-edge wraparoundness
+ if (r == rowspan)
+ {
+ cliph = K056832_PAGE_HEIGHT + ty;
+ clipy = line_starty = 0;
+ line_endy = cliph;
+ ty = -ty;
+ sdat_start = ty;
+ if (scrollmode == 2) { sdat_start &= ~7; line_starty -= ty & 7; }
+ }
+
+ // clip y
+ else
+ {
+ if (ty < 0)
+ ty += height;
+
+ clipy = ty;
+ cliph = K056832_PAGE_HEIGHT;
+
+ if (clipy + cliph > height)
+ {
+ cliph = height - clipy;
+ need_wrap =r;
+ }
+
+ line_starty = ty;
+ line_endy = line_starty + cliph;
+ sdat_start = 0;
+ }
+
+ if (r == rowspan)
+ sdat_start += need_wrap * K056832_PAGE_HEIGHT;
+ else
+ sdat_start += r * K056832_PAGE_HEIGHT;
+ sdat_start <<= 1;
+
+ clipmaxy = clipy + cliph - 1;
+
+ for (c=0; c<colspan; c++)
+ {
+ if (r == rowspan)
+ pageIndex = (((rowstart + need_wrap) & 3) << 2) + ((colstart + c) & 3);
+ else
+ pageIndex = (((rowstart + r) & 3) << 2) + ((colstart + c) & 3);
+
+ if (K056832_LayerAssociation)
+ {
+ if (K056832_LayerAssociatedWithPage[pageIndex] != layer) continue;
+ }
+ else
+ {
+ if (K056832_LayerAssociatedWithPage[pageIndex] == -1) continue;
+ K056832_ActiveLayer = layer;
+ }
+
+ if (K056832_UpdateMode)
+ {
+ if (last_colorbase[pageIndex] != new_colorbase)
+ {
+ last_colorbase[pageIndex] = new_colorbase;
+ K056832_mark_page_dirty(pageIndex);
+ }
+ }
+ else
+ if (!pageIndex) K056832_ActiveLayer = 0;
+
+ if (K056832_update_linemap(machine, bitmap, pageIndex, flags)) continue;
+
+ tmap = K056832_tilemap[pageIndex];
+ tilemap_set_scrolly(tmap, 0, ay);
+
+ last_dx = 0x100000;
+ last_visible = 0;
+
+ for (sdat_walk=sdat_start, line_y=line_starty; line_y<line_endy; sdat_walk+=sdat_adv, line_y+=line_height)
+ {
+ dminy = line_y;
+ dmaxy = line_y + line_height - 1;
+
+ if (dminy < clipy) dminy = clipy;
+ if (dmaxy > clipmaxy) dmaxy = clipmaxy;
+ if (dminy > cmaxy || dmaxy < cminy) continue;
+
+ sdat_offs = sdat_walk & sdat_wrapmask;
+
+ drawrect.min_y = (dminy < cminy ) ? cminy : dminy;
+ drawrect.max_y = (dmaxy > cmaxy ) ? cmaxy : dmaxy;
+
+ dx = ((int)pScrollData[sdat_offs]<<16 | (int)pScrollData[sdat_offs+1]) + corr;
+
+ if (last_dx == dx) { if (last_visible) goto LINE_SHORTCIRCUIT; continue; }
+ last_dx = dx;
+
+ if (colspan > 1)
+ {
+ //sx = (unsigned)dx % width;
+ sx = (unsigned)dx & (width-1);
+
+ //tx = c * K056832_PAGE_WIDTH;
+ tx = c << 9;
+
+ if (!flipx)
+ {
+ // handle right-edge wraparoundness and cull off-screen tilemaps
+ if ((c == 0) && (sx > width - K056832_PAGE_WIDTH)) sx -= width;
+ if ((sx + K056832_PAGE_WIDTH <= tx) || (sx - K056832_PAGE_WIDTH >= tx))
+ { last_visible = 0; continue; }
+
+ // switch frame of reference and clip x
+ if ((tx -= sx) <= 0) { clipw = K056832_PAGE_WIDTH + tx; clipx = 0; }
+ else { clipw = K056832_PAGE_WIDTH - tx; clipx = tx; }
+ }
+ else
+ {
+ tx += K056832_PAGE_WIDTH;
+
+ // handle left-edge wraparoundness and cull off-screen tilemaps
+ if ((c == colspan-1) && (sx < K056832_PAGE_WIDTH)) sx += width;
+ if ((sx + K056832_PAGE_WIDTH <= tx) || (sx - K056832_PAGE_WIDTH >= tx))
+ { last_visible = 0; continue; }
+
+ // switch frame of reference and clip y
+ if ((tx -= sx) >= 0) { clipw = K056832_PAGE_WIDTH - tx; clipx = 0; }
+ else { clipw = K056832_PAGE_WIDTH + tx; clipx = -tx; }
+ }
+ }
+ else { clipw = K056832_PAGE_WIDTH; clipx = 0; }
+
+ last_visible = 1;
+
+ dminx = clipx;
+ dmaxx = clipx + clipw - 1;
+
+ drawrect.min_x = (dminx < cminx ) ? cminx : dminx;
+ drawrect.max_x = (dmaxx > cmaxx ) ? cmaxx : dmaxx;
+
+ tilemap_set_scrollx(tmap, 0, dx);
+
+ LINE_SHORTCIRCUIT:
+ tilemap_draw(bitmap, &drawrect, tmap, flags, priority);
+
+ } // end of line loop
+ } // end of column loop
+ } // end of row loop
+
+ K056832_ActiveLayer = last_active;
+
+} // end of function
+
+void K056832_set_LayerAssociation(int status)
+{
+ K056832_DefaultLayerAssociation = status;
+}
+
+int K056832_get_LayerAssociation(void)
+{
+ return(K056832_LayerAssociation);
+}
+
+void K056832_set_LayerOffset(int layer, int offsx, int offsy)
+{
+ K056832_LayerOffset[layer][0] = offsx;
+ K056832_LayerOffset[layer][1] = offsy;
+}
+
+void K056832_set_LSRAMPage(int logical_page, int physical_page, int physical_offset)
+{
+ K056832_LSRAMPage[logical_page][0] = physical_page;
+ K056832_LSRAMPage[logical_page][1] = physical_offset;
+}
+
+void K056832_set_UpdateMode(int mode)
+{
+ K056832_UpdateMode = mode;
+}
+
+void K056832_linemap_enable(int enable)
+{
+ K056832_linemap_enabled = enable;
+}
+
+int K056832_is_IRQ_enabled(int irqline)
+{
+ return(K056832_regs[0x06/2] & (1<<irqline & 7));
+}
+
+void K056832_read_AVAC(int *mode, int *data)
+{
+ *mode = K056832_regs[0x04/2] & 7;
+ *data = K056832_regs[0x38/2];
+}
+
+int K056832_read_register(int regnum)
+{
+ return(K056832_regs[regnum]);
+}
+
+
+
+/***************************************************************************/
+/* */
+/* 055555 */
+/* */
+/***************************************************************************/
+
+/* K055555 5-bit-per-pixel priority encoder */
+/* This device has 48 8-bit-wide registers */
+
+static UINT8 k55555_regs[128];
+
+void K055555_vh_start(void)
+{
+ state_save_register_global_array(k55555_regs);
+
+ memset(k55555_regs, 0, 64*sizeof(UINT8));
+}
+
+void K055555_write_reg(UINT8 regnum, UINT8 regdat)
+{
+ #if VERBOSE
+ static const char *rnames[46] =
+ {
+ "BGC CBLK", "BGC SET", "COLSET0", "COLSET1", "COLSET2", "COLSET3", "COLCHG ON",
+ "A PRI 0", "A PRI 1", "A COLPRI", "B PRI 0", "B PRI 1", "B COLPRI", "C PRI", "D PRI",
+ "OBJ PRI", "SUB1 PRI", "SUB2 PRI", "SUB3 PRI", "OBJ INPRI ON", "S1 INPRI ON", "S2 INPRI ON",
+ "S3 INPRI ON", "A PAL", "B PAL", "C PAL", "D PAL", "OBJ PAL", "SUB1 PAL", "SUB2 PAL", "SUB3 PAL",
+ "SUB2 PAL ON", "SUB3 PAL ON", "V INMIX", "V INMIX ON", "OS INMIX", "OS INMIX ON", "SHD PRI 1",
+ "SHD PRI 2", "SHD PRI 3", "SHD ON", "SHD PRI SEL", "V BRI", "OS INBRI", "OS INBRI ON", "ENABLE"
+ };
+
+ if (regdat != k55555_regs[regnum])
+ {
+ logerror("5^5: %x to reg %x (%s)\n", regdat, regnum, rnames[regnum]);
+ }
+ #endif
+
+ k55555_regs[regnum] = regdat;
+}
+
+WRITE32_HANDLER( K055555_long_w )
+{
+ UINT8 regnum, regdat;
+
+ if (!(mem_mask & 0xff000000))
+ {
+ regnum = offset<<1;
+ regdat = data>>24;
+ }
+ else
+ {
+ if (!(mem_mask & 0xff00))
+ {
+ regnum = (offset<<1)+1;
+ regdat = data>>8;
+ }
+ else
+ {
+// logerror("5^5: unknown mem_mask %08x\n", mem_mask);
+ return;
+ }
+ }
+
+ K055555_write_reg(regnum, regdat);
+}
+
+WRITE16_HANDLER( K055555_word_w )
+{
+ if (mem_mask == 0xff00)
+ {
+ K055555_write_reg(offset, data&0xff);
+ }
+ else
+ {
+ K055555_write_reg(offset, data>>8);
+ }
+}
+
+int K055555_read_register(int regnum)
+{
+ return(k55555_regs[regnum]);
+}
+
+int K055555_get_palette_index(int idx)
+{
+ return(k55555_regs[K55_PALBASE_A + idx]);
+}
+
+
+
+/***************************************************************************/
+/* */
+/* 054338 */
+/* */
+/***************************************************************************/
+
+static UINT16 k54338_regs[32];
+static int K054338_shdRGB[9];
+static int K054338_alphainverted;
+
+
+// K054338 alpha blend / final mixer (normally used with the 55555)
+// because the implementation is video dependant, this is just a
+// register-handling shell.
+void K054338_vh_start(void)
+{
+ memset(k54338_regs, 0, sizeof(UINT16)*32);
+ memset(K054338_shdRGB, 0, sizeof(int)*9);
+ K054338_alphainverted = 1;
+
+ state_save_register_global_array(k54338_regs);
+}
+
+WRITE16_HANDLER( K054338_word_w )
+{
+ COMBINE_DATA(k54338_regs + offset);
+}
+
+WRITE32_HANDLER( K054338_long_w )
+{
+ offset <<= 1;
+ K054338_word_w(offset, data>>16, mem_mask>>16);
+ K054338_word_w(offset+1, data, mem_mask);
+}
+
+// returns a 16-bit '338 register
+int K054338_read_register(int reg)
+{
+ return k54338_regs[reg];
+}
+
+void K054338_update_all_shadows(running_machine *machine)
+{
+ int i, d;
+ int noclip = k54338_regs[K338_REG_CONTROL] & K338_CTL_CLIPSL;
+
+ for (i=0; i<9; i++)
+ {
+ d = k54338_regs[K338_REG_SHAD1R+i] & 0x1ff;
+ if (d >= 0x100) d -= 0x200;
+ K054338_shdRGB[i] = d;
+ }
+
+ palette_set_shadow_dRGB32(machine, 0, K054338_shdRGB[0], K054338_shdRGB[1], K054338_shdRGB[2], noclip);
+ palette_set_shadow_dRGB32(machine, 1, K054338_shdRGB[3], K054338_shdRGB[4], K054338_shdRGB[5], noclip);
+ palette_set_shadow_dRGB32(machine, 2, K054338_shdRGB[6], K054338_shdRGB[7], K054338_shdRGB[8], noclip);
+}
+
+// K054338 BG color fill
+void K054338_fill_solid_bg(mame_bitmap *bitmap)
+{
+ UINT32 bgcolor;
+ UINT32 *pLine;
+ int x, y;
+
+ bgcolor = (K054338_read_register(K338_REG_BGC_R)&0xff)<<16;
+ bgcolor |= K054338_read_register(K338_REG_BGC_GB);
+
+ /* and fill the screen with it */
+ for (y = 0; y < bitmap->height; y++)
+ {
+ pLine = (UINT32 *)bitmap->base;
+ pLine += (bitmap->rowpixels*y);
+ for (x = 0; x < bitmap->width; x++)
+ *pLine++ = bgcolor;
+ }
+}
+
+// Unified K054338/K055555 BG color fill
+void K054338_fill_backcolor(running_machine *machine, mame_bitmap *bitmap, int mode) // (see p.67)
+{
+ int clipx, clipy, clipw, cliph, i, dst_pitch;
+ int BGC_CBLK, BGC_SET;
+ UINT32 *dst_ptr, *pal_ptr;
+ register int bgcolor;
+
+ clipx = machine->screen[0].visarea.min_x & ~3;
+ clipy = machine->screen[0].visarea.min_y;
+ clipw = (machine->screen[0].visarea.max_x - clipx + 4) & ~3;
+ cliph = machine->screen[0].visarea.max_y - clipy + 1;
+
+ dst_ptr = BITMAP_ADDR32(bitmap, clipy, 0);
+ dst_pitch = bitmap->rowpixels;
+ dst_ptr += clipx;
+
+ BGC_SET = 0;
+ pal_ptr = paletteram32;
+
+ if (!mode)
+ {
+ // single color output from CLTC
+ bgcolor = (int)(k54338_regs[K338_REG_BGC_R]&0xff)<<16 | (int)k54338_regs[K338_REG_BGC_GB];
+ }
+ else
+ {
+ BGC_CBLK = K055555_read_register(0);
+ BGC_SET = K055555_read_register(1);
+ pal_ptr += BGC_CBLK << 9;
+
+ // single color output from PCU2
+ if (!(BGC_SET & 2)) { bgcolor = *pal_ptr; mode = 0; } else bgcolor = 0;
+ }
+
+ if (!mode)
+ {
+ // single color fill
+ dst_ptr += clipw;
+ i = clipw = -clipw;
+ do
+ {
+ do { dst_ptr[i] = dst_ptr[i+1] = dst_ptr[i+2] = dst_ptr[i+3] = bgcolor; } while (i += 4);
+ dst_ptr += dst_pitch;
+ i = clipw;
+ }
+ while (--cliph);
+ }
+ else
+ {
+ if (!(BGC_SET & 1))
+ {
+ // vertical gradient fill
+ pal_ptr += clipy;
+ dst_ptr += clipw;
+ bgcolor = *pal_ptr++;
+ i = clipw = -clipw;
+ do
+ {
+ do { dst_ptr[i] = dst_ptr[i+1] = dst_ptr[i+2] = dst_ptr[i+3] = bgcolor; } while (i += 4);
+ dst_ptr += dst_pitch;
+ bgcolor = *pal_ptr++;
+ i = clipw;
+ }
+ while (--cliph);
+ }
+ else
+ {
+ // horizontal gradient fill
+ pal_ptr += clipx;
+ clipw <<= 2;
+ do
+ {
+ memcpy(dst_ptr, pal_ptr, clipw);
+ dst_ptr += dst_pitch;
+ }
+ while (--cliph);
+ }
+ }
+}
+
+// addition blending unimplemented (requires major changes to drawgfx and tilemap.c)
+int K054338_set_alpha_level(int pblend)
+{
+ UINT16 *regs;
+ int ctrl, mixpri, mixset, mixlv;
+
+ if (pblend <= 0 || pblend > 3)
+ {
+ alpha_set_level(255);
+ return(255);
+ }
+
+ regs = k54338_regs;
+ ctrl = k54338_regs[K338_REG_CONTROL];
+ mixpri = ctrl & K338_CTL_MIXPRI;
+ mixset = regs[K338_REG_PBLEND + (pblend>>1 & 1)] >> (~pblend<<3 & 8);
+ mixlv = mixset & 0x1f;
+
+ if (K054338_alphainverted) mixlv = 0x1f - mixlv;
+
+ if (!(mixset & 0x20))
+ {
+ mixlv = mixlv<<3 | mixlv>>2;
+ alpha_set_level(mixlv); // source x alpha/255 + target x (255-alpha)/255
+ }
+ else
+ {
+ if (!mixpri)
+ {
+ // source x alpha + target (clipped at 255)
+ }
+ else
+ {
+ // source + target x alpha (clipped at 255)
+ }
+
+ // DUMMY
+ if (mixlv && mixlv<0x1f) mixlv = 0x10;
+ mixlv = mixlv<<3 | mixlv>>2;
+ alpha_set_level(mixlv);
+
+ #if VERBOSE
+ popmessage("MIXSET%1d %s addition mode: %02x",pblend,(mixpri)?"dst":"src",mixset&0x1f);
+ #endif
+ }
+
+ return(mixlv);
+}
+
+void K054338_invert_alpha(int invert)
+{
+ K054338_alphainverted = invert;
+}
+
+void K054338_export_config(int **shdRGB)
+{
+ *shdRGB = K054338_shdRGB;
+}
+
+
+
+/***************************************************************************/
+/* */
+/* 053250 */
+/* */
+/***************************************************************************/
+
+static struct
+{
+ int chips;
+ struct K053250_CHIPTAG
+ {
+ UINT8 regs[8];
+ UINT8 *base;
+ UINT16 *ram, *rammax;
+ UINT16 *buffer[2];
+ UINT32 rommask;
+ int page[2];
+ int frame, offsx, offsy;
+ } chip[2];
+} K053250_info;
+
+void K053250_set_LayerOffset(int chip, int offsx, int offsy)
+{
+ K053250_info.chip[chip].offsx = offsx;
+ K053250_info.chip[chip].offsy = offsy;
+}
+
+// The DMA process should be instantaneous but since rendering in MAME is performed at VIDEO_UPDATE()
+// the K053250 memory must be buffered to maintain visual integrity.
+void K053250_dma(int chip, int limiter)
+{
+ struct K053250_CHIPTAG *chip_ptr;
+ int last_frame, current_frame;
+
+ chip_ptr = &K053250_info.chip[chip];
+
+ current_frame = cpu_getcurrentframe();
+ last_frame = chip_ptr->frame;
+
+ if (limiter && current_frame == last_frame) return; // make sure we only do DMA transfer once per frame
+
+ chip_ptr->frame = current_frame;
+ memcpy(chip_ptr->buffer[chip_ptr->page[chip]], chip_ptr->ram, 0x1000);
+ chip_ptr->page[chip] ^= 1;
+}
+
+// Pixel data of the K053250 is nibble packed. It's preferable to be unpacked into byte format.
+void K053250_unpack_pixels(int region)
+{
+ UINT8 *src_ptr, *dst_ptr;
+ int hi_nibble, lo_nibble, offset;
+
+ dst_ptr = src_ptr = memory_region(region);
+ offset = memory_region_length(region) / 2 - 1;
+
+ do
+ {
+ lo_nibble = hi_nibble = src_ptr[offset];
+ hi_nibble >>= 4;
+ lo_nibble &= 0xf;
+ dst_ptr[offset*2 ] = hi_nibble;
+ dst_ptr[offset*2+1] = lo_nibble;
+ }
+ while ((--offset) >= 0);
+}
+
+void K053250_vh_start(int chips, int *region)
+{
+ UINT16 *ram;
+ int chip;
+
+ K053250_info.chips = chips;
+
+ for(chip=0; chip<chips; chip++)
+ {
+ K053250_info.chip[chip].base = memory_region(region[chip]);
+ ram = auto_malloc(0x6000);
+ K053250_info.chip[chip].ram = ram;
+ K053250_info.chip[chip].rammax = ram + 0x800;
+ K053250_info.chip[chip].buffer[0] = ram + 0x2000;
+ K053250_info.chip[chip].buffer[1] = ram + 0x2800;
+ memset(ram+0x2000, 0, 0x2000);
+ K053250_info.chip[chip].rommask = memory_region_length(region[chip]);
+ K053250_info.chip[chip].page[1] = K053250_info.chip[chip].page[0] = 0;
+ K053250_info.chip[chip].offsy = K053250_info.chip[chip].offsx = 0;
+ K053250_info.chip[chip].frame = -1;
+
+ state_save_register_item_pointer("K053250", chip, K053250_info.chip[chip].ram, 0x800);
+ state_save_register_item_array("K053250", chip, K053250_info.chip[chip].regs);
+ }
+}
+
+WRITE16_HANDLER( K053250_0_w )
+{
+ if (ACCESSING_LSB)
+ {
+ // start LVC DMA transfer at the falling edge of control register's bit1
+ if (offset == 4 && !(data & 2) && (K053250_info.chip[0].regs[4] & 2)) K053250_dma(0, 1);
+
+ K053250_info.chip[0].regs[offset] = data;
+ }
+}
+
+READ16_HANDLER( K053250_0_r )
+{
+ return K053250_info.chip[0].regs[offset];
+}
+
+WRITE16_HANDLER( K053250_0_ram_w )
+{
+ COMBINE_DATA( K053250_info.chip[0].ram + offset);
+}
+
+READ16_HANDLER( K053250_0_ram_r )
+{
+ return K053250_info.chip[0].ram[offset];
+}
+
+READ16_HANDLER( K053250_0_rom_r )
+{
+// if (!(K053250_info.chip[0].regs[5] & 1)) logerror("Back: Reading rom memory with enable=0\n");
+
+ return *(K053250_info.chip[0].base + 0x80000*K053250_info.chip[0].regs[6] + 0x800*K053250_info.chip[0].regs[7] + (offset>>1));
+}
+
+WRITE16_HANDLER( K053250_1_w )
+{
+ if (ACCESSING_LSB)
+ {
+ // start LVC DMA transfer at the falling edge of control register's bit1
+ if (offset == 4 && !(data & 2) && (K053250_info.chip[1].regs[4] & 2)) K053250_dma(1, 1);
+
+ K053250_info.chip[1].regs[offset] = data;
+ }
+}
+
+READ16_HANDLER( K053250_1_r )
+{
+ return K053250_info.chip[1].regs[offset];
+}
+
+WRITE16_HANDLER( K053250_1_ram_w )
+{
+ COMBINE_DATA( K053250_info.chip[1].ram + offset);
+}
+
+READ16_HANDLER( K053250_1_ram_r )
+{
+ return K053250_info.chip[1].ram[offset];
+}
+
+READ16_HANDLER( K053250_1_rom_r )
+{
+// if (!(K053250_info.chip[1].regs[5] & 1)) logerror("Back: Reading rom memory with enable=0\n");
+
+ return *(K053250_info.chip[1].base + 0x80000*K053250_info.chip[1].regs[6] + 0x800*K053250_info.chip[1].regs[7] + (offset>>1));
+}
+
+#if 0
+
+static void K053250_pdraw_scanline8(
+ mame_bitmap *bitmap,int x,int y,int length,
+ const UINT8 *src,pen_t *pens,int transparent_pen,UINT32 orient,int pri)
+{
+ /* 8bpp destination */
+ if (bitmap->bpp == 8)
+ {
+ /* adjust in case we're oddly oriented */
+ ADJUST_FOR_ORIENTATION(UINT8, orient, bitmap, priority_bitmap, x, y);
+
+ /* with pen lookups */
+ if (pens)
+ {
+ if (transparent_pen == -1)
+ while (length--)
+ {
+ *dsti = pens[*src++];
+ *dstp = pri;
+ dsti += xadv;
+ dstp += xadv;
+ }
+ else
+ while (length--)
+ {
+ UINT32 spixel = *src++;
+ if (spixel != transparent_pen)
+ {
+ *dsti = pens[spixel];
+ *dstp = pri;
+ }
+ dsti += xadv;
+ dstp += xadv;
+ }
+ }
+
+ /* without pen lookups */
+ else
+ {
+ if (transparent_pen == -1)
+ while (length--)
+ {
+ *dsti = *src++;
+ *dstp = pri;
+ dsti += xadv;
+ dstp += xadv;
+ }
+ else
+ while (length--)
+ {
+ UINT32 spixel = *src++;
+ if (spixel != transparent_pen)
+ {
+ *dsti = spixel;
+ *dstp = pri;
+ }
+ dsti += xadv;
+ dstp += xadv;
+ }
+ }
+ }
+
+ /* 16bpp destination */
+ else if(bitmap->bpp == 16)
+ {
+ /* adjust in case we're oddly oriented */
+ ADJUST_FOR_ORIENTATION(UINT16, orient, bitmap, priority_bitmap, x, y);
+ /* with pen lookups */
+ if (pens)
+ {
+ if (transparent_pen == -1)
+ while (length--)
+ {
+ *dsti = pens[*src++];
+ *dstp = pri;
+ dsti += xadv;
+ dstp += xadv;
+ }
+ else
+ while (length--)
+ {
+ UINT32 spixel = *src++;
+ if (spixel != transparent_pen)
+ {
+ *dsti = pens[spixel];
+ *dstp = pri;
+ }
+ dsti += xadv;
+ dstp += xadv;
+ }
+ }
+
+ /* without pen lookups */
+ else
+ {
+ if (transparent_pen == -1)
+ while (length--)
+ {
+ *dsti = *src++;
+ *dstp = pri;
+ dsti += xadv;
+ dstp += xadv;
+ }
+ else
+ while (length--)
+ {
+ UINT32 spixel = *src++;
+ if (spixel != transparent_pen)
+ {
+ *dsti = spixel;
+ *dstp = pri;
+ }
+ dsti += xadv;
+ dstp += xadv;
+ }
+ }
+ }
+
+ /* 32bpp destination */
+ else
+ {
+ /* adjust in case we're oddly oriented */
+ ADJUST_FOR_ORIENTATION(UINT32, orient, bitmap, priority_bitmap, x, y);
+ /* with pen lookups */
+ if (pens)
+ {
+ if (transparent_pen == -1)
+ while (length--)
+ {
+ *dsti = pens[*src++];
+ *dstp = pri;
+ dsti += xadv;
+ dstp += xadv;
+ }
+ else
+ while (length--)
+ {
+ UINT32 spixel = *src++;
+ if (spixel != transparent_pen)
+ {
+ *dsti = pens[spixel];
+ *dstp = pri;
+ }
+ dsti += xadv;
+ dstp += xadv;
+ }
+ }
+
+ /* without pen lookups */
+ else
+ {
+ if (transparent_pen == -1)
+ while (length--)
+ {
+ *dsti = *src++;
+ *dstp = pri;
+ dsti += xadv;
+ dstp += xadv;
+ }
+ else
+ while (length--)
+ {
+ UINT32 spixel = *src++;
+ if (spixel != transparent_pen)
+ {
+ *dsti = spixel;
+ *dstp = pri;
+ }
+ dsti += xadv;
+ dstp += xadv;
+ }
+ }
+ }
+}
+
+void K053250_draw(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int chip, int colorbase, int pri)
+{
+ static int pmode[2] = {-1,-1};
+ static int kc=-1, kk=0, kxx=-105, kyy=0;
+
+ const rectangle area = machine->screen[0].visarea;
+ UINT16 *line;
+ int delta, dim1, dim1_max, dim2_max;
+ UINT32 mask1, mask2;
+ int sp;
+#if 1
+ int orientation = ((K053250_info.chip[chip].regs[4] & 8) ? ORIENTATION_FLIP_X : 0)
+ | ((K053250_info.chip[chip].regs[4] & 16) ? ORIENTATION_FLIP_Y : 0)
+ | ((K053250_info.chip[chip].regs[4] & 1) ? 0 : ORIENTATION_SWAP_XY);
+#else
+ int orientation = (!K053250_info.chip[chip].regs[4] & 8 ? ORIENTATION_FLIP_X : 0)
+ | (K053250_info.chip[chip].regs[4] & 16 ? ORIENTATION_FLIP_Y : 0)
+ | (!(K053250_info.chip[chip].regs[4] & 1) ? 0 : ORIENTATION_SWAP_XY);
+#endif
+
+ INT16 cur_x = (K053250_info.chip[chip].regs[0] << 8) | K053250_info.chip[chip].regs[1];
+ INT16 cur_y = (K053250_info.chip[chip].regs[2] << 8) | K053250_info.chip[chip].regs[3];
+
+ if(pmode[chip] != K053250_info.chip[chip].regs[4]) {
+ pmode[chip] = K053250_info.chip[chip].regs[4];
+#if 0
+ fprintf(stderr, "NEW MODE %d %02x [%x %c%c%c%c%c]\n", chip,
+ pmode[chip],
+ pmode[chip] >> 5,
+ pmode[chip] & 16 ? 'y' : '-',
+ pmode[chip] & 8 ? 'x' : '-',
+ pmode[chip] & 4 ? 'w' : '-',
+ pmode[chip] & 2 ? '?' : '-',
+ pmode[chip] & 1 ? 's' : '-');
+#endif
+ }
+
+ colorbase <<= 4;
+
+ if(orientation & ORIENTATION_SWAP_XY) {
+ dim1_max = area.max_x - area.min_x + 1;
+ dim2_max = area.max_y - area.min_y + 1;
+ // -358 for level 1 boss, huh? -495
+ if(orientation & ORIENTATION_FLIP_Y)
+ delta = 238 - cur_y;
+ else
+ delta = kyy + cur_y;
+ line = K053250_info.chip[chip].ram + (((area.min_x + cur_x + kxx) & 0x1ff) << 2);
+ } else {
+ dim1_max = area.max_y - area.min_y + 1;
+ dim2_max = area.max_x - area.min_x + 1;
+ delta = cur_x + 49;
+ line = K053250_info.chip[chip].ram + (((area.min_y + cur_y + 16) & 0x1ff) << 2);
+ }
+
+ if(chip && ++kk == 3) {
+ int kx=0, kkc = 0;
+ kk = 0;
+ if(input_code_pressed(KEYCODE_Y)) {
+ kx = 1;
+ kc--;
+ if(kc<-1)
+ kc = 511;
+ }
+ if(input_code_pressed(KEYCODE_U)) {
+ kx = 1;
+ kc++;
+ if(kc==512)
+ kc = -1;
+ }
+
+ if(input_code_pressed(KEYCODE_T)) {
+ kkc = 1;
+ kyy--;
+ }
+ if(input_code_pressed(KEYCODE_V)) {
+ kkc = 1;
+ kyy++;
+ }
+ if(input_code_pressed(KEYCODE_F)) {
+ kkc = 1;
+ kxx--;
+ }
+ if(input_code_pressed(KEYCODE_G)) {
+ kkc = 1;
+ kxx++;
+ }
+#if 0
+ if(kx) {
+ UINT16 *l1 = line + ((4*kc) & 0x7ff);
+ popmessage("Line %d [%02x] (%04x %04x %04x %04x)", kc,
+ K053250_info.chip[chip].regs[4],
+ l1[0],
+ l1[1],
+ l1[2],
+ l1[3]);
+ }
+
+ if(kkc)
+ popmessage("(%d, %d)", kxx, kyy);
+#endif
+ }
+
+
+ switch(K053250_info.chip[chip].regs[4] >> 5) {
+ case 0: // Not sure. Warp level
+ mask1 = 0xffff0000;
+ mask2 = 0x0000ffff;
+ sp = 0;
+ break;
+ case 1: // Elaine's background
+ mask1 = 0xffff8000;
+ mask2 = 0x00007fff;
+ sp = 0;
+ break;
+ case 2:
+ mask1 = 0xffff0000;
+ mask2 = 0x0000ffff;
+ sp = 0;
+ break;
+ case 4: // Level 1 boss, water level (planet)
+ mask1 = 0xffffc000;
+ mask2 = 0x00003fff;
+ sp = 0;
+ break;
+ case 7: // Organic level
+ mask1 = 0xffff0000;
+ mask2 = 0x0000ffff;
+ sp = 1;
+ break;
+ default:
+// logerror("Unknown mode %02x\n", K053250_info.chip[chip].regs[4] & 0xe0);
+ mask1 = 0xffff0000;
+ mask2 = 0x0000ffff;
+ sp = 0;
+ break;
+ }
+
+ if(K053250_info.chip[chip].regs[4] & 4)
+ mask1 = 0;
+
+ for(dim1 = 0; dim1 < dim1_max; dim1++) {
+ UINT16 color = *line++;
+ UINT16 start = *line++;
+ UINT16 inc = *line++;
+ INT16 offset = *line++;
+ int dim2;
+ UINT8 *pixel;
+ UINT32 cpos;
+ UINT8 scanline[512];
+ UINT8 *gbase = K053250_info.chip[chip].base + (((start & 0xff00) << 7) % K053250_info.chip[chip].rommask);
+
+ if(offset >= 0x500)
+ offset -= 0x800;
+
+ if(line == K053250_info.chip[chip].rammax)
+ line = K053250_info.chip[chip].ram;
+
+ if(!color && !start)
+ continue;
+
+ pixel = scanline;
+ start = (start & 0xff) << 7;
+ cpos = (offset + delta)*inc;
+ // fprintf(stderr, "%3d %08x %04x\n", dim1, cpos, inc);
+
+ for(dim2 = 0; dim2 < dim2_max; dim2++) {
+ int romp;
+ UINT32 rcpos = cpos;
+
+ if(sp && (rcpos & mask1))
+ rcpos += inc << 9;
+
+ if(rcpos & mask1) {
+ *pixel++ = 0;
+ cpos += inc;
+ continue;
+ }
+
+ romp = gbase[(((rcpos & mask2)>>7) + start) & 0x7fff];
+
+ if(rcpos & 0x40)
+ romp &= 0xf;
+ else
+ romp >>= 4;
+ *pixel++ = romp;
+ cpos += inc;
+ }
+ if(orientation & ORIENTATION_SWAP_XY)
+ K053250_pdraw_scanline8(bitmap, area.min_y, area.min_x+dim1, dim2_max, scanline,
+ machine->pens + ((dim1 == kc ? 0x200 : colorbase) | ((color & 0x0f) << 4)),
+ 0, orientation, pri);
+ else
+ K053250_pdraw_scanline8(bitmap, area.min_x, area.min_y+dim1, dim2_max, scanline,
+ machine->pens + ((dim1 == kc ? 0x200 : colorbase) | ((color & 0x0f) << 4)),
+ 0, orientation, pri);
+ }
+}
+
+#else
+
+// utility function to render a clipped scanline vertically or horizontally
+INLINE void K053250_pdraw_scanline32(mame_bitmap *bitmap, const pen_t *palette, UINT8 *source,
+ const rectangle *cliprect, int linepos, int scroll, int zoom,
+ UINT32 clipmask, UINT32 wrapmask, UINT32 orientation, int priority)
+{
+// a sixteen-bit fixed point resolution should be adequate to our application
+#define FIXPOINT_PRECISION 16
+#define FIXPOINT_PRECISION_HALF (1<<(FIXPOINT_PRECISION-1))
+
+ int end_pixel, flip, dst_min, dst_max, dst_start, dst_length;
+
+ UINT32 src_wrapmask;
+ UINT8 *src_base;
+ int src_x;
+ int src_fx, src_fdx;
+ int pix_data, dst_offset;
+ const pen_t *pal_base;
+ UINT8 *pri_base;
+ UINT32 *dst_base;
+ int dst_adv;
+ UINT8 pri;
+
+ // flip X and flip Y also switch role when the X Y coordinates are swapped
+ if (!(orientation & ORIENTATION_SWAP_XY))
+ {
+ flip = orientation & ORIENTATION_FLIP_X;
+ dst_min = cliprect->min_x;
+ dst_max = cliprect->max_x;
+ }
+ else
+ {
+ flip = orientation & ORIENTATION_FLIP_Y;
+ dst_min = cliprect->min_y;
+ dst_max = cliprect->max_y;
+ }
+
+ if (clipmask)
+ {
+ // reject scanlines that are outside of the target bitmap's right(bottom) clip boundary
+ dst_start = -scroll;
+ if (dst_start > dst_max) return;
+
+ // calculate target length
+ dst_length = clipmask + 1;
+ if (zoom) dst_length = (dst_length << 6) / zoom;
+
+ // reject scanlines that are outside of the target bitmap's left(top) clip boundary
+ end_pixel = dst_start + dst_length - 1;
+ if (end_pixel < dst_min) return;
+
+ // clip scanline tail
+ if ((end_pixel -= dst_max) > 0) dst_length -= end_pixel;
+
+ // reject zero-length scanlines
+ if (dst_length <= 0) return;
+
+ // calculate zoom factor
+ src_fdx = zoom << (FIXPOINT_PRECISION-6);
+
+ // clip scanline head
+ end_pixel = dst_min;
+ if ((end_pixel -= dst_start) > 0)
+ {
+ // chop scanline to the correct length and move target start location to the left(top) clip boundary
+ dst_length -= end_pixel;
+ dst_start = dst_min;
+
+ // and skip the source for the left(top) clip region
+ src_fx = end_pixel * src_fdx + FIXPOINT_PRECISION_HALF;
+ }
+ else
+ // the point five bias is to ensure even distribution of stretched or shrinked pixels
+ src_fx = FIXPOINT_PRECISION_HALF;
+
+ // adjust flipped source
+ if (flip)
+ {
+ // start from the target's clipped end if the scanline is flipped
+ dst_start = dst_max + dst_min - dst_start - (dst_length-1);
+
+ // and move source start location to the opposite end
+ src_fx += (dst_length-1) * src_fdx - 1;
+ src_fdx = -src_fdx;
+ }
+ }
+ else
+ {
+ // draw wrapped scanline at virtual bitmap boundary when source clipping is off
+ dst_start = dst_min;
+ dst_length = dst_max - dst_min + 1; // target scanline spans the entire visible area
+ src_fdx = zoom << (FIXPOINT_PRECISION-6);
+
+ // pre-advance source for the clipped region
+ if (!flip)
+ src_fx = (scroll + dst_min) * src_fdx + FIXPOINT_PRECISION_HALF;
+ else
+ {
+ src_fx = (scroll + dst_max) * src_fdx + FIXPOINT_PRECISION_HALF-1;
+ src_fdx = -src_fdx;
+ }
+ }
+
+ if (!(orientation & ORIENTATION_SWAP_XY))
+ {
+ // calculate target increment for horizontal scanlines which is exactly one
+ dst_adv = 1;
+ dst_offset = dst_length;
+ pri_base = BITMAP_ADDR8(priority_bitmap, linepos, dst_start + dst_offset);
+ dst_base = BITMAP_ADDR32(bitmap, linepos, dst_start + dst_length);
+ }
+ else
+ {
+ // calculate target increment for vertical scanlines which is the bitmap's pitch value
+ dst_adv = bitmap->rowpixels;
+ dst_offset= dst_length * dst_adv;
+ pri_base = BITMAP_ADDR8(priority_bitmap, dst_start, linepos + dst_offset);
+ dst_base = BITMAP_ADDR32(bitmap, dst_start, linepos + dst_offset);
+ }
+
+ // generalized
+ src_base = source;
+ src_x = 0;
+
+ // there is no need to wrap source offsets along with source clipping
+ // so we set all bits of the wrapmask to one
+ src_wrapmask = (clipmask) ? ~0 : wrapmask;
+
+ pal_base = palette;
+ pri = (UINT8)priority;
+ dst_offset = -dst_offset; // negate target offset in order to terminated draw loop at zero condition
+
+ if (pri)
+ {
+ // draw scanline and update priority bitmap
+ do
+ {
+ pix_data = src_base[(src_fx>>FIXPOINT_PRECISION) & src_wrapmask];
+ src_fx += src_fdx;
+
+ if (pix_data)
+ {
+ pix_data = pal_base[pix_data];
+ pri_base[dst_offset] = pri;
+ dst_base[dst_offset] = pix_data;
+ }
+ }
+ while (dst_offset += dst_adv);
+ }
+ else
+ {
+ // draw scanline but do not update priority bitmap
+ do
+ {
+ pix_data = src_base[(src_fx>>FIXPOINT_PRECISION) & src_wrapmask];
+ src_fx += src_fdx;
+
+ if (pix_data)
+ {
+ dst_base[dst_offset] = pal_base[pix_data];
+ }
+ }
+ while (dst_offset += dst_adv);
+ }
+
+#undef FIXPOINT_PRECISION
+#undef FIXPOINT_PRECISION_HALF
+}
+
+void K053250_draw(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int chip, int colorbase, int flags, int priority)
+{
+ struct K053250_CHIPTAG *chip_ptr;
+ UINT16 *line_ram;
+ UINT8 *pix_base, *pix_ptr, *regs;
+ const pen_t *pal_base, *pal_ptr;
+ UINT32 rommask, src_clipmask, src_wrapmask, dst_wrapmask;
+ int map_scrollx, map_scrolly, ctrl, orientation;
+ int dst_minx, dst_maxx, dst_miny, dst_maxy;
+ int linedata_offs, linedata_adv, line_pos, line_start, line_end, scroll_corr;
+ int color, offset, zoom, scroll, passes, i, dst_height;
+
+ chip_ptr = &K053250_info.chip[chip]; // pointer to chip parameters
+ line_ram = chip_ptr->buffer[chip_ptr->page[chip]]; // pointer to physical line RAM
+ pix_base = chip_ptr->base; // pointer to source pixel ROM
+ rommask = chip_ptr->rommask; // source ROM limit
+ regs = chip_ptr->regs; // pointer to registers group
+
+ map_scrollx = (short)(regs[0]<<8 | regs[1]); // signed horizontal scroll value
+ map_scrolly = (short)(regs[2]<<8 | regs[3]); // signed vertical scroll value
+ map_scrollx -= chip_ptr->offsx; // add user X offset to horizontal scroll
+ map_scrolly -= chip_ptr->offsy; // add user Y offset to vertical scroll
+ ctrl = regs[4]; // register four is the main control register
+
+ // copy visible boundary values to more accessible locations
+ dst_minx = cliprect->min_x;
+ dst_maxx = cliprect->max_x;
+ dst_miny = cliprect->min_y;
+ dst_maxy = cliprect->max_y;
+
+ orientation = 0; // orientation defaults to no swapping and no flipping
+ dst_height = 512; // virtual bitmap height defaults to five hundred and twelve pixels
+ linedata_adv = 4; // line info packets are four words(eight bytes) apart
+
+ {
+ // switch X and Y parameters when the first bit of the control register is cleared
+ if (!(ctrl & 0x01)) orientation |= ORIENTATION_SWAP_XY;
+
+ // invert X parameters when the forth bit of the control register is set
+ if (ctrl & 0x08) orientation |= ORIENTATION_FLIP_X;
+
+ // invert Y parameters when the fifth bit of the control register is set
+ if (ctrl & 0x10) orientation |= ORIENTATION_FLIP_Y;
+
+ switch (ctrl>>5) // the upper four bits of the control register select source and target dimensions
+ {
+ case 0 :
+ // Xexex: L6 galaxies
+ // Metam: L4 forest, L5 arena, L6 tower interior, final boss
+
+ // crop source offset between zero and two hundred and fifty-five inclusive,
+ // and set virtual bitmap height to two hundred and fifty-six pixels
+ src_wrapmask = src_clipmask = 0xff;
+ dst_height = 0x100;
+ break;
+ case 1 :
+ // Xexex: prologue, L7 nebulae
+
+ // the source offset is cropped to zero and five hundred and eleven inclusive
+ src_wrapmask = src_clipmask = 0x1ff;
+ break;
+ case 4 :
+ // Xexex: L1 sky and boss, L3 planet, L5 poly-face, L7 battle ship patches
+ // Metam: L1 summoning circle, L3 caves, L6 gargoyle towers
+
+ // crop source offset between zero and two hundred and fifty-five inclusive,
+ // and allow source offset to wrap back at 500 hexadecimal to minus 300 hexadecimal
+ src_wrapmask = src_clipmask = 0xff;
+ flags |= K053250_WRAP500;
+ break;
+// case 2 : // Xexex: title
+// case 7 : // Xexex: L4 organic stage
+ default:
+
+ // crop source offset between zero and one thousand and eleven inclusive,
+ // keep other dimensions to their defaults
+ src_wrapmask = src_clipmask = 0x3ff;
+ break;
+ }
+
+ // disable source clipping when the third bit of the control register is set
+ if (ctrl & 0x04) src_clipmask = 0;
+
+ if (!(orientation & ORIENTATION_SWAP_XY)) // normal orientaion with no X Y switching
+ {
+ line_start = dst_miny; // the first scanline starts at the minimum Y clip location
+ line_end = dst_maxy; // the last scanline ends at the maximum Y clip location
+ scroll_corr = map_scrollx; // concentrate global X scroll
+ linedata_offs = map_scrolly; // determine where to get info for the first line
+
+ if (orientation & ORIENTATION_FLIP_X)
+ {
+ scroll_corr = -scroll_corr; // X scroll adjustment should be negated in X flipped scenarioes
+ }
+
+ if (orientation & ORIENTATION_FLIP_Y)
+ {
+ linedata_adv = -linedata_adv; // traverse line RAM backward in Y flipped scenarioes
+ linedata_offs += bitmap->height - 1; // and get info for the first line from the bottom
+ }
+
+ dst_wrapmask = ~0; // scanlines don't seem to wrap horizontally in normal orientation
+ passes = 1; // draw scanline in a single pass
+ }
+ else // orientaion with X and Y parameters switched
+ {
+ line_start = dst_minx; // the first scanline starts at the minimum X clip location
+ line_end = dst_maxx; // the last scanline ends at the maximum X clip location
+ scroll_corr = map_scrolly; // concentrate global Y scroll
+ linedata_offs = map_scrollx; // determine where to get info for the first line
+
+ if (orientation & ORIENTATION_FLIP_Y)
+ {
+ scroll_corr = 0x100 - scroll_corr; // apply common vertical correction
+
+ // Y correction (ref: 1st and 5th boss)
+ scroll_corr -= 2; // apply unique vertical correction
+
+ // X correction (ref: 1st boss, seems to undo non-rotated global X offset)
+ linedata_offs -= 5; // apply unique horizontal correction
+ }
+
+ if (orientation & ORIENTATION_FLIP_X)
+ {
+ linedata_adv = -linedata_adv; // traverse line RAM backward in X flipped scenarioes
+ linedata_offs += bitmap->width - 1; // and get info for the first line from the bottom
+ }
+
+ if (src_clipmask)
+ {
+ // determine target wrap boundary and draw scanline in two passes if the source is clipped
+ dst_wrapmask = dst_height - 1;
+ passes = 2;
+ }
+ else
+ {
+ // otherwise disable target wraparound and draw scanline in a single pass
+ dst_wrapmask = ~0;
+ passes = 1;
+ }
+ }
+ }
+
+ linedata_offs *= 4; // each line info packet has four words(eight bytes)
+ linedata_offs &= 0x7ff; // and it should wrap at the four-kilobyte boundary
+ linedata_offs += line_start * linedata_adv; // pre-advance line info offset for the clipped region
+
+ // load physical palette base
+ pal_base = machine->remapped_colortable + (colorbase << 4) % machine->drv->total_colors;
+
+ // walk the target bitmap within the visible area vertically or horizontally, one line at a time
+ for (line_pos=line_start; line_pos<=line_end; linedata_offs+=linedata_adv, line_pos++)
+ {
+ linedata_offs &= 0x7ff; // line info data wraps at the four-kilobyte boundary
+
+ color = line_ram[linedata_offs]; // get scanline color code
+ if (color == 0xffff) continue; // reject scanline if color code equals minus one
+
+ offset = line_ram[linedata_offs+1]; // get first pixel offset in ROM
+ if (!(color & 0xff) && !offset) continue; // reject scanline if both color and pixel offset are zero
+
+ // calculate physical palette location
+ // there can be thirty-two color codes and each code represents sixteen pens
+ pal_ptr = pal_base + ((color & 0x1f)<<4);
+
+ // calculate physical pixel location
+ // each offset unit represents two hundred and fifty six pixels and should wrap at ROM boundary for safty
+ pix_ptr = pix_base + (offset<<8) % rommask;
+
+ // get scanline zoom factor
+ // For example, 0x20 doubles the length, 0x40 maintains a one-to-one length,
+ // and 0x80 halves the length. The zoom center is at the beginning of the
+ // scanline therefore it is not necessary to adjust render start position
+ zoom = line_ram[linedata_offs+2];
+
+ scroll = (short)line_ram[linedata_offs+3]; // get signed local scroll value for the current scanline
+
+ // scavenged from old code; improves Xexex' first level sky
+ if (flags & K053250_WRAP500 && scroll >= 0x500) scroll -= 0x800;
+
+ scroll += scroll_corr; // apply final scroll correction
+ scroll &= dst_wrapmask; // wraparound scroll value if necessary
+
+ // draw scanlines wrapped at virtual bitmap boundary in two passes
+ // this should not impose too much overhead due to clipping performed by the render code
+ i = passes;
+ do
+ {
+ /*
+ Parameter descriptions:
+
+ bitmap : pointer to a MAME bitmap as the render target
+ pal_ptr : pointer to the palette's physical location relative to the scanline
+ pix_ptr : pointer to the physical start location of source pixels in ROM
+ cliprect : pointer to a rectangle structue which describes the visible area of the target bitmap
+ line_pos : scanline render position relative to the target bitmap
+ should be a Y offset to the target bitmap in normal orientaion,
+ or an X offset to the target bitmap if X,Y are swapped
+ scroll : source scroll value of the scanline
+ zoom : source zoom factor of the scanline
+ src_clipmask : source offset clip mask; source pixels with offsets beyond the scope of this mask will not be drawn
+ src_wrapmask : source offset wrap mask; wraps source offset around, no effect when src_clipmask is set
+ orientation : flags indicating whether scanlines should be drawn horizontally, vertically, forward or backward
+ priority : value to be written to the priority bitmap, no effect when equals zero
+ */
+ K053250_pdraw_scanline32(bitmap, pal_ptr, pix_ptr, cliprect,
+ line_pos, scroll, zoom, src_clipmask, src_wrapmask, orientation, priority);
+
+ // shift scanline position one virtual screen upward to render the wrapped end if necessary
+ scroll -= dst_height;
+ }
+ while (--i);
+ }
+}
+
+#endif
+
+
+
+/***************************************************************************/
+/* */
+/* 053252 */
+/* */
+/***************************************************************************/
+
+// K053252 CRT and interrupt control unit
+static UINT16 K053252_regs[16];
+
+READ16_HANDLER( K053252_word_r )
+{
+ return(K053252_regs[offset]);
+}
+
+WRITE16_HANDLER( K053252_word_w )
+{
+ COMBINE_DATA(K053252_regs + offset);
+}
+
+WRITE32_HANDLER( K053252_long_w )
+{
+ offset <<= 1;
+ K053252_word_w(offset, data>>16, mem_mask>>16);
+ K053252_word_w(offset+1, data, mem_mask);
+}
+
+
+
+// debug handlers
+READ16_HANDLER( K056832_word_r ) { return(K056832_regs[offset]); } // VACSET
+READ16_HANDLER( K056832_b_word_r ) { return(K056832_regsb[offset]); } // VSCCS (board dependent)
+READ16_HANDLER( K053246_reg_word_r ) { return(K053246_regs[offset*2]<<8|K053246_regs[offset*2+1]); } // OBJSET1
+READ16_HANDLER( K053247_reg_word_r ) { return(K053247_regs[offset]); } // OBJSET2
+READ16_HANDLER( K054338_word_r ) { return(k54338_regs[offset]); } // CLTC
+READ16_HANDLER( K053251_lsb_r ) { return(K053251_ram[offset]); } // PCU1
+READ16_HANDLER( K053251_msb_r ) { return(K053251_ram[offset]<<8); } // PCU1
+READ16_HANDLER( K055555_word_r ) { return(k55555_regs[offset]<<8); } // PCU2
+
+READ32_HANDLER( K056832_long_r )
+{
+ offset <<= 1;
+ return (K056832_word_r(offset+1, 0xffff) | K056832_word_r(offset, 0xffff)<<16);
+}
+
+READ32_HANDLER( K053247_reg_long_r )
+{
+ offset <<= 1;
+ return (K053247_reg_word_r(offset+1, 0xffff) | K053247_reg_word_r(offset, 0xffff)<<16);
+}
+
+READ32_HANDLER( K055555_long_r )
+{
+ offset <<= 1;
+ return (K055555_word_r(offset+1, 0xffff) | K055555_word_r(offset, 0xffff)<<16);
+}
+
+READ16_HANDLER( K053244_reg_word_r ) { return(K053244_regs[0][offset*2]<<8|K053244_regs[0][offset*2+1]); }
+
diff --git a/src/mame/video/konamiic.h b/src/mame/video/konamiic.h
new file mode 100644
index 00000000000..56fc348649d
--- /dev/null
+++ b/src/mame/video/konamiic.h
@@ -0,0 +1,454 @@
+/* helper function to join two 16-bit ROMs and form a 32-bit data stream */
+void konami_rom_deinterleave_2(int mem_region);
+void konami_rom_deinterleave_2_half(int mem_region);
+/* helper function to join four 16-bit ROMs and form a 64-bit data stream */
+void konami_rom_deinterleave_4(int mem_region);
+
+
+#define MAX_K007121 2
+extern UINT8 K007121_ctrlram[MAX_K007121][8];
+
+void K007121_ctrl_w(int chip,int offset,int data);
+WRITE8_HANDLER( K007121_ctrl_0_w );
+WRITE8_HANDLER( K007121_ctrl_1_w );
+void K007121_sprites_draw(running_machine *machine,int chip,mame_bitmap *bitmap,const rectangle *cliprect,
+ const UINT8 *source,int base_color,int global_x_offset,int bank_base,
+ UINT32 pri_mask);
+
+
+void K007342_vh_start(int gfx_index, void (*callback)(int layer,int bank,int *code,int *color,int *flags));
+READ8_HANDLER( K007342_r );
+WRITE8_HANDLER( K007342_w );
+READ8_HANDLER( K007342_scroll_r );
+WRITE8_HANDLER( K007342_scroll_w );
+void K007342_tilemap_update(void);
+WRITE8_HANDLER( K007342_vreg_w );
+void K007342_tilemap_set_enable(int layer, int enable);
+void K007342_tilemap_draw(mame_bitmap *bitmap,const rectangle *cliprect,int num,int flags,UINT32 priority);
+int K007342_is_INT_enabled(void);
+
+
+void K007420_vh_start(running_machine *machine, int gfxnum, void (*callback)(int *code,int *color));
+READ8_HANDLER( K007420_r );
+WRITE8_HANDLER( K007420_w );
+void K007420_sprites_draw(mame_bitmap *bitmap,const rectangle *cliprect);
+void K007420_set_banklimit(int limit);
+
+
+/*
+You don't have to decode the graphics: the vh_start() routines will do that
+for you, using the plane order passed.
+Of course the ROM data must be in the correct order. This is a way to ensure
+that the ROM test will pass.
+The konami_rom_deinterleave() function above will do the reorganization for
+you in most cases (but see tmnt.c for additional bit rotations or byte
+permutations which may be required).
+*/
+#define NORMAL_PLANE_ORDER 0,1,2,3
+#define REVERSE_PLANE_ORDER 3,2,1,0
+
+
+/*
+The callback is passed:
+- layer number (0 = FIX, 1 = A, 2 = B)
+- bank (range 0-3, output of the pins CAB1 and CAB2)
+- code (range 00-FF, output of the pins VC3-VC10)
+ NOTE: code is in the range 0000-FFFF for X-Men, which uses extra RAM
+- color (range 00-FF, output of the pins COL0-COL7)
+The callback must put:
+- in code the resulting tile number
+- in color the resulting color index
+- if necessary, put flags and/or priority for the TileMap code in the tile_info
+ structure (e.g. TILE_FLIPX). Note that TILE_FLIPY is handled internally by the
+ chip so it must not be set by the callback.
+*/
+extern tilemap *K052109_tilemap[3];
+
+void K052109_vh_start(running_machine *machine,int gfx_memory_region,int plane0,int plane1,int plane2,int plane3,
+ void (*callback)(int layer,int bank,int *code,int *color,int *flags,int *priority));
+/* plain 8-bit access */
+READ8_HANDLER( K052109_r );
+WRITE8_HANDLER( K052109_w );
+READ16_HANDLER( K052109_word_r );
+WRITE16_HANDLER( K052109_word_w );
+READ16_HANDLER( K052109_lsb_r );
+WRITE16_HANDLER( K052109_lsb_w );
+void K052109_set_RMRD_line(int state);
+void K052109_tilemap_update(void);
+int K052109_is_IRQ_enabled(void);
+void K052109_set_layer_offsets(int layer, int dx, int dy);
+
+
+/*
+The callback is passed:
+- code (range 00-1FFF, output of the pins CA5-CA17)
+- color (range 00-FF, output of the pins OC0-OC7). Note that most of the
+ time COL7 seems to be "shadow", but not always (e.g. Aliens).
+The callback must put:
+- in code the resulting sprite number
+- in color the resulting color index
+- if necessary, in priority the priority of the sprite wrt tilemaps
+- if necessary, alter shadow to indicate whether the sprite has shadows enabled.
+ shadow is preloaded with color & 0x80 so it doesn't need to be changed unless
+ the game has special treatment (Aliens)
+*/
+void K051960_vh_start(running_machine *machine,int gfx_memory_region,int plane0,int plane1,int plane2,int plane3,
+ void (*callback)(int *code,int *color,int *priority,int *shadow));
+READ8_HANDLER( K051960_r );
+WRITE8_HANDLER( K051960_w );
+READ16_HANDLER( K051960_word_r );
+WRITE16_HANDLER( K051960_word_w );
+READ8_HANDLER( K051937_r );
+WRITE8_HANDLER( K051937_w );
+READ16_HANDLER( K051937_word_r );
+WRITE16_HANDLER( K051937_word_w );
+void K051960_sprites_draw(mame_bitmap *bitmap,const rectangle *cliprect,int min_priority,int max_priority);
+int K051960_is_IRQ_enabled(void);
+int K051960_is_NMI_enabled(void);
+void K051960_set_sprite_offsets(int dx, int dy);
+
+/* special handling for the chips sharing address space */
+READ8_HANDLER( K052109_051960_r );
+WRITE8_HANDLER( K052109_051960_w );
+
+
+void K053245_vh_start(running_machine *machine,int chip, int gfx_memory_region,int plane0,int plane1,int plane2,int plane3,
+ void (*callback)(int *code,int *color,int *priority_mask));
+READ16_HANDLER( K053245_word_r );
+WRITE16_HANDLER( K053245_word_w );
+READ8_HANDLER( K053245_r );
+WRITE8_HANDLER( K053245_w );
+WRITE8_HANDLER( K053245_1_w );
+READ8_HANDLER( K053244_r );
+WRITE8_HANDLER( K053244_w );
+WRITE8_HANDLER( K053244_1_w );
+READ16_HANDLER( K053244_lsb_r );
+WRITE16_HANDLER( K053244_lsb_w );
+READ16_HANDLER( K053244_word_r );
+WRITE16_HANDLER( K053244_word_w );
+void K053244_bankselect(int chip, int bank); /* used by TMNT2, Asterix and Premier Soccer for ROM testing */
+void K053245_sprites_draw(int chip, mame_bitmap *bitmap,const rectangle *cliprect);
+void K053245_sprites_draw_lethal(running_machine *machine, int chip, mame_bitmap *bitmap,const rectangle *cliprect); /* for lethal enforcers */
+void K053245_clear_buffer(int chip);
+void K053245_set_SpriteOffset(int chip,int offsx, int offsy);
+
+#define K055673_LAYOUT_GX 0
+#define K055673_LAYOUT_RNG 1
+#define K055673_LAYOUT_LE2 2
+#define K055673_LAYOUT_GX6 3
+
+void K055673_vh_start(running_machine *machine, int gfx_memory_region, int alt_layout, int dx, int dy,
+ void (*callback)(int *code,int *color,int *priority));
+READ16_HANDLER( K055673_rom_word_r );
+READ16_HANDLER( K055673_GX6bpp_rom_word_r );
+
+/*
+Callback procedures for non-standard shadows:
+
+1) translate shadow code to the correct 2-bit form (0=off, 1-3=style)
+2) shift shadow code left by K053247_SHDSHIFT and add the K053247_CUSTOMSHADOW flag
+3) combine the result with sprite color
+*/
+#define K053247_CUSTOMSHADOW 0x20000000
+#define K053247_SHDSHIFT 20
+
+void K053247_vh_start(running_machine *machine, int gfx_memory_region,int dx,int dy,int plane0,int plane1,int plane2,int plane3,
+ void (*callback)(int *code,int *color,int *priority_mask));
+READ8_HANDLER( K053247_r );
+WRITE8_HANDLER( K053247_w );
+READ16_HANDLER( K053247_word_r );
+WRITE16_HANDLER( K053247_word_w );
+READ32_HANDLER( K053247_long_r );
+WRITE32_HANDLER( K053247_long_w );
+WRITE16_HANDLER( K053247_reg_word_w ); // "OBJSET2" registers
+WRITE32_HANDLER( K053247_reg_long_w );
+void K053247_sprites_draw(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect);
+int K053247_read_register(int regnum);
+void K053247_set_SpriteOffset(int offsx, int offsy);
+void K053247_wraparound_enable(int status);
+void K05324x_set_z_rejection(int zcode); // common to K053245/6/7
+void K053247_export_config(UINT16 **ram, gfx_element **gfx, void (**callback)(int *, int *, int *), int *dx, int *dy);
+
+READ8_HANDLER( K053246_r );
+WRITE8_HANDLER( K053246_w );
+READ16_HANDLER( K053246_word_r );
+WRITE16_HANDLER( K053246_word_w );
+READ32_HANDLER( K053246_long_r );
+WRITE32_HANDLER( K053246_long_w );
+void K053246_set_OBJCHA_line(int state);
+int K053246_is_IRQ_enabled(void);
+int K053246_read_register(int regnum);
+
+
+/*
+The callback is passed:
+- code (range 00-FF, contents of the first tilemap RAM byte)
+- color (range 00-FF, contents of the first tilemap RAM byte). Note that bit 6
+ seems to be hardcoded as flip X.
+The callback must put:
+- in code the resulting tile number
+- in color the resulting color index
+- if necessary, put flags for the TileMap code in the tile_info
+ structure (e.g. TILE_FLIPX)
+*/
+void K051316_vh_start_0(running_machine *machine,int gfx_memory_region,int bpp,
+ int tilemap_type,int transparent_pen,
+ void (*callback)(int *code,int *color,int *flags));
+void K051316_vh_start_1(running_machine *machine,int gfx_memory_region,int bpp,
+ int tilemap_type,int transparent_pen,
+ void (*callback)(int *code,int *color,int *flags));
+void K051316_vh_start_2(running_machine *machine,int gfx_memory_region,int bpp,
+ int tilemap_type,int transparent_pen,
+ void (*callback)(int *code,int *color,int *flags));
+READ8_HANDLER( K051316_0_r );
+READ8_HANDLER( K051316_1_r );
+READ8_HANDLER( K051316_2_r );
+WRITE8_HANDLER( K051316_0_w );
+WRITE8_HANDLER( K051316_1_w );
+WRITE8_HANDLER( K051316_2_w );
+READ8_HANDLER( K051316_rom_0_r );
+READ8_HANDLER( K051316_rom_1_r );
+READ8_HANDLER( K051316_rom_2_r );
+WRITE8_HANDLER( K051316_ctrl_0_w );
+WRITE8_HANDLER( K051316_ctrl_1_w );
+WRITE8_HANDLER( K051316_ctrl_2_w );
+void K051316_zoom_draw_0(mame_bitmap *bitmap,const rectangle *cliprect,int flags,UINT32 priority);
+void K051316_zoom_draw_1(mame_bitmap *bitmap,const rectangle *cliprect,int flags,UINT32 priority);
+void K051316_zoom_draw_2(mame_bitmap *bitmap,const rectangle *cliprect,int flags,UINT32 priority);
+void K051316_wraparound_enable(int chip, int status);
+void K051316_set_offset(int chip, int xoffs, int yoffs);
+
+
+extern UINT16 *K053936_0_ctrl,*K053936_0_linectrl;
+extern UINT16 *K053936_1_ctrl,*K053936_1_linectrl;
+void K053936_0_zoom_draw(mame_bitmap *bitmap,const rectangle *cliprect,tilemap *tmap,int flags,UINT32 priority);
+void K053936_1_zoom_draw(mame_bitmap *bitmap,const rectangle *cliprect,tilemap *tmap,int flags,UINT32 priority);
+void K053936_wraparound_enable(int chip, int status);
+void K053936_set_offset(int chip, int xoffs, int yoffs);
+
+
+/*
+ Note: K053251_w() automatically does a tilemap_mark_all_tiles_dirty(ALL_TILEMAPS)
+ when some palette index changes. If ALL_TILEMAPS is too expensive, use
+ K053251_set_tilemaps() to indicate which tilemap is associated with each index.
+ */
+WRITE8_HANDLER( K053251_w );
+WRITE16_HANDLER( K053251_lsb_w );
+WRITE16_HANDLER( K053251_msb_w );
+enum { K053251_CI0=0,K053251_CI1,K053251_CI2,K053251_CI3,K053251_CI4 };
+int K053251_get_priority(int ci);
+int K053251_get_palette_index(int ci);
+void K053251_set_tilemaps(tilemap *ci0,tilemap *ci1,tilemap *ci2,tilemap *ci3,tilemap *ci4);
+void K053251_vh_start(void);
+
+
+WRITE8_HANDLER( K054000_w );
+READ8_HANDLER( K054000_r );
+WRITE16_HANDLER( K054000_lsb_w );
+READ16_HANDLER( K054000_lsb_r );
+
+WRITE8_HANDLER( K051733_w );
+READ8_HANDLER( K051733_r );
+
+void K056832_SetExtLinescroll(void); /* Lethal Enforcers */
+
+void K056832_vh_start(running_machine *machine, int gfx_memory_region, int bpp, int big,
+ int (*scrolld)[4][2],
+ void (*callback)(int layer, int *code, int *color, int *flags),
+ int djmain_hack);
+READ16_HANDLER( K056832_ram_word_r );
+WRITE16_HANDLER( K056832_ram_word_w );
+READ16_HANDLER( K056832_ram_half_word_r );
+WRITE16_HANDLER( K056832_ram_half_word_w );
+READ16_HANDLER( K056832_5bpp_rom_word_r );
+READ32_HANDLER( K056832_5bpp_rom_long_r );
+READ32_HANDLER( K056832_6bpp_rom_long_r );
+READ16_HANDLER( K056832_rom_word_r );
+READ16_HANDLER( K056832_mw_rom_word_r );
+READ16_HANDLER( K056832_bishi_rom_word_r );
+READ16_HANDLER( K056832_old_rom_word_r );
+READ16_HANDLER( K056832_rom_word_8000_r );
+WRITE16_HANDLER( K056832_word_w ); // "VRAM" registers
+WRITE16_HANDLER( K056832_b_word_w );
+READ8_HANDLER( K056832_ram_code_lo_r );
+READ8_HANDLER( K056832_ram_code_hi_r );
+READ8_HANDLER( K056832_ram_attr_lo_r );
+READ8_HANDLER( K056832_ram_attr_hi_r );
+WRITE8_HANDLER( K056832_ram_code_lo_w );
+WRITE8_HANDLER( K056832_ram_code_hi_w );
+WRITE8_HANDLER( K056832_ram_attr_lo_w );
+WRITE8_HANDLER( K056832_ram_attr_hi_w );
+WRITE8_HANDLER( K056832_w );
+WRITE8_HANDLER( K056832_b_w );
+void K056832_mark_plane_dirty(int num);
+void K056832_MarkAllTilemapsDirty(void);
+void K056832_tilemap_draw(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int num, int flags, UINT32 priority);
+void K056832_tilemap_draw_dj(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int layer, int flags, UINT32 priority);
+void K056832_set_LayerAssociation(int status);
+int K056832_get_LayerAssociation(void);
+void K056832_set_LayerOffset(int layer, int offsx, int offsy);
+void K056832_set_LSRAMPage(int logical_page, int physical_page, int physical_offset);
+void K056832_set_UpdateMode(int mode);
+void K056832_linemap_enable(int enable);
+int K056832_is_IRQ_enabled(int irqline);
+void K056832_read_AVAC(int *mode, int *data);
+int K056832_read_register(int regnum);
+int K056832_get_current_rambank(void);
+int K056832_get_lookup(int bits); /* Asterix */
+void K056832_set_tile_bank(int bank); /* Asterix */
+
+READ32_HANDLER( K056832_ram_long_r );
+READ32_HANDLER( K056832_rom_long_r );
+WRITE32_HANDLER( K056832_ram_long_w );
+WRITE32_HANDLER( K056832_long_w );
+WRITE32_HANDLER( K056832_b_long_w );
+
+/* bit depths for the 56832 */
+#define K056832_BPP_4 0
+#define K056832_BPP_5 1
+#define K056832_BPP_6 2
+#define K056832_BPP_8 3
+#define K056832_BPP_4dj 4
+#define K056832_BPP_8LE 5
+
+void K055555_vh_start(void); // "PCU2"
+void K055555_write_reg(UINT8 regnum, UINT8 regdat);
+WRITE16_HANDLER( K055555_word_w );
+WRITE32_HANDLER( K055555_long_w );
+int K055555_read_register(int regnum);
+int K055555_get_palette_index(int idx);
+
+/* K055555 registers */
+/* priority inputs */
+#define K55_PALBASE_BG 0 // background palette
+#define K55_CONTROL 1 // control register
+#define K55_COLSEL_0 2 // layer A, B color depth
+#define K55_COLSEL_1 3 // layer C, D color depth
+#define K55_COLSEL_2 4 // object, S1 color depth
+#define K55_COLSEL_3 5 // S2, S3 color depth
+
+#define K55_PRIINP_0 7 // layer A pri 0
+#define K55_PRIINP_1 8 // layer A pri 1
+#define K55_PRIINP_2 9 // layer A "COLPRI"
+#define K55_PRIINP_3 10 // layer B pri 0
+#define K55_PRIINP_4 11 // layer B pri 1
+#define K55_PRIINP_5 12 // layer B "COLPRI"
+#define K55_PRIINP_6 13 // layer C pri
+#define K55_PRIINP_7 14 // layer D pri
+#define K55_PRIINP_8 15 // OBJ pri
+#define K55_PRIINP_9 16 // sub 1 (GP:PSAC) pri
+#define K55_PRIINP_10 17 // sub 2 (GX:PSAC) pri
+#define K55_PRIINP_11 18 // sub 3 pri
+
+#define K55_OINPRI_ON 19 // object priority bits selector
+
+#define K55_PALBASE_A 23 // layer A palette
+#define K55_PALBASE_B 24 // layer B palette
+#define K55_PALBASE_C 25 // layer C palette
+#define K55_PALBASE_D 26 // layer D palette
+#define K55_PALBASE_OBJ 27 // OBJ palette
+#define K55_PALBASE_SUB1 28 // SUB1 palette
+#define K55_PALBASE_SUB2 29 // SUB2 palette
+#define K55_PALBASE_SUB3 30 // SUB3 palette
+
+#define K55_BLEND_ENABLES 33 // blend enables for tilemaps
+#define K55_VINMIX_ON 34 // additional blend enables for tilemaps
+#define K55_OSBLEND_ENABLES 35 // obj/sub blend enables
+#define K55_OSBLEND_ON 36 // not sure, related to obj/sub blend
+
+#define K55_SHAD1_PRI 37 // shadow/highlight 1 priority
+#define K55_SHAD2_PRI 38 // shadow/highlight 2 priority
+#define K55_SHAD3_PRI 39 // shadow/highlight 3 priority
+#define K55_SHD_ON 40 // shadow/highlight
+#define K55_SHD_PRI_SEL 41 // shadow/highlight
+
+#define K55_VBRI 42 // VRAM layer brightness enable
+#define K55_OSBRI 43 // obj/sub brightness enable, part 1
+#define K55_OSBRI_ON 44 // obj/sub brightness enable, part 2
+#define K55_INPUT_ENABLES 45 // input enables
+
+/* bit masks for the control register */
+#define K55_CTL_GRADDIR 0x01 // 0=vertical, 1=horizontal
+#define K55_CTL_GRADENABLE 0x02 // 0=BG is base color only, 1=gradient
+#define K55_CTL_FLIPPRI 0x04 // 0=standard Konami priority, 1=reverse
+#define K55_CTL_SDSEL 0x08 // 0=normal shadow timing, 1=(not used by GX)
+
+/* bit masks for the input enables */
+#define K55_INP_VRAM_A 0x01
+#define K55_INP_VRAM_B 0x02
+#define K55_INP_VRAM_C 0x04
+#define K55_INP_VRAM_D 0x08
+#define K55_INP_OBJ 0x10
+#define K55_INP_SUB1 0x20
+#define K55_INP_SUB2 0x40
+#define K55_INP_SUB3 0x80
+
+/* K054338 mixer/alpha blender */
+void K054338_vh_start(void);
+WRITE16_HANDLER( K054338_word_w ); // "CLCT" registers
+WRITE32_HANDLER( K054338_long_w );
+int K054338_read_register(int reg);
+void K054338_update_all_shadows(running_machine *machine); // called at the beginning of VIDEO_UPDATE()
+void K054338_fill_solid_bg(mame_bitmap *bitmap); // solid backcolor fill
+void K054338_fill_backcolor(running_machine *machine, mame_bitmap *bitmap, int mode); // unified fill, 0=solid, 1=gradient
+int K054338_set_alpha_level(int pblend); // blend style 0-2
+void K054338_invert_alpha(int invert); // 0=0x00(invis)-0x1f(solid), 1=0x1f(invis)-0x00(solod)
+void K054338_export_config(int **shdRGB);
+
+#define K338_REG_BGC_R 0
+#define K338_REG_BGC_GB 1
+#define K338_REG_SHAD1R 2
+#define K338_REG_BRI3 11
+#define K338_REG_PBLEND 13
+#define K338_REG_CONTROL 15
+
+#define K338_CTL_KILL 0x01 /* 0 = no video output, 1 = enable */
+#define K338_CTL_MIXPRI 0x02
+#define K338_CTL_SHDPRI 0x04
+#define K338_CTL_BRTPRI 0x08
+#define K338_CTL_WAILSL 0x10
+#define K338_CTL_CLIPSL 0x20
+
+void K053250_vh_start(int chips, int *region);
+WRITE16_HANDLER( K053250_0_w );
+READ16_HANDLER( K053250_0_r );
+WRITE16_HANDLER( K053250_0_ram_w );
+READ16_HANDLER( K053250_0_ram_r );
+READ16_HANDLER( K053250_0_rom_r );
+WRITE16_HANDLER( K053250_1_w );
+READ16_HANDLER( K053250_1_r );
+WRITE16_HANDLER( K053250_1_ram_w );
+READ16_HANDLER( K053250_1_ram_r );
+READ16_HANDLER( K053250_1_rom_r );
+
+// K053250_draw() control flags
+#define K053250_WRAP500 0x01
+#define K053250_OVERDRIVE 0x02
+
+void K053250_draw(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int chip, int colorbase, int flags, int pri);
+void K053250_set_LayerOffset(int chip, int offsx, int offsy);
+void K053250_unpack_pixels(int region);
+void K053250_dma(int chip, int limiter);
+
+
+// K053252 CRT and interrupt control unit
+READ16_HANDLER( K053252_word_r ); // CCU registers
+WRITE16_HANDLER( K053252_word_w );
+WRITE32_HANDLER( K053252_long_w );
+
+
+// debug handlers
+READ16_HANDLER( K056832_word_r ); // VACSET
+READ16_HANDLER( K056832_b_word_r ); // VSCCS (board dependent)
+READ16_HANDLER( K053246_reg_word_r ); // OBJSET1
+READ16_HANDLER( K053247_reg_word_r ); // OBJSET2
+READ16_HANDLER( K053251_lsb_r ); // PCU1
+READ16_HANDLER( K053251_msb_r ); // PCU1
+READ16_HANDLER( K055555_word_r ); // PCU2
+READ16_HANDLER( K054338_word_r ); // CLTC
+
+READ32_HANDLER( K056832_long_r ); // VACSET
+READ32_HANDLER( K053247_reg_long_r ); // OBJSET2
+READ32_HANDLER( K055555_long_r ); // PCU2
+
+READ16_HANDLER( K053244_reg_word_r ); // OBJSET0
diff --git a/src/mame/video/kopunch.c b/src/mame/video/kopunch.c
new file mode 100644
index 00000000000..1c7f61b57c7
--- /dev/null
+++ b/src/mame/video/kopunch.c
@@ -0,0 +1,124 @@
+#include "driver.h"
+
+UINT8 *kopunch_videoram2;
+
+static INT8 scroll[2]; // REMOVE
+static int gfxbank, gfxflip;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+PALETTE_INIT( kopunch )
+{
+ int i;
+
+ color_prom+=24; /* first 24 colors are black */
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( kopunch_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( kopunch_videoram2_w )
+{
+ kopunch_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( kopunch_scroll_x_w )
+{
+ scroll[0] = data; // REMOVE
+ tilemap_set_scrollx(fg_tilemap, 0, data);
+}
+
+WRITE8_HANDLER( kopunch_scroll_y_w )
+{
+ scroll[1] = data; // REMOVE
+ tilemap_set_scrolly(fg_tilemap, 0, data);
+}
+
+WRITE8_HANDLER( kopunch_gfxbank_w )
+{
+ if (gfxbank != (data & 0x07))
+ {
+ gfxbank = data & 0x07;
+ tilemap_mark_all_tiles_dirty(fg_tilemap);
+ }
+
+ gfxflip = data & 0x08; // REMOVE
+
+ tilemap_set_flip(fg_tilemap, (data & 0x08) ? TILEMAP_FLIPY : 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index];
+
+ SET_TILE_INFO(0, code, 0, 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = (kopunch_videoram2[tile_index] & 0x7f) + 128 * gfxbank;
+
+ SET_TILE_INFO(1, code, 0, 0);
+}
+
+VIDEO_START( kopunch )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 16, 16);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+VIDEO_UPDATE( kopunch )
+{
+ int offs;
+
+ tilemap_draw(bitmap, &machine->screen[0].visarea, bg_tilemap, 0, 0);
+ //tilemap_draw(bitmap, &machine->screen[0].visarea, fg_tilemap, 0, 0);
+
+ for (offs = 1023;offs >= 0;offs--)
+ {
+ int sx,sy;
+
+ sx = offs % 16;
+ sy = offs / 16;
+
+ drawgfx(bitmap,machine->gfx[1],
+ (kopunch_videoram2[offs] & 0x7f) + 128 * gfxbank,
+ 0,
+ 0,gfxflip,
+ 8*(sx+8)+scroll[0],8*(8+(gfxflip ? 15-sy : sy))+scroll[1],
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/ksayakyu.c b/src/mame/video/ksayakyu.c
new file mode 100644
index 00000000000..5746535ba51
--- /dev/null
+++ b/src/mame/video/ksayakyu.c
@@ -0,0 +1,116 @@
+#include "driver.h"
+
+static tilemap *ksayakyu_tilemap;
+static tilemap *ksayakyu_textmap;
+
+static int video_ctrl;
+static int flipscreen;
+
+WRITE8_HANDLER(ksayakyu_videoram_w)
+{
+ videoram[offset]=data;
+ tilemap_mark_tile_dirty(ksayakyu_textmap,offset>>1);
+}
+
+WRITE8_HANDLER(ksayakyu_videoctrl_w)
+{
+ /*
+ bits:
+ 76543210
+ xx - ?? layers enable ?
+ x - screen flip
+ xx - ??
+ xxx - scroll offset
+
+ */
+ video_ctrl=data;
+
+ flipscreen = (data&4)?(TILEMAP_FLIPX|TILEMAP_FLIPY):0;
+ tilemap_set_flip( ALL_TILEMAPS,flipscreen );
+ tilemap_set_scrolly( ksayakyu_tilemap, 0, (data&0xe0)<<3 );
+}
+
+PALETTE_INIT( ksayakyu )
+{
+ int i,j,b1,b2;
+ for(j=0;j<16;j++)
+ for(i=0;i<8;i++)
+ {
+ b1=memory_region(REGION_PROMS)[j*16+i];
+ b2=memory_region(REGION_PROMS)[j*16+i+8];
+
+ b1=b2|(b1<<8);
+ palette_set_color_rgb(machine,j*8+i,pal5bit(b1 >> 10),pal5bit(b1 >> 0),pal5bit(b1 >> 5));
+ }
+}
+
+static TILE_GET_INFO( get_ksayakyu_tile_info )
+{
+ int code = memory_region(REGION_USER1)[tile_index];
+ int attr = memory_region(REGION_USER1)[tile_index+0x2000];
+ code+=(attr&3)<<8;
+ SET_TILE_INFO(1,code,((attr>>2)&0x07)*2,(attr&0x80) ? TILE_FLIPX : 0);
+}
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ int code = videoram[tile_index*2+1];
+ int attr = videoram[tile_index*2];
+ int flags=((attr&0x80) ? TILE_FLIPX : 0) | ((attr&0x40) ? TILE_FLIPY : 0);
+
+ code|=(attr&3)<<8;
+
+ SET_TILE_INFO(0,code,((attr>>2)&7),flags);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ const UINT8 *source = spriteram+spriteram_size-4;
+ const UINT8 *finish = spriteram;
+
+ while( source>=finish ) /* is order correct ? */
+ {
+ int sx=source[2];
+ int sy=240-source[1];
+ int attributes=source[3];
+ int tile=source[0];
+ int flipx=(tile&0x80)?1:0;
+ int flipy=0;
+
+ gfx_element *gfx = machine->gfx[2];
+
+ if (flipscreen)
+ {
+ sx = 240-sx;
+ sy = 240-sy;
+ flipx^=1;
+ flipy^=1;
+ }
+
+ drawgfx(bitmap,gfx,
+ tile&0x7f,
+ (attributes) & 7,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0 );
+
+ source -= 4;
+ }
+}
+
+VIDEO_START(ksayakyu)
+{
+ ksayakyu_tilemap = tilemap_create(get_ksayakyu_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32*8);
+ ksayakyu_textmap = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+ tilemap_set_transparent_pen(ksayakyu_textmap,0);
+}
+
+VIDEO_UPDATE(ksayakyu)
+{
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ if(video_ctrl&1)
+ tilemap_draw(bitmap,cliprect,ksayakyu_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,ksayakyu_textmap, 0,0);
+ return 0;
+}
diff --git a/src/mame/video/kyugo.c b/src/mame/video/kyugo.c
new file mode 100644
index 00000000000..951f7e2662b
--- /dev/null
+++ b/src/mame/video/kyugo.c
@@ -0,0 +1,232 @@
+/***************************************************************************
+
+ Kyugo hardware games
+
+***************************************************************************/
+
+#include "driver.h"
+#include "kyugo.h"
+
+
+UINT8 *kyugo_fgvideoram;
+UINT8 *kyugo_bgvideoram;
+UINT8 *kyugo_bgattribram;
+UINT8 *kyugo_spriteram_1;
+UINT8 *kyugo_spriteram_2;
+
+
+static UINT8 scroll_x_lo;
+static UINT8 scroll_x_hi;
+static UINT8 scroll_y;
+static tilemap *fg_tilemap;
+static tilemap *bg_tilemap;
+static int bgpalbank,fgcolor;
+static int flipscreen;
+static const UINT8 *color_codes;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = kyugo_fgvideoram[tile_index];
+ SET_TILE_INFO(0,
+ code,
+ 2*color_codes[code >> 3] + fgcolor,
+ 0);
+}
+
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = kyugo_bgvideoram[tile_index];
+ int attr = kyugo_bgattribram[tile_index];
+ SET_TILE_INFO(1,
+ code | ((attr & 0x03) << 8),
+ (attr >> 4) | (bgpalbank << 4),
+ TILE_FLIPYX((attr & 0x0c) >> 2));
+}
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( kyugo )
+{
+ color_codes = memory_region(REGION_PROMS) + 0x300;
+
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ tilemap_set_scrolldx(fg_tilemap, 0, 224);
+ tilemap_set_scrolldx(bg_tilemap, -32, 32);
+}
+
+
+/*************************************
+ *
+ * Memory handlers
+ *
+ *************************************/
+
+WRITE8_HANDLER( kyugo_fgvideoram_w )
+{
+ kyugo_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty( fg_tilemap, offset );
+}
+
+
+WRITE8_HANDLER( kyugo_bgvideoram_w )
+{
+ kyugo_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty( bg_tilemap, offset );
+}
+
+
+WRITE8_HANDLER( kyugo_bgattribram_w )
+{
+ kyugo_bgattribram[offset] = data;
+ tilemap_mark_tile_dirty( bg_tilemap, offset );
+}
+
+
+READ8_HANDLER( kyugo_spriteram_2_r )
+{
+ // only the lower nibble is connected
+ return kyugo_spriteram_2[offset] | 0xf0;
+}
+
+
+WRITE8_HANDLER( kyugo_scroll_x_lo_w )
+{
+ scroll_x_lo = data;
+}
+
+
+WRITE8_HANDLER( kyugo_gfxctrl_w )
+{
+ /* bit 0 is scroll MSB */
+ scroll_x_hi = data & 0x01;
+
+ /* bit 5 is front layer color (Son of Phoenix only) */
+ if (fgcolor != ((data & 0x20) >> 5))
+ {
+ fgcolor = (data & 0x20) >> 5;
+
+ tilemap_mark_all_tiles_dirty(fg_tilemap);
+ }
+
+ /* bit 6 is background palette bank */
+ if (bgpalbank != ((data & 0x40) >> 6))
+ {
+ bgpalbank = (data & 0x40) >> 6;
+
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ if (data & 0x9e)
+ popmessage("%02x",data);
+}
+
+
+WRITE8_HANDLER( kyugo_scroll_y_w )
+{
+ scroll_y = data;
+}
+
+
+WRITE8_HANDLER( kyugo_flipscreen_w )
+{
+ if (flipscreen != (data & 0x01))
+ {
+ flipscreen = (data & 0x01);
+
+ tilemap_set_flip(ALL_TILEMAPS, (flipscreen ? (TILEMAP_FLIPX | TILEMAP_FLIPY): 0));
+ }
+}
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /* sprite information is scattered through memory */
+ /* and uses a portion of the text layer memory (outside the visible area) */
+ UINT8 *spriteram_area1 = &kyugo_spriteram_1[0x28];
+ UINT8 *spriteram_area2 = &kyugo_spriteram_2[0x28];
+ UINT8 *spriteram_area3 = &kyugo_fgvideoram[0x28];
+
+ int n;
+
+ for( n = 0; n < 12*2; n++ )
+ {
+ int offs,y,sy,sx,color;
+
+ offs = 2*(n % 12) + 64*(n / 12);
+
+ sx = spriteram_area3[offs+1] + 256 * (spriteram_area2[offs+1] & 1);
+ if (sx > 320) sx -= 512;
+
+ sy = 255 - spriteram_area1[offs];
+ if (flipscreen) sy = 240 - sy;
+
+ color = spriteram_area1[offs+1] & 0x1f;
+
+ for (y = 0;y < 16;y++)
+ {
+ int code,attr,flipx,flipy;
+
+ code = spriteram_area3[offs + 128*y];
+ attr = spriteram_area2[offs + 128*y];
+
+ code = code | ((attr & 0x01) << 9) | ((attr & 0x02) << 7);
+
+ flipx = attr & 0x08;
+ flipy = attr & 0x04;
+
+ if (flipscreen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+
+ drawgfx( bitmap, machine->gfx[2],
+ code,
+ color,
+ flipx,flipy,
+ sx,flipscreen ? sy - 16*y : sy + 16*y,
+ cliprect,TRANSPARENCY_PEN, 0 );
+ }
+ }
+}
+
+
+VIDEO_UPDATE( kyugo )
+{
+ if (flipscreen)
+ tilemap_set_scrollx(bg_tilemap,0,-(scroll_x_lo + (scroll_x_hi*256)));
+ else
+ tilemap_set_scrollx(bg_tilemap,0, scroll_x_lo + (scroll_x_hi*256));
+
+ tilemap_set_scrolly(bg_tilemap,0,scroll_y);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/labyrunr.c b/src/mame/video/labyrunr.c
new file mode 100644
index 00000000000..c938f76c38b
--- /dev/null
+++ b/src/mame/video/labyrunr.c
@@ -0,0 +1,242 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+UINT8 *labyrunr_videoram1,*labyrunr_videoram2,*labyrunr_scrollram;
+static tilemap *layer0, *layer1;
+static rectangle clip0, clip1;
+
+
+PALETTE_INIT( labyrunr )
+{
+ int i,pal;
+
+ for (pal = 0;pal < 8;pal++)
+ {
+ if (pal & 1) /* chars, no lookup table */
+ {
+ for (i = 0;i < 256;i++)
+ *(colortable++) = 16 * pal + (i & 0x0f);
+ }
+ else /* sprites */
+ {
+ for (i = 0;i < 256;i++)
+ if (color_prom[i] == 0)
+ *(colortable++) = 0;
+ else
+ *(colortable++) = 16 * pal + color_prom[i];
+ }
+ }
+}
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info0 )
+{
+ int attr = labyrunr_videoram1[tile_index];
+ int code = labyrunr_videoram1[tile_index + 0x400];
+ int bit0 = (K007121_ctrlram[0][0x05] >> 0) & 0x03;
+ int bit1 = (K007121_ctrlram[0][0x05] >> 2) & 0x03;
+ int bit2 = (K007121_ctrlram[0][0x05] >> 4) & 0x03;
+ int bit3 = (K007121_ctrlram[0][0x05] >> 6) & 0x03;
+ int bank = ((attr & 0x80) >> 7) |
+ ((attr >> (bit0+2)) & 0x02) |
+ ((attr >> (bit1+1)) & 0x04) |
+ ((attr >> (bit2 )) & 0x08) |
+ ((attr >> (bit3-1)) & 0x10) |
+ ((K007121_ctrlram[0][0x03] & 0x01) << 5);
+ int mask = (K007121_ctrlram[0][0x04] & 0xf0) >> 4;
+
+ bank = (bank & ~(mask << 1)) | ((K007121_ctrlram[0][0x04] & mask) << 1);
+
+ SET_TILE_INFO(
+ 0,
+ code+bank*256,
+ ((K007121_ctrlram[0][6]&0x30)*2+16)+(attr&7),
+ 0);
+}
+
+static TILE_GET_INFO( get_tile_info1 )
+{
+ int attr = labyrunr_videoram2[tile_index];
+ int code = labyrunr_videoram2[tile_index + 0x400];
+ int bit0 = (K007121_ctrlram[0][0x05] >> 0) & 0x03;
+ int bit1 = (K007121_ctrlram[0][0x05] >> 2) & 0x03;
+ int bit2 = (K007121_ctrlram[0][0x05] >> 4) & 0x03;
+ int bit3 = (K007121_ctrlram[0][0x05] >> 6) & 0x03;
+ int bank = ((attr & 0x80) >> 7) |
+ ((attr >> (bit0+2)) & 0x02) |
+ ((attr >> (bit1+1)) & 0x04) |
+ ((attr >> (bit2 )) & 0x08) |
+ ((attr >> (bit3-1)) & 0x10) |
+ ((K007121_ctrlram[0][0x03] & 0x01) << 5);
+ int mask = (K007121_ctrlram[0][0x04] & 0xf0) >> 4;
+
+ bank = (bank & ~(mask << 1)) | ((K007121_ctrlram[0][0x04] & mask) << 1);
+
+ SET_TILE_INFO(
+ 0,
+ code+bank*256,
+ ((K007121_ctrlram[0][6]&0x30)*2+16)+(attr&7),
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( labyrunr )
+{
+ layer0 = tilemap_create(get_tile_info0,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ layer1 = tilemap_create(get_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(layer0,0);
+ tilemap_set_transparent_pen(layer1,0);
+
+ clip0 = machine->screen[0].visarea;
+ clip0.min_x += 40;
+
+ clip1 = machine->screen[0].visarea;
+ clip1.max_x = 39;
+ clip1.min_x = 0;
+
+ tilemap_set_scroll_cols(layer0,32);
+}
+
+
+
+/***************************************************************************
+
+ Memory Handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( labyrunr_vram1_w )
+{
+ labyrunr_videoram1[offset] = data;
+ tilemap_mark_tile_dirty(layer0,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( labyrunr_vram2_w )
+{
+ labyrunr_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(layer1,offset & 0x3ff);
+}
+
+
+
+/***************************************************************************
+
+ Screen Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( labyrunr )
+{
+ rectangle finalclip0, finalclip1;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ if(~K007121_ctrlram[0][3] & 0x20)
+ {
+ int i;
+
+ finalclip0 = clip0;
+ finalclip1 = clip1;
+
+ sect_rect(&finalclip0, cliprect);
+ sect_rect(&finalclip1, cliprect);
+
+ tilemap_set_scrollx(layer0,0,K007121_ctrlram[0][0x00] - 40);
+ tilemap_set_scrollx(layer1,0,0);
+
+ for(i = 0; i < 32; i++)
+ {
+ /* enable colscroll */
+ if((K007121_ctrlram[0][1] & 6) == 6) // it's probably just one bit, but it's only used once in the game so I don't know which it's
+ tilemap_set_scrolly(layer0,(i+2) & 0x1f,K007121_ctrlram[0][0x02] + labyrunr_scrollram[i]);
+ else
+ tilemap_set_scrolly(layer0,(i+2) & 0x1f,K007121_ctrlram[0][0x02]);
+ }
+
+ tilemap_draw(bitmap,&finalclip0,layer0,TILEMAP_DRAW_OPAQUE,0);
+ K007121_sprites_draw(machine,0,bitmap,cliprect,spriteram,(K007121_ctrlram[0][6]&0x30)*2,40,0,(K007121_ctrlram[0][3] & 0x40) >> 5);
+ /* we ignore the transparency because layer1 is drawn only at the top of the screen also covering sprites */
+ tilemap_draw(bitmap,&finalclip1,layer1,TILEMAP_DRAW_OPAQUE,0);
+ }
+ else
+ {
+ int use_clip3[2] = { 0, 0 };
+ rectangle finalclip3;
+
+ /* custom cliprects needed for the weird effect used in the endinq sequence to hide and show the needed part of text */
+ finalclip0.min_y = finalclip1.min_y = cliprect->min_y;
+ finalclip0.max_y = finalclip1.max_y = cliprect->max_y;
+
+ if(K007121_ctrlram[0][1] & 1)
+ {
+ finalclip0.min_x = cliprect->max_x - K007121_ctrlram[0][0x00] + 8;
+ finalclip0.max_x = cliprect->max_x;
+
+ if(K007121_ctrlram[0][0x00] >= 40)
+ {
+ finalclip1.min_x = cliprect->min_x;
+ }
+ else
+ {
+ use_clip3[0] = 1;
+
+ finalclip1.min_x = 40 - K007121_ctrlram[0][0x00];
+ }
+
+ finalclip1.max_x = cliprect->max_x - K007121_ctrlram[0][0x00] + 8;
+
+ }
+ else
+ {
+ if(K007121_ctrlram[0][0x00] >= 40)
+ {
+ finalclip0.min_x = cliprect->min_x;
+ }
+ else
+ {
+ use_clip3[1] = 1;
+
+ finalclip0.min_x = 40 - K007121_ctrlram[0][0x00];
+ }
+
+ finalclip0.max_x = cliprect->max_x - K007121_ctrlram[0][0x00] + 8;
+
+ finalclip1.min_x = cliprect->max_x - K007121_ctrlram[0][0x00] + 8;
+ finalclip1.max_x = cliprect->max_x;
+ }
+
+ if(use_clip3[0] || use_clip3[1])
+ {
+ finalclip3.min_y = cliprect->min_y;
+ finalclip3.max_y = cliprect->max_y;
+ finalclip3.min_x = cliprect->min_x;
+ finalclip3.max_x = 40 - K007121_ctrlram[0][0x00] - 8;
+ }
+
+ tilemap_set_scrollx(layer0,0,K007121_ctrlram[0][0x00] - 40);
+ tilemap_set_scrollx(layer1,0,K007121_ctrlram[0][0x00] - 40);
+
+ tilemap_draw(bitmap,&finalclip0,layer0,0,1);
+ if(use_clip3[0]) tilemap_draw(bitmap,&finalclip3,layer0,0,1);
+
+ tilemap_draw(bitmap,&finalclip1,layer1,0,1);
+ if(use_clip3[1]) tilemap_draw(bitmap,&finalclip3,layer1,0,1);
+
+ K007121_sprites_draw(machine,0,bitmap,cliprect,spriteram,(K007121_ctrlram[0][6]&0x30)*2,40,0,(K007121_ctrlram[0][3] & 0x40) >> 5);
+ }
+ return 0;
+}
diff --git a/src/mame/video/ladybug.c b/src/mame/video/ladybug.c
new file mode 100644
index 00000000000..08a4f6b77bc
--- /dev/null
+++ b/src/mame/video/ladybug.c
@@ -0,0 +1,475 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+/* Use the Zero Hour star generator board */
+extern void redclash_set_stars_enable( UINT8 on );
+extern void redclash_update_stars_state(void);
+extern void redclash_set_stars_speed( UINT8 speed );
+extern void redclash_draw_stars(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8 palette_offset, UINT8 sraider, UINT8 firstx, UINT8 lastx);
+
+static tilemap *bg_tilemap;
+static tilemap *grid_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Lady Bug has a 32 bytes palette PROM and a 32 bytes sprite color lookup
+ table PROM.
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- inverter -- 220 ohm resistor -- BLUE
+ -- inverter -- 220 ohm resistor -- GREEN
+ -- inverter -- 220 ohm resistor -- RED
+ -- inverter -- 470 ohm resistor -- BLUE
+ -- unused
+ -- inverter -- 470 ohm resistor -- GREEN
+ -- unused
+ bit 0 -- inverter -- 470 ohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( ladybug )
+{
+ int i;
+
+ for (i = 0;i < 32;i++)
+ {
+ int bit1,bit2,r,g,b;
+
+
+ bit1 = (~color_prom[i] >> 0) & 0x01;
+ bit2 = (~color_prom[i] >> 5) & 0x01;
+ r = 0x47 * bit1 + 0x97 * bit2;
+ bit1 = (~color_prom[i] >> 2) & 0x01;
+ bit2 = (~color_prom[i] >> 6) & 0x01;
+ g = 0x47 * bit1 + 0x97 * bit2;
+ bit1 = (~color_prom[i] >> 4) & 0x01;
+ bit2 = (~color_prom[i] >> 7) & 0x01;
+ b = 0x47 * bit1 + 0x97 * bit2;
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ /* characters */
+ for (i = 0;i < 8;i++)
+ {
+ colortable[4 * i] = 0;
+ colortable[4 * i + 1] = i + 0x08;
+ colortable[4 * i + 2] = i + 0x10;
+ colortable[4 * i + 3] = i + 0x18;
+ }
+
+ /* sprites */
+ for (i = 0;i < 4 * 8;i++)
+ {
+ int bit0,bit1,bit2,bit3;
+
+
+ /* low 4 bits are for sprite n */
+ bit0 = (color_prom[i + 32] >> 3) & 0x01;
+ bit1 = (color_prom[i + 32] >> 2) & 0x01;
+ bit2 = (color_prom[i + 32] >> 1) & 0x01;
+ bit3 = (color_prom[i + 32] >> 0) & 0x01;
+ colortable[i + 4 * 8] = 1 * bit0 + 2 * bit1 + 4 * bit2 + 8 * bit3;
+
+ /* high 4 bits are for sprite n + 8 */
+ bit0 = (color_prom[i + 32] >> 7) & 0x01;
+ bit1 = (color_prom[i + 32] >> 6) & 0x01;
+ bit2 = (color_prom[i + 32] >> 5) & 0x01;
+ bit3 = (color_prom[i + 32] >> 4) & 0x01;
+ colortable[i + 4 * 16] = 1 * bit0 + 2 * bit1 + 4 * bit2 + 8 * bit3;
+ }
+}
+
+PALETTE_INIT( sraider )
+{
+ int i;
+
+ for (i = 0;i < 32;i++)
+ {
+ int bit1,bit2,r,g,b;
+
+
+ bit1 = (~color_prom[i] >> 3) & 0x01;
+ bit2 = (~color_prom[i] >> 0) & 0x01;
+ r = 0x47 * bit1 + 0x97 * bit2;
+ bit1 = (~color_prom[i] >> 5) & 0x01;
+ bit2 = (~color_prom[i] >> 4) & 0x01;
+ g = 0x47 * bit1 + 0x97 * bit2;
+ bit1 = (~color_prom[i] >> 7) & 0x01;
+ bit2 = (~color_prom[i] >> 6) & 0x01;
+ b = 0x47 * bit1 + 0x97 * bit2;
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ /* This is for the stars colors */
+ for (i = 32;i < 64;i++)
+ {
+ int bit1,bit2,r,g,b;
+
+
+ bit2 = (i >> 4) & 0x01;
+ bit1 = (i >> 3) & 0x01;
+ b = 0x47 * bit1 + 0x97 * bit2;
+ bit2 = (i >> 2) & 0x01;
+ bit1 = (i >> 1) & 0x01;
+ g = 0x47 * bit1 + 0x97 * bit2;
+ bit1 = i & 0x01;
+ r = 0x47 * bit1;
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ /* This is reserved for the grid color */
+ palette_set_color(machine,64,MAKE_RGB(0,0,0));
+
+ /* characters */
+ for (i = 0;i < 8;i++)
+ {
+ colortable[4 * i] = 0;
+ colortable[4 * i + 1] = i + 0x08;
+ colortable[4 * i + 2] = i + 0x10;
+ colortable[4 * i + 3] = i + 0x18;
+ }
+
+ /* sprites */
+ for (i = 0;i < 4 * 8;i++)
+ {
+ int bit0,bit1,bit2,bit3;
+
+
+ /* low 4 bits are for sprite n */
+ bit0 = (color_prom[i + 32] >> 3) & 0x01;
+ bit1 = (color_prom[i + 32] >> 2) & 0x01;
+ bit2 = (color_prom[i + 32] >> 1) & 0x01;
+ bit3 = (color_prom[i + 32] >> 0) & 0x01;
+ colortable[i + 4 * 8] = 1 * bit0 + 2 * bit1 + 4 * bit2 + 8 * bit3;
+
+ /* high 4 bits are for sprite n + 8 */
+ bit0 = (color_prom[i + 32] >> 7) & 0x01;
+ bit1 = (color_prom[i + 32] >> 6) & 0x01;
+ bit2 = (color_prom[i + 32] >> 5) & 0x01;
+ bit3 = (color_prom[i + 32] >> 4) & 0x01;
+ colortable[i + 4 * 16] = 1 * bit0 + 2 * bit1 + 4 * bit2 + 8 * bit3;
+ }
+
+ /* stationary part of grid */
+ colortable[32 + 64] = 0;
+ colortable[32 + 64 + 1] = 64;
+}
+
+WRITE8_HANDLER( ladybug_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( ladybug_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( ladybug_flipscreen_w )
+{
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+////////////////////////////////////////////////
+/* All this should probably go somewhere else */
+
+/* Sound comm between CPU's */
+static UINT8 sraider_sound_low;
+
+READ8_HANDLER( sraider_sound_low_r )
+{
+ return sraider_sound_low;
+}
+
+static UINT8 sraider_sound_high;
+
+READ8_HANDLER( sraider_sound_high_r )
+{
+ return sraider_sound_high;
+}
+
+WRITE8_HANDLER( sraider_sound_low_w )
+{
+ sraider_sound_low = data;
+}
+
+WRITE8_HANDLER( sraider_sound_high_w )
+{
+ sraider_sound_high = data;
+}
+
+/* Protection? */
+
+READ8_HANDLER( sraider_8005_r )
+{
+ /* This must return X011111X or cpu #1 will hang */
+ /* see code at rst $10 */
+ return 0x3e;
+}
+
+/* Unknown IO */
+
+static UINT8 sraider_wierd_value[8];
+static UINT8 sraider_0x30, sraider_0x38;
+
+WRITE8_HANDLER( sraider_misc_w )
+{
+ switch(offset)
+ {
+ /* These 8 bits are stored in the latch at A7 */
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ sraider_wierd_value[offset&7] = data&1;
+ break;
+ /* These 6 bits are stored in the latch at N7 */
+ case 0x08:
+ sraider_0x30 = data&0x3f;
+ break;
+ /* These 6 bits are stored in the latch at N8 */
+ case 0x10:
+ sraider_0x38 = data&0x3f;
+ break;
+ default:
+ mame_printf_debug("(%04X) write to %02X\n",activecpu_get_pc(),offset);
+ break;
+ }
+}
+
+////////////////////////////////////////////////////
+
+static UINT8 gridline[256];
+
+WRITE8_HANDLER( sraider_grid_data_w )
+{
+ static int x = 0;
+
+ if (x == 0)
+ {
+ tilemap_mark_all_tiles_dirty(grid_tilemap);
+ x = 1;
+ }
+ gridline[offset] = data;
+
+}
+
+WRITE8_HANDLER( sraider_io_w )
+{
+ // bit7 = flip
+ // bit6 = grid red
+ // bit5 = grid green
+ // bit4 = grid blue
+ // bit3 = enable stars
+ // bit210 = stars speed/dir
+
+ if (flip_screen != (data & 0x80))
+ {
+ flip_screen_set(data & 0x80);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ palette_set_color_rgb(Machine,64,
+ ((data&0x40)>>6)*0xff,
+ ((data&0x20)>>5)*0xff,
+ ((data&0x10)>>4)*0xff);
+
+ redclash_set_stars_enable((data&0x08)>>3);
+
+ /*
+ * There must be a subtle clocking difference between
+ * Space Raider and the other games using this star generator,
+ * hence the -1 here
+ */
+
+ redclash_set_stars_speed((data&0x07) - 1);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + 32 * (colorram[tile_index] & 0x08);
+ int color = colorram[tile_index] & 0x07;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static TILE_GET_INFO( get_grid_tile_info )
+{
+ if (tile_index < 512)
+ SET_TILE_INFO(3, tile_index, 0, 0);
+ else
+ {
+ int temp = tile_index/32;
+ tile_index = (31 - temp) * 32 + (tile_index % 32);
+ SET_TILE_INFO(4, tile_index, 0, 0);
+ }
+}
+
+VIDEO_START( ladybug )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_scroll_rows(bg_tilemap, 32);
+}
+
+VIDEO_START( sraider )
+{
+ grid_tilemap = tilemap_create(get_grid_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_scroll_rows(grid_tilemap, 32);
+
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_scroll_rows(bg_tilemap, 32);
+
+ tilemap_set_transparent_pen(grid_tilemap, 0);
+ tilemap_set_transparent_pen(bg_tilemap, 0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 2*0x40;offs >= 2*0x40;offs -= 0x40)
+ {
+ int i = 0;
+
+ while (i < 0x40 && spriteram[offs + i] != 0)
+ i += 4;
+
+ while (i > 0)
+ {
+/*
+ abccdddd eeeeeeee fffghhhh iiiiiiii
+
+ a enable?
+ b size (0 = 8x8, 1 = 16x16)
+ cc flip
+ dddd y offset
+ eeeeeeee sprite code (shift right 2 bits for 16x16 sprites)
+ fff unknown
+ g sprite bank
+ hhhh color
+ iiiiiiii x position
+*/
+ i -= 4;
+
+ if (spriteram[offs + i] & 0x80)
+ {
+ if (spriteram[offs + i] & 0x40) /* 16x16 */
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs + i + 1] >> 2) + 4 * (spriteram[offs + i + 2] & 0x10),
+ spriteram[offs + i + 2] & 0x0f,
+ spriteram[offs + i] & 0x20,spriteram[offs + i] & 0x10,
+ spriteram[offs + i + 3],
+ offs / 4 - 8 + (spriteram[offs + i] & 0x0f),
+ cliprect,TRANSPARENCY_PEN,0);
+ else /* 8x8 */
+ drawgfx(bitmap,machine->gfx[2],
+ spriteram[offs + i + 1] + 16 * (spriteram[offs + i + 2] & 0x10),
+ spriteram[offs + i + 2] & 0x0f,
+ spriteram[offs + i] & 0x20,spriteram[offs + i] & 0x10,
+ spriteram[offs + i + 3],
+ offs / 4 + (spriteram[offs + i] & 0x0f),
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( ladybug )
+{
+ int offs;
+
+ for (offs = 0; offs < 32; offs++)
+ {
+ int sx = offs % 4;
+ int sy = offs / 4;
+
+ if (flip_screen)
+ tilemap_set_scrollx(bg_tilemap, offs, -videoram[32 * sx + sy]);
+ else
+ tilemap_set_scrollx(bg_tilemap, offs, videoram[32 * sx + sy]);
+ }
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
+
+VIDEO_EOF( sraider ) /* update starfield position */
+{
+ redclash_update_stars_state();
+}
+
+VIDEO_UPDATE( sraider )
+{
+ // this part is boilerplate from ladybug, not sure if hardware does this,
+ // since it's not used
+
+ int offs;
+ int i;
+
+ for (offs = 0; offs < 32; offs++)
+ {
+ int sx = offs % 4;
+ int sy = offs / 4;
+
+ if (flip_screen)
+ tilemap_set_scrollx(bg_tilemap, offs, -videoram[32 * sx + sy]);
+ else
+ tilemap_set_scrollx(bg_tilemap, offs, videoram[32 * sx + sy]);
+ }
+
+ // clear the bg bitmap
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ // draw the stars
+ if (flip_screen)
+ redclash_draw_stars(machine,bitmap,cliprect,32,1,0x27,0xff);
+ else
+ redclash_draw_stars(machine,bitmap,cliprect,32,1,0x00,0xd8);
+
+ // draw the horizontal gridlines
+ tilemap_draw(bitmap, cliprect, grid_tilemap, 0, flip_screen);
+ for(i=0;i<256;i++)
+ {
+ if (gridline[i] != 0)
+ {
+ if (flip_screen)
+ plot_box(bitmap,i^0xff,0,1,255,machine->pens[64]);
+ else
+ plot_box(bitmap,i,0,1,255,machine->pens[64]);
+ }
+ }
+
+ // now the chars
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, flip_screen);
+
+ // now the sprites
+ draw_sprites(machine, bitmap, cliprect);
+
+ return 0;
+}
+
diff --git a/src/mame/video/ladyfrog.c b/src/mame/video/ladyfrog.c
new file mode 100644
index 00000000000..2e7a7968dba
--- /dev/null
+++ b/src/mame/video/ladyfrog.c
@@ -0,0 +1,155 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+#include "driver.h"
+static int tilebank=0;
+
+static tilemap *bg_tilemap;
+static int palette_bank;
+//static int gfxctrl;
+
+UINT8 *ladyfrog_scrlram;
+
+static UINT8 *ladyfrog_spriteram;
+extern UINT8 *ladyfrog_sharedram;
+
+WRITE8_HANDLER(ladyfrog_spriteram_w)
+{
+ ladyfrog_spriteram[offset]=data;
+}
+
+READ8_HANDLER(ladyfrog_spriteram_r)
+{
+ return ladyfrog_spriteram[offset];
+}
+
+static TILE_GET_INFO( get_tile_info )
+{
+ int pal,tile;
+ pal=videoram[tile_index*2+1]&0x0f;
+ tile=videoram[tile_index*2] + ((videoram[tile_index*2+1] & 0xc0) << 2)+ ((videoram[tile_index*2+1] & 0x30) <<6 );
+ SET_TILE_INFO(
+ 0,
+ tile +0x1000 * tilebank,
+ pal,TILE_FLIPY
+ );
+}
+
+WRITE8_HANDLER( ladyfrog_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset>>1);
+}
+
+READ8_HANDLER( ladyfrog_videoram_r )
+{
+ return videoram[offset];
+}
+
+WRITE8_HANDLER( ladyfrog_palette_w )
+{
+ if (offset & 0x100)
+ paletteram_xxxxBBBBGGGGRRRR_split2_w((offset & 0xff) + (palette_bank << 8),data);
+ else
+ paletteram_xxxxBBBBGGGGRRRR_split1_w((offset & 0xff) + (palette_bank << 8),data);
+}
+
+READ8_HANDLER( ladyfrog_palette_r )
+{
+ if (offset & 0x100)
+ return paletteram_2[ (offset & 0xff) + (palette_bank << 8) ];
+ else
+ return paletteram [ (offset & 0xff) + (palette_bank << 8) ];
+}
+
+WRITE8_HANDLER( ladyfrog_gfxctrl_w )
+{
+ palette_bank = (data & 0x20) >> 5;
+
+}
+
+WRITE8_HANDLER( ladyfrog_gfxctrl2_w )
+{
+ tilebank=((data & 0x18) >> 3)^3;
+ tilemap_mark_all_tiles_dirty( bg_tilemap );
+}
+
+
+#ifdef UNUSED_FUNCTION
+READ8_HANDLER( ladyfrog_gfxctrl_r )
+{
+ return gfxctrl;
+}
+#endif
+
+READ8_HANDLER( ladyfrog_scrlram_r )
+{
+ return ladyfrog_scrlram[offset];
+}
+
+WRITE8_HANDLER( ladyfrog_scrlram_w )
+{
+ ladyfrog_scrlram[offset] = data;
+ tilemap_set_scrolly(bg_tilemap, offset, data );
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int i;
+ for (i=0;i<0x20;i++)
+ {
+ int pr = ladyfrog_spriteram[0x9f-i];
+ int offs = (pr & 0x1f) * 4;
+ {
+ int code,sx,sy,flipx,flipy,pal;
+ code = ladyfrog_spriteram[offs+2] + ((ladyfrog_spriteram[offs+1] & 0x10) << 4)+0x800;
+ pal=ladyfrog_spriteram[offs+1] & 0x0f;
+ sx = ladyfrog_spriteram[offs+3];
+ sy = 240-ladyfrog_spriteram[offs+0];
+ flipx = ((ladyfrog_spriteram[offs+1]&0x40)>>6);
+ flipy = ((ladyfrog_spriteram[offs+1]&0x80)>>7);
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ pal,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+
+ if(ladyfrog_spriteram[offs+3]>240)
+ {
+ sx = (ladyfrog_spriteram[offs+3]-256);
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ pal,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+ }
+
+}
+
+VIDEO_START( ladyfrog )
+{
+ ladyfrog_spriteram = auto_malloc (160);
+ bg_tilemap = tilemap_create( get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+
+ paletteram = auto_malloc(0x200);
+ paletteram_2 = auto_malloc(0x200);
+ tilemap_set_scroll_cols(bg_tilemap,32);
+ tilemap_set_scrolldy( bg_tilemap, 15, 15 );
+}
+
+
+VIDEO_UPDATE( ladyfrog )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
diff --git a/src/mame/video/lasso.c b/src/mame/video/lasso.c
new file mode 100644
index 00000000000..4c12ef9a236
--- /dev/null
+++ b/src/mame/video/lasso.c
@@ -0,0 +1,403 @@
+/***************************************************************************
+
+ Lasso and similar hardware
+
+ driver by Phil Stroffolino, Nicola Salmoria, Luca Elia
+
+
+ Every game has 1 256 x 256 tilemap (non scrollable) made of 8 x 8
+ tiles, and 16 x 16 sprites (some games use 32, some more).
+
+ The graphics for tiles and sprites are held inside the same ROMs,
+ but aren't shared between the two:
+
+ the first $100 tiles are for the tilemap, the following $100 are
+ for sprites. This constitutes the first graphics bank. There can
+ be several.
+
+ Lasso has an additional pixel layer (256 x 256 x 1) and a third
+ CPU devoted to drawing into it (the lasso!)
+
+ Wwjgtin has an additional $800 x $400 scrolling tilemap in ROM
+ and $100 more 16 x 16 x 4 tiles for it.
+
+ The colors are static ($40 colors, 2 PROMs) but the background
+ color can be changed at runtime. Wwjgtin can change the last
+ 4 colors (= last palette) too.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "lasso.h"
+
+
+UINT8 *lasso_videoram;
+UINT8 *lasso_colorram;
+UINT8 *lasso_spriteram;
+size_t lasso_spriteram_size;
+UINT8 *lasso_bitmap_ram; /* 0x2000 bytes for a 256 x 256 x 1 bitmap */
+UINT8 *wwjgtin_track_scroll;
+
+/* variables only used here: */
+static tilemap *bg_tilemap, *track_tilemap;
+static UINT8 gfxbank; /* used by lasso, chameleo, wwjgtin and pinbo */
+static UINT8 wwjgtin_track_enable; /* used by wwjgtin */
+
+
+/***************************************************************************
+
+
+ Colors (BBGGGRRR)
+
+
+***************************************************************************/
+
+static void lasso_set_color(int i, int data)
+{
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (data >> 0) & 0x01;
+ bit1 = (data >> 1) & 0x01;
+ bit2 = (data >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (data >> 3) & 0x01;
+ bit1 = (data >> 4) & 0x01;
+ bit2 = (data >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (data >> 6) & 0x01;
+ bit1 = (data >> 7) & 0x01;
+ b = 0x4f * bit0 + 0xa8 * bit1;
+
+ palette_set_color( Machine,i,MAKE_RGB(r,g,b) );
+}
+
+PALETTE_INIT( lasso )
+{
+ int i;
+
+ for (i = 0;i < 0x40;i++)
+ {
+ lasso_set_color(i,*color_prom);
+ color_prom++;
+ }
+}
+
+/* 16 color tiles with a 4 color step for the palettes */
+PALETTE_INIT( wwjgtin )
+{
+ int color, pen;
+
+ palette_init_lasso(machine,colortable,color_prom);
+
+ for( color = 0; color < 0x10; color++ )
+ for( pen = 0; pen < 16; pen++ )
+ colortable[color * 16 + pen + 4*16] = (color * 4 + pen) % 0x40;
+}
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( lasso_get_bg_tile_info )
+{
+ int code = lasso_videoram[tile_index];
+ int color = lasso_colorram[tile_index];
+ SET_TILE_INFO(0,
+ code + ((UINT16)gfxbank << 8),
+ color & 0x0f,
+ 0);
+}
+
+static TILE_GET_INFO( wwjgtin_get_track_tile_info )
+{
+ UINT8 *ROM = memory_region(REGION_USER1);
+ int code = ROM[tile_index];
+ int color = ROM[tile_index + 0x2000];
+ SET_TILE_INFO(2,
+ code,
+ color & 0x0f,
+ 0);
+}
+
+static TILE_GET_INFO( pinbo_get_bg_tile_info )
+{
+ int code = lasso_videoram[tile_index];
+ int color = lasso_colorram[tile_index];
+ SET_TILE_INFO(0,
+ code + ((color & 0x30) << 4),
+ color & 0x0f,
+ 0);
+}
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( lasso )
+{
+ /* create tilemap */
+ bg_tilemap = tilemap_create(lasso_get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+
+ /* register for saving */
+ state_save_register_global(gfxbank);
+}
+
+VIDEO_START( wwjgtin )
+{
+ /* create tilemaps */
+ bg_tilemap = tilemap_create(lasso_get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+ track_tilemap = tilemap_create(wwjgtin_get_track_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,16, 0x80,0x40);
+
+ tilemap_set_transparent_pen(bg_tilemap,0);
+
+ /* register for saving */
+ state_save_register_global(gfxbank);
+ state_save_register_global(wwjgtin_track_enable);
+}
+
+VIDEO_START( pinbo )
+{
+ /* create tilemap */
+ bg_tilemap = tilemap_create(pinbo_get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+
+ /* register for saving */
+ state_save_register_global(gfxbank);
+}
+
+
+/*************************************
+ *
+ * Memory handlers
+ *
+ *************************************/
+
+WRITE8_HANDLER( lasso_videoram_w )
+{
+ lasso_videoram[offset] = data;
+ tilemap_mark_tile_dirty( bg_tilemap, offset );
+}
+
+WRITE8_HANDLER( lasso_colorram_w )
+{
+ lasso_colorram[offset] = data;
+ tilemap_mark_tile_dirty( bg_tilemap, offset );
+}
+
+
+static WRITE8_HANDLER( lasso_flip_screen_w )
+{
+ /* don't know which is which, but they are always set together */
+ flip_screen_x = data & 0x01;
+ flip_screen_y = data & 0x02;
+
+ tilemap_set_flip(ALL_TILEMAPS, (flip_screen_x ? TILEMAP_FLIPX : 0) |
+ (flip_screen_y ? TILEMAP_FLIPY : 0));
+}
+
+
+WRITE8_HANDLER( lasso_video_control_w )
+{
+ int bank = (data & 0x04) >> 2;
+
+ if (gfxbank != bank)
+ {
+ gfxbank = bank;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ lasso_flip_screen_w(offset, data);
+}
+
+WRITE8_HANDLER( wwjgtin_video_control_w )
+{
+ int bank = ((data & 0x04) ? 0 : 1) + ((data & 0x10) ? 2 : 0);
+ wwjgtin_track_enable = data & 0x08;
+
+ if (gfxbank != bank)
+ {
+ gfxbank = bank;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ lasso_flip_screen_w(offset, data);
+}
+
+WRITE8_HANDLER( pinbo_video_control_w )
+{
+ /* no need to dirty the tilemap -- only the sprites use the global bank */
+ gfxbank = (data & 0x0c) >> 2;
+
+ lasso_flip_screen_w(offset, data);
+}
+
+
+/* The bg_tilemap color can be changed */
+WRITE8_HANDLER( lasso_backcolor_w )
+{
+ int i;
+ for( i=0; i<0x40; i+=4 ) /* stuff into color#0 of each palette */
+ lasso_set_color(i,data);
+}
+
+
+/* The last 4 color (= last palette) entries can be changed */
+WRITE8_HANDLER( wwjgtin_lastcolor_w )
+{
+ lasso_set_color(0x3f - offset,data);
+}
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int reverse )
+{
+ const UINT8 *finish, *source;
+ int inc;
+
+ if (reverse)
+ {
+ source = lasso_spriteram;
+ finish = lasso_spriteram + lasso_spriteram_size;
+ inc = 4;
+ }
+ else
+ {
+ source = lasso_spriteram + lasso_spriteram_size - 4;
+ finish = lasso_spriteram - 4;
+ inc = -4;
+ }
+
+ while( source != finish )
+ {
+ int sx,sy,flipx,flipy;
+ int code,color;
+
+ sx = source[3];
+ sy = source[0];
+ flipx = source[1] & 0x40;
+ flipy = source[1] & 0x80;
+
+ if (flip_screen_x)
+ {
+ sx = 240 - sx;
+ flipx = !flipx;
+ }
+
+ if (flip_screen_y)
+ {
+ flipy = !flipy;
+ }
+ else
+ {
+ sy = 240 - sy;
+ }
+
+ code = source[1] & 0x3f;
+ color = source[2] & 0x0f;
+
+
+ drawgfx(bitmap, machine->gfx[1],
+ code | ((UINT16)gfxbank << 6),
+ color,
+ flipx, flipy,
+ sx,sy,
+ cliprect, TRANSPARENCY_PEN,0);
+
+ source += inc;
+ }
+}
+
+
+static void draw_lasso(running_machine *machine, mame_bitmap *bitmap)
+{
+ const UINT8 *source = lasso_bitmap_ram;
+ int x,y;
+ pen_t pen = machine->pens[0x3f];
+
+
+ for (y = 0; y < 256; y++)
+ {
+ for (x = 0; x < 256; )
+ {
+ UINT8 data = *source++;
+
+ if (data)
+ {
+ int bit;
+
+ for (bit = 0; bit < 8; bit++)
+ {
+ if (data & 0x80)
+ {
+ if (flip_screen_x)
+ {
+ if (flip_screen_y)
+ *BITMAP_ADDR16(bitmap, 255-y, 255-x) = pen;
+ else
+ *BITMAP_ADDR16(bitmap, y, 255-x) = pen;
+ }
+ else
+ {
+ if (flip_screen_y)
+ *BITMAP_ADDR16(bitmap, 255-y, x) = pen;
+ else
+ *BITMAP_ADDR16(bitmap, y, x) = pen;
+ }
+ }
+
+ x++;
+ data <<= 1;
+ }
+ }
+ else
+ {
+ x += 8;
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( lasso )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_lasso(machine, bitmap);
+ draw_sprites(machine, bitmap, cliprect, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( chameleo )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect, 0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( wwjgtin )
+{
+ tilemap_set_scrollx(track_tilemap,0,wwjgtin_track_scroll[0] + wwjgtin_track_scroll[1]*256);
+ tilemap_set_scrolly(track_tilemap,0,wwjgtin_track_scroll[2] + wwjgtin_track_scroll[3]*256);
+
+ if (wwjgtin_track_enable)
+ tilemap_draw(bitmap, cliprect, track_tilemap, 0, 0);
+ else
+ fillbitmap(bitmap, machine->pens[0x40], cliprect); // black
+
+ draw_sprites(machine, bitmap, cliprect, 1); // reverse order
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/lastduel.c b/src/mame/video/lastduel.c
new file mode 100644
index 00000000000..2de12a5ad5b
--- /dev/null
+++ b/src/mame/video/lastduel.c
@@ -0,0 +1,253 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *lastduel_vram,*lastduel_scroll2,*lastduel_scroll1;
+
+static tilemap *bg_tilemap,*fg_tilemap,*tx_tilemap;
+
+static int sprite_flipy_mask,sprite_pri_mask;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( ld_get_bg_tile_info )
+{
+ int tile = lastduel_scroll2[2*tile_index] & 0x1fff;
+ int color = lastduel_scroll2[2*tile_index+1];
+ SET_TILE_INFO(
+ 2,
+ tile,color & 0xf,
+ TILE_FLIPYX((color & 0x60) >> 5));
+}
+
+static TILE_GET_INFO( ld_get_fg_tile_info )
+{
+ int tile = lastduel_scroll1[2*tile_index] & 0x1fff;
+ int color = lastduel_scroll1[2*tile_index+1];
+ SET_TILE_INFO(
+ 3,
+ tile,
+ color & 0xf,
+ TILE_FLIPYX((color & 0x60) >> 5));
+ tileinfo->group = (color & 0x80) >> 7;
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int tile = lastduel_scroll2[tile_index] & 0x1fff;
+ int color = lastduel_scroll2[tile_index+0x0800];
+ SET_TILE_INFO(
+ 2,
+ tile,
+ color & 0xf,
+ TILE_FLIPYX((color & 0x60) >> 5));
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int tile = lastduel_scroll1[tile_index] & 0x1fff;
+ int color = lastduel_scroll1[tile_index+0x0800];
+ SET_TILE_INFO(
+ 3,
+ tile,
+ color & 0xf,
+ TILE_FLIPYX((color & 0x60) >> 5));
+ tileinfo->group = (color & 0x10) >> 4;
+}
+
+static TILE_GET_INFO( get_fix_info )
+{
+ int tile = lastduel_vram[tile_index];
+ SET_TILE_INFO(
+ 1,
+ tile & 0x7ff,
+ tile>>12,
+ (tile & 0x800) ? TILE_FLIPY : 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( lastduel )
+{
+ bg_tilemap = tilemap_create(ld_get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ fg_tilemap = tilemap_create(ld_get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ tx_tilemap = tilemap_create(get_fix_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_transmask(fg_tilemap,0,0xffff,0x0001);
+ tilemap_set_transmask(fg_tilemap,1,0xf07f,0x0f81);
+ tilemap_set_transparent_pen(tx_tilemap,3);
+
+ sprite_flipy_mask = 0x40;
+ sprite_pri_mask = 0x00;
+}
+
+VIDEO_START( madgear )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,64,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,64,32);
+ tx_tilemap = tilemap_create(get_fix_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_transmask(fg_tilemap,0,0xffff,0x8000);
+ tilemap_set_transmask(fg_tilemap,1,0x80ff,0xff00);
+ tilemap_set_transparent_pen(tx_tilemap,3);
+
+ sprite_flipy_mask = 0x80;
+ sprite_pri_mask = 0x10;
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( lastduel_flip_w )
+{
+ if (ACCESSING_LSB)
+ {
+ flip_screen_set(data & 0x01);
+
+ coin_lockout_w(0,~data & 0x10);
+ coin_lockout_w(1,~data & 0x20);
+ coin_counter_w(0,data & 0x40);
+ coin_counter_w(1,data & 0x80);
+ }
+}
+
+WRITE16_HANDLER( lastduel_scroll_w )
+{
+ static UINT16 scroll[4];
+
+ data = COMBINE_DATA(&scroll[offset]);
+ switch (offset)
+ {
+ case 0: tilemap_set_scrolly(fg_tilemap,0,data); break;
+ case 1: tilemap_set_scrollx(fg_tilemap,0,data); break;
+ case 2: tilemap_set_scrolly(bg_tilemap,0,data); break;
+ case 3: tilemap_set_scrollx(bg_tilemap,0,data); break;
+ }
+}
+
+WRITE16_HANDLER( lastduel_scroll1_w )
+{
+ COMBINE_DATA(&lastduel_scroll1[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( lastduel_scroll2_w )
+{
+ COMBINE_DATA(&lastduel_scroll2[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( lastduel_vram_w )
+{
+ COMBINE_DATA(&lastduel_vram[offset]);
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+WRITE16_HANDLER( madgear_scroll1_w )
+{
+ COMBINE_DATA(&lastduel_scroll1[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x7ff);
+}
+
+WRITE16_HANDLER( madgear_scroll2_w )
+{
+ COMBINE_DATA(&lastduel_scroll2[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x7ff);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri)
+{
+ int offs;
+
+ if (!sprite_pri_mask)
+ if (pri == 1) return; /* only low priority sprites in lastduel */
+
+ for(offs=0x400-4;offs>=0;offs-=4)
+ {
+ int attr,sy,sx,flipx,flipy,code,color;
+
+ attr = buffered_spriteram16[offs+1];
+ if (sprite_pri_mask) /* only madgear seems to have this */
+ {
+ if (pri==1 && (attr & sprite_pri_mask)) continue;
+ if (pri==0 && !(attr & sprite_pri_mask)) continue;
+ }
+
+ code = buffered_spriteram16[offs];
+ sx = buffered_spriteram16[offs+3] & 0x1ff;
+ sy = buffered_spriteram16[offs+2] & 0x1ff;
+ if (sy > 0x100)
+ sy -= 0x200;
+
+ flipx = attr & 0x20;
+ flipy = attr & sprite_flipy_mask; /* 0x40 for lastduel, 0x80 for madgear */
+ color = attr & 0x0f;
+
+ if (flip_screen)
+ {
+ sx = 496 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN,15);
+ }
+}
+
+VIDEO_UPDATE( lastduel )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,TILEMAP_DRAW_LAYER1,0);
+ draw_sprites(machine,bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,TILEMAP_DRAW_LAYER0,0);
+ draw_sprites(machine,bitmap,cliprect,1);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+
+VIDEO_EOF( lastduel )
+{
+ /* Spriteram is always 1 frame ahead, suggesting buffering. I can't find
+ a register to control this so I assume it happens automatically
+ every frame at the end of vblank */
+ buffer_spriteram16_w(0,0,0);
+}
diff --git a/src/mame/video/lazercmd.c b/src/mame/video/lazercmd.c
new file mode 100644
index 00000000000..33a51ce08ec
--- /dev/null
+++ b/src/mame/video/lazercmd.c
@@ -0,0 +1,85 @@
+/*************************************************************/
+/* */
+/* Lazer Command video handler */
+/* */
+/*************************************************************/
+
+#include "driver.h"
+#include "includes/lazercmd.h"
+
+int marker_x, marker_y;
+
+
+/* scale a markers vertical position */
+/* the following table shows how the markers */
+/* vertical position worked in hardware */
+/* marker_y lines marker_y lines */
+/* 0 0 + 1 8 10 + 11 */
+/* 1 2 + 3 9 12 + 13 */
+/* 2 4 + 5 10 14 + 15 */
+/* 3 6 + 7 11 16 + 17 */
+/* 4 8 + 9 12 18 + 19 */
+static int vert_scale(int data)
+{
+ return ((data & 0x07)<<1) + ((data & 0xf8)>>3) * VERT_CHR;
+}
+
+/* plot a bitmap marker */
+/* hardware has 2 marker sizes 2x2 and 4x2 selected by jumper */
+/* meadows lanes normaly use 2x2 pixels and lazer command uses either */
+static void plot_pattern(running_machine *machine, mame_bitmap *bitmap, int x, int y)
+{
+ int xbit, ybit, size;
+
+ size = 2;
+ if (input_port_2_r(0) & 0x40)
+ {
+ size = 4;
+ }
+
+ for (ybit = 0; ybit < 2; ybit++)
+ {
+ if (y+ybit < 0 || y+ybit >= VERT_RES * VERT_CHR)
+ return;
+
+ for (xbit = 0; xbit < size; xbit++)
+ {
+ if (x+xbit < 0 || x+xbit >= HORZ_RES * HORZ_CHR)
+ continue;
+
+ *BITMAP_ADDR16(bitmap, y+ybit, x+xbit) = machine->pens[2];
+ }
+ }
+}
+
+
+VIDEO_UPDATE( lazercmd )
+{
+ int i,x,y;
+
+ int video_inverted = input_port_2_r(0) & 0x20;
+
+ /* The first row of characters are invisible */
+ for (i = 0; i < (VERT_RES - 1) * HORZ_RES; i++)
+ {
+ int sx,sy;
+
+ sx = i % HORZ_RES;
+ sy = i / HORZ_RES;
+
+ sx *= HORZ_CHR;
+ sy *= VERT_CHR;
+
+ drawgfx(bitmap, machine->gfx[0],
+ videoram[i], video_inverted ? 1 : 0,
+ 0,0,
+ sx,sy,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ }
+
+ x = marker_x - 1; /* normal video lags marker by 1 pixel */
+ y = vert_scale(marker_y) - VERT_CHR; /* first line used as scratch pad */
+ plot_pattern(machine, bitmap,x,y);
+
+ return 0;
+}
diff --git a/src/mame/video/legionna.c b/src/mame/video/legionna.c
new file mode 100644
index 00000000000..83ebd6a7979
--- /dev/null
+++ b/src/mame/video/legionna.c
@@ -0,0 +1,450 @@
+/***************************************************************************
+
+ Legionnaire / Heated Barrel video hardware (derived from D-Con)
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *legionna_back_data,*legionna_fore_data,*legionna_mid_data,*legionna_scrollram16,*legionna_textram;
+
+static tilemap *background_layer,*foreground_layer,*midground_layer,*text_layer;
+//static int legionna_enable;
+
+/******************************************************************************/
+
+static UINT16 back_gfx_bank = 0,fore_gfx_bank = 0,mid_gfx_bank = 0;
+UINT8 sdgndmrb_pri_n;
+
+void heatbrl_setgfxbank(UINT16 data)
+{
+ back_gfx_bank = (data &0x4000) >> 2;
+}
+
+/*xxx- --- ---- ---- banking*/
+void denjinmk_setgfxbank(UINT16 data)
+{
+ fore_gfx_bank = (data &0x2000) >> 1;//???
+ back_gfx_bank = (data &0x4000) >> 2;
+ mid_gfx_bank = (data &0x8000) >> 3;//???
+}
+
+#ifdef UNUSED_FUNCTION
+WRITE16_HANDLER( legionna_control_w )
+{
+ if (ACCESSING_LSB)
+ {
+ legionna_enable=data;
+ if ((legionna_enable&4)==4)
+ tilemap_set_enable(foreground_layer,0);
+ else
+ tilemap_set_enable(foreground_layer,1);
+
+ if ((legionna_enable&2)==2)
+ tilemap_set_enable(midground_layer,0);
+ else
+ tilemap_set_enable(midground_layer,1);
+
+ if ((legionna_enable&1)==1)
+ tilemap_set_enable(background_layer,0);
+ else
+ tilemap_set_enable(background_layer,1);
+ }
+}
+#endif
+
+WRITE16_HANDLER( legionna_background_w )
+{
+ COMBINE_DATA(&legionna_back_data[offset]);
+ tilemap_mark_tile_dirty(background_layer,offset);
+}
+
+WRITE16_HANDLER( legionna_midground_w )
+{
+ COMBINE_DATA(&legionna_mid_data[offset]);
+ tilemap_mark_tile_dirty(midground_layer,offset);
+}
+
+WRITE16_HANDLER( legionna_foreground_w )
+{
+ COMBINE_DATA(&legionna_fore_data[offset]);
+ tilemap_mark_tile_dirty(foreground_layer,offset);
+}
+
+WRITE16_HANDLER( legionna_text_w )
+{
+ COMBINE_DATA(&legionna_textram[offset]);
+ tilemap_mark_tile_dirty(text_layer,offset);
+}
+
+static TILE_GET_INFO( get_back_tile_info )
+{
+ int tile=legionna_back_data[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile &= 0xfff;
+ tile |= back_gfx_bank; /* Heatbrl uses banking */
+
+ SET_TILE_INFO(1,tile,color,0);
+}
+
+static TILE_GET_INFO( get_mid_tile_info )
+{
+ int tile=legionna_mid_data[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile &= 0xfff;
+
+ SET_TILE_INFO(5,tile,color,0);
+}
+
+static TILE_GET_INFO( get_mid_tile_info_denji )
+{
+ int tile=legionna_mid_data[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile &= 0xfff;
+ tile |= mid_gfx_bank;
+
+ SET_TILE_INFO(5,tile,color,0);
+}
+
+static TILE_GET_INFO( get_mid_tile_info_cupsoc )
+{
+ int tile=legionna_mid_data[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile &= 0xfff;
+
+ tile |= 0x1000;
+
+ SET_TILE_INFO(1,tile,color,0);
+}
+
+static TILE_GET_INFO( get_fore_tile_info ) /* this is giving bad tiles... */
+{
+ int tile=legionna_fore_data[tile_index];
+ int color=(tile>>12)&0xf;
+
+ // legionnaire tile numbers / gfx set wrong, see screen after coin insertion
+ tile &= 0xfff;
+
+ SET_TILE_INFO(4,tile,color,0);
+}
+
+static TILE_GET_INFO( get_fore_tile_info_denji )
+{
+ int tile=legionna_fore_data[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile &= 0xfff;
+ tile |= fore_gfx_bank;
+
+ SET_TILE_INFO(4,tile,color,0);
+}
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ int tile = legionna_textram[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile &= 0xfff;
+
+ SET_TILE_INFO(0,tile,color,0);
+}
+
+VIDEO_START( legionna )
+{
+ background_layer = tilemap_create(get_back_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ foreground_layer = tilemap_create(get_fore_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ midground_layer = tilemap_create(get_mid_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ text_layer = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,32);
+
+ legionna_scrollram16 = auto_malloc(0x60);
+
+ tilemap_set_transparent_pen(background_layer,15);
+ tilemap_set_transparent_pen(midground_layer,15);
+ tilemap_set_transparent_pen(foreground_layer,15);
+ tilemap_set_transparent_pen(text_layer,15);
+}
+
+VIDEO_START( denjinmk )
+{
+ background_layer = tilemap_create(get_back_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ foreground_layer = tilemap_create(get_fore_tile_info_denji,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ midground_layer = tilemap_create(get_mid_tile_info_denji, tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ text_layer = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,32);
+
+ legionna_scrollram16 = auto_malloc(0x60);
+
+ tilemap_set_transparent_pen(background_layer,15);
+ tilemap_set_transparent_pen(midground_layer,15);
+ tilemap_set_transparent_pen(foreground_layer,15);
+ tilemap_set_transparent_pen(text_layer,7);//?
+}
+
+VIDEO_START( cupsoc )
+{
+ background_layer = tilemap_create(get_back_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ foreground_layer = tilemap_create(get_fore_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ midground_layer = tilemap_create(get_mid_tile_info_cupsoc, tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ text_layer = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,32);
+
+ legionna_scrollram16 = auto_malloc(0x60);
+
+ tilemap_set_transparent_pen(background_layer,15);
+ tilemap_set_transparent_pen(midground_layer,15);
+ tilemap_set_transparent_pen(foreground_layer,15);
+ tilemap_set_transparent_pen(text_layer,15);
+}
+
+
+/*************************************************************************
+
+ Legionnaire Spriteram (similar to Dcon)
+ ---------------------
+
+ It has "big sprites" created by setting width or height >0. Tile
+ numbers are read consecutively.
+
+ +0 x....... ........ Sprite enable
+ +0 .x...... ........ Flip x
+ +0 ..x..... ........ Flip y ???
+ +0 ...xxx.. ........ Width: do this many tiles horizontally
+ +0 ......xx x....... Height: do this many tiles vertically
+ +0 ........ .x...... Tile bank,used in Denjin Makai
+ +0 ........ ..xxxxxx Color bank
+
+ +1 xx...... ........ Priority? (1=high?)
+ +1 ..xxxxxx xxxxxxxx Tile number
+ +2 xxxxxxxx xxxxxxxx X coordinate (signed)
+ +3 xxxxxxxx xxxxxxxx Y coordinate (signed)
+
+*************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int pri)
+{
+ int offs,fx,fy,x,y,color,sprite,cur_pri;
+ int dx,dy,ax,ay;
+
+ for (offs = 0x400-4;offs >= 0;offs -= 4)
+ {
+ UINT16 data = spriteram16[offs];
+ if (!(data &0x8000)) continue;
+
+ cur_pri = (spriteram16[offs+1] & 0xc000) >> 14;
+ if (cur_pri!=pri) continue;
+
+ sprite = spriteram16[offs+1];
+
+ sprite &= 0x3fff;
+ if(data & 0x40) sprite |= 0x4000;//tile banking,used in Denjin Makai
+
+ y = spriteram16[offs+3];
+ x = spriteram16[offs+2];
+
+ if (x &0x8000) x = -(0x200-(x &0x1ff));
+ else x &= 0x1ff;
+ if (y &0x8000) y = -(0x200-(y &0x1ff));
+ else y &= 0x1ff;
+
+ color = (data &0x3f) + 0x40;
+ fx = (data &0x4000) >> 14;
+ fy = (data &0x2000) >> 13;
+ dy = ((data &0x0380) >> 7) + 1;
+ dx = ((data &0x1c00) >> 10) + 1;
+
+ if (!fx)
+ {
+ if(!fy)
+ {
+ for (ax=0; ax<dx; ax++)
+ for (ay=0; ay<dy; ay++)
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ sprite++,
+ color,fx,fy,x+ax*16,y+ay*16,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+ else
+ {
+ for (ax=0; ax<dx; ax++)
+ for (ay=0; ay<dy; ay++)
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ sprite++,
+ color,fx,fy,x+ax*16,y+(dy-ay-1)*16,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+ }
+ else
+ {
+ if(!fy)
+ {
+ for (ax=0; ax<dx; ax++)
+ for (ay=0; ay<dy; ay++)
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ sprite++,
+ color,fx,fy,x+(dx-ax-1)*16,y+ay*16,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+ else
+ {
+ for (ax=0; ax<dx; ax++)
+ for (ay=0; ay<dy; ay++)
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ sprite++,
+ color,fx,fy,x+(dx-ax-1)*16,y+(dy-ay-1)*16,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+ }
+ }
+}
+
+#define LAYER_DB 0
+
+VIDEO_UPDATE( legionna )
+{
+#if LAYER_DB
+ static int dislayer[5]; /* Layer toggles to help get the layers correct */
+#endif
+
+#if LAYER_DB
+if (input_code_pressed_once (KEYCODE_Z))
+ {
+ dislayer[0] ^= 1;
+ ui_popup("bg0: %01x",dislayer[0]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_X))
+ {
+ dislayer[1] ^= 1;
+ ui_popup("bg1: %01x",dislayer[1]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_C))
+ {
+ dislayer[2] ^= 1;
+ ui_popup("bg2: %01x",dislayer[2]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_V))
+ {
+ dislayer[3] ^= 1;
+ ui_popup("sprites: %01x",dislayer[3]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_B))
+ {
+ dislayer[4] ^= 1;
+ ui_popup("text: %01x",dislayer[4]);
+ }
+#endif
+
+ /* Setup the tilemaps */
+ tilemap_set_scrollx( background_layer, 0, legionna_scrollram16[0] );
+ tilemap_set_scrolly( background_layer, 0, legionna_scrollram16[1] );
+ tilemap_set_scrollx( midground_layer, 0, legionna_scrollram16[2] );
+ tilemap_set_scrolly( midground_layer, 0, legionna_scrollram16[3] );
+ tilemap_set_scrollx( foreground_layer, 0, legionna_scrollram16[4] );
+ tilemap_set_scrolly( foreground_layer, 0, legionna_scrollram16[5] );
+
+// if ((legionna_enable&1)!=1)
+
+ fillbitmap(bitmap,get_black_pen(machine),cliprect); /* wrong color? */
+
+#if LAYER_DB
+ if (dislayer[2]==0)
+#endif
+ tilemap_draw(bitmap,cliprect,foreground_layer,TILEMAP_DRAW_OPAQUE,0);
+
+#if LAYER_DB
+ if (dislayer[1]==0)
+#endif
+ tilemap_draw(bitmap,cliprect,midground_layer,0,0);
+
+ draw_sprites(machine, bitmap,cliprect,3);
+#if LAYER_DB
+ if (dislayer[0]==0)
+#endif
+ tilemap_draw(bitmap,cliprect,background_layer,0,0);
+ draw_sprites(machine,bitmap,cliprect,2);
+ draw_sprites(machine,bitmap,cliprect,1);
+ draw_sprites(machine,bitmap,cliprect,0);
+
+#if LAYER_DB
+ if (dislayer[4]==0)
+#endif
+ tilemap_draw(bitmap,cliprect,text_layer,0,0);
+
+ return 0;
+}
+
+VIDEO_UPDATE( godzilla )
+{
+// tilemap_set_scrollx( text_layer, 0, 0 );
+// tilemap_set_scrolly( text_layer, 0, 112 );
+ /* Setup the tilemaps */
+ tilemap_set_scrollx( background_layer, 0, legionna_scrollram16[0] );
+ tilemap_set_scrolly( background_layer, 0, legionna_scrollram16[1] );
+ tilemap_set_scrollx( midground_layer, 0, legionna_scrollram16[2] );
+ tilemap_set_scrolly( midground_layer, 0, legionna_scrollram16[3] );
+ tilemap_set_scrollx( foreground_layer, 0, legionna_scrollram16[4] );
+ tilemap_set_scrolly( foreground_layer, 0, legionna_scrollram16[5] );
+
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ tilemap_draw(bitmap,cliprect,background_layer,0,0);
+ draw_sprites(machine,bitmap,cliprect,2);
+ tilemap_draw(bitmap,cliprect,midground_layer,0,0);
+ draw_sprites(machine,bitmap,cliprect,1);
+ tilemap_draw(bitmap,cliprect,foreground_layer,0,0);
+ draw_sprites(machine,bitmap,cliprect,0);
+ draw_sprites(machine,bitmap,cliprect,3);
+ tilemap_draw(bitmap,cliprect,text_layer,0,0);
+
+ return 0;
+}
+
+VIDEO_UPDATE( sdgndmrb )
+{
+ /* Setup the tilemaps */
+ tilemap_set_scrollx( background_layer, 0, legionna_scrollram16[0] );
+ tilemap_set_scrolly( background_layer, 0, legionna_scrollram16[1] );
+ tilemap_set_scrollx( midground_layer, 0, legionna_scrollram16[2] );
+ tilemap_set_scrolly( midground_layer, 0, legionna_scrollram16[3] );
+ tilemap_set_scrollx( foreground_layer, 0, legionna_scrollram16[4] );
+ tilemap_set_scrolly( foreground_layer, 0, legionna_scrollram16[5] );
+ tilemap_set_scrollx( text_layer, 0, legionna_scrollram16[6] );
+ tilemap_set_scrolly( text_layer, 0, legionna_scrollram16[7] );
+
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ if(!(sdgndmrb_pri_n & 1))
+ tilemap_draw(bitmap,cliprect,background_layer,0,0);
+ draw_sprites(machine,bitmap,cliprect,2);
+
+ if(!(sdgndmrb_pri_n & 2))
+ tilemap_draw(bitmap,cliprect,midground_layer,0,0);
+
+ draw_sprites(machine,bitmap,cliprect,1);
+
+ if(!(sdgndmrb_pri_n & 4))
+ tilemap_draw(bitmap,cliprect,foreground_layer,0,0);
+
+ draw_sprites(machine,bitmap,cliprect,0);
+
+ draw_sprites(machine,bitmap,cliprect,3);
+
+ if(!(sdgndmrb_pri_n & 8))
+ tilemap_draw(bitmap,cliprect,text_layer,0,0);
+
+ return 0;
+}
+
diff --git a/src/mame/video/leland.c b/src/mame/video/leland.c
new file mode 100644
index 00000000000..1f44b6e6b4e
--- /dev/null
+++ b/src/mame/video/leland.c
@@ -0,0 +1,573 @@
+/***************************************************************************
+
+ Cinemat/Leland driver
+
+ Leland video hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "leland.h"
+#include "sound/dac.h"
+
+
+/* constants */
+#define VRAM_SIZE 0x10000
+#define QRAM_SIZE 0x10000
+
+#define VIDEO_WIDTH 0x28
+#define VIDEO_HEIGHT 0x1e
+
+
+/* debugging */
+#define LOG_COMM 0
+
+
+
+struct vram_state_data
+{
+ UINT16 addr;
+ UINT8 latch[2];
+};
+
+
+/* video RAM */
+UINT8 *ataxx_qram;
+UINT8 leland_last_scanline_int;
+static mame_bitmap *fgbitmap;
+static UINT8 *leland_video_ram;
+
+/* video RAM bitmap drawing */
+static struct vram_state_data vram_state[2];
+static UINT8 sync_next_write;
+
+/* partial screen updating */
+static int next_update_scanline;
+
+/* scroll background registers */
+static UINT16 xscroll;
+static UINT16 yscroll;
+static UINT8 gfxbank;
+
+
+
+/*************************************
+ *
+ * Start video hardware
+ *
+ *************************************/
+
+VIDEO_START( leland )
+{
+ /* allocate memory */
+ leland_video_ram = auto_malloc(VRAM_SIZE);
+ fgbitmap = auto_bitmap_alloc(VIDEO_WIDTH * 8, VIDEO_HEIGHT * 8, machine->screen[0].format);
+
+ /* reset videoram */
+ memset(leland_video_ram, 0, VRAM_SIZE);
+}
+
+
+VIDEO_START( ataxx )
+{
+ /* first do the standard stuff */
+ video_start_leland(machine);
+
+ /* allocate memory */
+ ataxx_qram = auto_malloc(QRAM_SIZE);
+
+ /* reset QRAM */
+ memset(ataxx_qram, 0, QRAM_SIZE);
+}
+
+
+
+/*************************************
+ *
+ * Scrolling and banking
+ *
+ *************************************/
+
+WRITE8_HANDLER( leland_gfx_port_w )
+{
+ /* adjust the proper scroll value */
+ switch (offset)
+ {
+ case -1:
+ if (gfxbank != data)
+ {
+ video_screen_update_partial(0, leland_last_scanline_int);
+ gfxbank = data;
+ }
+ break;
+
+ case 0:
+ if ((xscroll & 0xff) != data)
+ {
+ video_screen_update_partial(0, leland_last_scanline_int);
+ xscroll = (xscroll & 0xff00) | (data & 0x00ff);
+ }
+ break;
+
+ case 1:
+ if ((xscroll >> 8) != data)
+ {
+ video_screen_update_partial(0, leland_last_scanline_int);
+ xscroll = (xscroll & 0x00ff) | ((data << 8) & 0xff00);
+ }
+ break;
+
+ case 2:
+ if ((yscroll & 0xff) != data)
+ {
+ video_screen_update_partial(0, leland_last_scanline_int);
+ yscroll = (yscroll & 0xff00) | (data & 0x00ff);
+ }
+ break;
+
+ case 3:
+ if ((yscroll >> 8) != data)
+ {
+ video_screen_update_partial(0, leland_last_scanline_int);
+ yscroll = (yscroll & 0x00ff) | ((data << 8) & 0xff00);
+ }
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video address setting
+ *
+ *************************************/
+
+static void leland_video_addr_w(int offset, int data, int num)
+{
+ struct vram_state_data *state = vram_state + num;
+
+ if (!offset)
+ state->addr = (state->addr & 0xfe00) | ((data << 1) & 0x01fe);
+ else
+ state->addr = ((data << 9) & 0xfe00) | (state->addr & 0x01fe);
+
+ if (num == 0)
+ sync_next_write = (state->addr >= 0xf000);
+}
+
+
+
+/*************************************
+ *
+ * Flush data from VRAM into our copy
+ *
+ *************************************/
+
+static void update_for_scanline(int scanline)
+{
+ int i, j;
+
+ /* skip if we're behind the times */
+ if (scanline <= next_update_scanline)
+ return;
+
+ /* update all scanlines */
+ for (i = next_update_scanline; i < scanline; i++)
+ if (i < VIDEO_HEIGHT * 8)
+ {
+ UINT8 scandata[VIDEO_WIDTH * 8];
+ UINT8 *dst = scandata;
+ UINT8 *src = &leland_video_ram[i * 256];
+
+ for (j = 0; j < VIDEO_WIDTH * 8 / 2; j++)
+ {
+ UINT8 pix = *src++;
+ *dst++ = pix >> 4;
+ *dst++ = pix & 15;
+ }
+ draw_scanline8(fgbitmap, 0, i, VIDEO_WIDTH * 8, scandata, NULL, -1);
+ }
+
+ /* also update the DACs */
+ if (scanline >= VIDEO_HEIGHT * 8)
+ scanline = 256;
+ for (i = next_update_scanline; i < scanline; i++)
+ {
+ if (!(leland_dac_control & 0x01))
+ leland_dac_update(0, leland_video_ram[i * 256 + 160]);
+ if (!(leland_dac_control & 0x02))
+ leland_dac_update(1, leland_video_ram[i * 256 + 161]);
+ }
+
+ /* set the new last update */
+ next_update_scanline = scanline;
+}
+
+
+
+/*************************************
+ *
+ * Common video RAM read
+ *
+ *************************************/
+
+static int leland_vram_port_r(int offset, int num)
+{
+ struct vram_state_data *state = vram_state + num;
+ int addr = state->addr;
+ int inc = (offset >> 2) & 2;
+ int ret;
+
+ switch (offset & 7)
+ {
+ case 3: /* read hi/lo (alternating) */
+ ret = leland_video_ram[addr];
+ addr += inc & (addr << 1);
+ addr ^= 1;
+ break;
+
+ case 5: /* read hi */
+ ret = leland_video_ram[addr | 1];
+ addr += inc;
+ break;
+
+ case 6: /* read lo */
+ ret = leland_video_ram[addr & ~1];
+ addr += inc;
+ break;
+
+ default:
+ logerror("CPU #%d %04x Warning: Unknown video port %02x read (address=%04x)\n",
+ cpu_getactivecpu(),activecpu_get_pc(), offset, addr);
+ ret = 0;
+ break;
+ }
+ state->addr = addr;
+
+ if (LOG_COMM && addr >= 0xf000)
+ logerror("%04X:%s comm read %04X = %02X\n", activecpu_get_previouspc(), num ? "slave" : "master", addr, ret);
+
+ return ret;
+}
+
+
+
+/*************************************
+ *
+ * Common video RAM write
+ *
+ *************************************/
+
+static void leland_vram_port_w(int offset, int data, int num)
+{
+ struct vram_state_data *state = vram_state + num;
+ int addr = state->addr;
+ int inc = (offset >> 2) & 2;
+ int trans = (offset >> 4) & num;
+
+ /* if we're writing "behind the beam", make sure we've cached what was there */
+ if (addr < 0xf000)
+ {
+ int cur_scanline = video_screen_get_vpos(0);
+ int mod_scanline = addr / 256;
+
+ if (cur_scanline != next_update_scanline && mod_scanline < cur_scanline)
+ update_for_scanline(cur_scanline);
+ }
+
+ if (LOG_COMM && addr >= 0xf000)
+ logerror("%04X:%s comm write %04X = %02X\n", activecpu_get_previouspc(), num ? "slave" : "master", addr, data);
+
+ /* based on the low 3 bits of the offset, update the destination */
+ switch (offset & 7)
+ {
+ case 1: /* write hi = data, lo = latch */
+ leland_video_ram[addr & ~1] = state->latch[0];
+ leland_video_ram[addr | 1] = data;
+ addr += inc;
+ break;
+
+ case 2: /* write hi = latch, lo = data */
+ leland_video_ram[addr & ~1] = data;
+ leland_video_ram[addr | 1] = state->latch[1];
+ addr += inc;
+ break;
+
+ case 3: /* write hi/lo = data (alternating) */
+ if (trans)
+ {
+ if (!(data & 0xf0)) data |= leland_video_ram[addr] & 0xf0;
+ if (!(data & 0x0f)) data |= leland_video_ram[addr] & 0x0f;
+ }
+ leland_video_ram[addr] = data;
+ addr += inc & (addr << 1);
+ addr ^= 1;
+ break;
+
+ case 5: /* write hi = data */
+ state->latch[1] = data;
+ if (trans)
+ {
+ if (!(data & 0xf0)) data |= leland_video_ram[addr | 1] & 0xf0;
+ if (!(data & 0x0f)) data |= leland_video_ram[addr | 1] & 0x0f;
+ }
+ leland_video_ram[addr | 1] = data;
+ addr += inc;
+ break;
+
+ case 6: /* write lo = data */
+ state->latch[0] = data;
+ if (trans)
+ {
+ if (!(data & 0xf0)) data |= leland_video_ram[addr & ~1] & 0xf0;
+ if (!(data & 0x0f)) data |= leland_video_ram[addr & ~1] & 0x0f;
+ }
+ leland_video_ram[addr & ~1] = data;
+ addr += inc;
+ break;
+
+ default:
+ logerror("CPU #%d %04x Warning: Unknown video port write (address=%04x value=%02x)\n",
+ cpu_getactivecpu(),activecpu_get_pc(), offset, addr);
+ break;
+ }
+
+ /* update the address and plane */
+ state->addr = addr;
+}
+
+
+
+/*************************************
+ *
+ * Master video RAM read/write
+ *
+ *************************************/
+
+WRITE8_HANDLER( leland_master_video_addr_w )
+{
+ leland_video_addr_w(offset, data, 0);
+}
+
+
+static TIMER_CALLBACK( leland_delayed_mvram_w )
+{
+ int num = (param >> 16) & 1;
+ int offset = (param >> 8) & 0xff;
+ int data = param & 0xff;
+ leland_vram_port_w(offset, data, num);
+}
+
+
+WRITE8_HANDLER( leland_mvram_port_w )
+{
+ if (sync_next_write)
+ {
+ timer_call_after_resynch(0x00000 | (offset << 8) | data, leland_delayed_mvram_w);
+ sync_next_write = 0;
+ }
+ else
+ leland_vram_port_w(offset, data, 0);
+}
+
+
+READ8_HANDLER( leland_mvram_port_r )
+{
+ return leland_vram_port_r(offset, 0);
+}
+
+
+
+/*************************************
+ *
+ * Slave video RAM read/write
+ *
+ *************************************/
+
+WRITE8_HANDLER( leland_slave_video_addr_w )
+{
+ leland_video_addr_w(offset, data, 1);
+}
+
+
+WRITE8_HANDLER( leland_svram_port_w )
+{
+ leland_vram_port_w(offset, data, 1);
+}
+
+
+READ8_HANDLER( leland_svram_port_r )
+{
+ return leland_vram_port_r(offset, 1);
+}
+
+
+
+/*************************************
+ *
+ * Ataxx master video RAM read/write
+ *
+ *************************************/
+
+WRITE8_HANDLER( ataxx_mvram_port_w )
+{
+ offset = ((offset >> 1) & 0x07) | ((offset << 3) & 0x08) | (offset & 0x10);
+ if (sync_next_write)
+ {
+ timer_call_after_resynch(0x00000 | (offset << 8) | data, leland_delayed_mvram_w);
+ sync_next_write = 0;
+ }
+ else
+ leland_vram_port_w(offset, data, 0);
+}
+
+
+WRITE8_HANDLER( ataxx_svram_port_w )
+{
+ offset = ((offset >> 1) & 0x07) | ((offset << 3) & 0x08) | (offset & 0x10);
+ leland_vram_port_w(offset, data, 1);
+}
+
+
+
+/*************************************
+ *
+ * Ataxx slave video RAM read/write
+ *
+ *************************************/
+
+READ8_HANDLER( ataxx_mvram_port_r )
+{
+ offset = ((offset >> 1) & 0x07) | ((offset << 3) & 0x08) | (offset & 0x10);
+ return leland_vram_port_r(offset, 0);
+}
+
+
+READ8_HANDLER( ataxx_svram_port_r )
+{
+ offset = ((offset >> 1) & 0x07) | ((offset << 3) & 0x08) | (offset & 0x10);
+ return leland_vram_port_r(offset, 1);
+}
+
+
+
+/*************************************
+ *
+ * End-of-frame routine
+ *
+ *************************************/
+
+static TIMER_CALLBACK( scanline_reset )
+{
+ /* flush the remaining scanlines */
+ next_update_scanline = 0;
+
+ /* turn off the DACs at the start of the frame */
+ leland_dac_control = 3;
+}
+
+
+VIDEO_EOF( leland )
+{
+ /* update anything remaining */
+ update_for_scanline(VIDEO_HEIGHT * 8);
+
+ /* set a timer to go off at the top of the frame */
+ timer_set(video_screen_get_time_until_pos(0, 0, 0), 0, scanline_reset);
+}
+
+
+
+/*************************************
+ *
+ * ROM-based refresh routine
+ *
+ *************************************/
+
+VIDEO_UPDATE( leland )
+{
+ const UINT8 *background_prom = memory_region(REGION_USER1);
+ const gfx_element *gfx = machine->gfx[0];
+ int char_bank = ((gfxbank >> 4) & 0x03) * 0x0400;
+ int prom_bank = ((gfxbank >> 3) & 0x01) * 0x2000;
+ int xcoarse = xscroll / 8;
+ int ycoarse = yscroll / 8;
+ int xfine = xscroll % 8;
+ int yfine = yscroll % 8;
+ int x, y;
+
+ /* update anything remaining */
+ update_for_scanline(cliprect->max_y);
+
+ /* draw what's visible to the main bitmap */
+ for (y = cliprect->min_y / 8; y < cliprect->max_y / 8 + 2; y++)
+ {
+ int ysum = ycoarse + y;
+ for (x = 0; x < VIDEO_WIDTH + 1; x++)
+ {
+ int xsum = xcoarse + x;
+ int offs = ((xsum << 0) & 0x000ff) |
+ ((ysum << 8) & 0x01f00) |
+ prom_bank |
+ ((ysum << 9) & 0x1c000);
+ int code = background_prom[offs] |
+ ((ysum << 2) & 0x300) |
+ char_bank;
+ int color = (code >> 5) & 7;
+
+ /* draw to the bitmap */
+ drawgfx(bitmap, gfx,
+ code, 8 * color, 0, 0,
+ 8 * x - xfine, 8 * y - yfine,
+ cliprect, TRANSPARENCY_NONE_RAW, 0);
+ }
+ }
+
+ /* Merge the two bitmaps together */
+ copybitmap(bitmap, fgbitmap, 0, 0, 0, 0, cliprect, TRANSPARENCY_BLEND, 6);
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * RAM-based refresh routine
+ *
+ *************************************/
+
+VIDEO_UPDATE( ataxx )
+{
+ const gfx_element *gfx = machine->gfx[0];
+ int xcoarse = xscroll / 8;
+ int ycoarse = yscroll / 8;
+ int xfine = xscroll % 8;
+ int yfine = yscroll % 8;
+ int x, y;
+
+ /* update anything remaining */
+ update_for_scanline(cliprect->max_y);
+
+ /* draw what's visible to the main bitmap */
+ for (y = cliprect->min_y / 8; y < cliprect->max_y / 8 + 2; y++)
+ {
+ int ysum = ycoarse + y;
+ for (x = 0; x < VIDEO_WIDTH + 1; x++)
+ {
+ int xsum = xcoarse + x;
+ int offs = ((ysum & 0x40) << 9) + ((ysum & 0x3f) << 8) + (xsum & 0xff);
+ int code = ataxx_qram[offs] | ((ataxx_qram[offs + 0x4000] & 0x7f) << 8);
+
+ /* draw to the bitmap */
+ drawgfx(bitmap, gfx,
+ code, 0, 0, 0,
+ 8 * x - xfine, 8 * y - yfine,
+ cliprect, TRANSPARENCY_NONE_RAW, 0);
+ }
+ }
+
+ /* Merge the two bitmaps together */
+ copybitmap(bitmap, fgbitmap, 0, 0, 0, 0, cliprect, TRANSPARENCY_BLEND, 6);
+ return 0;
+}
diff --git a/src/mame/video/lemmings.c b/src/mame/video/lemmings.c
new file mode 100644
index 00000000000..10886630fe7
--- /dev/null
+++ b/src/mame/video/lemmings.c
@@ -0,0 +1,199 @@
+/***************************************************************************
+
+ Lemmings video emulation - Bryan McPhail, mish@tendril.co.uk
+
+*********************************************************************
+
+ There are two sets of sprites, the combination of custom chips 52 & 71.
+ There is a background pixel layer implemented with discrete logic
+ rather than a custom chip and a foreground VRAM tilemap layer that the
+ game mostly uses as a pixel layer (the vram format is arranged as
+ sequential pixels, rather than sequential characters).
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/lemmings.h"
+
+UINT16 *lemmings_pixel_0_data,*lemmings_pixel_1_data,*lemmings_vram_data,*lemmings_control_data;
+static UINT16 *sprite_triple_buffer_0,*sprite_triple_buffer_1;
+static UINT8 *vram_buffer, *vram_dirty;
+static mame_bitmap *bitmap0;
+static tilemap *vram_tilemap;
+
+/******************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT16 *spritedata, int gfxbank, UINT16 pri)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ sprite = spritedata[offs+1] & 0x3fff;
+
+ if ((spritedata[offs+2]&0x2000)!=pri)
+ continue;
+
+ y = spritedata[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ x = spritedata[offs+2];
+ colour = (x >>9) & 0xf;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+
+ if (x>320 || x<-16) continue;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = 1;
+ else
+ {
+ sprite += multi;
+ inc = -1;
+ }
+ mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[gfxbank],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ multi--;
+ }
+ }
+}
+
+/******************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT16 tile=lemmings_vram_data[tile_index];
+
+ SET_TILE_INFO(
+ 2,
+ tile&0x7ff,
+ (tile>>12)&0xf,
+ 0);
+}
+
+VIDEO_START( lemmings )
+{
+ bitmap0 = auto_bitmap_alloc(2048,256,machine->screen[0].format);
+ vram_tilemap = tilemap_create(get_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ vram_buffer = (UINT8*)auto_malloc(2048*64); /* 64 bytes per VRAM character */
+ vram_dirty = (UINT8*)auto_malloc(2048);
+ sprite_triple_buffer_0 = (UINT16*)auto_malloc(0x800);
+ sprite_triple_buffer_1 = (UINT16*)auto_malloc(0x800);
+
+ tilemap_set_transparent_pen(vram_tilemap,0);
+ fillbitmap(bitmap0,0x100,0);
+}
+
+VIDEO_EOF( lemmings )
+{
+ memcpy(sprite_triple_buffer_0,buffered_spriteram16,0x800);
+ memcpy(sprite_triple_buffer_1,buffered_spriteram16_2,0x800);
+}
+
+/******************************************************************************/
+
+WRITE16_HANDLER( lemmings_pixel_0_w )
+{
+ int sx,sy,src,old;
+
+ old=lemmings_pixel_0_data[offset];
+ COMBINE_DATA(&lemmings_pixel_0_data[offset]);
+ src=lemmings_pixel_0_data[offset];
+ if (old==src)
+ return;
+
+ sy=(offset<<1)/0x800;
+ sx=(offset<<1)&0x7ff;
+
+ if (sx>2047 || sy>255)
+ return;
+
+ *BITMAP_ADDR16(bitmap0, sy, sx+0) = Machine->pens[((src>>8)&0xf)|0x100];
+ *BITMAP_ADDR16(bitmap0, sy, sx+1) = Machine->pens[((src>>0)&0xf)|0x100];
+}
+
+WRITE16_HANDLER( lemmings_pixel_1_w )
+{
+ int sx,sy,src,old,tile;
+
+ old=lemmings_pixel_1_data[offset];
+ COMBINE_DATA(&lemmings_pixel_1_data[offset]);
+ src=lemmings_pixel_1_data[offset];
+// if (old==src)
+// return;
+
+ sy=((offset<<1)/0x200);
+ sx=((offset<<1)&0x1ff);
+
+ /* Copy pixel to buffer for easier decoding later */
+ tile=((sx/8)*32)+(sy/8);
+ vram_dirty[tile]=1;
+ vram_buffer[(tile*64) + ((sx&7)) + ((sy&7)*8)]=(src>>8)&0xf;
+
+ sx+=1; /* Update both pixels in the word */
+ vram_buffer[(tile*64) + ((sx&7)) + ((sy&7)*8)]=(src>>0)&0xf;
+}
+
+WRITE16_HANDLER( lemmings_vram_w )
+{
+ COMBINE_DATA(&lemmings_vram_data[offset]);
+ tilemap_mark_tile_dirty(vram_tilemap,offset);
+}
+
+VIDEO_UPDATE( lemmings )
+{
+ int x1=-lemmings_control_data[0],x0=-lemmings_control_data[2],i,y=0;
+ rectangle rect;
+ rect.max_y=cliprect->max_y;
+ rect.min_y=cliprect->min_y;
+
+ /* Decode any characters that have changed in vram */
+ for (i=0; i<2048; i++) {
+ if (vram_dirty[i]) {
+ decodechar(machine->gfx[2],i,vram_buffer,machine->drv->gfxdecodeinfo[2].gfxlayout);
+ tilemap_mark_tile_dirty(vram_tilemap,i);
+ vram_dirty[i]=0;
+ }
+ }
+
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ draw_sprites(machine,bitmap,cliprect,sprite_triple_buffer_1,1,0x0000);
+
+ /* Pixel layer can be windowed in hardware (two player mode) */
+ if ((lemmings_control_data[6]&2)==0) {
+ copyscrollbitmap(bitmap,bitmap0,1,&x1,1,&y,cliprect,TRANSPARENCY_PEN,0x100);
+ } else {
+ rect.max_x=159;
+ rect.min_x=0;
+ copyscrollbitmap(bitmap,bitmap0,1,&x0,1,&y,&rect,TRANSPARENCY_PEN,0x100);
+ rect.max_x=319;
+ rect.min_x=160;
+ copyscrollbitmap(bitmap,bitmap0,1,&x1,1,&y,&rect,TRANSPARENCY_PEN,0x100);
+ }
+ draw_sprites(machine,bitmap,cliprect,sprite_triple_buffer_0,0,0x0000);
+ draw_sprites(machine,bitmap,cliprect,sprite_triple_buffer_1,1,0x2000);
+ tilemap_draw(bitmap,cliprect,vram_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect,sprite_triple_buffer_0,0,0x2000);
+ return 0;
+}
diff --git a/src/mame/video/lethal.c b/src/mame/video/lethal.c
new file mode 100644
index 00000000000..164f79467a4
--- /dev/null
+++ b/src/mame/video/lethal.c
@@ -0,0 +1,146 @@
+/***************************************************************************
+
+ Lethal Enforcers
+ (c) 1992 Konami
+
+ Video hardware emulation.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+#define GUNX( a ) ( ( readinputport( a ) * 287 ) / 0xff )
+#define GUNY( a ) ( ( readinputport( a ) * 223 ) / 0xff )
+
+static int sprite_colorbase;
+static int layer_colorbase[4];
+//static int layerpri[4] ={ 1,2,4,0 };
+
+static void lethalen_sprite_callback(int *code, int *color, int *priority_mask)
+{
+ int pri = (*color & 0xfff0);
+ *color = *color & 0x000f;
+ *color+=0x400/64; // colourbase?
+
+ /* this isn't ideal.. shouldn't need to hardcode it? not 100% sure about it anyway*/
+ if (pri==0x10) *priority_mask = 0xf0; // guys on first level
+ else if (pri==0x90) *priority_mask = 0xf0; // car doors
+ else if (pri==0x20) *priority_mask = 0xf0|0xcc; // people behind glass on 1st level
+ else if (pri==0xa0) *priority_mask = 0xf0|0xcc; // glass on 1st/2nd level
+ else if (pri==0x40) *priority_mask = 0; // blood splats?
+ else if (pri==0x00) *priority_mask = 0; // gunshots etc
+ else if (pri==0x30) *priority_mask = 0xf0|0xcc|0xaa; // mask sprites (always in a bad colour, used to do special effects i think
+ else
+ {
+ popmessage("unknown pri %04x\n",pri);
+ *priority_mask = 0;
+ }
+
+ *code = (*code & 0x3fff); // | spritebanks[(*code >> 12) & 3];
+}
+
+static void lethalen_tile_callback(int layer, int *code, int *color, int *flags)
+{
+ *color = layer_colorbase[layer] + ((*color & 0x3c)<<2);
+}
+
+VIDEO_START(lethalen)
+{
+ int i;
+
+ K053251_vh_start();
+
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_8LE, 1, NULL, lethalen_tile_callback, 0);
+
+ K053245_vh_start(machine, 0, REGION_GFX3,NORMAL_PLANE_ORDER, lethalen_sprite_callback);
+
+ /* the default drawmode table is no good for 6bpp, create a new one */
+ gfx_drawmode_table[0] = DRAWMODE_NONE;
+ for (i = 1;i < 64;i++)
+ gfx_drawmode_table[i] = DRAWMODE_SOURCE;
+
+ gfx_drawmode_table[63] = DRAWMODE_SHADOW;
+
+ // this game uses external linescroll RAM
+ K056832_SetExtLinescroll();
+
+ // the US and Japanese cabinets apparently use different mirror setups
+ if (!strcmp(machine->gamedrv->name, "lethalej"))
+ {
+ K056832_set_LayerOffset(0, -196, 0);
+ K056832_set_LayerOffset(1, -194, 0);
+ K056832_set_LayerOffset(2, -192, 0);
+ K056832_set_LayerOffset(3, -190, 0);
+ K053245_set_SpriteOffset(0, -105, 0);
+ }
+ else
+ { /* fixme */
+ K056832_set_LayerOffset(0, 188, 0);
+ K056832_set_LayerOffset(1, 190, 0);
+ K056832_set_LayerOffset(2, 192, 0);
+ K056832_set_LayerOffset(3, 194, 0);
+ K053245_set_SpriteOffset(0, 95, 0);
+ }
+
+ layer_colorbase[0] = 0x00;
+ layer_colorbase[1] = 0x40;
+ layer_colorbase[2] = 0x80;
+ layer_colorbase[3] = 0xc0;
+}
+
+WRITE8_HANDLER(le_palette_control)
+{
+ switch (offset)
+ {
+ case 0: // 40c8 - PCU1 from schematics
+ layer_colorbase[0] = ((data & 0x7)-1) * 0x40;
+ layer_colorbase[1] = (((data>>4) & 0x7)-1) * 0x40;
+ K056832_mark_plane_dirty(0);
+ K056832_mark_plane_dirty(1);
+ break;
+
+ case 4: // 40cc - PCU2 from schematics
+ layer_colorbase[2] = ((data & 0x7)-1) * 0x40;
+ layer_colorbase[3] = (((data>>4) & 0x7)-1) * 0x40;
+ K056832_mark_plane_dirty(2);
+ K056832_mark_plane_dirty(3);
+ break;
+
+ case 8: // 40d0 - PCU3 from schematics
+ sprite_colorbase = ((data & 0x7)-1) * 0x40;
+ break;
+ }
+}
+
+extern UINT16 *K056832_videoram;
+
+VIDEO_UPDATE(lethalen)
+{
+ fillbitmap(bitmap, 7168, cliprect);
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ K056832_tilemap_draw(machine, bitmap, cliprect, 3, 0, 1);
+ K056832_tilemap_draw(machine, bitmap, cliprect, 2, 0, 2);
+ K056832_tilemap_draw(machine, bitmap, cliprect, 1, 0, 4);
+
+ K053245_sprites_draw_lethal(machine,0, bitmap, cliprect);
+
+ // force "A" layer over top of everything
+ K056832_tilemap_draw(machine, bitmap, cliprect, 0, 0, 0);
+
+
+#if 0
+ {
+ FILE *fp;
+
+ fp=fopen("K056832_videoram", "w+b");
+ if (fp)
+ {
+ fwrite(K056832_videoram, 0x10000, 2, fp);
+ fclose(fp);
+ }
+ }
+#endif
+ return 0;
+}
diff --git a/src/mame/video/lethalj.c b/src/mame/video/lethalj.c
new file mode 100644
index 00000000000..12f6b3a3adc
--- /dev/null
+++ b/src/mame/video/lethalj.c
@@ -0,0 +1,200 @@
+/***************************************************************************
+
+ The Game Room Lethal Justice hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "cpu/tms34010/tms34010.h"
+#include "lethalj.h"
+
+
+#define BLITTER_SOURCE_WIDTH 1024
+#define BLITTER_DEST_WIDTH 512
+#define BLITTER_DEST_HEIGHT 512
+
+
+static UINT16 blitter_data[8];
+
+static UINT16 *screenram;
+static UINT16 *blitter_base;
+static int blitter_rows;
+
+static UINT16 gunx, guny;
+static UINT8 blank_palette;
+
+
+
+/*************************************
+ *
+ * Compute X/Y coordinates
+ *
+ *************************************/
+
+INLINE void get_crosshair_xy(int player, int *x, int *y)
+{
+ *x = ((readinputport(2 + player * 2) & 0xff) * Machine->screen[0].width) / 255;
+ *y = ((readinputport(3 + player * 2) & 0xff) * Machine->screen[0].height) / 255;
+}
+
+
+
+/*************************************
+ *
+ * Gun input handling
+ *
+ *************************************/
+
+READ16_HANDLER( lethalj_gun_r )
+{
+ UINT16 result = 0;
+ int beamx, beamy;
+
+ switch (offset)
+ {
+ case 4:
+ case 5:
+ /* latch the crosshair position */
+ get_crosshair_xy(offset - 4, &beamx, &beamy);
+ gunx = beamx;
+ guny = beamy;
+ blank_palette = 1;
+ break;
+
+ case 6:
+ result = gunx/2;
+ break;
+
+ case 7:
+ result = guny + 4;
+ break;
+ }
+/* logerror("%08X:lethalj_gun_r(%d) = %04X\n", activecpu_get_pc(), offset, result); */
+ return result;
+}
+
+
+
+/*************************************
+ *
+ * video startup
+ *
+ *************************************/
+
+VIDEO_START( lethalj )
+{
+ /* allocate video RAM for screen */
+ screenram = auto_malloc(BLITTER_DEST_WIDTH * BLITTER_DEST_HEIGHT * sizeof(screenram[0]));
+
+ /* predetermine blitter info */
+ blitter_base = (UINT16 *)memory_region(REGION_GFX1);
+ blitter_rows = memory_region_length(REGION_GFX1) / (2*BLITTER_SOURCE_WIDTH);
+}
+
+
+
+/*************************************
+ *
+ * Memory maps
+ *
+ *************************************/
+
+static TIMER_CALLBACK( gen_ext1_int )
+{
+ cpunum_set_input_line(0, 0, ASSERT_LINE);
+}
+
+
+
+static void do_blit(void)
+{
+ int dsty = (INT16)blitter_data[1];
+ int srcx = (UINT16)blitter_data[2];
+ int srcy = (UINT16)blitter_data[3];
+ int width = (UINT16)blitter_data[5];
+ int dstx = (INT16)blitter_data[6];
+ int height = (UINT16)blitter_data[7];
+ int y;
+
+ if (srcy == 0xffff)
+ {
+ return;
+ }
+
+/* logerror("blitter data = %04X %04X %04X %04X %04X %04X %04X %04X\n",
+ blitter_data[0], blitter_data[1], blitter_data[2], blitter_data[3],
+ blitter_data[4], blitter_data[5], blitter_data[6], blitter_data[7]);*/
+
+ /* loop over Y coordinates */
+ for (y = 0; y <= height; y++, srcy++, dsty++)
+ {
+ UINT16 *source = blitter_base + srcy * BLITTER_SOURCE_WIDTH;
+ UINT16 *dest = screenram + dsty * BLITTER_DEST_WIDTH;
+
+ /* clip in Y */
+ if (dsty >= 0 && dsty < BLITTER_DEST_HEIGHT)
+ {
+ int sx = srcx;
+ int dx = dstx;
+ int x;
+
+ /* loop over X coordinates */
+ for (x = 0; x <= width; x++, sx++, dx++)
+ if (dx >= 0 && dx < BLITTER_DEST_WIDTH)
+ {
+ int pix = source[sx % BLITTER_SOURCE_WIDTH];
+ if (pix)
+ dest[dx] = pix;
+ }
+ }
+ }
+}
+
+
+
+WRITE16_HANDLER( lethalj_blitter_w )
+{
+ /* combine the data */
+ COMBINE_DATA(&blitter_data[offset]);
+
+ /* blit on a write to offset 7, and signal an IRQ */
+ if (offset == 7)
+ {
+ do_blit();
+ timer_set(ATTOTIME_IN_USEC(10), 0, gen_ext1_int);
+ }
+
+ /* clear the IRQ on offset 0 */
+ else if (offset == 0)
+ cpunum_set_input_line(0, 0, CLEAR_LINE);
+}
+
+
+
+/*************************************
+ *
+ * video update
+ *
+ *************************************/
+
+void lethalj_scanline_update(running_machine *machine, int screen, mame_bitmap *bitmap, int scanline, const tms34010_display_params *params)
+{
+ UINT16 *src = &screenram[(params->rowaddr << 9) & 0x3fe00];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0);
+ int coladdr = params->coladdr << 1;
+ int x;
+
+ /* blank palette: fill with white */
+ if (blank_palette)
+ {
+ for (x = params->heblnk; x < params->hsblnk; x++)
+ dest[x] = 0x7fff;
+ if (scanline == machine->screen[0].visarea.max_y)
+ blank_palette = 0;
+ return;
+ }
+
+ /* copy the non-blanked portions of this scanline */
+ for (x = params->heblnk; x < params->hsblnk; x++)
+ dest[x] = src[coladdr++ & 0x1ff] & 0x7fff;
+}
diff --git a/src/mame/video/liberate.c b/src/mame/video/liberate.c
new file mode 100644
index 00000000000..1815baa2bd1
--- /dev/null
+++ b/src/mame/video/liberate.c
@@ -0,0 +1,419 @@
+/*******************************************************************************
+
+ Todo:
+ There are some kind of resistors hooked up to the background colours,
+ the same prom colours can change for the background but not the
+ foreground. It's rarely used (Liberation title screen only?).
+
+ Emulation by Bryan McPhail, mish@tendril.co.uk
+
+*******************************************************************************/
+
+#include "driver.h"
+#include "cpu/m6502/m6502.h"
+
+static int background_color,background_disable;
+static tilemap *background_tilemap, *fix_tilemap;
+static UINT8 deco16_io_ram[16];
+
+#if 0
+void debug_print(mame_bitmap *bitmap)
+{
+ int i,j;
+ char buf[20*16];
+ char *bufptr = buf;
+ for (i = 0;i < 16;i+=2)
+ bufptr += sprintf(bufptr,"%04X",deco16_io_ram[i+1]|(deco16_io_ram[i]<<8));
+ ui_draw_text(buf, 10, 6*6);
+}
+#endif
+
+static TILEMAP_MAPPER( back_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return ((row & 0xf)) + ((15-(col &0xf))<<4) + ((row&0x10)<<5) + ((col&0x10)<<4);
+}
+
+static TILEMAP_MAPPER( fix_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (row & 0x1f) + ((31-(col &0x1f))<<5);
+}
+
+static TILE_GET_INFO( get_back_tile_info )
+{
+ const UINT8 *RAM = memory_region(REGION_USER1);
+ int tile,bank;
+
+ /* Convert tile index of 512x512 to paged format */
+ if (tile_index&0x100) {
+ if (tile_index&0x200)
+ tile_index=(tile_index&0xff)+(deco16_io_ram[5]<<8); /* Bottom right */
+ else
+ tile_index=(tile_index&0xff)+(deco16_io_ram[4]<<8); /* Bottom left */
+ } else {
+ if (tile_index&0x200)
+ tile_index=(tile_index&0xff)+(deco16_io_ram[3]<<8); /* Top right */
+ else
+ tile_index=(tile_index&0xff)+(deco16_io_ram[2]<<8); /* Top left */
+ }
+
+ tile=RAM[tile_index];
+ if (tile>0x7f) bank=3; else bank=2;
+ SET_TILE_INFO(bank,tile&0x7f,background_color,0);
+}
+
+static TILE_GET_INFO( get_fix_tile_info )
+{
+ int tile,color;
+
+ tile=videoram[tile_index+0x400]+((videoram[tile_index]&0x7)<<8);
+ color=(videoram[tile_index]&0x70)>>4;
+
+//if (tile&0x300) tile-=0x000;
+//else if(tile&0x200) tile-=0x100;
+//else if (tile&0x100) tile-=0x100;
+//else tile+=0x200;
+
+ SET_TILE_INFO(0,tile,color,0);
+}
+
+/***************************************************************************/
+
+WRITE8_HANDLER( deco16_io_w )
+{
+ deco16_io_ram[offset]=data;
+ if (offset>1 && offset<6)
+ tilemap_mark_all_tiles_dirty(background_tilemap);
+
+ switch (offset) {
+ case 6: /* Background colour */
+ if (((data>>4)&3)!=background_color) {
+ background_color=(data>>4)&3;
+ tilemap_mark_all_tiles_dirty(background_tilemap);
+ }
+ background_disable=data&0x4;
+ flip_screen_set(data&0x1);
+ break;
+ case 7: /* Background palette resistors? */
+ /* Todo */
+ break;
+ case 8: /* Irq ack */
+ cpunum_set_input_line(0,DECO16_IRQ_LINE,CLEAR_LINE);
+ break;
+ case 9: /* Sound */
+ soundlatch_w(0,data);
+ cpunum_set_input_line(1,M6502_IRQ_LINE,HOLD_LINE);
+ break;
+ }
+}
+
+WRITE8_HANDLER( liberate_videoram_w )
+{
+ videoram[offset]=data;
+ tilemap_mark_tile_dirty(fix_tilemap,offset&0x3ff);
+}
+
+/***************************************************************************/
+
+VIDEO_START( prosoccr )
+{
+ background_tilemap = tilemap_create(get_back_tile_info,back_scan,TILEMAP_TYPE_PEN,16,16,32,32);
+ fix_tilemap = tilemap_create(get_fix_tile_info,fix_scan,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(fix_tilemap,0);
+}
+
+VIDEO_START( boomrang )
+{
+ background_tilemap = tilemap_create(get_back_tile_info,back_scan,TILEMAP_TYPE_PEN,16,16,32,32);
+ fix_tilemap = tilemap_create(get_fix_tile_info,fix_scan,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transmask(background_tilemap,0,0x0001,0x007e); /* Bottom 1 pen/Top 7 pens */
+ tilemap_set_transparent_pen(fix_tilemap,0);
+}
+
+VIDEO_START( liberate )
+{
+ background_tilemap = tilemap_create(get_back_tile_info,back_scan,TILEMAP_TYPE_PEN,16,16,32,32);
+ fix_tilemap = tilemap_create(get_fix_tile_info,fix_scan,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(fix_tilemap,0);
+}
+
+/***************************************************************************/
+
+WRITE8_HANDLER( prosport_paletteram_w )
+{
+ /* RGB output is inverted */
+ paletteram_BBGGGRRR_w(offset,~data);
+}
+
+PALETTE_INIT( liberate )
+{
+ int i,bit0,bit1,bit2,g,r,b;
+
+ for (i = 0;i < 32;i++)
+ {
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ color_prom++;
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+ palette_set_color(machine,32,MAKE_RGB(0,0,0)); /* Allocate black for when no background is displayed */
+}
+
+/***************************************************************************/
+
+static void liberate_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ /* Sprites */
+ for (offs = 0;offs < 0x800;offs += 4)
+ {
+ int multi,fx,fy,sx,sy,sy2,code,color;
+
+ code = spriteram[offs+1] + ( ( spriteram[offs+0] & 0x60 ) << 3 );
+ sx = (240 - spriteram[offs+3]);
+ //if (sx < -7) sx += 256;
+
+ sy = 240-spriteram[offs+2];
+ color = 0;//(spriteram[offs+1] & 0x03);// + ((spriteram[offs+1] & 0x08) >> 1);
+
+// if (pri==0 && color!=0) continue;
+// if (pri==1 && color==0) continue;
+
+ fx = spriteram[offs+0] & 0x04;
+ fy = spriteram[offs+0] & 0x08; // or 0x02 ?
+ multi = spriteram[offs+0] & 0x10;
+
+
+ if (multi) sy-=16;
+
+ if (flip_screen) {
+ sy=240-sy;
+ sx=240-sx;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ sy2=sy-16;
+ }
+ else sy2=sy+16;
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ fx,fy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ if (multi)
+ drawgfx(bitmap,machine->gfx[1],
+ code+1,
+ color,
+ fx,fy,
+ sx,sy2,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+static void prosport_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs,multi,fx,fy,sx,sy,sy2,code,code2,color;
+
+ for (offs = 0x000;offs < 0x800;offs += 4)
+ {
+ // if ((spriteram[offs+0]&1)!=1) continue;
+
+ code = spriteram[offs+1] + ((spriteram[offs+0]&0x3)<<8);
+ code2=code+1;
+
+ multi = spriteram[offs+0] & 0x10;
+
+ sy=spriteram[offs+2];
+ if (multi) sy+=16;
+ sx = (240 - spriteram[offs+3]);
+// sy = (240-spriteram[offs+2]);//-16;
+ sy = 240-sy;
+
+ color = 1;//(spriteram[offs+0]&0x4)>>2;
+
+ fx = 0;
+ fy = spriteram[offs+0] & 0x04;
+ multi = 0;// spriteram[offs+0] & 0x10;
+
+// if (multi) sy-=16;
+ if (fy && multi) { code2=code; code++; }
+
+ if (flip_screen) {
+ sy=240-sy;
+ sx=240-sx;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ sy2=sy-16;
+ }
+ else {
+ sy2=sy+16;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ fx,fy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ if (multi)
+ drawgfx(bitmap,machine->gfx[1],
+ code2,
+ color,
+ fx,fy,
+ sx,sy2,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+static void boomrang_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri)
+{
+ int offs,multi,fx,fy,sx,sy,sy2,code,code2,color;
+
+ for (offs = 0x000;offs < 0x800;offs += 4)
+ {
+ if ((spriteram[offs+0]&1)!=1) continue;
+ if ((spriteram[offs+0]&0x8)!=pri) continue;
+
+ code = spriteram[offs+1] + ((spriteram[offs+0]&0xe0)<<3);
+ code2=code+1;
+
+ multi = spriteram[offs+0] & 0x10;
+
+ sy=spriteram[offs+2];
+ if (multi) sy+=16;
+ sx = (240 - spriteram[offs+3]);
+// sy = (240-spriteram[offs+2]);//-16;
+ sy = 240-sy;
+
+ color = (spriteram[offs+0]&0x4)>>2;
+
+ fx = 0;
+ fy = spriteram[offs+0] & 0x02;
+ multi = spriteram[offs+0] & 0x10;
+
+// if (multi) sy-=16;
+ if (fy && multi) { code2=code; code++; }
+
+ if (flip_screen) {
+ sy=240-sy;
+ sx=240-sx;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ sy2=sy-16;
+ }
+ else {
+ sy2=sy+16;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ fx,fy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ if (multi)
+ drawgfx(bitmap,machine->gfx[1],
+ code2,
+ color,
+ fx,fy,
+ sx,sy2,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+/***************************************************************************/
+
+VIDEO_UPDATE( prosoccr )
+{
+ tilemap_set_scrolly(background_tilemap,0,deco16_io_ram[1]);
+ tilemap_set_scrollx(background_tilemap,0,-deco16_io_ram[0]);
+
+ if (background_disable)
+ fillbitmap(bitmap,machine->pens[32],cliprect);
+ else
+ tilemap_draw(bitmap,cliprect,background_tilemap,0,0);
+ boomrang_draw_sprites(machine,bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,fix_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( prosport )
+{
+ int mx,my,tile,color,offs;
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ prosport_draw_sprites(machine,bitmap,cliprect);
+
+ for (offs = 0;offs < 0x400;offs++) {
+ tile=videoram[offs+0x400]+((videoram[offs]&0x3)<<8);
+
+ tile+=((deco16_io_ram[0]&0x30)<<6);
+
+ if (!tile) continue;
+
+ color=1;//(videoram[offs]&0x70)>>4;
+ my = (offs) % 32;
+ mx = (offs) / 32;
+
+ drawgfx(bitmap,machine->gfx[0],
+ tile,1,0,0,248-8*mx,8*my,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
+
+VIDEO_UPDATE( boomrang )
+{
+ tilemap_set_scrolly(background_tilemap,0, deco16_io_ram[1]);
+ tilemap_set_scrollx(background_tilemap,0,-deco16_io_ram[0]);
+
+ if (background_disable)
+ fillbitmap(bitmap,machine->pens[32],cliprect);
+ else
+ tilemap_draw(bitmap,cliprect,background_tilemap,TILEMAP_DRAW_LAYER1,0);
+
+ boomrang_draw_sprites(machine,bitmap,cliprect,8);
+ if (!background_disable)
+ tilemap_draw(bitmap,cliprect,background_tilemap,TILEMAP_DRAW_LAYER0,0);
+ boomrang_draw_sprites(machine,bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,fix_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( liberate )
+{
+ tilemap_set_scrolly(background_tilemap,0, deco16_io_ram[1]);
+ tilemap_set_scrollx(background_tilemap,0,-deco16_io_ram[0]);
+
+ if (background_disable)
+ fillbitmap(bitmap,machine->pens[32],cliprect);
+ else
+ tilemap_draw(bitmap,cliprect,background_tilemap,0,0);
+
+ liberate_draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,fix_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/liberatr.c b/src/mame/video/liberatr.c
new file mode 100644
index 00000000000..8dbe752addb
--- /dev/null
+++ b/src/mame/video/liberatr.c
@@ -0,0 +1,377 @@
+/***************************************************************************
+
+ liberator.c - 'video.c'
+
+ Functions to emulate the video hardware of the machine.
+
+ Liberator's screen is 256 pixels by 256 pixels. The
+ round planet in the middle of the screen is 128 pixels
+ tall by 96 equivalent (192 at double pixel rate). The
+ emulator needs to account for the aspect ratio of 4/3
+ from the arcade video system in order to make the planet
+ appear round.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "liberatr.h"
+
+
+#define NUM_PENS (0x18)
+
+
+UINT8 *liberatr_base_ram;
+UINT8 *liberatr_planet_frame;
+UINT8 *liberatr_planet_select;
+UINT8 *liberatr_x;
+UINT8 *liberatr_y;
+UINT8 *liberatr_bitmapram;
+UINT8 *liberatr_colorram;
+
+static UINT8 *liberatr_videoram;
+
+
+
+/*
+ The following structure describes the (up to 32) line segments
+ that make up one horizontal line (latitude) for one display frame of the planet.
+ Note: this and the following structure is only used to collect the
+ data before it is packed for actual use.
+*/
+typedef struct
+{
+ UINT8 segment_count; /* the number of segments on this line */
+ UINT8 max_x; /* the maximum value of x_array for this line */
+ UINT8 color_array[32]; /* the color values */
+ UINT8 x_array[32]; /* and maximum x values for each segment */
+} planet_frame_line;
+
+/*
+ The following structure describes the lines (latitudes)
+ that make up one complete display frame of the planet.
+ Note: this and the previous structure is only used to collect the
+ data before it is packed for actual use.
+*/
+typedef struct
+{
+ planet_frame_line lines[0x80];
+} planet_frame;
+
+
+/*
+ The following structure collects the 256 frames of the
+ planet (one per value of longitude).
+ The data is packed segment_count,segment_start,color,length,color,length,... then
+ segment_count,segment_start,color,length,color,length... for the next line, etc
+ for the 128 lines.
+*/
+typedef struct
+{
+ UINT8 *frames[256];
+} planet;
+
+
+/*
+ The following array collects the 2 different planet
+ descriptions, which are selected by liberatr_planetbit
+*/
+static planet *liberatr_planets[2];
+
+
+WRITE8_HANDLER( liberatr_bitmap_xy_w )
+{
+ liberatr_videoram[(*liberatr_y << 8) | *liberatr_x] = data & 0xe0;
+}
+
+
+READ8_HANDLER( liberatr_bitmap_xy_r )
+{
+ return liberatr_videoram[(*liberatr_y << 8) | *liberatr_x];
+}
+
+
+WRITE8_HANDLER( liberatr_bitmap_w )
+{
+ UINT8 x, y;
+
+ liberatr_bitmapram[offset] = data;
+
+ x = (offset & 0x3f) << 2;
+ y = offset >> 6;
+
+ data = data & 0xe0;
+
+ liberatr_videoram[(y << 8) | x | 0] = data;
+ liberatr_videoram[(y << 8) | x | 1] = data;
+ liberatr_videoram[(y << 8) | x | 2] = data;
+ liberatr_videoram[(y << 8) | x | 3] = data;
+}
+
+
+
+/********************************************************************************************
+ liberatr_init_planet()
+
+ The data for the planet is stored in ROM using a run-length type of encoding. This
+ function does the conversion to the above structures and then a smaller
+ structure which is quicker to use in real time.
+
+ Its a multi-step process, reflecting the history of the code. Not quite as efficient
+ as it might be, but this is not realtime stuff, so who cares...
+ ********************************************************************************************/
+
+static void liberatr_init_planet(running_machine *machine, planet *liberatr_planet, UINT8 *planet_rom)
+{
+ UINT16 longitude;
+
+ const UINT8* latitude_scale = memory_region(REGION_USER1);
+ const UINT8* longitude_scale = memory_region(REGION_USER2);
+
+ /* for each starting longitude */
+ for (longitude = 0; longitude < 0x100; longitude++)
+ {
+ UINT8 i, latitude, start_segment, segment_count;
+ UINT8 *buffer;
+
+ planet_frame frame;
+ planet_frame_line *line = 0;
+
+ UINT16 total_segment_count = 0;
+
+ /* for each latitude */
+ for (latitude = 0; latitude < 0x80; latitude++)
+ {
+ UINT8 segment, longitude_scale_factor, latitude_scale_factor, color, x=0;
+ UINT8 x_array[32], color_array[32], visible_array[32];
+
+ /* point to the structure which will hold the data for this line */
+ line = &frame.lines[latitude];
+
+ latitude_scale_factor = latitude_scale[latitude];
+
+ /* for this latitude, load the 32 segments into the arrays */
+ for (segment = 0; segment < 0x20; segment++)
+ {
+ UINT16 length, planet_data, address;
+
+ /*
+ read the planet picture ROM and get the
+ latitude and longitude scaled from the scaling PROMS
+ */
+ address = (latitude << 5) + segment;
+ planet_data = (planet_rom[address] << 8) | planet_rom[address + 0x1000];
+
+ color = (planet_data >> 8) & 0x0f;
+ length = ((planet_data << 1) & 0x1fe) + ((planet_data >> 15) & 0x01);
+
+
+ /* scale the longitude limit (adding the starting longitude) */
+ address = longitude + ( length >> 1 ) + ( length & 1 ); /* shift with rounding */
+ visible_array[segment] = (( address & 0x100 ) ? 1 : 0);
+ if (address & 0x80)
+ {
+ longitude_scale_factor = 0xff;
+ }
+ else
+ {
+ address = ((address & 0x7f) << 1) + (((length & 1) || visible_array[segment]) ? 0 : 1);
+ longitude_scale_factor = longitude_scale[address];
+ }
+
+ x_array[segment] = (((UINT16)latitude_scale_factor * (UINT16)longitude_scale_factor) + 0x80) >> 8; /* round it */
+ color_array[segment] = color;
+ }
+
+ /*
+ determine which segment is the western horizon and
+ leave 'segment' indexing it.
+ */
+ for (segment = 0; segment < 0x1f; segment++) /* if not found, 'segment' = 0x1f */
+ if (visible_array[segment]) break;
+
+ /* transfer from the temporary arrays to the structure */
+ line->max_x = (latitude_scale_factor * 0xc0) >> 8;
+ if (line->max_x & 1)
+ line->max_x += 1; /* make it even */
+
+ /*
+ as part of the quest to reduce memory usage (and to a lesser degree
+ execution time), stitch together segments that have the same color
+ */
+ segment_count = 0;
+ i = 0;
+ start_segment = segment;
+
+ do
+ {
+ color = color_array[segment];
+ while (color == color_array[segment])
+ {
+ x = x_array[segment];
+ segment = (segment+1) & 0x1f;
+ if (segment == start_segment)
+ break;
+ }
+
+ line->color_array[i] = color;
+ line->x_array[i] = (x > line->max_x) ? line->max_x : x;
+ i++;
+ segment_count++;
+ } while ((i < 32) && (x <= line->max_x));
+
+ total_segment_count += segment_count;
+ line->segment_count = segment_count;
+ }
+
+ /* now that the all the lines have been processed, and we know how
+ many segments it will take to store the description, allocate the
+ space for it and copy the data to it.
+ */
+ buffer = auto_malloc(2*(128 + total_segment_count));
+
+ liberatr_planet->frames[longitude] = buffer;
+
+ for (latitude = 0; latitude < 0x80; latitude++)
+ {
+ UINT8 last_x;
+
+
+ line = &frame.lines[latitude];
+ segment_count = line->segment_count;
+ *buffer++ = segment_count;
+ last_x = 0;
+
+ /* calculate the bitmap's x coordinate for the western horizon
+ center of bitmap - (the number of planet pixels) / 4 */
+ *buffer++ = machine->screen[0].width/2 - (line->max_x + 2) / 4;
+
+ for (i = 0; i < segment_count; i++)
+ {
+ UINT8 current_x = (line->x_array[i] + 1) / 2;
+
+ *buffer++ = line->color_array[i];
+ *buffer++ = current_x - last_x;
+
+ last_x = current_x;
+ }
+ }
+ }
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( liberatr )
+{
+ liberatr_videoram = auto_malloc(machine->screen[0].width * machine->screen[0].height);
+
+ /* allocate the planet descriptor structure */
+ liberatr_planets[0] = auto_malloc(sizeof(planet));
+ liberatr_planets[1] = auto_malloc(sizeof(planet));
+
+ /* for each planet in the planet ROMs */
+ liberatr_init_planet(machine, liberatr_planets[0], &memory_region(REGION_GFX1)[0x2000]);
+ liberatr_init_planet(machine, liberatr_planets[1], &memory_region(REGION_GFX1)[0x0000]);
+}
+
+
+static void get_pens(pen_t *pens)
+{
+ offs_t i;
+
+ for (i = 0; i < NUM_PENS; i++)
+ {
+ UINT8 r,g,b;
+
+ /* handle the hardware flip of the bit order from 765 to 576 that
+ hardware does between vram and color ram */
+ static offs_t penmap[] = { 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x10, 0x12, 0x14, 0x16, 0x11, 0x13, 0x15, 0x17 };
+
+ UINT8 data = liberatr_colorram[i];
+
+ /* scale it from 0x00-0xff */
+ r = ((~data >> 3) & 0x07) * 0x24 + 3; if (r == 3) r = 0;
+ g = ((~data >> 0) & 0x07) * 0x24 + 3; if (g == 3) g = 0;
+ b = ((~data >> 5) & 0x06) * 0x24 + 3; if (b == 3) b = 0;
+
+ pens[penmap[i]] = MAKE_RGB(r, g, b);
+ }
+}
+
+
+static void liberatr_draw_planet(mame_bitmap *bitmap, pen_t *pens)
+{
+ UINT8 latitude;
+
+ UINT8 *buffer = liberatr_planets[(*liberatr_planet_select >> 4) & 0x01]->frames[*liberatr_planet_frame];
+
+ /* for each latitude */
+ for (latitude = 0; latitude < 0x80; latitude++)
+ {
+ UINT8 segment;
+
+ /* grab the color value for the base (if any) at this latitude */
+ UINT8 base_color = liberatr_base_ram[latitude >> 3] ^ 0x0f;
+
+ UINT8 segment_count = *buffer++;
+ UINT8 x = *buffer++;
+ UINT8 y = 64 + latitude;
+
+ /* run through the segments, drawing its color until its x_array value comes up. */
+ for (segment = 0; segment < segment_count; segment++)
+ {
+ UINT8 i;
+
+ UINT8 color = *buffer++;
+ UINT8 segment_length = *buffer++;
+
+ if ((color & 0x0c) == 0x0c)
+ {
+ color = base_color;
+ }
+
+ for (i = 0; i < segment_length; i++, x++)
+ {
+ *BITMAP_ADDR32(bitmap, y, x) = pens[color];
+ }
+ }
+ }
+}
+
+
+static void liberatr_draw_bitmap(running_machine *machine, mame_bitmap *bitmap, pen_t *pens)
+{
+ offs_t offs;
+
+ for (offs = 0; offs < machine->screen[0].width * machine->screen[0].height; offs++)
+ {
+ UINT8 data = liberatr_videoram[offs];
+
+ UINT8 y = offs >> 8;
+ UINT8 x = offs & 0xff;
+
+ if (data)
+ *BITMAP_ADDR32(bitmap, y, x) = pens[(data >> 5) | 0x10];
+ }
+}
+
+
+VIDEO_UPDATE( liberatr )
+{
+ pen_t pens[NUM_PENS];
+ get_pens(pens);
+
+ fillbitmap(bitmap, RGB_BLACK, cliprect);
+
+ liberatr_draw_planet(bitmap, pens);
+
+ liberatr_draw_bitmap(machine, bitmap, pens);
+
+ return 0;
+}
diff --git a/src/mame/video/lkage.c b/src/mame/video/lkage.c
new file mode 100644
index 00000000000..77e383a6d05
--- /dev/null
+++ b/src/mame/video/lkage.c
@@ -0,0 +1,210 @@
+#include "driver.h"
+
+static tilemap *bg_tilemap, *fg_tilemap, *tx_tilemap;
+static UINT8 bg_tile_bank, fg_tile_bank;
+UINT8 *lkage_scroll, *lkage_vreg;
+
+/*
+ lkage_scroll[0x00]: text layer horizontal scroll
+ lkage_scroll[0x01]: text layer vertical scroll
+ lkage_scroll[0x02]: foreground layer horizontal scroll
+ lkage_scroll[0x03]: foreground layer vertical scroll
+ lkage_scroll[0x04]: background layer horizontal scroll
+ lkage_scroll[0x05]: background layer vertical scroll
+
+ lkage_vreg[0]: 0x00,0x04
+ 0x04: fg tile bank select
+ 0x08: ?
+
+ lkage_vreg[1]: 0x7d
+ 0xf0: background/foreground palette select
+ 0x08: bg tile bank select
+ 0x07: priority config?
+
+ lkage_vreg[2]: 0xf3
+ 0x03: flip screen x/y
+ 0xf0: normally 1111, but 1001 and 0001 inbetween stages (while the
+ backgrounds are are being redrawn). These bits are probably used to enable
+ individual layers, but we have no way of knowing the mapping.
+
+ lkage_vreg:
+ 04 7d f3 : title screen 101
+ 0c 7d f3 : high score 101
+ 04 06 f3 : attract#1 110
+ 04 1e f3 : attract#2 110
+ 04 1e f3 : attract#3 110
+ 00 4e f3 : attract#4 110
+*/
+
+WRITE8_HANDLER( lkage_videoram_w )
+{
+ videoram[offset] = data;
+
+ switch( offset/0x400 )
+ {
+ case 0:
+ tilemap_mark_tile_dirty(tx_tilemap,offset & 0x3ff);
+ break;
+
+ case 1:
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x3ff);
+ break;
+
+ case 2:
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+ break;
+
+ default:
+ break;
+ }
+} /* lkage_videoram_w */
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index + 0x800] + 256 * (bg_tile_bank?5:1);
+ SET_TILE_INFO( 0/*gfx*/, code, 0/*color*/, 0/*flags*/ );
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = videoram[tile_index + 0x400] + 256 * (fg_tile_bank?1:0);
+ SET_TILE_INFO( 0/*gfx*/, code, 0/*color*/, 0/*flags*/);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int code = videoram[tile_index];
+ SET_TILE_INFO( 0/*gfx*/, code, 0/*color*/, 0/*flags*/);
+}
+
+VIDEO_START( lkage )
+{
+ bg_tile_bank = fg_tile_bank = 0;
+
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,32,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_transparent_pen(tx_tilemap,0);
+
+ tilemap_set_scrolldx(bg_tilemap,-5,-5+24);
+ tilemap_set_scrolldx(fg_tilemap,-3,-3+24);
+ tilemap_set_scrolldx(tx_tilemap,-1,-1+24);
+} /* VIDEO_START( lkage ) */
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ const UINT8 *source = spriteram;
+ const UINT8 *finish = source+0x60;
+ while( source<finish )
+ {
+ int attributes = source[2];
+ /* 0x01: horizontal flip
+ * 0x02: vertical flip
+ * 0x04: bank select
+ * 0x08: sprite size
+ * 0x70: color
+ * 0x80: priority
+ */
+ int priority_mask = 0;
+ int color = (attributes>>4)&7;
+ int flipx = attributes&0x01;
+ int flipy = attributes&0x02;
+ int height = (attributes&0x08) ? 2 : 1;
+ int sx = source[0]-15;
+ int sy = 256-16*height-source[1];
+ int sprite_number = source[3] + ((attributes & 0x04) << 6);
+ int y;
+
+ if( attributes&0x80 )
+ {
+ priority_mask = (0xf0|0xcc );
+ }
+ else
+ {
+ priority_mask = (0xf0);
+ }
+
+ if (flip_screen_x)
+ {
+ sx = 239 - sx - 24;
+ flipx = !flipx;
+ }
+ if( flip_screen_y )
+ {
+ sy = 254 - 16*height - sy;
+ flipy = !flipy;
+ }
+ if (height == 2 && !flipy)
+ {
+ sprite_number ^= 1;
+ }
+
+ for (y = 0;y < height;y++)
+ {
+ pdrawgfx(
+ bitmap,
+ machine->gfx[1],
+ sprite_number ^ y,
+ color,
+ flipx,flipy,
+ sx&0xff,
+ sy + 16*y,
+ cliprect,
+ TRANSPARENCY_PEN,0,
+ priority_mask );
+ }
+ source+=4;
+ }
+} /* draw_sprites */
+
+VIDEO_UPDATE( lkage )
+{
+ int bank;
+
+ flip_screen_x_set(~lkage_vreg[2] & 0x01);
+ flip_screen_y_set(~lkage_vreg[2] & 0x02);
+
+ bank = lkage_vreg[1]&0x08;
+ if( bg_tile_bank != bank )
+ {
+ bg_tile_bank = bank;
+ tilemap_mark_all_tiles_dirty( bg_tilemap );
+ }
+
+ bank = lkage_vreg[0]&0x04;
+ if( fg_tile_bank != bank )
+ {
+ fg_tile_bank = bank;
+ tilemap_mark_all_tiles_dirty( fg_tilemap );
+ }
+
+ tilemap_set_palette_offset( bg_tilemap, 0x300 + (lkage_vreg[1]&0xf0) );
+ tilemap_set_palette_offset( fg_tilemap, 0x200 + (lkage_vreg[1]&0xf0) );
+ tilemap_set_palette_offset( tx_tilemap, 0x110 );
+
+ tilemap_set_scrollx(tx_tilemap,0,lkage_scroll[0]);
+ tilemap_set_scrolly(tx_tilemap,0,lkage_scroll[1]);
+
+ tilemap_set_scrollx(fg_tilemap,0,lkage_scroll[2]);
+ tilemap_set_scrolly(fg_tilemap,0,lkage_scroll[3]);
+
+ tilemap_set_scrollx(bg_tilemap,0,lkage_scroll[4]);
+ tilemap_set_scrolly(bg_tilemap,0,lkage_scroll[5]);
+
+ fillbitmap(priority_bitmap, 0, cliprect);
+ if ((lkage_vreg[2] & 0xf0) == 0xf0)
+ {
+ tilemap_draw( bitmap,cliprect,bg_tilemap,0,1 );
+ tilemap_draw( bitmap,cliprect,fg_tilemap,0,(lkage_vreg[1]&2)?2:4 );
+ tilemap_draw( bitmap,cliprect,tx_tilemap,0,4 );
+ }
+ else
+ {
+ tilemap_draw( bitmap,cliprect,tx_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ }
+ draw_sprites(machine, bitmap,cliprect );
+ return 0;
+}
diff --git a/src/mame/video/lordgun.c b/src/mame/video/lordgun.c
new file mode 100644
index 00000000000..28e59356418
--- /dev/null
+++ b/src/mame/video/lordgun.c
@@ -0,0 +1,305 @@
+/***************************************************************************
+
+ -= IGS Lord Of Gun =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z with:
+
+ Q / W / E / R Shows Layer 0 / 1 / 2 / 3
+ A Shows Sprites
+
+ Keys can be used together!
+
+
+ [ 4 Scrolling Layers ]
+
+ Tiles Layer size
+
+ 8 x 8 x 6 0x800 x 0x200
+ 8 x 8 x 6 0x200 x 0x100
+ 16x16 x 6 0x800 x 0x200
+ 32x32 x 6 0x800 x 0x800
+
+ [ 256 Sprites ]
+
+ Plain 16 x 16 x 6 sprites
+
+ [ 2048 colors ]
+
+ [ Priorities ]
+
+ RAM based priorities, with probably a per tile priority code
+ (the same sprite goes below some parts, and above others, of the same layer)
+
+***************************************************************************/
+
+#include "driver.h"
+
+// Variables needed by driver:
+
+UINT16 *lordgun_vram_0, *lordgun_scroll_x_0, *lordgun_scroll_y_0;
+UINT16 *lordgun_vram_1, *lordgun_scroll_x_1, *lordgun_scroll_y_1;
+UINT16 *lordgun_vram_2, *lordgun_scroll_x_2, *lordgun_scroll_y_2;
+UINT16 *lordgun_vram_3, *lordgun_scroll_x_3, *lordgun_scroll_y_3;
+UINT16 *lordgun_scrollram;
+int lordgun_whitescreen;
+
+struct
+{
+ int scr_x, scr_y;
+ UINT16 hw_x, hw_y;
+} lordgun_gun[2];
+
+
+/***************************************************************************
+
+ Tilemaps
+
+***************************************************************************/
+
+static tilemap *tilemap_0, *tilemap_1, *tilemap_2, *tilemap_3;
+
+static TILE_GET_INFO( get_tile_info_0 )
+{
+ UINT16 attr = lordgun_vram_0[ tile_index * 2 + 0 ];
+ UINT16 code = lordgun_vram_0[ tile_index * 2 + 1 ];
+ SET_TILE_INFO( 1, code, (attr & 0x0030) >> 4, TILE_FLIPXY(attr >> 14));
+}
+
+static TILE_GET_INFO( get_tile_info_1 )
+{
+ UINT16 attr = lordgun_vram_1[ tile_index * 2 + 0 ];
+ UINT16 code = lordgun_vram_1[ tile_index * 2 + 1 ];
+ SET_TILE_INFO( 2, code, (attr & 0x0070) >> 4, TILE_FLIPXY(attr >> 14));
+}
+
+static TILE_GET_INFO( get_tile_info_2 )
+{
+ UINT16 attr = lordgun_vram_2[ tile_index * 2 + 0 ];
+ UINT16 code = lordgun_vram_2[ tile_index * 2 + 1 ];
+ SET_TILE_INFO( 3, code, (attr & 0x0300) >> 8, TILE_FLIPXY(attr >> 14));
+}
+
+static TILE_GET_INFO( get_tile_info_3 )
+{
+ UINT16 attr = lordgun_vram_3[ tile_index * 2 + 0 ];
+ UINT16 code = lordgun_vram_3[ tile_index * 2 + 1 ];
+ SET_TILE_INFO( 4, code, (attr & 0x00f0) >> 4, TILE_FLIPXY(attr >> 14));
+}
+
+WRITE16_HANDLER( lordgun_vram_0_w )
+{
+ COMBINE_DATA(&lordgun_vram_0[offset]);
+ tilemap_mark_tile_dirty(tilemap_0, offset/2);
+}
+
+WRITE16_HANDLER( lordgun_vram_1_w )
+{
+ COMBINE_DATA(&lordgun_vram_1[offset]);
+ tilemap_mark_tile_dirty(tilemap_1, offset/2);
+}
+
+WRITE16_HANDLER( lordgun_vram_2_w )
+{
+ COMBINE_DATA(&lordgun_vram_2[offset]);
+ tilemap_mark_tile_dirty(tilemap_2, offset/2);
+}
+
+WRITE16_HANDLER( lordgun_vram_3_w )
+{
+ COMBINE_DATA(&lordgun_vram_3[offset]);
+ tilemap_mark_tile_dirty(tilemap_3, offset/2);
+}
+
+/***************************************************************************
+
+ Video Init
+
+***************************************************************************/
+
+VIDEO_START( lordgun )
+{
+ tilemap_0 = tilemap_create( get_tile_info_0, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, 0x100, 0x40 );
+
+ tilemap_1 = tilemap_create( get_tile_info_1, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 0x80,0x20 );
+
+ tilemap_2 = tilemap_create( get_tile_info_2, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 32,32, 0x40,0x40 );
+
+ tilemap_3 = tilemap_create( get_tile_info_3, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, 0x40,0x20 );
+
+ tilemap_set_scroll_rows(tilemap_0,1);
+ tilemap_set_scroll_cols(tilemap_0,1);
+ tilemap_set_transparent_pen(tilemap_0,0x3f);
+
+ tilemap_set_scroll_rows(tilemap_1,0x200);
+ tilemap_set_scroll_cols(tilemap_1,1);
+ tilemap_set_transparent_pen(tilemap_1,0x3f);
+
+ tilemap_set_scroll_rows(tilemap_2,1);
+ tilemap_set_scroll_cols(tilemap_2,1);
+ tilemap_set_transparent_pen(tilemap_2,0x3f);
+
+ tilemap_set_scroll_rows(tilemap_3,1);
+ tilemap_set_scroll_cols(tilemap_3,1);
+ tilemap_set_transparent_pen(tilemap_3,0x3f);
+}
+
+/***************************************************************************
+
+ Gun screen position
+
+***************************************************************************/
+
+static int lordgun_gun_x_table[] =
+{
+ -100, 0x001,0x001,0x002,0x002,0x003,0x003,0x004,0x005,0x006,0x007,0x008,0x009,0x00A,0x00B,0x00C,
+ 0x00D,0x00E,0x00F,0x010,0x011,0x012,0x013,0x014,0x015,0x016,0x017,0x018,0x019,0x01A,0x01B,0x01C,
+ 0x01D,0x01E,0x01F,0x020,0x021,0x022,0x023,0x024,0x025,0x026,0x027,0x028,0x029,0x02A,0x02B,0x02C,
+ 0x02D,0x02E,0x02F,0x030,0x031,0x032,0x033,0x034,0x035,0x036,0x037,0x038,0x039,0x03A,0x03B,0x03C,
+ 0x03D,0x03E,0x03F,0x040,0x041,0x043,0x044,0x045,0x046,0x047,0x048,0x049,0x04A,0x04B,0x04C,0x04E,
+ 0x04F,0x050,0x051,0x052,0x053,0x054,0x055,0x056,0x057,0x059,0x05A,0x05B,0x05C,0x05D,0x05E,0x05F,
+ 0x060,0x061,0x05A,0x063,0x065,0x066,0x067,0x068,0x069,0x06A,0x06B,0x06C,0x06D,0x06E,0x06F,0x071,
+ 0x072,0x074,0x075,0x077,0x078,0x07A,0x07B,0x07D,0x07E,0x080,0x081,0x083,0x085,0x087,0x089,0x08B,
+ 0x08D,0x08E,0x08F,0x090,0x092,0x093,0x095,0x097,0x098,0x099,0x09A,0x09B,0x09C,0x09D,0x09E,0x0A0,
+ 0x0A1,0x0A2,0x0A3,0x0A4,0x0A5,0x0A6,0x0A7,0x0A8,0x0A9,0x0AA,0x0AC,0x0AD,0x0AE,0x0AF,0x0B0,0x0B1,
+ 0x0B2,0x0B3,0x0B4,0x0B5,0x0B6,0x0B8,0x0B9,0x0BA,0x0BB,0x0BC,0x0BD,0x0BE,0x0BF,0x0C0,0x0C1,0x0C2,
+ 0x0C4,0x0C5,0x0C6,0x0C7,0x0C8,0x0C9,0x0CA,0x0CB,0x0CC,0x0CD,0x0CF,0x0D0,0x0D1,0x0D2,0x0D3,0x0D4,
+ 0x0D5,0x0D6,0x0D7,0x0D8,0x0D9,0x0DB,0x0DC,0x0DD,0x0DE,0x0DF,0x0E0,0x0E1,0x0E2,0x0E3,0x0E4,0x0E5,
+ 0x0E7,0x0E8,0x0E9,0x0EA,0x0EB,0x0EC,0x0ED,0x0EE,0x0EF,0x0F0,0x0F1,0x0F3,0x0F4,0x0F5,0x0F6,0x0F7,
+ 0x0F8,0x0F9,0x0FA,0x0FB,0x0FC,0x0FE,0x0FF,0x100,0x101,0x102,0x103,0x104,0x105,0x106,0x107,0x108,
+ 0x10A,0x10B,0x10C,0x10D,0x10E,0x10F,0x110,0x111,0x112,0x113,0x114,0x116,0x117,0x118,0x119,0x11A,
+ 0x11B,0x11C,0x11D,0x11E,0x11F,0x120,0x122,0x123,0x124,0x125,0x126,0x127,0x128,0x129,0x12A,0x12B,
+ 0x12C,0x12E,0x12F,0x130,0x131,0x132,0x133,0x134,0x135,0x136,0x137,0x139,0x13A,0x13B,0x13C,0x13D,
+ 0x13E,0x13F,0x140,0x141,0x142,0x143,0x145,0x146,0x147,0x148,0x149,0x14A,0x14B,0x14C,0x14D,0x14E,
+ 0x14F,0x151,0x152,0x153,0x154,0x155,0x156,0x157,0x158,0x159,0x15A,0x15B,0x15D,0x15E,0x15F,0x160,
+ 0x161,0x162,0x163,0x164,0x165,0x166,0x167,0x169,0x16A,0x16B,0x16C,0x16D,0x16E,0x16F,0x170,0x171,
+ 0x172,0x174,0x175,0x176,0x177,0x178,0x179,0x17A,0x17B,0x17C,0x17D,0x17E,0x17F,0x180,0x181,0x182,
+ 0x183,0x184,0x185,0x186,0x187,0x188,0x189,0x18A,0x18B,0x18C,0x18D,0x18E,0x18F,0x190,0x191,0x192,
+ 0x193,0x194,0x195,0x196,0x197,0x198,0x199,0x19A,0x19B,0x19C,0x19D,0x19E,0x19F,0x1A0,0x1A1,0x1A2,
+ 0x1A3,0x1A4,0x1A5,0x1A6,0x1A7,0x1A8,0x1A9,0x1AA,0x1AB,0x1AC,0x1AD,0x1AE,0x1AF,0x1B0,0x1B1,0x1B2,
+ 0x1B3,0x1B4,0x1B5,0x1B6,0x1B7,0x1B8,0x1B9,0x1BA,0x1BB,0x1BC,0x1BD,0x1BE,0x1BF,0x1BF
+};
+
+static void lorddgun_calc_gun_scr(int i)
+{
+ int x = readinputport(5+i) - 0x3c;
+ if ( (x < 0) || (x > sizeof(lordgun_gun_x_table)/sizeof(lordgun_gun_x_table[0])) )
+ x = 0;
+
+ lordgun_gun[i].scr_x = lordgun_gun_x_table[x];
+ lordgun_gun[i].scr_y = readinputport(7+i);
+}
+
+void lordgun_update_gun(int i)
+{
+ lordgun_gun[i].hw_x = readinputport(5+i);
+ lordgun_gun[i].hw_y = readinputport(7+i);
+
+ lorddgun_calc_gun_scr(i);
+
+ if ( (lordgun_gun[i].scr_x < Machine->screen[0].visarea.min_x) ||
+ (lordgun_gun[i].scr_x > Machine->screen[0].visarea.max_x) ||
+ (lordgun_gun[i].scr_y < Machine->screen[0].visarea.min_y) ||
+ (lordgun_gun[i].scr_y > Machine->screen[0].visarea.max_y) )
+ lordgun_gun[i].hw_x = lordgun_gun[i].hw_y = 0;
+}
+
+
+/***************************************************************************
+
+ Sprites
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT16 *s = spriteram16;
+ UINT16 *end = spriteram16 + spriteram_size/2;
+
+ for ( ; s < end; s += 8/2 )
+ {
+ int attr, code, color, sx, sy, flipx, flipy;
+
+ sy = s[ 0 ];
+ attr = s[ 1 ];
+ code = s[ 2 ];
+ sx = s[ 3 ];
+
+ // Last sprite
+ if (sy & 0x8000) break;
+
+ flipx = attr & 0x8000;
+ flipy = attr & 0x4000;
+ color = (attr & 0x00f0) >> 4;
+
+ // Sign extend the position
+ sx -= 0x18;
+ sy = (sy & 0x7ff) - (sy & 0x800);
+
+ drawgfx( bitmap, machine->gfx[0],
+ code, color,
+ flipx, flipy, sx, sy,
+ cliprect, TRANSPARENCY_PEN, 0x3f);
+ }
+}
+
+/***************************************************************************
+
+ Video Update
+
+***************************************************************************/
+
+VIDEO_UPDATE( lordgun )
+{
+ int layers_ctrl = -1;
+ int y;
+
+#ifdef MAME_DEBUG
+if (input_code_pressed(KEYCODE_Z))
+{
+ int msk = 0;
+
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+ if (input_code_pressed(KEYCODE_E)) msk |= 4;
+ if (input_code_pressed(KEYCODE_R)) msk |= 8;
+ if (input_code_pressed(KEYCODE_A)) msk |= 16;
+ if (msk != 0) layers_ctrl &= msk;
+}
+#endif
+
+ if (lordgun_whitescreen)
+ {
+ fillbitmap( bitmap, get_white_pen(machine), cliprect );
+ return 0;
+ }
+
+ tilemap_set_scrollx( tilemap_0, 0, *lordgun_scroll_x_0 );
+ tilemap_set_scrolly( tilemap_0, 0, *lordgun_scroll_y_0 );
+
+ for (y = 0; y < 0x200; y++)
+ tilemap_set_scrollx( tilemap_1, y, (*lordgun_scroll_x_1) + lordgun_scrollram[y * 4/2 + 2/2]);
+ tilemap_set_scrolly( tilemap_1, 0, *lordgun_scroll_y_1 );
+
+ tilemap_set_scrollx( tilemap_2, 0, *lordgun_scroll_x_2 );
+ tilemap_set_scrolly( tilemap_2, 0, *lordgun_scroll_y_2 );
+
+ tilemap_set_scrollx( tilemap_3, 0, *lordgun_scroll_x_3 );
+ tilemap_set_scrolly( tilemap_3, 0, *lordgun_scroll_y_3 );
+
+ fillbitmap( bitmap, machine->pens[0], cliprect );
+
+ if (layers_ctrl & 4) tilemap_draw(bitmap, cliprect, tilemap_2, 0, 0);
+ if (layers_ctrl & 1) tilemap_draw(bitmap, cliprect, tilemap_0, 0, 0);
+ if (layers_ctrl & 2) tilemap_draw(bitmap, cliprect, tilemap_1, 0, 0);
+ if (layers_ctrl & 16) draw_sprites(machine, bitmap, cliprect);
+ if (layers_ctrl & 8) tilemap_draw(bitmap, cliprect, tilemap_3, 0, 0);
+
+ return 0;
+}
diff --git a/src/mame/video/lsasquad.c b/src/mame/video/lsasquad.c
new file mode 100644
index 00000000000..59334c670db
--- /dev/null
+++ b/src/mame/video/lsasquad.c
@@ -0,0 +1,221 @@
+#include "driver.h"
+
+UINT8 *lsasquad_scrollram;
+
+
+
+static void draw_layer(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8 *scrollram)
+{
+ int offs,scrollx,scrolly;
+
+
+ scrollx = scrollram[3];
+ scrolly = -scrollram[0];
+
+ for (offs = 0;offs < 0x080;offs += 4)
+ {
+ int base,y,sx,sy,code,color;
+
+ base = 64 * scrollram[offs+1];
+ sx = 8*(offs/4) + scrollx;
+ if (flip_screen) sx = 248 - sx;
+ sx &= 0xff;
+
+ for (y = 0;y < 32;y++)
+ {
+ int attr;
+
+ sy = 8*y + scrolly;
+ if (flip_screen) sy = 248 - sy;
+ sy &= 0xff;
+
+ attr = videoram[base + 2*y + 1];
+ code = videoram[base + 2*y] + ((attr & 0x0f) << 8);
+ color = attr >> 4;
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flip_screen,flip_screen,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ if (sx > 248) /* wraparound */
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flip_screen,flip_screen,
+ sx-256,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+}
+
+static int draw_layer_daikaiju(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int offs, int * previd, int type)
+{
+ int id,scrollx,scrolly,initoffs, globalscrollx;
+ int stepx=0;
+ initoffs=offs;
+
+ globalscrollx=0;
+
+ id=lsasquad_scrollram[offs+2];
+
+ for(;offs < 0x400; offs+=4)
+ {
+ int base,y,sx,sy,code,color;
+
+ //id change
+ if(id!=lsasquad_scrollram[offs+2])
+ {
+ *previd = id;
+ return offs;
+ }
+ else
+ {
+ id=lsasquad_scrollram[offs+2];
+ }
+
+ //skip empty (??) column, potential probs with 1st column in scrollram (scroll 0, tile 0, id 0)
+ if( (lsasquad_scrollram[offs+0]|lsasquad_scrollram[offs+1]|lsasquad_scrollram[offs+2]|lsasquad_scrollram[offs+3])==0)
+ continue;
+
+ //local scroll x/y
+ scrolly = -lsasquad_scrollram[offs+0];
+ scrollx = lsasquad_scrollram[offs+3];
+
+ //check for global x scroll used in bg layer in game (starts at offset 0 in scrollram
+ // and game name/logo on title screen (starts in the middle of scrollram, but with different
+ // (NOT unique )id than prev coulmn(s)
+
+ if( *previd!=1 )
+ {
+ if(offs!=initoffs)
+ {
+ scrollx+=globalscrollx;
+ }
+ else
+ {
+ //global scroll init
+ globalscrollx=scrollx;
+ }
+ }
+
+ base = 64 * lsasquad_scrollram[offs+1];
+ sx = scrollx+stepx;
+
+ if (flip_screen) sx = 248 - sx;
+ sx &= 0xff;
+
+ for (y = 0;y < 32;y++)
+ {
+ int attr;
+
+ sy = 8*y + scrolly;
+ if (flip_screen) sy = 248 - sy;
+ sy &= 0xff;
+
+ attr = videoram[base + 2*y + 1];
+ code = videoram[base + 2*y] + ((attr & 0x0f) << 8);
+ color = attr >> 4;
+
+
+ if((type==0 && color!=0x0d) || (type !=0 && color==0x0d))
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flip_screen,flip_screen,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ if (sx > 248) /* wraparound */
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flip_screen,flip_screen,
+ sx-256,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+ }
+ return offs;
+}
+
+static void drawbg(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int type)
+{
+ int i=0;
+ int id=-1;
+
+ while(i<0x400)
+ {
+ if(!(lsasquad_scrollram[i+2]&1))
+ {
+ i=draw_layer_daikaiju(machine, bitmap, cliprect, i, &id,type);
+ }
+ else
+ {
+ id=lsasquad_scrollram[i+2];
+ i+=4;
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size-4;offs >= 0;offs -= 4)
+ {
+ int sx,sy,attr,code,color,flipx,flipy;
+
+ sx = spriteram[offs+3];
+ sy = 240 - spriteram[offs];
+ attr = spriteram[offs+1];
+ code = spriteram[offs+2] + ((attr & 0x30) << 4);
+ color = attr & 0x0f;
+ flipx = attr & 0x40;
+ flipy = attr & 0x80;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ /* wraparound */
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx-256,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+VIDEO_UPDATE( lsasquad )
+{
+ fillbitmap(bitmap,machine->pens[511],cliprect);
+
+ draw_layer(machine,bitmap,cliprect,lsasquad_scrollram + 0x000);
+ draw_layer(machine,bitmap,cliprect,lsasquad_scrollram + 0x080);
+ draw_sprites(machine,bitmap,cliprect);
+ draw_layer(machine,bitmap,cliprect,lsasquad_scrollram + 0x100);
+ return 0;
+}
+
+
+VIDEO_UPDATE( daikaiju )
+{
+ fillbitmap(bitmap,machine->pens[511],cliprect);
+ drawbg(machine,bitmap,cliprect,0); // bottom
+ draw_sprites(machine,bitmap,cliprect);
+ drawbg(machine,bitmap,cliprect,1); // top = pallete $d ?
+ return 0;
+}
diff --git a/src/mame/video/lvcards.c b/src/mame/video/lvcards.c
new file mode 100644
index 00000000000..dd4505f2c51
--- /dev/null
+++ b/src/mame/video/lvcards.c
@@ -0,0 +1,115 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+PALETTE_INIT( ponttehk )
+{
+ int i;
+
+ for ( i = 0; i < machine->drv->total_colors; i++ )
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ /* green component */
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ /* blue component */
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+}
+
+PALETTE_INIT( lvcards ) //Ever so slightly different, but different enough.
+{
+ int i;
+
+ for ( i = 0; i < machine->drv->total_colors; i++ )
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[0] >> 0) & 0x11;
+ bit1 = (color_prom[0] >> 1) & 0x11;
+ bit2 = (color_prom[0] >> 2) & 0x11;
+ bit3 = (color_prom[0] >> 3) & 0x11;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ /* green component */
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x11;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x11;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x11;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x11;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ /* blue component */
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x11;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x11;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x11;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x11;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( lvcards_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( lvcards_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + ((attr & 0x30) << 4) + ((attr & 0x80) << 3);
+ int color = attr & 0x0f;
+ int flags = (attr & 0x40) ? TILE_FLIPX : 0;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( lvcards )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+VIDEO_UPDATE( lvcards )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/lwings.c b/src/mame/video/lwings.c
new file mode 100644
index 00000000000..dc2bc216958
--- /dev/null
+++ b/src/mame/video/lwings.c
@@ -0,0 +1,293 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "lwings.h"
+
+UINT8 *lwings_fgvideoram;
+UINT8 *lwings_bg1videoram;
+
+static int bAvengersHardware, bg2_image;
+static tilemap *fg_tilemap, *bg1_tilemap, *bg2_tilemap;
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( get_bg2_memory_offset )
+{
+ return (row * 0x800) | (col * 2);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code, color;
+
+ code = lwings_fgvideoram[tile_index];
+ color = lwings_fgvideoram[tile_index + 0x400];
+ SET_TILE_INFO(
+ 0,
+ code + ((color & 0xc0) << 2),
+ color & 0x0f,
+ TILE_FLIPYX((color & 0x30) >> 4));
+}
+
+static TILE_GET_INFO( lwings_get_bg1_tile_info )
+{
+ int code, color;
+
+ code = lwings_bg1videoram[tile_index];
+ color = lwings_bg1videoram[tile_index + 0x400];
+ SET_TILE_INFO(
+ 1,
+ code + ((color & 0xe0) << 3),
+ color & 0x07,
+ TILE_FLIPYX((color & 0x18) >> 3));
+}
+
+static TILE_GET_INFO( trojan_get_bg1_tile_info )
+{
+ int code, color;
+
+ code = lwings_bg1videoram[tile_index];
+ color = lwings_bg1videoram[tile_index + 0x400];
+ code += (color & 0xe0)<<3;
+ SET_TILE_INFO(
+ 1,
+ code,
+ bAvengersHardware ? ((color & 7) ^ 6) : (color & 7),
+ ((color & 0x10) ? TILE_FLIPX : 0));
+ tileinfo->group = (color & 0x08) >> 3;
+}
+
+static TILE_GET_INFO( get_bg2_tile_info )
+{
+ int code, color;
+ UINT8 *rom = memory_region(REGION_GFX5);
+ int mask = memory_region_length(REGION_GFX5) - 1;
+
+ tile_index = (tile_index + bg2_image * 0x20) & mask;
+ code = rom[tile_index];
+ color = rom[tile_index + 1];
+ SET_TILE_INFO(
+ 3,
+ code + ((color & 0x80) << 1),
+ color & 0x07,
+ TILE_FLIPYX((color & 0x30) >> 4));
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( lwings )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+ bg1_tilemap = tilemap_create(lwings_get_bg1_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 16,16,32,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,3);
+}
+
+VIDEO_START( trojan )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN,8, 8,32,32);
+ bg1_tilemap = tilemap_create(trojan_get_bg1_tile_info,tilemap_scan_cols, TILEMAP_TYPE_PEN, 16,16,32,32);
+ bg2_tilemap = tilemap_create(get_bg2_tile_info, get_bg2_memory_offset,TILEMAP_TYPE_PEN, 16,16,32,16);
+
+ tilemap_set_transparent_pen(fg_tilemap,3);
+ tilemap_set_transmask(bg1_tilemap,0,0xffff,0x0001); /* split type 0 is totally transparent in front half */
+ tilemap_set_transmask(bg1_tilemap,1,0xf07f,0x0f81); /* split type 1 has pens 7-11 opaque in front half */
+
+ bAvengersHardware = 0;
+}
+
+VIDEO_START( avengers )
+{
+ video_start_trojan(machine);
+ bAvengersHardware = 1;
+}
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( lwings_fgvideoram_w )
+{
+ lwings_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( lwings_bg1videoram_w )
+{
+ lwings_bg1videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg1_tilemap,offset & 0x3ff);
+}
+
+
+WRITE8_HANDLER( lwings_bg1_scrollx_w )
+{
+ static UINT8 scroll[2];
+
+ scroll[offset] = data;
+ tilemap_set_scrollx(bg1_tilemap,0,scroll[0] | (scroll[1] << 8));
+}
+
+WRITE8_HANDLER( lwings_bg1_scrolly_w )
+{
+ static UINT8 scroll[2];
+
+ scroll[offset] = data;
+ tilemap_set_scrolly(bg1_tilemap,0,scroll[0] | (scroll[1] << 8));
+}
+
+WRITE8_HANDLER( trojan_bg2_scrollx_w )
+{
+ tilemap_set_scrollx(bg2_tilemap,0,data);
+}
+
+WRITE8_HANDLER( trojan_bg2_image_w )
+{
+ if (bg2_image != data)
+ {
+ bg2_image = data;
+ tilemap_mark_all_tiles_dirty(bg2_tilemap);
+ }
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+INLINE int is_sprite_on(int offs)
+{
+ int sx,sy;
+
+
+ sx = buffered_spriteram[offs + 3] - 0x100 * (buffered_spriteram[offs + 1] & 0x01);
+ sy = buffered_spriteram[offs + 2];
+
+ return sx || sy;
+}
+
+static void lwings_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ if (is_sprite_on(offs))
+ {
+ int code,color,sx,sy,flipx,flipy;
+
+
+ sx = buffered_spriteram[offs + 3] - 0x100 * (buffered_spriteram[offs + 1] & 0x01);
+ sy = buffered_spriteram[offs + 2];
+ if (sy > 0xf8) sy-=0x100;
+ code = buffered_spriteram[offs] | (buffered_spriteram[offs + 1] & 0xc0) << 2;
+ color = (buffered_spriteram[offs + 1] & 0x38) >> 3;
+ flipx = buffered_spriteram[offs + 1] & 0x02;
+ flipy = buffered_spriteram[offs + 1] & 0x04;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[2],
+ code,color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+}
+
+static void trojan_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ if (is_sprite_on(offs))
+ {
+ int code,color,sx,sy,flipx,flipy;
+
+
+ sx = buffered_spriteram[offs + 3] - 0x100 * (buffered_spriteram[offs + 1] & 0x01);
+ sy = buffered_spriteram[offs + 2];
+ if (sy > 0xf8) sy-=0x100;
+ code = buffered_spriteram[offs] |
+ ((buffered_spriteram[offs + 1] & 0x20) << 4) |
+ ((buffered_spriteram[offs + 1] & 0x40) << 2) |
+ ((buffered_spriteram[offs + 1] & 0x80) << 3);
+ color = (buffered_spriteram[offs + 1] & 0x0e) >> 1;
+
+ if( bAvengersHardware )
+ {
+ flipx = 0; /* Avengers */
+ flipy = ~buffered_spriteram[offs + 1] & 0x10;
+ }
+ else
+ {
+ flipx = buffered_spriteram[offs + 1] & 0x10; /* Trojan */
+ flipy = 1;
+ }
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[2],
+ code,color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+}
+
+VIDEO_UPDATE( lwings )
+{
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,0,0);
+ lwings_draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( trojan )
+{
+ tilemap_draw(bitmap,cliprect,bg2_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,TILEMAP_DRAW_LAYER1,0);
+ trojan_draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,TILEMAP_DRAW_LAYER0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_EOF( lwings )
+{
+ buffer_spriteram_w(0,0);
+}
diff --git a/src/mame/video/m107.c b/src/mame/video/m107.c
new file mode 100644
index 00000000000..4e02ffc6ebf
--- /dev/null
+++ b/src/mame/video/m107.c
@@ -0,0 +1,320 @@
+/****************************************************************************
+
+ Irem M107 video hardware, Bryan McPhail, mish@tendril.co.uk
+
+ Close to M92 hardware, but with 4 playfields, not 3.
+ Twice as many colours, twice as many sprites.
+
+*****************************************************************************
+
+ Port:
+ 0x80: pf1 Y scroll
+ 0x82: pf1 X scroll
+ 0x84: pf2 Y scroll
+ 0x86: pf2 X scroll
+ 0x88: pf3 Y scroll
+ 0x8a: pf3 X scroll
+ 0x8c: pf4 Y scroll
+ 0x8e: pf4 X scroll
+
+ 0x90: pf1 control
+ 0x92: pf2 control
+ 0x94: pf3 control
+ 0x96: pf4 control
+
+ 0x98: Priority?
+ 0x9a:
+ 0x9c:
+ 0x9e: Raster interrupt value
+
+ Playfield control:
+ Bit 0x0f00: Playfield location in VRAM (in steps of 0x1000)
+ Bit 0x0080: 0 = Playfield enable, 1 = disable
+ Bit 0x0002: 1 = Rowscroll enable, 0 = disable
+
+*****************************************************************************/
+
+#include "driver.h"
+#include "m107.h"
+
+typedef struct _pf_layer_info pf_layer_info;
+struct _pf_layer_info
+{
+ tilemap * tmap;
+ UINT16 vram_base;
+ UINT16 control[4];
+};
+
+static pf_layer_info pf_layer[4];
+
+
+static UINT16 m107_control[0x10];
+static UINT16 *m107_spriteram;
+UINT16 *m107_vram_data;
+UINT16 m107_raster_irq_position;
+UINT8 m107_spritesystem;
+
+
+/*****************************************************************************/
+
+static TILE_GET_INFO( get_pf_tile_info )
+{
+ pf_layer_info *layer = param;
+ int tile, attrib;
+ tile_index = 2 * tile_index + layer->vram_base;
+
+ attrib = m107_vram_data[tile_index + 1];
+ tile = m107_vram_data[tile_index] + ((attrib & 0x1000) << 4);
+
+ SET_TILE_INFO(
+ 0,
+ tile,
+ attrib & 0x7f,
+ TILE_FLIPYX(attrib >> 10));
+
+ /* Priority 1 = tile appears above sprites */
+ tileinfo->category = (attrib >> 9) & 1;
+}
+
+/*****************************************************************************/
+
+WRITE16_HANDLER( m107_vram_w )
+{
+ int laynum;
+
+ COMBINE_DATA(&m107_vram_data[offset]);
+ for (laynum = 0; laynum < 4; laynum++)
+ if ((offset & 0x6000) == pf_layer[laynum].vram_base)
+ tilemap_mark_tile_dirty(pf_layer[laynum].tmap, (offset & 0x1fff) / 2);
+}
+
+/*****************************************************************************/
+
+WRITE16_HANDLER( m107_control_w )
+{
+ UINT16 old = m107_control[offset];
+ pf_layer_info *layer;
+
+ COMBINE_DATA(&m107_control[offset]);
+
+ switch (offset)
+ {
+ case 0x08: /* Playfield 1 (top layer) */
+ case 0x09: /* Playfield 2 */
+ case 0x0a: /* Playfield 3 */
+ case 0x0b: /* Playfield 4 (bottom layer) */
+ layer = &pf_layer[offset - 0x08];
+
+ /* update VRAM base (bits 8-11) */
+ layer->vram_base = ((m107_control[offset] >> 8) & 15) * 0x800;
+
+ /* update enable (bit 7) */
+ tilemap_set_enable(layer->tmap, (~m107_control[offset] >> 7) & 1);
+
+ /* mark everything dirty of the VRAM base changes */
+ if ((old ^ m107_control[offset]) & 0x0f00)
+ tilemap_mark_all_tiles_dirty(layer->tmap);
+ break;
+
+ case 0x0f:
+ m107_raster_irq_position = m107_control[offset] - 128;
+ break;
+ }
+}
+
+/*****************************************************************************/
+
+VIDEO_START( m107 )
+{
+ int laynum;
+
+ for (laynum = 0; laynum < 4; laynum++)
+ {
+ pf_layer_info *layer = &pf_layer[laynum];
+
+ /* allocate a tilemaps per layer */
+ layer->tmap = tilemap_create(get_pf_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,64);
+
+ /* set the user data to point to the layer */
+ tilemap_set_user_data(layer->tmap, &pf_layer[laynum]);
+
+ /* set scroll offsets */
+ tilemap_set_scrolldx(layer->tmap, -3 + 2 * laynum, -3 + 2 * laynum);
+ tilemap_set_scrolldy(layer->tmap, -128, -128);
+
+ /* set pen 0 to transparent for all tilemaps except #4 */
+ if (laynum != 3)
+ tilemap_set_transparent_pen(layer->tmap, 0);
+ }
+
+ m107_spriteram = auto_malloc(0x1000);
+ memset(m107_spriteram,0,0x1000);
+}
+
+/*****************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri)
+{
+ int offs;
+
+ for (offs = 0x800-4;offs >= 0;offs -= 4)
+ {
+ int x,y,sprite,colour,fx,fy,y_multi,i,s_ptr;
+
+ if (((m107_spriteram[offs+2]&0x80)==0x80) && pri==0) continue;
+ if (((m107_spriteram[offs+2]&0x80)==0x00) && pri==1) continue;
+
+ y=m107_spriteram[offs+0];
+ x=m107_spriteram[offs+3];
+ x&=0x1ff;
+ y&=0x1ff;
+
+ if (x==0 || y==0) continue; /* offscreen */
+
+ sprite=m107_spriteram[offs+1]&0x7fff;
+
+ x = x - 16;
+ y = 384 - 16 - y;
+
+ colour=m107_spriteram[offs+2]&0x7f;
+ fx=m107_spriteram[offs+2]&0x100;
+ fy=m107_spriteram[offs+2]&0x200;
+ y_multi=(m107_spriteram[offs+0]>>11)&0x3;
+
+ if (m107_spritesystem == 0)
+ {
+ y_multi=1 << y_multi; /* 1, 2, 4 or 8 */
+
+ s_ptr = 0;
+ if (!fy) s_ptr+=y_multi-1;
+
+ for (i=0; i<y_multi; i++)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ sprite + s_ptr,
+ colour,
+ fx,fy,
+ x,y-i*16,
+ cliprect,TRANSPARENCY_PEN,0);
+ if (fy) s_ptr++; else s_ptr--;
+ }
+ }
+ else
+ {
+ UINT8 *rom = memory_region(REGION_USER1);
+ int rom_offs = sprite*8;
+
+ if (rom[rom_offs+1] || rom[rom_offs+3] || rom[rom_offs+5] || rom[rom_offs+7])
+ {
+ while (rom_offs < 0x40000) /* safety check */
+ {
+ int xdisp = rom[rom_offs+6]+256*rom[rom_offs+7];
+ int ydisp = rom[rom_offs+2]+256*rom[rom_offs+3];
+ int ffx=fx^(rom[rom_offs+1]&1);
+ int ffy=fy^(rom[rom_offs+1]&2);
+ sprite=rom[rom_offs+4]+256*rom[rom_offs+5];
+ y_multi=1<<((rom[rom_offs+3]>>1)&0x3);
+ if (fx) xdisp = -xdisp;
+ if (fy) ydisp = -ydisp - (16*y_multi-1);
+ if (!ffy) sprite+=y_multi-1;
+ for (i=0; i<y_multi; i++)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ sprite+(ffy?i:-i),
+ colour,
+ ffx,ffy,
+ (x+xdisp)&0x1ff,(y-ydisp-16*i)&0x1ff,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ if (rom[rom_offs+1]&0x80) break; /* end of block */
+
+ rom_offs += 8;
+ }
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+static void m107_update_scroll_positions(void)
+{
+ int laynum;
+ int i;
+
+ /* Playfield 4 rowscroll data is 0xde800 - 0xdebff???
+ Playfield 3 rowscroll data is 0xdf800 - 0xdfbff
+ Playfield 2 rowscroll data is 0xdf400 - 0xdf7ff
+ Playfield 1 rowscroll data is 0xde800 - 0xdebff ??
+ */
+
+ for (laynum = 0; laynum < 4; laynum++)
+ {
+ pf_layer_info *layer = &pf_layer[laynum];
+
+ if (m107_control[0x08 + laynum] & 0x02)
+ {
+ const UINT16 *scrolldata = m107_vram_data + (0xf000 + 0x400 * laynum) / 2;
+
+ tilemap_set_scroll_rows(layer->tmap, 512);
+ for (i = 0; i < 512; i++)
+ tilemap_set_scrollx(layer->tmap, i, scrolldata[i]);
+ }
+ else
+ {
+ tilemap_set_scroll_rows(layer->tmap, 1);
+ tilemap_set_scrollx(layer->tmap, 0, m107_control[1 + 2 * laynum]);
+ }
+
+ tilemap_set_scrolly(layer->tmap, 0, m107_control[0 + 2 * laynum]);
+ }
+}
+
+/*****************************************************************************/
+
+static void m107_screenrefresh(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ if ((~m107_control[0x0b] >> 7) & 1)
+ {
+ tilemap_draw(bitmap, cliprect, pf_layer[3].tmap, 0, 0);
+ tilemap_draw(bitmap, cliprect, pf_layer[3].tmap, 1, 0);
+ }
+ else
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ tilemap_draw(bitmap, cliprect, pf_layer[2].tmap, 0, 0);
+ tilemap_draw(bitmap, cliprect, pf_layer[2].tmap, 1, 0);
+
+ tilemap_draw(bitmap, cliprect, pf_layer[1].tmap, 0, 0);
+ tilemap_draw(bitmap, cliprect, pf_layer[0].tmap, 0, 0);
+
+ draw_sprites(machine, bitmap, cliprect, 0);
+ tilemap_draw(bitmap, cliprect, pf_layer[1].tmap, 1, 0);
+ tilemap_draw(bitmap, cliprect, pf_layer[0].tmap, 1, 0);
+
+ draw_sprites(machine, bitmap, cliprect, 1);
+
+ /* This hardware probably has more priority values - but I haven't found
+ any used yet */
+}
+
+/*****************************************************************************/
+
+WRITE16_HANDLER( m107_spritebuffer_w )
+{
+ if (ACCESSING_LSB) {
+// logerror("%04x: buffered spriteram\n",activecpu_get_pc());
+ memcpy(m107_spriteram,spriteram16,0x1000);
+ }
+}
+
+/*****************************************************************************/
+
+VIDEO_UPDATE( m107 )
+{
+ m107_update_scroll_positions();
+ m107_screenrefresh(machine, bitmap, cliprect);
+ return 0;
+}
+
diff --git a/src/mame/video/m3raster.c b/src/mame/video/m3raster.c
new file mode 100644
index 00000000000..e41b1e1a635
--- /dev/null
+++ b/src/mame/video/m3raster.c
@@ -0,0 +1,283 @@
+static void draw_scanline_normal(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ const cached_texture *texture = extra->texture;
+ mame_bitmap *destmap = dest;
+ UINT16 *p = BITMAP_ADDR16(destmap, scanline, 0);
+ UINT32 *d = BITMAP_ADDR32(zbuffer, scanline, 0);
+ float ooz = extent->param[0].start;
+ float uoz = extent->param[1].start;
+ float voz = extent->param[2].start;
+ float doozdx = extent->param[0].dpdx;
+ float duozdx = extent->param[1].dpdx;
+ float dvozdx = extent->param[2].dpdx;
+ UINT32 polyi = extra->polygon_intensity;
+ UINT32 umask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1;
+ UINT32 vmask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1;
+ UINT32 width = 6 + texture->width;
+ int x;
+
+ for (x = extent->startx; x < extent->stopx; x++)
+ {
+ UINT32 iz = ooz * 256.0f;
+ if (iz > d[x])
+ {
+ float z = 1.0f / ooz;
+ UINT32 u = uoz * z;
+ UINT32 v = voz * z;
+ UINT32 u1 = (u >> 8) & umask;
+ UINT32 v1 = (v >> 8) & vmask;
+ UINT32 u2 = (u1 + 1) & umask;
+ UINT32 v2 = (v1 + 1) & vmask;
+ UINT32 pix00 = texture->data[(v1 << width) + u1];
+ UINT32 pix01 = texture->data[(v1 << width) + u2];
+ UINT32 pix10 = texture->data[(v2 << width) + u1];
+ UINT32 pix11 = texture->data[(v2 << width) + u2];
+ UINT32 texel = rgba_bilinear_filter(pix00, pix01, pix10, pix11, u, v);
+ UINT32 fr = ((texel & 0x00ff0000) * polyi) >> (8+9);
+ UINT32 fg = ((texel & 0x0000ff00) * polyi) >> (8+6);
+ UINT32 fb = ((texel & 0x000000ff) * polyi) >> (8+3);
+ p[x] = (fr & 0x7c00) | (fg & 0x3e0) | (fb & 0x1f);
+ d[x] = iz;
+ }
+
+ ooz += doozdx;
+ uoz += duozdx;
+ voz += dvozdx;
+ }
+}
+
+static void draw_scanline_trans(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ const cached_texture *texture = extra->texture;
+ mame_bitmap *destmap = dest;
+ UINT16 *p = BITMAP_ADDR16(destmap, scanline, 0);
+ UINT32 *d = BITMAP_ADDR32(zbuffer, scanline, 0);
+ float ooz = extent->param[0].start;
+ float uoz = extent->param[1].start;
+ float voz = extent->param[2].start;
+ float doozdx = extent->param[0].dpdx;
+ float duozdx = extent->param[1].dpdx;
+ float dvozdx = extent->param[2].dpdx;
+ UINT32 polyi = (extra->polygon_intensity * extra->polygon_transparency) >> 5;
+ int desttrans = 32 - extra->polygon_transparency;
+ UINT32 umask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1;
+ UINT32 vmask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1;
+ UINT32 width = 6 + texture->width;
+ int x;
+
+ for (x = extent->startx; x < extent->stopx; x++)
+ {
+ UINT32 iz = ooz * 256.0f;
+ if (iz > d[x])
+ {
+ float z = 1.0f / ooz;
+ UINT32 u = uoz * z;
+ UINT32 v = voz * z;
+ UINT32 u1 = (u >> 8) & umask;
+ UINT32 v1 = (v >> 8) & vmask;
+ UINT32 u2 = (u1 + 1) & umask;
+ UINT32 v2 = (v1 + 1) & vmask;
+ UINT32 pix00 = texture->data[(v1 << width) + u1];
+ UINT32 pix01 = texture->data[(v1 << width) + u2];
+ UINT32 pix10 = texture->data[(v2 << width) + u1];
+ UINT32 pix11 = texture->data[(v2 << width) + u2];
+ UINT32 texel = rgba_bilinear_filter(pix00, pix01, pix10, pix11, u, v);
+ UINT32 fr = ((texel & 0x00ff0000) * polyi) >> (8+9);
+ UINT32 fg = ((texel & 0x0000ff00) * polyi) >> (8+6);
+ UINT32 fb = ((texel & 0x000000ff) * polyi) >> (8+3);
+ UINT16 orig = p[x];
+ fr += ((orig & 0x7c00) * desttrans) >> 5;
+ fg += ((orig & 0x03e0) * desttrans) >> 5;
+ fb += ((orig & 0x001f) * desttrans) >> 5;
+ p[x] = (fr & 0x7c00) | (fg & 0x3e0) | (fb & 0x1f);
+ d[x] = iz;
+ }
+
+ ooz += doozdx;
+ uoz += duozdx;
+ voz += dvozdx;
+ }
+}
+
+
+static void draw_scanline_alpha(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ const cached_texture *texture = extra->texture;
+ mame_bitmap *destmap = dest;
+ UINT16 *p = BITMAP_ADDR16(destmap, scanline, 0);
+ UINT32 *d = BITMAP_ADDR32(zbuffer, scanline, 0);
+ float ooz = extent->param[0].start;
+ float uoz = extent->param[1].start;
+ float voz = extent->param[2].start;
+ float doozdx = extent->param[0].dpdx;
+ float duozdx = extent->param[1].dpdx;
+ float dvozdx = extent->param[2].dpdx;
+ UINT32 polyi = (extra->polygon_intensity * extra->polygon_transparency) >> 5;
+ int desttrans = 32 - extra->polygon_transparency;
+ UINT32 umask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1;
+ UINT32 vmask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1;
+ UINT32 width = 6 + texture->width;
+ int x;
+
+ for (x = extent->startx; x < extent->stopx; x++)
+ {
+ UINT32 iz = ooz * 256.0f;
+ if (iz > d[x])
+ {
+ float z = 1.0f / ooz;
+ UINT32 u = uoz * z;
+ UINT32 v = voz * z;
+ UINT32 u1 = (u >> 8) & umask;
+ UINT32 v1 = (v >> 8) & vmask;
+ UINT32 u2 = (u1 + 1) & umask;
+ UINT32 v2 = (v1 + 1) & vmask;
+ UINT32 pix00 = texture->data[(v1 << width) + u1];
+ UINT32 pix01 = texture->data[(v1 << width) + u2];
+ UINT32 pix10 = texture->data[(v2 << width) + u1];
+ UINT32 pix11 = texture->data[(v2 << width) + u2];
+ UINT32 texel = rgba_bilinear_filter(pix00, pix01, pix10, pix11, u, v);
+ UINT32 fa = texel >> 24;
+ UINT32 combined = ((fa + 1) * polyi) >> 8;
+ UINT32 fr = ((texel & 0x00ff0000) * combined) >> (8+9);
+ UINT32 fg = ((texel & 0x0000ff00) * combined) >> (8+6);
+ UINT32 fb = ((texel & 0x000000ff) * combined) >> (8+3);
+ UINT16 orig = p[x];
+ combined = ((255 - fa) * desttrans) >> 8;
+ fr += ((orig & 0x7c00) * combined) >> 5;
+ fg += ((orig & 0x03e0) * combined) >> 5;
+ fb += ((orig & 0x001f) * combined) >> 5;
+ p[x] = (fr & 0x7c00) | (fg & 0x3e0) | (fb & 0x1f);
+ d[x] = iz;
+ }
+
+ ooz += doozdx;
+ uoz += duozdx;
+ voz += dvozdx;
+ }
+}
+
+
+static void draw_scanline_alpha_test(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ const cached_texture *texture = extra->texture;
+ mame_bitmap *destmap = dest;
+ UINT16 *p = BITMAP_ADDR16(destmap, scanline, 0);
+ UINT32 *d = BITMAP_ADDR32(zbuffer, scanline, 0);
+ float ooz = extent->param[0].start;
+ float uoz = extent->param[1].start;
+ float voz = extent->param[2].start;
+ float doozdx = extent->param[0].dpdx;
+ float duozdx = extent->param[1].dpdx;
+ float dvozdx = extent->param[2].dpdx;
+ UINT32 polyi = (extra->polygon_intensity * extra->polygon_transparency) >> 5;
+ int desttrans = 32 - extra->polygon_transparency;
+ UINT32 umask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1;
+ UINT32 vmask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1;
+ UINT32 width = 6 + texture->width;
+ int x;
+
+ for (x = extent->startx; x < extent->stopx; x++)
+ {
+ UINT32 iz = ooz * 256.0f;
+ if (iz > d[x])
+ {
+ float z = 1.0f / ooz;
+ UINT32 u = uoz * z;
+ UINT32 v = voz * z;
+ UINT32 u1 = (u >> 8) & umask;
+ UINT32 v1 = (v >> 8) & vmask;
+ UINT32 u2 = (u1 + 1) & umask;
+ UINT32 v2 = (v1 + 1) & vmask;
+ UINT32 pix00 = texture->data[(v1 << width) + u1];
+ UINT32 pix01 = texture->data[(v1 << width) + u2];
+ UINT32 pix10 = texture->data[(v2 << width) + u1];
+ UINT32 pix11 = texture->data[(v2 << width) + u2];
+ UINT32 texel = rgba_bilinear_filter(pix00, pix01, pix10, pix11, u, v);
+ UINT32 fa = texel >> 24;
+ if (fa >= 0xf8)
+ {
+ UINT32 combined = ((fa + 1) * polyi) >> 8;
+ UINT32 fr = ((texel & 0x00ff0000) * combined) >> (8+9);
+ UINT32 fg = ((texel & 0x0000ff00) * combined) >> (8+6);
+ UINT32 fb = ((texel & 0x000000ff) * combined) >> (8+3);
+ UINT16 orig = p[x];
+ combined = ((255 - fa) * desttrans) >> 8;
+ fr += ((orig & 0x7c00) * combined) >> 5;
+ fg += ((orig & 0x03e0) * combined) >> 5;
+ fb += ((orig & 0x001f) * combined) >> 5;
+ p[x] = (fr & 0x7c00) | (fg & 0x3e0) | (fb & 0x1f);
+ d[x] = iz;
+ }
+ }
+
+ ooz += doozdx;
+ uoz += duozdx;
+ voz += dvozdx;
+ }
+}
+
+static void draw_scanline_color(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ mame_bitmap *destmap = dest;
+ UINT16 *p = BITMAP_ADDR16(destmap, scanline, 0);
+ UINT32 *d = BITMAP_ADDR32(zbuffer, scanline, 0);
+ float ooz = extent->param[0].start;
+ float doozdx = extent->param[0].dpdx;
+ int fr = extra->color & 0x7c00;
+ int fg = extra->color & 0x03e0;
+ int fb = extra->color & 0x001f;
+ int x;
+
+ // apply intensity
+ fr = (fr * extra->polygon_intensity) >> 8;
+ fg = (fg * extra->polygon_intensity) >> 8;
+ fb = (fb * extra->polygon_intensity) >> 8;
+
+ /* simple case: no transluceny */
+ if (extra->polygon_transparency >= 32)
+ {
+ UINT32 color = (fr & 0x7c00) | (fg & 0x03e0) | (fb & 0x1f);
+ for (x = extent->startx; x < extent->stopx; x++)
+ {
+ UINT32 iz = ooz * 256.0f;
+ if (iz > d[x])
+ {
+ p[x] = color;
+ d[x] = iz;
+ }
+ ooz += doozdx;
+ }
+ }
+
+ /* translucency */
+ else
+ {
+ int polytrans = extra->polygon_transparency;
+
+ fr = (fr * polytrans) >> 5;
+ fg = (fg * polytrans) >> 5;
+ fb = (fb * polytrans) >> 5;
+ polytrans = 32 - polytrans;
+
+ for (x = extent->startx; x < extent->stopx; x++)
+ {
+ UINT32 iz = ooz * 256.0f;
+ if (iz > d[x])
+ {
+ UINT16 orig = p[x];
+ int r = fr + (((orig & 0x7c00) * polytrans) >> 5);
+ int g = fg + (((orig & 0x03e0) * polytrans) >> 5);
+ int b = fb + (((orig & 0x001f) * polytrans) >> 5);
+
+ p[x] = (r & 0x7c00) | (g & 0x3e0) | (b & 0x1f);
+ d[x] = iz;
+ }
+ ooz += doozdx;
+ }
+ }
+}
diff --git a/src/mame/video/m62.c b/src/mame/video/m62.c
new file mode 100644
index 00000000000..04e2ef7fbf1
--- /dev/null
+++ b/src/mame/video/m62.c
@@ -0,0 +1,893 @@
+/***************************************************************************
+
+Video Hardware for Irem Games:
+Battle Road, Lode Runner, Kid Niki, Spelunker
+
+Tile/sprite priority system (for the Kung Fu Master M62 board):
+- Tiles with color code >= N (where N is set by jumpers) have priority over
+ sprites. Only bits 1-4 of the color code are used, bit 0 is ignored.
+
+- Two jumpers select whether bit 5 of the sprite color code should be used
+ to index the high address pin of the color PROMs, or to select high
+ priority over tiles (or both, but is this used by any game?)
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/resnet.h"
+
+UINT8 *m62_tileram;
+UINT8 *m62_textram;
+UINT8 *horizon_scrollram;
+
+static tilemap *m62_background;
+static tilemap *m62_foreground;
+static UINT8 flipscreen;
+static const UINT8 *sprite_height_prom;
+static INT32 m62_background_hscroll;
+static INT32 m62_background_vscroll;
+
+static UINT8 *irem_textram;
+static size_t irem_textram_size;
+
+static UINT8 kidniki_background_bank;
+static INT32 kidniki_text_vscroll;
+
+static INT32 spelunkr_palbank;
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Kung Fu Master has a six 256x4 palette PROMs (one per gun; three for
+ characters, three for sprites).
+ I don't know the exact values of the resistors between the RAM and the
+ RGB output. I assumed these values (the same as Commando)
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+
+
+static const res_net_info m62_tile_net_info =
+{
+ RES_NET_VCC_5V | RES_NET_VIN_TTL_OUT,
+ {
+ { RES_NET_AMP_NONE, 0, 0, 4, { 22000, 1000, 470, 220 } },
+ { RES_NET_AMP_NONE, 0, 0, 4, { 22000, 1000, 470, 220 } },
+ { RES_NET_AMP_NONE, 0, 0, 4, { 22000, 1000, 470, 220 } }
+ }
+};
+
+
+static const res_net_info m62_sprite_net_info =
+{
+ RES_NET_VCC_5V | RES_NET_VIN_TTL_OUT,
+ {
+ { RES_NET_AMP_NONE, 0, 470, 4, { 22000, 1000, 470, 220 } },
+ { RES_NET_AMP_NONE, 0, 470, 4, { 22000, 1000, 470, 220 } },
+ { RES_NET_AMP_NONE, 0, 470, 4, { 22000, 1000, 470, 220 } }
+ }
+};
+
+
+/* this is a complete guess */
+static const res_net_info battroad_char_net_info =
+{
+ RES_NET_VCC_5V | RES_NET_VIN_TTL_OUT,
+ {
+ { RES_NET_AMP_NONE, 0, 0, 3, { 1000, 470, 220 } },
+ { RES_NET_AMP_NONE, 0, 0, 3, { 1000, 470, 220 } },
+ { RES_NET_AMP_NONE, 0, 0, 2, { 470, 220 } }
+ }
+};
+
+
+
+static const res_net_decode_info m62_tile_decode_info =
+{
+ 1, /* single PROM per color */
+ 0x000, 0x0ff, /* start/end */
+ /* R G B */
+ { 0x000, 0x200, 0x400 }, /* offsets */
+ { 0, 0, 0 }, /* shifts */
+ { 0x0f, 0x0f, 0x0f } /* masks */
+};
+
+
+static const res_net_decode_info m62_sprite_decode_info =
+{
+ 1, /* single PROM per color */
+ 0x000, 0x0ff, /* start/end */
+ /* R G B */
+ { 0x100, 0x300, 0x500 }, /* offsets */
+ { 0, 0, 0 }, /* shifts */
+ { 0x0f, 0x0f, 0x0f } /* masks */
+};
+
+
+static const res_net_decode_info lotlot_tile_decode_info =
+{
+ 1, /* single PROM per color */
+ 0x000, 0x17f, /* start/end */
+ /* R G B */
+ { 0x000, 0x300, 0x600 }, /* offsets */
+ { 0, 0, 0 }, /* shifts */
+ { 0x0f, 0x0f, 0x0f } /* masks */
+};
+
+
+static const res_net_decode_info lotlot_sprite_decode_info =
+{
+ 1, /* single PROM per color */
+ 0x000, 0x17f, /* start/end */
+ /* R G B */
+ { 0x180, 0x480, 0x780 }, /* offsets */
+ { 0, 0, 0 }, /* shifts */
+ { 0x0f, 0x0f, 0x0f } /* masks */
+};
+
+
+static const res_net_decode_info battroad_char_decode_info =
+{
+ 1, /* single PROM per color */
+ 0x000, 0x01f, /* start/end */
+ /* R G B */
+ { 0x600, 0x600, 0x600 }, /* offsets */
+ { 0, 3, 6 }, /* shifts */
+ { 0x07, 0x07, 0x03 } /* masks */
+};
+
+
+static const res_net_decode_info spelunk2_tile_decode_info =
+{
+ 1, /* single PROM per color */
+ 0x000, 0x1ff, /* start/end */
+ /* R G B */
+ { 0x000, 0x000, 0x200 }, /* offsets */
+ { 0, 4, 0 }, /* shifts */
+ { 0x0f, 0x0f, 0x0f } /* masks */
+};
+
+
+static const res_net_decode_info spelunk2_sprite_decode_info =
+{
+ 1, /* single PROM per color */
+ 0x000, 0x0ff, /* start/end */
+ /* R G B */
+ { 0x400, 0x500, 0x600 }, /* offsets */
+ { 0, 0, 0 }, /* shifts */
+ { 0x0f, 0x0f, 0x0f } /* masks */
+};
+
+
+PALETTE_INIT( m62 )
+{
+ rgb_t *rgb;
+
+ rgb = compute_res_net_all(color_prom, &m62_tile_decode_info, &m62_tile_net_info);
+ palette_set_colors(machine, 0x000, rgb, 0x100);
+ free(rgb);
+
+ rgb = compute_res_net_all(color_prom, &m62_sprite_decode_info, &m62_sprite_net_info);
+ palette_set_colors(machine, 0x100, rgb, 0x100);
+ free(rgb);
+
+ palette_normalize_range(machine->palette, 0x000, 0x1ff, 0x00, 0xff);
+
+ /* we'll need this at run time */
+ sprite_height_prom = color_prom + 0x600;
+}
+
+
+PALETTE_INIT( lotlot )
+{
+ rgb_t *rgb;
+
+ rgb = compute_res_net_all(color_prom, &lotlot_tile_decode_info, &m62_tile_net_info);
+ palette_set_colors(machine, 0x000, rgb, 0x180);
+ free(rgb);
+
+ rgb = compute_res_net_all(color_prom, &lotlot_sprite_decode_info, &m62_sprite_net_info);
+ palette_set_colors(machine, 0x180, rgb, 0x180);
+ free(rgb);
+
+ palette_normalize_range(machine->palette, 0x000, 0x2ff, 0x00, 0xff);
+
+ /* we'll need this at run time */
+ sprite_height_prom = color_prom + 0x900;
+}
+
+
+PALETTE_INIT( battroad )
+{
+ rgb_t *rgb;
+
+ rgb = compute_res_net_all(color_prom, &m62_tile_decode_info, &m62_tile_net_info);
+ palette_set_colors(machine, 0x000, rgb, 0x100);
+ free(rgb);
+
+ rgb = compute_res_net_all(color_prom, &m62_sprite_decode_info, &m62_sprite_net_info);
+ palette_set_colors(machine, 0x100, rgb, 0x100);
+ free(rgb);
+
+ rgb = compute_res_net_all(color_prom, &battroad_char_decode_info, &m62_tile_net_info);
+ palette_set_colors(machine, 0x200, rgb, 0x020);
+ free(rgb);
+
+ palette_normalize_range(machine->palette, 0x000, 0x21f, 0x00, 0xff);
+
+ sprite_height_prom = color_prom + 0x620; /* we'll need this at run time */
+}
+
+
+PALETTE_INIT( spelunk2 )
+{
+ rgb_t *rgb;
+
+ rgb = compute_res_net_all(color_prom, &spelunk2_tile_decode_info, &m62_tile_net_info);
+ palette_set_colors(machine, 0x000, rgb, 0x200);
+ free(rgb);
+
+ rgb = compute_res_net_all(color_prom, &spelunk2_sprite_decode_info, &m62_sprite_net_info);
+ palette_set_colors(machine, 0x200, rgb, 0x100);
+ free(rgb);
+
+ palette_normalize_range(machine->palette, 0x000, 0x2ff, 0x00, 0xff);
+
+ /* we'll need this at run time */
+ sprite_height_prom = color_prom + 0x700;
+}
+
+
+
+static void register_savestate(void)
+{
+ state_save_register_global(flipscreen);
+ state_save_register_global(kidniki_background_bank);
+ state_save_register_global(m62_background_hscroll);
+ state_save_register_global(m62_background_vscroll);
+ state_save_register_global(kidniki_text_vscroll);
+ state_save_register_global(spelunkr_palbank);
+ state_save_register_global_pointer(irem_textram, irem_textram_size);
+}
+
+WRITE8_HANDLER( m62_flipscreen_w )
+{
+ /* screen flip is handled both by software and hardware */
+ data ^= ~readinputport(4) & 1;
+
+ flipscreen = data & 0x01;
+ if (flipscreen)
+ tilemap_set_flip(ALL_TILEMAPS, TILEMAP_FLIPX | TILEMAP_FLIPY);
+ else
+ tilemap_set_flip(ALL_TILEMAPS, 0);
+
+ coin_counter_w(0,data & 2);
+ coin_counter_w(1,data & 4);
+}
+
+WRITE8_HANDLER( m62_hscroll_low_w )
+{
+ m62_background_hscroll = ( m62_background_hscroll & 0xff00 ) | data;
+}
+
+WRITE8_HANDLER( m62_hscroll_high_w )
+{
+ m62_background_hscroll = ( m62_background_hscroll & 0xff ) | ( data << 8 );
+}
+
+WRITE8_HANDLER( m62_vscroll_low_w )
+{
+ m62_background_vscroll = ( m62_background_vscroll & 0xff00 ) | data;
+}
+
+WRITE8_HANDLER( m62_vscroll_high_w )
+{
+ m62_background_vscroll = ( m62_background_vscroll & 0xff ) | ( data << 8 );
+}
+
+WRITE8_HANDLER( m62_tileram_w )
+{
+ m62_tileram[ offset ] = data;
+ tilemap_mark_tile_dirty( m62_background, offset >> 1 );
+}
+
+WRITE8_HANDLER( m62_textram_w )
+{
+ m62_textram[ offset ] = data;
+ tilemap_mark_tile_dirty( m62_foreground, offset >> 1 );
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int colormask, int prioritymask, int priority)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 8)
+ {
+ int i,incr,code,col,flipx,flipy,sx,sy;
+
+ if( ( spriteram[offs] & prioritymask ) == priority )
+ {
+ code = spriteram[offs+4] + ((spriteram[offs+5] & 0x07) << 8);
+ col = spriteram[offs+0] & colormask;
+ sx = 256 * (spriteram[offs+7] & 1) + spriteram[offs+6],
+ sy = 256+128-15 - (256 * (spriteram[offs+3] & 1) + spriteram[offs+2]),
+ flipx = spriteram[offs+5] & 0x40;
+ flipy = spriteram[offs+5] & 0x80;
+
+ i = sprite_height_prom[(code >> 5) & 0x1f];
+ if (i == 1) /* double height */
+ {
+ code &= ~1;
+ sy -= 16;
+ }
+ else if (i == 2) /* quadruple height */
+ {
+ i = 3;
+ code &= ~3;
+ sy -= 3*16;
+ }
+
+ if (flipscreen)
+ {
+ sx = 496 - sx;
+ sy = 242 - i*16 - sy; /* sprites are slightly misplaced by the hardware */
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if (flipy)
+ {
+ incr = -1;
+ code += i;
+ }
+ else incr = 1;
+
+ do
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ code + i * incr,col,
+ flipx,flipy,
+ sx,sy + 16 * i,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ i--;
+ } while (i >= 0);
+ }
+ }
+}
+
+static void m62_start( tile_get_info_callback tile_get_info, int rows, int cols, int x1, int y1, int x2, int y2 )
+{
+ m62_background = tilemap_create( tile_get_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, x1, y1, x2, y2 );
+
+ m62_background_hscroll = 0;
+ m62_background_vscroll = 0;
+
+ register_savestate();
+
+ if( rows != 0 )
+ {
+ tilemap_set_scroll_rows( m62_background, rows );
+ }
+ if( cols != 0 )
+ {
+ tilemap_set_scroll_cols( m62_background, cols );
+ }
+}
+
+static void m62_textlayer( tile_get_info_callback tile_get_info, int rows, int cols, int x1, int y1, int x2, int y2 )
+{
+ m62_foreground = tilemap_create( tile_get_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, x1, y1, x2, y2 );
+
+ if( rows != 0 )
+ {
+ tilemap_set_scroll_rows( m62_foreground, rows );
+ }
+ if( cols != 0 )
+ {
+ tilemap_set_scroll_cols( m62_foreground, cols );
+ }
+}
+
+WRITE8_HANDLER( kungfum_tileram_w )
+{
+ m62_tileram[ offset ] = data;
+ tilemap_mark_tile_dirty( m62_background, offset & 0x7ff );
+}
+
+static TILE_GET_INFO( get_kungfum_bg_tile_info )
+{
+ int code;
+ int color;
+ int flags;
+ code = m62_tileram[ tile_index ];
+ color = m62_tileram[ tile_index + 0x800 ];
+ flags = 0;
+ if( ( color & 0x20 ) )
+ {
+ flags |= TILE_FLIPX;
+ }
+ SET_TILE_INFO( 0, code | ( ( color & 0xc0 ) << 2 ), color & 0x1f, flags );
+
+ /* is the following right? */
+ if( ( tile_index / 64 ) < 6 || ( ( color & 0x1f ) >> 1 ) > 0x0c )
+ {
+ tileinfo->category = 1;
+ }
+ else
+ {
+ tileinfo->category = 0;
+ }
+}
+
+VIDEO_UPDATE( kungfum )
+{
+ int i;
+ for( i = 0; i < 6; i++ )
+ {
+ tilemap_set_scrollx( m62_background, i, 0 );
+ }
+ for( i = 6; i < 32; i++ )
+ {
+ tilemap_set_scrollx( m62_background, i, m62_background_hscroll );
+ }
+ tilemap_draw( bitmap, cliprect, m62_background, 0, 0 );
+ draw_sprites( machine, bitmap, cliprect, 0x1f, 0x00, 0x00 );
+ tilemap_draw( bitmap, cliprect, m62_background, 1, 0 );
+ return 0;
+}
+
+VIDEO_START( kungfum )
+{
+ m62_start( get_kungfum_bg_tile_info, 32, 0, 8, 8, 64, 32 );
+}
+
+
+static TILE_GET_INFO( get_ldrun_bg_tile_info )
+{
+ int code;
+ int color;
+ int flags;
+ code = m62_tileram[ tile_index << 1 ];
+ color = m62_tileram[ ( tile_index << 1 ) | 1 ];
+ flags = 0;
+ if( ( color & 0x20 ) )
+ {
+ flags |= TILE_FLIPX;
+ }
+ SET_TILE_INFO( 0, code | ( ( color & 0xc0 ) << 2 ), color & 0x1f, flags );
+ if( ( ( color & 0x1f ) >> 1 ) >= 0x0c )
+ {
+ tileinfo->category = 1;
+ }
+ else
+ {
+ tileinfo->category = 0;
+ }
+}
+
+VIDEO_UPDATE( ldrun )
+{
+ tilemap_set_scrollx( m62_background, 0, m62_background_hscroll );
+ tilemap_set_scrolly( m62_background, 0, m62_background_vscroll );
+
+ tilemap_draw( bitmap, cliprect, m62_background, 0, 0 );
+ draw_sprites( machine, bitmap, cliprect, 0x0f, 0x10, 0x00 );
+ tilemap_draw( bitmap, cliprect, m62_background, 1, 0 );
+ draw_sprites( machine, bitmap, cliprect, 0x0f, 0x10, 0x10 );
+ return 0;
+}
+
+VIDEO_START( ldrun )
+{
+ m62_start( get_ldrun_bg_tile_info, 1, 1, 8, 8, 64, 32 );
+}
+
+static TILE_GET_INFO( get_ldrun2_bg_tile_info )
+{
+ int code;
+ int color;
+ int flags;
+ code = m62_tileram[ tile_index << 1 ];
+ color = m62_tileram[ ( tile_index << 1 ) | 1 ];
+ flags = 0;
+ if( ( color & 0x20 ) )
+ {
+ flags |= TILE_FLIPX;
+ }
+ SET_TILE_INFO( 0, code | ( ( color & 0xc0 ) << 2 ), color & 0x1f, flags );
+ if( ( ( color & 0x1f ) >> 1 ) >= 0x04 )
+ {
+ tileinfo->category = 1;
+ }
+ else
+ {
+ tileinfo->category = 0;
+ }
+}
+
+VIDEO_START( ldrun2 )
+{
+ m62_start( get_ldrun2_bg_tile_info, 1, 1, 8, 8, 64, 32 );
+}
+
+static TILE_GET_INFO( get_battroad_bg_tile_info )
+{
+ int code;
+ int color;
+ int flags;
+ code = m62_tileram[ tile_index << 1 ];
+ color = m62_tileram[ ( tile_index << 1 ) | 1 ];
+ flags = 0;
+ if( ( color & 0x20 ) )
+ {
+ flags |= TILE_FLIPX;
+ }
+ SET_TILE_INFO( 0, code | ( ( color & 0x40 ) << 3 ) | ( ( color & 0x10 ) << 4 ), color & 0x0f, flags );
+ if( ( ( color & 0x1f ) >> 1 ) >= 0x04 )
+ {
+ tileinfo->category = 1;
+ }
+ else
+ {
+ tileinfo->category = 0;
+ }
+}
+
+static TILE_GET_INFO( get_battroad_fg_tile_info )
+{
+ int code;
+ int color;
+ code = m62_textram[ tile_index << 1 ];
+ color = m62_textram[ ( tile_index << 1 ) | 1 ];
+ SET_TILE_INFO( 2, code | ( ( color & 0x40 ) << 3 ) | ( ( color & 0x10 ) << 4 ), color & 0x0f, 0 );
+}
+
+VIDEO_UPDATE( battroad )
+{
+ tilemap_set_scrollx( m62_background, 0, m62_background_hscroll );
+ tilemap_set_scrolly( m62_background, 0, m62_background_vscroll );
+ tilemap_set_scrollx( m62_foreground, 0, 128 );
+ tilemap_set_scrolly( m62_foreground, 0, 0 );
+ tilemap_set_transparent_pen( m62_foreground, 0 );
+
+ tilemap_draw( bitmap, cliprect, m62_background, 0, 0 );
+ draw_sprites( machine, bitmap, cliprect, 0x0f, 0x10, 0x00 );
+ tilemap_draw( bitmap, cliprect, m62_background, 1, 0 );
+ draw_sprites( machine, bitmap, cliprect, 0x0f, 0x10, 0x10 );
+ tilemap_draw( bitmap, cliprect, m62_foreground, 0, 0 );
+ return 0;
+}
+
+VIDEO_START( battroad )
+{
+ m62_start( get_battroad_bg_tile_info, 1, 1, 8, 8, 64, 32 );
+ m62_textlayer( get_battroad_fg_tile_info, 1, 1, 8, 8, 32, 32 );
+}
+
+
+/* almost identical but scrolling background, more characters, */
+/* no char x flip, and more sprites */
+static TILE_GET_INFO( get_ldrun4_bg_tile_info )
+{
+ int code;
+ int color;
+ code = m62_tileram[ tile_index << 1 ];
+ color = m62_tileram[ ( tile_index << 1 ) | 1 ];
+ SET_TILE_INFO( 0, code | ( ( color & 0xc0 ) << 2 ) | ( ( color & 0x20 ) << 5 ), color & 0x1f, 0 );
+}
+
+VIDEO_UPDATE( ldrun4 )
+{
+ tilemap_set_scrollx( m62_background, 0, m62_background_hscroll );
+
+ tilemap_draw( bitmap, cliprect, m62_background, 0, 0 );
+ draw_sprites( machine, bitmap, cliprect, 0x1f, 0x00, 0x00 );
+ return 0;
+}
+
+VIDEO_START( ldrun4 )
+{
+ m62_start( get_ldrun4_bg_tile_info, 1, 0, 8, 8, 64, 32 );
+}
+
+
+static TILE_GET_INFO( get_lotlot_bg_tile_info )
+{
+ int code;
+ int color;
+ int flags;
+ code = m62_tileram[ tile_index << 1 ];
+ color = m62_tileram[ ( tile_index << 1 ) | 1 ];
+ flags = 0;
+ if( ( color & 0x20 ) )
+ {
+ flags |= TILE_FLIPX;
+ }
+ SET_TILE_INFO( 0, code | ( ( color & 0xc0 ) << 2 ), color & 0x1f, flags );
+}
+
+static TILE_GET_INFO( get_lotlot_fg_tile_info )
+{
+ int code;
+ int color;
+ code = m62_textram[ tile_index << 1 ];
+ color = m62_textram[ ( tile_index << 1 ) | 1 ];
+ SET_TILE_INFO( 2, code | ( ( color & 0xc0 ) << 2 ), color & 0x1f, 0 );
+}
+
+VIDEO_UPDATE( lotlot )
+{
+ tilemap_set_scrollx( m62_background, 0, m62_background_hscroll - 64 );
+ tilemap_set_scrolly( m62_background, 0, m62_background_vscroll + 32 );
+ tilemap_set_scrollx( m62_foreground, 0, -64 );
+ tilemap_set_scrolly( m62_foreground, 0, 32 );
+ tilemap_set_transparent_pen( m62_foreground, 0 );
+
+ tilemap_draw( bitmap, cliprect, m62_background, 0, 0 );
+ tilemap_draw( bitmap, cliprect, m62_foreground, 0, 0 );
+ draw_sprites( machine, bitmap, cliprect, 0x1f, 0x00, 0x00 );
+ return 0;
+}
+
+VIDEO_START( lotlot )
+{
+ m62_start( get_lotlot_bg_tile_info, 1, 1, 12, 10, 32, 64 );
+ m62_textlayer( get_lotlot_fg_tile_info, 1, 1, 12, 10, 32, 64 );
+}
+
+
+WRITE8_HANDLER( kidniki_text_vscroll_low_w )
+{
+ kidniki_text_vscroll = (kidniki_text_vscroll & 0xff00) | data;
+}
+
+WRITE8_HANDLER( kidniki_text_vscroll_high_w )
+{
+ kidniki_text_vscroll = (kidniki_text_vscroll & 0xff) | (data << 8);
+}
+
+WRITE8_HANDLER( kidniki_background_bank_w )
+{
+ if (kidniki_background_bank != (data & 1))
+ {
+ kidniki_background_bank = data & 1;
+ tilemap_mark_all_tiles_dirty(m62_background);
+ }
+}
+
+static TILE_GET_INFO( get_kidniki_bg_tile_info )
+{
+ int code;
+ int color;
+ code = m62_tileram[ tile_index << 1 ];
+ color = m62_tileram[ ( tile_index << 1 ) | 1 ];
+ SET_TILE_INFO( 0, code | ( ( color & 0xe0 ) << 3 ) | ( kidniki_background_bank << 11 ), color & 0x1f, 0);
+ tileinfo->group = ( ( color & 0xe0 ) == 0xe0 ) ? 1 : 0;
+}
+
+static TILE_GET_INFO( get_kidniki_fg_tile_info )
+{
+ int code;
+ int color;
+ code = m62_textram[ tile_index << 1 ];
+ color = m62_textram[ ( tile_index << 1 ) | 1 ];
+ SET_TILE_INFO( 2, code | ( ( color & 0xc0 ) << 2 ), color & 0x1f, 0 );
+}
+
+VIDEO_UPDATE( kidniki )
+{
+ tilemap_set_scrollx( m62_background, 0, m62_background_hscroll );
+ tilemap_set_scrollx( m62_foreground, 0, -64 );
+ tilemap_set_scrolly( m62_foreground, 0, kidniki_text_vscroll + 128 );
+ tilemap_set_transparent_pen( m62_foreground, 0 );
+
+ tilemap_draw( bitmap, cliprect, m62_background, TILEMAP_DRAW_LAYER1, 0 );
+ draw_sprites( machine, bitmap, cliprect, 0x1f, 0x00, 0x00 );
+ tilemap_draw( bitmap, cliprect, m62_background, TILEMAP_DRAW_LAYER0, 0 );
+ tilemap_draw( bitmap, cliprect, m62_foreground, 0, 0 );
+ return 0;
+}
+
+VIDEO_START( kidniki )
+{
+ m62_background = tilemap_create( get_kidniki_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32 );
+
+ m62_background_hscroll = 0;
+ m62_background_vscroll = 0;
+
+ tilemap_set_transmask(m62_background,0,0xffff,0x0000); /* split type 0 is totally transparent in front half */
+ tilemap_set_transmask(m62_background,1,0x0001,0xfffe); /* split type 1 has pen 0 transparent in front half */
+
+ register_savestate();
+
+ m62_textlayer( get_kidniki_fg_tile_info, 1, 1, 12, 8, 32, 64 );
+}
+
+
+WRITE8_HANDLER( spelunkr_palbank_w )
+{
+ if (spelunkr_palbank != (data & 0x01))
+ {
+ spelunkr_palbank = data & 0x01;
+ tilemap_mark_all_tiles_dirty(m62_background);
+ tilemap_mark_all_tiles_dirty(m62_foreground);
+ }
+}
+
+static TILE_GET_INFO( get_spelunkr_bg_tile_info )
+{
+ int code;
+ int color;
+ code = m62_tileram[ tile_index << 1 ];
+ color = m62_tileram[ ( tile_index << 1 ) | 1 ];
+ SET_TILE_INFO( 0, code | ( ( color & 0x10 ) << 4 ) | ( ( color & 0x20 ) << 6 ) | ( ( color & 0xc0 ) << 3 ), ( color & 0x0f ) | ( spelunkr_palbank << 4 ), 0 );
+}
+
+static TILE_GET_INFO( get_spelunkr_fg_tile_info )
+{
+ int code;
+ int color;
+ code = m62_textram[ tile_index << 1 ];
+ color = m62_textram[ ( tile_index << 1 ) | 1 ];
+if (color&0xe0) popmessage("fg tilemap %x %x",tile_index,color&0xe0);
+ SET_TILE_INFO( 2, code | ( ( color & 0x10 ) << 4 ), ( color & 0x0f ) | ( spelunkr_palbank << 4 ), 0 );
+}
+
+VIDEO_UPDATE( spelunkr )
+{
+ tilemap_set_scrollx( m62_background, 0, m62_background_hscroll );
+ tilemap_set_scrolly( m62_background, 0, m62_background_vscroll + 128 );
+ tilemap_set_scrollx( m62_foreground, 0, -64 );
+ tilemap_set_scrolly( m62_foreground, 0, 0 );
+ tilemap_set_transparent_pen( m62_foreground, 0 );
+
+ tilemap_draw( bitmap, cliprect, m62_background, 0, 0 );
+ draw_sprites( machine, bitmap, cliprect, 0x1f, 0x00, 0x00 );
+ tilemap_draw( bitmap, cliprect, m62_foreground, 0, 0 );
+ return 0;
+}
+
+VIDEO_START( spelunkr )
+{
+ m62_start( get_spelunkr_bg_tile_info, 1, 1, 8, 8, 64, 64 );
+ m62_textlayer( get_spelunkr_fg_tile_info, 1, 1, 12, 8, 32, 32 );
+}
+
+
+WRITE8_HANDLER( spelunk2_gfxport_w )
+{
+ m62_hscroll_high_w(0,(data&2)>>1);
+ m62_vscroll_high_w(0,(data&1));
+ if (spelunkr_palbank != ((data & 0x0c) >> 2))
+ {
+ spelunkr_palbank = (data & 0x0c) >> 2;
+ tilemap_mark_all_tiles_dirty(m62_background);
+ tilemap_mark_all_tiles_dirty(m62_foreground);
+ }
+}
+
+static TILE_GET_INFO( get_spelunk2_bg_tile_info )
+{
+ int code;
+ int color;
+ code = m62_tileram[ tile_index << 1 ];
+ color = m62_tileram[ ( tile_index << 1 ) | 1 ];
+ SET_TILE_INFO( 0, code | ( ( color & 0xf0 ) << 4 ), ( color & 0x0f ) | ( spelunkr_palbank << 4 ), 0 );
+}
+
+VIDEO_UPDATE( spelunk2 )
+{
+ tilemap_set_scrollx( m62_background, 0, m62_background_hscroll - 1);
+ tilemap_set_scrolly( m62_background, 0, m62_background_vscroll + 128 );
+ tilemap_set_scrollx( m62_foreground, 0, -65 );
+ tilemap_set_scrolly( m62_foreground, 0, 0 );
+ tilemap_set_transparent_pen( m62_foreground, 0 );
+
+ tilemap_draw( bitmap, cliprect, m62_background, 0, 0 );
+ draw_sprites( machine, bitmap, cliprect, 0x1f, 0x00, 0x00 );
+ tilemap_draw( bitmap, cliprect, m62_foreground, 0, 0 );
+ return 0;
+}
+
+VIDEO_START( spelunk2 )
+{
+ m62_start( get_spelunk2_bg_tile_info, 1, 1, 8, 8, 64, 64 );
+ m62_textlayer( get_spelunkr_fg_tile_info, 1, 1, 12, 8, 32, 32 );
+}
+
+
+static TILE_GET_INFO( get_youjyudn_bg_tile_info )
+{
+ int code;
+ int color;
+ code = m62_tileram[ tile_index << 1 ];
+ color = m62_tileram[ ( tile_index << 1 ) | 1 ];
+ SET_TILE_INFO( 0, code | ( ( color & 0x60 ) << 3 ), color & 0x1f, 0 );
+ if( ( ( color & 0x1f ) >> 1 ) >= 0x08 )
+ {
+ tileinfo->category = 1;
+ }
+ else
+ {
+ tileinfo->category = 0;
+ }
+}
+
+static TILE_GET_INFO( get_youjyudn_fg_tile_info )
+{
+ int code;
+ int color;
+ code = m62_textram[ tile_index << 1 ];
+ color = m62_textram[ ( tile_index << 1 ) | 1 ];
+ SET_TILE_INFO( 2, code | ( ( color & 0xc0 ) << 2 ), ( color & 0x0f ), 0 );
+}
+
+VIDEO_UPDATE( youjyudn )
+{
+ tilemap_set_scrollx( m62_background, 0, m62_background_hscroll );
+ tilemap_set_scrollx( m62_foreground, 0, -64 );
+ tilemap_set_scrolly( m62_foreground, 0, 0 );
+ tilemap_set_transparent_pen( m62_foreground, 0 );
+
+ tilemap_draw( bitmap, cliprect, m62_background, 0, 0 );
+ draw_sprites( machine, bitmap, cliprect, 0x1f, 0x00, 0x00 );
+ tilemap_draw( bitmap, cliprect, m62_background, 1, 0 );
+ tilemap_draw( bitmap, cliprect, m62_foreground, 0, 0 );
+ return 0;
+}
+
+VIDEO_START( youjyudn )
+{
+ m62_start( get_youjyudn_bg_tile_info, 1, 0, 8, 16, 64, 16 );
+ m62_textlayer( get_youjyudn_fg_tile_info, 1, 1, 12, 8, 32, 32 );
+}
+
+
+WRITE8_HANDLER( horizon_scrollram_w )
+{
+ horizon_scrollram[ offset ] = data;
+}
+
+static TILE_GET_INFO( get_horizon_bg_tile_info )
+{
+ int code;
+ int color;
+ code = m62_tileram[ tile_index << 1 ];
+ color = m62_tileram[ ( tile_index << 1 ) | 1 ];
+ SET_TILE_INFO( 0, code | ( ( color & 0xc0 ) << 2 ) | ( ( color & 0x20 ) << 5 ), color & 0x1f, 0 );
+ if( ( ( color & 0x1f ) >> 1 ) >= 0x08 )
+ {
+ tileinfo->category = 1;
+ }
+ else
+ {
+ tileinfo->category = 0;
+ }
+}
+
+VIDEO_UPDATE( horizon )
+{
+ int i;
+ for( i = 0; i < 32; i++ )
+ {
+ tilemap_set_scrollx( m62_background, i, horizon_scrollram[ i << 1 ] | ( horizon_scrollram[ ( i << 1 ) | 1 ] << 8 ) );
+ }
+ tilemap_draw( bitmap, cliprect, m62_background, 0, 0 );
+ draw_sprites( machine, bitmap, cliprect, 0x1f, 0x00, 0x00 );
+ tilemap_draw( bitmap, cliprect, m62_background, 1, 0 );
+ return 0;
+}
+
+VIDEO_START( horizon )
+{
+ m62_start( get_horizon_bg_tile_info, 32, 0, 8, 8, 64, 32 );
+}
diff --git a/src/mame/video/m72.c b/src/mame/video/m72.c
new file mode 100644
index 00000000000..a0d85fb21aa
--- /dev/null
+++ b/src/mame/video/m72.c
@@ -0,0 +1,597 @@
+#include "driver.h"
+#include "audio/m72.h"
+#include "m72.h"
+
+
+
+UINT16 *m72_videoram1,*m72_videoram2,*majtitle_rowscrollram;
+static UINT16 *m72_spriteram;
+static INT32 splitline;
+static tilemap *fg_tilemap,*bg_tilemap;
+static int xadjust;
+static int bgadjust;
+static INT32 scrollx1,scrolly1,scrollx2,scrolly2;
+static INT32 video_off;
+
+static int irqbase;
+
+MACHINE_RESET( m72 )
+{
+ irqbase = 0x20;
+ machine_reset_m72_sound(machine);
+}
+
+MACHINE_RESET( xmultipl )
+{
+ irqbase = 0x08;
+ machine_reset_m72_sound(machine);
+}
+
+MACHINE_RESET( kengo )
+{
+ irqbase = 0x18;
+ machine_reset_m72_sound(machine);
+}
+
+INTERRUPT_GEN( m72_interrupt )
+{
+ int line = 255 - cpu_getiloops();
+
+ if (line == 255) /* vblank */
+ {
+ cpunum_set_input_line_and_vector(0, 0, HOLD_LINE, irqbase+0);
+ }
+ else
+ {
+ if (line != splitline - 128)
+ return;
+
+ video_screen_update_partial(0, line + 128);
+
+ /* this is used to do a raster effect and show the score display at
+ the bottom of the screen or other things. The line where the
+ interrupt happens is programmable (and the interrupt can be triggered
+ multiple times, by changing the interrupt line register in the
+ interrupt handler).
+ */
+ cpunum_set_input_line_and_vector(0, 0, HOLD_LINE, irqbase+2);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+INLINE void m72_get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,const UINT16 *vram,int gfxnum)
+{
+ int code,attr,color,pri;
+
+ tile_index *= 2;
+
+ code = vram[tile_index] & 0xff;
+ attr = vram[tile_index] >> 8;
+ color = vram[tile_index+1] & 0xff;
+
+ if (color & 0x80) pri = 2;
+ else if (color & 0x40) pri = 1;
+ else pri = 0;
+/* color & 0x10 is used in bchopper and hharry, more priority? */
+
+ SET_TILE_INFO(
+ gfxnum,
+ code + ((attr & 0x3f) << 8),
+ color & 0x0f,
+ TILE_FLIPYX((attr & 0xc0) >> 6));
+ tileinfo->group = pri;
+}
+
+INLINE void rtype2_get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,const UINT16 *vram,int gfxnum)
+{
+ int code,attr,color,pri;
+
+ tile_index *= 2;
+
+ code = vram[tile_index];
+ color = vram[tile_index+1] & 0xff;
+ attr = vram[tile_index+1] >> 8;
+
+ if (attr & 0x01) pri = 2;
+ else if (color & 0x80) pri = 1;
+ else pri = 0;
+
+/* (vram[tile_index+2] & 0x10) is used by majtitle on the green, but it's not clear for what */
+/* (vram[tile_index+3] & 0xfe) are used as well */
+
+ SET_TILE_INFO(
+ gfxnum,
+ code,
+ color & 0x0f,
+ TILE_FLIPYX((color & 0x60) >> 5));
+ tileinfo->group = pri;
+}
+
+
+static TILE_GET_INFO( m72_get_bg_tile_info )
+{
+ m72_get_tile_info(machine,tileinfo,tile_index,m72_videoram2,2);
+}
+
+static TILE_GET_INFO( m72_get_fg_tile_info )
+{
+ m72_get_tile_info(machine,tileinfo,tile_index,m72_videoram1,1);
+}
+
+static TILE_GET_INFO( hharry_get_bg_tile_info )
+{
+ m72_get_tile_info(machine,tileinfo,tile_index,m72_videoram2,1);
+}
+
+static TILE_GET_INFO( rtype2_get_bg_tile_info )
+{
+ rtype2_get_tile_info(machine,tileinfo,tile_index,m72_videoram2,1);
+}
+
+static TILE_GET_INFO( rtype2_get_fg_tile_info )
+{
+ rtype2_get_tile_info(machine,tileinfo,tile_index,m72_videoram1,1);
+}
+
+
+static TILEMAP_MAPPER( majtitle_scan_rows )
+{
+ /* logical (col,row) -> memory offset */
+ return row*256 + col;
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+static void register_savestate(void)
+{
+ state_save_register_global(splitline);
+ state_save_register_global(video_off);
+ state_save_register_global(scrollx1);
+ state_save_register_global(scrolly1);
+ state_save_register_global(scrollx2);
+ state_save_register_global(scrolly2);
+ state_save_register_global_pointer(m72_spriteram, spriteram_size);
+}
+
+
+VIDEO_START( m72 )
+{
+ bg_tilemap = tilemap_create(m72_get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ fg_tilemap = tilemap_create(m72_get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ m72_spriteram = auto_malloc(spriteram_size);
+
+ tilemap_set_transmask(fg_tilemap,0,0xffff,0x0001);
+ tilemap_set_transmask(fg_tilemap,1,0x00ff,0xff01);
+ tilemap_set_transmask(fg_tilemap,2,0x0001,0xffff);
+
+ tilemap_set_transmask(bg_tilemap,0,0xffff,0x0000);
+ tilemap_set_transmask(bg_tilemap,1,0x00ff,0xff00);
+ tilemap_set_transmask(bg_tilemap,2,0x0001,0xfffe);
+
+ memset(m72_spriteram,0,spriteram_size);
+
+ xadjust = 0;
+ bgadjust = 0;
+
+ register_savestate();
+}
+
+VIDEO_START( rtype2 )
+{
+ bg_tilemap = tilemap_create(rtype2_get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ fg_tilemap = tilemap_create(rtype2_get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ m72_spriteram = auto_malloc(spriteram_size);
+
+ tilemap_set_transmask(fg_tilemap,0,0xffff,0x0001);
+ tilemap_set_transmask(fg_tilemap,1,0x00ff,0xff01);
+ tilemap_set_transmask(fg_tilemap,2,0x0001,0xffff);
+
+ tilemap_set_transmask(bg_tilemap,0,0xffff,0x0000);
+ tilemap_set_transmask(bg_tilemap,1,0x00ff,0xff00);
+ tilemap_set_transmask(bg_tilemap,2,0x0001,0xfffe);
+
+ memset(m72_spriteram,0,spriteram_size);
+
+ xadjust = -4;
+ bgadjust = 0;
+
+ register_savestate();
+}
+
+VIDEO_START( poundfor )
+{
+ video_start_rtype2(machine);
+
+ xadjust = -6;
+}
+
+
+/* Major Title has a larger background RAM, and rowscroll */
+VIDEO_START( majtitle )
+{
+// The tilemap can be 256x64, but seems to be used at 128x64 (scroll wraparound).
+// The layout ramains 256x64, the right half is just not displayed.
+// bg_tilemap = tilemap_create(rtype2_get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,256,64);
+ bg_tilemap = tilemap_create(rtype2_get_bg_tile_info,majtitle_scan_rows,TILEMAP_TYPE_PEN,8,8,128,64);
+ fg_tilemap = tilemap_create(rtype2_get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ m72_spriteram = auto_malloc(spriteram_size);
+
+ tilemap_set_transmask(fg_tilemap,0,0xffff,0x0001);
+ tilemap_set_transmask(fg_tilemap,1,0x00ff,0xff01);
+ tilemap_set_transmask(fg_tilemap,2,0x0001,0xffff);
+
+ tilemap_set_transmask(bg_tilemap,0,0xffff,0x0000);
+ tilemap_set_transmask(bg_tilemap,1,0x00ff,0xff00);
+ tilemap_set_transmask(bg_tilemap,2,0x0001,0xfffe);
+
+ memset(m72_spriteram,0,spriteram_size);
+
+ xadjust = -4;
+ bgadjust = 0;
+
+ register_savestate();
+}
+
+VIDEO_START( hharry )
+{
+ bg_tilemap = tilemap_create(hharry_get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ fg_tilemap = tilemap_create(m72_get_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ m72_spriteram = auto_malloc(spriteram_size);
+
+ tilemap_set_transmask(fg_tilemap,0,0xffff,0x0001);
+ tilemap_set_transmask(fg_tilemap,1,0x00ff,0xff01);
+ tilemap_set_transmask(fg_tilemap,2,0x0001,0xffff);
+
+ tilemap_set_transmask(bg_tilemap,0,0xffff,0x0000);
+ tilemap_set_transmask(bg_tilemap,1,0x00ff,0xff00);
+ tilemap_set_transmask(bg_tilemap,2,0x0001,0xfffe);
+
+ memset(m72_spriteram,0,spriteram_size);
+
+ xadjust = -4;
+ bgadjust = -2;
+
+ register_savestate();
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ16_HANDLER( m72_palette1_r )
+{
+ /* A9 isn't connected, so 0x200-0x3ff mirrors 0x000-0x1ff etc. */
+ offset &= ~0x100;
+
+ return paletteram16[offset] | 0xffe0; /* only D0-D4 are connected */
+}
+
+READ16_HANDLER( m72_palette2_r )
+{
+ /* A9 isn't connected, so 0x200-0x3ff mirrors 0x000-0x1ff etc. */
+ offset &= ~0x100;
+
+ return paletteram16_2[offset] | 0xffe0; /* only D0-D4 are connected */
+}
+
+INLINE void changecolor(int color,int r,int g,int b)
+{
+ palette_set_color_rgb(Machine,color,pal5bit(r),pal5bit(g),pal5bit(b));
+}
+
+WRITE16_HANDLER( m72_palette1_w )
+{
+ /* A9 isn't connected, so 0x200-0x3ff mirrors 0x000-0x1ff etc. */
+ offset &= ~0x100;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ offset &= 0x0ff;
+ changecolor(offset,
+ paletteram16[offset + 0x000],
+ paletteram16[offset + 0x200],
+ paletteram16[offset + 0x400]);
+}
+
+WRITE16_HANDLER( m72_palette2_w )
+{
+ /* A9 isn't connected, so 0x200-0x3ff mirrors 0x000-0x1ff etc. */
+ offset &= ~0x100;
+
+ COMBINE_DATA(&paletteram16_2[offset]);
+ offset &= 0x0ff;
+ changecolor(offset + 256,
+ paletteram16_2[offset + 0x000],
+ paletteram16_2[offset + 0x200],
+ paletteram16_2[offset + 0x400]);
+}
+
+WRITE16_HANDLER( m72_videoram1_w )
+{
+ COMBINE_DATA(&m72_videoram1[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( m72_videoram2_w )
+{
+ COMBINE_DATA(&m72_videoram2[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( m72_irq_line_w )
+{
+ COMBINE_DATA(&splitline);
+}
+
+WRITE16_HANDLER( m72_scrollx1_w )
+{
+ COMBINE_DATA(&scrollx1);
+}
+
+WRITE16_HANDLER( m72_scrollx2_w )
+{
+ COMBINE_DATA(&scrollx2);
+}
+
+WRITE16_HANDLER( m72_scrolly1_w )
+{
+ COMBINE_DATA(&scrolly1);
+}
+
+WRITE16_HANDLER( m72_scrolly2_w )
+{
+ COMBINE_DATA(&scrolly2);
+}
+
+WRITE16_HANDLER( m72_dmaon_w )
+{
+ if (ACCESSING_LSB)
+ memcpy(m72_spriteram,spriteram16,spriteram_size);
+}
+
+
+WRITE16_HANDLER( m72_port02_w )
+{
+ if (ACCESSING_LSB)
+ {
+ if (data & 0xe0) logerror("write %02x to port 02\n",data);
+
+ /* bits 0/1 are coin counters */
+ coin_counter_w(0,data & 0x01);
+ coin_counter_w(1,data & 0x02);
+
+ /* bit 2 is flip screen (handled both by software and hardware) */
+ flip_screen_set(((data & 0x04) >> 2) ^ ((~readinputport(2) >> 8) & 1));
+
+ /* bit 3 is display disable */
+ video_off = data & 0x08;
+
+ /* bit 4 resets sound CPU (active low) */
+ if (data & 0x10)
+ cpunum_set_input_line(1, INPUT_LINE_RESET, CLEAR_LINE);
+ else
+ cpunum_set_input_line(1, INPUT_LINE_RESET, ASSERT_LINE);
+
+ /* bit 5 = "bank"? */
+ }
+}
+
+WRITE16_HANDLER( rtype2_port02_w )
+{
+ if (ACCESSING_LSB)
+ {
+ if (data & 0xe0) logerror("write %02x to port 02\n",data);
+
+ /* bits 0/1 are coin counters */
+ coin_counter_w(0,data & 0x01);
+ coin_counter_w(1,data & 0x02);
+
+ /* bit 2 is flip screen (handled both by software and hardware) */
+ flip_screen_set(((data & 0x04) >> 2) ^ ((~readinputport(2) >> 8) & 1));
+
+ /* bit 3 is display disable */
+ video_off = data & 0x08;
+
+ /* other bits unknown */
+ }
+}
+
+
+static int majtitle_rowscroll;
+
+/* the following is mostly a kludge. This register seems to be used for something else */
+WRITE16_HANDLER( majtitle_gfx_ctrl_w )
+{
+ if (ACCESSING_MSB)
+ {
+ if (data & 0xff00) majtitle_rowscroll = 1;
+ else majtitle_rowscroll = 0;
+ }
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void m72_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ offs = 0;
+ while (offs < spriteram_size/2)
+ {
+ int code,color,sx,sy,flipx,flipy,w,h,x,y;
+
+
+ code = m72_spriteram[offs+1];
+ color = m72_spriteram[offs+2] & 0x0f;
+ sx = -256+(m72_spriteram[offs+3] & 0x3ff);
+ sy = 512-(m72_spriteram[offs+0] & 0x1ff);
+ flipx = m72_spriteram[offs+2] & 0x0800;
+ flipy = m72_spriteram[offs+2] & 0x0400;
+
+ w = 1 << ((m72_spriteram[offs+2] & 0xc000) >> 14);
+ h = 1 << ((m72_spriteram[offs+2] & 0x3000) >> 12);
+ sy -= 16 * h;
+
+ if (flip_screen)
+ {
+ sx = 512 - 16*w - sx;
+ sy = 512 - 16*h - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ for (x = 0;x < w;x++)
+ {
+ for (y = 0;y < h;y++)
+ {
+ int c = code;
+
+ if (flipx) c += 8*(w-1-x);
+ else c += 8*x;
+ if (flipy) c += h-1-y;
+ else c += y;
+
+ drawgfx(bitmap,machine->gfx[0],
+ c,
+ color,
+ flipx,flipy,
+ sx + 16*x,sy + 16*y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+
+ offs += w*4;
+ }
+}
+
+static void majtitle_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int code,color,sx,sy,flipx,flipy,w,h,x,y;
+
+
+ code = spriteram16_2[offs+1];
+ color = spriteram16_2[offs+2] & 0x0f;
+ sx = -256+(spriteram16_2[offs+3] & 0x3ff);
+ sy = 512-(spriteram16_2[offs+0] & 0x1ff);
+ flipx = spriteram16_2[offs+2] & 0x0800;
+ flipy = spriteram16_2[offs+2] & 0x0400;
+
+ w = 1;// << ((spriteram16_2[offs+2] & 0xc000) >> 14);
+ h = 1 << ((spriteram16_2[offs+2] & 0x3000) >> 12);
+ sy -= 16 * h;
+
+ if (flip_screen)
+ {
+ sx = 512 - 16*w - sx;
+ sy = 512 - 16*h - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ for (x = 0;x < w;x++)
+ {
+ for (y = 0;y < h;y++)
+ {
+ int c = code;
+
+ if (flipx) c += 8*(w-1-x);
+ else c += 8*x;
+ if (flipy) c += h-1-y;
+ else c += y;
+
+ drawgfx(bitmap,machine->gfx[2],
+ c,
+ color,
+ flipx,flipy,
+ sx + 16*x,sy + 16*y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( m72 )
+{
+ if (video_off)
+ {
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ return 0;
+ }
+
+ tilemap_set_scrollx(fg_tilemap,0,scrollx1 + xadjust);
+ tilemap_set_scrolly(fg_tilemap,0,scrolly1);
+
+ tilemap_set_scrollx(bg_tilemap,0,scrollx2 + xadjust + bgadjust);
+ tilemap_set_scrolly(bg_tilemap,0,scrolly2);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,TILEMAP_DRAW_LAYER1,0);
+ m72_draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,TILEMAP_DRAW_LAYER0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( majtitle )
+{
+ int i;
+
+
+ if (video_off)
+ {
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ return 0;
+ }
+
+ tilemap_set_scrollx(fg_tilemap,0,scrollx1 + xadjust);
+ tilemap_set_scrolly(fg_tilemap,0,scrolly1);
+
+ if (majtitle_rowscroll)
+ {
+ tilemap_set_scroll_rows(bg_tilemap,512);
+ for (i = 0;i < 512;i++)
+ tilemap_set_scrollx(bg_tilemap,(i+scrolly2)&0x1ff,
+ 256 + majtitle_rowscrollram[i] + xadjust);
+ }
+ else
+ {
+ tilemap_set_scroll_rows(bg_tilemap,1);
+ tilemap_set_scrollx(bg_tilemap,0,256 + scrollx2 + xadjust);
+ }
+ tilemap_set_scrolly(bg_tilemap,0,scrolly2);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,TILEMAP_DRAW_LAYER1,0);
+ majtitle_draw_sprites(machine, bitmap,cliprect);
+ m72_draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,TILEMAP_DRAW_LAYER0,0);
+ return 0;
+}
diff --git a/src/mame/video/m79amb.c b/src/mame/video/m79amb.c
new file mode 100644
index 00000000000..fe610883124
--- /dev/null
+++ b/src/mame/video/m79amb.c
@@ -0,0 +1,42 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+static UINT8 mask = 0;
+
+WRITE8_HANDLER( ramtek_mask_w )
+{
+ mask = data;
+}
+
+WRITE8_HANDLER( ramtek_videoram_w )
+{
+ data = data & ~mask;
+
+ if (videoram[offset] != data)
+ {
+ int i,x,y;
+
+ videoram[offset] = data;
+
+ y = offset / 32;
+ x = 8 * (offset % 32);
+
+ for (i = 0; i < 8; i++)
+ {
+ pen_t pen = (data & 0x80) ? RGB_WHITE : RGB_BLACK;
+ *BITMAP_ADDR32(tmpbitmap, y, x) = pen;
+
+ x++;
+ data <<= 1;
+ }
+ }
+}
diff --git a/src/mame/video/m90.c b/src/mame/video/m90.c
new file mode 100644
index 00000000000..08f28d3554f
--- /dev/null
+++ b/src/mame/video/m90.c
@@ -0,0 +1,261 @@
+/*****************************************************************************
+
+ Irem M90 system. There is 1 video chip - NANAO GA-25, it produces
+ 2 tilemaps and sprites. 16 control bytes:
+
+ 0: Playfield 1 X scroll
+ 2: Playfield 1 Y scroll
+ 4: Playfield 2 X scroll
+ 6: Playfield 2 Y scroll
+ 8: Bit 0x01 - unknown (set by hasamu)
+ 10: Playfield 1 control
+ Bits0x03 - Playfield 1 VRAM base
+ Bit 0x04 - Playfield 1 width (0 is 64 tiles, 0x4 is 128 tiles)
+ Bit 0x10 - Playfield 1 disable
+ Bit 0x20 - Playfield 1 rowscroll enable
+ 12: Playfield 2 control
+ Bits0x03 - Playfield 2 VRAM base
+ Bit 0x04 - Playfield 2 width (0 is 64 tiles, 0x4 is 128 tiles)
+ Bit 0x10 - Playfield 2 disable
+ Bit 0x20 - Playfield 2 rowscroll enable
+ 14: Bit 0x02 - unknown (set by hasamu)
+
+ Emulation by Bryan McPhail, mish@tendril.co.uk, thanks to Chris Hardy!
+
+*****************************************************************************/
+
+#include "driver.h"
+
+static UINT16 *m90_spriteram;
+UINT16 *m90_video_data;
+static UINT16 m90_video_control_data[8];
+static tilemap *pf1_layer,*pf2_layer,*pf1_wide_layer,*pf2_wide_layer;
+
+INLINE void get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int layer,int page_mask)
+{
+ int tile,color;
+ tile_index = 2*tile_index + ((m90_video_control_data[5+layer] & page_mask) * 0x2000);
+
+ tile=m90_video_data[tile_index];
+ color=m90_video_data[tile_index+1];
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color&0xf,
+ TILE_FLIPYX((color & 0xc0) >> 6));
+ tileinfo->category = (color & 0x30) ? 1 : 0;
+}
+
+
+static TILE_GET_INFO( get_pf1_tile_info ) { get_tile_info(machine,tileinfo,tile_index,0,0x3); }
+static TILE_GET_INFO( get_pf1w_tile_info ) { get_tile_info(machine,tileinfo,tile_index,0,0x2); }
+static TILE_GET_INFO( get_pf2_tile_info ) { get_tile_info(machine,tileinfo,tile_index,1,0x3); }
+static TILE_GET_INFO( get_pf2w_tile_info ) { get_tile_info(machine,tileinfo,tile_index,1,0x2); }
+
+
+VIDEO_START( m90 )
+{
+ pf1_layer = tilemap_create(get_pf1_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ pf1_wide_layer = tilemap_create(get_pf1w_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,128,64);
+ pf2_layer = tilemap_create(get_pf2_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ pf2_wide_layer = tilemap_create(get_pf2w_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,128,64);
+
+ tilemap_set_transparent_pen(pf1_layer,0);
+ tilemap_set_transparent_pen(pf1_wide_layer,0);
+
+ state_save_register_global_array(m90_video_control_data);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0x1f2/2;offs >= 0;offs -= 3)
+ {
+ int x,y,sprite,colour,fx,fy,y_multi,i;
+
+ sprite = m90_spriteram[offs+1];
+ colour = (m90_spriteram[offs+0] >> 9) & 0x0f;
+
+ y = m90_spriteram[offs+0] & 0x1ff;
+ x = m90_spriteram[offs+2] & 0x1ff;
+
+ x = x - 16;
+ y = 512 - y;
+
+ fx = (m90_spriteram[offs+2] >> 8) & 0x02;
+ fy = (m90_spriteram[offs+0] >> 8) & 0x80;
+
+ y_multi = 1 << ((m90_spriteram[offs+0] & 0x6000) >> 13);
+ y -= 16 * y_multi;
+
+ for (i = 0;i < y_multi;i++)
+ pdrawgfx(bitmap,machine->gfx[1],
+ sprite + (fy ? y_multi-1 - i : i),
+ colour,
+ fx,fy,
+ x,y+i*16,
+ cliprect,TRANSPARENCY_PEN,0,
+ (colour & 0x08) ? 0x00 : 0x02);
+ }
+}
+
+#if 0
+static void bootleg_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0x0;offs <0x800-8;offs+= 8) {
+ int x,y,sprite,colour,fx,fy;
+
+ if (/*spriteram[offs+0]==0x78 &&*/ spriteram[offs+1]==0x7f) continue;
+
+ y=(spriteram[offs+0] | (spriteram[offs+1]<<8))&0x1ff;
+ x=(spriteram[offs+6] | (spriteram[offs+7]<<8))&0x1ff;
+
+ x = x - /*64 -*/ 16;
+ y = 256 - /*32 -*/ y;
+
+ sprite=(spriteram[offs+2] | (spriteram[offs+3]<<8));
+ colour=(spriteram[offs+5]>>1)&0xf;
+
+ fx=spriteram[offs+5]&1;
+ fy=0;//spriteram[offs+5]&2;
+
+ drawgfx(bitmap,machine->gfx[1],
+ sprite&0x1fff,
+ colour,
+ fx,fy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+#endif
+
+WRITE16_HANDLER( m90_video_control_w )
+{
+ COMBINE_DATA(&m90_video_control_data[offset]);
+}
+
+
+static void markdirty(tilemap *tmap,int page,offs_t offset)
+{
+ offset -= page * 0x2000;
+
+ if (offset >= 0 && offset < 0x2000)
+ tilemap_mark_tile_dirty(tmap,offset/2);
+}
+
+
+WRITE16_HANDLER( m90_video_w )
+{
+ COMBINE_DATA(&m90_video_data[offset]);
+
+ markdirty(pf1_layer, m90_video_control_data[5] & 0x3,offset);
+ markdirty(pf1_wide_layer,m90_video_control_data[5] & 0x2,offset);
+ markdirty(pf2_layer, m90_video_control_data[6] & 0x3,offset);
+ markdirty(pf2_wide_layer,m90_video_control_data[6] & 0x2,offset);
+}
+
+VIDEO_UPDATE( m90 )
+{
+ static int last_pf1,last_pf2;
+ int pf1_base = m90_video_control_data[5] & 0x3;
+ int pf2_base = m90_video_control_data[6] & 0x3;
+ int i,pf1_enable,pf2_enable;
+
+ if (m90_video_control_data[5]&0x10) pf1_enable=0; else pf1_enable=1;
+ if (m90_video_control_data[6]&0x10) pf2_enable=0; else pf2_enable=1;
+// tilemap_set_enable(pf1_layer,pf1_enable);
+// tilemap_set_enable(pf2_layer,pf2_enable);
+// tilemap_set_enable(pf1_wide_layer,pf1_enable);
+// tilemap_set_enable(pf2_wide_layer,pf2_enable);
+
+ /* Dirty tilemaps if VRAM base changes */
+ if (pf1_base!=last_pf1)
+ {
+ tilemap_mark_all_tiles_dirty(pf1_layer);
+ tilemap_mark_all_tiles_dirty(pf1_wide_layer);
+ }
+ if (pf2_base!=last_pf2)
+ {
+ tilemap_mark_all_tiles_dirty(pf2_layer);
+ tilemap_mark_all_tiles_dirty(pf2_wide_layer);
+ }
+ last_pf1=pf1_base;
+ last_pf2=pf2_base;
+
+ m90_spriteram=m90_video_data+0xee00/2;
+
+ /* Setup scrolling */
+ if (m90_video_control_data[5]&0x20)
+ {
+ tilemap_set_scroll_rows(pf1_layer,512);
+ tilemap_set_scroll_rows(pf1_wide_layer,512);
+ for (i=0; i<512; i++)
+ tilemap_set_scrollx( pf1_layer,i, m90_video_data[0xf000/2+i]+2);
+ for (i=0; i<512; i++)
+ tilemap_set_scrollx( pf1_wide_layer,i, m90_video_data[0xf000/2+i]+256+2);
+ }
+ else
+ {
+ tilemap_set_scroll_rows(pf1_layer,1);
+ tilemap_set_scroll_rows(pf1_wide_layer,1);
+ tilemap_set_scrollx( pf1_layer,0, m90_video_control_data[1]+2);
+ tilemap_set_scrollx( pf1_wide_layer,0, m90_video_control_data[1]+256+2);
+ }
+
+ /* Setup scrolling */
+ if (m90_video_control_data[6]&0x20) {
+ tilemap_set_scroll_rows(pf2_layer,512);
+ tilemap_set_scroll_rows(pf2_wide_layer,512);
+ for (i=0; i<512; i++)
+ tilemap_set_scrollx( pf2_layer,i, m90_video_data[0xf400/2+i]-2);
+ for (i=0; i<512; i++)
+ tilemap_set_scrollx( pf2_wide_layer,i, m90_video_data[0xf400/2+i]+256-2);
+ } else {
+ tilemap_set_scroll_rows(pf2_layer,1);
+ tilemap_set_scroll_rows(pf2_wide_layer,1);
+ tilemap_set_scrollx( pf2_layer,0, m90_video_control_data[3]-2);
+ tilemap_set_scrollx( pf2_wide_layer,0, m90_video_control_data[3]+256-2 );
+ }
+
+ tilemap_set_scrolly( pf1_layer,0, m90_video_control_data[0] );
+ tilemap_set_scrolly( pf2_layer,0, m90_video_control_data[2] );
+ tilemap_set_scrolly( pf1_wide_layer,0, m90_video_control_data[0] );
+ tilemap_set_scrolly( pf2_wide_layer,0, m90_video_control_data[2] );
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ if (!pf2_enable)
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ if (pf2_enable)
+ {
+ if (m90_video_control_data[6] & 0x4)
+ tilemap_draw(bitmap,cliprect,pf2_wide_layer,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf2_layer,0,0);
+
+ if (m90_video_control_data[6] & 0x4)
+ tilemap_draw(bitmap,cliprect,pf2_wide_layer,1,1);
+ else
+ tilemap_draw(bitmap,cliprect,pf2_layer,1,1);
+ }
+
+ if (pf1_enable)
+ {
+ if (m90_video_control_data[5] & 0x4)
+ tilemap_draw(bitmap,cliprect,pf1_wide_layer,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1_layer,0,0);
+
+ if (m90_video_control_data[5] & 0x4)
+ tilemap_draw(bitmap,cliprect,pf1_wide_layer,1,1);
+ else
+ tilemap_draw(bitmap,cliprect,pf1_layer,1,1);
+ }
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/m92.c b/src/mame/video/m92.c
new file mode 100644
index 00000000000..7451f1d3b1e
--- /dev/null
+++ b/src/mame/video/m92.c
@@ -0,0 +1,471 @@
+/*****************************************************************************
+
+ Irem M92 video hardware, Bryan McPhail, mish@tendril.co.uk
+
+ Brief Overview:
+
+ 3 scrolling playfields, 512 by 512.
+ Each playfield can enable rowscroll, change shape (to 1024 by 512),
+ be enabled/disabled and change position in VRAM.
+
+ Tiles can have several priority values:
+ 0 = standard
+ 1 = Top 8 pens appear over sprites (split tilemap)
+ 2 = Whole tile appears over sprites
+ 3 = ? Seems to be the whole tile is over sprites (as 2).
+
+ Sprites have 2 priority values:
+ 0 = standard
+ 1 = Sprite appears over all tiles, including high priority pf1
+
+ Raster interrupts can be triggered at any line of the screen redraw,
+ typically used in games like R-Type Leo to multiplex the top playfield.
+
+*****************************************************************************
+
+ Master Control registers:
+
+ Word 0: Playfield 1 control
+ Bit 0x40: 1 = Rowscroll enable, 0 = disable
+ Bit 0x10: 0 = Playfield enable, 1 = disable
+ Bit 0x04: 0 = 512 x 512 playfield, 1 = 1024 x 512 playfield
+ Bits 0x03: Playfield location in VRAM (0, 0x4000, 0x8000, 0xc000)
+ Word 1: Playfield 2 control (as above)
+ Word 2: Playfield 3 control (as above)
+ Word 3: Raster IRQ position.
+
+ The raster IRQ position is offset by 128+8 from the first visible line,
+ suggesting there are 8 lines before the first visible one.
+
+*****************************************************************************/
+
+#include "driver.h"
+#include "m92.h"
+
+typedef struct _pf_layer_info pf_layer_info;
+struct _pf_layer_info
+{
+ tilemap * tmap;
+ tilemap * wide_tmap;
+ UINT16 vram_base;
+ UINT16 control[4];
+};
+
+static pf_layer_info pf_layer[3];
+
+static UINT16 pf_master_control[4];
+static INT32 m92_sprite_list;
+
+UINT32 m92_raster_irq_position;
+UINT16 *m92_vram_data,*m92_spritecontrol;
+UINT8 m92_game_kludge;
+
+extern void m92_sprite_interrupt(void);
+UINT8 m92_sprite_buffer_busy;
+static int m92_palette_bank;
+
+/*****************************************************************************/
+
+static TIMER_CALLBACK( spritebuffer_callback )
+{
+ m92_sprite_buffer_busy = 1;
+ if (m92_game_kludge!=2) /* Major Title 2 doesn't like this interrupt!? */
+ m92_sprite_interrupt();
+}
+
+WRITE16_HANDLER( m92_spritecontrol_w )
+{
+ COMBINE_DATA(&m92_spritecontrol[offset]);
+
+ /* Sprite list size register - used in spriteroutine */
+
+ /* Sprite control - display all sprites, or partial list */
+ if (offset==2 && ACCESSING_LSB)
+ {
+ if ((data & 0xff) == 8)
+ m92_sprite_list = (((0x100 - m92_spritecontrol[0]) & 0xff) * 4);
+ else
+ m92_sprite_list = 0x400;
+
+ /* Bit 0 is also significant */
+ }
+
+ /* Sprite buffer - the data written doesn't matter (confirmed by several games) */
+ if (offset==4)
+ {
+ buffer_spriteram16_w(0,0,0);
+ m92_sprite_buffer_busy = 0;
+
+ /* Pixel clock is 26.6666 MHz, we have 0x800 bytes, or 0x400 words
+ to copy from spriteram to the buffer. It seems safe to assume 1
+ word can be copied per clock.*/
+ timer_set(attotime_mul(ATTOTIME_IN_HZ(26666000), 0x400), 0, spritebuffer_callback);
+ }
+// logerror("%04x: m92_spritecontrol_w %08x %08x\n",activecpu_get_pc(),offset,data);
+}
+
+WRITE16_HANDLER( m92_videocontrol_w )
+{
+ /*
+ Many games write:
+ 0x2000
+ 0x201b in alternate frames.
+
+ Some games write to this both before and after the sprite buffer
+ register - perhaps some kind of acknowledge bit is in there?
+
+ Lethal Thunder fails it's RAM test with the upper palette bank
+ enabled. This was one of the earlier games and could actually
+ be a different motherboard revision (most games use M92-A-B top
+ pcb, a M92-A-A revision could exist...).
+ */
+ if (ACCESSING_LSB)
+ {
+ /* Access to upper palette bank */
+ m92_palette_bank = (data >> 1) & 1;
+ }
+// logerror("%04x: m92_videocontrol_w %d = %02x\n",activecpu_get_pc(),offset,data);
+}
+
+READ16_HANDLER( m92_paletteram_r )
+{
+ return paletteram16_word_r(offset + 0x400 * m92_palette_bank, mem_mask);
+}
+
+WRITE16_HANDLER( m92_paletteram_w )
+{
+ paletteram16_xBBBBBGGGGGRRRRR_word_w(offset + 0x400 * m92_palette_bank, data, mem_mask);
+}
+
+/*****************************************************************************/
+
+static TILE_GET_INFO( get_pf_tile_info )
+{
+ pf_layer_info *layer = param;
+ int tile, attrib;
+ tile_index = 2 * tile_index + layer->vram_base;
+
+ attrib = m92_vram_data[tile_index + 1];
+ tile = m92_vram_data[tile_index] + ((attrib & 0x8000) << 1);
+
+ SET_TILE_INFO(
+ 0,
+ tile,
+ attrib & 0x7f,
+ TILE_FLIPYX(attrib >> 9));
+ if (attrib & 0x100) tileinfo->group = 2;
+ else if (attrib & 0x80) tileinfo->group = 1;
+ else tileinfo->group = 0;
+}
+
+/*****************************************************************************/
+
+WRITE16_HANDLER( m92_vram_w )
+{
+ int laynum;
+
+ COMBINE_DATA(&m92_vram_data[offset]);
+
+ for (laynum = 0; laynum < 3; laynum++)
+ {
+ if ((offset & 0x6000) == pf_layer[laynum].vram_base)
+ {
+ tilemap_mark_tile_dirty(pf_layer[laynum].tmap, (offset & 0x1fff) / 2);
+ tilemap_mark_tile_dirty(pf_layer[laynum].wide_tmap, (offset & 0x3fff) / 2);
+ }
+ if ((offset & 0x6000) == pf_layer[laynum].vram_base + 0x2000)
+ tilemap_mark_tile_dirty(pf_layer[laynum].wide_tmap, (offset & 0x3fff) / 2);
+ }
+}
+
+/*****************************************************************************/
+
+WRITE16_HANDLER( m92_pf1_control_w )
+{
+ COMBINE_DATA(&pf_layer[0].control[offset]);
+}
+
+WRITE16_HANDLER( m92_pf2_control_w )
+{
+ COMBINE_DATA(&pf_layer[1].control[offset]);
+}
+
+WRITE16_HANDLER( m92_pf3_control_w )
+{
+ COMBINE_DATA(&pf_layer[2].control[offset]);
+}
+
+WRITE16_HANDLER( m92_master_control_w )
+{
+ UINT16 old = pf_master_control[offset];
+ pf_layer_info *layer;
+
+ COMBINE_DATA(&pf_master_control[offset]);
+
+ switch (offset)
+ {
+ case 0: /* Playfield 1 (top layer) */
+ case 1: /* Playfield 2 (middle layer) */
+ case 2: /* Playfield 3 (bottom layer) */
+ layer = &pf_layer[offset];
+
+ /* update VRAM base (bits 0-1) */
+ layer->vram_base = (pf_master_control[offset] & 3) * 0x2000;
+
+ /* update size (bit 2) */
+ if (pf_master_control[offset] & 0x04)
+ {
+ tilemap_set_enable(layer->tmap, FALSE);
+ tilemap_set_enable(layer->wide_tmap, (~pf_master_control[offset] >> 4) & 1);
+ }
+ else
+ {
+ tilemap_set_enable(layer->tmap, (~pf_master_control[offset] >> 4) & 1);
+ tilemap_set_enable(layer->wide_tmap, FALSE);
+ }
+
+ /* mark everything dirty of the VRAM base or size changes */
+ if ((old ^ pf_master_control[offset]) & 0x07)
+ {
+ tilemap_mark_all_tiles_dirty(layer->tmap);
+ tilemap_mark_all_tiles_dirty(layer->wide_tmap);
+ }
+ break;
+
+ case 3:
+ m92_raster_irq_position = pf_master_control[3] - 128;
+ break;
+ }
+}
+
+/*****************************************************************************/
+
+VIDEO_START( m92 )
+{
+ int laynum;
+
+ memset(&pf_layer, 0, sizeof(pf_layer));
+ for (laynum = 0; laynum < 3; laynum++)
+ {
+ pf_layer_info *layer = &pf_layer[laynum];
+
+ /* allocate two tilemaps per layer, one normal, one wide */
+ layer->tmap = tilemap_create(get_pf_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,64);
+ layer->wide_tmap = tilemap_create(get_pf_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 128,64);
+
+ /* set the user data for each one to point to the layer */
+ tilemap_set_user_data(layer->tmap, &pf_layer[laynum]);
+ tilemap_set_user_data(layer->wide_tmap, &pf_layer[laynum]);
+
+ /* set scroll offsets */
+ tilemap_set_scrolldx(layer->tmap, 2 * laynum, -2 * laynum + 8);
+ tilemap_set_scrolldy(layer->tmap, -128, -128);
+ tilemap_set_scrolldx(layer->wide_tmap, 2 * laynum - 256, -2 * laynum + 8 - 256);
+ tilemap_set_scrolldy(layer->wide_tmap, -128, -128);
+
+ /* layer group 0 - totally transparent in front half */
+ tilemap_set_transmask(layer->tmap, 0, 0xffff, (laynum == 2) ? 0x0000 : 0x0001);
+ tilemap_set_transmask(layer->wide_tmap, 0, 0xffff, (laynum == 2) ? 0x0000 : 0x0001);
+
+ /* layer group 1 - pens 0-7 transparent in front half */
+ tilemap_set_transmask(layer->tmap, 1, 0x00ff, (laynum == 2) ? 0xff00 : 0xff01);
+ tilemap_set_transmask(layer->wide_tmap, 1, 0x00ff, (laynum == 2) ? 0xff00 : 0xff01);
+
+ /* layer group 2 - pen 0 transparent in front half */
+ tilemap_set_transmask(layer->tmap, 2, 0x0001, (laynum == 2) ? 0xfffe : 0xffff);
+ tilemap_set_transmask(layer->wide_tmap, 2, 0x0001, (laynum == 2) ? 0xfffe : 0xffff);
+
+ state_save_register_item("layer", laynum, layer->vram_base);
+ state_save_register_item_array("layer", laynum, layer->control);
+ }
+
+ paletteram16 = auto_malloc(0x1000);
+
+ memset(spriteram16,0,0x800);
+ memset(buffered_spriteram16,0,0x800);
+
+ state_save_register_global_array(pf_master_control);
+
+ state_save_register_global(m92_sprite_list);
+ state_save_register_global(m92_raster_irq_position);
+ state_save_register_global(m92_sprite_buffer_busy);
+ state_save_register_global(m92_palette_bank);
+
+ state_save_register_global_pointer(paletteram16, 0x1000);
+}
+
+/*****************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs,k;
+
+ for (k=0; k<8; k++)
+ {
+ for (offs = 0; offs < m92_sprite_list; )
+ {
+ int x,y,sprite,colour,fx,fy,x_multi,y_multi,i,j,s_ptr,pri_back,pri_sprite;
+
+ y = buffered_spriteram16[offs+0] & 0x1ff;
+ x = buffered_spriteram16[offs+3] & 0x1ff;
+
+ if ((buffered_spriteram16[offs+2] & 0x0080)==0x0080) pri_back=0; else pri_back=2;
+
+ sprite= buffered_spriteram16[offs+1];
+ colour = buffered_spriteram16[offs+2] & 0x007f;
+ pri_sprite= (buffered_spriteram16[offs+0] & 0xe000) >> 13;
+
+ fx = (buffered_spriteram16[offs+2] >> 8) & 1;
+ fy = (buffered_spriteram16[offs+2] >> 9) & 1;
+ y_multi = (buffered_spriteram16[offs+0] >> 9) & 3;
+ x_multi = (buffered_spriteram16[offs+0] >> 11) & 3;
+
+ y_multi = 1 << y_multi;
+ x_multi = 1 << x_multi;
+
+ offs += 4 * x_multi;
+ if (pri_sprite != k)
+ continue;
+
+ x = x - 16;
+ y = 384 - 16 - y;
+
+ if (fx) x+=16 * (x_multi - 1);
+
+ for (j=0; j<x_multi; j++)
+ {
+ s_ptr=8 * j;
+ if (!fy) s_ptr+=y_multi-1;
+
+ x &= 0x1ff;
+ for (i=0; i<y_multi; i++)
+ {
+ if (flip_screen) {
+ pdrawgfx(bitmap,machine->gfx[1],
+ sprite + s_ptr,
+ colour,
+ !fx,!fy,
+ 464-x,240-(y-i*16),
+ cliprect,TRANSPARENCY_PEN,0,pri_back);
+
+ // wrap around x
+ pdrawgfx(bitmap,machine->gfx[1],
+ sprite + s_ptr,
+ colour,
+ !fx,!fy,
+ 464-x+512,240-(y-i*16),
+ cliprect,TRANSPARENCY_PEN,0,pri_back);
+ } else {
+ pdrawgfx(bitmap,machine->gfx[1],
+ sprite + s_ptr,
+ colour,
+ fx,fy,
+ x,y-i*16,
+ cliprect,TRANSPARENCY_PEN,0,pri_back);
+
+ // wrap around x
+ pdrawgfx(bitmap,machine->gfx[1],
+ sprite + s_ptr,
+ colour,
+ fx,fy,
+ x-512,y-i*16,
+ cliprect,TRANSPARENCY_PEN,0,pri_back);
+ }
+ if (fy) s_ptr++; else s_ptr--;
+ }
+ if (fx) x-=16; else x+=16;
+ }
+ }
+ }
+}
+
+
+/*****************************************************************************/
+
+static void m92_update_scroll_positions(void)
+{
+ int laynum;
+ int i;
+
+ /* Playfield 3 rowscroll data is 0xdfc00 - 0xdffff
+ Playfield 2 rowscroll data is 0xdf800 - 0xdfbff
+ Playfield 1 rowscroll data is 0xdf400 - 0xdf7ff
+
+ It appears to be hardwired to those locations.
+
+ In addition, each playfield is staggered 2 pixels horizontally from the
+ previous one. This is most obvious in Hook & Blademaster.
+
+ */
+
+ for (laynum = 0; laynum < 3; laynum++)
+ {
+ pf_layer_info *layer = &pf_layer[laynum];
+
+ if (pf_master_control[laynum] & 0x40)
+ {
+ const UINT16 *scrolldata = m92_vram_data + (0xf400 + 0x400 * laynum) / 2;
+
+ tilemap_set_scroll_rows(layer->tmap, 512);
+ tilemap_set_scroll_rows(layer->wide_tmap, 512);
+ for (i = 0; i < 512; i++)
+ {
+ tilemap_set_scrollx(layer->tmap, i, scrolldata[i]);
+ tilemap_set_scrollx(layer->wide_tmap, i, scrolldata[i]);
+ }
+ }
+ else
+ {
+ tilemap_set_scroll_rows(layer->tmap, 1);
+ tilemap_set_scroll_rows(layer->wide_tmap, 1);
+ tilemap_set_scrollx(layer->tmap, 0, layer->control[2]);
+ tilemap_set_scrollx(layer->wide_tmap, 0, layer->control[2]);
+ }
+
+ tilemap_set_scrolly(layer->tmap, 0, layer->control[0]);
+ tilemap_set_scrolly(layer->wide_tmap, 0, layer->control[0]);
+ }
+}
+
+/*****************************************************************************/
+
+static void m92_screenrefresh(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ if ((~pf_master_control[2] >> 4) & 1)
+ {
+ tilemap_draw(bitmap, cliprect, pf_layer[2].wide_tmap, TILEMAP_DRAW_LAYER1, 0);
+ tilemap_draw(bitmap, cliprect, pf_layer[2].tmap, TILEMAP_DRAW_LAYER1, 0);
+ tilemap_draw(bitmap, cliprect, pf_layer[2].wide_tmap, TILEMAP_DRAW_LAYER0, 1);
+ tilemap_draw(bitmap, cliprect, pf_layer[2].tmap, TILEMAP_DRAW_LAYER0, 1);
+ }
+ else
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ tilemap_draw(bitmap, cliprect, pf_layer[1].wide_tmap, TILEMAP_DRAW_LAYER1, 0);
+ tilemap_draw(bitmap, cliprect, pf_layer[1].tmap, TILEMAP_DRAW_LAYER1, 0);
+ tilemap_draw(bitmap, cliprect, pf_layer[1].wide_tmap, TILEMAP_DRAW_LAYER0, 1);
+ tilemap_draw(bitmap, cliprect, pf_layer[1].tmap, TILEMAP_DRAW_LAYER0, 1);
+
+ tilemap_draw(bitmap, cliprect, pf_layer[0].wide_tmap, TILEMAP_DRAW_LAYER1, 0);
+ tilemap_draw(bitmap, cliprect, pf_layer[0].tmap, TILEMAP_DRAW_LAYER1, 0);
+ tilemap_draw(bitmap, cliprect, pf_layer[0].wide_tmap, TILEMAP_DRAW_LAYER0, 1);
+ tilemap_draw(bitmap, cliprect, pf_layer[0].tmap, TILEMAP_DRAW_LAYER0, 1);
+
+ draw_sprites(machine, bitmap, cliprect);
+}
+
+
+VIDEO_UPDATE( m92 )
+{
+ m92_update_scroll_positions();
+ m92_screenrefresh(machine, bitmap, cliprect);
+
+ /* Flipscreen appears hardwired to the dipswitch - strange */
+ if (readinputportbytag("DIPS21") & 0x100)
+ flip_screen_set(0);
+ else
+ flip_screen_set(1);
+ return 0;
+}
diff --git a/src/mame/video/macrossp.c b/src/mame/video/macrossp.c
new file mode 100644
index 00000000000..6fc8213ffb6
--- /dev/null
+++ b/src/mame/video/macrossp.c
@@ -0,0 +1,414 @@
+/* Macross Plus - video
+ see DRIVER file for notes */
+
+#include "driver.h"
+
+
+UINT32 *macrossp_scra_videoram, *macrossp_scra_videoregs;
+UINT32 *macrossp_scrb_videoram, *macrossp_scrb_videoregs;
+UINT32 *macrossp_scrc_videoram, *macrossp_scrc_videoregs;
+UINT32 *macrossp_text_videoram, *macrossp_text_videoregs;
+UINT32 *macrossp_spriteram;
+
+static UINT32 *spriteram_old,*spriteram_old2;
+
+static tilemap *macrossp_scra_tilemap, *macrossp_scrb_tilemap,*macrossp_scrc_tilemap, *macrossp_text_tilemap;
+
+
+/*** SCR A LAYER ***/
+
+WRITE32_HANDLER( macrossp_scra_videoram_w )
+{
+ COMBINE_DATA(&macrossp_scra_videoram[offset]);
+
+ tilemap_mark_tile_dirty(macrossp_scra_tilemap,offset);
+}
+
+
+static TILE_GET_INFO( get_macrossp_scra_tile_info )
+{
+ UINT32 attr,tileno,color;
+
+ attr = macrossp_scra_videoram[tile_index];
+ tileno = attr & 0x0000ffff;
+
+ switch (macrossp_scra_videoregs[0] & 0x00000c00)
+ {
+ case 0x00000800:
+ color = (attr & 0x000e0000) >> 15;
+ break;
+
+ case 0x00000400:
+ color = (attr & 0x003e0000) >> 17;
+ break;
+
+ default:
+ color = mame_rand(Machine) & 7;
+ break;
+ }
+
+ SET_TILE_INFO(1,tileno,color,TILE_FLIPYX((attr & 0xc0000000) >> 30));
+}
+
+/*** SCR B LAYER ***/
+
+WRITE32_HANDLER( macrossp_scrb_videoram_w )
+{
+ COMBINE_DATA(&macrossp_scrb_videoram[offset]);
+
+ tilemap_mark_tile_dirty(macrossp_scrb_tilemap,offset);
+}
+
+
+static TILE_GET_INFO( get_macrossp_scrb_tile_info )
+{
+ UINT32 attr,tileno,color;
+
+ attr = macrossp_scrb_videoram[tile_index];
+ tileno = attr & 0x0000ffff;
+
+ switch (macrossp_scrb_videoregs[0] & 0x00000c00)
+ {
+ case 0x00000800:
+ color = (attr & 0x000e0000) >> 15;
+ break;
+
+ case 0x00000400:
+ color = (attr & 0x003e0000) >> 17;
+ break;
+
+ default:
+ color = mame_rand(Machine) & 7;
+ break;
+ }
+
+ SET_TILE_INFO(2,tileno,color,TILE_FLIPYX((attr & 0xc0000000) >> 30));
+}
+
+/*** SCR C LAYER ***/
+
+WRITE32_HANDLER( macrossp_scrc_videoram_w )
+{
+ COMBINE_DATA(&macrossp_scrc_videoram[offset]);
+
+ tilemap_mark_tile_dirty(macrossp_scrc_tilemap,offset);
+}
+
+
+static TILE_GET_INFO( get_macrossp_scrc_tile_info )
+{
+ UINT32 attr,tileno,color;
+
+ attr = macrossp_scrc_videoram[tile_index];
+ tileno = attr & 0x0000ffff;
+
+ switch (macrossp_scrc_videoregs[0] & 0x00000c00)
+ {
+ case 0x00000800:
+ color = (attr & 0x000e0000) >> 15;
+ break;
+
+ case 0x00000400:
+ color = (attr & 0x003e0000) >> 17;
+ break;
+
+ default:
+ color = mame_rand(Machine) & 7;
+ break;
+ }
+
+ SET_TILE_INFO(3,tileno,color,TILE_FLIPYX((attr & 0xc0000000) >> 30));
+}
+
+/*** TEXT LAYER ***/
+
+WRITE32_HANDLER( macrossp_text_videoram_w )
+{
+ COMBINE_DATA(&macrossp_text_videoram[offset]);
+
+ tilemap_mark_tile_dirty(macrossp_text_tilemap,offset);
+}
+
+
+static TILE_GET_INFO( get_macrossp_text_tile_info )
+{
+ UINT32 tileno, colour;
+
+ tileno = macrossp_text_videoram[tile_index] & 0x0000ffff;
+ colour = (macrossp_text_videoram[tile_index] & 0x00fe0000) >> 17;
+
+ SET_TILE_INFO(4,tileno,colour,0);
+}
+
+
+
+/*** VIDEO START / UPDATE ***/
+
+VIDEO_START(macrossp)
+{
+ spriteram_old = auto_malloc(spriteram_size);
+ spriteram_old2 = auto_malloc(spriteram_size);
+
+ memset(spriteram_old,0,spriteram_size);
+ memset(spriteram_old2,0,spriteram_size);
+
+ macrossp_text_tilemap = tilemap_create(get_macrossp_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ macrossp_scra_tilemap = tilemap_create(get_macrossp_scra_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ macrossp_scrb_tilemap = tilemap_create(get_macrossp_scrb_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ macrossp_scrc_tilemap = tilemap_create(get_macrossp_scrc_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+
+ tilemap_set_transparent_pen(macrossp_text_tilemap,0);
+ tilemap_set_transparent_pen(macrossp_scra_tilemap,0);
+ tilemap_set_transparent_pen(macrossp_scrb_tilemap,0);
+ tilemap_set_transparent_pen(macrossp_scrc_tilemap,0);
+
+ machine->gfx[0]->color_granularity=64;
+ machine->gfx[1]->color_granularity=64;
+ machine->gfx[2]->color_granularity=64;
+ machine->gfx[3]->color_granularity=64;
+
+ alpha_set_level(0x80); /* guess */
+}
+
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority )
+{
+ const gfx_element *gfx = machine->gfx[0];
+// UINT32 *source = macrossp_spriteram;
+ UINT32 *source = spriteram_old2; /* buffers by two frames */
+ UINT32 *finish = source + spriteram_size/4;
+
+
+ while( source<finish )
+ {
+
+ /*
+
+ --hh hhyy yyyy yyyy CCww wwxx xxxx xxxx
+
+ ---- --zz zzzz zzzz ---- --ZZ ZZZZ ZZZZ
+
+ fFa- pp-- cccc c--- tttt tttt tttt tttt
+
+ */
+
+
+ int wide = (source[0] & 0x00003c00) >> 10;
+ int high = (source[0] & 0x3c000000) >> 26;
+
+ int xpos = (source[0] & 0x000003ff) >> 0;
+ int ypos = (source[0] & 0x03ff0000) >> 16;
+
+ int xzoom = (source[1] & 0x000003ff) >> 0; /* 0x100 is zoom factor of 1.0 */
+ int yzoom = (source[1] & 0x03ff0000) >> 16;
+
+ int col;
+ int tileno = (source[2] & 0x0000ffff) >> 0;
+
+ int flipx = (source[2] & 0x40000000) >> 30;
+ int flipy = (source[2] & 0x80000000) >> 31;
+
+ int trans = (source[2] & 0x20000000)?TRANSPARENCY_ALPHA:TRANSPARENCY_PEN; /* alpha blending enable? */
+
+ int loopno = 0;
+
+ int xcnt,ycnt;
+ int xoffset,yoffset;
+
+ int pri = (source[2] & 0x0c000000) >> 26;
+
+ if (pri == priority)
+ {
+ switch (source[0] & 0x0000c000)
+ {
+ case 0x00008000:
+ col = (source[2] & 0x00380000) >> 17;
+ break;
+
+ case 0x00004000:
+ col = (source[2] & 0x00f80000) >> 19;
+ break;
+
+ default:
+ col = mame_rand(Machine);
+ break;
+ }
+
+
+ if (xpos > 0x1ff) xpos -=0x400;
+ if (ypos > 0x1ff) ypos -=0x400;
+
+ if (!flipx) {
+ if (!flipy) { /* noxflip, noyflip */
+ yoffset = 0; /* I'm doing this so rounding errors are cumulative, still looks a touch crappy when multiple sprites used together */
+ for (ycnt = 0; ycnt <= high; ycnt++) {
+ xoffset = 0;
+ for (xcnt = 0; xcnt <= wide; xcnt++) {
+ drawgfxzoom(bitmap,gfx,tileno+loopno,col,flipx,flipy,xpos+xoffset,ypos+yoffset,cliprect,trans,0,xzoom*0x100,yzoom*0x100);
+
+ xoffset += ((xzoom*16 + (1<<7)) >> 8);
+ loopno++;
+ }
+ yoffset += ((yzoom*16 + (1<<7)) >> 8);
+ }
+ }else{ /* noxflip, flipy */
+ yoffset = ((high*yzoom*16) >> 8);
+ for (ycnt = high; ycnt >= 0; ycnt--) {
+ xoffset = 0;
+ for (xcnt = 0; xcnt <= wide; xcnt++) {
+ drawgfxzoom(bitmap,gfx,tileno+loopno,col,flipx,flipy,xpos+xoffset,ypos+yoffset,cliprect,trans,0,xzoom*0x100,yzoom*0x100);
+
+ xoffset += ((xzoom*16 + (1<<7)) >> 8);
+ loopno++;
+ }
+ yoffset -= ((yzoom*16 + (1<<7)) >> 8);
+ }
+ }
+ }else{
+ if (!flipy) { /* xflip, noyflip */
+ yoffset = 0;
+ for (ycnt = 0; ycnt <= high; ycnt++) {
+ xoffset = ((wide*xzoom*16) >> 8);
+ for (xcnt = wide; xcnt >= 0; xcnt--) {
+ drawgfxzoom(bitmap,gfx,tileno+loopno,col,flipx,flipy,xpos+xoffset,ypos+yoffset,cliprect,trans,0,xzoom*0x100,yzoom*0x100);
+
+ xoffset -= ((xzoom*16 + (1<<7)) >> 8);
+ loopno++;
+ }
+ yoffset += ((yzoom*16 + (1<<7)) >> 8);
+ }
+ }else{ /* xflip, yflip */
+ yoffset = ((high*yzoom*16) >> 8);
+ for (ycnt = high; ycnt >= 0; ycnt--) {
+ xoffset = ((wide*xzoom*16) >> 8);
+ for (xcnt = wide; xcnt >=0 ; xcnt--) {
+ drawgfxzoom(bitmap,gfx,tileno+loopno,col,flipx,flipy,xpos+xoffset,ypos+yoffset,cliprect,trans,0,xzoom*0x100,yzoom*0x100);
+
+ xoffset -= ((xzoom*16 + (1<<7)) >> 8);
+ loopno++;
+ }
+ yoffset -= ((yzoom*16 + (1<<7)) >> 8);
+ }
+ }
+ }
+ }
+ source += 3;
+ }
+}
+
+
+static void draw_layer(mame_bitmap *bitmap, const rectangle *cliprect, int layer)
+{
+ tilemap *tm;
+ UINT32 *vr;
+
+ switch (layer)
+ {
+ case 0:
+ default:
+ tm = macrossp_scra_tilemap;
+ vr = macrossp_scra_videoregs;
+ break;
+
+ case 1:
+ tm = macrossp_scrb_tilemap;
+ vr = macrossp_scrb_videoregs;
+ break;
+
+ case 2:
+ tm = macrossp_scrc_tilemap;
+ vr = macrossp_scrc_videoregs;
+ break;
+ }
+
+ if ((vr[2] & 0xf0000000) == 0xe0000000) /* zoom enable (guess, surely wrong) */
+ {
+ int startx,starty,inc;
+
+ startx = (vr[1] & 0x0000ffff) << 16;
+ starty = (vr[1] & 0xffff0000) >> 0;
+ inc = (vr[2] & 0x00ff0000) >> 6,
+
+ /* WRONG! */
+ /* scroll register contain position relative to the center of the screen, so adjust */
+ startx -= (368/2) * inc;
+ starty -= (240/2) * inc;
+
+ tilemap_draw_roz(bitmap,cliprect,tm,
+ startx,starty,inc,0,0,inc,
+ 1, /* wraparound */
+ 0,0);
+ }
+ else
+ {
+ tilemap_set_scrollx( tm, 0, ((vr[0] & 0x000003ff) >> 0 ) );
+ tilemap_set_scrolly( tm, 0, ((vr[0] & 0x03ff0000) >> 16) );
+ tilemap_draw(bitmap,cliprect,tm,0,0);
+ }
+}
+
+/* useful function to sort the three tile layers by priority order */
+static void sortlayers(int *layer,int *pri)
+{
+#define SWAP(a,b) \
+ if (pri[a] >= pri[b]) \
+ { \
+ int t; \
+ t = pri[a]; pri[a] = pri[b]; pri[b] = t; \
+ t = layer[a]; layer[a] = layer[b]; layer[b] = t; \
+ }
+
+ SWAP(0,1)
+ SWAP(0,2)
+ SWAP(1,2)
+}
+
+VIDEO_UPDATE(macrossp)
+{
+ int layers[3],layerpri[3];
+
+
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ layers[0] = 0;
+ layerpri[0] = (macrossp_scra_videoregs[0] & 0x0000c000) >> 14;
+ layers[1] = 1;
+ layerpri[1] = (macrossp_scrb_videoregs[0] & 0x0000c000) >> 14;
+ layers[2] = 2;
+ layerpri[2] = (macrossp_scrc_videoregs[0] & 0x0000c000) >> 14;
+
+ sortlayers(layers, layerpri);
+
+ draw_layer(bitmap,cliprect,layers[0]);
+ draw_sprites(machine,bitmap,cliprect,0);
+ draw_layer(bitmap,cliprect,layers[1]);
+ draw_sprites(machine,bitmap,cliprect,1);
+ draw_layer(bitmap,cliprect,layers[2]);
+ draw_sprites(machine,bitmap,cliprect,2);
+ draw_sprites(machine,bitmap,cliprect,3);
+ tilemap_draw(bitmap,cliprect,macrossp_text_tilemap,0,0);
+
+#if 0
+popmessage ("scra - %08x %08x %08x\nscrb - %08x %08x %08x\nscrc - %08x %08x %08x",
+macrossp_scra_videoregs[0]&0xffff33ff, // yyyyxxxx
+macrossp_scra_videoregs[1], // ??? more scrolling?
+macrossp_scra_videoregs[2], // 08 - 0b
+
+macrossp_scrb_videoregs[0]&0xffff33ff, // 00 - 03
+macrossp_scrb_videoregs[1], // 04 - 07
+macrossp_scrb_videoregs[2], // 08 - 0b
+
+macrossp_scrc_videoregs[0]&0xffff33ff, // 00 - 03
+macrossp_scrc_videoregs[1], // 04 - 07
+macrossp_scrc_videoregs[2]);// 08 - 0b
+#endif
+ return 0;
+}
+
+VIDEO_EOF( macrossp )
+{
+ /* looks like sprites are *two* frames ahead, like nmk16 */
+ memcpy(spriteram_old2,spriteram_old,spriteram_size);
+ memcpy(spriteram_old,macrossp_spriteram,spriteram_size);
+}
diff --git a/src/mame/video/madmotor.c b/src/mame/video/madmotor.c
new file mode 100644
index 00000000000..c6d415c9268
--- /dev/null
+++ b/src/mame/video/madmotor.c
@@ -0,0 +1,297 @@
+/***************************************************************************
+
+ Mad Motor video emulation - Bryan McPhail, mish@tendril.co.uk
+
+ Notes: Playfield 3 can change size between 512x1024 and 2048x256
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *madmotor_pf1_rowscroll;
+UINT16 *madmotor_pf1_data,*madmotor_pf2_data,*madmotor_pf3_data;
+
+static UINT16 madmotor_pf1_control[16];
+static UINT16 madmotor_pf2_control[16];
+static UINT16 madmotor_pf3_control[16];
+
+static int flipscreen;
+static tilemap *madmotor_pf1_tilemap,*madmotor_pf2_tilemap,*madmotor_pf3_tilemap,*madmotor_pf3a_tilemap;
+
+
+
+
+/* 512 by 512 playfield, 8 by 8 tiles */
+static TILEMAP_MAPPER( pf1_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((row & 0x20) << 5) + ((col & 0x20) << 6);
+}
+
+static TILE_GET_INFO( get_pf1_tile_info )
+{
+ int tile,color;
+
+ tile=madmotor_pf1_data[tile_index];
+ color=tile >> 12;
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+/* 512 by 512 playfield, 16 by 16 tiles */
+static TILEMAP_MAPPER( pf2_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x0f) + ((row & 0x0f) << 4) + ((row & 0x10) << 4) + ((col & 0x10) << 5);
+}
+
+static TILE_GET_INFO( get_pf2_tile_info )
+{
+ int tile,color;
+
+ tile=madmotor_pf2_data[tile_index];
+ color=tile >> 12;
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 1,
+ tile,
+ color,
+ 0);
+}
+
+/* 512 by 1024 playfield, 16 by 16 tiles */
+static TILEMAP_MAPPER( pf3_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x0f) + ((row & 0x0f) << 4) + ((row & 0x30) << 4) + ((col & 0x10) << 6);
+}
+
+static TILE_GET_INFO( get_pf3_tile_info )
+{
+ int tile,color;
+
+ tile=madmotor_pf3_data[tile_index];
+ color=tile >> 12;
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 2,
+ tile,
+ color,
+ 0);
+}
+
+/* 2048 by 256 playfield, 16 by 16 tiles */
+static TILEMAP_MAPPER( pf3a_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x0f) + ((row & 0x0f) << 4) + ((col & 0x70) << 4);
+}
+
+static TILE_GET_INFO( get_pf3a_tile_info )
+{
+ int tile,color;
+
+ tile=madmotor_pf3_data[tile_index];
+ color=tile >> 12;
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 2,
+ tile,
+ color,
+ 0);
+}
+
+/******************************************************************************/
+
+VIDEO_START( madmotor )
+{
+ madmotor_pf1_tilemap = tilemap_create(get_pf1_tile_info, pf1_scan, TILEMAP_TYPE_PEN, 8, 8, 64,64);
+ madmotor_pf2_tilemap = tilemap_create(get_pf2_tile_info, pf2_scan, TILEMAP_TYPE_PEN,16,16, 32,32);
+ madmotor_pf3_tilemap = tilemap_create(get_pf3_tile_info, pf3_scan, TILEMAP_TYPE_PEN, 16,16, 32,64);
+ madmotor_pf3a_tilemap= tilemap_create(get_pf3a_tile_info,pf3a_scan,TILEMAP_TYPE_PEN, 16,16,128,16);
+
+ tilemap_set_transparent_pen(madmotor_pf1_tilemap,0);
+ tilemap_set_transparent_pen(madmotor_pf2_tilemap,0);
+ tilemap_set_scroll_rows(madmotor_pf1_tilemap,512);
+}
+
+/******************************************************************************/
+
+READ16_HANDLER( madmotor_pf1_data_r )
+{
+ return madmotor_pf1_data[offset];
+}
+
+READ16_HANDLER( madmotor_pf2_data_r )
+{
+ return madmotor_pf2_data[offset];
+}
+
+READ16_HANDLER( madmotor_pf3_data_r )
+{
+ return madmotor_pf3_data[offset];
+}
+
+WRITE16_HANDLER( madmotor_pf1_data_w )
+{
+ COMBINE_DATA(&madmotor_pf1_data[offset]);
+ tilemap_mark_tile_dirty(madmotor_pf1_tilemap,offset);
+}
+
+WRITE16_HANDLER( madmotor_pf2_data_w )
+{
+ COMBINE_DATA(&madmotor_pf2_data[offset]);
+ tilemap_mark_tile_dirty(madmotor_pf2_tilemap,offset);
+}
+
+WRITE16_HANDLER( madmotor_pf3_data_w )
+{
+ COMBINE_DATA(&madmotor_pf3_data[offset]);
+
+ /* Mark the dirty position on the 512 x 1024 version */
+ tilemap_mark_tile_dirty(madmotor_pf3_tilemap,offset);
+
+ /* Mark the dirty position on the 2048 x 256 version */
+ tilemap_mark_tile_dirty(madmotor_pf3a_tilemap,offset);
+}
+
+WRITE16_HANDLER( madmotor_pf1_control_w )
+{
+ COMBINE_DATA(&madmotor_pf1_control[offset]);
+}
+
+WRITE16_HANDLER( madmotor_pf2_control_w )
+{
+ COMBINE_DATA(&madmotor_pf2_control[offset]);
+}
+
+WRITE16_HANDLER( madmotor_pf3_control_w )
+{
+ COMBINE_DATA(&madmotor_pf3_control[offset]);
+}
+
+READ16_HANDLER( madmotor_pf1_rowscroll_r )
+{
+ return madmotor_pf1_rowscroll[offset];
+}
+
+WRITE16_HANDLER( madmotor_pf1_rowscroll_w )
+{
+ COMBINE_DATA(&madmotor_pf1_rowscroll[offset]);
+}
+
+/******************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int pri_mask,int pri_val)
+{
+ int offs;
+
+ offs = 0;
+ while (offs < spriteram_size/2)
+ {
+ int sx,sy,code,color,w,h,flipx,flipy,incy,flash,mult,x,y;
+
+ sy = spriteram16[offs];
+ sx = spriteram16[offs+2];
+ color = sx >> 12;
+
+ flash=sx&0x800;
+
+ flipx = sy & 0x2000;
+ flipy = sy & 0x4000;
+ h = (1 << ((sy & 0x1800) >> 11)); /* 1x, 2x, 4x, 8x height */
+ w = (1 << ((sy & 0x0600) >> 9)); /* 1x, 2x, 4x, 8x width */
+ /* multi width used only on the title screen? */
+
+ code = spriteram16[offs+1] & 0x1fff;
+
+ sx = sx & 0x01ff;
+ sy = sy & 0x01ff;
+ if (sx >= 256) sx -= 512;
+ if (sy >= 256) sy -= 512;
+ sx = 240 - sx;
+ sy = 240 - sy;
+
+ code &= ~(h-1);
+ if (flipy)
+ incy = -1;
+ else
+ {
+ code += h-1;
+ incy = 1;
+ }
+
+ if (flipscreen) {
+ sy=240-sy;
+ sx=240-sx;
+ if (flipx) flipx=0; else flipx=1;
+ if (flipy) flipy=0; else flipy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ for (x = 0;x < w;x++)
+ {
+ for (y = 0;y < h;y++)
+ {
+ if ((color & pri_mask) == pri_val &&
+ (!flash || (cpu_getcurrentframe() & 1)))
+ drawgfx(bitmap,machine->gfx[3],
+ code - y * incy + h * x,
+ color,
+ flipx,flipy,
+ sx + mult * x,sy + mult * y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ offs += 4;
+ if (offs >= spriteram_size/2 ||
+ spriteram16[offs] & 0x8000) // seems the expected behaviour on the title screen
+ break;
+ }
+ }
+}
+
+
+/******************************************************************************/
+
+VIDEO_UPDATE( madmotor )
+{
+ int offs;
+
+ /* Update flipscreen */
+ if (madmotor_pf1_control[0]&0x80)
+ flipscreen=1;
+ else
+ flipscreen=0;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ /* Setup scroll registers */
+ for (offs = 0;offs < 512;offs++)
+ tilemap_set_scrollx( madmotor_pf1_tilemap,offs, madmotor_pf1_control[0x08] + madmotor_pf1_rowscroll[0x200+offs] );
+ tilemap_set_scrolly( madmotor_pf1_tilemap,0, madmotor_pf1_control[0x09] );
+ tilemap_set_scrollx( madmotor_pf2_tilemap,0, madmotor_pf2_control[0x08] );
+ tilemap_set_scrolly( madmotor_pf2_tilemap,0, madmotor_pf2_control[0x09] );
+ tilemap_set_scrollx( madmotor_pf3_tilemap,0, madmotor_pf3_control[0x08] );
+ tilemap_set_scrolly( madmotor_pf3_tilemap,0, madmotor_pf3_control[0x09] );
+ tilemap_set_scrollx( madmotor_pf3a_tilemap,0, madmotor_pf3_control[0x08] );
+ tilemap_set_scrolly( madmotor_pf3a_tilemap,0, madmotor_pf3_control[0x09] );
+
+ /* Draw playfields & sprites */
+ if (madmotor_pf3_control[0x03]==2)
+ tilemap_draw(bitmap,cliprect,madmotor_pf3_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,madmotor_pf3a_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,madmotor_pf2_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect,0x00,0x00);
+ tilemap_draw(bitmap,cliprect,madmotor_pf1_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/magmax.c b/src/mame/video/magmax.c
new file mode 100644
index 00000000000..4a3605d8f18
--- /dev/null
+++ b/src/mame/video/magmax.c
@@ -0,0 +1,373 @@
+/***************************************************************************
+
+Video Hardware for MAGMAX.
+
+Driver by Takahiro Nogi (nogi@kt.rim.or.jp) 1999/11/05 -
+Additional tweaking by Jarek Burczynski
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *magmax_scroll_x;
+UINT16 *magmax_scroll_y;
+UINT16 magmax_vreg;
+static int flipscreen = 0;
+
+static UINT32 pens_line_tab[256];
+static UINT32 *prom_tab = NULL;
+
+
+static void blit_horiz_pixel_line(mame_bitmap *b,int x,int y,int w, UINT32* pens)
+{
+ UINT16* lineadr = BITMAP_ADDR16(b, y, x);
+ while(w-->0)
+ {
+ *lineadr++ = (UINT16)(*pens);
+ pens++;
+ }
+}
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Mag Max has three 256x4 palette PROMs (one per gun), connected to the
+ RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+PALETTE_INIT( magmax )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn, offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int bit0, bit1, bit2, bit3, r, g, b;
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the lookup tables */
+
+ /* characters use colors 0-15 */
+ for (i = 0; i < TOTAL_COLORS(0);i++)
+ COLOR(0, i) = i;
+
+ /*sprites use colors 16-32, color 31 being transparent*/
+ for (i = 0; i < TOTAL_COLORS(1);i++)
+ {
+ COLOR(1, i) = *(color_prom++) + 16;
+ }
+
+}
+
+VIDEO_START( magmax )
+{
+ int i,v;
+ UINT8 * prom14D = memory_region(REGION_USER2);
+
+ /* Set up save state */
+ state_save_register_global(magmax_vreg);
+
+ prom_tab = auto_malloc(256 * sizeof(UINT32));
+
+ /* Allocate temporary bitmap */
+ tmpbitmap = auto_bitmap_alloc(256,256,machine->screen[0].format);
+
+ for (i=0; i<256; i++)
+ {
+ v = (prom14D[i] << 4) + prom14D[i + 0x100];
+ prom_tab[i] = ((v&0x1f)<<8) | ((v&0x10)<<10) | ((v&0xe0)>>1); /*convert data into more useful format*/
+ }
+}
+
+
+
+VIDEO_UPDATE( magmax )
+{
+ int offs;
+
+ /* bit 2 flip screen */
+ if (flipscreen != (magmax_vreg & 0x04))
+ {
+ flipscreen = magmax_vreg & 0x04;
+ }
+
+ /* copy the background graphics */
+ if (magmax_vreg & 0x40) /* background disable */
+ {
+ fillbitmap(bitmap, machine->pens[0], &machine->screen[0].visarea);
+ }
+ else
+ {
+ UINT32 h,v;
+ UINT8 * rom18B = memory_region(REGION_USER1);
+ UINT32 scroll_h = (*magmax_scroll_x) & 0x3fff;
+ UINT32 scroll_v = (*magmax_scroll_y) & 0xff;
+
+ /*clear background-over-sprites bitmap*/
+ fillbitmap(tmpbitmap, 0, &machine->screen[0].visarea);
+
+ for (v = 2*8; v < 30*8; v++) /*only for visible area*/
+ {
+ UINT32 map_v_scr_100 = (scroll_v + v) & 0x100;
+ UINT32 rom18D_addr = ((scroll_v + v) & 0xf8) + (map_v_scr_100<<5);
+ UINT32 rom15F_addr = (((scroll_v + v) & 0x07)<<2) + (map_v_scr_100<<5);
+ UINT32 map_v_scr_1fe_6 =((scroll_v + v) & 0x1fe)<<6;
+
+ const pen_t *pens = &machine->pens[2*16 + (map_v_scr_100>>1)];
+
+ if (!map_v_scr_100)
+ {
+ /* we are drawing surface */
+ for (h = 0; h < 0x80; h++)
+ {
+ UINT32 graph_data;
+ UINT32 graph_color;
+ UINT32 LS283;
+ UINT32 prom_data;
+
+ LS283 = scroll_h + h + rom18B[ map_v_scr_1fe_6 + h ] + 0xff01;
+
+ prom_data = prom_tab[ (LS283 >> 6) & 0xff ];
+
+ rom18D_addr &= 0x20f8;
+ rom18D_addr += (prom_data & 0x1f00) + ((LS283 & 0x38) >>3);
+
+ rom15F_addr &= 0x201c;
+ rom15F_addr += (rom18B[0x4000 + rom18D_addr ]<<5) + ((LS283 & 0x6)>>1);
+ rom15F_addr += (prom_data & 0x4000);
+
+ graph_color = (prom_data & 0x0070);
+
+ graph_data = rom18B[0x8000 + rom15F_addr];
+ if ((LS283 & 1))
+ graph_data >>= 4;
+ graph_data &= 0x0f;
+
+ pens_line_tab[h] = pens[graph_color + graph_data];
+
+ /*priority: background over sprites*/
+ /* not possible on the surface*/
+ //if ((map_v_scr_100) && ((graph_data & 0x0c)==0x0c))
+ //{
+ // *BITMAP_ADDR16(tmpbitmap, v, h) = pens[graph_color + graph_data];
+ //}
+ }
+ for (h = 0x80; h < 0x100; h++)
+ {
+ UINT32 graph_data;
+ UINT32 graph_color;
+ UINT32 LS283;
+ UINT32 prom_data;
+
+ LS283 = scroll_h + h + (rom18B[ (map_v_scr_1fe_6) + (h ^ 0xff) ] ^ 0xff);
+
+ prom_data = prom_tab[ (LS283 >> 6) & 0xff ];
+
+ rom18D_addr &= 0x20f8;
+ rom18D_addr += (prom_data & 0x1f00) + ((LS283 & 0x38) >>3);
+
+ rom15F_addr &= 0x201c;
+ rom15F_addr += (rom18B[0x4000 + rom18D_addr ]<<5) + ((LS283 & 0x6)>>1);
+ rom15F_addr += (prom_data & 0x4000);
+
+ graph_color = (prom_data & 0x0070);
+
+ graph_data = rom18B[0x8000 + rom15F_addr];
+ if ((LS283 & 1))
+ graph_data >>= 4;
+ graph_data &= 0x0f;
+
+ pens_line_tab[h] = pens[graph_color + graph_data];
+
+ /*priority: background over sprites*/
+ /* not possible on the surface*/
+ //if ((map_v_scr_100) && ((graph_data & 0x0c)==0x0c))
+ //{
+ // *BITMAP_ADDR16(tmpbitmap, v, h) = pens[graph_color + graph_data];
+ //}
+ }
+ }
+ else
+ {
+ /* we are drawing underground */
+ for (h = 0; h < 0x80; h++)
+ {
+ UINT32 graph_data;
+ UINT32 graph_color;
+ UINT32 LS283;
+ UINT32 prom_data;
+
+ LS283 = scroll_h + h;
+
+ prom_data = prom_tab[ (LS283 >> 6) & 0xff ];
+
+ rom18D_addr &= 0x20f8;
+ rom18D_addr += (prom_data & 0x1f00) + ((LS283 & 0x38) >>3);
+
+ rom15F_addr &= 0x201c;
+ rom15F_addr += (rom18B[0x4000 + rom18D_addr ]<<5) + ((LS283 & 0x6)>>1);
+ rom15F_addr += (prom_data & 0x4000);
+
+ graph_color = (prom_data & 0x0070);
+
+ graph_data = rom18B[0x8000 + rom15F_addr];
+ if ((LS283 & 1))
+ graph_data >>= 4;
+ graph_data &= 0x0f;
+
+ pens_line_tab[h] = pens[graph_color + graph_data];
+
+ /*priority: background over sprites*/
+ if (/*(map_v_scr_100) &&*/ ((graph_data & 0x0c)==0x0c))
+ {
+ *BITMAP_ADDR16(tmpbitmap, v, h) = pens[graph_color + graph_data];
+ }
+ }
+ for (h = 0x80; h < 0x100; h++)
+ {
+ UINT32 graph_data;
+ UINT32 graph_color;
+ UINT32 LS283;
+ UINT32 prom_data;
+
+ LS283 = scroll_h + h;
+
+ prom_data = prom_tab[ (LS283 >> 6) & 0xff ];
+
+ rom18D_addr &= 0x20f8;
+ rom18D_addr += (prom_data & 0x1f00) + ((LS283 & 0x38) >>3);
+
+ rom15F_addr &= 0x201c;
+ rom15F_addr += (rom18B[0x4000 + rom18D_addr ]<<5) + ((LS283 & 0x6)>>1);
+ rom15F_addr += (prom_data & 0x4000);
+
+ graph_color = (prom_data & 0x0070);
+
+ graph_data = rom18B[0x8000 + rom15F_addr];
+ if ((LS283 & 1))
+ graph_data >>= 4;
+ graph_data &= 0x0f;
+
+ pens_line_tab[h] = pens[graph_color + graph_data];
+
+ /*priority: background over sprites*/
+ if (/*(map_v_scr_100) &&*/ ((graph_data & 0x0c)==0x0c))
+ {
+ *BITMAP_ADDR16(tmpbitmap, v, h) = pens[graph_color + graph_data];
+ }
+ }
+ }
+
+ if (flipscreen)
+ {
+ int i;
+ UINT32 pens_line_tab_flipped[256];
+ for (i=0; i<256; i++)
+ pens_line_tab_flipped[i] = pens_line_tab[255-i];
+ blit_horiz_pixel_line(bitmap,0,255-v,256,pens_line_tab_flipped);
+ }
+ else
+ blit_horiz_pixel_line(bitmap,0, v,256,pens_line_tab);
+ }
+ }
+
+ /* draw the sprites */
+ for (offs = 0; offs < spriteram_size/2; offs += 4)
+ {
+ int sx, sy;
+
+ sy = spriteram16[offs] & 0xff;
+ if (sy)
+ {
+ int code = spriteram16[offs + 1] & 0xff;
+ int attr = spriteram16[offs + 2] & 0xff;
+ int color = (attr & 0xf0) >> 4;
+ int flipx = attr & 0x04;
+ int flipy = attr & 0x08;
+
+ sx = (spriteram16[offs + 3] & 0xff) - 0x80 + 0x100 * (attr & 0x01);
+ sy = 239 - sy;
+
+ if (flipscreen)
+ {
+ sx = 255-16 - sx;
+ sy = 239 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if (code & 0x80) /* sprite bankswitch */
+ {
+ code += (magmax_vreg & 0x30) * 0x8;
+ }
+
+ drawgfx(bitmap, machine->gfx[1],
+ code,
+ color,
+ flipx, flipy,
+ sx, sy,
+ &machine->screen[0].visarea, TRANSPARENCY_COLOR, 31);
+ }
+ }
+ if (!(magmax_vreg & 0x40)) /* background disable */
+ {
+ copybitmap(bitmap, tmpbitmap, flipscreen,flipscreen,0,0, &machine->screen[0].visarea, TRANSPARENCY_PEN, 0);
+ }
+
+
+ /* draw the foreground characters */
+ for (offs = 32*32-1; offs >= 0; offs -= 1)
+ {
+ //int page = (magmax_vreg>>3) & 0x1;
+ int code;
+
+ code = videoram16[offs /*+ page*/] & 0xff;
+ if (code)
+ {
+ int sx = (offs % 32);
+ int sy = (offs / 32);
+
+ if (flipscreen)
+ {
+ sx = 31 - sx;
+ sy = 31 - sy;
+ }
+
+ drawgfx(bitmap, machine->gfx[0],
+ code,
+ 0,
+ flipscreen, flipscreen,
+ 8 * sx, 8 * sy,
+ &machine->screen[0].visarea, TRANSPARENCY_PEN, 15);
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/mainevt.c b/src/mame/video/mainevt.c
new file mode 100644
index 00000000000..12a26d62d1d
--- /dev/null
+++ b/src/mame/video/mainevt.c
@@ -0,0 +1,115 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+static int layer_colorbase[3],sprite_colorbase;
+
+
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void mainevt_tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ *flags = (*color & 0x02) ? TILE_FLIPX : 0;
+
+ /* priority relative to HALF priority sprites */
+ *priority = (layer == 2) ? (*color & 0x20) >> 5 : 0;
+ *code |= ((*color & 0x01) << 8) | ((*color & 0x1c) << 7);
+ *color = layer_colorbase[layer] + ((*color & 0xc0) >> 6);
+}
+
+static void dv_tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ /* (color & 0x02) is flip y handled internally by the 052109 */
+ *code |= ((*color & 0x01) << 8) | ((*color & 0x3c) << 7);
+ *color = layer_colorbase[layer] + ((*color & 0xc0) >> 6);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051960
+
+***************************************************************************/
+
+static void mainevt_sprite_callback(int *code,int *color,int *priority_mask,int *shadow)
+{
+ /* bit 5 = priority over layer B (has precedence) */
+ /* bit 6 = HALF priority over layer B (used for crowd when you get out of the ring) */
+ if (*color & 0x20) *priority_mask = 0xff00;
+ else if (*color & 0x40) *priority_mask = 0xff00|0xf0f0;
+ else *priority_mask = 0xff00|0xf0f0|0xcccc;
+ /* bit 7 is shadow, not used */
+
+ *color = sprite_colorbase + (*color & 0x03);
+}
+
+static void dv_sprite_callback(int *code,int *color,int *priority,int *shadow)
+{
+ /* TODO: the priority/shadow handling (bits 5-7) seems to be quite complex (see PROM) */
+ *color = sprite_colorbase + (*color & 0x07);
+}
+
+
+/*****************************************************************************/
+
+VIDEO_START( mainevt )
+{
+ layer_colorbase[0] = 0;
+ layer_colorbase[1] = 8;
+ layer_colorbase[2] = 4;
+ sprite_colorbase = 12;
+
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,mainevt_tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,NORMAL_PLANE_ORDER,mainevt_sprite_callback);
+}
+
+VIDEO_START( dv )
+{
+ layer_colorbase[0] = 0;
+ layer_colorbase[1] = 0;
+ layer_colorbase[2] = 4;
+ sprite_colorbase = 8;
+
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,dv_tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,NORMAL_PLANE_ORDER,dv_sprite_callback);
+}
+
+/*****************************************************************************/
+
+VIDEO_UPDATE( mainevt )
+{
+ K052109_tilemap_update();
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],TILEMAP_DRAW_OPAQUE,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],1,2); /* low priority part of layer */
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],0,4); /* high priority part of layer */
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],0,8);
+
+ K051960_sprites_draw(bitmap,cliprect,-1,-1);
+ return 0;
+}
+
+VIDEO_UPDATE( dv )
+{
+ K052109_tilemap_update();
+
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],0,0);
+ K051960_sprites_draw(bitmap,cliprect,0,0);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],0,0);
+ return 0;
+}
diff --git a/src/mame/video/mainsnk.c b/src/mame/video/mainsnk.c
new file mode 100644
index 00000000000..0b943ef9536
--- /dev/null
+++ b/src/mame/video/mainsnk.c
@@ -0,0 +1,205 @@
+#include "driver.h"
+
+static UINT8 bg_color, old_bg_color;
+#define mainsnk_offset 8
+static tilemap *me_fg_tilemap;
+static tilemap *me_bg_tilemap;
+UINT8 *mainsnk_fgram;
+UINT8 *mainsnk_bgram;
+static int me_gfx_ctrl;
+
+WRITE8_HANDLER(mainsnk_c600_w)
+{
+ bg_color = data&0xf;
+ me_gfx_ctrl=data;
+ tilemap_mark_all_tiles_dirty (me_bg_tilemap);
+ mame_printf_debug("canvas %04x\n",data&=0xf0);
+}
+
+static TILE_GET_INFO( get_me_fg_tile_info )
+{
+ int code = (mainsnk_fgram[tile_index]);
+
+ SET_TILE_INFO(
+ 0,
+ code,
+ 0x10,
+ 0);
+}
+
+static void stuff_palette( running_machine *machine, int source_index, int dest_index, int num_colors )
+{
+
+
+
+ UINT8 *color_prom = memory_region(REGION_PROMS) + source_index;
+ int i;
+ for( i=0; i<num_colors; i++ )
+ {
+ int bit0=0,bit1,bit2,bit3;
+ int red, green, blue;
+
+ bit0 = (color_prom[0x1000] >> 2) & 0x01; // ?
+ bit1 = (color_prom[0x000] >> 1) & 0x01;
+ bit2 = (color_prom[0x000] >> 2) & 0x01;
+ bit3 = (color_prom[0x000] >> 3) & 0x01;
+ red = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[0x1000] >> 1) & 0x01; // ?
+ bit1 = (color_prom[0x800] >> 2) & 0x01;
+ bit2 = (color_prom[0x800] >> 3) & 0x01;
+ bit3 = (color_prom[0x000] >> 0) & 0x01;
+ green = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[0x1000] >> 0) & 0x01; // ?
+ bit1 = (color_prom[0x1000] >> 3) & 0x01; // ?
+ bit2 = (color_prom[0x800] >> 0) & 0x01;
+ bit3 = (color_prom[0x800] >> 1) & 0x01;
+ blue = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color( machine, dest_index++, MAKE_RGB(red, green, blue) );
+ color_prom++;
+ }
+
+}
+
+static void update_palette( int type )
+{
+ if( bg_color!=old_bg_color )
+ {
+ stuff_palette( Machine, 256+16*(bg_color&0x7), (0x11-type)*16, 16 );
+ old_bg_color = bg_color;
+ }
+}
+
+
+WRITE8_HANDLER( mainsnk_fgram_w )
+{
+ mainsnk_fgram[offset] = data;
+ tilemap_mark_tile_dirty(me_fg_tilemap,offset);
+}
+
+
+static TILE_GET_INFO( get_me_bg_tile_info )
+{
+ int code = (mainsnk_bgram[tile_index]);
+
+ SET_TILE_INFO(
+ 0,
+ code + ((me_gfx_ctrl<<4)&0x700),
+ 0x10,
+ 0);
+}
+
+
+WRITE8_HANDLER( mainsnk_bgram_w )
+{
+ mainsnk_bgram[offset] = data;
+ tilemap_mark_tile_dirty(me_bg_tilemap,offset);
+}
+
+
+VIDEO_START(mainsnk)
+{
+ old_bg_color = -1;
+ stuff_palette( machine, 0, 0, 16*8 );
+ stuff_palette( machine, 16*8*3, 16*8, 16*8 );
+ me_fg_tilemap = tilemap_create(get_me_fg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32, 32);
+ tilemap_set_transparent_pen(me_fg_tilemap,15);
+ me_bg_tilemap = tilemap_create(get_me_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32, 32);
+ tilemap_set_scrollx( me_fg_tilemap, 0, -mainsnk_offset );
+ tilemap_set_scrollx( me_bg_tilemap, 0, -mainsnk_offset );
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int scrollx, int scrolly )
+{
+ const gfx_element *gfx = machine->gfx[1];
+ const UINT8 *source, *finish;
+ source = spriteram;
+ finish = source + 0x64;
+
+ while( source<finish )
+ {
+ int attributes = source[3];
+ int tile_number = source[1];
+ int sy = source[0];
+ int sx = source[2];
+ int color = attributes&0xf;
+ if( sy>240 ) sy -= 256;
+
+ tile_number |= attributes<<4 & 0x300;
+
+ drawgfx( bitmap,gfx,
+ tile_number,
+ color,
+ 0,0,
+ 256-sx+mainsnk_offset,sy,
+ cliprect,TRANSPARENCY_PEN,7);
+
+ source+=4;
+ }
+}
+
+
+static void draw_status(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect,int dx,int off )
+{
+ const UINT8 *base = mainsnk_fgram+off;
+ const gfx_element *gfx = machine->gfx[0];
+ int row;
+ for( row=0; row<4; row++ )
+ {
+ int sy,sx = (row&1)*8;
+ const UINT8 *source = base + (row&1)*32;
+ if( row>1 )
+ {
+ sx+=256+16;
+ }
+ else
+ {
+ source+=30*32;
+ }
+
+ for( sy=0; sy<256; sy+=8 )
+ {
+ int tile_number = *source++;
+ drawgfx( bitmap, gfx,
+ tile_number, tile_number>>5,
+ 0,0,
+ sx+dx,sy,
+ cliprect,
+ TRANSPARENCY_NONE, 0xf );
+ }
+ }
+}
+
+VIDEO_UPDATE(mainsnk)
+{
+ rectangle myclip;
+ myclip.min_x = cliprect->min_x+8;
+ myclip.max_x = cliprect->max_x-8;
+ myclip.min_y = cliprect->min_y;
+ myclip.max_y = cliprect->max_y;
+ tilemap_draw(bitmap,&myclip,me_bg_tilemap,0,0);
+ draw_sprites(machine,bitmap,&myclip, 0,0 );
+ tilemap_draw(bitmap,&myclip,me_fg_tilemap,0,0);
+ draw_status(machine,bitmap,cliprect,0,0x400 );
+ draw_status(machine,bitmap,cliprect,32*8,0x40 );
+ update_palette(1);
+ return 0;
+}
+
+VIDEO_UPDATE(canvas)
+{
+ rectangle myclip;
+ myclip.min_x = cliprect->min_x+8;
+ myclip.max_x = cliprect->max_x-8;
+ myclip.min_y = cliprect->min_y;
+ myclip.max_y = cliprect->max_y;
+ tilemap_draw(bitmap,&myclip,me_bg_tilemap,0,0);
+ draw_sprites(machine,bitmap,&myclip, 0,0 );
+// tilemap_draw(bitmap,&myclip,me_fg_tilemap,0,0);
+// draw_status(machine,bitmap,cliprect,0,0x400 );
+// draw_status(machine,bitmap,cliprect,32*8,0x40 );
+ update_palette(1);
+ return 0;
+}
diff --git a/src/mame/video/malzak.c b/src/mame/video/malzak.c
new file mode 100644
index 00000000000..76dd47cece3
--- /dev/null
+++ b/src/mame/video/malzak.c
@@ -0,0 +1,230 @@
+/*
+
+ Malzak
+
+ Video functions
+
+ SAA 5050 -- Character display
+ S2636 (x2) -- Sprites, Sprite->Sprite collisions
+ Playfield graphics generator
+ (TODO: probably best to switch this to tilemaps one day, figure out banking)
+
+*/
+
+
+#include "driver.h"
+#include "video/s2636.h"
+
+static INT8 frame_count;
+
+#define SAA5050_DBLHI 0x0001
+#define SAA5050_SEPGR 0x0002
+#define SAA5050_FLASH 0x0004
+#define SAA5050_BOX 0x0008
+#define SAA5050_GRAPH 0x0010
+#define SAA5050_CONCEAL 0x0020
+#define SAA5050_HOLDGR 0x0040
+
+#define SAA5050_BLACK 0
+#define SAA5050_WHITE 7
+
+struct {
+ UINT16 saa5050_flags;
+ UINT8 saa5050_forecol;
+ UINT8 saa5050_backcol;
+ UINT8 saa5050_prvcol;
+ UINT8 saa5050_prvchr;
+} saa5050_state;
+
+
+UINT8* saa5050_vidram; /* Video RAM for SAA 5050 */
+
+static mame_bitmap* collision_bitmap;
+
+int malzak_x;
+int malzak_y;
+
+static struct playfield
+{
+ //int x;
+ //int y;
+ int code;
+} field[256];
+
+VIDEO_START( malzak )
+{
+ collision_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,BITMAP_FORMAT_INDEXED8);
+
+ saa5050_vidram = auto_malloc(0x800);
+ s2636_1_ram = auto_malloc(0x100);
+ s2636_2_ram = auto_malloc(0x100);
+}
+
+VIDEO_UPDATE( malzak )
+{
+ int code, colour;
+ int sx, sy;
+ int x,y;
+
+ fillbitmap(bitmap,0,0);
+
+ // SAA 5050 - Teletext character generator
+ for (sy = 24; sy >= 0; sy--)
+ {
+ /* Set start of line state */
+ saa5050_state.saa5050_flags = 0;
+ saa5050_state.saa5050_prvchr = 32;
+ saa5050_state.saa5050_forecol = SAA5050_WHITE;
+ saa5050_state.saa5050_prvcol = SAA5050_WHITE;
+ saa5050_state.saa5050_backcol = SAA5050_BLACK;
+
+ for (sx = 0; sx < 42; sx++)
+ {
+ int blank = 0;
+ code = saa5050_vidram[sy * 64 + sx];
+ if (code < 32)
+ {
+ switch (code) {
+ case 0x00:
+ blank = 1; // code 0x00 should not display anything
+ break; // unless HOLDGR is set
+ case 0x01: case 0x02: case 0x03: case 0x04:
+ case 0x05: case 0x06: case 0x07:
+ saa5050_state.saa5050_prvcol = saa5050_state.saa5050_forecol = code;
+ saa5050_state.saa5050_flags &= ~(SAA5050_GRAPH | SAA5050_CONCEAL);
+ break;
+ case 0x11: case 0x12: case 0x13: case 0x14:
+ case 0x15: case 0x16: case 0x17:
+ saa5050_state.saa5050_prvcol = (saa5050_state.saa5050_forecol =
+ (code & 0x07));
+ saa5050_state.saa5050_flags &= ~SAA5050_CONCEAL;
+ saa5050_state.saa5050_flags |= SAA5050_GRAPH;
+ break;
+ case 0x08:
+ saa5050_state.saa5050_flags |= SAA5050_FLASH;
+ break;
+ case 0x09:
+ saa5050_state.saa5050_flags &= ~SAA5050_FLASH;
+ break;
+ case 0x0a:
+ saa5050_state.saa5050_flags |= SAA5050_BOX;
+ break;
+ case 0x0b:
+ saa5050_state.saa5050_flags &= ~SAA5050_BOX;
+ break;
+ case 0x0c:
+ saa5050_state.saa5050_flags &= ~SAA5050_DBLHI;
+ break;
+ case 0x0d:
+ saa5050_state.saa5050_flags |= SAA5050_DBLHI;
+ break;
+ case 0x18:
+ saa5050_state.saa5050_flags |= SAA5050_CONCEAL;
+ break;
+ case 0x19:
+ saa5050_state.saa5050_flags |= SAA5050_SEPGR;
+ break;
+ case 0x1a:
+ saa5050_state.saa5050_flags &= ~SAA5050_SEPGR;
+ break;
+ case 0x1c:
+ saa5050_state.saa5050_backcol = SAA5050_BLACK;
+ break;
+ case 0x1d:
+ saa5050_state.saa5050_backcol = saa5050_state.saa5050_prvcol;
+ break;
+ case 0x1e:
+ saa5050_state.saa5050_flags |= SAA5050_HOLDGR;
+ break;
+ case 0x1f:
+ saa5050_state.saa5050_flags &= ~SAA5050_HOLDGR;
+ break;
+ }
+ if (saa5050_state.saa5050_flags & SAA5050_HOLDGR)
+ code = saa5050_state.saa5050_prvchr;
+ else
+ code = 32;
+ }
+
+ if (code & 0x80)
+ colour = (saa5050_state.saa5050_forecol << 3) | saa5050_state.saa5050_backcol;
+ else
+ colour = saa5050_state.saa5050_forecol | (saa5050_state.saa5050_backcol << 3);
+
+ if (saa5050_state.saa5050_flags & SAA5050_CONCEAL)
+ code = 32;
+ else if ((saa5050_state.saa5050_flags & SAA5050_FLASH) && (frame_count > 38))
+ code = 32;
+ else
+ {
+ saa5050_state.saa5050_prvchr = code;
+ if ((saa5050_state.saa5050_flags & SAA5050_GRAPH) && (code & 0x20))
+ {
+ code += (code & 0x40) ? 64 : 96;
+ if (saa5050_state.saa5050_flags & SAA5050_SEPGR)
+ code += 64;
+ }
+ }
+
+ if((blank == 0) || (saa5050_state.saa5050_flags & SAA5050_HOLDGR))
+ {
+ if (saa5050_state.saa5050_flags & SAA5050_DBLHI)
+ {
+ drawgfx (bitmap, machine->gfx[4], code, colour, 0, 0,
+ sx * 6, sy * 10, &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ drawgfx (bitmap, machine->gfx[5], code, colour, 0, 0,
+ sx * 6, (sy + 1) * 10, &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ }
+ else
+ {
+ drawgfx (bitmap, machine->gfx[3], code, colour, 0, 0,
+ sx * 6, sy * 10, &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ }
+ }
+ }
+ if (saa5050_state.saa5050_flags & SAA5050_DBLHI)
+ {
+ sy--;
+ saa5050_state.saa5050_flags &= ~SAA5050_DBLHI;
+ }
+ }
+
+ frame_count++;
+ if(frame_count > 50)
+ frame_count = 0;
+
+ // playfield - not sure exactly how this works...
+ for(x = 0;x < 16;x++)
+ for(y = 0; y < 16;y++)
+ {
+ sx = ((x*16-48) - malzak_x);
+ sy = ((y*16) - malzak_y);
+
+ if(sx < -271)
+ sx+=512;
+ if(sx < -15)
+ sx+=256;
+
+ drawgfx(bitmap,machine->gfx[0],field[x*16 + y].code,7,0,0,
+ sx, sy, &machine->screen[0].visarea, TRANSPARENCY_COLOR, 0);
+ }
+
+ // S2636 - Sprites / Collision detection (x2)
+
+ s2636_x_offset = -16;
+// s2636_y_offset = -8;
+
+ s2636_update_bitmap(machine,bitmap,s2636_1_ram,s2636_1_dirty,1,collision_bitmap);
+ s2636_update_bitmap(machine,bitmap,s2636_2_ram,s2636_2_dirty,2,collision_bitmap);
+ return 0;
+}
+
+WRITE8_HANDLER( playfield_w )
+{
+ int tile = ((malzak_x / 16) * 16) + (offset / 16);
+
+// field[tile].x = malzak_x / 16;
+// field[tile].y = malzak_y;
+ field[tile].code = (data & 0x1f);
+ logerror("GFX: 0x16%02x write 0x%02x\n",offset,data);
+}
diff --git a/src/mame/video/mappy.c b/src/mame/video/mappy.c
new file mode 100644
index 00000000000..2dfdc872d18
--- /dev/null
+++ b/src/mame/video/mappy.c
@@ -0,0 +1,590 @@
+#include "driver.h"
+#include "video/resnet.h"
+
+
+UINT8 *mappy_videoram;
+UINT8 *mappy_spriteram;
+
+static UINT8 mappy_scroll;
+static tilemap *bg_tilemap;
+
+static mame_bitmap *sprite_bitmap;
+
+static colortable *mappy_colortable;
+
+
+/***************************************************************************
+
+ Convert the color PROMs.
+
+ All games except Phozon have one 32x8 palette PROM and two 256x4 color
+ lookup table PROMs (one for characters, one for sprites), except todruaga
+ which has a larger 1024x4 PROM for sprites.
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+ The way how the lookup tables are mapped to palette colors, and priority
+ handling, are controlled by a PAL (SPV-5 in Super Pacman, MPI-4 in Mappy),
+ so the two hardwares work differently.
+ Super Pacman has a special "super priority" for sprite colors, allowing
+ one pen to be over high priority tiles (used by Pac & Pal for ghost eyes),
+ which isn't present in Mappy.
+
+***************************************************************************/
+
+PALETTE_INIT( superpac )
+{
+ static const int resistances[3] = { 1000, 470, 220 };
+ double rweights[3], gweights[3], bweights[2];
+ int i;
+
+ /* compute the color output resistor weights */
+ compute_resistor_weights(0, 255, -1.0,
+ 3, &resistances[0], rweights, 0, 0,
+ 3, &resistances[0], gweights, 0, 0,
+ 2, &resistances[1], bweights, 0, 0);
+
+ /* allocate the colortable */
+ mappy_colortable = colortable_alloc(machine, 32);
+
+ /* create a lookup table for the palette */
+ for (i = 0; i < 32; i++)
+ {
+ int bit0, bit1, bit2;
+ int r, g, b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = combine_3_weights(rweights, bit0, bit1, bit2);
+
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = combine_3_weights(gweights, bit0, bit1, bit2);
+
+ /* blue component */
+ bit0 = (color_prom[i] >> 6) & 0x01;
+ bit1 = (color_prom[i] >> 7) & 0x01;
+ b = combine_2_weights(bweights, bit0, bit1);
+
+ colortable_palette_set_color(mappy_colortable, i, MAKE_RGB(r, g, b));
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+ color_prom += 32;
+
+ /* characters map to the upper 16 palette entries */
+ for (i = 0; i < 64*4; i++)
+ {
+ UINT8 ctabentry = color_prom[i] & 0x0f;
+ colortable_entry_set_value(mappy_colortable, i, (ctabentry ^ 15) + 0x10);
+ }
+
+ /* sprites map to the lower 16 palette entries */
+ for (i = 64*4; i < 128*4; i++)
+ {
+ UINT8 ctabentry = color_prom[i] & 0x0f;
+ colortable_entry_set_value(mappy_colortable, i, ctabentry);
+ }
+}
+
+PALETTE_INIT( mappy )
+{
+ static const int resistances[3] = { 1000, 470, 220 };
+ double rweights[3], gweights[3], bweights[2];
+ int i;
+
+ /* compute the color output resistor weights */
+ compute_resistor_weights(0, 255, -1.0,
+ 3, &resistances[0], rweights, 0, 0,
+ 3, &resistances[0], gweights, 0, 0,
+ 2, &resistances[1], bweights, 0, 0);
+
+ /* allocate the colortable */
+ mappy_colortable = colortable_alloc(machine, 32);
+
+ /* create a lookup table for the palette */
+ for (i = 0; i < 32; i++)
+ {
+ int bit0, bit1, bit2;
+ int r, g, b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = combine_3_weights(rweights, bit0, bit1, bit2);
+
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = combine_3_weights(gweights, bit0, bit1, bit2);
+
+ /* blue component */
+ bit0 = (color_prom[i] >> 6) & 0x01;
+ bit1 = (color_prom[i] >> 7) & 0x01;
+ b = combine_2_weights(bweights, bit0, bit1);
+
+ colortable_palette_set_color(mappy_colortable, i, MAKE_RGB(r, g, b));
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+ color_prom += 32;
+
+ /* characters map to the upper 16 palette entries */
+ for (i = 0*4; i < 64*4; i++)
+ {
+ UINT8 ctabentry = color_prom[i] & 0x0f;
+ colortable_entry_set_value(mappy_colortable, i, ctabentry + 0x10);
+ }
+
+ /* sprites map to the lower 16 palette entries */
+ for (i = 64*4; i < machine->drv->total_colors; i++)
+ {
+ UINT8 ctabentry = color_prom[i] & 0x0f;
+ colortable_entry_set_value(mappy_colortable, i, ctabentry);
+ }
+}
+
+
+/***************************************************************************
+
+ In Phozon, the palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+
+PALETTE_INIT( phozon )
+{
+ static const int resistances[4] = { 2200, 1000, 470, 220 };
+ double rweights[4], gweights[4], bweights[4];
+ int i;
+
+ /* compute the color output resistor weights */
+ compute_resistor_weights(0, 255, -1.0,
+ 4, &resistances[0], rweights, 0, 0,
+ 4, &resistances[0], gweights, 0, 0,
+ 4, &resistances[0], bweights, 0, 0);
+
+ /* allocate the colortable */
+ mappy_colortable = colortable_alloc(machine, 32);
+
+ /* create a lookup table for the palette */
+ for (i = 0; i < 32; i++)
+ {
+ int bit0, bit1, bit2, bit3;
+ int r, g, b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ bit3 = (color_prom[i] >> 3) & 0x01;
+ r = combine_4_weights(rweights, bit0, bit1, bit2, bit3);
+
+ /* green component */
+ bit0 = (color_prom[i + 0x100] >> 0) & 0x01;
+ bit1 = (color_prom[i + 0x100] >> 1) & 0x01;
+ bit2 = (color_prom[i + 0x100] >> 2) & 0x01;
+ bit3 = (color_prom[i + 0x100] >> 3) & 0x01;
+ g = combine_4_weights(gweights, bit0, bit1, bit2, bit3);
+
+ /* blue component */
+ bit0 = (color_prom[i + 0x200] >> 0) & 0x01;
+ bit1 = (color_prom[i + 0x200] >> 1) & 0x01;
+ bit2 = (color_prom[i + 0x200] >> 2) & 0x01;
+ bit3 = (color_prom[i + 0x200] >> 3) & 0x01;
+ b = combine_4_weights(bweights, bit0, bit1, bit2, bit3);
+
+ colortable_palette_set_color(mappy_colortable, i, MAKE_RGB(r, g, b));
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+ color_prom += 0x300;
+
+ /* characters map to the lower 16 palette entries */
+ for (i = 0; i < 64*4; i++)
+ {
+ UINT8 ctabentry = color_prom[i] & 0x0f;
+ colortable_entry_set_value(mappy_colortable, i, ctabentry);
+ }
+
+ /* sprites map to the upper 16 palette entries */
+ for (i = 64*4; i < 128*4; i++)
+ {
+ UINT8 ctabentry = color_prom[i] & 0x0f;
+ colortable_entry_set_value(mappy_colortable, i, ctabentry + 0x10);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/* convert from 32x32 to 36x28 */
+static TILEMAP_MAPPER( superpac_tilemap_scan )
+{
+ int offs;
+
+ row += 2;
+ col -= 2;
+ if (col & 0x20)
+ offs = row + ((col & 0x1f) << 5);
+ else
+ offs = col + (row << 5);
+
+ return offs;
+}
+
+/* tilemap is a composition of a 32x60 scrolling portion and two 2x28 fixed portions on the sides */
+static TILEMAP_MAPPER( mappy_tilemap_scan )
+{
+ int offs;
+
+ col -= 2;
+ if (col & 0x20)
+ {
+ /* in the following code, note the +2 followed by & 0x0f. This causes unintuitive
+ mapping from logical to hardware coordinates, which is true to the hardware.
+ Not doing it that way would cause missing tiles in motos and todruaga */
+ if (row & 0x20)
+ offs = 0x7ff; // outside visible area
+ else
+ offs = ((row + 2) & 0x0f) + (row & 0x10) + ((col & 3) << 5) + 0x780;
+ }
+ else
+ offs = col + (row << 5);
+
+ return offs;
+}
+
+static TILE_GET_INFO( superpac_get_tile_info )
+{
+ UINT8 attr = mappy_videoram[tile_index + 0x400];
+ tileinfo->category = (attr & 0x40) >> 6;
+ tileinfo->group = attr & 0x3f;
+ SET_TILE_INFO(
+ 0,
+ mappy_videoram[tile_index],
+ attr & 0x3f,
+ 0);
+}
+
+static TILE_GET_INFO( phozon_get_tile_info )
+{
+ UINT8 attr = mappy_videoram[tile_index + 0x400];
+ tileinfo->category = (attr & 0x40) >> 6;
+ tileinfo->group = attr & 0x3f;
+ SET_TILE_INFO(
+ 0,
+ mappy_videoram[tile_index] + ((attr & 0x80) << 1),
+ attr & 0x3f,
+ 0);
+}
+
+static TILE_GET_INFO( mappy_get_tile_info )
+{
+ UINT8 attr = mappy_videoram[tile_index + 0x800];
+ tileinfo->category = (attr & 0x40) >> 6;
+ tileinfo->group = attr & 0x3f;
+ SET_TILE_INFO(
+ 0,
+ mappy_videoram[tile_index],
+ attr & 0x3f,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( superpac )
+{
+ bg_tilemap = tilemap_create(superpac_get_tile_info,superpac_tilemap_scan,TILEMAP_TYPE_PEN,8,8,36,28);
+ sprite_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ colortable_configure_tilemap_groups(mappy_colortable, bg_tilemap, machine->gfx[0], 31);
+
+ spriteram = mappy_spriteram + 0x780;
+ spriteram_2 = spriteram + 0x800;
+ spriteram_3 = spriteram_2 + 0x800;
+}
+
+VIDEO_START( phozon )
+{
+ bg_tilemap = tilemap_create(phozon_get_tile_info,superpac_tilemap_scan,TILEMAP_TYPE_PEN,8,8,36,28);
+
+ colortable_configure_tilemap_groups(mappy_colortable, bg_tilemap, machine->gfx[0], 15);
+
+ spriteram = mappy_spriteram + 0x780;
+ spriteram_2 = spriteram + 0x800;
+ spriteram_3 = spriteram_2 + 0x800;
+}
+
+VIDEO_START( mappy )
+{
+ bg_tilemap = tilemap_create(mappy_get_tile_info,mappy_tilemap_scan,TILEMAP_TYPE_PEN,8,8,36,60);
+
+ colortable_configure_tilemap_groups(mappy_colortable, bg_tilemap, machine->gfx[0], 31);
+ tilemap_set_scroll_cols(bg_tilemap, 36);
+
+ spriteram = mappy_spriteram + 0x780;
+ spriteram_2 = spriteram + 0x800;
+ spriteram_3 = spriteram_2 + 0x800;
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( superpac_videoram_w )
+{
+ mappy_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( mappy_videoram_w )
+{
+ mappy_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x7ff);
+}
+
+WRITE8_HANDLER( superpac_flipscreen_w )
+{
+ flip_screen_set(data & 1);
+}
+
+READ8_HANDLER( superpac_flipscreen_r )
+{
+ flip_screen_set(1);
+ return 0xff;
+}
+
+WRITE8_HANDLER( mappy_scroll_w )
+{
+ mappy_scroll = offset >> 3;
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+/* also used by toypop.c */
+void mappy_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int xoffs, int yoffs, colortable *ctable, int transcolor)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x80;offs += 2)
+ {
+ /* is it on? */
+ if ((spriteram_3[offs+1] & 2) == 0)
+ {
+ static const UINT8 gfx_offs[2][2] =
+ {
+ { 0, 1 },
+ { 2, 3 }
+ };
+ int sprite = spriteram[offs];
+ int color = spriteram[offs+1];
+ int sx = spriteram_2[offs+1] + 0x100 * (spriteram_3[offs+1] & 1) - 40 + xoffs;
+ int sy = 256 - spriteram_2[offs] + yoffs + 1; // sprites are buffered and delayed by one scanline
+ int flipx = (spriteram_3[offs] & 0x01);
+ int flipy = (spriteram_3[offs] & 0x02) >> 1;
+ int sizex = (spriteram_3[offs] & 0x04) >> 2;
+ int sizey = (spriteram_3[offs] & 0x08) >> 3;
+ int x,y;
+
+ sprite &= ~sizex;
+ sprite &= ~(sizey << 1);
+
+ if (flip_screen)
+ {
+ flipx ^= 1;
+ flipy ^= 1;
+ }
+
+ sy -= 16 * sizey;
+ sy = (sy & 0xff) - 32; // fix wraparound
+
+ for (y = 0;y <= sizey;y++)
+ {
+ for (x = 0;x <= sizex;x++)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ sprite + gfx_offs[y ^ (sizey * flipy)][x ^ (sizex * flipx)],
+ color,
+ flipx,flipy,
+ sx + 16*x,sy + 16*y,
+ cliprect,TRANSPARENCY_PENS,
+ colortable_get_transpen_mask(ctable, machine->gfx[1], color, transcolor));
+ }
+ }
+ }
+ }
+}
+
+
+/*
+sprite format:
+
+spriteram
+0 xxxxxxxx tile number
+1 --xxxxxx color
+
+spriteram_2
+0 xxxxxxxx Y position
+1 xxxxxxxx X position
+
+spriteram_3
+0 xx------ tile number LSB
+0 --xx---- Y size (16, 8, 32, 4?)
+0 ----xx-- X size (16, 8, 32, 4?)
+0 ------x- Y flip
+0 -------x X flip
+1 ------x- disable
+1 -------x X position MSB
+*/
+
+static void phozon_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = 0;offs < 0x80;offs += 2)
+ {
+ /* is it on? */
+ if ((spriteram_3[offs+1] & 2) == 0)
+ {
+ static const UINT8 size[4] = { 1, 0, 3, 0 }; /* 16, 8, 32 pixels; fourth combination unused? */
+ static const UINT8 gfx_offs[4][4] =
+ {
+ { 0, 1, 4, 5 },
+ { 2, 3, 6, 7 },
+ { 8, 9,12,13 },
+ {10,11,14,15 }
+ };
+ int sprite = (spriteram[offs] << 2) | ((spriteram_3[offs] & 0xc0) >> 6);
+ int color = spriteram[offs+1] & 0x3f;
+ int sx = spriteram_2[offs+1] + 0x100 * (spriteram_3[offs+1] & 1) - 69;
+ int sy = 256 - spriteram_2[offs];
+ int flipx = (spriteram_3[offs] & 0x01);
+ int flipy = (spriteram_3[offs] & 0x02) >> 1;
+ int sizex = size[(spriteram_3[offs] & 0x0c) >> 2];
+ int sizey = size[(spriteram_3[offs] & 0x30) >> 4];
+ int x,y;
+
+ if (flip_screen)
+ {
+ flipx ^= 1;
+ flipy ^= 1;
+ }
+
+ sy -= 8 * sizey;
+ sy = (sy & 0xff) - 32; // fix wraparound
+
+ for (y = 0;y <= sizey;y++)
+ {
+ for (x = 0;x <= sizex;x++)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ sprite + gfx_offs[y ^ (sizey * flipy)][x ^ (sizex * flipx)],
+ color,
+ flipx,flipy,
+ sx + 8*x,sy + 8*y,
+ cliprect,TRANSPARENCY_PENS,
+ colortable_get_transpen_mask(mappy_colortable, machine->gfx[1], color, 31));
+ }
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( superpac )
+{
+ int x,y;
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0|TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,1|TILEMAP_DRAW_OPAQUE,0);
+
+ fillbitmap(sprite_bitmap,15,cliprect);
+ mappy_draw_sprites(machine,sprite_bitmap,cliprect,0,0,mappy_colortable,15);
+ copybitmap(bitmap,sprite_bitmap,0,0,0,0,cliprect,TRANSPARENCY_PEN,15);
+
+ /* Redraw the high priority characters */
+ tilemap_draw(bitmap,cliprect,bg_tilemap,1,0);
+
+ /* sprite color 0 still has priority over that (ghost eyes in Pac 'n Pal) */
+ for (y = 0;y < sprite_bitmap->height;y++)
+ {
+ for (x = 0;x < sprite_bitmap->width;x++)
+ {
+ if (*BITMAP_ADDR16(sprite_bitmap, y, x) == 0)
+ *BITMAP_ADDR16(bitmap, y, x) = 0;
+ }
+ }
+ return 0;
+}
+
+VIDEO_UPDATE( phozon )
+{
+ /* flip screen control is embedded in RAM */
+ flip_screen_set(mappy_spriteram[0x1f7f-0x800] & 1);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0|TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,1|TILEMAP_DRAW_OPAQUE,0);
+
+ phozon_draw_sprites(machine,bitmap,cliprect);
+
+ /* Redraw the high priority characters */
+ tilemap_draw(bitmap,cliprect,bg_tilemap,1,0);
+ return 0;
+}
+
+VIDEO_UPDATE( mappy )
+{
+ int offs;
+
+ for (offs = 2;offs < 34;offs++)
+ tilemap_set_scrolly(bg_tilemap,offs,mappy_scroll);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0|TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,1|TILEMAP_DRAW_OPAQUE,0);
+
+ mappy_draw_sprites(machine,bitmap,cliprect,0,0,mappy_colortable,15);
+
+ /* Redraw the high priority characters */
+ tilemap_draw(bitmap,cliprect,bg_tilemap,1,0);
+ return 0;
+}
diff --git a/src/mame/video/marineb.c b/src/mame/video/marineb.c
new file mode 100644
index 00000000000..ce8f1ee5530
--- /dev/null
+++ b/src/mame/video/marineb.c
@@ -0,0 +1,472 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/espial.h"
+
+
+UINT8 *marineb_videoram;
+UINT8 *marineb_colorram;
+UINT8 marineb_active_low_flipscreen;
+
+static UINT8 column_scroll;
+static UINT8 palette_bank;
+static UINT8 flipscreen_x;
+static UINT8 flipscreen_y;
+static tilemap *bg_tilemap;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 code = marineb_videoram[tile_index];
+ UINT8 col = marineb_colorram[tile_index];
+
+ SET_TILE_INFO(0,
+ code | ((col & 0xc0) << 2),
+ (col & 0x0f) | (palette_bank << 4),
+ TILE_FLIPXY((col >> 4) & 0x03));
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( marineb )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+}
+
+
+
+/*************************************
+ *
+ * Memory handlers
+ *
+ *************************************/
+
+WRITE8_HANDLER( marineb_videoram_w )
+{
+ marineb_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( marineb_colorram_w )
+{
+ marineb_colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( marineb_column_scroll_w )
+{
+ column_scroll = data;
+}
+
+
+WRITE8_HANDLER( marineb_palette_bank_0_w )
+{
+ UINT8 old = palette_bank;
+
+ palette_bank = (palette_bank & 0x02) | ((data & 0x01) << 0);
+
+ if (old != palette_bank)
+ {
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+
+WRITE8_HANDLER( marineb_palette_bank_1_w )
+{
+ UINT8 old = palette_bank;
+
+ palette_bank = (palette_bank & 0x01) | ((data & 0x01) << 1);
+
+ if (old != palette_bank)
+ {
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+
+WRITE8_HANDLER( marineb_flipscreen_x_w )
+{
+ flipscreen_x = data ^ marineb_active_low_flipscreen;
+
+ tilemap_set_flip(bg_tilemap, (flipscreen_x ? TILEMAP_FLIPX : 0) | (flipscreen_y ? TILEMAP_FLIPY : 0));
+}
+
+
+WRITE8_HANDLER( marineb_flipscreen_y_w )
+{
+ flipscreen_y = data ^ marineb_active_low_flipscreen;
+
+ tilemap_set_flip(bg_tilemap, (flipscreen_x ? TILEMAP_FLIPX : 0) | (flipscreen_y ? TILEMAP_FLIPY : 0));
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+static void set_tilemap_scrolly(int cols)
+{
+ int col;
+
+ for (col = 0; col < cols; col++)
+ tilemap_set_scrolly(bg_tilemap, col, column_scroll);
+
+ for (; col < 32; col++)
+ tilemap_set_scrolly(bg_tilemap, col, 0);
+}
+
+
+VIDEO_UPDATE( marineb )
+{
+ int offs;
+
+
+ set_tilemap_scrolly(24);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+
+ /* draw the sprites */
+ for (offs = 0x0f; offs >= 0; offs--)
+ {
+ int gfx,sx,sy,code,col,flipx,flipy,offs2;
+
+
+ if ((offs == 0) || (offs == 2)) continue; /* no sprites here */
+
+
+ if (offs < 8)
+ {
+ offs2 = 0x0018 + offs;
+ }
+ else
+ {
+ offs2 = 0x03d8 - 8 + offs;
+ }
+
+
+ code = marineb_videoram[offs2];
+ sx = marineb_videoram[offs2 + 0x20];
+ sy = marineb_colorram[offs2];
+ col = (marineb_colorram[offs2 + 0x20] & 0x0f) + 16 * palette_bank;
+ flipx = code & 0x02;
+ flipy = !(code & 0x01);
+
+ if (offs < 4)
+ {
+ /* big sprite */
+ gfx = 2;
+ code = (code >> 4) | ((code & 0x0c) << 2);
+ }
+ else
+ {
+ /* small sprite */
+ gfx = 1;
+ code >>= 2;
+ }
+
+ if (!flipscreen_y)
+ {
+ sy = 256 - machine->gfx[gfx]->width - sy;
+ flipy = !flipy;
+ }
+
+ if (flipscreen_x)
+ {
+ sx++;
+ }
+
+ drawgfx(bitmap,machine->gfx[gfx],
+ code,
+ col,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( changes )
+{
+ int offs,sx,sy,code,col,flipx,flipy;
+
+
+ set_tilemap_scrolly(26);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+
+ /* draw the small sprites */
+ for (offs = 0x05; offs >= 0; offs--)
+ {
+ int offs2;
+
+
+ offs2 = 0x001a + offs;
+
+ code = marineb_videoram[offs2];
+ sx = marineb_videoram[offs2 + 0x20];
+ sy = marineb_colorram[offs2];
+ col = (marineb_colorram[offs2 + 0x20] & 0x0f) + 16 * palette_bank;
+ flipx = code & 0x02;
+ flipy = !(code & 0x01);
+
+ if (!flipscreen_y)
+ {
+ sy = 256 - machine->gfx[1]->width - sy;
+ flipy = !flipy;
+ }
+
+ if (flipscreen_x)
+ {
+ sx++;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code >> 2,
+ col,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ /* draw the big sprite */
+
+ code = marineb_videoram[0x3df];
+ sx = marineb_videoram[0x3ff];
+ sy = marineb_colorram[0x3df];
+ col = marineb_colorram[0x3ff];
+ flipx = code & 0x02;
+ flipy = !(code & 0x01);
+
+ if (!flipscreen_y)
+ {
+ sy = 256 - machine->gfx[2]->width - sy;
+ flipy = !flipy;
+ }
+
+ if (flipscreen_x)
+ {
+ sx++;
+ }
+
+ code >>= 4;
+
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ col,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ /* draw again for wrap around */
+
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ col,
+ flipx,flipy,
+ sx-256,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( springer )
+{
+ int offs;
+
+
+ set_tilemap_scrolly(0);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+
+ /* draw the sprites */
+ for (offs = 0x0f; offs >= 0; offs--)
+ {
+ int gfx,sx,sy,code,col,flipx,flipy,offs2;
+
+
+ if ((offs == 0) || (offs == 2)) continue; /* no sprites here */
+
+
+ offs2 = 0x0010 + offs;
+
+
+ code = marineb_videoram[offs2];
+ sx = 240 - marineb_videoram[offs2 + 0x20];
+ sy = marineb_colorram[offs2];
+ col = (marineb_colorram[offs2 + 0x20] & 0x0f) + 16 * palette_bank;
+ flipx = !(code & 0x02);
+ flipy = !(code & 0x01);
+
+ if (offs < 4)
+ {
+ /* big sprite */
+ sx -= 0x10;
+ gfx = 2;
+ code = (code >> 4) | ((code & 0x0c) << 2);
+ }
+ else
+ {
+ /* small sprite */
+ gfx = 1;
+ code >>= 2;
+ }
+
+ if (!flipscreen_y)
+ {
+ sy = 256 - machine->gfx[gfx]->width - sy;
+ flipy = !flipy;
+ }
+
+ if (!flipscreen_x)
+ {
+ sx--;
+ }
+
+ drawgfx(bitmap,machine->gfx[gfx],
+ code,
+ col,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( hoccer )
+{
+ int offs;
+
+
+ set_tilemap_scrolly(0);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+
+ /* draw the sprites */
+ for (offs = 0x07; offs >= 0; offs--)
+ {
+ int sx,sy,code,col,flipx,flipy,offs2;
+
+
+ offs2 = 0x0018 + offs;
+
+
+ code = spriteram[offs2];
+ sx = spriteram[offs2 + 0x20];
+ sy = marineb_colorram[offs2];
+ col = marineb_colorram[offs2 + 0x20];
+ flipx = code & 0x02;
+ flipy = !(code & 0x01);
+
+ if (!flipscreen_y)
+ {
+ sy = 256 - machine->gfx[1]->width - sy;
+ flipy = !flipy;
+ }
+
+ if (flipscreen_x)
+ {
+ sx = 256 - machine->gfx[1]->width - sx;
+ flipx = !flipx;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code >> 2,
+ col,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( hopprobo )
+{
+ int offs;
+
+
+ set_tilemap_scrolly(0);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+
+ /* draw the sprites */
+ for (offs = 0x0f; offs >= 0; offs--)
+ {
+ int gfx,sx,sy,code,col,flipx,flipy,offs2;
+
+
+ if ((offs == 0) || (offs == 2)) continue; /* no sprites here */
+
+
+ offs2 = 0x0010 + offs;
+
+
+ code = marineb_videoram[offs2];
+ sx = marineb_videoram[offs2 + 0x20];
+ sy = marineb_colorram[offs2];
+ col = (marineb_colorram[offs2 + 0x20] & 0x0f) + 16 * palette_bank;
+ flipx = code & 0x02;
+ flipy = !(code & 0x01);
+
+ if (offs < 4)
+ {
+ /* big sprite */
+ gfx = 2;
+ code = (code >> 4) | ((code & 0x0c) << 2);
+ }
+ else
+ {
+ /* small sprite */
+ gfx = 1;
+ code >>= 2;
+ }
+
+ if (!flipscreen_y)
+ {
+ sy = 256 - machine->gfx[gfx]->width - sy;
+ flipy = !flipy;
+ }
+
+ if (!flipscreen_x)
+ {
+ sx--;
+ }
+
+ drawgfx(bitmap,machine->gfx[gfx],
+ code,
+ col,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/mario.c b/src/mame/video/mario.c
new file mode 100644
index 00000000000..ac9ac5bbb3a
--- /dev/null
+++ b/src/mame/video/mario.c
@@ -0,0 +1,157 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static UINT8 gfx_bank, palette_bank;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Mario Bros. has a 512x8 palette PROM; interstingly, bytes 0-255 contain an
+ inverted palette, as other Nintendo games like Donkey Kong, while bytes
+ 256-511 contain a non inverted palette. This was probably done to allow
+ connection to both the special Nintendo and a standard monitor.
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- inverter -- RED
+ -- 470 ohm resistor -- inverter -- RED
+ -- 1 kohm resistor -- inverter -- RED
+ -- 220 ohm resistor -- inverter -- GREEN
+ -- 470 ohm resistor -- inverter -- GREEN
+ -- 1 kohm resistor -- inverter -- GREEN
+ -- 220 ohm resistor -- inverter -- BLUE
+ bit 0 -- 470 ohm resistor -- inverter -- BLUE
+
+***************************************************************************/
+PALETTE_INIT( mario )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (*color_prom >> 5) & 1;
+ bit1 = (*color_prom >> 6) & 1;
+ bit2 = (*color_prom >> 7) & 1;
+ r = 255 - (0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2);
+ /* green component */
+ bit0 = (*color_prom >> 2) & 1;
+ bit1 = (*color_prom >> 3) & 1;
+ bit2 = (*color_prom >> 4) & 1;
+ g = 255 - (0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2);
+ /* blue component */
+ bit0 = (*color_prom >> 0) & 1;
+ bit1 = (*color_prom >> 1) & 1;
+ b = 255 - (0x55 * bit0 + 0xaa * bit1);
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* characters use the same palette as sprites, however characters */
+ /* use only colors 64-127 and 192-255. */
+ for (i = 0;i < 8;i++)
+ {
+ COLOR(0,4*i) = 8*i + 64;
+ COLOR(0,4*i+1) = 8*i+1 + 64;
+ COLOR(0,4*i+2) = 8*i+2 + 64;
+ COLOR(0,4*i+3) = 8*i+3 + 64;
+ }
+ for (i = 0;i < 8;i++)
+ {
+ COLOR(0,4*i+8*4) = 8*i + 192;
+ COLOR(0,4*i+8*4+1) = 8*i+1 + 192;
+ COLOR(0,4*i+8*4+2) = 8*i+2 + 192;
+ COLOR(0,4*i+8*4+3) = 8*i+3 + 192;
+ }
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = i;
+}
+
+WRITE8_HANDLER( mario_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( mario_gfxbank_w )
+{
+ if (gfx_bank != (data & 0x01))
+ {
+ gfx_bank = data & 0x01;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( mario_palettebank_w )
+{
+ if (palette_bank != (data & 0x01))
+ {
+ palette_bank = data & 0x01;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( mario_scroll_w )
+{
+ tilemap_set_scrolly(bg_tilemap, 0, data + 17);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + 256 * gfx_bank;
+ int color = (videoram[tile_index] >> 5) + 8 * palette_bank;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( mario )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ state_save_register_global(gfx_bank);
+ state_save_register_global(palette_bank);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ if (spriteram[offs])
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ spriteram[offs + 2],
+ (spriteram[offs + 1] & 0x0f) + 16 * palette_bank,
+ spriteram[offs + 1] & 0x80,spriteram[offs + 1] & 0x40,
+ spriteram[offs + 3] - 8,240 - spriteram[offs] + 8,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( mario )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/markham.c b/src/mame/video/markham.c
new file mode 100644
index 00000000000..c63b9ccd3d6
--- /dev/null
+++ b/src/mame/video/markham.c
@@ -0,0 +1,139 @@
+/******************************************************************************
+
+Markham (c) 1983 Sun Electronics
+
+Video hardware driver by Uki
+
+ 17/Jun/2001 -
+
+******************************************************************************/
+
+#include "driver.h"
+
+static UINT8 markham_xscroll[2];
+
+static tilemap *bg_tilemap;
+
+PALETTE_INIT( markham )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int r = color_prom[0];
+ int g = color_prom[machine->drv->total_colors];
+ int b = color_prom[2*machine->drv->total_colors];
+
+ palette_set_color_rgb(machine,i,pal4bit(r),pal4bit(g),pal4bit(b));
+ color_prom++;
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* sprites lookup table */
+ for (i=0; i<512; i++)
+ *(colortable++) = *(color_prom++);
+
+ /* bg lookup table */
+ for (i=0; i<512; i++)
+ *(colortable++) = *(color_prom++);
+
+}
+
+WRITE8_HANDLER( markham_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+WRITE8_HANDLER( markham_scroll_x_w )
+{
+ markham_xscroll[offset] = data;
+}
+
+WRITE8_HANDLER( markham_flipscreen_w )
+{
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = videoram[tile_index * 2];
+ int code = videoram[(tile_index * 2) + 1] + ((attr & 0x60) << 3);
+ int color = (attr & 0x1f) | ((attr & 0x80) >> 2);
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( markham )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_scroll_rows(bg_tilemap, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs=0x60; offs<0x100; offs +=4)
+ {
+ int chr = spriteram[offs+1];
+ int col = spriteram[offs+2];
+
+ int fx = flip_screen;
+ int fy = flip_screen;
+
+ int x = spriteram[offs+3];
+ int y = spriteram[offs+0];
+ int px,py;
+ col &= 0x3f ;
+
+ if (flip_screen==0)
+ {
+ px = x-2;
+ py = 240-y;
+ }
+ else
+ {
+ px = 240-x;
+ py = y;
+ }
+
+ px = px & 0xff;
+
+ if (px>248)
+ px = px-256;
+
+ drawgfx(bitmap,machine->gfx[1],
+ chr,
+ col,
+ fx,fy,
+ px,py,
+ cliprect,TRANSPARENCY_COLOR,0);
+ }
+}
+
+VIDEO_UPDATE( markham )
+{
+ int i;
+
+ for (i = 0; i < 32; i++)
+ {
+ if ((i > 3) && (i<16))
+ tilemap_set_scrollx(bg_tilemap, i, markham_xscroll[0]);
+ if (i >= 16)
+ tilemap_set_scrollx(bg_tilemap, i, markham_xscroll[1]);
+ }
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/marvins.c b/src/mame/video/marvins.c
new file mode 100644
index 00000000000..bf735170ce6
--- /dev/null
+++ b/src/mame/video/marvins.c
@@ -0,0 +1,434 @@
+#include "driver.h"
+#include "cpu/z80/z80.h"
+#include "snk.h"
+
+static int flipscreen, sprite_flip_adjust;
+static tilemap *fg_tilemap, *bg_tilemap, *tx_tilemap;
+static UINT8 bg_color, fg_color, old_bg_color, old_fg_color;
+static rectangle tilemap_clip;
+
+/***************************************************************************
+**
+** Palette Handling:
+**
+** Each color entry is encoded by 12 bits in color proms
+**
+** There are sixteen 8-color sprite palettes
+** sprite palette is selected by a nibble of spriteram
+**
+** There are eight 16-color text layer character palettes
+** character palette is determined by character_number
+**
+** Background and Foreground tilemap layers each have eight 16-color
+** palettes. A palette bank select register is associated with the whole
+** layer.
+**
+***************************************************************************/
+
+WRITE8_HANDLER( marvins_palette_bank_w )
+{
+ bg_color = data>>4;
+ fg_color = data&0xf;
+}
+
+static void stuff_palette( running_machine *machine, int source_index, int dest_index, int num_colors )
+{
+ UINT8 *color_prom = memory_region(REGION_PROMS) + source_index;
+ int i;
+ for( i=0; i<num_colors; i++ )
+ {
+ int bit0=0,bit1,bit2,bit3;
+ int red, green, blue;
+
+ bit0 = (color_prom[0x800] >> 2) & 0x01; // ?
+ bit1 = (color_prom[0x000] >> 1) & 0x01;
+ bit2 = (color_prom[0x000] >> 2) & 0x01;
+ bit3 = (color_prom[0x000] >> 3) & 0x01;
+ red = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[0x800] >> 1) & 0x01; // ?
+ bit1 = (color_prom[0x400] >> 2) & 0x01;
+ bit2 = (color_prom[0x400] >> 3) & 0x01;
+ bit3 = (color_prom[0x000] >> 0) & 0x01;
+ green = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[0x800] >> 0) & 0x01; // ?
+ bit1 = (color_prom[0x800] >> 3) & 0x01; // ?
+ bit2 = (color_prom[0x400] >> 0) & 0x01;
+ bit3 = (color_prom[0x400] >> 1) & 0x01;
+ blue = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color( machine, dest_index++, MAKE_RGB(red, green, blue) );
+ color_prom++;
+ }
+
+ for (i=0; i<=5; i++) gfx_drawmode_table[i] = DRAWMODE_SOURCE;
+
+ gfx_drawmode_table[6] = DRAWMODE_SHADOW;
+ gfx_drawmode_table[7] = DRAWMODE_NONE;
+}
+
+static void update_palette(running_machine *machine, int type )
+{
+ if( bg_color!=old_bg_color )
+ {
+ stuff_palette( machine, 256+16*(bg_color&0x7), (0x11-type)*16, 16 );
+ old_bg_color = bg_color;
+ }
+
+ if( fg_color!=old_fg_color )
+ {
+ stuff_palette( machine, 128+16*(fg_color&0x7), (0x10+type)*16, 16 );
+ old_fg_color = fg_color;
+ }
+}
+
+/***************************************************************************
+**
+** Memory Handlers
+**
+***************************************************************************/
+
+#ifdef UNUSED_FUNCTION
+WRITE8_HANDLER( marvins_spriteram_w )
+{
+ spriteram[offset] = data;
+}
+#endif
+
+WRITE8_HANDLER( marvins_foreground_ram_w )
+{
+ spriteram_2[offset] = data;
+ if (offset < 0x800) tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE8_HANDLER( marvins_background_ram_w )
+{
+ spriteram_3[offset] = data;
+ if (offset < 0x800) tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( marvins_text_ram_w )
+{
+ videoram[offset] = data;
+ if (offset < 0x400) tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+/***************************************************************************
+**
+** Callbacks for Tilemap Manager
+**
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tilemap_info )
+{
+ SET_TILE_INFO(
+ 2,
+ spriteram_3[tile_index],
+ 0,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tilemap_info )
+{
+ SET_TILE_INFO(
+ 1,
+ spriteram_2[tile_index],
+ 0,
+ 0);
+}
+
+static TILE_GET_INFO( get_tx_tilemap_info )
+{
+ int tile_number = videoram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ (tile_number>>5),
+ 0);
+}
+
+/***************************************************************************
+**
+** Video Initialization
+**
+***************************************************************************/
+
+VIDEO_START( marvins )
+{
+ flipscreen = -1; old_bg_color = old_fg_color = -1;
+
+ stuff_palette( machine, 0, 0, 16*8 ); /* load sprite colors */
+ stuff_palette( machine, 16*8*3, 16*8, 16*8 ); /* load text colors */
+
+ fg_tilemap = tilemap_create(get_fg_tilemap_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,64,32);
+ bg_tilemap = tilemap_create(get_bg_tilemap_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,64,32);
+ tx_tilemap = tilemap_create(get_tx_tilemap_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ {
+ tilemap_clip = machine->screen[0].visarea;
+ if (snk_gamegroup != 1) // not Mad Crasher
+ {
+ tilemap_clip.max_x-=16;
+ tilemap_clip.min_x+=16;
+ }
+
+ tilemap_set_transparent_pen(fg_tilemap,0xf);
+ tilemap_set_transparent_pen(bg_tilemap,0xf);
+ tilemap_set_transparent_pen(tx_tilemap,0xf);
+
+ switch (snk_gamegroup)
+ {
+ case 0: // Marvin's Maze
+ tilemap_set_scrolldx( bg_tilemap, 271, 287 );
+ tilemap_set_scrolldy( bg_tilemap, 0, -40 );
+
+ tilemap_set_scrolldx( fg_tilemap, 15, 13+18 );
+ tilemap_set_scrolldy( fg_tilemap, 0, -40 );
+
+ sprite_flip_adjust = 256+182+1;
+ break;
+
+ /*
+ Old settings for the the following games:
+
+ tilemap_set_scrolldx( bg_tilemap, -16, -10 );
+ tilemap_set_scrolldy( bg_tilemap, 0, -40 );
+
+ tilemap_set_scrolldx( fg_tilemap, 16, 22 );
+ tilemap_set_scrolldy( fg_tilemap, 0, -40 );
+
+ Note that while the new settings are more accurate they cannot handle flipscreen.
+ */
+ case 1: // Mad Crasher
+ tilemap_set_scrolldx( bg_tilemap,256, 0 );
+ tilemap_set_scrolldy( bg_tilemap, 12, 0 );
+
+ tilemap_set_scrolldx( fg_tilemap, 0, 0 );
+ tilemap_set_scrolldy( fg_tilemap, 6, 0 );
+ break;
+
+ case 2: // VanguardII
+ tilemap_set_scrolldx( bg_tilemap, 7, 0 );
+ tilemap_set_scrolldy( bg_tilemap,-20, 0 );
+
+ tilemap_set_scrolldx( fg_tilemap, 15, 0 );
+ tilemap_set_scrolldy( fg_tilemap, 0, 0 );
+
+ sprite_flip_adjust = 256+182;
+ break;
+ }
+
+ tilemap_set_scrolldx( tx_tilemap, 16, 16 );
+ tilemap_set_scrolldy( tx_tilemap, 0, 0 );
+ }
+}
+
+/***************************************************************************
+**
+** Screen Refresh
+**
+***************************************************************************/
+
+static void draw_status(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ const UINT8 *base = videoram+0x400;
+ const gfx_element *gfx = machine->gfx[0];
+ int row;
+ for( row=0; row<4; row++ )
+ {
+ int sy,sx = (row&1)*8;
+ const UINT8 *source = base + (row&1)*32;
+ if( row>1 )
+ {
+ sx+=256+16;
+ }
+ else
+ {
+ source+=30*32;
+ }
+
+ for( sy=0; sy<256; sy+=8 )
+ {
+ int tile_number = *source++;
+ drawgfx( bitmap, gfx,
+ tile_number, tile_number>>5,
+ 0,0, /* no flip */
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_NONE, 0xf );
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int scrollx, int scrolly,
+ int priority, UINT8 sprite_partition )
+{
+ const gfx_element *gfx = machine->gfx[3];
+ const UINT8 *source, *finish;
+
+ if( sprite_partition>0x64 ) sprite_partition = 0x64;
+
+ if( priority )
+ {
+ source = spriteram + sprite_partition;
+ finish = spriteram + 0x64;
+ }
+ else
+ {
+ source = spriteram;
+ finish = spriteram + sprite_partition;
+ }
+
+ while( source<finish )
+ {
+ int attributes = source[3]; /* Y?F? CCCC */
+ int tile_number = source[1];
+ int sy = source[0] - scrolly;
+ int sx = source[2] - scrollx + ((attributes&0x80)?256:0);
+ int color = attributes&0xf;
+ int flipy = (attributes&0x20);
+ int flipx = 0;
+
+ if( flipscreen )
+ {
+ if( flipy )
+ {
+ flipx = 1; flipy = 0;
+ }
+ else
+ {
+ flipx = flipy = 1;
+ }
+ sx = sprite_flip_adjust-sx;
+ sy = 246-sy;
+ }
+
+ sx = (256-sx) & 0x1ff;
+ sy = sy & 0xff;
+ if (sx > 512-16) sx -= 512;
+ if (sy > 256-16) sy -= 256;
+
+ drawgfx( bitmap,gfx,
+ tile_number,
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,TRANSPARENCY_PEN_TABLE,7);
+
+ source+=4;
+ }
+}
+
+VIDEO_UPDATE( marvins )
+{
+ cpuintrf_push_context(0);
+ {
+ UINT8 sprite_partition = program_read_byte(0xfe00);
+
+ int attributes = program_read_byte(0x8600); /* 0x20: normal, 0xa0: video flipped */
+ int scroll_attributes = program_read_byte(0xff00);
+ int sprite_scrolly = program_read_byte(0xf800);
+ int sprite_scrollx = program_read_byte(0xf900);
+
+ int bg_scrolly = program_read_byte(0xfa00);
+ int bg_scrollx = program_read_byte(0xfb00);
+ int fg_scrolly = program_read_byte(0xfc00);
+ int fg_scrollx = program_read_byte(0xfd00);
+
+ rectangle finalclip = tilemap_clip;
+ sect_rect(&finalclip, cliprect);
+
+ if( (scroll_attributes & 4)==0 ) bg_scrollx += 256;
+ if( scroll_attributes & 1 ) sprite_scrollx += 256;
+ if( scroll_attributes & 2 ) fg_scrollx += 256;
+
+ /* palette bank for background/foreground is set by a memory-write handler */
+ update_palette(machine, 0);
+
+ if( flipscreen != (attributes&0x80) )
+ {
+ flipscreen = attributes&0x80;
+ tilemap_set_flip( ALL_TILEMAPS, flipscreen?TILEMAP_FLIPY|TILEMAP_FLIPX:0);
+ }
+
+ tilemap_set_scrollx( bg_tilemap, 0, bg_scrollx );
+ tilemap_set_scrolly( bg_tilemap, 0, bg_scrolly );
+ tilemap_set_scrollx( fg_tilemap, 0, fg_scrollx );
+ tilemap_set_scrolly( fg_tilemap, 0, fg_scrolly );
+ tilemap_set_scrollx( tx_tilemap, 0, 0 );
+ tilemap_set_scrolly( tx_tilemap, 0, 0 );
+
+ tilemap_draw( bitmap,&finalclip,fg_tilemap,TILEMAP_DRAW_OPAQUE ,0);
+ draw_sprites( machine,bitmap,cliprect, sprite_scrollx+29+1, sprite_scrolly+16, 0, sprite_partition );
+ tilemap_draw( bitmap,&finalclip,bg_tilemap,0 ,0);
+ draw_sprites( machine,bitmap,cliprect, sprite_scrollx+29+1, sprite_scrolly+16, 1, sprite_partition );
+ tilemap_draw( bitmap,&finalclip,tx_tilemap,0 ,0);
+ draw_status( machine,bitmap,cliprect );
+ }
+ cpuintrf_pop_context();
+ return 0;
+}
+
+VIDEO_UPDATE( madcrash )
+{
+/***************************************************************************
+**
+** Game Specific Initialization
+**
+** madcrash_vreg defines an offset for the video registers which is
+** different in Mad Crasher and Vanguard II.
+**
+** init_sound defines the location of the polled sound CPU busy bit,
+** which also varies across games.
+**
+***************************************************************************/
+
+ cpuintrf_push_context(0);
+ {
+ int madcrash_vreg = (snk_gamegroup == 1) ? 0x00 : 0xf1; // Mad Crasher=0x00, VanguardII=0xf1
+
+ UINT8 sprite_partition = program_read_byte(0xfa00);
+
+ int attributes = program_read_byte(0x8600+madcrash_vreg); /* 0x20: normal, 0xa0: video flipped */
+ int bg_scrolly = program_read_byte(0xf800+madcrash_vreg);
+ int bg_scrollx = program_read_byte(0xf900+madcrash_vreg);
+ int scroll_attributes = program_read_byte(0xfb00+madcrash_vreg);
+ int sprite_scrolly = program_read_byte(0xfc00+madcrash_vreg);
+ int sprite_scrollx = program_read_byte(0xfd00+madcrash_vreg);
+ int fg_scrolly = program_read_byte(0xfe00+madcrash_vreg);
+ int fg_scrollx = program_read_byte(0xff00+madcrash_vreg);
+
+ rectangle finalclip = tilemap_clip;
+ sect_rect(&finalclip, cliprect);
+
+ if( (scroll_attributes & 4)==0 ) bg_scrollx += 256;
+ if( scroll_attributes & 1 ) sprite_scrollx += 256;
+ if( scroll_attributes & 2 ) fg_scrollx += 256;
+
+ marvins_palette_bank_w(0, program_read_byte(0xc800+madcrash_vreg));
+ update_palette(machine, 1);
+
+ if( flipscreen != (attributes&0x80) )
+ {
+ flipscreen = attributes&0x80;
+ tilemap_set_flip( ALL_TILEMAPS, flipscreen?TILEMAP_FLIPY|TILEMAP_FLIPX:0);
+ }
+
+ tilemap_set_scrollx( bg_tilemap, 0, bg_scrollx );
+ tilemap_set_scrolly( bg_tilemap, 0, bg_scrolly );
+ tilemap_set_scrollx( fg_tilemap, 0, fg_scrollx );
+ tilemap_set_scrolly( fg_tilemap, 0, fg_scrolly );
+ tilemap_set_scrollx( tx_tilemap, 0, 0 );
+ tilemap_set_scrolly( tx_tilemap, 0, 0 );
+
+ tilemap_draw( bitmap,&finalclip,bg_tilemap,TILEMAP_DRAW_OPAQUE ,0);
+ draw_sprites( machine,bitmap,cliprect, sprite_scrollx+29, sprite_scrolly+17, 0, sprite_partition );
+ tilemap_draw( bitmap,&finalclip,fg_tilemap,0 ,0);
+ draw_sprites( machine,bitmap,cliprect, sprite_scrollx+29, sprite_scrolly+17, 1, sprite_partition );
+ tilemap_draw( bitmap,&finalclip,tx_tilemap,0 ,0);
+ draw_status( machine,bitmap,cliprect );
+ }
+ cpuintrf_pop_context();
+ return 0;
+}
diff --git a/src/mame/video/matmania.c b/src/mame/video/matmania.c
new file mode 100644
index 00000000000..fea0cdc1e1d
--- /dev/null
+++ b/src/mame/video/matmania.c
@@ -0,0 +1,358 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+ There are only a few differences between the video hardware of Mysterious
+ Stones and Mat Mania. The tile bank select bit is different and the sprite
+ selection seems to be different as well. Additionally, the palette is stored
+ differently. I'm also not sure that the 2nd tile page is really used in
+ Mysterious Stones.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+UINT8 *matmania_videoram2,*matmania_colorram2;
+size_t matmania_videoram2_size;
+UINT8 *matmania_videoram3,*matmania_colorram3;
+size_t matmania_videoram3_size;
+UINT8 *matmania_scroll;
+static mame_bitmap *tmpbitmap2;
+static UINT8 *dirtybuffer2;
+
+UINT8 *matmania_pageselect;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Mat Mania is unusual in that it has both PROMs and RAM to control the
+ palette. PROMs are used for characters and background tiles, RAM for
+ sprites.
+ I don't know for sure how the PROMs are connected to the RGB output,
+ but it's probably the usual:
+
+ bit 7 -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 2.2kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ -- 1 kohm resistor -- RED
+ bit 0 -- 2.2kohm resistor -- RED
+
+ bit 3 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 1 kohm resistor -- BLUE
+ bit 0 -- 2.2kohm resistor -- BLUE
+
+***************************************************************************/
+PALETTE_INIT( matmania )
+{
+ int i;
+
+ for (i = 0;i < 64;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[0] >> 4) & 0x01;
+ bit1 = (color_prom[0] >> 5) & 0x01;
+ bit2 = (color_prom[0] >> 6) & 0x01;
+ bit3 = (color_prom[0] >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[64] >> 0) & 0x01;
+ bit1 = (color_prom[64] >> 1) & 0x01;
+ bit2 = (color_prom[64] >> 2) & 0x01;
+ bit3 = (color_prom[64] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+
+
+WRITE8_HANDLER( matmania_paletteram_w )
+{
+ int bit0,bit1,bit2,bit3,val;
+ int r,g,b;
+ int offs2;
+
+
+ paletteram[offset] = data;
+ offs2 = offset & 0x0f;
+
+ val = paletteram[offs2];
+ bit0 = (val >> 0) & 0x01;
+ bit1 = (val >> 1) & 0x01;
+ bit2 = (val >> 2) & 0x01;
+ bit3 = (val >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ val = paletteram[offs2 | 0x10];
+ bit0 = (val >> 0) & 0x01;
+ bit1 = (val >> 1) & 0x01;
+ bit2 = (val >> 2) & 0x01;
+ bit3 = (val >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ val = paletteram[offs2 | 0x20];
+ bit0 = (val >> 0) & 0x01;
+ bit1 = (val >> 1) & 0x01;
+ bit2 = (val >> 2) & 0x01;
+ bit3 = (val >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(Machine,offs2 + 64,MAKE_RGB(r,g,b));
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+VIDEO_START( matmania )
+{
+ dirtybuffer = auto_malloc(videoram_size);
+ memset(dirtybuffer,1,videoram_size);
+
+ dirtybuffer2 = auto_malloc(matmania_videoram3_size);
+ memset(dirtybuffer2,1,matmania_videoram3_size);
+
+ /* Mat Mania has a virtual screen twice as large as the visible screen */
+ tmpbitmap = auto_bitmap_alloc(machine->screen[0].width,2* machine->screen[0].height,machine->screen[0].format);
+
+ /* Mat Mania has a virtual screen twice as large as the visible screen */
+ tmpbitmap2 = auto_bitmap_alloc(machine->screen[0].width,2 * machine->screen[0].height,machine->screen[0].format);
+}
+
+
+
+WRITE8_HANDLER( matmania_videoram3_w )
+{
+ if (matmania_videoram3[offset] != data)
+ {
+ dirtybuffer2[offset] = 1;
+
+ matmania_videoram3[offset] = data;
+ }
+}
+
+
+
+WRITE8_HANDLER( matmania_colorram3_w )
+{
+ if (matmania_colorram3[offset] != data)
+ {
+ dirtybuffer2[offset] = 1;
+
+ matmania_colorram3[offset] = data;
+ }
+}
+
+
+VIDEO_UPDATE( matmania )
+{
+ int offs;
+
+
+ /* Update the tiles in the left tile ram bank */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ if (dirtybuffer[offs])
+ {
+ int sx,sy;
+
+
+ dirtybuffer[offs] = 0;
+
+ sx = 15 - offs / 32;
+ sy = offs % 32;
+
+ drawgfx(tmpbitmap,machine->gfx[1],
+ videoram[offs] + ((colorram[offs] & 0x08) << 5),
+ (colorram[offs] & 0x30) >> 4,
+ 0,sy >= 16, /* flip horizontally tiles on the right half of the bitmap */
+ 16*sx,16*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ /* Update the tiles in the right tile ram bank */
+ for (offs = matmania_videoram3_size - 1;offs >= 0;offs--)
+ {
+ if (dirtybuffer2[offs])
+ {
+ int sx,sy;
+
+
+ dirtybuffer2[offs] = 0;
+
+ sx = 15 - offs / 32;
+ sy = offs % 32;
+
+ drawgfx(tmpbitmap2,machine->gfx[1],
+ matmania_videoram3[offs] + ((matmania_colorram3[offs] & 0x08) << 5),
+ (matmania_colorram3[offs] & 0x30) >> 4,
+ 0,sy >= 16, /* flip horizontally tiles on the right half of the bitmap */
+ 16*sx,16*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+
+ /* copy the temporary bitmap to the screen */
+ {
+ int scrolly;
+
+
+ scrolly = -*matmania_scroll;
+ if (*matmania_pageselect)
+ copyscrollbitmap(bitmap,tmpbitmap2,0,0,1,&scrolly,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ else
+ copyscrollbitmap(bitmap,tmpbitmap,0,0,1,&scrolly,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ }
+
+
+ /* Draw the sprites */
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ if (spriteram[offs] & 0x01)
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ spriteram[offs+1] + ((spriteram[offs] & 0xf0) << 4),
+ (spriteram[offs] & 0x08) >> 3,
+ spriteram[offs] & 0x04,spriteram[offs] & 0x02,
+ 239 - spriteram[offs+3],(240 - spriteram[offs+2]) & 0xff,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ }
+
+
+ /* draw the frontmost playfield. They are characters, but draw them as sprites */
+ for (offs = matmania_videoram2_size - 1;offs >= 0;offs--)
+ {
+ int sx,sy;
+
+
+ sx = 31 - offs / 32;
+ sy = offs % 32;
+
+ drawgfx(bitmap,machine->gfx[0],
+ matmania_videoram2[offs] + 256 * (matmania_colorram2[offs] & 0x07),
+ (matmania_colorram2[offs] & 0x30) >> 4,
+ 0,0,
+ 8*sx,8*sy,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
+
+VIDEO_UPDATE( maniach )
+{
+ int offs;
+
+
+ /* Update the tiles in the left tile ram bank */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ if (dirtybuffer[offs])
+ {
+ int sx,sy;
+
+
+ dirtybuffer[offs] = 0;
+
+ sx = 15 - offs / 32;
+ sy = offs % 32;
+
+ drawgfx(tmpbitmap,machine->gfx[1],
+ videoram[offs] + ((colorram[offs] & 0x03) << 8),
+ (colorram[offs] & 0x30) >> 4,
+ 0,sy >= 16, /* flip horizontally tiles on the right half of the bitmap */
+ 16*sx,16*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ /* Update the tiles in the right tile ram bank */
+ for (offs = matmania_videoram3_size - 1;offs >= 0;offs--)
+ {
+ if (dirtybuffer2[offs])
+ {
+ int sx,sy;
+
+
+ dirtybuffer2[offs] = 0;
+
+ sx = 15 - offs / 32;
+ sy = offs % 32;
+
+ drawgfx(tmpbitmap2,machine->gfx[1],
+ matmania_videoram3[offs] + ((matmania_colorram3[offs] & 0x03) << 8),
+ (matmania_colorram3[offs] & 0x30) >> 4,
+ 0,sy >= 16, /* flip horizontally tiles on the right half of the bitmap */
+ 16*sx,16*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+
+ /* copy the temporary bitmap to the screen */
+ {
+ int scrolly;
+
+
+ scrolly = -*matmania_scroll;
+ if (*matmania_pageselect)
+ copyscrollbitmap(bitmap,tmpbitmap2,0,0,1,&scrolly,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ else
+ copyscrollbitmap(bitmap,tmpbitmap,0,0,1,&scrolly,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ }
+
+
+ /* Draw the sprites */
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ if (spriteram[offs] & 0x01)
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ spriteram[offs+1] + ((spriteram[offs] & 0xf0) << 4),
+ (spriteram[offs] & 0x08) >> 3,
+ spriteram[offs] & 0x04,spriteram[offs] & 0x02,
+ 239 - spriteram[offs+3],(240 - spriteram[offs+2]) & 0xff,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ }
+
+
+ /* draw the frontmost playfield. They are characters, but draw them as sprites */
+ for (offs = matmania_videoram2_size - 1;offs >= 0;offs--)
+ {
+ int sx,sy;
+
+
+ sx = 31 - offs / 32;
+ sy = offs % 32;
+
+ drawgfx(bitmap,machine->gfx[0],
+ matmania_videoram2[offs] + 256 * (matmania_colorram2[offs] & 0x07),
+ (matmania_colorram2[offs] & 0x30) >> 4,
+ 0,0,
+ 8*sx,8*sy,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/mayumi.c b/src/mame/video/mayumi.c
new file mode 100644
index 00000000000..8cf35f0d538
--- /dev/null
+++ b/src/mame/video/mayumi.c
@@ -0,0 +1,47 @@
+/******************************************************************************
+
+Kikiippatsu Mayumi-chan (c) 1988 Victory L.L.C.
+
+Video hardware
+ driver by Uki
+
+******************************************************************************/
+
+#include "driver.h"
+
+static UINT8 *mayumi_videoram;
+static tilemap *mayumi_tilemap;
+
+static TILE_GET_INFO( get_tile_info )
+{
+ int code = mayumi_videoram[tile_index] + (mayumi_videoram[tile_index+0x800] & 0x1f)*0x100 ;
+ int col = (mayumi_videoram[tile_index+0x1000] >> 3) & 0x1f;
+
+ SET_TILE_INFO(0, code, col, 0);
+}
+
+VIDEO_START( mayumi )
+{
+ mayumi_videoram = auto_malloc(0x1800);
+
+ mayumi_tilemap = tilemap_create( get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32 );
+}
+
+WRITE8_HANDLER( mayumi_videoram_w )
+{
+ mayumi_videoram[offset] = data;
+
+ tilemap_mark_tile_dirty(mayumi_tilemap, offset & 0x7ff );
+}
+
+READ8_HANDLER( mayumi_videoram_r )
+{
+ return mayumi_videoram[offset];
+}
+
+VIDEO_UPDATE( mayumi )
+{
+ tilemap_draw(bitmap, cliprect, mayumi_tilemap, 0, 0);
+ return 0;
+}
+
diff --git a/src/mame/video/mcatadv.c b/src/mame/video/mcatadv.c
new file mode 100644
index 00000000000..e4d4ca78b7f
--- /dev/null
+++ b/src/mame/video/mcatadv.c
@@ -0,0 +1,273 @@
+/* Magical Cat Adventure / Nostradamus Video Hardware */
+
+/*
+Notes:
+Tilemap drawing is a killer on the first level of Nost due to the whole tilemap being dirty every frame.
+Sprite drawing is quite fast (See USER1 in the profiler)
+
+Nost final boss, the priority of the arms is under the tilemaps, everything else is above. Should it be blended? i.e. Shadow.
+
+ToDo: Fix Sprites & Rowscroll/Select for Cocktail
+*/
+
+#include "driver.h"
+#include "profiler.h"
+
+/* Defined in driver */
+extern UINT16 *mcatadv_videoram1, *mcatadv_videoram2;
+extern UINT16 *mcatadv_scroll, *mcatadv_scroll2;
+extern UINT16 *mcatadv_vidregs;
+
+static tilemap *mcatadv_tilemap1, *mcatadv_tilemap2;
+static UINT16 *spriteram_old, *vidregs_old;
+static int palette_bank1, palette_bank2;
+
+
+static TILE_GET_INFO( get_mcatadv_tile_info1 )
+{
+ int tileno, colour, pri;
+
+ tileno = mcatadv_videoram1[tile_index*2+1];
+ colour = (mcatadv_videoram1[tile_index*2] & 0x3f00)>>8;
+ pri = (mcatadv_videoram1[tile_index*2] & 0xc000)>>14;
+
+ SET_TILE_INFO(0,tileno,colour + palette_bank1*0x40,0);
+ tileinfo->category = pri;
+}
+
+WRITE16_HANDLER( mcatadv_videoram1_w )
+{
+ COMBINE_DATA(&mcatadv_videoram1[offset]);
+ tilemap_mark_tile_dirty(mcatadv_tilemap1,offset/2);
+}
+
+static TILE_GET_INFO( get_mcatadv_tile_info2 )
+{
+ int tileno, colour, pri;
+
+ tileno = mcatadv_videoram2[tile_index*2+1];
+ colour = (mcatadv_videoram2[tile_index*2] & 0x3f00)>>8;
+ pri = (mcatadv_videoram2[tile_index*2] & 0xc000)>>14;
+
+ SET_TILE_INFO(1,tileno,colour + palette_bank2*0x40,0);
+ tileinfo->category = pri;
+}
+
+WRITE16_HANDLER( mcatadv_videoram2_w )
+{
+ COMBINE_DATA(&mcatadv_videoram2[offset]);
+ tilemap_mark_tile_dirty(mcatadv_tilemap2,offset/2);
+}
+
+
+static void draw_sprites( mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ UINT16 *source = spriteram_old;
+ UINT16 *finish = source + (spriteram_size/2)/2;
+ int global_x = mcatadv_vidregs[0]-0x184;
+ int global_y = mcatadv_vidregs[1]-0x1f1;
+
+ UINT16 *destline;
+ UINT8 *priline;
+
+ int xstart, xend, xinc;
+ int ystart, yend, yinc;
+
+ if( vidregs_old[2] == 0x0001 ) /* Double Buffered */
+ {
+ source += (spriteram_size/2)/2;
+ finish += (spriteram_size/2)/2;
+ }
+ else if( vidregs_old[2] ) /* I suppose it's possible that there is 4 banks, haven't seen it used though */
+ {
+ logerror("Spritebank != 0/1\n");
+ }
+
+ while ( source<finish )
+ {
+ int pen = (source[0]&0x3f00)>>8;
+ int tileno = source[1]&0xffff;
+ int pri = (source[0]&0xc000)>>14;
+ int x = source[2]&0x3ff;
+ int y = source[3]&0x3ff;
+ int flipy = source[0] & 0x0040;
+ int flipx = source[0] & 0x0080;
+
+ int height = ((source[3]&0xf000)>>12)*16;
+ int width = ((source[2]&0xf000)>>12)*16;
+ int offset = tileno * 256;
+
+ UINT8 *sprdata = memory_region ( REGION_GFX1 );
+
+ int drawxpos, drawypos;
+ int xcnt,ycnt;
+ int pix;
+
+ if (x & 0x200) x-=0x400;
+ if (y & 0x200) y-=0x400;
+
+#if 0 // For Flipscreen/Cocktail
+ if(mcatadv_vidregs[0]&0x8000)
+ {
+ flipx = !flipx;
+ }
+ if(mcatadv_vidregs[1]&0x8000)
+ {
+ flipy = !flipy;
+ }
+#endif
+
+ if (source[3] != source[0]) // 'hack' don't draw sprites while its testing the ram!
+ {
+ if(!flipx) { xstart = 0; xend = width; xinc = 1; }
+ else { xstart = width-1; xend = -1; xinc = -1; }
+ if(!flipy) { ystart = 0; yend = height; yinc = 1; }
+ else { ystart = height-1; yend = -1; yinc = -1; }
+
+ for (ycnt = ystart; ycnt != yend; ycnt += yinc) {
+ drawypos = y+ycnt-global_y;
+
+ if ((drawypos >= cliprect->min_y) && (drawypos <= cliprect->max_y)) {
+ destline = BITMAP_ADDR16(bitmap, drawypos, 0);
+ priline = BITMAP_ADDR8(priority_bitmap, drawypos, 0);
+
+ for (xcnt = xstart; xcnt != xend; xcnt += xinc) {
+ drawxpos = x+xcnt-global_x;
+
+ if (offset >= 0x500000*2) offset = 0;
+ pix = sprdata[offset/2];
+
+ if (offset & 1) pix = pix >> 4;
+ pix &= 0x0f;
+
+ if ((drawxpos >= cliprect->min_x) && (drawxpos <= cliprect->max_x) && pix)
+ if((priline[drawxpos] < pri))
+ destline[drawxpos] = (pix + (pen<<4));
+
+ offset++;
+ }
+ }
+ else {
+ offset += width;
+ }
+ }
+ }
+ source+=4;
+ }
+}
+
+static void mcatadv_draw_tilemap_part(UINT16* current_scroll, UINT16* current_videoram1, int i, tilemap* current_tilemap, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int flip;
+ UINT32 drawline;
+ rectangle clip;
+
+ clip.min_x = cliprect->min_x;
+ clip.max_x = cliprect->max_x;
+
+ for(drawline = cliprect->min_y; drawline <= cliprect->max_y;drawline++)
+ {
+ int scrollx, scrolly;
+
+ clip.min_y = drawline;
+ clip.max_y = drawline;
+
+ scrollx = (current_scroll[0]&0x1ff)-0x194;
+ scrolly = (current_scroll[1]&0x1ff)-0x1df;
+
+ if ((current_scroll[1]&0x4000)==0x4000)
+ {
+ int rowselect;
+ rowselect = current_videoram1[0x1000/2 + (((drawline+scrolly)&0x1ff) * 2) + 1];
+ scrolly = rowselect - drawline;
+ }
+
+ if ((current_scroll[0]&0x4000)==0x4000)
+ {
+ int rowscroll;
+ rowscroll = current_videoram1[0x1000/2 + (((drawline+scrolly)&0x1ff) * 2) + 0];
+ scrollx += rowscroll;
+ }
+
+ /* Global Flip */
+ if(!(current_scroll[0]&0x8000)) scrollx -= 0x19;
+ if(!(current_scroll[1]&0x8000)) scrolly -= 0x141;
+ flip = ((current_scroll[0]&0x8000)?0:TILEMAP_FLIPX) | ((current_scroll[1]&0x8000)?0:TILEMAP_FLIPY);
+
+ tilemap_set_scrollx(current_tilemap, 0, scrollx);
+ tilemap_set_scrolly(current_tilemap, 0, scrolly);
+ tilemap_set_flip(current_tilemap, flip);
+
+ tilemap_draw(bitmap, &clip, current_tilemap, i, i);
+ }
+}
+
+VIDEO_UPDATE( mcatadv )
+{
+ int i;
+
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ if(mcatadv_scroll[2] != palette_bank1) {
+ palette_bank1 = mcatadv_scroll[2];
+ tilemap_mark_all_tiles_dirty(mcatadv_tilemap1);
+ }
+
+ if(mcatadv_scroll2[2] != palette_bank2) {
+ palette_bank2 = mcatadv_scroll2[2];
+ tilemap_mark_all_tiles_dirty(mcatadv_tilemap2);
+ }
+
+/*
+ popmessage("%02x %02x %02x %02x",
+ (mcatadv_scroll[0]&0x4000)>>8,
+ (mcatadv_scroll[1]&0x4000)>>8,
+ (mcatadv_scroll2[0]&0x4000)>>8,
+ (mcatadv_scroll2[1]&0x4000)>>8);
+*/
+
+ for (i=0; i<=3; i++)
+ {
+ #ifdef MAME_DEBUG
+ if (!input_code_pressed(KEYCODE_Q))
+ #endif
+ mcatadv_draw_tilemap_part(mcatadv_scroll, mcatadv_videoram1, i, mcatadv_tilemap1, bitmap, cliprect);
+
+ #ifdef MAME_DEBUG
+ if (!input_code_pressed(KEYCODE_W))
+ #endif
+ mcatadv_draw_tilemap_part(mcatadv_scroll2, mcatadv_videoram2, i, mcatadv_tilemap2, bitmap, cliprect);
+ }
+
+ profiler_mark(PROFILER_USER1);
+#ifdef MAME_DEBUG
+ if (!input_code_pressed(KEYCODE_E))
+#endif
+ draw_sprites (bitmap, cliprect);
+ profiler_mark(PROFILER_END);
+ return 0;
+}
+
+VIDEO_START( mcatadv )
+{
+ mcatadv_tilemap1 = tilemap_create(get_mcatadv_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+ tilemap_set_transparent_pen(mcatadv_tilemap1,0);
+
+ mcatadv_tilemap2 = tilemap_create(get_mcatadv_tile_info2,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+ tilemap_set_transparent_pen(mcatadv_tilemap2,0);
+
+ spriteram_old = auto_malloc(spriteram_size);
+ vidregs_old = auto_malloc(0xf);
+
+ memset(spriteram_old,0,spriteram_size);
+
+ palette_bank1 = 0;
+ palette_bank2 = 0;
+}
+
+VIDEO_EOF( mcatadv )
+{
+ memcpy(spriteram_old,spriteram16,spriteram_size);
+ memcpy(vidregs_old,mcatadv_vidregs,0xf);
+}
diff --git a/src/mame/video/mcr.c b/src/mame/video/mcr.c
new file mode 100644
index 00000000000..01f2e588efa
--- /dev/null
+++ b/src/mame/video/mcr.c
@@ -0,0 +1,417 @@
+/***************************************************************************
+
+ Midway MCR systems
+
+***************************************************************************/
+
+#include "driver.h"
+#include "mcr.h"
+
+
+INT8 mcr12_sprite_xoffs;
+INT8 mcr12_sprite_xoffs_flip;
+
+static tilemap *bg_tilemap;
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+/*
+ The 90009 board uses 1 byte per tile:
+
+ Byte 0:
+ pppppppp = picture index
+ */
+static TILE_GET_INFO( mcr_90009_get_tile_info )
+{
+ SET_TILE_INFO(0, videoram[tile_index], 0, 0);
+
+ /* sprite color base is constant 0x10 */
+ tileinfo->category = 1;
+}
+
+
+/*
+ The 90010 board uses 2 adjacent bytes per tile:
+
+ Byte 0:
+ pppppppp = picture index (low 8 bits)
+
+ Byte 1:
+ ss------ = sprite palette bank
+ ---cc--- = tile palette bank
+ -----y-- = Y flip
+ ------x- = X flip
+ -------p = picture index (high 1 bit)
+ */
+static TILE_GET_INFO( mcr_90010_get_tile_info )
+{
+ int data = videoram[tile_index * 2] | (videoram[tile_index * 2 + 1] << 8);
+ int code = data & 0x1ff;
+ int color = (data >> 11) & 3;
+ SET_TILE_INFO(0, code, color, TILE_FLIPYX((data >> 9) & 3));
+
+ /* sprite color base comes from the top 2 bits */
+ tileinfo->category = (data >> 14) & 3;
+}
+
+
+/*
+ The 91490 board uses 2 adjacent bytes per tile:
+
+ Byte 0:
+ pppppppp = picture index (low 8 bits)
+
+ Byte 1:
+ ss------ = sprite palette bank (can be disabled via jumpers)
+ --cc---- = tile palette bank
+ ----y--- = Y flip
+ -----x-- = X flip
+ ------pp = picture index (high 2 bits)
+ */
+static TILE_GET_INFO( mcr_91490_get_tile_info )
+{
+ int data = videoram[tile_index * 2] | (videoram[tile_index * 2 + 1] << 8);
+ int code = data & 0x3ff;
+ int color = (data >> 12) & 3;
+ SET_TILE_INFO(0, code, color, TILE_FLIPYX((data >> 10) & 3));
+
+ /* sprite color base might come from the top 2 bits */
+ tileinfo->category = (data >> 14) & 3;
+}
+
+
+
+/*************************************
+ *
+ * Common video startup/shutdown
+ *
+ *************************************/
+
+VIDEO_START( mcr )
+{
+ /* the tilemap callback is based on the CPU board */
+ switch (mcr_cpu_board)
+ {
+ case 90009:
+ bg_tilemap = tilemap_create(mcr_90009_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,16, 32,30);
+ break;
+
+ case 90010:
+ bg_tilemap = tilemap_create(mcr_90010_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,16, 32,30);
+ break;
+
+ case 91475:
+ bg_tilemap = tilemap_create(mcr_90010_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,16, 32,30);
+ break;
+
+ case 91490:
+ bg_tilemap = tilemap_create(mcr_91490_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,16, 32,30);
+ break;
+
+ default:
+ assert_always(0, "Unknown mcr board");
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM writes
+ *
+ *************************************/
+
+static void mcr_set_color(int index, int data)
+{
+ palette_set_color_rgb(Machine, index, pal3bit(data >> 6), pal3bit(data >> 0), pal3bit(data >> 3));
+}
+
+
+static void journey_set_color(int index, int data)
+{
+ /* 3 bits each, RGB */
+ int r = (data >> 6) & 7;
+ int g = (data >> 0) & 7;
+ int b = (data >> 3) & 7;
+
+ /* up to 8 bits */
+ r = (r << 5) | (r << 1);
+ g = (g << 5) | (g << 1);
+ b = (b << 5) | (b << 1);
+
+ /* set the BG color */
+ palette_set_color(Machine, index, MAKE_RGB(r, g, b));
+
+ /* if this is an odd entry in the upper palette bank, the hardware */
+ /* hard-codes a low 1 bit -- this is used for better grayscales */
+ if ((index & 0x31) == 0x31)
+ {
+ r |= 0x11;
+ g |= 0x11;
+ b |= 0x11;
+ }
+
+ /* set the FG color */
+ palette_set_color(Machine, index + 64, MAKE_RGB(r, g, b));
+}
+
+
+WRITE8_HANDLER( mcr_91490_paletteram_w )
+{
+ paletteram[offset] = data;
+ offset &= 0x7f;
+ mcr_set_color((offset / 2) & 0x3f, data | ((offset & 1) << 8));
+}
+
+
+
+/*************************************
+ *
+ * Video RAM writes
+ *
+ *************************************/
+
+WRITE8_HANDLER( mcr_90009_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( mcr_90010_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+
+ /* palette RAM is mapped into the upper 0x80 bytes here */
+ if ((offset & 0x780) == 0x780)
+ {
+ if (mcr_cpu_board != 91475)
+ mcr_set_color((offset / 2) & 0x3f, data | ((offset & 1) << 8));
+ else
+ journey_set_color((offset / 2) & 0x3f, data | ((offset & 1) << 8));
+ }
+}
+
+
+READ8_HANDLER( twotiger_videoram_r )
+{
+ /* Two Tigers swizzles the address bits on videoram */
+ int effoffs = ((offset << 1) & 0x7fe) | ((offset >> 10) & 1);
+ return videoram[effoffs];
+}
+
+WRITE8_HANDLER( twotiger_videoram_w )
+{
+ /* Two Tigers swizzles the address bits on videoram */
+ int effoffs = ((offset << 1) & 0x7fe) | ((offset >> 10) & 1);
+
+ videoram[effoffs] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, effoffs / 2);
+
+ /* palette RAM is mapped into the upper 0x80 bytes here */
+ if ((effoffs & 0x780) == 0x780)
+ mcr_set_color(((offset & 0x400) >> 5) | ((offset >> 1) & 0x1f), data | ((offset & 1) << 8));
+}
+
+
+WRITE8_HANDLER( mcr_91490_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+
+
+/*************************************
+ *
+ * 91399 Video Gen sprite renderer
+ *
+ * Paired with:
+ * 90009 CPU -> fixed palette @ 1
+ * 90010 CPU -> palette specified by tiles
+ *
+ *************************************/
+
+static void render_sprites_91399(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const gfx_element *gfx = machine->gfx[1];
+ int offs;
+
+ /* render the sprites into the bitmap, ORing together */
+ for (offs = 0; offs < spriteram_size; offs += 4)
+ {
+ int code, x, y, sx, sy, hflip, vflip;
+
+ /* extract the bits of information */
+ code = spriteram[offs + 1] & 0x3f;
+ hflip = (spriteram[offs + 1] & 0x40) ? 31 : 0;
+ vflip = (spriteram[offs + 1] & 0x80) ? 31 : 0;
+ sx = (spriteram[offs + 2] - 4) * 2;
+ sy = (240 - spriteram[offs]) * 2;
+
+ /* apply cocktail mode */
+ if (mcr_cocktail_flip)
+ {
+ hflip ^= 31;
+ vflip ^= 31;
+ sx = 466 - sx + mcr12_sprite_xoffs_flip;
+ sy = 450 - sy;
+ }
+ else
+ sx += mcr12_sprite_xoffs;
+
+ /* clamp within 512 */
+ sx &= 0x1ff;
+ sy &= 0x1ff;
+
+ /* loop over lines in the sprite */
+ for (y = 0; y < 32; y++, sy = (sy + 1) & 0x1ff)
+ if (sy >= cliprect->min_y && sy <= cliprect->max_y)
+ {
+ UINT8 *src = gfx->gfxdata + gfx->char_modulo * code + gfx->line_modulo * (y ^ vflip);
+ UINT16 *dst = BITMAP_ADDR16(bitmap, sy, 0);
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, sy, 0);
+
+ /* loop over columns */
+ for (x = 0; x < 32; x++)
+ {
+ int tx = (sx + x) & 0x1ff;
+ int pix = pri[tx] | src[x ^ hflip];
+
+ /* update the effective sprite pixel */
+ pri[tx] = pix;
+
+ /* only draw if the low 3 bits are set */
+ if (pix & 0x07)
+ dst[tx] = pix;
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * 91464 Super Video Gen sprite renderer
+ *
+ * Paired with:
+ * 91442 CPU -> fixed palette @ 1 (upper half) or 3 (lower half)
+ * 91475 CPU -> palette specified by sprite board; sprites have extra implicit colors
+ * 91490 CPU -> palette specified by sprite board or by tiles (select via jumpers)
+ * 91721 CPU -> palette specified by sprite board
+ *
+ *************************************/
+
+static void render_sprites_91464(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int primask, int sprmask, int colormask)
+{
+ const gfx_element *gfx = machine->gfx[1];
+ int offs;
+
+ /* render the sprites into the bitmap, working from topmost to bottommost */
+ for (offs = spriteram_size - 4; offs >= 0; offs -= 4)
+ {
+ int code, color, x, y, sx, sy, hflip, vflip;
+
+ /* extract the bits of information */
+ code = (spriteram[offs + 2] + 256 * ((spriteram[offs + 1] >> 3) & 0x01)) % gfx->total_elements;
+ color = (((~spriteram[offs + 1] & 3) << 4) & sprmask) | colormask;
+ hflip = (spriteram[offs + 1] & 0x10) ? 31 : 0;
+ vflip = (spriteram[offs + 1] & 0x20) ? 31 : 0;
+ sx = (spriteram[offs + 3] - 3) * 2;
+ sy = (241 - spriteram[offs]) * 2;
+
+ /* apply cocktail mode */
+ if (mcr_cocktail_flip)
+ {
+ hflip ^= 31;
+ vflip ^= 31;
+ sx = 480 - sx;
+ sy = 452 - sy;
+ }
+
+ /* clamp within 512 */
+ sx &= 0x1ff;
+ sy &= 0x1ff;
+
+ /* loop over lines in the sprite */
+ for (y = 0; y < 32; y++, sy = (sy + 1) & 0x1ff)
+ if (sy >= 2 && sy >= cliprect->min_y && sy <= cliprect->max_y)
+ {
+ UINT8 *src = gfx->gfxdata + gfx->char_modulo * code + gfx->line_modulo * (y ^ vflip);
+ UINT16 *dst = BITMAP_ADDR16(bitmap, sy, 0);
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, sy, 0);
+
+ /* loop over columns */
+ for (x = 0; x < 32; x++)
+ {
+ int tx = (sx + x) & 0x1ff;
+ int pix = pri[tx];
+ if (pix != 0xff)
+ {
+ /* compute the final value */
+ pix = (pix & primask) | color | src[x ^ hflip];
+
+ /* if non-zero, draw */
+ if (pix & 0x0f)
+ {
+ /* mark this pixel so we don't draw there again */
+ pri[tx] = 0xff;
+
+ /* only draw if the low 3 bits are set */
+ if (pix & 0x07)
+ dst[tx] = pix;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh routines
+ *
+ *************************************/
+
+VIDEO_UPDATE( mcr )
+{
+ /* update the flip state */
+ tilemap_set_flip(bg_tilemap, mcr_cocktail_flip ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
+
+ /* draw the background */
+ fillbitmap(priority_bitmap, 0, cliprect);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0x00);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 1, 0x10);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 2, 0x20);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 3, 0x30);
+
+ /* update the sprites and render them */
+ switch (mcr_sprite_board)
+ {
+ case 91399:
+ render_sprites_91399(machine, bitmap, cliprect);
+ break;
+
+ case 91464:
+ if (mcr_cpu_board == 91442)
+ render_sprites_91464(machine, bitmap, cliprect, 0x00, 0x30, 0x00);
+ else if (mcr_cpu_board == 91475)
+ render_sprites_91464(machine, bitmap, cliprect, 0x00, 0x30, 0x40);
+ else if (mcr_cpu_board == 91490)
+ render_sprites_91464(machine, bitmap, cliprect, 0x00, 0x30, 0x00);
+ else if (mcr_cpu_board == 91721)
+ render_sprites_91464(machine, bitmap, cliprect, 0x00, 0x30, 0x00);
+ break;
+ }
+ return 0;
+}
diff --git a/src/mame/video/mcr3.c b/src/mame/video/mcr3.c
new file mode 100644
index 00000000000..7366ea78cdd
--- /dev/null
+++ b/src/mame/video/mcr3.c
@@ -0,0 +1,292 @@
+/***************************************************************************
+
+ Midway MCR-III system
+
+***************************************************************************/
+
+#include "driver.h"
+#include "mcr.h"
+
+
+
+/*************************************
+ *
+ * Global variables
+ *
+ *************************************/
+
+/* Spy Hunter hardware extras */
+UINT8 spyhunt_sprite_color_mask;
+INT16 spyhunt_scrollx, spyhunt_scrolly;
+INT16 spyhunt_scroll_offset;
+
+UINT8 *spyhunt_alpharam;
+//size_t spyhunt_alpharam_size;
+
+
+
+/*************************************
+ *
+ * Local variables
+ *
+ *************************************/
+
+static tilemap *bg_tilemap;
+static tilemap *alpha_tilemap;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int data = videoram[tile_index * 2] | (videoram[tile_index * 2 + 1] << 8);
+ int code = (data & 0x3ff) | ((data >> 4) & 0x400);
+ int color = (data >> 12) & 3;
+ SET_TILE_INFO(0, code, color, TILE_FLIPYX((data >> 10) & 3));
+}
+
+
+static TILE_GET_INFO( mcrmono_get_bg_tile_info )
+{
+ int data = videoram[tile_index * 2] | (videoram[tile_index * 2 + 1] << 8);
+ int code = (data & 0x3ff) | ((data >> 4) & 0x400);
+ int color = ((data >> 12) & 3) ^ 3;
+ SET_TILE_INFO(0, code, color, TILE_FLIPYX((data >> 10) & 3));
+}
+
+
+static TILEMAP_MAPPER( spyhunt_bg_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (row & 0x0f) | ((col & 0x3f) << 4) | ((row & 0x10) << 6);
+}
+
+
+static TILE_GET_INFO( spyhunt_get_bg_tile_info )
+{
+ int data = videoram[tile_index];
+ int code = (data & 0x3f) | ((data >> 1) & 0x40);
+ SET_TILE_INFO(0, code, 0, (data & 0x40) ? TILE_FLIPY : 0);
+}
+
+
+static TILE_GET_INFO( spyhunt_get_alpha_tile_info )
+{
+ SET_TILE_INFO(2, spyhunt_alpharam[tile_index], 0, 0);
+}
+
+
+
+/*************************************
+ *
+ * Spy Hunter-specific palette init
+ *
+ *************************************/
+
+PALETTE_INIT( spyhunt )
+{
+ /* alpha colors are hard-coded */
+ palette_set_color(machine,4*16+0,MAKE_RGB(0x00,0x00,0x00));
+ palette_set_color(machine,4*16+1,MAKE_RGB(0x00,0xff,0x00));
+ palette_set_color(machine,4*16+2,MAKE_RGB(0x00,0x00,0xff));
+ palette_set_color(machine,4*16+3,MAKE_RGB(0xff,0xff,0xff));
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( mcr3 )
+{
+ /* initialize the background tilemap */
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,16, 32,30);
+}
+
+
+VIDEO_START( mcrmono )
+{
+ /* initialize the background tilemap */
+ bg_tilemap = tilemap_create(mcrmono_get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,16, 32,30);
+}
+
+
+VIDEO_START( spyhunt )
+{
+ /* initialize the background tilemap */
+ bg_tilemap = tilemap_create(spyhunt_get_bg_tile_info, spyhunt_bg_scan, TILEMAP_TYPE_PEN, 64,32, 64,32);
+
+ /* initialize the text tilemap */
+ alpha_tilemap = tilemap_create(spyhunt_get_alpha_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 16,16, 32,32);
+ tilemap_set_transparent_pen(alpha_tilemap, 0);
+ tilemap_set_scrollx(alpha_tilemap, 0, 16);
+
+ state_save_register_global(spyhunt_sprite_color_mask);
+ state_save_register_global(spyhunt_scrollx);
+ state_save_register_global(spyhunt_scrolly);
+ state_save_register_global(spyhunt_scroll_offset);
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM writes
+ *
+ *************************************/
+
+WRITE8_HANDLER( mcr3_paletteram_w )
+{
+ paletteram[offset] = data;
+ offset &= 0x7f;
+
+ /* high bit of red comes from low bit of address */
+ palette_set_color_rgb(Machine, offset / 2, pal3bit(((offset & 1) << 2) + (data >> 6)), pal3bit(data >> 0), pal3bit(data >> 3));
+}
+
+
+
+/*************************************
+ *
+ * Video RAM writes
+ *
+ *************************************/
+
+WRITE8_HANDLER( mcr3_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+
+WRITE8_HANDLER( spyhunt_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( spyhunt_alpharam_w )
+{
+ spyhunt_alpharam[offset] = data;
+ tilemap_mark_tile_dirty(alpha_tilemap, offset);
+}
+
+
+
+/*************************************
+ *
+ * Sprite update
+ *
+ *************************************/
+
+static void mcr3_update_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int color_mask, int code_xor, int dx, int dy)
+{
+ int offs;
+
+ fillbitmap(priority_bitmap, 1, cliprect);
+
+ /* loop over sprite RAM */
+ for (offs = spriteram_size - 4; offs >= 0; offs -= 4)
+ {
+ int code, color, flipx, flipy, sx, sy, flags;
+
+ /* skip if zero */
+ if (spriteram[offs] == 0)
+ continue;
+
+/*
+ monoboard:
+ flags.d0 -> ICG0~ -> PCG0~/PCG2~/PCG4~/PCG6~ -> bit 4 of linebuffer
+ flags.d1 -> ICG1~ -> PCG1~/PCG3~/PCG5~/PCG7~ -> bit 5 of linebuffer
+ flags.d2 -> IPPR -> PPR0 /PPR1 /PPR2 /PPR3 -> bit 6 of linebuffer
+ flags.d3 -> IRA15 ----------------------------> address line 15 of FG ROMs
+ flags.d4 -> HFLIP
+ flags.d5 -> VFLIP
+
+*/
+
+ /* extract the bits of information */
+ flags = spriteram[offs + 1];
+ code = spriteram[offs + 2] + 256 * ((flags >> 3) & 0x01);
+ color = ~flags & color_mask;
+ flipx = flags & 0x10;
+ flipy = flags & 0x20;
+ sx = (spriteram[offs + 3] - 3) * 2;
+ sy = (241 - spriteram[offs]) * 2;
+
+ code ^= code_xor;
+
+ sx += dx;
+ sy += dy;
+
+ /* sprites use color 0 for background pen and 8 for the 'under tile' pen.
+ The color 8 is used to cover over other sprites. */
+ if (!mcr_cocktail_flip)
+ {
+ /* first draw the sprite, visible */
+ pdrawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy, sx, sy,
+ cliprect, TRANSPARENCY_PENS, 0x0101, 0x00);
+
+ /* then draw the mask, behind the background but obscuring following sprites */
+ pdrawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy, sx, sy,
+ cliprect, TRANSPARENCY_PENS, 0xfeff, 0x02);
+ }
+ else
+ {
+ /* first draw the sprite, visible */
+ pdrawgfx(bitmap, machine->gfx[1], code, color, !flipx, !flipy, 480 - sx, 452 - sy,
+ cliprect, TRANSPARENCY_PENS, 0x0101, 0x00);
+
+ /* then draw the mask, behind the background but obscuring following sprites */
+ pdrawgfx(bitmap, machine->gfx[1], code, color, !flipx, !flipy, 480 - sx, 452 - sy,
+ cliprect, TRANSPARENCY_PENS, 0xfeff, 0x02);
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Generic MCR3 redraw
+ *
+ *************************************/
+
+VIDEO_UPDATE( mcr3 )
+{
+ /* update the flip state */
+ tilemap_set_flip(bg_tilemap, mcr_cocktail_flip ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
+
+ /* draw the background */
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* draw the sprites */
+ mcr3_update_sprites(machine, bitmap, cliprect, 0x03, 0, 0, 0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( spyhunt )
+{
+ /* for every character in the Video RAM, check if it has been modified */
+ /* since last time and update it accordingly. */
+ tilemap_set_scrollx(bg_tilemap, 0, spyhunt_scrollx * 2 + spyhunt_scroll_offset);
+ tilemap_set_scrolly(bg_tilemap, 0, spyhunt_scrolly * 2);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* draw the sprites */
+ mcr3_update_sprites(machine, bitmap, cliprect, spyhunt_sprite_color_mask, 0, -12, 0);
+
+ /* render any characters on top */
+ tilemap_draw(bitmap, cliprect, alpha_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/mcr68.c b/src/mame/video/mcr68.c
new file mode 100644
index 00000000000..cba2fcb06a6
--- /dev/null
+++ b/src/mame/video/mcr68.c
@@ -0,0 +1,335 @@
+/***************************************************************************
+
+ Midway MCR-68k system
+
+***************************************************************************/
+
+#include "driver.h"
+#include "mcr.h"
+
+
+#define LOW_BYTE(x) ((x) & 0xff)
+
+
+UINT8 mcr68_sprite_clip;
+INT8 mcr68_sprite_xoffset;
+
+static tilemap *bg_tilemap;
+static tilemap *fg_tilemap;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int data = LOW_BYTE(videoram16[tile_index * 2]) | (LOW_BYTE(videoram16[tile_index * 2 + 1]) << 8);
+ int code = (data & 0x3ff) | ((data >> 4) & 0xc00);
+ int color = (~data >> 12) & 3;
+ SET_TILE_INFO(0, code, color, TILE_FLIPYX((data >> 10) & 3));
+ if (machine->gfx[0]->total_elements < 0x1000)
+ tileinfo->category = (data >> 15) & 1;
+}
+
+
+static TILE_GET_INFO( zwackery_get_bg_tile_info )
+{
+ int data = videoram16[tile_index];
+ int color = (data >> 13) & 7;
+ SET_TILE_INFO(0, data & 0x3ff, color, TILE_FLIPYX((data >> 11) & 3));
+}
+
+
+static TILE_GET_INFO( zwackery_get_fg_tile_info )
+{
+ int data = videoram16[tile_index];
+ int color = (data >> 13) & 7;
+ SET_TILE_INFO(2, data & 0x3ff, color, TILE_FLIPYX((data >> 11) & 3));
+ tileinfo->category = (color != 0);
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( mcr68 )
+{
+ /* initialize the background tilemap */
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,16, 32,32);
+ tilemap_set_transparent_pen(bg_tilemap, 0);
+}
+
+
+VIDEO_START( zwackery )
+{
+ const UINT8 *colordatabase = (const UINT8 *)memory_region(REGION_GFX3);
+ gfx_element *gfx0 = machine->gfx[0];
+ gfx_element *gfx2 = machine->gfx[2];
+ int code, y, x;
+
+ /* initialize the background tilemap */
+ bg_tilemap = tilemap_create(zwackery_get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,16, 32,32);
+
+ /* initialize the foreground tilemap */
+ fg_tilemap = tilemap_create(zwackery_get_fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,16, 32,32);
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+
+ /* "colorize" each code */
+ for (code = 0; code < gfx0->total_elements; code++)
+ {
+ const UINT8 *coldata = colordatabase + code * 32;
+ UINT8 *gfxdata0 = gfx0->gfxdata + code * gfx0->char_modulo;
+ UINT8 *gfxdata2 = gfx2->gfxdata + code * gfx2->char_modulo;
+
+ /* assume 16 rows */
+ for (y = 0; y < 16; y++)
+ {
+ UINT8 *gd0 = gfxdata0;
+ UINT8 *gd2 = gfxdata2;
+
+ /* 16 columns */
+ for (x = 0; x < 16; x++, gd0++, gd2++)
+ {
+ int coloffs = (y & 0x0c) | ((x >> 2) & 0x03);
+ int pen0 = coldata[coloffs * 2 + 0];
+ int pen1 = coldata[coloffs * 2 + 1];
+ int tp0, tp1;
+
+ /* every 4 pixels gets its own foreground/background colors */
+ *gd0 = *gd0 ? pen1 : pen0;
+
+ /* for gfx 2, we convert all low-priority pens to 0 */
+ tp0 = (pen0 & 0x80) ? pen0 : 0;
+ tp1 = (pen1 & 0x80) ? pen1 : 0;
+ *gd2 = *gd2 ? tp1 : tp0;
+ }
+
+ /* advance */
+ gfxdata0 += gfx0->line_modulo;
+ gfxdata2 += gfx2->line_modulo;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM writes
+ *
+ *************************************/
+
+WRITE16_HANDLER( mcr68_paletteram_w )
+{
+ int newword;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ newword = paletteram16[offset];
+ palette_set_color_rgb(Machine, offset, pal3bit(newword >> 6), pal3bit(newword >> 0), pal3bit(newword >> 3));
+}
+
+
+WRITE16_HANDLER( zwackery_paletteram_w )
+{
+ int newword;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ newword = paletteram16[offset];
+ palette_set_color_rgb(Machine, offset, pal5bit(~newword >> 10), pal5bit(~newword >> 0), pal5bit(~newword >> 5));
+}
+
+
+
+/*************************************
+ *
+ * Video RAM writes
+ *
+ *************************************/
+
+WRITE16_HANDLER( mcr68_videoram_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+
+WRITE16_HANDLER( zwackery_videoram_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+
+WRITE16_HANDLER( zwackery_spriteram_w )
+{
+ /* yech -- Zwackery relies on the upper 8 bits of a spriteram read being $ff! */
+ /* to make this happen we always write $ff in the upper 8 bits */
+ COMBINE_DATA(&spriteram16[offset]);
+ spriteram16[offset] |= 0xff00;
+}
+
+
+
+/*************************************
+ *
+ * Sprite update
+ *
+ *************************************/
+
+static void mcr68_update_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ rectangle sprite_clip = machine->screen[0].visarea;
+ int offs;
+
+ /* adjust for clipping */
+ sprite_clip.min_x += mcr68_sprite_clip;
+ sprite_clip.max_x -= mcr68_sprite_clip;
+ sect_rect(&sprite_clip, cliprect);
+
+ fillbitmap(priority_bitmap,1,&sprite_clip);
+
+ /* loop over sprite RAM */
+ for (offs = spriteram_size / 2 - 4;offs >= 0;offs -= 4)
+ {
+ int code, color, flipx, flipy, x, y, flags;
+
+ flags = LOW_BYTE(spriteram16[offs + 1]);
+ code = LOW_BYTE(spriteram16[offs + 2]) + 256 * ((flags >> 3) & 0x01) + 512 * ((flags >> 6) & 0x03);
+
+ /* skip if zero */
+ if (code == 0)
+ continue;
+
+ /* also skip if this isn't the priority we're drawing right now */
+ if (((flags >> 2) & 1) != priority)
+ continue;
+
+ /* extract the bits of information */
+ color = ~flags & 0x03;
+ flipx = flags & 0x10;
+ flipy = flags & 0x20;
+ x = LOW_BYTE(spriteram16[offs + 3]) * 2 + mcr68_sprite_xoffset;
+ y = (241 - LOW_BYTE(spriteram16[offs])) * 2;
+
+ /* allow sprites to clip off the left side */
+ if (x > 0x1f0) x -= 0x200;
+
+ /* sprites use color 0 for background pen and 8 for the 'under tile' pen.
+ The color 8 is used to cover over other sprites. */
+
+ /* first draw the sprite, visible */
+ pdrawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy, x, y,
+ &sprite_clip, TRANSPARENCY_PENS, 0x0101, 0x00);
+
+ /* then draw the mask, behind the background but obscuring following sprites */
+ pdrawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy, x, y,
+ &sprite_clip, TRANSPARENCY_PENS, 0xfeff, 0x02);
+ }
+}
+
+
+static void zwackery_update_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int offs;
+
+ fillbitmap(priority_bitmap,1,cliprect);
+
+ /* loop over sprite RAM */
+ for (offs = spriteram_size / 2 - 4;offs >= 0;offs -= 4)
+ {
+ int code, color, flipx, flipy, x, y, flags;
+
+ /* get the code and skip if zero */
+ code = LOW_BYTE(spriteram16[offs + 2]);
+ if (code == 0)
+ continue;
+
+ /* extract the flag bits and determine the color */
+ flags = LOW_BYTE(spriteram16[offs + 1]);
+ color = ((~flags >> 2) & 0x0f) | ((flags & 0x02) << 3);
+
+ /* for low priority, draw everything but color 7 */
+ if (!priority)
+ {
+ if (color == 7)
+ continue;
+ }
+
+ /* for high priority, only draw color 7 */
+ else
+ {
+ if (color != 7)
+ continue;
+ }
+
+ /* determine flipping and coordinates */
+ flipx = ~flags & 0x40;
+ flipy = flags & 0x80;
+ x = (231 - LOW_BYTE(spriteram16[offs + 3])) * 2;
+ y = (241 - LOW_BYTE(spriteram16[offs])) * 2;
+
+ if (x <= -32) x += 512;
+
+ /* sprites use color 0 for background pen and 8 for the 'under tile' pen.
+ The color 8 is used to cover over other sprites. */
+
+ /* first draw the sprite, visible */
+ pdrawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy, x, y,
+ cliprect, TRANSPARENCY_PENS, 0x0101, 0x00);
+
+ /* then draw the mask, behind the background but obscuring following sprites */
+ pdrawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy, x, y,
+ cliprect, TRANSPARENCY_PENS, 0xfeff, 0x02);
+ }
+}
+
+
+
+/*************************************
+ *
+ * General MCR/68k update
+ *
+ *************************************/
+
+VIDEO_UPDATE( mcr68 )
+{
+ /* draw the background */
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_OPAQUE | 0, 0);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_OPAQUE | 1, 0);
+
+ /* draw the low-priority sprites */
+ mcr68_update_sprites(machine, bitmap, cliprect, 0);
+
+ /* redraw tiles with priority over sprites */
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 1, 0);
+
+ /* draw the high-priority sprites */
+ mcr68_update_sprites(machine, bitmap, cliprect, 1);
+ return 0;
+}
+
+
+VIDEO_UPDATE( zwackery )
+{
+ /* draw the background */
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* draw the low-priority sprites */
+ zwackery_update_sprites(machine, bitmap, cliprect, 0);
+
+ /* redraw tiles with priority over sprites */
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 1, 0);
+
+ /* draw the high-priority sprites */
+ zwackery_update_sprites(machine, bitmap, cliprect, 1);
+ return 0;
+}
diff --git a/src/mame/video/meadows.c b/src/mame/video/meadows.c
new file mode 100644
index 00000000000..7a08e248f9f
--- /dev/null
+++ b/src/mame/video/meadows.c
@@ -0,0 +1,113 @@
+/***************************************************************************
+
+ Meadows S2650 driver
+
+****************************************************************************/
+
+#include "driver.h"
+#include "meadows.h"
+
+/* some constants to make life easier */
+#define SPR_ADJUST_X -18
+#define SPR_ADJUST_Y -14
+
+
+static tilemap *bg_tilemap;
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ SET_TILE_INFO(0, videoram[tile_index] & 0x7f, 0, 0);
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( meadows )
+{
+ bg_tilemap = tilemap_create(get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,30);
+}
+
+
+
+/*************************************
+ *
+ * Video RAM write
+ *
+ *************************************/
+
+WRITE8_HANDLER( meadows_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+
+/*************************************
+ *
+ * Sprite RAM write
+ *
+ *************************************/
+
+WRITE8_HANDLER( meadows_spriteram_w )
+{
+ if (spriteram[offset] != data)
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ spriteram[offset] = data;
+}
+
+
+
+/*************************************
+ *
+ * Sprite rendering
+ *
+ *************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *clip)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ int x = spriteram[i+0] + SPR_ADJUST_X;
+ int y = spriteram[i+4] + SPR_ADJUST_Y;
+ int code = spriteram[i+8] & 0x0f; /* bit #0 .. #3 select sprite */
+/* int bank = (spriteram[i+8] >> 4) & 1; bit #4 selects prom ??? */
+ int bank = i; /* that fixes it for now :-/ */
+ int flip = spriteram[i+8] >> 5; /* bit #5 flip vertical flag */
+
+ drawgfx(bitmap, machine->gfx[bank + 1], code, 0, flip, 0, x, y, clip, TRANSPARENCY_PEN, 0);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Primary video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( meadows )
+{
+ /* draw the background */
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* draw the sprites */
+ if (machine->gfx[1])
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/megasys1.c b/src/mame/video/megasys1.c
new file mode 100644
index 00000000000..d8a4798c7aa
--- /dev/null
+++ b/src/mame/video/megasys1.c
@@ -0,0 +1,1022 @@
+/***************************************************************************
+
+ -= Jaleco Mega System 1 =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+
+********** There are 3 scrolling layers, 1 word per tile:
+
+* Note: MS1-Z has 2 layers only.
+
+ A page is 256x256, approximately the visible screen size. Each layer is
+ made up of 8 pages (8x8 tiles) or 32 pages (16x16 tiles). The number of
+ horizontal pages and the tiles size is selectable, using the layer's
+ control register. I think that when tiles are 16x16 a layer can be made
+ of 16x2, 8x4, 4x8 or 2x16 pages (see below). When tile size is 8x8 we
+ have two examples to guide the choice:
+
+ the copyright screen of p47j (0x12) should be 4x2 (unless it's been hacked :)
+ the ending sequence of 64th street (0x13) should be 2x4.
+
+ I don't see a relation.
+
+
+MS1-A MS1-B MS1-C
+-----------------
+
+ Scrolling layers:
+
+90000 50000 e0000 Scroll 0
+94000 54000 e8000 Scroll 1
+98000 58000 f0000 Scroll 2 * Note: missing on MS1-Z
+
+Tile format: fedc------------ Palette
+ ----ba9876543210 Tile Number
+
+
+
+84000 44000 c2208 Layers Enable * Note: missing on MS1-Z?
+
+ fedc ---- ---- ---- unused
+ ---- ba98 ---- ---- Priority Code
+ ---- ---- 7654 ---- unused
+ ---- ---- ---- 3--- Enable Sprites
+ ---- ---- ---- -210 Enable Layer 210
+
+ (Note that the bottom layer can't be disabled)
+
+
+84200 44200 c2000 Scroll 0 Control
+84208 44208 c2008 Scroll 1 Control
+84008 44008 c2100 Scroll 2 Control * Note: missing on MS1-Z
+
+Offset: 00 Scroll X
+ 02 Scroll Y
+ 04 fedc ba98 765- ---- ? (unused?)
+ ---- ---- ---4 ---- 0<->16x16 Tiles 1<->8x8 Tiles
+ ---- ---- ---- 32-- ? (used, by p47!)
+ ---- ---- ---- --10 N: Layer H pages = 16 / (2^N)
+
+
+
+84300 44300 c2308 Screen Control
+
+ fed- ---- ---- ---- ? (unused?)
+ ---c ---- ---- ---- ? (on, troughout peekaboo)
+ ---- ba9- ---- ---- ? (unused?)
+ ---- ---8 ---- ---- Portrait F/F (?FullFill?)
+ ---- ---- 765- ---- ? (unused?)
+ ---- ---- ---4 ---- Reset Sound CPU (1->0 Transition)
+ ---- ---- ---- 321- ? (unused?)
+ ---- ---- ---- ---0 Flip Screen
+
+
+
+********** There are 256*4 colors (256*3 for MS1-Z):
+
+Colors MS1-A/C MS1-Z
+
+000-0ff Scroll 0 Scroll 0
+100-1ff Scroll 1 Sprites
+200-2ff Scroll 2 Scroll 1
+300-3ff Sprites -
+
+88000 48000 f8000 Palette
+
+ fedc--------3--- Red
+ ----ba98-----2-- Blue
+ --------7654--1- Green
+ ---------------0 ? (used, not RGB! [not changed in fades])
+
+
+********** There are 256 sprites (128 for MS1-Z):
+
+&RAM[8000] Sprite Data (16 bytes/entry. 128? entries)
+
+Offset: 0-6 ? (used, but as normal RAM, I think)
+ 08 fed- ---- ---- ---- ?
+ ---c ---- ---- ---- mosaic sol. (?)
+ ---- ba98 ---- ---- mosaic (?)
+ ---- ---- 7--- ---- y flip
+ ---- ---- -6-- ---- x flip
+ ---- ---- --45 ---- ?
+ ---- ---- ---- 3210 color code (* bit 3 = priority *)
+ 0A H position
+ 0C V position
+ 0E fedc ---- ---- ---- ? (used by p47j, 0-8!)
+ ---- ba98 7654 3210 Number
+
+
+
+Object RAM tells the hw how to use Sprite Data (missing on MS1-Z).
+This makes it possible to group multiple small sprite, up to 256,
+into one big virtual sprite (up to a whole screen):
+
+8e000 4e000 d2000 Object RAM (8 bytes/entry. 256*4 entries)
+
+Offset: 00 Index into Sprite Data RAM
+ 02 H Displacement
+ 04 V Displacement
+ 06 Number Displacement
+
+Only one of these four 256 entries is used to see if the sprite is to be
+displayed, according to this latter's flipx/y state:
+
+Object RAM entries: Used by sprites with:
+
+000-0ff No Flip
+100-1ff Flip X
+200-2ff Flip Y
+300-3ff Flip X & Y
+
+
+
+
+No? No? c2108 Sprite Bank
+
+ fedc ba98 7654 321- ? (unused?)
+ ---- ---- ---- ---0 Sprite Bank
+
+
+
+84100 44100 c2200 Sprite Control
+
+ fedc ba9- ---- ---- ? (unused?)
+ ---- ---8 ---- ---- Enable Sprite Splitting In 2 Groups:
+ Some Sprite Appear Over, Some Below The Layers
+ ---- ---- 765- ---- ? (unused?)
+ ---- ---- ---4 ---- Enable Effect (?)
+ ---- ---- ---- 3210 Effect Number (?)
+
+I think bit 4 enables some sort of color cycling for sprites having priority
+bit set. See code of p7j at 6488, affecting the rotating sprites before the
+Jaleco logo is shown: values 11-1f, then 0. I fear the Effect Number is an
+offset to be applied over the pens used by those sprites. As for bit 8, it's
+not used during game, but it is turned on when sprite/foreground priority is
+tested, along with Effect Number being 1, so ...
+
+
+********** Priorities (ouch!)
+
+[ Sprite / Sprite order ]
+
+ [MS1-A,B,C] From first in Object RAM (frontmost) to last.
+ [MS1-Z] From last in Sprite RAM (frontmost) to first.
+
+[ Layer / Layer & Sprite / Layer order ]
+
+Controlled by:
+
+ * bits 7-4 (16 values) of the Layer Control register
+ * bit 4 of the Sprite Control register
+
+ Layer Control Sprite Control
+MS1-Z -
+MS1-A 84000 84100
+MS1-B 44000 44100
+MS1-C c2208 c2200
+
+When bit 4 of the Sprite Contol register is set, sprites with color
+code 0-7 and sprites with color 8-f form two groups. Each group can
+appear over or below some layers.
+
+The 16 values in the Layer Control register determine the order of
+the layers, and of the groups of sprites.
+
+There is a PROM that translates the values in the register to the
+actual code sent to the hardware.
+
+
+***************************************************************************/
+
+#include "driver.h"
+#include "megasys1.h"
+
+/* Variables defined here, that have to be shared: */
+tilemap *megasys1_tmap[3];
+
+UINT16 *megasys1_scrollram[3];
+UINT16 *megasys1_objectram, *megasys1_vregs, *megasys1_ram;
+
+int megasys1_scrollx[3], megasys1_scrolly[3];
+int megasys1_active_layers;
+int megasys1_bits_per_color_code;
+
+static int megasys1_scroll_flag[3];
+static int megasys1_sprite_bank;
+static int megasys1_screen_flag, megasys1_sprite_flag;
+static int megasys1_8x8_scroll_factor[3], megasys1_16x16_scroll_factor[3];
+
+static tilemap *megasys1_tilemap[3][2][4];
+
+/* Variables defined in driver: */
+static int hardware_type_z;
+
+static void create_tilemaps(void);
+
+
+
+#ifdef MAME_DEBUG
+
+#define SHOW_WRITE_ERROR(_format_,_offset_,_data_)\
+{ \
+ popmessage(_format_,_offset_,_data_);\
+ logerror("CPU #0 PC %06X : Warning, ",activecpu_get_pc()); \
+ logerror(_format_,_offset_,_data_);\
+ logerror("\n");\
+}
+
+#else
+
+#define SHOW_WRITE_ERROR(_format_,_offset_,_data_)\
+{\
+ logerror("CPU #0 PC %06X : Warning, ",activecpu_get_pc()); \
+ logerror(_format_,_offset_,_data_); \
+ logerror("\n");\
+}
+
+#endif
+
+
+
+VIDEO_START( megasys1 )
+{
+ int i;
+
+ spriteram16 = &megasys1_ram[0x8000/2];
+
+ create_tilemaps();
+ megasys1_tmap[0] = megasys1_tilemap[0][0][0];
+ megasys1_tmap[1] = megasys1_tilemap[1][0][0];
+ megasys1_tmap[2] = megasys1_tilemap[2][0][0];
+
+ megasys1_active_layers = megasys1_sprite_bank = megasys1_screen_flag = megasys1_sprite_flag = 0;
+
+ for (i = 0; i < 3; i ++)
+ {
+ megasys1_scroll_flag[i] = megasys1_scrollx[i] = megasys1_scrolly[i] = 0;
+ }
+
+ megasys1_bits_per_color_code = 4;
+
+/*
+ The tile code of a specific layer is multiplied for a constant
+ depending on the tile mode (8x8 or 16x16)
+
+ The most reasonable arrangement seems a 1:1 mapping (meaning we
+ must multiply by 4 the tile code in 16x16 mode, since we decode
+ the graphics like 8x8)
+
+ However, this is probably a game specific thing, as Soldam uses
+ layer 1 in both modes, and even with 8x8 tiles the tile code must
+ be multiplied by 4!
+
+ AFAIK, the other games use a layer in one mode only (always 8x8 or
+ 16x16) so it could be that the multiplication factor is constant
+ for each layer and hardwired to 1x or 4x for both tile sizes
+*/
+
+ megasys1_8x8_scroll_factor[0] = 1; megasys1_16x16_scroll_factor[0] = 4;
+ megasys1_8x8_scroll_factor[1] = 1; megasys1_16x16_scroll_factor[1] = 4;
+ megasys1_8x8_scroll_factor[2] = 1; megasys1_16x16_scroll_factor[2] = 4;
+
+ if (strcmp(machine->gamedrv->name, "soldamj") == 0)
+ {
+ megasys1_8x8_scroll_factor[1] = 4; megasys1_16x16_scroll_factor[1] = 4;
+ }
+
+ hardware_type_z = 0;
+ if (strcmp(machine->gamedrv->name, "lomakai") == 0 ||
+ strcmp(machine->gamedrv->name, "makaiden") == 0)
+ hardware_type_z = 1;
+}
+
+/***************************************************************************
+
+ Layers declarations:
+
+ * Read and write handlers for the layer
+ * Callbacks for the TileMap code
+
+***************************************************************************/
+
+#define TILES_PER_PAGE_X (0x20)
+#define TILES_PER_PAGE_Y (0x20)
+#define TILES_PER_PAGE (TILES_PER_PAGE_X * TILES_PER_PAGE_Y)
+
+INLINE void scrollram_w(int which, offs_t offset, UINT16 data, UINT16 mem_mask)
+{
+ COMBINE_DATA(&megasys1_scrollram[which][offset]);
+ if (offset < 0x40000/2 && megasys1_tmap[which])
+ {
+ if (megasys1_scroll_flag[which] & 0x10) /* tiles are 8x8 */
+ {
+ tilemap_mark_tile_dirty(megasys1_tmap[which], offset );
+ }
+ else
+ {
+ tilemap_mark_tile_dirty(megasys1_tmap[which], offset*4 + 0);
+ tilemap_mark_tile_dirty(megasys1_tmap[which], offset*4 + 1);
+ tilemap_mark_tile_dirty(megasys1_tmap[which], offset*4 + 2);
+ tilemap_mark_tile_dirty(megasys1_tmap[which], offset*4 + 3);
+ }
+ }
+}
+
+WRITE16_HANDLER( megasys1_scrollram_0_w ) { scrollram_w(0, offset, data, mem_mask); }
+WRITE16_HANDLER( megasys1_scrollram_1_w ) { scrollram_w(1, offset, data, mem_mask); }
+WRITE16_HANDLER( megasys1_scrollram_2_w ) { scrollram_w(2, offset, data, mem_mask); }
+
+
+
+
+/***************************************************************************
+
+ Video registers access
+
+***************************************************************************/
+
+
+/* Tilemap Size (PagesX x PagesY)
+
+ Reg. Value 16 8 <- Tile Size
+
+ 0 16 x 2 8 x 1
+ 1 8 x 4 4 x 2
+ 2 4 x 8 4 x 2
+ 3 2 x 16 2 x 4
+*/
+
+static TILEMAP_MAPPER( megasys1_scan_8x8 )
+{
+ return (col * TILES_PER_PAGE_Y) +
+ (row / TILES_PER_PAGE_Y) * TILES_PER_PAGE * (num_cols / TILES_PER_PAGE_X) +
+ (row % TILES_PER_PAGE_Y);
+}
+
+static TILEMAP_MAPPER( megasys1_scan_16x16 )
+{
+ return ( ((col / 2) * (TILES_PER_PAGE_Y / 2)) +
+ ((row / 2) / (TILES_PER_PAGE_Y / 2)) * (TILES_PER_PAGE / 4) * (num_cols / TILES_PER_PAGE_X) +
+ ((row / 2) % (TILES_PER_PAGE_Y / 2)) )*4 + (row&1) + (col&1)*2;
+}
+
+static TILE_GET_INFO( megasys1_get_scroll_tile_info_8x8 )
+{
+ int tmap = (FPTR)param;
+ UINT16 code = megasys1_scrollram[tmap][tile_index];
+ SET_TILE_INFO(tmap, (code & 0xfff) * megasys1_8x8_scroll_factor[tmap], code >> (16 - megasys1_bits_per_color_code), 0);
+}
+
+static TILE_GET_INFO( megasys1_get_scroll_tile_info_16x16 )
+{
+ int tmap = (FPTR)param;
+ UINT16 code = megasys1_scrollram[tmap][tile_index/4];
+ SET_TILE_INFO(tmap, (code & 0xfff) * megasys1_16x16_scroll_factor[tmap] + (tile_index & 3), code >> (16 - megasys1_bits_per_color_code), 0);
+}
+
+static void create_tilemaps(void)
+{
+ int layer, i;
+
+ for (layer = 0; layer < 3; layer++)
+ {
+ /* 16x16 tilemaps */
+ megasys1_tilemap[layer][0][0] = tilemap_create(megasys1_get_scroll_tile_info_16x16, megasys1_scan_16x16,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 16, TILES_PER_PAGE_Y * 2);
+ megasys1_tilemap[layer][0][1] = tilemap_create(megasys1_get_scroll_tile_info_16x16, megasys1_scan_16x16,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 8, TILES_PER_PAGE_Y * 4);
+ megasys1_tilemap[layer][0][2] = tilemap_create(megasys1_get_scroll_tile_info_16x16, megasys1_scan_16x16,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 4, TILES_PER_PAGE_Y * 8);
+ megasys1_tilemap[layer][0][3] = tilemap_create(megasys1_get_scroll_tile_info_16x16, megasys1_scan_16x16,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 2, TILES_PER_PAGE_Y * 16);
+
+ /* 8x8 tilemaps */
+ megasys1_tilemap[layer][1][0] = tilemap_create(megasys1_get_scroll_tile_info_8x8, megasys1_scan_8x8,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 8, TILES_PER_PAGE_Y * 1);
+ megasys1_tilemap[layer][1][1] = tilemap_create(megasys1_get_scroll_tile_info_8x8, megasys1_scan_8x8,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 4, TILES_PER_PAGE_Y * 2);
+ megasys1_tilemap[layer][1][2] = tilemap_create(megasys1_get_scroll_tile_info_8x8, megasys1_scan_8x8,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 4, TILES_PER_PAGE_Y * 2);
+ megasys1_tilemap[layer][1][3] = tilemap_create(megasys1_get_scroll_tile_info_8x8, megasys1_scan_8x8,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 2, TILES_PER_PAGE_Y * 4);
+
+ /* set user data and transparency */
+ for (i = 0; i < 8; i++)
+ {
+ tilemap_set_user_data(megasys1_tilemap[layer][i/4][i%4], (void *)(FPTR)layer);
+ tilemap_set_transparent_pen(megasys1_tilemap[layer][i/4][i%4], 15);
+ }
+ }
+}
+
+void megasys1_set_vreg_flag(int which, int data)
+{
+ if (megasys1_scroll_flag[which] != data)
+ {
+ megasys1_scroll_flag[which] = data;
+ megasys1_tmap[which] = megasys1_tilemap[which][(data >> 4) & 1][data & 3];
+ tilemap_mark_all_tiles_dirty(megasys1_tmap[which]);
+ }
+}
+
+
+
+/* Used by MS1-A/Z, B */
+WRITE16_HANDLER( megasys1_vregs_A_w )
+{
+ UINT16 new_data = COMBINE_DATA(&megasys1_vregs[offset]);
+
+ switch (offset)
+ {
+ case 0x000/2 : megasys1_active_layers = new_data; break;
+
+ case 0x008/2+0 : megasys1_scrollx[2] = new_data; break;
+ case 0x008/2+1 : megasys1_scrolly[2] = new_data; break;
+ case 0x008/2+2 : megasys1_set_vreg_flag(2, new_data); break;
+
+ case 0x200/2+0 : megasys1_scrollx[0] = new_data; break;
+ case 0x200/2+1 : megasys1_scrolly[0] = new_data; break;
+ case 0x200/2+2 : megasys1_set_vreg_flag(0, new_data); break;
+
+ case 0x208/2+0 : megasys1_scrollx[1] = new_data; break;
+ case 0x208/2+1 : megasys1_scrolly[1] = new_data; break;
+ case 0x208/2+2 : megasys1_set_vreg_flag(1, new_data); break;
+
+ case 0x100/2 : megasys1_sprite_flag = new_data; break;
+
+ case 0x300/2 : megasys1_screen_flag = new_data;
+ if (new_data & 0x10)
+ cpunum_set_input_line(1, INPUT_LINE_RESET, ASSERT_LINE);
+ else
+ cpunum_set_input_line(1, INPUT_LINE_RESET, CLEAR_LINE);
+ break;
+
+ case 0x308/2 : soundlatch_word_w(0,new_data,0);
+ cpunum_set_input_line(1,4,HOLD_LINE);
+ break;
+
+ default : SHOW_WRITE_ERROR("vreg %04X <- %04X",offset*2,data);
+ }
+
+}
+
+
+
+
+/* Used by MS1-C only */
+READ16_HANDLER( megasys1_vregs_C_r )
+{
+ switch (offset)
+ {
+ case 0x8000/2: return soundlatch2_word_r(0,0);
+ default: return megasys1_vregs[offset];
+ }
+}
+
+WRITE16_HANDLER( megasys1_vregs_C_w )
+{
+ UINT16 new_data = COMBINE_DATA(&megasys1_vregs[offset]);
+
+ switch (offset)
+ {
+ case 0x2000/2+0 : megasys1_scrollx[0] = new_data; break;
+ case 0x2000/2+1 : megasys1_scrolly[0] = new_data; break;
+ case 0x2000/2+2 : megasys1_set_vreg_flag(0, new_data); break;
+
+ case 0x2008/2+0 : megasys1_scrollx[1] = new_data; break;
+ case 0x2008/2+1 : megasys1_scrolly[1] = new_data; break;
+ case 0x2008/2+2 : megasys1_set_vreg_flag(1, new_data); break;
+
+ case 0x2100/2+0 : megasys1_scrollx[2] = new_data; break;
+ case 0x2100/2+1 : megasys1_scrolly[2] = new_data; break;
+ case 0x2100/2+2 : megasys1_set_vreg_flag(2, new_data); break;
+
+ case 0x2108/2 : megasys1_sprite_bank = new_data; break;
+ case 0x2200/2 : megasys1_sprite_flag = new_data; break;
+ case 0x2208/2 : megasys1_active_layers = new_data; break;
+
+ case 0x2308/2 : megasys1_screen_flag = new_data;
+ if (new_data & 0x10)
+ cpunum_set_input_line(1, INPUT_LINE_RESET, ASSERT_LINE);
+ else
+ cpunum_set_input_line(1, INPUT_LINE_RESET, CLEAR_LINE);
+ break;
+
+ case 0x8000/2 : /* Cybattler reads sound latch on irq 2 */
+ soundlatch_word_w(0,new_data,0);
+ cpunum_set_input_line(1,2,HOLD_LINE);
+ break;
+
+ default: SHOW_WRITE_ERROR("vreg %04X <- %04X",offset*2,data);
+ }
+}
+
+
+
+/* Used by MS1-D only */
+WRITE16_HANDLER( megasys1_vregs_D_w )
+{
+ UINT16 new_data = COMBINE_DATA(&megasys1_vregs[offset]);
+
+ switch (offset)
+ {
+ case 0x2000/2+0 : megasys1_scrollx[0] = new_data; break;
+ case 0x2000/2+1 : megasys1_scrolly[0] = new_data; break;
+ case 0x2000/2+2 : megasys1_set_vreg_flag(0, new_data); break;
+
+ case 0x2008/2+0 : megasys1_scrollx[1] = new_data; break;
+ case 0x2008/2+1 : megasys1_scrolly[1] = new_data; break;
+ case 0x2008/2+2 : megasys1_set_vreg_flag(1, new_data); break;
+
+// case 0x2100/2+0 : megasys1_scrollx[2] = new_data; break;
+// case 0x2100/2+1 : megasys1_scrolly[2] = new_data; break;
+// case 0x2100/2+2 : megasys1_set_vreg_flag(2, new_data); break;
+
+ case 0x2108/2 : megasys1_sprite_bank = new_data; break;
+ case 0x2200/2 : megasys1_sprite_flag = new_data; break;
+ case 0x2208/2 : megasys1_active_layers = new_data; break;
+ case 0x2308/2 : megasys1_screen_flag = new_data; break;
+
+ default: SHOW_WRITE_ERROR("vreg %04X <- %04X",offset*2,data);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Sprites Drawing
+
+***************************************************************************/
+
+
+/* Draw sprites in the given bitmap.
+
+ Sprite Data:
+
+ Offset Data
+
+ 00-07 ?
+ 08 fed- ---- ---- ---- ?
+ ---c ---- ---- ---- mosaic sol. (?)
+ ---- ba98 ---- ---- mosaic (?)
+ ---- ---- 7--- ---- y flip
+ ---- ---- -6-- ---- x flip
+ ---- ---- --45 ---- ?
+ ---- ---- ---- 3210 color code (bit 3 = priority)
+ 0A X position
+ 0C Y position
+ 0E Code */
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int color,code,sx,sy,flipx,flipy,attr,sprite,offs,color_mask;
+
+/* objram: 0x100*4 entries spritedata: 0x80 entries */
+
+ /* sprite order is from first in Sprite Data RAM (frontmost) to last */
+
+ if (hardware_type_z == 0) /* standard sprite hardware */
+ {
+ color_mask = (megasys1_sprite_flag & 0x100) ? 0x07 : 0x0f;
+
+ for (offs = (0x800-8)/2;offs >= 0;offs -= 8/2)
+ {
+ for (sprite = 0; sprite < 4 ; sprite ++)
+ {
+ UINT16 *objectdata = &megasys1_objectram[offs + (0x800/2) * sprite];
+ UINT16 *spritedata = &spriteram16[ (objectdata[ 0 ] & 0x7f) * 0x10/2];
+
+ attr = spritedata[ 8/2 ];
+ if (((attr & 0xc0)>>6) != sprite) continue; // flipping
+
+ /* apply the position displacements */
+ sx = ( spritedata[0x0A/2] + objectdata[0x02/2] ) % 512;
+ sy = ( spritedata[0x0C/2] + objectdata[0x04/2] ) % 512;
+
+ if (sx > 256-1) sx -= 512;
+ if (sy > 256-1) sy -= 512;
+
+ flipx = attr & 0x40;
+ flipy = attr & 0x80;
+
+ if (megasys1_screen_flag & 1)
+ {
+ flipx = !flipx; flipy = !flipy;
+ sx = 240-sx; sy = 240-sy;
+ }
+
+ /* sprite code is displaced as well */
+ code = spritedata[0x0E/2] + objectdata[0x06/2];
+ color = (attr & color_mask);
+
+ pdrawgfx(bitmap,machine->gfx[3],
+ (code & 0xfff ) + ((megasys1_sprite_bank & 1) << 12),
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN,15,
+ (attr & 0x08) ? 0x0c : 0x0a);
+ } /* sprite */
+ } /* offs */
+ } /* non Z hw */
+ else
+ {
+
+ /* MS1-Z just draws Sprite Data, and in reverse order */
+
+ for (sprite = 0x80-1;sprite >= 0;sprite--)
+ {
+ UINT16 *spritedata = &spriteram16[ sprite * 0x10/2];
+
+ attr = spritedata[ 8/2 ];
+
+ sx = spritedata[0x0A/2] % 512;
+ sy = spritedata[0x0C/2] % 512;
+
+ if (sx > 256-1) sx -= 512;
+ if (sy > 256-1) sy -= 512;
+
+ code = spritedata[0x0E/2];
+ color = (attr & 0x0F);
+
+ flipx = attr & 0x40;
+ flipy = attr & 0x80;
+
+ if (megasys1_screen_flag & 1)
+ {
+ flipx = !flipx; flipy = !flipy;
+ sx = 240-sx; sy = 240-sy;
+ }
+
+ pdrawgfx(bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN,15,
+ (attr & 0x08) ? 0x0c : 0x0a);
+ } /* sprite */
+ } /* Z hw */
+
+}
+
+
+
+
+/***************************************************************************
+ Convert the Priority Prom
+***************************************************************************/
+
+struct priority
+{
+ const char *driver;
+ int priorities[16];
+};
+
+static int megasys1_layers_order[16];
+
+/*
+ Layers order encoded as an int like: 0x01234, where
+
+ 0: Scroll 0
+ 1: Scroll 1
+ 2: Scroll 2
+ 3: Sprites with color 0-7
+ (*every sprite*, if sprite splitting is not active)
+ 4: Sprites with color 8-f
+ f: empty placeholder (we can't use 0!)
+
+ and the bottom layer is on the left (e.g. 0).
+
+ The special value 0xfffff means that the order is either unknown
+ or no simple stack of layers can account for the values in the prom.
+ (the default value, 0x04132, will be used in those cases)
+
+*/
+
+static const struct priority priorities[] =
+{
+ { "64street",
+ { 0x04132,0x03142,0x14032,0x04132,0xfffff,0x04132,0xfffff,0xfffff,
+ 0xfffff,0xfffff,0xfffff,0xfffff,0xfffff,0xfffff,0xfffff,0xfffff }
+ },
+ { "chimerab",
+ { 0x14032,0x04132,0x14032,0x04132,0xfffff,0xfffff,0xfffff,0xfffff,
+ 0xfffff,0xfffff,0x01324,0xfffff,0xfffff,0xfffff,0xfffff,0xfffff }
+ },
+ { 0 } // end of list: use the prom's data
+};
+
+
+/*
+ Convert the 512 bytes in the Priority Prom into 16 ints, encoding
+ the layers order for 16 selectable priority schemes.
+
+ INPUT (to the video chip):
+
+ 4 pixels: 3 layers(012) + 1 sprite (3)
+ (there are low and high priority sprites which
+ are split when the "split sprites" bit is set)
+
+ addr = ( (low pri sprite & split sprites ) << 0 ) +
+ ( (pixel 0 is enabled and opaque ) << 1 ) +
+ ( (pixel 1 is enabled and opaque ) << 2 ) +
+ ( (pixel 2 is enabled and opaque ) << 3 ) +
+ ( (pixel 3 is enabled and opaque ) << 4 ) +
+ ( (layers_enable bits 11-8 ) << 5 )
+
+ OUTPUT (to video):
+ 1 pixel, the one from layer: PROM[addr] (layer can be 0-3)
+
+ This scheme can generate a wealth of funky priority schemes
+ while we can account for just a simple stack of transparent
+ layers like: 01324. That is: bottom layer is 0, then 1, then
+ sprites (low priority sprites if sprite splitting is active,
+ every sprite if not) then layer 2 and high priority sprites
+ (only if sprite splitting is active).
+
+ Hence, during the conversion process we make sure each of the
+ 16 priority scheme in the prom is a "simple" one like the above
+ and log a warning otherwise. The feasibility criterion is such:
+
+ the opaque pens of the top layer must be above any other layer.
+ The transparent pens of the top layer must be either totally
+ opaque or totally transparent with respects to the other layers:
+ when the bit relative to the top layer is not set, the top layer's
+ code must be either always absent (transparent case) or always
+ present (opaque case) in the prom.
+
+ NOTE: This can't account for orders starting like: 030..
+ as found in peekaboo's prom. That's where sprites go below
+ the bottom layer's opaque pens, but above its transparent
+ pens.
+*/
+
+PALETTE_INIT( megasys1 )
+{
+ int pri_code, offset, i, order;
+
+ /* First check if we have an hand-crafted priority scheme
+ available (this should happen only if no good dump
+ of the prom is known) */
+
+ i = 0;
+ while ( priorities[i].driver &&
+ strcmp(priorities[i].driver, machine->gamedrv->name) != 0 &&
+ strcmp(priorities[i].driver, machine->gamedrv->parent) != 0)
+ i++;
+
+ if (priorities[i].driver)
+ {
+ memcpy (megasys1_layers_order, priorities[i].priorities, 16 * sizeof(int));
+
+ logerror("WARNING: using an hand-crafted priorities scheme\n");
+
+ return;
+ }
+
+ /* Otherwise, perform the conversion from the prom itself */
+
+ for (pri_code = 0; pri_code < 0x10 ; pri_code++) // 16 priority codes
+ {
+ int layers_order[2]; // 2 layers orders (split sprites on/off)
+
+ for (offset = 0; offset < 2; offset ++)
+ {
+ int enable_mask = 0xf; // start with every layer enabled
+
+ layers_order[offset] = 0xfffff;
+
+ do
+ {
+ int top = color_prom[pri_code * 0x20 + offset + enable_mask * 2] & 3; // this must be the top layer
+ int top_mask = 1 << top;
+
+ int result = 0; // result of the feasibility check for this layer
+
+ for (i = 0; i < 0x10 ; i++) // every combination of opaque and transparent pens
+ {
+ int opacity = i & enable_mask; // only consider active layers
+ int layer = color_prom[pri_code * 0x20 + offset + opacity * 2];
+
+ if (opacity)
+ {
+ if (opacity & top_mask)
+ {
+ if (layer != top ) result |= 1; // error: opaque pens aren't always opaque!
+ }
+ else
+ {
+ if (layer == top) result |= 2; // transparent pen is opaque
+ else result |= 4; // transparent pen is transparent
+ }
+ }
+ }
+
+ /* note: 3210 means that layer 0 is the bottom layer
+ (the order is reversed in the hand-crafted data) */
+
+ layers_order[offset] = ( (layers_order[offset] << 4) | top ) & 0xfffff;
+ enable_mask &= ~top_mask;
+
+ if (result & 1)
+ {
+ logerror("WARNING, pri $%X split %d - layer %d's opaque pens not totally opaque\n",pri_code,offset,top);
+
+ layers_order[offset] = 0xfffff;
+ break;
+ }
+
+ if ((result & 6) == 6)
+ {
+ logerror("WARNING, pri $%X split %d - layer %d's transparent pens aren't always transparent nor always opaque\n",pri_code,offset,top);
+
+ layers_order[offset] = 0xfffff;
+ break;
+ }
+
+ if (result == 2) enable_mask = 0; // totally opaque top layer
+
+ } while (enable_mask);
+
+ } // offset
+
+ /* merge the two layers orders */
+
+ order = 0xfffff;
+
+ for (i = 5; i > 0 ; ) // 5 layers to write
+ {
+ int layer;
+ int layer0 = layers_order[0] & 0x0f;
+ int layer1 = layers_order[1] & 0x0f;
+
+ if (layer0 != 3) // 0,1,2 or f
+ {
+ if (layer1 == 3)
+ {
+ layer = 4;
+ layers_order[0] <<= 4; // layer1 won't change next loop
+ }
+ else
+ {
+ layer = layer0;
+ if (layer0 != layer1)
+ {
+ logerror("WARNING, pri $%X - 'sprite splitting' does not simply split sprites\n",pri_code);
+
+ order = 0xfffff;
+ break;
+ }
+
+ }
+ }
+ else // layer0 = 3;
+ {
+ if (layer1 == 3)
+ {
+ layer = 0x43; // 4 must always be present
+ order <<= 4;
+ i --; // 2 layers written at once
+ }
+ else
+ {
+ layer = 3;
+ layers_order[1] <<= 4; // layer1 won't change next loop
+ }
+ }
+
+ /* reverse the order now */
+ order = (order << 4 ) | layer;
+
+ i --; // layer written
+
+ layers_order[0] >>= 4;
+ layers_order[1] >>= 4;
+
+ } // merging
+
+ megasys1_layers_order[pri_code] = order & 0xfffff; // at last!
+
+ } // pri_code
+
+
+
+#if 0
+ /* log the priority schemes */
+ for (i = 0; i < 16; i++)
+ logerror("PROM %X] %05x\n", i, megasys1_layers_order[i]);
+#endif
+
+
+}
+
+
+
+
+
+/***************************************************************************
+ Draw the game screen in the given mame_bitmap.
+***************************************************************************/
+
+
+VIDEO_UPDATE( megasys1 )
+{
+ int i,flag,pri,primask;
+ int active_layers;
+
+ if (hardware_type_z)
+ {
+ /* no layer 2 and fixed layers order? */
+ active_layers = 0x000b;
+ pri = 0x0314f;
+ }
+ else
+ {
+ int reallyactive = 0;
+
+ /* get layers order */
+ pri = megasys1_layers_order[(megasys1_active_layers & 0x0f0f) >> 8];
+
+#ifdef MAME_DEBUG
+ if (pri == 0xfffff)
+ {
+ popmessage("Pri: %04X - Flag: %04X", megasys1_active_layers, megasys1_sprite_flag);
+ }
+#endif
+
+ if (pri == 0xfffff) pri = 0x04132;
+
+ /* see what layers are really active (layers 4 & f will do no harm) */
+ for (i = 0;i < 5;i++)
+ reallyactive |= 1 << ((pri >> (4*i)) & 0x0f);
+
+ active_layers = megasys1_active_layers & reallyactive;
+ active_layers |= 1 << ((pri & 0xf0000) >> 16); // bottom layer can't be disabled
+ }
+
+ tilemap_set_flip( ALL_TILEMAPS, (megasys1_screen_flag & 1) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0 );
+
+ for (i = 0;i < 3;i++)
+ {
+ if (megasys1_tmap[i])
+ {
+ tilemap_set_enable(megasys1_tmap[i],active_layers & (1 << i));
+
+ tilemap_set_scrollx(megasys1_tmap[i],0,megasys1_scrollx[i]);
+ tilemap_set_scrolly(megasys1_tmap[i],0,megasys1_scrolly[i]);
+ }
+ }
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ flag = TILEMAP_DRAW_OPAQUE;
+ primask = 0;
+
+ for (i = 0;i < 5;i++)
+ {
+ int layer = (pri & 0xf0000) >> 16;
+ pri <<= 4;
+
+ switch (layer)
+ {
+ case 0:
+ case 1:
+ case 2:
+ if ( (megasys1_tmap[layer]) && (active_layers & (1 << layer) ) )
+ {
+ tilemap_draw(bitmap,cliprect,megasys1_tmap[layer],flag,primask);
+ flag = 0;
+ }
+ break;
+ case 3:
+ case 4:
+ if (flag != 0)
+ {
+ flag = 0;
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ }
+
+ if (megasys1_sprite_flag & 0x100) /* sprites are split */
+ {
+ /* following tilemaps will obscure this sprites layer */
+ primask |= 1 << (layer-3);
+ }
+ else
+ /* following tilemaps will obscure all sprites */
+ if (layer == 3) primask |= 3;
+
+ break;
+ }
+ }
+
+ if (active_layers & 0x08)
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/megazone.c b/src/mame/video/megazone.c
new file mode 100644
index 00000000000..f85a7b5a5c6
--- /dev/null
+++ b/src/mame/video/megazone.c
@@ -0,0 +1,222 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *megazone_scrollx;
+UINT8 *megazone_scrolly;
+static int flipscreen;
+
+UINT8 *megazone_videoram2;
+UINT8 *megazone_colorram2;
+size_t megazone_videoram2_size;
+
+/***************************************************************************
+Based on driver from MAME 0.55
+Changes by Martin M. (pfloyd@gmx.net) 14.10.2001:
+
+ - Added support for screen flip in cocktail mode (tricky!) */
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Megazone has one 32x8 palette PROM and two 256x4 lookup table PROMs
+ (one for characters, one for sprites).
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( megazone )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = *(color_prom++) & 0x0f;
+
+ /* characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = (*(color_prom++) & 0x0f) + 0x10;
+}
+
+WRITE8_HANDLER( megazone_flipscreen_w )
+{
+ if (flipscreen != (data & 1))
+ {
+ flipscreen = data & 1;
+ memset(dirtybuffer,1,videoram_size);
+ }
+}
+
+VIDEO_START( megazone )
+{
+ dirtybuffer = 0;
+ tmpbitmap = 0;
+
+ dirtybuffer = auto_malloc(videoram_size);
+ memset(dirtybuffer,1,videoram_size);
+
+ tmpbitmap = auto_bitmap_alloc(256,256,machine->screen[0].format);
+}
+
+
+VIDEO_UPDATE( megazone )
+{
+ int offs;
+ int x,y;
+
+ /* for every character in the Video RAM, check if it has been modified */
+ /* since last time and update it accordingly. */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ if (dirtybuffer[offs])
+ {
+ int sx,sy,flipx,flipy;
+
+ dirtybuffer[offs] = 0;
+
+ sx = offs % 32;
+ sy = offs / 32;
+ flipx = colorram[offs] & (1<<6);
+ flipy = colorram[offs] & (1<<5);
+ if (flipscreen)
+ {
+ sx = 31 - sx;
+ sy = 31 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(tmpbitmap,machine->gfx[0],
+ ((int)videoram[offs]) + ((colorram[offs] & (1<<7) ? 256 : 0) ),
+ (colorram[offs] & 0x0f) + 0x10,
+ flipx,flipy,
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ /* copy the temporary bitmap to the screen */
+ {
+ int scrollx;
+ int scrolly;
+
+ if (flipscreen)
+ {
+ scrollx = *megazone_scrolly;
+ scrolly = *megazone_scrollx;
+ }
+ else
+ {
+ scrollx = -*megazone_scrolly+4*8; // leave space for credit&score overlay
+ scrolly = -*megazone_scrollx;
+ }
+
+
+ copyscrollbitmap(bitmap,tmpbitmap,1,&scrollx,1,&scrolly,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ }
+
+
+ /* Draw the sprites. */
+ {
+ for (offs = spriteram_size-4; offs >= 0;offs -= 4)
+ {
+ int sx,sy,flipx,flipy;
+
+
+ sx = spriteram[offs + 3];
+ if (flipscreen) sx-=11; else sx+=4*8; // Sprite y-position correction depending on screen flip
+ sy = 255-((spriteram[offs + 1]+16)&0xff);
+ if (flipscreen) sy+=2; // Sprite x-position correction depending on screen flip
+
+ flipx = ~spriteram[offs+0] & 0x40;
+ flipy = spriteram[offs+0] & 0x80;
+
+ drawgfx(bitmap,machine->gfx[1],
+ spriteram[offs + 2],
+ spriteram[offs + 0] & 0x0f,
+ flipx,flipy,
+ sx,sy,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+ }
+ }
+
+ for (y = 0; y < 32;y++)
+ {
+ offs = y*32;
+ for (x = 0; x < 6; x++)
+ {
+ int sx,sy,flipx,flipy;
+
+ sx = x;
+ sy = y;
+
+ flipx = megazone_colorram2[offs] & (1<<6);
+ flipy = megazone_colorram2[offs] & (1<<5);
+
+ if (flipscreen)
+ {
+ sx = 35 - sx;
+ sy = 31 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+
+
+
+ drawgfx(bitmap,machine->gfx[0],
+ ((int)megazone_videoram2[offs]) + ((megazone_colorram2[offs] & (1<<7) ? 256 : 0) ),
+ (megazone_colorram2[offs] & 0x0f) + 0x10,
+ flipx,flipy,
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+ offs++;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/mermaid.c b/src/mame/video/mermaid.c
new file mode 100644
index 00000000000..6f736e06621
--- /dev/null
+++ b/src/mame/video/mermaid.c
@@ -0,0 +1,197 @@
+#include "driver.h"
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+UINT8* mermaid_videoram2;
+UINT8* mermaid_bg_scrollram;
+UINT8* mermaid_fg_scrollram;
+
+static int rougien_gfxbank1, rougien_gfxbank2;
+
+static rectangle spritevisiblearea =
+{
+ 0*8, 26*8-1,
+ 2*8, 30*8-1
+};
+
+static rectangle flip_spritevisiblearea =
+{
+ 6*8, 31*8-1,
+ 2*8, 30*8-1
+};
+
+PALETTE_INIT( mermaid )
+{
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ // first, the char actor/sprite palette
+ int i;
+
+ for (i = 0; i < TOTAL_COLORS(0); i++)
+ {
+ int r = 0x21 * BIT(*color_prom, 0) + 0x47 * BIT(*color_prom, 1) + 0x97 * BIT(*color_prom, 2);
+ int g = 0x21 * BIT(*color_prom, 3) + 0x47 * BIT(*color_prom, 4) + 0x97 * BIT(*color_prom, 5);
+ int b = 0x47 * BIT(*color_prom, 6) + 0x97 * BIT(*color_prom, 7);
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+
+ color_prom++;
+ }
+
+ // blue background
+ palette_set_color(machine, TOTAL_COLORS(0), MAKE_RGB(0, 0, 0xff));
+
+ // set up background palette
+ COLOR(2,0) = 32;
+ COLOR(2,1) = 33;
+
+ COLOR(2,2) = 64;
+ COLOR(2,3) = 33;
+}
+
+WRITE8_HANDLER( mermaid_videoram2_w )
+{
+ mermaid_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( mermaid_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( mermaid_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( mermaid_flip_screen_x_w )
+{
+ flip_screen_x_set(data & 0x01);
+}
+
+WRITE8_HANDLER( mermaid_flip_screen_y_w )
+{
+ flip_screen_y_set(data & 0x01);
+}
+
+WRITE8_HANDLER( mermaid_bg_scroll_w )
+{
+ mermaid_bg_scrollram[offset] = data;
+ tilemap_set_scrolly(bg_tilemap, offset, data);
+}
+
+WRITE8_HANDLER( mermaid_fg_scroll_w )
+{
+ mermaid_fg_scrollram[offset] = data;
+ tilemap_set_scrolly(fg_tilemap, offset, data);
+}
+
+WRITE8_HANDLER( rougien_gfxbankswitch1_w )
+{
+ rougien_gfxbank1 = data & 0x01;
+}
+
+WRITE8_HANDLER( rougien_gfxbankswitch2_w )
+{
+ rougien_gfxbank2 = data & 0x01;
+}
+
+READ8_HANDLER( mermaid_collision_r )
+{
+ /*
+ collision register active LO
+ Bit 0
+ Bit 1 - Sprite - Foreground
+ Bit 2 - Sprite - Stream
+ Bit 3
+ Bit 4
+ Bit 5
+ Bit 6
+ Bit 7
+ */
+
+ return 0; // not implemented
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = mermaid_videoram2[tile_index];
+ int sx = tile_index % 32;
+ int color = (sx >= 26) ? 0 : 1;
+
+ SET_TILE_INFO(2, code, color, 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + ((attr & 0x30) << 4);
+ int color = attr & 0x0f;
+ int flags = TILE_FLIPYX((attr & 0xc0) >> 6);
+
+ code |= rougien_gfxbank1 * 0x2800;
+ code |= rougien_gfxbank2 * 0x2400;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( mermaid )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+ tilemap_set_scroll_cols(fg_tilemap, 32);
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 4; offs >= 0; offs -= 4)
+ {
+ int attr = spriteram[offs + 2];
+ int bank = (attr & 0x30) >> 4;
+ int code = (spriteram[offs] & 0x3f) | (bank << 6);
+ int color = attr & 0x0f;
+ int flipx = spriteram[offs] & 0x40;
+ int flipy = spriteram[offs] & 0x80;
+ int sx = spriteram[offs + 3] + 1;
+ int sy = 240 - spriteram[offs + 1];
+
+ code |= rougien_gfxbank1 * 0x2800;
+ code |= rougien_gfxbank2 * 0x2400;
+
+ if (flip_screen_x)
+ {
+ flipx = !flipx;
+ sx = 240 - sx;
+ }
+
+ if (flip_screen_y)
+ {
+ flipy = !flipy;
+ sy = 240 - sy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy, sx, sy,
+ (flip_screen_x ? &flip_spritevisiblearea : &spritevisiblearea),
+ TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( mermaid )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/metlclsh.c b/src/mame/video/metlclsh.c
new file mode 100644
index 00000000000..ec2efa8fa7b
--- /dev/null
+++ b/src/mame/video/metlclsh.c
@@ -0,0 +1,256 @@
+/***************************************************************************
+
+ -= Metal Clash =-
+
+ Sprites:
+ 16x16 tiles with 8 pens and 2 color codes,
+ each sprite can be 1 or 2 tiles tall
+
+ Background:
+ size is 512x256 (scrolling, peculiar memory layout),
+ 16x16 tiles with 8 pens and no color code,
+ 1 byte per tile (tiles are banked)
+
+ Foreground:
+ size is 256x256 (no scrolling),
+ 8x8 tiles with 4 pens and 4 color codes,
+ 2 bytes per tile, low and high per tile priority
+
+***************************************************************************/
+
+#include "driver.h"
+
+/* Local variables: */
+
+static tilemap *bg_tilemap,*fg_tilemap;
+
+static UINT8 metlclsh_write_mask, *metlclsh_otherram;
+
+/* Variables that driver has access to: */
+
+UINT8 *metlclsh_bgram, *metlclsh_fgram, *metlclsh_scrollx;
+
+/* Functions that driver has access to: */
+
+WRITE8_HANDLER( metlclsh_rambank_w )
+{
+ if (data & 1)
+ {
+ metlclsh_write_mask = 0;
+ memory_set_bankptr(1, metlclsh_bgram);
+ }
+ else
+ {
+ metlclsh_write_mask = 1 << (data >> 1);
+ memory_set_bankptr(1, metlclsh_otherram);
+ }
+}
+
+static UINT8 metlclsh_gfxbank;
+WRITE8_HANDLER( metlclsh_gfxbank_w )
+{
+ if (!(data & 4) && (metlclsh_gfxbank != data))
+ {
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ metlclsh_gfxbank = data & 3;
+ }
+}
+
+/***************************************************************************
+
+ Background tilemap
+
+ memory offset of each tile of the tilemap:
+
+ 00 08 .. 78 100 108 .. 178
+ . . . . . .
+ . . . . . .
+ 07 0f .. 7f 107 10f .. 17f
+ 80 88 .. f8 180 188 .. 1f8
+ . . . . . .
+ . . . . . .
+ 87 8f .. ff 187 18f .. 1ff
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( metlclsh_bgtilemap_scan )
+{
+ return (row & 7) + ((row & ~7) << 4) + ((col & 0xf) << 3) + ((col & ~0xf) << 4);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ SET_TILE_INFO(1, metlclsh_bgram[tile_index] + (metlclsh_gfxbank << 7),0,0);
+}
+
+WRITE8_HANDLER( metlclsh_bgram_w )
+{
+ /* This ram is banked: it's either the tilemap (e401 = 1)
+ or bit n of another area (e401 = n << 1)? (that I don't understand) */
+ if (metlclsh_write_mask)
+ {
+ /* unknown area - the following is almost surely wrong */
+// 405b (e401 = e c a 8 6 4 2 0) writes d400++
+// 4085 (e401 = e c a 8 6 4 2 0) writes d400++
+// 4085 (e401 = e a 6 2) writes d000++
+// 405b (e401 = e a 6 2) writes d000++
+
+// metlclsh_otherram[offset] |= (data & metlclsh_write_mask);
+ metlclsh_otherram[offset] = (metlclsh_otherram[offset] & ~metlclsh_write_mask) | (data & metlclsh_write_mask);
+ }
+ else
+ {
+ /* tilemap */
+ metlclsh_bgram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x1ff);
+ }
+}
+
+/***************************************************************************
+
+ Foreground tilemap
+
+ Offset: Bits: Value:
+
+ 0x000 Code
+ 0x400 7--- ---- Priority (0/1 -> over/below sprites and background)
+ -65- ---- Color
+ ---- --10 Code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 code = metlclsh_fgram[tile_index + 0x000];
+ UINT8 attr = metlclsh_fgram[tile_index + 0x400];
+ SET_TILE_INFO(2, code + ((attr & 0x03) << 8), (attr >> 5) & 3, 0);
+ tileinfo->category = ((attr & 0x80) ? 1 : 2);
+}
+
+WRITE8_HANDLER( metlclsh_fgram_w )
+{
+ metlclsh_fgram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x3ff);
+}
+
+
+/***************************************************************************
+
+ Video Hardware Init
+
+***************************************************************************/
+
+VIDEO_START( metlclsh )
+{
+ metlclsh_otherram = auto_malloc(0x800); // banked ram
+
+ bg_tilemap = tilemap_create(get_bg_tile_info,metlclsh_bgtilemap_scan,TILEMAP_TYPE_PEN,16,16,32,16);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen( bg_tilemap, 0 );
+ tilemap_set_transparent_pen( fg_tilemap, 0 );
+}
+
+
+/***************************************************************************
+
+ Sprites Drawing
+
+ Offset: Bits: Value:
+
+ 0 7--- ---- 0
+ -65- ---- Code (high bits)
+ ---4 ---- Double height (2 tiles)
+ ---- 3--- Color
+ ---- -2-- Flip X
+ ---- --1- Flip Y
+ ---- ---0 Enable
+
+ 1 Code (low bits)
+ 2 Y (bottom -> top)
+ 3 X (right -> left)
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ gfx_element *gfx = machine->gfx[0];
+ int offs;
+
+ for (offs = 0;offs < spriteram_size; offs += 4)
+ {
+ int attr,code,color,sx,sy,flipx,flipy,wrapy,sizey;
+
+ attr = spriteram[offs];
+ if (!(attr & 0x01)) continue; // enable
+
+ flipy = (attr & 0x02);
+ flipx = (attr & 0x04);
+ color = (attr & 0x08) >> 3;
+ sizey = (attr & 0x10); // double height
+ code = ((attr & 0x60) << 3) + spriteram[offs+1];
+
+ sx = 240 - spriteram[offs+3];
+ if (sx < -7) sx += 256;
+ sy = 240 - spriteram[offs+2];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx; flipx = !flipx;
+ sy = 240 - sy; flipy = !flipy; if (sizey) sy+=16;
+ if (sy > 240) sy -= 256;
+ }
+
+ /* Draw twice, at sy and sy + 256 (wrap around) */
+ for ( wrapy = 0; wrapy <= 256; wrapy += 256 )
+ {
+ if (sizey)
+ {
+ drawgfx(bitmap,gfx, code & ~1, color, flipx,flipy,
+ sx, sy + (flipy ? 0 : -16) + wrapy, cliprect,TRANSPARENCY_PEN,0);
+
+ drawgfx(bitmap,gfx, code | 1, color, flipx,flipy,
+ sx,sy + (flipy ? -16 : 0) + wrapy, cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ drawgfx(bitmap,gfx, code, color, flipx,flipy,
+ sx,sy + wrapy, cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+}
+
+/***************************************************************************
+
+ Screen Drawing
+
+ Video register e402 (metlclsh seems to only use the values 0,8,9,b):
+
+ 7654 ---- 0
+ ---- 3--- Background enable
+ ---- -2-- 0
+ ---- --1- Background scroll x high bit
+ ---- ---0 ? (not bg flipx!)
+
+***************************************************************************/
+
+VIDEO_UPDATE( metlclsh )
+{
+ fillbitmap(bitmap,machine->pens[0x10],cliprect);
+
+ tilemap_draw(bitmap,cliprect,fg_tilemap,1,0); // low priority tiles of foreground
+ if (metlclsh_scrollx[0] & 0x08) // background (if enabled)
+ {
+ /* The background seems to be always flipped along x */
+ tilemap_set_flip(bg_tilemap, (flip_screen ? (TILEMAP_FLIPX|TILEMAP_FLIPY) : 0) ^ TILEMAP_FLIPX);
+ tilemap_set_scrollx(bg_tilemap, 0,metlclsh_scrollx[1] + ((metlclsh_scrollx[0]&0x02)<<7) );
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ }
+ draw_sprites(machine,bitmap,cliprect); // sprites
+ tilemap_draw(bitmap,cliprect,fg_tilemap,2,0); // high priority tiles of foreground
+
+// popmessage("%02X",metlclsh_scrollx[0]);
+ return 0;
+}
+
diff --git a/src/mame/video/metro.c b/src/mame/video/metro.c
new file mode 100644
index 00000000000..36ba7068323
--- /dev/null
+++ b/src/mame/video/metro.c
@@ -0,0 +1,934 @@
+/***************************************************************************
+
+ -= Metro Games =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z with:
+
+ Q Shows Layer 0
+ W Shows Layer 1
+ E Shows Layer 2
+ A Shows Sprites
+
+ Keys can be used together!
+
+
+ [ 3 Scrolling Layers ]
+
+ There is memory for a huge layer, but the actual tilemap
+ is a smaller window (of fixed size) carved from anywhere
+ inside that layer.
+
+ Tile Size: 8 x 8 x 4
+ (later games can switch to 8 x 8 x 8, 16 x 16 x 4/8 at run time)
+
+ Big Layer Size: 2048 x 2048 (8x8 tiles) or 4096 x 4096 (16x16 tiles)
+
+ Tilemap Window Size: 512 x 256 (8x8 tiles) or 1024 x 512 (16x16 tiles)
+
+ The tile codes in memory do not map directly to tiles. They
+ are indexes into a table (with 0x200 entries) that defines
+ a virtual set of tiles for the 3 layers. Each entry in that
+ table adds 16 tiles to the set of available tiles, and decides
+ their color code.
+
+ Tile code with their msbit set are different as they mean:
+ draw a tile filled with a single color (0-1ff)
+
+
+ [ 512 Zooming Sprites ]
+
+ The sprites are NOT tile based: the "tile" size can vary from
+ 8 to 64 (independently for width and height) with an 8 pixel
+ granularity. The "tile" address is a multiple of 8x8 pixels.
+
+ Each sprite can be shrinked to ~1/4 or enlarged to ~32x following
+ an exponential curve of sizes (with one zoom value for both width
+ and height)
+
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+/* Variables that driver has access to: */
+
+UINT16 *metro_videoregs;
+UINT16 *metro_screenctrl;
+UINT16 *metro_scroll;
+UINT16 *metro_tiletable;
+size_t metro_tiletable_size;
+UINT16 *metro_vram_0,*metro_vram_1,*metro_vram_2;
+UINT16 *metro_window;
+
+static int support_8bpp,support_16x16;
+static int has_zoom;
+
+
+UINT16 *metro_K053936_ram;
+static tilemap *metro_K053936_tilemap;
+
+static UINT16 *metro_tiletable_old;
+static UINT8 *dirtyindex;
+
+
+static TILE_GET_INFO( metro_K053936_get_tile_info )
+{
+ int code = metro_K053936_ram[tile_index];
+
+ SET_TILE_INFO(
+ 2,
+ code & 0x7fff,
+ 0x1e,
+ 0);
+}
+
+static TILE_GET_INFO( metro_K053936_gstrik2_get_tile_info )
+{
+ int code = metro_K053936_ram[tile_index];
+
+ SET_TILE_INFO(
+ 2,
+ (code & 0x7fff)>>2,
+ 0x1e,
+ 0);
+}
+
+WRITE16_HANDLER( metro_K053936_w )
+{
+ COMBINE_DATA(&metro_K053936_ram[offset]);
+ tilemap_mark_tile_dirty(metro_K053936_tilemap,offset);
+}
+
+static TILEMAP_MAPPER( tilemap_scan_gstrik2 )
+{
+ /* logical (col,row) -> memory offset */
+ int val;
+
+ val = (row&0x3f)*(256*2) + (col*2);
+
+ if (row&0x40) val+=1;
+ if (row&0x80) val+=256;
+
+ return val;
+}
+
+
+/***************************************************************************
+
+
+ Palette GGGGGRRRRRBBBBBx
+
+
+***************************************************************************/
+
+WRITE16_HANDLER( metro_paletteram_w )
+{
+ data = COMBINE_DATA(&paletteram16[offset]);
+ /* We need the ^0xff because we had to invert the pens in the gfx */
+ palette_set_color_rgb(Machine,offset^0xff,pal5bit(data >> 6),pal5bit(data >> 11),pal5bit(data >> 1));
+}
+
+
+/***************************************************************************
+
+
+ Tilemaps: Tiles Set & Window
+
+ Each entry in the Tiles Set RAM uses 2 words to specify a starting
+ tile code and a color code. This adds 16 consecutive tiles with
+ that color code to the set of available tiles.
+
+ Offset: Bits: Value:
+
+ 0.w fedc ---- ---- ----
+ ---- ba98 7654 ---- Color Code
+ ---- ---- ---- 3210 Code High Bits
+
+ 2.w Code Low Bits
+
+
+***************************************************************************/
+
+
+/***************************************************************************
+
+
+ Tilemaps: Rendering
+
+
+***************************************************************************/
+
+static tilemap *bg_tilemap[3];
+static tilemap *tilemap_16x16[3];
+static UINT8 *empty_tiles;
+
+/* A 2048 x 2048 virtual tilemap */
+
+#define BIG_NX (0x100)
+#define BIG_NY (0x100)
+
+/* A smaller 512 x 256 window defines the actual tilemap */
+
+#define WIN_NX (0x40)
+#define WIN_NY (0x20)
+//#define WIN_NX (0x40+1)
+//#define WIN_NY (0x20+1)
+
+
+/* 8x8x4 tiles only */
+INLINE void get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int layer,UINT16 *vram)
+{
+ UINT16 code;
+ int table_index;
+ UINT32 tile;
+
+ /* The actual tile index depends on the window */
+ tile_index = ((tile_index / WIN_NX + metro_window[layer * 2 + 0] / 8) % BIG_NY) * BIG_NX +
+ ((tile_index % WIN_NX + metro_window[layer * 2 + 1] / 8) % BIG_NX);
+
+ /* Fetch the code */
+ code = vram[ tile_index ];
+
+ /* Use it as an index into the tiles set table */
+ table_index = ( (code & 0x1ff0) >> 4 ) * 2;
+ tile = (metro_tiletable[table_index + 0] << 16 ) +
+ metro_tiletable[table_index + 1];
+
+ if (code & 0x8000) /* Special: draw a tile of a single color (i.e. not from the gfx ROMs) */
+ {
+ int _code = code & 0x000f;
+ tileinfo->pen_data = empty_tiles + _code*16*16;
+ tileinfo->palette_base = ((code & 0x0ff0) ^ 0x0f0) + 0x1000;
+ tileinfo->flags = 0;
+ }
+ else
+ SET_TILE_INFO(
+ 0,
+ (tile & 0xfffff) + (code & 0xf),
+ (((tile & 0x0ff00000) >> 20) ^ 0x0f) + 0x100,
+ TILE_FLIPXY((code & 0x6000) >> 13));
+}
+
+
+/* 8x8x4 or 8x8x8 tiles. It's the tile's color that decides: if its low 4
+ bits are high ($f,$1f,$2f etc) the tile is 8bpp, otherwise it's 4bpp */
+INLINE void get_tile_info_8bit(running_machine *machine,tile_data *tileinfo,int tile_index,int layer,UINT16 *vram)
+{
+ UINT16 code;
+ int table_index;
+ UINT32 tile;
+
+ /* The actual tile index depends on the window */
+ tile_index = ((tile_index / WIN_NX + metro_window[layer * 2 + 0] / 8) % BIG_NY) * BIG_NX +
+ ((tile_index % WIN_NX + metro_window[layer * 2 + 1] / 8) % BIG_NX);
+
+ /* Fetch the code */
+ code = vram[ tile_index ];
+
+ /* Use it as an index into the tiles set table */
+ table_index = ( (code & 0x1ff0) >> 4 ) * 2;
+ tile = (metro_tiletable[table_index + 0] << 16 ) +
+ metro_tiletable[table_index + 1];
+
+ if (code & 0x8000) /* Special: draw a tile of a single color (i.e. not from the gfx ROMs) */
+ {
+ int _code = code & 0x000f;
+ tileinfo->pen_data = empty_tiles + _code*16*16;
+ tileinfo->palette_base = ((code & 0x0ff0) ^ 0x0f0) + 0x1000;
+ tileinfo->flags = 0;
+ }
+ else if ((tile & 0x00f00000)==0x00f00000) /* draw tile as 8bpp */
+ SET_TILE_INFO(
+ 1,
+ (tile & 0xfffff) + 2*(code & 0xf),
+ ((tile & 0x0f000000) >> 24) + 0x10,
+ TILE_FLIPXY((code & 0x6000) >> 13));
+ else
+ SET_TILE_INFO(
+ 0,
+ (tile & 0xfffff) + (code & 0xf),
+ (((tile & 0x0ff00000) >> 20) ^ 0x0f) + 0x100,
+ TILE_FLIPXY((code & 0x6000) >> 13));
+}
+
+/* 16x16x4 or 16x16x8 tiles. It's the tile's color that decides: if its low 4
+ bits are high ($f,$1f,$2f etc) the tile is 8bpp, otherwise it's 4bpp */
+INLINE void get_tile_info_16x16_8bit(running_machine *machine,tile_data *tileinfo,int tile_index,int layer,UINT16 *vram)
+{
+ UINT16 code;
+ int table_index;
+ UINT32 tile;
+
+ /* The actual tile index depends on the window */
+ tile_index = ((tile_index / WIN_NX + metro_window[layer * 2 + 0] / 8) % BIG_NY) * BIG_NX +
+ ((tile_index % WIN_NX + metro_window[layer * 2 + 1] / 8) % BIG_NX);
+
+ /* Fetch the code */
+ code = vram[ tile_index ];
+
+ /* Use it as an index into the tiles set table */
+ table_index = ( (code & 0x1ff0) >> 4 ) * 2;
+ tile = (metro_tiletable[table_index + 0] << 16 ) +
+ metro_tiletable[table_index + 1];
+
+ if (code & 0x8000) /* Special: draw a tile of a single color (i.e. not from the gfx ROMs) */
+ {
+ int _code = code & 0x000f;
+ tileinfo->pen_data = empty_tiles + _code*16*16;
+ tileinfo->palette_base = ((code & 0x0ff0) ^ 0x0f0) + 0x1000;
+ tileinfo->flags = 0;
+ }
+ else if ((tile & 0x00f00000)==0x00f00000) /* draw tile as 8bpp */
+ SET_TILE_INFO(
+ 3,
+ (tile & 0xfffff) + 8*(code & 0xf),
+ ((tile & 0x0f000000) >> 24) + 0x10,
+ TILE_FLIPXY((code & 0x6000) >> 13));
+ else
+ SET_TILE_INFO(
+ 2,
+ (tile & 0xfffff) + 4*(code & 0xf),
+ (((tile & 0x0ff00000) >> 20) ^ 0x0f) + 0x100,
+ TILE_FLIPXY((code & 0x6000) >> 13));
+}
+
+
+INLINE void metro_vram_w(offs_t offset,UINT16 data,UINT16 mem_mask,int layer,UINT16 *vram)
+{
+ COMBINE_DATA(&vram[offset]);
+ {
+ /* Account for the window */
+ int col = (offset % BIG_NX) - ((metro_window[layer * 2 + 1] / 8) % BIG_NX);
+ int row = (offset / BIG_NX) - ((metro_window[layer * 2 + 0] / 8) % BIG_NY);
+ if (col < -(BIG_NX-WIN_NX)) col += (BIG_NX-WIN_NX) + WIN_NX;
+ if (row < -(BIG_NY-WIN_NY)) row += (BIG_NY-WIN_NY) + WIN_NY;
+ if ( (col >= 0) && (col < WIN_NX) &&
+ (row >= 0) && (row < WIN_NY) )
+ {
+ tilemap_mark_tile_dirty(bg_tilemap[layer], row * WIN_NX + col );
+ if (tilemap_16x16[layer])
+ tilemap_mark_tile_dirty(tilemap_16x16[layer], row * WIN_NX + col );
+ }
+ }
+}
+
+
+
+static TILE_GET_INFO( get_tile_info_0 ) { get_tile_info(machine,tileinfo,tile_index,0,metro_vram_0); }
+static TILE_GET_INFO( get_tile_info_1 ) { get_tile_info(machine,tileinfo,tile_index,1,metro_vram_1); }
+static TILE_GET_INFO( get_tile_info_2 ) { get_tile_info(machine,tileinfo,tile_index,2,metro_vram_2); }
+
+static TILE_GET_INFO( get_tile_info_0_8bit ) { get_tile_info_8bit(machine,tileinfo,tile_index,0,metro_vram_0); }
+static TILE_GET_INFO( get_tile_info_1_8bit ) { get_tile_info_8bit(machine,tileinfo,tile_index,1,metro_vram_1); }
+static TILE_GET_INFO( get_tile_info_2_8bit ) { get_tile_info_8bit(machine,tileinfo,tile_index,2,metro_vram_2); }
+
+static TILE_GET_INFO( get_tile_info_0_16x16_8bit ) { get_tile_info_16x16_8bit(machine,tileinfo,tile_index,0,metro_vram_0); }
+static TILE_GET_INFO( get_tile_info_1_16x16_8bit ) { get_tile_info_16x16_8bit(machine,tileinfo,tile_index,1,metro_vram_1); }
+static TILE_GET_INFO( get_tile_info_2_16x16_8bit ) { get_tile_info_16x16_8bit(machine,tileinfo,tile_index,2,metro_vram_2); }
+
+WRITE16_HANDLER( metro_vram_0_w ) { metro_vram_w(offset,data,mem_mask,0,metro_vram_0); }
+WRITE16_HANDLER( metro_vram_1_w ) { metro_vram_w(offset,data,mem_mask,1,metro_vram_1); }
+WRITE16_HANDLER( metro_vram_2_w ) { metro_vram_w(offset,data,mem_mask,2,metro_vram_2); }
+
+
+
+/* Dirty the relevant tilemap when its window changes */
+WRITE16_HANDLER( metro_window_w )
+{
+ UINT16 olddata = metro_window[offset];
+ UINT16 newdata = COMBINE_DATA( &metro_window[offset] );
+ if ( newdata != olddata )
+ {
+ offset /= 2;
+ tilemap_mark_all_tiles_dirty(bg_tilemap[offset]);
+ if (tilemap_16x16[offset]) tilemap_mark_all_tiles_dirty(tilemap_16x16[offset]);
+ }
+}
+
+
+
+/***************************************************************************
+
+
+ Video Init Routines
+
+
+***************************************************************************/
+
+/*
+ Sprites are not tile based, so we decode their graphics at runtime.
+
+ We can't do it at startup because drawgfx requires the tiles to be
+ pre-rotated to support vertical games, and that, in turn, requires
+ the tile's sizes to be known at startup - which we don't!
+*/
+
+static int metro_sprite_xoffs, metro_sprite_yoffs;
+
+
+static void alloc_empty_tiles(void)
+{
+ int code,i;
+
+ empty_tiles = auto_malloc(16*16*16);
+
+ for (code = 0;code < 0x10;code++)
+ for (i = 0;i < 16*16;i++)
+ empty_tiles[16*16*code + i] = code ^ 0x0f;
+}
+
+VIDEO_START( metro_14100 )
+{
+ support_8bpp = 0;
+ support_16x16 = 0;
+ has_zoom = 0;
+
+ alloc_empty_tiles();
+ metro_tiletable_old = auto_malloc(metro_tiletable_size);
+ dirtyindex = auto_malloc(metro_tiletable_size/4);
+
+ bg_tilemap[0] = tilemap_create(get_tile_info_0,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,WIN_NX,WIN_NY);
+ bg_tilemap[1] = tilemap_create(get_tile_info_1,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,WIN_NX,WIN_NY);
+ bg_tilemap[2] = tilemap_create(get_tile_info_2,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,WIN_NX,WIN_NY);
+
+ tilemap_16x16[0] = NULL;
+ tilemap_16x16[1] = NULL;
+ tilemap_16x16[2] = NULL;
+
+ tilemap_set_transparent_pen(bg_tilemap[0],0);
+ tilemap_set_transparent_pen(bg_tilemap[1],0);
+ tilemap_set_transparent_pen(bg_tilemap[2],0);
+}
+
+VIDEO_START( metro_14220 )
+{
+ support_8bpp = 1;
+ support_16x16 = 0;
+ has_zoom = 0;
+
+ alloc_empty_tiles();
+ metro_tiletable_old = auto_malloc(metro_tiletable_size);
+ dirtyindex = auto_malloc(metro_tiletable_size/4);
+
+ bg_tilemap[0] = tilemap_create(get_tile_info_0_8bit,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,WIN_NX,WIN_NY);
+ bg_tilemap[1] = tilemap_create(get_tile_info_1_8bit,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,WIN_NX,WIN_NY);
+ bg_tilemap[2] = tilemap_create(get_tile_info_2_8bit,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,WIN_NX,WIN_NY);
+
+ tilemap_16x16[0] = NULL;
+ tilemap_16x16[1] = NULL;
+ tilemap_16x16[2] = NULL;
+
+ tilemap_set_transparent_pen(bg_tilemap[0],0);
+ tilemap_set_transparent_pen(bg_tilemap[1],0);
+ tilemap_set_transparent_pen(bg_tilemap[2],0);
+
+ tilemap_set_scrolldx(bg_tilemap[0], -2, 2);
+ tilemap_set_scrolldx(bg_tilemap[1], -2, 2);
+ tilemap_set_scrolldx(bg_tilemap[2], -2, 2);
+}
+
+VIDEO_START( metro_14300 )
+{
+ support_8bpp = 1;
+ support_16x16 = 1;
+ has_zoom = 0;
+
+ alloc_empty_tiles();
+ metro_tiletable_old = auto_malloc(metro_tiletable_size);
+ dirtyindex = auto_malloc(metro_tiletable_size/4);
+
+ bg_tilemap[0] = tilemap_create(get_tile_info_0_8bit,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,WIN_NX,WIN_NY);
+ bg_tilemap[1] = tilemap_create(get_tile_info_1_8bit,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,WIN_NX,WIN_NY);
+ bg_tilemap[2] = tilemap_create(get_tile_info_2_8bit,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,WIN_NX,WIN_NY);
+
+ tilemap_16x16[0] = tilemap_create(get_tile_info_0_16x16_8bit,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,WIN_NX,WIN_NY);
+ tilemap_16x16[1] = tilemap_create(get_tile_info_1_16x16_8bit,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,WIN_NX,WIN_NY);
+ tilemap_16x16[2] = tilemap_create(get_tile_info_2_16x16_8bit,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,WIN_NX,WIN_NY);
+
+ tilemap_set_transparent_pen(bg_tilemap[0],0);
+ tilemap_set_transparent_pen(bg_tilemap[1],0);
+ tilemap_set_transparent_pen(bg_tilemap[2],0);
+ tilemap_set_transparent_pen(tilemap_16x16[0],0);
+ tilemap_set_transparent_pen(tilemap_16x16[1],0);
+ tilemap_set_transparent_pen(tilemap_16x16[2],0);
+}
+
+VIDEO_START( blzntrnd )
+{
+ video_start_metro_14220(machine);
+
+ has_zoom = 1;
+
+ metro_K053936_tilemap = tilemap_create(metro_K053936_get_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, 256, 512 );
+
+ K053936_wraparound_enable(0, 0);
+ K053936_set_offset(0, -69, -21);
+
+ tilemap_set_scrolldx(bg_tilemap[0], 8, -8);
+ tilemap_set_scrolldx(bg_tilemap[1], 8, -8);
+ tilemap_set_scrolldx(bg_tilemap[2], 8, -8);
+}
+
+VIDEO_START( gstrik2 )
+{
+ video_start_metro_14220(machine);
+
+ has_zoom = 1;
+
+ metro_K053936_tilemap = tilemap_create(metro_K053936_gstrik2_get_tile_info, tilemap_scan_gstrik2,
+ TILEMAP_TYPE_PEN, 16,16, 128, 256 );
+
+ K053936_wraparound_enable(0, 0);
+ K053936_set_offset(0, -69, -19);
+
+ tilemap_set_scrolldx(bg_tilemap[0], 8, -8);
+ tilemap_set_scrolldx(bg_tilemap[1], 0, 0);
+ tilemap_set_scrolldx(bg_tilemap[2], 8, -8);
+}
+
+/***************************************************************************
+
+ Video Registers
+
+
+ Offset: Bits: Value:
+
+ 0.w Number Of Sprites To Draw
+ 2.w f--- ---- ---- ---- Disable Sprites Layer Priority
+ -edc ---- ---- ----
+ ---- ba-- ---- ---- Sprites Masked Layer
+ ---- --98 ---- ---- Sprites Priority
+ ---- ---- 765- ----
+ ---- ---- ---4 3210 Sprites Masked Number
+ 4.w Sprites Y Offset
+ 6.w Sprites X Offset
+ 8.w Sprites Color Codes Start
+
+ -
+
+ 10.w fedc ba98 76-- ----
+ ---- ---- --54 ---- Layer 2 Priority (3 backmost, 0 frontmost)
+ ---- ---- ---- 32-- Layer 1 Priority
+ ---- ---- ---- --10 Layer 0 Priority
+
+ 12.w Backround Color
+
+
+***************************************************************************/
+
+
+
+/***************************************************************************
+
+
+ Sprites Drawing
+
+
+ Offset: Bits: Value:
+
+ 0.w fedc b--- ---- ---- Priority (0 = Max)
+ ---- -a98 7654 3210 X
+
+ 2.w fedc ba-- ---- ---- Zoom (Both X & Y)
+ ---- --98 7654 3210 Y
+
+ 4.w f--- ---- ---- ---- Flip X
+ -e-- ---- ---- ---- Flip Y
+ --dc b--- ---- ---- Size X *
+ ---- -a98 ---- ---- Size Y *
+ ---- ---- 7654 ---- Color
+ ---- ---- ---- 3210 Code High Bits **
+
+ 6.w Code Low Bits **
+
+* 8 pixel increments
+** 8x8 pixel increments
+
+***************************************************************************/
+
+/* Draw sprites */
+
+void metro_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const int region = REGION_GFX1;
+
+ UINT8 *base_gfx = memory_region(region);
+ UINT8 *gfx_max = base_gfx + memory_region_length(region);
+
+ int max_x = machine->screen[0].width;
+ int max_y = machine->screen[0].height;
+
+ int max_sprites = spriteram_size / 8;
+ int sprites = metro_videoregs[0x00/2] % max_sprites;
+
+ int color_start = ((metro_videoregs[0x08/2] & 0xf) << 4 ) + 0x100;
+
+ int i, j, pri;
+ static const int primask[4] = { 0x0000, 0xff00, 0xff00|0xf0f0, 0xff00|0xf0f0|0xcccc };
+
+ UINT16 *src;
+ int inc;
+
+ if (sprites == 0)
+ return;
+
+ for (i=0; i<0x20; i++)
+ {
+ if (!(metro_videoregs[0x02/2] & 0x8000))
+ {
+ src = spriteram16 + (sprites - 1) * (8/2);
+ inc = -(8/2);
+ } else {
+ src = spriteram16;
+ inc = (8/2);
+ }
+
+ for (j=0; j<sprites; j++)
+ {
+ int x,y, attr,code,color,flipx,flipy, zoom, curr_pri,width,height;
+ UINT8 *gfxdata;
+
+ /* Exponential zoom table extracted from daitoride */
+ static const int zoomtable[0x40] =
+ { 0xAAC,0x800,0x668,0x554,0x494,0x400,0x390,0x334,
+ 0x2E8,0x2AC,0x278,0x248,0x224,0x200,0x1E0,0x1C8,
+ 0x1B0,0x198,0x188,0x174,0x164,0x154,0x148,0x13C,
+ 0x130,0x124,0x11C,0x110,0x108,0x100,0x0F8,0x0F0,
+ 0x0EC,0x0E4,0x0DC,0x0D8,0x0D4,0x0CC,0x0C8,0x0C4,
+ 0x0C0,0x0BC,0x0B8,0x0B4,0x0B0,0x0AC,0x0A8,0x0A4,
+ 0x0A0,0x09C,0x098,0x094,0x090,0x08C,0x088,0x080,
+ 0x078,0x070,0x068,0x060,0x058,0x050,0x048,0x040 };
+
+ x = src[ 0 ];
+ curr_pri = (x & 0xf800) >> 11;
+
+ if ((curr_pri == 0x1f) || (curr_pri != i))
+ {
+ src += inc;
+ continue;
+ }
+
+ pri = (metro_videoregs[0x02/2] & 0x0300) >> 8;
+
+ if (!(metro_videoregs[0x02/2] & 0x8000))
+ {
+ if (curr_pri > (metro_videoregs[0x02/2] & 0x1f))
+ pri = (metro_videoregs[0x02/2] & 0x0c00) >> 10;
+ }
+
+ y = src[ 1 ];
+ attr = src[ 2 ];
+ code = src[ 3 ];
+
+ flipx = attr & 0x8000;
+ flipy = attr & 0x4000;
+ color = (attr & 0xf0) >> 4;
+
+ zoom = zoomtable[(y & 0xfc00) >> 10] << (16-8);
+
+ x = (x & 0x07ff) - metro_sprite_xoffs;
+ y = (y & 0x03ff) - metro_sprite_yoffs;
+
+ width = (( (attr >> 11) & 0x7 ) + 1 ) * 8;
+ height = (( (attr >> 8) & 0x7 ) + 1 ) * 8;
+
+ gfxdata = base_gfx + (8*8*4/8) * (((attr & 0x000f) << 16) + code);
+
+ if (flip_screen)
+ {
+ flipx = !flipx; x = max_x - x - width;
+ flipy = !flipy; y = max_y - y - height;
+ }
+
+ if (support_8bpp && color == 0xf) /* 8bpp */
+ {
+ /* prepare GfxElement on the fly */
+ gfx_element gfx;
+ gfx.width = width;
+ gfx.height = height;
+ gfx.total_elements = 1;
+ gfx.color_depth = 256;
+ gfx.color_granularity = 256;
+ gfx.color_base = 0;
+ gfx.total_colors = 0x20;
+ gfx.pen_usage = NULL;
+ gfx.gfxdata = gfxdata;
+ gfx.line_modulo = width;
+ gfx.char_modulo = 0; /* doesn't matter */
+ gfx.flags = 0;
+
+ /* Bounds checking */
+ if ( (gfxdata + width * height - 1) >= gfx_max )
+ continue;
+
+ pdrawgfxzoom( bitmap,&gfx,
+ 0,
+ color_start >> 4,
+ flipx, flipy,
+ x, y,
+ cliprect, TRANSPARENCY_PEN, 0,
+ zoom, zoom,
+ primask[pri]);
+ }
+ else
+ {
+ /* prepare GfxElement on the fly */
+ gfx_element gfx;
+ gfx.width = width;
+ gfx.height = height;
+ gfx.total_elements = 1;
+ gfx.color_depth = 16;
+ gfx.color_granularity = 16;
+ gfx.color_base = 0;
+ gfx.total_colors = 0x200;
+ gfx.pen_usage = NULL;
+ gfx.gfxdata = gfxdata;
+ gfx.line_modulo = width/2;
+ gfx.char_modulo = 0; /* doesn't matter */
+ gfx.flags = GFX_ELEMENT_PACKED;
+
+ /* Bounds checking */
+ if ( (gfxdata + width/2 * height - 1) >= gfx_max )
+ continue;
+
+ pdrawgfxzoom( bitmap,&gfx,
+ 0,
+ (color ^ 0x0f) + color_start,
+ flipx, flipy,
+ x, y,
+ cliprect, TRANSPARENCY_PEN, 0,
+ zoom, zoom,
+ primask[pri]);
+ }
+#if 0
+{ /* Display priority + zoom on each sprite */
+ char buf[80];
+ sprintf(buf, "%02X %02X",((src[ 0 ] & 0xf800) >> 11)^0x1f,((src[ 1 ] & 0xfc00) >> 10) );
+ ui_draw_text(buf, x, y);
+}
+#endif
+ src += inc;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+static void draw_tilemap(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, tilemap *tmap, UINT32 flags, UINT32 priority,
+ int sx, int sy, int wx, int wy) // scroll & window values
+{
+#if 1
+ tilemap_set_scrollx(tmap, 0, sx - wx + (wx & 7));
+ tilemap_set_scrolly(tmap, 0, sy - wy + (wy & 7));
+ tilemap_draw(bitmap,cliprect,tmap, flags, priority);
+#else
+ int x,y,i;
+
+ /* sub tile placement */
+// sx = sx - (wx & ~7) + (wx & 7);
+ sx = sx - wx;
+ sx = ( (sx & 0x7fff) - (sx & 0x8000) ) % ((WIN_NX-1)*8);
+
+// sy = sy - (wy & ~7) + (wy & 7);
+ sy = sy - wy;
+ sy = ( (sy & 0x7fff) - (sy & 0x8000) ) % ((WIN_NY-1)*8);
+
+ /* splitting point */
+ x = (WIN_NX-1)*8 - sx;
+
+ y = (WIN_NY-1)*8 - sy;
+
+ for ( i = 0; i < 4 ; i++ )
+ {
+ rectangle clip;
+
+ tilemap_set_scrollx(tmap, 0, sx + ((i & 1) ? -x : 0));
+ tilemap_set_scrolly(tmap, 0, sy + ((i & 2) ? -y : 0));
+
+ clip.min_x = x - ((i & 1) ? 0 : (WIN_NX-1)*8);
+ clip.min_y = y - ((i & 2) ? 0 : (WIN_NY-1)*8);
+
+ clip.max_x = clip.min_x + (WIN_NX-1)*8 - 1;
+ clip.max_y = clip.min_y + (WIN_NY-1)*8 - 1;
+
+ if (clip.min_x > machine->screen[0].visarea.max_x) continue;
+ if (clip.min_y > machine->screen[0].visarea.max_y) continue;
+
+ if (clip.max_x < machine->screen[0].visarea.min_x) continue;
+ if (clip.max_y < machine->screen[0].visarea.min_y) continue;
+
+ if (clip.min_x < machine->screen[0].visarea.min_x) clip.min_x = machine->screen[0].visarea.min_x;
+ if (clip.max_x > machine->screen[0].visarea.max_x) clip.max_x = machine->screen[0].visarea.max_x;
+
+ if (clip.min_y < machine->screen[0].visarea.min_y) clip.min_y = machine->screen[0].visarea.min_y;
+ if (clip.max_y > machine->screen[0].visarea.max_y) clip.max_y = machine->screen[0].visarea.max_y;
+
+ /* The clip region's width must be a multiple of 8!
+ This fact renderes the function useless, as far as
+ we are concerned! */
+ tilemap_set_clip(tmap, &clip);
+ tilemap_draw(bitmap,cliprect,tmap, flags, priority);
+ }
+#endif
+}
+
+
+/* Draw all the layers that match the given priority */
+static void draw_layers(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri, int layers_ctrl)
+{
+ UINT16 layers_pri = metro_videoregs[0x10/2];
+ int layer;
+
+ /* Draw all the layers with priority == pri */
+ for (layer = 2; layer >= 0; layer--) // tilemap[2] below?
+ {
+ if ( pri == ((layers_pri >> (layer*2)) & 3) )
+ {
+ /* Scroll and Window values */
+ UINT16 sy = metro_scroll[layer * 2 + 0]; UINT16 sx = metro_scroll[layer * 2 + 1];
+ UINT16 wy = metro_window[layer * 2 + 0]; UINT16 wx = metro_window[layer * 2 + 1];
+
+ if (layers_ctrl & (1<<layer)) // for debug
+ {
+ /* Only *one* of tilemap_16x16 & tilemap is enabled at any given time! */
+ draw_tilemap(machine, bitmap,cliprect,bg_tilemap[layer], 0, 1<<(3-pri), sx, sy, wx, wy);
+ if (tilemap_16x16[layer]) draw_tilemap(machine, bitmap,cliprect,tilemap_16x16[layer], 0, 1<<(3-pri), sx, sy, wx, wy);
+ }
+ }
+ }
+}
+
+
+
+/* Dirty tilemaps when the tiles set changes */
+static void dirty_tiles(int layer,UINT16 *vram)
+{
+ int col,row;
+
+ for (row = 0;row < WIN_NY;row++)
+ {
+ for (col = 0;col < WIN_NX;col++)
+ {
+ int offset = (col + metro_window[layer * 2 + 1] / 8) % BIG_NX +
+ ((row + metro_window[layer * 2 + 0] / 8) % BIG_NY) * BIG_NX;
+ UINT16 code = vram[offset];
+
+ if (!(code & 0x8000) && dirtyindex[(code & 0x1ff0) >> 4])
+ {
+ tilemap_mark_tile_dirty(bg_tilemap[layer], row * WIN_NX + col );
+ if (tilemap_16x16[layer])
+ tilemap_mark_tile_dirty(tilemap_16x16[layer], row * WIN_NX + col );
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( metro )
+{
+ int i,pri,layers_ctrl = -1;
+ UINT16 screenctrl = *metro_screenctrl;
+
+ {
+ int dirty = 0;
+
+ memset(dirtyindex,0,metro_tiletable_size/4);
+ for (i = 0;i < metro_tiletable_size/4;i++)
+ {
+ UINT32 tile_new = (metro_tiletable[2*i + 0] << 16 ) + metro_tiletable[2*i + 1];
+ UINT32 tile_old = (metro_tiletable_old[2*i + 0] << 16 ) + metro_tiletable_old[2*i + 1];
+
+ if ((tile_new ^ tile_old) & 0x0fffffff)
+ {
+ dirtyindex[i] = 1;
+ dirty = 1;
+ }
+ }
+ memcpy(metro_tiletable_old,metro_tiletable,metro_tiletable_size);
+
+ if (dirty)
+ {
+ dirty_tiles(0,metro_vram_0);
+ dirty_tiles(1,metro_vram_1);
+ dirty_tiles(2,metro_vram_2);
+ }
+ }
+
+ metro_sprite_xoffs = metro_videoregs[0x06/2] - machine->screen[0].width / 2;
+ metro_sprite_yoffs = metro_videoregs[0x04/2] - machine->screen[0].height / 2;
+
+ /* The background color is selected by a register */
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[((metro_videoregs[0x12/2] & 0x0fff) ^ 0x0ff) + 0x1000],cliprect);
+
+ /* Screen Control Register:
+
+ f--- ---- ---- ---- ?
+ -edc b--- ---- ----
+ ---- -a98 ---- ---- ? Leds
+ ---- ---- 7--- ---- 16x16 Tiles (Layer 2)
+ ---- ---- -6-- ---- 16x16 Tiles (Layer 1)
+ ---- ---- --5- ---- 16x16 Tiles (Layer 0)
+ ---- ---- ---4 32--
+ ---- ---- ---- --1- ? Blank Screen
+ ---- ---- ---- ---0 Flip Screen */
+ if (screenctrl & 2) return 0;
+ flip_screen_set(screenctrl & 1);
+
+ /* If the game supports 16x16 tiles, make sure that the
+ 16x16 and 8x8 tilemaps of a given layer are not simultaneously
+ enabled! */
+ if (support_16x16)
+ {
+ int layer;
+
+ for (layer = 0;layer < 3;layer++)
+ {
+ int big = screenctrl & (0x0020 << layer);
+
+ tilemap_set_enable(bg_tilemap[layer],!big);
+ tilemap_set_enable(tilemap_16x16[layer],big);
+ }
+ }
+
+
+#if 0
+if (input_code_pressed(KEYCODE_Z))
+{ int msk = 0;
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+ if (input_code_pressed(KEYCODE_E)) msk |= 4;
+ if (input_code_pressed(KEYCODE_A)) msk |= 8;
+ if (msk != 0)
+ { fillbitmap(bitmap,0,cliprect);
+ layers_ctrl &= msk; }
+
+ popmessage("l %x-%x-%x r %04x %04x %04x",
+ (metro_videoregs[0x10/2]&0x30)>>4,(metro_videoregs[0x10/2]&0xc)>>2,metro_videoregs[0x10/2]&3,
+ metro_videoregs[0x02/2], metro_videoregs[0x12/2],
+ *metro_screenctrl); }
+#endif
+
+ if (has_zoom) K053936_0_zoom_draw(bitmap,cliprect,metro_K053936_tilemap,0,0);
+
+
+ for (pri=3; pri>=0; pri--)
+ draw_layers(machine, bitmap,cliprect,pri,layers_ctrl);
+
+ if (layers_ctrl & 0x08)
+ metro_draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/mexico86.c b/src/mame/video/mexico86.c
new file mode 100644
index 00000000000..e5cc0d9368b
--- /dev/null
+++ b/src/mame/video/mexico86.c
@@ -0,0 +1,249 @@
+#include "driver.h"
+
+UINT8 *mexico86_videoram,*mexico86_objectram;
+size_t mexico86_objectram_size;
+static int charbank;
+
+
+
+WRITE8_HANDLER( mexico86_bankswitch_w )
+{
+ UINT8 *RAM = memory_region(REGION_CPU1);
+
+ if ((data & 7) > 5)
+ popmessage( "Switching to invalid bank!" );
+
+ memory_set_bankptr(1, &RAM[0x10000 + 0x4000 * (data & 0x07)]);
+
+ charbank = (data & 0x20) >> 5;
+}
+
+
+
+VIDEO_UPDATE( mexico86 )
+{
+ int offs;
+ int sx,sy,xc,yc;
+ int gfx_num,gfx_attr,gfx_offs;
+
+
+ /* Bubble Bobble doesn't have a real video RAM. All graphics (characters */
+ /* and sprites) are stored in the same memory region, and information on */
+ /* the background character columns is stored inthe area dd00-dd3f */
+
+ /* This clears & redraws the entire screen each pass */
+ fillbitmap(bitmap,machine->pens[255],&machine->screen[0].visarea);
+
+ sx = 0;
+/* the score display seems to be outside of the main objectram. */
+ for (offs = 0;offs < mexico86_objectram_size+0x200;offs += 4)
+ {
+ int height;
+
+if (offs >= mexico86_objectram_size && offs < mexico86_objectram_size+0x180) continue;
+if (offs >= mexico86_objectram_size+0x1c0) continue;
+
+ /* skip empty sprites */
+ /* this is dword aligned so the UINT32 * cast shouldn't give problems */
+ /* on any architecture */
+ if (*(UINT32 *)(&mexico86_objectram[offs]) == 0)
+ continue;
+
+ gfx_num = mexico86_objectram[offs + 1];
+ gfx_attr = mexico86_objectram[offs + 3];
+
+ if ((gfx_num & 0x80) == 0) /* 16x16 sprites */
+ {
+ gfx_offs = ((gfx_num & 0x1f) * 0x80) + ((gfx_num & 0x60) >> 1) + 12;
+ height = 2;
+ }
+ else /* tilemaps (each sprite is a 16x256 column) */
+ {
+ gfx_offs = ((gfx_num & 0x3f) * 0x80);
+ height = 32;
+ }
+
+ if ((gfx_num & 0xc0) == 0xc0) /* next column */
+ sx += 16;
+ else
+ {
+ sx = mexico86_objectram[offs + 2];
+// if (gfx_attr & 0x40) sx -= 256;
+ }
+ sy = 256 - height*8 - (mexico86_objectram[offs + 0]);
+
+ for (xc = 0;xc < 2;xc++)
+ {
+ for (yc = 0;yc < height;yc++)
+ {
+ int goffs,code,color,flipx,flipy,x,y;
+
+ goffs = gfx_offs + xc * 0x40 + yc * 0x02;
+ code = mexico86_videoram[goffs] + ((mexico86_videoram[goffs + 1] & 0x07) << 8)
+ + ((mexico86_videoram[goffs + 1] & 0x80) << 4) + (charbank << 12);
+ color = ((mexico86_videoram[goffs + 1] & 0x38) >> 3) + ((gfx_attr & 0x02) << 2);
+ flipx = mexico86_videoram[goffs + 1] & 0x40;
+ flipy = 0;
+// x = sx + xc * 8;
+ x = (sx + xc * 8) & 0xff;
+ y = (sy + yc * 8) & 0xff;
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ x,y,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,15);
+ }
+ }
+ }
+ return 0;
+}
+//AT
+#if 0 // old code
+VIDEO_UPDATE( kikikai )
+{
+ int offs;
+ int sx,sy,xc,yc;
+ int gfx_num,gfx_attr,gfx_offs;
+
+
+ /* Bubble Bobble doesn't have a real video RAM. All graphics (characters */
+ /* and sprites) are stored in the same memory region, and information on */
+ /* the background character columns is stored inthe area dd00-dd3f */
+
+ /* This clears & redraws the entire screen each pass */
+ fillbitmap(bitmap,machine->pens[255],&machine->screen[0].visarea);
+
+ sx = 0;
+/* the score display seems to be outside of the main objectram. */
+ for (offs = 0;offs < mexico86_objectram_size+0x200;offs += 4)
+ {
+ int height;
+
+if (offs >= mexico86_objectram_size && offs < mexico86_objectram_size+0x180) continue;
+if (offs >= mexico86_objectram_size+0x1c0) continue;
+
+ /* skip empty sprites */
+ /* this is dword aligned so the UINT32 * cast shouldn't give problems */
+ /* on any architecture */
+ if (*(UINT32 *)(&mexico86_objectram[offs]) == 0)
+ continue;
+
+ gfx_num = mexico86_objectram[offs + 1];
+ gfx_attr = mexico86_objectram[offs + 3];
+
+ if ((gfx_num & 0x80) == 0) /* 16x16 sprites */
+ {
+ gfx_offs = ((gfx_num & 0x1f) * 0x80) + ((gfx_num & 0x60) >> 1) + 12;
+ height = 2;
+ }
+ else /* tilemaps (each sprite is a 16x256 column) */
+ {
+ gfx_offs = ((gfx_num & 0x3f) * 0x80);
+ height = 32;
+ }
+
+ if ((gfx_num & 0xc0) == 0xc0) /* next column */
+ sx += 16;
+ else
+ {
+ sx = mexico86_objectram[offs + 2];
+// if (gfx_attr & 0x40) sx -= 256;
+ }
+ sy = 256 - height*8 - (mexico86_objectram[offs + 0]);
+
+ for (xc = 0;xc < 2;xc++)
+ {
+ for (yc = 0;yc < height;yc++)
+ {
+ int goffs,code,color,flipx,flipy,x,y;
+
+ goffs = gfx_offs + xc * 0x40 + yc * 0x02;
+ code = mexico86_videoram[goffs] + ((mexico86_videoram[goffs + 1] & 0x1f) << 8);
+ color = (mexico86_videoram[goffs + 1] & 0xe0) >> 5;
+ flipx = 0;
+ flipy = 0;
+// x = sx + xc * 8;
+ x = (sx + xc * 8) & 0xff;
+ y = (sy + yc * 8) & 0xff;
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ x,y,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,15);
+ }
+ }
+ }
+ return 0;
+}
+#endif
+
+VIDEO_UPDATE( kikikai )
+{
+ int offs;
+ int sx,sy,yc;
+ int gfx_num,gfx_attr,gfx_offs;
+ int height;
+ int goffs,code,color,y;
+ int tx, ty;
+
+ fillbitmap(bitmap, get_black_pen(machine), &machine->screen[0].visarea);
+ sx = 0;
+ for (offs=0; offs<mexico86_objectram_size; offs+=4)
+ {
+ if (*(UINT32*)(mexico86_objectram + offs) == 0) continue;
+
+ ty = mexico86_objectram[offs];
+ gfx_num = mexico86_objectram[offs + 1];
+ tx = mexico86_objectram[offs + 2];
+ gfx_attr = mexico86_objectram[offs + 3];
+
+ if (gfx_num & 0x80)
+ {
+ gfx_offs = ((gfx_num & 0x3f) << 7);
+ height = 32;
+ if (gfx_num & 0x40) sx += 16;
+ else sx = tx;
+ }
+ else
+ {
+ if (!(ty && tx)) continue;
+ gfx_offs = ((gfx_num & 0x1f) << 7) + ((gfx_num & 0x60) >> 1) + 12;
+ height = 2;
+ sx = tx;
+ }
+ sy = 256 - (height << 3) - ty;
+
+ height <<= 1;
+ for (yc=0; yc<height; yc+=2)
+ {
+ y = (sy + (yc << 2)) & 0xff;
+ goffs = gfx_offs + yc;
+ code = mexico86_videoram[goffs] + ((mexico86_videoram[goffs + 1] & 0x1f) << 8);
+ color = (mexico86_videoram[goffs + 1] & 0xe0) >> 5;
+ goffs += 0x40;
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ 0,0,
+ sx&0xff,y,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,15);
+
+ code = mexico86_videoram[goffs] + ((mexico86_videoram[goffs + 1] & 0x1f) << 8);
+ color = (mexico86_videoram[goffs + 1] & 0xe0) >> 5;
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ 0,0,
+ (sx+8)&0xff,y,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,15);
+ }
+ }
+ return 0;
+}
+//ZT
diff --git a/src/mame/video/midtunit.c b/src/mame/video/midtunit.c
new file mode 100644
index 00000000000..75a2dc9f017
--- /dev/null
+++ b/src/mame/video/midtunit.c
@@ -0,0 +1,842 @@
+/*************************************************************************
+
+ Driver for Midway T-unit games.
+
+**************************************************************************/
+
+#include "driver.h"
+#include "profiler.h"
+#include "cpu/tms34010/tms34010.h"
+#include "cpu/tms34010/34010ops.h"
+#include "midtunit.h"
+
+
+/* compile-time options */
+#define LOG_DMA 0 /* DMAs are logged if the 'L' key is pressed */
+
+
+/* constants for the DMA chip */
+enum
+{
+ DMA_LRSKIP = 0,
+ DMA_COMMAND,
+ DMA_OFFSETLO,
+ DMA_OFFSETHI,
+ DMA_XSTART,
+ DMA_YSTART,
+ DMA_WIDTH,
+ DMA_HEIGHT,
+ DMA_PALETTE,
+ DMA_COLOR,
+ DMA_SCALE_X,
+ DMA_SCALE_Y,
+ DMA_TOPCLIP,
+ DMA_BOTCLIP,
+ DMA_UNKNOWN_E, /* MK1/2 never write here; NBA only writes 0 */
+ DMA_CONFIG,
+ DMA_LEFTCLIP, /* pseudo-register */
+ DMA_RIGHTCLIP /* pseudo-register */
+};
+
+
+
+/* graphics-related variables */
+ UINT8 midtunit_gfx_rom_large;
+static UINT16 midtunit_control;
+
+/* palette-related variables */
+static pen_t * pen_map;
+
+/* videoram-related variables */
+static UINT32 gfxbank_offset[2];
+static UINT16 * local_videoram;
+static UINT8 videobank_select;
+
+/* DMA-related variables */
+static UINT16 dma_register[18];
+static struct
+{
+ UINT32 offset; /* source offset, in bits */
+ INT32 rowbits; /* source bits to skip each row */
+ INT32 xpos; /* x position, clipped */
+ INT32 ypos; /* y position, clipped */
+ INT32 width; /* horizontal pixel count */
+ INT32 height; /* vertical pixel count */
+ UINT16 palette; /* palette base */
+ UINT16 color; /* current foreground color with palette */
+
+ UINT8 yflip; /* yflip? */
+ UINT8 bpp; /* bits per pixel */
+ UINT8 preskip; /* preskip scale */
+ UINT8 postskip; /* postskip scale */
+ INT32 topclip; /* top clipping scanline */
+ INT32 botclip; /* bottom clipping scanline */
+ INT32 leftclip; /* left clipping column */
+ INT32 rightclip; /* right clipping column */
+ INT32 startskip; /* pixels to skip at start */
+ INT32 endskip; /* pixels to skip at end */
+ UINT16 xstep; /* 8.8 fixed number scale x factor */
+ UINT16 ystep; /* 8.8 fixed number scale y factor */
+} dma_state;
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( midtunit )
+{
+ int i;
+
+ /* allocate memory */
+ local_videoram = auto_malloc(0x100000);
+ pen_map = auto_malloc(65536 * sizeof(pen_map[0]));
+
+ /* initialize pen map */
+ for (i = 0; i < 0x10000; i++)
+ pen_map[i] = i & 0x7fff;
+
+ /* reset all the globals */
+ gfxbank_offset[0] = 0x000000;
+ gfxbank_offset[1] = 0x400000;
+
+ memset(dma_register, 0, sizeof(dma_register));
+ memset(&dma_state, 0, sizeof(dma_state));
+
+ /* register for state saving */
+ state_save_register_global(midtunit_control);
+ state_save_register_global_array(gfxbank_offset);
+ state_save_register_global_pointer(local_videoram, 0x100000/sizeof(local_videoram[0]));
+ state_save_register_global(videobank_select);
+ state_save_register_global_array(dma_register);
+}
+
+
+VIDEO_START( midwunit )
+{
+ video_start_midtunit(machine);
+ midtunit_gfx_rom_large = 1;
+}
+
+
+VIDEO_START( midxunit )
+{
+ video_start_midtunit(machine);
+ midtunit_gfx_rom_large = 1;
+ videobank_select = 1;
+}
+
+
+
+/*************************************
+ *
+ * Banked graphics ROM access
+ *
+ *************************************/
+
+READ16_HANDLER( midtunit_gfxrom_r )
+{
+ UINT8 *base = &midyunit_gfx_rom[gfxbank_offset[(offset >> 21) & 1]];
+ offset = (offset & 0x01fffff) * 2;
+ return base[offset] | (base[offset + 1] << 8);
+}
+
+
+READ16_HANDLER( midwunit_gfxrom_r )
+{
+ UINT8 *base = &midyunit_gfx_rom[gfxbank_offset[0]];
+ offset *= 2;
+ return base[offset] | (base[offset + 1] << 8);
+}
+
+
+
+/*************************************
+ *
+ * Video RAM read/write
+ *
+ *************************************/
+
+WRITE16_HANDLER( midtunit_vram_w )
+{
+ offset *= 2;
+ if (videobank_select)
+ {
+ if (ACCESSING_LSB)
+ local_videoram[offset] = (data & 0xff) | ((dma_register[DMA_PALETTE] & 0xff) << 8);
+ if (ACCESSING_MSB)
+ local_videoram[offset + 1] = ((data >> 8) & 0xff) | (dma_register[DMA_PALETTE] & 0xff00);
+ }
+ else
+ {
+ if (ACCESSING_LSB)
+ local_videoram[offset] = (local_videoram[offset] & 0xff) | ((data & 0xff) << 8);
+ if (ACCESSING_MSB)
+ local_videoram[offset + 1] = (local_videoram[offset + 1] & 0xff) | (data & 0xff00);
+ }
+}
+
+
+WRITE16_HANDLER( midtunit_vram_data_w )
+{
+ offset *= 2;
+ if (ACCESSING_LSB)
+ local_videoram[offset] = (data & 0xff) | ((dma_register[DMA_PALETTE] & 0xff) << 8);
+ if (ACCESSING_MSB)
+ local_videoram[offset + 1] = ((data >> 8) & 0xff) | (dma_register[DMA_PALETTE] & 0xff00);
+}
+
+
+WRITE16_HANDLER( midtunit_vram_color_w )
+{
+ offset *= 2;
+ if (ACCESSING_LSB)
+ local_videoram[offset] = (local_videoram[offset] & 0xff) | ((data & 0xff) << 8);
+ if (ACCESSING_MSB)
+ local_videoram[offset + 1] = (local_videoram[offset + 1] & 0xff) | (data & 0xff00);
+}
+
+
+READ16_HANDLER( midtunit_vram_r )
+{
+ offset *= 2;
+ if (videobank_select)
+ return (local_videoram[offset] & 0x00ff) | (local_videoram[offset + 1] << 8);
+ else
+ return (local_videoram[offset] >> 8) | (local_videoram[offset + 1] & 0xff00);
+}
+
+
+READ16_HANDLER( midtunit_vram_data_r )
+{
+ offset *= 2;
+ return (local_videoram[offset] & 0x00ff) | (local_videoram[offset + 1] << 8);
+}
+
+
+READ16_HANDLER( midtunit_vram_color_r )
+{
+ offset *= 2;
+ return (local_videoram[offset] >> 8) | (local_videoram[offset + 1] & 0xff00);
+}
+
+
+
+/*************************************
+ *
+ * Shift register read/write
+ *
+ *************************************/
+
+void midtunit_to_shiftreg(UINT32 address, UINT16 *shiftreg)
+{
+ memcpy(shiftreg, &local_videoram[address >> 3], 2 * 512 * sizeof(UINT16));
+}
+
+
+void midtunit_from_shiftreg(UINT32 address, UINT16 *shiftreg)
+{
+ memcpy(&local_videoram[address >> 3], shiftreg, 2 * 512 * sizeof(UINT16));
+}
+
+
+
+/*************************************
+ *
+ * Control register
+ *
+ *************************************/
+
+WRITE16_HANDLER( midtunit_control_w )
+{
+ /*
+ other important bits:
+ bit 2 (0x0004) is toggled periodically
+ */
+ logerror("T-unit control = %04X\n", data);
+
+ COMBINE_DATA(&midtunit_control);
+
+ /* gfx bank select is bit 7 */
+ if (!(midtunit_control & 0x0080) || !midtunit_gfx_rom_large)
+ gfxbank_offset[0] = 0x000000;
+ else
+ gfxbank_offset[0] = 0x800000;
+
+ /* video bank select is bit 5 */
+ videobank_select = (midtunit_control >> 5) & 1;
+}
+
+
+WRITE16_HANDLER( midwunit_control_w )
+{
+ /*
+ other important bits:
+ bit 2 (0x0004) is toggled periodically
+ */
+ logerror("Wolf-unit control = %04X\n", data);
+
+ COMBINE_DATA(&midtunit_control);
+
+ /* gfx bank select is bits 8-9 */
+ gfxbank_offset[0] = 0x800000 * ((midtunit_control >> 8) & 3);
+
+ /* video bank select is unknown */
+ videobank_select = (midtunit_control >> 11) & 1;
+}
+
+
+READ16_HANDLER( midwunit_control_r )
+{
+ return midtunit_control;
+}
+
+
+
+/*************************************
+ *
+ * Palette handlers
+ *
+ *************************************/
+
+WRITE16_HANDLER( midtunit_paletteram_w )
+{
+ int newword;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ newword = paletteram16[offset];
+ palette_set_color_rgb(Machine, offset, pal5bit(data >> 10), pal5bit(data >> 5), pal5bit(data >> 0));
+}
+
+
+WRITE16_HANDLER( midxunit_paletteram_w )
+{
+ if (!(offset & 1))
+ midtunit_paletteram_w(offset / 2, data, mem_mask);
+}
+
+
+READ16_HANDLER( midxunit_paletteram_r )
+{
+ return paletteram16_word_r(offset / 2, 0);
+}
+
+
+
+/*************************************
+ *
+ * DMA drawing routines
+ *
+ *************************************/
+
+/*** constant definitions ***/
+#define PIXEL_SKIP 0
+#define PIXEL_COLOR 1
+#define PIXEL_COPY 2
+
+#define XFLIP_NO 0
+#define XFLIP_YES 1
+
+#define SKIP_NO 0
+#define SKIP_YES 1
+
+#define SCALE_NO 0
+#define SCALE_YES 1
+
+#define XPOSMASK 0x3ff
+#define YPOSMASK 0x1ff
+
+
+typedef void (*dma_draw_func)(void);
+
+
+/*** fast pixel extractors ***/
+#if !defined(ALIGN_SHORTS) && defined(LSB_FIRST)
+#define EXTRACTGEN(m) ((*(UINT16 *)&base[o >> 3] >> (o & 7)) & (m))
+#elif defined(powerc)
+#define EXTRACTGEN(m) ((__lhbrx(base, o >> 3) >> (o & 7)) & (m))
+#else
+#define EXTRACTGEN(m) (((base[o >> 3] | (base[(o >> 3) + 1] << 8)) >> (o & 7)) & (m))
+#endif
+
+/*** core blitter routine macro ***/
+#define DMA_DRAW_FUNC_BODY(name, bitsperpixel, extractor, xflip, skip, scale, zero, nonzero) \
+{ \
+ int height = dma_state.height << 8; \
+ UINT8 *base = midyunit_gfx_rom; \
+ UINT32 offset = dma_state.offset; \
+ UINT16 pal = dma_state.palette; \
+ UINT16 color = pal | dma_state.color; \
+ int sy = dma_state.ypos, iy = 0, ty; \
+ int bpp = bitsperpixel; \
+ int mask = (1 << bpp) - 1; \
+ int xstep = scale ? dma_state.xstep : 0x100; \
+ \
+ /* loop over the height */ \
+ while (iy < height) \
+ { \
+ int startskip = dma_state.startskip << 8; \
+ int endskip = dma_state.endskip << 8; \
+ int width = dma_state.width << 8; \
+ int sx = dma_state.xpos, ix = 0, tx; \
+ UINT32 o = offset; \
+ int pre, post; \
+ UINT16 *d; \
+ \
+ /* handle skipping */ \
+ if (skip) \
+ { \
+ UINT8 value = EXTRACTGEN(0xff); \
+ o += 8; \
+ \
+ /* adjust for preskip */ \
+ pre = (value & 0x0f) << (dma_state.preskip + 8); \
+ tx = pre / xstep; \
+ if (xflip) \
+ sx = (sx - tx) & XPOSMASK; \
+ else \
+ sx = (sx + tx) & XPOSMASK; \
+ ix += tx * xstep; \
+ \
+ /* adjust for postskip */ \
+ post = ((value >> 4) & 0x0f) << (dma_state.postskip + 8); \
+ width -= post; \
+ endskip -= post; \
+ } \
+ \
+ /* handle Y clipping */ \
+ if (sy < dma_state.topclip || sy > dma_state.botclip) \
+ goto clipy; \
+ \
+ /* handle start skip */ \
+ if (ix < startskip) \
+ { \
+ tx = ((startskip - ix) / xstep) * xstep; \
+ ix += tx; \
+ o += (tx >> 8) * bpp; \
+ } \
+ \
+ /* handle end skip */ \
+ if ((width >> 8) > dma_state.width - dma_state.endskip) \
+ width = (dma_state.width - dma_state.endskip) << 8; \
+ \
+ /* determine destination pointer */ \
+ d = &local_videoram[sy * 512]; \
+ \
+ /* loop until we draw the entire width */ \
+ while (ix < width) \
+ { \
+ /* only process if not clipped */ \
+ if (sx >= dma_state.leftclip && sx <= dma_state.rightclip) \
+ { \
+ /* special case similar handling of zero/non-zero */ \
+ if (zero == nonzero) \
+ { \
+ if (zero == PIXEL_COLOR) \
+ d[sx] = color; \
+ else if (zero == PIXEL_COPY) \
+ d[sx] = (extractor(mask)) | pal; \
+ } \
+ \
+ /* otherwise, read the pixel and look */ \
+ else \
+ { \
+ int pixel = (extractor(mask)); \
+ \
+ /* non-zero pixel case */ \
+ if (pixel) \
+ { \
+ if (nonzero == PIXEL_COLOR) \
+ d[sx] = color; \
+ else if (nonzero == PIXEL_COPY) \
+ d[sx] = pixel | pal; \
+ } \
+ \
+ /* zero pixel case */ \
+ else \
+ { \
+ if (zero == PIXEL_COLOR) \
+ d[sx] = color; \
+ else if (zero == PIXEL_COPY) \
+ d[sx] = pal; \
+ } \
+ } \
+ } \
+ \
+ /* update pointers */ \
+ if (xflip) \
+ sx = (sx - 1) & XPOSMASK; \
+ else \
+ sx = (sx + 1) & XPOSMASK; \
+ \
+ /* advance to the next pixel */ \
+ if (!scale) \
+ { \
+ ix += 0x100; \
+ o += bpp; \
+ } \
+ else \
+ { \
+ tx = ix >> 8; \
+ ix += xstep; \
+ tx = (ix >> 8) - tx; \
+ o += bpp * tx; \
+ } \
+ } \
+ \
+ clipy: \
+ /* advance to the next row */ \
+ if (dma_state.yflip) \
+ sy = (sy - 1) & YPOSMASK; \
+ else \
+ sy = (sy + 1) & YPOSMASK; \
+ if (!scale) \
+ { \
+ iy += 0x100; \
+ width = dma_state.width; \
+ if (skip) \
+ { \
+ offset += 8; \
+ width -= (pre + post) >> 8; \
+ if (width > 0) offset += width * bpp; \
+ } \
+ else \
+ offset += width * bpp; \
+ } \
+ else \
+ { \
+ ty = iy >> 8; \
+ iy += dma_state.ystep; \
+ ty = (iy >> 8) - ty; \
+ if (!skip) \
+ offset += ty * dma_state.width * bpp; \
+ else if (ty--) \
+ { \
+ o = offset + 8; \
+ width = dma_state.width - ((pre + post) >> 8); \
+ if (width > 0) o += width * bpp; \
+ while (ty--) \
+ { \
+ UINT8 value = EXTRACTGEN(0xff); \
+ o += 8; \
+ pre = (value & 0x0f) << dma_state.preskip; \
+ post = ((value >> 4) & 0x0f) << dma_state.postskip; \
+ width = dma_state.width - pre - post; \
+ if (width > 0) o += width * bpp; \
+ } \
+ offset = o; \
+ } \
+ } \
+ } \
+}
+
+
+/*** slightly simplified one for most blitters ***/
+#define DMA_DRAW_FUNC(name, bpp, extract, xflip, skip, scale, zero, nonzero) \
+static void name(void) \
+{ \
+ DMA_DRAW_FUNC_BODY(name, bpp, extract, xflip, skip, scale, zero, nonzero) \
+}
+
+/*** empty blitter ***/
+static void dma_draw_none(void)
+{
+}
+
+/*** super macro for declaring an entire blitter family ***/
+#define DECLARE_BLITTER_SET(prefix, bpp, extract, skip, scale) \
+DMA_DRAW_FUNC(prefix##_p0, bpp, extract, XFLIP_NO, skip, scale, PIXEL_COPY, PIXEL_SKIP) \
+DMA_DRAW_FUNC(prefix##_p1, bpp, extract, XFLIP_NO, skip, scale, PIXEL_SKIP, PIXEL_COPY) \
+DMA_DRAW_FUNC(prefix##_c0, bpp, extract, XFLIP_NO, skip, scale, PIXEL_COLOR, PIXEL_SKIP) \
+DMA_DRAW_FUNC(prefix##_c1, bpp, extract, XFLIP_NO, skip, scale, PIXEL_SKIP, PIXEL_COLOR) \
+DMA_DRAW_FUNC(prefix##_p0p1, bpp, extract, XFLIP_NO, skip, scale, PIXEL_COPY, PIXEL_COPY) \
+DMA_DRAW_FUNC(prefix##_c0c1, bpp, extract, XFLIP_NO, skip, scale, PIXEL_COLOR, PIXEL_COLOR) \
+DMA_DRAW_FUNC(prefix##_c0p1, bpp, extract, XFLIP_NO, skip, scale, PIXEL_COLOR, PIXEL_COPY) \
+DMA_DRAW_FUNC(prefix##_p0c1, bpp, extract, XFLIP_NO, skip, scale, PIXEL_COPY, PIXEL_COLOR) \
+ \
+DMA_DRAW_FUNC(prefix##_p0_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_COPY, PIXEL_SKIP) \
+DMA_DRAW_FUNC(prefix##_p1_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_SKIP, PIXEL_COPY) \
+DMA_DRAW_FUNC(prefix##_c0_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_COLOR, PIXEL_SKIP) \
+DMA_DRAW_FUNC(prefix##_c1_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_SKIP, PIXEL_COLOR) \
+DMA_DRAW_FUNC(prefix##_p0p1_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_COPY, PIXEL_COPY) \
+DMA_DRAW_FUNC(prefix##_c0c1_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_COLOR, PIXEL_COLOR) \
+DMA_DRAW_FUNC(prefix##_c0p1_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_COLOR, PIXEL_COPY) \
+DMA_DRAW_FUNC(prefix##_p0c1_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_COPY, PIXEL_COLOR) \
+ \
+static dma_draw_func prefix[32] = \
+{ \
+/* B0:N / B1:N B0:Y / B1:N B0:N / B1:Y B0:Y / B1:Y */ \
+ dma_draw_none, prefix##_p0, prefix##_p1, prefix##_p0p1, /* no color */ \
+ prefix##_c0, prefix##_c0, prefix##_c0p1, prefix##_c0p1, /* color 0 pixels */ \
+ prefix##_c1, prefix##_p0c1, prefix##_c1, prefix##_p0c1, /* color non-0 pixels */\
+ prefix##_c0c1, prefix##_c0c1, prefix##_c0c1, prefix##_c0c1, /* fill */ \
+ \
+ dma_draw_none, prefix##_p0_xf, prefix##_p1_xf, prefix##_p0p1_xf, /* no color */ \
+ prefix##_c0_xf, prefix##_c0_xf, prefix##_c0p1_xf, prefix##_c0p1_xf, /* color 0 pixels */ \
+ prefix##_c1_xf, prefix##_p0c1_xf, prefix##_c1_xf, prefix##_p0c1_xf, /* color non-0 pixels */\
+ prefix##_c0c1_xf, prefix##_c0c1_xf, prefix##_c0c1_xf, prefix##_c0c1_xf /* fill */ \
+};
+
+
+/* allow for custom blitters */
+#ifdef midtunit_CUSTOM_BLITTERS
+#include "midtblit.c"
+#endif
+
+
+/*** blitter family declarations ***/
+DECLARE_BLITTER_SET(dma_draw_skip_scale, dma_state.bpp, EXTRACTGEN, SKIP_YES, SCALE_YES)
+DECLARE_BLITTER_SET(dma_draw_noskip_scale, dma_state.bpp, EXTRACTGEN, SKIP_NO, SCALE_YES)
+DECLARE_BLITTER_SET(dma_draw_skip_noscale, dma_state.bpp, EXTRACTGEN, SKIP_YES, SCALE_NO)
+DECLARE_BLITTER_SET(dma_draw_noskip_noscale, dma_state.bpp, EXTRACTGEN, SKIP_NO, SCALE_NO)
+
+
+
+/*************************************
+ *
+ * DMA finished callback
+ *
+ *************************************/
+
+static TIMER_CALLBACK( dma_callback )
+{
+ dma_register[DMA_COMMAND] &= ~0x8000; /* tell the cpu we're done */
+ cpunum_set_input_line(0, 0, ASSERT_LINE);
+}
+
+
+
+/*************************************
+ *
+ * DMA reader
+ *
+ *************************************/
+
+READ16_HANDLER( midtunit_dma_r )
+{
+ /* rmpgwt sometimes reads register 0, expecting it to return the */
+ /* current DMA status; thus we map register 0 to register 1 */
+ /* openice does it as well */
+ if (offset == 0)
+ offset = 1;
+ return dma_register[offset];
+}
+
+
+
+/*************************************
+ *
+ * DMA write handler
+ *
+ *************************************/
+
+/*
+ * DMA registers
+ * ------------------
+ *
+ * Register | Bit | Use
+ * ----------+-FEDCBA9876543210-+------------
+ * 0 | xxxxxxxx-------- | pixels to drop at the start of each row
+ * | --------xxxxxxxx | pixels to drop at the end of each row
+ * 1 | x--------------- | trigger write (or clear if zero)
+ * | -421------------ | image bpp (0=8)
+ * | ----84---------- | post skip size = (1<<x)
+ * | ------21-------- | pre skip size = (1<<x)
+ * | --------8------- | pre/post skip enable
+ * | ---------4------ | clipping enable
+ * | ----------2----- | flip y
+ * | -----------1---- | flip x
+ * | ------------8--- | blit nonzero pixels as color
+ * | -------------4-- | blit zero pixels as color
+ * | --------------2- | blit nonzero pixels
+ * | ---------------1 | blit zero pixels
+ * 2 | xxxxxxxxxxxxxxxx | source address low word
+ * 3 | xxxxxxxxxxxxxxxx | source address high word
+ * 4 | -------xxxxxxxxx | detination x
+ * 5 | -------xxxxxxxxx | destination y
+ * 6 | ------xxxxxxxxxx | image columns
+ * 7 | ------xxxxxxxxxx | image rows
+ * 8 | xxxxxxxxxxxxxxxx | palette
+ * 9 | xxxxxxxxxxxxxxxx | color
+ * 10 | ---xxxxxxxxxxxxx | scale x
+ * 11 | ---xxxxxxxxxxxxx | scale y
+ * 12 | -------xxxxxxxxx | top/left clip
+ * 13 | -------xxxxxxxxx | bottom/right clip
+ * 14 | ---------------- | test
+ * 15 | xxxxxxxx-------- | zero detect byte
+ * | --------8------- | extra page
+ * | ---------4------ | destination size
+ * | ----------2----- | select top/bottom or left/right for reg 12/13
+ */
+
+WRITE16_HANDLER( midtunit_dma_w )
+{
+ static const UINT8 register_map[2][16] =
+ {
+ { 0,1,2,3,4,5,6,7,8,9,10,11,16,17,14,15 },
+ { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }
+ };
+ int regbank = (dma_register[DMA_CONFIG] >> 5) & 1;
+ int command, bpp, regnum;
+ UINT32 gfxoffset;
+ int pixels = 0;
+
+ /* blend with the current register contents */
+ regnum = register_map[regbank][offset];
+ COMBINE_DATA(&dma_register[regnum]);
+
+ /* only writes to DMA_COMMAND actually cause actions */
+ if (regnum != DMA_COMMAND)
+ return;
+
+ /* high bit triggers action */
+ command = dma_register[DMA_COMMAND];
+ cpunum_set_input_line(0, 0, CLEAR_LINE);
+ if (!(command & 0x8000))
+ return;
+
+ profiler_mark(PROFILER_USER1);
+
+ /* determine bpp */
+ bpp = (command >> 12) & 7;
+
+ /* fill in the basic data */
+ dma_state.xpos = dma_register[DMA_XSTART] & XPOSMASK;
+ dma_state.ypos = dma_register[DMA_YSTART] & YPOSMASK;
+ dma_state.width = dma_register[DMA_WIDTH] & 0x3ff;
+ dma_state.height = dma_register[DMA_HEIGHT] & 0x3ff;
+ dma_state.palette = dma_register[DMA_PALETTE] & 0x7f00;
+ dma_state.color = dma_register[DMA_COLOR] & 0xff;
+
+ /* fill in the rev 2 data */
+ dma_state.yflip = (command & 0x20) >> 5;
+ dma_state.bpp = bpp ? bpp : 8;
+ dma_state.preskip = (command >> 8) & 3;
+ dma_state.postskip = (command >> 10) & 3;
+ dma_state.xstep = dma_register[DMA_SCALE_X] ? dma_register[DMA_SCALE_X] : 0x100;
+ dma_state.ystep = dma_register[DMA_SCALE_Y] ? dma_register[DMA_SCALE_Y] : 0x100;
+
+ /* clip the clippers */
+ dma_state.topclip = dma_register[DMA_TOPCLIP] & 0x1ff;
+ dma_state.botclip = dma_register[DMA_BOTCLIP] & 0x1ff;
+ dma_state.leftclip = dma_register[DMA_LEFTCLIP] & 0x3ff;
+ dma_state.rightclip = dma_register[DMA_RIGHTCLIP] & 0x3ff;
+
+ /* determine the offset */
+ gfxoffset = dma_register[DMA_OFFSETLO] | (dma_register[DMA_OFFSETHI] << 16);
+
+#if LOG_DMA
+ if (input_code_pressed(KEYCODE_L))
+ {
+ logerror("DMA command %04X: (bpp=%d skip=%d xflip=%d yflip=%d preskip=%d postskip=%d)\n",
+ command, (command >> 12) & 7, (command >> 7) & 1, (command >> 4) & 1, (command >> 5) & 1, (command >> 8) & 3, (command >> 10) & 3);
+ logerror(" offset=%08X pos=(%d,%d) w=%d h=%d clip=(%d,%d)-(%d,%d)\n", gfxoffset, dma_register[DMA_XSTART], dma_register[DMA_YSTART],
+ dma_register[DMA_WIDTH], dma_register[DMA_HEIGHT], dma_register[DMA_LEFTCLIP], dma_register[DMA_TOPCLIP], dma_register[DMA_RIGHTCLIP], dma_register[DMA_BOTCLIP]);
+ logerror(" offset=%08X pos=(%d,%d) w=%d h=%d clip=(%d,%d)-(%d,%d)\n", gfxoffset, dma_state.xpos, dma_state.ypos,
+ dma_state.width, dma_state.height, dma_state.leftclip, dma_state.topclip, dma_state.rightclip, dma_state.botclip);
+ logerror(" palette=%04X color=%04X lskip=%02X rskip=%02X xstep=%04X ystep=%04X test=%04X config=%04X\n",
+ dma_register[DMA_PALETTE], dma_register[DMA_COLOR],
+ dma_register[DMA_LRSKIP] >> 8, dma_register[DMA_LRSKIP] & 0xff,
+ dma_register[DMA_SCALE_X], dma_register[DMA_SCALE_Y], dma_register[DMA_UNKNOWN_E],
+ dma_register[DMA_CONFIG]);
+ logerror("----\n");
+ }
+#endif
+
+ /* special case: drawing mode C doesn't need to know about any pixel data */
+ if ((command & 0x0f) == 0x0c)
+ gfxoffset = 0;
+
+ /* determine the location */
+ if (!midtunit_gfx_rom_large && gfxoffset >= 0x2000000)
+ gfxoffset -= 0x2000000;
+ if (gfxoffset >= 0xf8000000)
+ gfxoffset -= 0xf8000000;
+ if (gfxoffset < 0x10000000)
+ dma_state.offset = gfxoffset;
+ else
+ {
+ logerror("DMA source out of range: %08X\n", gfxoffset);
+ goto skipdma;
+ }
+
+ /* there seems to be two types of behavior for the DMA chip */
+ /* for MK1 and MK2, the upper byte of the LRSKIP is the */
+ /* starting skip value, and the lower byte is the ending */
+ /* skip value; for the NBA Jam, Hangtime, and Open Ice, the */
+ /* full word seems to be the starting skip value. */
+ if (command & 0x40)
+ {
+ dma_state.startskip = dma_register[DMA_LRSKIP] & 0xff;
+ dma_state.endskip = dma_register[DMA_LRSKIP] >> 8;
+ }
+ else
+ {
+ dma_state.startskip = 0;
+ dma_state.endskip = dma_register[DMA_LRSKIP];
+ }
+
+ /* then draw */
+ if (dma_state.xstep == 0x100 && dma_state.ystep == 0x100)
+ {
+ if (command & 0x80)
+ (*dma_draw_skip_noscale[command & 0x1f])();
+ else
+ (*dma_draw_noskip_noscale[command & 0x1f])();
+
+ pixels = dma_state.width * dma_state.height;
+ }
+ else
+ {
+ if (command & 0x80)
+ (*dma_draw_skip_scale[command & 0x1f])();
+ else
+ (*dma_draw_noskip_scale[command & 0x1f])();
+
+ if (dma_state.xstep && dma_state.ystep)
+ pixels = ((dma_state.width << 8) / dma_state.xstep) * ((dma_state.height << 8) / dma_state.ystep);
+ else
+ pixels = 0;
+ }
+
+ /* signal we're done */
+skipdma:
+ timer_set(ATTOTIME_IN_NSEC(41 * pixels), 0, dma_callback);
+
+ profiler_mark(PROFILER_END);
+}
+
+
+
+/*************************************
+ *
+ * Core refresh routine
+ *
+ *************************************/
+
+void midtunit_scanline_update(running_machine *machine, int screen, mame_bitmap *bitmap, int scanline, const tms34010_display_params *params)
+{
+ UINT16 *src = &local_videoram[(params->rowaddr << 9) & 0x3fe00];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0);
+ int coladdr = params->coladdr << 1;
+ int x;
+
+ /* copy the non-blanked portions of this scanline */
+ for (x = params->heblnk; x < params->hsblnk; x++)
+ dest[x] = pen_map[src[coladdr++ & 0x1ff]];
+}
+
+void midxunit_scanline_update(running_machine *machine, int screen, mame_bitmap *bitmap, int scanline, const tms34010_display_params *params)
+{
+ UINT32 fulladdr = ((params->rowaddr << 16) | params->coladdr) >> 3;
+ UINT16 *src = &local_videoram[fulladdr & 0x3fe00];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0);
+ int x;
+
+ /* copy the non-blanked portions of this scanline */
+ for (x = params->heblnk; x < params->hsblnk; x++)
+ dest[x] = pen_map[src[fulladdr++ & 0x1ff]];
+}
diff --git a/src/mame/video/midvunit.c b/src/mame/video/midvunit.c
new file mode 100644
index 00000000000..31577255a60
--- /dev/null
+++ b/src/mame/video/midvunit.c
@@ -0,0 +1,573 @@
+/*************************************************************************
+
+ Driver for Midway V-Unit games
+
+**************************************************************************/
+
+#include "driver.h"
+#include "cpu/tms34010/tms34010.h"
+#include "cpu/adsp2100/adsp2100.h"
+#include "audio/williams.h"
+#include "video/poly.h"
+#include "midvunit.h"
+
+
+#define WATCH_RENDER (0)
+#define LOG_DMA (0)
+
+
+#define DMA_CLOCK 40000000
+
+
+/* for when we implement DMA timing */
+#define DMA_QUEUE_SIZE 273
+#define TIME_PER_PIXEL 41e-9
+
+
+
+UINT16 *midvunit_videoram;
+UINT32 *midvunit_textureram;
+
+static UINT16 video_regs[16];
+static UINT16 dma_data[16];
+static UINT8 dma_data_index;
+static UINT16 page_control;
+static UINT8 video_changed;
+
+static emu_timer *scanline_timer;
+static poly_manager *poly;
+
+typedef struct _poly_extra_data poly_extra_data;
+struct _poly_extra_data
+{
+ UINT8 * texbase;
+ UINT16 pixdata;
+ UINT8 dither;
+};
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+static TIMER_CALLBACK( scanline_timer_cb )
+{
+ int scanline = param;
+
+ cpunum_set_input_line(0, 0, ASSERT_LINE);
+ timer_adjust(scanline_timer, video_screen_get_time_until_pos(0, scanline + 1, 0), scanline, attotime_zero);
+}
+
+
+static void midvunit_exit(running_machine *machine)
+{
+ poly_free(poly);
+}
+
+
+VIDEO_START( midvunit )
+{
+ scanline_timer = timer_alloc(scanline_timer_cb);
+ poly = poly_alloc(4000, sizeof(poly_extra_data), POLYFLAG_ALLOW_QUADS);
+ add_exit_callback(machine, midvunit_exit);
+}
+
+
+
+/*************************************
+ *
+ * Generic flat quad renderer
+ *
+ *************************************/
+
+static void render_flat(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ UINT16 pixdata = extra->pixdata;
+ int xstep = extra->dither + 1;
+ UINT16 *dest = (UINT16 *)destbase + scanline * 512;
+ int startx = extent->startx;
+ int x;
+
+ /* if dithering, ensure that we start on an appropriate pixel */
+ startx += (scanline ^ startx) & extra->dither;
+
+ /* non-dithered 0 pixels can use a memset */
+ if (pixdata == 0 && xstep == 1)
+ memset(&dest[startx], 0, 2 * (extent->stopx - startx + 1));
+
+ /* otherwise, we fill manually */
+ else
+ {
+ for (x = startx; x < extent->stopx; x += xstep)
+ dest[x] = pixdata;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Generic textured quad renderers
+ *
+ *************************************/
+
+static void render_tex(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ UINT16 pixdata = extra->pixdata & 0xff00;
+ const UINT8 *texbase = extra->texbase;
+ int xstep = extra->dither + 1;
+ UINT16 *dest = (UINT16 *)destbase + scanline * 512;
+ int startx = extent->startx;
+ int stopx = extent->stopx;
+ INT32 u = extent->param[0].start;
+ INT32 v = extent->param[1].start;
+ INT32 dudx = extent->param[0].dpdx;
+ INT32 dvdx = extent->param[1].dpdx;
+ int x;
+
+ /* if dithering, we advance by 2x; also ensure that we start on an appropriate pixel */
+ if (xstep == 2)
+ {
+ if ((scanline ^ startx) & 1)
+ {
+ startx++;
+ u += dudx;
+ v += dvdx;
+ }
+ dudx *= 2;
+ dvdx *= 2;
+ }
+
+ /* general case; render every pixel */
+ for (x = startx; x < stopx; x += xstep)
+ {
+ dest[x] = pixdata | texbase[((v >> 8) & 0xff00) + (u >> 16)];
+ u += dudx;
+ v += dvdx;
+ }
+}
+
+
+static void render_textrans(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ UINT16 pixdata = extra->pixdata & 0xff00;
+ const UINT8 *texbase = extra->texbase;
+ int xstep = extra->dither + 1;
+ UINT16 *dest = (UINT16 *)destbase + scanline * 512;
+ int startx = extent->startx;
+ int stopx = extent->stopx;
+ INT32 u = extent->param[0].start;
+ INT32 v = extent->param[1].start;
+ INT32 dudx = extent->param[0].dpdx;
+ INT32 dvdx = extent->param[1].dpdx;
+ int x;
+
+ /* if dithering, we advance by 2x; also ensure that we start on an appropriate pixel */
+ if (xstep == 2)
+ {
+ if ((scanline ^ startx) & 1)
+ {
+ startx++;
+ u += dudx;
+ v += dvdx;
+ }
+ dudx *= 2;
+ dvdx *= 2;
+ }
+
+ /* general case; render every non-zero texel */
+ for (x = startx; x < stopx; x += xstep)
+ {
+ UINT8 pix = texbase[((v >> 8) & 0xff00) + (u >> 16)];
+ if (pix != 0)
+ dest[x] = pixdata | pix;
+ u += dudx;
+ v += dvdx;
+ }
+}
+
+
+static void render_textransmask(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ UINT16 pixdata = extra->pixdata;
+ const UINT8 *texbase = extra->texbase;
+ int xstep = extra->dither + 1;
+ UINT16 *dest = (UINT16 *)destbase + scanline * 512;
+ int startx = extent->startx;
+ int stopx = extent->stopx;
+ INT32 u = extent->param[0].start;
+ INT32 v = extent->param[1].start;
+ INT32 dudx = extent->param[0].dpdx;
+ INT32 dvdx = extent->param[1].dpdx;
+ int x;
+
+ /* if dithering, we advance by 2x; also ensure that we start on an appropriate pixel */
+ if (xstep == 2)
+ {
+ if ((scanline ^ startx) & 1)
+ {
+ startx++;
+ u += dudx;
+ v += dvdx;
+ }
+ dudx *= 2;
+ dvdx *= 2;
+ }
+
+ /* general case; every non-zero texel renders pixdata */
+ for (x = startx; x < stopx; x += xstep)
+ {
+ UINT8 pix = texbase[((v >> 8) & 0xff00) + (u >> 16)];
+ if (pix != 0)
+ dest[x] = pixdata;
+ u += dudx;
+ v += dvdx;
+ }
+}
+
+
+
+/*************************************
+ *
+ * DMA queue processor
+ *
+ *************************************/
+
+static void make_vertices_inclusive(poly_vertex *vert)
+{
+ UINT8 rmask = 0, bmask = 0, eqmask = 0;
+ int vnum;
+
+ /* build up a mask of right and bottom points */
+ /* note we assume clockwise orientation here */
+ for (vnum = 0; vnum < 4; vnum++)
+ {
+ poly_vertex *currv = &vert[vnum];
+ poly_vertex *nextv = &vert[(vnum + 1) & 3];
+
+ /* if this vertex equals the next one, tag it */
+ if (nextv->y == currv->y && nextv->x == currv->x)
+ eqmask |= 1 << vnum;
+
+ /* if the next vertex is down from us, we are a right coordinate */
+ if (nextv->y > currv->y || (nextv->y == currv->y && nextv->x < currv->x))
+ rmask |= 1 << vnum;
+
+ /* if the next vertex is left from us, we are a bottom coordinate */
+ if (nextv->x < currv->x || (nextv->x == currv->x && nextv->y < currv->y))
+ bmask |= 1 << vnum;
+ }
+
+ /* bail on the edge case */
+ if (eqmask == 0x0f)
+ return;
+
+ /* adjust the right/bottom points so that they get included */
+ for (vnum = 0; vnum < 4; vnum++)
+ {
+ poly_vertex *currv = &vert[vnum];
+ int effvnum = vnum;
+
+ /* if we're equal to the next vertex, use that instead */
+ while (eqmask & (1 << effvnum))
+ effvnum = (effvnum + 1) & 3;
+
+ /* adjust the points */
+ if (rmask & (1 << effvnum))
+ currv->x += 0.001f;
+ if (bmask & (1 << effvnum))
+ currv->y += 0.001f;
+ }
+}
+
+
+static void process_dma_queue(running_machine *machine)
+{
+ poly_extra_data *extra = poly_get_extra_data(poly);
+ UINT16 *dest = &midvunit_videoram[(page_control & 4) ? 0x40000 : 0x00000];
+ int textured = ((dma_data[0] & 0x300) == 0x100);
+ poly_draw_scanline callback;
+ poly_vertex vert[4];
+
+ /* if we're rendering to the same page we're viewing, it has changed */
+ if ((((page_control >> 2) ^ page_control) & 1) == 0)
+ video_changed = TRUE;
+
+ /* fill in the vertex data */
+ vert[0].x = (float)(INT16)dma_data[2] + 0.5f;
+ vert[0].y = (float)(INT16)dma_data[3] + 0.5f;
+ vert[1].x = (float)(INT16)dma_data[4] + 0.5f;
+ vert[1].y = (float)(INT16)dma_data[5] + 0.5f;
+ vert[2].x = (float)(INT16)dma_data[6] + 0.5f;
+ vert[2].y = (float)(INT16)dma_data[7] + 0.5f;
+ vert[3].x = (float)(INT16)dma_data[8] + 0.5f;
+ vert[3].y = (float)(INT16)dma_data[9] + 0.5f;
+
+ /* make the vertices inclusive of right/bottom points */
+ make_vertices_inclusive(vert);
+
+ /* handle flat-shaded quads here */
+ if (!textured)
+ callback = render_flat;
+
+ /* handle textured quads here */
+ else
+ {
+ /* if textured, add the texture info */
+ vert[0].p[0] = (float)(dma_data[10] & 0xff) * 65536.0f + 32768.0f;
+ vert[0].p[1] = (float)(dma_data[10] >> 8) * 65536.0f + 32768.0f;
+ vert[1].p[0] = (float)(dma_data[11] & 0xff) * 65536.0f + 32768.0f;
+ vert[1].p[1] = (float)(dma_data[11] >> 8) * 65536.0f + 32768.0f;
+ vert[2].p[0] = (float)(dma_data[12] & 0xff) * 65536.0f + 32768.0f;
+ vert[2].p[1] = (float)(dma_data[12] >> 8) * 65536.0f + 32768.0f;
+ vert[3].p[0] = (float)(dma_data[13] & 0xff) * 65536.0f + 32768.0f;
+ vert[3].p[1] = (float)(dma_data[13] >> 8) * 65536.0f + 32768.0f;
+
+ /* handle non-masked, non-transparent quads */
+ if ((dma_data[0] & 0xc00) == 0x000)
+ callback = render_tex;
+
+ /* handle non-masked, transparent quads */
+ else if ((dma_data[0] & 0xc00) == 0x800)
+ callback = render_textrans;
+
+ /* handle masked, transparent quads */
+ else if ((dma_data[0] & 0xc00) == 0xc00)
+ callback = render_textransmask;
+
+ /* handle masked, non-transparent quads */
+ else
+ callback = render_flat;
+ }
+
+ /* set up the extra data for this triangle */
+ extra->texbase = (UINT8 *)midvunit_textureram + (dma_data[14] * 256);
+ extra->pixdata = dma_data[1] | (dma_data[0] & 0x00ff);
+ extra->dither = ((dma_data[0] & 0x2000) != 0);
+
+ /* render as a quad */
+ poly_render_quad(poly, dest, &machine->screen[0].visarea, callback, textured ? 2 : 0, &vert[0], &vert[1], &vert[2], &vert[3]);
+}
+
+
+
+/*************************************
+ *
+ * DMA pipe control control
+ *
+ *************************************/
+
+WRITE32_HANDLER( midvunit_dma_queue_w )
+{
+ if (LOG_DMA && input_code_pressed(KEYCODE_L))
+ logerror("%06X:queue(%X) = %08X\n", activecpu_get_pc(), dma_data_index, data);
+ if (dma_data_index < 16)
+ dma_data[dma_data_index++] = data;
+}
+
+
+READ32_HANDLER( midvunit_dma_queue_entries_r )
+{
+ /* always return 0 entries */
+ return 0;
+}
+
+
+READ32_HANDLER( midvunit_dma_trigger_r )
+{
+ if (offset)
+ {
+ if (LOG_DMA && input_code_pressed(KEYCODE_L))
+ logerror("%06X:trigger\n", activecpu_get_pc());
+ process_dma_queue(Machine);
+ dma_data_index = 0;
+ }
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Paging control
+ *
+ *************************************/
+
+WRITE32_HANDLER( midvunit_page_control_w )
+{
+ /* watch for the display page to change */
+ if ((page_control ^ data) & 1)
+ {
+ video_changed = TRUE;
+ if (LOG_DMA && input_code_pressed(KEYCODE_L))
+ logerror("##########################################################\n");
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+ }
+ page_control = data;
+}
+
+
+READ32_HANDLER( midvunit_page_control_r )
+{
+ return page_control;
+}
+
+
+
+/*************************************
+ *
+ * Video control
+ *
+ *************************************/
+
+WRITE32_HANDLER( midvunit_video_control_w )
+{
+ UINT16 old = video_regs[offset];
+
+ /* update the data */
+ COMBINE_DATA(&video_regs[offset]);
+
+ /* update the scanline timer */
+ if (offset == 0)
+ timer_adjust(scanline_timer, video_screen_get_time_until_pos(0, (data & 0x1ff) + 1, 0), data & 0x1ff, attotime_zero);
+
+ /* if something changed, update our parameters */
+ if (old != video_regs[offset] && video_regs[6] != 0 && video_regs[11] != 0)
+ {
+ rectangle visarea;
+
+ /* derive visible area from blanking */
+ visarea.min_x = 0;
+ visarea.max_x = (video_regs[6] + video_regs[2] - video_regs[5]) % video_regs[6];
+ visarea.min_y = 0;
+ visarea.max_y = (video_regs[11] + video_regs[7] - video_regs[10]) % video_regs[11];
+ video_screen_configure(0, video_regs[6], video_regs[11], &visarea, HZ_TO_ATTOSECONDS(MIDVUNIT_VIDEO_CLOCK / 2) * video_regs[6] * video_regs[11]);
+ }
+}
+
+
+READ32_HANDLER( midvunit_scanline_r )
+{
+ return video_screen_get_vpos(0);
+}
+
+
+
+/*************************************
+ *
+ * Video RAM access
+ *
+ *************************************/
+
+WRITE32_HANDLER( midvunit_videoram_w )
+{
+ poly_wait(poly, "Video RAM write");
+ if (!video_changed)
+ {
+ int visbase = (page_control & 1) ? 0x40000 : 0x00000;
+ if ((offset & 0x40000) == visbase)
+ video_changed = TRUE;
+ }
+ COMBINE_DATA(&midvunit_videoram[offset]);
+}
+
+
+READ32_HANDLER( midvunit_videoram_r )
+{
+ poly_wait(poly, "Video RAM read");
+ return midvunit_videoram[offset];
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM access
+ *
+ *************************************/
+
+WRITE32_HANDLER( midvunit_paletteram_w )
+{
+ int newword;
+
+ COMBINE_DATA(&paletteram32[offset]);
+ newword = paletteram32[offset];
+ palette_set_color_rgb(Machine, offset, pal5bit(newword >> 10), pal5bit(newword >> 5), pal5bit(newword >> 0));
+}
+
+
+
+/*************************************
+ *
+ * Texture RAM access
+ *
+ *************************************/
+
+WRITE32_HANDLER( midvunit_textureram_w )
+{
+ UINT8 *base = (UINT8 *)midvunit_textureram;
+ poly_wait(poly, "Texture RAM write");
+ base[offset * 2] = data;
+ base[offset * 2 + 1] = data >> 8;
+}
+
+
+READ32_HANDLER( midvunit_textureram_r )
+{
+ UINT8 *base = (UINT8 *)midvunit_textureram;
+ return (base[offset * 2 + 1] << 8) | base[offset * 2];
+}
+
+
+
+
+/*************************************
+ *
+ * Video system update
+ *
+ *************************************/
+
+VIDEO_UPDATE( midvunit )
+{
+ int x, y, width, xoffs;
+ UINT32 offset;
+
+ poly_wait(poly, "Refresh Time");
+
+ /* if the video didn't change, indicate as much */
+ if (!video_changed)
+ return UPDATE_HAS_NOT_CHANGED;
+ video_changed = FALSE;
+
+ /* determine the base of the videoram */
+#if WATCH_RENDER
+ offset = (page_control & 4) ? 0x40000 : 0x00000;
+#else
+ offset = (page_control & 1) ? 0x40000 : 0x00000;
+#endif
+
+ /* determine how many pixels to copy */
+ xoffs = cliprect->min_x;
+ width = cliprect->max_x - xoffs + 1;
+
+ /* adjust the offset */
+ offset += xoffs;
+ offset += 512 * (cliprect->min_y - machine->screen[0].visarea.min_y);
+
+ /* loop over rows */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *dest = (UINT16 *)bitmap->base + y * bitmap->rowpixels + cliprect->min_x;
+ for (x = 0; x < width; x++)
+ *dest++ = midvunit_videoram[offset + x] & 0x7fff;
+ offset += 512;
+ }
+ return 0;
+}
diff --git a/src/mame/video/midyunit.c b/src/mame/video/midyunit.c
new file mode 100644
index 00000000000..2fbb9624b02
--- /dev/null
+++ b/src/mame/video/midyunit.c
@@ -0,0 +1,623 @@
+/*************************************************************************
+
+ Williams/Midway Y/Z-unit system
+
+**************************************************************************/
+
+#include "driver.h"
+#include "profiler.h"
+#include "cpu/tms34010/tms34010.h"
+#include "cpu/tms34010/34010ops.h"
+#include "midyunit.h"
+
+
+/* compile-time options */
+#define LOG_DMA 0 /* DMAs are logged if the 'L' key is pressed */
+
+
+/* constants for the DMA chip */
+enum
+{
+ DMA_COMMAND = 0,
+ DMA_ROWBYTES,
+ DMA_OFFSETLO,
+ DMA_OFFSETHI,
+ DMA_XSTART,
+ DMA_YSTART,
+ DMA_WIDTH,
+ DMA_HEIGHT,
+ DMA_PALETTE,
+ DMA_COLOR
+};
+
+
+
+/* graphics-related variables */
+ UINT8 * midyunit_gfx_rom;
+ size_t midyunit_gfx_rom_size;
+static UINT8 autoerase_enable;
+
+/* palette-related variables */
+static UINT32 palette_mask;
+static pen_t * pen_map;
+
+/* videoram-related variables */
+static UINT16 * local_videoram;
+static UINT8 videobank_select;
+
+/* DMA-related variables */
+static UINT8 yawdim_dma;
+static UINT16 dma_register[16];
+static struct
+{
+ UINT32 offset; /* source offset, in bits */
+ INT32 rowbytes; /* source bytes to skip each row */
+ INT32 xpos; /* x position, clipped */
+ INT32 ypos; /* y position, clipped */
+ INT32 width; /* horizontal pixel count */
+ INT32 height; /* vertical pixel count */
+ UINT16 palette; /* palette base */
+ UINT16 color; /* current foreground color with palette */
+} dma_state;
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+static VIDEO_START( common )
+{
+ /* allocate memory */
+ midyunit_cmos_ram = auto_malloc(0x2000 * 4);
+ local_videoram = auto_malloc(0x80000);
+ pen_map = auto_malloc(65536 * sizeof(pen_map[0]));
+
+ /* we have to erase this since we rely on upper bits being 0 */
+ memset(local_videoram, 0, 0x80000);
+
+ /* reset all the globals */
+ midyunit_cmos_page = 0;
+ autoerase_enable = 0;
+ yawdim_dma = 0;
+
+ /* reset DMA state */
+ memset(dma_register, 0, sizeof(dma_register));
+ memset(&dma_state, 0, sizeof(dma_state));
+
+ /* register for state saving */
+ state_save_register_global(autoerase_enable);
+ state_save_register_global_pointer(local_videoram, 0x80000/sizeof(local_videoram[0]));
+ state_save_register_global_pointer(midyunit_cmos_ram, (0x2000 * 4)/sizeof(midyunit_cmos_ram[0]));
+ state_save_register_global(videobank_select);
+ state_save_register_global_array(dma_register);
+}
+
+
+VIDEO_START( midyunit_4bit )
+{
+ int i;
+
+ video_start_common(machine);
+
+ /* init for 4-bit */
+ for (i = 0; i < 65536; i++)
+ pen_map[i] = ((i & 0xf000) >> 8) | (i & 0x000f);
+ palette_mask = 0x00ff;
+}
+
+
+VIDEO_START( midyunit_6bit )
+{
+ int i;
+
+ video_start_common(machine);
+
+ /* init for 6-bit */
+ for (i = 0; i < 65536; i++)
+ pen_map[i] = ((i & 0xc000) >> 8) | (i & 0x0f3f);
+ palette_mask = 0x0fff;
+}
+
+
+VIDEO_START( mkyawdim )
+{
+ video_start_midyunit_6bit(machine);
+ yawdim_dma = 1;
+}
+
+
+VIDEO_START( midzunit )
+{
+ int i;
+
+ video_start_common(machine);
+
+ /* init for 8-bit */
+ for (i = 0; i < 65536; i++)
+ pen_map[i] = i & 0x1fff;
+ palette_mask = 0x1fff;
+}
+
+
+
+/*************************************
+ *
+ * Banked graphics ROM access
+ *
+ *************************************/
+
+READ16_HANDLER( midyunit_gfxrom_r )
+{
+ offset *= 2;
+ if (palette_mask == 0x00ff)
+ return midyunit_gfx_rom[offset] | (midyunit_gfx_rom[offset] << 4) |
+ (midyunit_gfx_rom[offset + 1] << 8) | (midyunit_gfx_rom[offset + 1] << 12);
+ else
+ return midyunit_gfx_rom[offset] | (midyunit_gfx_rom[offset + 1] << 8);
+}
+
+
+
+/*************************************
+ *
+ * Video/color RAM read/write
+ *
+ *************************************/
+
+WRITE16_HANDLER( midyunit_vram_w )
+{
+ offset *= 2;
+ if (videobank_select)
+ {
+ if (ACCESSING_LSB)
+ local_videoram[offset] = (data & 0x00ff) | (dma_register[DMA_PALETTE] << 8);
+ if (ACCESSING_MSB)
+ local_videoram[offset + 1] = (data >> 8) | (dma_register[DMA_PALETTE] & 0xff00);
+ }
+ else
+ {
+ if (ACCESSING_LSB)
+ local_videoram[offset] = (local_videoram[offset] & 0x00ff) | (data << 8);
+ if (ACCESSING_MSB)
+ local_videoram[offset + 1] = (local_videoram[offset + 1] & 0x00ff) | (data & 0xff00);
+ }
+}
+
+
+READ16_HANDLER( midyunit_vram_r )
+{
+ offset *= 2;
+ if (videobank_select)
+ return (local_videoram[offset] & 0x00ff) | (local_videoram[offset + 1] << 8);
+ else
+ return (local_videoram[offset] >> 8) | (local_videoram[offset + 1] & 0xff00);
+}
+
+
+
+/*************************************
+ *
+ * Shift register read/write
+ *
+ *************************************/
+
+void midyunit_to_shiftreg(UINT32 address, UINT16 *shiftreg)
+{
+ memcpy(shiftreg, &local_videoram[address >> 3], 2 * 512 * sizeof(UINT16));
+}
+
+
+void midyunit_from_shiftreg(UINT32 address, UINT16 *shiftreg)
+{
+ memcpy(&local_videoram[address >> 3], shiftreg, 2 * 512 * sizeof(UINT16));
+}
+
+
+
+/*************************************
+ *
+ * Y/Z-unit control register
+ *
+ *************************************/
+
+WRITE16_HANDLER( midyunit_control_w )
+{
+ /*
+ * Narc system register
+ * ------------------
+ *
+ * | Bit | Use
+ * --+-FEDCBA9876543210-+------------
+ * | xxxxxxxx-------- | 7 segment led on CPU board
+ * | --------xx------ | CMOS page
+ * | ----------x----- | - OBJ PAL RAM select
+ * | -----------x---- | - autoerase enable
+ * | ---------------- | - watchdog
+ *
+ */
+
+ if (ACCESSING_LSB)
+ {
+ /* CMOS page is bits 6-7 */
+ midyunit_cmos_page = ((data >> 6) & 3) * 0x1000;
+
+ /* video bank select is bit 5 */
+ videobank_select = (data >> 5) & 1;
+
+ /* handle autoerase disable (bit 4) */
+ autoerase_enable = ((data & 0x10) == 0);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Palette handlers
+ *
+ *************************************/
+
+WRITE16_HANDLER( midyunit_paletteram_w )
+{
+ int newword;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ newword = paletteram16[offset];
+ palette_set_color_rgb(Machine, offset & palette_mask, pal5bit(newword >> 10), pal5bit(newword >> 5), pal5bit(newword >> 0));
+}
+
+
+
+/*************************************
+ *
+ * DMA drawing routines
+ *
+ *************************************/
+
+/*** constant definitions ***/
+#define PIXEL_SKIP 0
+#define PIXEL_COLOR 1
+#define PIXEL_COPY 2
+
+#define XFLIP_NO 0
+#define XFLIP_YES 1
+
+
+typedef void (*dma_draw_func)(void);
+
+
+/*** core blitter routine macro ***/
+#define DMA_DRAW_FUNC_BODY(name, xflip, zero, nonzero) \
+{ \
+ int height = dma_state.height; \
+ int width = dma_state.width; \
+ UINT8 *base = midyunit_gfx_rom; \
+ UINT32 offset = dma_state.offset >> 3; \
+ UINT16 pal = dma_state.palette; \
+ UINT16 color = pal | dma_state.color; \
+ int x, y; \
+ \
+ /* loop over the height */ \
+ for (y = 0; y < height; y++) \
+ { \
+ int tx = dma_state.xpos; \
+ int ty = dma_state.ypos; \
+ UINT32 o = offset; \
+ UINT16 *dest; \
+ \
+ /* determine Y position */ \
+ ty = (ty + y) & 0x1ff; \
+ offset += dma_state.rowbytes; \
+ \
+ /* check for over/underrun */ \
+ if (o >= 0x06000000) \
+ continue; \
+ \
+ /* determine destination pointer */ \
+ dest = &local_videoram[ty * 512]; \
+ \
+ /* loop until we draw the entire width */ \
+ for (x = 0; x < width; x++, o++) \
+ { \
+ /* special case similar handling of zero/non-zero */ \
+ if (zero == nonzero) \
+ { \
+ if (zero == PIXEL_COLOR) \
+ dest[tx] = color; \
+ else if (zero == PIXEL_COPY) \
+ dest[tx] = base[o] | pal; \
+ } \
+ \
+ /* otherwise, read the pixel and look */ \
+ else \
+ { \
+ int pixel = base[o]; \
+ \
+ /* non-zero pixel case */ \
+ if (pixel) \
+ { \
+ if (nonzero == PIXEL_COLOR) \
+ dest[tx] = color; \
+ else if (nonzero == PIXEL_COPY) \
+ dest[tx] = pixel | pal; \
+ } \
+ \
+ /* zero pixel case */ \
+ else \
+ { \
+ if (zero == PIXEL_COLOR) \
+ dest[tx] = color; \
+ else if (zero == PIXEL_COPY) \
+ dest[tx] = pal; \
+ } \
+ } \
+ \
+ /* update pointers */ \
+ if (xflip) tx--; \
+ else tx++; \
+ } \
+ } \
+}
+
+/*** slightly simplified one for most blitters ***/
+#define DMA_DRAW_FUNC(name, xflip, zero, nonzero) \
+static void name(void) \
+{ \
+ DMA_DRAW_FUNC_BODY(name, xflip, zero, nonzero) \
+}
+
+/*** empty blitter ***/
+static void dma_draw_none(void)
+{
+}
+
+/*** super macro for declaring an entire blitter family ***/
+#define DECLARE_BLITTER_SET(prefix) \
+DMA_DRAW_FUNC(prefix##_p0, XFLIP_NO, PIXEL_COPY, PIXEL_SKIP) \
+DMA_DRAW_FUNC(prefix##_p1, XFLIP_NO, PIXEL_SKIP, PIXEL_COPY) \
+DMA_DRAW_FUNC(prefix##_c0, XFLIP_NO, PIXEL_COLOR, PIXEL_SKIP) \
+DMA_DRAW_FUNC(prefix##_c1, XFLIP_NO, PIXEL_SKIP, PIXEL_COLOR) \
+DMA_DRAW_FUNC(prefix##_p0p1, XFLIP_NO, PIXEL_COPY, PIXEL_COPY) \
+DMA_DRAW_FUNC(prefix##_c0c1, XFLIP_NO, PIXEL_COLOR, PIXEL_COLOR) \
+DMA_DRAW_FUNC(prefix##_c0p1, XFLIP_NO, PIXEL_COLOR, PIXEL_COPY) \
+DMA_DRAW_FUNC(prefix##_p0c1, XFLIP_NO, PIXEL_COPY, PIXEL_COLOR) \
+ \
+DMA_DRAW_FUNC(prefix##_p0_xf, XFLIP_YES, PIXEL_COPY, PIXEL_SKIP) \
+DMA_DRAW_FUNC(prefix##_p1_xf, XFLIP_YES, PIXEL_SKIP, PIXEL_COPY) \
+DMA_DRAW_FUNC(prefix##_c0_xf, XFLIP_YES, PIXEL_COLOR, PIXEL_SKIP) \
+DMA_DRAW_FUNC(prefix##_c1_xf, XFLIP_YES, PIXEL_SKIP, PIXEL_COLOR) \
+DMA_DRAW_FUNC(prefix##_p0p1_xf, XFLIP_YES, PIXEL_COPY, PIXEL_COPY) \
+DMA_DRAW_FUNC(prefix##_c0c1_xf, XFLIP_YES, PIXEL_COLOR, PIXEL_COLOR) \
+DMA_DRAW_FUNC(prefix##_c0p1_xf, XFLIP_YES, PIXEL_COLOR, PIXEL_COPY) \
+DMA_DRAW_FUNC(prefix##_p0c1_xf, XFLIP_YES, PIXEL_COPY, PIXEL_COLOR) \
+ \
+static dma_draw_func prefix[32] = \
+{ \
+/* B0:N / B1:N B0:Y / B1:N B0:N / B1:Y B0:Y / B1:Y */ \
+ dma_draw_none, prefix##_p0, prefix##_p1, prefix##_p0p1, /* no color */ \
+ prefix##_c0, prefix##_c0, prefix##_c0p1, prefix##_c0p1, /* color 0 pixels */ \
+ prefix##_c1, prefix##_p0c1, prefix##_c1, prefix##_p0c1, /* color non-0 pixels */ \
+ prefix##_c0c1, prefix##_c0c1, prefix##_c0c1, prefix##_c0c1, /* fill */ \
+ \
+ dma_draw_none, prefix##_p0_xf, prefix##_p1_xf, prefix##_p0p1_xf, /* no color */ \
+ prefix##_c0_xf, prefix##_c0_xf, prefix##_c0p1_xf, prefix##_c0p1_xf, /* color 0 pixels */ \
+ prefix##_c1_xf, prefix##_p0c1_xf, prefix##_c1_xf, prefix##_p0c1_xf, /* color non-0 pixels */ \
+ prefix##_c0c1_xf, prefix##_c0c1_xf, prefix##_c0c1_xf, prefix##_c0c1_xf /* fill */ \
+};
+
+/*** blitter family declarations ***/
+DECLARE_BLITTER_SET(dma_draw)
+
+
+
+/*************************************
+ *
+ * DMA finished callback
+ *
+ *************************************/
+
+static TIMER_CALLBACK( dma_callback )
+{
+ dma_register[DMA_COMMAND] &= ~0x8000; /* tell the cpu we're done */
+ cpunum_set_input_line(0, 0, ASSERT_LINE);
+}
+
+
+
+/*************************************
+ *
+ * DMA reader
+ *
+ *************************************/
+
+READ16_HANDLER( midyunit_dma_r )
+{
+ return dma_register[offset];
+}
+
+
+
+/*************************************
+ *
+ * DMA write handler
+ *
+ *************************************/
+
+/*
+ * DMA registers
+ * ------------------
+ *
+ * Register | Bit | Use
+ * ----------+-FEDCBA9876543210-+------------
+ * 0 | x--------------- | trigger write (or clear if zero)
+ * | ---184-1-------- | unknown
+ * | ----------x----- | flip y
+ * | -----------x---- | flip x
+ * | ------------x--- | blit nonzero pixels as color
+ * | -------------x-- | blit zero pixels as color
+ * | --------------x- | blit nonzero pixels
+ * | ---------------x | blit zero pixels
+ * 1 | xxxxxxxxxxxxxxxx | width offset
+ * 2 | xxxxxxxxxxxxxxxx | source address low word
+ * 3 | xxxxxxxxxxxxxxxx | source address high word
+ * 4 | xxxxxxxxxxxxxxxx | detination x
+ * 5 | xxxxxxxxxxxxxxxx | destination y
+ * 6 | xxxxxxxxxxxxxxxx | image columns
+ * 7 | xxxxxxxxxxxxxxxx | image rows
+ * 8 | xxxxxxxxxxxxxxxx | palette
+ * 9 | xxxxxxxxxxxxxxxx | color
+ */
+
+WRITE16_HANDLER( midyunit_dma_w )
+{
+ UINT32 gfxoffset;
+ int command;
+
+ /* blend with the current register contents */
+ COMBINE_DATA(&dma_register[offset]);
+
+ /* only writes to DMA_COMMAND actually cause actions */
+ if (offset != DMA_COMMAND)
+ return;
+
+ /* high bit triggers action */
+ command = dma_register[DMA_COMMAND];
+ cpunum_set_input_line(0, 0, CLEAR_LINE);
+ if (!(command & 0x8000))
+ return;
+
+#if LOG_DMA
+ if (input_code_pressed(KEYCODE_L))
+ {
+ logerror("----\n");
+ logerror("DMA command %04X: (xflip=%d yflip=%d)\n",
+ command, (command >> 4) & 1, (command >> 5) & 1);
+ logerror(" offset=%08X pos=(%d,%d) w=%d h=%d rb=%d\n",
+ dma_register[DMA_OFFSETLO] | (dma_register[DMA_OFFSETHI] << 16),
+ (INT16)dma_register[DMA_XSTART], (INT16)dma_register[DMA_YSTART],
+ dma_register[DMA_WIDTH], dma_register[DMA_HEIGHT], (INT16)dma_register[DMA_ROWBYTES]);
+ logerror(" palette=%04X color=%04X\n",
+ dma_register[DMA_PALETTE], dma_register[DMA_COLOR]);
+ }
+#endif
+
+ profiler_mark(PROFILER_USER1);
+
+ /* fill in the basic data */
+ dma_state.rowbytes = (INT16)dma_register[DMA_ROWBYTES];
+ dma_state.xpos = (INT16)dma_register[DMA_XSTART];
+ dma_state.ypos = (INT16)dma_register[DMA_YSTART];
+ dma_state.width = dma_register[DMA_WIDTH];
+ dma_state.height = dma_register[DMA_HEIGHT];
+ dma_state.palette = dma_register[DMA_PALETTE] << 8;
+ dma_state.color = dma_register[DMA_COLOR] & 0xff;
+
+ /* determine the offset and adjust the rowbytes */
+ gfxoffset = dma_register[DMA_OFFSETLO] | (dma_register[DMA_OFFSETHI] << 16);
+ if (command & 0x10)
+ {
+ if (!yawdim_dma)
+ {
+ gfxoffset -= (dma_state.width - 1) * 8;
+ dma_state.rowbytes = (dma_state.rowbytes - dma_state.width + 3) & ~3;
+ }
+ else
+ dma_state.rowbytes = (dma_state.rowbytes + dma_state.width + 3) & ~3;
+ dma_state.xpos += dma_state.width - 1;
+ }
+ else
+ dma_state.rowbytes = (dma_state.rowbytes + dma_state.width + 3) & ~3;
+
+ /* apply Y clipping */
+ if (dma_state.ypos < 0)
+ {
+ dma_state.height -= -dma_state.ypos;
+ dma_state.offset += (-dma_state.ypos * dma_state.rowbytes) << 3;
+ dma_state.ypos = 0;
+ }
+ if (dma_state.ypos + dma_state.height > 512)
+ dma_state.height = 512 - dma_state.ypos;
+
+ /* apply X clipping */
+ if (!(command & 0x10))
+ {
+ if (dma_state.xpos < 0)
+ {
+ dma_state.width -= -dma_state.xpos;
+ dma_state.offset += -dma_state.xpos << 3;
+ dma_state.xpos = 0;
+ }
+ if (dma_state.xpos + dma_state.width > 512)
+ dma_state.width = 512 - dma_state.xpos;
+ }
+ else
+ {
+ if (dma_state.xpos >= 512)
+ {
+ dma_state.width -= dma_state.xpos - 511;
+ dma_state.offset += (dma_state.xpos - 511) << 3;
+ dma_state.xpos = 511;
+ }
+ if (dma_state.xpos - dma_state.width < 0)
+ dma_state.width = dma_state.xpos;
+ }
+
+ /* special case: drawing mode C doesn't need to know about any pixel data */
+ /* shimpact relies on this behavior */
+ if ((command & 0x0f) == 0x0c)
+ gfxoffset = 0;
+
+ /* determine the location and draw */
+ if (gfxoffset < 0x02000000)
+ gfxoffset += 0x02000000;
+ if (gfxoffset < 0x06000000)
+ {
+ dma_state.offset = gfxoffset - 0x02000000;
+ (*dma_draw[command & 0x1f])();
+ }
+
+ /* signal we're done */
+ timer_set(ATTOTIME_IN_NSEC(41 * dma_state.width * dma_state.height), 0, dma_callback);
+
+ profiler_mark(PROFILER_END);
+}
+
+
+
+/*************************************
+ *
+ * Core refresh routine
+ *
+ *************************************/
+
+static TIMER_CALLBACK( autoerase_line )
+{
+ int scanline = param;
+
+ if (autoerase_enable && scanline >= 0 && scanline < 510)
+ memcpy(&local_videoram[512 * scanline], &local_videoram[512 * (510 + (scanline & 1))], 512 * sizeof(UINT16));
+}
+
+
+void midyunit_scanline_update(running_machine *machine, int screen, mame_bitmap *bitmap, int scanline, const tms34010_display_params *params)
+{
+ UINT16 *src = &local_videoram[(params->rowaddr << 9) & 0x3fe00];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0);
+ int coladdr = params->coladdr << 1;
+ int x;
+
+ /* adjust the display address to account for ignored bits */
+ for (x = params->heblnk; x < params->hsblnk; x++)
+ dest[x] = pen_map[src[coladdr++ & 0x1ff]];
+
+ /* handle autoerase on the previous line */
+ autoerase_line(machine, params->rowaddr - 1);
+
+ /* if this is the last update of the screen, set a timer to clear out the final line */
+ /* (since we update one behind) */
+ if (scanline == machine->screen[0].visarea.max_y)
+ timer_set(video_screen_get_time_until_pos(0, scanline + 1, 0), params->rowaddr, autoerase_line);
+}
diff --git a/src/mame/video/midzeus.c b/src/mame/video/midzeus.c
new file mode 100644
index 00000000000..ce44dda519e
--- /dev/null
+++ b/src/mame/video/midzeus.c
@@ -0,0 +1,1157 @@
+/*************************************************************************
+
+ Driver for Midway Zeus games
+
+**************************************************************************/
+
+#include "driver.h"
+#include "eminline.h"
+#include "includes/midzeus.h"
+#include "video/poly.h"
+
+
+
+/*************************************
+ *
+ * Constants
+ *
+ *************************************/
+
+#define WAVERAM_WIDTH 512
+#define WAVERAM_HEIGHT 4096
+
+
+
+/*************************************
+ *
+ * Type definitions
+ *
+ *************************************/
+
+typedef struct _poly_extra_data poly_extra_data;
+struct _poly_extra_data
+{
+ const UINT32 * palbase;
+ const UINT32 * texbase;
+ UINT16 transcolor;
+ UINT16 texwidth;
+ UINT16 color;
+ UINT32 alpha;
+};
+
+
+
+/*************************************
+ *
+ * Global variables
+ *
+ *************************************/
+
+UINT32 *zeusbase;
+
+static poly_manager *poly;
+
+static UINT32 zeuscmd_buffer[8];
+static UINT8 zeuscmd_buffer_words;
+static UINT8 zeuscmd_buffer_expected_words;
+static INT16 zeus_matrix[3][3];
+static INT32 zeus_point[3];
+static UINT32 *zeus_palbase;
+static int zeus_enable_logging;
+static UINT32 zeus_blend;
+static UINT32 zeus_texdata;
+static UINT32 zeus_objdata;
+
+static UINT32 last_tex[1000][2];
+static int last_tex_index;
+
+static UINT32 *waveram;
+
+
+
+/*************************************
+ *
+ * Function prototypes
+ *
+ *************************************/
+
+static void exit_handler(running_machine *machine);
+
+
+
+/*************************************
+ *
+ * Inlines
+ *
+ *************************************/
+
+INLINE UINT32 *waveram_ptr_from_addr(UINT32 addr)
+{
+ return &waveram[((addr & 0x1ff) | ((addr & 0xfff000) >> 3)) * 2];
+}
+
+
+INLINE UINT32 *waveram_pixel_ptr(int bank, int y, int x)
+{
+ return &waveram[bank * (WAVERAM_HEIGHT * WAVERAM_WIDTH) + y * WAVERAM_WIDTH + (x & ~1)];
+}
+
+
+INLINE void waveram_plot(int y, int x, UINT16 color)
+{
+ if (x >= 0 && x < 400 && y >= 0 && y < 256)
+ {
+ UINT32 *ptr = waveram_pixel_ptr(1, y, x);
+ if (x & 1)
+ *ptr = (*ptr & 0x0000ffff) | (color << 16);
+ else
+ *ptr = (*ptr & 0xffff0000) | color;
+ }
+}
+
+
+INLINE void waveram_plot_depth(int y, int x, UINT16 color, UINT16 depth)
+{
+ if (x >= 0 && x < 400 && y >= 0 && y < 256)
+ {
+ UINT32 *ptr = waveram_pixel_ptr(1, y, x);
+ if (x & 1)
+ {
+ ptr[0] = (ptr[0] & 0x0000ffff) | (color << 16);
+ ptr[1] = (ptr[1] & 0x0000ffff) | (depth << 16);
+ }
+ else
+ {
+ ptr[0] = (ptr[0] & 0xffff0000) | color;
+ ptr[1] = (ptr[1] & 0xffff0000) | depth;
+ }
+ }
+}
+
+
+INLINE void waveram_plot_check_depth(int y, int x, UINT16 color, UINT16 depth)
+{
+ if (x >= 0 && x < 400 && y >= 0 && y < 256)
+ {
+ UINT32 *ptr = waveram_pixel_ptr(1, y, x);
+ if (x & 1)
+ {
+ if (depth <= (ptr[1] >> 16))
+ {
+ ptr[0] = (ptr[0] & 0x0000ffff) | (color << 16);
+ ptr[1] = (ptr[1] & 0x0000ffff) | (depth << 16);
+ }
+ }
+ else
+ {
+ if (depth <= (ptr[1] & 0xffff))
+ {
+ ptr[0] = (ptr[0] & 0xffff0000) | color;
+ ptr[1] = (ptr[1] & 0xffff0000) | depth;
+ }
+ }
+ }
+}
+
+
+INLINE UINT32 *zeus_pixaddr(void)
+{
+ int bank = (zeusbase[0xb6] >> 31) & 1;
+ int x = (zeusbase[0xb4] & 0xff) << 1;
+ int y = ((zeusbase[0xb4] >> 15) & 0xffe) | ((zeusbase[0xb4] >> 8) & 0x01);
+ return waveram_pixel_ptr(bank, y, x);
+}
+
+
+INLINE UINT8 get_texel_8bit(const UINT32 *base, int y, int x, int width)
+{
+ if (x >= width)
+ return 0;
+ base += (y / 2) * (width / 2) + (x / 4) * 2 + (y & 1);
+ return *base >> (8 * (x & 3));
+}
+
+
+INLINE UINT8 get_texel_4bit(const UINT32 *base, int y, int x, int width)
+{
+ if (x >= width * 2)
+ return 0;
+ base += (y / 2) * (width / 2) + (x / 8) * 2 + (y & 1);
+ return (*base >> (4 * (x & 7))) & 0x0f;
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( midzeus )
+{
+ int i;
+
+ /* allocate memory for "wave" RAM */
+ waveram = auto_malloc(2 * WAVERAM_WIDTH * WAVERAM_HEIGHT * sizeof(*waveram));
+ state_save_register_global_pointer(waveram, 2 * WAVERAM_WIDTH * WAVERAM_HEIGHT);
+
+ /* initialize a 5-5-5 palette */
+ for (i = 0; i < 32768; i++)
+ palette_set_color_rgb(machine, i, pal5bit(i >> 10), pal5bit(i >> 5), pal5bit(i >> 0));
+
+ /* initialize polygon engine */
+ poly = poly_alloc(1000, sizeof(poly_extra_data), POLYFLAG_ALLOW_QUADS);
+
+ /* we need to cleanup on exit */
+ add_exit_callback(machine, exit_handler);
+}
+
+
+static void exit_handler(running_machine *machine)
+{
+ FILE *f = fopen("waveram.dmp", "w");
+ int i;
+
+ for (i = 0; i < 2 * WAVERAM_WIDTH * WAVERAM_HEIGHT; i += 2)
+ {
+ if (i % 8 == 0) fprintf(f, "%03X%03X: ", (i / 1024), (i / 2) & 0x1ff);
+ fprintf(f, " %08X %08X ", waveram[i+0], waveram[i+1]);
+ if (i % 8 == 6) fprintf(f, "\n");
+ }
+ fclose(f);
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( midzeus )
+{
+ int x, y;
+
+ /* normal update case */
+ if (!input_code_pressed(KEYCODE_W))
+ {
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT32 *src = waveram_pixel_ptr(1, y, 0);
+ UINT16 *dest = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+ for (x = cliprect->min_x; x <= cliprect->max_x; x += 2)
+ {
+ UINT32 pixels = *src;
+ dest[x+0] = pixels & 0x7fff;
+ dest[x+1] = (pixels >> 16) & 0x7fff;
+ src += 2;
+ }
+ }
+ }
+
+ /* waveram drawing case */
+ else
+ {
+ static int yoffs = 0;
+ static int width = 256;
+ UINT32 *base;
+
+ if (input_code_pressed(KEYCODE_DOWN)) yoffs += input_code_pressed(KEYCODE_LSHIFT) ? 0x40 : 1;
+ if (input_code_pressed(KEYCODE_UP)) yoffs -= input_code_pressed(KEYCODE_LSHIFT) ? 0x40 : 1;
+ if (input_code_pressed(KEYCODE_LEFT) && width > 4) { width >>= 1; while (input_code_pressed(KEYCODE_LEFT)) ; }
+ if (input_code_pressed(KEYCODE_RIGHT) && width < 512) { width <<= 1; while (input_code_pressed(KEYCODE_RIGHT)) ; }
+
+ if (yoffs < 0) yoffs = 0;
+ base = waveram_ptr_from_addr(yoffs << 12);
+
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *dest = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ UINT8 tex = get_texel_8bit(base, y, x, width);
+ dest[x] = (tex << 8) | tex;
+ }
+ }
+ popmessage("offs = %06X", yoffs << 12);
+ }
+
+ if (input_code_pressed(KEYCODE_T) && last_tex_index != 0)
+ {
+ int i;
+ printf("----\n");
+ for (i = 0; i < last_tex_index; i++)
+ printf("%06X %03X (w=%d)\n", last_tex[i][0], last_tex[i][1], 512 >> ((last_tex[i][1] >> 6) & 7));
+ last_tex_index = 0;
+ }
+
+ return 0;
+}
+
+
+
+/*
+
+ New analysis:
+
+ Offset
+ ------
+
+ $58 W Usually written after $5A; after writing, waits for $F6 bit 4 to be cleared
+
+ $5A W Usually written first, followed by $58
+
+ $68 W Written at startup:
+ $00030000 = toggled on then off at startup
+
+ $76 W
+
+ $7C W
+
+ $80 W Master control
+
+ $40000000 = set along with $02000000 when enabling FIFO empty interrupt
+ $02000000 = enable internal data FIFO empty interrupt
+ $01000000 = cleared along with $02000000 when disabling FIFO empty interrupt
+ $00020000 = 16-bit (0) or 32-bit (1) mode
+ $00000008 = cleared just before writing to offsets $200-$3FF
+
+ $82 W
+ $84 W
+ $86 W
+ $88 W
+ $8A W
+ $8C W
+ $8E W
+
+ $B0 R/W Data port for direct RAM access
+ $B2 R/W Data port for direct RAM access
+
+ $B4 W Address for direct RAM access
+
+ $07FF0100 = mask for Y coordinate
+ $000000FF = mask for X coordinate
+
+ $B6 W Direct RAM access control
+
+ $80000000 = enable writes to wave RAM 0
+ $40000000 = enable writes to wave RAM 1
+ $02000000 = perform access on write to B0(0) or B2(1) ?????
+ $00800000 = enable writes from [$B2] to depth buffer
+ $00400000 = enable writes from [$B0] to depth buffer
+ $00200000 = enable writes from [$B2] to RAM buffer
+ $00100000 = enable writes from [$B0] to RAM buffer
+ $00020000 = auto increment the address
+ $00010000 = perform a read when the address is written
+ $00000001 = enable direct RAM access
+
+ Examples:
+ $80A00000 when writing a single pixel (address written each time)
+ $80A20001 when writing the right pixel of a pair (autoinc assumed)
+ $80F60001 when writing the middle pairs of pixels (autoinc assumed)
+ $80520001 when writing the left pixel of a pair (autoinc assumed)
+ $82F00001 when testing wave RAM page 1 (address written each pair)
+ $42F00001 when testing wave RAM page 0 (address written each pair)
+ $82F60001 when uploading to wave RAM page 1 (autoinc assumed)
+ $42F60001 when uploading to wave RAM page 0 (autoinc assumed)
+
+ $C0 W Written at startup = $801F2500
+ $C2 W Written at startup = $0015E591
+ $C4 W Written at startup = $000C0042 (HSYNC start/HSYNC end?)
+ $C6 W Written at startup = $0211007F (HTOTAL/HBLANK end?)
+ $C8 W Written at startup = $010300FF (VSYNC start/VBLANK start?)
+ $CA W Written at startup = $01160107 (VTOTAL/VSYNC end?)
+ $CC W Written at startup = $00000000
+ $CE W Written at startup = $00C87620
+
+ $E0 W Internal data FIFO
+
+ $F2 R Looped on until it returns a stable value; must change frequently; PRNG?
+
+ $F4 R Status register
+
+ $00000800 = VBLANK? code waits for it to clear to 0 and then reset to 1
+ $00000140 = tested together in tight loop until both are 0
+ $00000008 = internal data FIFO full
+ $00000004 = tested in tight loop along with $00000002 until at least one is set
+ $00000002 = tested in tight loop after handling FIFO interrupt until set
+
+ $F6 R Status register 2
+
+ $00000010 = tested in tight loop after writing 5A/59/58 until set to 0
+
+ $200- W Unknown, but written in a loop with master control bit $00000008 cleared
+ $3FF Possible fast buffer clear? One set of writes stores $7F7F to all entries.
+ A second set writes $E00,$25,$E01,$25,...,$E7F,$25. A third set writes
+ $52,$A0000000,...
+
+Notes:
+
+ In 16-bit mode, writes to $E0 are done via $E1 first then $E0
+
+-------------------------------------------------------
+
+Old info:
+
+ offset B7 = control....
+
+ 8000 = page 1 enable
+ 4000 = page 0 enable
+
+ 0080 = 2nd pixel enable (maybe Z buff?)
+ 0040 = 1st pixel enable (maybe Z buff?)
+ 0020 = 2nd pixel enable
+ 0010 = 1st pixel enable
+
+
+ writes 80a2 to write an odd pixel at startup
+ writes 80f6 to write the middle pixels
+ writes 8052 to write an odd pixel at the end
+
+ writes 8050 before writing an odd pixel
+ writes 80a0 before writing an even pixel
+
+ writes 44f1 before reading from page 0 of wave ram
+ writes 84f1 before reading from page 1 of wave ram
+
+ writes 42f0 before writing to page 0 of wave ram
+ writes 82f0 before writing to page 1 of wave ram
+
+*/
+
+/*
+ zeus data notes:
+
+ Data from $1000-1A20
+ Palettes at $2000,$2200,$2400
+ Data from $2600-27C7
+ Palettes at $27C8,$29C8,$2BC8,$2DC8
+ Palettes up through $5A000
+
+ Interesting data at $5A000-5BFFF
+
+ Common sequence:
+ $8000 xxxx $0C01 $3805
+ x = matches address of next data * 8
+*/
+
+
+
+/*
+ Control = $80F6 when doing initial screen clear.
+ Writes 256 consecutive values to $B0, must mean autoincrement
+ Uses latched value in $B2 (maybe also in $B0)
+
+ Control = $82F0 when doing video RAM test write phase.
+ Writes 512 values across, but updates address before each one.
+
+ Control = $84F1 when doing video RAM test read phase.
+ Reads 512 values across, but updates address before each one.
+
+ Control = $80F2 when doing screen clear.
+ Writes 256 consecutive values to $B0, must mean autoincrement.
+ Uses latched value in $B2 (maybe also in $B0)
+
+ Control = $80A0/$8050 when plotting pixels.
+
+ Control = $42F0 when doing wave RAM test write phase.
+ Writes 512 values across, but updates address before each one.
+
+ Control = $44F1 when doing wave RAM test read phase.
+ Reads 512 values across, but updates address before each one.
+*/
+
+
+/*
+
+ Known commands:
+
+ $00rrxxxx = another type of register set?
+ yyyyyyyy
+
+ $0000C040 = set palette to 'yyyyyyyy'
+
+ $17rrxxxx = 16-bit write 'xxxx' to register 'rr'
+
+ $1752xxxx = write 'xxxx' to something that reflects back through $B2
+ $1770xxxx = write 'xxxx' to upper 16 bits of X coordinate
+ $1772xxxx = write 'xxxx' to upper 16 bits of Y coordinate
+ $1774xxxx = write 'xxxx' to upper 16 bits of Z coordinate
+
+ $18rr0000 = 32-bit write 'xxxxxxxx' to register 'rr'
+ xxxxxxxx
+
+ $1A000000 = pipeline synchronize (guess)
+
+ $1C00cccc = load matrix (abc)(def)(ghi) and point (xyz)
+ ffffiiii
+ bbbbaaaa
+ eeeedddd
+ hhhhgggg
+ xxxxxxxx
+ yyyyyyyy
+ zzzzzzzz
+
+ $6700xxxx = render object described at 'bbbbbb' in waveram
+ aabbbbbb
+ ccddcccc
+*/
+
+/*
+Zeus cmd 18 : 18D60000 500A00FF
+Zeus cmd 00 : 0005C0A5 21001125
+Zeus cmd 25 : 25000000 007F0018 01000400 B0F60008
+Zeus cmd 18 : 18D60000 500A00FF
+Zeus cmd 18 : 18CE0000 00FFFFFF
+Zeus cmd 1A : 1A000000
+Zeus cmd 18 : 187E0000 0000FFFF
+Zeus cmd 1A : 1A000000
+Zeus cmd 18 : 18CE0000 00FFFFFF
+Zeus cmd 1A : 1A000000
+Zeus cmd 18 : 187E0000 FF980000
+Zeus cmd 00 : 0080C0A5 3F00102F
+Zeus cmd 17 : 17681370
+Zeus cmd 17 : 176940C4
+Zeus cmd 1C : ( 4000 0000 0000 ) ( 0000 4000 0000 ) ( 0000 0000 4000 ) -152.00 -50.00 1.25000
+Zeus cmd 00 : 0000C040 0318E132 -> palette @ (18E,132)
+Zeus cmd 67 : 67008000 0919F1C4 151 01FA4C -> render @ (19F,1C4)
+Zeus cmd 1C : ( 4000 0000 0000 ) ( 0000 4000 0000 ) ( 0000 0000 4000 ) -135.00 -50.00 1.25000
+Zeus cmd 67 : 67008000 0919F1C4 151 01FA4C
+Zeus cmd 1C : ( 4000 0000 0000 ) ( 0000 4000 0000 ) ( 0000 0000 4000 ) -118.00 -50.00 1.25000
+Zeus cmd 67 : 67008000 0919F1C4 151 01F988
+Zeus cmd 1C : ( 4000 0000 0000 ) ( 0000 4000 0000 ) ( 0000 0000 4000 ) -101.00 -50.00 1.25000
+
+19F1BA: 19DC0000 00000000 19840000 00F01605 25810000 21010000 FFD00000 00000000 FFD00038 000E0000 00080038 0E0E0000 00080000 0E000000 30000000 30000000 30000000 30000000 08000000 00000000
+19F1C4: 19DC0000 00000000 19840000 00F01605 25800000 21010000 FFD0FFFC 00000000 FFD0003C 00100000 0008003C 0E100000 0008FFFC 0E000000 30000000 30000000 30000000 30000000 08000000 00000000
+19F1CE: 19DC0000 00000000 19840000 00F01605 25800000 21010000 FFD0FFFC 00000000 FFD00028 000B0000 00080028 0E0B0000 0008FFFC 0E000000 30000000 30000000 30000000 30000000 08000000 00000000
+19F1D8: 19DC0000 00000000 19840000 00F01605 25800000 21010000 FFD00000 00000000 FFD00034 000D0000 00080034 0E0D0000 00080000 0E000000 30000000 30000000 30000000 30000000 08000000 00000000
+19F1E2: 19DC0000 00000000 19840000 00F01605 25800000 21010000 FFD00000 00000000 FFD00028 000A0000 000C0028 0F0A0000 000C0000 0F000000 30000000 30000000 30000000 30000000 08000000 00000000
+19F1EC: 19DC0000 00000000 19840000 00F01605 25800000 21010000 FFD00000 00000000 FFD00014 00050000 00080014 0E050000 00080000 0E000000 30000000 30000000 30000000 30000000 08000000 00000000
+19F1F6: 19DC0000 00000000 19840000 00F01605 25810000 21010000 FFD0FFFC 00000000 FFD00034 000E0000 00080034 0E0E0000 0008FFFC 0E000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A0000: 19DC0000 00000000 19840000 00F01605 25800000 21010000 FFCC0000 00000000 FFCC0038 000E0000 000C0038 100E0000 000C0000 10000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A000A: 19DC0000 00000000 19840000 00F01605 25800000 21010000 FFCC0000 00000000 FFCC0034 000D0000 000C0034 100D0000 000C0000 10000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A0014: 19DC0000 00000000 19840000 00F01605 25800000 21010000 FFCC0000 00000000 FFCC002C 000B0000 0008002C 0F0B0000 00080000 0F000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A001E: 19DC0000 00000000 19840000 00F01605 25800000 21010000 FFCC0000 00000000 FFCC002C 000B0000 000C002C 100B0000 000C0000 10000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A0028: 19DC0000 00000000 19840000 00F01605 25800000 21010000 FFD00000 00000000 FFD0002C 000B0000 000C002C 0F0B0000 000C0000 0F000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A0032: 19DC0000 00000000 19840000 00F01605 25800000 21010000 FFD00000 00000000 FFD00018 00060000 00080018 0E060000 00080000 0E000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A003C: 19DC0000 40B68800 19840000 00001604 25800000 21010000 FF9CFF64 00000000 FF9C0084 00480000 005C0084 30480000 005CFF64 30000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A0046: 19DC0000 40B68800 19840000 00001604 25800000 21010000 FF80FF48 00000000 FF80009C 00550000 0070009C 3C550000 0070FF48 3C000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A0050: 19DC0000 40B68800 19840000 00001604 25800000 21010000 FF68FF30 00000000 FF6800B0 00600000 008800B0 48600000 0088FF30 48000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A005A: 19DC0000 40B68800 19840000 00001604 25800000 21010000 FF54FF20 00000000 FF5400C4 00690000 00A000C4 53690000 00A0FF20 53000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A0064: 19DC0000 40B68800 19840000 00001604 25800000 21010000 FF44FF10 00000000 FF4400D4 00710000 00B000D4 5B710000 00B0FF10 5B000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A006E: 19DC0000 40B68800 19840000 00001604 25800000 21010000 FF3CFF08 00000000 FF3C00E4 00770000 00B400E4 5E770000 00B4FF08 5E000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A0078: 19DC0000 40B68800 19840000 00001604 25800000 21010000 FF38FEFC 00000000 FF3800E4 007A0000 00C000E4 627A0000 00C0FEFC 62000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A0082: 19DC0000 40B68800 19840000 00001604 25800000 21010000 FF28FEFC 00000000 FF2800EC 007C0000 00C000EC 667C0000 00C0FEFC 66000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A008C: 19DC0000 40B68800 19840000 00001604 25800000 21010000 FF60FF28 00000000 FF6000C0 00660000 009C00C0 4F660000 009CFF28 4F000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A0096: 19DC0000 40B68800 19840000 00001604 25800000 21010000 FF80FF48 00000000 FF80009C 00550000 0078009C 3E550000 0078FF48 3E000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A00A0: 19DC0000 40B68800 19840000 00001604 25800000 21010000 FF94FF5C 00000000 FF940088 004B0000 00640088 344B0000 0064FF5C 34000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A00AA: 19DC0000 40B68800 19840000 00001604 25810000 21010000 FFA4FF6C 00000000 FFA4007C 00440000 0054007C 2C440000 0054FF6C 2C000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A00B4: 19DC0000 40B68800 19840000 00001604 25800000 21010000 FFACFF78 00000000 FFAC0070 003E0000 00480070 273E0000 0048FF78 27000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A00BE: 19DC0000 40B68800 19840000 00001604 25800000 21010000 FFB4FF7C 00000000 FFB4006C 003C0000 0044006C 243C0000 0044FF7C 24000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A00C8: 19DC0000 00000000 19840000 00001605 25800000 21000000 FF42FF02 00000000 FF4200FE 007F0000 00BE00FE 5F7F0000 00BEFF02 5F000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A00D2: 19DC0000 00000000 19840000 00001605 25800000 21010000 FFB0FF70 00000000 FFB0007C 00430000 0054007C 29430000 0054FF70 29000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A00DC: 19DC0000 40B68800 19840000 00001604 25800000 21010000 FA10F810 00000000 FA1007F0 007F0000 05F007F0 5F7F0000 05F0F810 5F000000 30000000 30000000 30000000 30000000 08000000 00000000
+1A00E6: 0C02C0F0 0F18E1BE
+ 19DC0000 4B23CB00 19840000 00001605 252978EF 200C0000 04480000 00000000 043D0000 0000001E 043DFFEB 00000015 043DFFEB 00000015 00040000 0A331400 0743178C 0743178C
+1A00F0: 251178D7 200C0000 04480000 00000000 043DFFEB 00000015 043DFFE2 00000000 043DFFE2 00000000 00040000 0743178C 0003175D 0003175D
+ 25EF78D7 200C0000 04480000 00000000 043DFFE2 00000000 043DFFEB 0000FFEB 043DFFEB 0000FFEB 00040000 0003175D 38C3178C 38C3178C
+ 25D778EF 200C0000 04480000 00000000 043DFFEB 0000FFEB 043D0000 0000FFE2 043D0000 0000FFE2 00040000 38C3178C 35D31400 35D31400
+ 25D77811 200C0000 04480000 00000000 043D0000 0000FFE2 043D0015 0000FFEB 043D0015 0000FFEB 00040000 35D31400 38C31474 38C31474
+1A010C: 25EF7829 200C0000 04480000 00000000 043D0015 0000FFEB 043D001E 00000000 043D001E 00000000 00040000 38C31474 000314A3 000314A3
+ 25117829 200C0000 04480000 00000000 043D001E 00000000 043D0015 00000015 043D0015 00000015 00040000 000314A3 07431474 07431474
+ 25297811 200C0000 04480000 00000000 043D0015 00000015 043D0000 0000001E 043D0000 0000001E 00040000 07431474 0A331400 0A331400
+ 0C018000 381A0122
+ 252186F3 200C0000 F64A0000 00000000 F652FFEB 00000015 F6520000 0000001E F6520000 0000001E 000C0000 06ECD393 09ACD3FF 09ACD3FF
+ 250D86DF 200C0000 F64A0000 00000000 F652FFE2 00000000 F652FFEB 00000015 F652FFEB 00000015 000C0000 001CD366 06DCD392 06DCD392
+1A0130: 25F386DF 200C0000 F64A0000 00000000 F652FFEB 0000FFEB F652FFE2 00000000 F652FFE2 00000000 000C0000 393CD392 3FFCD366 3FFCD366
+ 25DF86F3 200C0000 F64A0000 00000000 F6520000 0000FFE2 F652FFEB 0000FFEB F652FFEB 0000FFEB 000C0000 366CD3FF 392CD393 392CD393
+ 25DF860D 200C0000 F64A0000 00000000 F6520015 0000FFEB F6520000 0000FFE2 F6520000 0000FFE2 000C0000 392CD06D 366CD001 366CD001
+ 25F38621 200C0000 F64A0000 00000000 F652001E 00000000 F6520015 0000FFEB F6520015 0000FFEB 000C0000 3FFCD09A 393CD06E 393CD06E
+1A014C: 250D8621 200C0000 F64A0000 00000000 F6520015 00000015 F652001E 00000000 F652001E 00000000 000C0000 06DCD06E 001CD09A 001CD09A
+ 2521860D 200C0000 F6520000 0000001E F6520015 00000015 F64A0000 00000000 F64A0000 00000000 09ACD001 06ECD06D 000C0000 000C0000
+ 0C018000 381A015B
+ 25D53969 200C0000 0429001D 0000FFE3 04290029 00000000 043D001E 00000000 043D0015 0000FFEB 356110B3 3FA110F7 3EB2D8B3 3902D88D
+ 252B3969 200C0000 04290029 00000000 0429001D 0000001D 043D0015 00000015 043D001E 00000000 006110F7 0AA110B3 0702D88D 0152D8B3
+ 2569392B 200C0000 0429001D 0000001D 04290000 00000029 043D0000 0000001E 043D0015 00000015 0B3110AA 0F711006 0B32D815 08D2D870
+1A0170: 256939D5 200C0000 04290000 00000029 0429FFE3 0000001D 043DFFEB 00000015 043D0000 0000001E 0F7113FA 0B311356 08D2DB90 0B32DBEB
+ 252B3997 200C0000 0429FFE3 0000001D 0429FFD7 00000000 043DFFE2 00000000 043DFFEB 00000015 0AA1134D 00611309 0152DB4D 0702DB73
+ 25D53997 200C0000 0429FFD7 00000000 0429FFE3 0000FFE3 043DFFEB 0000FFEB 043DFFE2 00000000 3FA11309 3561134D 3902DB73 3EB2DB4D
+ 259739D5 200C0000 0429FFE3 0000FFE3 04290000 0000FFD7 043D0000 0000FFE2 043DFFEB 0000FFEB 34D11356 309113FA 34D2DBEB 3732DB90
+1A018C: 2597392B 200C0000 04290000 0000FFD7 0429001D 0000FFE3 043D0015 0000FFEB 043D0000 0000FFE2 30911006 34D110AA 3732D870 34D2D815
+ 0C018000 381A0194
+1A0194: 252BC769 200C0000 F666001D 0000001D F6660029 00000000 F652001E 00000000 F6520015 00000015 0AAEF0B3 006EF0F7 018D20B0 06CD208D
+ 25D5C769 200C0000 F6660029 00000000 F666001D 0000FFE3 F6520015 0000FFEB F652001E 00000000 3FAEF0F7 356EF0B3 394D208D 3E8D20B0
+ 2597C72B 200C0000 F666001D 0000FFE3 F6660000 0000FFD7 F6520000 0000FFE2 F6520015 0000FFEB 34DEF0AA 309EF006 350D2018 373D206C
+ 2597C7D5 200C0000 F6660000 0000FFD7 F666FFE3 0000FFE3 F652FFEB 0000FFEB F6520000 0000FFE2 309EF3FA 34DEF356 373D2394 350D23E8
+1A01B0: 25D5C797 200C0000 F666FFE3 0000FFE3 F666FFD7 00000000 F652FFE2 00000000 F652FFEB 0000FFEB 356EF34D 3FAEF309 3E8D2350 394D2373
+ 252BC797 200C0000 F666FFD7 00000000 F666FFE3 0000001D F652FFEB 00000015 F652FFE2 00000000 006EF309 0AAEF34D 06CD2373 018D2350
+ 2569C7D5 200C0000 F666FFE3 0000001D F6660000 00000029 F6520000 0000001E F652FFEB 00000015 0B3EF356 0F7EF3FA 0B0D23E8 08DD2394
+ 2569C72B 200C0000 F6660000 00000029 F666001D 0000001D F6520015 00000015 F6520000 0000001E 0F7EF006 0B3EF0AA 08DD206C 0B0D2018
+1A01CC: 0C018000 311A01CD
+ 25300076 200C0000 F6660029 00000000 F666001D 0000001D 0429001D 0000001D 04290029 00000000 00FF24FA 0A6F24BB 0A60DCBB 00F0DCFA
+1A01D4: 25760030 200C0000 F666001D 0000001D F6660000 00000029 04290000 00000029 0429001D 0000001D 0BBF24A6 0FAF240F 0FA0DC0F 0BB0DCA6
+ 257600D0 200C0000 F6660000 00000029 F666FFE3 0000001D 0429FFE3 0000001D 04290000 00000029 0FAF27F1 0BBF275A 0BB0DF5A 0FA0DFF1
+ 2530008A 200C0000 F666FFE3 0000001D F666FFD7 00000000 0429FFD7 00000000 0429FFE3 0000001D 0A6F2745 00FF2706 00F0DF06 0A60DF45
+ 25D0008A 200C0000 F666FFD7 00000000 F666FFE3 0000FFE3 0429FFE3 0000FFE3 0429FFD7 00000000 3F1F2706 35AF2745 35A0DF45 3F10DF06
+1A01F0: 258A00D0 200C0000 F666FFE3 0000FFE3 F6660000 0000FFD7 04290000 0000FFD7 0429FFE3 0000FFE3 345F275A 306F27F1 3060DFF1 3450DF5A
+ 258A0030 200C0000 F6660000 0000FFD7 F666001D 0000FFE3 0429001D 0000FFE3 04290000 0000FFD7 306F240F 345F24A6 3450DCA6 3060DC0F
+ 0C018000 071A1000 00000000 00000000
+1A1000: 25D00076 200C0000 F666001D 0000FFE3 F6660029 00000000 04290029 00000000 0429001D 0000FFE3 35AF24BB 3F1F24FA 3F10DCFA 35A0DCBB
+ 08000000 00000000
+*/
+
+
+static void render_poly_4bit(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ float ooz = extent->param[0].start;
+ float uoz = extent->param[1].start;
+ float voz = extent->param[2].start;
+ float doozdx = extent->param[0].dpdx;
+ float duozdx = extent->param[1].dpdx;
+ float dvozdx = extent->param[2].dpdx;
+ const UINT32 *texbase = extra->texbase;
+ const UINT32 *palbase = extra->palbase;
+ UINT16 transcolor = extra->transcolor;
+ int texwidth = extra->texwidth;
+ int x;
+
+ for (x = extent->startx; x < extent->stopx; x++)
+ {
+ float z = recip_approx(ooz);
+ int u = (int)(uoz * z) & ((texwidth * 2) - 1);
+ int v = (int)(voz * z) & 255;
+ UINT8 texel = get_texel_4bit(texbase, v, u, texwidth);
+ if (texel != transcolor)
+ {
+ UINT16 color = palbase[texel >> 1] >> (16 * (texel & 1));
+ INT32 depth = z * 256.0f;
+ if (depth > 0x7fff) depth = 0x7fff;
+ if (depth >= 0)
+ waveram_plot_check_depth(scanline, x, color, depth);
+ }
+
+ ooz += doozdx;
+ uoz += duozdx;
+ voz += dvozdx;
+ }
+}
+
+
+static void render_poly_8bit(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ float ooz = extent->param[0].start;
+ float uoz = extent->param[1].start;
+ float voz = extent->param[2].start;
+ float doozdx = extent->param[0].dpdx;
+ float duozdx = extent->param[1].dpdx;
+ float dvozdx = extent->param[2].dpdx;
+ const UINT32 *texbase = extra->texbase;
+ const UINT32 *palbase = extra->palbase;
+ UINT16 transcolor = extra->transcolor;
+ int texwidth = extra->texwidth;
+ int x;
+
+ for (x = extent->startx; x < extent->stopx; x++)
+ {
+ float z = recip_approx(ooz);
+ int u = (int)(uoz * z) & (texwidth - 1);
+ int v = (int)(voz * z) & 255;
+ UINT8 texel = get_texel_8bit(texbase, v, u, texwidth);
+ if (texel != transcolor)
+ {
+ UINT16 color = palbase[texel >> 1] >> (16 * (texel & 1));
+ INT32 depth = z * 256.0f;
+ if (depth > 0x7fff) depth = 0x7fff;
+ if (depth >= 0)
+ waveram_plot_check_depth(scanline, x, color, depth);
+ }
+
+ ooz += doozdx;
+ uoz += duozdx;
+ voz += dvozdx;
+ }
+}
+
+
+static void zeus_draw_polys(UINT32 addr_and_count, UINT32 texdata, int logcmd)
+{
+ static UINT32 *loglist[1000];
+ static int loglist_last = 0;
+ UINT32 *data = waveram_ptr_from_addr(addr_and_count);
+ UINT32 val1, val2;
+ int i, logit = FALSE;
+ int texwshift;
+ int testbit = 0;
+
+ val1 = ((texdata >> 10) & 0x3f0000) | (texdata & 0xffff);
+ val2 = (texdata >> 16) & 0x3ff;
+ texwshift = (val2 >> 6) & 7;
+
+ if (logcmd)
+ {
+ int texwshift = (val2 >> 6) & 7;
+ logerror("Zeus cmd 67 : %08X %08X %03X %06X (w=%d adj=%03X%03X)\n",
+ zeuscmd_buffer[0], addr_and_count, val2, val1,
+ 512 >> texwshift,
+ ((val1 << (7 - texwshift)) >> 10) & 0xfff,
+ ((val1 << (7 - texwshift)) >> 1) & 0x1ff
+ );
+ }
+
+ for (i = 0; i < last_tex_index; i++)
+ if (last_tex[i][0] == val1 && last_tex[i][1] == val2)
+ break;
+ if (i == last_tex_index)
+ {
+ last_tex[i][0] = val1;
+ last_tex[i][1] = val2;
+ last_tex_index++;
+ }
+
+ if (logcmd)
+ {
+ for (i = 0; i < loglist_last; i++)
+ if (loglist[i] == data)
+ break;
+ logit = (i == loglist_last);
+ if (i == loglist_last)
+ loglist[loglist_last++] = data;
+ }
+
+ if (input_code_pressed(KEYCODE_Z)) testbit = 1;
+ if (input_code_pressed(KEYCODE_X)) testbit = 2;
+ if (input_code_pressed(KEYCODE_C)) testbit = 3;
+ if (input_code_pressed(KEYCODE_V)) testbit = 4;
+ if (input_code_pressed(KEYCODE_B)) testbit = 5;
+ if (input_code_pressed(KEYCODE_N)) testbit = 6;
+ if (input_code_pressed(KEYCODE_M)) testbit = 7;
+
+ if (testbit != 0)
+ texwshift = testbit;
+
+ while (1)
+ {
+ const UINT32 *data = waveram_ptr_from_addr(addr_and_count);
+ int count = ((addr_and_count >> 24) + 1) * 2;
+ UINT32 next_addr_and_count = 0;
+ int datanum;
+ int length;
+
+ for (datanum = 0; datanum < count; datanum += length * 2)
+ {
+ int offs;
+
+ length = ((data[datanum] >> 24) == 0x25 || (data[datanum] >> 24) == 0x30) ? 7 : 1;
+
+ if (logit)
+ {
+ logerror("\t%08X", data[datanum]);
+ for (offs = 1; offs < length * 2; offs++)
+ logerror(" %08X", data[datanum + offs]);
+ logerror("\n");
+ }
+
+ if ((data[datanum] >> 24) == 0x25 || (data[datanum] >> 24) == 0x30 /* invasn */)
+ {
+ poly_draw_scanline callback;
+ poly_extra_data *extra;
+ poly_vertex vert[4];
+ int i;
+
+ callback = (val2 & 0x20) ? render_poly_8bit : render_poly_4bit;
+
+ for (i = 0; i < 4; i++)
+ {
+ UINT32 ixy = data[datanum + 2 + 2*i];
+ UINT32 iuvz = data[datanum + 3 + 2*i];
+ INT32 xo = (INT16)ixy;
+ INT32 yo = (INT16)(ixy >> 16);
+ INT32 zo = (INT16)iuvz;
+ UINT8 u = iuvz >> 16;
+ UINT8 v = iuvz >> 24;
+ float z, ooz;
+
+ vert[i].x = (xo * zeus_matrix[0][0] + yo * zeus_matrix[0][1] + zo * zeus_matrix[0][2] + zeus_point[0]) * (1.0f / 65536.0f);
+ vert[i].y = (xo * zeus_matrix[1][0] + yo * zeus_matrix[1][1] + zo * zeus_matrix[1][2] + zeus_point[1]) * (1.0f / 65536.0f);
+ z = (xo * zeus_matrix[2][0] + yo * zeus_matrix[2][1] + zo * zeus_matrix[2][2] + zeus_point[2]) * (1.0f / (512.0f * 65536.0f));
+
+ ooz = 1.0f / z;
+ vert[i].x *= ooz;
+ vert[i].y *= ooz;
+ vert[i].p[0] = ooz;
+ vert[i].p[1] = u * ooz;
+ vert[i].p[2] = v * ooz;
+
+ vert[i].x += 200.0f;
+ vert[i].y += 128.0f;
+ }
+
+ val1 <<= 7 - texwshift;
+
+ extra = poly_get_extra_data(poly);
+ extra->transcolor = 0x100;
+ extra->texbase = &waveram[val1 & 0x3fffff];
+ extra->texwidth = 512 >> texwshift;
+ extra->palbase = zeus_palbase;
+ extra->alpha = zeus_blend;
+ poly_render_quad(poly, NULL, &Machine->screen[0].visarea, callback, 3, &vert[0], &vert[1], &vert[2], &vert[3]);
+
+ poly_wait(poly, "Normal");
+ }
+ else if (data[datanum] == 0x0c018000)
+ next_addr_and_count = data[datanum + 1];
+ }
+ if (datanum != count)
+ logerror("Overran data\n");
+
+ if (next_addr_and_count == 0)
+ break;
+ else
+ addr_and_count = next_addr_and_count;
+ }
+}
+
+
+static void zeuscmd_execute(void)
+{
+ static int colorcount;
+ int logcmd = input_code_pressed(KEYCODE_L);
+ int wordnum;
+
+ switch (zeuscmd_buffer[0] >> 24)
+ {
+ case 0x1c:
+ if (logcmd)
+ logerror("Zeus cmd 1C : ( %04X %04X %04X ) ( %04X %04X %04X ) ( %04X %04X %04X ) %8.2f %8.2f %8.5f\n",
+ zeuscmd_buffer[2] & 0xffff,
+ zeuscmd_buffer[2] >> 16,
+ zeuscmd_buffer[0] & 0xffff,
+ zeuscmd_buffer[3] & 0xffff,
+ zeuscmd_buffer[3] >> 16,
+ zeuscmd_buffer[1] >> 16,
+ zeuscmd_buffer[4] & 0xffff,
+ zeuscmd_buffer[4] >> 16,
+ zeuscmd_buffer[1] & 0xffff,
+ (float)(INT32)zeuscmd_buffer[5] * (1.0f / 65536.0f),
+ (float)(INT32)zeuscmd_buffer[6] * (1.0f / 65536.0f),
+ (float)(INT32)zeuscmd_buffer[7] * (1.0f / (65536.0f * 512.0f)));
+
+ zeus_matrix[0][0] = zeuscmd_buffer[2];
+ zeus_matrix[0][1] = zeuscmd_buffer[2] >> 16;
+ zeus_matrix[0][2] = zeuscmd_buffer[0];
+ zeus_matrix[1][0] = zeuscmd_buffer[3];
+ zeus_matrix[1][1] = zeuscmd_buffer[3] >> 16;
+ zeus_matrix[1][2] = zeuscmd_buffer[1] >> 16;
+ zeus_matrix[2][0] = zeuscmd_buffer[4];
+ zeus_matrix[2][1] = zeuscmd_buffer[4] >> 16;
+ zeus_matrix[2][2] = zeuscmd_buffer[1];
+ zeus_point[0] = zeuscmd_buffer[5];
+ zeus_point[1] = zeuscmd_buffer[6];
+ zeus_point[2] = zeuscmd_buffer[7];
+ break;
+
+ case 0x13: /* invasn */
+ zeus_draw_polys(zeus_objdata, zeus_texdata, logcmd);
+ break;
+
+ case 0x67:
+ zeus_draw_polys(zeuscmd_buffer[1], zeuscmd_buffer[2], logcmd);
+ break;
+
+ case 0x01: /* invasn */
+ if (logcmd)
+ logerror("Zeus cmd %02X : %08X %08X\n", zeuscmd_buffer[0] >> 24, zeuscmd_buffer[0], zeuscmd_buffer[1]);
+ if (zeuscmd_buffer[0] == 0x01008000)
+ zeus_objdata = zeuscmd_buffer[1];
+ else if (zeuscmd_buffer[0] == 0x0100c0b0)
+ zeus_texdata = zeuscmd_buffer[1];
+ else if (zeuscmd_buffer[0] == 0x0100C040)
+ zeus_palbase = waveram_ptr_from_addr(zeuscmd_buffer[1]);
+ break;
+
+ default:
+ if ((zeuscmd_buffer[0] >> 16) == 0x1752)
+ {
+ zeusbase[0xb2] = zeuscmd_buffer[0];
+// zeus_enable_logging = 1;
+ }
+ if ((zeuscmd_buffer[0] >> 16) == 0x1770)
+ zeus_point[0] = zeuscmd_buffer[0] << 16;
+ if ((zeuscmd_buffer[0] >> 16) == 0x1772)
+ zeus_point[1] = zeuscmd_buffer[0] << 16;
+ if ((zeuscmd_buffer[0] >> 16) == 0x1774)
+ zeus_point[2] = zeuscmd_buffer[0] << 16;
+ if ((zeuscmd_buffer[0] >> 16) == 0x18ce)
+ zeus_blend = zeuscmd_buffer[1];
+
+ if (zeuscmd_buffer[0] == 0x0000c040)
+ zeus_palbase = waveram_ptr_from_addr(zeuscmd_buffer[1]);
+
+ if (zeuscmd_buffer[0] == 0x0080C0A5)
+ {
+ /* not right -- just a hack */
+ int x, y;
+ for (y = 0; y <= 255; y++)
+ for (x = 0; x <= 399; x++)
+ waveram_plot_depth(y, x, 0, 0x7fff);
+ colorcount = 0;
+ last_tex_index = 0;
+ }
+
+ if (logcmd)
+ {
+ logerror("Zeus cmd %02X : %08X", zeuscmd_buffer[0] >> 24, zeuscmd_buffer[0]);
+ for (wordnum = 1; wordnum < zeuscmd_buffer_expected_words; wordnum++)
+ logerror(" %08X", zeuscmd_buffer[wordnum]);
+ logerror("\n");
+ }
+ break;
+ }
+}
+
+
+static UINT8 zeuscmd_length(UINT32 word)
+{
+ switch (word >> 24)
+ {
+ case 0x00:
+ case 0x01:
+ return (word == 0) ? 1 : 2;
+
+ case 0x13:
+ case 0x17:
+ case 0x1a:
+ case 0x2d: /* invasn */
+ case 0x70:
+ return 1;
+
+ case 0x18:
+ case 0x23:
+ case 0x2e: /* invasn */
+ return 2;
+
+ case 0x67:
+ return 3;
+
+ case 0x25:
+ case 0x30: /* invasn */
+ return 4; /* ??? */
+
+ case 0x1c:
+ return 8;
+
+ default:
+ printf("Unknown command %02X\n", zeusbase[0xe0] >> 24);
+ break;
+ }
+ return 1;
+}
+
+
+READ32_HANDLER( zeus_r )
+{
+ int logit = (offset < 0xb0 || offset > 0xb7);
+ UINT32 result = zeusbase[offset & ~1];
+
+ switch (offset & ~1)
+ {
+ case 0x00:
+ // crusnexo wants bit 0x20 to be non-zero
+ result = 0x20;
+ break;
+
+ case 0x51:
+ // crusnexo expects a reflection of the data at 0x08 here (b425)
+ result = zeusbase[0x08];
+ break;
+
+ case 0xf2:
+ // polled frequently during gametime; expected to change often
+ // as it is polled multiple times and a consistent value is looked for
+ result = video_screen_get_vpos(0);
+ logit = 0;
+ break;
+
+ case 0xf4:
+ result = 6;
+ if (video_screen_get_vblank(0))
+ result |= 0x800;
+ logit = 0;
+ break;
+
+ case 0xf6: // status -- they wait for this & 9 == 0
+ if (zeusbase[0xb6] == 0x80040000)
+ result = 1;
+ else
+ result = 0;
+ logit = 0;
+ break;
+ }
+
+ /* 32-bit mode */
+ if (zeusbase[0x80] & 0x00020000)
+ {
+ if (offset & 1)
+ result >>= 16;
+ if (logit)
+ {
+ if (offset & 1)
+ logerror("%06X:zeus32_r(%02X) = %08X -- unexpected in 32-bit mode\n", activecpu_get_pc(), offset, result);
+ else if (offset != 0xe0)
+ logerror("%06X:zeus32_r(%02X) = %08X\n", activecpu_get_pc(), offset, result);
+ else
+ logerror("%06X:zeus32_r(%02X) = %08X\n", activecpu_get_pc(), offset, result);
+ }
+ }
+
+ /* 16-bit mode */
+ else
+ {
+ if (offset & 1)
+ result >>= 16;
+ else
+ result &= 0xffff;
+ if (logit)
+ logerror("%06X:zeus16_r(%02X) = %04X\n", activecpu_get_pc(), offset, result);
+ }
+ return result;
+}
+
+
+WRITE32_HANDLER( zeus_w )
+{
+ int logit = zeus_enable_logging || ((offset < 0xb0 || offset > 0xb7) && (offset < 0xe0 || offset > 0xe1));
+
+ /* 32-bit mode */
+ if (zeusbase[0x80] & 0x00020000)
+ {
+ zeusbase[offset & ~1] = data;
+
+ if (logit)
+ {
+ if (offset & 1)
+ logerror("%06X:zeus32_w(%02X) = %08X -- unexpected in 32-bit mode\n", activecpu_get_pc(), offset, data);
+ else if (offset != 0xe0)
+ logerror("%06X:zeus32_w(%02X) = %08X\n", activecpu_get_pc(), offset, data);
+ else
+ logerror("%06X:zeus32_w(%02X) = %08X\n", activecpu_get_pc(), offset, data);
+ }
+ }
+
+ /* 16-bit mode */
+ else
+ {
+ if (offset & 1)
+ zeusbase[offset & ~1] = (zeusbase[offset & ~1] & 0x0000ffff) | (data << 16);
+ else
+ zeusbase[offset & ~1] = (zeusbase[offset & ~1] & 0xffff0000) | (data & 0xffff);
+
+ if (logit)
+ logerror("%06X:zeus16_w(%02X) = %04X [%08X]\n", activecpu_get_pc(), offset, data & 0xffff, zeusbase[offset & ~1]);
+ }
+
+ /* handle the writes; only trigger on low accesses */
+ switch (offset)
+ {
+ case 0x60:
+ /* invasn writes here to execute a command (?) */
+ if (zeusbase[0x60] & 1)
+ {
+ if (zeusbase[0x80] == 0x0022FCFF)
+ {
+ int startx, stopx, starty, stopy;
+ int x, y;
+ // zeusbase[0x00] = color
+ // zeusbase[0x02] = ??? = 0x000C0000
+ // zeusbase[0x04] = ??? = 0x00000E01
+ // zeusbase[0x06] = ??? = 0xFFFF0030
+ // zeusbase[0x08] = vert[0] = (y0 << 16) | x0
+ // zeusbase[0x0a] = vert[1] = (y1 << 16) | x1
+ // zeusbase[0x0c] = vert[2] = (y2 << 16) | x2
+ // zeusbase[0x0e] = vert[3] = (y3 << 16) | x3
+ // zeusbase[0x18] = ??? = 0xFFFFFFFF
+ // zeusbase[0x1a] = ??? = 0xFFFFFFFF
+ // zeusbase[0x1c] = ??? = 0xFFFFFFFF
+ // zeusbase[0x1e] = ??? = 0xFFFFFFFF
+ // zeusbase[0x20] = ??? = 0x00000000
+ // zeusbase[0x22] = ??? = 0x00000000
+ // zeusbase[0x24] = ??? = 0x00000000
+ // zeusbase[0x26] = ??? = 0x00000000
+ // zeusbase[0x40] = ??? = 0x00000000
+ // zeusbase[0x42] = ??? = 0x00000000
+ // zeusbase[0x44] = ??? = 0x00000000
+ // zeusbase[0x46] = ??? = 0x00000000
+ // zeusbase[0x4c] = ??? = 0x00808080 (brightness?)
+ // zeusbase[0x4e] = ??? = 0x00808080 (brightness?)
+ startx = (zeusbase[0x08] & 0xffff);
+ starty = zeusbase[0x08] >> 16;
+ stopx = (zeusbase[0x0c] & 0xffff);
+ stopy = zeusbase[0x0c] >> 16;
+ for (y = starty; y <= stopy; y++)
+ for (x = startx; x <= stopx; x++)
+ waveram[(1 * WAVERAM_HEIGHT + (y % WAVERAM_HEIGHT)) * WAVERAM_WIDTH + x] = zeusbase[0x00];
+ }
+ else
+ logerror("Execute unknown command\n");
+ }
+ break;
+
+ case 0xb0:
+ case 0xb2:
+ if ((zeusbase[0xb6] >> 16) != 0)
+ {
+ UINT32 *dest = zeus_pixaddr();
+ if ((offset == 0xb0 && (zeusbase[0xb6] & 0x02000000) == 0) ||
+ (offset == 0xb2 && (zeusbase[0xb6] & 0x02000000) != 0))
+ {
+ if (zeusbase[0xb6] & 0x00100000)
+ dest[0] = (dest[0] & 0xffff0000) | (zeusbase[0xb0] & 0x0000ffff);
+ if (zeusbase[0xb6] & 0x00200000)
+ dest[0] = (dest[0] & 0x0000ffff) | (zeusbase[0xb0] & 0xffff0000);
+ if (zeusbase[0xb6] & 0x00400000)
+ dest[1] = (dest[1] & 0xffff0000) | (zeusbase[0xb2] & 0x0000ffff);
+ if (zeusbase[0xb6] & 0x00800000)
+ dest[1] = (dest[1] & 0x0000ffff) | (zeusbase[0xb2] & 0xffff0000);
+ if (zeusbase[0xb6] & 0x00020000)
+ zeusbase[0xb4]++;
+ }
+ }
+ break;
+
+ case 0xb4:
+ if (zeusbase[0xb6] & 0x00010000)
+ {
+ UINT32 *src = zeus_pixaddr();
+ zeusbase[0xb0] = src[0];
+ zeusbase[0xb2] = src[1];
+ }
+ break;
+
+ case 0xe0:
+ zeuscmd_buffer[zeuscmd_buffer_words++] = zeusbase[0xe0];
+ if (zeuscmd_buffer_words == 1)
+ zeuscmd_buffer_expected_words = zeuscmd_length(zeusbase[0xe0]);
+ if (zeuscmd_buffer_words == zeuscmd_buffer_expected_words)
+ {
+ zeuscmd_execute();
+ zeuscmd_buffer_words = 0;
+ }
+ break;
+ }
+}
+
+
+READ32_HANDLER( zeus2_r )
+{
+ return zeus_r(offset * 2, 0);
+}
+
+
+WRITE32_HANDLER( zeus2_w )
+{
+ zeus_w(offset * 2, data, mem_mask);
+}
diff --git a/src/mame/video/mikie.c b/src/mame/video/mikie.c
new file mode 100644
index 00000000000..2f924410526
--- /dev/null
+++ b/src/mame/video/mikie.c
@@ -0,0 +1,171 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static int palettebank;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Mikie has three 256x4 palette PROMs (one per gun) and two 256x4 lookup
+ table PROMs (one for characters, one for sprites).
+ I don't know for sure how the palette PROMs are connected to the RGB
+ output, but it's probably the usual:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+PALETTE_INIT( mikie )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the character lookup table */
+
+
+ /* there are eight 32 colors palette banks; sprites use colors 0-15 and */
+ /* characters 16-31 of each bank. */
+ for (i = 0;i < TOTAL_COLORS(0)/8;i++)
+ {
+ int j;
+
+
+ for (j = 0;j < 8;j++)
+ COLOR(0,i + j * TOTAL_COLORS(0)/8) = (*color_prom & 0x0f) + 32 * j + 16;
+
+ color_prom++;
+ }
+
+ for (i = 0;i < TOTAL_COLORS(1)/8;i++)
+ {
+ int j;
+
+
+ for (j = 0;j < 8;j++)
+ COLOR(1,i + j * TOTAL_COLORS(1)/8) = (*color_prom & 0x0f) + 32 * j;
+
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( mikie_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( mikie_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( mikie_palettebank_w )
+{
+ if (palettebank != (data & 0x07))
+ {
+ palettebank = data & 0x07;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( mikie_flipscreen_w )
+{
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + ((colorram[tile_index] & 0x20) << 3);
+ int color = (colorram[tile_index] & 0x0f) + 16 * palettebank;
+ int flags = ((colorram[tile_index] & 0x40) ? TILE_FLIPX : 0) | ((colorram[tile_index] & 0x80) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( mikie )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int gfxbank = (spriteram[offs+2] & 0x40) ? 2 : 1;
+ int code = (spriteram[offs + 2] & 0x3f) + ((spriteram[offs + 2] & 0x80) >> 1) + ((spriteram[offs] & 0x40) << 1);
+ int color = (spriteram[offs] & 0x0f) + 16 * palettebank;
+ int sx = spriteram[offs + 3];
+ int sy = 244 - spriteram[offs + 1];
+ int flipx = ~spriteram[offs] & 0x10;
+ int flipy = spriteram[offs] & 0x20;
+
+ if (flip_screen)
+ {
+ sy = 242 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[gfxbank],
+ code, color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( mikie )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/mitchell.c b/src/mame/video/mitchell.c
new file mode 100644
index 00000000000..6e294211054
--- /dev/null
+++ b/src/mame/video/mitchell.c
@@ -0,0 +1,288 @@
+/***************************************************************************
+
+ Pang Video Hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "sound/okim6295.h"
+
+
+/* Globals */
+size_t pang_videoram_size;
+UINT8 *pang_videoram;
+UINT8 *pang_colorram;
+
+/* Private */
+static UINT8 *pang_objram; /* Sprite RAM */
+
+static tilemap *bg_tilemap;
+static int flipscreen;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 attr = pang_colorram[tile_index];
+ int code = pang_videoram[2*tile_index] + (pang_videoram[2*tile_index+1] << 8);
+ SET_TILE_INFO(
+ 0,
+ code,
+ attr & 0x7f,
+ (attr & 0x80) ? TILE_FLIPX : 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( pang )
+{
+ pang_objram=NULL;
+ paletteram=NULL;
+
+
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_transparent_pen(bg_tilemap,15);
+
+ /*
+ OBJ RAM
+ */
+ pang_objram=auto_malloc(pang_videoram_size);
+ memset(pang_objram, 0, pang_videoram_size);
+
+ /*
+ Palette RAM
+ */
+ paletteram = auto_malloc(2*machine->drv->total_colors);
+ memset(paletteram, 0, 2*machine->drv->total_colors);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+/***************************************************************************
+ OBJ / CHAR RAM HANDLERS (BANK 0 = CHAR, BANK 1=OBJ)
+***************************************************************************/
+
+static int video_bank;
+
+WRITE8_HANDLER( pang_video_bank_w )
+{
+ /* Bank handler (sets base pointers for video write) (doesn't apply to mgakuen) */
+ video_bank = data;
+}
+
+WRITE8_HANDLER( mstworld_video_bank_w )
+{
+ /* Monsters World seems to freak out if more bits are used.. */
+ video_bank = data&1;
+}
+
+
+WRITE8_HANDLER( mgakuen_videoram_w )
+{
+ pang_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+READ8_HANDLER( mgakuen_videoram_r )
+{
+ return pang_videoram[offset];
+}
+
+WRITE8_HANDLER( mgakuen_objram_w )
+{
+ pang_objram[offset]=data;
+}
+
+READ8_HANDLER( mgakuen_objram_r )
+{
+ return pang_objram[offset];
+}
+
+WRITE8_HANDLER( pang_videoram_w )
+{
+ if (video_bank) mgakuen_objram_w(offset,data);
+ else mgakuen_videoram_w(offset,data);
+}
+
+READ8_HANDLER( pang_videoram_r )
+{
+ if (video_bank) return mgakuen_objram_r(offset);
+ else return mgakuen_videoram_r(offset);
+}
+
+/***************************************************************************
+ COLOUR RAM
+****************************************************************************/
+
+WRITE8_HANDLER( pang_colorram_w )
+{
+ pang_colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+READ8_HANDLER( pang_colorram_r )
+{
+ return pang_colorram[offset];
+}
+
+/***************************************************************************
+ PALETTE HANDLERS (COLOURS: BANK 0 = 0x00-0x3f BANK 1=0x40-0xff)
+****************************************************************************/
+
+static int paletteram_bank;
+
+WRITE8_HANDLER( pang_gfxctrl_w )
+{
+logerror("PC %04x: pang_gfxctrl_w %02x\n",activecpu_get_pc(),data);
+{
+ char baf[40];
+ sprintf(baf,"%02x",data);
+// popmessage(baf);
+}
+
+ /* bit 0 is unknown (used, maybe back color enable?) */
+
+ /* bit 1 is coin counter */
+ coin_counter_w(0,data & 2);
+
+ /* bit 2 is flip screen */
+ if (flipscreen != (data & 0x04))
+ {
+ flipscreen = data & 0x04;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ }
+
+ /* bit 3 is unknown (used, e.g. marukin pulses it on the title screen) */
+
+ /* bit 4 selects OKI M6295 bank */
+ if (sndti_exists(SOUND_OKIM6295,0)) OKIM6295_set_bank_base(0, (data & 0x10) ? 0x40000 : 0x00000);
+
+ /* bit 5 is palette RAM bank selector (doesn't apply to mgakuen) */
+ paletteram_bank = data & 0x20;
+
+ /* bits 6 and 7 are unknown, used in several places. At first I thought */
+ /* they were bg and sprites enable, but this screws up spang (screen flickers */
+ /* every time you pop a bubble). However, not using them as enable bits screws */
+ /* up marukin - you can see partially built up screens during attract mode. */
+}
+
+WRITE8_HANDLER( mstworld_gfxctrl_w )
+{
+logerror("PC %04x: pang_gfxctrl_w %02x\n",activecpu_get_pc(),data);
+{
+ char baf[40];
+ sprintf(baf,"%02x",data);
+// popmessage(baf);
+}
+
+ /* bit 0 is unknown (used, maybe back color enable?) */
+
+ /* bit 1 is coin counter */
+ coin_counter_w(0,data & 2);
+
+ /* bit 2 is flip screen */
+ if (flipscreen != (data & 0x04))
+ {
+ flipscreen = data & 0x04;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ }
+
+ /* bit 3 is unknown (used, e.g. marukin pulses it on the title screen) */
+
+ /* bit 4 selects OKI M6295 bank */
+// OKIM6295_set_bank_base(0, (data & 0x10) ? 0x40000 : 0x00000);
+ /* not here.. it has its own z80 + sound banking */
+
+ /* bit 5 is palette RAM bank selector (doesn't apply to mgakuen) */
+ paletteram_bank = data & 0x20;
+
+ /* bits 6 and 7 are unknown, used in several places. At first I thought */
+ /* they were bg and sprites enable, but this screws up spang (screen flickers */
+ /* every time you pop a bubble). However, not using them as enable bits screws */
+ /* up marukin - you can see partially built up screens during attract mode. */
+}
+
+WRITE8_HANDLER( pang_paletteram_w )
+{
+ if (paletteram_bank) paletteram_xxxxRRRRGGGGBBBB_le_w(offset + 0x800,data);
+ else paletteram_xxxxRRRRGGGGBBBB_le_w(offset,data);
+}
+
+READ8_HANDLER( pang_paletteram_r )
+{
+ if (paletteram_bank) return paletteram_r(offset + 0x800);
+ return paletteram_r(offset);
+}
+
+WRITE8_HANDLER( mgakuen_paletteram_w )
+{
+ paletteram_xxxxRRRRGGGGBBBB_le_w(offset,data);
+}
+
+READ8_HANDLER( mgakuen_paletteram_r )
+{
+ return paletteram_r(offset);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs,sx,sy;
+
+ /* the last entry is not a sprite, we skip it otherwise spang shows a bubble */
+ /* moving diagonally across the screen */
+ for (offs = 0x1000-0x40;offs >= 0;offs -= 0x20)
+ {
+ int code = pang_objram[offs];
+ int attr = pang_objram[offs+1];
+ int color = attr & 0x0f;
+ sx = pang_objram[offs+3] + ((attr & 0x10) << 4);
+ sy = ((pang_objram[offs+2] + 8) & 0xff) - 8;
+ code += (attr & 0xe0) << 3;
+ if (flipscreen)
+ {
+ sx = 496 - sx;
+ sy = 240 - sy;
+ }
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipscreen,flipscreen,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+VIDEO_UPDATE( pang )
+{
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/mjkjidai.c b/src/mame/video/mjkjidai.c
new file mode 100644
index 00000000000..c279586d94c
--- /dev/null
+++ b/src/mame/video/mjkjidai.c
@@ -0,0 +1,141 @@
+#include "driver.h"
+
+
+UINT8 *mjkjidai_videoram;
+
+static int display_enable;
+static tilemap *bg_tilemap;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ int attr = mjkjidai_videoram[tile_index + 0x800];
+ int code = mjkjidai_videoram[tile_index] + ((attr & 0x1f) << 8);
+ int color = mjkjidai_videoram[tile_index + 0x1000];
+ SET_TILE_INFO(0,code,color >> 3,0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( mjkjidai )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( mjkjidai_videoram_w )
+{
+ mjkjidai_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x7ff);
+}
+
+WRITE8_HANDLER( mjkjidai_ctrl_w )
+{
+ UINT8 *rom = memory_region(REGION_CPU1);
+
+// logerror("%04x: port c0 = %02x\n",activecpu_get_pc(),data);
+
+ /* bit 0 = NMI enable */
+ interrupt_enable_w(0,data & 1);
+
+ /* bit 1 = flip screen */
+ flip_screen_set(data & 0x02);
+
+ /* bit 2 =display enable */
+ display_enable = data & 0x04;
+
+ /* bit 5 = coin counter */
+ coin_counter_w(0,data & 0x20);
+
+ /* bits 6-7 select ROM bank */
+ if (data & 0xc0)
+ {
+ memory_set_bankptr(1,rom + 0x10000-0x4000 + ((data & 0xc0) << 8));
+ }
+ else
+ {
+ /* there is code flowing from 7fff to this bank so they have to be contiguous in memory */
+ memory_set_bankptr(1,rom + 0x08000);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0x20-2;offs >= 0;offs -= 2)
+ {
+ int code = spriteram[offs] + ((spriteram_2[offs] & 0x1f) << 8);
+ int color = (spriteram_3[offs] & 0x78) >> 3;
+ int sx = 2*spriteram_2[offs+1];
+ int sy = 240 - spriteram[offs+1];
+ int flipx = code & 1;
+ int flipy = code & 2;
+
+ code >>= 2;
+
+ sx += (spriteram_2[offs] & 0x20) >> 5; // not sure about this
+
+ if (flip_screen)
+ {
+ sx = 496 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ sx += 16;
+ sy += 1;
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+
+VIDEO_UPDATE( mjkjidai )
+{
+ if (!display_enable)
+ {
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ }
+ else
+ {
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ }
+ return 0;
+}
diff --git a/src/mame/video/mjsister.c b/src/mame/video/mjsister.c
new file mode 100644
index 00000000000..737caa855b4
--- /dev/null
+++ b/src/mame/video/mjsister.c
@@ -0,0 +1,111 @@
+/*****************************************************************************
+
+Mahjong Sisters (c) 1986 Toa Plan
+
+Video hardware
+ driver by Uki
+
+*****************************************************************************/
+
+#include "driver.h"
+
+int mjsister_screen_redraw;
+int mjsister_flip_screen;
+int mjsister_video_enable;
+
+int mjsister_vrambank;
+int mjsister_colorbank;
+
+static mame_bitmap *mjsister_tmpbitmap0, *mjsister_tmpbitmap1;
+static UINT8 *mjsister_videoram0, *mjsister_videoram1;
+
+/****************************************************************************/
+
+VIDEO_START( mjsister )
+{
+ mjsister_tmpbitmap0 = auto_bitmap_alloc(256,256,machine->screen[0].format);
+ mjsister_tmpbitmap1 = auto_bitmap_alloc(256,256,machine->screen[0].format);
+ mjsister_videoram0 = auto_malloc(0x8000);
+ mjsister_videoram1 = auto_malloc(0x8000);
+}
+
+static void mjsister_plot0(int offset,UINT8 data)
+{
+ int x,y,c1,c2;
+
+ x = offset & 0x7f;
+ y = offset / 0x80;
+
+ c1 = (data & 0x0f) + mjsister_colorbank * 0x20;
+ c2 = ((data & 0xf0) >> 4) + mjsister_colorbank * 0x20;
+
+ *BITMAP_ADDR16(mjsister_tmpbitmap0, y, x*2+0) = Machine->pens[c1];
+ *BITMAP_ADDR16(mjsister_tmpbitmap0, y, x*2+1) = Machine->pens[c2];
+}
+
+static void mjsister_plot1(int offset,UINT8 data)
+{
+ int x,y,c1,c2;
+
+ x = offset & 0x7f;
+ y = offset / 0x80;
+
+ c1 = data & 0x0f;
+ c2 = (data & 0xf0) >> 4;
+
+ if (c1)
+ c1 += mjsister_colorbank * 0x20 + 0x10;
+ if (c2)
+ c2 += mjsister_colorbank * 0x20 + 0x10;
+
+ *BITMAP_ADDR16(mjsister_tmpbitmap1, y, x*2+0) = Machine->pens[c1];
+ *BITMAP_ADDR16(mjsister_tmpbitmap1, y, x*2+1) = Machine->pens[c2];
+}
+
+WRITE8_HANDLER( mjsister_videoram_w )
+{
+ if (mjsister_vrambank)
+ {
+ mjsister_videoram1[offset] = data;
+ mjsister_plot1(offset,data);
+ }
+ else
+ {
+ mjsister_videoram0[offset] = data;
+ mjsister_plot0(offset,data);
+ }
+}
+
+VIDEO_UPDATE( mjsister )
+{
+ int f = mjsister_flip_screen;
+ int i,j;
+
+ if (mjsister_screen_redraw)
+ {
+ int offs;
+
+ for (offs=0; offs<0x8000; offs++)
+ {
+ mjsister_plot0(offs,mjsister_videoram0[offs]);
+ mjsister_plot1(offs,mjsister_videoram1[offs]);
+ }
+
+ mjsister_screen_redraw = 0;
+ }
+
+ if (mjsister_video_enable)
+ {
+ for (i=0; i<256; i++)
+ {
+ for (j=0; j<4; j++)
+ *BITMAP_ADDR16(bitmap, i, 256+j) = machine->pens[mjsister_colorbank * 0x20];
+ }
+
+ copybitmap(bitmap,mjsister_tmpbitmap0,f,f,0,0,cliprect,TRANSPARENCY_NONE,0);
+ copybitmap(bitmap,mjsister_tmpbitmap1,f,f,2,0,cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ fillbitmap(bitmap, get_black_pen(machine), &machine->screen[0].visarea);
+ return 0;
+}
diff --git a/src/mame/video/mnight.c b/src/mame/video/mnight.c
new file mode 100644
index 00000000000..e4541d1e4b3
--- /dev/null
+++ b/src/mame/video/mnight.c
@@ -0,0 +1,206 @@
+#include "driver.h"
+
+UINT8 *mnight_scrolly_ram;
+UINT8 *mnight_scrollx_ram;
+UINT8 *mnight_bgenable_ram;
+UINT8 *mnight_spoverdraw_ram;
+UINT8 *mnight_background_videoram;
+size_t mnight_backgroundram_size;
+UINT8 *mnight_foreground_videoram;
+size_t mnight_foregroundram_size;
+
+static mame_bitmap *bitmap_bg;
+static mame_bitmap *bitmap_sp;
+
+static UINT8 *bg_dirtybuffer;
+static int bg_enable = 1;
+static int sp_overdraw = 0;
+
+static void mnight_mark_background_dirty(void)
+{
+ /* set 1024 bytes allocated in VIDEO_START( mnight ) to 'true' */
+ memset(bg_dirtybuffer,1,1024);
+}
+
+VIDEO_START( mnight )
+{
+ bg_dirtybuffer = auto_malloc(1024);
+
+ bitmap_bg = auto_bitmap_alloc (machine->screen[0].width*2,machine->screen[0].height*2,machine->screen[0].format);
+ bitmap_sp = auto_bitmap_alloc (machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ mnight_mark_background_dirty() ;
+
+ state_save_register_func_postload(mnight_mark_background_dirty) ;
+}
+
+
+WRITE8_HANDLER( mnight_bgvideoram_w )
+{
+ if (mnight_background_videoram[offset] != data)
+ {
+ bg_dirtybuffer[offset >> 1] = 1;
+ mnight_background_videoram[offset] = data;
+ }
+}
+
+WRITE8_HANDLER( mnight_fgvideoram_w )
+{
+ if (mnight_foreground_videoram[offset] != data)
+ mnight_foreground_videoram[offset] = data;
+}
+
+WRITE8_HANDLER( mnight_background_enable_w )
+{
+ if (bg_enable!=data)
+ {
+ mnight_bgenable_ram[offset] = data;
+ bg_enable = data;
+ if (bg_enable)
+ memset(bg_dirtybuffer, 1, mnight_backgroundram_size / 2);
+ else
+ fillbitmap(bitmap_bg, Machine->pens[0],0);
+ }
+}
+
+WRITE8_HANDLER( mnight_sprite_overdraw_w )
+{
+ if (sp_overdraw != (data&1))
+ {
+ mnight_spoverdraw_ram[offset] = data;
+ fillbitmap(bitmap_sp,15,&Machine->screen[0].visarea);
+ sp_overdraw = data & 1;
+ }
+}
+
+static void draw_foreground(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ /* Draw the foreground text */
+
+ for (offs = 0 ;offs < mnight_foregroundram_size / 2; offs++)
+ {
+ int sx,sy,tile,palette,flipx,flipy,lo,hi;
+
+ if (mnight_foreground_videoram[offs*2] | mnight_foreground_videoram[offs*2+1])
+ {
+ sx = (offs % 32) << 3;
+ sy = (offs >> 5) << 3;
+
+ lo = mnight_foreground_videoram[offs*2];
+ hi = mnight_foreground_videoram[offs*2+1];
+ tile = ((hi & 0xc0) << 2) | lo;
+ flipx = hi & 0x10;
+ flipy = hi & 0x20;
+ palette = hi & 0x0f;
+
+ drawgfx(bitmap,machine->gfx[3],
+ tile,
+ palette,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN, 15);
+ }
+
+ }
+}
+
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ /* for every character in the Video RAM, check if it has been modified */
+ /* since last time and update it accordingly. */
+
+ for (offs = 0 ;offs < mnight_backgroundram_size / 2; offs++)
+ {
+ int sx,sy,tile,palette,flipy,lo,hi;
+
+ if (bg_dirtybuffer[offs])
+ {
+ sx = (offs % 32) << 4;
+ sy = (offs >> 5) << 4;
+
+ bg_dirtybuffer[offs] = 0;
+
+ lo = mnight_background_videoram[offs*2];
+ hi = mnight_background_videoram[offs*2+1];
+ tile = ((hi & 0x10) << 6) | ((hi & 0xc0) << 2) | lo;
+ flipy = hi & 0x20;
+ palette = hi & 0x0f;
+ drawgfx(bitmap,machine->gfx[0],
+ tile,
+ palette,
+ 0,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_NONE,0);
+ }
+
+ }
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 11 ;offs < spriteram_size; offs+=16)
+ {
+ int sx,sy,tile,palette,flipx,flipy,big;
+
+ if (spriteram[offs+2] & 2)
+ {
+ sx = spriteram[offs+1];
+ sy = spriteram[offs];
+ if (spriteram[offs+2] & 1) sx-=256;
+ tile = spriteram[offs+3]+((spriteram[offs+2] & 0xc0)<<2) + ((spriteram[offs+2] & 0x08)<<7);
+ big = spriteram[offs+2] & 4;
+ if (big) tile /= 4;
+ flipx = spriteram[offs+2] & 0x10;
+ flipy = spriteram[offs+2] & 0x20;
+ palette = spriteram[offs+4] & 0x0f;
+ drawgfx(bitmap,machine->gfx[(big)?2:1],
+ tile,
+ palette,
+ flipx,flipy,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN, 15);
+
+ /* kludge to clear shots */
+ if (((spriteram[offs+2]==2) || (spriteram[offs+2]==0x12)) && (((tile>=0xd0) && (tile<=0xd5)) || ((tile>=0x20) && (tile<=0x25))))
+ spriteram[offs+2]=0;
+ }
+ }
+}
+
+
+VIDEO_UPDATE( mnight )
+{
+ int scrollx,scrolly;
+
+
+ if (bg_enable)
+ draw_background(machine, bitmap_bg, 0);
+
+ scrollx = -((mnight_scrollx_ram[0]+mnight_scrollx_ram[1]*256) & 0x1FF);
+ scrolly = -((mnight_scrolly_ram[0]+mnight_scrolly_ram[1]*256) & 0x1FF);
+
+ if (sp_overdraw) /* overdraw sprite mode */
+ {
+ copyscrollbitmap(bitmap,bitmap_bg,1,&scrollx,1,&scrolly,cliprect,TRANSPARENCY_NONE,0);
+ draw_sprites(machine, bitmap_sp, 0);
+ draw_foreground(machine, bitmap_sp, 0);
+ copybitmap(bitmap,bitmap_sp,0,0,0,0,cliprect,TRANSPARENCY_PEN, 15);
+ }
+ else /* normal sprite mode */
+ {
+ copyscrollbitmap(bitmap,bitmap_bg,1,&scrollx,1,&scrolly,cliprect,TRANSPARENCY_NONE,0);
+ draw_sprites(machine, bitmap, cliprect);
+ draw_foreground(machine, bitmap, cliprect);
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/model1.c b/src/mame/video/model1.c
new file mode 100644
index 00000000000..d0f5eb2b184
--- /dev/null
+++ b/src/mame/video/model1.c
@@ -0,0 +1,1535 @@
+#include "driver.h"
+#include "video/segaic24.h"
+#include <math.h>
+
+#define LOG_TGP_VIDEO 0
+
+#if LOG_TGP_VIDEO
+#define LOG_TGP logerror
+#else
+static void dummy_log(const char *s,...) {}
+#define LOG_TGP dummy_log
+#endif
+
+UINT16 *model1_display_list0, *model1_display_list1;
+UINT16 *model1_color_xlat;
+static UINT16 listctl[2];
+static UINT16 *glist;
+
+// Model 1 geometrizer TGP and rasterizer simulation
+enum { FRAC_SHIFT = 16 };
+
+static int render_done;
+static UINT16 *tgp_ram;
+static float trans_mat[12];
+
+static float vxx, vyy, vzz, ayy, ayyc, ayys;
+
+struct vector {
+ float x, y, z;
+};
+
+static struct {
+ int xc, yc, x1, y1, x2, y2;
+ float zoomx, zoomy, transx, transy;
+ float a_bottom, a_top, a_left, a_right;
+ struct vector light;
+} view;
+
+struct spoint {
+ INT32 x, y;
+};
+
+struct point {
+ float x, y, z;
+ float xx, yy;
+ struct spoint s;
+};
+
+static struct lightparam
+{
+ float a;
+ float d;
+ float s;
+ int p;
+} lightparams[32];
+
+enum { MOIRE = 0x00010000 };
+
+struct quad {
+ struct point *p[4];
+ float z;
+ int col;
+};
+
+static struct point *pointdb, *pointpt;
+static struct quad *quaddb, *quadpt;
+static struct quad **quadind;
+
+static UINT32 *poly_rom,*poly_ram;
+
+static UINT32 readi(const UINT16 *adr)
+{
+ return adr[0]|(adr[1] << 16);
+}
+
+static INT16 readi16(const UINT16 *adr)
+{
+ return adr[0];
+}
+
+static float readf(const UINT16 *adr)
+{
+ return u2f(readi(adr));
+}
+
+static void transform_point(struct point *p)
+{
+ struct point q = *p;
+ float xx, zz;
+ xx = trans_mat[0]*q.x+trans_mat[3]*q.y+trans_mat[6]*q.z+trans_mat[9]+vxx;
+ p->y = trans_mat[1]*q.x+trans_mat[4]*q.y+trans_mat[7]*q.z+trans_mat[10]+vyy;
+ zz = trans_mat[2]*q.x+trans_mat[5]*q.y+trans_mat[8]*q.z+trans_mat[11]+vzz;
+ p->x = ayyc*xx-ayys*zz;
+ p->z = ayys*xx+ayyc*zz;
+}
+
+static void transform_vector(struct vector *p)
+{
+ struct vector q = *p;
+ p->x = trans_mat[0]*q.x+trans_mat[3]*q.y+trans_mat[6]*q.z;
+ p->y = trans_mat[1]*q.x+trans_mat[4]*q.y+trans_mat[7]*q.z;
+ p->z = trans_mat[2]*q.x+trans_mat[5]*q.y+trans_mat[8]*q.z;
+}
+
+static void normalize_vector(struct vector *p)
+{
+ float norm = sqrt(p->x*p->x+p->y*p->y+p->z*p->z);
+ if(norm) {
+ p->x /= norm;
+ p->y /= norm;
+ p->z /= norm;
+ }
+}
+
+static float mult_vector(const struct vector *p, const struct vector *q)
+{
+ return p->x*q->x+p->y*q->y+p->z*q->z;
+}
+
+static float view_determinant(const struct point *p1, const struct point *p2, const struct point *p3)
+{
+ float x1 = p2->x - p1->x;
+ float y1 = p2->y - p1->y;
+ float z1 = p2->z - p1->z;
+ float x2 = p3->x - p1->x;
+ float y2 = p3->y - p1->y;
+ float z2 = p3->z - p1->z;
+
+ return p1->x*(y1*z2-y2*z1) + p1->y*(z1*x2-z2*x1) + p1->z*(x1*y2-x2*y1);
+}
+
+
+static void project_point(struct point *p)
+{
+ p->xx = p->x / p->z;
+ p->yy = p->y / p->z;
+ p->s.x = view.xc+(p->xx*view.zoomx+view.transx);
+ p->s.y = view.yc-(p->yy*view.zoomy+view.transy);
+}
+
+static void project_point_direct(struct point *p)
+{
+ p->xx = p->x /*/ p->z*/;
+ p->yy = p->y /*/ p->z*/;
+ p->s.x = view.xc+(p->xx);
+ p->s.y = view.yc-(p->yy);
+}
+
+
+static void draw_hline(mame_bitmap *bitmap, int x1, int x2, int y, int color)
+{
+ UINT16 *base = BITMAP_ADDR16(bitmap, y, 0);
+ while(x1 <= x2) {
+ base[x1] = color;
+ x1++;
+ }
+}
+
+static void draw_hline_moired(mame_bitmap *bitmap, int x1, int x2, int y, int color)
+{
+ UINT16 *base = BITMAP_ADDR16(bitmap, y, 0);
+ while(x1 <= x2) {
+ if((x1^y)&1)
+ base[x1] = color;
+ x1++;
+ }
+}
+
+static void fill_slope(mame_bitmap *bitmap, int color, INT32 x1, INT32 x2, INT32 sl1, INT32 sl2, INT32 y1, INT32 y2, INT32 *nx1, INT32 *nx2)
+{
+ if(y1 > view.y2)
+ return;
+
+ if(y2 <= view.y1) {
+ int delta = y2-y1;
+ *nx1 = x1+delta*sl1;
+ *nx2 = x2+delta*sl2;
+ return;
+ }
+
+ if(y2 > view.y2)
+ y2 = view.y2+1;
+
+ if(y1 < view.y1) {
+ int delta = view.y1 - y1;
+ x1 += delta*sl1;
+ x2 += delta*sl2;
+ y1 = view.y1;
+ }
+
+ if(x1 > x2 || (x1==x2 && sl1 > sl2)) {
+ INT32 t, *tp;
+ t = x1;
+ x1 = x2;
+ x2 = t;
+ t = sl1;
+ sl1 = sl2;
+ sl2 = t;
+ tp = nx1;
+ nx1 = nx2;
+ nx2 = tp;
+ }
+
+ while(y1 < y2) {
+ if(y1 >= view.y1) {
+ int xx1 = x1>>FRAC_SHIFT;
+ int xx2 = x2>>FRAC_SHIFT;
+ if(xx1 <= view.x2 || xx2 >= view.x1) {
+ if(xx1 < view.x1)
+ xx1 = view.x1;
+ if(xx2 > view.x2)
+ xx2 = view.x2;
+
+ if(color & MOIRE)
+ draw_hline_moired(bitmap, xx1, xx2, y1, color);
+ else
+ draw_hline(bitmap, xx1, xx2, y1, color);
+ }
+ }
+
+ x1 += sl1;
+ x2 += sl2;
+ y1++;
+ }
+ *nx1 = x1;
+ *nx2 = x2;
+}
+
+static void fill_line(mame_bitmap *bitmap, int color, INT32 y, INT32 x1, INT32 x2)
+{
+ int xx1 = x1>>FRAC_SHIFT;
+ int xx2 = x2>>FRAC_SHIFT;
+
+ if(y > view.y2 || y < view.y1)
+ return;
+
+ if(xx1 <= view.x2 || xx2 >= view.x1) {
+ if(xx1 < view.x1)
+ xx1 = view.x1;
+ if(xx2 > view.x2)
+ xx2 = view.x2;
+
+ if(color & MOIRE)
+ draw_hline_moired(bitmap, xx1, xx2, y, color);
+ else
+ draw_hline(bitmap, xx1, xx2, y, color);
+ }
+}
+
+static void fill_quad(mame_bitmap *bitmap, const struct quad *q)
+{
+ INT32 sl1, sl2, cury, limy, x1, x2;
+ int pmin, pmax, i, ps1, ps2;
+ struct spoint p[8];
+ int color = q->col;
+
+ if(color < 0) {
+ color = -1-color;
+ LOG_TGP("VIDEOD: Q (%d, %d)-(%d, %d)-(%d, %d)-(%d, %d)\n",
+ q->p[0]->s.x, q->p[0]->s.y,
+ q->p[1]->s.x, q->p[1]->s.y,
+ q->p[2]->s.x, q->p[2]->s.y,
+ q->p[3]->s.x, q->p[3]->s.y);
+ }
+
+ for(i=0; i<4; i++) {
+ p[i].x = p[i+4].x = q->p[i]->s.x << FRAC_SHIFT;
+ p[i].y = p[i+4].y = q->p[i]->s.y;
+ }
+
+ pmin = pmax = 0;
+ for(i=1; i<4; i++) {
+ if(p[i].y < p[pmin].y)
+ pmin = i;
+ if(p[i].y > p[pmax].y)
+ pmax = i;
+ }
+
+ cury = p[pmin].y;
+ limy = p[pmax].y;
+
+ if(cury == limy) {
+ x1 = x2 = p[0].x;
+ for(i=1; i<4; i++) {
+ if(p[i].x < x1)
+ x1 = p[i].x;
+ if(p[i].x > x2)
+ x2 = p[i].x;
+ }
+ fill_line(bitmap, color, cury, x1, x2);
+ return;
+ }
+
+ if(cury > view.y2)
+ return;
+ if(limy <= view.y1)
+ return;
+
+ if(limy > view.y2)
+ limy = view.y2;
+
+ ps1 = pmin+4;
+ ps2 = pmin;
+
+ goto startup;
+
+ for(;;) {
+ if(p[ps1-1].y == p[ps2+1].y) {
+ fill_slope(bitmap, color, x1, x2, sl1, sl2, cury, p[ps1-1].y, &x1, &x2);
+ cury = p[ps1-1].y;
+ if(cury >= limy)
+ break;
+ ps1--;
+ ps2++;
+
+ startup:
+ while(p[ps1-1].y == cury)
+ ps1--;
+ while(p[ps2+1].y == cury)
+ ps2++;
+ x1 = p[ps1].x;
+ x2 = p[ps2].x;
+ sl1 = (x1-p[ps1-1].x)/(cury-p[ps1-1].y);
+ sl2 = (x2-p[ps2+1].x)/(cury-p[ps2+1].y);
+ } else if(p[ps1-1].y < p[ps2+1].y) {
+ fill_slope(bitmap, color, x1, x2, sl1, sl2, cury, p[ps1-1].y, &x1, &x2);
+ cury = p[ps1-1].y;
+ if(cury >= limy)
+ break;
+ ps1--;
+ while(p[ps1-1].y == cury)
+ ps1--;
+ x1 = p[ps1].x;
+ sl1 = (x1-p[ps1-1].x)/(cury-p[ps1-1].y);
+ } else {
+ fill_slope(bitmap, color, x1, x2, sl1, sl2, cury, p[ps2+1].y, &x1, &x2);
+ cury = p[ps2+1].y;
+ if(cury >= limy)
+ break;
+ ps2++;
+ while(p[ps2+1].y == cury)
+ ps2++;
+ x2 = p[ps2].x;
+ sl2 = (x2-p[ps2+1].x)/(cury-p[ps2+1].y);
+ }
+ }
+ if(cury == limy)
+ fill_line(bitmap, color, cury, x1, x2);
+}
+#if 0
+static void draw_line(mame_bitmap *bitmap, int color, int x1, int y1, int x2, int y2)
+{
+ int s1x, s1y, s2x, s2y;
+ int d1, d2;
+ int cur;
+ int x, y;
+
+ if((x1 < view.x1 && x2 < view.x1) ||
+ (x1 > view.x2 && x2 > view.x2) ||
+ (y1 < view.y1 && y2 < view.y1) ||
+ (y1 > view.y2 && y2 > view.y2))
+ return;
+
+ x = x1;
+ y = y1;
+ s1x = 1;
+ s1y = 0;
+ s2x = 0;
+ s2y = 1;
+
+ d1 = x2-x1;
+ d2 = y2-y1;
+ if(d1<0) {
+ s1x = -s1x;
+ d1 = -d1;
+ }
+ if(d2<0) {
+ s2y = -s2y;
+ d2 = -d2;
+ }
+ if(d1 < d2) {
+ int t;
+ t = s1x;
+ s1x = s2x;
+ s2x = t;
+ t = s1y;
+ s1y = s2y;
+ s2y = t;
+ t = d1;
+ d1 = d2;
+ d2 = t;
+ }
+
+ if(d1 > 600)
+ return;
+
+ cur = 0;
+ while(x != x2 || y != y2) {
+ if(x>=view.x1 && x<=view.x2 && y>=view.y1 && y<=view.y2)
+ *BITMAP_ADDR16(bitmap, y, x) = color;
+ x += s1x;
+ y += s1y;
+ cur += d2;
+ if(cur >= d1) {
+ cur -= d1;
+ x += s2x;
+ y += s2y;
+ }
+ }
+ if(x>=view.x1 && x<=view.x2 && y>=view.y1 && y<=view.y2)
+ *BITMAP_ADDR16(bitmap, y, x) = color;
+}
+#endif
+static int comp_quads(const void *q1, const void *q2)
+{
+ float z1 = (*(const struct quad **)q1)->z;
+ float z2 = (*(const struct quad **)q2)->z;
+
+ if(z1<z2)
+ return +1;
+ if(z1>z2)
+ return -1;
+
+ if (*(const struct quad **)q1 - quaddb < *(const struct quad **)q2 - quaddb)
+ return -1;
+
+ return +1;
+}
+
+static void sort_quads(void)
+{
+ int count = quadpt - quaddb;
+ int i;
+ for(i=0; i<count; i++)
+ quadind[i] = quaddb+i;
+ qsort(quadind, count, sizeof(struct quad *), comp_quads);
+}
+
+static void unsort_quads(void)
+{
+ int count = quadpt - quaddb;
+ int i;
+ for(i=0; i<count; i++)
+ quadind[i] = quaddb+i;
+}
+
+
+static void draw_quads(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int count = quadpt - quaddb;
+ int i;
+
+ /* clip to the cliprect */
+ int save_x1 = view.x1;
+ int save_x2 = view.x2;
+ int save_y1 = view.y1;
+ int save_y2 = view.y2;
+ view.x1 = MAX(view.x1, cliprect->min_x);
+ view.x2 = MIN(view.x2, cliprect->max_x);
+ view.y1 = MAX(view.y1, cliprect->min_y);
+ view.y2 = MIN(view.y2, cliprect->max_y);
+
+ for(i=0; i<count; i++) {
+ struct quad *q = quadind[i];
+
+ fill_quad(bitmap, q);
+#if 0
+ draw_line(bitmap, get_black_pen(machine), q->p[0]->s.x, q->p[0]->s.y, q->p[1]->s.x, q->p[1]->s.y);
+ draw_line(bitmap, get_black_pen(machine), q->p[1]->s.x, q->p[1]->s.y, q->p[2]->s.x, q->p[2]->s.y);
+ draw_line(bitmap, get_black_pen(machine), q->p[2]->s.x, q->p[2]->s.y, q->p[3]->s.x, q->p[3]->s.y);
+ draw_line(bitmap, get_black_pen(machine), q->p[3]->s.x, q->p[3]->s.y, q->p[0]->s.x, q->p[0]->s.y);
+#endif
+ }
+
+ view.x1 = save_x1;
+ view.x2 = save_x2;
+ view.y1 = save_y1;
+ view.y2 = save_y2;
+}
+#if 0
+static UINT16 scale_color(UINT16 color, float level)
+{
+ int r, g, b;
+ r = ((color >> 10) & 31)*level;
+ g = ((color >> 5) & 31)*level;
+ b = (color & 31)*level;
+ return (r<<10)|(g<<5)|b;
+}
+#endif
+// xe = xc + (x/z * zm + tx)
+// xe < x1 => xc + (x/z * zm + tx) < x1
+// => x/z < (x1-xc-tx)/zm
+// => x < z*(x1-xc-tx)/zm
+
+// ye = yc - (y/z * zm + ty)
+// ye < y1 => yc - (y/z * zm + ty) < y1
+// => -y/z < (y1-yc+ty)/zm
+// => y > -z*(y1-yc+ty)/zm
+
+// xf = zf*a
+// xx = x1*t+x2(1-t); zz = z1*t+z2(1-t)
+// => x1*t+x2(1-t) = z1*t*a+z2*(1-t)*a
+// => t*(x1-x2+a*(z2-z1) = -x2+a*z2
+// => t = (z2*a-x2)/((z2-z1)*a-(x2-x1))
+
+static void recompute_frustrum(void)
+{
+ view.a_left = ( view.x1-view.xc-view.transx)/view.zoomx;
+ view.a_right = ( view.x2-view.xc-view.transx)/view.zoomx;
+ view.a_bottom = (-view.y1+view.yc-view.transy)/view.zoomy;
+ view.a_top = (-view.y2+view.yc-view.transy)/view.zoomy;
+}
+
+static int fclip_isc_bottom(struct point *p)
+{
+ return p->y > p->z*view.a_bottom;
+}
+
+static struct point *fclip_clip_bottom(struct point *p1, struct point *p2)
+{
+ float t = (p2->z*view.a_bottom-p2->y)/((p2->z-p1->z)*view.a_bottom-(p2->y-p1->y));
+ pointpt->x = p1->x*t + p2->x*(1-t);
+ pointpt->y = p1->y*t + p2->y*(1-t);
+ pointpt->z = p1->z*t + p2->z*(1-t);
+ project_point(pointpt);
+ return pointpt++;
+}
+
+static int fclip_isc_top(struct point *p)
+{
+ return p->y < p->z*view.a_top;
+}
+
+static struct point *fclip_clip_top(struct point *p1, struct point *p2)
+{
+ float t = (p2->z*view.a_top-p2->y)/((p2->z-p1->z)*view.a_top-(p2->y-p1->y));
+ pointpt->x = p1->x*t + p2->x*(1-t);
+ pointpt->y = p1->y*t + p2->y*(1-t);
+ pointpt->z = p1->z*t + p2->z*(1-t);
+ project_point(pointpt);
+ return pointpt++;
+}
+
+static int fclip_isc_left(struct point *p)
+{
+ return p->x < p->z*view.a_left;
+}
+
+static struct point *fclip_clip_left(struct point *p1, struct point *p2)
+{
+ float t = (p2->z*view.a_left-p2->x)/((p2->z-p1->z)*view.a_left-(p2->x-p1->x));
+ pointpt->x = p1->x*t + p2->x*(1-t);
+ pointpt->y = p1->y*t + p2->y*(1-t);
+ pointpt->z = p1->z*t + p2->z*(1-t);
+ project_point(pointpt);
+ return pointpt++;
+}
+
+static int fclip_isc_right(struct point *p)
+{
+ return p->x > p->z*view.a_right;
+}
+
+static struct point *fclip_clip_right(struct point *p1, struct point *p2)
+{
+ float t = (p2->z*view.a_right-p2->x)/((p2->z-p1->z)*view.a_right-(p2->x-p1->x));
+ pointpt->x = p1->x*t + p2->x*(1-t);
+ pointpt->y = p1->y*t + p2->y*(1-t);
+ pointpt->z = p1->z*t + p2->z*(1-t);
+ project_point(pointpt);
+ return pointpt++;
+}
+
+static struct {
+ int (*isclipped)(struct point *p);
+ struct point *(*clip)(struct point *p1, struct point *p2);
+} clipfn[4] = {
+ { fclip_isc_bottom, fclip_clip_bottom },
+ { fclip_isc_top, fclip_clip_top },
+ { fclip_isc_left, fclip_clip_left },
+ { fclip_isc_right, fclip_clip_right },
+};
+
+static void fclip_push_quad(int level, struct quad *q);
+
+static void fclip_push_quad_next(int level, struct quad *q,
+ struct point *p1, struct point *p2, struct point *p3, struct point *p4)
+{
+ struct quad q2;
+ q2.col = q->col;
+ q2.z = q->z;
+ q2.p[0] = p1;
+ q2.p[1] = p2;
+ q2.p[2] = p3;
+ q2.p[3] = p4;
+
+ fclip_push_quad(level+1, &q2);
+}
+
+static void fclip_push_quad(int level, struct quad *q)
+{
+ int i, j;
+ struct point *pt[4], *pi1, *pi2;
+ int is_out[4], is_out2[4];
+ struct point *(*fclip_point)(struct point *p1, struct point *p2);
+
+ if(level == 4) {
+ LOG_TGP("VIDEOCQ %d", level);
+ for(i=0; i<4; i++)
+ LOG_TGP(" (%f, %f, %f)", q->p[i]->x, q->p[i]->y, q->p[i]->z);
+ LOG_TGP("\n");
+ *quadpt = *q;
+ quadpt++;
+ return;
+ }
+
+ for(i=0; i<4; i++)
+ is_out[i] = clipfn[level].isclipped(q->p[i]);
+
+ LOG_TGP("VIDEOCQ %d", level);
+ for(i=0; i<4; i++)
+ LOG_TGP(" (%f, %f, %f, %d)", q->p[i]->x, q->p[i]->y, q->p[i]->z, is_out[i]);
+ LOG_TGP("\n");
+
+ // No clipping
+ if(!is_out[0] && !is_out[1] && !is_out[2] && !is_out[3]) {
+ fclip_push_quad(level+1, q);
+ return;
+ }
+
+ fclip_point = clipfn[level].clip;
+
+ // Full clipping
+ if(is_out[0] && is_out[1] && is_out[2] && is_out[3])
+ return;
+
+ // Find n so that point n is clipped and n-1 isn't
+ for(i=0; i<4; i++)
+ if(is_out[i] && !is_out[(i-1)&3])
+ break;
+
+ for(j=0; j<4; j++) {
+ pt[j] = q->p[(i+j)&3];
+ is_out2[j] = is_out[(i+j)&3];
+ }
+
+ // At this point, pt[0] is clipped out and pt[3] isn't. Test for the 4 possible cases
+ if(is_out2[1])
+ if(is_out2[2]) {
+ // pt 0,1,2 clipped out, one triangle left
+ pi1 = fclip_point(pt[2], pt[3]);
+ pi2 = fclip_point(pt[3], pt[0]);
+ fclip_push_quad_next(level, q, pi1, pt[3], pi2, pi2);
+ } else {
+ // pt 0,1 clipped out, one quad left
+ pi1 = fclip_point(pt[1], pt[2]);
+ pi2 = fclip_point(pt[3], pt[0]);
+ fclip_push_quad_next(level, q, pi1, pt[2], pt[3], pi2);
+ }
+ else
+ if(is_out2[2]) {
+ // pt 0,2 clipped out, shouldn't happen, two triangles
+ pi1 = fclip_point(pt[0], pt[1]);
+ pi2 = fclip_point(pt[1], pt[2]);
+ fclip_push_quad_next(level, q, pi1, pt[1], pi2, pi2);
+ pi1 = fclip_point(pt[2], pt[3]);
+ pi2 = fclip_point(pt[3], pt[0]);
+ fclip_push_quad_next(level, q, pi1, pt[3], pi2, pi2);
+ } else {
+ // pt 0 clipped out, one decagon left, split in quad+tri
+ pi1 = fclip_point(pt[0], pt[1]);
+ pi2 = fclip_point(pt[3], pt[0]);
+ fclip_push_quad_next(level, q, pi1, pt[1], pt[2], pt[3]);
+ fclip_push_quad_next(level, q, pt[3], pi2, pi1, pi1);
+ }
+}
+
+static float min4f(float a, float b, float c, float d)
+{
+ float m = a;
+ if(b<m)
+ m = b;
+ if(c<m)
+ m = c;
+ if(d<m)
+ m = d;
+ return m;
+}
+
+static float max4f(float a, float b, float c, float d)
+{
+ float m = a;
+ if(b>m)
+ m = b;
+ if(c>m)
+ m = c;
+ if(d>m)
+ m = d;
+ return m;
+}
+
+static const UINT8 num_of_times[]={1,1,1,1,2,2,2,3};
+static float compute_specular(struct vector *normal, struct vector *light,float diffuse,int lmode)
+{
+#if 0
+ float s;
+ int p=lightparams[lmode].p&7;
+ int i;
+ float sv=lightparams[lmode].s;
+
+ //This is how it should be according to model2 geo program, but doesn't work fine
+ s=2*(diffuse*normal->z-light->z);
+ for(i=0;i<num_of_times[p];++i)
+ s*=s;
+ s*=sv;
+ if(s<0.0)
+ return 0.0;
+ if(s>1.0)
+ return 1.0;
+ return s;
+
+ return fabs(diffuse)*sv;
+
+#endif
+
+ return 0;
+}
+
+static void push_object(UINT32 tex_adr, UINT32 poly_adr, UINT32 size)
+{
+ int i;
+ UINT32 flags;
+ struct point *old_p0, *old_p1, *p0, *p1;
+ struct vector vn;
+ int link, type;
+ int dump;
+ int lightmode;
+ float old_z;
+ struct quad cquad;
+ float *poly_data;
+
+ if(poly_adr & 0x800000)
+ poly_data=(float *) poly_ram;
+ else
+ poly_data=(float *) poly_rom;
+
+ poly_adr &= 0x7fffff;
+ dump = poly_adr == 0x944ea;
+ dump = 0;
+
+#if 0
+ if(poly_adr < 0x10000 || poly_adr >= 0x80000)
+ return;
+
+ if(poly_adr < 0x40000 || poly_adr >= 0x50000)
+ return;
+
+ if(poly_adr == 0x4c7db || poly_adr == 0x4cdaa || poly_adr == 0x4d3e7)
+ return;
+
+ if(poly_adr != 0x483e5)
+ return;
+#endif
+
+ if(1) {
+ LOG_TGP("XVIDEO: draw object (%x, %x, %x)\n", tex_adr, poly_adr, size);
+ }
+
+ if(!size)
+ size = 0xffffffff;
+
+ old_p0 = pointpt++;
+ old_p1 = pointpt++;
+
+ old_p0->x = poly_data[poly_adr+0];
+ old_p0->y = poly_data[poly_adr+1];
+ old_p0->z = poly_data[poly_adr+2];
+ old_p1->x = poly_data[poly_adr+3];
+ old_p1->y = poly_data[poly_adr+4];
+ old_p1->z = poly_data[poly_adr+5];
+ transform_point(old_p0);
+ transform_point(old_p1);
+ if(old_p0->z > 0)
+ project_point(old_p0);
+ else
+ old_p0->s.x = old_p0->s.y = 0;
+ if(old_p1->z > 0)
+ project_point(old_p1);
+ else
+ old_p1->s.x = old_p1->s.y = 0;
+
+ old_z = 0;
+
+ poly_adr += 6;
+
+ for(i=0; i<size; i++) {
+#if 0
+ LOG_TGP("VIDEO: %08x (%f, %f, %f) (%f, %f, %f) (%f, %f, %f)\n",
+ *(UINT32 *)(poly_data+poly_adr) & ~(0x01800303),
+ poly_data[poly_adr+1], poly_data[poly_adr+2], poly_data[poly_adr+3],
+ poly_data[poly_adr+4], poly_data[poly_adr+5], poly_data[poly_adr+6],
+ poly_data[poly_adr+7], poly_data[poly_adr+8], poly_data[poly_adr+9]);
+#endif
+ flags = *(UINT32 *)(poly_data+poly_adr);
+
+ type = flags & 3;
+ if(!type)
+ break;
+
+ if(flags & 0x00001000)
+ tex_adr ++;
+ lightmode=(flags>>17)&15;
+
+ p0 = pointpt++;
+ p1 = pointpt++;
+
+ vn.x = poly_data[poly_adr+1];
+ vn.y = poly_data[poly_adr+2];
+ vn.z = poly_data[poly_adr+3];
+ p0->x = poly_data[poly_adr+4];
+ p0->y = poly_data[poly_adr+5];
+ p0->z = poly_data[poly_adr+6];
+ p1->x = poly_data[poly_adr+7];
+ p1->y = poly_data[poly_adr+8];
+ p1->z = poly_data[poly_adr+9];
+
+ link = (flags >> 8) & 3;
+
+ transform_vector(&vn);
+
+ transform_point(p0);
+ transform_point(p1);
+ if(p0->z > 0)
+ project_point(p0);
+ else
+ p0->s.x = p0->s.y = 0;
+ if(p1->z > 0)
+ project_point(p1);
+ else
+ p1->s.x = p1->s.y = 0;
+
+#if 0
+ if(dump)
+ LOG_TGP("VIDEO: %08x (%f, %f, %f) (%f, %f, %f)\n",
+ *(UINT32 *)(poly_data+poly_adr),
+ p0->x, p0->y, p0->z,
+ p1->x, p1->y, p1->z);
+#endif
+
+
+#if 0
+ if(1 || dump) {
+ LOG_TGP("VIDEO: %08x (%d, %d) (%d, %d) (%d, %d) (%d, %d)\n",
+ *(UINT32 *)(poly_data+poly_adr),
+ old_p0->s.x, old_p0->s.y,
+ old_p1->s.x, old_p1->s.y,
+ p0->s.x, p0->s.y,
+ p1->s.x, p1->s.y);
+ }
+#endif
+
+ if(!link)
+ goto next;
+
+ if(!(flags & 0x00004000) && view_determinant(old_p1, old_p0, p0) > 0)
+ goto next;
+
+ normalize_vector(&vn);
+
+ cquad.p[0] = old_p1;
+ cquad.p[1] = old_p0;
+ cquad.p[2] = p0;
+ cquad.p[3] = p1;
+
+ switch((flags >> 10) & 3) {
+ case 0:
+ cquad.z = old_z;
+ break;
+ case 1:
+ cquad.z = old_z = min4f(old_p1->z, old_p0->z, p0->z, p1->z);
+ break;
+ case 2:
+ cquad.z = old_z = max4f(old_p1->z, old_p0->z, p0->z, p1->z);
+ break;
+ case 3:
+ default:
+ cquad.z = 0.0;
+ break;
+ }
+
+ {
+ /*float dif=mult_vector(&vn, &view.light);
+ float ln=lightparams[lightmode].a + lightparams[lightmode].d*MAX(0.0,dif);
+ cquad.col = scale_color(Machine->pens[0x1000|(tgp_ram[tex_adr-0x40000] & 0x3ff)], MIN(1.0,ln));
+ cquad.col = scale_color(Machine->pens[0x1000|(tgp_ram[tex_adr-0x40000] & 0x3ff)], MIN(1.0,ln));
+ */
+ float dif=mult_vector(&vn, &view.light);
+ float spec=compute_specular(&vn,&view.light,dif,lightmode);
+ float ln=lightparams[lightmode].a + lightparams[lightmode].d*MAX(0.0,dif) + spec;
+ int lumval=255.0*MIN(1.0,ln);
+ int color=paletteram16[0x1000|(tgp_ram[tex_adr-0x40000] & 0x3ff)];
+ int r=(color>>0x0)&0x1f;
+ int g=(color>>0x5)&0x1f;
+ int b=(color>>0xA)&0x1f;
+ lumval>>=2; //there must be a luma translation table somewhere
+ if(lumval>0x3f) lumval=0x3f;
+ else if(lumval<0) lumval=0;
+ r=(model1_color_xlat[(r<<8)|lumval|0x0]>>3)&0x1f;
+ g=(model1_color_xlat[(g<<8)|lumval|0x2000]>>3)&0x1f;
+ b=(model1_color_xlat[(b<<8)|lumval|0x4000]>>3)&0x1f;
+ cquad.col=(r<<10)|(g<<5)|(b<<0);
+ }
+
+ if(flags & 0x00002000)
+ cquad.col |= MOIRE;
+
+ fclip_push_quad(0, &cquad);
+
+ next:
+ poly_adr += 10;
+ switch(link) {
+ case 0:
+ case 2:
+ old_p0 = p0;
+ old_p1 = p1;
+ break;
+ case 1:
+ old_p1 = p0;
+ break;
+ case 3:
+ old_p0 = p1;
+ break;
+ }
+ }
+}
+
+static UINT16 *push_direct(UINT16 *list)
+{
+ UINT32 flags;
+ UINT32 tex_adr, lum, v1, v2;
+ struct point *old_p0, *old_p1, *p0, *p1;
+ int link, type;
+ float z;
+ struct quad cquad;
+
+ tex_adr = readi(list);
+ v1 = readi(list+2);
+ v2 = readi(list+10);
+
+ old_p0 = pointpt++;
+ old_p1 = pointpt++;
+
+ old_p0->x = readf(list+4);
+ old_p0->y = readf(list+6);
+ old_p0->z = readf(list+8);
+ old_p1->x = readf(list+12);
+ old_p1->y = readf(list+14);
+ old_p1->z = readf(list+16);
+
+ LOG_TGP("VIDEOD start direct\n");
+ LOG_TGP("VIDEOD (%f, %f, %f) (%f, %f, %f)\n",
+ old_p0->x, old_p0->y, old_p0->z,
+ old_p1->x, old_p1->y, old_p1->z);
+
+// transform_point(old_p0);
+// transform_point(old_p1);
+ if(old_p0->z > 0)
+ project_point_direct(old_p0);
+ else
+ old_p0->s.x = old_p0->s.y = 0;
+ if(old_p1->z > 0)
+ project_point_direct(old_p1);
+ else
+ old_p1->s.x = old_p1->s.y = 0;
+
+ list += 18;
+
+ for(;;) {
+ flags = readi(list);
+
+ type = flags & 3;
+ if(!type)
+ break;
+
+ if(flags & 0x00001000)
+ tex_adr ++;
+
+ // list+2 is luminosity
+ // list+4 is 0?
+ // list+12 is z?
+
+ p0 = pointpt++;
+ p1 = pointpt++;
+
+ lum = readi(list+2);
+ v1 = readi(list+4);
+
+ if(type == 2) {
+ p0->x = readf(list+6);
+ p0->y = readf(list+8);
+ p0->z = readf(list+10);
+ z = p0->z;
+ LOG_TGP("VIDEOD %08x %08x (%f, %f, %f)\n",
+ flags, lum,
+ p0->x, p0->y, p0->z);
+ *p1 = *p0;
+ list += 12;
+ } else {
+ p0->x = readf(list+6);
+ p0->y = readf(list+8);
+ p0->z = readf(list+10);
+ p1->x = readf(list+14);
+ p1->y = readf(list+16);
+ p1->z = readf(list+18);
+ z = readf(list+12);
+ LOG_TGP("VIDEOD %08x %08x (%f, %f, %f) (%f, %f, %f)\n",
+ flags, lum,
+ p0->x, p0->y, p0->z,
+ p1->x, p1->y, p1->z);
+ list += 20;
+ }
+
+ link = (flags >> 8) & 3;
+
+// transform_point(p0);
+// transform_point(p1);
+ if(p0->z > 0)
+ project_point_direct(p0);
+ if(p1->z > 0)
+ project_point_direct(p1);
+
+#if 1
+ if(old_p0 && old_p1)
+ LOG_TGP("VIDEOD: %08x (%d, %d) (%d, %d) (%d, %d) (%d, %d)\n",
+ flags,
+ old_p0->s.x, old_p0->s.y,
+ old_p1->s.x, old_p1->s.y,
+ p0->s.x, p0->s.y,
+ p1->s.x, p1->s.y);
+ else
+ LOG_TGP("VIDEOD: %08x (%d, %d) (%d, %d)\n",
+ flags,
+ p0->s.x, p0->s.y,
+ p1->s.x, p1->s.y);
+
+#endif
+
+ if(!link)
+ goto next;
+
+ cquad.p[0] = old_p1;
+ cquad.p[1] = old_p0;
+ cquad.p[2] = p0;
+ cquad.p[3] = p1;
+ cquad.z = z;
+ {
+ int lumval=((float) (lum>>24)) * 2.0;
+ int color=paletteram16[0x1000|(tgp_ram[tex_adr-0x40000] & 0x3ff)];
+ int r=(color>>0x0)&0x1f;
+ int g=(color>>0x5)&0x1f;
+ int b=(color>>0xA)&0x1f;
+ lumval>>=2; //there must be a luma translation table somewhere
+ if(lumval>0x3f) lumval=0x3f;
+ else if(lumval<0) lumval=0;
+ r=(model1_color_xlat[(r<<8)|lumval|0x0]>>3)&0x1f;
+ g=(model1_color_xlat[(g<<8)|lumval|0x2000]>>3)&0x1f;
+ b=(model1_color_xlat[(b<<8)|lumval|0x4000]>>3)&0x1f;
+ cquad.col=(r<<10)|(g<<5)|(b<<0);
+ }
+ //cquad.col = scale_color(Machine->pens[0x1000|(tgp_ram[tex_adr-0x40000] & 0x3ff)],((float) (lum>>24)) / 128.0);
+ if(flags & 0x00002000)
+ cquad.col |= MOIRE;
+
+ fclip_push_quad(0, &cquad);
+
+ next:
+ switch(link) {
+ case 0:
+ case 2:
+ old_p0 = p0;
+ old_p1 = p1;
+ break;
+ case 1:
+ old_p1 = p0;
+ break;
+ case 3:
+ old_p0 = p1;
+ break;
+ }
+ }
+ return list+2;
+}
+
+static UINT16 *skip_direct(UINT16 *list)
+{
+ UINT32 flags;
+ int type;
+
+ list += 18;
+
+ for(;;) {
+ flags = readi(list);
+
+ type = flags & 3;
+ if(!type)
+ break;
+
+ if(type == 2)
+ list += 12;
+ else
+ list += 20;
+ }
+ return list+2;
+}
+
+static void draw_objects(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ if(quadpt != quaddb) {
+ LOG_TGP("VIDEO: sort&draw\n");
+ sort_quads();
+ draw_quads(bitmap, cliprect);
+ }
+
+ quadpt = quaddb;
+ pointpt = pointdb;
+}
+
+static UINT16 *draw_direct(UINT16 *list, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT16 *res;
+
+ LOG_TGP("VIDEO: draw direct %x\n", readi(list));
+
+ draw_objects(bitmap, cliprect);
+ res = push_direct(list);
+ unsort_quads();
+ draw_quads(bitmap, cliprect);
+
+ quadpt = quaddb;
+ pointpt = pointdb;
+ return res;
+}
+
+static UINT16 *get_list(void)
+{
+ if(!(listctl[0] & 4))
+ listctl[0] = (listctl[0] & ~0x40) | (listctl[0] & 8 ? 0x40 : 0);
+ return listctl[0] & 0x40 ? model1_display_list1 : model1_display_list0;
+}
+
+static int get_list_number(void)
+{
+ if(!(listctl[0] & 4))
+ listctl[0] = (listctl[0] & ~0x40) | (listctl[0] & 8 ? 0x40 : 0);
+ return listctl[0] & 0x40 ? 0 : 1;
+}
+
+static void end_frame(void)
+{
+ if((listctl[0] & 4) && (cpu_getcurrentframe() & 1))
+ listctl[0] ^= 0x40;
+}
+
+READ16_HANDLER( model1_listctl_r )
+{
+ if(!offset)
+ return listctl[0] | 0x30;
+ else
+ return listctl[1];
+}
+
+WRITE16_HANDLER( model1_listctl_w )
+{
+ COMBINE_DATA(listctl+offset);
+ LOG_TGP("VIDEO: control=%08x\n", (listctl[1]<<16)|listctl[0]);
+}
+
+static void tgp_render(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ render_done = 1;
+ if((listctl[1] & 0x1f) == 0x1f) {
+ UINT16 *list = get_list();
+ int zz = 0;
+ LOG_TGP("VIDEO: render list %d\n", get_list_number());
+
+ memset(trans_mat, 0, sizeof(trans_mat));
+ trans_mat[0] = 1.0;
+ trans_mat[4] = 1.0;
+ trans_mat[8] = 1.0;
+
+ for(;;) {
+ int type = (list[1]<<16)|list[0];
+ glist=list;
+ switch(type & 15) {
+ case 0:
+ list += 2;
+ break;
+ case 1:
+ // 1 = plane 1
+ // 2 = ?? draw object (413d3, 17c4c, e)
+ // 3 = plane 2
+ // 4 = ?? draw object (408a8, a479, 9)
+ // 5 = decor
+ // 6 = ?? draw object (57bd4, 387460, 2ad)
+
+ if(1 || zz >= 666)
+ push_object(readi(list+2), readi(list+4), readi(list+6));
+ list += 8;
+ break;
+ case 2:
+ list = draw_direct(list+2, bitmap, cliprect);
+ break;
+ case 3:
+ LOG_TGP("VIDEO: viewport (%d, %d, %d, %d, %d, %d, %d)\n",
+ readi(list+2),
+ readi16(list+4), readi16(list+6), readi16(list+8),
+ readi16(list+10), readi16(list+12), readi16(list+14));
+
+ draw_objects(bitmap, cliprect);
+
+ view.xc = readi16(list+4);
+ view.yc = 383-(readi16(list+6)-39);
+ view.x1 = readi16(list+8);
+ view.y2 = 383-(readi16(list+10)-39);
+ view.x2 = readi16(list+12);
+ view.y1 = 383-(readi16(list+14)-39);
+
+ recompute_frustrum();
+
+ list += 16;
+ break;
+ case 4: {
+ int adr = readi(list+2);
+ int len = readi(list+4)+1;
+ int i;
+ LOG_TGP("ZVIDEO: color write, adr=%x, len=%x\n", adr, len);
+ for(i=0; i<len; i++)
+ tgp_ram[adr-0x40000+i] = list[6+2*i];
+ list += 6+len*2;
+ break;
+ }
+ case 5:
+ {
+ int adr = readi(list+2);
+ int len = readi(list+4);
+ int i;
+ for(i=0;i<len;++i)
+ {
+ poly_ram[adr-0x800000+i]=readi(list+2*i+6);
+ }
+ list+=6+len*2;
+ }
+ break;
+ case 6: {
+ int adr = readi(list+2);
+ int len = readi(list+4);
+ int i;
+ LOG_TGP("VIDEO: upload data, adr=%x, len=%x\n", adr, len);
+ for(i=0;i<len;++i)
+ {
+ int v=readi(list+6+i*2);
+ lightparams[i+adr].d=((float) (v&0xff))/255.0;
+ lightparams[i+adr].a=((float) ((v>>8)&0xff))/255.0;
+ lightparams[i+adr].s=((float) ((v>>16)&0xff))/255.0;
+ lightparams[i+adr].p=(v>>24)&0xff;
+ }
+ list += 6+len*2;
+ break;
+ }
+ case 7:
+ LOG_TGP("VIDEO: code 7 (%d)\n", readi(list+2));
+ zz++;
+ list += 4;
+ break;
+ case 8:
+ LOG_TGP("VIDEO: select mode %08x\n", readi(list+2));
+ list += 4;
+ break;
+ case 9:
+ LOG_TGP("VIDEO: zoom (%f, %f)\n", readf(list+2), readf(list+4));
+ view.zoomx = readf(list+2)*4;
+ view.zoomy = readf(list+4)*4;
+
+ recompute_frustrum();
+
+ list += 6;
+ break;
+ case 0xa:
+ LOG_TGP("VIDEO: light vector (%f, %f, %f)\n", readf(list+2), readf(list+4), readf(list+6));
+ view.light.x = readf(list+2);
+ view.light.y = readf(list+4);
+ view.light.z = readf(list+6);
+ normalize_vector(&view.light);
+ list += 8;
+ break;
+ case 0xb: {
+ int i;
+ LOG_TGP("VIDEO: matrix (%f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f)\n",
+ readf(list+2), readf(list+4), readf(list+6),
+ readf(list+8), readf(list+10), readf(list+12),
+ readf(list+14), readf(list+16), readf(list+18),
+ readf(list+20), readf(list+22), readf(list+24));
+ for(i=0; i<12; i++)
+ trans_mat[i] = readf(list+2+2*i);
+ list += 26;
+ break;
+ }
+ case 0xc:
+ LOG_TGP("VIDEO: trans (%f, %f)\n", readf(list+2), readf(list+4));
+ view.transx = readf(list+2);
+ view.transy = readf(list+4);
+
+ recompute_frustrum();
+
+ list += 6;
+ break;
+ case 0xf:
+ case -1:
+ goto end;
+ default:
+ LOG_TGP("VIDEO: unknown type %d\n", type);
+ goto end;
+ }
+ }
+ end:
+ draw_objects(bitmap, cliprect);
+ }
+}
+
+static void tgp_scan(void)
+{
+#if 0
+ if (input_code_pressed_once(KEYCODE_F))
+ {
+ FILE *fp;
+ fp=fopen("tgp-ram.bin", "w+b");
+ if (fp)
+ {
+ fwrite(tgp_ram, (0x100000-0x40000)*2, 1, fp);
+ fclose(fp);
+ }
+ exit(0);
+ }
+#endif
+ if(!render_done && (listctl[1] & 0x1f) == 0x1f) {
+ UINT16 *list = get_list();
+ // Skip everything but the data uploads
+ LOG_TGP("VIDEO: scan list %d\n", get_list_number());
+ for(;;) {
+ int type = (list[1]<<16)|list[0];
+ switch(type) {
+ case 0:
+ list += 2;
+ break;
+ case 1:
+ list += 8;
+ break;
+ case 2:
+ list = skip_direct(list+2);
+ break;
+ case 3:
+ list += 16;
+ break;
+ case 4: {
+ int adr = readi(list+2);
+ int len = readi(list+4)+1;
+ int i;
+ LOG_TGP("ZVIDEO: scan color write, adr=%x, len=%x\n", adr, len);
+ for(i=0; i<len; i++)
+ tgp_ram[adr-0x40000+i] = list[6+2*i];
+ list += 6+len*2;
+ break;
+ }
+ case 5:
+ {
+ int adr = readi(list+2);
+ int len = readi(list+4);
+ int i;
+ for(i=0;i<len;++i)
+ {
+ poly_ram[adr-0x800000+i]=readi(list+2*i+6);
+ }
+ list+=6+len*2;
+ }
+ break;
+ case 6: {
+ int adr = readi(list+2);
+ int len = readi(list+4);
+ int i;
+ //LOG_TGP("VIDEO: upload data, adr=%x, len=%x\n", adr, len);
+ for(i=0;i<len;++i)
+ {
+ int v=readi(list+6+i*2);
+ lightparams[i+adr].d=((float) (v&0xff))/255.0;
+ lightparams[i+adr].a=((float) ((v>>8)&0xff))/255.0;
+ lightparams[i+adr].s=((float) ((v>>16)&0xff))/255.0;
+ lightparams[i+adr].p=(v>>24)&0xff;
+ //LOG_TGP(" %02X\n",v);
+ }
+ list += 6+len*2;
+ break;
+ }
+ case 7:
+ list += 4;
+ break;
+ case 8:
+ list += 4;
+ break;
+ case 9:
+ list += 6;
+ break;
+ case 0xa:
+ list += 8;
+ break;
+ case 0xb:
+ list += 26;
+ break;
+ case 0xc:
+ list += 6;
+ break;
+ case 0xf:
+ case -1:
+ goto end;
+ default:
+ LOG_TGP("VIDEO: unknown type %d\n", type);
+ goto end;
+ }
+ }
+ end:
+ ;
+ }
+ render_done = 0;
+}
+
+VIDEO_START(model1)
+{
+ vxx=vyy=vzz=0;
+ ayy = 0;
+
+ sys24_tile_vh_start(machine, 0x3fff);
+
+ poly_rom = (UINT32 *)memory_region(REGION_USER1);
+ poly_ram = auto_malloc(0x400000*4);
+ memset(poly_ram, 0, 0x400000*4);
+ tgp_ram = auto_malloc((0x100000-0x40000)*2);
+ memset(tgp_ram, 0, (0x100000-0x40000)*2);
+ pointdb = auto_malloc(1000000*2*sizeof(struct point));
+ memset(pointdb, 0, 1000000*2*sizeof(struct point));
+ quaddb = auto_malloc(1000000*sizeof(struct quad));
+ memset(quaddb, 0, 1000000*sizeof(struct quad));
+ quadind = auto_malloc(1000000*sizeof(struct quad *));
+ memset(quadind, 0, 1000000*sizeof(struct quad *));
+
+ pointpt = pointdb;
+ quadpt = quaddb;
+ listctl[0] = listctl[1] = 0;
+
+ state_save_register_global_pointer(tgp_ram, 0x100000-0x40000);
+ state_save_register_global_pointer(poly_ram, 0x40000);
+ state_save_register_global_array(listctl);
+}
+
+VIDEO_UPDATE(model1)
+{
+ sys24_tile_update(machine);
+#if 0
+ {
+ int mod = 0;
+ double delta;
+ delta = 1;
+
+ if(input_code_pressed(KEYCODE_F)) {
+ mod = 1;
+ vxx -= delta;
+ }
+ if(input_code_pressed(KEYCODE_G)) {
+ mod = 1;
+ vxx += delta;
+ }
+ if(input_code_pressed(KEYCODE_H)) {
+ mod = 1;
+ vyy -= delta;
+ }
+ if(input_code_pressed(KEYCODE_J)) {
+ mod = 1;
+ vyy += delta;
+ }
+ if(input_code_pressed(KEYCODE_K)) {
+ mod = 1;
+ vzz -= delta;
+ }
+ if(input_code_pressed(KEYCODE_L)) {
+ mod = 1;
+ vzz += delta;
+ }
+ if(input_code_pressed(KEYCODE_U)) {
+ mod = 1;
+ ayy -= 0.05;
+ }
+ if(input_code_pressed(KEYCODE_I)) {
+ mod = 1;
+ ayy += 0.05;
+ }
+ if(mod)
+ popmessage("%g,%g,%g:%g", vxx, vyy, vzz, ayy);
+ }
+#endif
+
+ ayyc = cos(ayy);
+ ayys = sin(ayy);
+
+ fillbitmap(priority_bitmap, 0, NULL);
+ fillbitmap(bitmap, machine->pens[0], &machine->screen[0].visarea);
+
+ sys24_tile_draw(machine, bitmap, cliprect, 6, 0, 0);
+ sys24_tile_draw(machine, bitmap, cliprect, 4, 0, 0);
+ sys24_tile_draw(machine, bitmap, cliprect, 2, 0, 0);
+ sys24_tile_draw(machine, bitmap, cliprect, 0, 0, 0);
+
+ tgp_render(bitmap, cliprect);
+
+ sys24_tile_draw(machine, bitmap, cliprect, 7, 0, 0);
+ sys24_tile_draw(machine, bitmap, cliprect, 5, 0, 0);
+ sys24_tile_draw(machine, bitmap, cliprect, 3, 0, 0);
+ sys24_tile_draw(machine, bitmap, cliprect, 1, 0, 0);
+
+ return 0;
+}
+
+VIDEO_EOF(model1)
+{
+ tgp_scan();
+ end_frame();
+ LOG_TGP("TGP: vsync\n");
+}
diff --git a/src/mame/video/model2.c b/src/mame/video/model2.c
new file mode 100644
index 00000000000..6e337d65844
--- /dev/null
+++ b/src/mame/video/model2.c
@@ -0,0 +1,2773 @@
+/*********************************************************************************************************************************
+
+ Sega Model 2 Geometry Engine and 3D Rasterizer Emulation
+
+ General Notes:
+
+ - The 3D rendering system has 3 main parts:
+ 1) The Geometry Engine: Model 2B and 2C hardware upload the geometry code to a DSP. The original and 2A hardware
+ have the geometry code in an internal ROM inside the DSP itself. The simulation written here for the geometry engine
+ is based off the disassembly of the code uploaded to a 2B game.
+ 2) The Z-Sort and Clip Hardware: Not much information about this hardware. There are a couple of variables that
+ can be passed to this stage, like a master Z-Clip enable register, and a Z-Sort mode variable.
+ 3) The Hardware Renderer: Not much information about the inner workings of this hardware. Based on the available
+ tidbits from the 2B manual, it is a double-buffered device (can be toggled between page flipping and single
+ buffer mode), and can also be switched to generate output at 60Hz or 30Hz.
+
+ - Most of the information used to write this code come from 3 main sources:
+ 1) The Geometry Engine code disassembly from a 2B game.
+ 2) The Model 2B-CRX Manual.
+ 3) ElSemi's Direct3D implementation of the geometrizer engine.
+
+ - The emulation strategy used here is to decouple the geometrizer code from the Z-Sort/Clip/Renderer code, so that for
+ original and 2A games, the HLE version of the geometrizer can be used, while for 2B and 2C games, the original geometrizer
+ DSP can be emulated, and data can be pushed to the Z-Sort/Clip/Renderer code.
+
+
+
+ Geometry Engine Notes and Known Bugs:
+
+ - Top Skater seem to use a slightly different geometry code that has a secondary transformation matrix. Once we implement
+ the real DSP code upload and emulation for 2B and 2C games, this should not be an issue.
+
+
+
+ Z-Sort Notes and Known Bugs:
+
+ - The Z-Sort algorithm is not entirely understood. The manual states that the Z-Sort works internally in 1.4.8 bit format,
+ but then it states that the Z-Sort Mode register value is added to the floating point z value, and converted to a 16 bit
+ format (most likely 4.12).
+ - The system allows for Z-Sort override, by means of specifying wether a polygon will use the same Z value ordinal as the
+ previous polygon, or the calculated minimum or maximum from it's points. This allows for a full object to be in front of
+ another, even though the first object might have some z coordinates that are bigger than the second object's z coordinates.
+ - The current implementation takes the effective computed z value for the polygon and converts it into a 4.12 fixed point
+ representation, used as an index into an array of linked polygons. Every polygon with the same z value is linked with any
+ previous polygon that had that same z value:
+
+ z-value index linked list of polygons
+ 0000 triangle3->triangle2->triangle1
+ 0001 triangle22->triangle8->triangle7
+ ....
+ FFFF triangle33->triangle11->triangle9
+
+ As we add polygons to the array, we also keep track of the minimum and maximum z-value indexes seen this frame.
+ When it's time to render, we start and the max z-value seen, and iterate through the array going down to the minimum
+ z-value seen, clipping and rendering the linked polygons as we go.
+ Unfortunately, it seems there's something not quite right, as there are some visible Z-Sort problems in various games.
+ Perhaps the linked list of polygons need to be presorted by a unknown factor before rendering.
+
+
+
+ Clip Notes and Known Bugs:
+
+ - The Z-Clip happens at z=0. Since dividing by 0 during projection would give bogus values, we scale by a distance of
+ 1, thus our projection equation turns into vd.x = (d*vs.x) / (d+vs.z) where d = 1, since we know we won't have polygons
+ with a z < 0. This, however, poses the problem that for objects originally between 0.0 and 1.0 are not going to be
+ scaled properly. We still need to find a solution for this.
+ - A small offset need to be added horizontally and vertically to the viewport and center variables for certain games (like
+ the original Model 2 games). The coordinate system has been worked out from the 2B specifications, but the older games
+ need a slight adjustment.
+
+
+
+ Hardware Renderer Notes and Known Bugs:
+
+ - Texturing code could use a real good speed optimization.
+ - The U and V coordinates provided by the game are in 13.3 fixed point format.
+ - The luma/texel combination algorithm is not known. There are currently some small color glitches here and
+ there, and this might be the culprit.
+ - The log tables and distance coefficients are used to calculate the number of texels per world unit that need to
+ be used to render a texture. Textures can also be provided with smaller levels of details and a LOD bit selector
+ in the texture header tells the rasterizer which texture map to use. The rasterizer then can average two texture
+ maps to do mip mapping. More information can be found on the 2B manual, on the 'Texturing' and 'Data Format' chapters.
+ This is currently unemulated. We always use the texture data from the bigger texture map.
+ - The rasterizer supports up to 128x128 'microtex' textures, which are supposed to be higher resolution textures used
+ to display more detail when a texture is real close to the viewer. This is currently unemulated.
+
+*********************************************************************************************************************************/
+#include "driver.h"
+#include "video/segaic24.h"
+#include "video/poly.h"
+#include "eminline.h"
+
+#define DEBUG 0
+
+extern UINT32 geo_read_start_address;
+extern UINT32 geo_write_start_address;
+extern UINT32 *model2_bufferram;
+extern UINT32 *model2_colorxlat;
+extern UINT32 *model2_textureram0;
+extern UINT32 *model2_textureram1;
+extern UINT32 *model2_lumaram;
+
+static poly_manager *poly;
+
+#define pz p[0]
+#define pu p[1]
+#define pv p[2]
+
+
+/*******************************************
+ *
+ * Basic Data Types
+ *
+ *******************************************/
+
+typedef struct
+{
+ poly_vertex normal;
+ float distance;
+} plane;
+
+typedef struct
+{
+ float diffuse;
+ float ambient;
+ UINT32 specular_control;
+ float specular_scale;
+} texture_parameter;
+
+typedef struct
+{
+ void * next;
+ poly_vertex v[3];
+ UINT16 z;
+ UINT16 texheader[4];
+ UINT8 luma;
+ INT16 viewport[4];
+ INT16 center[2];
+} triangle;
+
+typedef struct
+{
+ poly_vertex v[4];
+ UINT16 z;
+ UINT16 texheader[4];
+ UINT8 luma;
+} quad;
+
+typedef struct _poly_extra_data poly_extra_data;
+struct _poly_extra_data
+{
+ UINT32 lumabase;
+ UINT32 colorbase;
+ UINT32 * texsheet;
+ UINT32 texwidth;
+ UINT32 texheight;
+ UINT32 texx, texy;
+ UINT8 texmirrorx;
+ UINT8 texmirrory;
+};
+
+
+/*******************************************
+ *
+ * Generic 3D Math Functions
+ *
+ *******************************************/
+
+INLINE void transform_point( poly_vertex *point, float *matrix )
+{
+ float tx = (point->x * matrix[0]) + (point->y * matrix[3]) + (point->pz * matrix[6]) + (matrix[9]);
+ float ty = (point->x * matrix[1]) + (point->y * matrix[4]) + (point->pz * matrix[7]) + (matrix[10]);
+ float tz = (point->x * matrix[2]) + (point->y * matrix[5]) + (point->pz * matrix[8]) + (matrix[11]);
+
+ point->x = tx;
+ point->y = ty;
+ point->pz = tz;
+}
+
+INLINE void transform_vector( poly_vertex *vector, float *matrix )
+{
+ float tx = (vector->x * matrix[0]) + (vector->y * matrix[3]) + (vector->pz * matrix[6]);
+ float ty = (vector->x * matrix[1]) + (vector->y * matrix[4]) + (vector->pz * matrix[7]);
+ float tz = (vector->x * matrix[2]) + (vector->y * matrix[5]) + (vector->pz * matrix[8]);
+
+ vector->x = tx;
+ vector->y = ty;
+ vector->pz = tz;
+}
+
+INLINE void normalize_vector( poly_vertex *vector )
+{
+ float n = sqrt( (vector->x * vector->x) + (vector->y * vector->y) + (vector->pz * vector->pz) );
+
+ if ( n )
+ {
+ float oon = 1.0f / n;
+ vector->x *= oon;
+ vector->y *= oon;
+ vector->pz *= oon;
+ }
+}
+
+INLINE float dot_product( poly_vertex *v1, poly_vertex *v2 )
+{
+ return (v1->x * v2->x) + (v1->y * v2->y) + (v1->pz * v2->pz);
+}
+
+INLINE void vector_cross3( poly_vertex *dst, poly_vertex *v0, poly_vertex *v1, poly_vertex *v2 )
+{
+ poly_vertex p1, p2;
+
+ p1.x = v1->x - v0->x; p1.y = v1->y - v0->y; p1.pz = v1->pz - v0->pz;
+ p2.x = v2->x - v0->x; p2.y = v2->y - v0->y; p2.pz = v2->pz - v0->pz;
+
+ dst->x = (p1.y * p2.pz) - (p1.pz * p2.y);
+ dst->y = (p1.pz * p2.x) - (p1.x * p2.pz);
+ dst->pz = (p1.x * p2.y) - (p1.y * p2.x);
+}
+
+/* 1.8.23 float to 4.12 float converter, courtesy of Aaron Giles */
+static UINT16 float_to_zval( float floatval )
+{
+ INT32 fpint = f2u(floatval);
+ INT32 exponent = ((fpint >> 23) & 0xff) - 127;
+ UINT32 mantissa = fpint & 0x7fffff;
+
+ /* round the low bits and reduce to 12 */
+ mantissa += 0x400;
+ if (mantissa > 0x7fffff) { exponent++; mantissa = (mantissa & 0x7fffff) >> 1; }
+ mantissa >>= 11;
+
+ /* if negative, clamp to 0 */
+ if (fpint < 0)
+ return 0x0000;
+
+ /* the rest depends on the exponent */
+ /* less than -12 is too small, return 0 */
+ if ( exponent < -12 )
+ return 0x0000;
+
+ /* between -12 and 0 create a denormal with exponent of 0 */
+ else if ( exponent < 0 )
+ return (mantissa | 0x1000) >> -exponent;
+
+ /* between 0 and 14 create a FP value with exponent + 1 */
+ else if ( exponent < 15 )
+ return (( exponent + 1 ) << 12) | mantissa;
+
+ /* above 14 is too large */
+ return 0xffff;
+}
+
+static INT32 clip_polygon(poly_vertex *v, INT32 num_vertices, plane *cp, poly_vertex *vout)
+{
+ poly_vertex *cur, *out;
+ float curdot, nextdot, scale;
+ INT32 i, curin, nextin, nextvert, outcount;
+
+ outcount = 0;
+
+ cur = v;
+ out = vout;
+
+ curdot = dot_product( cur, &cp->normal );
+ curin = (curdot >= cp->distance) ? 1 : 0;
+
+ for( i = 0; i < num_vertices; i++ )
+ {
+ nextvert = (i + 1) % num_vertices;
+
+ /* if the current point is inside the plane, add it */
+ if ( curin ) memcpy( &out[outcount++], cur, sizeof( poly_vertex ) );
+
+ nextdot = dot_product( &v[nextvert], &cp->normal );
+ nextin = (nextdot >= cp->distance) ? 1 : 0;
+
+ /* Add a clipped vertex if one end of the current edge is inside the plane and the other is outside */
+ if ( curin != nextin )
+ {
+ scale = (cp->distance - curdot) / (nextdot - curdot);
+
+ out[outcount].x = cur->x + ((v[nextvert].x - cur->x) * scale);
+ out[outcount].y = cur->y + ((v[nextvert].y - cur->y) * scale);
+ out[outcount].pz = cur->pz + ((v[nextvert].pz - cur->pz) * scale);
+ out[outcount].pu = (UINT16)((float)cur->pu + (((float)v[nextvert].pu - (float)cur->pu) * scale));
+ out[outcount].pv = (UINT16)((float)cur->pv + (((float)v[nextvert].pv - (float)cur->pv) * scale));
+ outcount++;
+ }
+
+ curdot = nextdot;
+ curin = nextin;
+ cur++;
+ }
+
+ return outcount;
+}
+
+/***********************************************************************************************/
+
+/*******************************************
+ *
+ * Hardware 3D Rasterizer Interal State
+ *
+ *******************************************/
+
+#define MAX_TRIANGLES 32768
+
+typedef struct
+{
+ UINT32 mode; /* bit 0 = Test Mode, bit 2 = Switch 60Hz(1)/30Hz(0) operation */
+ UINT16 * texture_rom; /* Texture ROM pointer */
+ UINT16 * texture_ram; /* Texture RAM pointer */
+ UINT8 * log_ram; /* Log RAM pointer */
+ INT16 viewport[4]; /* View port (startx,starty,endx,endy) */
+ INT16 center[4][2]; /* Centers (eye 0[x,y],1[x,y],2[x,y],3[x,y]) */
+ UINT16 center_sel; /* Selected center */
+ UINT32 reverse; /* Left/Right Reverse */
+ float z_adjust; /* ZSort Mode */
+ float triangle_z; /* Current Triangle z value */
+ UINT8 master_z_clip; /* Master Z-Clip value */
+ UINT32 cur_command; /* Current command */
+ UINT32 command_buffer[32]; /* Command buffer */
+ UINT32 command_index; /* Command buffer index */
+ triangle * tri_list; /* Triangle list */
+ UINT32 tri_list_index; /* Triangle list index */
+ triangle ** tri_sorted_list; /* Sorted Triangle list */
+ UINT16 min_z; /* Minimum sortable Z value */
+ UINT16 max_z; /* Maximum sortable Z value */
+
+} raster_state;
+
+static raster_state raster;
+
+/*******************************************
+ *
+ * Hardware 3D Rasterizer Initialization
+ *
+ *******************************************/
+
+static void model2_3d_init( UINT16 *texture_rom )
+{
+ memset( &raster, 0, sizeof( raster_state ) );
+
+ raster.texture_rom = texture_rom;
+ raster.texture_ram = auto_malloc(0x10000 * sizeof(UINT16));
+ raster.log_ram = auto_malloc(0x40000 * sizeof(UINT8));
+ raster.tri_list = auto_malloc(MAX_TRIANGLES * sizeof(triangle));
+ raster.tri_sorted_list = auto_malloc(0x10000 * sizeof( triangle * ));
+}
+
+/*******************************************
+ *
+ * Hardware 3D Rasterizer Z-Clip selection
+ *
+ *******************************************/
+
+void model2_3d_set_zclip( UINT8 clip )
+{
+ raster.master_z_clip = clip;
+}
+
+/*******************************************
+ *
+ * Hardware 3D Rasterizer Processing
+ *
+ *******************************************/
+
+static void model2_3d_process_quad( UINT32 attr )
+{
+ quad object;
+ UINT16 *th, *tp;
+ INT32 tho;
+ UINT32 cull, i;
+ float zvalue;
+ float min_z, max_z;
+
+ /* extract P0(n-1) */
+ object.v[1].x = u2f( raster.command_buffer[2] << 8 );
+ object.v[1].y = u2f( raster.command_buffer[3] << 8 );
+ object.v[1].pz = u2f( raster.command_buffer[4] << 8 );
+
+ /* extract P1(n-1) */
+ object.v[0].x = u2f( raster.command_buffer[5] << 8 );
+ object.v[0].y = u2f( raster.command_buffer[6] << 8 );
+ object.v[0].pz = u2f( raster.command_buffer[7] << 8 );
+
+ /* extract P0(n) */
+ object.v[2].x = u2f( raster.command_buffer[11] << 8 );
+ object.v[2].y = u2f( raster.command_buffer[12] << 8 );
+ object.v[2].pz = u2f( raster.command_buffer[13] << 8 );
+
+ /* extract P1(n) */
+ object.v[3].x = u2f( raster.command_buffer[14] << 8 );
+ object.v[3].y = u2f( raster.command_buffer[15] << 8 );
+ object.v[3].pz = u2f( raster.command_buffer[16] << 8 );
+
+ /* always calculate the min z and max z value */
+ min_z = object.v[0].pz;
+ if ( object.v[1].pz < min_z ) min_z = object.v[1].pz;
+ if ( object.v[2].pz < min_z ) min_z = object.v[2].pz;
+ if ( object.v[3].pz < min_z ) min_z = object.v[3].pz;
+
+ max_z = object.v[0].pz;
+ if ( object.v[1].pz > max_z ) max_z = object.v[1].pz;
+ if ( object.v[2].pz > max_z ) max_z = object.v[2].pz;
+ if ( object.v[3].pz > max_z ) max_z = object.v[3].pz;
+
+ /* read in the texture information */
+
+ /* texture point data */
+ if ( raster.command_buffer[0] & 0x800000 )
+ tp = &raster.texture_ram[raster.command_buffer[0] & 0xFFFF];
+ else
+ tp = &raster.texture_rom[raster.command_buffer[0] & 0x7FFFFF];
+
+ object.v[0].pv = *tp++;
+ object.v[0].pu = *tp++;
+ object.v[1].pv = *tp++;
+ object.v[1].pu = *tp++;
+ object.v[2].pv = *tp++;
+ object.v[2].pu = *tp++;
+ object.v[3].pv = *tp++;
+ object.v[3].pu = *tp++;
+
+ /* update the address */
+ raster.command_buffer[0] += 8;
+
+ /* texture header data */
+ if ( raster.command_buffer[1] & 0x800000 )
+ th = &raster.texture_ram[raster.command_buffer[1] & 0xFFFF];
+ else
+ th = &raster.texture_rom[raster.command_buffer[1] & 0x7FFFFF];
+
+ object.texheader[0] = *th++;
+ object.texheader[1] = *th++;
+ object.texheader[2] = *th++;
+ object.texheader[3] = *th++;
+
+ /* extract the texture header offset */
+ tho = (attr >> 12) & 0x1F;
+
+ /* adjust for sign */
+ if ( tho & 0x10 )
+ tho |= -16;
+
+ /* update the address */
+ raster.command_buffer[1] += tho * 4;
+
+ /* set the luma value of this quad */
+ object.luma = (raster.command_buffer[9] >> 15) & 0xFF;
+
+ /* determine wether we can cull this quad */
+ cull = 0;
+
+ /* if doubleside is disabled */
+ if ( ((attr >> 17) & 1) == 0 )
+ {
+ /* if it's the backface, cull it */
+ if ( raster.command_buffer[9] & 0x00800000 )
+ cull = 1;
+ }
+
+ /* if the linktype is 0, then we can also cull it */
+ if ( ((attr >> 8) & 3) == 0 )
+ cull = 1;
+
+ /* if the minimum z value is bigger than the master z clip value, don't render */
+ if ( (INT32)(1.0/min_z) > raster.master_z_clip )
+ cull = 1;
+
+ /* if the maximum z value is < 0 then we can safely clip the entire polygon */
+ if ( max_z < 0 )
+ cull = 1;
+
+ /* set the object's z value */
+ zvalue = raster.triangle_z;
+
+ /* see if we need to recompute min/max z */
+ if ( (attr >> 10) & 3 )
+ {
+ if ( (attr >> 10) & 1 ) /* min value */
+ {
+ zvalue = min_z;
+ }
+ else if ( (attr >> 10) & 2 ) /* max value */
+ {
+ zvalue = max_z;
+ }
+
+ raster.triangle_z = zvalue;
+ }
+
+ if ( cull == 0 )
+ {
+ INT32 clipped_verts;
+ poly_vertex verts[10];
+ plane clip_plane;
+
+ clip_plane.normal.x = 0;
+ clip_plane.normal.y = 0;
+ clip_plane.normal.pz = 1;
+ clip_plane.distance = 0;
+
+ /* do near z clipping */
+ clipped_verts = clip_polygon( object.v, 4, &clip_plane, verts);
+
+ if ( clipped_verts > 2 )
+ {
+ triangle *ztri;
+
+ /* adjust and set the object z-sort value */
+ object.z = float_to_zval( zvalue + raster.z_adjust );
+
+ /* get our list read to add the triangles */
+ ztri = raster.tri_sorted_list[object.z];
+
+ if ( ztri != NULL )
+ {
+ while( ztri->next != NULL )
+ ztri = ztri->next;
+ }
+
+ /* go through the clipped vertex list, adding triangles */
+ for( i = 2; i < clipped_verts; i++ )
+ {
+ triangle *tri;
+
+ tri = &raster.tri_list[raster.tri_list_index++];
+
+ if ( raster.tri_list_index >= MAX_TRIANGLES )
+ {
+ fatalerror( "SEGA 3D: Max triangle limit exceeded\n" );
+ }
+
+ /* copy the object information */
+ tri->z = object.z;
+ tri->texheader[0] = object.texheader[0];
+ tri->texheader[1] = object.texheader[1];
+ tri->texheader[2] = object.texheader[2];
+ tri->texheader[3] = object.texheader[3];
+ tri->luma = object.luma;
+
+ /* set the viewport */
+ tri->viewport[0] = raster.viewport[0];
+ tri->viewport[1] = raster.viewport[1];
+ tri->viewport[2] = raster.viewport[2];
+ tri->viewport[3] = raster.viewport[3];
+
+ /* set the center */
+ tri->center[0] = raster.center[raster.center_sel][0];
+ tri->center[1] = raster.center[raster.center_sel][1];
+
+ memcpy( &tri->v[0], &verts[0], sizeof( poly_vertex ) );
+ memcpy( &tri->v[1], &verts[i-1], sizeof( poly_vertex ) );
+ memcpy( &tri->v[2], &verts[i], sizeof( poly_vertex ) );
+
+ /* add to our sorted list */
+ tri->next = NULL;
+
+ if ( ztri == NULL )
+ {
+ raster.tri_sorted_list[object.z] = tri;
+ }
+ else
+ {
+ ztri->next = tri;
+ }
+
+ ztri = tri;
+ }
+
+ /* keep around the min and max z values for this frame */
+ if ( object.z < raster.min_z ) raster.min_z = object.z;
+ if ( object.z > raster.max_z ) raster.max_z = object.z;
+ }
+ }
+
+ /* update linking */
+ switch( ((attr >> 8) & 3) )
+ {
+ case 0:
+ case 2:
+ {
+ /* reuse P0(n) and P1(n) */
+ for( i = 0; i < 6; i++ ) /* P0(n) -> P0(n-1) */
+ raster.command_buffer[2+i] = raster.command_buffer[11+i]; /* P1(n) -> P1(n-1) */
+ }
+ break;
+
+ case 1:
+ {
+ /* reuse P0(n-1) and P0(n) */
+ for( i = 0; i < 3; i++ )
+ raster.command_buffer[5+i] = raster.command_buffer[11+i]; /* P0(n) -> P1(n-1) */
+ }
+ break;
+
+ case 3:
+ {
+ /* reuse P1(n-1) and P1(n) */
+ for( i = 0; i < 3; i++ )
+ raster.command_buffer[2+i] = raster.command_buffer[14+i]; /* P1(n) -> P1(n-1) */
+ }
+ break;
+ }
+}
+
+static void model2_3d_process_triangle( UINT32 attr )
+{
+ triangle object;
+ UINT16 *th, *tp;
+ INT32 tho;
+ UINT32 cull, i;
+ float zvalue;
+ float min_z, max_z;
+
+ /* extract P0(n-1) */
+ object.v[1].x = u2f( raster.command_buffer[2] << 8 );
+ object.v[1].y = u2f( raster.command_buffer[3] << 8 );
+ object.v[1].pz = u2f( raster.command_buffer[4] << 8 );
+
+ /* extract P1(n-1) */
+ object.v[0].x = u2f( raster.command_buffer[5] << 8 );
+ object.v[0].y = u2f( raster.command_buffer[6] << 8 );
+ object.v[0].pz = u2f( raster.command_buffer[7] << 8 );
+
+ /* extract P0(n) */
+ object.v[2].x = u2f( raster.command_buffer[11] << 8 );
+ object.v[2].y = u2f( raster.command_buffer[12] << 8 );
+ object.v[2].pz = u2f( raster.command_buffer[13] << 8 );
+
+ /* for triangles, the rope of P1(n) is achieved by P0(n-1) (linktype 3) */
+ raster.command_buffer[14] = raster.command_buffer[11];
+ raster.command_buffer[15] = raster.command_buffer[12];
+ raster.command_buffer[16] = raster.command_buffer[13];
+
+ /* always calculate the min z and max z values */
+ min_z = object.v[0].pz;
+ if ( object.v[1].pz < min_z ) min_z = object.v[1].pz;
+ if ( object.v[2].pz < min_z ) min_z = object.v[2].pz;
+
+ max_z = object.v[0].pz;
+ if ( object.v[1].pz > max_z ) max_z = object.v[1].pz;
+ if ( object.v[2].pz > max_z ) max_z = object.v[2].pz;
+
+ /* read in the texture information */
+
+ /* texture point data */
+ if ( raster.command_buffer[0] & 0x800000 )
+ tp = &raster.texture_ram[raster.command_buffer[0] & 0xFFFF];
+ else
+ tp = &raster.texture_rom[raster.command_buffer[0] & 0x7FFFFF];
+
+ object.v[0].pv = *tp++;
+ object.v[0].pu = *tp++;
+ object.v[1].pv = *tp++;
+ object.v[1].pu = *tp++;
+ object.v[2].pv = *tp++;
+ object.v[2].pu = *tp++;
+
+ /* update the address */
+ raster.command_buffer[0] += 6;
+
+ /* texture header data */
+ if ( raster.command_buffer[1] & 0x800000 )
+ th = &raster.texture_ram[raster.command_buffer[1] & 0xFFFF];
+ else
+ th = &raster.texture_rom[raster.command_buffer[1] & 0x7FFFFF];
+
+ object.texheader[0] = *th++;
+ object.texheader[1] = *th++;
+ object.texheader[2] = *th++;
+ object.texheader[3] = *th++;
+
+ /* extract the texture header offset */
+ tho = (attr >> 12) & 0x1F;
+
+ /* adjust for sign */
+ if ( tho & 0x10 )
+ tho |= -16;
+
+ /* update the address */
+ raster.command_buffer[1] += tho * 4;
+
+ /* set the luma value of this quad */
+ object.luma = (raster.command_buffer[9] >> 15) & 0xFF;
+
+ /* determine wether we can cull this quad */
+ cull = 0;
+
+ /* if doubleside is disabled */
+ if ( ((attr >> 17) & 1) == 0 )
+ {
+ /* if it's the backface, cull it */
+ if ( raster.command_buffer[9] & 0x00800000 )
+ cull = 1;
+ }
+
+ /* if the linktype is 0, then we can also cull it */
+ if ( ((attr >> 8) & 3) == 0 )
+ cull = 1;
+
+ /* if the minimum z value is bigger than the master z clip value, don't render */
+ if ( (INT32)(1.0/min_z) > raster.master_z_clip )
+ cull = 1;
+
+ /* if the maximum z value is < 0 then we can safely clip the entire polygon */
+ if ( max_z < 0 )
+ cull = 1;
+
+ /* set the object's z value */
+ zvalue = raster.triangle_z;
+
+ /* see if we need to recompute min/max z */
+ if ( (attr >> 10) & 3 )
+ {
+ if ( (attr >> 10) & 1 ) /* min value */
+ {
+ zvalue = min_z;
+ }
+ else if ( (attr >> 10) & 2 ) /* max value */
+ {
+ zvalue = max_z;
+ }
+
+ raster.triangle_z = zvalue;
+ }
+
+ /* if we're not culling, do z-clip and add to out triangle list */
+ if ( cull == 0 )
+ {
+ INT32 clipped_verts;
+ poly_vertex verts[10];
+ plane clip_plane;
+
+ clip_plane.normal.x = 0;
+ clip_plane.normal.y = 0;
+ clip_plane.normal.pz = 1;
+ clip_plane.distance = 0;
+
+ /* do near z clipping */
+ clipped_verts = clip_polygon( object.v, 3, &clip_plane, verts);
+
+ if ( clipped_verts > 2 )
+ {
+ triangle *ztri;
+
+ /* adjust and set the object z-sort value */
+ object.z = float_to_zval( zvalue + raster.z_adjust );
+
+ /* get our list read to add the triangles */
+ ztri = raster.tri_sorted_list[object.z];
+
+ if ( ztri != NULL )
+ {
+ while( ztri->next != NULL )
+ ztri = ztri->next;
+ }
+
+ /* go through the clipped vertex list, adding triangles */
+ for( i = 2; i < clipped_verts; i++ )
+ {
+ triangle *tri;
+
+ tri = &raster.tri_list[raster.tri_list_index++];
+
+ if ( raster.tri_list_index >= MAX_TRIANGLES )
+ {
+ fatalerror( "SEGA 3D: Max triangle limit exceeded\n" );
+ }
+
+ /* copy the object information */
+ tri->z = object.z;
+ tri->texheader[0] = object.texheader[0];
+ tri->texheader[1] = object.texheader[1];
+ tri->texheader[2] = object.texheader[2];
+ tri->texheader[3] = object.texheader[3];
+ tri->luma = object.luma;
+
+ /* set the viewport */
+ tri->viewport[0] = raster.viewport[0];
+ tri->viewport[1] = raster.viewport[1];
+ tri->viewport[2] = raster.viewport[2];
+ tri->viewport[3] = raster.viewport[3];
+
+ /* set the center */
+ tri->center[0] = raster.center[raster.center_sel][0];
+ tri->center[1] = raster.center[raster.center_sel][1];
+
+ memcpy( &tri->v[0], &verts[0], sizeof( poly_vertex ) );
+ memcpy( &tri->v[1], &verts[i-1], sizeof( poly_vertex ) );
+ memcpy( &tri->v[2], &verts[i], sizeof( poly_vertex ) );
+
+ /* add to our sorted list */
+ tri->next = NULL;
+
+ if ( ztri == NULL )
+ {
+ raster.tri_sorted_list[object.z] = tri;
+ }
+ else
+ {
+ ztri->next = tri;
+ }
+
+ ztri = tri;
+ }
+
+ /* keep around the min and max z values for this frame */
+ if ( object.z < raster.min_z ) raster.min_z = object.z;
+ if ( object.z > raster.max_z ) raster.max_z = object.z;
+ }
+ }
+
+ /* update linking */
+ switch( ((attr >> 8) & 3) )
+ {
+ case 0:
+ case 2:
+ {
+ /* reuse P0(n) and P1(n) */
+ for( i = 0; i < 6; i++ ) /* P0(n) -> P0(n-1) */
+ raster.command_buffer[2+i] = raster.command_buffer[11+i]; /* P1(n) -> P1(n-1) */
+ }
+ break;
+
+ case 1:
+ {
+ /* reuse P0(n-1) and P0(n) */
+ for( i = 0; i < 3; i++ )
+ raster.command_buffer[5+i] = raster.command_buffer[11+i]; /* P0(n) -> P1(n-1) */
+ }
+ break;
+
+ case 3:
+ {
+ /* reuse P1(n-1) and P1(n) */
+ for( i = 0; i < 3; i++ )
+ raster.command_buffer[2+i] = raster.command_buffer[14+i]; /* P1(n) -> P1(n-1) */
+ }
+ break;
+ }
+}
+
+/***********************************************************************************************/
+
+INLINE UINT16 get_texel( UINT32 base_x, UINT32 base_y, int x, int y, UINT32 *sheet )
+{
+ UINT32 baseoffs = ((base_y/2)*512)+(base_x/2);
+ UINT32 texeloffs = ((y/2)*512)+(x/2);
+ UINT32 offset = baseoffs + texeloffs;
+ UINT32 texel = sheet[offset>>1];
+
+ if ( offset & 1 )
+ texel >>= 16;
+
+ if ( (y & 1) == 0 )
+ texel >>= 8;
+
+ if ( (x & 1) == 0 )
+ texel >>= 4;
+
+ return (texel & 0x0f);
+}
+
+/* checker = 0, textured = 0, transparent = 0 */
+#define MODEL2_FUNC 0
+#define MODEL2_FUNC_NAME model2_3d_render_0
+#include "model2rd.c"
+#undef MODEL2_FUNC
+#undef MODEL2_FUNC_NAME
+
+/* checker = 0, textured = 0, translucent = 1 */
+#define MODEL2_FUNC 1
+#define MODEL2_FUNC_NAME model2_3d_render_1
+#include "model2rd.c"
+#undef MODEL2_FUNC
+#undef MODEL2_FUNC_NAME
+
+/* checker = 0, textured = 1, translucent = 0 */
+#define MODEL2_FUNC 2
+#define MODEL2_FUNC_NAME model2_3d_render_2
+#include "model2rd.c"
+#undef MODEL2_FUNC
+#undef MODEL2_FUNC_NAME
+
+/* checker = 0, textured = 1, translucent = 1 */
+#define MODEL2_FUNC 3
+#define MODEL2_FUNC_NAME model2_3d_render_3
+#include "model2rd.c"
+#undef MODEL2_FUNC
+#undef MODEL2_FUNC_NAME
+
+/* checker = 1, textured = 0, translucent = 0 */
+#define MODEL2_FUNC 4
+#define MODEL2_FUNC_NAME model2_3d_render_4
+#include "model2rd.c"
+#undef MODEL2_FUNC
+#undef MODEL2_FUNC_NAME
+
+/* checker = 1, textured = 0, translucent = 1 */
+#define MODEL2_FUNC 5
+#define MODEL2_FUNC_NAME model2_3d_render_5
+#include "model2rd.c"
+#undef MODEL2_FUNC
+#undef MODEL2_FUNC_NAME
+
+/* checker = 1, textured = 1, translucent = 0 */
+#define MODEL2_FUNC 6
+#define MODEL2_FUNC_NAME model2_3d_render_6
+#include "model2rd.c"
+#undef MODEL2_FUNC
+#undef MODEL2_FUNC_NAME
+
+/* checker = 1, textured = 1, translucent = 1 */
+#define MODEL2_FUNC 7
+#define MODEL2_FUNC_NAME model2_3d_render_7
+#include "model2rd.c"
+#undef MODEL2_FUNC
+#undef MODEL2_FUNC_NAME
+
+/***********************************************************************************************/
+
+static poly_draw_scanline render_funcs[8] =
+{
+ model2_3d_render_0, /* checker = 0, textured = 0, translucent = 0 */
+ model2_3d_render_1, /* checker = 0, textured = 0, translucent = 1 */
+ model2_3d_render_2, /* checker = 0, textured = 1, translucent = 0 */
+ model2_3d_render_3, /* checker = 0, textured = 1, translucent = 1 */
+ model2_3d_render_4, /* checker = 1, textured = 0, translucent = 0 */
+ model2_3d_render_5, /* checker = 1, textured = 0, translucent = 1 */
+ model2_3d_render_6, /* checker = 1, textured = 1, translucent = 0 */
+ model2_3d_render_7 /* checker = 1, textured = 1, translucent = 1 */
+};
+
+static void model2_3d_render( mame_bitmap *bitmap, triangle *tri, const rectangle *cliprect )
+{
+ poly_extra_data *extra = poly_get_extra_data(poly);
+ UINT8 renderer;
+ rectangle vp;
+
+ /* select renderer based on attributes (bit15 = checker, bit14 = textured, bit13 = transparent */
+ renderer = (tri->texheader[0] >> 13) & 7;
+
+ /* calculate and clip to viewport */
+ vp.min_x = tri->viewport[0] - 8;
+ vp.max_x = tri->viewport[2] - 8;
+ vp.min_y = (384-tri->viewport[3])+90;
+ vp.max_y = (384-tri->viewport[1])+90;
+
+ if ( vp.min_x < cliprect->min_x ) vp.min_x = cliprect->min_x;
+ if ( vp.max_x > cliprect->max_x ) vp.max_x = cliprect->max_x;
+ if ( vp.min_y < cliprect->min_y ) vp.min_y = cliprect->min_y;
+ if ( vp.max_y > cliprect->max_y ) vp.max_y = cliprect->max_y;
+
+ extra->lumabase = ((tri->texheader[1] & 0xFF) << 7) + ((tri->luma >> 5) ^ 0x7);
+ extra->colorbase = (tri->texheader[3] >> 6) & 0x3FF;
+
+ if (renderer & 2)
+ {
+ extra->texwidth = 32 << ((tri->texheader[0] >> 0) & 0x7);
+ extra->texheight = 32 << ((tri->texheader[0] >> 3) & 0x7);
+ extra->texx = 32 * ((tri->texheader[2] >> 0) & 0x1f);
+ extra->texy = 32 * (((tri->texheader[2] >> 6) & 0x1f) + ( tri->texheader[2] & 0x20 ));
+ extra->texmirrorx = (tri->texheader[0] >> 9) & 1;
+ extra->texmirrory = (tri->texheader[0] >> 8) & 1;
+ extra->texsheet = (tri->texheader[2] & 0x1000) ? model2_textureram1 : model2_textureram0;
+
+ tri->v[0].pz = 1.0f / (1.0f + tri->v[0].pz);
+ tri->v[0].pu = tri->v[0].pu * tri->v[0].pz * (1.0f / 8.0f);
+ tri->v[0].pv = tri->v[0].pv * tri->v[0].pz * (1.0f / 8.0f);
+ tri->v[1].pz = 1.0f / (1.0f + tri->v[1].pz);
+ tri->v[1].pu = tri->v[1].pu * tri->v[1].pz * (1.0f / 8.0f);
+ tri->v[1].pv = tri->v[1].pv * tri->v[1].pz * (1.0f / 8.0f);
+ tri->v[2].pz = 1.0f / (1.0f + tri->v[2].pz);
+ tri->v[2].pu = tri->v[2].pu * tri->v[2].pz * (1.0f / 8.0f);
+ tri->v[2].pv = tri->v[2].pv * tri->v[2].pz * (1.0f / 8.0f);
+
+ poly_render_triangle(poly, bitmap, &vp, render_funcs[renderer], 3, &tri->v[0], &tri->v[1], &tri->v[2]);
+ }
+ else
+ poly_render_triangle(poly, bitmap, &vp, render_funcs[renderer], 0, &tri->v[0], &tri->v[1], &tri->v[2]);
+}
+
+/*
+ Projection:
+
+ According to the 2B Manual the screen coordinates are:
+
+ (8,474) (504,474)
+ +--------------------------------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------------------------------+
+ (8,90) (504,90)
+*/
+
+/* 3D Rasterizer projection: projects a triangle into screen coordinates */
+static void model2_3d_project( triangle *tri )
+{
+ UINT16 i;
+
+ for( i = 0; i < 3; i++ )
+ {
+ /* project the vertices */
+ tri->v[i].x = -8 + tri->center[0] + (tri->v[i].x / (1.0f+tri->v[i].pz));
+ tri->v[i].y = ((384 - tri->center[1])+90) - (tri->v[i].y / (1.0f+tri->v[i].pz));
+ }
+}
+
+/* 3D Rasterizer frame start: Resets frame variables */
+static void model2_3d_frame_start( void )
+{
+ /* reset the triangle list index */
+ raster.tri_list_index = 0;
+
+ /* reset the sorted z list */
+ memset( raster.tri_sorted_list, 0, 0x10000 * sizeof( triangle * ) );
+
+ /* reset the min-max sortable Z values */
+ raster.min_z = 0xFFFF;
+ raster.max_z = 0;
+}
+
+static void model2_3d_frame_end( bitmap_t *bitmap, const rectangle *cliprect )
+{
+ INT32 z;
+
+ /* if we have nothing to render, bail */
+ if ( raster.tri_list_index == 0 )
+ return;
+
+#if DEBUG
+ if (input_code_pressed(KEYCODE_Q))
+ {
+ UINT32 i;
+
+ FILE *f = fopen( "triangles.txt", "w" );
+
+ if ( f )
+ {
+ for( i = 0; i < raster.tri_list_index; i++ )
+ {
+
+ fprintf( f, "index: %d\n", i );
+ fprintf( f, "v0.x = %f, v0.y = %f, v0.z = %f\n", raster.tri_list[i].v[0].x, raster.tri_list[i].v[0].y, raster.tri_list[i].v[0].pz );
+ fprintf( f, "v1.x = %f, v1.y = %f, v1.z = %f\n", raster.tri_list[i].v[1].x, raster.tri_list[i].v[1].y, raster.tri_list[i].v[1].pz );
+ fprintf( f, "v2.x = %f, v2.y = %f, v2.z = %f\n", raster.tri_list[i].v[2].x, raster.tri_list[i].v[2].y, raster.tri_list[i].v[2].pz );
+
+ fprintf( f, "tri z: %04x\n", raster.tri_list[i].pz );
+ fprintf( f, "texheader - 0: %04x\n", raster.tri_list[i].texheader[0] );
+ fprintf( f, "texheader - 1: %04x\n", raster.tri_list[i].texheader[1] );
+ fprintf( f, "texheader - 2: %04x\n", raster.tri_list[i].texheader[2] );
+ fprintf( f, "texheader - 3: %04x\n", raster.tri_list[i].texheader[3] );
+ fprintf( f, "luma: %02x\n", raster.tri_list[i].luma );
+ fprintf( f, "vp.sx: %04x\n", raster.tri_list[i].viewport[0] );
+ fprintf( f, "vp.sy: %04x\n", raster.tri_list[i].viewport[1] );
+ fprintf( f, "vp.ex: %04x\n", raster.tri_list[i].viewport[2] );
+ fprintf( f, "vp.ey: %04x\n", raster.tri_list[i].viewport[3] );
+ fprintf( f, "vp.swx: %04x\n", raster.tri_list[i].center[0] );
+ fprintf( f, "vp.swy: %04x\n", raster.tri_list[i].center[1] );
+ fprintf( f, "\n---\n\n" );
+ }
+
+ fprintf( f, "min_z = %04x, max_z = %04x\n", raster.min_z, raster.max_z );
+
+ fclose( f );
+ }
+ }
+#endif
+
+ /* go through the Z levels, and render each bucket */
+ for( z = raster.max_z; z >= raster.min_z; z-- )
+ {
+ /* see if we have items at this z level */
+ if ( raster.tri_sorted_list[z] != NULL )
+ {
+ /* get a pointer to the first triangle */
+ triangle *tri = raster.tri_sorted_list[z];
+
+ /* and loop clipping and rendering each triangle */
+ while( tri != NULL )
+ {
+ /* project and render */
+ model2_3d_project( tri );
+ model2_3d_render( bitmap, tri, cliprect );
+
+ tri = tri->next;
+ }
+ }
+ }
+ poly_wait(poly, "End of frame");
+}
+
+/* 3D Rasterizer main data input port */
+static void model2_3d_push( UINT32 input )
+{
+ /* see if we have a command in progress */
+ if ( raster.cur_command != 0 )
+ {
+ raster.command_buffer[raster.command_index++] = input;
+
+ switch( raster.cur_command )
+ {
+ case 0x00: /* NOP */
+ break;
+
+ case 0x01: /* Polygon Data */
+ {
+ UINT32 attr;
+
+ /* start by looking if we have the basic input data */
+ if ( raster.command_index < 9 )
+ return;
+
+ /* get the attributes */
+ attr = raster.command_buffer[8];
+
+ /* see if we're done */
+ if ( (attr & 3) == 0 )
+ {
+ raster.cur_command = 0;
+ return;
+ }
+
+ /* see if it's a quad or a triangle */
+ if ( attr & 1 )
+ {
+ /* it's a quad, wait for the rest of the points */
+ if ( raster.command_index < 17 )
+ return;
+
+ /* we have a full quad info, fill up our quad structure */
+ model2_3d_process_quad( attr );
+
+ /* back up and wait for more data */
+ raster.command_index = 8;
+ }
+ else
+ {
+ /* it's a triangle, wait for the rest of the point */
+ if ( raster.command_index < 14 )
+ return;
+
+ /* we have a full quad info, fill up our quad structure */
+ model2_3d_process_triangle( attr );
+
+ /* back up and wait for more data */
+ raster.command_index = 8;
+ }
+ }
+ break;
+
+ case 0x03: /* Window Data */
+ {
+ UINT32 i;
+
+ /* make sure we have all the data */
+ if ( raster.command_index < 6 )
+ return;
+
+ /* coordinates are 12 bit signed */
+
+ /* extract the viewport start x */
+ raster.viewport[0] = (raster.command_buffer[0] >> 12) & 0xFFF;
+
+ if ( raster.viewport[0] & 0x800 )
+ raster.viewport[0] = -( 0x800 - (raster.viewport[0] & 0x7FF) );
+
+ /* extract the viewport start y */
+ raster.viewport[1] = raster.command_buffer[0] & 0xFFF;
+
+ if ( raster.viewport[1] & 0x800 )
+ raster.viewport[1] = -( 0x800 - (raster.viewport[1] & 0x7FF) );
+
+ /* extract the viewport end x */
+ raster.viewport[2] = (raster.command_buffer[1] >> 12) & 0xFFF;
+
+ if ( raster.viewport[2] & 0x800 )
+ raster.viewport[2] = -( 0x800 - (raster.viewport[2] & 0x7FF) );
+
+ /* extract the viewport end y */
+ raster.viewport[3] = raster.command_buffer[1] & 0xFFF;
+
+ if ( raster.viewport[3] & 0x800 )
+ raster.viewport[3] = -( 0x800 - (raster.viewport[3] & 0x7FF) );
+
+ /* extract the centers */
+ for( i = 0; i < 4; i++ )
+ {
+ /* center x */
+ raster.center[i][0] = (raster.command_buffer[2+i] >> 12) & 0xFFF;
+
+ if ( raster.center[i][0] & 0x800 )
+ raster.center[i][0] = -( 0x800 - (raster.center[i][0] & 0x7FF) );
+
+ /* center y */
+ raster.center[i][1] = raster.command_buffer[2+i] & 0xFFF;
+
+ if ( raster.center[i][1] & 0x800 )
+ raster.center[i][1] = -( 0x800 - (raster.center[i][1] & 0x7FF) );
+ }
+
+ /* done with this command */
+ raster.cur_command = 0;
+ }
+ break;
+
+ case 0x04: /* Texture/Log Data write */
+ {
+ /* make sure we have enough data */
+ if ( raster.command_index < 2 )
+ return;
+
+ /* see if the count is non-zero */
+ if ( raster.command_buffer[1] > 0 )
+ {
+ /* see if we have data available */
+ if ( raster.command_index >= 3 )
+ {
+ /* get the address */
+ UINT32 address = raster.command_buffer[0];
+
+ /* do the write */
+ if ( address & 0x800000 )
+ raster.texture_ram[address&0xFFFF] = raster.command_buffer[2];
+ else
+ raster.log_ram[address&0xFFFF] = raster.command_buffer[2];
+
+ /* increment the address and decrease the count */
+ raster.command_buffer[0]++;
+ raster.command_buffer[1]--;
+
+ /* decrease the index, so we keep placing data in the same slot */
+ raster.command_index--;
+ }
+ }
+
+ /* see if we're done with this command */
+ if ( raster.command_buffer[1] == 0 )
+ raster.cur_command = 0;
+ }
+ break;
+
+ case 0x08: /* ZSort mode */
+ {
+ /* save the zsort mode value */
+ raster.z_adjust = u2f( raster.command_buffer[0] << 8 );
+
+ /* done with this command */
+ raster.cur_command = 0;
+ }
+ break;
+
+ default:
+ {
+ fatalerror( "SEGA 3D: Unknown rasterizer command %08x\n", raster.cur_command );
+ }
+ break;
+ }
+ }
+ else
+ {
+ /* new command */
+ raster.cur_command = input & 0x0F;
+ raster.command_index = 0;
+
+ /* see if it's object data */
+ if ( raster.cur_command == 1 )
+ {
+ /* extract reverse bit */
+ raster.reverse = (input >> 4) & 1;
+
+ /* extract center select */
+ raster.center_sel = ( input >> 6 ) & 3;
+
+ /* reset the triangle z value */
+ raster.triangle_z = 0;
+ }
+ }
+}
+
+/***********************************************************************************************/
+
+
+
+/*******************************************
+ *
+ * Geometry Engine Internal State
+ *
+ *******************************************/
+
+typedef struct
+{
+ UINT32 mode; /* bit 0 = Enable Specular, bit 1 = Calculate Normals */
+ UINT32 * polygon_rom; /* Polygon ROM pointer */
+ UINT32 * polygon_ram0; /* Fast Polygon RAM pointer */
+ UINT32 * polygon_ram1; /* Slow Polygon RAM pointer */
+ float matrix[12]; /* Current Transformation Matrix */
+ poly_vertex focus; /* Focus (x,y) */
+ poly_vertex light; /* Light Vector */
+ float lod; /* LOD */
+ float coef_table[32]; /* Distane Coefficient table */
+ texture_parameter texture_parameters[32]; /* Texture parameters */
+} geo_state;
+
+static geo_state geo;
+
+/*******************************************
+ *
+ * Geometry Engine Initialization
+ *
+ *******************************************/
+
+static void geo_init( UINT32 *polygon_rom )
+{
+ memset( &geo, 0, sizeof( geo_state ) );
+
+ geo.polygon_rom = polygon_rom;
+ geo.polygon_ram0 = auto_malloc(0x8000 * sizeof(UINT32));
+ geo.polygon_ram1 = auto_malloc(0x8000 * sizeof(UINT32));
+}
+
+/*******************************************
+ *
+ * Geometry Engine Polygon Parsers
+ *
+ *******************************************/
+
+/* Parse Polygons: Normals Present, No Specular case */
+static void geo_parse_np_ns( UINT32 *input, UINT32 count )
+{
+ poly_vertex point, normal;
+ UINT32 attr, i;
+
+ /* read the 1st point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* push it to the 3d rasterizer */
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+
+ /* read the 2nd point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* push it to the 3d rasterizer */
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+
+ /* loop through the following links */
+ for( i = 0; i < count; i++ )
+ {
+ /* read in the attributes */
+ attr = *input++;
+
+ /* push to the 3d rasterizer */
+ model2_3d_push( attr & 0x0003FFFF );
+
+ /* read in the normal */
+ normal.x = u2f(*input++);
+ normal.y = u2f(*input++);
+ normal.pz = u2f(*input++);
+
+ /* transform with the current matrix */
+ transform_vector( &normal, geo.matrix );
+
+ if ( (attr & 3) != 0 ) /* quad or triangle */
+ {
+ float dotl, dotp, luminance, distance;
+ float coef, face;
+ INT32 luma;
+ texture_parameter * texparam;
+
+ /* read in the next point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* calculate the dot product of the normal and the light vector */
+ dotl = dot_product( &normal, &geo.light );
+
+ /* calculate the dot product of the normal and the point */
+ dotp = dot_product( &normal, &point );
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* determine wether this is the front or the back of the polygon */
+ face = 0x100; /* rear */
+ if ( dotp >= 0 ) face = 0; /* front */
+
+ /* get the texture parameters */
+ texparam = &geo.texture_parameters[(attr>>18) & 0x1f];
+
+ /* calculate luminance */
+ if ( (dotl * dotp) < 0 ) luminance = 0;
+ else luminance = fabs( dotl );
+
+ luminance = (luminance * texparam->diffuse) + texparam->ambient;
+ luma = (INT32)luminance;
+
+ if ( luma > 255 ) luma = 255;
+ if ( luma < 0 ) luma = 0;
+
+ /* add the face bit to the luma */
+ luma += face;
+
+ /* extract distance coefficient */
+ coef = geo.coef_table[attr>>27];
+
+ /* calculate texture level of detail */
+ distance = coef * fabs( dotp ) * geo.lod;
+
+ /* push to the 3d rasterizer */
+ model2_3d_push( luma << 15 );
+ model2_3d_push( f2u(distance) >> 8 );
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+
+ /* if it's a quad, push one more point */
+ if ( attr & 1 )
+ {
+ /* read in the next point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* push to the 3d rasterizer */
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+ }
+ else /* triangle */
+ {
+ /* skip the next 3 points */
+ input += 3;
+ }
+ }
+ else /* we're done */
+ {
+ break;
+ }
+ }
+
+ /* notify the 3d rasterizer we're done */
+ model2_3d_push( 0 );
+}
+
+/* Parse Polygons: Normals Present, Specular case */
+static void geo_parse_np_s( UINT32 *input, UINT32 count )
+{
+ poly_vertex point, normal;
+ UINT32 attr, i;
+
+ /* read the 1st point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* push it to the 3d rasterizer */
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+
+ /* read the 2nd point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* push it to the 3d rasterizer */
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+
+ /* loop through the following links */
+ for( i = 0; i < count; i++ )
+ {
+ /* read in the attributes */
+ attr = *input++;
+
+ /* push to the 3d rasterizer */
+ model2_3d_push( attr & 0x0003FFFF );
+
+ /* read in the normal */
+ normal.x = u2f(*input++);
+ normal.y = u2f(*input++);
+ normal.pz = u2f(*input++);
+
+ /* transform with the current matrix */
+ transform_vector( &normal, geo.matrix );
+
+ if ( (attr & 3) != 0 ) /* quad or triangle */
+ {
+ float dotl, dotp, luminance, distance, specular;
+ float coef, face;
+ INT32 luma;
+ texture_parameter * texparam;
+
+ /* read in the next point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* calculate the dot product of the normal and the light vector */
+ dotl = dot_product( &normal, &geo.light );
+
+ /* calculate the dot product of the normal and the point */
+ dotp = dot_product( &normal, &point );
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* determine wether this is the front or the back of the polygon */
+ face = 0x100; /* rear */
+ if ( dotp >= 0 ) face = 0; /* front */
+
+ /* get the texture parameters */
+ texparam = &geo.texture_parameters[(attr>>18) & 0x1f];
+
+ /* calculate luminance and specular */
+ if ( (dotl * dotp) < 0 ) luminance = 0;
+ else luminance = fabs( dotl );
+
+ specular = ((2*dotl) * normal.pz) - geo.light.pz;
+ if ( specular < 0 ) specular = 0;
+ if ( texparam->specular_control == 0 ) specular = 0;
+ if ( (texparam->specular_control >> 1) != 0 ) specular *= specular;
+ if ( (texparam->specular_control >> 2) != 0 ) specular *= specular;
+ if ( ((texparam->specular_control+1) >> 3) != 0 ) specular *= specular;
+
+ specular *= texparam->specular_scale;
+
+ luminance = (luminance * texparam->diffuse) + texparam->ambient + specular;
+ luma = (INT32)luminance;
+
+ if ( luma > 255 ) luma = 255;
+ if ( luma < 0 ) luma = 0;
+
+ /* add the face bit to the luma */
+ luma += face;
+
+ /* extract distance coefficient */
+ coef = geo.coef_table[attr>>27];
+
+ /* calculate texture level of detail */
+ distance = coef * fabs( dotp ) * geo.lod;
+
+ /* push to the 3d rasterizer */
+ model2_3d_push( luma << 15 );
+ model2_3d_push( f2u(distance) >> 8 );
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+
+ /* if it's a quad, push one more point */
+ if ( attr & 1 )
+ {
+ /* read in the next point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* push to the 3d rasterizer */
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+ }
+ else /* triangle */
+ {
+ /* skip the next 3 points */
+ input += 3;
+ }
+ }
+ else /* we're done */
+ {
+ break;
+ }
+ }
+
+ /* notify the 3d rasterizer we're done */
+ model2_3d_push( 0 );
+}
+
+/* Parse Polygons: No Normals, No Specular case */
+static void geo_parse_nn_ns( UINT32 *input, UINT32 count )
+{
+ poly_vertex point, normal, p0, p1, p2, p3;
+ UINT32 attr, i;
+
+ /* read the 1st point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* save for normal calculation */
+ p0.x = point.x; p0.y = point.y; p0.pz = point.pz;
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* push it to the 3d rasterizer */
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+
+ /* read the 2nd point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* save for normal calculation */
+ p1.x = point.x; p1.y = point.y; p1.pz = point.pz;
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* push it to the 3d rasterizer */
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+
+ /* skip 4 */
+ input += 4;
+
+ /* loop through the following links */
+ for( i = 0; i < count; i++ )
+ {
+ /* read in the attributes */
+ attr = *input++;
+
+ /* push to the 3d rasterizer */
+ model2_3d_push( attr & 0x0003FFFF );
+
+ if ( (attr & 3) != 0 ) /* quad or triangle */
+ {
+ float dotl, dotp, luminance, distance;
+ float coef, face;
+ INT32 luma;
+ texture_parameter * texparam;
+
+ /* read in the next point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* save for normal calculation */
+ p2.x = point.x; p2.y = point.y; p2.pz = point.pz;
+
+ /* compute the normal */
+ vector_cross3( &normal, &p0, &p1, &p2 );
+
+ /* normalize it */
+ normalize_vector( &normal );
+
+ /* calculate the dot product of the normal and the light vector */
+ dotl = dot_product( &normal, &geo.light );
+
+ /* calculate the dot product of the normal and the point */
+ dotp = dot_product( &normal, &point );
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* determine wether this is the front or the back of the polygon */
+ face = 0x100; /* rear */
+ if ( dotp >= 0 ) face = 0; /* front */
+
+ /* get the texture parameters */
+ texparam = &geo.texture_parameters[(attr>>18) & 0x1f];
+
+ /* calculate luminance */
+ if ( (dotl * dotp) < 0 ) luminance = 0;
+ else luminance = fabs( dotl );
+
+ luminance = (luminance * texparam->diffuse) + texparam->ambient;
+ luma = (INT32)luminance;
+
+ if ( luma > 255 ) luma = 255;
+ if ( luma < 0 ) luma = 0;
+
+ /* add the face bit to the luma */
+ luma += face;
+
+ /* extract distance coefficient */
+ coef = geo.coef_table[attr>>27];
+
+ /* calculate texture level of detail */
+ distance = coef * fabs( dotp ) * geo.lod;
+
+ /* push to the 3d rasterizer */
+ model2_3d_push( luma << 15 );
+ model2_3d_push( f2u(distance) >> 8 );
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+
+ /* if it's a quad, push one more point */
+ if ( attr & 1 )
+ {
+ /* read in the next point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* save for normal calculation */
+ p3.x = point.x; p3.y = point.y; p3.pz = point.pz;
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* push to the 3d rasterizer */
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+ }
+ else
+ {
+ /* skip the next 3 points */
+ input += 3;
+
+ /* for triangles, the rope of P1(n) is achieved by P0(n-1) (linktype 3) */
+ p3.x = p2.x; p3.y = p2.y; p3.pz = p2.pz;
+ }
+ }
+ else /* we're done */
+ {
+ break;
+ }
+
+ /* link type */
+ switch( (attr>>8) & 3 )
+ {
+ case 0:
+ case 2:
+ {
+ /* reuse P0(n) and P1(n) */
+ p0.x = p2.x; p0.y = p2.y; p0.pz = p2.pz;
+ p1.x = p3.x; p1.y = p3.y; p1.pz = p3.pz;
+ }
+ break;
+
+ case 1:
+ {
+ /* reuse P0(n-1) and P0(n) */
+ p1.x = p2.x; p1.y = p2.y; p1.pz = p2.pz;
+ }
+ break;
+
+ case 3:
+ {
+ /* reuse P1(n-1) and P1(n) */
+ p0.x = p3.x; p0.y = p3.y; p0.pz = p3.pz;
+ }
+ break;
+ }
+ }
+
+ /* notify the 3d rasterizer we're done */
+ model2_3d_push( 0 );
+}
+
+/* Parse Polygons: No Normals, Specular case */
+static void geo_parse_nn_s( UINT32 *input, UINT32 count )
+{
+ poly_vertex point, normal, p0, p1, p2, p3;
+ UINT32 attr, i;
+
+ /* read the 1st point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* save for normal calculation */
+ p0.x = point.x; p0.y = point.y; p0.pz = point.pz;
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* push it to the 3d rasterizer */
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+
+ /* read the 2nd point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* save for normal calculation */
+ p1.x = point.x; p1.y = point.y; p1.pz = point.pz;
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* push it to the 3d rasterizer */
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+
+ /* skip 4 */
+ input += 4;
+
+ /* loop through the following links */
+ for( i = 0; i < count; i++ )
+ {
+ /* read in the attributes */
+ attr = *input++;
+
+ /* push to the 3d rasterizer */
+ model2_3d_push( attr & 0x0003FFFF );
+
+ if ( (attr & 3) != 0 ) /* quad or triangle */
+ {
+ float dotl, dotp, luminance, distance, specular;
+ float coef, face;
+ INT32 luma;
+ texture_parameter * texparam;
+
+ /* read in the next point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* save for normal calculation */
+ p2.x = point.x; p2.y = point.y; p2.pz = point.pz;
+
+ /* compute the normal */
+ vector_cross3( &normal, &p0, &p1, &p2 );
+
+ /* normalize it */
+ normalize_vector( &normal );
+
+ /* calculate the dot product of the normal and the light vector */
+ dotl = dot_product( &normal, &geo.light );
+
+ /* calculate the dot product of the normal and the point */
+ dotp = dot_product( &normal, &point );
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* determine wether this is the front or the back of the polygon */
+ face = 0x100; /* rear */
+ if ( dotp >= 0 ) face = 0; /* front */
+
+ /* get the texture parameters */
+ texparam = &geo.texture_parameters[(attr>>18) & 0x1f];
+
+ /* calculate luminance and specular */
+ if ( (dotl * dotp) < 0 ) luminance = 0;
+ else luminance = fabs( dotl );
+
+ specular = ((2*dotl) * normal.pz) - geo.light.pz;
+ if ( specular < 0 ) specular = 0;
+ if ( texparam->specular_control == 0 ) specular = 0;
+ if ( (texparam->specular_control >> 1) != 0 ) specular *= specular;
+ if ( (texparam->specular_control >> 2) != 0 ) specular *= specular;
+ if ( ((texparam->specular_control+1) >> 3) != 0 ) specular *= specular;
+
+ specular *= texparam->specular_scale;
+
+ luminance = (luminance * texparam->diffuse) + texparam->ambient + specular;
+ luma = (INT32)luminance;
+
+ if ( luma > 255 ) luma = 255;
+ if ( luma < 0 ) luma = 0;
+
+ /* add the face bit to the luma */
+ luma += face;
+
+ /* extract distance coefficient */
+ coef = geo.coef_table[attr>>27];
+
+ /* calculate texture level of detail */
+ distance = coef * fabs( dotp ) * geo.lod;
+
+ /* push to the 3d rasterizer */
+ model2_3d_push( luma << 15 );
+ model2_3d_push( f2u(distance) >> 8 );
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+
+ /* if it's a quad, push one more point */
+ if ( attr & 1 )
+ {
+ /* read in the next point */
+ point.x = u2f( *input++ );
+ point.y = u2f( *input++ );
+ point.pz = u2f( *input++ );
+
+ /* transform with the current matrix */
+ transform_point( &point, geo.matrix );
+
+ /* save for normal calculation */
+ p3.x = point.x; p3.y = point.y; p3.pz = point.pz;
+
+ /* apply focus */
+ point.x *= geo.focus.x;
+ point.y *= geo.focus.y;
+
+ /* push to the 3d rasterizer */
+ model2_3d_push( f2u(point.x) >> 8 );
+ model2_3d_push( f2u(point.y) >> 8 );
+ model2_3d_push( f2u(point.pz) >> 8 );
+ }
+ else
+ {
+ /* skip the next 3 points */
+ input += 3;
+
+ /* for triangles, the rope of P1(n) is achieved by P0(n-1) (linktype 3) */
+ p3.x = p2.x; p3.y = p2.y; p3.pz = p2.pz;
+ }
+ }
+ else /* we're done */
+ {
+ break;
+ }
+
+ /* link type */
+ switch( (attr>>8) & 3 )
+ {
+ case 0:
+ case 2:
+ {
+ /* reuse P0(n) and P1(n) */
+ p0.x = p2.x; p0.y = p2.y; p0.pz = p2.pz;
+ p1.x = p3.x; p1.y = p3.y; p1.pz = p3.pz;
+ }
+ break;
+
+ case 1:
+ {
+ /* reuse P0(n-1) and P0(n) */
+ p1.x = p2.x; p1.y = p2.y; p1.pz = p2.pz;
+ }
+ break;
+
+ case 3:
+ {
+ /* reuse P1(n-1) and P1(n) */
+ p0.x = p3.x; p0.y = p3.y; p0.pz = p3.pz;
+ }
+ break;
+ }
+ }
+
+ /* notify the 3d rasterizer we're done */
+ model2_3d_push( 0 );
+}
+
+/*******************************************
+ *
+ * Geometry Engine Commands
+ *
+ *******************************************/
+
+/* Command 00: NOP */
+static UINT32 * geo_nop( UINT32 opcode, UINT32 *input )
+{
+ /* push the opcode to the 3d rasterizer */
+ model2_3d_push( opcode >> 23 );
+
+ return input;
+}
+
+/* Command 01: Object Data */
+static UINT32 * geo_object_data( UINT32 opcode, UINT32 *input )
+{
+ UINT32 tpa = *input++; /* Texture Point Address */
+ UINT32 tha = *input++; /* Texture Header Address */
+ UINT32 oba = *input++; /* Object Address */
+ UINT32 obc = *input++; /* Object Count */
+
+ UINT32 *obp; /* Object Pointer */
+
+ /* push the initial set of data to the 3d rasterizer */
+ model2_3d_push( opcode >> 23 );
+ model2_3d_push( tpa );
+ model2_3d_push( tha );
+
+ /* select where we're reading polygon information from */
+ if ( oba & 0x01000000 )
+ {
+ /* Fast polygon RAM */
+ obp = &geo.polygon_ram0[oba & 0x7FFF];
+ }
+ else if ( oba & 0x00800000 )
+ {
+ /* Polygon ROM */
+ obp = &geo.polygon_rom[oba & 0x7FFFFF];
+ }
+ else
+ {
+ /* Slow Polygon RAM */
+ obp = &geo.polygon_ram1[oba & 0x7FFF];
+ }
+
+ switch( geo.mode & 3 )
+ {
+ /* Normals present, No Specular */
+ case 0: geo_parse_np_ns( obp, obc ); break;
+
+ /* Normals present, Specular */
+ case 1: geo_parse_np_s( obp, obc ); break;
+
+ /* No Normals present, No Specular */
+ case 2: geo_parse_nn_ns( obp, obc ); break;
+
+ /* No Normals present, Specular */
+ case 3: geo_parse_nn_s( obp, obc ); break;
+ }
+
+ /* move by 4 parameters */
+ return input;
+}
+
+/* Command 02: Direct Data */
+static UINT32 * geo_direct_data( UINT32 opcode, UINT32 *input )
+{
+ UINT32 tpa = *input++; /* Texture Point Address */
+ UINT32 tha = *input++; /* Texture Header Address */
+ UINT32 attr;
+
+ /* push the initial set of data to the 3d rasterizer */
+ model2_3d_push( (opcode >> 23) - 1 );
+ model2_3d_push( tpa );
+ model2_3d_push( tha );
+
+ /* push the initial points */
+ model2_3d_push( (*input++) >> 8 ); /* x */
+ model2_3d_push( (*input++) >> 8 ); /* y */
+ model2_3d_push( (*input++) >> 8 ); /* z */
+
+ model2_3d_push( (*input++) >> 8 ); /* x */
+ model2_3d_push( (*input++) >> 8 ); /* y */
+ model2_3d_push( (*input++) >> 8 ); /* z */
+
+ do
+ {
+ /* read in the attributes */
+ attr = *input++;
+
+ if ( (attr & 3) == 0 )
+ break;
+
+ /* push attributes */
+ model2_3d_push( attr & 0x00FFFFFF );
+
+ /* push luma */
+ model2_3d_push( (*input++) >> 8 );
+
+ /* push distance */
+ model2_3d_push( (*input++) >> 8 );
+
+ /* push the next point */
+ model2_3d_push( (*input++) >> 8 ); /* x */
+ model2_3d_push( (*input++) >> 8 ); /* y */
+ model2_3d_push( (*input++) >> 8 ); /* z */
+
+ /* if it's a quad, output another point */
+ if ( attr & 1 )
+ {
+ model2_3d_push( (*input++) >> 8 ); /* x */
+ model2_3d_push( (*input++) >> 8 ); /* y */
+ model2_3d_push( (*input++) >> 8 ); /* z */
+ }
+ } while( 1 );
+
+ /* we're done */
+ model2_3d_push( 0 );
+
+ return input;
+}
+
+/* Command 03: Window Data */
+static UINT32 * geo_window_data( UINT32 opcode, UINT32 *input )
+{
+ UINT32 x, y, i;
+
+ /* start by pushing the opcode */
+ model2_3d_push( opcode >> 23 );
+
+ /*
+ we're going to move 6 coordinates to the 3d rasterizer:
+ - starting coordinate
+ - completion coordinate
+ - vanishing point 0 (eye mode 0)
+ - vanishing point 1 (eye mode 1)
+ - vanishing point 2 (eye mode 2)
+ - vanishing point 3 (eye mode 3)
+ */
+
+ for( i = 0; i < 6; i++ )
+ {
+ /* read in the coordinate */
+ y = *input++;
+
+ /* convert to the 3d rasterizer format (00XXXYYY) */
+ x = ( y & 0x0FFF0000 ) >> 4 ;
+ y &= 0xFFF;
+
+ /* push it */
+ model2_3d_push( x | y );
+ }
+
+ return input;
+}
+
+/* Command 04: Texture Data Write */
+static UINT32 * geo_texture_data( UINT32 opcode, UINT32 *input )
+{
+ UINT32 i, count;
+
+ /* start by pushing the opcode */
+ model2_3d_push( opcode >> 23 );
+
+ /* push the starting address/dsp id */
+ model2_3d_push( *input++ );
+
+ /* get the count */
+ count = *input++;
+
+ /* push the count */
+ model2_3d_push( count );
+
+ /* loop and send the data */
+ for( i = 0; i < count; i++ )
+ model2_3d_push( *input++ );
+
+ return input;
+}
+
+/* Command 05: Polygon Data */
+static UINT32 * geo_polygon_data( UINT32 opcode, UINT32 *input )
+{
+ UINT32 address, count, i;
+ UINT32 *p;
+
+ (void)opcode;
+
+ /* read in the address */
+ address = *input++;
+
+ /* prepare the pointer */
+ if ( address & 0x01000000 )
+ {
+ /* Fast polygon RAM */
+ p = &geo.polygon_ram0[address & 0x7FFF];
+ }
+ else
+ {
+ /* Slow Polygon RAM */
+ p = &geo.polygon_ram1[address & 0x7FFF];
+ }
+
+ /* read the count */
+ count = *input++;
+
+ /* move the data */
+ for( i = 0; i < count; i++ )
+ *p++ = *input++;
+
+ return input;
+}
+
+/* Command 06: Texture Parameters */
+static UINT32 * geo_texture_parameters( UINT32 opcode, UINT32 *input )
+{
+ UINT32 index, count, i, param;
+
+ (void)opcode;
+
+ /* read in the index */
+ index = *input++;
+
+ /* read in the conut */
+ count = *input++;
+
+ for( i = 0; i < count; i++ )
+ {
+ /* read in the texture parameters */
+ param = *input++;
+
+ geo.texture_parameters[index].diffuse = (float)( param & 0xFF );
+ geo.texture_parameters[index].ambient = (float)( (param >> 8) & 0xFF );
+ geo.texture_parameters[index].specular_control = (param >> 24) & 0xFF;
+ geo.texture_parameters[index].specular_scale = (float)( (param >> 16) & 0xFF );
+
+ /* read in the distance coefficient */
+ geo.coef_table[index] = u2f(*input++);
+
+ index = (index + 1) & 0x1F;
+ }
+
+ return input;
+}
+
+/* Command 07: Geo Mode */
+static UINT32 * geo_mode( UINT32 opcode, UINT32 *input )
+{
+ (void)opcode;
+
+ /* read in the mode */
+ geo.mode = *input++;
+
+ return input;
+}
+
+/* Command 08: ZSort Mode */
+static UINT32 * geo_zsort_mode( UINT32 opcode, UINT32 *input )
+{
+ /* push the opcode */
+ model2_3d_push( opcode >> 23 );
+
+ /* push the mode */
+ model2_3d_push( (*input++) >> 8 );
+
+ return input;
+}
+
+/* Command 09: Focal Distance */
+static UINT32 * geo_focal_distance( UINT32 opcode, UINT32 *input )
+{
+ (void)opcode;
+
+ /* read the x focus value */
+ geo.focus.x = u2f( *input++ );
+
+ /* read the y focus value */
+ geo.focus.y = u2f( *input++ );
+
+ return input;
+}
+
+/* Command 0A: Light Source Vector Write */
+static UINT32 * geo_light_source( UINT32 opcode, UINT32 *input )
+{
+ (void)opcode;
+
+ /* read the x light value */
+ geo.light.x = u2f( *input++ );
+
+ /* read the y light value */
+ geo.light.y = u2f( *input++ );
+
+ /* read the z light value */
+ geo.light.pz = u2f( *input++ );
+
+ return input;
+}
+
+/* Command 0B: Transformation Matrix Write */
+static UINT32 * geo_matrix_write( UINT32 opcode, UINT32 *input )
+{
+ UINT32 i;
+
+ (void)opcode;
+
+ /* read in the transformation matrix */
+ for( i = 0; i < 12; i++ )
+ geo.matrix[i] = u2f( *input++ );
+
+ return input;
+}
+
+/* Command 0C: Parallel Transfer Vector Write */
+static UINT32 * geo_translate_write( UINT32 opcode, UINT32 *input )
+{
+ UINT32 i;
+
+ (void)opcode;
+
+ /* read in the translation vector */
+ for( i = 0; i < 3; i++ )
+ geo.matrix[i+9] = u2f( *input++ );
+
+ return input;
+}
+
+/* Command 0D: Geo Data Memory Push (undocumented, unsupported) */
+static UINT32 * geo_data_mem_push( UINT32 opcode, UINT32 *input )
+{
+ UINT32 address, count, i;
+
+ /*
+ This command pushes data stored in the Geometry DSP's RAM
+ to the hardware 3D rasterizer. Since we don't emulate the
+ DSP, we don't know what the RAM contents are.
+
+ Eventually, we could check for the address, and if it
+ happens to point to a polygon ROM, we could potentially
+ emulate it partially.
+
+ No games are known to use this command yet.
+ */
+
+
+ (void)opcode;
+
+ /* read in the address */
+ address = *input++;
+
+ /* read in the count */
+ count = *input++;
+
+ logerror( "SEGA GEO: Executing unsupported geo_data_mem_push (address = %08x, count = %08x)\n", address, count );
+
+ (void)i;
+/*
+ for( i = 0; i < count; i++ )
+ model2_3d_push( 0 );
+*/
+
+ return input;
+}
+
+/* Command 0E: Geo Test */
+static UINT32 * geo_test( UINT32 opcode, UINT32 *input )
+{
+ UINT32 data, blocks, address, count, checksum, i;
+
+ (void)opcode;
+
+ /* fifo test */
+ data = 1;
+
+ for( i = 0; i < 32; i++ )
+ {
+ if ( *input++ != data )
+ {
+ /* TODO: Set Red LED on */
+ logerror( "SEGA GEO: FIFO Test failed\n" );
+ }
+
+ data <<= 1;
+ }
+
+ /* get the number of checksums we have to run */
+ blocks = *input++;
+
+ for( i = 0; i < blocks; i++ )
+ {
+ UINT32 sum_even, sum_odd, j;
+
+ /* read in the address */
+ address = (*input++) & 0x7FFFFF;
+
+ /* read in the count */
+ count = *input++;
+
+ /* read in the checksum */
+ checksum = *input++;
+
+ /* reset the checksum counters */
+ sum_even = 0;
+ sum_odd = 0;
+
+ for( j = 0; j < count; j++ )
+ {
+ data = geo.polygon_rom[address++];
+
+ address &= 0x7FFFFF;
+
+ sum_even += data >> 16;
+ sum_even &= 0xFFFF;
+
+ sum_odd += data & 0xFFFF;
+ sum_odd &= 0xFFFF;
+ }
+
+ sum_even += checksum >> 16;
+ sum_even &= 0xFFFF;
+
+ sum_odd += checksum & 0xFFFF;
+ sum_odd &= 0xFFFF;
+
+ if ( sum_even != 0 || sum_odd != 0 )
+ {
+ /* TODO: Set Green LED on */
+ logerror( "SEGA GEO: Polygon ROM Test failed\n" );
+ }
+ }
+
+ return input;
+}
+
+/* Command 0F: End */
+static UINT32 * geo_end( UINT32 opcode, UINT32 *input )
+{
+ (void)opcode;
+
+ /* signal the end of this data block the rasterizer */
+ model2_3d_push( 0xFF000000 );
+
+ /* signal end by returning NULL */
+ return NULL;
+}
+
+/* Command 10: Dummy */
+static UINT32 * geo_dummy( UINT32 opcode, UINT32 *input )
+{
+ UINT32 data;
+ (void)opcode;
+
+ /* do the dummy read cycle */
+ data = *input++;
+
+ return input;
+}
+
+/* Command 14: Log Data Write */
+static UINT32 * geo_log_data( UINT32 opcode, UINT32 *input )
+{
+ UINT32 i, count;
+
+ /* start by pushing the opcode */
+ model2_3d_push( opcode >> 23 );
+
+ /* push the starting address/dsp id */
+ model2_3d_push( *input++ );
+
+ /* get the count */
+ count = *input++;
+
+ /* push the count */
+ model2_3d_push( count << 2 );
+
+ /* loop and send the data */
+ for( i = 0; i < count; i++ )
+ {
+ UINT32 data = *input++;
+
+ model2_3d_push( data & 0xff );
+ model2_3d_push( (data >> 8) & 0xff );
+ model2_3d_push( (data >> 16) & 0xff );
+ model2_3d_push( (data >> 24) & 0xff );
+ }
+
+ return input;
+}
+
+/* Command 16: LOD */
+static UINT32 * geo_lod( UINT32 opcode, UINT32 *input )
+{
+ (void)opcode;
+
+ /* read in the LOD */
+ geo.lod = u2f(*input++);
+
+ return input;
+}
+
+/* Command 1D: Code Upload (undocumented, unsupported) */
+static UINT32 * geo_code_upload( UINT32 opcode, UINT32 *input )
+{
+ UINT32 flags, count, i;
+
+ /*
+ This command uploads code to program memory and
+ optionally runs it. Probably used for debugging.
+
+ No games are known to use this command yet.
+ */
+
+ logerror( "SEGA GEO: Uploading debug code (unimplemented)\n" );
+
+ (void)opcode;
+
+ /* read in the flags */
+ flags = *input++;
+
+ /* read in the count */
+ count = *input++;
+
+ for( i = 0; i < count; i++ )
+ {
+ UINT64 code;
+
+ /* read the top part of the opcode */
+ code = *input++;
+
+ code <<= 32;
+
+ /* the bottom part comes in two pieces */
+ code |= *input++;
+ code |= (*input++) << 16;
+ }
+
+ /*
+ Bit 10 of flags indicate wether to run iummediately after upload
+ */
+
+/*
+ if ( flags & 0x400 )
+ code_jump();
+*/
+
+ return input;
+}
+
+/* Command 1E: Code Jump (undocumented, unsupported) */
+static UINT32 * geo_code_jump( UINT32 opcode, UINT32 *input )
+{
+ UINT32 address;
+
+ /*
+ This command jumps to a specified address in program
+ memory. Code can be uploaded with function 1D.
+ Probably used for debugging.
+
+ No games are known to use this command yet.
+ */
+
+ logerror( "SEGA GEO: Jumping to debug code (unimplemented)\n" );
+
+ (void)opcode;
+
+ address = *input++ & 0x3FF;
+
+/*
+ code_jump( address )
+*/
+ return input;
+}
+
+static UINT32 * geo_process_command( UINT32 opcode, UINT32 *input )
+{
+ switch( opcode >> 23 )
+ {
+ case 0x00: input = geo_nop( opcode, input ); break;
+ case 0x01: input = geo_object_data( opcode, input ); break;
+ case 0x02: input = geo_direct_data( opcode, input ); break;
+ case 0x03: input = geo_window_data( opcode, input ); break;
+ case 0x04: input = geo_texture_data( opcode, input ); break;
+ case 0x05: input = geo_polygon_data( opcode, input ); break;
+ case 0x06: input = geo_texture_parameters( opcode, input ); break;
+ case 0x07: input = geo_mode( opcode, input ); break;
+ case 0x08: input = geo_zsort_mode( opcode, input ); break;
+ case 0x09: input = geo_focal_distance( opcode, input ); break;
+ case 0x0A: input = geo_light_source( opcode, input ); break;
+ case 0x0B: input = geo_matrix_write( opcode, input ); break;
+ case 0x0C: input = geo_translate_write( opcode, input ); break;
+ case 0x0D: input = geo_data_mem_push( opcode, input ); break;
+ case 0x0E: input = geo_test( opcode, input ); break;
+ case 0x0F: input = geo_end( opcode, input ); break;
+ case 0x10: input = geo_dummy( opcode, input ); break;
+ case 0x11: input = geo_object_data( opcode, input ); break;
+ case 0x12: input = geo_direct_data( opcode, input ); break;
+ case 0x13: input = geo_window_data( opcode, input ); break;
+ case 0x14: input = geo_log_data( opcode, input ); break;
+ case 0x15: input = geo_polygon_data( opcode, input ); break;
+ case 0x16: input = geo_lod( opcode, input ); break;
+ case 0x17: input = geo_mode( opcode, input ); break;
+ case 0x18: input = geo_zsort_mode( opcode, input ); break;
+ case 0x19: input = geo_focal_distance( opcode, input ); break;
+ case 0x1A: input = geo_light_source( opcode, input ); break;
+ case 0x1B: input = geo_matrix_write( opcode, input ); break;
+ case 0x1C: input = geo_translate_write( opcode, input ); break;
+ case 0x1D: input = geo_code_upload( opcode, input ); break;
+ case 0x1E: input = geo_code_jump( opcode, input ); break;
+ case 0x1F: input = geo_end( opcode, input ); break;
+ }
+
+ return input;
+}
+
+static void geo_parse( void )
+{
+ UINT32 address = (geo_read_start_address/4);
+ UINT32 *input = &model2_bufferram[address];
+ UINT32 opcode;
+
+ while( input != NULL && (input - model2_bufferram) < 0x20000 )
+ {
+ /* read in the opcode */
+ opcode = *input++;
+
+ /* if it's a jump opcode, do the jump */
+ if ( opcode & 0x80000000 )
+ {
+ /* get the address */
+ address = (opcode & 0x7FFFF) / 4;
+
+ /* update our pointer */
+ input = &model2_bufferram[address];
+
+ /* go again */
+ continue;
+ }
+
+ /* process it */
+ input = geo_process_command( opcode, input );
+ }
+}
+
+/***********************************************************************************************/
+
+static bitmap_t *sys24_bitmap = NULL;
+
+static void model2_exit(running_machine *machine)
+{
+ poly_free(poly);
+ if ( sys24_bitmap != NULL )
+ {
+ bitmap_free( sys24_bitmap );
+ sys24_bitmap = NULL;
+ }
+}
+
+VIDEO_START(model2)
+{
+ int width = machine->screen[0].visarea.max_x - machine->screen[0].visarea.min_x;
+ int height = machine->screen[0].visarea.max_y - machine->screen[0].visarea.min_y;
+
+ sys24_tile_vh_start(machine, 0x3fff);
+ sys24_bitmap = bitmap_alloc(width, height+4, BITMAP_FORMAT_INDEXED16);
+
+ poly = poly_alloc(4000, sizeof(poly_extra_data), 0);
+ add_exit_callback(machine, model2_exit);
+
+ /* initialize the geometry engine */
+ geo_init( (UINT32*)memory_region(REGION_USER2) );
+
+ /* initialize the hardware rasterizer */
+ model2_3d_init( (UINT16*)memory_region(REGION_USER3) );
+}
+
+static void convert_bitmap( running_machine *machine, bitmap_t *dst, bitmap_t *src, const rectangle *rect )
+{
+ int x, y;
+
+ for( y = rect->min_y; y < rect->max_y; y++ )
+ {
+ UINT32 *d = BITMAP_ADDR32( dst, y, 0 );
+ UINT16 *s = BITMAP_ADDR16( src, y, 0 );
+
+ for( x = rect->min_x; x < rect->max_x; x++ )
+ {
+ if ( s[x] )
+ d[x] = machine->pens[s[x]];
+ }
+ }
+}
+
+VIDEO_UPDATE(model2)
+{
+ logerror("--- frame ---\n");
+
+ sys24_tile_update(machine);
+ fillbitmap(bitmap, machine->pens[0], &machine->screen[0].visarea);
+ fillbitmap(sys24_bitmap, 0, &machine->screen[0].visarea);
+
+ sys24_tile_draw(machine, sys24_bitmap, cliprect, 7, 0, 0);
+ sys24_tile_draw(machine, sys24_bitmap, cliprect, 6, 0, 0);
+ sys24_tile_draw(machine, sys24_bitmap, cliprect, 5, 0, 0);
+ sys24_tile_draw(machine, sys24_bitmap, cliprect, 4, 0, 0);
+
+ convert_bitmap(machine, bitmap, sys24_bitmap, cliprect);
+
+ /* tell the rasterizer we're starting a frame */
+ model2_3d_frame_start();
+
+ /* let the geometry engine do it's thing */
+ geo_parse();
+
+ /* have the rasterizer output the frame */
+ model2_3d_frame_end( bitmap, cliprect );
+
+ fillbitmap(sys24_bitmap, 0, &machine->screen[0].visarea);
+ sys24_tile_draw(machine, sys24_bitmap, cliprect, 3, 0, 0);
+ sys24_tile_draw(machine, sys24_bitmap, cliprect, 2, 0, 0);
+ sys24_tile_draw(machine, sys24_bitmap, cliprect, 1, 0, 0);
+ sys24_tile_draw(machine, sys24_bitmap, cliprect, 0, 0, 0);
+
+ convert_bitmap(machine, bitmap, sys24_bitmap, cliprect);
+
+ return 0;
+}
+
diff --git a/src/mame/video/model2rd.c b/src/mame/video/model2rd.c
new file mode 100644
index 00000000000..57fb4a76189
--- /dev/null
+++ b/src/mame/video/model2rd.c
@@ -0,0 +1,191 @@
+/********************************************************************
+
+ Sega Model 2 3D rasterization functions
+
+********************************************************************/
+
+#undef MODEL2_CHECKER
+#undef MODEL2_TEXTURED
+#undef MODEL2_TRANSLUCENT
+
+#ifndef MODEL2_FUNC
+#error "Model 2 renderer: No function defined!"
+#endif
+
+#ifndef MODEL2_FUNC_NAME
+#error "Model 2 renderer: No function name defined!"
+#endif
+
+#if MODEL2_FUNC == 0
+#undef MODEL2_CHECKER
+#undef MODEL2_TEXTURED
+#undef MODEL2_TRANSLUCENT
+#elif MODEL2_FUNC == 1
+#undef MODEL2_CHECKER
+#undef MODEL2_TEXTURED
+#define MODEL2_TRANSLUCENT
+#elif MODEL2_FUNC == 2
+#undef MODEL2_CHECKER
+#define MODEL2_TEXTURED
+#undef MODEL2_TRANSLUCENT
+#elif MODEL2_FUNC == 3
+#undef MODEL2_CHECKER
+#define MODEL2_TEXTURED
+#define MODEL2_TRANSLUCENT
+#elif MODEL2_FUNC == 4
+#define MODEL2_CHECKER
+#undef MODEL2_TEXTURED
+#undef MODEL2_TRANSLUCENT
+#elif MODEL2_FUNC == 5
+#define MODEL2_CHECKER
+#undef MODEL2_TEXTURED
+#define MODEL2_TRANSLUCENT
+#elif MODEL2_FUNC == 6
+#define MODEL2_CHECKER
+#define MODEL2_TEXTURED
+#undef MODEL2_TRANSLUCENT
+#elif MODEL2_FUNC == 7
+#define MODEL2_CHECKER
+#define MODEL2_TEXTURED
+#define MODEL2_TRANSLUCENT
+#elif
+#error "Model 2 renderer: Invalif function selected!"
+#endif
+
+#ifndef MODEL2_TEXTURED
+/* non-textured render path */
+static void MODEL2_FUNC_NAME(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ mame_bitmap *destmap = dest;
+ UINT32 *p = BITMAP_ADDR32(destmap, scanline, 0);
+
+ /* extract color information */
+ const UINT16 *colortable_r = (const UINT16 *)&model2_colorxlat[0x0000/4];
+ const UINT16 *colortable_g = (const UINT16 *)&model2_colorxlat[0x4000/4];
+ const UINT16 *colortable_b = (const UINT16 *)&model2_colorxlat[0x8000/4];
+ const UINT16 *lumaram = (const UINT16 *)model2_lumaram;
+ const UINT16 *palram = (const UINT16 *)paletteram32;
+ UINT32 lumabase = extra->lumabase;
+ UINT32 color = extra->colorbase;
+ UINT8 luma;
+ UINT32 tr, tg, tb;
+ int x;
+
+ /* if it's translucent, there's nothing to render */
+#if defined( MODEL2_TRANSLUCENT)
+ return;
+#endif
+
+ luma = lumaram[BYTE_XOR_LE(lumabase + (0xf << 3))] & 0x3F;
+
+ color = palram[BYTE_XOR_LE(color + 0x1000)] & 0x7fff;
+
+ colortable_r += ((color >> 0) & 0x1f) << 8;
+ colortable_g += ((color >> 5) & 0x1f) << 8;
+ colortable_b += ((color >> 10) & 0x1f) << 8;
+
+ /* we have the 6 bits of luma information along with 5 bits per color component */
+ /* now build and index into the master color lookup table and extract the raw RGB values */
+
+ tr = colortable_r[BYTE_XOR_LE(luma)] & 0xff;
+ tg = colortable_g[BYTE_XOR_LE(luma)] & 0xff;
+ tb = colortable_b[BYTE_XOR_LE(luma)] & 0xff;
+
+ /* build the final color */
+ color = MAKE_RGB(tr, tg, tb);
+
+ for(x = extent->startx; x < extent->stopx; x++)
+#if defined(MODEL2_CHECKER)
+ if ((x^scanline) & 1) p[x] = color;
+#else
+ p[x] = color;
+#endif
+}
+
+#else
+/* textured render path */
+static void MODEL2_FUNC_NAME(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ mame_bitmap *destmap = dest;
+ UINT32 *p = BITMAP_ADDR32(destmap, scanline, 0);
+
+ UINT32 tex_width = extra->texwidth;
+ UINT32 tex_height = extra->texheight;
+
+ /* extract color information */
+ const UINT16 *colortable_r = (const UINT16 *)&model2_colorxlat[0x0000/4];
+ const UINT16 *colortable_g = (const UINT16 *)&model2_colorxlat[0x4000/4];
+ const UINT16 *colortable_b = (const UINT16 *)&model2_colorxlat[0x8000/4];
+ const UINT16 *lumaram = (const UINT16 *)model2_lumaram;
+ const UINT16 *palram = (const UINT16 *)paletteram32;
+ UINT32 colorbase = extra->colorbase;
+ UINT32 lumabase = extra->lumabase;
+ UINT32 tex_x = extra->texx;
+ UINT32 tex_y = extra->texy;
+ UINT32 tex_x_mask, tex_y_mask;
+ UINT32 tex_mirr_x = extra->texmirrorx;
+ UINT32 tex_mirr_y = extra->texmirrory;
+ UINT32 *sheet = extra->texsheet;
+ float ooz = extent->param[0].start;
+ float uoz = extent->param[1].start;
+ float voz = extent->param[2].start;
+ float dooz = extent->param[0].dpdx;
+ float duoz = extent->param[1].dpdx;
+ float dvoz = extent->param[2].dpdx;
+ int x;
+
+ tex_x_mask = tex_width - 1;
+ tex_y_mask = tex_height - 1;
+
+ colorbase = palram[BYTE_XOR_LE(colorbase + 0x1000)] & 0x7fff;
+
+ colortable_r += ((colorbase >> 0) & 0x1f) << 8;
+ colortable_g += ((colorbase >> 5) & 0x1f) << 8;
+ colortable_b += ((colorbase >> 10) & 0x1f) << 8;
+
+ for(x = extent->startx; x < extent->stopx; x++, uoz += duoz, voz += dvoz, ooz += dooz)
+ {
+ float z = recip_approx(ooz) * 256.0f;
+ INT32 u = uoz * z;
+ INT32 v = voz * z;
+ UINT32 tr, tg, tb;
+ UINT16 t;
+ UINT8 luma;
+ int u2;
+ int v2;
+
+#if defined(MODEL2_CHECKER)
+ if ( ((x^scanline) & 1) == 0 )
+ continue;
+#endif
+ u2 = (u >> 8) & tex_x_mask;
+ v2 = (v >> 8) & tex_y_mask;
+
+ if ( tex_mirr_x )
+ u2 = ( tex_width - 1 ) - u2;
+
+ if ( tex_mirr_y )
+ v2 = ( tex_height - 1 ) - v2;
+
+ t = get_texel( tex_x, tex_y, u2, v2, sheet );
+
+#if defined(MODEL2_TRANSLUCENT)
+ if ( t == 0x0f )
+ continue;
+#endif
+ luma = lumaram[BYTE_XOR_LE(lumabase + (t << 3))] & 0x3f;
+
+ /* we have the 6 bits of luma information along with 5 bits per color component */
+ /* now build and index into the master color lookup table and extract the raw RGB values */
+
+ tr = colortable_r[BYTE_XOR_LE(luma)] & 0xff;
+ tg = colortable_g[BYTE_XOR_LE(luma)] & 0xff;
+ tb = colortable_b[BYTE_XOR_LE(luma)] & 0xff;
+
+ p[x] = MAKE_RGB(tr, tg, tb);
+ }
+}
+
+#endif
diff --git a/src/mame/video/model3.c b/src/mame/video/model3.c
new file mode 100644
index 00000000000..b2831fea32e
--- /dev/null
+++ b/src/mame/video/model3.c
@@ -0,0 +1,1512 @@
+#include "driver.h"
+#include "video/poly.h"
+#include "video/rgbutil.h"
+#include "eminline.h"
+#include <math.h>
+
+
+#define pz p[0]
+#define pu p[1]
+#define pv p[2]
+
+
+
+typedef float MATRIX[4][4];
+typedef float VECTOR[4];
+typedef float VECTOR3[3];
+
+typedef struct {
+ float x,y,z,d;
+} PLANE;
+
+typedef struct
+{
+ poly_vertex v[3];
+ UINT8 texture_x, texture_y;
+ UINT8 texture_width, texture_height;
+ UINT8 transparency;
+ UINT8 texture_format, param;
+ int intensity;
+ UINT32 color;
+} TRIANGLE;
+
+typedef struct _cached_texture cached_texture;
+struct _cached_texture
+{
+ cached_texture *next;
+ UINT8 width;
+ UINT8 height;
+ UINT8 format;
+ UINT8 alpha;
+ rgb_t data[1];
+};
+
+typedef struct _poly_extra_data poly_extra_data;
+struct _poly_extra_data
+{
+ cached_texture *texture;
+ UINT32 color;
+ UINT8 texture_param;
+ int polygon_transparency;
+ int polygon_intensity;
+};
+
+#define TRI_PARAM_TEXTURE_PAGE 0x1
+#define TRI_PARAM_TEXTURE_MIRROR_U 0x2
+#define TRI_PARAM_TEXTURE_MIRROR_V 0x4
+#define TRI_PARAM_TEXTURE_ENABLE 0x8
+#define TRI_PARAM_ALPHA_TEST 0x10
+
+#define MAX_TRIANGLES 131072
+
+
+/* forward declarations */
+static void real3d_traverse_display_list(void);
+static void draw_model(UINT32 addr);
+static void init_matrix_stack(void);
+static void get_top_matrix(MATRIX *out);
+static void push_matrix_stack(void);
+static void pop_matrix_stack(void);
+static void multiply_matrix_stack(MATRIX matrix);
+static void translate_matrix_stack(float x, float y, float z);
+static void traverse_list(UINT32 address);
+static void draw_block(UINT32 address);
+static void draw_viewport(int pri, UINT32 address);
+
+/*****************************************************************************/
+
+extern int model3_irq_state;
+
+extern int model3_step;
+
+extern UINT32 *model3_vrom;
+
+UINT64 *paletteram64;
+
+static UINT8 model3_layer_enable = 0;
+static UINT32 layer_modulate_r;
+static UINT32 layer_modulate_g;
+static UINT32 layer_modulate_b;
+static UINT32 model3_layer_modulate1;
+static UINT32 model3_layer_modulate2;
+static UINT64 layer_scroll[2];
+
+static UINT64 *m3_char_ram;
+static UINT64 *m3_tile_ram;
+
+static UINT32 *texture_fifo;
+static int texture_fifo_pos = 0;
+
+static UINT16 *texture_ram[2];
+static UINT32 *display_list_ram;
+static UINT32 *culling_ram;
+static UINT32 *polygon_ram;
+
+static UINT16 *pal_lookup;
+
+static int real3d_display_list = 0;
+
+static mame_bitmap *bitmap3d;
+static mame_bitmap *zbuffer;
+static rectangle clip3d;
+static rectangle *screen_clip;
+
+
+static VECTOR3 parallel_light;
+static float parallel_light_intensity;
+static float ambient_light_intensity;
+
+static poly_manager *poly;
+static cached_texture *texcache[2][1024/32][2048/32];
+
+
+static int list_depth = 0;
+
+
+#define BYTE_REVERSE32(x) (((x >> 24) & 0xff) | \
+ ((x >> 8) & 0xff00) | \
+ ((x << 8) & 0xff0000) | \
+ ((x << 24) & 0xff000000))
+
+#define BYTE_REVERSE16(x) (((x >> 8) & 0xff) | ((x << 8) & 0xff00))
+
+static void invalidate_texture(int page, int texx, int texy, int texwidth, int texheight);
+
+
+static void model3_exit(running_machine *machine)
+{
+ invalidate_texture(0, 0, 0, 6, 5);
+ invalidate_texture(1, 0, 0, 6, 5);
+ poly_free(poly);
+}
+
+VIDEO_START( model3 )
+{
+ poly = poly_alloc(4000, sizeof(poly_extra_data), 0);
+ add_exit_callback(machine, model3_exit);
+
+ bitmap3d = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ zbuffer = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED32);
+
+ m3_char_ram = auto_malloc(0x100000);
+ m3_tile_ram = auto_malloc(0x8000);
+
+ memset(m3_char_ram, 0, 0x100000);
+ memset(m3_tile_ram, 0, 0x8000);
+
+ pal_lookup = auto_malloc(65536*2);
+ memset(pal_lookup, 0, 65536*2);
+
+ texture_fifo = auto_malloc(0x100000);
+
+ /* 2x 4MB texture sheets */
+ texture_ram[0] = auto_malloc(0x400000);
+ texture_ram[1] = auto_malloc(0x400000);
+
+ /* 1MB Display List RAM */
+ display_list_ram = auto_malloc(0x100000);
+ /* 4MB for nodes (< Step 2.0 have only 2MB) */
+ culling_ram = auto_malloc(0x400000);
+ /* 4MB Polygon RAM */
+ polygon_ram = auto_malloc(0x400000);
+
+ memset(display_list_ram, 0, 0x100000);
+ memset(culling_ram, 0, 0x400000);
+ memset(polygon_ram, 0, 0x400000);
+ memset(texture_fifo, 0, 0x100000);
+
+ init_matrix_stack();
+}
+
+static void draw_tile_4bit(mame_bitmap *bitmap, int tx, int ty, int tilenum)
+{
+ int x, y;
+ UINT8 *tile_base = (UINT8*)m3_char_ram;
+ UINT8 *tile;
+
+ int data = (BYTE_REVERSE16(tilenum));
+ int c = data & 0x7ff0;
+ int tile_index = ((data << 1) & 0x7ffe) | ((data >> 15) & 0x1);
+ tile_index *= 32;
+
+ tile = &tile_base[tile_index];
+
+ for(y = ty; y < ty+8; y++) {
+ UINT16 *d = BITMAP_ADDR16(bitmap, y^1, 0);
+ for(x = tx; x < tx+8; x+=2) {
+ UINT8 tile0, tile1;
+ UINT16 pix0, pix1;
+ tile0 = *tile >> 4;
+ tile1 = *tile & 0xf;
+ pix0 = pal_lookup[c + tile0];
+ pix1 = pal_lookup[c + tile1];
+ if((pix0 & 0x8000) == 0)
+ {
+ d[x+0] = pix0;
+ }
+ if((pix1 & 0x8000) == 0)
+ {
+ d[x+1] = pix1;
+ }
+ ++tile;
+ }
+ }
+}
+
+static void draw_tile_8bit(mame_bitmap *bitmap, int tx, int ty, int tilenum)
+{
+ int x, y;
+ UINT8 *tile_base = (UINT8*)m3_char_ram;
+ UINT8 *tile;
+
+ int data = (BYTE_REVERSE16(tilenum));
+ int c = data & 0x7f00;
+ int tile_index = ((data << 1) & 0x7ffe) | ((data >> 15) & 0x1);
+ tile_index *= 32;
+
+ tile = &tile_base[tile_index];
+
+ for(y = ty; y < ty+8; y++) {
+ UINT16 *d = BITMAP_ADDR16(bitmap, y, 0);
+ int xx = 0;
+ for(x = tx; x < tx+8; x++) {
+ UINT8 tile0;
+ UINT16 pix;
+ tile0 = tile[xx^4];
+ pix = pal_lookup[c + tile0];
+ if((pix & 0x8000) == 0)
+ {
+ d[x] = pix;
+ }
+ ++xx;
+ }
+ tile += 8;
+ }
+}
+#if 0
+static void draw_texture_sheet(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int x,y;
+ for(y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *d = BITMAP_ADDR16(bitmap, y, 0);
+ int index = (y*2)*2048;
+ for(x = cliprect->min_x; x <= cliprect->max_x; x++) {
+ UINT16 pix = texture_ram[0][index];
+ index+=4;
+ if(pix != 0) {
+ d[x] = pix;
+ }
+ }
+ }
+}
+#endif
+
+static void draw_layer(mame_bitmap *bitmap, const rectangle *cliprect, int layer, int bitdepth)
+{
+ int x, y;
+ int tile_index = 0;
+ UINT16 *tiles = (UINT16*)&m3_tile_ram[layer * 0x400];
+
+ //logerror("Layer %d: X: %d, Y: %d\n", layer, x1, y1);
+
+ if(layer > 1) {
+ int modr = (model3_layer_modulate2 >> 8) & 0xff;
+ int modg = (model3_layer_modulate2 >> 16) & 0xff;
+ int modb = (model3_layer_modulate2 >> 24) & 0xff;
+ if(modr & 0x80) {
+ layer_modulate_r = -(0x7f - (modr & 0x7f)) << 10;
+ } else {
+ layer_modulate_r = (modr & 0x7f) << 10;
+ }
+ if(modg & 0x80) {
+ layer_modulate_g = -(0x7f - (modr & 0x7f)) << 5;
+ } else {
+ layer_modulate_g = (modr & 0x7f) << 5;
+ }
+ if(modb & 0x80) {
+ layer_modulate_b = -(0x7f - (modr & 0x7f));
+ } else {
+ layer_modulate_b = (modr & 0x7f);
+ }
+ } else {
+ int modr = (model3_layer_modulate1 >> 8) & 0xff;
+ int modg = (model3_layer_modulate1 >> 16) & 0xff;
+ int modb = (model3_layer_modulate1 >> 24) & 0xff;
+ if(modr & 0x80) {
+ layer_modulate_r = -(0x7f - (modr & 0x7f)) << 10;
+ } else {
+ layer_modulate_r = (modr & 0x7f) << 10;
+ }
+ if(modg & 0x80) {
+ layer_modulate_g = -(0x7f - (modr & 0x7f)) << 5;
+ } else {
+ layer_modulate_g = (modr & 0x7f) << 5;
+ }
+ if(modb & 0x80) {
+ layer_modulate_b = -(0x7f - (modr & 0x7f));
+ } else {
+ layer_modulate_b = (modr & 0x7f);
+ }
+ }
+
+ if(bitdepth) /* 4-bit */
+ {
+ for(y = cliprect->min_y; y <= cliprect->max_y; y+=8)
+ {
+ tile_index = ((y/8) * 64);
+ for (x = cliprect->min_x; x <= cliprect->max_x; x+=8) {
+ UINT16 tile = tiles[tile_index ^ 0x2];
+ draw_tile_4bit(bitmap, x, y, tile);
+ ++tile_index;
+ }
+ }
+ }
+ else /* 8-bit */
+ {
+ for(y = cliprect->min_y; y <= cliprect->max_y; y+=8)
+ {
+ tile_index = ((y/8) * 64);
+ for (x = cliprect->min_x; x <= cliprect->max_x; x+=8) {
+ UINT16 tile = tiles[tile_index ^ 0x2];
+ draw_tile_8bit(bitmap, x, y, tile);
+ ++tile_index;
+ }
+ }
+ }
+}
+
+#ifdef UNUSED_FUNCTION
+static void copy_screen(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int x,y;
+ for(y=cliprect->min_y; y <= cliprect->max_y; y++) {
+ UINT16 *d = BITMAP_ADDR16(bitmap, y, 0);
+ UINT16 *s = BITMAP_ADDR16(bitmap3d, y, 0);
+ for(x=cliprect->min_x; x <= cliprect->max_x; x++) {
+ UINT16 pix = s[x];
+ if(!(pix & 0x8000)) {
+ d[x] = pix;
+ }
+ }
+ }
+}
+#endif
+
+static int tick = 0;
+static int debug_layer_disable = 0;
+
+VIDEO_UPDATE( model3 )
+{
+ int layer_scroll_x[4], layer_scroll_y[4];
+ UINT32 layer_data[4];
+
+ layer_data[0] = BYTE_REVERSE32((UINT32)(layer_scroll[0] >> 32));
+ layer_data[1] = BYTE_REVERSE32((UINT32)(layer_scroll[0] >> 0));
+ layer_data[2] = BYTE_REVERSE32((UINT32)(layer_scroll[1] >> 32));
+ layer_data[3] = BYTE_REVERSE32((UINT32)(layer_scroll[1] >> 0));
+ layer_scroll_x[0] = (layer_data[0] & 0x8000) ? (layer_data[0] & 0x1ff) : -(layer_data[0] & 0x1ff);
+ layer_scroll_y[0] = (layer_data[0] & 0x8000) ? (layer_data[0] & 0x1ff) : -(layer_data[0] & 0x1ff);
+ layer_scroll_x[1] = (layer_data[1] & 0x8000) ? (layer_data[1] & 0x1ff) : -(layer_data[1] & 0x1ff);
+ layer_scroll_y[1] = (layer_data[1] & 0x8000) ? (layer_data[1] & 0x1ff) : -(layer_data[1] & 0x1ff);
+ layer_scroll_x[2] = (layer_data[2] & 0x8000) ? (layer_data[2] & 0x1ff) : -(layer_data[2] & 0x1ff);
+ layer_scroll_y[2] = (layer_data[2] & 0x8000) ? (layer_data[2] & 0x1ff) : -(layer_data[2] & 0x1ff);
+ layer_scroll_x[3] = (layer_data[3] & 0x8000) ? (layer_data[3] & 0x1ff) : -(layer_data[3] & 0x1ff);
+ layer_scroll_y[3] = (layer_data[3] & 0x8000) ? (layer_data[3] & 0x1ff) : -(layer_data[3] & 0x1ff);
+
+ screen_clip = (rectangle*)cliprect;
+
+ clip3d.min_x = cliprect->min_x;
+ clip3d.max_x = cliprect->max_x;
+ clip3d.min_y = cliprect->min_y;
+ clip3d.max_y = cliprect->max_y;
+
+ /* layer disable debug keys */
+ tick++;
+ if( tick >= 5 ) {
+ tick = 0;
+
+ if( input_code_pressed(KEYCODE_Y) )
+ debug_layer_disable ^= 0x1;
+ if( input_code_pressed(KEYCODE_U) )
+ debug_layer_disable ^= 0x2;
+ if( input_code_pressed(KEYCODE_I) )
+ debug_layer_disable ^= 0x4;
+ if( input_code_pressed(KEYCODE_O) )
+ debug_layer_disable ^= 0x8;
+ if( input_code_pressed(KEYCODE_T) )
+ debug_layer_disable ^= 0x10;
+ }
+
+ fillbitmap(bitmap, 0, cliprect);
+
+ if (!(debug_layer_disable & 0x8))
+ draw_layer(bitmap, cliprect, 3, (model3_layer_enable >> 3) & 0x1);
+
+ if (!(debug_layer_disable & 0x4))
+ draw_layer(bitmap, cliprect, 2, (model3_layer_enable >> 2) & 0x1);
+
+ if( !(debug_layer_disable & 0x10) )
+ {
+// if(real3d_display_list) {
+// fillbitmap(zbuffer, 0, cliprect);
+// fillbitmap(bitmap3d, 0x8000, cliprect);
+// real3d_traverse_display_list();
+// }
+ copybitmap(bitmap, bitmap3d, 0, 0, 0, 0, cliprect, TRANSPARENCY_PEN, 0x8000);
+ }
+
+ if (!(debug_layer_disable & 0x2))
+ draw_layer(bitmap, cliprect, 1, (model3_layer_enable >> 1) & 0x1);
+
+ if (!(debug_layer_disable & 0x1))
+ draw_layer(bitmap, cliprect, 0, (model3_layer_enable >> 0) & 0x1);
+
+ //copy_screen(bitmap, cliprect);
+
+ //draw_texture_sheet(bitmap, cliprect);
+
+ real3d_display_list = 0;
+ return 0;
+}
+
+
+
+READ64_HANDLER(model3_char_r)
+{
+ return m3_char_ram[offset];
+}
+
+WRITE64_HANDLER(model3_char_w)
+{
+ COMBINE_DATA(&m3_char_ram[offset]);
+}
+
+READ64_HANDLER(model3_tile_r)
+{
+ return m3_tile_ram[offset];
+}
+
+WRITE64_HANDLER(model3_tile_w)
+{
+ COMBINE_DATA(&m3_tile_ram[offset]);
+}
+
+static UINT64 vid_reg0;
+READ64_HANDLER(model3_vid_reg_r)
+{
+ switch(offset)
+ {
+ case 0x00/8: return vid_reg0;
+ case 0x08/8: return U64(0xffffffffffffffff); /* ??? */
+ case 0x20/8: return (UINT64)model3_layer_enable << 52;
+ case 0x40/8: return ((UINT64)model3_layer_modulate1 << 32) | (UINT64)model3_layer_modulate2;
+ default: logerror("read reg %02X\n", offset);break;
+ }
+ return 0;
+}
+
+WRITE64_HANDLER(model3_vid_reg_w)
+{
+ switch(offset)
+ {
+ case 0x00/8: logerror("vid_reg0: %08X%08X\n", (UINT32)(data>>32),(UINT32)(data)); vid_reg0 = data; break;
+ case 0x08/8: break; /* ??? */
+ case 0x10/8: model3_irq_state &= ~(data >> 56); break; /* VBL IRQ Ack */
+
+ case 0x20/8: model3_layer_enable = (data >> 52); break;
+
+ case 0x40/8: model3_layer_modulate1 = (UINT32)(data >> 32);
+ model3_layer_modulate2 = (UINT32)(data);
+ break;
+ case 0x60/8: COMBINE_DATA(&layer_scroll[0]); break;
+ case 0x68/8: COMBINE_DATA(&layer_scroll[1]); break;
+ default: logerror("model3_vid_reg_w: %02X, %08X%08X\n", offset, (UINT32)(data >> 32), (UINT32)(data)); break;
+ }
+}
+
+WRITE64_HANDLER( model3_palette_w )
+{
+ int r1,g1,b1,r2,g2,b2;
+ UINT32 data1,data2;
+
+ COMBINE_DATA(&paletteram64[offset]);
+ data1 = BYTE_REVERSE32((UINT32)(paletteram64[offset] >> 32));
+ data2 = BYTE_REVERSE32((UINT32)(paletteram64[offset] >> 0));
+
+ r1 = ((data1 >> 0) & 0x1f);
+ g1 = ((data1 >> 5) & 0x1f);
+ b1 = ((data1 >> 10) & 0x1f);
+ r2 = ((data2 >> 0) & 0x1f);
+ g2 = ((data2 >> 5) & 0x1f);
+ b2 = ((data2 >> 10) & 0x1f);
+
+ pal_lookup[(offset*2)+0] = (data1 & 0x8000) | (r1 << 10) | (g1 << 5) | b1;
+ pal_lookup[(offset*2)+1] = (data2 & 0x8000) | (r2 << 10) | (g2 << 5) | b2;
+}
+
+READ64_HANDLER( model3_palette_r )
+{
+ return paletteram64[offset];
+}
+
+
+/*****************************************************************************/
+/* texture caching */
+
+/*
+ array of cached textures:
+ 4 potential textures for 4-bit grayscale
+ 2 pages
+ 1024 pixels / 32 pixel resolution vertically
+ 2048 pixels / 32 pixel resolution horizontally
+*/
+static void invalidate_texture(int page, int texx, int texy, int texwidth, int texheight)
+{
+ int wtiles = 1 << texwidth;
+ int htiles = 1 << texheight;
+ int x, y;
+
+ for (y = 0; y < htiles; y++)
+ for (x = 0; x < wtiles; x++)
+ while (texcache[page][texy + y][texx + x] != NULL)
+ {
+ cached_texture *freeme = texcache[page][texy + y][texx + x];
+ texcache[page][texy + y][texx + x] = freeme->next;
+ free(freeme);
+ }
+}
+
+static cached_texture *get_texture(int page, int texx, int texy, int texwidth, int texheight, int format)
+{
+ cached_texture *tex = texcache[page][texy][texx];
+ int pixheight = 32 << texheight;
+ int pixwidth = 32 << texwidth;
+ UINT32 alpha = ~0;
+ int x, y;
+
+ /* if we have one already, validate it */
+ for (tex = texcache[page][texy][texx]; tex != NULL; tex = tex->next)
+ if (tex->width == texwidth && tex->height == texheight && tex->format == format)
+ return tex;
+
+ /* create a new texture */
+ tex = malloc_or_die(sizeof(cached_texture) + (2 * pixwidth * 2 * pixheight) * sizeof(rgb_t));
+ tex->width = texwidth;
+ tex->height = texheight;
+ tex->format = format;
+
+ /* set the new texture */
+ tex->next = texcache[page][texy][texx];
+ texcache[page][texy][texx] = tex;
+
+ /* decode it */
+ for (y = 0; y < pixheight; y++)
+ {
+ const UINT16 *texsrc = &texture_ram[page][(texy * 32 + y) * 2048 + texx * 32];
+ rgb_t *dest = tex->data + 2 * pixwidth * y;
+
+ switch (format)
+ {
+ case 0: /* 1-5-5-5 ARGB */
+ for (x = 0; x < pixwidth; x++)
+ {
+ UINT16 pixdata = texsrc[x];
+ dest[x] = MAKE_ARGB(pal1bit(pixdata >> 15), pal5bit(pixdata >> 10), pal5bit(pixdata >> 5), pal5bit(pixdata >> 0));
+ alpha = ~0;
+ }
+ break;
+
+ case 1: /* 4-bit grayscale in low nibble */
+ for (x = 0; x < pixwidth; x++)
+ {
+ UINT8 grayvalue = pal4bit(texsrc[x] >> 0);
+ alpha &= dest[x] = MAKE_ARGB(0xff, grayvalue, grayvalue, grayvalue);
+ }
+ break;
+
+ case 2: /* 4-bit grayscale in 2nd nibble */
+ for (x = 0; x < pixwidth; x++)
+ {
+ UINT8 grayvalue = pal4bit(texsrc[x] >> 4);
+ alpha &= dest[x] = MAKE_ARGB(0xff, grayvalue, grayvalue, grayvalue);
+ }
+ break;
+
+ case 3: /* 4-bit grayscale in 3rd nibble */
+ for (x = 0; x < pixwidth; x++)
+ {
+ UINT8 grayvalue = pal4bit(texsrc[x] >> 8);
+ alpha &= dest[x] = MAKE_ARGB(0xff, grayvalue, grayvalue, grayvalue);
+ }
+ break;
+
+ case 4: /* 8-bit A4L4 */
+ for (x = 0; x < pixwidth; x++)
+ {
+ UINT8 pixdata = texsrc[x / 2] >> ((~x & 1) * 8);
+ alpha &= dest[x] = MAKE_ARGB(pal4bit(pixdata >> 4), pal4bit(~pixdata), pal4bit(~pixdata), pal4bit(~pixdata));
+ }
+ break;
+
+ case 5: /* 8-bit grayscale */
+ for (x = 0; x < pixwidth; x++)
+ {
+ UINT8 grayvalue = texsrc[x / 2] >> ((~x & 1) * 8);
+ alpha &= dest[x] = MAKE_ARGB(0xff, grayvalue, grayvalue, grayvalue);
+ }
+ break;
+
+ case 6: /* 4-bit grayscale in high nibble */
+ for (x = 0; x < pixwidth; x++)
+ {
+ UINT8 grayvalue = pal4bit(texsrc[x] >> 12);
+ alpha &= dest[x] = MAKE_ARGB(0xff, grayvalue, grayvalue, grayvalue);
+ }
+ break;
+
+ case 7: /* 4-4-4-4 ARGB */
+ for (x = 0; x < pixwidth; x++)
+ {
+ UINT16 pixdata = texsrc[x];
+ alpha &= dest[x] = MAKE_ARGB(pal4bit(pixdata >> 0), pal4bit(pixdata >> 12), pal4bit(pixdata >> 8), pal4bit(pixdata >> 4));
+ }
+ break;
+ }
+
+ /* create the horizontal mirror of this line */
+ for (x = 0; x < pixwidth; x++)
+ dest[pixwidth * 2 - 1 - x] = dest[x];
+ }
+
+ /* create the vertical mirror of the texture */
+ for (y = 0; y < pixheight; y++)
+ memcpy(tex->data + 2 * pixwidth * (pixheight * 2 - 1 - y), tex->data + 2 * pixwidth * y, sizeof(rgb_t) * pixwidth * 2);
+
+ /* remember the overall alpha */
+ tex->alpha = alpha >> 24;
+
+ /* return a pointer to the texture */
+ return tex;
+}
+
+/*****************************************************************************/
+/* Real3D Graphics stuff */
+
+WRITE64_HANDLER( real3d_display_list_w )
+{
+ if(!(mem_mask & U64(0xffffffff00000000))) {
+ display_list_ram[offset*2] = BYTE_REVERSE32((UINT32)(data >> 32));
+ }
+ if(!(mem_mask & U64(0x00000000ffffffff))) {
+ display_list_ram[(offset*2)+1] = BYTE_REVERSE32((UINT32)(data));
+ }
+}
+
+WRITE64_HANDLER( real3d_polygon_ram_w )
+{
+ if(!(mem_mask & U64(0xffffffff00000000))) {
+ polygon_ram[offset*2] = BYTE_REVERSE32((UINT32)(data >> 32));
+ }
+ if(!(mem_mask & U64(0x00000000ffffffff))) {
+ polygon_ram[(offset*2)+1] = BYTE_REVERSE32((UINT32)(data));
+ }
+}
+
+static const UINT8 texture_decode[64] =
+{
+ 0, 1, 4, 5, 8, 9, 12, 13,
+ 2, 3, 6, 7, 10, 11, 14, 15,
+ 16, 17, 20, 21, 24, 25, 28, 29,
+ 18, 19, 22, 23, 26, 27, 30, 31,
+ 32, 33, 36, 37, 40, 41, 44, 45,
+ 34, 35, 38, 39, 42, 43, 46, 47,
+ 48, 49, 52, 53, 56, 57, 60, 61,
+ 50, 51, 54, 55, 58, 59, 62, 63
+};
+
+INLINE void write_texture16(int xpos, int ypos, int width, int height, int page, UINT16 *data)
+{
+ int x,y,i,j;
+
+ for(y=ypos; y < ypos+height; y+=8)
+ {
+ for(x=xpos; x < xpos+width; x+=8)
+ {
+ UINT16 *texture = &texture_ram[page][y*2048+x];
+ int b = 0;
+ for(j=y; j < y+8; j++) {
+ for(i=x; i < x+8; i++) {
+ *texture++ = data[texture_decode[b^1]];
+ ++b;
+ }
+ texture += 2048-8;
+ }
+ data += 64;
+ }
+ }
+}
+
+INLINE void write_texture8(int xpos, int ypos, int width, int height, int page, UINT16 *data)
+{
+ int x,y,i,j;
+ UINT16 color = 0x7c00;
+
+ for(y=ypos; y < ypos+(height/2); y+=4)
+ {
+ for(x=xpos; x < xpos+width; x+=8)
+ {
+ UINT16 *texture = &texture_ram[page][y*2048+x];
+ int b = 0;
+ for(j=y; j < y+4; j++) {
+ for(i=x; i < x+8; i++) {
+ *texture = color;
+ texture++;
+ ++b;
+ }
+ texture += 2048-8;
+ }
+ }
+ }
+}
+
+static void real3d_upload_texture(UINT32 header, UINT32 *data)
+{
+ int width = 32 << ((header >> 14) & 0x7);
+ int height = 32 << ((header >> 17) & 0x7);
+ int xpos = (header & 0x3f) * 32;
+ int ypos = ((header >> 7) & 0x1f) * 32;
+ int page = (header >> 20) & 0x1;
+// int bitdepth = (header >> 23) & 0x1;
+
+ switch(header >> 24)
+ {
+ case 0x00: /* Texture with mipmaps */
+// if(bitdepth) {
+ write_texture16(xpos, ypos, width, height, page, (UINT16*)data);
+ invalidate_texture(page, header & 0x3f, (header >> 7) & 0x1f, (header >> 14) & 0x7, (header >> 17) & 0x7);
+// } else {
+ /* TODO: 8-bit textures are weird. need to figure out some additional bits */
+ //logerror("W: %d, H: %d, X: %d, Y: %d, P: %d, Bit: %d, : %08X, %08X\n", width, height, xpos, ypos, page, bitdepth, header & 0x00681040, header);
+ //write_texture8(xpos, ypos, width, height, page, (UINT16*)data);
+// }
+ break;
+ case 0x01: /* Texture without mipmaps */
+// if(bitdepth) {
+ write_texture16(xpos, ypos, width, height, page, (UINT16*)data);
+ invalidate_texture(page, header & 0x3f, (header >> 7) & 0x1f, (header >> 14) & 0x7, (header >> 17) & 0x7);
+// } else {
+ /* TODO: 8-bit textures are weird. need to figure out some additional bits */
+ //logerror("W: %d, H: %d, X: %d, Y: %d, P: %d, Bit: %d, : %08X, %08X\n", width, height, xpos, ypos, page, bitdepth, header & 0x00681040, header);
+ //write_texture8(xpos, ypos, width, height, page, (UINT16*)data);
+// }
+ break;
+ case 0x02: /* Only mipmaps */
+ break;
+ case 0x80: /* Gamma-table ? */
+ break;
+ default:
+ fatalerror("Unknown texture type: %02X: ", header >> 24);
+ break;
+ }
+}
+
+void real3d_display_list_end(void)
+{
+ /* upload textures if there are any in the FIFO */
+ if (texture_fifo_pos > 0)
+ {
+ int i = 0;
+ while(i < texture_fifo_pos)
+ {
+ int length = (texture_fifo[i] / 2) + 2;
+ UINT32 header = texture_fifo[i+1];
+ real3d_upload_texture(header, &texture_fifo[i+2]);
+ i += length;
+ };
+ }
+ texture_fifo_pos = 0;
+ fillbitmap(zbuffer, 0, NULL);
+ fillbitmap(bitmap3d, 0x8000, NULL);
+ real3d_traverse_display_list();
+// real3d_display_list = 1;
+}
+
+void real3d_display_list1_dma(UINT32 src, UINT32 dst, int length, int byteswap)
+{
+ int i;
+ int d = (dst & 0xffffff) / 4;
+ for(i=0; i < length; i+=4) {
+ UINT32 w;
+ if (byteswap) {
+ w = BYTE_REVERSE32(program_read_dword_64le(src^4));
+ } else {
+ w = program_read_dword_64le(src^4);
+ }
+ display_list_ram[d++] = w;
+ src += 4;
+ }
+}
+
+void real3d_display_list2_dma(UINT32 src, UINT32 dst, int length, int byteswap)
+{
+ int i;
+ int d = (dst & 0xffffff) / 4;
+ for(i=0; i < length; i+=4) {
+ UINT32 w;
+ if (byteswap) {
+ w = BYTE_REVERSE32(program_read_dword_64le(src^4));
+ } else {
+ w = program_read_dword_64le(src^4);
+ }
+ culling_ram[d++] = w;
+ src += 4;
+ }
+}
+
+void real3d_vrom_texture_dma(UINT32 src, UINT32 dst, int length, int byteswap)
+{
+ if((dst & 0xff) == 0) {
+
+ UINT32 address, header;
+
+ if (byteswap) {
+ address = BYTE_REVERSE32(program_read_dword_64le((src+0)^4));
+ header = BYTE_REVERSE32(program_read_dword_64le((src+4)^4));
+ } else {
+ address = program_read_dword_64le((src+0)^4);
+ header = program_read_dword_64le((src+4)^4);
+ }
+ real3d_upload_texture(header, (UINT32*)&model3_vrom[address]);
+ }
+}
+
+void real3d_texture_fifo_dma(UINT32 src, int length, int byteswap)
+{
+ int i;
+ for(i=0; i < length; i+=4) {
+ UINT32 w;
+ if (byteswap) {
+ w = BYTE_REVERSE32(program_read_dword_64le(src^4));
+ } else {
+ w = program_read_dword_64le(src^4);
+ }
+ texture_fifo[texture_fifo_pos] = w;
+ texture_fifo_pos++;
+ src += 4;
+ }
+}
+
+void real3d_polygon_ram_dma(UINT32 src, UINT32 dst, int length, int byteswap)
+{
+ int i;
+ int d = (dst & 0xffffff) / 4;
+ for(i=0; i < length; i+=4) {
+ UINT32 w;
+ if (byteswap) {
+ w = BYTE_REVERSE32(program_read_dword_64le(src^4));
+ } else {
+ w = program_read_dword_64le(src^4);
+ }
+ polygon_ram[d++] = w;
+ src += 4;
+ }
+}
+
+WRITE64_HANDLER( real3d_cmd_w )
+{
+ real3d_display_list_end();
+}
+
+
+/*****************************************************************************/
+/* matrix and vector operations */
+
+INLINE float dot_product(VECTOR a, VECTOR b)
+{
+ return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]) + (a[3] * b[3]);
+}
+
+INLINE float dot_product3(VECTOR3 a, VECTOR3 b)
+{
+ return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
+}
+
+/* multiplies a 4-element vector by a 4x4 matrix */
+static void matrix_multiply_vector(MATRIX matrix, const VECTOR v, VECTOR *p)
+{
+ (*p)[0] = (v[0] * matrix[0][0]) + (v[1] * matrix[1][0]) + (v[2] * matrix[2][0]) + (v[3] * matrix[3][0]);
+ (*p)[1] = (v[0] * matrix[0][1]) + (v[1] * matrix[1][1]) + (v[2] * matrix[2][1]) + (v[3] * matrix[3][1]);
+ (*p)[2] = (v[0] * matrix[0][2]) + (v[1] * matrix[1][2]) + (v[2] * matrix[2][2]) + (v[3] * matrix[3][2]);
+ (*p)[3] = (v[0] * matrix[0][3]) + (v[1] * matrix[1][3]) + (v[2] * matrix[2][3]) + (v[3] * matrix[3][3]);
+}
+
+/* multiplies a 4x4 matrix with another 4x4 matrix */
+static void matrix_multiply(MATRIX a, MATRIX b, MATRIX *out)
+{
+ int i,j;
+ MATRIX tmp;
+
+ for( i=0; i < 4; i++ ) {
+ for( j=0; j < 4; j++ ) {
+ tmp[i][j] = (a[i][0] * b[0][j]) + (a[i][1] * b[1][j]) + (a[i][2] * b[2][j]) + (a[i][3] * b[3][j]);
+ }
+ }
+ memcpy(out, &tmp, sizeof(MATRIX));
+}
+
+/* matrix stack */
+#define MATRIX_STACK_SIZE 256
+
+static int matrix_stack_ptr = 0;
+static MATRIX matrix_stack[MATRIX_STACK_SIZE];
+
+static void init_matrix_stack(void)
+{
+ /* initialize the first matrix as identity */
+ matrix_stack[0][0][0] = 1.0f;
+ matrix_stack[0][0][1] = 0.0f;
+ matrix_stack[0][0][2] = 0.0f;
+ matrix_stack[0][0][3] = 0.0f;
+ matrix_stack[0][1][0] = 0.0f;
+ matrix_stack[0][1][1] = 1.0f;
+ matrix_stack[0][1][2] = 0.0f;
+ matrix_stack[0][1][3] = 0.0f;
+ matrix_stack[0][2][0] = 0.0f;
+ matrix_stack[0][2][1] = 0.0f;
+ matrix_stack[0][2][2] = 1.0f;
+ matrix_stack[0][2][3] = 0.0f;
+ matrix_stack[0][3][0] = 0.0f;
+ matrix_stack[0][3][1] = 0.0f;
+ matrix_stack[0][3][2] = 0.0f;
+ matrix_stack[0][3][3] = 1.0f;
+
+ matrix_stack_ptr = 0;
+}
+
+static void get_top_matrix(MATRIX *out)
+{
+ memcpy( out, &matrix_stack[matrix_stack_ptr], sizeof(MATRIX));
+}
+
+void push_matrix_stack(void)
+{
+ matrix_stack_ptr++;
+ if (matrix_stack_ptr >= MATRIX_STACK_SIZE)
+ fatalerror("push_matrix_stack: matrix stack overflow");
+
+ memcpy( &matrix_stack[matrix_stack_ptr], &matrix_stack[matrix_stack_ptr-1], sizeof(MATRIX));
+}
+
+void pop_matrix_stack(void)
+{
+ matrix_stack_ptr--;
+ if (matrix_stack_ptr < 0)
+ fatalerror("pop_matrix_stack: matrix stack underflow");
+}
+
+void multiply_matrix_stack(MATRIX matrix)
+{
+ matrix_multiply(matrix, matrix_stack[matrix_stack_ptr], &matrix_stack[matrix_stack_ptr]);
+}
+
+void translate_matrix_stack(float x, float y, float z)
+{
+ MATRIX tm;
+
+ tm[0][0] = 1.0f; tm[0][1] = 0.0f; tm[0][2] = 0.0f; tm[0][3] = 0.0f;
+ tm[1][0] = 0.0f; tm[1][1] = 1.0f; tm[1][2] = 0.0f; tm[1][3] = 0.0f;
+ tm[2][0] = 0.0f; tm[2][1] = 0.0f; tm[2][2] = 1.0f; tm[2][3] = 0.0f;
+ tm[3][0] = x; tm[3][1] = y; tm[3][2] = z; tm[3][3] = 1.0f;
+
+ matrix_multiply(tm, matrix_stack[matrix_stack_ptr], &matrix_stack[matrix_stack_ptr]);
+}
+
+/*****************************************************************************/
+/* transformation and rasterizing */
+
+#include "m3raster.c"
+
+INLINE int is_point_inside(float x, float y, float z, PLANE cp)
+{
+ float s = (x * cp.x) + (y * cp.y) + (z * cp.z) + cp.d;
+ if (s >= 0.0f)
+ return 1;
+ else
+ return 0;
+}
+
+INLINE float line_plane_intersection(const poly_vertex *v1, const poly_vertex *v2, PLANE cp)
+{
+ float x = v1->x - v2->x;
+ float y = v1->y - v2->y;
+ float z = v1->pz - v2->pz;
+ float t = ((cp.x * v1->x) + (cp.y * v1->y) + (cp.z * v1->pz)) / ((cp.x * x) + (cp.y * y) + (cp.z * z));
+ return t;
+}
+
+static int clip_polygon(const poly_vertex *v, int num_vertices, PLANE cp, poly_vertex *vout)
+{
+ poly_vertex clipv[10];
+ int clip_verts = 0;
+ float t;
+ int i;
+
+ int previ = num_vertices - 1;
+
+ for (i=0; i < num_vertices; i++)
+ {
+ int v1_in = is_point_inside(v[i].x, v[i].y, v[i].pz, cp);
+ int v2_in = is_point_inside(v[previ].x, v[previ].y, v[previ].pz, cp);
+
+ if (v1_in && v2_in) /* edge is completely inside the volume */
+ {
+ clipv[clip_verts] = v[i];
+ ++clip_verts;
+ }
+ else if (!v1_in && v2_in) /* edge is entering the volume */
+ {
+ /* insert vertex at intersection point */
+ t = line_plane_intersection(&v[i], &v[previ], cp);
+ clipv[clip_verts].x = v[i].x + ((v[previ].x - v[i].x) * t);
+ clipv[clip_verts].y = v[i].y + ((v[previ].y - v[i].y) * t);
+ clipv[clip_verts].pz = v[i].pz + ((v[previ].pz - v[i].pz) * t);
+ clipv[clip_verts].pu = v[i].pu + ((v[previ].pu - v[i].pu) * t);
+ clipv[clip_verts].pv = v[i].pv + ((v[previ].pv - v[i].pv) * t);
+ ++clip_verts;
+ }
+ else if (v1_in && !v2_in) /* edge is leaving the volume */
+ {
+ /* insert vertex at intersection point */
+ t = line_plane_intersection(&v[i], &v[previ], cp);
+ clipv[clip_verts].x = v[i].x + ((v[previ].x - v[i].x) * t);
+ clipv[clip_verts].y = v[i].y + ((v[previ].y - v[i].y) * t);
+ clipv[clip_verts].pz = v[i].pz + ((v[previ].pz - v[i].pz) * t);
+ clipv[clip_verts].pu = v[i].pu + ((v[previ].pu - v[i].pu) * t);
+ clipv[clip_verts].pv = v[i].pv + ((v[previ].pv - v[i].pv) * t);
+ ++clip_verts;
+
+ /* insert the existing vertex */
+ clipv[clip_verts] = v[i];
+ ++clip_verts;
+ }
+
+ previ = i;
+ }
+ memcpy(&vout[0], &clipv[0], sizeof(vout[0]) * clip_verts);
+ return clip_verts;
+}
+
+static const int num_bits[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
+
+static MATRIX coordinate_system;
+static float viewport_focal_length = 300;
+static int viewport_region_x = 0;
+static int viewport_region_y = 0;
+static int viewport_region_width = 496;
+static int viewport_region_height = 384;
+
+static PLANE clip_plane[5];
+
+static void render_one(TRIANGLE *tri)
+{
+ poly_extra_data *extra = poly_get_extra_data(poly);
+ poly_draw_scanline callback = NULL;
+
+ tri->v[0].pz = 1.0f / tri->v[0].pz;
+ tri->v[1].pz = 1.0f / tri->v[1].pz;
+ tri->v[2].pz = 1.0f / tri->v[2].pz;
+
+ if (tri->param & TRI_PARAM_TEXTURE_ENABLE)
+ {
+ tri->v[0].pu = tri->v[0].pu * tri->v[0].pz * 256.0f;
+ tri->v[0].pv = tri->v[0].pv * tri->v[0].pz * 256.0f;
+ tri->v[1].pu = tri->v[1].pu * tri->v[1].pz * 256.0f;
+ tri->v[1].pv = tri->v[1].pv * tri->v[1].pz * 256.0f;
+ tri->v[2].pu = tri->v[2].pu * tri->v[2].pz * 256.0f;
+ tri->v[2].pv = tri->v[2].pv * tri->v[2].pz * 256.0f;
+
+ extra->texture = get_texture((tri->param & TRI_PARAM_TEXTURE_PAGE) ? 1 : 0, tri->texture_x, tri->texture_y, tri->texture_width, tri->texture_height, tri->texture_format);
+ extra->texture_param = tri->param;
+ extra->polygon_transparency = tri->transparency;
+ extra->polygon_intensity = tri->intensity;
+
+ if (tri->param & TRI_PARAM_ALPHA_TEST)
+ callback = draw_scanline_alpha_test;
+ else if (extra->texture->alpha == 0xff)
+ callback = (tri->transparency >= 32) ? draw_scanline_normal : draw_scanline_trans;
+ else
+ callback = draw_scanline_alpha;
+ poly_render_triangle(poly, bitmap3d, &clip3d, callback, 3, &tri->v[0], &tri->v[1], &tri->v[2]);
+ }
+ else
+ {
+ extra->polygon_transparency = tri->transparency;
+ extra->polygon_intensity = tri->intensity;
+ extra->color = tri->color;
+
+ poly_render_triangle(poly, bitmap3d, &clip3d, draw_scanline_color, 1, &tri->v[0], &tri->v[1], &tri->v[2]);
+ }
+}
+
+static void draw_model(UINT32 addr)
+{
+ UINT32 *model = (addr >= 0x100000) ? &model3_vrom[addr] : &polygon_ram[addr];
+ UINT32 header[7];
+ int index = 0;
+ int last_polygon = FALSE;
+ int num_vertices;
+ int i, v, vi;
+ float fixed_point_fraction;
+ poly_vertex vertex[4];
+ poly_vertex prev_vertex[4];
+ poly_vertex clip_vert[10];
+
+ int polynum = 0;
+ MATRIX transform_matrix;
+ float center_x, center_y;
+
+ if(model3_step < 0x15) { /* position coordinates are 17.15 fixed-point in Step 1.0 */
+ fixed_point_fraction = 1.0f / 32768.0f;
+ } else { /* 13.19 fixed-point in other Steps */
+ fixed_point_fraction = 1.0f / 524288.0f;
+ }
+
+ get_top_matrix(&transform_matrix);
+
+ /* current viewport center coordinates on screen */
+ center_x = (float)(viewport_region_x + (viewport_region_width / 2));
+ center_y = (float)(viewport_region_y + (viewport_region_height / 2));
+
+ while (!last_polygon)
+ {
+ float texture_coord_scale;
+ UINT16 color;
+ VECTOR3 normal;
+ VECTOR3 sn;
+ VECTOR p[4];
+ TRIANGLE tri;
+ float dot;
+ int intensity;
+ int polygon_transparency;
+
+ for (i = 0; i < 7; i++)
+ header[i] = model[index++];
+
+ if (header[6] == 0)
+ return;
+
+ if (header[1] & 0x4)
+ last_polygon = TRUE;
+
+ num_vertices = (header[0] & 0x40) ? 4 : 3;
+
+ /* texture coordinates are 16.0 or 13.3 fixed-point */
+ texture_coord_scale = (header[1] & 0x40) ? 1.0f : (1.0f / 8.0f);
+
+ /* polygon normal (sign + 1.22 fixed-point) */
+ normal[0] = (float)((INT32)header[1] >> 8) * (1.0f / 4194304.0f);
+ normal[1] = (float)((INT32)header[2] >> 8) * (1.0f / 4194304.0f);
+ normal[2] = (float)((INT32)header[3] >> 8) * (1.0f / 4194304.0f);
+
+ /* load reused vertices */
+ vi = 0;
+ for (v = 0; v < 4; v++)
+ if (header[0] & (1 << v))
+ vertex[vi++] = prev_vertex[v];
+
+ /* load new vertices */
+ for ( ; vi < num_vertices; vi++)
+ {
+ vertex[vi].x = (float)((INT32)model[index++]) * fixed_point_fraction;
+ vertex[vi].y = (float)((INT32)model[index++]) * fixed_point_fraction;
+ vertex[vi].pz = (float)((INT32)model[index++]) * fixed_point_fraction;
+ vertex[vi].pu = (UINT16)(model[index] >> 16);
+ vertex[vi].pv = (UINT16)(model[index++]);
+ }
+
+ /* Copy current vertices as previous vertices */
+ memcpy(prev_vertex, vertex, sizeof(poly_vertex) * 4);
+
+ color = (((header[4] >> 27) & 0x1f) << 10) | (((header[4] >> 19) & 0x1f) << 5) | ((header[4] >> 11) & 0x1f);
+ polygon_transparency = (header[6] & 0x800000) ? 32 : ((header[6] >> 18) & 0x1f);
+
+ /* transform polygon normal to view-space */
+ sn[0] = (normal[0] * transform_matrix[0][0]) +
+ (normal[1] * transform_matrix[1][0]) +
+ (normal[2] * transform_matrix[2][0]);
+ sn[1] = (normal[0] * transform_matrix[0][1]) +
+ (normal[1] * transform_matrix[1][1]) +
+ (normal[2] * transform_matrix[2][1]);
+ sn[2] = (normal[0] * transform_matrix[0][2]) +
+ (normal[1] * transform_matrix[1][2]) +
+ (normal[2] * transform_matrix[2][2]);
+
+ sn[0] *= coordinate_system[0][1];
+ sn[1] *= coordinate_system[1][2];
+ sn[2] *= coordinate_system[2][0];
+
+ /* TODO: backface culling */
+ /* transform vertices */
+ for (i = 0; i < num_vertices; i++)
+ {
+ VECTOR vect;
+
+ vect[0] = vertex[i].x;
+ vect[1] = vertex[i].y;
+ vect[2] = vertex[i].pz;
+ vect[3] = 1.0f;
+
+ /* transform to world-space */
+ matrix_multiply_vector(transform_matrix, vect, &p[i]);
+
+ /* apply coordinate system */
+ clip_vert[i].x = p[i][0] * coordinate_system[0][1];
+ clip_vert[i].y = p[i][1] * coordinate_system[1][2];
+ clip_vert[i].pz = p[i][2] * coordinate_system[2][0];
+ clip_vert[i].pu = vertex[i].pu * texture_coord_scale;
+ clip_vert[i].pv = vertex[i].pv * texture_coord_scale;
+ }
+
+ /* clip against view frustum */
+ num_vertices = clip_polygon(clip_vert, num_vertices, clip_plane[0], clip_vert);
+ num_vertices = clip_polygon(clip_vert, num_vertices, clip_plane[1], clip_vert);
+ num_vertices = clip_polygon(clip_vert, num_vertices, clip_plane[2], clip_vert);
+ num_vertices = clip_polygon(clip_vert, num_vertices, clip_plane[3], clip_vert);
+ num_vertices = clip_polygon(clip_vert, num_vertices, clip_plane[4], clip_vert);
+
+ /* homogeneous Z-divide, screen-space transformation */
+ for(i=0; i < num_vertices; i++) {
+ float ooz = 1.0f / clip_vert[i].pz;
+ clip_vert[i].x = ((clip_vert[i].x * ooz) * viewport_focal_length) + center_x;
+ clip_vert[i].y = ((clip_vert[i].y * ooz) * viewport_focal_length) + center_y;
+ }
+
+ // lighting
+ if ((header[6] & 0x10000) == 0)
+ {
+ dot = dot_product3(sn, parallel_light);
+ intensity = ((dot * parallel_light_intensity) + ambient_light_intensity) * 256.0f;
+ if (intensity > 256)
+ {
+ intensity = 256;
+ }
+ if (intensity < 0)
+ {
+ intensity = 0;
+ }
+ }
+ else
+ {
+ // apply luminosity
+ intensity = 256;
+ }
+
+ for (i=2; i < num_vertices; i++)
+ {
+ memcpy(&tri.v[0], &clip_vert[0], sizeof(poly_vertex));
+ memcpy(&tri.v[1], &clip_vert[i-1], sizeof(poly_vertex));
+ memcpy(&tri.v[2], &clip_vert[i], sizeof(poly_vertex));
+ tri.texture_x = ((header[4] & 0x1f) << 1) | ((header[5] >> 7) & 0x1);
+ tri.texture_y = (header[5] & 0x1f);
+ tri.texture_width = ((header[3] >> 3) & 0x7);
+ tri.texture_height = (header[3] & 0x7);
+ tri.texture_format = (header[6] >> 7) & 0x7;
+ tri.transparency = polygon_transparency;
+ tri.intensity = intensity;
+ tri.color = color;
+
+ tri.param = 0;
+ tri.param |= (header[4] & 0x40) ? TRI_PARAM_TEXTURE_PAGE : 0;
+ tri.param |= (header[6] & 0x4000000) ? TRI_PARAM_TEXTURE_ENABLE : 0;
+ tri.param |= (header[2] & 0x2) ? TRI_PARAM_TEXTURE_MIRROR_U : 0;
+ tri.param |= (header[2] & 0x1) ? TRI_PARAM_TEXTURE_MIRROR_V : 0;
+ tri.param |= (header[6] & 0x80000000) ? TRI_PARAM_ALPHA_TEST : 0;
+
+ render_one(&tri);
+ }
+
+ ++polynum;
+ };
+}
+
+
+/*****************************************************************************/
+/* display list parser */
+
+static UINT32 matrix_base_address;
+
+static UINT32 *get_memory_pointer(UINT32 address)
+{
+ if (address & 0x800000)
+ {
+ if (address >= 0x840000) {
+ fatalerror("get_memory_pointer: invalid display list memory address %08X", address);
+ }
+ return &display_list_ram[address & 0x7fffff];
+ }
+ else
+ {
+ if (address >= 0x100000) {
+ fatalerror("get_memory_pointer: invalid node ram address %08X", address);
+ }
+ return &culling_ram[address];
+ }
+ return NULL;
+}
+
+static void load_matrix(int matrix_num, MATRIX *out)
+{
+ float *matrix = (float *)get_memory_pointer(matrix_base_address + matrix_num * 12);
+
+ (*out)[0][0] = matrix[3]; (*out)[0][1] = matrix[6]; (*out)[0][2] = matrix[9]; (*out)[0][3] = 0.0f;
+ (*out)[1][0] = matrix[4]; (*out)[1][1] = matrix[7]; (*out)[1][2] = matrix[10]; (*out)[1][3] = 0.0f;
+ (*out)[2][0] = matrix[5]; (*out)[2][1] = matrix[8]; (*out)[2][2] = matrix[11]; (*out)[2][3] = 0.0f;
+ (*out)[3][0] = matrix[0]; (*out)[3][1] = matrix[1]; (*out)[3][2] = matrix[2]; (*out)[3][3] = 1.0f;
+}
+
+static void traverse_list4(int lod_num, UINT32 address)
+{
+ /* does something with the LOD selection */
+ UINT32 *list = get_memory_pointer(address);
+ UINT32 link = list[0];
+
+ draw_model(link & 0xffffff);
+}
+
+static void traverse_list(UINT32 address)
+{
+ UINT32 *list = get_memory_pointer(address);
+ int list_ptr = 0;
+
+ if (list_depth > 2)
+ return;
+
+ list_depth++;
+
+ /* find the end of the list */
+ while (1)
+ {
+ address = list[list_ptr++];
+ if (address & 0x02000000)
+ break;
+ if (address == 0 || (address >> 24) != 0)
+ {
+ list_ptr--;
+ break;
+ }
+ }
+
+ /* walk it backwards */
+ while (list_ptr > 0)
+ {
+ address = list[--list_ptr] & 0xffffff;
+ if (address != 0 && address != 0x800800)
+// if (address != 0)
+ draw_block(address);
+ }
+
+ list_depth--;
+}
+
+INLINE void process_link(UINT32 address, UINT32 link)
+{
+ if (link != 0 && link != 0x0fffffff && link != 0x00800800 && link != 0x01000000)
+ {
+ switch (link >> 24)
+ {
+ case 0x00: /* link to another node */
+ draw_block(link & 0xffffff);
+ break;
+
+ case 0x01:
+ case 0x03: /* both of these link to models, is there any difference ? */
+ draw_model(link & 0xffffff);
+ break;
+
+ case 0x04: /* list of links */
+ traverse_list(link & 0xffffff);
+ break;
+
+ default:
+ logerror("process_link %08X: link = %08X\n", address, link);
+ break;
+ }
+ }
+}
+
+static void draw_block(UINT32 address)
+{
+ const UINT32 *node = get_memory_pointer(address);
+ UINT32 link;
+ int node_matrix;
+ float x, y, z;
+ MATRIX matrix;
+ int offset;
+
+ offset = (model3_step < 0x15) ? 2 : 0;
+ link = node[7 - offset];
+
+ /* apply matrix and translation */
+ node_matrix = node[3 - offset] & 0xfff;
+ load_matrix(node_matrix, &matrix);
+
+ push_matrix_stack();
+
+ if (node[0] & 0x10)
+ {
+ x = *(float *)&node[4 - offset];
+ y = *(float *)&node[5 - offset];
+ z = *(float *)&node[6 - offset];
+ translate_matrix_stack(x, y, z);
+ }
+ else if (node_matrix != 0)
+ multiply_matrix_stack(matrix);
+
+ /* bit 0x08 of word 0 indicates a pointer list */
+ if (node[0] & 0x08)
+ traverse_list4((node[3 - offset] >> 12) & 0x7f, link & 0xffffff);
+ else
+ process_link(address, link);
+
+ pop_matrix_stack();
+
+ /* handle the second link */
+ link = node[8 - offset];
+ process_link(address, link);
+}
+
+static void draw_viewport(int pri, UINT32 address)
+{
+ const UINT32 *node = get_memory_pointer(address);
+ UINT32 link_address;
+ float viewport_left, viewport_right, viewport_top, viewport_bottom;
+ float fov_x, fov_y;
+
+ link_address = node[1];
+ if (link_address == 0)
+ return;
+
+ /* traverse to the link node before drawing this viewport */
+ /* check this is correct as this affects the rendering order */
+ if (link_address != 0x01000000)
+ draw_viewport(pri, link_address);
+
+ /* skip if this isn't the right priority */
+ if (pri != ((node[0] >> 3) & 3))
+ return;
+
+ /* set viewport parameters */
+ viewport_region_x = (node[26] & 0xffff) >> 4; /* 12.4 fixed point */
+ viewport_region_y = ((node[26] >> 16) & 0xffff) >> 4;
+ viewport_region_width = (node[20] & 0xffff) >> 2; /* 14.2 fixed point */
+ viewport_region_height = ((node[20] >> 16) & 0xffff) >> 2;
+
+ /* frustum plane angles */
+ viewport_left = RADIAN_TO_DEGREE(asin(*(float *)&node[12]));
+ viewport_right = RADIAN_TO_DEGREE(asin(*(float *)&node[16]));
+ viewport_top = RADIAN_TO_DEGREE(asin(*(float *)&node[14]));
+ viewport_bottom = RADIAN_TO_DEGREE(asin(*(float *)&node[18]));
+
+ /* build clipping planes */
+ clip_plane[0].x = *(float *)&node[13]; clip_plane[0].y = 0.0f; clip_plane[0].z = *(float *)&node[12]; clip_plane[0].d = 0.0f;
+ clip_plane[1].x = *(float *)&node[17]; clip_plane[1].y = 0.0f; clip_plane[1].z = *(float *)&node[16]; clip_plane[1].d = 0.0f;
+ clip_plane[2].x = 0.0f; clip_plane[2].y = *(float *)&node[15]; clip_plane[2].z = *(float *)&node[14]; clip_plane[2].d = 0.0f;
+ clip_plane[3].x = 0.0f; clip_plane[3].y = *(float *)&node[19]; clip_plane[3].z = *(float *)&node[18]; clip_plane[3].d = 0.0f;
+ clip_plane[4].x = 0.0f; clip_plane[4].y = 0.0f; clip_plane[4].z = 1.0f; clip_plane[4].d = 1.0f;
+
+ /* compute field of view */
+ fov_x = viewport_left + viewport_right;
+ fov_y = viewport_top + viewport_bottom;
+ viewport_focal_length = (viewport_region_height / 2) / tan( (fov_y * M_PI / 180.0f) / 2.0f );
+
+ matrix_base_address = node[22];
+ /* TODO: where does node[23] point to ? LOD table ? */
+
+ /* set lighting parameters */
+ parallel_light[0] = -*(float *)&node[5];
+ parallel_light[1] = *(float *)&node[6];
+ parallel_light[2] = *(float *)&node[4];
+ parallel_light_intensity = *(float *)&node[7];
+ ambient_light_intensity = (UINT8)(node[36] >> 8) / 256.0f;
+
+ /* set coordinate system matrix */
+ load_matrix(0, &coordinate_system);
+
+ /* process a link */
+ process_link(link_address, node[2]);
+}
+
+
+static void real3d_traverse_display_list(void)
+{
+ int pri;
+
+ init_matrix_stack();
+
+ for (pri = 0; pri < 4; pri++)
+ draw_viewport(pri, 0x800000);
+
+ poly_wait(poly, "real3d_traverse_display_list");
+}
+
diff --git a/src/mame/video/mole.c b/src/mame/video/mole.c
new file mode 100644
index 00000000000..d0881c308fa
--- /dev/null
+++ b/src/mame/video/mole.c
@@ -0,0 +1,59 @@
+/***************************************************************************
+ video/mole.c
+ Functions to emulate the video hardware of Mole Attack!.
+ Mole Attack's Video hardware is essentially two banks of 512 characters.
+ The program uses a single byte to indicate which character goes in each location,
+ and uses a control location (0x8400) to select the character sets
+***************************************************************************/
+
+#include "driver.h"
+
+static int tile_bank;
+static UINT16 *tileram;
+static tilemap *bg_tilemap;
+
+PALETTE_INIT( mole )
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ palette_set_color_rgb(machine, i, pal1bit(i >> 0), pal1bit(i >> 2), pal1bit(i >> 1));
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT16 code = tileram[tile_index];
+ SET_TILE_INFO((code & 0x200) ? 1 : 0, code & 0x1ff, 0, 0);
+}
+
+VIDEO_START( mole )
+{
+ tileram = (UINT16 *)auto_malloc(0x400 * sizeof(UINT16));
+
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 40, 25);
+}
+
+WRITE8_HANDLER( mole_videoram_w )
+{
+ tileram[offset] = data | (tile_bank << 8);
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( mole_tilebank_w )
+{
+ tile_bank = data;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+}
+
+WRITE8_HANDLER( mole_flipscreen_w )
+{
+ flip_screen_set(data & 0x01);
+}
+
+VIDEO_UPDATE( mole )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/momoko.c b/src/mame/video/momoko.c
new file mode 100644
index 00000000000..f69c97ec57b
--- /dev/null
+++ b/src/mame/video/momoko.c
@@ -0,0 +1,324 @@
+/*******************************************************************************
+
+Momoko 120% (c) 1986 Jaleco
+
+Video hardware driver by Uki
+
+ 02/Mar/2001 -
+
+*******************************************************************************/
+
+#include "driver.h"
+
+UINT8 *momoko_bg_scrollx;
+UINT8 *momoko_bg_scrolly;
+static UINT8 momoko_fg_scrollx;
+static UINT8 momoko_fg_scrolly;
+static UINT8 momoko_fg_select;
+static UINT8 momoko_text_scrolly;
+static UINT8 momoko_text_mode;
+static UINT8 momoko_bg_select;
+static UINT8 momoko_bg_priority;
+static UINT8 momoko_bg_mask;
+static UINT8 momoko_fg_mask;
+static UINT8 momoko_flipscreen;
+
+/****************************************************************************/
+
+WRITE8_HANDLER ( momoko_fg_scrollx_w )
+{
+ momoko_fg_scrollx = data;
+}
+WRITE8_HANDLER ( momoko_fg_scrolly_w )
+{
+ momoko_fg_scrolly = data;
+}
+WRITE8_HANDLER ( momoko_fg_select_w )
+{
+ momoko_fg_select = data & 0x0f;
+ momoko_fg_mask = data & 0x10;
+}
+WRITE8_HANDLER ( momoko_text_scrolly_w )
+{
+ momoko_text_scrolly = data;
+}
+WRITE8_HANDLER ( momoko_text_mode_w )
+{
+ momoko_text_mode = data;
+}
+WRITE8_HANDLER ( momoko_bg_scrollx_w )
+{
+ momoko_bg_scrollx[ offset ] = data;
+}
+WRITE8_HANDLER ( momoko_bg_scrolly_w )
+{
+ momoko_bg_scrolly[ offset ] = data;
+}
+WRITE8_HANDLER( momoko_bg_select_w )
+{
+ momoko_bg_select = data & 0x0f;
+ momoko_bg_mask = data & 0x10;
+}
+WRITE8_HANDLER( momoko_bg_priority_w )
+{
+ momoko_bg_priority = data & 0x01;
+}
+WRITE8_HANDLER( momoko_flipscreen_w )
+{
+ momoko_flipscreen = data & 0x01;
+}
+/****************************************************************************/
+
+static void momoko_draw_bg_pri(running_machine *machine, mame_bitmap *bitmap, int chr, int col, int flipx, int flipy, int x,int y, int pri)
+{
+ int xx,sx,sy,px,py,dot;
+ UINT32 gfxadr;
+ UINT8 d0, d1;
+ UINT8 *BG_GFX = memory_region( REGION_GFX2 );
+ for (sy=0; sy<8; sy++)
+ {
+ gfxadr = chr*16 + sy*2;
+ for (xx=0; xx<2; xx++)
+ {
+ d0 = BG_GFX[gfxadr + xx*4096];
+ d1 = BG_GFX[gfxadr + xx*4096+1];
+ for (sx=0; sx<4; sx++)
+ {
+ dot = (d0 & 0x08) | ((d0 & 0x80) >>5) | ((d1 & 0x08) >>2) | ((d1 & 0x80) >>7);
+ if (flipx==0) px=sx+xx*4 + x;
+ else px=7-sx-xx*4 + x;
+ if (flipy==0) py=sy + y;
+ else py=7-sy + y;
+
+ if (dot>=pri)
+ *BITMAP_ADDR16(bitmap, py, px) = machine->pens[col*16+dot+256];
+ d0 = d0 << 1;
+ d1 = d1 << 1;
+ }
+ }
+ }
+}
+
+/****************************************************************************/
+
+VIDEO_UPDATE( momoko )
+{
+ int x, y, dx, dy, rx, ry, radr, chr, sy, fx, fy, px, py, offs, col, pri, flip ;
+
+ UINT8 *BG_MAP = memory_region( REGION_USER1 );
+ UINT8 *BG_COL_MAP = memory_region( REGION_USER2 );
+ UINT8 *FG_MAP = memory_region( REGION_USER3 );
+ UINT8 *TEXT_COLOR = memory_region( REGION_PROMS );
+
+
+ flip = momoko_flipscreen ^ (readinputport(4) & 0x01);
+
+/* draw BG layer */
+
+ dx = ( 7 - momoko_bg_scrollx[0] ) & 7 ;
+ dy = ( 7 - momoko_bg_scrolly[0] ) & 7 ;
+ rx = (momoko_bg_scrollx[0] + momoko_bg_scrollx[1]*256) >> 3 ;
+ ry = (momoko_bg_scrolly[0] + momoko_bg_scrolly[1]*256) >> 3 ;
+
+ if (momoko_bg_mask == 0)
+ {
+ for (y=0; y<29; y++)
+ {
+ for (x=0; x<32; x++)
+ {
+ radr = ( (ry + y +2 ) & 0x3ff ) * 128 + ( (rx + x) & 0x7f ) ;
+ chr = BG_MAP[ radr ] ;
+ col = BG_COL_MAP[ chr+momoko_bg_select*512+momoko_bg_priority*256] & 0x0f;
+ chr = chr + momoko_bg_select * 512;
+
+ if (flip==0)
+ {
+ px = 8*x+dx-6;
+ py = 8*y+dy+9;
+ }
+ else
+ {
+ px = 248-(8*x+dx-8);
+ py = 248-(8*y+dy+9);
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ chr,
+ col,
+ flip,flip,
+ px,py,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ }
+ }
+ }
+ else
+ fillbitmap(bitmap, machine->pens[256], 0);
+
+
+/* draw sprites (momoko) */
+
+ for (offs=0; offs<9*4; offs +=4)
+ {
+ chr = spriteram[offs+1] | ((spriteram[offs+2]&0x60)<<3);
+ chr = ((chr & 0x380) << 1) | (chr & 0x7f);
+ col = spriteram[offs+2] & 0x07;
+ fx = ((spriteram[offs+2] & 0x10) >> 4) ^ flip;
+ fy = ((spriteram[offs+2] & 0x08) >> 3) ^ flip; /* ??? */
+ x = spriteram[offs+3];
+ y = spriteram[offs+0];
+ if (flip==0)
+ {
+ px = x;
+ py = 239-y;
+ }
+ else
+ {
+ px = 248-x;
+ py = y+1;
+ }
+
+ drawgfx(bitmap,machine->gfx[3],
+ chr,
+ col,
+ !fx,fy,
+ px,py,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+
+
+/* draw BG layer */
+
+ if (momoko_bg_mask ==0)
+ {
+ for (y=0; y<29; y++)
+ {
+ for (x=0; x<32; x++)
+ {
+ radr = ( (ry + y +2 ) & 0x3ff ) * 128 + ( (rx + x) & 0x7f ) ;
+ chr = BG_MAP[ radr ] ;
+ col = BG_COL_MAP[ chr+momoko_bg_select*512+momoko_bg_priority*256 ];
+ pri = (col & 0x10) >> 1;
+
+ if (flip==0)
+ {
+ px = 8*x+dx-6;
+ py = 8*y+dy+9;
+ }
+ else
+ {
+ px = 248-(8*x+dx-8);
+ py = 248-(8*y+dy+9);
+ }
+ if (pri != 0)
+ {
+ col = col & 0x0f;
+ chr = chr + momoko_bg_select * 512;
+ momoko_draw_bg_pri(machine, bitmap,chr,col,flip,flip,px,py,pri);
+ }
+ }
+ }
+ }
+
+
+/* draw sprites (others) */
+
+ for (offs=9*4; offs<spriteram_size; offs +=4)
+ {
+ chr = spriteram[offs+1] | ((spriteram[offs+2]&0x60)<<3);
+ chr = ((chr & 0x380) << 1) | (chr & 0x7f);
+ col = spriteram[offs+2] & 0x07;
+ fx = ((spriteram[offs+2] & 0x10) >> 4) ^ flip;
+ fy = ((spriteram[offs+2] & 0x08) >> 3) ^ flip; /* ??? */
+ x = spriteram[offs+3];
+ y = spriteram[offs+0];
+ if (flip==0)
+ {
+ px = x;
+ py = 239-y;
+ }
+ else
+ {
+ px = 248-x;
+ py = y+1;
+ }
+ drawgfx(bitmap,machine->gfx[3],
+ chr,
+ col,
+ !fx,fy,
+ px,py,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+
+
+/* draw text layer */
+
+ for (y=16; y<240; y++)
+ {
+ for (x=0; x<32; x++)
+ {
+ sy = y;
+ if (momoko_text_mode == 0)
+ col = TEXT_COLOR[ (sy >> 3) + 0x100 ] & 0x0f;
+ else
+ {
+ if (TEXT_COLOR[ y ] < 0x08)
+ sy += momoko_text_scrolly;
+ col = (TEXT_COLOR[ y ] & 0x07) + 0x10;
+ }
+ dy=sy & 7;
+ if (flip==0)
+ {
+ px = x*8;
+ py = y;
+ }
+ else
+ {
+ px = 248-x*8;
+ py = 255-y;
+ }
+ drawgfx(bitmap,machine->gfx[0],
+ videoram[(sy>>3)*32+x]*8+dy,
+ col,
+ flip,0,
+ px,py,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ }
+
+
+/* draw FG layer */
+
+ if (momoko_fg_mask==0)
+ {
+ dx = ( 7 - momoko_fg_scrollx ) & 7 ;
+ dy = ( 7 - momoko_fg_scrolly ) & 7 ;
+ rx = momoko_fg_scrollx >> 3 ;
+ ry = momoko_fg_scrolly >> 3 ;
+
+ for (y=0; y<29; y++)
+ {
+ for (x=0; x<32; x++)
+ {
+ radr = ((ry + y +34) & 0x3f) *0x20 + ((rx + x) & 0x1f) + (momoko_fg_select & 3) *0x800;
+ chr = FG_MAP[ radr ] ;
+ if (flip==0)
+ {
+ px = 8*x+dx-6;
+ py = 8*y+dy+9;
+ }
+ else
+ {
+ px = 248-(8*x+dx-8);
+ py = 248-(8*y+dy+9);
+ }
+ drawgfx(bitmap,machine->gfx[2],
+ chr,
+ 0, /* color */
+ flip,flip, /* flip */
+ px,py,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/moo.c b/src/mame/video/moo.c
new file mode 100644
index 00000000000..87acfab2d1b
--- /dev/null
+++ b/src/mame/video/moo.c
@@ -0,0 +1,169 @@
+/***************************************************************************
+
+ Wild West C.O.W.boys of Moo Mesa
+ Bucky O'Hare
+ (c) 1992 Konami
+
+ Video hardware emulation.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+static int sprite_colorbase;
+static int layer_colorbase[4], layerpri[3];
+static int alpha_enabled;
+
+#ifdef UNUSED_FUNCTION
+void moo_set_alpha(int on)
+{
+ alpha_enabled = on;
+}
+#endif
+
+static void moo_sprite_callback(int *code, int *color, int *priority_mask)
+{
+ int pri = (*color & 0x03e0) >> 4;
+
+ if (pri <= layerpri[2]) *priority_mask = 0;
+ else if (pri <= layerpri[1]) *priority_mask = 0xf0;
+ else if (pri <= layerpri[0]) *priority_mask = 0xf0|0xcc;
+ else *priority_mask = 0xf0|0xcc|0xaa;
+
+ *color = sprite_colorbase | (*color & 0x001f);
+}
+
+static void moo_tile_callback(int layer, int *code, int *color, int *flags)
+{
+ *color = layer_colorbase[layer] | (*color>>2 & 0x0f);
+}
+
+VIDEO_START(moo)
+{
+ int offsx, offsy;
+
+ assert(machine->screen[0].format == BITMAP_FORMAT_RGB32);
+
+ alpha_enabled = 0;
+
+ K053251_vh_start();
+ K054338_vh_start();
+
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_4, 1, NULL, moo_tile_callback, 0);
+
+ if (!strcmp(machine->gamedrv->name, "bucky") || !strcmp(machine->gamedrv->name, "buckyua"))
+ {
+ // Bucky doesn't chain tilemaps
+ K056832_set_LayerAssociation(0);
+
+ K056832_set_LayerOffset(0, -2, 0);
+ K056832_set_LayerOffset(1, 2, 0);
+ K056832_set_LayerOffset(2, 4, 0);
+ K056832_set_LayerOffset(3, 6, 0);
+
+ offsx = -48;
+ offsy = 23;
+ }
+ else
+ {
+ // other than the intro showing one blank line alignment is good through the game
+ K056832_set_LayerOffset(0, -2+1, 0);
+ K056832_set_LayerOffset(1, 2+1, 0);
+ K056832_set_LayerOffset(2, 4+1, 0);
+ K056832_set_LayerOffset(3, 6+1, 0);
+
+ offsx = -48+1;
+ offsy = 23;
+ }
+
+ K053247_vh_start(machine, REGION_GFX2, offsx, offsy, NORMAL_PLANE_ORDER, moo_sprite_callback);
+
+ K054338_invert_alpha(0);
+}
+
+/* useful function to sort the three tile layers by priority order */
+static void sortlayers(int *layer,int *pri)
+{
+#define SWAP(a,b) \
+ if (pri[a] < pri[b]) \
+ { \
+ int t; \
+ t = pri[a]; pri[a] = pri[b]; pri[b] = t; \
+ t = layer[a]; layer[a] = layer[b]; layer[b] = t; \
+ }
+
+ SWAP(0,1)
+ SWAP(0,2)
+ SWAP(1,2)
+}
+
+VIDEO_UPDATE(moo)
+{
+ static const int K053251_CI[4] = { K053251_CI1, K053251_CI2, K053251_CI3, K053251_CI4 };
+ int layers[3];
+ int bg_colorbase, new_colorbase, plane, dirty, alpha;
+
+ bg_colorbase = K053251_get_palette_index(K053251_CI1);
+ sprite_colorbase = K053251_get_palette_index(K053251_CI0);
+ layer_colorbase[0] = 0x70;
+
+ if (K056832_get_LayerAssociation())
+ {
+ for (plane=1; plane<4; plane++)
+ {
+ new_colorbase = K053251_get_palette_index(K053251_CI[plane]);
+ if (layer_colorbase[plane] != new_colorbase)
+ {
+ layer_colorbase[plane] = new_colorbase;
+ K056832_mark_plane_dirty(plane);
+ }
+ }
+ }
+ else
+ {
+ for (dirty=0, plane=1; plane<4; plane++)
+ {
+ new_colorbase = K053251_get_palette_index(K053251_CI[plane]);
+ if (layer_colorbase[plane] != new_colorbase)
+ {
+ layer_colorbase[plane] = new_colorbase;
+ dirty = 1;
+ }
+ }
+ if (dirty) K056832_MarkAllTilemapsDirty();
+ }
+
+ layers[0] = 1;
+ layerpri[0] = K053251_get_priority(K053251_CI2);
+ layers[1] = 2;
+ layerpri[1] = K053251_get_priority(K053251_CI3);
+ layers[2] = 3;
+ layerpri[2] = K053251_get_priority(K053251_CI4);
+
+ sortlayers(layers, layerpri);
+
+ K054338_update_all_shadows(machine);
+ K054338_fill_backcolor(machine, bitmap, 0);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ if (layerpri[0] < K053251_get_priority(K053251_CI1)) /* bucky hides back layer behind background */
+ K056832_tilemap_draw(machine, bitmap, cliprect, layers[0], 0, 1);
+
+ K056832_tilemap_draw(machine, bitmap, cliprect, layers[1], 0, 2);
+
+ // Enabling alpha improves fog and fading in Moo but causes other things to disappear.
+ // There is probably a control bit somewhere to turn off alpha blending.
+ alpha_enabled = K054338_read_register(K338_REG_CONTROL) & K338_CTL_MIXPRI; // DUMMY
+
+ alpha = (alpha_enabled) ? K054338_set_alpha_level(1) : 255;
+
+ if (alpha > 0)
+ K056832_tilemap_draw(machine, bitmap, cliprect, layers[2], (alpha >= 255) ? 0 : TILEMAP_DRAW_ALPHA, 4);
+
+ K053247_sprites_draw(machine, bitmap,cliprect);
+
+ K056832_tilemap_draw(machine, bitmap, cliprect, 0, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/mosaic.c b/src/mame/video/mosaic.c
new file mode 100644
index 00000000000..46ca2b87252
--- /dev/null
+++ b/src/mame/video/mosaic.c
@@ -0,0 +1,87 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *mosaic_fgvideoram;
+UINT8 *mosaic_bgvideoram;
+
+static tilemap *bg_tilemap,*fg_tilemap;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ tile_index *= 2;
+ SET_TILE_INFO(
+ 0,
+ mosaic_fgvideoram[tile_index] + (mosaic_fgvideoram[tile_index+1] << 8),
+ 0,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ tile_index *= 2;
+ SET_TILE_INFO(
+ 1,
+ mosaic_bgvideoram[tile_index] + (mosaic_bgvideoram[tile_index+1] << 8),
+ 0,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( mosaic )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0xff);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( mosaic_fgvideoram_w )
+{
+ mosaic_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset/2);
+}
+
+WRITE8_HANDLER( mosaic_bgvideoram_w )
+{
+ mosaic_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+
+
+VIDEO_UPDATE( mosaic )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/mouser.c b/src/mame/video/mouser.c
new file mode 100644
index 00000000000..c45ccec98e8
--- /dev/null
+++ b/src/mame/video/mouser.c
@@ -0,0 +1,190 @@
+/*******************************************************************************
+
+ Mouser - Video Hardware:
+
+ Character map with scrollable rows, 1024 possible characters.
+ - index = byte from videoram + 2 bits from colorram)
+ - (if row is scrolled, videoram is offset, colorram is not)
+ - 16 4-color combinations for each char, from colorram
+
+ 15 Sprites controlled by 4-byte records
+ - 16 4-color combinations
+ - 2 banks of 64 sprite characters each
+
+*******************************************************************************/
+
+#include "driver.h"
+
+PALETTE_INIT( mouser )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = BIT(*color_prom,0);
+ bit1 = BIT(*color_prom,1);
+ bit2 = BIT(*color_prom,2);
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = BIT(*color_prom,3);
+ bit1 = BIT(*color_prom,4);
+ bit2 = BIT(*color_prom,5);
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = BIT(*color_prom,6);
+ bit1 = BIT(*color_prom,7);
+ b = 0x4f * bit0 + 0xa8 * bit1;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( mouser_flip_screen_x_w )
+{
+ flip_screen_x_set(~data & 1);
+}
+
+WRITE8_HANDLER( mouser_flip_screen_y_w )
+{
+ flip_screen_y_set(~data & 1);
+}
+
+WRITE8_HANDLER( mouser_spriteram_w )
+{
+ /* Mark the entire row as dirty if row scrollram is written */
+ /* Only used by the MOUSER logo */
+
+ int i;
+
+ if (offset < 32)
+ {
+ for(i=0;i<32;i++)
+ dirtybuffer[offset+i*32] = 1;
+ }
+ spriteram_w(offset, data);
+}
+
+WRITE8_HANDLER( mouser_colorram_w )
+{
+ dirtybuffer[offset] = 1;
+ colorram_w(offset, data);
+}
+
+VIDEO_UPDATE( mouser )
+{
+ int offs;
+ int sx,sy;
+ int flipx,flipy;
+
+ /* for every character in the Video RAM, check if it has been modified */
+ /* since last time and update it accordingly. */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int scrolled_y_position;
+ int color_offs;
+
+ if (dirtybuffer[offs])
+ {
+ dirtybuffer[offs] = 0;
+
+ sx = offs % 32;
+ sy = offs / 32;
+
+ if (flip_screen_x)
+ {
+ sx = 31 - sx;
+ }
+
+ if (flip_screen_y)
+ {
+ sy = 31 - sy;
+ }
+
+ /* This bit of spriteram appears to be for row scrolling */
+ /* Note: this is dependant on flipping in y */
+ scrolled_y_position = (256 + 8*sy - spriteram[offs%32])%256;
+ /* I think we still need to fetch the colorram bits to from the ram underneath, which is not scrolled */
+ /* Ideally we would merge these on a pixel-by-pixel basis, but it's ok to do this char-by-char, */
+ /* Since it's only for the MOUSER logo and it looks fine */
+ /* Note: this is _not_ dependant on flipping */
+ color_offs = offs%32 + ((256 + 8*(offs/32) - spriteram[offs%32])%256)/8*32;
+
+ drawgfx(tmpbitmap,machine->gfx[0],
+ videoram[offs] | (colorram[color_offs]>>5)*256 | ((colorram[color_offs]>>4)&1)*512,
+ colorram[color_offs]%16,
+ flip_screen_x,flip_screen_y,
+ 8*sx,scrolled_y_position,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ copyscrollbitmap(bitmap,tmpbitmap,0,0,0,0,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+
+ /* There seem to be two sets of sprites, each decoded identically */
+
+ /* This is the first set of 7 sprites */
+ for(offs = 0x0084; offs < 0x00A0; offs += 4)
+ {
+ sx = spriteram[offs+3];
+ sy = 0xef-spriteram[offs+2];
+
+ flipx = (spriteram[offs]&0x40)>>6;
+ flipy = (spriteram[offs]&0x80)>>7;
+
+ if (flip_screen_x)
+ {
+ flipx = !flipx;
+ sx = 240 - sx;
+ }
+
+ if (flip_screen_y)
+ {
+ flipy = !flipy;
+ sy = 238 - sy;
+ }
+
+ if ((spriteram[offs+1]&0x10)>>4)
+ drawgfx(bitmap,machine->gfx[1+((spriteram[offs+1]&0x20)>>5)],
+ spriteram[offs]&0x3f,
+ spriteram[offs+1]%16,
+ flipx,flipy,
+ sx,sy,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+
+ /* This is the second set of 8 sprites */
+ for(offs = 0x00C4; offs < 0x00E4; offs += 4)
+ {
+ sx = spriteram[offs+3];
+ sy = 0xef-spriteram[offs+2];
+
+ flipx = (spriteram[offs]&0x40)>>6;
+ flipy = (spriteram[offs]&0x80)>>7;
+
+ if (flip_screen_x)
+ {
+ flipx = !flipx;
+ sx = 240 - sx;
+ }
+
+ if (flip_screen_y)
+ {
+ flipy = !flipy;
+ sy = 238 - sy;
+ }
+
+ if ((spriteram[offs+1]&0x10)>>4)
+ drawgfx(bitmap,machine->gfx[1+((spriteram[offs+1]&0x20)>>5)],
+ spriteram[offs]&0x3f,
+ spriteram[offs+1]%16,
+ flipx,flipy,
+ sx,sy,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/mpatrol.c b/src/mame/video/mpatrol.c
new file mode 100644
index 00000000000..4ca7ce6e3af
--- /dev/null
+++ b/src/mame/video/mpatrol.c
@@ -0,0 +1,391 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+#define BGHEIGHT 64
+
+static UINT8 bg1xpos;
+static UINT8 bg1ypos;
+static UINT8 bg2xpos;
+static UINT8 bg2ypos;
+static UINT8 bgcontrol;
+
+static tilemap* bg_tilemap;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Moon Patrol has one 256x8 character palette PROM, one 32x8 background
+ palette PROM, one 32x8 sprite palette PROM and one 256x4 sprite lookup
+ table PROM.
+
+ The character and background palette PROMs are connected to the RGB output
+ this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+ The sprite palette PROM is connected to the RGB output this way. Note that
+ RED and BLUE are swapped wrt the usual configuration.
+
+ bit 7 -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ bit 0 -- 1 kohm resistor -- BLUE
+
+***************************************************************************/
+PALETTE_INIT( mpatrol )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ /* character palette */
+ for (i = 0;i < 512;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ COLOR(0, i) = i;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* background palette */
+ for (i = 0;i < 32;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i+512,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the sprite palette */
+
+ /* sprite palette */
+ for (i = 0;i < 32;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i+512+32,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the sprite lookup table */
+
+ /* sprite lookup table */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ {
+ COLOR(1,i) = 512+32 + (*color_prom++);
+ if (i % 4 == 3) color_prom += 4; /* half of the PROM is unused */
+ }
+
+ /* background */
+ /* the palette is a 32x8 PROM with many colors repeated. The address of */
+ /* the colors to pick is as follows: */
+ /* xbb00: mountains */
+ /* 0xxbb: hills */
+ /* 1xxbb: city */
+ COLOR(2,0) = 512;
+ COLOR(2,1) = 512+4;
+ COLOR(2,2) = 512+8;
+ COLOR(2,3) = 512+12;
+ COLOR(3,0) = 512;
+ COLOR(3,1) = 512+1;
+ COLOR(3,2) = 512+2;
+ COLOR(3,3) = 512+3;
+ COLOR(4,0) = 512;
+ COLOR(4,1) = 512+16+1;
+ COLOR(4,2) = 512+16+2;
+ COLOR(4,3) = 512+16+3;
+}
+
+
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 video = videoram[tile_index];
+ UINT8 color = colorram[tile_index];
+
+ int flag = 0;
+ int code = 0;
+
+ code = video;
+
+ if (color & 0x80)
+ {
+ code |= 0x100;
+ }
+
+ if (tile_index / 32 <= 6)
+ {
+ flag |= TILE_FORCE_LAYER0; /* lines 0 to 6 are opaqe? */
+ }
+
+ SET_TILE_INFO(0, code, color & 0x3f, flag);
+}
+
+
+
+VIDEO_START( mpatrol )
+{
+ int y;
+
+ bg_tilemap = tilemap_create(get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(bg_tilemap, 0);
+
+ tilemap_set_scroll_rows(bg_tilemap, 4); /* only lines 192-256 scroll */
+
+ /* Set the first 3 quarters of the screen to 255 */
+ for (y=0;y<3;y++)
+ {
+ tilemap_set_scrollx(bg_tilemap, y, 255);
+ }
+}
+
+
+
+WRITE8_HANDLER( mpatrol_scroll_w )
+{
+
+/*
+ According to the schematics there is only one video register that holds the X scroll value
+ with a NAND gate on the V64 and V128 lines to control when it's read, and when
+ 255 (via 8 pull up resistors) is used.
+
+ So we set the first 3 quarters to 255 (done in VIDEO_START) and the last to the scroll value
+*/
+ tilemap_set_scrollx(bg_tilemap, 3, -data);
+}
+
+
+
+WRITE8_HANDLER( mpatrol_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+
+WRITE8_HANDLER( mpatrol_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+
+WRITE8_HANDLER( mpatrol_bg1ypos_w )
+{
+ bg1ypos = data;
+}
+WRITE8_HANDLER( mpatrol_bg1xpos_w )
+{
+ bg1xpos = data;
+}
+WRITE8_HANDLER( mpatrol_bg2xpos_w )
+{
+ bg2xpos = data;
+}
+WRITE8_HANDLER( mpatrol_bg2ypos_w )
+{
+ bg2ypos = data;
+}
+WRITE8_HANDLER( mpatrol_bgcontrol_w )
+{
+ bgcontrol = data;
+}
+
+
+
+WRITE8_HANDLER( mpatrol_flipscreen_w )
+{
+ coin_counter_w(0, data & 0x02);
+ coin_counter_w(1, data & 0x20);
+
+ /* screen flip is handled both by software and hardware */
+
+ flip_screen_set((data ^ ~readinputport(4)) & 1);
+}
+
+
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int xpos, int ypos, int image)
+{
+ rectangle rect;
+
+ if (flip_screen)
+ {
+ xpos = 255 - xpos;
+ ypos = 255 - ypos - BGHEIGHT;
+ }
+
+ drawgfx(bitmap, machine->gfx[image],
+ 0, 0,
+ flip_screen,
+ flip_screen,
+ xpos,
+ ypos,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+
+ drawgfx(bitmap, machine->gfx[image],
+ 0, 0,
+ flip_screen,
+ flip_screen,
+ xpos - 256,
+ ypos,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+
+ rect.min_x = machine->screen[0].visarea.min_x;
+ rect.max_x = machine->screen[0].visarea.max_x;
+
+ if (flip_screen)
+ {
+ rect.min_y = ypos - BGHEIGHT;
+ rect.max_y = ypos - 1;
+ }
+ else
+ {
+ rect.min_y = ypos + BGHEIGHT;
+ rect.max_y = ypos + 2 * BGHEIGHT - 1;
+ }
+
+ fillbitmap(bitmap, machine->remapped_colortable[machine->gfx[image]->color_base + 3], &rect);
+}
+
+
+
+VIDEO_UPDATE( mpatrol )
+{
+ int offs;
+
+ fillbitmap(bitmap, 0, cliprect);
+
+ if (!(bgcontrol & 0x20))
+ {
+ if (!(bgcontrol & 0x10))
+ {
+ draw_background(machine, bitmap, cliprect, bg2xpos, bg2ypos, 2); /* distant mountains */
+ }
+ if (!(bgcontrol & 0x02))
+ {
+ draw_background(machine, bitmap, cliprect, bg1xpos, bg1ypos, 3); /* hills */
+ }
+ if (!(bgcontrol & 0x04))
+ {
+ draw_background(machine, bitmap, cliprect, bg1xpos, bg1ypos, 4); /* cityscape */
+ }
+ }
+
+ tilemap_set_flip(bg_tilemap, flip_screen ? TILEMAP_FLIPX | TILEMAP_FLIPY : 0);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* draw the sprites */
+
+ for (offs = spriteram_size - 4; offs >= 0; offs -= 4)
+ {
+ int sx,sy,flipx,flipy;
+
+ if (!(offs & 0x60))
+ {
+ continue; /* some addresses in sprite RAM are skipped? */
+ }
+
+ sx = spriteram[offs + 3];
+ sy = 240 - spriteram[offs];
+ flipx = spriteram[offs + 1] & 0x40;
+ flipy = spriteram[offs + 1] & 0x80;
+
+ if (flip_screen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+ sx = 240 - sx;
+ sy = 240 - sy;
+ }
+
+ sy++; /* odd */
+
+ drawgfx(bitmap, machine->gfx[1],
+ spriteram[offs + 2],
+ spriteram[offs + 1] & 0x3f,
+ flipx, flipy,
+ sx, sy,
+ cliprect, TRANSPARENCY_COLOR, 512+32);
+ }
+ return 0;
+}
diff --git a/src/mame/video/mrdo.c b/src/mame/video/mrdo.c
new file mode 100644
index 00000000000..8d744c8f969
--- /dev/null
+++ b/src/mame/video/mrdo.c
@@ -0,0 +1,240 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *mrdo_bgvideoram,*mrdo_fgvideoram;
+static tilemap *bg_tilemap,*fg_tilemap;
+static int flipscreen;
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Mr. Do! has two 32 bytes palette PROM and a 32 bytes sprite color lookup
+ table PROM.
+ The palette PROMs are connected to the RGB output this way:
+
+ U2:
+ bit 7 -- unused
+ -- unused
+ -- 100 ohm resistor -diode- BLUE
+ -- 75 ohm resistor -diode- BLUE
+ -- 100 ohm resistor -diode- GREEN
+ -- 75 ohm resistor -diode- GREEN
+ -- 100 ohm resistor -diode- RED
+ bit 0 -- 75 ohm resistor -diode- RED
+
+ T2:
+ bit 7 -- unused
+ -- unused
+ -- 150 ohm resistor -diode- BLUE
+ -- 120 ohm resistor -diode- BLUE
+ -- 150 ohm resistor -diode- GREEN
+ -- 120 ohm resistor -diode- GREEN
+ -- 150 ohm resistor -diode- RED
+ bit 0 -- 120 ohm resistor -diode- RED
+
+ 200 ohm pulldown on all three components
+
+***************************************************************************/
+PALETTE_INIT( mrdo )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ const int R1 = 150;
+ const int R2 = 120;
+ const int R3 = 100;
+ const int R4 = 75;
+ const int pull = 200;
+ float pot[16];
+ int weight[16];
+ const float potadjust = 0.2; /* diode voltage drop */
+
+ for (i = 15;i >= 0;i--)
+ {
+ float par = 0;
+
+ if (i & 1) par += 1.0/R1;
+ if (i & 2) par += 1.0/R2;
+ if (i & 4) par += 1.0/R3;
+ if (i & 8) par += 1.0/R4;
+ if (par)
+ {
+ par = 1/par;
+ pot[i] = pull/(pull+par) - potadjust;
+ }
+ else pot[i] = 0;
+
+ weight[i] = 255 * pot[i] / pot[15];
+ }
+
+ for (i = 0;i < 256;i++)
+ {
+ int a1,a2;
+ int bits0,bits2,r,g,b;
+
+ a1 = ((i >> 3) & 0x1c) + (i & 0x03) + 32;
+ a2 = ((i >> 0) & 0x1c) + (i & 0x03);
+
+ bits0 = (color_prom[a1] >> 0) & 0x03;
+ bits2 = (color_prom[a2] >> 0) & 0x03;
+ r = weight[bits0 + (bits2 << 2)];
+ bits0 = (color_prom[a1] >> 2) & 0x03;
+ bits2 = (color_prom[a2] >> 2) & 0x03;
+ g = weight[bits0 + (bits2 << 2)];
+ bits0 = (color_prom[a1] >> 4) & 0x03;
+ bits2 = (color_prom[a2] >> 4) & 0x03;
+ b = weight[bits0 + (bits2 << 2)];
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ color_prom += 64;
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(2);i++)
+ {
+ int bits;
+
+ if (i < 32)
+ bits = color_prom[i] & 0x0f; /* low 4 bits are for sprite color n */
+ else
+ bits = color_prom[i & 0x1f] >> 4; /* high 4 bits are for sprite color n + 8 */
+
+ COLOR(2,i) = bits + ((bits & 0x0c) << 3);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 attr = mrdo_bgvideoram[tile_index];
+ SET_TILE_INFO(
+ 1,
+ mrdo_bgvideoram[tile_index+0x400] + ((attr & 0x80) << 1),
+ attr & 0x3f,
+ (attr & 0x40) ? TILE_FORCE_LAYER0 : 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 attr = mrdo_fgvideoram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ mrdo_fgvideoram[tile_index+0x400] + ((attr & 0x80) << 1),
+ attr & 0x3f,
+ (attr & 0x40) ? TILE_FORCE_LAYER0 : 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( mrdo )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(bg_tilemap,0);
+ tilemap_set_transparent_pen(fg_tilemap,0);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( mrdo_bgvideoram_w )
+{
+ mrdo_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( mrdo_fgvideoram_w )
+{
+ mrdo_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x3ff);
+}
+
+
+WRITE8_HANDLER( mrdo_scrollx_w )
+{
+ tilemap_set_scrollx(bg_tilemap,0,data);
+}
+
+WRITE8_HANDLER( mrdo_scrolly_w )
+{
+ /* This is NOT affected by flipscreen (so stop it happening) */
+
+ if (flipscreen) tilemap_set_scrolly(bg_tilemap,0,((256-data) & 0xff));
+ else tilemap_set_scrolly(bg_tilemap,0,data);
+}
+
+
+WRITE8_HANDLER( mrdo_flipscreen_w )
+{
+ /* bits 1-3 control the playfield priority, but they are not used by */
+ /* Mr. Do! so we don't emulate them */
+
+ flipscreen = data & 0x01;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ if (spriteram[offs + 1] != 0)
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ spriteram[offs],spriteram[offs + 2] & 0x0f,
+ spriteram[offs + 2] & 0x10,spriteram[offs + 2] & 0x20,
+ spriteram[offs + 3],256 - spriteram[offs + 1],
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( mrdo )
+{
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/mrflea.c b/src/mame/video/mrflea.c
new file mode 100644
index 00000000000..aa1826e05fa
--- /dev/null
+++ b/src/mame/video/mrflea.c
@@ -0,0 +1,97 @@
+/******************************************************************
+
+Mr. F. Lea
+(C) 1983 PACIFIC NOVELTY MFG. INC.
+
+******************************************************************/
+
+#include "driver.h"
+
+static int mrflea_gfx_bank;
+
+WRITE8_HANDLER( mrflea_gfx_bank_w ){
+ mrflea_gfx_bank = data;
+ if( data & ~0x14 ){
+ logerror( "unknown gfx bank: 0x%02x\n", data );
+ }
+}
+
+WRITE8_HANDLER( mrflea_videoram_w ){
+ int bank = offset/0x400;
+ offset &= 0x3ff;
+ videoram[offset] = data;
+ videoram[offset+0x400] = bank;
+ /* the address range that tile data is written to sets one bit of
+ ** the bank select. The remaining bits are from a video register.
+ */
+}
+
+WRITE8_HANDLER( mrflea_spriteram_w ){
+ if( offset&2 ){ /* tile_number */
+ spriteram[offset|1] = offset&1;
+ offset &= ~1;
+ }
+ spriteram[offset] = data;
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const gfx_element *gfx = machine->gfx[0];
+ const UINT8 *source = spriteram;
+ const UINT8 *finish = source+0x100;
+ rectangle clip = machine->screen[0].visarea;
+ clip.max_x -= 24;
+ clip.min_x += 16;
+ while( source<finish ){
+ int xpos = source[1]-3;
+ int ypos = source[0]-16+3;
+ int tile_number = source[2]+source[3]*0x100;
+
+ drawgfx( bitmap, gfx,
+ tile_number,
+ 0, /* color */
+ 0,0, /* no flip */
+ xpos,ypos,
+ &clip,TRANSPARENCY_PEN,0 );
+ drawgfx( bitmap, gfx,
+ tile_number,
+ 0, /* color */
+ 0,0, /* no flip */
+ xpos,256+ypos,
+ &clip,TRANSPARENCY_PEN,0 );
+ source+=4;
+ }
+}
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const UINT8 *source = videoram;
+ const gfx_element *gfx = machine->gfx[1];
+ int sx,sy;
+ int base = 0;
+ if( mrflea_gfx_bank&0x04 ) base |= 0x400;
+ if( mrflea_gfx_bank&0x10 ) base |= 0x200;
+ for( sy=0; sy<256; sy+=8 ){
+ for( sx=0; sx<256; sx+=8 ){
+ int tile_number = base+source[0]+source[0x400]*0x100;
+ source++;
+ drawgfx( bitmap, gfx,
+ tile_number,
+ 0, /* color */
+ 0,0, /* no flip */
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_NONE,0 );
+ }
+ }
+}
+
+VIDEO_START( mrflea ){
+}
+
+VIDEO_UPDATE( mrflea )
+{
+ draw_background(machine, bitmap, cliprect);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/mrjong.c b/src/mame/video/mrjong.c
new file mode 100644
index 00000000000..51dd6ac88fb
--- /dev/null
+++ b/src/mame/video/mrjong.c
@@ -0,0 +1,139 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs. (from video/penco.c)
+
+***************************************************************************/
+PALETTE_INIT( mrjong )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn, offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + (offs)])
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 0x10;
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* character lookup table */
+ /* sprites use the same color lookup table as characters */
+ for (i = 0; i < TOTAL_COLORS(0); i++)
+ COLOR(0, i) = *(color_prom++) & 0x0f;
+}
+
+
+/***************************************************************************
+
+ Display control parameter.
+
+***************************************************************************/
+WRITE8_HANDLER( mrjong_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( mrjong_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( mrjong_flipscreen_w )
+{
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] | ((colorram[tile_index] & 0x20) << 3);
+ int color = colorram[tile_index] & 0x1f;
+ int flags = ((colorram[tile_index] & 0x40) ? TILE_FLIPX : 0) | ((colorram[tile_index] & 0x80) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( mrjong )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows_flip_xy,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = (spriteram_size - 4); offs >= 0; offs -= 4)
+ {
+ int sprt;
+ int color;
+ int sx, sy;
+ int flipx, flipy;
+
+ sprt = (((spriteram[offs + 1] >> 2) & 0x3f) | ((spriteram[offs + 3] & 0x20) << 1));
+ flipx = (spriteram[offs + 1] & 0x01) >> 0;
+ flipy = (spriteram[offs + 1] & 0x02) >> 1;
+ color = (spriteram[offs + 3] & 0x1f);
+
+ sx = 224 - spriteram[offs + 2];
+ sy = spriteram[offs + 0];
+ if (flip_screen)
+ {
+ sx = 208 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1],
+ sprt,
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( mrjong )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/ms32.c b/src/mame/video/ms32.c
new file mode 100644
index 00000000000..ccaf805a62c
--- /dev/null
+++ b/src/mame/video/ms32.c
@@ -0,0 +1,510 @@
+/* Jaleco MegaSystem 32 Video Hardware */
+
+/* The Video Hardware is Similar to the Non-MS32 Version of Tetris Plus 2 */
+
+/* Plenty to do, see list in drivers/ms32.c */
+
+/*
+
+priority should be given to
+(a) dekluding the priorities, the kludge for kirarast made it easier to emulate the rest of it until then
+(b) working out the background registers correctly ...
+*/
+
+
+#include "driver.h"
+
+//UINT32 *ms32_fce00000;
+UINT32 *ms32_roz_ctrl;
+UINT32 *ms32_tx_scroll;
+UINT32 *ms32_bg_scroll;
+UINT32 *ms32_priram;
+UINT32 *ms32_palram;
+UINT32 *ms32_bgram;
+UINT32 *ms32_rozram;
+UINT32 *ms32_lineram;
+UINT32 *ms32_spram;
+UINT32 *ms32_txram;
+UINT32 *ms32_mainram;
+
+// kirarast, tp2m32, and 47pie2 require the sprites in a different order
+static int ms32_reverse_sprite_order;
+
+/********** Tilemaps **********/
+
+static tilemap *ms32_tx_tilemap, *ms32_roz_tilemap, *ms32_bg_tilemap;
+static int flipscreen;
+
+
+static TILE_GET_INFO( get_ms32_tx_tile_info )
+{
+ int tileno, colour;
+
+ tileno = ms32_txram[tile_index *2] & 0x0000ffff;
+ colour = ms32_txram[tile_index *2+1] & 0x000000f;
+
+ SET_TILE_INFO(3,tileno,colour,0);
+}
+
+static TILE_GET_INFO( get_ms32_roz_tile_info )
+{
+ int tileno,colour;
+
+ tileno = ms32_rozram[tile_index *2] & 0x0000ffff;
+ colour = ms32_rozram[tile_index *2+1] & 0x000000f;
+
+ SET_TILE_INFO(1,tileno,colour,0);
+}
+
+static TILE_GET_INFO( get_ms32_bg_tile_info )
+{
+ int tileno,colour;
+
+ tileno = ms32_bgram[tile_index *2] & 0x0000ffff;
+ colour = ms32_bgram[tile_index *2+1] & 0x000000f;
+
+ SET_TILE_INFO(2,tileno,colour,0);
+}
+
+static UINT32 brt[4];
+static int brt_r,brt_g,brt_b;
+
+VIDEO_START( ms32 )
+{
+ ms32_tx_tilemap = tilemap_create(get_ms32_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,64);
+ ms32_bg_tilemap = tilemap_create(get_ms32_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ ms32_roz_tilemap = tilemap_create(get_ms32_roz_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,128,128);
+
+ tilemap_set_transparent_pen(ms32_tx_tilemap,0);
+ tilemap_set_transparent_pen(ms32_bg_tilemap,0);
+ tilemap_set_transparent_pen(ms32_roz_tilemap,0);
+
+ ms32_reverse_sprite_order = 1;
+
+ /* i hate per game patches...how should priority really work? tetrisp2.c ? i can't follow it */
+ if (!strcmp(machine->gamedrv->name,"kirarast")) ms32_reverse_sprite_order = 0;
+ if (!strcmp(machine->gamedrv->name,"tp2m32")) ms32_reverse_sprite_order = 0;
+ if (!strcmp(machine->gamedrv->name,"47pie2")) ms32_reverse_sprite_order = 0;
+ if (!strcmp(machine->gamedrv->name,"47pie2o")) ms32_reverse_sprite_order = 0;
+ if (!strcmp(machine->gamedrv->name,"hayaosi3")) ms32_reverse_sprite_order = 0;
+
+ // tp2m32 doesn't set the brightness registers so we need sensible defaults
+ brt[0] = brt[1] = 0xffff;
+}
+
+/********** PALETTE WRITES **********/
+
+
+static void update_color(int color)
+{
+ int r,g,b;
+
+ /* I'm not sure how the brightness should be applied, currently I'm only
+ affecting bg & sprites, not fg.
+ The second brightness control might apply to shadows, see gametngk.
+ */
+ if (~color & 0x4000)
+ {
+ r = ((ms32_palram[color*2] & 0xff00) >>8 ) * brt_r / 0x100;
+ g = ((ms32_palram[color*2] & 0x00ff) >>0 ) * brt_g / 0x100;
+ b = ((ms32_palram[color*2+1] & 0x00ff) >>0 ) * brt_b / 0x100;
+ }
+ else
+ {
+ r = ((ms32_palram[color*2] & 0xff00) >>8 );
+ g = ((ms32_palram[color*2] & 0x00ff) >>0 );
+ b = ((ms32_palram[color*2+1] & 0x00ff) >>0 );
+ }
+
+ palette_set_color(Machine,color,MAKE_RGB(r,g,b));
+}
+
+WRITE32_HANDLER( ms32_brightness_w )
+{
+ int oldword = brt[offset];
+ COMBINE_DATA(&brt[offset]);
+
+ if (brt[offset] != oldword)
+ {
+ int bank = ((offset & 2) >> 1) * 0x4000;
+ int i;
+
+ if (bank == 0)
+ {
+ brt_r = 0x100 - ((brt[0] & 0xff00) >> 8);
+ brt_g = 0x100 - ((brt[0] & 0x00ff) >> 0);
+ brt_b = 0x100 - ((brt[1] & 0x00ff) >> 0);
+
+ for (i = 0;i < 0x3000;i++) // colors 0x3000-0x3fff are not used
+ update_color(i);
+ }
+ }
+
+//popmessage("%04x %04x %04x %04x",brt[0],brt[1],brt[2],brt[3]);
+}
+
+WRITE32_HANDLER( ms32_palram_w )
+{
+ COMBINE_DATA(&ms32_palram[offset]);
+
+ update_color(offset/2);
+}
+
+
+
+READ32_HANDLER( ms32_txram_r )
+{
+ return ms32_txram[offset];
+}
+
+WRITE32_HANDLER( ms32_txram_w )
+{
+ COMBINE_DATA(&ms32_txram[offset]);
+ tilemap_mark_tile_dirty(ms32_tx_tilemap,offset/2);
+}
+
+READ32_HANDLER( ms32_rozram_r )
+{
+ return ms32_rozram[offset];
+}
+
+WRITE32_HANDLER( ms32_rozram_w )
+{
+ COMBINE_DATA(&ms32_rozram[offset]);
+ tilemap_mark_tile_dirty(ms32_roz_tilemap,offset/2);
+}
+
+READ32_HANDLER( ms32_lineram_r )
+{
+ return ms32_lineram[offset];
+}
+
+WRITE32_HANDLER( ms32_lineram_w )
+{
+ COMBINE_DATA(&ms32_lineram[offset]);
+}
+
+READ32_HANDLER( ms32_bgram_r )
+{
+ return ms32_bgram[offset];
+}
+
+WRITE32_HANDLER( ms32_bgram_w )
+{
+ COMBINE_DATA(&ms32_bgram[offset]);
+ tilemap_mark_tile_dirty(ms32_bg_tilemap,offset/2);
+}
+
+READ32_HANDLER( ms32_spram_r )
+{
+ return ms32_spram[offset];
+}
+
+WRITE32_HANDLER( ms32_spram_w )
+{
+ COMBINE_DATA(&ms32_spram[offset]);
+}
+
+READ32_HANDLER( ms32_priram_r )
+{
+ return ms32_priram[offset];
+}
+
+WRITE32_HANDLER( ms32_priram_w )
+{
+ COMBINE_DATA(&ms32_priram[offset]);
+}
+
+WRITE32_HANDLER( ms32_gfxctrl_w )
+{
+ if (ACCESSING_LSB32)
+ {
+ /* bit 1 = flip screen */
+ flipscreen = data & 0x02;
+ tilemap_set_flip(ms32_tx_tilemap,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ tilemap_set_flip(ms32_bg_tilemap,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ /* bit 2 used by f1superb, unknown */
+
+ /* bit 3 used by several games, unknown */
+
+//popmessage("%08x",data);
+ }
+}
+
+
+
+/* SPRITES based on tetrisp2 for now, readd priority bits later */
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT32 *sprram_top, size_t sprram_size)
+{
+/***************************************************************************
+
+
+ Sprites Drawing
+
+ Offset: Bits: Meaning:
+
+ 0.w fedc ba98 ---- ----
+ ---- ---- 7654 ---- Priority
+ ---- ---- ---- 3---
+ ---- ---- ---- -2-- Draw this sprite
+ ---- ---- ---- --1- Flip Y
+ ---- ---- ---- ---0 Flip X
+
+ 1.w fedc ba98 ---- ---- Tile's Y position in the tile page (*)
+ ---- ---- 7654 3210 Tile's X position in the tile page (*)
+
+ 2.w fedc ---- ---- ---- Color
+ ---- ba98 7654 3210 Tile Page (32x32 tiles = 256x256 pixels each)
+
+ 3.w fedc ba98 ---- ---- Y Size - 1 (*)
+ ---- ---- 7654 3210 X Size - 1 (*)
+
+ 4.w fedc ba-- ---- ----
+ ---- --98 7654 3210 Y (Signed)
+
+ 5.w fedc b--- ---- ----
+ ---- -a98 7654 3210 X (Signed)
+
+ 6.w fedc ba98 7654 3210 Zoom Y
+
+ 7.w fedc ba98 7654 3210 Zoom X
+
+(*) 1 pixel granularity
+
+***************************************************************************/
+
+ int tx, ty, sx, sy, flipx, flipy;
+ int xsize, ysize, xzoom, yzoom;
+ int code, attr, color, size, pri, pri_mask, trans;
+ gfx_element *gfx = machine->gfx[0];
+ gfx_element mygfx = *gfx;
+
+ UINT32 *source = sprram_top;
+ const UINT32 *finish = sprram_top + (sprram_size - 0x10) / 4;
+
+
+ if (ms32_reverse_sprite_order == 1)
+ {
+ source = sprram_top + (sprram_size - 0x10) / 4;
+ finish = sprram_top;
+ }
+
+
+ for (;ms32_reverse_sprite_order ? (source>=finish) : (source<finish); ms32_reverse_sprite_order ? (source-=4) : (source+=4))
+ {
+ attr = source[ 0 ];
+
+ if ((attr & 0x0004) == 0) continue;
+
+ flipx = attr & 1;
+ flipy = attr & 2;
+
+ pri = (attr >> 4)&0xf;
+
+ code = source[ 1 ];
+ color = source[ 2 ];
+
+ tx = (code >> 0) & 0xff;
+ ty = (code >> 8) & 0xff;
+
+ code = (color & 0x0fff);
+
+ color = (color >> 12) & 0xf;
+
+ size = source[ 3 ];
+
+ xsize = ((size >> 0) & 0xff) + 1;
+ ysize = ((size >> 8) & 0xff) + 1;
+
+ sy = source[ 4 ];
+ sx = source[ 5 ];
+
+ sx = (sx & 0x3ff) - (sx & 0x400);
+ sy = (sy & 0x1ff) - (sy & 0x200);
+
+ xzoom = (source[ 6 ]&0xffff);
+ yzoom = (source[ 7 ]&0xffff);
+
+ if (!yzoom || !xzoom) continue;
+
+ yzoom = 0x1000000/yzoom;
+ xzoom = 0x1000000/xzoom;
+
+ trans = TRANSPARENCY_PEN; // there are surely also shadows (see gametngk) but how they're enabled we don't know
+
+ if (flipscreen)
+ {
+ sx = 320 - ((xsize*xzoom)>>16) - sx;
+ sy = 224 - ((ysize*yzoom)>>16) - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ /* change GfxElement parameters to draw only the needed part of the 256x256 tile */
+ mygfx.width = xsize;
+ mygfx.height = ysize;
+ mygfx.gfxdata = gfx->gfxdata + tx + ty * gfx->line_modulo;
+
+#if 0
+if (input_code_pressed(KEYCODE_A) && (pri & 8)) color = rand();
+if (input_code_pressed(KEYCODE_S) && (pri & 4)) color = rand();
+if (input_code_pressed(KEYCODE_D) && (pri & 2)) color = rand();
+if (input_code_pressed(KEYCODE_F) && (pri & 1)) color = rand();
+#endif
+
+ /* TODO: priority handling is completely wrong, but better than nothing */
+ if (pri == 0x0)
+ pri_mask = 0x00;
+ else if (pri <= 0xd)
+ pri_mask = 0xf0;
+ else if (pri <= 0xe)
+ pri_mask = 0xfc;
+ else
+ pri_mask = 0xfe;
+
+ pdrawgfxzoom(bitmap, &mygfx,
+ code,
+ color,
+ flipx, flipy,
+ sx,sy,
+ cliprect, trans, 0,
+ xzoom, yzoom, pri_mask);
+ } /* end sprite loop */
+}
+
+
+
+static void draw_roz(mame_bitmap *bitmap, const rectangle *cliprect,int priority)
+{
+ /* TODO: registers 0x40/4 / 0x44/4 and 0x50/4 / 0x54/4 are used, meaning unknown */
+
+ if (ms32_roz_ctrl[0x5c/4] & 1) /* "super" mode */
+ {
+ rectangle my_clip;
+ int y,maxy;
+
+ my_clip.min_x = cliprect->min_x;
+ my_clip.max_x = cliprect->max_x;
+
+ y = cliprect->min_y;
+ maxy = cliprect->max_y;
+
+ while (y <= maxy)
+ {
+ UINT32 *lineaddr = ms32_lineram + 8 * (y & 0xff);
+
+ int start2x = (lineaddr[0x00/4] & 0xffff) | ((lineaddr[0x04/4] & 3) << 16);
+ int start2y = (lineaddr[0x08/4] & 0xffff) | ((lineaddr[0x0c/4] & 3) << 16);
+ int incxx = (lineaddr[0x10/4] & 0xffff) | ((lineaddr[0x14/4] & 1) << 16);
+ int incxy = (lineaddr[0x18/4] & 0xffff) | ((lineaddr[0x1c/4] & 1) << 16);
+ int startx = (ms32_roz_ctrl[0x00/4] & 0xffff) | ((ms32_roz_ctrl[0x04/4] & 3) << 16);
+ int starty = (ms32_roz_ctrl[0x08/4] & 0xffff) | ((ms32_roz_ctrl[0x0c/4] & 3) << 16);
+ int offsx = ms32_roz_ctrl[0x30/4];
+ int offsy = ms32_roz_ctrl[0x34/4];
+
+ my_clip.min_y = my_clip.max_y = y;
+
+ offsx += (ms32_roz_ctrl[0x38/4] & 1) * 0x400; // ??? gratia, hayaosi1...
+ offsy += (ms32_roz_ctrl[0x3c/4] & 1) * 0x400; // ??? gratia, hayaosi1...
+
+ /* extend sign */
+ if (start2x & 0x20000) start2x |= ~0x3ffff;
+ if (start2y & 0x20000) start2y |= ~0x3ffff;
+ if (startx & 0x20000) startx |= ~0x3ffff;
+ if (starty & 0x20000) starty |= ~0x3ffff;
+ if (incxx & 0x10000) incxx |= ~0x1ffff;
+ if (incxy & 0x10000) incxy |= ~0x1ffff;
+
+ tilemap_draw_roz(bitmap, &my_clip, ms32_roz_tilemap,
+ (start2x+startx+offsx)<<16, (start2y+starty+offsy)<<16,
+ incxx<<8, incxy<<8, 0, 0,
+ 1, // Wrap
+ 0, priority);
+
+ y++;
+ }
+ }
+ else /* "simple" mode */
+ {
+ int startx = (ms32_roz_ctrl[0x00/4] & 0xffff) | ((ms32_roz_ctrl[0x04/4] & 3) << 16);
+ int starty = (ms32_roz_ctrl[0x08/4] & 0xffff) | ((ms32_roz_ctrl[0x0c/4] & 3) << 16);
+ int incxx = (ms32_roz_ctrl[0x10/4] & 0xffff) | ((ms32_roz_ctrl[0x14/4] & 1) << 16);
+ int incxy = (ms32_roz_ctrl[0x18/4] & 0xffff) | ((ms32_roz_ctrl[0x1c/4] & 1) << 16);
+ int incyy = (ms32_roz_ctrl[0x20/4] & 0xffff) | ((ms32_roz_ctrl[0x24/4] & 1) << 16);
+ int incyx = (ms32_roz_ctrl[0x28/4] & 0xffff) | ((ms32_roz_ctrl[0x2c/4] & 1) << 16);
+ int offsx = ms32_roz_ctrl[0x30/4];
+ int offsy = ms32_roz_ctrl[0x34/4];
+
+ offsx += (ms32_roz_ctrl[0x38/4] & 1) * 0x400; // ??? gratia, hayaosi1...
+ offsy += (ms32_roz_ctrl[0x3c/4] & 1) * 0x400; // ??? gratia, hayaosi1...
+
+ /* extend sign */
+ if (startx & 0x20000) startx |= ~0x3ffff;
+ if (starty & 0x20000) starty |= ~0x3ffff;
+ if (incxx & 0x10000) incxx |= ~0x1ffff;
+ if (incxy & 0x10000) incxy |= ~0x1ffff;
+ if (incyy & 0x10000) incyy |= ~0x1ffff;
+ if (incyx & 0x10000) incyx |= ~0x1ffff;
+
+ tilemap_draw_roz(bitmap, cliprect, ms32_roz_tilemap,
+ (startx+offsx)<<16, (starty+offsy)<<16,
+ incxx<<8, incxy<<8, incyx<<8, incyy<<8,
+ 1, // Wrap
+ 0, priority);
+ }
+}
+
+
+
+VIDEO_UPDATE( ms32 )
+{
+ int scrollx,scrolly;
+
+ /* TODO: registers 0x04/4 and 0x10/4 are used too; the most interesting case
+ is gametngk, where they are *usually*, but not always, copies of 0x00/4
+ and 0x0c/4 (used for scrolling).
+ 0x10/4 is 0xdf in most games (apart from gametngk's special case), but
+ it's 0x00 in hayaosi1 and kirarast, and 0xe2 (!) in gratia's tx layer.
+ The two registers might be somewhat related to the width and height of the
+ tilemaps, but there's something that just doesn't fit.
+ */
+ scrollx = ms32_tx_scroll[0x00/4] + ms32_tx_scroll[0x08/4] + 0x18;
+ scrolly = ms32_tx_scroll[0x0c/4] + ms32_tx_scroll[0x14/4];
+ tilemap_set_scrollx(ms32_tx_tilemap, 0, scrollx);
+ tilemap_set_scrolly(ms32_tx_tilemap, 0, scrolly);
+
+ scrollx = ms32_bg_scroll[0x00/4] + ms32_bg_scroll[0x08/4] + 0x10;
+ scrolly = ms32_bg_scroll[0x0c/4] + ms32_bg_scroll[0x14/4];
+ tilemap_set_scrollx(ms32_bg_tilemap, 0, scrollx);
+ tilemap_set_scrolly(ms32_bg_tilemap, 0, scrolly);
+
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* TODO: 0 is correct for gametngk, but break f1superb scrolling grid (text at
+ top and bottom of the screen becomes black on black) */
+ fillbitmap(bitmap,machine->pens[0],cliprect); /* bg color */
+
+
+ /* priority hack, we really need to figure out what priority ram is I think */
+ if (!strcmp(machine->gamedrv->name,"hayaosi3"))
+ {
+ tilemap_draw(bitmap,cliprect,ms32_bg_tilemap,0,1);
+ tilemap_draw(bitmap,cliprect,ms32_tx_tilemap,0,4);
+ draw_roz(bitmap,cliprect,4); // this question text needs to appear over the sprites
+ draw_sprites(machine,bitmap,cliprect, ms32_spram, 0x40000);
+
+ }
+ else
+ {
+ tilemap_draw(bitmap,cliprect,ms32_bg_tilemap,0,1);
+ draw_roz(bitmap,cliprect,2);
+ tilemap_draw(bitmap,cliprect,ms32_tx_tilemap,0,4);
+ draw_sprites(machine,bitmap,cliprect, ms32_spram, 0x40000);
+ }
+
+
+ return 0;
+}
diff --git a/src/mame/video/msisaac.c b/src/mame/video/msisaac.c
new file mode 100644
index 00000000000..601aa133f58
--- /dev/null
+++ b/src/mame/video/msisaac.c
@@ -0,0 +1,251 @@
+/*
+* Video Driver for Metal Soldier Isaac II (1985)
+*/
+
+#include "driver.h"
+
+/*
+* variables
+*/
+UINT8 *msisaac_videoram;
+UINT8 *msisaac_videoram2;
+
+//static int textbank1;
+static int bg2_textbank;
+
+static tilemap *background, *background2, *foreground;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int tile_number = videoram[tile_index];
+ SET_TILE_INFO( 0,
+ tile_number,
+ 0x10,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg2_tile_info )
+{
+ int tile_number = msisaac_videoram2[tile_index];
+
+ /* graphics 0 or 1 */
+ int gfx_b = (bg2_textbank>>3) & 1;
+
+ SET_TILE_INFO( gfx_b,
+ tile_number,
+ 0x20,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int tile_number = msisaac_videoram[tile_index];
+ SET_TILE_INFO( 1,
+ 0x100+tile_number,
+ 0x30,
+ 0);
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( msisaac )
+{
+ background = tilemap_create(get_bg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,32,32);
+ background2 = tilemap_create(get_bg2_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ foreground = tilemap_create(get_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(background2,0);
+ tilemap_set_transparent_pen(foreground,0);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( msisaac_fg_scrolly_w )
+{
+ tilemap_set_scrolly( foreground, 0, data );
+}
+
+WRITE8_HANDLER( msisaac_fg_scrollx_w )
+{
+ tilemap_set_scrollx( foreground, 0, 9+data );
+}
+
+WRITE8_HANDLER( msisaac_bg2_scrolly_w )
+{
+ tilemap_set_scrolly( background2, 0, data );
+}
+
+WRITE8_HANDLER( msisaac_bg2_scrollx_w )
+{
+ tilemap_set_scrollx( background2, 0, 9+2+data );
+}
+
+WRITE8_HANDLER( msisaac_bg_scrolly_w )
+{
+ tilemap_set_scrolly( background, 0, data );
+}
+
+WRITE8_HANDLER( msisaac_bg_scrollx_w )
+{
+ tilemap_set_scrollx( background, 0, 9+4+data );
+}
+
+
+#ifdef UNUSED_FUNCTION
+WRITE8_HANDLER( msisaac_textbank1_w )
+{
+ if( textbank1!=data )
+ {
+ textbank1 = data;
+ tilemap_mark_all_tiles_dirty( foreground );
+ }
+}
+#endif
+
+WRITE8_HANDLER( msisaac_bg2_textbank_w )
+{
+ if( bg2_textbank != data )
+ {
+ bg2_textbank = data;
+ tilemap_mark_all_tiles_dirty( background2 );
+
+ //check if we are correct on this one
+ if ((data!=8) && (data!=0))
+ {
+ logerror("bg2 control=%2x\n",data);
+ }
+ }
+}
+
+WRITE8_HANDLER( msisaac_bg_videoram_w )
+{
+ msisaac_videoram[offset]=data;
+ tilemap_mark_tile_dirty(background,offset);
+}
+
+WRITE8_HANDLER( msisaac_bg2_videoram_w )
+{
+ msisaac_videoram2[offset]=data;
+ tilemap_mark_tile_dirty(background2,offset);
+}
+
+WRITE8_HANDLER( msisaac_fg_videoram_w )
+{
+ videoram[offset]=data;
+ tilemap_mark_tile_dirty(foreground,offset);
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ const UINT8 *source = spriteram+32*4-4;
+ const UINT8 *finish = spriteram; /* ? */
+
+ while( source>=finish )
+ {
+ int sx = source[0];
+ int sy = 240-source[1]-1;
+ int attributes = source[2];
+ int sprite_number = source[3];
+
+ int color = (attributes>>4) & 0xf;
+ int flipx = (attributes&0x1);
+ int flipy = (attributes&0x2);
+
+ gfx_element *gfx = machine->gfx[2];
+
+ if (attributes&4)
+ {
+ //color = rand()&15;
+ gfx = machine->gfx[3];
+ }
+
+ if (attributes&8) /* double size sprite */
+ {
+ switch(attributes&3)
+ {
+ case 0: /* flipx==0 && flipy==0 */
+ drawgfx(bitmap,gfx,
+ sprite_number+1,color,
+ flipx,flipy,
+ sx,sy-16,cliprect,TRANSPARENCY_PEN,0 );
+ drawgfx(bitmap,gfx,
+ sprite_number,color,
+ flipx,flipy,
+ sx,sy,cliprect,TRANSPARENCY_PEN,0 );
+ break;
+ case 1: /* flipx==1 && flipy==0 */
+ drawgfx(bitmap,gfx,
+ sprite_number+1,color,
+ flipx,flipy,
+ sx,sy-16,cliprect,TRANSPARENCY_PEN,0 );
+ drawgfx(bitmap,gfx,
+ sprite_number,color,
+ flipx,flipy,
+ sx,sy,cliprect,TRANSPARENCY_PEN,0 );
+ break;
+ case 2: /* flipx==0 && flipy==1 */
+ drawgfx(bitmap,gfx,
+ sprite_number,color,
+ flipx,flipy,
+ sx,sy-16,cliprect,TRANSPARENCY_PEN,0 );
+ drawgfx(bitmap,gfx,
+ sprite_number+1,color,
+ flipx,flipy,
+ sx,sy,cliprect,TRANSPARENCY_PEN,0 );
+ break;
+ case 3: /* flipx==1 && flipy==1 */
+ drawgfx(bitmap,gfx,
+ sprite_number,color,
+ flipx,flipy,
+ sx,sy-16,cliprect,TRANSPARENCY_PEN,0 );
+ drawgfx(bitmap,gfx,
+ sprite_number+1,color,
+ flipx,flipy,
+ sx,sy,cliprect,TRANSPARENCY_PEN,0 );
+ break;
+ }
+ }
+ else
+ {
+ drawgfx(bitmap,gfx,
+ sprite_number,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0 );
+ }
+ source -= 4;
+ }
+}
+
+VIDEO_UPDATE( msisaac )
+{
+ tilemap_draw(bitmap,cliprect,background, 0,0);
+ tilemap_draw(bitmap,cliprect,background2,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,foreground, 0,0);
+ return 0;
+}
+
diff --git a/src/mame/video/mugsmash.c b/src/mame/video/mugsmash.c
new file mode 100644
index 00000000000..05906115a0a
--- /dev/null
+++ b/src/mame/video/mugsmash.c
@@ -0,0 +1,155 @@
+/* video/mugsmash.c - see drivers/mugsmash.c for more info */
+
+#include "driver.h"
+
+static tilemap *mugsmash_tilemap1, *mugsmash_tilemap2;
+
+extern UINT16 *mugsmash_videoram1, *mugsmash_videoram2, *mugs_spriteram;
+extern UINT16 *mugsmash_regs1, *mugsmash_regs2;
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+
+ /* Each Sprite takes 16 bytes, 5 used? */
+
+ /* ---- ---- xxxx xxxx ---- ---- aaaa aaaa ---- ---- NNNN NNNN ---- ---- nnnn nnnn ---- ---- yyyy yyyy (rest unused?) */
+
+ /* x = xpos LSB
+ y = ypos LSB
+ N = tile number MSB
+ n = tile number LSB
+ a = attribute / extra
+ f?XY cccc
+
+ f = x-flip
+ ? = unknown, probably y-flip
+ X = xpos MSB
+ y = ypos MSB
+ c = colour
+
+ */
+
+ const UINT16 *source = mugs_spriteram;
+ const UINT16 *finish = source+0x2000;
+ const gfx_element *gfx = machine->gfx[0];
+
+ while( source<finish )
+ {
+ int xpos = source[0] & 0x00ff;
+ int ypos = source[4] & 0x00ff;
+ int num = (source[3] & 0x00ff) | ((source[2] & 0x00ff) << 8);
+ int attr = source[1];
+ int flipx = (attr & 0x0080)>>7;
+ int colour = (attr & 0x000f);
+
+ xpos += ((attr & 0x0020) >> 5) * 0x100;
+ ypos += ((attr & 0x0010) >> 4) * 0x100;
+
+ xpos -= 28;
+ ypos -= 16;
+
+ drawgfx(
+ bitmap,
+ gfx,
+ num,
+ colour,
+ flipx,0,
+ xpos,ypos,
+ cliprect,
+ TRANSPARENCY_PEN,0
+ );
+
+ source += 0x8;
+ }
+}
+
+static TILE_GET_INFO( get_mugsmash_tile_info1 )
+{
+
+ /* fF-- cccc nnnn nnnn */
+
+ /* c = colour?
+ n = number?
+ F = flip-X
+ f = flip-Y
+ */
+
+ int tileno,colour,fx;
+
+ tileno = mugsmash_videoram1[tile_index *2 +1];
+ colour = mugsmash_videoram1[tile_index *2] & 0x000f;
+ fx = (mugsmash_videoram1[tile_index *2] & 0xc0) >>6;
+
+ SET_TILE_INFO(1,tileno,colour,TILE_FLIPYX(fx));
+}
+
+WRITE16_HANDLER( mugsmash_videoram1_w )
+{
+ mugsmash_videoram1[offset] = data;
+ tilemap_mark_tile_dirty(mugsmash_tilemap1,offset/2);
+}
+
+static TILE_GET_INFO( get_mugsmash_tile_info2 )
+{
+
+ /* fF-- cccc nnnn nnnn */
+
+ /* c = colour?
+ n = number?
+ F = flip-X
+ f = flip-Y
+ */
+
+ int tileno,colour,fx;
+
+ tileno = mugsmash_videoram2[tile_index *2 +1];
+ colour = mugsmash_videoram2[tile_index *2] & 0x000f;
+ fx = (mugsmash_videoram2[tile_index *2] & 0xc0) >>6;
+
+ SET_TILE_INFO(1,tileno,16+colour,TILE_FLIPYX(fx));
+}
+
+WRITE16_HANDLER( mugsmash_videoram2_w )
+{
+ mugsmash_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(mugsmash_tilemap2,offset/2);
+}
+
+WRITE16_HANDLER (mugsmash_reg_w)
+{
+ mugsmash_regs1[offset] = data;
+// popmessage ("Regs %04x, %04x, %04x, %04x", mugsmash_regs1[0], mugsmash_regs1[1],mugsmash_regs1[2], mugsmash_regs1[3]);
+
+ switch (offset)
+ {
+ case 0:
+ tilemap_set_scrollx(mugsmash_tilemap2,0, mugsmash_regs1[2]+7);
+ break;
+ case 1:
+ tilemap_set_scrolly(mugsmash_tilemap2,0, mugsmash_regs1[3]+4);
+ break;
+ case 2:
+ tilemap_set_scrollx(mugsmash_tilemap1,0, mugsmash_regs1[0]+3);
+ break;
+ case 3:
+ tilemap_set_scrolly(mugsmash_tilemap1,0, mugsmash_regs1[1]+4);
+ break;
+ }
+}
+
+VIDEO_START( mugsmash )
+{
+
+ mugsmash_tilemap1 = tilemap_create(get_mugsmash_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+ tilemap_set_transparent_pen(mugsmash_tilemap1,0);
+
+ mugsmash_tilemap2 = tilemap_create(get_mugsmash_tile_info2,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+}
+
+VIDEO_UPDATE( mugsmash )
+{
+ tilemap_draw(bitmap,cliprect,mugsmash_tilemap2,0,0);
+ tilemap_draw(bitmap,cliprect,mugsmash_tilemap1,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/munchmo.c b/src/mame/video/munchmo.c
new file mode 100644
index 00000000000..c95bf5bd3f2
--- /dev/null
+++ b/src/mame/video/munchmo.c
@@ -0,0 +1,197 @@
+#include "driver.h"
+
+
+UINT8 *mnchmobl_vreg;
+UINT8 *mnchmobl_status_vram;
+UINT8 *mnchmobl_sprite_xpos;
+UINT8 *mnchmobl_sprite_attr;
+UINT8 *mnchmobl_sprite_tile;
+
+static int mnchmobl_palette_bank;
+static int flipscreen;
+
+PALETTE_INIT( mnchmobl )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (color_prom[i] >> 6) & 0x01;
+ bit1 = (color_prom[i] >> 7) & 0x01;
+ b = 0x4f * bit0 + 0xa8 * bit1;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+WRITE8_HANDLER( mnchmobl_palette_bank_w )
+{
+ if( mnchmobl_palette_bank!=(data&0x3) )
+ {
+ memset( dirtybuffer, 1, 0x100 );
+ mnchmobl_palette_bank = data&0x3;
+ }
+}
+
+WRITE8_HANDLER( mnchmobl_flipscreen_w )
+{
+ if( flipscreen!=data )
+ {
+ memset( dirtybuffer, 1, 0x100 );
+ flipscreen = data;
+ }
+}
+
+
+READ8_HANDLER( mnchmobl_sprite_xpos_r ){ return mnchmobl_sprite_xpos[offset]; }
+WRITE8_HANDLER( mnchmobl_sprite_xpos_w ){ mnchmobl_sprite_xpos[offset] = data; }
+
+READ8_HANDLER( mnchmobl_sprite_attr_r ){ return mnchmobl_sprite_attr[offset]; }
+WRITE8_HANDLER( mnchmobl_sprite_attr_w ){ mnchmobl_sprite_attr[offset] = data; }
+
+READ8_HANDLER( mnchmobl_sprite_tile_r ){ return mnchmobl_sprite_tile[offset]; }
+WRITE8_HANDLER( mnchmobl_sprite_tile_w ){ mnchmobl_sprite_tile[offset] = data; }
+
+VIDEO_START( mnchmobl )
+{
+ dirtybuffer = auto_malloc(0x100);
+ memset( dirtybuffer, 1, 0x100 );
+ tmpbitmap = auto_bitmap_alloc(512,512,machine->screen[0].format);
+}
+
+READ8_HANDLER( mnchmobl_videoram_r )
+{
+ return videoram[offset];
+}
+
+WRITE8_HANDLER( mnchmobl_videoram_w )
+{
+ offset = offset&0xff; /* mirror the two banks? */
+ if( videoram[offset]!=data )
+ {
+ videoram[offset] = data;
+ dirtybuffer[offset] = 1;
+ }
+}
+
+static void draw_status(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const gfx_element *gfx = machine->gfx[0];
+ int row;
+
+ for( row=0; row<4; row++ )
+ {
+ int sy,sx = (row&1)*8;
+ const UINT8 *source = mnchmobl_status_vram + (~row&1)*32;
+ if( row<=1 )
+ {
+ source+=2*32;
+ sx+=256+32+16;
+ }
+ for( sy=0; sy<256; sy+=8 )
+ {
+ drawgfx( bitmap, gfx,
+ *source++,
+ 0, /* color */
+ 0,0, /* no flip */
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_NONE, 0 );
+ }
+ }
+}
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+/*
+ ROM B1.2C contains 256 tilemaps defining 4x4 configurations of
+ the tiles in ROM B2.2B
+*/
+ UINT8 *rom = memory_region(REGION_GFX2);
+ const gfx_element *gfx = machine->gfx[1];
+ int offs;
+
+ for( offs=0; offs<0x100; offs++ )
+ {
+ if( dirtybuffer[offs] )
+ {
+ int sy = (offs%16)*32;
+ int sx = (offs/16)*32;
+ int tile_number = videoram[offs];
+ int row,col;
+ dirtybuffer[offs] = 0;
+ for( row=0; row<4; row++ )
+ {
+ for( col=0; col<4; col++ )
+ {
+ drawgfx( tmpbitmap,gfx,
+ rom[col+tile_number*4+row*0x400],
+ mnchmobl_palette_bank,
+ 0,0, /* flip */
+ sx+col*8, sy+row*8,
+ 0, TRANSPARENCY_NONE, 0 );
+ }
+ }
+ }
+ }
+
+ {
+ int scrollx = -(mnchmobl_vreg[6]*2+(mnchmobl_vreg[7]>>7))-64-128-16;
+ int scrolly = 0;
+
+ copyscrollbitmap(bitmap,tmpbitmap,
+ 1,&scrollx,1,&scrolly,
+ cliprect,TRANSPARENCY_NONE,0);
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int scroll = mnchmobl_vreg[6];
+ int flags = mnchmobl_vreg[7]; /* XB?????? */
+ int xadjust = - 128-16 - ((flags&0x80)?1:0);
+ int bank = (flags&0x40)?1:0;
+ const gfx_element *gfx = machine->gfx[2+bank];
+ int color_base = mnchmobl_palette_bank*4+3;
+ int i;
+ for( i=0; i<0x200; i++ )
+ {
+ int tile_number = mnchmobl_sprite_tile[i]; /* ETTTTTTT */
+ int attributes = mnchmobl_sprite_attr[i]; /* XYYYYYCC */
+ int sx = mnchmobl_sprite_xpos[i]; /* XXXXXXX? */
+ int sy = (i/0x40)*0x20; /* Y YY------ */
+ sy += (attributes>>2)&0x1f;
+ if( tile_number != 0xff && (attributes&0x80) )
+ {
+ sx = (sx>>1) | (tile_number&0x80);
+ sx = 2*((-32-scroll - sx)&0xff)+xadjust;
+ drawgfx( bitmap, gfx,
+ 0x7f - (tile_number&0x7f),
+ color_base-(attributes&0x03),
+ 0,0, /* no flip */
+ sx,sy,
+ cliprect, TRANSPARENCY_PEN, 7 );
+ }
+ }
+}
+
+VIDEO_UPDATE( mnchmobl )
+{
+ draw_background(machine, bitmap, cliprect);
+ draw_sprites(machine, bitmap, cliprect);
+ draw_status(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/mustache.c b/src/mame/video/mustache.c
new file mode 100644
index 00000000000..3708e33ad6c
--- /dev/null
+++ b/src/mame/video/mustache.c
@@ -0,0 +1,143 @@
+/***************************************************************************
+
+ Mustache Boy
+ (c)1987 March Electronics
+
+***************************************************************************/
+
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+static int control_byte;
+
+PALETTE_INIT(mustache)
+{
+ int i;
+
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ bit3 = (color_prom[i] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ /* green component */
+ bit0 = (color_prom[i + 256] >> 0) & 0x01;
+ bit1 = (color_prom[i + 256] >> 1) & 0x01;
+ bit2 = (color_prom[i + 256] >> 2) & 0x01;
+ bit3 = (color_prom[i + 256] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ /* blue component */
+ bit0 = (color_prom[i + 512] >> 0) & 0x01;
+ bit1 = (color_prom[i + 512] >> 1) & 0x01;
+ bit2 = (color_prom[i + 512] >> 2) & 0x01;
+ bit3 = (color_prom[i + 512] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+WRITE8_HANDLER( mustache_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+WRITE8_HANDLER (mustache_video_control_w)
+{
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ /* tile bank */
+
+ if ((control_byte ^ data) & 0x08)
+ {
+ control_byte = data;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( mustache_scroll_w )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, 0x100 - data);
+ tilemap_set_scrollx(bg_tilemap, 1, 0x100 - data);
+ tilemap_set_scrollx(bg_tilemap, 2, 0x100 - data);
+ tilemap_set_scrollx(bg_tilemap, 3, 0x100);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = videoram[2 * tile_index + 1];
+ int code = videoram[2 * tile_index] + ((attr & 0x60) << 3) + ((control_byte & 0x08) << 7);
+ int color = attr & 0x0f;
+
+ SET_TILE_INFO(0, code, color, ((attr & 0x10) ? TILE_FLIPX : 0) | ((attr & 0x80) ? TILE_FLIPY : 0) );
+
+
+}
+
+VIDEO_START( mustache )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows_flip_x,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ tilemap_set_scroll_rows(bg_tilemap, 4);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ rectangle clip = *cliprect;
+ const gfx_element *gfx = machine->gfx[1];
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int sy = 240-spriteram[offs];
+ int sx = 240-spriteram[offs+3];
+ int code = spriteram[offs+2];
+ int attr = spriteram[offs+1];
+ int color = (attr & 0xe0)>>5;
+
+ if (sy == 240) continue;
+
+ code+=(attr&0x0c)<<6;
+
+ if ((control_byte & 0xa))
+ clip.max_y = machine->screen[0].visarea.max_y;
+ else
+ if (flip_screen)
+ clip.min_y = machine->screen[0].visarea.min_y + 56;
+ else
+ clip.max_y = machine->screen[0].visarea.max_y - 56;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ }
+
+ drawgfx(bitmap,gfx,
+ code,
+ color,
+ flip_screen,flip_screen,
+ sx,sy,
+ &clip,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( mustache )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/mw8080bw.c b/src/mame/video/mw8080bw.c
new file mode 100644
index 00000000000..f4be6c575f9
--- /dev/null
+++ b/src/mame/video/mw8080bw.c
@@ -0,0 +1,391 @@
+/***************************************************************************
+
+ Midway 8080-based black and white hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "mw8080bw.h"
+
+
+
+VIDEO_UPDATE( mw8080bw )
+{
+ UINT8 x = 0;
+ UINT8 y = MW8080BW_VCOUNTER_START_NO_VBLANK;
+ UINT8 video_data = 0;
+
+ while (1)
+ {
+ /* plot the current pixel */
+ pen_t pen = (video_data & 0x01) ? RGB_WHITE : RGB_BLACK;
+ *BITMAP_ADDR32(bitmap, y - MW8080BW_VCOUNTER_START_NO_VBLANK, x) = pen;
+
+ /* next pixel */
+ video_data = video_data >> 1;
+ x = x + 1;
+
+ /* end of line? */
+ if (x == 0)
+ {
+ /* yes, flush out the shift register */
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ pen = (video_data & 0x01) ? RGB_WHITE : RGB_BLACK;
+ *BITMAP_ADDR32(bitmap, y - MW8080BW_VCOUNTER_START_NO_VBLANK, 256 + i) = pen;
+
+ video_data = video_data >> 1;
+ }
+
+ /* next row, video_data is now 0, so the next line will start
+ with 4 blank pixels */
+ y = y + 1;
+
+ /* end of screen? */
+ if (y == 0)
+ break;
+ }
+ /* the video RAM is read at every 8 pixels starting with pixel 4 */
+ else if ((x & 0x07) == 0x04)
+ {
+ offs_t offs = ((offs_t)y << 5) | (x >> 3);
+ video_data = mw8080bw_ram[offs];
+ }
+ }
+
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Space Encounters
+ *
+ *************************************/
+
+
+#define PHANTOM2_BOTTOM_TRENCH_DARK_RGB32_PEN RGB_BLACK
+#define PHANTOM2_BOTTOM_TRENCH_LIGHT_RGB32_PEN MAKE_RGB(0x5a, 0x5a, 0x5a)
+#define PHANTOM2_TOP_TRENCH_DARK_RGB32_PEN RGB_BLACK
+#define PHANTOM2_TOP_TRENCH_LIGHT_RGB32_PEN RGB_WHITE
+#define PHANTOM2_SIDE_TRENCH_DARK_RGB32_PEN RGB_BLACK
+#define PHANTOM2_SIDE_TRENCH_LIGHT_RGB32_PEN MAKE_RGB(0x72, 0x72, 0x72)
+
+
+VIDEO_UPDATE( spcenctr )
+{
+ UINT8 line_buf[256]; /* 256x1 bit RAM */
+
+ UINT8 x = 0;
+ UINT8 y = MW8080BW_VCOUNTER_START_NO_VBLANK;
+ UINT8 video_data = 0;
+ UINT8 draw_line = 0;
+ UINT8 draw_trench = 0;
+ UINT8 draw_floor = 0;
+ UINT8 width = spcenctr_get_trench_width();
+ UINT8 floor_width = width;
+ UINT8 center = spcenctr_get_trench_center();
+
+ memset(line_buf, 0, 256);
+
+ while (1)
+ {
+ /* plot the current pixel */
+ UINT8 bit = video_data & 0x01;
+ pen_t pen = bit ? RGB_WHITE : RGB_BLACK;
+
+ /* possibly draw trench in the background, top of trench first */
+ if (!(width & 0x80) && draw_trench)
+ {
+ line_buf[x] = draw_line;
+
+ if (!bit)
+ pen = draw_line ? PHANTOM2_TOP_TRENCH_LIGHT_RGB32_PEN : PHANTOM2_TOP_TRENCH_DARK_RGB32_PEN;
+ }
+ /* sides of trench? */
+ else if (!(floor_width & 0x80) && (draw_trench || draw_floor))
+ {
+ if (!bit)
+ pen = line_buf[x] ? PHANTOM2_SIDE_TRENCH_LIGHT_RGB32_PEN : PHANTOM2_SIDE_TRENCH_DARK_RGB32_PEN;
+ }
+ /* bottom of trench? */
+ else if (draw_floor)
+ {
+ line_buf[x] = line_buf[x - 1];
+
+ if (!bit)
+ pen = line_buf[x] ? PHANTOM2_BOTTOM_TRENCH_LIGHT_RGB32_PEN : PHANTOM2_BOTTOM_TRENCH_DARK_RGB32_PEN;
+ }
+
+ *BITMAP_ADDR32(bitmap, y - MW8080BW_VCOUNTER_START_NO_VBLANK, x) = pen;
+
+ center = center + 1;
+ width = width + ((center & 0x80) ? -1 : 1);
+ floor_width = floor_width + ((center & 0x80) ? -1 : 1);
+
+ /* next pixel */
+ video_data = video_data >> 1;
+ x = x + 1;
+
+ /* end of line? */
+ if (x == 0)
+ {
+ offs_t offs;
+ UINT8 trench_control;
+
+ /* yes, flush out the shift register */
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ pen = (video_data & 0x01) ? RGB_WHITE : RGB_BLACK;
+ *BITMAP_ADDR32(bitmap, y - MW8080BW_VCOUNTER_START_NO_VBLANK, 256 + i) = pen;
+
+ video_data = video_data >> 1;
+ }
+
+ /* update the trench control for the next line */
+ offs = ((offs_t)y << 5) | 0x1f;
+ trench_control = mw8080bw_ram[offs];
+
+ if (trench_control & 0x40)
+ draw_trench = 1;
+
+ if (trench_control & 0x20)
+ draw_trench = 0;
+
+ if (trench_control & 0x10)
+ draw_floor = 1;
+
+ if (trench_control & 0x08)
+ draw_floor = 0;
+
+ draw_line = (trench_control & 0x80) >> 7;
+
+ /* add the lower 2 bits stored in the slope array to width */
+ if (draw_trench)
+ width = width + (spcenctr_get_trench_slope(y) & 0x03);
+
+ /* add the higher 2 bits stored in the slope array to floor width */
+ if (draw_floor)
+ floor_width = floor_width + ((spcenctr_get_trench_slope(y) & 0x0c) >> 2);
+
+ /* next row, video_data is now 0, so the next line will start
+ with 4 blank pixels */
+ y = y + 1;
+
+ /* end of screen? */
+ if (y == 0)
+ break;
+ }
+ /* the video RAM is read at every 8 pixels starting with pixel 4 */
+ else if ((x & 0x07) == 0x04)
+ {
+ offs_t offs = ((offs_t)y << 5) | (x >> 3);
+ video_data = mw8080bw_ram[offs];
+ }
+ }
+
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Phantom II
+ *
+ *************************************/
+
+
+/* the cloud generator comprises of 2 counters and a shift register:
+
+ * counter 1 is 8 bits and and clocked every pixel. It gets cleared at the end of HBLANK .
+ Bit 0 is used to clock the shift register, thus repeating every pixel twice.
+ Bits 4-7 go to address line A0-A3 of the cloud gfx prom.
+ * counter 2 is 12 bits starting from 0xe0b and counts up to 0xfff. It gets clocked at the
+ beginning of HBLANK and is never cleared.
+ Bits 1-7 go to address line A4-A10 of the cloud gfx prom.
+*/
+
+#define PHANTOM2_CLOUD_COUNTER_START (0x0e0b)
+#define PHANTOM2_CLOUD_COUNTER_END (0x1000)
+#define PHANTOM2_CLOUD_COUNTER_PERIOD (PHANTOM2_CLOUD_COUNTER_END - PHANTOM2_CLOUD_COUNTER_START)
+
+#define PHANTOM2_RGB32_CLOUD_PEN MAKE_RGB(0xc0, 0xc0, 0xc0)
+
+
+VIDEO_UPDATE( phantom2 )
+{
+ UINT8 x = 0;
+ UINT8 y = MW8080BW_VCOUNTER_START_NO_VBLANK;
+ UINT8 video_data = 0;
+ UINT8 cloud_data = 0;
+
+ UINT16 cloud_counter = phantom2_get_cloud_counter();
+
+ UINT8 *cloud_region = memory_region(REGION_PROMS);
+
+ while (1)
+ {
+ int load_shift_reg;
+ UINT8 cloud_data_to_load = 0;
+ pen_t pen;
+
+ /* plot the current pixel */
+ UINT8 bit = video_data & 0x01;
+
+ /* if background color, cloud gfx in the background */
+ if ((bit == 0) && (cloud_data & 0x01))
+ pen = PHANTOM2_RGB32_CLOUD_PEN;
+ else
+ pen = bit ? RGB_WHITE : RGB_BLACK;
+
+ *BITMAP_ADDR32(bitmap, y - MW8080BW_VCOUNTER_START_NO_VBLANK, x) = pen;
+
+ /* move to next pixel -- if ripple carry is currently set,
+ prepare for loading the shift register */
+ load_shift_reg = ((x & 0x0f) == 0x0f);
+
+ if (load_shift_reg)
+ {
+ offs_t cloud_offs = ((cloud_counter & 0xfe) << 3) | (x >> 4);
+ cloud_data_to_load = cloud_region[cloud_offs];
+ }
+
+ video_data = video_data >> 1;
+ x = x + 1;
+
+ /* the sift register is clocked on the falling edge of bit 0 */
+ if (!(x & 0x01))
+ {
+ /* load or shift? */
+ if (load_shift_reg)
+ cloud_data = cloud_data_to_load;
+ else
+ cloud_data = cloud_data >> 1;
+ }
+
+ /* end of line? */
+ if (x == 0)
+ {
+ /* yes, flush out the shift register */
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ pen = (video_data & 0x01) ? RGB_WHITE : RGB_BLACK;
+ *BITMAP_ADDR32(bitmap, y - MW8080BW_VCOUNTER_START_NO_VBLANK, 256 + i) = pen;
+
+ video_data = video_data >> 1;
+ }
+
+ /* next row of clouds */
+ cloud_counter = cloud_counter + 1;
+
+ if (cloud_counter == PHANTOM2_CLOUD_COUNTER_END)
+ cloud_counter = PHANTOM2_CLOUD_COUNTER_START;
+
+ /* next row of pixels, video_data is now 0, so the next
+ line will start with 4 blank pixels */
+ y = y + 1;
+
+ /* end of screen? */
+ if (y == 0)
+ break;
+ }
+ /* the video RAM is read at every 8 pixels starting with pixel 4 */
+ else if ((x & 0x07) == 0x04)
+ {
+ offs_t offs = ((offs_t)y << 5) | (x >> 3);
+ video_data = mw8080bw_ram[offs];
+ }
+ }
+
+ return 0;
+}
+
+
+VIDEO_EOF( phantom2 )
+{
+ UINT16 cloud_counter = phantom2_get_cloud_counter();
+
+ cloud_counter = cloud_counter + MW8080BW_VTOTAL;
+
+ if (cloud_counter >= PHANTOM2_CLOUD_COUNTER_END)
+ cloud_counter = PHANTOM2_CLOUD_COUNTER_START + (cloud_counter - PHANTOM2_CLOUD_COUNTER_END);
+
+ phantom2_set_cloud_counter(cloud_counter);
+}
+
+
+
+/*************************************
+ *
+ * Space Invaders
+ *
+ *************************************/
+
+
+/* the flip screen circuit is just a couple of relays on the monitor PCB */
+
+VIDEO_UPDATE( invaders )
+{
+ UINT8 x = 0;
+ UINT8 y = MW8080BW_VCOUNTER_START_NO_VBLANK;
+ UINT8 video_data = 0;
+ UINT8 flip = invaders_is_flip_screen();
+
+ while (1)
+ {
+ /* plot the current pixel */
+ pen_t pen = (video_data & 0x01) ? RGB_WHITE : RGB_BLACK;
+
+ if (flip)
+ *BITMAP_ADDR32(bitmap, MW8080BW_VBSTART - 1 - (y - MW8080BW_VCOUNTER_START_NO_VBLANK), MW8080BW_HPIXCOUNT - 1 - x) = pen;
+ else
+ *BITMAP_ADDR32(bitmap, y - MW8080BW_VCOUNTER_START_NO_VBLANK, x) = pen;
+
+ /* next pixel */
+ video_data = video_data >> 1;
+ x = x + 1;
+
+ /* end of line? */
+ if (x == 0)
+ {
+ /* yes, flush out the shift register */
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ pen = (video_data & 0x01) ? RGB_WHITE : RGB_BLACK;
+
+ if (flip)
+ *BITMAP_ADDR32(bitmap, MW8080BW_VBSTART - 1 - (y - MW8080BW_VCOUNTER_START_NO_VBLANK), MW8080BW_HPIXCOUNT - 1 - (256 + i)) = pen;
+ else
+ *BITMAP_ADDR32(bitmap, y - MW8080BW_VCOUNTER_START_NO_VBLANK, 256 + i) = pen;
+
+ video_data = video_data >> 1;
+ }
+
+ /* next row, video_data is now 0, so the next line will start
+ with 4 blank pixels */
+ y = y + 1;
+
+ /* end of screen? */
+ if (y == 0)
+ break;
+ }
+ /* the video RAM is read at every 8 pixels starting with pixel 4 */
+ else if ((x & 0x07) == 0x04)
+ {
+ offs_t offs = ((offs_t)y << 5) | (x >> 3);
+ video_data = mw8080bw_ram[offs];
+ }
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/mystston.c b/src/mame/video/mystston.c
new file mode 100644
index 00000000000..b656dd6a00b
--- /dev/null
+++ b/src/mame/video/mystston.c
@@ -0,0 +1,172 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+ There are only a few differences between the video hardware of Mysterious
+ Stones and Mat Mania. The tile bank select bit is different and the sprite
+ selection seems to be different as well. Additionally, the palette is stored
+ differently. I'm also not sure that the 2nd tile page is really used in
+ Mysterious Stones.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *mystston_videoram2;
+
+static int mystston_fgcolor, mystston_bgpage;
+
+static tilemap *fg_tilemap, *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Mysterious Stones has both palette RAM and a PROM. The PROM is used for
+ text.
+
+***************************************************************************/
+
+PALETTE_INIT( mystston )
+{
+ int i;
+
+ for (i = 0; i < 32; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ // red component
+
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ // green component
+
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ // blue component
+
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine, i + 24, MAKE_RGB(r, g, b)); // first 24 colors are from RAM
+
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( mystston_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset & 0x3ff);
+}
+
+WRITE8_HANDLER( mystston_videoram2_w )
+{
+ mystston_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset & 0x1ff);
+}
+
+WRITE8_HANDLER( mystston_scroll_w )
+{
+ tilemap_set_scrolly(bg_tilemap, 0, data);
+}
+
+WRITE8_HANDLER( mystston_control_w )
+{
+ // bits 0 and 1 are foreground text color
+ if (mystston_fgcolor != ((data & 0x01) << 1) + ((data & 0x02) >> 1))
+ {
+ mystston_fgcolor = ((data & 0x01) << 1) + ((data & 0x02) >> 1);
+ tilemap_mark_all_tiles_dirty(fg_tilemap);
+ }
+
+ // bit 2 is background page select
+ mystston_bgpage = (data & 0x04) ? 1:0;
+
+ // bits 4 and 5 are coin counters in flipped order
+ coin_counter_w(0, data & 0x20);
+ coin_counter_w(1, data & 0x10);
+
+ // bit 7 is screen flip
+ flip_screen_set((data & 0x80) ^ ((readinputport(3) & 0x20) ? 0x80:0));
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = mystston_videoram2[tile_index] + ((mystston_videoram2[tile_index + 0x200] & 0x01) << 8);
+ int flags = (tile_index & 0x10) ? TILE_FLIPY : 0;
+
+ SET_TILE_INFO(1, code, 0, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = videoram[tile_index] + ((videoram[tile_index + 0x400] & 0x07) << 8);
+ int color = mystston_fgcolor;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( mystston )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols_flip_x,
+ TILEMAP_TYPE_PEN, 16, 16, 16, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols_flip_x,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = 0; offs < spriteram_size; offs += 4)
+ {
+ int attr = spriteram[offs];
+
+ if (attr & 0x01)
+ {
+ int code = spriteram[offs + 1] + ((attr & 0x10) << 4);
+ int color = (attr & 0x08) >> 3;
+ int flipx = attr & 0x04;
+ int flipy = attr & 0x02;
+ int sx = 240 - spriteram[offs + 3];
+ int sy = (240 - spriteram[offs + 2]) & 0xff;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[2], code, color, flipx, flipy,
+ sx, sy, cliprect, TRANSPARENCY_PEN, 0);
+ }
+ }
+}
+
+VIDEO_UPDATE( mystston )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/mystwarr.c b/src/mame/video/mystwarr.c
new file mode 100644
index 00000000000..7fb14946d40
--- /dev/null
+++ b/src/mame/video/mystwarr.c
@@ -0,0 +1,555 @@
+#define MW_VERBOSE 0
+
+/*
+ * video/mystwarr.c - Konami "Pre-GX" video hardware (here there be dragons)
+ *
+ */
+
+#include "driver.h"
+#include "video/konamiic.h"
+#include "machine/konamigx.h"
+
+static int layer_colorbase[6];
+static int oinprion, cbparam;
+static int sprite_colorbase, sub1_colorbase, last_psac_colorbase, gametype;
+static int roz_enable, roz_rombank;
+static tilemap *ult_936_tilemap;
+static char *orig_roms;
+
+// do some trickery since we know the graphics decode doesn't touch the source data again
+// and we want the original data
+static void mystwarr_save_orig_tiles(void)
+{
+ UINT8 *s = memory_region(REGION_GFX1);
+ UINT8 *pFinish = s+memory_region_length(REGION_GFX1)-3;
+
+ orig_roms = malloc_or_die(memory_region_length(REGION_GFX1));
+ memcpy(orig_roms, s, memory_region_length(REGION_GFX1));
+
+ // now convert the data into a drawable format so we can decode it
+ while (s < pFinish)
+ {
+ /* convert the whole mess to 5bpp planar in System GX's format
+ (p3 p1 p2 p0 p5)
+ (the original ROMs are stored as chunky for the first 4 bits
+ and the 5th bit is planar, which is undecodable as-is) */
+ int d0 = ((s[0]&0x80) )|((s[0]&0x08)<<3)|((s[1]&0x80)>>2)|((s[1]&0x08)<<1)|
+ ((s[2]&0x80)>>4)|((s[2]&0x08)>>1)|((s[3]&0x80)>>6)|((s[3]&0x08)>>3);
+ int d1 = ((s[0]&0x40)<<1)|((s[0]&0x04)<<4)|((s[1]&0x40)>>1)|((s[1]&0x04)<<2)|
+ ((s[2]&0x40)>>3)|((s[2]&0x04) )|((s[3]&0x40)>>5)|((s[3]&0x04)>>2);
+ int d2 = ((s[0]&0x20)<<2)|((s[0]&0x02)<<5)|((s[1]&0x20) )|((s[1]&0x02)<<3)|
+ ((s[2]&0x20)>>2)|((s[2]&0x02)<<1)|((s[3]&0x20)>>4)|((s[3]&0x02)>>1);
+ int d3 = ((s[0]&0x10)<<3)|((s[0]&0x01)<<6)|((s[1]&0x10)<<1)|((s[1]&0x01)<<4)|
+ ((s[2]&0x10)>>1)|((s[2]&0x01)<<2)|((s[3]&0x10)>>3)|((s[3]&0x01) );
+
+ s[0] = d3;
+ s[1] = d1;
+ s[2] = d2;
+ s[3] = d0;
+
+ s += 5;
+ }
+}
+
+static void mystwarr_rest_orig_tiles(void)
+{
+ UINT8 *s = memory_region(REGION_GFX1);
+
+ // restore the original data so the ROM test can pass
+ memcpy(s, orig_roms, memory_region_length(REGION_GFX1));
+ free(orig_roms);
+}
+
+
+// Mystic Warriors requires tile based blending.
+static void mystwarr_tile_callback(int layer, int *code, int *color, int *flags)
+{
+ if (layer==1) {if ((*code&0xff00)+(*color)==0x4101) cbparam++; else cbparam--;} //* water hack (TEMPORARY)
+
+ *color = layer_colorbase[layer] | (*color>>1 & 0x1f);
+}
+
+// for games with 5bpp tile data
+static void game5bpp_tile_callback(int layer, int *code, int *color, int *flags)
+{
+ *color = layer_colorbase[layer] | (*color>>1 & 0x1f);
+}
+
+// for games with 4bpp tile data
+static void game4bpp_tile_callback(int layer, int *code, int *color, int *flags)
+{
+ *color = layer_colorbase[layer] | (*color>>2 & 0x0f);
+}
+
+static void mystwarr_sprite_callback(int *code, int *color, int *priority)
+{
+ int c = *color;
+
+ *color = sprite_colorbase | (c & 0x001f);
+ *priority = c & 0x00f0;
+}
+
+static void metamrph_sprite_callback(int *code, int *color, int *priority)
+{
+ int c = *color;
+ int attr = c;
+
+ c = (c & 0x1f) | sprite_colorbase;
+
+ // Bit8 & 9 are effect attributes. It is not known whether the effects are generated by external logic.
+ if ((attr & 0x300) != 0x300)
+ {
+ *color = c;
+ *priority = (attr & 0xe0) >> 2;
+ }
+ else
+ {
+ *color = c | 3<<K055555_MIXSHIFT | K055555_SKIPSHADOW; // reflection?
+ *priority = 0x1c;
+ }
+}
+
+static void gaiapols_sprite_callback(int *code, int *color, int *priority)
+{
+ int c = *color;
+
+ *color = sprite_colorbase | (c>>4 & 0x20) | (c & 0x001f);
+ *priority = c & 0x00e0;
+}
+
+static void martchmp_sprite_callback(int *code, int *color, int *priority)
+{
+ int c = *color;
+
+ // Bit8 & 9 are effect attributes. It is not known whether the effects are generated by external logic.
+ if ((c & 0x3ff) == 0x11f)
+ *color = K055555_FULLSHADOW;
+ else
+ *color = sprite_colorbase | (c & 0x1f);
+
+ if (oinprion & 0xf0)
+ *priority = cbparam; // use PCU2 internal priority
+ else
+ *priority = c & 0xf0; // use color implied priority
+}
+
+
+
+static TILE_GET_INFO( get_gai_936_tile_info )
+{
+ int tileno, colour;
+ UINT8 *ROM = memory_region(REGION_GFX4);
+ UINT8 *dat1 = ROM, *dat2 = ROM + 0x20000, *dat3 = ROM + 0x60000;
+
+ tileno = dat3[tile_index] | ((dat2[tile_index]&0x3f)<<8);
+
+ if (tile_index & 1)
+ colour = (dat1[tile_index>>1]&0xf);
+ else
+ colour = ((dat1[tile_index>>1]>>4)&0xf);
+
+ if (dat2[tile_index] & 0x80) colour |= 0x10;
+
+ colour |= sub1_colorbase << 4;
+
+ SET_TILE_INFO(0, tileno, colour, 0);
+}
+
+VIDEO_START(gaiapols)
+{
+ K055555_vh_start();
+ K054338_vh_start();
+
+ gametype = 0;
+
+ mystwarr_save_orig_tiles();
+
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_5, 0, NULL, game4bpp_tile_callback, 0);
+
+ mystwarr_rest_orig_tiles();
+
+ K055673_vh_start(machine, REGION_GFX2, 1, -61, -22, gaiapols_sprite_callback); // stage2 brick walls
+
+ konamigx_mixer_init(0);
+
+ K056832_set_LayerOffset(0, -2+2-1, 0-1);
+ K056832_set_LayerOffset(1, 0+2, 0);
+ K056832_set_LayerOffset(2, 2+2, 0);
+ K056832_set_LayerOffset(3, 3+2, 0);
+
+ K053936_wraparound_enable(0, 1);
+ K053936GP_set_offset(0, -10, 0); // floor tiles in demo loop2 (Elaine vs. boss)
+
+ ult_936_tilemap = tilemap_create(get_gai_936_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 512, 512);
+ tilemap_set_transparent_pen(ult_936_tilemap, 0);
+}
+
+static TILE_GET_INFO( get_ult_936_tile_info )
+{
+ int tileno, colour;
+ UINT8 *ROM = memory_region(REGION_GFX4);
+ UINT8 *dat1 = ROM, *dat2 = ROM + 0x40000;
+
+ tileno = dat2[tile_index] | ((dat1[tile_index]&0x1f)<<8);
+
+ colour = sub1_colorbase;
+
+ SET_TILE_INFO(0, tileno, colour, (dat1[tile_index]&0x40) ? TILE_FLIPX : 0);
+}
+
+VIDEO_START(dadandrn)
+{
+ K055555_vh_start();
+ K054338_vh_start();
+
+ gametype = 1;
+
+ mystwarr_save_orig_tiles();
+
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_5, 0, NULL, game5bpp_tile_callback, 0);
+
+ mystwarr_rest_orig_tiles();
+
+ K055673_vh_start(machine, REGION_GFX2, 0, -42, -22, gaiapols_sprite_callback);
+
+ konamigx_mixer_init(0);
+
+ konamigx_mixer_primode(1);
+
+ K056832_set_LayerOffset(0, -2+4, 0);
+ K056832_set_LayerOffset(1, 0+4, 0);
+ K056832_set_LayerOffset(2, 2+4, 0);
+ K056832_set_LayerOffset(3, 3+4, 0);
+
+ K053936_wraparound_enable(0, 1);
+ K053936GP_set_offset(0, -8, 0); // Brainy's laser
+
+ ult_936_tilemap = tilemap_create(get_ult_936_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 512, 512);
+ tilemap_set_transparent_pen(ult_936_tilemap, 0);
+}
+
+VIDEO_START(mystwarr)
+{
+ K055555_vh_start();
+ K054338_vh_start();
+
+ gametype = 0;
+
+ mystwarr_save_orig_tiles();
+
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_5, 0, NULL, mystwarr_tile_callback, 0);
+
+ mystwarr_rest_orig_tiles();
+
+ K055673_vh_start(machine, REGION_GFX2, 0, -48, -24, mystwarr_sprite_callback);
+
+ konamigx_mixer_init(0);
+
+ K056832_set_LayerOffset(0, -2-3, 0);
+ K056832_set_LayerOffset(1, 0-3, 0);
+ K056832_set_LayerOffset(2, 2-3, 0);
+ K056832_set_LayerOffset(3, 3-3, 0);
+
+ cbparam = 0;
+}
+
+VIDEO_START(metamrph)
+{
+ int rgn_250 = REGION_GFX3;
+
+ gametype = 0;
+
+ K055555_vh_start();
+ K054338_vh_start();
+ K053250_vh_start(1, &rgn_250);
+
+ mystwarr_save_orig_tiles();
+
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_5, 0, NULL, game4bpp_tile_callback, 0);
+
+ mystwarr_rest_orig_tiles();
+
+ K055673_vh_start(machine, REGION_GFX2, 1, -51, -22, metamrph_sprite_callback);
+
+ konamigx_mixer_init(0);
+
+ // other reference, floor at first boss
+ K056832_set_LayerOffset(0, -2+4, 0); // text
+ K056832_set_LayerOffset(1, 0+4, 0); // attract sea
+ K056832_set_LayerOffset(2, 2+4, 0); // attract red monster in background of sea
+ K056832_set_LayerOffset(3, 3+4, 0); // attract sky background to sea
+
+ K053250_set_LayerOffset(0, -7, 0);
+}
+
+VIDEO_START(viostorm)
+{
+ gametype = 0;
+
+ K055555_vh_start();
+ K054338_vh_start();
+
+ mystwarr_save_orig_tiles();
+
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_5, 0, NULL, game4bpp_tile_callback, 0);
+
+ mystwarr_rest_orig_tiles();
+
+ K055673_vh_start(machine, REGION_GFX2, 1, -62, -23, metamrph_sprite_callback);
+
+ konamigx_mixer_init(0);
+
+ K056832_set_LayerOffset(0, -2+1, 0);
+ K056832_set_LayerOffset(1, 0+1, 0);
+ K056832_set_LayerOffset(2, 2+1, 0);
+ K056832_set_LayerOffset(3, 3+1, 0);
+}
+
+VIDEO_START(martchmp)
+{
+ gametype = 0;
+
+ K055555_vh_start();
+ K054338_vh_start();
+
+ mystwarr_save_orig_tiles();
+
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_5, 0, NULL, game5bpp_tile_callback, 0);
+
+ mystwarr_rest_orig_tiles();
+
+ K055673_vh_start(machine, REGION_GFX2, 0, -58, -23, martchmp_sprite_callback);
+
+ konamigx_mixer_init(0);
+
+ K056832_set_LayerOffset(0, -2-4, 0);
+ K056832_set_LayerOffset(1, 0-4, 0);
+ K056832_set_LayerOffset(2, 2-4, 0);
+ K056832_set_LayerOffset(3, 3-4, 0);
+
+ K054338_invert_alpha(0);
+}
+
+
+
+VIDEO_UPDATE(mystwarr)
+{
+ int i, old, blendmode=0;
+
+ if (cbparam<0) cbparam=0; else if (cbparam>=32) blendmode=(1<<16|GXMIX_BLEND_FORCE)<<2; //* water hack (TEMPORARY)
+
+ for (i = 0; i < 4; i++)
+ {
+ old = layer_colorbase[i];
+ layer_colorbase[i] = K055555_get_palette_index(i)<<4;
+ if( old != layer_colorbase[i] ) K056832_mark_plane_dirty(i);
+ }
+
+ sprite_colorbase = K055555_get_palette_index(4)<<5;
+
+ konamigx_mixer(machine, bitmap, cliprect, 0, 0, 0, 0, blendmode);
+ return 0;
+}
+
+VIDEO_UPDATE(metamrph)
+{
+ int i, old;
+
+ for (i = 0; i < 4; i++)
+ {
+ old = layer_colorbase[i];
+ layer_colorbase[i] = K055555_get_palette_index(i)<<4;
+ if (old != layer_colorbase[i]) K056832_mark_plane_dirty(i);
+ }
+
+ sprite_colorbase = K055555_get_palette_index(4)<<4;
+
+ konamigx_mixer(machine, bitmap, cliprect, 0, GXSUB_K053250 | GXSUB_4BPP, 0, 0, 0);
+ return 0;
+}
+
+VIDEO_UPDATE(martchmp)
+{
+ int i, old, blendmode;
+
+ for (i = 0; i < 4; i++)
+ {
+ old = layer_colorbase[i];
+ layer_colorbase[i] = K055555_get_palette_index(i)<<4;
+ if (old != layer_colorbase[i]) K056832_mark_plane_dirty(i);
+ }
+
+ sprite_colorbase = K055555_get_palette_index(4)<<5;
+
+ cbparam = K055555_read_register(K55_PRIINP_8);
+ oinprion = K055555_read_register(K55_OINPRI_ON);
+
+ // not quite right
+ blendmode = (oinprion==0xef && K054338_read_register(K338_REG_PBLEND)) ? ((1<<16|GXMIX_BLEND_FORCE)<<2) : 0;
+
+ konamigx_mixer(machine, bitmap, cliprect, 0, 0, 0, 0, blendmode);
+ return 0;
+}
+
+
+
+WRITE16_HANDLER(ddd_053936_enable_w)
+{
+ if (ACCESSING_MSB)
+ {
+ roz_enable = data & 0x0100;
+ roz_rombank = (data & 0xc000)>>14;
+ }
+}
+
+WRITE16_HANDLER(ddd_053936_clip_w)
+{
+ static UINT16 clip;
+ int old, clip_x, clip_y, size_x, size_y;
+ int minx, maxx, miny, maxy;
+
+ if (offset == 1)
+ {
+ if (ACCESSING_MSB) K053936GP_clip_enable(0, data & 0x0100);
+ }
+ else
+ {
+ old = clip;
+ COMBINE_DATA(&clip);
+ if (clip != old)
+ {
+ clip_x = (clip & 0x003f) >> 0;
+ clip_y = (clip & 0x0fc0) >> 6;
+ size_x = (clip & 0x3000) >> 12;
+ size_y = (clip & 0xc000) >> 14;
+
+ switch (size_x)
+ {
+ case 0x3: size_x = 1; break;
+ case 0x2: size_x = 2; break;
+ default: size_x = 4; break;
+ }
+
+ switch (size_y)
+ {
+ case 0x3: size_y = 1; break;
+ case 0x2: size_y = 2; break;
+ default: size_y = 4; break;
+ }
+
+ minx = clip_x << 7;
+ maxx = ((clip_x + size_x) << 7) - 1;
+ miny = clip_y << 7;
+ maxy = ((clip_y + size_y) << 7) - 1;
+
+ K053936GP_set_cliprect(0, minx, maxx, miny, maxy);
+ }
+ }
+}
+
+// reference: 223e5c in gaiapolis (ROMs 34j and 36m)
+READ16_HANDLER(gai_053936_tilerom_0_r)
+{
+ UINT8 *ROM1 = (UINT8 *)memory_region(REGION_GFX4);
+ UINT8 *ROM2 = (UINT8 *)memory_region(REGION_GFX4);
+
+ ROM1 += 0x20000;
+ ROM2 += 0x20000+0x40000;
+
+ return ((ROM1[offset]<<8) | ROM2[offset]);
+}
+
+READ16_HANDLER(ddd_053936_tilerom_0_r)
+{
+ UINT8 *ROM1 = (UINT8 *)memory_region(REGION_GFX4);
+ UINT8 *ROM2 = (UINT8 *)memory_region(REGION_GFX4);
+
+ ROM2 += 0x40000;
+
+ return ((ROM1[offset]<<8) | ROM2[offset]);
+}
+
+// reference: 223e1a in gaiapolis (ROM 36j)
+READ16_HANDLER(ddd_053936_tilerom_1_r)
+{
+ UINT8 *ROM = (UINT8 *)memory_region(REGION_GFX4);
+
+ return ROM[offset/2];
+}
+
+// reference: 223db0 in gaiapolis (ROMs 32n, 29n, 26n)
+READ16_HANDLER(gai_053936_tilerom_2_r)
+{
+ UINT8 *ROM = (UINT8 *)memory_region(REGION_GFX3);
+
+ offset += (roz_rombank * 0x100000);
+
+ return ROM[offset/2]<<8;
+}
+
+READ16_HANDLER(ddd_053936_tilerom_2_r)
+{
+ UINT8 *ROM = (UINT8 *)memory_region(REGION_GFX3);
+
+ offset += (roz_rombank * 0x100000);
+
+ return ROM[offset]<<8;
+}
+
+VIDEO_UPDATE(dadandrn) /* and gaiapols */
+{
+ int i, newbase, dirty, rozmode;
+
+ if (gametype == 0)
+ {
+ sprite_colorbase = (K055555_get_palette_index(4)<<4)&0x7f;
+ rozmode = GXSUB_4BPP;
+ }
+ else
+ {
+ sprite_colorbase = (K055555_get_palette_index(4)<<3)&0x7f;
+ rozmode = GXSUB_8BPP;
+ }
+
+ if (K056832_get_LayerAssociation())
+ {
+ for (i=0; i<4; i++)
+ {
+ newbase = K055555_get_palette_index(i)<<4;
+ if (layer_colorbase[i] != newbase)
+ {
+ layer_colorbase[i] = newbase;
+ K056832_mark_plane_dirty(i);
+ }
+ }
+ }
+ else
+ {
+ for (dirty=0, i=0; i<4; i++)
+ {
+ newbase = K055555_get_palette_index(i)<<4;
+ if (layer_colorbase[i] != newbase)
+ {
+ layer_colorbase[i] = newbase;
+ dirty = 1;
+ }
+ }
+ if (dirty) K056832_MarkAllTilemapsDirty();
+
+ }
+
+ last_psac_colorbase = sub1_colorbase;
+ sub1_colorbase = K055555_get_palette_index(5);
+
+ if (last_psac_colorbase != sub1_colorbase)
+ {
+ tilemap_mark_all_tiles_dirty(ult_936_tilemap);
+
+ #if MW_VERBOSE
+ popmessage("K053936: PSAC colorbase changed");
+ #endif
+ }
+
+ konamigx_mixer(machine, bitmap, cliprect, (roz_enable) ? ult_936_tilemap : 0, rozmode, 0, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/n64.c b/src/mame/video/n64.c
new file mode 100644
index 00000000000..31e54dbc5e5
--- /dev/null
+++ b/src/mame/video/n64.c
@@ -0,0 +1,3479 @@
+/*
+ Nintendo 64 Video Hardware
+*/
+
+#include "driver.h"
+#include "includes/n64.h"
+
+#define LOG_RDP_EXECUTION 0
+
+#if LOG_RDP_EXECUTION
+static FILE *rdp_exec;
+#endif
+
+/* defined in systems/n64.c */
+extern UINT32 *rdram;
+extern UINT32 *rsp_imem;
+extern UINT32 *rsp_dmem;
+extern void dp_full_sync(void);
+
+extern UINT32 vi_origin;
+extern UINT32 vi_width;
+extern UINT32 vi_control;
+
+extern UINT32 dp_start;
+extern UINT32 dp_end;
+extern UINT32 dp_current;
+extern UINT32 dp_status;
+
+static UINT32 rdp_cmd_data[0x1000];
+static int rdp_cmd_ptr = 0;
+static int rdp_cmd_cur = 0;
+
+typedef struct
+{
+ int lx, rx;
+ int s, ds;
+ int t, dt;
+ int w, dw;
+ int r, dr;
+ int g, dg;
+ int b, db;
+ int a, da;
+ int z, dz;
+} SPAN;
+
+static SPAN span[1024];
+
+/*****************************************************************************/
+
+#define BYTE_ADDR_XOR BYTE4_XOR_BE(0)
+#define WORD_ADDR_XOR (WORD_XOR_BE(0) >> 1)
+
+typedef struct
+{
+ UINT8 r, g, b, a;
+} COLOR;
+
+typedef struct
+{
+ UINT16 xl, yl, xh, yh; // 10.2 fixed-point
+} RECTANGLE;
+
+typedef struct
+{
+ int tilenum;
+ UINT16 xl, yl, xh, yh; // 10.2 fixed-point
+ INT16 s, t; // 10.5 fixed-point
+ INT16 dsdx, dtdy; // 5.10 fixed-point
+} TEX_RECTANGLE;
+
+typedef struct
+{
+ int format, size;
+ UINT32 line;
+ UINT32 tmem;
+ int palette;
+ // TODO: clamp & mirror parameters
+ int ct, mt, cs, ms;
+ int mask_t, shift_t, mask_s, shift_s;
+
+ UINT16 sl, tl, sh, th; // 10.2 fixed-point
+} TILE;
+
+typedef struct
+{
+ int sub_a_rgb0;
+ int sub_b_rgb0;
+ int mul_rgb0;
+ int add_rgb0;
+ int sub_a_a0;
+ int sub_b_a0;
+ int mul_a0;
+ int add_a0;
+
+ int sub_a_rgb1;
+ int sub_b_rgb1;
+ int mul_rgb1;
+ int add_rgb1;
+ int sub_a_a1;
+ int sub_b_a1;
+ int mul_a1;
+ int add_a1;
+} COMBINE_MODES;
+
+typedef struct
+{
+ int cycle_type;
+ int persp_tex_en;
+ int detail_tex_en;
+ int sharpen_tex_en;
+ int tex_lod_en;
+ int en_tlut;
+ int tlut_type;
+ int sample_type;
+ int mid_texel;
+ int bi_lerp0;
+ int bi_lerp1;
+ int convert_one;
+ int key_en;
+ int rgb_dither_sel;
+ int alpha_dither_sel;
+ int blend_m1a_0;
+ int blend_m1a_1;
+ int blend_m1b_0;
+ int blend_m1b_1;
+ int blend_m2a_0;
+ int blend_m2a_1;
+ int blend_m2b_0;
+ int blend_m2b_1;
+ int force_blend;
+ int alpha_cvg_select;
+ int cvg_times_alpha;
+ int z_mode;
+ int cvg_dest;
+ int color_on_cvg;
+ int image_read_en;
+ int z_update_en;
+ int z_compare_en;
+ int antialias_en;
+ int z_source_sel;
+ int dither_alpha_en;
+ int alpha_compare_en;
+} OTHER_MODES;
+
+/*****************************************************************************/
+
+#define PIXEL_SIZE_4BIT 0
+#define PIXEL_SIZE_8BIT 1
+#define PIXEL_SIZE_16BIT 2
+#define PIXEL_SIZE_32BIT 3
+
+#define CYCLE_TYPE_1 0
+#define CYCLE_TYPE_2 1
+#define CYCLE_TYPE_COPY 2
+#define CYCLE_TYPE_FILL 3
+
+static COMBINE_MODES combine;
+static OTHER_MODES other_modes;
+
+static COLOR blend_color;
+static COLOR prim_color;
+static COLOR env_color;
+static COLOR fog_color;
+static COLOR combined_color;
+static COLOR texel0_color;
+static COLOR texel1_color;
+static COLOR shade_color;
+
+static COLOR one_color = { 0xff, 0xff, 0xff, 0xff };
+static COLOR zero_color = { 0x00, 0x00, 0x00, 0x00 };
+
+// combiner inputs
+static UINT8 *combiner_rgbsub_a_r[2];
+static UINT8 *combiner_rgbsub_a_g[2];
+static UINT8 *combiner_rgbsub_a_b[2];
+static UINT8 *combiner_rgbsub_b_r[2];
+static UINT8 *combiner_rgbsub_b_g[2];
+static UINT8 *combiner_rgbsub_b_b[2];
+static UINT8 *combiner_rgbmul_r[2];
+static UINT8 *combiner_rgbmul_g[2];
+static UINT8 *combiner_rgbmul_b[2];
+static UINT8 *combiner_rgbadd_r[2];
+static UINT8 *combiner_rgbadd_g[2];
+static UINT8 *combiner_rgbadd_b[2];
+
+static UINT8 *combiner_alphasub_a[2];
+static UINT8 *combiner_alphasub_b[2];
+static UINT8 *combiner_alphamul[2];
+static UINT8 *combiner_alphaadd[2];
+
+// blender input
+static UINT8 *blender1a_r[2];
+static UINT8 *blender1a_g[2];
+static UINT8 *blender1a_b[2];
+static UINT8 *blender1b_a[2];
+static UINT8 *blender2a_r[2];
+static UINT8 *blender2a_g[2];
+static UINT8 *blender2a_b[2];
+static UINT8 *blender2b_a[2];
+
+
+static COLOR pixel_color;
+static COLOR inv_pixel_color;
+static COLOR blended_pixel_color;
+static COLOR memory_color;
+
+
+
+static UINT32 fill_color; // packed 16-bit or 32-bit, depending on framebuffer format
+
+static UINT16 primitive_z;
+static UINT16 primitive_delta_z;
+
+static int fb_format;
+static int fb_size;
+int fb_width;
+static UINT32 fb_address;
+
+static UINT32 zb_address;
+
+static int ti_format;
+static int ti_size;
+static int ti_width;
+static UINT32 ti_address;
+
+static TILE tile[8];
+
+static RECTANGLE clip;
+
+static UINT8 *texture_cache;
+static UINT32 tlut[256];
+
+#define CLAMP(S, T) \
+do \
+{ \
+ if (clamp_s) \
+ { \
+ if (S < (tsl >> 2)) S = (tsl >> 2); \
+ if (S > (tsh >> 2)) S = (tsh >> 2); \
+ } \
+ if (mirror_s) \
+ { \
+ if (S < (tsl >> 2)) S = abs(S - (tsl >> 2)); \
+ if (S > (tsh >> 2)) S = abs(S - (tsh >> 2)); \
+ } \
+ if (mask_s != 0) \
+ { \
+ S &= (((UINT32)(0xffffffff) >> (32-mask_s))); \
+ } \
+ if (clamp_t) \
+ { \
+ if (T < (ttl >> 2)) T = (ttl >> 2); \
+ if (T > (tth >> 2)) T = (tth >> 2); \
+ } \
+ if (mirror_t) \
+ { \
+ if (T < (ttl >> 2)) T = abs(T - (ttl >> 2)); \
+ if (T > (tth >> 2)) T = abs(T - (tth >> 2)); \
+ } \
+ if (mask_t != 0) \
+ { \
+ T &= (((UINT32)(0xffffffff) >> (32-mask_t))); \
+ } \
+} \
+while (0)
+
+/*****************************************************************************/
+
+
+
+VIDEO_START(n64)
+{
+#if LOG_RDP_EXECUTION
+ rdp_exec = fopen("rdp_execute.txt", "wt");
+#endif
+
+ texture_cache = auto_malloc(0x100000);
+
+ combiner_rgbsub_a_r[0] = combiner_rgbsub_a_r[1] = &one_color.r;
+ combiner_rgbsub_a_g[0] = combiner_rgbsub_a_g[1] = &one_color.g;
+ combiner_rgbsub_a_b[0] = combiner_rgbsub_a_b[1] = &one_color.b;
+ combiner_rgbsub_b_r[0] = combiner_rgbsub_b_r[1] = &one_color.r;
+ combiner_rgbsub_b_g[0] = combiner_rgbsub_b_g[1] = &one_color.g;
+ combiner_rgbsub_b_b[0] = combiner_rgbsub_b_b[1] = &one_color.b;
+ combiner_rgbmul_r[0] = combiner_rgbmul_r[1] = &one_color.r;
+ combiner_rgbmul_g[0] = combiner_rgbmul_g[1] = &one_color.g;
+ combiner_rgbmul_b[0] = combiner_rgbmul_b[1] = &one_color.b;
+ combiner_rgbadd_r[0] = combiner_rgbadd_r[1] = &one_color.r;
+ combiner_rgbadd_g[0] = combiner_rgbadd_g[1] = &one_color.g;
+ combiner_rgbadd_b[0] = combiner_rgbadd_b[1] = &one_color.b;
+
+ combiner_alphasub_a[0] = combiner_alphasub_a[1] = &one_color.a;
+ combiner_alphasub_b[0] = combiner_alphasub_b[1] = &one_color.a;
+ combiner_alphamul[0] = combiner_alphamul[1] = &one_color.a;
+ combiner_alphaadd[0] = combiner_alphaadd[1] = &one_color.a;
+
+ blender1a_r[0] = blender1a_r[1] = &pixel_color.r;
+ blender1a_g[0] = blender1a_g[1] = &pixel_color.r;
+ blender1a_b[0] = blender1a_b[1] = &pixel_color.r;
+ blender1b_a[0] = blender1b_a[1] = &pixel_color.r;
+ blender2a_r[0] = blender2a_r[1] = &pixel_color.r;
+ blender2a_g[0] = blender2a_g[1] = &pixel_color.r;
+ blender2a_b[0] = blender2a_b[1] = &pixel_color.r;
+ blender2b_a[0] = blender2b_a[1] = &pixel_color.r;
+}
+
+VIDEO_UPDATE(n64)
+{
+ int i, j;
+ int height = (vi_control & 0x40) ? 479 : 239;
+
+ switch (vi_control & 0x3)
+ {
+ case 0: // blank/no signal
+ {
+ break;
+ }
+
+ case 2: // RGBA5551
+ {
+ UINT16 *frame_buffer = (UINT16*)&rdram[vi_origin / 4];
+ if (frame_buffer)
+ {
+ for (j=0; j <height; j++)
+ {
+ UINT32 *d = BITMAP_ADDR32(bitmap, j, 0);
+ for (i=0; i < fb_width; i++)
+ {
+ UINT16 pix = *frame_buffer++;
+ int r = ((pix >> 11) & 0x1f) << 3;
+ int g = ((pix >> 6) & 0x1f) << 3;
+ int b = ((pix >> 1) & 0x1f) << 3;
+ d[i^1] = (r << 16) | (g << 8) | b;
+ }
+ }
+ }
+ break;
+ }
+
+ case 3: // RGBA8888
+ {
+ UINT32 *frame_buffer = (UINT32*)&rdram[vi_origin / 4];
+ if (frame_buffer)
+ {
+ for (j=0; j < height; j++)
+ {
+ UINT32 *d = BITMAP_ADDR32(bitmap, j, 0);
+ for (i=0; i < fb_width; i++)
+ {
+ UINT32 pix = *frame_buffer++;
+ *d++ = pix & 0xffffff;
+ }
+ }
+ }
+ break;
+ }
+
+ default: fatalerror("Unknown framebuffer format %d\n", vi_control & 0x3);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+
+INLINE void SET_SUBA_RGB_INPUT(UINT8 **input_r, UINT8 **input_g, UINT8 **input_b, int code)
+{
+ switch (code & 0xf)
+ {
+ case 0: *input_r = &combined_color.r; *input_g = &combined_color.g; *input_b = &combined_color.b; break;
+ case 1: *input_r = &texel0_color.r; *input_g = &texel0_color.g; *input_b = &texel0_color.b; break;
+ case 2: *input_r = &texel1_color.r; *input_g = &texel1_color.g; *input_b = &texel1_color.b; break;
+ case 3: *input_r = &prim_color.r; *input_g = &prim_color.g; *input_b = &prim_color.b; break;
+ case 4: *input_r = &shade_color.r; *input_g = &shade_color.g; *input_b = &shade_color.b; break;
+ case 5: *input_r = &env_color.r; *input_g = &env_color.g; *input_b = &env_color.b; break;
+ case 6: *input_r = &one_color.r; *input_g = &one_color.g; *input_b = &one_color.b; break;
+ case 7: break; //TODO fatalerror("SET_SUBA_RGB_INPUT: noise\n"); break;
+ case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15:
+ {
+ *input_r = &zero_color.r; *input_g = &zero_color.g; *input_b = &zero_color.b; break;
+ }
+ }
+}
+
+INLINE void SET_SUBB_RGB_INPUT(UINT8 **input_r, UINT8 **input_g, UINT8 **input_b, int code)
+{
+ switch (code & 0xf)
+ {
+ case 0: *input_r = &combined_color.r; *input_g = &combined_color.g; *input_b = &combined_color.b; break;
+ case 1: *input_r = &texel0_color.r; *input_g = &texel0_color.g; *input_b = &texel0_color.b; break;
+ case 2: *input_r = &texel1_color.r; *input_g = &texel1_color.g; *input_b = &texel1_color.b; break;
+ case 3: *input_r = &prim_color.r; *input_g = &prim_color.g; *input_b = &prim_color.b; break;
+ case 4: *input_r = &shade_color.r; *input_g = &shade_color.g; *input_b = &shade_color.b; break;
+ case 5: *input_r = &env_color.r; *input_g = &env_color.g; *input_b = &env_color.b; break;
+ case 6: fatalerror("SET_SUBB_RGB_INPUT: key_center\n"); break;
+ case 7: fatalerror("SET_SUBB_RGB_INPUT: convert_k4\n"); break;
+ case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15:
+ {
+ *input_r = &zero_color.r; *input_g = &zero_color.g; *input_b = &zero_color.b; break;
+ }
+ }
+}
+
+INLINE void SET_MUL_RGB_INPUT(UINT8 **input_r, UINT8 **input_g, UINT8 **input_b, int code)
+{
+ switch (code & 0x1f)
+ {
+ case 0: *input_r = &combined_color.r; *input_g = &combined_color.g; *input_b = &combined_color.b; break;
+ case 1: *input_r = &texel0_color.r; *input_g = &texel0_color.g; *input_b = &texel0_color.b; break;
+ case 2: *input_r = &texel1_color.r; *input_g = &texel1_color.g; *input_b = &texel1_color.b; break;
+ case 3: *input_r = &prim_color.r; *input_g = &prim_color.g; *input_b = &prim_color.b; break;
+ case 4: *input_r = &shade_color.r; *input_g = &shade_color.g; *input_b = &shade_color.b; break;
+ case 5: *input_r = &env_color.r; *input_g = &env_color.g; *input_b = &env_color.b; break;
+ case 6: fatalerror("SET_MUL_RGB_INPUT: key scale\n"); break;
+ case 7: *input_r = &combined_color.a; *input_g = &combined_color.a; *input_b = &combined_color.a; break;
+ case 8: *input_r = &texel0_color.a; *input_g = &texel0_color.a; *input_b = &texel0_color.a; break;
+ case 9: *input_r = &texel1_color.a; *input_g = &texel1_color.a; *input_b = &texel1_color.a; break;
+ case 10: *input_r = &prim_color.a; *input_g = &prim_color.a; *input_b = &prim_color.a; break;
+ case 11: *input_r = &shade_color.a; *input_g = &shade_color.a; *input_b = &shade_color.a; break;
+ case 12: *input_r = &env_color.a; *input_g = &env_color.a; *input_b = &env_color.a; break;
+ case 13: break;//TODO fatalerror("SET_MUL_RGB_INPUT: lod fraction\n"); break;
+ case 14: break;//TODO fatalerror("SET_MUL_RGB_INPUT: primitive lod fraction\n"); break;
+ case 15: break;//TODO fatalerror("SET_MUL_RGB_INPUT: convert k5\n"); break;
+ case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23:
+ case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31:
+ {
+ *input_r = &zero_color.r; *input_g = &zero_color.g; *input_b = &zero_color.b; break;
+ }
+ }
+}
+
+INLINE void SET_ADD_RGB_INPUT(UINT8 **input_r, UINT8 **input_g, UINT8 **input_b, int code)
+{
+ switch (code & 0x7)
+ {
+ case 0: *input_r = &combined_color.r; *input_g = &combined_color.g; *input_b = &combined_color.b; break;
+ case 1: *input_r = &texel0_color.r; *input_g = &texel0_color.g; *input_b = &texel0_color.b; break;
+ case 2: *input_r = &texel1_color.r; *input_g = &texel1_color.g; *input_b = &texel1_color.b; break;
+ case 3: *input_r = &prim_color.r; *input_g = &prim_color.g; *input_b = &prim_color.b; break;
+ case 4: *input_r = &shade_color.r; *input_g = &shade_color.g; *input_b = &shade_color.b; break;
+ case 5: *input_r = &env_color.r; *input_g = &env_color.g; *input_b = &env_color.b; break;
+ case 6: *input_r = &one_color.r; *input_g = &one_color.g; *input_b = &one_color.b; break;
+ case 7: *input_r = &zero_color.r; *input_g = &zero_color.g; *input_b = &zero_color.b; break;
+ }
+}
+
+INLINE void SET_SUB_ALPHA_INPUT(UINT8 **input, int code)
+{
+ switch (code & 0x7)
+ {
+ case 0: *input = &combined_color.a; break;
+ case 1: *input = &texel0_color.a; break;
+ case 2: *input = &texel1_color.a; break;
+ case 3: *input = &prim_color.a; break;
+ case 4: *input = &shade_color.a; break;
+ case 5: *input = &env_color.a; break;
+ case 6: *input = &one_color.a; break;
+ case 7: *input = &zero_color.a; break;
+ }
+}
+
+INLINE void SET_MUL_ALPHA_INPUT(UINT8 **input, int code)
+{
+ switch (code & 0x7)
+ {
+ case 0: break;//TODO fatalerror("SET_MUL_ALPHA_INPUT: lod fraction\n"); break;
+ case 1: *input = &texel0_color.a; break;
+ case 2: *input = &texel1_color.a; break;
+ case 3: *input = &prim_color.a; break;
+ case 4: *input = &shade_color.a; break;
+ case 5: *input = &env_color.a; break;
+ case 6: break;//TODO fatalerror("SET_MUL_ALPHA_INPUT: primitive lod fraction\n"); break;
+ case 7: *input = &zero_color.a; break;
+ }
+}
+
+
+
+INLINE COLOR COLOR_COMBINER(int cycle)
+{
+ COLOR c;
+ UINT32 r, g, b, a;
+
+ r = (((int)((UINT8)(*combiner_rgbsub_a_r[cycle]) - (UINT8)(*combiner_rgbsub_b_r[cycle])) *
+ *combiner_rgbmul_r[cycle]) >> 8) + *combiner_rgbadd_r[cycle];
+
+ g = (((int)((UINT8)(*combiner_rgbsub_a_g[cycle]) - (UINT8)(*combiner_rgbsub_b_g[cycle])) *
+ *combiner_rgbmul_g[cycle]) >> 8) + *combiner_rgbadd_g[cycle];
+
+ b = (((int)((UINT8)(*combiner_rgbsub_a_b[cycle]) - (UINT8)(*combiner_rgbsub_b_b[cycle])) *
+ *combiner_rgbmul_b[cycle]) >> 8) + *combiner_rgbadd_b[cycle];
+
+ a = (((int)((UINT8)(*combiner_alphasub_a[cycle]) - (UINT8)(*combiner_alphasub_b[cycle])) *
+ *combiner_alphamul[cycle]) >> 8) + *combiner_alphaadd[cycle];
+
+ if (r > 255) r = 255;
+ if (g > 255) g = 255;
+ if (b > 255) b = 255;
+ if (a > 255) a = 255;
+
+ c.r = r; c.g = g; c.b = b; c.a = a;
+ return c;
+}
+
+
+
+INLINE void SET_BLENDER_INPUT(int cycle, int which, UINT8 **input_r, UINT8 **input_g, UINT8 **input_b, UINT8 **input_a, int a, int b)
+{
+ switch (a & 0x3)
+ {
+ case 0:
+ {
+ if (cycle == 0)
+ {
+ *input_r = &pixel_color.r;
+ *input_g = &pixel_color.g;
+ *input_b = &pixel_color.b;
+ }
+ else
+ {
+ *input_r = &blended_pixel_color.r;
+ *input_g = &blended_pixel_color.g;
+ *input_b = &blended_pixel_color.b;
+ }
+ break;
+ }
+
+ case 1:
+ {
+ //fatalerror("SET_BLENDER_INPUT: cycle %d, input A: memory color\n", cycle);
+ // TODO
+ *input_r = &memory_color.r;
+ *input_g = &memory_color.g;
+ *input_b = &memory_color.b;
+ break;
+ }
+
+ case 2:
+ {
+ *input_r = &blend_color.r; *input_g = &blend_color.g; *input_b = &blend_color.b;
+ break;
+ }
+
+ case 3:
+ {
+ *input_r = &fog_color.r; *input_g = &fog_color.g; *input_b = &fog_color.b;
+ break;
+ }
+ }
+
+ if (which == 0)
+ {
+ switch (b & 0x3)
+ {
+ case 0: *input_a = &pixel_color.a; break;
+ case 1: *input_a = &one_color.a; break;
+ case 2: *input_a = &shade_color.a; break;
+ case 3: *input_a = &zero_color.a; break;
+ }
+ }
+ else
+ {
+ switch (b & 0x3)
+ {
+ case 0: *input_a = &inv_pixel_color.a; break;
+ case 1: *input_a = &memory_color.a; break;
+ case 2: *input_a = &one_color.a; break;
+ case 3: *input_a = &zero_color.a; break;
+ }
+ }
+}
+
+static const UINT8 dither_matrix_4x4[16] =
+{
+ 0, 8, 2, 10,
+ 12, 4, 14, 6,
+ 3, 11, 1, 9,
+ 15, 7, 13, 5
+};
+
+#define DITHER_RB(val,dith) ((((val) << 1) - ((val) >> 4) + ((val) >> 7) + (dith)) >> 1)
+#define DITHER_G(val,dith) ((((val) << 2) - ((val) >> 4) + ((val) >> 6) + (dith)) >> 2)
+
+INLINE void BLENDER1_16(UINT16 *fb, COLOR c, int dith)
+{
+ int r, g, b;
+
+ pixel_color.r = c.r; inv_pixel_color.r = 0xff - c.r;
+ pixel_color.g = c.g; inv_pixel_color.g = 0xff - c.g;
+ pixel_color.b = c.b; inv_pixel_color.b = 0xff - c.b;
+ pixel_color.a = c.a; inv_pixel_color.a = 0xff - c.a;
+
+
+
+ if (other_modes.image_read_en)
+ {
+ UINT16 mem = *fb;
+ memory_color.r = ((mem >> 11) & 0x1f) << 3;
+ memory_color.g = ((mem >> 6) & 0x1f) << 3;
+ memory_color.b = ((mem >> 1) & 0x1f) << 3;
+ memory_color.a = 0;
+ }
+
+ r = (((int)(*blender1a_r[0]) * (int)(*blender1b_a[0])) >> 8) +
+ (((int)(*blender2a_r[0]) * (int)(*blender2b_a[0])) >> 8);
+
+ g = (((int)(*blender1a_g[0]) * (int)(*blender1b_a[0])) >> 8) +
+ (((int)(*blender2a_g[0]) * (int)(*blender2b_a[0])) >> 8);
+
+ b = (((int)(*blender1a_b[0]) * (int)(*blender1b_a[0])) >> 8) +
+ (((int)(*blender2a_b[0]) * (int)(*blender2b_a[0])) >> 8);
+
+ //r = g = b = 0xff;
+
+ if (r > 255) r = 255;
+ if (g > 255) g = 255;
+ if (b > 255) b = 255;
+
+ if (other_modes.rgb_dither_sel != 3)
+ {
+ r = DITHER_RB(r, dith);
+ g = DITHER_G (g, dith);
+ b = DITHER_RB(b, dith);
+ }
+
+ if (c.a != 0)
+ {
+ *fb = ((r >> 3) << 11) | ((g >> 3) << 6) | ((b >> 3) << 1);
+ }
+}
+
+INLINE void BLENDER2_16(UINT16 *fb, COLOR c1, COLOR c2, int dith)
+{
+ int r, g, b;
+
+ pixel_color.r = c1.r; inv_pixel_color.r = 0xff - c1.r;
+ pixel_color.g = c1.g; inv_pixel_color.g = 0xff - c1.g;
+ pixel_color.b = c1.b; inv_pixel_color.b = 0xff - c1.b;
+ pixel_color.a = c1.a; inv_pixel_color.a = 0xff - c1.a;
+
+ if (other_modes.image_read_en)
+ {
+ UINT16 mem = *fb;
+ memory_color.r = ((mem >> 11) & 0x1f) << 3;
+ memory_color.g = ((mem >> 6) & 0x1f) << 3;
+ memory_color.b = ((mem >> 1) & 0x1f) << 3;
+ memory_color.a = 0;
+ }
+
+ r = (((int)(*blender1a_r[0]) * (int)(*blender1b_a[0])) >> 8) +
+ (((int)(*blender2a_r[0]) * (int)(*blender2b_a[0])) >> 8);
+
+ g = (((int)(*blender1a_g[0]) * (int)(*blender1b_a[0])) >> 8) +
+ (((int)(*blender2a_g[0]) * (int)(*blender2b_a[0])) >> 8);
+
+ b = (((int)(*blender1a_b[0]) * (int)(*blender1b_a[0])) >> 8) +
+ (((int)(*blender2a_b[0]) * (int)(*blender2b_a[0])) >> 8);
+
+ blended_pixel_color.r = r;
+ blended_pixel_color.g = g;
+ blended_pixel_color.b = b;
+
+ pixel_color.r = c2.r; inv_pixel_color.r = 0xff - c2.r;
+ pixel_color.g = c2.g; inv_pixel_color.g = 0xff - c2.g;
+ pixel_color.b = c2.b; inv_pixel_color.b = 0xff - c2.b;
+ pixel_color.a = c2.a; inv_pixel_color.a = 0xff - c2.a;
+
+ r = (((int)(*blender1a_r[1]) * (int)(*blender1b_a[1])) >> 8) +
+ (((int)(*blender2a_r[1]) * (int)(*blender2b_a[1])) >> 8);
+
+ g = (((int)(*blender1a_g[1]) * (int)(*blender1b_a[1])) >> 8) +
+ (((int)(*blender2a_g[1]) * (int)(*blender2b_a[1])) >> 8);
+
+ b = (((int)(*blender1a_b[1]) * (int)(*blender1b_a[1])) >> 8) +
+ (((int)(*blender2a_b[1]) * (int)(*blender2b_a[1])) >> 8);
+
+ r = c1.r;
+ g = c1.g;
+ b = c1.b;
+
+ if (r > 255) r = 255;
+ if (g > 255) g = 255;
+ if (b > 255) b = 255;
+
+ if (other_modes.rgb_dither_sel != 3)
+ {
+ r = DITHER_RB(r, dith);
+ g = DITHER_G (g, dith);
+ b = DITHER_RB(b, dith);
+ }
+
+ {
+ *fb = ((r >> 3) << 11) | ((g >> 3) << 6) | ((b >> 3) << 1);
+ }
+}
+
+/*****************************************************************************/
+
+static void fill_rectangle_16bit(RECTANGLE *rect)
+{
+ UINT16 *fb = (UINT16*)&rdram[(fb_address / 4)];
+ int index, i, j;
+ int x1 = rect->xh / 4;
+ int x2 = rect->xl / 4;
+ int y1 = rect->yh / 4;
+ int y2 = rect->yl / 4;
+ int clipx1, clipx2, clipy1, clipy2;
+
+ UINT16 fill_color1, fill_color2;
+ fill_color1 = (fill_color >> 16) & 0xffff;
+ fill_color2 = (fill_color >> 0) & 0xffff;
+
+ // TODO: clip
+ clipx1 = clip.xh / 4;
+ clipx2 = clip.xl / 4;
+ clipy1 = clip.yh / 4;
+ clipy2 = clip.yl / 4;
+
+ // clip
+ if (x1 < clipx1)
+ {
+ x1 = clipx1;
+ }
+ if (y1 < clipy1)
+ {
+ y1 = clipy1;
+ }
+ if (x2 >= clipx2)
+ {
+ x2 = clipx2-1;
+ }
+ if (y2 >= clipy2)
+ {
+ y2 = clipy2-1;
+ }
+
+ if (other_modes.cycle_type == CYCLE_TYPE_FILL)
+ {
+ for (j=y1; j <= y2; j++)
+ {
+ index = j * fb_width;
+ for (i=x1; i <= x2; i++)
+ {
+ fb[(index + i) ^ 1] = (i & 1) ? fill_color1 : fill_color2;
+ }
+ }
+ }
+ else if (other_modes.cycle_type == CYCLE_TYPE_1)
+ {
+ shade_color.r = prim_color.r;
+ shade_color.g = prim_color.g;
+ shade_color.b = prim_color.b;
+ shade_color.a = prim_color.a;
+
+ for (j=y1; j <= y2; j++)
+ {
+ index = j * fb_width;
+ for (i=x1; i <= x2; i++)
+ {
+ COLOR c = COLOR_COMBINER(0);
+
+ //BLENDER1_16(&fb[(index + i) ^ 1], c);
+ {
+ int dith = dither_matrix_4x4[(((j) & 3) << 2) + ((i^WORD_ADDR_XOR) & 3)];
+ BLENDER1_16(&fb[(index + i) ^ WORD_ADDR_XOR], c, dith);
+ }
+ }
+ }
+ }
+ else if (other_modes.cycle_type == CYCLE_TYPE_2)
+ {
+ shade_color.r = prim_color.r;
+ shade_color.g = prim_color.g;
+ shade_color.b = prim_color.b;
+ shade_color.a = prim_color.a;
+
+ for (j=y1; j <= y2; j++)
+ {
+ index = j * fb_width;
+ for (i=x1; i <= x2; i++)
+ {
+ COLOR c1 = COLOR_COMBINER(0);
+ COLOR c2 = COLOR_COMBINER(1);
+
+ //BLENDER1_16(&fb[(index + i) ^ 1], c);
+ {
+ int dith = dither_matrix_4x4[(((j) & 3) << 2) + ((i^WORD_ADDR_XOR) & 3)];
+ BLENDER2_16(&fb[(index + i) ^ WORD_ADDR_XOR], c1, c2, dith);
+ }
+ }
+ }
+ }
+ else
+ {
+ fatalerror("fill_rectangle_16bit: cycle type copy");
+ }
+}
+
+#define XOR_SWAP_BYTE 4
+#define XOR_SWAP_WORD 2
+#define XOR_SWAP_DWORD 1
+
+INLINE void FETCH_TEXEL(COLOR *color, int s, int t, UINT32 twidth, UINT32 tformat, UINT32 tsize, UINT32 tbase)
+{
+ if (t < 0) t = 0;
+ if (s < 0) s = 0;
+
+ switch (tformat)
+ {
+ case 0: // RGBA
+ {
+ switch (tsize)
+ {
+ case 0:
+ color->r = color->g = color->b = color->a = 0xff;
+ break;
+ case 1:
+ // FIXME?: Extreme-G 2 does this
+ color->r = color->g = color->b = color->a = 0xff;
+ break;
+ case PIXEL_SIZE_16BIT:
+ {
+ UINT16 *tc = (UINT16*)texture_cache;
+ int taddr = ((tbase/2) + ((t) * (twidth/2)) + (s)) ^ ((t & 1) ? XOR_SWAP_WORD : 0);
+ UINT16 c = tc[taddr ^ WORD_ADDR_XOR];
+
+ color->r = ((c >> 11) & 0x1f) << 3;
+ color->g = ((c >> 6) & 0x1f) << 3;
+ color->b = ((c >> 1) & 0x1f) << 3;
+ color->a = (c & 1) ? 0xff : 0;
+ break;
+ }
+ case PIXEL_SIZE_32BIT:
+ {
+ UINT32 *tc = (UINT32*)texture_cache;
+ int taddr = ((tbase/4) + ((t) * (twidth/2)) + (s)) ^ ((t & 1) ? XOR_SWAP_DWORD : 0);
+ UINT32 c = tc[taddr];
+
+ color->r = ((c >> 24) & 0xff);
+ color->g = ((c >> 16) & 0xff);
+ color->b = ((c >> 8) & 0xff);
+ color->a = ((c >> 0) & 0xff);
+ break;
+ }
+ default:
+ color->r = color->g = color->b = color->a = 0xff;
+ fatalerror("FETCH_TEXEL: unknown RGBA texture size %d\n", tsize);
+ break;
+ }
+ break;
+ }
+ case 2: // Color Index
+ {
+ switch (tsize)
+ {
+ case PIXEL_SIZE_4BIT:
+ {
+ UINT8 *tc = (UINT8*)texture_cache;
+ int taddr = (tbase + ((t) * twidth) + ((s) / 2)) ^ ((t & 1) ? XOR_SWAP_BYTE : 0);
+ UINT8 p = ((s) & 1) ? (tc[taddr ^ BYTE_ADDR_XOR] & 0xf) : (tc[taddr ^ BYTE_ADDR_XOR] >> 4);
+ UINT16 c = tlut[p ^ WORD_ADDR_XOR];
+
+ if (other_modes.tlut_type == 0)
+ {
+ color->r = ((c >> 11) & 0x1f) << 3;
+ color->g = ((c >> 6) & 0x1f) << 3;
+ color->b = ((c >> 1) & 0x1f) << 3;
+ color->a = (c & 1) ? 0xff : 0;
+ }
+ else
+ {
+ color->r = color->g = color->b = (c >> 8) & 0xff;
+ color->a = c & 0xff;
+ }
+ break;
+ }
+ case PIXEL_SIZE_8BIT:
+ {
+ UINT8 *tc = (UINT8*)texture_cache;
+ int taddr = (tbase + ((t) * twidth) + ((s))) ^ ((t & 1) ? XOR_SWAP_BYTE : 0);
+ UINT8 p = tc[taddr ^ BYTE_ADDR_XOR];
+ UINT16 c = tlut[p ^ WORD_ADDR_XOR];
+
+ if (other_modes.tlut_type == 0)
+ {
+ color->r = ((c >> 11) & 0x1f) << 3;
+ color->g = ((c >> 6) & 0x1f) << 3;
+ color->b = ((c >> 1) & 0x1f) << 3;
+ color->a = (c & 1) ? 0xff : 0;
+ }
+ else
+ {
+ color->r = color->g = color->b = (c >> 8) & 0xff;
+ color->a = c & 0xff;
+ }
+ break;
+ }
+ case 2:
+ // FIXME?: Clay Fighter Sculptor's Cut does this..
+ color->r = color->g = color->b = color->a = 0xff;
+ break;
+ default:
+ color->r = color->g = color->b = color->a = 0xff;
+ fatalerror("FETCH_TEXEL: unknown CI texture size %d\n", tsize);
+ break;
+ }
+ break;
+ }
+ case 3: // Intensity + Alpha
+ {
+ switch (tsize)
+ {
+ case PIXEL_SIZE_4BIT:
+ {
+ UINT8 *tc = (UINT8*)texture_cache;
+ int taddr = (tbase + ((t) * twidth) + ((s) / 2)) ^ ((t & 1) ? XOR_SWAP_BYTE : 0);
+ UINT8 p = ((s) & 1) ? (tc[taddr ^ BYTE_ADDR_XOR] & 0xf) : (tc[taddr ^ BYTE_ADDR_XOR] >> 4);
+ UINT8 i = ((p & 0xe) << 4) | ((p & 0xe) << 1) | (p & 0xe >> 2);
+
+ color->r = i;
+ color->g = i;
+ color->b = i;
+ color->a = (p & 0x1) ? 0xff : 0;
+ break;
+ }
+ case PIXEL_SIZE_8BIT:
+ {
+ UINT8 *tc = (UINT8*)texture_cache;
+ int taddr = (tbase + ((t) * twidth) + ((s))) ^ ((t & 1) ? XOR_SWAP_BYTE : 0);
+ UINT8 p = tc[taddr ^ BYTE_ADDR_XOR];
+ UINT8 i = (p >> 4) | (p & 0xf0);
+
+ color->r = i;
+ color->g = i;
+ color->b = i;
+ color->a = (p & 0xf) | ((p << 4) & 0xf0);
+ break;
+ }
+ case PIXEL_SIZE_16BIT:
+ {
+ UINT16 *tc = (UINT16*)texture_cache;
+ int taddr = (tbase + ((t) * (twidth/2)) + (s)) ^ ((t & 1) ? XOR_SWAP_WORD : 0);
+ UINT16 c = tc[taddr ^ WORD_ADDR_XOR];
+ UINT8 i = (c >> 8);
+
+ color->r = i;
+ color->g = i;
+ color->b = i;
+ color->a = c & 0xff;
+ break;
+ }
+ default:
+ color->r = color->g = color->b = color->a = 0xff;
+ fatalerror("FETCH_TEXEL: unknown IA texture size %d\n", tsize);
+ break;
+ }
+ break;
+ }
+ case 4: // Intensity
+ {
+ switch (tsize)
+ {
+ case PIXEL_SIZE_4BIT:
+ {
+ UINT8 *tc = (UINT8*)texture_cache;
+ int taddr = (tbase + ((t) * twidth) + ((s) / 2)) ^ ((t & 1) ? XOR_SWAP_BYTE : 0);
+ UINT8 c = ((s) & 1) ? (tc[taddr ^ BYTE_ADDR_XOR] & 0xf) : (tc[taddr ^ BYTE_ADDR_XOR] >> 4);
+ c |= (c << 4);
+
+ color->r = c;
+ color->g = c;
+ color->b = c;
+ color->a = c;
+ break;
+ }
+ case PIXEL_SIZE_8BIT:
+ {
+ UINT8 *tc = (UINT8*)texture_cache;
+ int taddr = (tbase + ((t) * twidth) + ((s))) ^ ((t & 1) ? XOR_SWAP_BYTE : 0);
+ UINT8 c = tc[taddr ^ BYTE_ADDR_XOR];
+
+ color->r = c;
+ color->g = c;
+ color->b = c;
+ color->a = c;
+ break;
+ }
+ default:
+ color->r = color->g = color->b = color->a = 0xff;
+ fatalerror("FETCH_TEXEL: unknown I texture size %d\n", tsize);
+ break;
+ }
+ break;
+ }
+ default:
+ {
+ color->r = color->g = color->b = color->a = 0xff;
+ fatalerror("FETCH_TEXEL: unknown texture format %d\n", tformat);
+ break;
+ }
+ }
+}
+
+#if 1
+#define TEXTURE_PIPELINE(TEX, SSS, SST, NOBILINEAR) \
+do \
+{ \
+ if (other_modes.sample_type && !NOBILINEAR) \
+ { \
+ COLOR t0, t1, t2, t3; \
+ int sss1, sst1, sss2, sst2; \
+ \
+ /* bilinear */ \
+ \
+ sss1 = (SSS >> 10) - (tsl >> 2); \
+ sss2 = sss1 + 1; \
+ \
+ sst1 = (SST >> 10) - (ttl >> 2); \
+ sst2 = sst1 + 1; \
+ \
+ CLAMP(sss1, sst1); \
+ CLAMP(sss2, sst2); \
+ \
+ FETCH_TEXEL(&t0, sss1, sst1, twidth, tformat, tsize, tbase); \
+ FETCH_TEXEL(&t1, sss2, sst1, twidth, tformat, tsize, tbase); \
+ FETCH_TEXEL(&t2, sss1, sst2, twidth, tformat, tsize, tbase); \
+ FETCH_TEXEL(&t3, sss2, sst2, twidth, tformat, tsize, tbase); \
+ \
+ TEX.r = (((( (t0.r * (0x3ff - (SSS & 0x3ff))) + (t1.r * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \
+ (((( (t2.r * (0x3ff - (SSS & 0x3ff))) + (t3.r * ((SSS & 0x3ff))) ) >> 10) * ((SST & 0x3ff))) >> 10); \
+ \
+ TEX.g = (((( (t0.g * (0x3ff - (SSS & 0x3ff))) + (t1.g * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \
+ (((( (t2.g * (0x3ff - (SSS & 0x3ff))) + (t3.g * ((SSS & 0x3ff))) ) >> 10) * ((SST & 0x3ff))) >> 10); \
+ \
+ TEX.b = (((( (t0.b * (0x3ff - (SSS & 0x3ff))) + (t1.b * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \
+ (((( (t2.b * (0x3ff - (SSS & 0x3ff))) + (t3.b * ((SSS & 0x3ff))) ) >> 10) * ((SST & 0x3ff))) >> 10); \
+ \
+ TEX.a = (((( (t0.a * (0x3ff - (SSS & 0x3ff))) + (t1.a * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \
+ (((( (t2.a * (0x3ff - (SSS & 0x3ff))) + (t3.a * ((SSS & 0x3ff))) ) >> 10) * ((SST & 0x3ff))) >> 10); \
+ } \
+ else \
+ { \
+ int sss1, sst1; \
+ sss1 = (SSS >> 10) - (tsl >> 2); \
+ if ((SSS & 0x3ff) >= 0x200) sss1++; \
+ \
+ sst1 = (SST >> 10) - (ttl >> 2); \
+ if ((SST & 0x3ff) >= 0x200) sst1++; \
+ \
+ CLAMP(sss1, sst1); \
+ \
+ /* point sample */ \
+ FETCH_TEXEL(&TEX, sss1, sst1, twidth, tformat, tsize, tbase); \
+ } \
+} \
+while(0)
+#endif
+
+// This is the implementation with 3-sample bilinear filtering, which should be more correct, but not yet working properly
+// TODO: check the correct texel samples and weighting values
+
+#if 0
+#define TEXTURE_PIPELINE(TEX, SSS, SST, NOBILINEAR) \
+do \
+{ \
+ if (other_modes.sample_type && !NOBILINEAR) \
+ { \
+ COLOR t0, t1, t2; \
+ int sss1, sst1, sss2, sst2; \
+ \
+ /* bilinear */ \
+ \
+ sss1 = (SSS >> 10) - (tsl >> 2); \
+ sss2 = sss1 + 1; \
+ \
+ sst1 = (SST >> 10) - (ttl >> 2); \
+ sst2 = sst1 + 1; \
+ \
+ CLAMP(sss1, sst1); \
+ CLAMP(sss2, sst2); \
+ \
+ FETCH_TEXEL(&t0, sss1, sst1, twidth, tformat, tsize, tbase); \
+ FETCH_TEXEL(&t1, sss2, sst1, twidth, tformat, tsize, tbase); \
+ FETCH_TEXEL(&t2, sss2, sst2, twidth, tformat, tsize, tbase); \
+ \
+ TEX.r = (((( (t0.r * (0x3ff - (SSS & 0x3ff))) + (t1.r * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \
+ (( (t2.r) * ((SST & 0x3ff))) >> 10); \
+ \
+ TEX.g = (((( (t0.g * (0x3ff - (SSS & 0x3ff))) + (t1.g * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \
+ (( (t2.g) * ((SST & 0x3ff))) >> 10); \
+ \
+ TEX.b = (((( (t0.b * (0x3ff - (SSS & 0x3ff))) + (t1.b * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \
+ (( (t2.b) * ((SST & 0x3ff))) >> 10); \
+ \
+ TEX.a = (((( (t0.a * (0x3ff - (SSS & 0x3ff))) + (t1.a * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \
+ (( (t2.a) * ((SST & 0x3ff))) >> 10); \
+ } \
+ else \
+ { \
+ int sss1, sst1; \
+ sss1 = (SSS >> 10) - (tsl >> 2); \
+ if ((SSS & 0x3ff) >= 0x200) sss1++; \
+ \
+ sst1 = (SST >> 10) - (ttl >> 2); \
+ if ((SST & 0x3ff) >= 0x200) sst1++; \
+ \
+ CLAMP(sss1, sst1); \
+ \
+ /* point sample */ \
+ FETCH_TEXEL(&TEX, sss1, sst1, twidth, tformat, tsize, tbase); \
+ } \
+} \
+while(0)
+#endif
+
+#define TEXTURE_PIPELINE1(SSS, SST, NOBILINEAR) \
+do \
+{ \
+ TEXTURE_PIPELINE(texel0_color, SSS, SST, NOBILINEAR); \
+} \
+while(0)
+
+#define TEXTURE_PIPELINE2(SSS, SST, NOBILINEAR) \
+do \
+{ \
+ TEXTURE_PIPELINE(texel0_color, SSS, SST, NOBILINEAR); \
+ TEXTURE_PIPELINE(texel1_color, SSS, SST, NOBILINEAR); \
+} \
+while(0)
+
+
+
+static void texture_rectangle_16bit(TEX_RECTANGLE *rect)
+{
+ UINT16 *fb = (UINT16*)&rdram[(fb_address / 4)];
+ int i, j;
+ int x1, x2, y1, y2;
+ int tsl, tsh, ttl, tth;
+ int s, t;
+ int twidth, tformat, tsize, tbase;
+ int clamp_s, clamp_t, mask_s, mask_t, mirror_s, mirror_t;
+ int clipx1, clipx2, clipy1, clipy2;
+
+ x1 = (rect->xh / 4);
+ x2 = (rect->xl / 4);
+ y1 = (rect->yh / 4);
+ y2 = (rect->yl / 4);
+
+ if (other_modes.cycle_type == CYCLE_TYPE_FILL || other_modes.cycle_type == CYCLE_TYPE_COPY)
+ {
+ rect->dsdx /= 4;
+ x2 += 1;
+ y2 += 1;
+ }
+
+ clipx1 = clip.xh / 4;
+ clipx2 = clip.xl / 4;
+ clipy1 = clip.yh / 4;
+ clipy2 = clip.yl / 4;
+
+ // clip
+ if (x1 < clipx1)
+ {
+ x1 = clipx1;
+ }
+ if (y1 < clipy1)
+ {
+ y1 = clipy1;
+ }
+ if (x2 >= clipx2)
+ {
+ x2 = clipx2-1;
+ }
+ if (y2 >= clipy2)
+ {
+ y2 = clipy2-1;
+ }
+
+ tsl = tile[rect->tilenum].sl;
+ tsh = tile[rect->tilenum].sh;
+ ttl = tile[rect->tilenum].tl;
+ tth = tile[rect->tilenum].th;
+
+ twidth = tile[rect->tilenum].line;
+ tformat = tile[rect->tilenum].format;
+ tsize = tile[rect->tilenum].size;
+ tbase = tile[rect->tilenum].tmem;
+
+ // FIXME?: clamping breaks at least Rampage World Tour
+ clamp_t = 0; //tile[rect->tilenum].ct;
+ clamp_s = 0; //tile[rect->tilenum].cs;
+
+ mirror_t = tile[rect->tilenum].mt;
+ mirror_s = tile[rect->tilenum].ms;
+ mask_t = tile[rect->tilenum].mask_t;
+ mask_s = tile[rect->tilenum].mask_s;
+
+ t = (int)(rect->t) << 5;
+
+ if (other_modes.cycle_type == CYCLE_TYPE_1 || other_modes.cycle_type == CYCLE_TYPE_2)
+ {
+ }
+
+ if (other_modes.cycle_type == CYCLE_TYPE_1)
+ {
+ for (j = y1; j < y2; j++)
+ {
+ int fb_index = j * fb_width;
+
+ s = (int)(rect->s) << 5;
+
+ for (i = x1; i < x2; i++)
+ {
+ COLOR c;
+
+ //ss = (s >> 10) - (tsl >> 2);
+ //if ((s & 0x3ff) >= 0x200) ss++;
+ //st = (t >> 10) - (ttl >> 2);
+ //if ((t & 0x3ff) >= 0x200) st++;
+
+ //CLAMP(ss, st);
+ //FETCH_TEXEL(&texel0_color, ss, st, twidth, tformat, tsize, tbase);
+
+ TEXTURE_PIPELINE1(s, t, (rect->dsdx == (1 << 10)) && (rect->dtdy == (1 << 10)));
+
+ c = COLOR_COMBINER(0);
+
+ {
+ int dith = dither_matrix_4x4[(((j) & 3) << 2) + ((i^WORD_ADDR_XOR) & 3)];
+ BLENDER1_16(&fb[(fb_index + i) ^ WORD_ADDR_XOR], c, dith);
+ }
+
+ s += rect->dsdx;
+ }
+
+ t += rect->dtdy;
+ }
+ }
+ else if (other_modes.cycle_type == CYCLE_TYPE_2)
+ {
+ for (j = y1; j < y2; j++)
+ {
+ int fb_index = j * fb_width;
+
+ s = (int)(rect->s) << 5;
+
+ for (i = x1; i < x2; i++)
+ {
+ COLOR c1, c2;
+
+ //ss = (s >> 10) - (tsl >> 2);
+ //if ((s & 0x3ff) >= 0x200) ss++;
+ //st = (t >> 10) - (ttl >> 2);
+ //if ((t & 0x3ff) >= 0x200) st++;
+
+ //CLAMP(ss, st);
+ //FETCH_TEXEL(&texel0_color, ss, st, twidth, tformat, tsize, tbase);
+ //FETCH_TEXEL(&texel1_color, ss, st, twidth, tformat, tsize, tbase);
+
+ TEXTURE_PIPELINE2(s, t, (rect->dsdx == (1 << 10)) && (rect->dtdy == (1 << 10)));
+
+ c1 = COLOR_COMBINER(0);
+ c2 = COLOR_COMBINER(1);
+
+ //BLENDER2_16(&fb[(fb_index + i) ^ WORD_ADDR_XOR], c1, c2);
+ {
+ int dith = dither_matrix_4x4[(((j) & 3) << 2) + ((i^WORD_ADDR_XOR) & 3)];
+ BLENDER2_16(&fb[(fb_index + i) ^ WORD_ADDR_XOR], c1, c2, dith);
+ }
+
+ s += rect->dsdx;
+ }
+
+ t += rect->dtdy;
+ }
+ }
+ else if (other_modes.cycle_type == CYCLE_TYPE_COPY)
+ {
+ for (j = y1; j < y2; j++)
+ {
+ int fb_index = j * fb_width;
+
+ s = (int)(rect->s) << 5;
+
+ for (i = x1; i < x2; i++)
+ {
+ /*
+ if (clamp_s)
+ {
+ if (s < (tsl << 8)) s = (tsl << 8);
+ if (s > (tsh << 8)) s = (tsh << 8);
+ }
+ if (clamp_t)
+ {
+ if (t < (ttl << 8)) t = (ttl << 8);
+ if (t > (tth << 8)) t = (tth << 8);
+ }
+ if (mask_s)
+ {
+ s &= (((UINT32)(0xffffffff) >> (32-mask_s)) << 10) | 0x3ff;
+ }
+ if (mask_t)
+ {
+ t &= (((UINT32)(0xffffffff) >> (32-mask_t)) << 10) | 0x3ff;
+ }
+
+ FETCH_TEXEL(&c, (s-tile[rect->tilenum].sl) >> 10, (t-tile[rect->tilenum].tl) >> 10, twidth, tformat, tsize, tbase);
+ */
+ //ss = (s >> 10) - (tsl >> 2);
+ //if ((s & 0x3ff) >= 0x200) ss++;
+ //st = (t >> 10) - (ttl >> 2);
+ //if ((t & 0x3ff) >= 0x200) st++;
+
+ //CLAMP(ss, st);
+ //FETCH_TEXEL(&c, ss, st, twidth, tformat, tsize, tbase);
+
+ TEXTURE_PIPELINE1(s, t, (rect->dsdx == (1 << 10)) && (rect->dtdy == (1 << 10)));
+
+ if (texel0_color.a != 0)
+ {
+ fb[(fb_index + i) ^ WORD_ADDR_XOR] = ((texel0_color.r >> 3) << 11) | ((texel0_color.g >> 3) << 6) | ((texel0_color.b >> 3) << 1);
+ }
+
+ s += rect->dsdx;
+ }
+
+ t += rect->dtdy;
+ }
+ }
+ else
+ {
+ fatalerror("texture_rectangle_16bit: unknown cycle type %d\n", other_modes.cycle_type);
+ }
+}
+
+/*****************************************************************************/
+
+INLINE void BLENDER1_32(UINT32 *fb, COLOR c)
+{
+ int r, g, b;
+
+ pixel_color.r = c.r; inv_pixel_color.r = 0xff - c.r;
+ pixel_color.g = c.g; inv_pixel_color.g = 0xff - c.g;
+ pixel_color.b = c.b; inv_pixel_color.b = 0xff - c.b;
+ pixel_color.a = c.a; inv_pixel_color.a = 0xff - c.a;
+
+ if (other_modes.image_read_en)
+ {
+ UINT32 mem = *fb;
+ memory_color.r = ((mem >> 16) & 0xff);
+ memory_color.g = ((mem >> 8) & 0xff);
+ memory_color.b = ((mem >> 0) & 0xff);
+ memory_color.a = 0;
+ }
+
+ r = (((int)(*blender1a_r[0]) * (int)(*blender1b_a[0])) >> 8) +
+ (((int)(*blender2a_r[0]) * (int)(*blender2b_a[0])) >> 8);
+
+ g = (((int)(*blender1a_g[0]) * (int)(*blender1b_a[0])) >> 8) +
+ (((int)(*blender2a_g[0]) * (int)(*blender2b_a[0])) >> 8);
+
+ b = (((int)(*blender1a_b[0]) * (int)(*blender1b_a[0])) >> 8) +
+ (((int)(*blender2a_b[0]) * (int)(*blender2b_a[0])) >> 8);
+
+ //r = g = b = 0xff;
+
+ if (r > 255) r = 255;
+ if (g > 255) g = 255;
+ if (b > 255) b = 255;
+
+ *fb = (r << 16) | (g << 8) | b;
+}
+
+INLINE void BLENDER2_32(UINT32 *fb, COLOR c1, COLOR c2)
+{
+ int r, g, b;
+
+ pixel_color.r = c1.r; inv_pixel_color.r = 0xff - c1.r;
+ pixel_color.g = c1.g; inv_pixel_color.g = 0xff - c1.g;
+ pixel_color.b = c1.b; inv_pixel_color.b = 0xff - c1.b;
+ pixel_color.a = c1.a; inv_pixel_color.a = 0xff - c1.a;
+
+ if (other_modes.image_read_en)
+ {
+ UINT32 mem = *fb;
+ memory_color.r = ((mem >> 16) & 0xff);
+ memory_color.g = ((mem >> 8) & 0xff);
+ memory_color.b = ((mem >> 0) & 0xff);
+ memory_color.a = 0;
+ }
+
+ r = (((int)(*blender1a_r[0]) * (int)(*blender1b_a[0])) >> 8) +
+ (((int)(*blender2a_r[0]) * (int)(*blender2b_a[0])) >> 8);
+
+ g = (((int)(*blender1a_g[0]) * (int)(*blender1b_a[0])) >> 8) +
+ (((int)(*blender2a_g[0]) * (int)(*blender2b_a[0])) >> 8);
+
+ b = (((int)(*blender1a_b[0]) * (int)(*blender1b_a[0])) >> 8) +
+ (((int)(*blender2a_b[0]) * (int)(*blender2b_a[0])) >> 8);
+
+ blended_pixel_color.r = r;
+ blended_pixel_color.g = g;
+ blended_pixel_color.b = b;
+
+ pixel_color.r = c2.r; inv_pixel_color.r = 0xff - c2.r;
+ pixel_color.g = c2.g; inv_pixel_color.g = 0xff - c2.g;
+ pixel_color.b = c2.b; inv_pixel_color.b = 0xff - c2.b;
+ pixel_color.a = c2.a; inv_pixel_color.a = 0xff - c2.a;
+
+ r = (((int)(*blender1a_r[1]) * (int)(*blender1b_a[1])) >> 8) +
+ (((int)(*blender2a_r[1]) * (int)(*blender2b_a[1])) >> 8);
+
+ g = (((int)(*blender1a_g[1]) * (int)(*blender1b_a[1])) >> 8) +
+ (((int)(*blender2a_g[1]) * (int)(*blender2b_a[1])) >> 8);
+
+ b = (((int)(*blender1a_b[1]) * (int)(*blender1b_a[1])) >> 8) +
+ (((int)(*blender2a_b[1]) * (int)(*blender2b_a[1])) >> 8);
+
+ if (r > 255) r = 255;
+ if (g > 255) g = 255;
+ if (b > 255) b = 255;
+
+ *fb = (r << 16) | (g << 8) | b;
+}
+
+static void fill_rectangle_32bit(RECTANGLE *rect)
+{
+ UINT32 *fb = (UINT32*)&rdram[(fb_address / 4)];
+ int index, i, j;
+ int x1 = rect->xh / 4;
+ int x2 = rect->xl / 4;
+ int y1 = rect->yh / 4;
+ int y2 = rect->yl / 4;
+ int clipx1, clipx2, clipy1, clipy2;
+
+ // TODO: clip
+ clipx1 = clip.xh / 4;
+ clipx2 = clip.xl / 4;
+ clipy1 = clip.yh / 4;
+ clipy2 = clip.yl / 4;
+
+ // clip
+ if (x1 < clipx1)
+ {
+ x1 = clipx1;
+ }
+ if (y1 < clipy1)
+ {
+ y1 = clipy1;
+ }
+ if (x2 >= clipx2)
+ {
+ x2 = clipx2-1;
+ }
+ if (y2 >= clipy2)
+ {
+ y2 = clipy2-1;
+ }
+
+ if (other_modes.cycle_type == CYCLE_TYPE_FILL)
+ {
+ for (j=y1; j <= y2; j++)
+ {
+ index = j * fb_width;
+ for (i=x1; i <= x2; i++)
+ {
+ fb[(index + i) ^ 1] = fill_color;
+ }
+ }
+ }
+ else if (other_modes.cycle_type == CYCLE_TYPE_1)
+ {
+ shade_color.r = prim_color.r;
+ shade_color.g = prim_color.g;
+ shade_color.b = prim_color.b;
+ shade_color.a = prim_color.a;
+
+ for (j=y1; j <= y2; j++)
+ {
+ index = j * fb_width;
+ for (i=x1; i <= x2; i++)
+ {
+ COLOR c = COLOR_COMBINER(0);
+
+ BLENDER1_32(&fb[(index + i)], c);
+ }
+ }
+ }
+ else if (other_modes.cycle_type == CYCLE_TYPE_2)
+ {
+ shade_color.r = prim_color.r;
+ shade_color.g = prim_color.g;
+ shade_color.b = prim_color.b;
+ shade_color.a = prim_color.a;
+
+ for (j=y1; j <= y2; j++)
+ {
+ index = j * fb_width;
+ for (i=x1; i <= x2; i++)
+ {
+ COLOR c1 = COLOR_COMBINER(0);
+ COLOR c2 = COLOR_COMBINER(1);
+
+ BLENDER2_32(&fb[(index + i)], c1, c2);
+ }
+ }
+ }
+ else
+ {
+ fatalerror("fill_rectangle_32bit: cycle type copy");
+ }
+}
+
+static void texture_rectangle_32bit(TEX_RECTANGLE *rect)
+{
+ UINT32 *fb = (UINT32*)&rdram[(fb_address / 4)];
+ int i, j;
+ int x1, x2, y1, y2;
+ int tsl, tsh, ttl, tth;
+ int s, t;
+ int twidth, tformat, tsize, tbase;
+ int clamp_s, clamp_t, mask_s, mask_t, mirror_s, mirror_t;
+ int clipx1, clipx2, clipy1, clipy2;
+
+ x1 = (rect->xh / 4);
+ x2 = (rect->xl / 4);
+ y1 = (rect->yh / 4);
+ y2 = (rect->yl / 4);
+
+ if (other_modes.cycle_type == CYCLE_TYPE_FILL || other_modes.cycle_type == CYCLE_TYPE_COPY)
+ {
+ rect->dsdx /= 4;
+ x2 += 1;
+ y2 += 1;
+ }
+
+ clipx1 = clip.xh / 4;
+ clipx2 = clip.xl / 4;
+ clipy1 = clip.yh / 4;
+ clipy2 = clip.yl / 4;
+
+ // clip
+ if (x1 < clipx1)
+ {
+ x1 = clipx1;
+ }
+ if (y1 < clipy1)
+ {
+ y1 = clipy1;
+ }
+ if (x2 >= clipx2)
+ {
+ x2 = clipx2-1;
+ }
+ if (y2 >= clipy2)
+ {
+ y2 = clipy2-1;
+ }
+
+ tsl = tile[rect->tilenum].sl;
+ tsh = tile[rect->tilenum].sh;
+ ttl = tile[rect->tilenum].tl;
+ tth = tile[rect->tilenum].th;
+
+ twidth = tile[rect->tilenum].line;
+ tformat = tile[rect->tilenum].format;
+ tsize = tile[rect->tilenum].size;
+ tbase = tile[rect->tilenum].tmem;
+
+ // FIXME?: clamping breaks at least Rampage World Tour
+ clamp_t = 0; //tile[rect->tilenum].ct;
+ clamp_s = 0; //tile[rect->tilenum].cs;
+
+ mirror_t = tile[rect->tilenum].mt;
+ mirror_s = tile[rect->tilenum].ms;
+ mask_t = tile[rect->tilenum].mask_t;
+ mask_s = tile[rect->tilenum].mask_s;
+
+ t = (int)(rect->t) << 5;
+
+ if (other_modes.cycle_type == CYCLE_TYPE_1 || other_modes.cycle_type == CYCLE_TYPE_2)
+ {
+ }
+
+ if (other_modes.cycle_type == CYCLE_TYPE_1)
+ {
+ for (j = y1; j < y2; j++)
+ {
+ int fb_index = j * fb_width;
+
+ s = (int)(rect->s) << 5;
+
+ for (i = x1; i < x2; i++)
+ {
+ COLOR c;
+
+ //ss = (s >> 10) - (tsl >> 2);
+ //if ((s & 0x3ff) >= 0x200) ss++;
+ //st = (t >> 10) - (ttl >> 2);
+ //if ((t & 0x3ff) >= 0x200) st++;
+
+ //CLAMP(ss, st);
+ //FETCH_TEXEL(&texel0_color, ss, st, twidth, tformat, tsize, tbase);
+
+ TEXTURE_PIPELINE1(s, t, (rect->dsdx == (1 << 10)) && (rect->dtdy == (1 << 10)));
+
+ c = COLOR_COMBINER(0);
+
+ BLENDER1_32(&fb[(fb_index + i)], c);
+
+ s += rect->dsdx;
+ }
+
+ t += rect->dtdy;
+ }
+ }
+ else if (other_modes.cycle_type == CYCLE_TYPE_2)
+ {
+ for (j = y1; j < y2; j++)
+ {
+ int fb_index = j * fb_width;
+
+ s = (int)(rect->s) << 5;
+
+ for (i = x1; i < x2; i++)
+ {
+ COLOR c1, c2;
+
+ //ss = (s >> 10) - (tsl >> 2);
+ //if ((s & 0x3ff) >= 0x200) ss++;
+ //st = (t >> 10) - (ttl >> 2);
+ //if ((t & 0x3ff) >= 0x200) st++;
+
+ //CLAMP(ss, st);
+ //FETCH_TEXEL(&texel0_color, ss, st, twidth, tformat, tsize, tbase);
+ //FETCH_TEXEL(&texel1_color, ss, st, twidth, tformat, tsize, tbase);
+
+ TEXTURE_PIPELINE2(s, t, (rect->dsdx == (1 << 10)) && (rect->dtdy == (1 << 10)));
+
+ c1 = COLOR_COMBINER(0);
+ c2 = COLOR_COMBINER(1);
+
+ BLENDER2_32(&fb[(fb_index + i)], c1, c2);
+
+ s += rect->dsdx;
+ }
+
+ t += rect->dtdy;
+ }
+ }
+ else if (other_modes.cycle_type == CYCLE_TYPE_COPY)
+ {
+ for (j = y1; j < y2; j++)
+ {
+ int fb_index = j * fb_width;
+
+ s = (int)(rect->s) << 5;
+
+ for (i = x1; i < x2; i++)
+ {
+ /*
+ if (clamp_s)
+ {
+ if (s < (tsl << 8)) s = (tsl << 8);
+ if (s > (tsh << 8)) s = (tsh << 8);
+ }
+ if (clamp_t)
+ {
+ if (t < (ttl << 8)) t = (ttl << 8);
+ if (t > (tth << 8)) t = (tth << 8);
+ }
+ if (mask_s)
+ {
+ s &= (((UINT32)(0xffffffff) >> (32-mask_s)) << 10) | 0x3ff;
+ }
+ if (mask_t)
+ {
+ t &= (((UINT32)(0xffffffff) >> (32-mask_t)) << 10) | 0x3ff;
+ }
+
+ FETCH_TEXEL(&c, (s-tile[rect->tilenum].sl) >> 10, (t-tile[rect->tilenum].tl) >> 10, twidth, tformat, tsize, tbase);
+ */
+ //ss = (s >> 10) - (tsl >> 2);
+ //if ((s & 0x3ff) >= 0x200) ss++;
+ //st = (t >> 10) - (ttl >> 2);
+ //if ((t & 0x3ff) >= 0x200) st++;
+
+ TEXTURE_PIPELINE1(s, t, (rect->dsdx == (1 << 10)) && (rect->dtdy == (1 << 10)));
+
+ //CLAMP(ss, st);
+ //FETCH_TEXEL(&c, ss, st, twidth, tformat, tsize, tbase);
+
+ if (texel0_color.a != 0)
+ {
+ fb[(fb_index + i) ^ WORD_ADDR_XOR] = (texel0_color.r << 16) | (texel0_color.g << 8) | (texel0_color.b << 0);
+ }
+
+ s += rect->dsdx;
+ }
+
+ t += rect->dtdy;
+ }
+ }
+ else
+ {
+ fatalerror("texture_rectangle_32bit: unknown cycle type %d\n", other_modes.cycle_type);
+ }
+}
+
+
+static void render_spans_32(int start, int end, int tilenum, int shade, int texture, int zbuffer, int flip)
+{
+ UINT32 *fb = (UINT32*)&rdram[fb_address / 4];
+ UINT16 *zb = (UINT16*)&rdram[zb_address / 4];
+ int i, j;
+ int tsl, tsh, ttl, tth;
+ int twidth, tformat, tsize, tbase;
+ int clamp_s, clamp_t, mask_s, mask_t, mirror_s, mirror_t;
+
+ int clipx1, clipx2, clipy1, clipy2;
+
+ clipx1 = clip.xh / 4;
+ clipx2 = clip.xl / 4;
+ clipy1 = clip.yh / 4;
+ clipy2 = clip.yl / 4;
+
+ tsl = tile[tilenum].sl;
+ tsh = tile[tilenum].sh;
+ ttl = tile[tilenum].tl;
+ tth = tile[tilenum].th;
+
+ twidth = tile[tilenum].line;
+ tformat = tile[tilenum].format;
+ tsize = tile[tilenum].size;
+ tbase = tile[tilenum].tmem;
+
+ clamp_t = tile[tilenum].ct;
+ clamp_s = tile[tilenum].cs;
+ mirror_t = tile[tilenum].mt;
+ mirror_s = tile[tilenum].ms;
+ mask_t = tile[tilenum].mask_t;
+ mask_s = tile[tilenum].mask_s;
+
+ if (start < clipy1)
+ {
+ start = clipy1;
+ }
+ if (start >= clipy2)
+ {
+ start = clipy2-1;
+ }
+ if (end < clipy1)
+ {
+ end = clipy1;
+ }
+ if (end >= clipy2)
+ {
+ end = clipy2-1;
+ }
+
+ for (i=start; i <= end; i++)
+ {
+ int xstart = span[i].lx;
+ int xend = span[i].rx;
+ int r = span[i].r;
+ int g = span[i].g;
+ int b = span[i].b;
+ int a = span[i].a;
+ int z = span[i].z;
+ int s = span[i].s;
+ int t = span[i].t;
+ int w = span[i].w;
+ int dr = span[i].dr;
+ int dg = span[i].dg;
+ int db = span[i].db;
+ int da = span[i].da;
+ int dz = span[i].dz;
+ int ds = span[i].ds;
+ int dt = span[i].dt;
+ int dw = span[i].dw;
+ int drinc, dginc, dbinc, dainc, dzinc, dsinc, dtinc, dwinc;
+
+ int x;
+ int xinc;
+
+ int fb_index = fb_width * i;
+ int length;
+
+ drinc = flip ? (dr) : -dr;
+ dginc = flip ? (dg) : -dg;
+ dbinc = flip ? (db) : -db;
+ dainc = flip ? (da) : -da;
+ dzinc = flip ? (dz) : -dz;
+ dsinc = flip ? (ds) : -ds;
+ dtinc = flip ? (dt) : -dt;
+ dwinc = flip ? (dw) : -dw;
+
+ xinc = flip ? 1 : -1;
+ x = xend;
+
+ length = flip ? (xstart - xend) : (xend - xstart);
+
+ for (j=0; j <= length; j++)
+ {
+ int sr = r >> 16;
+ int sg = g >> 16;
+ int sb = b >> 16;
+ int sa = a >> 16;
+ int ss = s >> 16;
+ int st = t >> 16;
+ int sw = w >> 16;
+ UINT16 sz = z >> 16;
+ int oz;
+ int sss = 0, sst = 0;
+
+ if (x >= clipx1 && x < clipx2)
+ {
+ COLOR c1, c2;
+ c1.r = c1.g = c1.b = c1.a = 0;
+ c2.r = c2.g = c2.b = c2.a = 0;
+
+ if ((z & 0xffff) >= 0x8000) sz++;
+ if ((w & 0xffff) >= 0x8000) sw++;
+
+ if (other_modes.persp_tex_en)
+ {
+ if (sw != 0)
+ {
+ sss = (((INT64)(ss) << 20) / sw);
+ sst = (((INT64)(st) << 20) / sw);
+ }
+ }
+ else
+ {
+ sss = ss;
+ sst = st;
+ }
+
+ if (sr > 0xff) sr = 0xff; if (sg > 0xff) sg = 0xff; if (sb > 0xff) sb = 0xff;
+
+ shade_color.r = sr; shade_color.g = sg; shade_color.b = sb; shade_color.a = sa;
+
+ if (texture)
+ {
+ /*if (other_modes.sample_type)
+ {
+ // bilinear
+
+ sss1 = (sss >> 10) - (tsl >> 2);
+ sss2 = sss1 + 1;
+
+ sst1 = (sst >> 10) - (ttl >> 2);
+ sst2 = sst1 + 1;
+
+ CLAMP(sss1, sst1);
+ CLAMP(sss2, sst2);
+
+ FETCH_TEXEL(&t0, sss1, sst1, twidth, tformat, tsize, tbase);
+ FETCH_TEXEL(&t1, sss2, sst1, twidth, tformat, tsize, tbase);
+ FETCH_TEXEL(&t2, sss1, sst2, twidth, tformat, tsize, tbase);
+ FETCH_TEXEL(&t3, sss2, sst2, twidth, tformat, tsize, tbase);
+
+ texel0_color.r = (((( (t0.r * (0x3ff - (sss & 0x3ff))) + (t1.r * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) +
+ (((( (t2.r * (0x3ff - (sss & 0x3ff))) + (t3.r * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10);
+
+ texel0_color.g = (((( (t0.g * (0x3ff - (sss & 0x3ff))) + (t1.g * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) +
+ (((( (t2.g * (0x3ff - (sss & 0x3ff))) + (t3.g * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10);
+
+ texel0_color.b = (((( (t0.b * (0x3ff - (sss & 0x3ff))) + (t1.b * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) +
+ (((( (t2.b * (0x3ff - (sss & 0x3ff))) + (t3.b * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10);
+
+ texel0_color.a = (((( (t0.a * (0x3ff - (sss & 0x3ff))) + (t1.a * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) +
+ (((( (t2.a * (0x3ff - (sss & 0x3ff))) + (t3.a * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10);
+ }
+ else
+ {
+ sss1 = (sss >> 10) - (tsl >> 2);
+ if ((sss & 0x3ff) >= 0x200) sss1++;
+
+ sst1 = (sst >> 10) - (ttl >> 2);
+ if ((sst & 0x3ff) >= 0x200) sst1++;
+
+ CLAMP(sss1, sst1);
+
+ // point sample
+ FETCH_TEXEL(&texel0_color, sss1, sst1, twidth, tformat, tsize, tbase);
+ }*/
+
+ if (other_modes.cycle_type == CYCLE_TYPE_1)
+ {
+ TEXTURE_PIPELINE1(sss, sst, 0);
+ }
+ else
+ {
+ TEXTURE_PIPELINE2(sss, sst, 0);
+ }
+ }
+
+ if (other_modes.cycle_type == CYCLE_TYPE_1)
+ {
+ c1 = COLOR_COMBINER(0);
+ }
+ else if (other_modes.cycle_type == CYCLE_TYPE_2)
+ {
+ c1 = COLOR_COMBINER(0);
+ c2 = COLOR_COMBINER(1);
+ }
+
+ oz = (UINT16)zb[(fb_index + x) ^ WORD_ADDR_XOR];
+ if (zbuffer)
+ {
+ if (sz < oz /*&& c.a != 0*/)
+ {
+ if (other_modes.cycle_type == CYCLE_TYPE_1)
+ {
+ BLENDER1_32(&fb[(fb_index + x)], c1);
+ }
+ else
+ {
+ BLENDER2_32(&fb[(fb_index + x)], c1, c2);
+ }
+
+ if (other_modes.z_compare_en && other_modes.z_update_en)
+ {
+ zb[(fb_index + x) ^ WORD_ADDR_XOR] = sz;
+ }
+ }
+ }
+ else
+ {
+ if (other_modes.cycle_type == CYCLE_TYPE_1)
+ {
+ BLENDER1_32(&fb[(fb_index + x)], c1);
+ }
+ else
+ {
+ BLENDER2_32(&fb[(fb_index + x)], c1, c2);
+ }
+ }
+ }
+
+ r += drinc;
+ g += dginc;
+ b += dbinc;
+ a += dainc;
+ z += dzinc;
+ s += dsinc;
+ t += dtinc;
+ w += dwinc;
+
+ x += xinc;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+
+
+static void render_spans_16(int start, int end, int tilenum, int shade, int texture, int zbuffer, int flip)
+{
+ UINT16 *fb = (UINT16*)&rdram[fb_address / 4];
+ UINT16 *zb = (UINT16*)&rdram[zb_address / 4];
+ int i, j;
+ int tsl, tsh, ttl, tth;
+ int twidth, tformat, tsize, tbase;
+ int clamp_s, clamp_t, mask_s, mask_t, mirror_s, mirror_t;
+
+ int clipx1, clipx2, clipy1, clipy2;
+
+ clipx1 = clip.xh / 4;
+ clipx2 = clip.xl / 4;
+ clipy1 = clip.yh / 4;
+ clipy2 = clip.yl / 4;
+
+ tsl = tile[tilenum].sl;
+ tsh = tile[tilenum].sh;
+ ttl = tile[tilenum].tl;
+ tth = tile[tilenum].th;
+
+ twidth = tile[tilenum].line;
+ tformat = tile[tilenum].format;
+ tsize = tile[tilenum].size;
+ tbase = tile[tilenum].tmem;
+
+ clamp_t = tile[tilenum].ct;
+ clamp_s = tile[tilenum].cs;
+ mirror_t = tile[tilenum].mt;
+ mirror_s = tile[tilenum].ms;
+ mask_t = tile[tilenum].mask_t;
+ mask_s = tile[tilenum].mask_s;
+
+ if (start < clipy1)
+ {
+ start = clipy1;
+ }
+ if (start >= clipy2)
+ {
+ start = clipy2-1;
+ }
+ if (end < clipy1)
+ {
+ end = clipy1;
+ }
+ if (end >= clipy2)
+ {
+ end = clipy2-1;
+ }
+
+ for (i=start; i <= end; i++)
+ {
+ int xstart = span[i].lx;
+ int xend = span[i].rx;
+ int r = span[i].r;
+ int g = span[i].g;
+ int b = span[i].b;
+ int a = span[i].a;
+ int z = span[i].z;
+ int s = span[i].s;
+ int t = span[i].t;
+ int w = span[i].w;
+ int dr = span[i].dr;
+ int dg = span[i].dg;
+ int db = span[i].db;
+ int da = span[i].da;
+ int dz = span[i].dz;
+ int ds = span[i].ds;
+ int dt = span[i].dt;
+ int dw = span[i].dw;
+ int drinc, dginc, dbinc, dainc, dzinc, dsinc, dtinc, dwinc;
+
+ int x;
+ int xinc;
+
+ int fb_index = fb_width * i;
+ int length;
+
+ drinc = flip ? (dr) : -dr;
+ dginc = flip ? (dg) : -dg;
+ dbinc = flip ? (db) : -db;
+ dainc = flip ? (da) : -da;
+ dzinc = flip ? (dz) : -dz;
+ dsinc = flip ? (ds) : -ds;
+ dtinc = flip ? (dt) : -dt;
+ dwinc = flip ? (dw) : -dw;
+
+ /*if (flip)
+ {
+ if (xend > clipx2)
+ {
+ int d = xend-clipx2;
+ r += d * drinc;
+ g += d * dginc;
+ b += d * dbinc;
+ a += d * dainc;
+ z += d * dzinc;
+ s += d * dsinc;
+ t += d * dtinc;
+ w += d * dwinc;
+
+ xend = clipx2;
+ }
+ if (xstart < clipx1)
+ {
+ xstart = clipx1;
+ }
+ }
+ else
+ {
+ if (xstart > clipx2)
+ {
+ int d = xstart-clipx2;
+ r += d * drinc;
+ g += d * dginc;
+ b += d * dbinc;
+ a += d * dainc;
+ z += d * dzinc;
+ s += d * dsinc;
+ t += d * dtinc;
+ w += d * dwinc;
+
+ xstart = clipx2;
+ }
+ if (xend < clipx1)
+ {
+ xend = clipx1;
+ }
+ }*/
+
+ xinc = flip ? 1 : -1;
+ x = xend;
+
+ length = flip ? (xstart - xend) : (xend - xstart);
+
+ for (j=0; j <= length; j++)
+ {
+ int sr = r >> 16;
+ int sg = g >> 16;
+ int sb = b >> 16;
+ int sa = a >> 16;
+ int ss = s >> 16;
+ int st = t >> 16;
+ int sw = w >> 16;
+ UINT16 sz = z >> 16;
+ int oz;
+ int sss = 0, sst = 0;
+ COLOR c1, c2;
+ c1.r = c1.g = c1.b = c1.a = 0;
+ c2.r = c2.g = c2.b = c2.a = 0;
+
+ if (x >= clipx1 && x < clipx2)
+ {
+ if ((z & 0xffff) >= 0x8000) sz++;
+ if ((w & 0xffff) >= 0x8000) sw++;
+
+ if (other_modes.persp_tex_en)
+ {
+ if (sw != 0)
+ {
+ sss = (((INT64)(ss) << 20) / sw);
+ sst = (((INT64)(st) << 20) / sw);
+ }
+ }
+ else
+ {
+ sss = ss;
+ sst = st;
+ }
+
+ if (sr > 0xff) sr = 0xff; if (sg > 0xff) sg = 0xff; if (sb > 0xff) sb = 0xff;
+
+ shade_color.r = sr; shade_color.g = sg; shade_color.b = sb; shade_color.a = sa;
+
+ if (texture)
+ {
+ /*if (other_modes.sample_type)
+ {
+ // bilinear
+
+ sss1 = (sss >> 10) - (tsl >> 2);
+ sss2 = sss1 + 1;
+
+ sst1 = (sst >> 10) - (ttl >> 2);
+ sst2 = sst1 + 1;
+
+ CLAMP(sss1, sst1);
+ CLAMP(sss2, sst2);
+
+ FETCH_TEXEL(&t0, sss1, sst1, twidth, tformat, tsize, tbase);
+ FETCH_TEXEL(&t1, sss2, sst1, twidth, tformat, tsize, tbase);
+ FETCH_TEXEL(&t2, sss1, sst2, twidth, tformat, tsize, tbase);
+ FETCH_TEXEL(&t3, sss2, sst2, twidth, tformat, tsize, tbase);
+
+ texel0_color.r = (((( (t0.r * (0x3ff - (sss & 0x3ff))) + (t1.r * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) +
+ (((( (t2.r * (0x3ff - (sss & 0x3ff))) + (t3.r * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10);
+
+ texel0_color.g = (((( (t0.g * (0x3ff - (sss & 0x3ff))) + (t1.g * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) +
+ (((( (t2.g * (0x3ff - (sss & 0x3ff))) + (t3.g * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10);
+
+ texel0_color.b = (((( (t0.b * (0x3ff - (sss & 0x3ff))) + (t1.b * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) +
+ (((( (t2.b * (0x3ff - (sss & 0x3ff))) + (t3.b * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10);
+
+ texel0_color.a = (((( (t0.a * (0x3ff - (sss & 0x3ff))) + (t1.a * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) +
+ (((( (t2.a * (0x3ff - (sss & 0x3ff))) + (t3.a * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10);
+ }
+ else
+ {
+ sss1 = (sss >> 10) - (tsl >> 2);
+ if ((sss & 0x3ff) >= 0x200) sss1++;
+
+ sst1 = (sst >> 10) - (ttl >> 2);
+ if ((sst & 0x3ff) >= 0x200) sst1++;
+
+ CLAMP(sss1, sst1);
+
+ // point sample
+ FETCH_TEXEL(&texel0_color, sss1, sst1, twidth, tformat, tsize, tbase);
+ }*/
+
+ if (other_modes.cycle_type == CYCLE_TYPE_1)
+ {
+ TEXTURE_PIPELINE1(sss, sst, 0);
+ }
+ else
+ {
+ TEXTURE_PIPELINE2(sss, sst, 0);
+ }
+ }
+
+ if (other_modes.cycle_type == CYCLE_TYPE_1)
+ {
+ c1 = COLOR_COMBINER(0);
+ }
+ else if (other_modes.cycle_type == CYCLE_TYPE_2)
+ {
+ c1 = COLOR_COMBINER(0);
+ c2 = COLOR_COMBINER(1);
+ }
+
+ oz = (UINT16)zb[(fb_index + x) ^ WORD_ADDR_XOR];
+ if (zbuffer)
+ {
+ if (sz < oz /*&& c.a != 0*/)
+ {
+ //BLENDER1_16(&fb[(fb_index + x) ^ WORD_ADDR_XOR], c);
+ {
+ int dith = dither_matrix_4x4[(((j) & 3) << 2) + ((i^WORD_ADDR_XOR) & 3)];
+ if (other_modes.cycle_type == CYCLE_TYPE_1)
+ {
+ BLENDER1_16(&fb[(fb_index + x) ^ WORD_ADDR_XOR], c1, dith);
+ }
+ else
+ {
+ BLENDER2_16(&fb[(fb_index + x) ^ WORD_ADDR_XOR], c1, c2, dith);
+ }
+ }
+
+ if (other_modes.z_compare_en && other_modes.z_update_en)
+ {
+ zb[(fb_index + x) ^ WORD_ADDR_XOR] = sz;
+ }
+ }
+ }
+ else
+ {
+ //BLENDER1_16(&fb[(fb_index + x) ^ WORD_ADDR_XOR], c);
+
+ {
+ int dith = dither_matrix_4x4[(((j) & 3) << 2) + ((i^WORD_ADDR_XOR) & 3)];
+ if (other_modes.cycle_type == CYCLE_TYPE_1)
+ {
+ BLENDER1_16(&fb[(fb_index + x) ^ WORD_ADDR_XOR], c1, dith);
+ }
+ else
+ {
+ BLENDER2_16(&fb[(fb_index + x) ^ WORD_ADDR_XOR], c1, c2, dith);
+ }
+ }
+ }
+ }
+
+ r += drinc;
+ g += dginc;
+ b += dbinc;
+ a += dainc;
+ z += dzinc;
+ s += dsinc;
+ t += dtinc;
+ w += dwinc;
+
+ x += xinc;
+ }
+ }
+}
+
+static void triangle(UINT32 w1, UINT32 w2, int shade, int texture, int zbuffer)
+{
+ int j;
+ int xleft, xright, xleft_inc, xright_inc;
+ int xstart, xend;
+ int r, g, b, a, z, s, t, w;
+ int dr, dg, db, da;
+ int drdx = 0, dgdx = 0, dbdx = 0, dadx = 0, dzdx = 0, dsdx = 0, dtdx = 0, dwdx = 0;
+ int drdy = 0, dgdy = 0, dbdy = 0, dady = 0, dzdy = 0, dsdy = 0, dtdy = 0, dwdy = 0;
+ int drde = 0, dgde = 0, dbde = 0, dade = 0, dzde = 0, dsde = 0, dtde = 0, dwde = 0;
+ int tile;
+ int flip = (w1 & 0x800000) ? 1 : 0;
+
+ INT32 yl, ym, yh;
+ INT32 xl, xm, xh;
+ INT64 dxldy, dxhdy, dxmdy;
+ UINT32 w3, w4, w5, w6, w7, w8;
+
+ int shade_base = rdp_cmd_cur + 8;
+ int texture_base = rdp_cmd_cur + 8;
+ int zbuffer_base = rdp_cmd_cur + 8;
+ if (shade)
+ {
+ texture_base += 16;
+ zbuffer_base += 16;
+ }
+ if (texture)
+ {
+ zbuffer_base += 16;
+ }
+
+ w3 = rdp_cmd_data[rdp_cmd_cur+2];
+ w4 = rdp_cmd_data[rdp_cmd_cur+3];
+ w5 = rdp_cmd_data[rdp_cmd_cur+4];
+ w6 = rdp_cmd_data[rdp_cmd_cur+5];
+ w7 = rdp_cmd_data[rdp_cmd_cur+6];
+ w8 = rdp_cmd_data[rdp_cmd_cur+7];
+
+ yl = (w1 & 0x3fff) >> 2;
+ ym = ((w2 >> 16) & 0x3fff) >> 2;
+ yh = ((w2 >> 0) & 0x3fff) >> 2;
+ xl = (INT32)(w3);
+ xh = (INT32)(w5);
+ xm = (INT32)(w7);
+ dxldy = (INT32)(w4);
+ dxhdy = (INT32)(w6);
+ dxmdy = (INT32)(w8);
+
+ if (yl & 0x800) yl |= 0xfffff000;
+ if (ym & 0x800) ym |= 0xfffff000;
+ if (yh & 0x800) yh |= 0xfffff000;
+
+ yl += (w1 >> 1) & 1;
+ ym += (w2 >> 17) & 1;
+ yh += (w2 >> 1) & 1;
+
+ tile = (w1 >> 16) & 0x7;
+
+ r = 0xff; g = 0xff; b = 0xff; a = 0xff; z = 0; s = 0; t = 0; w = 0;
+ dr = 0; dg = 0; db = 0; da = 0;
+
+ if (shade)
+ {
+ r = (rdp_cmd_data[shade_base+0 ] & 0xffff0000) | ((rdp_cmd_data[shade_base+4 ] >> 16) & 0x0000ffff);
+ g = ((rdp_cmd_data[shade_base+0 ] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+4 ] & 0x0000ffff);
+ b = (rdp_cmd_data[shade_base+1 ] & 0xffff0000) | ((rdp_cmd_data[shade_base+5 ] >> 16) & 0x0000ffff);
+ a = ((rdp_cmd_data[shade_base+1 ] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+5 ] & 0x0000ffff);
+ drdx = (rdp_cmd_data[shade_base+2 ] & 0xffff0000) | ((rdp_cmd_data[shade_base+6 ] >> 16) & 0x0000ffff);
+ dgdx = ((rdp_cmd_data[shade_base+2 ] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+6 ] & 0x0000ffff);
+ dbdx = (rdp_cmd_data[shade_base+3 ] & 0xffff0000) | ((rdp_cmd_data[shade_base+7 ] >> 16) & 0x0000ffff);
+ dadx = ((rdp_cmd_data[shade_base+3 ] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+7 ] & 0x0000ffff);
+ drde = (rdp_cmd_data[shade_base+8 ] & 0xffff0000) | ((rdp_cmd_data[shade_base+12] >> 16) & 0x0000ffff);
+ dgde = ((rdp_cmd_data[shade_base+8 ] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+12] & 0x0000ffff);
+ dbde = (rdp_cmd_data[shade_base+9 ] & 0xffff0000) | ((rdp_cmd_data[shade_base+13] >> 16) & 0x0000ffff);
+ dade = ((rdp_cmd_data[shade_base+9 ] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+13] & 0x0000ffff);
+ drdy = (rdp_cmd_data[shade_base+10] & 0xffff0000) | ((rdp_cmd_data[shade_base+14] >> 16) & 0x0000ffff);
+ dgdy = ((rdp_cmd_data[shade_base+10] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+14] & 0x0000ffff);
+ dbdy = (rdp_cmd_data[shade_base+11] & 0xffff0000) | ((rdp_cmd_data[shade_base+15] >> 16) & 0x0000ffff);
+ dady = ((rdp_cmd_data[shade_base+11] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+15] & 0x0000ffff);
+ }
+ if (texture)
+ {
+ s = (rdp_cmd_data[texture_base+0 ] & 0xffff0000) | ((rdp_cmd_data[texture_base+4 ] >> 16) & 0x0000ffff);
+ t = ((rdp_cmd_data[texture_base+0 ] << 16) & 0xffff0000) | (rdp_cmd_data[texture_base+4 ] & 0x0000ffff);
+ w = (rdp_cmd_data[texture_base+1 ] & 0xffff0000) | ((rdp_cmd_data[texture_base+5 ] >> 16) & 0x0000ffff);
+ dsdx = (rdp_cmd_data[texture_base+2 ] & 0xffff0000) | ((rdp_cmd_data[texture_base+6 ] >> 16) & 0x0000ffff);
+ dtdx = ((rdp_cmd_data[texture_base+2 ] << 16) & 0xffff0000) | (rdp_cmd_data[texture_base+6 ] & 0x0000ffff);
+ dwdx = (rdp_cmd_data[texture_base+3 ] & 0xffff0000) | ((rdp_cmd_data[texture_base+7 ] >> 16) & 0x0000ffff);
+ dsde = (rdp_cmd_data[texture_base+8 ] & 0xffff0000) | ((rdp_cmd_data[texture_base+12] >> 16) & 0x0000ffff);
+ dtde = ((rdp_cmd_data[texture_base+8 ] << 16) & 0xffff0000) | (rdp_cmd_data[texture_base+12] & 0x0000ffff);
+ dwde = (rdp_cmd_data[texture_base+9 ] & 0xffff0000) | ((rdp_cmd_data[texture_base+13] >> 16) & 0x0000ffff);
+ dsdy = (rdp_cmd_data[texture_base+10] & 0xffff0000) | ((rdp_cmd_data[texture_base+14] >> 16) & 0x0000ffff);
+ dtdy = ((rdp_cmd_data[texture_base+10] << 16) & 0xffff0000) | (rdp_cmd_data[texture_base+14] & 0x0000ffff);
+ dwdy = (rdp_cmd_data[texture_base+11] & 0xffff0000) | ((rdp_cmd_data[texture_base+15] >> 16) & 0x0000ffff);
+ }
+ if (zbuffer)
+ {
+ z = rdp_cmd_data[zbuffer_base+0];
+ dzdx = rdp_cmd_data[zbuffer_base+1];
+ dzde = rdp_cmd_data[zbuffer_base+2];
+ dzdy = rdp_cmd_data[zbuffer_base+3];
+ }
+
+ xleft = xm;
+ xright = xh;
+ xleft_inc = dxmdy;
+ xright_inc = dxhdy;
+
+ for (j=yh; j < ym; j++)
+ {
+ xstart = xleft >> 16;
+ xend = xright >> 16;
+
+ if (j >= 0)
+ {
+ span[j].lx = xstart;
+ span[j].rx = xend;
+ span[j].s = s; span[j].ds = dsdx;
+ span[j].t = t; span[j].dt = dtdx;
+ span[j].w = w; span[j].dw = dwdx;
+ span[j].r = r; span[j].dr = drdx;
+ span[j].g = g; span[j].dg = dgdx;
+ span[j].b = b; span[j].db = dbdx;
+ span[j].a = a; span[j].da = dadx;
+ span[j].z = z; span[j].dz = dzdx;
+ }
+
+ xleft += xleft_inc;
+ xright += xright_inc;
+ s += dsde;
+ t += dtde;
+ w += dwde;
+ r += drde;
+ g += dgde;
+ b += dbde;
+ a += dade;
+ z += dzde;
+ }
+
+ xleft = xl;
+ xleft_inc = dxldy;
+ xright_inc = dxhdy;
+
+ for (j=ym; j <= yl; j++)
+ {
+ xstart = xleft >> 16;
+ xend = xright >> 16;
+
+ if (j >= 0)
+ {
+ span[j].lx = xstart;
+ span[j].rx = xend;
+ span[j].s = s; span[j].ds = dsdx;
+ span[j].t = t; span[j].dt = dtdx;
+ span[j].w = w; span[j].dw = dwdx;
+ span[j].r = r; span[j].dr = drdx;
+ span[j].g = g; span[j].dg = dgdx;
+ span[j].b = b; span[j].db = dbdx;
+ span[j].a = a; span[j].da = dadx;
+ span[j].z = z; span[j].dz = dzdx;
+ }
+
+ xleft += xleft_inc;
+ xright += xright_inc;
+ s += dsde;
+ t += dtde;
+ w += dwde;
+ r += drde;
+ g += dgde;
+ b += dbde;
+ a += dade;
+ z += dzde;
+ }
+
+ switch (fb_size)
+ {
+ case PIXEL_SIZE_16BIT: render_spans_16(yh, yl, tile, shade, texture, zbuffer, flip); break;
+ case PIXEL_SIZE_32BIT: render_spans_32(yh, yl, tile, shade, texture, zbuffer, flip); break;
+ }
+}
+
+/*****************************************************************************/
+
+INLINE UINT32 READ_RDP_DATA(UINT32 address)
+{
+ if (dp_status & 0x1) // XBUS_DMEM_DMA enabled
+ {
+ return rsp_dmem[(address & 0xfff) / 4];
+ }
+ else
+ {
+ return rdram[(address / 4)];
+ }
+}
+
+#if LOG_RDP_EXECUTION
+static const char *image_format[] = { "RGBA", "YUV", "CI", "IA", "I", "???", "???", "???" };
+static const char *image_size[] = { "4-bit", "8-bit", "16-bit", "32-bit" };
+#endif
+
+static const int rdp_command_length[64] =
+{
+ 8, // 0x00, No Op
+ 8, // 0x01, ???
+ 8, // 0x02, ???
+ 8, // 0x03, ???
+ 8, // 0x04, ???
+ 8, // 0x05, ???
+ 8, // 0x06, ???
+ 8, // 0x07, ???
+ 32, // 0x08, Non-Shaded Triangle
+ 32+16, // 0x09, Non-Shaded, Z-Buffered Triangle
+ 32+64, // 0x0a, Textured Triangle
+ 32+64+16, // 0x0b, Textured, Z-Buffered Triangle
+ 32+64, // 0x0c, Shaded Triangle
+ 32+64+16, // 0x0d, Shaded, Z-Buffered Triangle
+ 32+64+64, // 0x0e, Shaded+Textured Triangle
+ 32+64+64+16,// 0x0f, Shaded+Textured, Z-Buffered Triangle
+ 8, // 0x10, ???
+ 8, // 0x11, ???
+ 8, // 0x12, ???
+ 8, // 0x13, ???
+ 8, // 0x14, ???
+ 8, // 0x15, ???
+ 8, // 0x16, ???
+ 8, // 0x17, ???
+ 8, // 0x18, ???
+ 8, // 0x19, ???
+ 8, // 0x1a, ???
+ 8, // 0x1b, ???
+ 8, // 0x1c, ???
+ 8, // 0x1d, ???
+ 8, // 0x1e, ???
+ 8, // 0x1f, ???
+ 8, // 0x20, ???
+ 8, // 0x21, ???
+ 8, // 0x22, ???
+ 8, // 0x23, ???
+ 16, // 0x24, Texture_Rectangle
+ 16, // 0x25, Texture_Rectangle_Flip
+ 8, // 0x26, Sync_Load
+ 8, // 0x27, Sync_Pipe
+ 8, // 0x28, Sync_Tile
+ 8, // 0x29, Sync_Full
+ 8, // 0x2a, Set_Key_GB
+ 8, // 0x2b, Set_Key_R
+ 8, // 0x2c, Set_Convert
+ 8, // 0x2d, Set_Scissor
+ 8, // 0x2e, Set_Prim_Depth
+ 8, // 0x2f, Set_Other_Modes
+ 8, // 0x30, Load_TLUT
+ 8, // 0x31, ???
+ 8, // 0x32, Set_Tile_Size
+ 8, // 0x33, Load_Block
+ 8, // 0x34, Load_Tile
+ 8, // 0x35, Set_Tile
+ 8, // 0x36, Fill_Rectangle
+ 8, // 0x37, Set_Fill_Color
+ 8, // 0x38, Set_Fog_Color
+ 8, // 0x39, Set_Blend_Color
+ 8, // 0x3a, Set_Prim_Color
+ 8, // 0x3b, Set_Env_Color
+ 8, // 0x3c, Set_Combine
+ 8, // 0x3d, Set_Texture_Image
+ 8, // 0x3e, Set_Mask_Image
+ 8 // 0x3f, Set_Color_Image
+};
+
+#if LOG_RDP_EXECUTION
+static int rdp_dasm(char *buffer)
+{
+ int i;
+ int tile;
+ const char *format, *size;
+ char sl[32], tl[32], sh[32], th[32];
+ char s[32], t[32], w[32];
+ char dsdx[32], dtdx[32], dwdx[32];
+ char dsdy[32], dtdy[32], dwdy[32];
+ char dsde[32], dtde[32], dwde[32];
+ char yl[32], yh[32], ym[32], xl[32], xh[32], xm[32];
+ char dxldy[32], dxhdy[32], dxmdy[32];
+ char rt[32], gt[32], bt[32], at[32];
+ char drdx[32], dgdx[32], dbdx[32], dadx[32];
+ char drdy[32], dgdy[32], dbdy[32], dady[32];
+ char drde[32], dgde[32], dbde[32], dade[32];
+ UINT32 r,g,b,a;
+
+ UINT32 cmd[64];
+ UINT32 length;
+ UINT32 command;
+
+ length = rdp_cmd_ptr * 4;
+ if (length < 8)
+ {
+ sprintf(buffer, "ERROR: length = %d\n", length);
+ return 0;
+ }
+
+ cmd[0] = rdp_cmd_data[rdp_cmd_cur+0];
+ cmd[1] = rdp_cmd_data[rdp_cmd_cur+1];
+
+ tile = (cmd[1] >> 24) & 0x7;
+ sprintf(sl, "%4.2f", (float)((cmd[0] >> 12) & 0xfff) / 4.0f);
+ sprintf(tl, "%4.2f", (float)((cmd[0] >> 0) & 0xfff) / 4.0f);
+ sprintf(sh, "%4.2f", (float)((cmd[1] >> 12) & 0xfff) / 4.0f);
+ sprintf(th, "%4.2f", (float)((cmd[1] >> 0) & 0xfff) / 4.0f);
+
+ format = image_format[(cmd[0] >> 21) & 0x7];
+ size = image_size[(cmd[0] >> 19) & 0x3];
+
+ r = (cmd[1] >> 24) & 0xff;
+ g = (cmd[1] >> 16) & 0xff;
+ b = (cmd[1] >> 8) & 0xff;
+ a = (cmd[1] >> 0) & 0xff;
+
+ command = (cmd[0] >> 24) & 0x3f;
+ switch (command)
+ {
+ case 0x00: sprintf(buffer, "No Op"); break;
+ case 0x08: // Tri_NoShade
+ {
+ int lft = (command >> 23) & 0x1;
+
+ if (length != rdp_command_length[command])
+ {
+ sprintf(buffer, "ERROR: Tri_NoShade length = %d\n", length);
+ return 0;
+ }
+
+ cmd[2] = rdp_cmd_data[rdp_cmd_cur+2];
+ cmd[3] = rdp_cmd_data[rdp_cmd_cur+3];
+ cmd[4] = rdp_cmd_data[rdp_cmd_cur+4];
+ cmd[5] = rdp_cmd_data[rdp_cmd_cur+5];
+ cmd[6] = rdp_cmd_data[rdp_cmd_cur+6];
+ cmd[7] = rdp_cmd_data[rdp_cmd_cur+7];
+
+ sprintf(yl, "%4.4f", (float)((cmd[0] >> 0) & 0x1fff) / 4.0f);
+ sprintf(ym, "%4.4f", (float)((cmd[1] >> 16) & 0x1fff) / 4.0f);
+ sprintf(yh, "%4.4f", (float)((cmd[1] >> 0) & 0x1fff) / 4.0f);
+ sprintf(xl, "%4.4f", (float)(cmd[2] / 65536.0f));
+ sprintf(dxldy, "%4.4f", (float)(cmd[3] / 65536.0f));
+ sprintf(xh, "%4.4f", (float)(cmd[4] / 65536.0f));
+ sprintf(dxhdy, "%4.4f", (float)(cmd[5] / 65536.0f));
+ sprintf(xm, "%4.4f", (float)(cmd[6] / 65536.0f));
+ sprintf(dxmdy, "%4.4f", (float)(cmd[7] / 65536.0f));
+
+ sprintf(buffer, "Tri_NoShade %d, XL: %s, XM: %s, XH: %s, YL: %s, YM: %s, YH: %s\n", lft, xl,xm,xh,yl,ym,yh);
+ break;
+ }
+ case 0x0a: // Tri_Tex
+ {
+ int lft = (command >> 23) & 0x1;
+
+ if (length < rdp_command_length[command])
+ {
+ sprintf(buffer, "ERROR: Tri_Tex length = %d\n", length);
+ return 0;
+ }
+
+ for (i=2; i < 24; i++)
+ {
+ cmd[i] = rdp_cmd_data[rdp_cmd_cur+i];
+ }
+
+ sprintf(yl, "%4.4f", (float)((cmd[0] >> 0) & 0x1fff) / 4.0f);
+ sprintf(ym, "%4.4f", (float)((cmd[1] >> 16) & 0x1fff) / 4.0f);
+ sprintf(yh, "%4.4f", (float)((cmd[1] >> 0) & 0x1fff) / 4.0f);
+ sprintf(xl, "%4.4f", (float)((INT32)cmd[2] / 65536.0f));
+ sprintf(dxldy, "%4.4f", (float)((INT32)cmd[3] / 65536.0f));
+ sprintf(xh, "%4.4f", (float)((INT32)cmd[4] / 65536.0f));
+ sprintf(dxhdy, "%4.4f", (float)((INT32)cmd[5] / 65536.0f));
+ sprintf(xm, "%4.4f", (float)((INT32)cmd[6] / 65536.0f));
+ sprintf(dxmdy, "%4.4f", (float)((INT32)cmd[7] / 65536.0f));
+
+ sprintf(s, "%4.4f", (float)(INT32)((cmd[ 8] & 0xffff0000) | ((cmd[12] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(t, "%4.4f", (float)(INT32)(((cmd[ 8] & 0xffff) << 16) | (cmd[12] & 0xffff)) / 65536.0f);
+ sprintf(w, "%4.4f", (float)(INT32)((cmd[ 9] & 0xffff0000) | ((cmd[13] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dsdx, "%4.4f", (float)(INT32)((cmd[10] & 0xffff0000) | ((cmd[14] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dtdx, "%4.4f", (float)(INT32)(((cmd[10] & 0xffff) << 16) | (cmd[14] & 0xffff)) / 65536.0f);
+ sprintf(dwdx, "%4.4f", (float)(INT32)((cmd[11] & 0xffff0000) | ((cmd[15] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dsde, "%4.4f", (float)(INT32)((cmd[16] & 0xffff0000) | ((cmd[20] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dtde, "%4.4f", (float)(INT32)(((cmd[16] & 0xffff) << 16) | (cmd[20] & 0xffff)) / 65536.0f);
+ sprintf(dwde, "%4.4f", (float)(INT32)((cmd[17] & 0xffff0000) | ((cmd[21] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dsdy, "%4.4f", (float)(INT32)((cmd[18] & 0xffff0000) | ((cmd[22] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dtdy, "%4.4f", (float)(INT32)(((cmd[18] & 0xffff) << 16) | (cmd[22] & 0xffff)) / 65536.0f);
+ sprintf(dwdy, "%4.4f", (float)(INT32)((cmd[19] & 0xffff0000) | ((cmd[23] >> 16) & 0xffff)) / 65536.0f);
+
+
+ buffer+=sprintf(buffer, "Tri_Tex %d, XL: %s, XM: %s, XH: %s, YL: %s, YM: %s, YH: %s\n", lft, xl,xm,xh,yl,ym,yh);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " S: %s, T: %s, W: %s\n", s, t, w);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " DSDX: %s, DTDX: %s, DWDX: %s\n", dsdx, dtdx, dwdx);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " DSDE: %s, DTDE: %s, DWDE: %s\n", dsde, dtde, dwde);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " DSDY: %s, DTDY: %s, DWDY: %s\n", dsdy, dtdy, dwdy);
+ break;
+ }
+ case 0x0c: // Tri_Shade
+ {
+ int lft = (command >> 23) & 0x1;
+
+ if (length != rdp_command_length[command])
+ {
+ sprintf(buffer, "ERROR: Tri_Shade length = %d\n", length);
+ return 0;
+ }
+
+ for (i=2; i < 24; i++)
+ {
+ cmd[i] = rdp_cmd_data[i];
+ }
+
+ sprintf(yl, "%4.4f", (float)((cmd[0] >> 0) & 0x1fff) / 4.0f);
+ sprintf(ym, "%4.4f", (float)((cmd[1] >> 16) & 0x1fff) / 4.0f);
+ sprintf(yh, "%4.4f", (float)((cmd[1] >> 0) & 0x1fff) / 4.0f);
+ sprintf(xl, "%4.4f", (float)((INT32)cmd[2] / 65536.0f));
+ sprintf(dxldy, "%4.4f", (float)((INT32)cmd[3] / 65536.0f));
+ sprintf(xh, "%4.4f", (float)((INT32)cmd[4] / 65536.0f));
+ sprintf(dxhdy, "%4.4f", (float)((INT32)cmd[5] / 65536.0f));
+ sprintf(xm, "%4.4f", (float)((INT32)cmd[6] / 65536.0f));
+ sprintf(dxmdy, "%4.4f", (float)((INT32)cmd[7] / 65536.0f));
+ sprintf(rt, "%4.4f", (float)(INT32)((cmd[8] & 0xffff0000) | ((cmd[12] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(gt, "%4.4f", (float)(INT32)(((cmd[8] & 0xffff) << 16) | (cmd[12] & 0xffff)) / 65536.0f);
+ sprintf(bt, "%4.4f", (float)(INT32)((cmd[9] & 0xffff0000) | ((cmd[13] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(at, "%4.4f", (float)(INT32)(((cmd[9] & 0xffff) << 16) | (cmd[13] & 0xffff)) / 65536.0f);
+ sprintf(drdx, "%4.4f", (float)(INT32)((cmd[10] & 0xffff0000) | ((cmd[14] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dgdx, "%4.4f", (float)(INT32)(((cmd[10] & 0xffff) << 16) | (cmd[14] & 0xffff)) / 65536.0f);
+ sprintf(dbdx, "%4.4f", (float)(INT32)((cmd[11] & 0xffff0000) | ((cmd[15] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dadx, "%4.4f", (float)(INT32)(((cmd[11] & 0xffff) << 16) | (cmd[15] & 0xffff)) / 65536.0f);
+ sprintf(drde, "%4.4f", (float)(INT32)((cmd[16] & 0xffff0000) | ((cmd[20] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dgde, "%4.4f", (float)(INT32)(((cmd[16] & 0xffff) << 16) | (cmd[20] & 0xffff)) / 65536.0f);
+ sprintf(dbde, "%4.4f", (float)(INT32)((cmd[17] & 0xffff0000) | ((cmd[21] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dade, "%4.4f", (float)(INT32)(((cmd[17] & 0xffff) << 16) | (cmd[21] & 0xffff)) / 65536.0f);
+ sprintf(drdy, "%4.4f", (float)(INT32)((cmd[18] & 0xffff0000) | ((cmd[22] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dgdy, "%4.4f", (float)(INT32)(((cmd[18] & 0xffff) << 16) | (cmd[22] & 0xffff)) / 65536.0f);
+ sprintf(dbdy, "%4.4f", (float)(INT32)((cmd[19] & 0xffff0000) | ((cmd[23] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dady, "%4.4f", (float)(INT32)(((cmd[19] & 0xffff) << 16) | (cmd[23] & 0xffff)) / 65536.0f);
+
+ buffer+=sprintf(buffer, "Tri_Shade %d, XL: %s, XM: %s, XH: %s, YL: %s, YM: %s, YH: %s\n", lft, xl,xm,xh,yl,ym,yh);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " R: %s, G: %s, B: %s, A: %s\n", rt, gt, bt, at);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " DRDX: %s, DGDX: %s, DBDX: %s, DADX: %s\n", drdx, dgdx, dbdx, dadx);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " DRDE: %s, DGDE: %s, DBDE: %s, DADE: %s\n", drde, dgde, dbde, dade);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " DRDY: %s, DGDY: %s, DBDY: %s, DADY: %s\n", drdy, dgdy, dbdy, dady);
+ break;
+ }
+ case 0x0e: // Tri_TexShade
+ {
+ int lft = (command >> 23) & 0x1;
+
+ if (length < rdp_command_length[command])
+ {
+ sprintf(buffer, "ERROR: Tri_TexShade length = %d\n", length);
+ return 0;
+ }
+
+ for (i=2; i < 40; i++)
+ {
+ cmd[i] = rdp_cmd_data[rdp_cmd_cur+i];
+ }
+
+ sprintf(yl, "%4.4f", (float)((cmd[0] >> 0) & 0x1fff) / 4.0f);
+ sprintf(ym, "%4.4f", (float)((cmd[1] >> 16) & 0x1fff) / 4.0f);
+ sprintf(yh, "%4.4f", (float)((cmd[1] >> 0) & 0x1fff) / 4.0f);
+ sprintf(xl, "%4.4f", (float)((INT32)cmd[2] / 65536.0f));
+ sprintf(dxldy, "%4.4f", (float)((INT32)cmd[3] / 65536.0f));
+ sprintf(xh, "%4.4f", (float)((INT32)cmd[4] / 65536.0f));
+ sprintf(dxhdy, "%4.4f", (float)((INT32)cmd[5] / 65536.0f));
+ sprintf(xm, "%4.4f", (float)((INT32)cmd[6] / 65536.0f));
+ sprintf(dxmdy, "%4.4f", (float)((INT32)cmd[7] / 65536.0f));
+ sprintf(rt, "%4.4f", (float)(INT32)((cmd[8] & 0xffff0000) | ((cmd[12] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(gt, "%4.4f", (float)(INT32)(((cmd[8] & 0xffff) << 16) | (cmd[12] & 0xffff)) / 65536.0f);
+ sprintf(bt, "%4.4f", (float)(INT32)((cmd[9] & 0xffff0000) | ((cmd[13] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(at, "%4.4f", (float)(INT32)(((cmd[9] & 0xffff) << 16) | (cmd[13] & 0xffff)) / 65536.0f);
+ sprintf(drdx, "%4.4f", (float)(INT32)((cmd[10] & 0xffff0000) | ((cmd[14] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dgdx, "%4.4f", (float)(INT32)(((cmd[10] & 0xffff) << 16) | (cmd[14] & 0xffff)) / 65536.0f);
+ sprintf(dbdx, "%4.4f", (float)(INT32)((cmd[11] & 0xffff0000) | ((cmd[15] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dadx, "%4.4f", (float)(INT32)(((cmd[11] & 0xffff) << 16) | (cmd[15] & 0xffff)) / 65536.0f);
+ sprintf(drde, "%4.4f", (float)(INT32)((cmd[16] & 0xffff0000) | ((cmd[20] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dgde, "%4.4f", (float)(INT32)(((cmd[16] & 0xffff) << 16) | (cmd[20] & 0xffff)) / 65536.0f);
+ sprintf(dbde, "%4.4f", (float)(INT32)((cmd[17] & 0xffff0000) | ((cmd[21] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dade, "%4.4f", (float)(INT32)(((cmd[17] & 0xffff) << 16) | (cmd[21] & 0xffff)) / 65536.0f);
+ sprintf(drdy, "%4.4f", (float)(INT32)((cmd[18] & 0xffff0000) | ((cmd[22] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dgdy, "%4.4f", (float)(INT32)(((cmd[18] & 0xffff) << 16) | (cmd[22] & 0xffff)) / 65536.0f);
+ sprintf(dbdy, "%4.4f", (float)(INT32)((cmd[19] & 0xffff0000) | ((cmd[23] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dady, "%4.4f", (float)(INT32)(((cmd[19] & 0xffff) << 16) | (cmd[23] & 0xffff)) / 65536.0f);
+
+ sprintf(s, "%4.4f", (float)(INT32)((cmd[24] & 0xffff0000) | ((cmd[28] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(t, "%4.4f", (float)(INT32)(((cmd[24] & 0xffff) << 16) | (cmd[28] & 0xffff)) / 65536.0f);
+ sprintf(w, "%4.4f", (float)(INT32)((cmd[25] & 0xffff0000) | ((cmd[29] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dsdx, "%4.4f", (float)(INT32)((cmd[26] & 0xffff0000) | ((cmd[30] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dtdx, "%4.4f", (float)(INT32)(((cmd[26] & 0xffff) << 16) | (cmd[30] & 0xffff)) / 65536.0f);
+ sprintf(dwdx, "%4.4f", (float)(INT32)((cmd[27] & 0xffff0000) | ((cmd[31] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dsde, "%4.4f", (float)(INT32)((cmd[32] & 0xffff0000) | ((cmd[36] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dtde, "%4.4f", (float)(INT32)(((cmd[32] & 0xffff) << 16) | (cmd[36] & 0xffff)) / 65536.0f);
+ sprintf(dwde, "%4.4f", (float)(INT32)((cmd[33] & 0xffff0000) | ((cmd[37] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dsdy, "%4.4f", (float)(INT32)((cmd[34] & 0xffff0000) | ((cmd[38] >> 16) & 0xffff)) / 65536.0f);
+ sprintf(dtdy, "%4.4f", (float)(INT32)(((cmd[34] & 0xffff) << 16) | (cmd[38] & 0xffff)) / 65536.0f);
+ sprintf(dwdy, "%4.4f", (float)(INT32)((cmd[35] & 0xffff0000) | ((cmd[39] >> 16) & 0xffff)) / 65536.0f);
+
+
+ buffer+=sprintf(buffer, "Tri_TexShade %d, XL: %s, XM: %s, XH: %s, YL: %s, YM: %s, YH: %s\n", lft, xl,xm,xh,yl,ym,yh);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " R: %s, G: %s, B: %s, A: %s\n", rt, gt, bt, at);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " DRDX: %s, DGDX: %s, DBDX: %s, DADX: %s\n", drdx, dgdx, dbdx, dadx);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " DRDE: %s, DGDE: %s, DBDE: %s, DADE: %s\n", drde, dgde, dbde, dade);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " DRDY: %s, DGDY: %s, DBDY: %s, DADY: %s\n", drdy, dgdy, dbdy, dady);
+
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " S: %s, T: %s, W: %s\n", s, t, w);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " DSDX: %s, DTDX: %s, DWDX: %s\n", dsdx, dtdx, dwdx);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " DSDE: %s, DTDE: %s, DWDE: %s\n", dsde, dtde, dwde);
+ buffer+=sprintf(buffer, " ");
+ buffer+=sprintf(buffer, " DSDY: %s, DTDY: %s, DWDY: %s\n", dsdy, dtdy, dwdy);
+ break;
+ }
+ case 0x24:
+ case 0x25:
+ {
+ if (length < 16)
+ {
+ sprintf(buffer, "ERROR: Texture_Rectangle length = %d\n", length);
+ return 0;
+ }
+ cmd[2] = rdp_cmd_data[rdp_cmd_cur+2];
+ cmd[3] = rdp_cmd_data[rdp_cmd_cur+3];
+ sprintf(s, "%4.4f", (float)(INT16)((cmd[2] >> 16) & 0xffff) / 32.0f);
+ sprintf(t, "%4.4f", (float)(INT16)((cmd[2] >> 0) & 0xffff) / 32.0f);
+ sprintf(dsdx, "%4.4f", (float)(INT16)((cmd[3] >> 16) & 0xffff) / 1024.0f);
+ sprintf(dtdy, "%4.4f", (float)(INT16)((cmd[3] >> 16) & 0xffff) / 1024.0f);
+
+ if (command == 0x24)
+ sprintf(buffer, "Texture_Rectangle %d, %s, %s, %s, %s, %s, %s, %s, %s", tile, sh, th, sl, tl, s, t, dsdx, dtdy);
+ else
+ sprintf(buffer, "Texture_Rectangle_Flip %d, %s, %s, %s, %s, %s, %s, %s, %s", tile, sh, th, sl, tl, s, t, dsdx, dtdy);
+
+ break;
+ }
+ case 0x26: sprintf(buffer, "Sync_Load"); break;
+ case 0x27: sprintf(buffer, "Sync_Pipe"); break;
+ case 0x28: sprintf(buffer, "Sync_Tile"); break;
+ case 0x29: sprintf(buffer, "Sync_Full"); break;
+ case 0x2d: sprintf(buffer, "Set_Scissor %s, %s, %s, %s", sl, tl, sh, th); break;
+ case 0x2e: sprintf(buffer, "Set_Prim_Depth %04X, %04X", (cmd[1] >> 16) & 0xffff, cmd[1] & 0xffff); break;
+ case 0x2f: sprintf(buffer, "Set_Other_Modes %08X %08X", cmd[0], cmd[1]); break;
+ case 0x30: sprintf(buffer, "Load_TLUT %d, %s, %s, %s, %s", tile, sl, tl, sh, th); break;
+ case 0x32: sprintf(buffer, "Set_Tile_Size %d, %s, %s, %s, %s", tile, sl, tl, sh, th); break;
+ case 0x33: sprintf(buffer, "Load_Block %d, %03X, %03X, %03X, %03X", tile, (cmd[0] >> 12) & 0xfff, cmd[0] & 0xfff, (cmd[1] >> 12) & 0xfff, cmd[1] & 0xfff); break;
+ case 0x34: sprintf(buffer, "Load_Tile %d, %s, %s, %s, %s", tile, sl, tl, sh, th); break;
+ case 0x35: sprintf(buffer, "Set_Tile %d, %s, %s, %d, %04X", tile, format, size, ((cmd[0] >> 9) & 0x1ff) * 8, (cmd[0] & 0x1ff) * 8); break;
+ case 0x36: sprintf(buffer, "Fill_Rectangle %s, %s, %s, %s", sh, th, sl, tl); break;
+ case 0x37: sprintf(buffer, "Set_Fill_Color R: %d, G: %d, B: %d, A: %d", r, g, b, a); break;
+ case 0x38: sprintf(buffer, "Set_Fog_Color R: %d, G: %d, B: %d, A: %d", r, g, b, a); break;
+ case 0x39: sprintf(buffer, "Set_Blend_Color R: %d, G: %d, B: %d, A: %d", r, g, b, a); break;
+ case 0x3a: sprintf(buffer, "Set_Prim_Color %d, %d, R: %d, G: %d, B: %d, A: %d", (cmd[0] >> 8) & 0x1f, cmd[0] & 0xff, r, g, b, a); break;
+ case 0x3b: sprintf(buffer, "Set_Env_Color R: %d, G: %d, B: %d, A: %d", r, g, b, a); break;
+ case 0x3c: sprintf(buffer, "Set_Combine %08X %08X", cmd[0], cmd[1]); break;
+ case 0x3d: sprintf(buffer, "Set_Texture_Image %s, %s, %d, %08X", format, size, (cmd[0] & 0x1ff)+1, cmd[1]); break;
+ case 0x3e: sprintf(buffer, "Set_Mask_Image %08X", cmd[1]); break;
+ case 0x3f: sprintf(buffer, "Set_Color_Image %s, %s, %d, %08X", format, size, (cmd[0] & 0x1ff)+1, cmd[1]); break;
+ default: sprintf(buffer, "??? (%08X %08X)", cmd[0], cmd[1]); break;
+ }
+
+ return rdp_command_length[command];
+}
+#endif
+
+/*****************************************************************************/
+
+////////////////////////
+// RDP COMMANDS
+////////////////////////
+
+static void rdp_invalid(UINT32 w1, UINT32 w2)
+{
+ fatalerror("RDP: invalid command %d, %08X %08X\n", (w1 >> 24) & 0x3f, w1, w2);
+}
+
+static void rdp_noop(UINT32 w1, UINT32 w2)
+{
+
+}
+
+static void rdp_tri_noshade(UINT32 w1, UINT32 w2)
+{
+ //fatalerror("RDP: unhandled command tri_noshade, %08X %08X\n", w1, w2);
+ triangle(w1, w2, 0, 0, 0);
+}
+
+static void rdp_tri_noshade_z(UINT32 w1, UINT32 w2)
+{
+ //fatalerror("RDP: unhandled command tri_noshade_z, %08X %08X\n", w1, w2);
+ triangle(w1, w2, 0, 0, 1);
+}
+
+static void rdp_tri_tex(UINT32 w1, UINT32 w2)
+{
+ //osd_die("RDP: unhandled command tri_tex, %08X %08X\n", w1, w2);
+
+ triangle(w1, w2, 0, 1, 0);
+}
+
+static void rdp_tri_tex_z(UINT32 w1, UINT32 w2)
+{
+ //osd_die("RDP: unhandled command tri_tex_z, %08X %08X\n", w1, w2);
+
+ triangle(w1, w2, 0, 1, 1);
+}
+
+static void rdp_tri_shade(UINT32 w1, UINT32 w2)
+{
+ //osd_die("RDP: unhandled command tri_shade, %08X %08X\n", w1, w2);
+
+ triangle(w1, w2, 1, 0, 0);
+}
+
+static void rdp_tri_shade_z(UINT32 w1, UINT32 w2)
+{
+ //osd_die("RDP: unhandled command tri_shade_z, %08X %08X\n", w1, w2);
+
+ triangle(w1, w2, 1, 0, 1);
+}
+
+static void rdp_tri_texshade(UINT32 w1, UINT32 w2)
+{
+ //osd_die("RDP: unhandled command tri_texshade, %08X %08X\n", w1, w2);
+
+ triangle(w1, w2, 1, 1, 0);
+}
+
+static void rdp_tri_texshade_z(UINT32 w1, UINT32 w2)
+{
+ //osd_die("RDP: unhandled command tri_texshade_z, %08X %08X\n", w1, w2);
+
+ triangle(w1, w2, 1, 1, 1);
+}
+
+static void rdp_tex_rect(UINT32 w1, UINT32 w2)
+{
+ UINT32 w3, w4;
+ TEX_RECTANGLE rect;
+
+ w3 = rdp_cmd_data[rdp_cmd_cur+2];
+ w4 = rdp_cmd_data[rdp_cmd_cur+3];
+
+ rect.tilenum = (w2 >> 24) & 0x7;
+ rect.xl = (w1 >> 12) & 0xfff;
+ rect.yl = (w1 >> 0) & 0xfff;
+ rect.xh = (w2 >> 12) & 0xfff;
+ rect.yh = (w2 >> 0) & 0xfff;
+ rect.s = (w3 >> 16) & 0xffff;
+ rect.t = (w3 >> 0) & 0xffff;
+ rect.dsdx = (w4 >> 16) & 0xffff;
+ rect.dtdy = (w4 >> 0) & 0xffff;
+
+ switch (fb_size)
+ {
+ case PIXEL_SIZE_16BIT: texture_rectangle_16bit(&rect); break;
+ case PIXEL_SIZE_32BIT: texture_rectangle_32bit(&rect); break;
+ }
+}
+
+static void rdp_tex_rect_flip(UINT32 w1, UINT32 w2)
+{
+ UINT32 w3, w4;
+ TEX_RECTANGLE rect;
+
+ w3 = rdp_cmd_data[rdp_cmd_cur+2];
+ w4 = rdp_cmd_data[rdp_cmd_cur+3];
+
+ rect.tilenum = (w2 >> 24) & 0x7;
+ rect.xl = (w1 >> 12) & 0xfff;
+ rect.yl = (w1 >> 0) & 0xfff;
+ rect.xh = (w2 >> 12) & 0xfff;
+ rect.yh = (w2 >> 0) & 0xfff;
+ rect.t = (w3 >> 16) & 0xffff;
+ rect.s = (w3 >> 0) & 0xffff;
+ rect.dtdy = (w4 >> 16) & 0xffff;
+ rect.dsdx = (w4 >> 0) & 0xffff;
+
+ switch (fb_size)
+ {
+ case PIXEL_SIZE_16BIT: texture_rectangle_16bit(&rect); break;
+ case PIXEL_SIZE_32BIT: texture_rectangle_32bit(&rect); break;
+ }
+}
+
+static void rdp_sync_load(UINT32 w1, UINT32 w2)
+{
+ // Nothing to do?
+}
+
+static void rdp_sync_pipe(UINT32 w1, UINT32 w2)
+{
+ // Nothing to do?
+}
+
+static void rdp_sync_tile(UINT32 w1, UINT32 w2)
+{
+ // Nothing to do?
+}
+
+static void rdp_sync_full(UINT32 w1, UINT32 w2)
+{
+ dp_full_sync();
+}
+
+static void rdp_set_key_gb(UINT32 w1, UINT32 w2)
+{
+ //osd_die("RDP: unhandled command set_key_gb, %08X %08X\n", w1, w2);
+}
+
+static void rdp_set_key_r(UINT32 w1, UINT32 w2)
+{
+ //osd_die("RDP: unhandled command set_key_r, %08X %08X\n", w1, w2);
+}
+
+static void rdp_set_convert(UINT32 w1, UINT32 w2)
+{
+ //osd_die("RDP: unhandled command set_convert, %08X %08X\n", w1, w2);
+}
+
+static void rdp_set_scissor(UINT32 w1, UINT32 w2)
+{
+ clip.xh = (w1 >> 12) & 0xfff;
+ clip.yh = (w1 >> 0) & 0xfff;
+ clip.xl = (w2 >> 12) & 0xfff;
+ clip.yl = (w2 >> 0) & 0xfff;
+
+ // TODO: handle f & o?
+}
+
+static void rdp_set_prim_depth(UINT32 w1, UINT32 w2)
+{
+ primitive_z = (UINT16)(w2 >> 16);
+ primitive_delta_z = (UINT16)(w1);
+}
+
+static void rdp_set_other_modes(UINT32 w1, UINT32 w2)
+{
+ other_modes.cycle_type = (w1 >> 20) & 0x3;
+ other_modes.persp_tex_en = (w1 & 0x80000) ? 1 : 0;
+ other_modes.detail_tex_en = (w1 & 0x40000) ? 1 : 0;
+ other_modes.sharpen_tex_en = (w1 & 0x20000) ? 1 : 0;
+ other_modes.tex_lod_en = (w1 & 0x10000) ? 1 : 0;
+ other_modes.en_tlut = (w1 & 0x08000) ? 1 : 0;
+ other_modes.tlut_type = (w1 & 0x04000) ? 1 : 0;
+ other_modes.sample_type = (w1 & 0x02000) ? 1 : 0;
+ other_modes.mid_texel = (w1 & 0x01000) ? 1 : 0;
+ other_modes.bi_lerp0 = (w1 & 0x00800) ? 1 : 0;
+ other_modes.bi_lerp1 = (w1 & 0x00400) ? 1 : 0;
+ other_modes.convert_one = (w1 & 0x00200) ? 1 : 0;
+ other_modes.key_en = (w1 & 0x00100) ? 1 : 0;
+ other_modes.rgb_dither_sel = (w1 >> 6) & 0x3;
+ other_modes.alpha_dither_sel = (w1 >> 4) & 0x3;
+ other_modes.blend_m1a_0 = (w2 >> 30) & 0x3;
+ other_modes.blend_m1a_1 = (w2 >> 28) & 0x3;
+ other_modes.blend_m1b_0 = (w2 >> 26) & 0x3;
+ other_modes.blend_m1b_1 = (w2 >> 24) & 0x3;
+ other_modes.blend_m2a_0 = (w2 >> 22) & 0x3;
+ other_modes.blend_m2a_1 = (w2 >> 20) & 0x3;
+ other_modes.blend_m2b_0 = (w2 >> 18) & 0x3;
+ other_modes.blend_m2b_1 = (w2 >> 16) & 0x3;
+ other_modes.force_blend = (w2 & 0x4000) ? 1 : 0;
+ other_modes.alpha_cvg_select = (w2 & 0x2000) ? 1 : 0;
+ other_modes.cvg_times_alpha = (w2 & 0x1000) ? 1 : 0;
+ other_modes.z_mode = (w2 >> 10) & 0x3;
+ other_modes.cvg_dest = (w2 >> 8) & 0x3;
+ other_modes.color_on_cvg = (w2 & 0x80) ? 1 : 0;
+ other_modes.image_read_en = (w2 & 0x40) ? 1 : 0;
+ other_modes.z_update_en = (w2 & 0x20) ? 1 : 0;
+ other_modes.z_compare_en = (w2 & 0x10) ? 1 : 0;
+ other_modes.antialias_en = (w2 & 0x08) ? 1 : 0;
+ other_modes.z_source_sel = (w2 & 0x04) ? 1 : 0;
+ other_modes.dither_alpha_en = (w2 & 0x02) ? 1 : 0;
+ other_modes.alpha_compare_en = (w2 & 0x01) ? 1 : 0;
+
+ SET_BLENDER_INPUT(0, 0, &blender1a_r[0], &blender1a_g[0], &blender1a_b[0], &blender1b_a[0],
+ other_modes.blend_m1a_0, other_modes.blend_m1b_0);
+ SET_BLENDER_INPUT(0, 1, &blender2a_r[0], &blender2a_g[0], &blender2a_b[0], &blender2b_a[0],
+ other_modes.blend_m2a_0, other_modes.blend_m2b_0);
+ SET_BLENDER_INPUT(1, 0, &blender1a_r[1], &blender1a_g[1], &blender1a_b[1], &blender1b_a[1],
+ other_modes.blend_m1a_1, other_modes.blend_m1b_1);
+ SET_BLENDER_INPUT(1, 1, &blender2a_r[1], &blender2a_g[1], &blender2a_b[1], &blender2b_a[1],
+ other_modes.blend_m2a_1, other_modes.blend_m2b_1);
+
+// mame_printf_debug("blend: m1a = %d, m1b = %d, m2a = %d, m2b = %d\n", other_modes.blend_m1a_0, other_modes.blend_m1b_0, other_modes.blend_m2a_0, other_modes.blend_m2b_0);
+
+ switch (other_modes.rgb_dither_sel)
+ {
+ case 0: break;
+ case 1: break; //fatalerror("bayer matrix dither\n"); break;
+ case 2: break; /////fatalerror("noise dither\n"); break;
+ case 3: break;
+ }
+}
+
+static void rdp_load_tlut(UINT32 w1, UINT32 w2)
+{
+ int i;
+ UINT16 sl, sh;
+// int tilenum = (w2 >> 24) & 0x7;
+
+ sl = ((w1 >> 12) & 0xfff) / 4;
+ sh = ((w2 >> 12) & 0xfff) / 4;
+
+ switch (ti_format)
+ {
+ case 0: // RGBA
+ {
+ switch (ti_size)
+ {
+ case PIXEL_SIZE_16BIT:
+ {
+ UINT16 *src = (UINT16*)&rdram[ti_address / 4];
+ // UINT16 *tlut = (UINT16*)&texture_cache[tile[tilenum].tmem/2];
+
+ for (i=sl; i <= sh; i++)
+ {
+ tlut[i] = src[i];
+ // mame_printf_debug("TLUT %d = %04X\n", i, tlut[i]);
+ }
+ break;
+ }
+ default: fatalerror("RDP: load_tlut: size = %d\n", ti_size);
+ }
+ break;
+ }
+
+ default: fatalerror("RDP: load_tlut: format = %d\n", ti_format);
+ }
+
+}
+
+static void rdp_set_tile_size(UINT32 w1, UINT32 w2)
+{
+ int tilenum = (w2 >> 24) & 0x7;
+
+ tile[tilenum].sl = (w1 >> 12) & 0xfff;
+ tile[tilenum].tl = (w1 >> 0) & 0xfff;
+ tile[tilenum].sh = (w2 >> 12) & 0xfff;
+ tile[tilenum].th = (w2 >> 0) & 0xfff;
+}
+
+static void rdp_load_block(UINT32 w1, UINT32 w2)
+{
+ int i, width;
+ UINT16 sl, sh, tl, dxt;
+ int tilenum = (w2 >> 24) & 0x7;
+ UINT32 *src, *tc;
+ int tb;
+
+ if (ti_format != tile[tilenum].format || ti_size != tile[tilenum].size)
+ fatalerror("RDP: load_block: format conversion required!\n");
+
+ sl = ((w1 >> 12) & 0xfff);
+ tl = ((w1 >> 0) & 0xfff) << 11;
+ sh = ((w2 >> 12) & 0xfff);
+ dxt = ((w2 >> 0) & 0xfff);
+
+ width = (sh - sl) + 1;
+
+ switch (ti_size)
+ {
+ case PIXEL_SIZE_4BIT: width >>= 1; break;
+ case PIXEL_SIZE_8BIT: break;
+ case PIXEL_SIZE_16BIT: width <<= 1; break;
+ case PIXEL_SIZE_32BIT: width <<= 2; break;
+ }
+
+
+ src = (UINT32*)&rdram[ti_address / 4];
+ tc = (UINT32*)texture_cache;
+ tb = tile[tilenum].tmem;
+
+ if (dxt != 0)
+ {
+ int j=0;
+ for (i=0; i < width; i+=2)
+ {
+ int t = j >> 11;
+
+ tc[((tb+i) + 0)] = src[((((tl * ti_width) / 4) + sl + i + 0) ^ ((t & 1) ? 1 : 0))];
+ tc[((tb+i) + 1)] = src[((((tl * ti_width) / 4) + sl + i + 1) ^ ((t & 1) ? 1 : 0))];
+
+ j += dxt;
+ }
+ }
+ else
+ {
+ for (i=0; i < width / 4; i++)
+ {
+ tc[(tb+i)] = src[((tl * ti_width) / 4) + sl + i];
+ }
+ }
+}
+
+static void rdp_load_tile(UINT32 w1, UINT32 w2)
+{
+ int i, j;
+ UINT16 sl, sh, tl, th;
+ int width, height;
+ int tilenum = (w2 >> 24) & 0x7;
+
+ if (ti_format != tile[tilenum].format || ti_size != tile[tilenum].size)
+ fatalerror("RDP: load_block: format conversion required!\n");
+
+ sl = ((w1 >> 12) & 0xfff) / 4;
+ tl = ((w1 >> 0) & 0xfff) / 4;
+ sh = ((w2 >> 12) & 0xfff) / 4;
+ th = ((w2 >> 0) & 0xfff) / 4;
+
+ width = (sh - sl) + 1;
+ height = (th - tl) + 1;
+
+ switch (ti_size)
+ {
+ case PIXEL_SIZE_8BIT:
+ {
+ UINT8 *src = (UINT8*)&rdram[ti_address / 4];
+ UINT8 *tc = (UINT8*)texture_cache;
+ int tb = tile[tilenum].tmem;
+
+ if (tb + (width * height) > 4096)
+ {
+ fatalerror("rdp_load_tile 8-bit: tmem %04X, width %d, height %d = %d\n", tile[tilenum].tmem, width, height, width*height);
+ }
+
+ for (j=0; j < height; j++)
+ {
+ int tline = tb + (tile[tilenum].line * j);
+ int s = ((j + tl) * ti_width) + sl;
+
+ for (i=0; i < width; i++)
+ {
+ tc[((tline+i) ^ BYTE_ADDR_XOR) ^ ((j & 1) ? 4 : 0)] = src[(s++) ^ BYTE_ADDR_XOR];
+ }
+ }
+ break;
+ }
+ case PIXEL_SIZE_16BIT:
+ {
+ UINT16 *src = (UINT16*)&rdram[ti_address / 4];
+ UINT16 *tc = (UINT16*)texture_cache;
+ int tb = (tile[tilenum].tmem / 2);
+
+ if (tb + (width * height) > 2048)
+ {
+ //fatalerror("rdp_load_tile 16-bit: tmem %04X, width %d, height %d = %d\n", tile[tilenum].tmem, width, height, width*height);
+ }
+
+ for (j=0; j < height; j++)
+ {
+ int tline = tb + ((tile[tilenum].line / 2) * j);
+ int s = ((j + tl) * ti_width) + sl;
+
+ for (i=0; i < width; i++)
+ {
+ tc[((tline+i) ^ WORD_ADDR_XOR) ^ ((j & 1) ? 2 : 0)] = src[(s++) ^ WORD_ADDR_XOR];
+ }
+ }
+ break;
+ }
+ case PIXEL_SIZE_32BIT:
+ {
+ UINT32 *src = (UINT32*)&rdram[ti_address / 4];
+ UINT32 *tc = (UINT32*)texture_cache;
+ int tb = (tile[tilenum].tmem / 4);
+
+ if (tb + (width * height) > 1024)
+ {
+ fatalerror("rdp_load_tile 32-bit: tmem %04X, width %d, height %d = %d\n", tile[tilenum].tmem, width, height, width*height);
+ }
+
+ for (j=0; j < height; j++)
+ {
+ int tline = tb + ((tile[tilenum].line / 4) * j);
+ int s = ((j + tl) * ti_width) + sl;
+
+ for (i=0; i < width; i++)
+ {
+ tc[(tline+i) ^ ((j & 1) ? 1 : 0)] = src[(s++)];
+ }
+ }
+ break;
+ }
+
+ default: fatalerror("RDP: load_tile: size = %d\n", ti_size);
+ }
+
+}
+
+static void rdp_set_tile(UINT32 w1, UINT32 w2)
+{
+ int tilenum = (w2 >> 24) & 0x7;
+
+ tile[tilenum].format = (w1 >> 21) & 0x7;
+ tile[tilenum].size = (w1 >> 19) & 0x3;
+ tile[tilenum].line = ((w1 >> 9) & 0x1ff) * 8;
+ tile[tilenum].tmem = ((w1 >> 0) & 0x1ff) * 8;
+ tile[tilenum].ct = (w2 >> 19) & 0x1;
+ tile[tilenum].mt = (w2 >> 18) & 0x1;
+ tile[tilenum].mask_t = (w2 >> 14) & 0xf;
+ tile[tilenum].shift_t = (w2 >> 10) & 0xf;
+ tile[tilenum].cs = (w2 >> 9) & 0x1;
+ tile[tilenum].ms = (w2 >> 8) & 0x1;
+ tile[tilenum].mask_s = (w2 >> 4) & 0xf;
+ tile[tilenum].shift_s = (w2 >> 0) & 0xf;
+
+ // TODO: clamp & mirror parameters
+}
+
+static void rdp_fill_rect(UINT32 w1, UINT32 w2)
+{
+ RECTANGLE rect;
+ rect.xl = (w1 >> 12) & 0xfff;
+ rect.yl = (w1 >> 0) & 0xfff;
+ rect.xh = (w2 >> 12) & 0xfff;
+ rect.yh = (w2 >> 0) & 0xfff;
+
+ switch (fb_size)
+ {
+ case PIXEL_SIZE_16BIT: fill_rectangle_16bit(&rect); break;
+ case PIXEL_SIZE_32BIT: fill_rectangle_32bit(&rect); break;
+ }
+}
+
+static void rdp_set_fill_color(UINT32 w1, UINT32 w2)
+{
+ fill_color = w2;
+}
+
+static void rdp_set_fog_color(UINT32 w1, UINT32 w2)
+{
+ fog_color.r = (w2 >> 24) & 0xff;
+ fog_color.g = (w2 >> 16) & 0xff;
+ fog_color.b = (w2 >> 8) & 0xff;
+ fog_color.a = (w2 >> 0) & 0xff;
+}
+
+static void rdp_set_blend_color(UINT32 w1, UINT32 w2)
+{
+ blend_color.r = (w2 >> 24) & 0xff;
+ blend_color.g = (w2 >> 16) & 0xff;
+ blend_color.b = (w2 >> 8) & 0xff;
+ blend_color.a = (w2 >> 0) & 0xff;
+}
+
+static void rdp_set_prim_color(UINT32 w1, UINT32 w2)
+{
+ // TODO: prim min level, prim_level
+ prim_color.r = (w2 >> 24) & 0xff;
+ prim_color.g = (w2 >> 16) & 0xff;
+ prim_color.b = (w2 >> 8) & 0xff;
+ prim_color.a = (w2 >> 0) & 0xff;
+}
+
+static void rdp_set_env_color(UINT32 w1, UINT32 w2)
+{
+ env_color.r = (w2 >> 24) & 0xff;
+ env_color.g = (w2 >> 16) & 0xff;
+ env_color.b = (w2 >> 8) & 0xff;
+ env_color.a = (w2 >> 0) & 0xff;
+}
+
+static void rdp_set_combine(UINT32 w1, UINT32 w2)
+{
+ combine.sub_a_rgb0 = (w1 >> 20) & 0xf;
+ combine.mul_rgb0 = (w1 >> 15) & 0x1f;
+ combine.sub_a_a0 = (w1 >> 12) & 0x7;
+ combine.mul_a0 = (w1 >> 9) & 0x7;
+ combine.sub_a_rgb1 = (w1 >> 5) & 0xf;
+ combine.mul_rgb1 = (w1 >> 0) & 0x1f;
+
+ combine.sub_b_rgb0 = (w2 >> 28) & 0xf;
+ combine.sub_b_rgb1 = (w2 >> 24) & 0xf;
+ combine.sub_a_a1 = (w2 >> 21) & 0x7;
+ combine.mul_a1 = (w2 >> 18) & 0x7;
+ combine.add_rgb0 = (w2 >> 15) & 0x7;
+ combine.sub_b_a0 = (w2 >> 12) & 0x7;
+ combine.add_a0 = (w2 >> 9) & 0x7;
+ combine.add_rgb1 = (w2 >> 6) & 0x7;
+ combine.sub_b_a1 = (w2 >> 3) & 0x7;
+ combine.add_a1 = (w2 >> 0) & 0x7;
+
+ SET_SUBA_RGB_INPUT(&combiner_rgbsub_a_r[0], &combiner_rgbsub_a_g[0], &combiner_rgbsub_a_b[0], combine.sub_a_rgb0);
+ SET_SUBB_RGB_INPUT(&combiner_rgbsub_b_r[0], &combiner_rgbsub_b_g[0], &combiner_rgbsub_b_b[0], combine.sub_b_rgb0);
+ SET_MUL_RGB_INPUT(&combiner_rgbmul_r[0], &combiner_rgbmul_g[0], &combiner_rgbmul_b[0], combine.mul_rgb0);
+ SET_ADD_RGB_INPUT(&combiner_rgbadd_r[0], &combiner_rgbadd_g[0], &combiner_rgbadd_b[0], combine.add_rgb0);
+ SET_SUB_ALPHA_INPUT(&combiner_alphasub_a[0], combine.sub_a_a0);
+ SET_SUB_ALPHA_INPUT(&combiner_alphasub_b[0], combine.sub_b_a0);
+ SET_MUL_ALPHA_INPUT(&combiner_alphamul[0], combine.mul_a0);
+ SET_SUB_ALPHA_INPUT(&combiner_alphaadd[0], combine.add_a0);
+
+ SET_SUBA_RGB_INPUT(&combiner_rgbsub_a_r[1], &combiner_rgbsub_a_g[1], &combiner_rgbsub_a_b[1], combine.sub_a_rgb1);
+ SET_SUBB_RGB_INPUT(&combiner_rgbsub_b_r[1], &combiner_rgbsub_b_g[1], &combiner_rgbsub_b_b[1], combine.sub_b_rgb1);
+ SET_MUL_RGB_INPUT(&combiner_rgbmul_r[1], &combiner_rgbmul_g[1], &combiner_rgbmul_b[1], combine.mul_rgb1);
+ SET_ADD_RGB_INPUT(&combiner_rgbadd_r[1], &combiner_rgbadd_g[1], &combiner_rgbadd_b[1], combine.add_rgb1);
+ SET_SUB_ALPHA_INPUT(&combiner_alphasub_a[1], combine.sub_a_a1);
+ SET_SUB_ALPHA_INPUT(&combiner_alphasub_b[1], combine.sub_b_a1);
+ SET_MUL_ALPHA_INPUT(&combiner_alphamul[1], combine.mul_a1);
+ SET_SUB_ALPHA_INPUT(&combiner_alphaadd[1], combine.add_a1);
+}
+
+static void rdp_set_texture_image(UINT32 w1, UINT32 w2)
+{
+ ti_format = (w1 >> 21) & 0x7;
+ ti_size = (w1 >> 19) & 0x3;
+ ti_width = (w1 & 0x3ff) + 1;
+ ti_address = w2 & 0x01ffffff;
+}
+
+static void rdp_set_mask_image(UINT32 w1, UINT32 w2)
+{
+ zb_address = w2 & 0x01ffffff;
+}
+
+static void rdp_set_color_image(UINT32 w1, UINT32 w2)
+{
+ fb_format = (w1 >> 21) & 0x7;
+ fb_size = (w1 >> 19) & 0x3;
+ fb_width = (w1 & 0x3ff) + 1;
+ fb_address = w2 & 0x01ffffff;
+
+ //if (fb_format != 0) fatalerror("rdp_set_color_image: format = %d\n", fb_format);
+ if (fb_format != 0) fb_format = 0;
+}
+
+/*****************************************************************************/
+
+static void (* rdp_command_table[64])(UINT32 w1, UINT32 w2) =
+{
+ /* 0x00 */
+ rdp_noop, rdp_invalid, rdp_invalid, rdp_invalid,
+ rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid,
+ rdp_tri_noshade, rdp_tri_noshade_z, rdp_tri_tex, rdp_tri_tex_z,
+ rdp_tri_shade, rdp_tri_shade_z, rdp_tri_texshade, rdp_tri_texshade_z,
+ /* 0x10 */
+ rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid,
+ rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid,
+ rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid,
+ rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid,
+ /* 0x20 */
+ rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid,
+ rdp_tex_rect, rdp_tex_rect_flip, rdp_sync_load, rdp_sync_pipe,
+ rdp_sync_tile, rdp_sync_full, rdp_set_key_gb, rdp_set_key_r,
+ rdp_set_convert, rdp_set_scissor, rdp_set_prim_depth, rdp_set_other_modes,
+ /* 0x30 */
+ rdp_load_tlut, rdp_invalid, rdp_set_tile_size, rdp_load_block,
+ rdp_load_tile, rdp_set_tile, rdp_fill_rect, rdp_set_fill_color,
+ rdp_set_fog_color, rdp_set_blend_color, rdp_set_prim_color, rdp_set_env_color,
+ rdp_set_combine, rdp_set_texture_image, rdp_set_mask_image, rdp_set_color_image
+};
+
+void rdp_process_list(void)
+{
+ int i;
+ UINT32 cmd, length, cmd_length;
+
+ length = dp_end - dp_current;
+
+ // load command data
+ for (i=0; i < length; i += 4)
+ {
+ rdp_cmd_data[rdp_cmd_ptr++] = READ_RDP_DATA(dp_current + i);
+ if (rdp_cmd_ptr >= 0x1000)
+ {
+ fatalerror("rdp_process_list: rdp_cmd_ptr overflow\n");
+ }
+ }
+
+ dp_current = dp_end;
+
+ cmd = (rdp_cmd_data[0] >> 24) & 0x3f;
+ cmd_length = (rdp_cmd_ptr + 1) * 4;
+
+ // check if more data is needed
+ if (cmd_length < rdp_command_length[cmd])
+ {
+ return;
+ }
+
+ while (rdp_cmd_cur < rdp_cmd_ptr)
+ {
+ cmd = (rdp_cmd_data[rdp_cmd_cur] >> 24) & 0x3f;
+ // if (((rdp_cmd_data[rdp_cmd_cur] >> 24) & 0xc0) != 0xc0)
+ // {
+ // fatalerror("rdp_process_list: invalid rdp command %08X at %08X\n", rdp_cmd_data[rdp_cmd_cur], dp_start+(rdp_cmd_cur * 4));
+ // }
+
+ if (((rdp_cmd_ptr-rdp_cmd_cur) * 4) < rdp_command_length[cmd])
+ {
+ return;
+ //fatalerror("rdp_process_list: not enough rdp command data: cur = %d, ptr = %d, expected = %d\n", rdp_cmd_cur, rdp_cmd_ptr, rdp_command_length[cmd]);
+ }
+
+#if LOG_RDP_EXECUTION
+ {
+ char string[4000];
+ rdp_dasm(string);
+
+ fprintf(rdp_exec, "%08X: %08X %08X %s\n", dp_start+(rdp_cmd_cur * 4), rdp_cmd_data[rdp_cmd_cur+0], rdp_cmd_data[rdp_cmd_cur+1], string);
+ }
+#endif
+
+ // execute the command
+ rdp_command_table[cmd](rdp_cmd_data[rdp_cmd_cur+0], rdp_cmd_data[rdp_cmd_cur+1]);
+
+ rdp_cmd_cur += rdp_command_length[cmd] / 4;
+ };
+ rdp_cmd_ptr = 0;
+ rdp_cmd_cur = 0;
+
+ dp_start = dp_end;
+}
diff --git a/src/mame/video/n8080.c b/src/mame/video/n8080.c
new file mode 100644
index 00000000000..8c42fc4b518
--- /dev/null
+++ b/src/mame/video/n8080.c
@@ -0,0 +1,405 @@
+/***************************************************************************
+
+ Nintendo 8080 video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/n8080.h"
+#include <math.h>
+
+int spacefev_red_screen;
+int spacefev_red_cannon;
+
+int helifire_flash;
+
+static emu_timer* cannon_timer;
+
+static int sheriff_color_mode;
+static int sheriff_color_data;
+
+static UINT8 helifire_LSFR[63];
+
+static unsigned helifire_mv;
+static unsigned helifire_sc; /* IC56 */
+
+
+WRITE8_HANDLER( n8080_video_control_w )
+{
+ sheriff_color_mode = (data >> 3) & 3;
+ sheriff_color_data = (data >> 0) & 7;
+
+ flip_screen = data & 0x20;
+}
+
+
+PALETTE_INIT( n8080 )
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ palette_set_color_rgb(machine,i,pal1bit(i >> 0),pal1bit(i >> 1),pal1bit(i >> 2));
+}
+
+
+PALETTE_INIT( helifire )
+{
+ int i;
+
+ palette_init_n8080(machine, NULL, NULL);
+
+ for (i = 0; i < 0x100; i++)
+ {
+ int level = 0xff * exp(-3 * i / 255.); /* capacitor discharge */
+
+ palette_set_color(machine,0x000 + 8 + i, MAKE_RGB(0x00, 0x00, level)); /* shades of blue */
+ palette_set_color(machine,0x100 + 8 + i, MAKE_RGB(0x00, 0xC0, level)); /* shades of blue w/ green star */
+
+ palette_set_color(machine,0x200 + 8 + i, MAKE_RGB(level, 0x00, 0x00)); /* shades of red */
+ palette_set_color(machine,0x300 + 8 + i, MAKE_RGB(level, 0xC0, 0x00)); /* shades of red w/ green star */
+ }
+}
+
+
+void spacefev_start_red_cannon(void)
+{
+ spacefev_red_cannon = 1;
+
+ timer_adjust(cannon_timer, ATTOTIME_IN_USEC(550 * 68 * 10), 0, attotime_zero);
+}
+
+
+static TIMER_CALLBACK( spacefev_stop_red_cannon )
+{
+ spacefev_red_cannon = 0;
+
+ timer_adjust(cannon_timer, attotime_never, 0, attotime_never);
+}
+
+
+static void helifire_next_line(void)
+{
+ helifire_mv++;
+
+ if (helifire_sc % 4 == 2)
+ {
+ helifire_mv %= 256;
+ }
+ else
+ {
+ if (flip_screen)
+ {
+ helifire_mv %= 255;
+ }
+ else
+ {
+ helifire_mv %= 257;
+ }
+ }
+
+ if (helifire_mv == 128)
+ {
+ helifire_sc++;
+ }
+}
+
+
+VIDEO_START( spacefev )
+{
+ cannon_timer = timer_alloc(spacefev_stop_red_cannon);
+
+ flip_screen = 0;
+
+ spacefev_red_screen = 0;
+ spacefev_red_cannon = 0;
+}
+
+
+VIDEO_START( sheriff )
+{
+ flip_screen = 0;
+
+ sheriff_color_mode = 0;
+ sheriff_color_data = 0;
+}
+
+
+VIDEO_START( helifire )
+{
+ UINT8 data = 0;
+
+ int i;
+
+ helifire_mv = 0;
+ helifire_sc = 0;
+
+ for (i = 0; i < 63; i++)
+ {
+ int bit =
+ (data >> 6) ^
+ (data >> 7) ^ 1;
+
+ data = (data << 1) | (bit & 1);
+
+ helifire_LSFR[i] = data;
+ }
+
+ flip_screen = 0;
+
+ helifire_flash = 0;
+}
+
+
+VIDEO_UPDATE( spacefev )
+{
+ UINT8 mask = flip_screen ? 0xff : 0x00;
+
+ int x;
+ int y;
+
+ const UINT8* pRAM = videoram;
+
+ for (y = 0; y < 256; y++)
+ {
+ UINT16* pLine = BITMAP_ADDR16(bitmap, y ^ mask, 0);
+
+ for (x = 0; x < 256; x += 8)
+ {
+ int n;
+
+ UINT8 color = 0;
+
+ if (spacefev_red_screen)
+ {
+ color = 1;
+ }
+ else
+ {
+ UINT8 val = memory_region(REGION_PROMS)[x >> 3];
+
+ if ((x >> 3) == 0x06)
+ {
+ color = spacefev_red_cannon ? 1 : 7;
+ }
+
+ if ((x >> 3) == 0x1b)
+ {
+ static const UINT8 ufo_color[] =
+ {
+ 1, /* red */
+ 2, /* green */
+ 7, /* white */
+ 3, /* yellow */
+ 5, /* magenta */
+ 6, /* cyan */
+ };
+
+ int cycle = cpu_getcurrentframe() / 32;
+
+ color = ufo_color[cycle % 6];
+ }
+
+ for (n = color + 1; n < 8; n++)
+ {
+ if (~val & (1 << n))
+ {
+ color = n;
+ }
+ }
+ }
+
+ for (n = 0; n < 8; n++)
+ {
+ pLine[(x + n) ^ mask] = (pRAM[x >> 3] & (1 << n)) ? color : 0;
+ }
+ }
+
+ pRAM += 32;
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( sheriff )
+{
+ UINT8 mask = flip_screen ? 0xff : 0x00;
+
+ const UINT8* pPROM = memory_region(REGION_PROMS);
+
+ int x;
+ int y;
+
+ const UINT8* pRAM = videoram;
+
+ for (y = 0; y < 256; y++)
+ {
+ UINT16* pLine = BITMAP_ADDR16(bitmap, y ^ mask, 0);
+
+ for (x = 0; x < 256; x += 8)
+ {
+ int n;
+
+ UINT8 color = pPROM[32 * (y >> 3) + (x >> 3)];
+
+ if (sheriff_color_mode == 1 && !(color & 8))
+ {
+ color = sheriff_color_data ^ 7;
+ }
+
+ if (sheriff_color_mode == 2)
+ {
+ color = sheriff_color_data ^ 7;
+ }
+
+ if (sheriff_color_mode == 3)
+ {
+ color = 7;
+ }
+
+ for (n = 0; n < 8; n++)
+ {
+ pLine[(x + n) ^ mask] = ((pRAM[x >> 3] >> n) & 1) ? (color & 7) : 0;
+ }
+ }
+
+ pRAM += 32;
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( helifire )
+{
+ int SUN_BRIGHTNESS = readinputport(4);
+ int SEA_BRIGHTNESS = readinputport(5);
+
+ static const int wave[8] = { 0, 1, 2, 2, 2, 1, 0, 0 };
+
+ unsigned saved_mv = helifire_mv;
+ unsigned saved_sc = helifire_sc;
+
+ int x;
+ int y;
+
+ for (y = 0; y < 256; y++)
+ {
+ UINT16* pLine = BITMAP_ADDR16(bitmap, y, 0);
+
+ int level = 120 + wave[helifire_mv & 7];
+
+ /* draw sky */
+
+ for (x = level; x < 256; x++)
+ {
+ pLine[x] = 0x200 + 8 + SUN_BRIGHTNESS + x - level;
+ }
+
+ /* draw stars */
+
+ if (helifire_mv % 8 == 4) /* upper half */
+ {
+ int step = (320 * (helifire_mv - 0)) % sizeof helifire_LSFR;
+
+ int data =
+ ((helifire_LSFR[step] & 1) << 6) |
+ ((helifire_LSFR[step] & 2) << 4) |
+ ((helifire_LSFR[step] & 4) << 2) |
+ ((helifire_LSFR[step] & 8) << 0);
+
+ pLine[0x80 + data] |= 0x100;
+ }
+
+ if (helifire_mv % 8 == 5) /* lower half */
+ {
+ int step = (320 * (helifire_mv - 1)) % sizeof helifire_LSFR;
+
+ int data =
+ ((helifire_LSFR[step] & 1) << 6) |
+ ((helifire_LSFR[step] & 2) << 4) |
+ ((helifire_LSFR[step] & 4) << 2) |
+ ((helifire_LSFR[step] & 8) << 0);
+
+ pLine[0x00 + data] |= 0x100;
+ }
+
+ /* draw sea */
+
+ for (x = 0; x < level; x++)
+ {
+ pLine[x] = 8 + SEA_BRIGHTNESS + x;
+ }
+
+ /* draw foreground */
+
+ for (x = 0; x < 256; x += 8)
+ {
+ int offset = 32 * y + (x >> 3);
+
+ int n;
+
+ for (n = 0; n < 8; n++)
+ {
+ if (flip_screen)
+ {
+ if ((videoram[offset ^ 0x1fff] << n) & 0x80)
+ {
+ pLine[x + n] = colorram[offset ^ 0x1fff] & 7;
+ }
+ }
+ else
+ {
+ if ((videoram[offset] >> n) & 1)
+ {
+ pLine[x + n] = colorram[offset] & 7;
+ }
+ }
+ }
+ }
+
+ /* next line */
+
+ helifire_next_line();
+ }
+
+ helifire_mv = saved_mv;
+ helifire_sc = saved_sc;
+ return 0;
+}
+
+
+VIDEO_EOF( helifire )
+{
+ int n = (cpu_getcurrentframe() >> 1) % sizeof helifire_LSFR;
+
+ int i;
+
+ for (i = 0; i < 8; i++)
+ {
+ int R = (i & 1);
+ int G = (i & 2);
+ int B = (i & 4);
+
+ if (helifire_flash)
+ {
+ if (helifire_LSFR[n] & 0x20)
+ {
+ G |= B;
+ }
+
+ if (cpu_getcurrentframe() & 0x04)
+ {
+ R |= G;
+ }
+ }
+
+ palette_set_color_rgb(machine,i,
+ R ? 255 : 0,
+ G ? 255 : 0,
+ B ? 255 : 0);
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ helifire_next_line();
+ }
+}
diff --git a/src/mame/video/namcofl.c b/src/mame/video/namcofl.c
new file mode 100644
index 00000000000..2bda14eebcf
--- /dev/null
+++ b/src/mame/video/namcofl.c
@@ -0,0 +1,184 @@
+/* video/namcofl.c */
+
+#include "driver.h"
+#include "namconb1.h"
+#include "namcoic.h"
+#include "namcos2.h"
+
+//UINT32 *namcofl_spritebank32;
+//UINT32 *namcofl_tilebank32;
+UINT32 *namcofl_mcuram;
+
+static UINT32 namcofl_sprbank;
+
+/* nth_word32 is a general-purpose utility function, which allows us to
+ * read from 32-bit aligned memory as if it were an array of 16 bit words.
+ */
+INLINE UINT16
+nth_word32( const UINT32 *source, int which )
+{
+ source += which/2;
+ which ^= 1; /* i960 is little-endian */
+ if( which&1 )
+ {
+ return (*source)&0xffff;
+ }
+ else
+ {
+ return (*source)>>16;
+ }
+}
+
+/* nth_byte32 is a general-purpose utility function, which allows us to
+ * read from 32-bit aligned memory as if it were an array of bytes.
+ */
+INLINE UINT8
+nth_byte32( const UINT32 *pSource, int which )
+{
+ UINT32 data = pSource[which/4];
+
+ which ^= 3; /* i960 is little-endian */
+ switch( which&3 )
+ {
+ case 0: return data>>24;
+ case 1: return (data>>16)&0xff;
+ case 2: return (data>>8)&0xff;
+ default: return data&0xff;
+ }
+} /* nth_byte32 */
+
+static void namcofl_install_palette(running_machine *machine)
+{
+ int pen, page, dword_offset, byte_offset;
+ UINT32 r,g,b;
+ UINT32 *pSource;
+
+ /* this is unnecessarily expensive. Better would be to mark palette entries dirty as
+ * they are modified, and only process those that have changed.
+ */
+ pen = 0;
+ for( page=0; page<4; page++ )
+ {
+ pSource = &paletteram32[page*0x2000/4];
+ for( dword_offset=0; dword_offset<0x800/4; dword_offset++ )
+ {
+ r = pSource[dword_offset+0x0000/4];
+ g = pSource[dword_offset+0x0800/4];
+ b = pSource[dword_offset+0x1000/4];
+
+ for( byte_offset=0; byte_offset<4; byte_offset++ )
+ {
+ palette_set_color_rgb( machine, pen++, r&0xff, g&0xff, b&0xff);
+ r>>=8; g>>=8; b>>=8;
+ }
+ }
+ }
+}
+
+/**
+ * MCU simulation. It manages coinage and input ports.
+ */
+
+static UINT8 credits1, credits2;
+ static int old_coin_state;
+
+static void
+handle_mcu( void )
+ {
+ UINT8 *IORAM = (UINT8 *)namcofl_mcuram;
+ static int toggle;
+ int new_coin_state = readinputport(3)&0x30;
+ unsigned p1 = readinputport(0);
+ unsigned p2 = readinputport(2);
+ unsigned p3 = readinputport(1);
+ unsigned p4 = readinputport(3);
+
+ IORAM[BYTE4_XOR_LE(0x6000)] = p1;
+ IORAM[BYTE4_XOR_LE(0x6003)] = p2;
+ IORAM[BYTE4_XOR_LE(0x6005)] = p3;
+ IORAM[BYTE4_XOR_LE(0x60b8)] = p4;
+
+ IORAM[BYTE4_XOR_LE(0x6014)] = readinputport(6)-1; // handle
+ IORAM[BYTE4_XOR_LE(0x6016)] = readinputport(5); // brake
+ IORAM[BYTE4_XOR_LE(0x6018)] = readinputport(4); // accelerator
+
+ if (!(new_coin_state & 0x20) && (old_coin_state & 0x20))
+ {
+ credits1++;
+ }
+
+ if (!(new_coin_state & 0x10) && (old_coin_state & 0x10))
+ {
+ credits2++;
+ }
+
+ old_coin_state = new_coin_state;
+ IORAM[BYTE4_XOR_LE(0x601e)] = credits1;
+ IORAM[BYTE4_XOR_LE(0x6020)] = credits2;
+
+ IORAM[BYTE4_XOR_LE(0x6009)] = 0;
+
+ toggle ^= 1;
+ if (toggle)
+ { // final lap
+ IORAM[BYTE4_XOR_LE(0x6000)]|=0x80;
+ }
+ else
+ { // speed racer
+ IORAM[BYTE4_XOR_LE(0x6000)]&=0x7f;
+ }
+} /* handle_mcu */
+
+static void
+TilemapCB(UINT16 code, int *tile, int *mask )
+{
+ *tile = code;
+ *mask = code;
+}
+
+
+VIDEO_UPDATE( namcofl )
+{
+ int pri;
+
+ handle_mcu();
+ namcofl_install_palette(machine);
+
+ fillbitmap( bitmap, get_black_pen(machine), cliprect );
+
+ for( pri=0; pri<16; pri++ )
+ {
+ namco_roz_draw( bitmap,cliprect,pri );
+ if((pri&1)==0)
+ namco_tilemap_draw( bitmap, cliprect, pri>>1 );
+ namco_obj_draw(machine, bitmap, cliprect, pri );
+ }
+
+ return 0;
+}
+
+// NOTE : The two low bits toggle banks (code + 0x4000) for two
+// groups of sprites. I am unsure how to differentiate those groups
+// at this time however.
+
+WRITE32_HANDLER(namcofl_spritebank_w)
+{
+ COMBINE_DATA(&namcofl_sprbank);
+}
+
+static int FLobjcode2tile( int code )
+{
+ if ((code & 0x2000) && (namcofl_sprbank & 2)) { code += 0x4000; }
+
+ return code;
+}
+
+VIDEO_START( namcofl )
+{
+ credits1 = credits2 = 0;
+ old_coin_state = readinputport(3)&0x30;
+
+ namco_tilemap_init( NAMCONB1_TILEGFX, memory_region(NAMCONB1_TILEMASKREGION), TilemapCB );
+ namco_obj_init(NAMCONB1_SPRITEGFX,0x0,FLobjcode2tile);
+ namco_roz_init(NAMCONB1_ROTGFX,NAMCONB1_ROTMASKREGION);
+} /* namcofl_vh_start */
diff --git a/src/mame/video/namcona1.c b/src/mame/video/namcona1.c
new file mode 100644
index 00000000000..80a1fe3e1b9
--- /dev/null
+++ b/src/mame/video/namcona1.c
@@ -0,0 +1,667 @@
+/* Namco System NA1/2 Video Hardware */
+
+#include "driver.h"
+#include "namcona1.h"
+
+#define NAMCONA1_NUM_TILEMAPS 4
+
+/* public variables */
+UINT16 *namcona1_vreg;
+UINT16 *namcona1_scroll;
+UINT16 *namcona1_workram;
+UINT16 *namcona1_sparevram;
+
+/* private variables */
+static char *dirtychar;
+static char dirtygfx;
+static UINT16 *shaperam;
+static UINT16 *cgram;
+static tilemap *bg_tilemap[NAMCONA1_NUM_TILEMAPS];
+static int tilemap_palette_bank[NAMCONA1_NUM_TILEMAPS];
+static int palette_is_dirty;
+
+static void tilemap_get_info(
+ running_machine *machine,tile_data *tileinfo,int tile_index,const UINT16 *tilemap_videoram,int tilemap_color )
+{
+#ifdef LSB_FIRST
+ UINT16 *source;
+ static UINT8 mask_data[8];
+#endif
+
+ int data = tilemap_videoram[tile_index];
+ int tile = data&0xfff;
+
+ if( data&0x8000 )
+ {
+ SET_TILE_INFO( 0,tile,tilemap_color,TILE_FORCE_LAYER0 );
+ }
+ else
+ {
+ SET_TILE_INFO( 0,tile,tilemap_color,0 );
+#ifdef LSB_FIRST
+ source = shaperam+4*tile;
+ mask_data[0] = source[0]>>8;
+ mask_data[1] = source[0]&0xff;
+ mask_data[2] = source[1]>>8;
+ mask_data[3] = source[1]&0xff;
+ mask_data[4] = source[2]>>8;
+ mask_data[5] = source[2]&0xff;
+ mask_data[6] = source[3]>>8;
+ mask_data[7] = source[3]&0xff;
+ tileinfo->mask_data = mask_data;
+#else
+ tileinfo->mask_data = (UINT8 *)(shaperam+4*tile);
+#endif
+ }
+} /* tilemap_get_info */
+
+static TILE_GET_INFO( tilemap_get_info0 ){ tilemap_get_info(machine,tileinfo,tile_index,0*0x1000+videoram16,tilemap_palette_bank[0]); }
+static TILE_GET_INFO( tilemap_get_info1 ){ tilemap_get_info(machine,tileinfo,tile_index,1*0x1000+videoram16,tilemap_palette_bank[1]); }
+static TILE_GET_INFO( tilemap_get_info2 ){ tilemap_get_info(machine,tileinfo,tile_index,2*0x1000+videoram16,tilemap_palette_bank[2]); }
+static TILE_GET_INFO( tilemap_get_info3 ){ tilemap_get_info(machine,tileinfo,tile_index,3*0x1000+videoram16,tilemap_palette_bank[3]); }
+
+/*************************************************************************/
+
+WRITE16_HANDLER( namcona1_videoram_w )
+{
+ COMBINE_DATA( &videoram16[offset] );
+ tilemap_mark_tile_dirty( bg_tilemap[offset/0x1000], offset&0xfff );
+} /* namcona1_videoram_w */
+
+READ16_HANDLER( namcona1_videoram_r )
+{
+ return videoram16[offset];
+} /* namcona1_videoram_r */
+
+/*************************************************************************/
+
+static void
+UpdatePalette(running_machine *machine, int offset )
+{
+ UINT16 color;
+
+ color = paletteram16[offset];
+
+ /* -RRRRRGGGGGBBBBB */
+ palette_set_color_rgb( machine, offset, pal5bit(color >> 10), pal5bit(color >> 5), pal5bit(color >> 0));
+} /* namcona1_paletteram_w */
+
+READ16_HANDLER( namcona1_paletteram_r )
+{
+ return paletteram16[offset];
+} /* namcona1_paletteram_r */
+
+WRITE16_HANDLER( namcona1_paletteram_w )
+{
+ COMBINE_DATA( &paletteram16[offset] );
+ if( namcona1_vreg[0x8e/2] )
+ {
+ /* graphics enabled; update palette immediately */
+ UpdatePalette(Machine, offset );
+ }
+ else
+ {
+ palette_is_dirty = 1;
+ }
+}
+
+/*************************************************************************/
+
+static const gfx_layout shape_layout =
+{
+ 8,8,
+ 0x1000,
+ 1,
+ { 0 },
+ { 0,1,2,3,4,5,6,7 },
+#ifdef LSB_FIRST
+ { 8*1,8*0,8*3,8*2,8*5,8*4,8*7,8*6 },
+#else
+ { 8*0,8*1,8*2,8*3,8*4,8*5,8*6,8*7 },
+#endif
+ 8*8
+}; /* shape_layout */
+
+static const gfx_layout cg_layout =
+{
+ 8,8,
+ 0x1000,
+ 8, /* 8BPP */
+ { 0,1,2,3,4,5,6,7 },
+#ifdef LSB_FIRST
+ { 8*1,8*0,8*3,8*2,8*5,8*4,8*7,8*6 },
+#else
+ { 8*0,8*1,8*2,8*3,8*4,8*5,8*6,8*7 },
+#endif
+ { 64*0,64*1,64*2,64*3,64*4,64*5,64*6,64*7 },
+ 64*8
+}; /* cg_layout */
+
+READ16_HANDLER( namcona1_gfxram_r )
+{
+ UINT16 type = namcona1_vreg[0x0c/2];
+ if( type == 0x03 )
+ {
+ if( offset<0x4000 )
+ {
+ return shaperam[offset];
+ }
+ }
+ else if( type == 0x02 )
+ {
+ return cgram[offset];
+ }
+ return 0x0000;
+} /* namcona1_gfxram_r */
+
+WRITE16_HANDLER( namcona1_gfxram_w )
+{
+ UINT16 type = namcona1_vreg[0x0c/2];
+ UINT16 old_word;
+
+ if( type == 0x03 )
+ {
+ if( offset<0x4000 )
+ {
+ old_word = shaperam[offset];
+ COMBINE_DATA( &shaperam[offset] );
+ if( shaperam[offset]!=old_word )
+ {
+ dirtygfx = 1;
+ dirtychar[offset/4] = 1;
+ }
+ }
+ }
+ else if( type == 0x02 )
+ {
+ old_word = cgram[offset];
+ COMBINE_DATA( &cgram[offset] );
+ if( cgram[offset]!=old_word )
+ {
+ dirtygfx = 1;
+ dirtychar[offset/0x20] = 1;
+ }
+ }
+} /* namcona1_gfxram_w */
+
+static void update_gfx(running_machine *machine)
+{
+ const UINT16 *pSource = videoram16;
+ int page;
+ int i;
+
+ if( dirtygfx )
+ {
+ for( page = 0; page<4; page++ )
+ {
+ for( i=0; i<0x1000; i++ )
+ {
+ if( dirtychar[*pSource++ & 0xfff] )
+ {
+ tilemap_mark_tile_dirty( bg_tilemap[page], i );
+ }
+ }
+ }
+ for( i = 0;i < 0x1000;i++ )
+ {
+ if( dirtychar[i] )
+ {
+ dirtychar[i] = 0;
+ decodechar(machine->gfx[0],i,(UINT8 *)cgram,&cg_layout);
+ decodechar(machine->gfx[1],i,(UINT8 *)shaperam,&shape_layout);
+ }
+ }
+ dirtygfx = 0;
+ }
+} /* update_gfx */
+
+VIDEO_START( namcona1 )
+{
+ int i;
+ gfx_element *gfx0,*gfx1;
+ static tile_get_info_callback get_info[4] =
+ { tilemap_get_info0, tilemap_get_info1, tilemap_get_info2, tilemap_get_info3 };
+
+ for( i=0; i<NAMCONA1_NUM_TILEMAPS; i++ )
+ {
+ bg_tilemap[i] = tilemap_create(
+ get_info[i],
+ tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,8,8,64,64 );
+
+ tilemap_palette_bank[i] = -1;
+ }
+
+ shaperam = auto_malloc( 0x1000*4*2 );
+ cgram = auto_malloc( 0x1000*0x20*2 );
+ dirtychar = auto_malloc( 0x1000 );
+
+ gfx0 = allocgfx( &cg_layout );
+ gfx1 = allocgfx( &shape_layout );
+ gfx0->total_colors = machine->drv->total_colors/256;
+ machine->gfx[0] = gfx0;
+
+ gfx1->total_colors = machine->drv->total_colors/2;
+ machine->gfx[1] = gfx1;
+} /* namcona1_vh_start */
+
+/*************************************************************************/
+
+static void pdraw_masked_tile(running_machine *machine,
+ mame_bitmap *bitmap,
+ const rectangle *cliprect,
+ unsigned code,
+ int color,
+ int sx, int sy,
+ int flipx, int flipy,
+ int priority,
+ int bShadow )
+{
+ const gfx_element *gfx,*mask;
+ const pen_t *paldata;
+ UINT8 *gfx_addr;
+ int gfx_pitch;
+ UINT8 *mask_addr;
+ int mask_pitch;
+ int x,y;
+
+ /*
+ * custom blitter for drawing a masked 8x8x8BPP tile
+ */
+ if( sx > cliprect->min_x-8 &&
+ sy > cliprect->min_y-8 &&
+ sx <= cliprect->max_x &&
+ sy <= cliprect->max_y ) /* all-or-nothing clip */
+ {
+ gfx = machine->gfx[0];
+ mask = machine->gfx[1];
+ code %= gfx->total_elements;
+ color %= gfx->total_colors;
+ paldata = &machine->remapped_colortable[gfx->color_base + gfx->color_granularity * color];
+ gfx_addr = gfx->gfxdata + code * gfx->char_modulo;
+ gfx_pitch = gfx->line_modulo;
+ mask_addr = mask->gfxdata + code * mask->char_modulo;
+ mask_pitch = mask->line_modulo;
+
+ /* The way we render shadows makes some Emeralda text invisible.
+ * The relevant text is composed of sprites with the shadow bit set,
+ * displayed over a black backdrop.
+ */
+ if( bShadow && namcona1_gametype!=NAMCO_EMERALDA )
+ {
+ for( y=0; y<8; y++ )
+ {
+ int ypos = sy+(flipy?7-y:y);
+ if (ypos >= cliprect->min_y && ypos <= cliprect->max_y)
+ {
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, ypos, 0);
+ UINT16 *dest = BITMAP_ADDR16(bitmap, ypos, 0);
+ if( flipx )
+ {
+ dest += sx+7;
+ pri += sx+7;
+ for( x=0; x<8; x++ )
+ if (sx+x >= cliprect->min_x && sx+x <= cliprect->max_x)
+ {
+ if( mask_addr[x] )
+ { /* sprite pixel is opaque */
+ if( priority>=pri[-x] )
+ {
+ dest[-x] |= 0x1000;
+ }
+ pri[-x] = 0xff;
+ }
+ }
+ }
+ else
+ {
+ dest += sx;
+ pri += sx;
+ for( x=0; x<8; x++ )
+ if (sx+x >= cliprect->min_x && sx+x <= cliprect->max_x)
+ {
+ if( mask_addr[x] )
+ { /* sprite pixel is opaque */
+ if( priority>=pri[x] )
+ {
+ dest[x] |= 0x1000;
+ }
+ pri[x] = 0xff;
+ }
+ }
+ }
+ }
+ mask_addr += mask_pitch;
+ }
+ } /* render translucent sprite */
+ else
+ {
+ for( y=0; y<8; y++ )
+ {
+ int ypos = sy+(flipy?7-y:y);
+ if (ypos >= cliprect->min_y && ypos <= cliprect->max_y)
+ {
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, ypos, 0);
+ UINT16 *dest = BITMAP_ADDR16(bitmap, ypos, 0);
+ if( flipx )
+ {
+ dest += sx+7;
+ pri += sx+7;
+ for( x=0; x<8; x++ )
+ if (sx-x >= cliprect->min_x && sx-x <= cliprect->max_x)
+ {
+ if( mask_addr[x] )
+ { /* sprite pixel is opaque */
+ if( priority>=pri[-x] )
+ {
+ dest[-x] = paldata[gfx_addr[x]];
+ }
+ pri[-x] = 0xff;
+ }
+ }
+ }
+ else
+ {
+ dest += sx;
+ pri += sx;
+ for( x=0; x<8; x++ )
+ if (sx+x >= cliprect->min_x && sx+x <= cliprect->max_x)
+ {
+ if( mask_addr[x] )
+ { /* sprite pixel is opaque */
+ if( priority>=pri[x] )
+ {
+ dest[x] = paldata[gfx_addr[x]];
+ }
+ pri[x] = 0xff;
+ }
+ } /* next x */
+ } /* !flipx */
+ }
+ gfx_addr += gfx_pitch;
+ mask_addr += mask_pitch;
+ } /* next y */
+ } /* render normal sprite (no translucency) */
+ }
+} /* pdraw_masked_tile */
+
+static void pdraw_opaque_tile(running_machine *machine,
+ mame_bitmap *bitmap,
+ const rectangle *cliprect,
+ unsigned code,
+ int color,
+ int sx, int sy,
+ int flipx, int flipy,
+ int priority,
+ int bShadow )
+{
+ const gfx_element *gfx;
+ const pen_t *paldata;
+ UINT8 *gfx_addr;
+ int gfx_pitch;
+ int x,y;
+ int ypos;
+ UINT8 *pri;
+ UINT16 *dest;
+
+ if( sx > cliprect->min_x-8 &&
+ sy > cliprect->min_y-8 &&
+ sx <= cliprect->max_x &&
+ sy <= cliprect->max_y ) /* all-or-nothing clip */
+ {
+ gfx = machine->gfx[0];
+ code %= gfx->total_elements;
+ color %= gfx->total_colors;
+ paldata = &machine->remapped_colortable[gfx->color_base + gfx->color_granularity * color];
+ gfx_addr = gfx->gfxdata + code * gfx->char_modulo;
+ gfx_pitch = gfx->line_modulo;
+
+ for( y=0; y<8; y++ )
+ {
+ ypos = sy+(flipy?7-y:y);
+ if (ypos >= cliprect->min_y && ypos <= cliprect->max_y)
+ {
+ pri = BITMAP_ADDR8(priority_bitmap, ypos, 0);
+ dest = BITMAP_ADDR16(bitmap, ypos, 0);
+ if( flipx )
+ {
+ dest += sx+7;
+ pri += sx+7;
+ for( x=0; x<8; x++ )
+ if (sx-x >= cliprect->min_x && sx-x <= cliprect->max_x)
+ {
+ if( priority>=pri[-x] )
+ {
+ dest[-x] = paldata[gfx_addr[x]];
+ }
+ pri[-x] = 0xff;
+ }
+ }
+ else
+ {
+ dest += sx;
+ pri += sx;
+ for( x=0; x<8; x++ )
+ if (sx+x >= cliprect->min_x && sx+x <= cliprect->max_x)
+ {
+ if( priority>=pri[x] )
+ {
+ dest[x] = paldata[gfx_addr[x]];
+ }
+ pri[x] = 0xff;
+ } /* next x */
+ } /* !flipx */
+ }
+ gfx_addr += gfx_pitch;
+ } /* next y */
+ }
+} /* pdraw_opaque_tile */
+
+static const UINT8 pri_mask[8] = { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f };
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int which;
+ const UINT16 *source = spriteram16;
+ void (*drawtile)(running_machine *,
+ mame_bitmap *,
+ const rectangle *,
+ unsigned code,
+ int color,
+ int sx, int sy,
+ int flipx, int flipy,
+ int priority,
+ int bShadow );
+ UINT16 sprite_control;
+ UINT16 ypos,tile,color,xpos;
+ int priority;
+ int width,height;
+ int flipy,flipx;
+ int row,col;
+ int sx,sy;
+
+ sprite_control = namcona1_vreg[0x22/2];
+ if( sprite_control&1 ) source += 0x400; /* alternate spriteram bank */
+
+ for( which=0; which<0x100; which++ )
+ { /* max 256 sprites */
+ ypos = source[0]; /* FHHH---E YYYYYYYY flipy, height, ypos */
+ tile = source[1]; /* O???TTTT TTTTTTTT opaque tile */
+ color = source[2]; /* FSWW???B CCCC?PPP flipx, shadow, width, color, pri*/
+ xpos = source[3]; /* -------X XXXXXXXX xpos */
+
+ priority = pri_mask[color&0x7];
+ width = ((color>>12)&0x3)+1;
+ height = ((ypos>>12)&0x7)+1;
+ flipy = ypos&0x8000;
+ flipx = color&0x8000;
+
+ if( (tile&0x8000)==0 )
+ {
+ drawtile = pdraw_masked_tile;
+ }
+ else
+ {
+ drawtile = pdraw_opaque_tile;
+ }
+ for( row=0; row<height; row++ )
+ {
+ sy = (ypos&0x1ff)-30+32;
+ if( flipy )
+ {
+ sy += (height-1-row)*8;
+ }
+ else
+ {
+ sy += row*8;
+ }
+ for( col=0; col<width; col++ )
+ {
+ sx = (xpos&0x1ff)-10;
+ if( flipx )
+ {
+ sx += (width-1-col)*8;
+ }
+ else
+ {
+ sx+=col*8;
+ }
+ drawtile(machine,
+ bitmap,
+ cliprect,
+ tile + row*64+col,
+ (color>>4)&0xf,
+ ((sx+16)&0x1ff)-8,
+ ((sy+8)&0x1ff)-8,
+ flipx,flipy,
+ priority,
+ color&0x4000 /* shadow */ );
+ } /* next col */
+ } /* next row */
+ source += 4;
+ }
+} /* draw_sprites */
+
+static void draw_pixel_line( UINT16 *pDest, UINT8 *pPri, UINT16 *pSource, const pen_t *paldata )
+{
+ int x;
+ UINT16 data;
+
+ memset( pPri, 0xff, 38*8 );
+ for( x=0; x<38*8; x+=2 )
+ {
+ data = *pSource++;
+ pDest[x] = paldata[data>>8];
+ pDest[x+1] = paldata[data&0xff];
+ } /* next x */
+} /* draw_pixel_line */
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int which, int primask )
+{
+ /* scrollx lineselect
+ * tmap0 ffe000 ffe200
+ * tmap1 ffe400 ffe600
+ * tmap2 ffe800 ffea00
+ * tmap3 ffec00 ffee00
+ */
+ int xadjust = 0x3a - which*2;
+ const UINT16 *scroll = namcona1_scroll+0x200*which;
+ int line;
+ UINT16 xdata, ydata;
+ int scrollx, scrolly;
+ rectangle clip;
+ const pen_t *paldata;
+ gfx_element *pGfx;
+
+ pGfx = machine->gfx[0];
+ paldata = &machine->remapped_colortable[pGfx->color_base + pGfx->color_granularity * tilemap_palette_bank[which]];
+
+ /* draw one scanline at a time */
+ clip.min_x = cliprect->min_x;
+ clip.max_x = cliprect->max_x;
+ scrollx = 0;
+ scrolly = 0;
+ for( line=0; line<256; line++ )
+ {
+ clip.min_y = line;
+ clip.max_y = line;
+ xdata = scroll[line];
+ if( xdata )
+ {
+ /* screenwise linescroll */
+ scrollx = xadjust+xdata;
+ }
+ ydata = scroll[line+0x100];
+ if( ydata&0x4000 )
+ {
+ /* line select: dword offset from 0xff000 or tilemap source line */
+ scrolly = (ydata - line)&0x1ff;
+ }
+
+ if (line >= cliprect->min_y && line <= cliprect->max_y)
+ {
+ if( xdata == 0xc001 )
+ {
+ /* This is a simplification, but produces the correct behavior for the only game that uses this
+ * feature, Numan Athletics.
+ */
+ draw_pixel_line(
+ BITMAP_ADDR16(bitmap, line, 0),
+ BITMAP_ADDR8(priority_bitmap, line, 0),
+ namcona1_sparevram + (ydata-0x4000) + 25,
+ paldata );
+ }
+ else
+ {
+ tilemap_set_scrollx( bg_tilemap[which], 0, scrollx );
+ tilemap_set_scrolly( bg_tilemap[which], 0, scrolly );
+ tilemap_draw( bitmap, &clip, bg_tilemap[which], 0, primask );
+ }
+ }
+ }
+} /* draw_background */
+
+VIDEO_UPDATE( namcona1 )
+{
+ int which;
+ int priority;
+ /* int flipscreen = namcona1_vreg[0x98/2]; (TBA) */
+
+ if( namcona1_vreg[0x8e/2] )
+ { /* gfx enabled */
+ if( palette_is_dirty )
+ {
+ /* palette updates are delayed when graphics are disabled */
+ for( which=0; which<0x1000; which++ )
+ {
+ UpdatePalette(machine, which );
+ }
+ palette_is_dirty = 0;
+ }
+ update_gfx(machine);
+ for( which=0; which<NAMCONA1_NUM_TILEMAPS; which++ )
+ {
+ static int tilemap_color;
+ tilemap_color = namcona1_vreg[0x58+(which&3)]&0xf;
+ if( tilemap_color!=tilemap_palette_bank[which] )
+ {
+ tilemap_mark_all_tiles_dirty( bg_tilemap[which] );
+ tilemap_palette_bank[which] = tilemap_color;
+ }
+ } /* next tilemap */
+ fillbitmap( priority_bitmap,0,cliprect );
+ fillbitmap( bitmap,0,cliprect );
+ for( priority = 0; priority<8; priority++ )
+ {
+ for( which=NAMCONA1_NUM_TILEMAPS-1; which>=0; which-- )
+ {
+ if( (namcona1_vreg[0x50+which]&0x7) == priority )
+ {
+ draw_background(machine,bitmap,cliprect,which,pri_mask[priority] );
+ }
+ } /* next tilemap */
+ } /* next priority level */
+ draw_sprites(machine,bitmap,cliprect);
+ } /* gfx enabled */
+ return 0;
+}
diff --git a/src/mame/video/namconb1.c b/src/mame/video/namconb1.c
new file mode 100644
index 00000000000..e3e4c8bc693
--- /dev/null
+++ b/src/mame/video/namconb1.c
@@ -0,0 +1,289 @@
+/* video/namconb1.c */
+
+#include "driver.h"
+#include "namconb1.h"
+#include "namcoic.h"
+#include "namcos2.h"
+
+static UINT32 tilemap_tile_bank[4];
+
+/* nth_word32 is a general-purpose utility function, which allows us to
+ * read from 32-bit aligned memory as if it were an array of 16 bit words.
+ */
+INLINE UINT16
+nth_word32( const UINT32 *source, int which )
+{
+ source += which/2;
+ if( which&1 )
+ {
+ return (*source)&0xffff;
+ }
+ else
+ {
+ return (*source)>>16;
+ }
+}
+
+/* nth_byte32 is a general-purpose utility function, which allows us to
+ * read from 32-bit aligned memory as if it were an array of bytes.
+ */
+INLINE UINT8
+nth_byte32( const UINT32 *pSource, int which )
+{
+ UINT32 data = pSource[which/4];
+ switch( which&3 )
+ {
+ case 0: return data>>24;
+ case 1: return (data>>16)&0xff;
+ case 2: return (data>>8)&0xff;
+ default: return data&0xff;
+ }
+} /* nth_byte32 */
+
+static void
+NB1TilemapCB(UINT16 code, int *tile, int *mask )
+{
+ *tile = code;
+ *mask = code;
+} /* NB1TilemapCB */
+
+static void
+NB2TilemapCB(UINT16 code, int *tile, int *mask )
+{
+ int mangle;
+
+ if( namcos2_gametype == NAMCONB2_MACH_BREAKERS )
+ {
+ /* 00010203 04050607 00010203 04050607 (normal) */
+ /* 00010718 191a1b07 00010708 090a0b07 (alt bank) */
+ int bank = nth_byte32( namconb1_tilebank32, (code>>13)+8 );
+ mangle = (code&0x1fff) + bank*0x2000;
+ *tile = mangle;
+ *mask = mangle;
+ }
+ else
+ {
+ /* the pixmap index is mangled, the transparency bitmask index is not */
+ mangle = code&~(0x140);
+ if( code&0x100 ) mangle |= 0x040;
+ if( code&0x040 ) mangle |= 0x100;
+ *tile = mangle;
+ *mask = code;
+ }
+} /* NB2TilemapCB */
+
+static void namconb1_install_palette(running_machine *machine)
+{
+ int pen, page, dword_offset, byte_offset;
+ UINT32 r,g,b;
+ UINT32 *pSource;
+
+ /**
+ * This is unnecessarily expensive. Better would be to mark palette entries dirty as
+ * they are modified, and only process those that have changed.
+ */
+ pen = 0;
+ for( page=0; page<4; page++ )
+ {
+ pSource = &paletteram32[page*0x2000/4];
+ for( dword_offset=0; dword_offset<0x800/4; dword_offset++ )
+ {
+ r = pSource[dword_offset+0x0000/4];
+ g = pSource[dword_offset+0x0800/4];
+ b = pSource[dword_offset+0x1000/4];
+
+ for( byte_offset=0; byte_offset<4; byte_offset++ )
+ {
+ palette_set_color_rgb( machine, pen++, r>>24, g>>24, b>>24 );
+ r<<=8; g<<=8; b<<=8;
+ }
+ }
+ }
+} /* namconb1_install_palette */
+
+/**
+ * MCU simulation. It manages coinage, input ports, and presumably
+ * communication with the sound CPU.
+ */
+static void
+handle_mcu( void )
+{
+ static int toggle;
+ static UINT16 credits;
+ static int old_coin_state;
+ static int old_p1;
+ static int old_p2;
+ static int old_p3;
+ static int old_p4;
+ int new_coin_state = readinputport(0)&0x3; /* coin1,2 */
+ unsigned dsw = readinputport(1)<<16;
+ unsigned p1 = readinputport(2);
+ unsigned p2 = readinputport(3);
+ unsigned p3;
+ unsigned p4;
+ toggle = !toggle;
+ if( toggle ) dsw &= ~(0x80<<16);
+ if( namcos2_gametype == NAMCONB2_MACH_BREAKERS )
+ {
+ p3 = readinputport(4);
+ p4 = readinputport(5);
+ }
+ else
+ {
+ p3 = 0;
+ p4 = 0;
+ }
+
+ p1 = (p1&(~old_p1))|(p1<<8);
+ p2 = (p2&(~old_p2))|(p2<<8);
+ p3 = (p3&(~old_p3))|(p3<<8);
+ p4 = (p4&(~old_p4))|(p4<<8);
+
+ old_p1 = p1;
+ old_p2 = p2;
+ old_p3 = p3;
+ old_p4 = p4;
+
+ namconb1_workram32[0x6000/4] = dsw|p1;
+ namconb1_workram32[0x6004/4] = (p2<<16)|p3;
+ namconb1_workram32[0x6008/4] = p4<<16;
+
+ if( new_coin_state && !old_coin_state )
+ {
+ credits++;
+ }
+ old_coin_state = new_coin_state;
+ namconb1_workram32[0x601e/4] &= 0xffff0000;
+ namconb1_workram32[0x601e/4] |= credits;
+} /* handle_mcu */
+
+static void
+video_update_common(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int bROZ )
+{
+ int pri;
+ handle_mcu();
+ namconb1_install_palette(machine);
+
+ if( bROZ )
+ {
+ for( pri=0; pri<16; pri++ )
+ {
+ namco_roz_draw( bitmap,cliprect,pri );
+ if( (pri&1)==0 )
+ {
+ namco_tilemap_draw( bitmap, cliprect, pri/2 );
+ }
+ namco_obj_draw(machine, bitmap, cliprect, pri );
+ }
+ }
+ else
+ {
+ for( pri=0; pri<8; pri++ )
+ {
+ namco_tilemap_draw( bitmap, cliprect, pri );
+ namco_obj_draw(machine, bitmap, cliprect, pri );
+ }
+ }
+} /* video_update_common */
+
+/************************************************************************************************/
+
+VIDEO_UPDATE( namconb1 )
+{
+ /* compute window for custom screen blanking */
+ rectangle clip;
+ //004a 016a 0021 0101 0144 0020 (nebulas ray)
+ UINT32 xclip = paletteram32[0x1800/4];
+ UINT32 yclip = paletteram32[0x1804/4];
+ clip.min_x = (xclip>>16) - 0x4a;
+ clip.max_x = (xclip&0xffff) - 0x4a - 1;
+ clip.min_y = (yclip>>16) - 0x21;
+ clip.max_y = (yclip&0xffff) - 0x21 - 1;
+ /* intersect with master clip rectangle */
+ if( clip.min_x < cliprect->min_x ){ clip.min_x = cliprect->min_x; }
+ if( clip.min_y < cliprect->min_y ){ clip.min_y = cliprect->min_y; }
+ if( clip.max_x > cliprect->max_x ){ clip.max_x = cliprect->max_x; }
+ if( clip.max_y > cliprect->max_y ){ clip.max_y = cliprect->max_y; }
+
+ fillbitmap( bitmap, get_black_pen(machine), cliprect );
+
+ video_update_common( machine, bitmap, &clip, 0 );
+
+ return 0;
+}
+
+static int
+NB1objcode2tile( int code )
+{
+ int bank = nth_word32( namconb1_spritebank32, code>>11 );
+ return (code&0x7ff) + bank*0x800;
+}
+
+VIDEO_START( namconb1 )
+{
+ namco_tilemap_init( NAMCONB1_TILEGFX, memory_region(NAMCONB1_TILEMASKREGION), NB1TilemapCB );
+ namco_obj_init(NAMCONB1_SPRITEGFX,0x0,NB1objcode2tile);
+} /* namconb1 */
+
+/****************************************************************************************************/
+
+VIDEO_UPDATE( namconb2 )
+{
+ /* compute window for custom screen blanking */
+ rectangle clip;
+ //004a016a 00210101 01440020
+ UINT32 xclip = paletteram32[0x1800/4];
+ UINT32 yclip = paletteram32[0x1804/4];
+ clip.min_x = (xclip>>16) - 0x4b;
+ clip.max_x = (xclip&0xffff) - 0x4b - 1;
+ clip.min_y = (yclip>>16) - 0x21;
+ clip.max_y = (yclip&0xffff) - 0x21 - 1;
+ /* intersect with master clip rectangle */
+ if( clip.min_x < cliprect->min_x ){ clip.min_x = cliprect->min_x; }
+ if( clip.min_y < cliprect->min_y ){ clip.min_y = cliprect->min_y; }
+ if( clip.max_x > cliprect->max_x ){ clip.max_x = cliprect->max_x; }
+ if( clip.max_y > cliprect->max_y ){ clip.max_y = cliprect->max_y; }
+
+ fillbitmap( bitmap, get_black_pen(machine), cliprect );
+
+ if( memcmp(tilemap_tile_bank,namconb1_tilebank32,sizeof(tilemap_tile_bank))!=0 )
+ {
+ namco_tilemap_invalidate();
+ memcpy(tilemap_tile_bank,namconb1_tilebank32,sizeof(tilemap_tile_bank));
+ }
+ video_update_common( machine, bitmap, &clip, 1 );
+ return 0;
+}
+
+static int
+NB2objcode2tile( int code )
+{
+ int bank = nth_byte32( namconb1_spritebank32, (code>>11)&0xf );
+ code &= 0x7ff;
+ if( namcos2_gametype == NAMCONB2_MACH_BREAKERS )
+ {
+ if( bank&0x01 ) code |= 0x01*0x800;
+ if( bank&0x02 ) code |= 0x02*0x800;
+ if( bank&0x04 ) code |= 0x04*0x800;
+ if( bank&0x08 ) code |= 0x08*0x800;
+ if( bank&0x10 ) code |= 0x10*0x800;
+ if( bank&0x40 ) code |= 0x20*0x800;
+ }
+ else
+ {
+ if( bank&0x01 ) code |= 0x01*0x800;
+ if( bank&0x02 ) code |= 0x04*0x800;
+ if( bank&0x04 ) code |= 0x02*0x800;
+ if( bank&0x08 ) code |= 0x08*0x800;
+ if( bank&0x10 ) code |= 0x10*0x800;
+ if( bank&0x40 ) code |= 0x20*0x800;
+ }
+ return code;
+} /* NB2objcode2tile */
+
+VIDEO_START( namconb2 )
+{
+ namco_tilemap_init(NAMCONB1_TILEGFX, memory_region(NAMCONB1_TILEMASKREGION), NB2TilemapCB );
+ namco_obj_init(NAMCONB1_SPRITEGFX,0x0,NB2objcode2tile);
+ namco_roz_init(NAMCONB1_ROTGFX,NAMCONB1_ROTMASKREGION);
+} /* namconb2_vh_start */
diff --git a/src/mame/video/namcos1.c b/src/mame/video/namcos1.c
new file mode 100644
index 00000000000..88eac81a69a
--- /dev/null
+++ b/src/mame/video/namcos1.c
@@ -0,0 +1,420 @@
+/*******************************************************************
+
+Namco System 1 Video Hardware
+
+*******************************************************************/
+
+#include "driver.h"
+
+
+/*
+ video ram map
+ 0000-1fff : scroll playfield (0) : 64*64*2
+ 2000-3fff : scroll playfield (1) : 64*64*2
+ 4000-5fff : scroll playfield (2) : 64*64*2
+ 6000-6fff : scroll playfield (3) : 64*32*2
+ 7000-700f : ?
+ 7010-77ef : fixed playfield (4) : 36*28*2
+ 77f0-77ff : ?
+ 7800-780f : ?
+ 7810-7fef : fixed playfield (5) : 36*28*2
+ 7ff0-7fff : ?
+*/
+static UINT8 *namcos1_videoram;
+
+/*
+ paletteram map (s1ram 0x0000-0x7fff)
+ 0000-17ff : palette page0 : sprite
+ 2000-37ff : palette page1 : playfield
+ 4000-57ff : palette page2 : playfield (shadow)
+ 6000-77ff : palette page3 : work RAM
+
+ x800-x807 : CUS116 registers (visibility window)
+
+ so there is just 3x0x2000 RAM, plus the CUS116 internal registers.
+*/
+extern UINT8 *namcos1_paletteram;
+static UINT8 namcos1_cus116[0x10];
+
+/*
+ spriteram map (s1ram 0x10000-0x10fff)
+ 0000-07ff : work ram
+ 0800-0fef : sprite ram : 0x10 * 127
+ 0ff0-0fff : display control registers
+
+ 1000-1fff : playfield control registers
+*/
+static UINT8 *namcos1_spriteram;
+
+static UINT8 namcos1_playfield_control[0x20];
+
+static tilemap *bg_tilemap[6];
+static UINT8 *tilemap_maskdata;
+
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+INLINE void bg_get_info(running_machine *machine,tile_data *tileinfo,int tile_index,UINT8 *info_vram)
+{
+ int code;
+
+ tile_index <<= 1;
+ code = info_vram[tile_index + 1] + ((info_vram[tile_index] & 0x3f) << 8);
+ SET_TILE_INFO(0,code,0,0);
+ tileinfo->mask_data = &tilemap_maskdata[code << 3];
+}
+
+INLINE void fg_get_info(running_machine *machine,tile_data *tileinfo,int tile_index,UINT8 *info_vram)
+{
+ int code;
+
+ tile_index <<= 1;
+ code = info_vram[tile_index + 1] + ((info_vram[tile_index] & 0x3f) << 8);
+ SET_TILE_INFO(0,code,0,0);
+ tileinfo->mask_data = &tilemap_maskdata[code << 3];
+}
+
+static TILE_GET_INFO( bg_get_info0 ) { bg_get_info(machine,tileinfo,tile_index,&namcos1_videoram[0x0000]); }
+static TILE_GET_INFO( bg_get_info1 ) { bg_get_info(machine,tileinfo,tile_index,&namcos1_videoram[0x2000]); }
+static TILE_GET_INFO( bg_get_info2 ) { bg_get_info(machine,tileinfo,tile_index,&namcos1_videoram[0x4000]); }
+static TILE_GET_INFO( bg_get_info3 ) { bg_get_info(machine,tileinfo,tile_index,&namcos1_videoram[0x6000]); }
+static TILE_GET_INFO( fg_get_info4 ) { fg_get_info(machine,tileinfo,tile_index,&namcos1_videoram[0x7010]); }
+static TILE_GET_INFO( fg_get_info5 ) { fg_get_info(machine,tileinfo,tile_index,&namcos1_videoram[0x7810]); }
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( namcos1 )
+{
+ int i;
+
+ tilemap_maskdata = (UINT8 *)memory_region(REGION_GFX1);
+
+ /* allocate videoram */
+ namcos1_videoram = auto_malloc(0x8000);
+ namcos1_spriteram = auto_malloc(0x1000);
+
+ /* initialize playfields */
+ bg_tilemap[0] = tilemap_create(bg_get_info0,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ bg_tilemap[1] = tilemap_create(bg_get_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ bg_tilemap[2] = tilemap_create(bg_get_info2,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ bg_tilemap[3] = tilemap_create(bg_get_info3,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ bg_tilemap[4] = tilemap_create(fg_get_info4,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,36,28);
+ bg_tilemap[5] = tilemap_create(fg_get_info5,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,36,28);
+
+ tilemap_set_scrolldx(bg_tilemap[4],73,512-73);
+ tilemap_set_scrolldx(bg_tilemap[5],73,512-73);
+ tilemap_set_scrolldy(bg_tilemap[4],0x10,0x110);
+ tilemap_set_scrolldy(bg_tilemap[5],0x10,0x110);
+
+ /* register videoram to the save state system (post-allocation) */
+ state_save_register_global_pointer(namcos1_videoram, 0x8000);
+ state_save_register_global_array(namcos1_cus116);
+ state_save_register_global_pointer(namcos1_spriteram, 0x1000);
+ state_save_register_global_array(namcos1_playfield_control);
+
+ /* set table for sprite color == 0x7f */
+ for (i = 0;i <= 15;i++)
+ gfx_drawmode_table[i] = DRAWMODE_SHADOW;
+
+ /* clear paletteram */
+ memset(namcos1_paletteram, 0, 0x8000);
+ memset(namcos1_cus116, 0, 0x10);
+ for (i = 0; i < 0x2000; i++)
+ palette_set_color(machine, i, MAKE_RGB(0, 0, 0));
+
+ /* all palette entries are not affected by shadow sprites... */
+ for (i = 0;i < 0x2000;i++)
+ machine->shadow_table[machine->pens[i]] = machine->pens[i];
+ /* ... except for tilemap colors */
+ for (i = 0x0800;i < 0x1000;i++)
+ machine->shadow_table[machine->pens[i]] = machine->pens[i + 0x0800];
+
+ spriteram = &namcos1_spriteram[0x800];
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ8_HANDLER( namcos1_videoram_r )
+{
+ return namcos1_videoram[offset];
+}
+
+WRITE8_HANDLER( namcos1_videoram_w )
+{
+ namcos1_videoram[offset] = data;
+ if (offset < 0x7000)
+ { /* background 0-3 */
+ int layer = offset >> 13;
+ int num = (offset & 0x1fff) >> 1;
+ tilemap_mark_tile_dirty(bg_tilemap[layer],num);
+ }
+ else
+ { /* foreground 4-5 */
+ int layer = (offset >> 11 & 1) + 4;
+ int num = ((offset & 0x7ff) - 0x10) >> 1;
+ if (num >= 0 && num < 0x3f0)
+ tilemap_mark_tile_dirty(bg_tilemap[layer],num);
+ }
+}
+
+
+WRITE8_HANDLER( namcos1_paletteram_w )
+{
+ if (namcos1_paletteram[offset] == data)
+ return;
+
+ if ((offset & 0x1800) != 0x1800)
+ {
+ int r,g,b;
+ int color = ((offset & 0x6000) >> 2) | (offset & 0x7ff);
+
+ namcos1_paletteram[offset] = data;
+
+ offset &= ~0x1800;
+ r = namcos1_paletteram[offset];
+ g = namcos1_paletteram[offset + 0x0800];
+ b = namcos1_paletteram[offset + 0x1000];
+ palette_set_color(Machine,color,MAKE_RGB(r,g,b));
+ }
+ else
+ {
+ int i, j;
+
+ namcos1_cus116[offset & 0x0f] = data;
+
+ for (i = 0x1800; i < 0x8000; i += 0x2000)
+ {
+ offset = (offset & 0x0f) | i;
+
+ for (j = 0; j < 0x80; j++, offset += 0x10)
+ namcos1_paletteram[offset] = data;
+ }
+ }
+}
+
+
+
+static int copy_sprites;
+
+READ8_HANDLER( namcos1_spriteram_r )
+{
+ /* 0000-07ff work ram */
+ /* 0800-0fff sprite ram */
+ if (offset < 0x1000)
+ return namcos1_spriteram[offset];
+ /* 1xxx playfield control ram */
+ else
+ return namcos1_playfield_control[offset & 0x1f];
+}
+
+WRITE8_HANDLER( namcos1_spriteram_w )
+{
+ /* 0000-07ff work ram */
+ /* 0800-0fff sprite ram */
+ if (offset < 0x1000)
+ {
+ namcos1_spriteram[offset] = data;
+
+ /* a write to this offset tells the sprite chip to buffer the sprite list */
+ if (offset == 0x0ff2)
+ copy_sprites = 1;
+ }
+ /* 1xxx playfield control ram */
+ else
+ namcos1_playfield_control[offset & 0x1f] = data;
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+/*
+sprite format:
+
+0-3 scratchpad RAM
+4-9 CPU writes here, hardware copies from here to 10-15
+10 xx------ X size (16, 8, 32, 4)
+10 --x----- X flip
+10 ---xx--- X offset inside 32x32 tile
+10 -----xxx tile bank
+11 xxxxxxxx tile number
+12 xxxxxxx- color
+12 -------x X position MSB
+13 xxxxxxxx X position
+14 xxx----- priority
+14 ---xx--- Y offset inside 32x32 tile
+14 -----xx- Y size (16, 8, 32, 4)
+14 -------x Y flip
+15 xxxxxxxx Y position
+*/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const UINT8 *source = &spriteram[0x0800-0x20]; /* the last is NOT a sprite */
+ const UINT8 *finish = &spriteram[0];
+ gfx_element *gfx = machine->gfx[1];
+ gfx_element mygfx = *gfx;
+
+ int sprite_xoffs = spriteram[0x07f5] + ((spriteram[0x07f4] & 1) << 8);
+ int sprite_yoffs = spriteram[0x07f7];
+
+ while (source >= finish)
+ {
+ static const int sprite_size[4] = { 16, 8, 32, 4 };
+ int attr1 = source[10];
+ int attr2 = source[14];
+ int color = source[12];
+ int flipx = (attr1 & 0x20) >> 5;
+ int flipy = (attr2 & 0x01);
+ int sizex = sprite_size[(attr1 & 0xc0) >> 6];
+ int sizey = sprite_size[(attr2 & 0x06) >> 1];
+ int tx = (attr1 & 0x18) & (~(sizex-1));
+ int ty = (attr2 & 0x18) & (~(sizey-1));
+ int sx = source[13] + ((color & 0x01) << 8);
+ int sy = -source[15] - sizey;
+ int sprite = source[11];
+ int sprite_bank = attr1 & 7;
+ int priority = (source[14] & 0xe0) >> 5;
+ int pri_mask = (0xff << (priority + 1)) & 0xff;
+
+ sprite += sprite_bank * 256;
+ color = color >> 1;
+
+ sx += sprite_xoffs;
+ sy -= sprite_yoffs;
+
+ if (flip_screen)
+ {
+ sx = -sx - sizex;
+ sy = -sy - sizey;
+ flipx ^= 1;
+ flipy ^= 1;
+ }
+
+ sy++; /* sprites are buffered and delayed by one scanline */
+
+ /* change GfxElement parameters to draw only the needed part of the 32x32 tile */
+ mygfx.width = sizex;
+ mygfx.height = sizey;
+ mygfx.gfxdata = gfx->gfxdata + tx + ty * gfx->line_modulo;
+
+ pdrawgfx( bitmap, &mygfx,
+ sprite,
+ color,
+ flipx,flipy,
+ sx & 0x1ff,
+ ((sy + 16) & 0xff) - 16,
+ cliprect,(color != 0x7f) ? TRANSPARENCY_PEN : TRANSPARENCY_PEN_TABLE,0xf, pri_mask);
+
+ source -= 0x10;
+ }
+}
+
+
+
+VIDEO_UPDATE( namcos1 )
+{
+ int i, j, scrollx, scrolly, priority;
+ rectangle new_clip = *cliprect;
+
+ /* flip screen is embedded in the sprite control registers */
+ /* can't use flip_screen_set() because the visible area is asymmetrical */
+ flip_screen = spriteram[0x07f6] & 1;
+ tilemap_set_flip(ALL_TILEMAPS,flip_screen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+
+ /* background color */
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ /* berabohm uses asymmetrical visibility windows to iris on the character */
+ i = ((namcos1_cus116[0] << 8) | namcos1_cus116[1]) - 1; // min x
+ if (new_clip.min_x < i) new_clip.min_x = i;
+ i = ((namcos1_cus116[2] << 8) | namcos1_cus116[3]) - 1 - 1; // max x
+ if (new_clip.max_x > i) new_clip.max_x = i;
+ i = ((namcos1_cus116[4] << 8) | namcos1_cus116[5]) - 0x11; // min y
+ if (new_clip.min_y < i) new_clip.min_y = i;
+ i = ((namcos1_cus116[6] << 8) | namcos1_cus116[7]) - 0x11 - 1; // max y
+ if (new_clip.max_y > i) new_clip.max_y = i;
+
+ if (new_clip.max_x < new_clip.min_x || new_clip.max_y < new_clip.min_y)
+ return 0;
+
+
+ /* set palette base */
+ for (i = 0;i < 6;i++)
+ tilemap_set_palette_offset(bg_tilemap[i],(namcos1_playfield_control[i + 24] & 7) * 256);
+
+ for (i = 0;i < 4;i++)
+ {
+ static int disp_x[] = { 25, 27, 28, 29 };
+
+ j = i << 2;
+ scrollx = ( namcos1_playfield_control[j+1] + (namcos1_playfield_control[j+0]<<8) ) - disp_x[i];
+ scrolly = ( namcos1_playfield_control[j+3] + (namcos1_playfield_control[j+2]<<8) ) + 8;
+
+ if (flip_screen)
+ {
+ scrollx = -scrollx;
+ scrolly = -scrolly;
+ }
+
+ tilemap_set_scrollx(bg_tilemap[i],0,scrollx);
+ tilemap_set_scrolly(bg_tilemap[i],0,scrolly);
+ }
+
+
+ fillbitmap(priority_bitmap, 0, &new_clip);
+
+ /* bit 0-2 priority */
+ /* bit 3 disable */
+ for (priority = 0; priority < 8;priority++)
+ {
+ for (i = 0;i < 6;i++)
+ {
+ if (namcos1_playfield_control[16 + i] == priority)
+ tilemap_draw_primask(bitmap,&new_clip,bg_tilemap[i],0,priority,0);
+ }
+ }
+
+ draw_sprites(machine, bitmap, &new_clip);
+ return 0;
+}
+
+
+VIDEO_EOF( namcos1 )
+{
+ if (copy_sprites)
+ {
+ int i,j;
+
+ for (i = 0;i < 0x800;i += 16)
+ {
+ for (j = 10;j < 16;j++)
+ spriteram[i+j] = spriteram[i+j - 6];
+ }
+
+ copy_sprites = 0;
+ }
+}
diff --git a/src/mame/video/namcos2.c b/src/mame/video/namcos2.c
new file mode 100644
index 00000000000..39854728d6a
--- /dev/null
+++ b/src/mame/video/namcos2.c
@@ -0,0 +1,496 @@
+/* video hardware for Namco System II */
+
+#include "driver.h"
+#include "namcos2.h"
+#include "namcoic.h"
+
+UINT16 *namcos2_sprite_ram;
+UINT16 *namcos2_68k_palette_ram;
+size_t namcos2_68k_palette_size;
+//size_t namcos2_68k_roz_ram_size;
+UINT16 *namcos2_68k_roz_ram;
+
+static UINT16 namcos2_68k_roz_ctrl[0x8];
+static tilemap *tilemap_roz;
+
+static void
+TilemapCB( UINT16 code, int *tile, int *mask )
+{
+ *mask = code;
+
+ switch( namcos2_gametype )
+ {
+ case NAMCOS2_FINAL_LAP_2:
+ case NAMCOS2_FINAL_LAP_3:
+ *tile = (code&0x07ff)|((code&0x4000)>>3)|((code&0x3800)<<1);
+ break;
+
+ default:
+ /* The order of bits needs to be corrected to index the right tile 14 15 11 12 13 */
+ *tile = (code&0x07ff)|((code&0xc000)>>3)|((code&0x3800)<<2);
+ break;
+ }
+} /* TilemapCB */
+
+/**
+ * namcos2_gfx_ctrl selects a bank of 128 sprites within spriteram
+ *
+ * namcos2_gfx_ctrl also supplies palette and priority information that is applied to the output of the
+ * Namco System 2 ROZ chip
+ *
+ * -xxx ---- ---- ---- roz priority
+ * ---- xxxx ---- ---- roz palette
+ * ---- ---- xxxx ---- always zero?
+ * ---- ---- ---- xxxx sprite bank
+ */
+static UINT16 namcos2_gfx_ctrl;
+
+READ16_HANDLER( namcos2_gfx_ctrl_r )
+{
+ return namcos2_gfx_ctrl;
+} /* namcos2_gfx_ctrl_r */
+
+WRITE16_HANDLER( namcos2_gfx_ctrl_w )
+{
+ COMBINE_DATA(&namcos2_gfx_ctrl);
+} /* namcos2_gfx_ctrl_w */
+
+static TILE_GET_INFO( get_tile_info_roz )
+{
+ int tile = namcos2_68k_roz_ram[tile_index];
+ SET_TILE_INFO(3,tile,0/*color*/,0);
+} /* get_tile_info_roz */
+
+struct RozParam
+{
+ UINT32 size;
+ UINT32 startx,starty;
+ int incxx,incxy,incyx,incyy;
+ int color;
+ int wrap;
+};
+
+static void
+DrawRozHelper(
+ mame_bitmap *bitmap,
+ tilemap *tmap,
+ const rectangle *clip,
+ const struct RozParam *rozInfo )
+{
+ tilemap_set_palette_offset( tmap, rozInfo->color );
+
+ if( bitmap->bpp == 16 )
+ {
+ UINT32 size_mask = rozInfo->size-1;
+ mame_bitmap *srcbitmap = tilemap_get_pixmap( tmap );
+ mame_bitmap *flagsbitmap = tilemap_get_flagsmap( tmap );
+ UINT32 startx = rozInfo->startx + clip->min_x * rozInfo->incxx + clip->min_y * rozInfo->incyx;
+ UINT32 starty = rozInfo->starty + clip->min_x * rozInfo->incxy + clip->min_y * rozInfo->incyy;
+ int sx = clip->min_x;
+ int sy = clip->min_y;
+ while( sy <= clip->max_y )
+ {
+ int x = sx;
+ UINT32 cx = startx;
+ UINT32 cy = starty;
+ UINT16 *dest = BITMAP_ADDR16(bitmap, sy, sx);
+ while( x <= clip->max_x )
+ {
+ UINT32 xpos = (cx>>16);
+ UINT32 ypos = (cy>>16);
+ if( rozInfo->wrap )
+ {
+ xpos &= size_mask;
+ ypos &= size_mask;
+ }
+ else if( xpos>rozInfo->size || ypos>=rozInfo->size )
+ {
+ goto L_SkipPixel;
+ }
+
+ if( *BITMAP_ADDR8(flagsbitmap, ypos, xpos)&TILEMAP_PIXEL_LAYER0 )
+ {
+ *dest = *BITMAP_ADDR16(srcbitmap, ypos, xpos)+rozInfo->color;
+ }
+L_SkipPixel:
+ cx += rozInfo->incxx;
+ cy += rozInfo->incxy;
+ x++;
+ dest++;
+ } /* next x */
+ startx += rozInfo->incyx;
+ starty += rozInfo->incyy;
+ sy++;
+ } /* next y */
+ }
+ else
+ {
+ tilemap_draw_roz(
+ bitmap,
+ clip,
+ tmap,
+ rozInfo->startx, rozInfo->starty,
+ rozInfo->incxx, rozInfo->incxy,
+ rozInfo->incyx, rozInfo->incyy,
+ rozInfo->wrap,0,0); // wrap, flags, pri
+ }
+} /* DrawRozHelper */
+
+static void
+DrawROZ(mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ const int xoffset = 38,yoffset = 0;
+ struct RozParam rozParam;
+
+ rozParam.color = (namcos2_gfx_ctrl & 0x0f00);
+ rozParam.incxx = (INT16)namcos2_68k_roz_ctrl[0];
+ rozParam.incxy = (INT16)namcos2_68k_roz_ctrl[1];
+ rozParam.incyx = (INT16)namcos2_68k_roz_ctrl[2];
+ rozParam.incyy = (INT16)namcos2_68k_roz_ctrl[3];
+ rozParam.startx = (INT16)namcos2_68k_roz_ctrl[4];
+ rozParam.starty = (INT16)namcos2_68k_roz_ctrl[5];
+ rozParam.size = 2048;
+ rozParam.wrap = 1;
+
+
+ switch( namcos2_68k_roz_ctrl[7] )
+ {
+ case 0x4400: /* (2048x2048) */
+ break;
+
+ case 0x4488: /* attract mode */
+ rozParam.wrap = 0;
+ break;
+
+ case 0x44cc: /* stage1 demo */
+ rozParam.wrap = 0;
+ break;
+
+ case 0x44ee: /* (256x256) used in Dragon Saber */
+ rozParam.wrap = 0;
+ rozParam.size = 256;
+ break;
+ }
+
+ rozParam.startx <<= 4;
+ rozParam.starty <<= 4;
+ rozParam.startx += xoffset * rozParam.incxx + yoffset * rozParam.incyx;
+ rozParam.starty += xoffset * rozParam.incxy + yoffset * rozParam.incyy;
+
+ rozParam.startx<<=8;
+ rozParam.starty<<=8;
+ rozParam.incxx<<=8;
+ rozParam.incxy<<=8;
+ rozParam.incyx<<=8;
+ rozParam.incyy<<=8;
+
+ DrawRozHelper( bitmap, tilemap_roz, cliprect, &rozParam );
+}
+
+READ16_HANDLER(namcos2_68k_roz_ctrl_r)
+{
+ return namcos2_68k_roz_ctrl[offset];
+}
+
+WRITE16_HANDLER( namcos2_68k_roz_ctrl_w )
+{
+ COMBINE_DATA(&namcos2_68k_roz_ctrl[offset]);
+}
+
+READ16_HANDLER( namcos2_68k_roz_ram_r )
+{
+ return namcos2_68k_roz_ram[offset];
+}
+
+WRITE16_HANDLER( namcos2_68k_roz_ram_w )
+{
+ COMBINE_DATA(&namcos2_68k_roz_ram[offset]);
+ tilemap_mark_tile_dirty(tilemap_roz,offset);
+// if( input_code_pressed(KEYCODE_Q) )
+// {
+// DEBUGGER_BREAK;
+// }
+}
+
+/**************************************************************************/
+
+READ16_HANDLER( namcos2_68k_video_palette_r )
+{
+ if( (offset&0x1800) == 0x1800 )
+ {
+ offset &= 0x180f;
+ if( offset == 0x180d ) return 0xff;
+ if( offset == 0x180f ) return 0xff;
+ }
+ return namcos2_68k_palette_ram[offset];
+} /* namcos2_68k_video_palette_r */
+
+WRITE16_HANDLER( namcos2_68k_video_palette_w )
+{
+ if( (offset&0x1800) == 0x1800 )
+ {
+ offset &= 0x180f;
+ if( ACCESSING_LSB )
+ {
+ namcos2_68k_palette_ram[offset] = data;
+ }
+ else
+ {
+ namcos2_68k_palette_ram[offset] = data>>8;
+ }
+ }
+ else
+ {
+ COMBINE_DATA(&namcos2_68k_palette_ram[offset]);
+ }
+} /* namcos2_68k_video_palette_w */
+
+static UINT16
+GetPaletteRegister( int which )
+{
+ const UINT16 *source = &namcos2_68k_palette_ram[0x3000/2];
+ return ((source[which*2]&0xff)<<8) | (source[which*2+1]&0xff);
+}
+
+int
+namcos2_GetPosIrqScanline( void )
+{
+ /* PaleteRegister(4)? used by Finest Hour; pc=0x356e */
+ int scanline = GetPaletteRegister(5) - 34;
+ if( scanline<0 )
+ {
+ scanline = 0;
+ }
+ else if( scanline > Machine->screen[0].height )
+ {
+ scanline = Machine->screen[0].height;
+ }
+ return scanline;
+} /* namcos2_GetPosIrqScanline */
+
+static void
+UpdatePalette( void )
+{
+ int bank;
+ for( bank=0; bank<0x20; bank++ )
+ {
+ int pen = bank*256;
+ int offset = ((pen & 0x1800) << 2) | (pen & 0x07ff);
+ int i;
+ for( i=0; i<256; i++ )
+ {
+ int r = namcos2_68k_palette_ram[offset | 0x0000] & 0x00ff;
+ int g = namcos2_68k_palette_ram[offset | 0x0800] & 0x00ff;
+ int b = namcos2_68k_palette_ram[offset | 0x1000] & 0x00ff;
+ palette_set_color(Machine,pen++,MAKE_RGB(r,g,b));
+ offset++;
+ }
+ }
+} /* UpdatePalette */
+
+/**************************************************************************/
+
+static void
+DrawSpriteInit( void )
+{
+ int i;
+ /* set table for sprite color == 0x0f */
+ for(i = 0;i <= 253;i++)
+ {
+ gfx_drawmode_table[i] = DRAWMODE_SOURCE;
+ }
+ gfx_drawmode_table[254] = DRAWMODE_SHADOW;
+ gfx_drawmode_table[255] = DRAWMODE_NONE;
+ for( i = 0; i<16*256; i++ )
+ {
+ Machine->shadow_table[i] = i+0x2000;
+ }
+}
+
+WRITE16_HANDLER( namcos2_sprite_ram_w )
+{
+ COMBINE_DATA(&namcos2_sprite_ram[offset]);
+}
+
+READ16_HANDLER( namcos2_sprite_ram_r )
+{
+ return namcos2_sprite_ram[offset];
+}
+
+/**************************************************************************/
+
+VIDEO_START( namcos2 )
+{
+ namco_tilemap_init(2,memory_region(REGION_GFX4),TilemapCB);
+ tilemap_roz = tilemap_create(get_tile_info_roz,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,256,256);
+ tilemap_set_transparent_pen(tilemap_roz,0xff);
+ DrawSpriteInit();
+}
+
+static void
+ApplyClip( rectangle *clip, const rectangle *cliprect )
+{
+ clip->min_x = GetPaletteRegister(0) - 0x4a;
+ clip->max_x = GetPaletteRegister(1) - 0x4a - 1;
+ clip->min_y = GetPaletteRegister(2) - 0x21;
+ clip->max_y = GetPaletteRegister(3) - 0x21 - 1;
+ /* intersect with master clip rectangle */
+ if( clip->min_x < cliprect->min_x ){ clip->min_x = cliprect->min_x; }
+ if( clip->min_y < cliprect->min_y ){ clip->min_y = cliprect->min_y; }
+ if( clip->max_x > cliprect->max_x ){ clip->max_x = cliprect->max_x; }
+ if( clip->max_y > cliprect->max_y ){ clip->max_y = cliprect->max_y; }
+} /* ApplyClip */
+
+VIDEO_UPDATE( namcos2_default )
+{
+ rectangle clip;
+ int pri;
+
+ UpdatePalette();
+ fillbitmap( bitmap, get_black_pen(machine), cliprect );
+ ApplyClip( &clip, cliprect );
+
+ /* HACK: enable ROZ layer only if it has priority > 0 */
+ tilemap_set_enable(tilemap_roz,(namcos2_gfx_ctrl & 0x7000) ? 1 : 0);
+
+ for( pri=0; pri<16; pri++ )
+ {
+ if( (pri&1)==0 )
+ {
+ namco_tilemap_draw( bitmap, &clip, pri/2 );
+
+ if( ((namcos2_gfx_ctrl & 0x7000) >> 12)==pri/2 )
+ {
+ DrawROZ(bitmap,&clip);
+ }
+ namcos2_draw_sprites(machine, bitmap, &clip, pri/2, namcos2_gfx_ctrl );
+ }
+ }
+ return 0;
+}
+
+/**************************************************************************/
+
+VIDEO_START( finallap )
+{
+ namco_tilemap_init(2,memory_region(REGION_GFX4),TilemapCB);
+ DrawSpriteInit();
+ namco_road_init(machine, 3);
+}
+
+VIDEO_UPDATE( finallap )
+{
+ rectangle clip;
+ int pri;
+
+ UpdatePalette();
+ fillbitmap( bitmap, get_black_pen(machine), cliprect );
+ ApplyClip( &clip, cliprect );
+
+ for( pri=0; pri<16; pri++ )
+ {
+ if( (pri&1)==0 )
+ {
+ namco_tilemap_draw( bitmap, &clip, pri/2 );
+ }
+ namco_road_draw(machine, bitmap,&clip,pri );
+ namcos2_draw_sprites(machine, bitmap,&clip,pri,namcos2_gfx_ctrl );
+ }
+ return 0;
+}
+
+/**************************************************************************/
+
+VIDEO_START( luckywld )
+{
+ namco_tilemap_init(2,memory_region(REGION_GFX4),TilemapCB);
+ namco_obj_init( 0, 0x0, NULL );
+ if( namcos2_gametype==NAMCOS2_LUCKY_AND_WILD )
+ {
+ namco_roz_init( 1, REGION_GFX5 );
+ }
+ if( namcos2_gametype!=NAMCOS2_STEEL_GUNNER_2 )
+ {
+ namco_road_init(machine, 3);
+ }
+} /* luckywld */
+
+VIDEO_UPDATE( luckywld )
+{
+ rectangle clip;
+ int pri;
+
+ UpdatePalette();
+ fillbitmap( bitmap, get_black_pen(machine), cliprect );
+ ApplyClip( &clip, cliprect );
+
+ for( pri=0; pri<16; pri++ )
+ {
+ if( (pri&1)==0 )
+ {
+ namco_tilemap_draw( bitmap, &clip, pri/2 );
+ }
+ namco_road_draw(machine, bitmap,&clip,pri );
+ if( namcos2_gametype==NAMCOS2_LUCKY_AND_WILD )
+ {
+ namco_roz_draw( bitmap, &clip, pri );
+ }
+ namco_obj_draw(machine, bitmap, &clip, pri );
+ }
+ return 0;
+}
+
+/**************************************************************************/
+
+VIDEO_START( sgunner )
+{
+ namco_tilemap_init(2,memory_region(REGION_GFX4),TilemapCB);
+ namco_obj_init( 0, 0x0, NULL );
+}
+
+VIDEO_UPDATE( sgunner )
+{
+ rectangle clip;
+ int pri;
+
+ UpdatePalette();
+ fillbitmap( bitmap, get_black_pen(machine), cliprect );
+ ApplyClip( &clip, cliprect );
+
+ for( pri=0; pri<8; pri++ )
+ {
+ namco_tilemap_draw( bitmap, &clip, pri );
+ namco_obj_draw(machine, bitmap, &clip, pri );
+ }
+ return 0;
+}
+
+
+/**************************************************************************/
+
+VIDEO_START( metlhawk )
+{
+ namco_tilemap_init(2,memory_region(REGION_GFX4),TilemapCB);
+ namco_roz_init( 1, REGION_GFX5 );
+}
+
+VIDEO_UPDATE( metlhawk )
+{
+ rectangle clip;
+ int pri;
+
+ UpdatePalette();
+ fillbitmap( bitmap, get_black_pen(machine), cliprect );
+ ApplyClip( &clip, cliprect );
+
+ for( pri=0; pri<16; pri++ )
+ {
+ if( (pri&1)==0 )
+ {
+ namco_tilemap_draw( bitmap, &clip, pri/2 );
+ }
+ namco_roz_draw( bitmap, &clip, pri );
+ namcos2_draw_sprites_metalhawk(machine, bitmap,&clip,pri );
+ }
+ return 0;
+}
diff --git a/src/mame/video/namcos21.c b/src/mame/video/namcos21.c
new file mode 100644
index 00000000000..100b066b179
--- /dev/null
+++ b/src/mame/video/namcos21.c
@@ -0,0 +1,489 @@
+/***************************************************************************
+Namco System 21 Video Hardware
+
+- sprite hardware is identical to Namco System NB1
+- there are no tilemaps
+- 3d graphics are managed by DSP processors
+*/
+
+#include "driver.h"
+#include "namcos2.h"
+#include "namcoic.h"
+#include "namcos21.h"
+
+#define FRAMEBUFFER_SIZE_IN_BYTES (sizeof(UINT16)*NAMCOS21_POLY_FRAME_WIDTH*NAMCOS21_POLY_FRAME_HEIGHT)
+
+/* work (hidden) framebuffer */
+static UINT16 *mpPolyFrameBufferPens;
+static UINT16 *mpPolyFrameBufferZ;
+
+/* visible framebuffer */
+static UINT16 *mpPolyFrameBufferPens2;
+static UINT16 *mpPolyFrameBufferZ2;
+
+static UINT16 winrun_color;
+static UINT16 winrun_gpu_register[0x10/2];
+
+READ16_HANDLER(winrun_gpu_color_r)
+{
+ return winrun_color;
+}
+
+WRITE16_HANDLER(winrun_gpu_color_w)
+{
+ COMBINE_DATA( &winrun_color );
+}
+
+READ16_HANDLER(winrun_gpu_register_r)
+{
+ return winrun_gpu_register[offset];
+}
+
+WRITE16_HANDLER(winrun_gpu_register_w)
+{
+ COMBINE_DATA( &winrun_gpu_register[offset] );
+}
+
+WRITE16_HANDLER( winrun_gpu_videoram_w)
+{
+ int color = data>>8;
+ int mask = data&0xff;
+ int i;
+ for( i=0; i<8; i++ )
+ {
+ if( mask&(0x01<<i) )
+ {
+ videoram[(offset+i)&0x7ffff] = color;
+ }
+ }
+} /* winrun_gpu_videoram_w */
+
+READ16_HANDLER( winrun_gpu_videoram_r )
+{
+ return videoram[offset]<<8;
+} /* winrun_gpu_videoram_r */
+
+static void
+AllocatePolyFrameBuffer( void )
+{
+ mpPolyFrameBufferZ = auto_malloc( FRAMEBUFFER_SIZE_IN_BYTES );
+ mpPolyFrameBufferPens = auto_malloc( FRAMEBUFFER_SIZE_IN_BYTES );
+
+ mpPolyFrameBufferZ2 = auto_malloc( FRAMEBUFFER_SIZE_IN_BYTES );
+ mpPolyFrameBufferPens2 = auto_malloc( FRAMEBUFFER_SIZE_IN_BYTES );
+
+ namcos21_ClearPolyFrameBuffer();
+ namcos21_ClearPolyFrameBuffer();
+} /* AllocatePolyFrameBuffer */
+
+void
+namcos21_ClearPolyFrameBuffer( void )
+{
+ int i;
+ UINT16 *temp2;
+
+ /* swap work and visible framebuffers */
+ temp2 = mpPolyFrameBufferZ;
+ mpPolyFrameBufferZ = mpPolyFrameBufferZ2;
+ mpPolyFrameBufferZ2 = temp2;
+
+ temp2 = mpPolyFrameBufferPens;
+ mpPolyFrameBufferPens = mpPolyFrameBufferPens2;
+ mpPolyFrameBufferPens2 = temp2;
+
+ /* wipe work zbuffer */
+ for( i=0; i<NAMCOS21_POLY_FRAME_WIDTH*NAMCOS21_POLY_FRAME_HEIGHT; i++ )
+ {
+ mpPolyFrameBufferZ[i] = 0x7fff;
+ }
+} /* namcos21_ClearPolyFrameBuffer */
+
+static void
+CopyVisiblePolyFrameBuffer( mame_bitmap *bitmap, const rectangle *clip, int zlo, int zhi )
+{ /* blit the visible framebuffer */
+ int sy;
+ for( sy=clip->min_y; sy<=clip->max_y; sy++ )
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, sy, 0);
+ const UINT16 *pPen = mpPolyFrameBufferPens2+NAMCOS21_POLY_FRAME_WIDTH*sy;
+ const UINT16 *pZ = mpPolyFrameBufferZ2+NAMCOS21_POLY_FRAME_WIDTH*sy;
+ int sx;
+ for( sx=clip->min_x; sx<=clip->max_x; sx++ )
+ {
+ int z = pZ[sx];
+ //if( pZ[sx]!=0x7fff )
+ if( z>=zlo && z<=zhi )
+ {
+ dest[sx] = pPen[sx];
+ }
+ }
+ }
+} /* CopyVisiblePolyFrameBuffer */
+
+static int objcode2tile( int code )
+{ /* callback for sprite drawing code in namcoic.c */
+ return code;
+} /* objcode2tile */
+
+VIDEO_START( namcos21 )
+{
+ if( namcos2_gametype == NAMCOS21_WINRUN91 )
+ {
+ videoram = auto_malloc(0x80000);
+ }
+ AllocatePolyFrameBuffer();
+ namco_obj_init(
+ 0, /* gfx bank */
+ 0xf, /* reverse palette mapping */
+ objcode2tile );
+} /* VIDEO_START( namcos21 ) */
+
+static void
+update_palette( void )
+{
+ int i;
+ INT16 data1,data2;
+ int r,g,b;
+
+ /*
+ Palette:
+ 0x0000..0x1fff sprite palettes (0x10 sets of 0x100 colors)
+
+ 0x2000..0x3fff polygon palette bank0 (0x10 sets of 0x200 colors)
+ (in starblade, some palette animation effects are performed here)
+
+ 0x4000..0x5fff polygon palette bank1 (0x10 sets of 0x200 colors)
+
+ 0x6000..0x7fff polygon palette bank2 (0x10 sets of 0x200 colors)
+
+ The polygon-dedicated color sets within a bank typically increase in
+ intensity from very dark to full intensity.
+
+ Probably the selected palette is determined by most significant bits of z-code.
+ This is not yet hooked up.
+ */
+ for( i=0; i<NAMCOS21_NUM_COLORS; i++ )
+ {
+ data1 = paletteram16[0x00000/2+i];
+ data2 = paletteram16[0x10000/2+i];
+
+ r = data1>>8;
+ g = data1&0xff;
+ b = data2&0xff;
+
+ palette_set_color( Machine,i, MAKE_RGB(r,g,b) );
+ }
+} /* update_palette */
+
+
+VIDEO_UPDATE( namcos21 )
+{
+ int pivot = 3;
+ int pri;
+ update_palette();
+ fillbitmap( bitmap, 0xff, cliprect );
+
+ if( namcos2_gametype != NAMCOS21_WINRUN91 )
+ { /* draw low priority 2d sprites */
+ namco_obj_draw( machine, bitmap, cliprect, 2 );
+ }
+
+ CopyVisiblePolyFrameBuffer( bitmap, cliprect,0x7fc0,0x7ffe );
+
+ if( namcos2_gametype != NAMCOS21_WINRUN91 )
+ { /* draw low priority 2d sprites */
+ namco_obj_draw( machine, bitmap, cliprect, 0 );
+ namco_obj_draw( machine, bitmap, cliprect, 1 );
+ }
+
+ CopyVisiblePolyFrameBuffer( bitmap, cliprect,0,0x7fbf );
+
+
+ if( namcos2_gametype != NAMCOS21_WINRUN91 )
+ { /* draw high priority 2d sprites */
+ for( pri=pivot; pri<8; pri++ )
+ {
+ namco_obj_draw( machine, bitmap, cliprect, pri );
+ }
+ }
+ else
+ { /* winrun bitmap layer */
+ int yscroll = -cliprect->min_y+(INT16)winrun_gpu_register[0x2/2];
+ int base = 0x1000+0x100*(winrun_color&0xf);
+ int sx,sy;
+ for( sy=cliprect->min_y; sy<=cliprect->max_y; sy++ )
+ {
+ const UINT8 *pSource = &videoram[((yscroll+sy)&0x3ff)*0x200];
+ UINT16 *pDest = BITMAP_ADDR16(bitmap, sy, 0);
+ for( sx=cliprect->min_x; sx<=cliprect->max_x; sx++ )
+ {
+ int pen = pSource[sx];
+ switch( pen )
+ {
+ case 0xff:
+ break;
+ case 0x00:
+ pDest[sx] = (pDest[sx]&0x1fff)+0x4000;
+ break;
+ case 0x01:
+ pDest[sx] = (pDest[sx]&0x1fff)+0x6000;
+ break;
+ default:
+ pDest[sx] = base|pen;
+ break;
+ }
+ }
+ }
+ } /* winrun bitmap layer */
+ return 0;
+} /* VIDEO_UPDATE( namcos21 ) */
+
+/*********************************************************************************************/
+
+typedef struct
+{
+ double x,y;
+ double z;
+} vertex;
+
+typedef struct
+{
+ double x;
+ double z;
+} edge;
+
+#define SWAP(A,B) { const void *temp = A; A = B; B = temp; }
+
+static void
+renderscanline_flat( const edge *e1, const edge *e2, int sy, unsigned color, int depthcueenable )
+{
+ if( e1->x > e2->x )
+ {
+ SWAP(e1,e2);
+ }
+
+ {
+ UINT16 *pDest = mpPolyFrameBufferPens + sy*NAMCOS21_POLY_FRAME_WIDTH;
+ UINT16 *pZBuf = mpPolyFrameBufferZ + sy*NAMCOS21_POLY_FRAME_WIDTH;
+ int x0 = (int)e1->x;
+ int x1 = (int)e2->x;
+ int w = x1-x0;
+ if( w )
+ {
+ double z = e1->z;
+ double dz = (e2->z - e1->z)/w;
+ int x, crop;
+ crop = - x0;
+ if( crop>0 )
+ {
+ z += crop*dz;
+ x0 = 0;
+ }
+ if( x1>NAMCOS21_POLY_FRAME_WIDTH-1 )
+ {
+ x1 = NAMCOS21_POLY_FRAME_WIDTH-1;
+ }
+
+ for( x=x0; x<x1; x++ )
+ {
+ UINT16 zz = (UINT16)z;
+ if( zz<pZBuf[x] )
+ {
+ int pen = color;
+ if( depthcueenable && zz>0 )
+ {
+ int depth = 0;
+ if( namcos2_gametype == NAMCOS21_WINRUN91 )
+ {
+ depth = (zz>>10)*0x100;
+ pen += depth;
+ }
+ else
+ {
+ depth = (zz>>11)*0x200;
+ pen -= depth;
+ }
+ }
+ pDest[x] = pen;
+ pZBuf[x] = zz;
+ }
+ z += dz;
+ }
+ }
+ }
+} /* renderscanline_flat */
+
+static void
+rendertri(
+ const vertex *v0,
+ const vertex *v1,
+ const vertex *v2,
+ unsigned color,
+ int depthcueenable )
+{
+ int dy,ystart,yend,crop;
+
+ /* first, sort so that v0->y <= v1->y <= v2->y */
+ for(;;)
+ {
+ if( v0->y > v1->y )
+ {
+ SWAP(v0,v1);
+ }
+ else if( v1->y > v2->y )
+ {
+ SWAP(v1,v2);
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ ystart = v0->y;
+ yend = v2->y;
+ dy = yend-ystart;
+ if( dy )
+ {
+ int y;
+ edge e1; /* short edge (top and bottom) */
+ edge e2; /* long (common) edge */
+
+ double dx2dy = (v2->x - v0->x)/dy;
+ double dz2dy = (v2->z - v0->z)/dy;
+
+ double dx1dy;
+ double dz1dy;
+
+ e2.x = v0->x;
+ e2.z = v0->z;
+ crop = -ystart;
+ if( crop>0 )
+ {
+ e2.x += dx2dy*crop;
+ e2.z += dz2dy*crop;
+ }
+
+ ystart = v0->y;
+ yend = v1->y;
+ dy = yend-ystart;
+ if( dy )
+ {
+ e1.x = v0->x;
+ e1.z = v0->z;
+
+ dx1dy = (v1->x - v0->x)/dy;
+ dz1dy = (v1->z - v0->z)/dy;
+
+ crop = -ystart;
+ if( crop>0 )
+ {
+ e1.x += dx1dy*crop;
+ e1.z += dz1dy*crop;
+ ystart = 0;
+ }
+ if( yend>NAMCOS21_POLY_FRAME_HEIGHT-1 ) yend = NAMCOS21_POLY_FRAME_HEIGHT-1;
+
+ for( y=ystart; y<yend; y++ )
+ {
+ renderscanline_flat( &e1, &e2, y, color, depthcueenable );
+
+ e2.x += dx2dy;
+ e2.z += dz2dy;
+
+ e1.x += dx1dy;
+ e1.z += dz1dy;
+ }
+ }
+
+ ystart = v1->y;
+ yend = v2->y;
+ dy = yend-ystart;
+ if( dy )
+ {
+ e1.x = v1->x;
+ e1.z = v1->z;
+
+ dx1dy = (v2->x - v1->x)/dy;
+ dz1dy = (v2->z - v1->z)/dy;
+
+ crop = -ystart;
+ if( crop>0 )
+ {
+ e1.x += dx1dy*crop;
+ e1.z += dz1dy*crop;
+ ystart = 0;
+ }
+ if( yend>NAMCOS21_POLY_FRAME_HEIGHT-1 )
+ {
+ yend = NAMCOS21_POLY_FRAME_HEIGHT-1;
+ }
+ for( y=ystart; y<yend; y++ )
+ {
+ renderscanline_flat( &e1, &e2, y, color, depthcueenable );
+
+ e2.x += dx2dy;
+ e2.z += dz2dy;
+
+ e1.x += dx1dy;
+ e1.z += dz1dy;
+ }
+ }
+ }
+} /* rendertri */
+
+void
+namcos21_DrawQuad( int sx[4], int sy[4], int zcode[4], int color )
+{
+ vertex a,b,c,d;
+ int depthcueenable = 1;
+ /*
+ 0x0000..0x1fff sprite palettes (0x20 sets of 0x100 colors)
+ 0x2000..0x3fff polygon palette bank0 (0x10 sets of 0x200 colors or 0x20 sets of 0x100 colors)
+ 0x4000..0x5fff polygon palette bank1 (0x10 sets of 0x200 colors or 0x20 sets of 0x100 colors)
+ 0x6000..0x7fff polygon palette bank2 (0x10 sets of 0x200 colors or 0x20 sets of 0x100 colors)
+ */
+ if( namcos2_gametype == NAMCOS21_WINRUN91 ||
+ namcos2_gametype == NAMCOS21_DRIVERS_EYES )
+ {
+ color = 0x4000|(color&0xff);
+ }
+ else
+ { /* map color code to hardware pen */
+ int code = color>>8;
+ if( code&0x80 )
+ {
+ color = color&0xff;
+// color = 0x3e00|color;
+ color = 0x2100|color;
+ depthcueenable = 0;
+ }
+ else
+ {
+ color&=0xff;
+ color = 0x3e00|color;
+ if( (code&0x02)==0 )
+ {
+ color|=0x100;
+ }
+ }
+ }
+ a.x = sx[0];
+ a.y = sy[0];
+ a.z = zcode[0];
+
+ b.x = sx[1];
+ b.y = sy[1];
+ b.z = zcode[1];
+
+ c.x = sx[2];
+ c.y = sy[2];
+ c.z = zcode[2];
+
+ d.x = sx[3];
+ d.y = sy[3];
+ d.z = zcode[3];
+
+ rendertri( &a, &b, &c, color, depthcueenable );
+ rendertri( &c, &d, &a, color, depthcueenable );
+} /* namcos21_DrawQuad */
diff --git a/src/mame/video/namcos22.c b/src/mame/video/namcos22.c
new file mode 100644
index 00000000000..5a461044269
--- /dev/null
+++ b/src/mame/video/namcos22.c
@@ -0,0 +1,2485 @@
+/**
+ * video hardware for Namco System22
+ *
+ * todo:
+ *
+ * - fog bugfixes
+ *
+ * - SPOT
+ *
+ * - sprite
+ * xy offset
+ * clipping to window
+ * eliminate garbage (air combat)
+ *
+ *
+ *******************************
+czram[0] = 1fff 1fdf 1fbf 1f9f 1f7f 1f5f 1f3f 1f1f 1eff 1edf 1ebf 1e9f 1e7f 1e5f 1e3f 1e1f 1dff 1ddf 1dbf 1d9f 1d7f 1d5f 1d3f 1d1f 1cff 1cdf 1cbf 1c9f 1c7f 1c5f 1c3f 1c1f 1bff 1bdf 1bbf 1b9f 1b7f 1b5f 1b3f 1b1f 1aff 1adf 1abf 1a9f 1a7f 1a5f 1a3f 1a1f 19ff 19df 19bf 199f 197f 195f 193f 191f 18ff 18df 18bf 189f 187f 185f 183f 181f 17ff 17df 17bf 179f 177f 175f 173f 171f 16ff 16df 16bf 169f 167f 165f 163f 161f 15ff 15df 15bf 159f 157f 155f 153f 151f 14ff 14df 14bf 149f 147f 145f 143f 141f 13ff 13df 13bf 139f 137f 135f 133f 131f 12ff 12df 12bf 129f 127f 125f 123f 121f 11ff 11df 11bf 119f 117f 115f 113f 111f 10ff 10df 10bf 109f 107f 105f 103f 101f 0fff 0fdf 0fbf 0f9f 0f7f 0f5f 0f3f 0f1f 0eff 0edf 0ebf 0e9f 0e7f 0e5f 0e3f 0e1f 0dff 0ddf 0dbf 0d9f 0d7f 0d5f 0d3f 0d1f 0cff 0cdf 0cbf 0c9f 0c7f 0c5f 0c3f 0c1f 0bff 0bdf 0bbf 0b9f 0b7f 0b5f 0b3f 0b1f 0aff 0adf 0abf 0a9f 0a7f 0a5f 0a3f 0a1f 09ff 09df 09bf 099f 097f 095f 093f 091f 08ff 08df 08bf 089f 087f 085f 083f 081f 07ff 07df 07bf 079f 077f 075f 073f 071f 06ff 06df 06bf 069f 067f 065f 063f 061f 05ff 05df 05bf 059f 057f 055f 053f 051f 04ff 04df 04bf 049f 047f 045f 043f 041f 03ff 03df 03bf 039f 037f 035f 033f 031f 02ff 02df 02bf 029f 027f 025f 023f 021f 01ff 01df 01bf 019f 017f 015f 013f 011f 00ff 00df 00bf 009f 007f 005f 003f 001f
+czram[1] = 0000 0000 0000 0001 0002 0003 0005 0007 0009 000b 000e 0011 0014 0017 001b 001f 0023 0027 002c 0031 0036 003b 0041 0047 004d 0053 005a 0061 0068 006f 0077 007f 0087 008f 0098 00a1 00aa 00b3 00bd 00c7 00d1 00db 00e6 00f1 00fc 0107 0113 011f 012b 0137 0144 0151 015e 016b 0179 0187 0195 01a3 01b2 01c1 01d0 01df 01ef 01ff 020f 021f 0230 0241 0252 0263 0275 0287 0299 02ab 02be 02d1 02e4 02f7 030b 031f 0333 0347 035c 0371 0386 039b 03b1 03c7 03dd 03f3 040a 0421 0438 044f 0467 047f 0497 04af 04c8 04e1 04fa 0513 052d 0547 0561 057b 0596 05b1 05cc 05e7 0603 061f 063b 0657 0674 0691 06ae 06cb 06e9 0707 0725 0743 0762 0781 07a0 07bf 07df 07ff 081f 083f 0860 0881 08a2 08c3 08e5 0907 0929 094b 096e 0991 09b4 09d7 09fb 0a1f 0a43 0a67 0a8c 0ab1 0ad6 0afb 0b21 0b47 0b6d 0b93 0bba 0be1 0c08 0c2f 0c57 0c7f 0ca7 0ccf 0cf8 0d21 0d4a 0d73 0d9d 0dc7 0df1 0e1b 0e46 0e71 0e9c 0ec7 0ef3 0f1f 0f4b 0f77 0fa4 0fd1 0ffe 102b 1059 1087 10b5 10e3 1112 1141 1170 119f 11cf 11ff 122f 125f 1290 12c1 12f2 1323 1355 1387 13b9 13eb 141e 1451 1484 14b7 14eb 151f 1553 1587 15bc 15f1 1626 165b 1691 16c7 16fd 1733 176a 17a1 17d8 180f 1847 187f 18b7 18ef 1928 1961 199a 19d3 1a0d 1a47 1a81 1abb 1af6 1b31 1b6c 1ba7 1be3 1c1f 1c5b 1c97 1cd4 1d11 1d4e 1d8b 1dc9 1e07 1e45 1e83 1ec2 1f01 1f40 1f7f 1fbf 1fff
+czram[2] = 003f 007f 00be 00fd 013c 017b 01b9 01f7 0235 0273 02b0 02ed 032a 0367 03a3 03df 041b 0457 0492 04cd 0508 0543 057d 05b7 05f1 062b 0664 069d 06d6 070f 0747 077f 07b7 07ef 0826 085d 0894 08cb 0901 0937 096d 09a3 09d8 0a0d 0a42 0a77 0aab 0adf 0b13 0b47 0b7a 0bad 0be0 0c13 0c45 0c77 0ca9 0cdb 0d0c 0d3d 0d6e 0d9f 0dcf 0dff 0e2f 0e5f 0e8e 0ebd 0eec 0f1b 0f49 0f77 0fa5 0fd3 1000 102d 105a 1087 10b3 10df 110b 1137 1162 118d 11b8 11e3 120d 1237 1261 128b 12b4 12dd 1306 132f 1357 137f 13a7 13cf 13f6 141d 1444 146b 1491 14b7 14dd 1503 1528 154d 1572 1597 15bb 15df 1603 1627 164a 166d 1690 16b3 16d5 16f7 1719 173b 175c 177d 179e 17bf 17df 17ff 181f 183f 185e 187d 189c 18bb 18d9 18f7 1915 1933 1950 196d 198a 19a7 19c3 19df 19fb 1a17 1a32 1a4d 1a68 1a83 1a9d 1ab7 1ad1 1aeb 1b04 1b1d 1b36 1b4f 1b67 1b7f 1b97 1baf 1bc6 1bdd 1bf4 1c0b 1c21 1c37 1c4d 1c63 1c78 1c8d 1ca2 1cb7 1ccb 1cdf 1cf3 1d07 1d1a 1d2d 1d40 1d53 1d65 1d77 1d89 1d9b 1dac 1dbd 1dce 1ddf 1def 1dff 1e0f 1e1f 1e2e 1e3d 1e4c 1e5b 1e69 1e77 1e85 1e93 1ea0 1ead 1eba 1ec7 1ed3 1edf 1eeb 1ef7 1f02 1f0d 1f18 1f23 1f2d 1f37 1f41 1f4b 1f54 1f5d 1f66 1f6f 1f77 1f7f 1f87 1f8f 1f96 1f9d 1fa4 1fab 1fb1 1fb7 1fbd 1fc3 1fc8 1fcd 1fd2 1fd7 1fdb 1fdf 1fe3 1fe7 1fea 1fed 1ff0 1ff3 1ff5 1ff7 1ff9 1ffb 1ffc 1ffd 1ffe 1fff 1fff 1fff
+czram[3] = 0000 001f 003f 005f 007f 009f 00bf 00df 00ff 011f 013f 015f 017f 019f 01bf 01df 01ff 021f 023f 025f 027f 029f 02bf 02df 02ff 031f 033f 035f 037f 039f 03bf 03df 03ff 041f 043f 045f 047f 049f 04bf 04df 04ff 051f 053f 055f 057f 059f 05bf 05df 05ff 061f 063f 065f 067f 069f 06bf 06df 06ff 071f 073f 075f 077f 079f 07bf 07df 07ff 081f 083f 085f 087f 089f 08bf 08df 08ff 091f 093f 095f 097f 099f 09bf 09df 09ff 0a1f 0a3f 0a5f 0a7f 0a9f 0abf 0adf 0aff 0b1f 0b3f 0b5f 0b7f 0b9f 0bbf 0bdf 0bff 0c1f 0c3f 0c5f 0c7f 0c9f 0cbf 0cdf 0cff 0d1f 0d3f 0d5f 0d7f 0d9f 0dbf 0ddf 0dff 0e1f 0e3f 0e5f 0e7f 0e9f 0ebf 0edf 0eff 0f1f 0f3f 0f5f 0f7f 0f9f 0fbf 0fdf 0fff 101f 103f 105f 107f 109f 10bf 10df 10ff 111f 113f 115f 117f 119f 11bf 11df 11ff 121f 123f 125f 127f 129f 12bf 12df 12ff 131f 133f 135f 137f 139f 13bf 13df 13ff 141f 143f 145f 147f 149f 14bf 14df 14ff 151f 153f 155f 157f 159f 15bf 15df 15ff 161f 163f 165f 167f 169f 16bf 16df 16ff 171f 173f 175f 177f 179f 17bf 17df 17ff 181f 183f 185f 187f 189f 18bf 18df 18ff 191f 193f 195f 197f 199f 19bf 19df 19ff 1a1f 1a3f 1a5f 1a7f 1a9f 1abf 1adf 1aff 1b1f 1b3f 1b5f 1b7f 1b9f 1bbf 1bdf 1bff 1c1f 1c3f 1c5f 1c7f 1c9f 1cbf 1cdf 1cff 1d1f 1d3f 1d5f 1d7f 1d9f 1dbf 1ddf 1dff 1e1f 1e3f 1e5f 1e7f 1e9f 1ebf 1edf 1eff 1f1f 1f3f 1f5f 1f7f 1f9f 1fbf 1fdf
+
+CZ (NORMAL) 00810000: 00000000 00000000 75550000 00e40000
+CZ (OFFSET) 00810000: 7fff8000 7fff8000 75550000 00e40000
+CZ (OFF) 00810000: 00000000 00000000 31110000 00e40000
+
+SPOT TABLE test
+03F282: 13FC 0000 0082 4011 move.b #$0, $824011.l
+03F28A: 13FC 0000 0082 4015 move.b #$0, $824015.l
+03F292: 13FC 0080 0082 400D move.b #$80, $82400d.l
+03F29A: 13FC 0001 0082 400E move.b #$1, $82400e.l
+03F2A2: 13FC 0001 0082 4021 move.b #$1, $824021.l
+03F2AA: 33FC 4038 0080 0000 move.w #$4038, $800000.l
+03F2B2: 06B9 0000 0001 00E0 AB08 addi.l #$1, $e0ab08.l
+*/
+
+#include "driver.h"
+#include "eminline.h"
+#include "video/rgbutil.h"
+#include "namcos22.h"
+#include "video/poly.h"
+#include <math.h>
+
+// uncomment this line to render everything as quads
+//#define RENDER_AS_QUADS
+
+static int mbSuperSystem22; /* used to conditionally support Super System22-specific features */
+static int mbSpotlightEnable;
+static UINT16 *namcos22_czram[4];
+
+static poly_manager *poly;
+
+static UINT8
+nthbyte( const UINT32 *pSource, int offs )
+{
+ pSource += offs/4;
+ return (pSource[0]<<((offs&3)*8))>>24;
+}
+
+static UINT16
+nthword( const UINT32 *pSource, int offs )
+{
+ pSource += offs/2;
+ return (pSource[0]<<((offs&1)*16))>>16;
+}
+
+static struct
+{
+ int target;
+ int rFogColor;
+ int gFogColor;
+ int bFogColor;
+ int rFogColor2;
+ int gFogColor2;
+ int bFogColor2;
+ int rBackColor;
+ int gBackColor;
+ int bBackColor;
+ int rFadeColor;
+ int gFadeColor;
+ int bFadeColor;
+ int fadeFactor;
+ int spot_translucency;
+ int poly_translucency;
+ int text_translucency;
+ int palBase;
+} mixer;
+
+static void
+UpdateVideoMixer( void )
+{
+ poly_wait(poly, "UpdateVideoMixer");
+ memset( &mixer, 0, sizeof(mixer) );
+ if( mbSuperSystem22 )
+ {
+/*
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 14 18 1c
+00824000: ffffff00 00000000 0000007f 00ff0000 1000ff00 0f000000 00ff007f 00010007 // time crisis
+00824000: ffffff00 00000000 1830407f 00800000 0000007f 0f000000 0000037f 00010007 // trans sprite
+00824000: ffffff00 00000000 3040307f 00000000 0080007f 0f000000 0000037f 00010007 // trans poly
+00824000: ffffff00 00000000 1800187f 00800000 0080007f 0f000000 0000037f 00010007 // trans poly(2)
+00824000: ffffff00 00000000 1800187f 00000000 0000007f 0f800000 0000037f 00010007 // trans text
+*/
+ mixer.rFogColor = nthbyte( namcos22_gamma, 0x05 );
+ mixer.gFogColor = nthbyte( namcos22_gamma, 0x06 );
+ mixer.bFogColor = nthbyte( namcos22_gamma, 0x07 );
+ mixer.rBackColor = nthbyte( namcos22_gamma, 0x08 );
+ mixer.gBackColor = nthbyte( namcos22_gamma, 0x09 );
+ mixer.bBackColor = nthbyte( namcos22_gamma, 0x0a );
+ mixer.spot_translucency = nthbyte( namcos22_gamma, 0x0d );
+ mixer.poly_translucency = nthbyte( namcos22_gamma, 0x11 );
+ mixer.text_translucency = nthbyte( namcos22_gamma, 0x15 );
+ mixer.rFadeColor = nthbyte( namcos22_gamma, 0x16 );
+ mixer.gFadeColor = nthbyte( namcos22_gamma, 0x17 );
+ mixer.bFadeColor = nthbyte( namcos22_gamma, 0x18 );
+ mixer.fadeFactor = nthbyte( namcos22_gamma, 0x19 );
+ mixer.target = nthbyte( namcos22_gamma, 0x1a );
+ mixer.palBase = nthbyte( namcos22_gamma, 0x1b );
+ }
+ else
+ {
+/*
+90020000: 4f030000 7f00007f 4d4d4d42 0c00c0c0
+90020010: c0010001 00010000 00000000 00000000
+90020080: 00010101 01010102 00000000 00000000
+900200c0: 00000000 00000000 00000000 03000000
+90020100: fff35000 00000000 00000000 00000000
+90020180: ff713700 00000000 00000000 00000000
+90020200: ff100000 00000000 00000000 00000000
+*/
+ mixer.palBase = 0x7f;
+ mixer.target = 0x7;//nthbyte( namcos22_gamma, 0x0002 )*256 + nthbyte( namcos22_gamma, 0x0003 );
+ mixer.rFadeColor = nthbyte( namcos22_gamma, 0x0011 )*256 + nthbyte( namcos22_gamma, 0x0012 );
+ mixer.gFadeColor = nthbyte( namcos22_gamma, 0x0013 )*256 + nthbyte( namcos22_gamma, 0x0014 );
+ mixer.bFadeColor = nthbyte( namcos22_gamma, 0x0015 )*256 + nthbyte( namcos22_gamma, 0x0016 );
+
+ mixer.fadeFactor = 0x100 - mixer.rFadeColor; // hack
+ mixer.rFadeColor = 0;
+ mixer.gFadeColor = 0;
+ mixer.bFadeColor = 0;
+
+ mixer.rFogColor = nthbyte( namcos22_gamma, 0x0100 );
+ mixer.rFogColor2 = nthbyte( namcos22_gamma, 0x0101 );
+ mixer.gFogColor = nthbyte( namcos22_gamma, 0x0180 );
+ mixer.gFogColor2 = nthbyte( namcos22_gamma, 0x0181 );
+ mixer.bFogColor = nthbyte( namcos22_gamma, 0x0200 );
+ mixer.bFogColor2 = nthbyte( namcos22_gamma, 0x0201 );
+
+/* +0x0002.w Fader Enable(?) (0: disabled)
+ * +0x0011.w Display Fader (R) (0x0100 = 1.0)
+ * +0x0013.w Display Fader (G) (0x0100 = 1.0)
+ * +0x0015.w Display Fader (B) (0x0100 = 1.0)
+ * +0x0100.b Fog1 Color (R) (world fogging)
+ * +0x0101.b Fog2 Color (R) (used for heating of brake-disc on RV1)
+ * +0x0180.b Fog1 Color (G)
+ * +0x0181.b Fog2 Color (G)
+ * +0x0200.b Fog1 Color (B)
+ * +0x0201.b Fog2 Color (B)
+ */
+ }
+}
+
+INLINE UINT8
+Clamp256( int v )
+{
+ if( v<0 )
+ {
+ v = 0;
+ }
+ else if( v>255 )
+ {
+ v = 255;
+ }
+ return v;
+} /* Clamp256 */
+
+#ifdef MAME_DEBUG
+static void Dump( FILE *f, unsigned addr1, unsigned addr2, const char *name );
+#endif
+
+static struct
+{
+ int cx,cy;
+ rectangle scissor;
+} mClip;
+
+static void
+poly3d_Clip( float vx, float vy, float vw, float vh )
+{
+ int cx = 320+vx;
+ int cy = 240+vy;
+ mClip.cx = cx;
+ mClip.cy = cy;
+ mClip.scissor.min_x = cx + vw;
+ mClip.scissor.min_y = cy + vh;
+ mClip.scissor.max_x = cx - vw;
+ mClip.scissor.max_y = cy - vh;
+ if( mClip.scissor.min_x<0 ) mClip.scissor.min_x = 0;
+ if( mClip.scissor.min_y<0 ) mClip.scissor.min_y = 0;
+ if( mClip.scissor.max_x>639 ) mClip.scissor.max_x = 639;
+ if( mClip.scissor.max_y>479 ) mClip.scissor.max_y = 479;
+}
+
+static void
+poly3d_NoClip( void )
+{
+ mClip.cx = 640/2;
+ mClip.cy = 480/2;
+ mClip.scissor.min_x = 0;
+ mClip.scissor.max_x = 639;
+ mClip.scissor.min_y = 0;
+ mClip.scissor.max_x = 479;
+}
+
+typedef struct
+{
+ float x,y,z;
+ int u,v; /* 0..0xfff */
+ int bri; /* 0..0xff */
+} Poly3dVertex;
+
+#define MIN_Z (10.0f)
+
+typedef struct
+{
+ float x,y;
+ float u,v,i,z;
+} vertex;
+
+typedef struct
+{
+ float x;
+ float u,v,i,z;
+} edge;
+
+#define SWAP(A,B) { const void *temp = A; A = B; B = temp; }
+
+static UINT16 *mpTextureTileMap16;
+static UINT8 *mpTextureTileMapAttr;
+static UINT8 *mpTextureTileData;
+static UINT8 mXYAttrToPixel[16][16][16];
+
+INLINE unsigned texel( unsigned x, unsigned y )
+{
+ unsigned offs = ((y&0xfff0)<<4)|((x&0xff0)>>4);
+ unsigned tile = mpTextureTileMap16[offs];
+ return mpTextureTileData[(tile<<8)|mXYAttrToPixel[mpTextureTileMapAttr[offs]][x&0xf][y&0xf]];
+} /* texel */
+
+
+
+typedef struct _poly_extra_data poly_extra_data;
+struct _poly_extra_data
+{
+ int color;
+ int bn;
+ UINT16 flags;
+ int cmode;
+ int fogFactor;
+ rgbint fogColor;
+ int fadeFactor;
+ rgbint fadeColor;
+ const UINT8 *source; /* sprites */
+ int z;
+ int alpha;
+ int prioverchar;
+ int line_modulo;
+};
+
+
+static void renderscanline_uvi_full(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ float z = extent->param[0].start;
+ float u = extent->param[1].start;
+ float v = extent->param[2].start;
+ float i = extent->param[3].start;
+ float dz = extent->param[0].dpdx;
+ float du = extent->param[1].dpdx;
+ float dv = extent->param[2].dpdx;
+ float di = extent->param[3].dpdx;
+ mame_bitmap *bitmap = dest;
+ const poly_extra_data *extra = extradata;
+ int bn = extra->bn * 0x1000;
+ const pen_t *pens = &Machine->pens[(extra->color&0x7f)<<8];
+ int fogFactor = 0xff - extra->fogFactor;
+ int fadeFactor = 0xff - extra->fadeFactor;
+ int transFactor = 0xff;
+ rgbint fogColor = extra->fogColor;
+ rgbint fadeColor = extra->fadeColor;
+ int penmask, penshift;
+ int prioverchar;
+ const UINT8 *pCharPri = BITMAP_ADDR8(priority_bitmap, scanline, 0);
+ UINT32 *pDest = BITMAP_ADDR32(bitmap, scanline, 0);
+ int x;
+
+ if (extra->cmode & 4)
+ {
+ prioverchar = 0;
+ pens += 0xec + ((extra->cmode & 8) << 1);
+ penmask = 0x03;
+ penshift = 2 * ~(extra->cmode & 3);
+ }
+ else if (extra->cmode & 2)
+ {
+ prioverchar = 0;
+ pens += 0xe0 + ((extra->cmode & 8) << 1);
+ penmask = 0x0f;
+ penshift = 4 * ~(extra->cmode & 1);
+ }
+ else if (extra->cmode & 1)
+ {
+ transFactor = 0xff - mixer.poly_translucency;
+ prioverchar = 1;
+ penmask = 0xff;
+ penshift = 0;
+ }
+ else
+ {
+ prioverchar = 0;
+ penmask = 0xff;
+ penshift = 0;
+ }
+
+ if (prioverchar)
+ {
+ for( x=extent->startx; x<extent->stopx; x++ )
+ {
+ float ooz = 1.0f / z;
+ int pen = texel((int)(u * ooz),bn+(int)(v*ooz));
+ int shade = i*ooz;
+ rgbint rgb;
+
+ rgb_to_rgbint(&rgb, pens[(pen >> penshift) & penmask]);
+ rgbint_scale_and_clamp(&rgb, shade << 2);
+
+ if( fogFactor != 0xff )
+ rgbint_blend(&rgb, &fogColor, fogFactor);
+
+ if( fadeFactor != 0xff )
+ rgbint_blend(&rgb, &fadeColor, fadeFactor);
+
+ if( transFactor != 0xff )
+ {
+ rgbint dest;
+ rgb_to_rgbint(&dest, pDest[x]);
+ rgbint_blend(&rgb, &dest, transFactor);
+ }
+
+ pDest[x] = rgbint_to_rgb(&rgb);
+
+ u += du;
+ v += dv;
+ i += di;
+ z += dz;
+ }
+ }
+ else
+ {
+ for( x=extent->startx; x<extent->stopx; x++ )
+ {
+ if( pCharPri[x]==0 )
+ {
+ float ooz = 1.0f / z;
+ int pen = texel((int)(u * ooz),bn+(int)(v*ooz));
+ int shade = i*ooz;
+ rgbint rgb;
+
+ rgb_to_rgbint(&rgb, pens[(pen >> penshift) & penmask]);
+ rgbint_scale_and_clamp(&rgb, shade << 2);
+
+ if( fogFactor != 0xff )
+ rgbint_blend(&rgb, &fogColor, fogFactor);
+
+ if( fadeFactor != 0xff )
+ rgbint_blend(&rgb, &fadeColor, fadeFactor);
+
+ pDest[x] = rgbint_to_rgb(&rgb);
+ }
+
+ u += du;
+ v += dv;
+ i += di;
+ z += dz;
+ }
+ }
+} /* renderscanline_uvi_full */
+
+static void poly3d_DrawQuad(running_machine *machine, mame_bitmap *bitmap, int textureBank, int color, Poly3dVertex pv[4], UINT16 flags, int direct, int cmode )
+{
+ poly_extra_data *extra;
+ poly_vertex v[4], clipv[5];
+ int clipverts;
+ int vertnum;
+
+ /* non-direct case: project and z-clip */
+ if (!direct)
+ {
+ for (vertnum = 0; vertnum < 4; vertnum++)
+ {
+ v[vertnum].x = pv[vertnum].x;
+ v[vertnum].y = pv[vertnum].y;
+ v[vertnum].p[0] = pv[vertnum].z;
+ v[vertnum].p[1] = pv[vertnum].u;
+ v[vertnum].p[2] = pv[vertnum].v;
+ v[vertnum].p[3] = pv[vertnum].bri;
+ }
+ clipverts = poly_zclip_if_less(4, v, clipv, 4, MIN_Z);
+ if (clipverts < 3)
+ return;
+ for (vertnum = 0; vertnum < clipverts; vertnum++)
+ {
+ float ooz = 1.0f / clipv[vertnum].p[0];
+ clipv[vertnum].x = mClip.cx + clipv[vertnum].x * ooz;
+ clipv[vertnum].y = mClip.cy - clipv[vertnum].y * ooz;
+ clipv[vertnum].p[0] = ooz;
+ clipv[vertnum].p[1] = (clipv[vertnum].p[1] + 0.5f) * ooz;
+ clipv[vertnum].p[2] = (clipv[vertnum].p[2] + 0.5f) * ooz;
+ clipv[vertnum].p[3] = (clipv[vertnum].p[3] + 0.5f) * ooz;
+ }
+ }
+
+ /* direct case: don't clip, and treat pv->z as 1/z */
+ else
+ {
+ clipverts = 4;
+ for (vertnum = 0; vertnum < 4; vertnum++)
+ {
+ float ooz = pv[vertnum].z;
+ clipv[vertnum].x = mClip.cx + pv[vertnum].x;
+ clipv[vertnum].y = mClip.cy - pv[vertnum].y;
+ clipv[vertnum].p[0] = ooz;
+ clipv[vertnum].p[1] = (pv[vertnum].u + 0.5f) * ooz;
+ clipv[vertnum].p[2] = (pv[vertnum].v + 0.5f) * ooz;
+ clipv[vertnum].p[3] = (pv[vertnum].bri + 0.5f) * ooz;
+ }
+ }
+
+ extra = poly_get_extra_data(poly);
+
+ extra->color = color;
+ extra->bn = textureBank;
+ extra->flags = flags;
+ extra->cmode = cmode;
+ extra->fogFactor = 0;
+ extra->fadeFactor = 0;
+
+ if (mixer.target&1)
+ {
+ extra->fadeFactor = mixer.fadeFactor;
+ rgb_comp_to_rgbint(&extra->fadeColor, mixer.rFadeColor, mixer.gFadeColor, mixer.bFadeColor);
+ }
+
+ if( mbSuperSystem22 )
+ {
+ if( !(color&0x80) )
+ {
+ int cz = flags>>8;
+ static const int cztype_remap[4] = { 3,1,2,0 };
+ int cztype = flags&3;
+ if( nthword(namcos22_czattr,4)&(0x4000>>(cztype*4)) )
+ {
+ int fogDelta = (INT16)nthword(namcos22_czattr, cztype);
+ int fogDensity = fogDelta + namcos22_czram[cztype_remap[cztype]][cz];
+ // if( fogDelta == 0x8000 ) fogDelta = -0x7fff;
+ //cz = Clamp256(cz+fogDelta);
+ if( fogDensity<0x0000 )
+ {
+ fogDensity = 0x0000;
+ }
+ else if( fogDensity>0x1fff )
+ {
+ fogDensity = 0x1fff;
+ }
+ extra->fogFactor = fogDensity >> 5;
+ rgb_comp_to_rgbint(&extra->fogColor, mixer.rFogColor, mixer.gFogColor, mixer.bFogColor);
+ }
+ }
+ }
+
+#ifdef RENDER_AS_QUADS
+ poly_render_quad_fan(poly, bitmap, &mClip.scissor, renderscanline_uvi_full, 4, clipverts, clipv);
+#else
+ poly_render_triangle_fan(poly, bitmap, &mClip.scissor, renderscanline_uvi_full, 4, clipverts, clipv);
+#endif
+}
+
+static void renderscanline_sprite(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ int x_index = extent->param[0].start * 65536.0f;
+ int y_index = extent->param[1].start * 65536.0f;
+ int dx = extent->param[0].dpdx * 65536.0f;
+ const poly_extra_data *extra = extradata;
+ mame_bitmap *destmap = destbase;
+ const pen_t *pal = &Machine->remapped_colortable[extra->color];
+ int prioverchar = extra->prioverchar;
+ int z = extra->z;
+ int alpha = extra->alpha;
+ UINT8 *source = (UINT8 *)extra->source + (y_index>>16) * extra->line_modulo;
+ UINT32 *dest = BITMAP_ADDR32(destmap, scanline, 0);
+ const UINT8 *pCharPri = BITMAP_ADDR8(priority_bitmap, scanline, 0);
+ int x;
+
+ int bFogEnable = 0;
+ INT16 fogDelta = 0;
+ int fadeEnable = (mixer.target&2) && mixer.fadeFactor;
+
+ if( mbSuperSystem22 )
+ {
+ fogDelta = nthword(namcos22_czattr, 0 );
+ bFogEnable = nthword(namcos22_czattr,4)&0x4000; /* ? */
+ }
+ else
+ {
+ bFogEnable = 0;
+ }
+
+ for( x=extent->startx; x<extent->stopx; x++ )
+ {
+ int pen = source[x_index>>16];
+ if( pen != 0xff )
+ {
+ if( pCharPri[x]==0 || prioverchar )
+ {
+ UINT32 color = pal[pen];
+ int r = color>>16;
+ int g = (color>>8)&0xff;
+ int b = color&0xff;
+ if( bFogEnable && z!=0xffff )
+ {
+ int zc = Clamp256(fogDelta + z);
+ UINT16 fogDensity = namcos22_czram[3][zc];
+ if( fogDensity>0 )
+ {
+ int fogDensity2 = 0x2000 - fogDensity;
+ r = (r*fogDensity2 + fogDensity*mixer.rFogColor)>>13;
+ g = (g*fogDensity2 + fogDensity*mixer.gFogColor)>>13;
+ b = (b*fogDensity2 + fogDensity*mixer.bFogColor)>>13;
+ }
+ }
+ if( fadeEnable )
+ {
+ int fade2 = 0x100-mixer.fadeFactor;
+ r = (r*fade2+mixer.fadeFactor*mixer.rFadeColor)>>8;
+ g = (g*fade2+mixer.fadeFactor*mixer.gFadeColor)>>8;
+ b = (b*fade2+mixer.fadeFactor*mixer.bFadeColor)>>8;
+ }
+ color = (r<<16)|(g<<8)|b;
+ color = alpha_blend_r32(dest[x], color, alpha);
+ color&=0xffffff;
+ dest[x] = color;
+ }
+ }
+ x_index += dx;
+ }
+}
+
+
+static void
+mydrawgfxzoom(
+ mame_bitmap *dest_bmp,const gfx_element *gfx,
+ UINT32 code,UINT32 color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,
+ int scalex, int scaley, int z, int prioverchar, int alpha )
+{
+ int sprite_screen_height = (scaley*gfx->height+0x8000)>>16;
+ int sprite_screen_width = (scalex*gfx->width+0x8000)>>16;
+ if (sprite_screen_width && sprite_screen_height && gfx)
+ {
+ float fsx = sx;
+ float fsy = sy;
+ float fwidth = gfx->width;
+ float fheight = gfx->height;
+ float fsw = sprite_screen_width;
+ float fsh = sprite_screen_height;
+ poly_extra_data *extra;
+ poly_vertex vert[4];
+
+ vert[0].x = fsx;
+ vert[0].y = fsy;
+ vert[0].p[0] = flipx ? fwidth : 0;
+ vert[0].p[1] = flipy ? fheight : 0;
+ vert[1].x = fsx + fsw;
+ vert[1].y = fsy;
+ vert[1].p[0] = flipx ? 0 : fwidth;
+ vert[1].p[1] = flipy ? fheight : 0;
+ vert[2].x = fsx + fsw;
+ vert[2].y = fsy + fsh;
+ vert[2].p[0] = flipx ? 0 : fwidth;
+ vert[2].p[1] = flipy ? 0 : fheight;
+ vert[3].x = fsx;
+ vert[3].y = fsy + fsh;
+ vert[3].p[0] = flipx ? fwidth : 0;
+ vert[3].p[1] = flipy ? 0 : fheight;
+
+ extra = poly_get_extra_data(poly);
+ extra->z = z;
+ extra->alpha = alpha;
+ extra->prioverchar = prioverchar;
+ extra->line_modulo = gfx->line_modulo;
+ extra->color = gfx->color_base + gfx->color_granularity * (color % gfx->total_colors);
+ extra->source = gfx->gfxdata + (code % gfx->total_elements) * gfx->char_modulo;
+#ifdef RENDER_AS_QUADS
+ poly_render_quad_fan(poly, dest_bmp, clip, renderscanline_sprite, 2, 4, &vert[0]);
+#else
+ poly_render_triangle_fan(poly, dest_bmp, clip, renderscanline_sprite, 2, 4, &vert[0]);
+#endif
+ }
+} /* mydrawgfxzoom */
+
+static void
+ApplyGamma( mame_bitmap *bitmap )
+{
+ int x,y;
+ if( mbSuperSystem22 )
+ { /* super system 22 */
+#ifdef LSB_FIRST
+#define XORPAT 0x3
+#else
+#define XORPAT 0x0
+#endif
+ const UINT8 *rlut = (const UINT8 *)&namcos22_gamma[0x100/4];
+ const UINT8 *glut = (const UINT8 *)&namcos22_gamma[0x200/4];
+ const UINT8 *blut = (const UINT8 *)&namcos22_gamma[0x300/4];
+ for( y=0; y<bitmap->height; y++ )
+ {
+ UINT32 *dest = BITMAP_ADDR32(bitmap, y, 0);
+ for( x=0; x<bitmap->width; x++ )
+ {
+ int rgb = dest[x];
+ int r = rlut[XORPAT^(rgb>>16)];
+ int g = glut[XORPAT^((rgb>>8)&0xff)];
+ int b = blut[XORPAT^(rgb&0xff)];
+ dest[x] = (r<<16)|(g<<8)|b;
+ }
+ }
+ }
+ else
+ { /* system 22 */
+ const UINT8 *rlut = 0x000+(const UINT8 *)memory_region(REGION_USER1);
+ const UINT8 *glut = 0x100+(const UINT8 *)memory_region(REGION_USER1);
+ const UINT8 *blut = 0x200+(const UINT8 *)memory_region(REGION_USER1);
+ for( y=0; y<bitmap->height; y++ )
+ {
+ UINT32 *dest = BITMAP_ADDR32(bitmap, y, 0);
+ for( x=0; x<bitmap->width; x++ )
+ {
+ int rgb = dest[x];
+ int r = rlut[rgb>>16];
+ int g = glut[(rgb>>8)&0xff];
+ int b = blut[rgb&0xff];
+ dest[x] = (r<<16)|(g<<8)|b;
+ }
+ }
+ }
+} /* ApplyGamma */
+
+static void
+poly3d_Draw3dSprite( mame_bitmap *bitmap, gfx_element *gfx, int tileNumber, int color, int sx, int sy, int width, int height, int translucency, int zc, UINT32 pri )
+{
+ int flipx = 0;
+ int flipy = 0;
+ rectangle clip;
+ clip.min_x = 0;
+ clip.min_y = 0;
+ clip.max_x = 640-1;
+ clip.max_y = 480-1;
+ mydrawgfxzoom(
+ bitmap,
+ gfx,
+ tileNumber,
+ color,
+ flipx, flipy,
+ sx, sy,
+ &clip,
+ TRANSPARENCY_ALPHA, 0xff,
+ (width<<16)/32,
+ (height<<16)/32,
+ zc, pri, 0xff - translucency );
+}
+
+#define DSP_FIXED_TO_FLOAT( X ) (((INT16)(X))/(float)0x7fff)
+#define SPRITERAM_SIZE (0x9b0000-0x980000)
+#define CGRAM_SIZE 0x1e000
+#define NUM_CG_CHARS ((CGRAM_SIZE*8)/(64*16)) /* 0x3c0 */
+
+/* 16 bit access to DSP RAM */
+static UINT16 namcos22_dspram_bank;
+static UINT16 mUpperWordLatch;
+
+static int mbDSPisActive;
+
+/* modal rendering properties */
+static INT32 mAbsolutePriority;
+static INT32 mObjectShiftValue22;
+
+static UINT16 mPrimitiveID; /* 3d primitive to render */
+
+static float mViewMatrix[4][4];
+
+static void
+matrix3d_Multiply( float A[4][4], float B[4][4] )
+{
+ float temp[4][4];
+ int row,col;
+
+ for( row=0;row<4;row++ )
+ {
+ for(col=0;col<4;col++)
+ {
+ float sum = 0.0;
+ int i;
+ for( i=0; i<4; i++ )
+ {
+ sum += A[row][i]*B[i][col];
+ }
+ temp[row][col] = sum;
+ }
+ }
+ memcpy( A, temp, sizeof(temp) );
+} /* matrix3d_Multiply */
+
+static void
+matrix3d_Identity( float M[4][4] )
+{
+ int r,c;
+
+ for( r=0; r<4; r++ )
+ {
+ for( c=0; c<4; c++ )
+ {
+ M[r][c] = (r==c)?1.0:0.0;
+ }
+ }
+} /* matrix3d_Identity */
+
+static void
+TransformPoint( float *vx, float *vy, float *vz, float m[4][4] )
+{
+ float x = *vx;
+ float y = *vy;
+ float z = *vz;
+ *vx = m[0][0]*x + m[1][0]*y + m[2][0]*z + m[3][0];
+ *vy = m[0][1]*x + m[1][1]*y + m[2][1]*z + m[3][1];
+ *vz = m[0][2]*x + m[1][2]*y + m[2][2]*z + m[3][2];
+}
+
+static void
+TransformNormal( float *nx, float *ny, float *nz, float m[4][4] )
+{
+ float x = *nx;
+ float y = *ny;
+ float z = *nz;
+ *nx = m[0][0]*x + m[1][0]*y + m[2][0]*z;
+ *ny = m[0][1]*x + m[1][1]*y + m[2][1]*z;
+ *nz = m[0][2]*x + m[1][2]*y + m[2][2]*z;
+}
+
+#define MAX_LIT_SURFACES 32
+static UINT8 mLitSurfaceInfo[MAX_LIT_SURFACES];
+static INT32 mSurfaceNormalFormat;
+
+static unsigned mLitSurfaceCount;
+static unsigned mLitSurfaceIndex;
+
+static int mPtRomSize;
+static const UINT8 *mpPolyH;
+static const UINT8 *mpPolyM;
+static const UINT8 *mpPolyL;
+
+static struct
+{
+ float zoom, vx, vy, vw, vh;
+ float lx,ly,lz; /* unit vector for light direction */
+ int ambient; /* 0.0..1.0 */
+ int power; /* 0.0..1.0 */
+} mCamera;
+
+typedef enum
+{
+ eSCENENODE_NONLEAF,
+ eSCENENODE_QUAD3D,
+ eSCENENODE_SPRITE
+} SceneNodeType;
+
+#define RADIX_BITS 4
+#define RADIX_BUCKETS (1<<RADIX_BITS)
+#define RADIX_MASK (RADIX_BUCKETS-1)
+
+struct SceneNode
+{
+ SceneNodeType type;
+ struct SceneNode *nextInBucket;
+ union
+ {
+ struct
+ {
+ struct SceneNode *next[RADIX_BUCKETS];
+ } nonleaf;
+
+ struct
+ {
+ float vx,vy,vw,vh;
+ int textureBank;
+ int color;
+ int cmode;
+ int flags;
+ int direct;
+ Poly3dVertex v[4];
+ } quad3d;
+
+ struct
+ {
+ int tile, color, pri;
+ int flipx, flipy;
+ int linkType;
+ int numcols, numrows;
+ int xpos, ypos;
+ int sizex, sizey;
+ int translucency;
+ int cz;
+ } sprite;
+ } data;
+};
+static struct SceneNode mSceneRoot;
+static struct SceneNode *mpFreeSceneNode;
+
+static void
+FreeSceneNode( struct SceneNode *node )
+{
+ node->nextInBucket = mpFreeSceneNode;
+ mpFreeSceneNode = node;
+} /* FreeSceneNode */
+
+static struct SceneNode *
+MallocSceneNode( void )
+{
+ struct SceneNode *node = mpFreeSceneNode;
+ if( node )
+ { /* use free pool */
+ mpFreeSceneNode = node->nextInBucket;
+ }
+ else
+ {
+#define SCENE_NODE_POOL_SIZE 64
+ struct SceneNode *pSceneNodePool = auto_malloc(sizeof(struct SceneNode)*SCENE_NODE_POOL_SIZE);
+ {
+ int i;
+ for( i=0; i<SCENE_NODE_POOL_SIZE; i++ )
+ {
+ FreeSceneNode( &pSceneNodePool[i] );
+ }
+ return MallocSceneNode();
+ }
+ }
+ memset( node, 0, sizeof(*node) );
+ return node;
+} /* MallocSceneNode */
+
+static struct SceneNode *
+NewSceneNode( UINT32 zsortvalue24, SceneNodeType type )
+{
+ struct SceneNode *node = &mSceneRoot;
+ int i;
+ for( i=0; i<24; i+=RADIX_BITS )
+ {
+ int hash = (zsortvalue24>>20)&RADIX_MASK;
+ struct SceneNode *next = node->data.nonleaf.next[hash];
+ if( !next )
+ { /* lazily allocate tree node for this radix */
+ next = MallocSceneNode();
+ next->type = eSCENENODE_NONLEAF;
+ node->data.nonleaf.next[hash] = next;
+ }
+ node = next;
+ zsortvalue24 <<= RADIX_BITS;
+ }
+
+ if( node->type == eSCENENODE_NONLEAF )
+ { /* first leaf allocation on this branch */
+ node->type = type;
+ return node;
+ }
+ else
+ {
+ struct SceneNode *leaf = MallocSceneNode();
+ leaf->type = type;
+#if 0
+ leaf->nextInBucket = node->nextInBucket;
+ node->nextInBucket = leaf;
+#else
+ /* stable insertion sort */
+ leaf->nextInBucket = NULL;
+ while( node->nextInBucket )
+ {
+ node = node->nextInBucket;
+ }
+ node->nextInBucket = leaf;
+#endif
+ return leaf;
+ }
+} /* NewSceneNode */
+
+
+static void RenderSprite(running_machine *machine, mame_bitmap *bitmap, struct SceneNode *node )
+{
+ int tile = node->data.sprite.tile;
+ int col,row;
+ int i = 0;
+ for( row=0; row<node->data.sprite.numrows; row++ )
+ {
+ for( col=0; col<node->data.sprite.numcols; col++ )
+ {
+ int code = tile;
+ if( node->data.sprite.linkType == 0xff )
+ {
+ code += i;
+ }
+ else
+ {
+ code += nthword( &spriteram32[0x800/4], i+node->data.sprite.linkType*4 );
+ }
+ poly3d_Draw3dSprite(
+ bitmap,
+ machine->gfx[GFX_SPRITE],
+ code,
+ node->data.sprite.color,
+ node->data.sprite.xpos+col*node->data.sprite.sizex,
+ node->data.sprite.ypos+row*node->data.sprite.sizey,
+ node->data.sprite.sizex,
+ node->data.sprite.sizey,
+ node->data.sprite.translucency,
+ node->data.sprite.cz,
+ node->data.sprite.pri );
+ i++;
+ } /* next col */
+ } /* next row */
+} /* RenderSprite */
+
+static void RenderSceneHelper(running_machine *machine, mame_bitmap *bitmap, struct SceneNode *node )
+{
+ if( node )
+ {
+ if( node->type == eSCENENODE_NONLEAF )
+ {
+ int i;
+ for( i=RADIX_BUCKETS-1; i>=0; i-- )
+ {
+ RenderSceneHelper(machine, bitmap, node->data.nonleaf.next[i] );
+ }
+ FreeSceneNode( node );
+ }
+ else
+ {
+ while( node )
+ {
+ struct SceneNode *next = node->nextInBucket;
+
+ switch( node->type )
+ {
+ case eSCENENODE_QUAD3D:
+ poly3d_Clip(
+ node->data.quad3d.vx,
+ node->data.quad3d.vy,
+ node->data.quad3d.vw,
+ node->data.quad3d.vh );
+ poly3d_DrawQuad(machine,
+ bitmap,
+ node->data.quad3d.textureBank,
+ node->data.quad3d.color,
+ node->data.quad3d.v,
+ node->data.quad3d.flags,
+ node->data.quad3d.direct,
+ node->data.quad3d.cmode );
+ break;
+
+ case eSCENENODE_SPRITE:
+ poly3d_NoClip();
+ RenderSprite(machine, bitmap,node );
+ break;
+
+ default:
+ fatalerror("invalid node->type");
+ break;
+ }
+ FreeSceneNode( node );
+ node = next;
+ }
+ }
+ }
+} /* RenderSceneHelper */
+
+static void RenderScene(running_machine *machine, mame_bitmap *bitmap )
+{
+ struct SceneNode *node = &mSceneRoot;
+ int i;
+ for( i=RADIX_BUCKETS-1; i>=0; i-- )
+ {
+ RenderSceneHelper(machine, bitmap, node->data.nonleaf.next[i] );
+ node->data.nonleaf.next[i] = NULL;
+ }
+ poly3d_NoClip();
+ poly_wait(poly, "DrawPolygons");
+} /* RenderScene */
+
+static float
+DspFloatToNativeFloat( UINT32 iVal )
+{
+ INT16 mantissa = (INT16)iVal;
+ float result = mantissa;//?((float)mantissa):((float)0x10000);
+ int exponent = (iVal>>16)&0xff;
+ while( exponent<0x2e )
+ {
+ result /= 2.0;
+ exponent++;
+ }
+ return result;
+} /* DspFloatToNativeFloat */
+
+static INT32
+GetPolyData( INT32 addr )
+{
+ INT32 result;
+ if( addr<0 || addr>=mPtRomSize )
+ {
+ return -1; /* HACK */
+ }
+ result = (mpPolyH[addr]<<16)|(mpPolyM[addr]<<8)|mpPolyL[addr];
+ if( result&0x00800000 )
+ {
+ result |= 0xff000000; /* sign extend */
+ }
+ return result;
+} /* GetPolyData */
+
+UINT32
+namcos22_point_rom_r( offs_t offs )
+{
+ return GetPolyData(offs);
+}
+
+UINT32 *namcos22_cgram;
+UINT32 *namcos22_textram;
+UINT32 *namcos22_polygonram;
+UINT32 *namcos22_gamma;
+UINT32 *namcos22_vics_data;
+UINT32 *namcos22_vics_control;
+
+/*
+ 0 2 4 6 8 a b
+ ^^^^ ^^^^ ^^^^ ^^^^ cz offset
+ ^^^^ target (4==poly)
+ ^^^^ ????
+ //00810000: 0000 0000 0000 0000 4444 0000 0000 0000 // solitar
+ //00810000: 0000 0000 0000 0000 7555 0000 00e4 0000 // normal
+ //00810000: 7fff 8000 7fff 8000 7555 0000 00e4 0000 // offset
+ //00810000: 0000 0000 0000 0000 3111 0000 00e4 0000 // off
+ //00810000: 0004 0004 0004 0004 4444 0000 0000 0000 // out pool
+ //00810000: 00a4 00a4 00a4 00a4 4444 0000 0000 0000 // in pool
+ //00810000: ff80 ff80 ff80 ff80 4444 0000 0000 0000 // ending
+ //00810000: ff80 ff80 ff80 ff80 0000 0000 0000 0000 // hs entry
+ //00810000: ff01 ff01 0000 0000 0000 0000 00e4 0000 // alpine racer
+*/
+UINT32 *namcos22_czattr;
+
+UINT32 *namcos22_tilemapattr;
+
+static int cgsomethingisdirty;
+static UINT8 *cgdirty;
+static UINT8 *dirtypal;
+
+READ32_HANDLER( namcos22_czram_r )
+{
+ int bank = nthword(namcos22_czattr,0xa/2);
+ const UINT16 *czram = namcos22_czram[bank&3];
+ return (czram[offset*2]<<16)|czram[offset*2+1];
+}
+
+WRITE32_HANDLER( namcos22_czram_w )
+{
+ int bank = nthword(namcos22_czattr,0xa/2);
+ UINT16 *czram = namcos22_czram[bank&3];
+ UINT32 dat = (czram[offset*2]<<16)|czram[offset*2+1];
+ COMBINE_DATA( &dat );
+ czram[offset*2] = dat>>16;
+ czram[offset*2+1] = dat&0xffff;
+}
+
+static void
+InitXYAttrToPixel( void )
+{
+ unsigned attr,x,y,ix,iy,temp;
+ for( attr=0; attr<16; attr++ )
+ {
+ for( y=0; y<16; y++ )
+ {
+ for( x=0; x<16; x++ )
+ {
+ ix = x; iy = y;
+ if( attr&4 ) ix = 15-ix;
+ if( attr&2 ) iy = 15-iy;
+ if( attr&8 ){ temp = ix; ix = iy; iy = temp; }
+ mXYAttrToPixel[attr][x][y] = (iy<<4)|ix;
+ }
+ }
+ }
+} /* InitXYAttrToPixel */
+
+static void
+PatchTexture( void )
+{
+ int i;
+ switch( namcos22_gametype )
+ {
+ case NAMCOS22_RIDGE_RACER:
+ case NAMCOS22_RIDGE_RACER2:
+ case NAMCOS22_ACE_DRIVER:
+ case NAMCOS22_CYBER_COMMANDO:
+ for( i=0; i<0x100000; i++ )
+ {
+ int tile = mpTextureTileMap16[i];
+ int attr = mpTextureTileMapAttr[i];
+ if( (attr&0x1)==0 )
+ {
+ tile = (tile&0x3fff)|0x8000;
+ mpTextureTileMap16[i] = tile;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+} /* PatchTexture */
+
+void
+namcos22_draw_direct_poly( const UINT16 *pSource )
+{
+ /**
+ * word#0:
+ * x--------------- end-of-display-list marker
+ * ----xxxxxxxxxxxx priority (lo)
+ *
+ * word#1:
+ * ----xxxxxxxxxxxx priority (hi)
+ *
+ * word#2:
+ * xxxxxxxx-------- PAL (high bit is fog enable)
+ * --------xxxx---- CMODE (color mode for texture unpack)
+ * ------------xxxx BN (texture bank)
+ *
+ * word#3:
+ * xxxxxxxx-------- ZC
+ * --------------xx depth cueing table select
+ *
+ * for each vertex:
+ * xxxx xxxx // u,v
+ *
+ * xxxx xxxx // sx,sy
+ *
+ * xx-- ---- // BRI
+ * --xx xxxx // zpos
+ */
+ INT32 zsortvalue24 = ((pSource[1]&0xfff)<<12)|(pSource[0]&0xfff);
+ struct SceneNode *node = NewSceneNode(zsortvalue24,eSCENENODE_QUAD3D);
+ int i;
+ node->data.quad3d.flags = ((pSource[3]&0x7f00)*2)|(pSource[3]&3);
+ node->data.quad3d.cmode = (pSource[2]&0x00f0)>>4;
+ node->data.quad3d.textureBank = pSource[2]&0xf;
+ node->data.quad3d.color = (pSource[2]&0xff00)>>8;
+ pSource += 4;
+ for( i=0; i<4; i++ )
+ {
+ Poly3dVertex *p = &node->data.quad3d.v[i];
+
+ p->u = pSource[0];
+ p->v = pSource[1];
+ if( mbSuperSystem22 )
+ {
+ p->u >>= 4;
+ p->v >>= 4;
+ }
+ p->u &= 0xfff;
+ p->v &= 0xfff;
+
+ {
+ int mantissa = (INT16)pSource[5];
+ float zf = (float)mantissa;
+ int exponent = (pSource[4])&0xff;
+ if( mantissa )
+ {
+ while( exponent<0x2e )
+ {
+ zf /= 2.0;
+ exponent++;
+ }
+ if( mbSuperSystem22 )
+ p->z = zf;
+ else
+ p->z = 1.0f/zf;
+ }
+ else
+ {
+ zf = (float)0x10000;
+ exponent = 0x40-exponent;
+ while( exponent<0x2e )
+ {
+ zf /= 2.0;
+ exponent++;
+ }
+ p->z = 1.0f/zf;
+ }
+ }
+
+ p->x = ((INT16)pSource[2]);
+ p->y = (-(INT16)pSource[3]);
+ p->bri = pSource[4]>>8;
+ pSource += 6;
+ }
+ node->data.quad3d.direct = 1;
+ node->data.quad3d.vx = 0;
+ node->data.quad3d.vy = 0;
+ node->data.quad3d.vw = -320;
+ node->data.quad3d.vh = -240;
+} /* namcos22_draw_direct_poly */
+
+static void
+Prepare3dTexture( void *pTilemapROM, void *pTextureROM )
+{
+ int i;
+ assert( pTilemapROM && pTextureROM );
+ { /* following setup is Namco System 22 specific */
+ const UINT8 *pPackedTileAttr = 0x200000 + (UINT8 *)pTilemapROM;
+ UINT8 *pUnpackedTileAttr = auto_malloc(0x080000*2);
+ {
+ InitXYAttrToPixel();
+ mpTextureTileMapAttr = pUnpackedTileAttr;
+ for( i=0; i<0x80000; i++ )
+ {
+ *pUnpackedTileAttr++ = (*pPackedTileAttr)>>4;
+ *pUnpackedTileAttr++ = (*pPackedTileAttr)&0xf;
+ pPackedTileAttr++;
+ }
+ mpTextureTileMap16 = pTilemapROM;
+ mpTextureTileData = pTextureROM;
+ PatchTexture();
+ }
+ }
+} /* Prepare3dTexture */
+
+static void
+DrawSpritesHelper(
+ mame_bitmap *bitmap,
+ const rectangle *cliprect,
+ const UINT32 *pSource,
+ const UINT32 *pPal,
+ int num_sprites,
+ int deltax,
+ int deltay )
+{
+ int i;
+ for( i=0; i<num_sprites; i++ )
+ {
+ /*
+ ----.-x--.----.----.----.----.----.---- hidden?
+ ----.--xx.----.----.----.----.----.---- ?
+ ----.----.xxxx.xxxx.xxxx.----.----.---- always 0xff0?
+ ----.----.----.----.----.--x-.----.---- right justify
+ ----.----.----.----.----.---x.----.---- bottom justify
+ ----.----.----.----.----.----.x---.---- flipx
+ ----.----.----.----.----.----.-xxx.---- numcols
+ ----.----.----.----.----.----.----.x--- flipy
+ ----.----.----.----.----.----.----.-xxx numrows
+ */
+ UINT32 attrs = pSource[2];
+ if( (attrs&0x04000000)==0 )
+ { /* sprite is not hidden */
+ INT32 zcoord = pPal[0];
+ int color = pPal[1]>>16;
+ int cz = pPal[1]&0xffff;
+ UINT32 xypos = pSource[0];
+ UINT32 size = pSource[1];
+ UINT32 code = pSource[3];
+ int xpos = (xypos>>16)-deltax;
+ int ypos = (xypos&0xffff)-deltay;
+ int sizex = size>>16;
+ int sizey = size&0xffff;
+ int zoomx = (1<<16)*sizex/0x20;
+ int zoomy = (1<<16)*sizey/0x20;
+ int flipy = attrs&0x8;
+ int numrows = attrs&0x7; /* 0000 0001 1111 1111 0000 0000 fccc frrr */
+ int linkType = (attrs&0x00ff0000)>>16;
+ int flipx = (attrs>>4)&0x8;
+ int numcols = (attrs>>4)&0x7;
+ int tile = code>>16;
+ int translucency = (code&0xff00)>>8;
+
+ if( numrows==0 )
+ numrows = 8;
+ if( flipy )
+ {
+ ypos += sizey*(numrows-1);
+ sizey = -sizey;
+ }
+
+ if( numcols==0 )
+ numcols = 8;
+ if( flipx )
+ {
+ xpos += sizex*(numcols-1);
+ sizex = -sizex;
+ }
+
+ if( attrs & 0x0200 )
+ { /* right justify */
+ xpos -= ((zoomx*numcols*0x20)>>16)-1;
+ }
+ if( attrs & 0x0100 )
+ { /* bottom justify */
+ ypos -= ((zoomy*numrows*0x20)>>16)-1;
+ }
+
+ {
+ struct SceneNode *node = NewSceneNode(zcoord,eSCENENODE_SPRITE);
+ node->data.sprite.tile = tile;
+ node->data.sprite.pri = cz&0x80;
+ // node->data.sprite.pri = (color&0x80);
+ node->data.sprite.color = color&0x7f;
+ node->data.sprite.flipx = flipx;
+ node->data.sprite.flipy = flipy;
+ node->data.sprite.numcols = numcols;
+ node->data.sprite.numrows = numrows;
+ node->data.sprite.linkType = linkType;
+ node->data.sprite.xpos = xpos;
+ node->data.sprite.ypos = ypos;
+ node->data.sprite.sizex = sizex;
+ node->data.sprite.sizey = sizey;
+ node->data.sprite.translucency = translucency;
+ node->data.sprite.cz = cz;
+ }
+ } /* visible sprite */
+ pSource += 4;
+ pPal += 2;
+ }
+} /* DrawSpritesHelper */
+
+static void
+DrawSprites( mame_bitmap *bitmap, const rectangle *cliprect )
+{
+/*
+// time crisis:
+00980000: 00060000 000b0053 03000200 03000000
+00980010: 00200020 028004ff 032a0509 00000000
+00980200: 000007ff 000007ff 000007ff 032a0509
+00980210: 000007ff 000007ff 000007ff 000007ff
+00980220: 000007ff 000007ff 000007ff 000007ff
+00980230: 000007ff 000007ff 05000500 050a050a
+
+// prop normal
+00980000: 00060000 00040053 03000200 03000000
+00980010: 00200020 028004ff 032a0509 00000000
+00980200: 028004ff 032a0509 028004ff 032a0509
+00980210: 028004ff 032a0509 028004ff 032a0509
+00980220: 028004ff 032a0509 028004ff 032a0509
+00980230: 028004ff 032a0509 028004ff 032a0509
+
+//alpine normal / prop test (-48,-43)
+00980000: 00060000 00000000 02ff0000 000007ff
+00980010: 00200020 000002ff 000007ff 00000000
+00980200: 000007ff 000007ff 000007ff 000007ff
+00980210: 000007ff 000007ff 000007ff 000007ff
+00980220: 000007ff 000007ff 000007ff 000007ff
+00980230: 000007ff 000007ff 000007ff 000007ff
+
+
+ 0x980000: 00060000 00010000 02ff0000 000007ff
+ ^^^^ 7 = disable
+ ^^^^ num sprites
+
+ 0x980010: 00200020 000002ff 000007ff 00000000
+ ^^^^^^^^ character size?
+ ^^^^ delta xpos?
+ ^^^^ delta ypos?
+
+ 0x980200: 000007ff 000007ff delta xpos, delta ypos?
+ 0x980208: 000007ff 000007ff
+ 0x980210: 000007ff 000007ff
+ 0x980218: 000007ff 000007ff
+ 0x980220: 000007ff 000007ff
+ 0x980228: 000007ff 000007ff
+ 0x980230: 000007ff 000007ff
+ 0x980238: 000007ff 000007ff
+
+ //time crisis
+ 00980200: 000007ff 000007ff 000007ff 032a0509
+ 00980210: 000007ff 000007ff 000007ff 000007ff
+ 00980220: 000007ff 000007ff 000007ff 000007ff
+ 00980230: 000007ff 000007ff 05000500 050a050a
+
+ 0x980400: hzoom table
+ 0x980600: vzoom table
+
+ link table:
+ 0x980800: 0000 0001 0002 0003 ... 03ff
+
+ eight words per sprite:
+ 0x984000: 010f 007b xpos, ypos
+ 0x984004: 0020 0020 size x, size y
+ 0x984008: 00ff 0311 00ff, chr x;chr y;flip x;flip y
+ 0x98400c: 0001 0000 sprite code, translucency
+ ...
+
+ additional sorting/color data for sprite:
+ 0x9a0000: C381 Z (sort)
+ 0x9a0004: palette, C381 ZC (depth cueing)
+ ...
+ */
+ int num_sprites = ((spriteram32[0x04/4]>>16)&0x3ff)+1;
+ const UINT32 *pSource = &spriteram32[0x4000/4];
+ const UINT32 *pPal = &spriteram32[0x20000/4];
+ int deltax = spriteram32[0x14/4]>>16;
+ int deltay = spriteram32[0x18/4]>>16;
+ int enable = spriteram32[0]>>16;
+
+ if( spriteram32[0x14/4] == 0x000002ff &&
+ spriteram32[0x18/4] == 0x000007ff )
+ { /* HACK (fixes alpine racer and self test) */
+ deltax = 48;
+ deltay = 43;
+ }
+
+ if( enable==6 /*&& namcos22_gametype!=NAMCOS22_AIR_COMBAT22*/ )
+ {
+ DrawSpritesHelper( bitmap, cliprect, pSource, pPal, num_sprites, deltax, deltay );
+ }
+
+ /* VICS RAM provides two additional banks */
+ /*
+ 0x940000 -x------ sprite chip busy
+ 0x940018 xxxx---- clr.w $940018.l
+
+ 0x940034 xxxxxxxx 0x3070b0f
+
+ 0x940040 xxxxxxxx sprite attribute size
+ 0x940048 xxxxxxxx sprite attribute list baseaddr
+ 0x940050 xxxxxxxx sprite color size
+ 0x940058 xxxxxxxx sprite color list baseaddr
+
+ 0x940060..0x94007c set#2
+ */
+
+ num_sprites = (namcos22_vics_control[0x40/4]&0xffff)/0x10;
+ if( num_sprites>=1 )
+ {
+ pSource = &namcos22_vics_data[(namcos22_vics_control[0x48/4]&0xffff)/4];
+ pPal = &namcos22_vics_data[(namcos22_vics_control[0x58/4]&0xffff)/4];
+ DrawSpritesHelper( bitmap, cliprect, pSource, pPal, num_sprites, deltax, deltay );
+ }
+
+ num_sprites = (namcos22_vics_control[0x60/4]&0xffff)/0x10;
+ if( num_sprites>=1 )
+ {
+ pSource = &namcos22_vics_data[(namcos22_vics_control[0x68/4]&0xffff)/4];
+ pPal = &namcos22_vics_data[(namcos22_vics_control[0x78/4]&0xffff)/4];
+ DrawSpritesHelper( bitmap, cliprect, pSource, pPal, num_sprites, deltax, deltay );
+ }
+} /* DrawSprites */
+
+static void UpdatePaletteS(running_machine *machine) /* for Super System22 - apply gamma correction and preliminary fader support */
+{
+ int i;
+ for( i=0; i<NAMCOS22_PALETTE_SIZE/4; i++ )
+ {
+ if( dirtypal[i] )
+ {
+ int j;
+ for( j=0; j<4; j++ )
+ {
+ int which = i*4+j;
+ int r = nthbyte(paletteram32,which+0x00000);
+ int g = nthbyte(paletteram32,which+0x08000);
+ int b = nthbyte(paletteram32,which+0x10000);
+ palette_set_color( machine,which,MAKE_RGB(r,g,b) );
+ }
+ dirtypal[i] = 0;
+ }
+ }
+} /* UpdatePaletteS */
+
+static void UpdatePalette(running_machine *machine) /* for System22 - ignore gamma/fader effects for now */
+{
+ int i,j;
+ for( i=0; i<NAMCOS22_PALETTE_SIZE/4; i++ )
+ {
+ if( dirtypal[i] )
+ {
+ for( j=0; j<4; j++ )
+ {
+ int which = i*4+j;
+ int r = nthbyte(paletteram32,which+0x00000);
+ int g = nthbyte(paletteram32,which+0x08000);
+ int b = nthbyte(paletteram32,which+0x10000);
+ palette_set_color( machine,which,MAKE_RGB(r,g,b) );
+ }
+ dirtypal[i] = 0;
+ }
+ }
+} /* UpdatePalette */
+
+static tilemap *bgtilemap;
+
+static TILE_GET_INFO( TextTilemapGetInfo )
+{
+ UINT16 data = nthword( namcos22_textram,tile_index );
+ /**
+ * x---.----.----.---- blend
+ * xxxx.----.----.---- palette select
+ * ----.xx--.----.---- flip
+ * ----.--xx.xxxx.xxxx code
+ */
+ SET_TILE_INFO( GFX_CHAR,data&0x03ff,data>>12,TILE_FLIPYX((data&0x0c00)>>10) );
+ if( data&0x8000 )
+ {
+ tileinfo->category = 1;
+ }
+} /* TextTilemapGetInfo */
+
+READ32_HANDLER( namcos22_textram_r )
+{
+ return namcos22_textram[offset];
+}
+
+WRITE32_HANDLER( namcos22_textram_w )
+{
+ COMBINE_DATA( &namcos22_textram[offset] );
+ tilemap_mark_tile_dirty( bgtilemap, offset*2 );
+ tilemap_mark_tile_dirty( bgtilemap, offset*2+1 );
+}
+
+static void
+DrawTranslucentCharacters( mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ alpha_set_level( 0xff-mixer.text_translucency ); /* ? */
+ tilemap_draw( bitmap, cliprect, bgtilemap, TILEMAP_DRAW_ALPHA|1, 0 );
+}
+
+static void DrawCharacterLayer(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ unsigned i;
+ INT32 dx = namcos22_tilemapattr[0]>>16;
+ INT32 dy = namcos22_tilemapattr[0]&0xffff;
+ /**
+ * namcos22_tilemapattr[0x4/4] == 0x006e0000
+ * namcos22_tilemapattr[0x8/4] == 0x01ff0000
+ * namcos22_tilemapattr[0xe/4] == ?
+ */
+ if( cgsomethingisdirty )
+ {
+ for( i=0; i<64*64; i+=2 )
+ {
+ UINT32 data = namcos22_textram[i/2];
+ if( cgdirty[(data>>16)&0x3ff] )
+ {
+ tilemap_mark_tile_dirty( bgtilemap,i );
+ }
+ if( cgdirty[data&0x3ff] )
+ {
+ tilemap_mark_tile_dirty( bgtilemap,i+1 );
+ }
+ }
+
+ for( i=0; i<NUM_CG_CHARS; i++ )
+ {
+ if( cgdirty[i] )
+ {
+ decodechar( machine->gfx[GFX_CHAR],i,(UINT8 *)namcos22_cgram,&namcos22_cg_layout );
+ cgdirty[i] = 0;
+ }
+ }
+ cgsomethingisdirty = 0;
+ }
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ tilemap_set_scrollx( bgtilemap,0, (dx-0x35c)&0x3ff );
+ tilemap_set_scrolly( bgtilemap,0, dy&0x3ff );
+ tilemap_set_palette_offset( bgtilemap, mixer.palBase*256 );
+ tilemap_draw( bitmap, cliprect, bgtilemap, 0/*flags*/, 0x1/*priority*/ ); /* opaque */
+} /* DrawCharacterLayer */
+
+/*********************************************************************************************/
+
+static int
+Cap( int val, int minval, int maxval )
+{
+ if( val<minval )
+ {
+ val = minval;
+ }
+ else if( val>maxval )
+ {
+ val = maxval;
+ }
+ return val;
+}
+
+#define LSB21 (0x1fffff)
+#define LSB18 (0x03ffff)
+
+static INT32
+Signed18( UINT32 value )
+{
+ INT32 offset = value&LSB18;
+ if( offset&0x20000 )
+ { /* sign extend */
+ offset |= ~LSB18;
+ }
+ return offset;
+}
+
+/**
+ * @brief render a single quad
+ *
+ * @param flags
+ * x1.----.----.---- priority over tilemap
+ * --.-xxx.----.---- representative z algorithm?
+ * --.----.-1x-.---- backface cull enable
+ * --.----.----.--1x fog enable?
+ *
+ * 1163 // sky
+ * 1262 // score (front)
+ * 1242 // score (hinge)
+ * 1243 // ?
+ * 1063 // n/a
+ * 1243 // various (2-sided?)
+ * 1263 // everything else (1-sided?)
+ * 1663 // ?
+ *
+ * @param color
+ * -------- xxxxxxxx unused?
+ * -xxxxxxx -------- palette select
+ * x------- -------- ?
+ *
+ * @param polygonShiftValue22
+ * 0x1fbd0 - sky+sea
+ * 0x0c350 - mountins
+ * 0x09c40 - boats, surf, road, buildings
+ * 0x07350 - guardrail
+ * 0x061a8 - red car
+ */
+static void
+BlitQuadHelper(
+ mame_bitmap *bitmap,
+ unsigned color,
+ unsigned addr,
+ float m[4][4],
+ INT32 polygonShiftValue22, /* 22 bits */
+ int flags,
+ int packetFormat )
+{
+ int absolutePriority = mAbsolutePriority;
+ UINT32 zsortvalue24;
+ float zmin = 0.0f;
+ float zmax = 0.0f;
+ Poly3dVertex v[4];
+ int i;
+ int bBackFace = 0;
+
+ for( i=0; i<4; i++ )
+ {
+ Poly3dVertex *pVerTex = &v[i];
+ pVerTex->x = GetPolyData( 8+i*3+addr );
+ pVerTex->y = GetPolyData( 9+i*3+addr );
+ pVerTex->z = GetPolyData( 10+i*3+addr );
+ TransformPoint( &pVerTex->x, &pVerTex->y, &pVerTex->z, m );
+ } /* for( i=0; i<4; i++ ) */
+
+ if( (v[2].x*((v[0].z*v[1].y)-(v[0].y*v[1].z)))+
+ (v[2].y*((v[0].x*v[1].z)-(v[0].z*v[1].x)))+
+ (v[2].z*((v[0].y*v[1].x)-(v[0].x*v[1].y))) >= 0 &&
+
+ (v[0].x*((v[2].z*v[3].y)-(v[2].y*v[3].z)))+
+ (v[0].y*((v[2].x*v[3].z)-(v[2].z*v[3].x)))+
+ (v[0].z*((v[2].y*v[3].x)-(v[2].x*v[3].y))) >= 0 )
+ {
+ bBackFace = 1;
+ }
+
+ /* backface cull one-sided polygons */
+ if( bBackFace && (flags&0x0020) )
+ return;
+
+ for( i=0; i<4; i++ )
+ {
+ Poly3dVertex *pVerTex = &v[i];
+ int bri;
+
+ pVerTex->u = GetPolyData( 0+i*2+addr );
+ pVerTex->v = GetPolyData( 1+i*2+addr );
+
+ if( i==0 || pVerTex->z > zmax ) zmax = pVerTex->z;
+ if( i==0 || pVerTex->z < zmin ) zmin = pVerTex->z;
+
+ if( mLitSurfaceCount )
+ {
+ bri = mLitSurfaceInfo[mLitSurfaceIndex%mLitSurfaceCount];
+ if( mSurfaceNormalFormat == 0x6666 )
+ {
+ if( i==3 )
+ mLitSurfaceIndex++;
+ }
+ else if( mSurfaceNormalFormat == 0x4000 )
+ mLitSurfaceIndex++;
+ else
+ logerror( "unknown normal format: 0x%x\n", mSurfaceNormalFormat );
+ } /* pLitSurfaceInfo */
+ else if( packetFormat & 0x40 )
+ bri = (GetPolyData(i+addr)>>16)&0xff;
+ else
+ bri = 0x40;
+ pVerTex->bri = bri;
+ } /* for( i=0; i<4; i++ ) */
+
+ if( zmin<0.0f ) zmin = 0.0f;
+ if( zmax<0.0f ) zmax = 0.0f;
+
+ switch( (flags&0x0f00)>>8 )
+ {
+ case 0:
+ zsortvalue24 = (INT32)zmin;
+ break;
+
+ case 1:
+ zsortvalue24 = (INT32)zmax;
+ break;
+
+ case 2:
+ default:
+ zsortvalue24 = (INT32)((zmin+zmax)/2.0f);
+ break;
+ }
+
+ /* relative: representative z + shift values
+ * 1x.xxxx.xxxxxxxx.xxxxxxxx fixed z value
+ * 0x.xx--.--------.-------- absolute priority shift
+ * 0-.--xx.xxxxxxxx.xxxxxxxx z-representative value shift
+ */
+ if( polygonShiftValue22 & 0x200000 )
+ zsortvalue24 = polygonShiftValue22 & LSB21;
+ else
+ {
+ zsortvalue24 += Signed18( polygonShiftValue22 );
+ absolutePriority += (polygonShiftValue22&0x1c0000)>>18;
+ }
+
+ if( mObjectShiftValue22 & 0x200000 )
+ zsortvalue24 = mObjectShiftValue22 & LSB21;
+ else
+ {
+ zsortvalue24 += Signed18( mObjectShiftValue22 );
+ absolutePriority += (mObjectShiftValue22&0x1c0000)>>18;
+ }
+
+ absolutePriority &= 7;
+ zsortvalue24 = Cap(zsortvalue24,0,0x1fffff);
+ zsortvalue24 |= (absolutePriority<<21);
+
+ {
+ struct SceneNode *node = NewSceneNode(zsortvalue24,eSCENENODE_QUAD3D);
+ node->data.quad3d.cmode = (v[0].u>>12)&0xf;
+ node->data.quad3d.textureBank = (v[0].v>>12)&0xf;
+ node->data.quad3d.color = (color>>8)&0xff;
+
+ {
+ INT32 cz = (INT32)((zmin+zmax)/2.0f);
+ cz = Clamp256(cz/0x2000);
+ node->data.quad3d.flags = (cz<<8)|(flags&3);
+ }
+
+ for( i=0; i<4; i++ )
+ {
+ Poly3dVertex *p = &node->data.quad3d.v[i];
+ p->x = v[i].x*mCamera.zoom;
+ p->y = v[i].y*mCamera.zoom;
+ p->z = v[i].z;
+ p->u = v[i].u&0xfff;
+ p->v = v[i].v&0xfff;
+ p->bri = v[i].bri;
+ }
+ node->data.quad3d.direct = 0;
+ node->data.quad3d.vx = mCamera.vx;
+ node->data.quad3d.vy = mCamera.vy;
+ node->data.quad3d.vw = mCamera.vw;
+ node->data.quad3d.vh = mCamera.vh;
+ }
+} /* BlitQuadHelper */
+
+static void
+RegisterNormals( INT32 addr, float m[4][4] )
+{
+ int i;
+ for( i=0; i<4; i++ )
+ {
+ float nx = DSP_FIXED_TO_FLOAT(GetPolyData(addr+i*3+0));
+ float ny = DSP_FIXED_TO_FLOAT(GetPolyData(addr+i*3+1));
+ float nz = DSP_FIXED_TO_FLOAT(GetPolyData(addr+i*3+2));
+ float dotproduct;
+
+ /* transform normal vector */
+ TransformNormal( &nx, &ny, &nz, m );
+ dotproduct = nx*mCamera.lx + ny*mCamera.ly + nz*mCamera.lz;
+ if( dotproduct<0.0f )
+ dotproduct = 0.0f;
+ mLitSurfaceInfo[mLitSurfaceCount++] = mCamera.ambient + mCamera.power*dotproduct;
+ }
+} /* RegisterNormals */
+
+static void
+BlitQuads( mame_bitmap *bitmap, INT32 addr, float m[4][4], INT32 base )
+{
+ int numAdditionalNormals = 0;
+ int chunkLength = GetPolyData(addr++);
+ int finish = addr + chunkLength;
+
+ if( chunkLength>0x100 )
+ fatalerror( "bad packet length" );
+
+ while( addr<finish )
+ {
+ int packetLength = GetPolyData( addr++ );
+ int packetFormat = GetPolyData( addr+0 );
+ int flags, color, bias;
+
+ /**
+ * packetFormat:
+ * 800000 final packet in chunk
+ * 080000 ?
+ * 020000 color word exists?
+ * 010000 z-offset word exists?
+ * 002000 ?
+ * 001000 z-offset word exists?
+ * 000400 ?
+ * 000080 tex# or UV or CMODE?
+ * 000040 use I
+ * 000001 ?
+ *
+ * flags:
+ * 1042 (always set)
+ * 0c00 depth-cueing mode (brake-disc(2108)=001e43, model font)
+ * 0200 usually 1
+ * 0100 ?
+ * 0040 1 ... polygon palette?
+ * 0020 cull backface
+ * 0002 ?
+ * 0001 ?
+ *
+ * color:
+ * ff0000 type?
+ * 008000 depth-cueing off
+ * 007f00 palette#
+ */
+ switch( packetLength )
+ {
+ case 0x17:
+ /**
+ * word 0: opcode (8a24c0)
+ * word 1: flags
+ * word 2: color
+ */
+ flags = GetPolyData(addr+1);
+ color = GetPolyData(addr+2);
+ bias = 0;
+ BlitQuadHelper( bitmap,color,addr+3,m,bias,flags,packetFormat );
+ break;
+
+ case 0x18:
+ /**
+ * word 0: opcode (0b3480 for first N-1 quads or 8b3480 for final quad in primitive)
+ * word 1: flags
+ * word 2: color
+ * word 3: depth bias
+ */
+ flags = GetPolyData(addr+1);
+ color = GetPolyData(addr+2);
+ bias = GetPolyData(addr+3);
+ BlitQuadHelper( bitmap,color,addr+4,m,bias,flags,packetFormat );
+ break;
+
+ case 0x10: /* vertex lighting */
+ /*
+ 333401 (opcode)
+ 000000 [count] [type]
+ 000000 000000 007fff // normal vector
+ 000000 000000 007fff // normal vector
+ 000000 000000 007fff // normal vector
+ 000000 000000 007fff // normal vector
+ */
+ numAdditionalNormals = GetPolyData(addr+2);
+ mSurfaceNormalFormat = GetPolyData(addr+3);
+ mLitSurfaceCount = 0;
+ mLitSurfaceIndex = 0;
+ RegisterNormals( addr+4, m );
+ break;
+
+ case 0x0d: /* additional normals */
+ /*
+ 300401 (opcode)
+ 007b09 ffdd04 0004c2
+ 007a08 ffd968 0001c1
+ ff8354 ffe401 000790
+ ff84f7 ffdd04 0004c2
+ */
+ RegisterNormals( addr+1, m );
+ break;
+
+ default:
+ break;
+ }
+ addr += packetLength;
+ }
+} /* BlitQuads */
+
+static void
+BlitPolyObject( mame_bitmap *bitmap, int code, float M[4][4] )
+{
+ unsigned addr1 = GetPolyData(code);
+ mLitSurfaceCount = 0;
+ mLitSurfaceIndex = 0;
+ for(;;)
+ {
+ INT32 addr2 = GetPolyData(addr1++);
+ if( addr2<0 )
+ break;
+ BlitQuads( bitmap, addr2, M, code );
+ }
+} /* BlitPolyObject */
+
+/*******************************************************************************/
+
+READ32_HANDLER( namcos22_dspram_r )
+{
+ return namcos22_polygonram[offset];
+}
+
+WRITE32_HANDLER( namcos22_dspram_w )
+{
+ COMBINE_DATA( &namcos22_polygonram[offset] );
+}
+
+/*******************************************************************************/
+
+/**
+ * master DSP can write directly to render device via port 0xc.
+ * This is used for "direct drawn" polygons, and "direct draw from point rom"
+ * feature - both opcodes exist in Ridge Racer's display-list processing
+ *
+ * record format:
+ * header (3 words)
+ * polygonShiftValue22
+ * color
+ * flags
+ *
+ * per-vertex data (4*6 words)
+ * u,v
+ * sx,sy
+ * intensity;z.exponent
+ * z.mantissa
+ *
+ * master DSP can specify 3d objects indirectly (along with view transforms),
+ * via the "transmit" PDP opcode. the "render device" sends quad data to the slave DSP
+ * viewspace clipping and projection
+ *
+ * most "3d object" references are 0x45 and greater. references less than 0x45 are "special"
+ * commands, using a similar point rom format. the point rom header may point to point ram.
+ *
+ * slave DSP reads records via port 4
+ * its primary purpose is applying lighting calculations
+ * the slave DSP forwards draw commands to a "draw device"
+ */
+
+/*******************************************************************************/
+
+/**
+ * 0xfffd
+ * 0x0: transform
+ * 0x1
+ * 0x2
+ * 0x5: transform
+ * >=0x45: draw primitive
+ */
+static void
+HandleBB0003( const INT32 *pSource )
+{
+ /*
+ bb0003 or 3b0003
+
+ 14.00c8 light.ambient light.power
+ 01.0000 ? light.dx
+ 06.5a82 window priority light.dy
+ 00.a57e ? light.dz
+
+ c8.0081 vx=200,vy=129
+ 29.6092 zoom = 772.5625
+ 1e.95f8 1e.95f8 0.5858154296875 0.5858154296875 // 452
+ 1e.b079 1e.b079 0.6893463134765 0.6893463134765 // 532
+ 29.58e8 711.25 (border? see time crisis)
+
+ 7ffe 0000 0000
+ 0000 7ffe 0000
+ 0000 0000 7ffe
+ */
+ mCamera.ambient = pSource[0x1]>>16;
+ mCamera.power = pSource[0x1]&0xffff;
+
+ mCamera.lx = DSP_FIXED_TO_FLOAT(pSource[0x2]);
+ mCamera.ly = DSP_FIXED_TO_FLOAT(pSource[0x3]);
+ mCamera.lz = DSP_FIXED_TO_FLOAT(pSource[0x4]);
+
+ mAbsolutePriority = pSource[0x3]>>16;
+ mCamera.vx = (INT16)(pSource[5]>>16);
+ mCamera.vy = (INT16)pSource[5];
+ mCamera.zoom = DspFloatToNativeFloat(pSource[6]);
+ mCamera.vw = DspFloatToNativeFloat(pSource[7])*mCamera.zoom;
+ mCamera.vh = DspFloatToNativeFloat(pSource[9])*mCamera.zoom;
+
+ mViewMatrix[0][0] = DSP_FIXED_TO_FLOAT(pSource[0x0c]);
+ mViewMatrix[1][0] = DSP_FIXED_TO_FLOAT(pSource[0x0d]);
+ mViewMatrix[2][0] = DSP_FIXED_TO_FLOAT(pSource[0x0e]);
+
+ mViewMatrix[0][1] = DSP_FIXED_TO_FLOAT(pSource[0x0f]);
+ mViewMatrix[1][1] = DSP_FIXED_TO_FLOAT(pSource[0x10]);
+ mViewMatrix[2][1] = DSP_FIXED_TO_FLOAT(pSource[0x11]);
+
+ mViewMatrix[0][2] = DSP_FIXED_TO_FLOAT(pSource[0x12]);
+ mViewMatrix[1][2] = DSP_FIXED_TO_FLOAT(pSource[0x13]);
+ mViewMatrix[2][2] = DSP_FIXED_TO_FLOAT(pSource[0x14]);
+
+ TransformNormal( &mCamera.lx, &mCamera.ly, &mCamera.lz, mViewMatrix );
+} /* HandleBB0003 */
+
+static void
+Handle200002( mame_bitmap *bitmap, const INT32 *pSource )
+{
+ if( mPrimitiveID>=0x45 )
+ {
+ float m[4][4]; /* row major */
+
+ matrix3d_Identity( m );
+
+ m[0][0] = DSP_FIXED_TO_FLOAT(pSource[0x1]);
+ m[1][0] = DSP_FIXED_TO_FLOAT(pSource[0x2]);
+ m[2][0] = DSP_FIXED_TO_FLOAT(pSource[0x3]);
+
+ m[0][1] = DSP_FIXED_TO_FLOAT(pSource[0x4]);
+ m[1][1] = DSP_FIXED_TO_FLOAT(pSource[0x5]);
+ m[2][1] = DSP_FIXED_TO_FLOAT(pSource[0x6]);
+
+ m[0][2] = DSP_FIXED_TO_FLOAT(pSource[0x7]);
+ m[1][2] = DSP_FIXED_TO_FLOAT(pSource[0x8]);
+ m[2][2] = DSP_FIXED_TO_FLOAT(pSource[0x9]);
+
+ m[3][0] = pSource[0xa]; /* xpos */
+ m[3][1] = pSource[0xb]; /* ypos */
+ m[3][2] = pSource[0xc]; /* zpos */
+
+ matrix3d_Multiply( m, mViewMatrix );
+ BlitPolyObject( bitmap, mPrimitiveID, m );
+ }
+ else if( mPrimitiveID !=0 && mPrimitiveID !=2 )
+ {
+ logerror( "Handle200002:unk code=0x%x\n", mPrimitiveID );
+ }
+} /* Handle200002 */
+
+static void
+Handle300000( const INT32 *pSource )
+{ /* set view transform */
+ mViewMatrix[0][0] = DSP_FIXED_TO_FLOAT(pSource[1]);
+ mViewMatrix[1][0] = DSP_FIXED_TO_FLOAT(pSource[2]);
+ mViewMatrix[2][0] = DSP_FIXED_TO_FLOAT(pSource[3]);
+
+ mViewMatrix[0][1] = DSP_FIXED_TO_FLOAT(pSource[4]);
+ mViewMatrix[1][1] = DSP_FIXED_TO_FLOAT(pSource[5]);
+ mViewMatrix[2][1] = DSP_FIXED_TO_FLOAT(pSource[6]);
+
+ mViewMatrix[0][2] = DSP_FIXED_TO_FLOAT(pSource[7]);
+ mViewMatrix[1][2] = DSP_FIXED_TO_FLOAT(pSource[8]);
+ mViewMatrix[2][2] = DSP_FIXED_TO_FLOAT(pSource[9]);
+} /* Handle300000 */
+
+static void
+Handle233002( const INT32 *pSource )
+{ /* set modal rendering options */
+ /*
+ 00233002
+ 00000000 // zc adjust?
+ 0003dd00 // z bias adjust
+ 001fffff // far plane?
+ 00007fff 00000000 00000000
+ 00000000 00007fff 00000000
+ 00000000 00000000 00007fff
+ 00000000 00000000 00000000
+ */
+ mObjectShiftValue22 = pSource[2];
+} /* Handle233002 */
+
+static void
+SimulateSlaveDSP( mame_bitmap *bitmap )
+{
+ const INT32 *pSource = 0x300 + (INT32 *)namcos22_polygonram;
+ INT16 len;
+
+ matrix3d_Identity( mViewMatrix );
+
+ if( mbSuperSystem22 )
+ {
+ pSource += 4; /* FFFE 0400 */
+ }
+ else
+ {
+ pSource--;
+ }
+
+ for(;;)
+ {
+ INT16 marker, next;
+ mPrimitiveID = *pSource++;
+ len = (INT16)*pSource++;
+
+ switch( len )
+ {
+ case 0x15:
+ HandleBB0003( pSource ); /* define viewport */
+ break;
+
+ case 0x10:
+ Handle233002( pSource ); /* set modal rendering options */
+ break;
+
+ case 0x0a:
+ Handle300000( pSource ); /* modify view transform */
+ break;
+
+ case 0x0d:
+ Handle200002( bitmap, pSource ); /* render primitive */
+ break;
+
+ default:
+ logerror( "unk 3d data(%d) addr=0x%x!", len, (int)(pSource-(INT32*)namcos22_polygonram) );
+ {
+ int i;
+ for( i=0; i<len; i++ )
+ {
+ logerror( " %06x", pSource[i]&0xffffff );
+ }
+ logerror( "\n" );
+ }
+ return;
+ }
+
+ /* hackery! commands should be streamed, not parsed here */
+ pSource += len;
+ marker = (INT16)*pSource++; /* always 0xffff */
+ next = (INT16)*pSource++; /* link to next command */
+ if( (next&0x7fff) != (pSource - (INT32 *)namcos22_polygonram) )
+ { /* end of list */
+ break;
+ }
+ } /* for(;;) */
+} /* SimulateSlaveDSP */
+
+static void
+DrawPolygons( mame_bitmap *bitmap )
+{
+ if( mbDSPisActive )
+ {
+ SimulateSlaveDSP( bitmap );
+ poly_wait(poly, "DrawPolygons");
+ }
+} /* DrawPolygons */
+
+void
+namcos22_enable_slave_simulation( void )
+{
+ mbDSPisActive = 1;
+}
+
+/*********************************************************************************************/
+
+READ32_HANDLER( namcos22_cgram_r )
+{
+ return namcos22_cgram[offset];
+}
+
+WRITE32_HANDLER( namcos22_cgram_w )
+{
+ COMBINE_DATA( &namcos22_cgram[offset] );
+ cgdirty[offset/32] = 1;
+ cgsomethingisdirty = 1;
+}
+
+READ32_HANDLER( namcos22_gamma_r )
+{
+ return namcos22_gamma[offset];
+}
+
+WRITE32_HANDLER( namcos22_gamma_w )
+{
+ COMBINE_DATA( &namcos22_gamma[offset] );
+}
+
+READ32_HANDLER( namcos22_paletteram_r )
+{
+ return paletteram32[offset];
+}
+
+WRITE32_HANDLER( namcos22_paletteram_w )
+{
+ COMBINE_DATA( &paletteram32[offset] );
+ dirtypal[offset&(0x7fff/4)] = 1;
+}
+
+static void namcos22_exit(running_machine *machine)
+{
+ poly_free(poly);
+}
+
+static void video_start_common(running_machine *machine)
+{
+ bgtilemap = tilemap_create( TextTilemapGetInfo,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64 );
+ tilemap_set_transparent_pen( bgtilemap, 0xf );
+
+ mbDSPisActive = 0;
+ memset( namcos22_polygonram, 0xcc, 0x20000 );
+
+ Prepare3dTexture(memory_region(REGION_TEXTURE_TILEMAP), machine->gfx[GFX_TEXTURE_TILE]->gfxdata );
+ dirtypal = auto_malloc(NAMCOS22_PALETTE_SIZE/4);
+ cgdirty = auto_malloc( 0x400 );
+ mPtRomSize = memory_region_length(REGION_POINTROM)/3;
+ mpPolyL = memory_region(REGION_POINTROM);
+ mpPolyM = mpPolyL + mPtRomSize;
+ mpPolyH = mpPolyM + mPtRomSize;
+
+#ifdef RENDER_AS_QUADS
+ poly = poly_alloc(4000, sizeof(poly_extra_data), POLYFLAG_ALLOW_QUADS);
+#else
+ poly = poly_alloc(4000, sizeof(poly_extra_data), 0);
+#endif
+ add_exit_callback(machine, namcos22_exit);
+}
+
+VIDEO_START( namcos22 )
+{
+ mbSuperSystem22 = 0;
+ video_start_common(machine);
+}
+
+VIDEO_START( namcos22s )
+{
+ mbSuperSystem22 = 1;
+ namcos22_czram[0] = auto_malloc( 0x200 );
+ namcos22_czram[1] = auto_malloc( 0x200 );
+ namcos22_czram[2] = auto_malloc( 0x200 );
+ namcos22_czram[3] = auto_malloc( 0x200 );
+ video_start_common(machine);
+}
+
+VIDEO_UPDATE( namcos22s )
+{
+ UINT32 bgColor;
+ UpdateVideoMixer();
+ bgColor = (mixer.rBackColor<<16)|(mixer.gBackColor<<8)|mixer.bBackColor;
+ fillbitmap( bitmap, bgColor, cliprect );
+ UpdatePaletteS(machine);
+ DrawCharacterLayer(machine, bitmap, cliprect );
+ DrawPolygons( bitmap );
+ DrawSprites( bitmap, cliprect );
+ RenderScene(machine, bitmap );
+ DrawTranslucentCharacters( bitmap, cliprect );
+ ApplyGamma( bitmap );
+
+#ifdef MAME_DEBUG
+ if( input_code_pressed(KEYCODE_D) )
+ {
+ FILE *f = fopen( "dump.txt", "wb" );
+ if( f )
+ {
+ {
+ int i,bank;
+ for( bank=0; bank<4; bank++ )
+ {
+ fprintf( f, "czram[%d] =", bank );
+ for( i=0; i<256; i++ )
+ {
+ fprintf( f, " %04x", namcos22_czram[bank][i] );
+ }
+ fprintf( f, "\n" );
+ }
+ }
+
+ Dump(f,0x810000, 0x81000f, "cz attr" );
+ Dump(f,0x820000, 0x8202ff, "unk_ac" );
+ Dump(f,0x824000, 0x8243ff, "gamma");
+ Dump(f,0x828000, 0x83ffff, "palette" );
+ Dump(f,0x8a0000, 0x8a000f, "tilemap_attr");
+ Dump(f,0x880000, 0x89ffff, "cgram/textram");
+ Dump(f,0x900000, 0x90ffff, "vics_data");
+ Dump(f,0x940000, 0x94007f, "vics_control");
+ Dump(f,0x980000, 0x9affff, "sprite374" );
+ Dump(f,0xc00000, 0xc1ffff, "polygonram");
+ fclose( f );
+ }
+ while( input_code_pressed(KEYCODE_D) ){}
+ }
+#endif
+ return 0;
+}
+
+VIDEO_UPDATE( namcos22 )
+{
+ UpdateVideoMixer();
+ fillbitmap( bitmap, get_black_pen(machine), cliprect );
+ UpdatePalette(machine);
+ DrawCharacterLayer(machine, bitmap, cliprect );
+ DrawPolygons( bitmap );
+ RenderScene(machine, bitmap);
+ DrawTranslucentCharacters( bitmap, cliprect );
+ ApplyGamma( bitmap );
+
+#ifdef MAME_DEBUG
+ if( input_code_pressed(KEYCODE_D) )
+ {
+ FILE *f = fopen( "dump.txt", "wb" );
+ if( f )
+ {
+// Dump(f,0x90000000, 0x90000003, "led?" );
+// Dump(f,0x90010000, 0x90017fff, "cz_ram");
+// Dump(f,0x900a0000, 0x900a000f, "tilemap_attr");
+ Dump(f,0x90020000, 0x90027fff, "gamma");
+ // 0x90020000, 0x90027fff
+// Dump(f,0x70000000, 0x7001ffff, "polygonram");
+ fclose( f );
+ }
+ while( input_code_pressed(KEYCODE_D) ){}
+ }
+#endif
+ return 0;
+}
+
+WRITE16_HANDLER( namcos22_dspram16_bank_w )
+{
+ COMBINE_DATA( &namcos22_dspram_bank );
+}
+
+READ16_HANDLER( namcos22_dspram16_r )
+{
+ UINT32 value = namcos22_polygonram[offset];
+ switch( namcos22_dspram_bank )
+ {
+ case 0:
+ value &= 0xffff;
+ break;
+
+ case 1:
+ value>>=16;
+ break;
+
+ case 2:
+ mUpperWordLatch = value>>16;
+ value &= 0xffff;
+ break;
+
+ default:
+ break;
+ }
+ return (UINT16)value;
+} /* namcos22_dspram16_r */
+
+WRITE16_HANDLER( namcos22_dspram16_w )
+{
+ UINT32 value = namcos22_polygonram[offset];
+ UINT16 lo = value&0xffff;
+ UINT16 hi = value>>16;
+ switch( namcos22_dspram_bank )
+ {
+ case 0:
+ COMBINE_DATA( &lo );
+ break;
+
+ case 1:
+ COMBINE_DATA( &hi );
+ break;
+
+ case 2:
+ COMBINE_DATA( &lo );
+ hi = mUpperWordLatch;
+ break;
+
+ default:
+ break;
+ }
+ namcos22_polygonram[offset] = (hi<<16)|lo;
+} /* namcos22_dspram16_w */
+
+#ifdef MAME_DEBUG
+static void
+Dump( FILE *f, unsigned addr1, unsigned addr2, const char *name )
+{
+ unsigned addr;
+ fprintf( f, "%s:\n", name );
+ for( addr=addr1; addr<=addr2; addr+=16 )
+ {
+ UINT8 data[16];
+ int bHasNonZero = 0;
+ int i;
+ for( i=0; i<16; i++ )
+ {
+ data[i] = cpunum_read_byte( 0, addr+i );
+ if( data[i] )
+ {
+ bHasNonZero = 1;
+ }
+ }
+ if( bHasNonZero )
+ {
+ fprintf( f,"%08x:", addr );
+ for( i=0; i<16; i++ )
+ {
+ if( (i&0x03)==0 )
+ {
+ fprintf( f, " " );
+ }
+ fprintf( f, "%02x", data[i] );
+ }
+ fprintf( f, "\n" );
+ }
+ }
+ fprintf( f, "\n" );
+}
+#endif
+
+/**
+ * 4038 spot enable?
+ * 0828 pre-initialization
+ * 0838 post-initialization
+ **********************************************
+ * upload:
+ * #bits data
+ * 0010 FEC0
+ * 0010 FF10
+ * 0004 0004
+ * 0004 000E
+ * 0003 0007
+ * 0002 0002
+ * 0002 0003
+ * 0001 0001
+ * 0001 0001
+ * 0001 0000
+ * 0001 0001
+ * 0001 0001
+ * 0001 0000
+ * 0001 0000
+ * 0001 0000
+ * 0001 0001
+ **********************************************
+ * 0008 00EA // 0x0ff
+ * 000A 0364 // 0x3ff
+ * 000A 027F // 0x3ff
+ * 0003 0005 // 0x007
+ * 0001 0001 // 0x001
+ * 0001 0001 // 0x001
+ * 0001 0001 // 0x001
+ **********************************************
+ */
+WRITE32_HANDLER(namcos22_port800000_w)
+{
+ /* 00000011011111110000100011111111001001111110111110110001 */
+ UINT16 word = data>>16;
+ logerror( "%x: C304/C399: 0x%04x\n", activecpu_get_previouspc(), word );
+ if( word == 0x4038 )
+ {
+ mbSpotlightEnable = 1;
+ }
+ else
+ {
+ mbSpotlightEnable = 0;
+ }
+} /* namcos22_port800000_w */
diff --git a/src/mame/video/namcos86.c b/src/mame/video/namcos86.c
new file mode 100644
index 00000000000..e0bdeff26df
--- /dev/null
+++ b/src/mame/video/namcos86.c
@@ -0,0 +1,400 @@
+/*******************************************************************
+
+Namco System 86 Video Hardware
+
+*******************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *rthunder_videoram1, *rthunder_videoram2, *rthunder_spriteram;
+
+static int tilebank;
+static int xscroll[4], yscroll[4]; /* scroll + priority */
+
+static tilemap *bg_tilemap[4];
+
+static int backcolor;
+static const UINT8 *tile_address_prom;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Rolling Thunder has two palette PROMs (512x8 and 512x4) and two 2048x8
+ lookup table PROMs.
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 1 kohm resistor -- BLUE
+ bit 0 -- 2.2kohm resistor -- BLUE
+
+ bit 7 -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 2.2kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ -- 1 kohm resistor -- RED
+ bit 0 -- 2.2kohm resistor -- RED
+
+***************************************************************************/
+
+PALETTE_INIT( namcos86 )
+{
+ int i;
+ int totcolors,totlookup;
+
+
+ totcolors = machine->drv->total_colors;
+ totlookup = machine->drv->color_table_len;
+
+ for (i = 0;i < totcolors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[0] >> 4) & 0x01;
+ bit1 = (color_prom[0] >> 5) & 0x01;
+ bit2 = (color_prom[0] >> 6) & 0x01;
+ bit3 = (color_prom[0] >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[totcolors] >> 0) & 0x01;
+ bit1 = (color_prom[totcolors] >> 1) & 0x01;
+ bit2 = (color_prom[totcolors] >> 2) & 0x01;
+ bit3 = (color_prom[totcolors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += totcolors;
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* tiles lookup table */
+ for (i = 0;i < totlookup/2;i++)
+ *(colortable++) = *color_prom++;
+
+ /* sprites lookup table */
+ for (i = 0;i < totlookup/2;i++)
+ *(colortable++) = *(color_prom++) + totcolors/2;
+
+ /* color_prom now points to the beginning of the tile address decode PROM */
+
+ tile_address_prom = color_prom; /* we'll need this at run time */
+}
+
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+INLINE void get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int layer,UINT8 *vram)
+{
+ int attr = vram[2*tile_index + 1];
+ int tile_offs;
+ if (layer & 2)
+ tile_offs = ((tile_address_prom[((layer & 1) << 4) + (attr & 0x03)] & 0xe0) >> 5) * 0x100;
+ else
+ tile_offs = ((tile_address_prom[((layer & 1) << 4) + ((attr & 0x03) << 2)] & 0x0e) >> 1) * 0x100 + tilebank * 0x800;
+
+ SET_TILE_INFO(
+ (layer & 2) ? 1 : 0,
+ vram[2*tile_index] + tile_offs,
+ attr,
+ 0);
+}
+
+static TILE_GET_INFO( get_tile_info0 ) { get_tile_info(machine,tileinfo,tile_index,0,&rthunder_videoram1[0x0000]); }
+static TILE_GET_INFO( get_tile_info1 ) { get_tile_info(machine,tileinfo,tile_index,1,&rthunder_videoram1[0x1000]); }
+static TILE_GET_INFO( get_tile_info2 ) { get_tile_info(machine,tileinfo,tile_index,2,&rthunder_videoram2[0x0000]); }
+static TILE_GET_INFO( get_tile_info3 ) { get_tile_info(machine,tileinfo,tile_index,3,&rthunder_videoram2[0x1000]); }
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( namcos86 )
+{
+ bg_tilemap[0] = tilemap_create(get_tile_info0,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ bg_tilemap[1] = tilemap_create(get_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ bg_tilemap[2] = tilemap_create(get_tile_info2,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ bg_tilemap[3] = tilemap_create(get_tile_info3,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_transparent_pen(bg_tilemap[0],7);
+ tilemap_set_transparent_pen(bg_tilemap[1],7);
+ tilemap_set_transparent_pen(bg_tilemap[2],7);
+ tilemap_set_transparent_pen(bg_tilemap[3],7);
+
+ spriteram = rthunder_spriteram + 0x1800;
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ8_HANDLER( rthunder_videoram1_r )
+{
+ return rthunder_videoram1[offset];
+}
+
+WRITE8_HANDLER( rthunder_videoram1_w )
+{
+ rthunder_videoram1[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap[offset/0x1000],(offset & 0xfff)/2);
+}
+
+READ8_HANDLER( rthunder_videoram2_r )
+{
+ return rthunder_videoram2[offset];
+}
+
+WRITE8_HANDLER( rthunder_videoram2_w )
+{
+ rthunder_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap[2+offset/0x1000],(offset & 0xfff)/2);
+}
+
+WRITE8_HANDLER( rthunder_tilebank_select_w )
+{
+ int bit = BIT(offset,10);
+ if (tilebank != bit)
+ {
+ tilebank = bit;
+ tilemap_mark_all_tiles_dirty(bg_tilemap[0]);
+ tilemap_mark_all_tiles_dirty(bg_tilemap[1]);
+ }
+}
+
+static void scroll_w(int layer,int offset,int data)
+{
+ switch (offset)
+ {
+ case 0:
+ xscroll[layer] = (xscroll[layer]&0xff)|(data<<8);
+ break;
+ case 1:
+ xscroll[layer] = (xscroll[layer]&0xff00)|data;
+ break;
+ case 2:
+ yscroll[layer] = data;
+ break;
+ }
+}
+
+WRITE8_HANDLER( rthunder_scroll0_w )
+{
+ scroll_w(0,offset,data);
+}
+WRITE8_HANDLER( rthunder_scroll1_w )
+{
+ scroll_w(1,offset,data);
+}
+WRITE8_HANDLER( rthunder_scroll2_w )
+{
+ scroll_w(2,offset,data);
+}
+WRITE8_HANDLER( rthunder_scroll3_w )
+{
+ scroll_w(3,offset,data);
+}
+
+WRITE8_HANDLER( rthunder_backcolor_w )
+{
+ backcolor = data;
+}
+
+
+static int copy_sprites;
+
+READ8_HANDLER( rthunder_spriteram_r )
+{
+ return rthunder_spriteram[offset];
+}
+
+WRITE8_HANDLER( rthunder_spriteram_w )
+{
+ rthunder_spriteram[offset] = data;
+
+ /* a write to this offset tells the sprite chip to buffer the sprite list */
+ if (offset == 0x1ff2)
+ copy_sprites = 1;
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+/*
+sprite format:
+
+0-3 scratchpad RAM
+4-9 CPU writes here, hardware copies from here to 10-15
+10 xx------ X size (16, 8, 32, 4)
+10 --x----- X flip
+10 ---xx--- X offset inside 32x32 tile
+10 -----xxx tile bank
+11 xxxxxxxx tile number
+12 xxxxxxx- color
+12 -------x X position MSB
+13 xxxxxxxx X position
+14 xxx----- priority
+14 ---xx--- Y offset inside 32x32 tile
+14 -----xx- Y size (16, 8, 32, 4)
+14 -------x Y flip
+15 xxxxxxxx Y position
+*/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const UINT8 *source = &spriteram[0x0800-0x20]; /* the last is NOT a sprite */
+ const UINT8 *finish = &spriteram[0];
+ gfx_element *gfx = machine->gfx[2];
+ gfx_element mygfx = *gfx;
+
+ int sprite_xoffs = spriteram[0x07f5] + ((spriteram[0x07f4] & 1) << 8);
+ int sprite_yoffs = spriteram[0x07f7];
+
+ int bank_sprites = machine->gfx[2]->total_elements / 8;
+
+ while (source >= finish)
+ {
+ static const int sprite_size[4] = { 16, 8, 32, 4 };
+ int attr1 = source[10];
+ int attr2 = source[14];
+ int color = source[12];
+ int flipx = (attr1 & 0x20) >> 5;
+ int flipy = (attr2 & 0x01);
+ int sizex = sprite_size[(attr1 & 0xc0) >> 6];
+ int sizey = sprite_size[(attr2 & 0x06) >> 1];
+ int tx = (attr1 & 0x18) & (~(sizex-1));
+ int ty = (attr2 & 0x18) & (~(sizey-1));
+ int sx = source[13] + ((color & 0x01) << 8);
+ int sy = -source[15] - sizey;
+ int sprite = source[11];
+ int sprite_bank = attr1 & 7;
+ int priority = (source[14] & 0xe0) >> 5;
+ int pri_mask = (0xff << (priority + 1)) & 0xff;
+
+ sprite &= bank_sprites-1;
+ sprite += sprite_bank * bank_sprites;
+ color = color >> 1;
+
+ sx += sprite_xoffs;
+ sy -= sprite_yoffs;
+
+ if (flip_screen)
+ {
+ sx = -sx - sizex;
+ sy = -sy - sizey;
+ flipx ^= 1;
+ flipy ^= 1;
+ }
+
+ sy++; /* sprites are buffered and delayed by one scanline */
+
+ /* change GfxElement parameters to draw only the needed part of the 32x32 tile */
+ mygfx.width = sizex;
+ mygfx.height = sizey;
+ mygfx.gfxdata = gfx->gfxdata + tx + ty * gfx->line_modulo;
+
+ pdrawgfx( bitmap, &mygfx,
+ sprite,
+ color,
+ flipx,flipy,
+ sx & 0x1ff,
+ ((sy + 16) & 0xff) - 16,
+ cliprect,TRANSPARENCY_PEN,0xf, pri_mask);
+
+ source -= 0x10;
+ }
+}
+
+
+static void set_scroll(int layer)
+{
+ static const int xdisp[4] = { 47, 49, 46, 48 };
+ int scrollx,scrolly;
+
+ scrollx = xscroll[layer] - xdisp[layer];
+ scrolly = yscroll[layer] + 9;
+ if (flip_screen)
+ {
+ scrollx = -scrollx;
+ scrolly = -scrolly;
+ }
+ tilemap_set_scrollx(bg_tilemap[layer], 0, scrollx);
+ tilemap_set_scrolly(bg_tilemap[layer], 0, scrolly);
+}
+
+
+VIDEO_UPDATE( namcos86 )
+{
+ int layer;
+
+ /* flip screen is embedded in the sprite control registers */
+ /* can't use flip_screen_set() because the visible area is asymmetrical */
+ flip_screen = spriteram[0x07f6] & 1;
+ tilemap_set_flip(ALL_TILEMAPS,flip_screen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ set_scroll(0);
+ set_scroll(1);
+ set_scroll(2);
+ set_scroll(3);
+
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ fillbitmap(bitmap,machine->remapped_colortable[machine->gfx[0]->color_base + 8*backcolor+7],cliprect);
+
+ for (layer = 0;layer < 8;layer++)
+ {
+ int i;
+
+ for (i = 3;i >= 0;i--)
+ {
+ if (((xscroll[i] & 0x0e00) >> 9) == layer)
+ tilemap_draw_primask(bitmap,cliprect,bg_tilemap[i],0,layer,0);
+ }
+ }
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+
+VIDEO_EOF( namcos86 )
+{
+ if (copy_sprites)
+ {
+ int i,j;
+
+ for (i = 0;i < 0x800;i += 16)
+ {
+ for (j = 10;j < 16;j++)
+ spriteram[i+j] = spriteram[i+j - 6];
+ }
+
+ copy_sprites = 0;
+ }
+}
diff --git a/src/mame/video/naughtyb.c b/src/mame/video/naughtyb.c
new file mode 100644
index 00000000000..997e61dbe62
--- /dev/null
+++ b/src/mame/video/naughtyb.c
@@ -0,0 +1,332 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/resnet.h"
+#include "includes/phoenix.h"
+
+UINT8 *naughtyb_videoram2;
+
+static int videoreg;
+
+/* use these to draw charset B */
+UINT8 *naughtyb_scrollreg;
+
+/* use this to select palette */
+static UINT8 palreg;
+
+/* used in Naughty Boy to select video bank */
+static int bankreg;
+
+// true if cabinet == cocktail -AND- handling player 2
+int naughtyb_cocktail;
+
+static rectangle scrollvisiblearea =
+{
+ 2*8, 34*8-1,
+ 0*8, 28*8-1
+};
+
+static rectangle leftvisiblearea =
+{
+ 0*8, 2*8-1,
+ 0*8, 28*8-1
+};
+
+static rectangle rightvisiblearea =
+{
+ 34*8, 36*8-1,
+ 0*8, 28*8-1
+};
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Naughty Boy has two 256x4 palette PROMs, one containing the high bits and
+ the other the low bits (2x2x2 color space).
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 --
+ -- 270 ohm resistor -- GREEN
+ -- 270 ohm resistor -- BLUE
+ bit 0 -- 270 ohm resistor -- RED
+
+ bit 3 --
+ -- GREEN
+ -- BLUE
+ bit 0 -- RED
+
+ plus 270 ohm pullup and pulldown resistors on all lines
+
+***************************************************************************/
+PALETTE_INIT( naughtyb )
+{
+ int i;
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ /* note: there is no resistor on second PROM so we define second resistance as 0 */
+ static const int resistances[2] = { 270, 0 };
+ double weights_r[2], weights_g[2], weights_b[2];
+
+
+ compute_resistor_weights(0, 255, -1.0,
+ 2, resistances, weights_r, 270, 270,
+ 2, resistances, weights_g, 270, 270,
+ 2, resistances, weights_b, 270, 270);
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+
+ /*r = 0x55 * bit0 + 0xaa * bit1;*/
+ r = combine_2_weights(weights_r, bit0, bit1);
+
+ bit0 = (color_prom[0] >> 2) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+
+ /*g = 0x55 * bit0 + 0xaa * bit1;*/
+ g = combine_2_weights(weights_g, bit0, bit1);
+
+ bit0 = (color_prom[0] >> 1) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+
+ /*b = 0x55 * bit0 + 0xaa * bit1;*/
+ b = combine_2_weights(weights_b, bit0, bit1);
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* first bank of characters use colors 0-31, 64-95, 128-159 and 192-223 */
+ for (i = 0;i < 8;i++)
+ {
+ int j;
+
+
+ for (j = 0;j < 4;j++)
+ {
+ COLOR(0,4*i + j*4*8) = i + j*64;
+ COLOR(0,4*i + j*4*8 + 1) = 8 + i + j*64;
+ COLOR(0,4*i + j*4*8 + 2) = 2*8 + i + j*64;
+ COLOR(0,4*i + j*4*8 + 3) = 3*8 + i + j*64;
+ }
+ }
+
+ /* second bank of characters use colors 32-63, 96-127, 160-191 and 224-255 */
+ for (i = 0;i < 8;i++)
+ {
+ int j;
+
+
+ for (j = 0;j < 4;j++)
+ {
+ COLOR(1,4*i + j*4*8) = i + 32 + j*64;
+ COLOR(1,4*i + j*4*8 + 1) = 8 + i + 32 + j*64;
+ COLOR(1,4*i + j*4*8 + 2) = 2*8 + i + 32 + j*64;
+ COLOR(1,4*i + j*4*8 + 3) = 3*8 + i + 32 + j*64;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+VIDEO_START( naughtyb )
+{
+ videoreg = palreg = bankreg = 0;
+
+ /* Naughty Boy has a virtual screen twice as large as the visible screen */
+ dirtybuffer = auto_malloc(videoram_size);
+ memset(dirtybuffer, 1, videoram_size);
+
+ tmpbitmap = auto_bitmap_alloc(68*8,28*8,machine->screen[0].format);
+}
+
+
+
+
+WRITE8_HANDLER( naughtyb_videoram2_w )
+{
+ if (naughtyb_videoram2[offset] != data)
+ {
+ dirtybuffer[offset] = 1;
+
+ naughtyb_videoram2[offset] = data;
+ }
+}
+
+
+
+WRITE8_HANDLER( naughtyb_videoreg_w )
+{
+ // bits 4+5 control the sound circuit
+
+ pleiads_sound_control_c_w(offset,data);
+
+ if ((videoreg & 0x0f) != (data & 0x0f))
+ {
+ videoreg = data;
+
+ naughtyb_cocktail =
+ ( ( input_port_2_r(0) & 0x80 ) && // cabinet == cocktail
+ ( data & 0x01 ) ); // handling player 2
+ palreg = (data >> 1) & 0x03; // pallette sel is bit 1 & 2
+ bankreg = (data >> 2) & 0x01; // banksel is just bit 2
+
+ memset (dirtybuffer, 1, videoram_size);
+ }
+}
+
+WRITE8_HANDLER( popflame_videoreg_w )
+{
+ // bits 4+5 control the sound circuit
+
+ pleiads_sound_control_c_w(offset,data);
+
+ if ((videoreg & 0x0f) != (data & 0x0f))
+ {
+ videoreg = data;
+
+ naughtyb_cocktail =
+ ( ( input_port_2_r(0) & 0x80 ) && // cabinet == cocktail
+ ( data & 0x01 ) ); // handling player 2
+ palreg = (data >> 1) & 0x03; // pallette sel is bit 1 & 2
+ bankreg = (data >> 3) & 0x01; // banksel is just bit 3
+
+ memset (dirtybuffer, 1, videoram_size);
+ }
+}
+
+
+
+/***************************************************************************
+
+ The Naughty Boy screen is split into two sections by the hardware
+
+ NonScrolled = 28x4 - (rows 0,1,34,35, as shown below)
+ this area is split between the top and bottom of the screen,
+ and the address mapping is really funky.
+
+ Scrolled = 28x64, with a 28x32 viewport, as shown below
+ Each column in the virtual screen is 64 (40h) characters high.
+ Thus, column 27 is stored in VRAm at address 0-3fh,
+ column 26 is stored at 40-7f, and so on.
+ This illustration shows the horizonal scroll register set to zero,
+ so the topmost 32 rows of the virtual screen are shown.
+
+ The following screen-to-memory mapping. This is shown from player's viewpoint,
+ which with the CRT rotated 90 degrees CCW. This example shows the horizonal
+ scroll register set to zero.
+
+
+ COLUMN
+ 0 1 2 - 25 26 27
+ -------------------------------
+ 0| 76E 76A 762 - 70A 706 702 |
+ | | Nonscrolled display
+ 1| 76F 76B 762 - 70B 707 703 |
+ |-------------------------------| -----
+ 2| 6C0 680 640 - 80 40 00 |
+ | |
+ R 3| 6C1 681 641 - 81 41 01 |
+ O | | 28 x 32 viewport
+ W || | | | into 28x64 virtual,
+ | | scrollable screen
+ 32| 6DE 69E 65E 9E 5E 1E |
+ | |
+ 33| 6DF 69F 65F - 9F 5F 1F |
+ |-------------------------------| -----
+ 34| 76C 768 764 708 704 700 |
+ | | Nonscrolled display
+ 35| 76D 769 765 709 705 701 |
+ -------------------------------
+
+
+***************************************************************************/
+VIDEO_UPDATE( naughtyb )
+{
+ int offs;
+
+ // for every character in the Video RAM, check if it has been modified
+ // since last time and update it accordingly.
+
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ if (dirtybuffer[offs])
+ {
+ int sx,sy;
+
+ dirtybuffer[offs] = 0;
+
+ if ( naughtyb_cocktail )
+ {
+ if (offs < 0x700)
+ {
+ sx = 63 - offs % 64;
+ sy = 27 - offs / 64;
+ }
+ else
+ {
+ sx = 64 + ( 3 - (offs - 0x700) % 4 );
+ sy = 27 - (offs - 0x700) / 4;
+ }
+ }
+ else
+ {
+ if (offs < 0x700)
+ {
+ sx = offs % 64;
+ sy = offs / 64;
+ }
+ else
+ {
+ sx = 64 + (offs - 0x700) % 4;
+ sy = (offs - 0x700) / 4;
+ }
+ }
+
+ drawgfx(tmpbitmap,machine->gfx[0],
+ naughtyb_videoram2[offs] + 256 * bankreg,
+ (naughtyb_videoram2[offs] >> 5) + 8 * palreg,
+ naughtyb_cocktail,naughtyb_cocktail,
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+
+ drawgfx(tmpbitmap,machine->gfx[1],
+ videoram[offs] + 256*bankreg,
+ (videoram[offs] >> 5) + 8 * palreg,
+ naughtyb_cocktail,naughtyb_cocktail,
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_PEN,0);
+ }
+ }
+
+ // copy the temporary bitmap to the screen
+ {
+ int scrollx;
+
+ copybitmap(bitmap,tmpbitmap,0,0,-66*8,0,&leftvisiblearea,TRANSPARENCY_NONE,0);
+ copybitmap(bitmap,tmpbitmap,0,0,-30*8,0,&rightvisiblearea,TRANSPARENCY_NONE,0);
+
+ scrollx = ( naughtyb_cocktail ) ? *naughtyb_scrollreg - 239 : -*naughtyb_scrollreg + 16;
+ copyscrollbitmap(bitmap,tmpbitmap,1,&scrollx,0,0,&scrollvisiblearea,TRANSPARENCY_NONE,0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/nbmj8688.c b/src/mame/video/nbmj8688.c
new file mode 100644
index 00000000000..45c7181db11
--- /dev/null
+++ b/src/mame/video/nbmj8688.c
@@ -0,0 +1,747 @@
+/******************************************************************************
+
+ Video Hardware for Nichibutsu Mahjong series.
+
+ Driver by Takahiro Nogi <nogi@kt.rim.or.jp> 1999/11/05 -
+
+******************************************************************************/
+
+#include "driver.h"
+#include "nb1413m3.h"
+
+
+static int mjsikaku_scrolly;
+static int blitter_destx, blitter_desty;
+static int blitter_sizex, blitter_sizey;
+static int blitter_direction_x, blitter_direction_y;
+static int blitter_src_addr;
+static int mjsikaku_gfxrom;
+static int mjsikaku_dispflag;
+static int mjsikaku_gfxflag2;
+static int mjsikaku_gfxflag3;
+static int mjsikaku_flipscreen;
+static int mjsikaku_screen_refresh;
+static int mjsikaku_gfxmode;
+
+static mame_bitmap *mjsikaku_tmpbitmap;
+static UINT16 *mjsikaku_videoram;
+static UINT8 *nbmj8688_clut;
+
+static UINT8 *HD61830B_ram[2];
+static int HD61830B_instr[2];
+static int HD61830B_addr[2];
+
+
+static void mjsikaku_vramflip(void);
+static void mbmj8688_gfxdraw(int gfxtype);
+
+
+/* the blitter can copy data both in "direct" mode, where every byte of the source
+ data is copied verbatim to video RAM *twice* (thus doubling the pixel width),
+ and in "lookup" mode, where the source byte is taken 4 bits at a time and indexed
+ though a lookup table.
+ Video RAM directly maps to a RGB output. In the first version of the hardware
+ the palette was 8-bit, then they added more video RAM to have better color
+ reproduction in photos. This was done in different ways, which differ for the
+ implementation and the control over pixel color in the two drawing modes.
+ */
+enum
+{
+ GFXTYPE_8BIT, // direct mode: 8-bit; lookup table: 8-bit
+ GFXTYPE_HYBRID_12BIT, // direct mode: 12-bit; lookup table: 8-bit
+ GFXTYPE_HYBRID_16BIT, // direct mode: 16-bit; lookup table: 12-bit
+ GFXTYPE_PURE_16BIT, // direct mode: 16-bit; lookup table: 16-bit
+ GFXTYPE_PURE_12BIT // direct mode: n/a; lookup table: 12-bit
+};
+
+
+/******************************************************************************
+
+
+******************************************************************************/
+
+PALETTE_INIT( mbmj8688_8bit )
+{
+ int i;
+ int bit0, bit1, bit2, r, g, b;
+
+ /* initialize 332 RGB lookup */
+ for (i = 0; i < 0x100; i++)
+ {
+ // xxxxxxxx_bbgggrrr
+ /* red component */
+ bit0 = ((i >> 0) & 0x01);
+ bit1 = ((i >> 1) & 0x01);
+ bit2 = ((i >> 2) & 0x01);
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = ((i >> 3) & 0x01);
+ bit1 = ((i >> 4) & 0x01);
+ bit2 = ((i >> 5) & 0x01);
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = ((i >> 6) & 0x01);
+ bit2 = ((i >> 7) & 0x01);
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ }
+}
+
+PALETTE_INIT( mbmj8688_12bit )
+{
+ int i;
+ int r, g, b;
+
+ /* initialize 444 RGB lookup */
+ for (i = 0; i < 0x1000; i++)
+ {
+ // high and low bytes swapped for convenience
+ r = ((i & 0x07) << 1) | (((i >> 8) & 0x01) >> 0);
+ g = ((i & 0x38) >> 2) | (((i >> 8) & 0x02) >> 1);
+ b = ((i & 0xc0) >> 4) | (((i >> 8) & 0x0c) >> 2);
+
+ palette_set_color_rgb(machine, i, pal4bit(r), pal4bit(g), pal4bit(b));
+ }
+}
+
+PALETTE_INIT( mbmj8688_16bit )
+{
+ int i;
+ int r, g, b;
+
+ /* initialize 655 RGB lookup */
+ for (i = 0; i < 0x10000; i++)
+ {
+ r = (((i & 0x0700) >> 5) | ((i & 0x0007) >> 0)); // R 6bit
+ g = (((i & 0x3800) >> 9) | ((i & 0x0018) >> 3)); // G 5bit
+ b = (((i & 0xc000) >> 11) | ((i & 0x00e0) >> 5)); // B 5bit
+
+ palette_set_color_rgb(machine, i, pal6bit(r), pal5bit(g), pal5bit(b));
+ }
+}
+
+
+
+WRITE8_HANDLER( nbmj8688_clut_w )
+{
+ nbmj8688_clut[offset] = (data ^ 0xff);
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+
+WRITE8_HANDLER( nbmj8688_blitter_w )
+{
+ switch (offset)
+ {
+ case 0x00: blitter_src_addr = (blitter_src_addr & 0xff00) | data; break;
+ case 0x01: blitter_src_addr = (blitter_src_addr & 0x00ff) | (data << 8); break;
+ case 0x02: blitter_destx = data; break;
+ case 0x03: blitter_desty = data; break;
+ case 0x04: blitter_sizex = data; break;
+ case 0x05: blitter_sizey = data;
+ /* writing here also starts the blit */
+ mbmj8688_gfxdraw(mjsikaku_gfxmode);
+ break;
+ case 0x06: blitter_direction_x = (data & 0x01) ? 1 : 0;
+ blitter_direction_y = (data & 0x02) ? 1 : 0;
+ mjsikaku_flipscreen = (data & 0x04) ? 0 : 1;
+ mjsikaku_dispflag = (data & 0x08) ? 0 : 1;
+ mjsikaku_vramflip();
+ break;
+ case 0x07: break;
+ }
+}
+
+WRITE8_HANDLER( mjsikaku_gfxflag2_w )
+{
+ mjsikaku_gfxflag2 = data;
+
+ if (nb1413m3_type == NB1413M3_SEIHAM
+ || nb1413m3_type == NB1413M3_KORINAI
+ || nb1413m3_type == NB1413M3_KORINAIM
+ || nb1413m3_type == NB1413M3_LIVEGAL)
+ mjsikaku_gfxflag2 ^= 0x20;
+
+ if (nb1413m3_type == NB1413M3_OJOUSANM
+ || nb1413m3_type == NB1413M3_RYUUHA)
+ mjsikaku_gfxflag2 |= 0x20;
+}
+
+static WRITE8_HANDLER( mjsikaku_gfxflag3_w )
+{
+ mjsikaku_gfxflag3 = (data & 0xe0);
+}
+
+WRITE8_HANDLER( mjsikaku_scrolly_w )
+{
+ mjsikaku_scrolly = data;
+}
+
+WRITE8_HANDLER( mjsikaku_romsel_w )
+{
+ mjsikaku_gfxrom = (data & 0x0f);
+
+ if ((mjsikaku_gfxrom << 17) > (memory_region_length(REGION_GFX1) - 1))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM BANK OVER!!");
+#endif
+ mjsikaku_gfxrom &= (memory_region_length(REGION_GFX1) / 0x20000 - 1);
+ }
+}
+
+WRITE8_HANDLER( secolove_romsel_w )
+{
+ mjsikaku_gfxrom = ((data & 0xc0) >> 4) + (data & 0x03);
+ mjsikaku_gfxflag2_w(0, data);
+
+ if ((mjsikaku_gfxrom << 17) > (memory_region_length(REGION_GFX1) - 1))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM BANK OVER!!");
+#endif
+ mjsikaku_gfxrom &= (memory_region_length(REGION_GFX1) / 0x20000 - 1);
+ }
+}
+
+WRITE8_HANDLER( crystalg_romsel_w )
+{
+ mjsikaku_gfxrom = (data & 0x03);
+ mjsikaku_gfxflag2_w(0, data);
+
+ if ((mjsikaku_gfxrom << 17) > (memory_region_length(REGION_GFX1) - 1))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM BANK OVER!!");
+#endif
+ mjsikaku_gfxrom &= (memory_region_length(REGION_GFX1) / 0x20000 - 1);
+ }
+}
+
+WRITE8_HANDLER( seiha_romsel_w )
+{
+ mjsikaku_gfxrom = (data & 0x1f);
+ mjsikaku_gfxflag3_w(0, data);
+
+ if ((mjsikaku_gfxrom << 17) > (memory_region_length(REGION_GFX1) - 1))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM BANK OVER!!");
+#endif
+ mjsikaku_gfxrom &= (memory_region_length(REGION_GFX1) / 0x20000 - 1);
+ }
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+void mjsikaku_vramflip(void)
+{
+ static int mjsikaku_flipscreen_old = 0;
+ int x, y;
+ UINT16 color1, color2;
+
+ if (mjsikaku_flipscreen == mjsikaku_flipscreen_old) return;
+
+ for (y = 0; y < (256 / 2); y++)
+ {
+ for (x = 0; x < 512; x++)
+ {
+ color1 = mjsikaku_videoram[(y * 512) + x];
+ color2 = mjsikaku_videoram[((y ^ 0xff) * 512) + (x ^ 0x1ff)];
+ mjsikaku_videoram[(y * 512) + x] = color2;
+ mjsikaku_videoram[((y ^ 0xff) * 512) + (x ^ 0x1ff)] = color1;
+ }
+ }
+
+ mjsikaku_flipscreen_old = mjsikaku_flipscreen;
+ mjsikaku_screen_refresh = 1;
+}
+
+
+static void update_pixel(int x, int y)
+{
+ int color = mjsikaku_videoram[(y * 512) + x];
+ *BITMAP_ADDR16(mjsikaku_tmpbitmap, y, x) = Machine->pens[color];
+}
+
+static void writeram_low(int x, int y, int color)
+{
+ mjsikaku_videoram[(y * 512) + x] &= 0xff00;
+ mjsikaku_videoram[(y * 512) + x] |= color;
+ update_pixel(x, y);
+}
+
+static void writeram_high(int x, int y, int color)
+{
+ mjsikaku_videoram[(y * 512) + x] &= 0x00ff;
+ mjsikaku_videoram[(y * 512) + x] |= color << 8;
+ update_pixel(x, y);
+}
+
+static TIMER_CALLBACK( blitter_timer_callback )
+{
+ nb1413m3_busyflag = 1;
+}
+
+static void mbmj8688_gfxdraw(int gfxtype)
+{
+ UINT8 *GFX = memory_region(REGION_GFX1);
+
+ int x, y;
+ int dx1, dx2, dy;
+ int startx, starty;
+ int sizex, sizey;
+ int skipx, skipy;
+ int ctrx, ctry;
+ int gfxaddr;
+ UINT16 color, color1, color2;
+
+ if (gfxtype == GFXTYPE_PURE_12BIT)
+ {
+ if (mjsikaku_gfxflag2 & 0x20) return;
+ }
+
+ nb1413m3_busyctr = 0;
+
+ startx = blitter_destx + blitter_sizex;
+ starty = blitter_desty + blitter_sizey;
+
+ if (blitter_direction_x)
+ {
+ sizex = blitter_sizex ^ 0xff;
+ skipx = 1;
+ }
+ else
+ {
+ sizex = blitter_sizex;
+ skipx = -1;
+ }
+
+ if (blitter_direction_y)
+ {
+ sizey = blitter_sizey ^ 0xff;
+ skipy = 1;
+ }
+ else
+ {
+ sizey = blitter_sizey;
+ skipy = -1;
+ }
+
+ gfxaddr = (mjsikaku_gfxrom << 17) + (blitter_src_addr << 1);
+//popmessage("ADDR:%08X DX:%03d DY:%03d SX:%03d SY:%03d", gfxaddr, startx, starty, sizex, sizey);
+//if (blitter_direction_x|blitter_direction_y) popmessage("ADDR:%08X FX:%01d FY:%01d", gfxaddr, blitter_direction_x, blitter_direction_y);
+
+ for (y = starty, ctry = sizey; ctry >= 0; y += skipy, ctry--)
+ {
+ for (x = startx, ctrx = sizex; ctrx >= 0; x += skipx, ctrx--)
+ {
+ if ((gfxaddr > (memory_region_length(REGION_GFX1) - 1)))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM ADDRESS OVER!!");
+#endif
+ gfxaddr = 0;
+ }
+
+ color = GFX[gfxaddr++];
+
+ dx1 = (2 * x + 0) & 0x1ff;
+ dx2 = (2 * x + 1) & 0x1ff;
+ dy = (y + mjsikaku_scrolly) & 0xff;
+
+ if (mjsikaku_flipscreen)
+ {
+ dx1 ^= 0x1ff;
+ dx2 ^= 0x1ff;
+ dy ^= 0xff;
+ }
+
+ if (gfxtype == GFXTYPE_HYBRID_16BIT)
+ {
+ if (mjsikaku_gfxflag3 & 0x40)
+ {
+ // direct mode
+
+ if (mjsikaku_gfxflag3 & 0x80)
+ {
+ /* least significant bits */
+ if (color != 0xff)
+ {
+ writeram_low(dx1, dy, color);
+ writeram_low(dx2, dy, color);
+ }
+ }
+ else
+ {
+ /* most significant bits */
+ if (color != 0xff)
+ {
+ writeram_high(dx1, dy, color);
+ writeram_high(dx2, dy, color);
+ }
+ }
+ }
+ else
+ {
+ /* 16-bit palette with 4-to-12 bit lookup (!) */
+ // lookup table mode
+
+ // unknown flag (seiha, seiham)
+ // if (mjsikaku_gfxflag3 & 0x80) return;
+
+ // unknown (seiha, seiham, iemoto, ojousan)
+ if (!(mjsikaku_gfxflag2 & 0x20)) return;
+
+ if (blitter_direction_x)
+ {
+ // flip
+ color1 = (color & 0x0f) >> 0;
+ color2 = (color & 0xf0) >> 4;
+ }
+ else
+ {
+ // normal
+ color1 = (color & 0xf0) >> 4;
+ color2 = (color & 0x0f) >> 0;
+ }
+
+ color1 = (nbmj8688_clut[color1] << 8) | ((nbmj8688_clut[color1 | 0x10] & 0x0f) << 4);
+ color2 = (nbmj8688_clut[color2] << 8) | ((nbmj8688_clut[color2 | 0x10] & 0x0f) << 4);
+
+ if (color1 != 0xfff0)
+ {
+ /* extend color from 12-bit to 16-bit */
+ color1 = (color1 & 0xffc0) | ((color1 & 0x20) >> 1) | ((color1 & 0x10) >> 2);
+ mjsikaku_videoram[(dy * 512) + dx1] = color1;
+ update_pixel(dx1, dy);
+ }
+
+ if (color2 != 0xfff0)
+ {
+ /* extend color from 12-bit to 16-bit */
+ color2 = (color2 & 0xffc0) | ((color2 & 0x20) >> 1) | ((color2 & 0x10) >> 2);
+ mjsikaku_videoram[(dy * 512) + dx2] = color2;
+ update_pixel(dx2, dy);
+ }
+ }
+ }
+ else if (gfxtype == GFXTYPE_PURE_12BIT)
+ {
+ /* 12-bit palette with 4-to-12 bit lookup table */
+
+ if (blitter_direction_x)
+ {
+ // flip
+ color1 = (color & 0x0f) >> 0;
+ color2 = (color & 0xf0) >> 4;
+ }
+ else
+ {
+ // normal
+ color1 = (color & 0xf0) >> 4;
+ color2 = (color & 0x0f) >> 0;
+ }
+
+ color1 = nbmj8688_clut[color1] | ((nbmj8688_clut[color1 | 0x10] & 0x0f) << 8);
+ color2 = nbmj8688_clut[color2] | ((nbmj8688_clut[color2 | 0x10] & 0x0f) << 8);
+
+ if (color1 != 0x0fff)
+ {
+ mjsikaku_videoram[(dy * 512) + dx1] = color1;
+ update_pixel(dx1, dy);
+ }
+ if (color2 != 0x0fff)
+ {
+ mjsikaku_videoram[(dy * 512) + dx2] = color2;
+ update_pixel(dx2, dy);
+ }
+ }
+ else
+ {
+ if (gfxtype == GFXTYPE_HYBRID_12BIT && (mjsikaku_gfxflag2 & 0x20))
+ {
+ /* 4096 colors mode, wedged in on top of normal mode
+ Here we affect only the 4 least significant bits, the others are
+ changed as usual.
+ */
+
+ if (mjsikaku_gfxflag2 & 0x10)
+ {
+ // 4096 colors low mode (2nd draw upper)
+ color = nbmj8688_clut[((color & 0xf0) >> 4)];
+ }
+ else
+ {
+ // 4096 colors low mode (1st draw lower)
+ color = nbmj8688_clut[((color & 0x0f) >> 0)];
+ }
+
+ if (color != 0xff)
+ {
+ color &= 0x0f;
+ writeram_high(dx1, dy, color);
+ writeram_high(dx2, dy, color);
+ }
+ }
+ else
+ {
+ if (mjsikaku_gfxflag2 & 0x04)
+ {
+ // direct mode
+
+ color1 = color2 = color;
+ }
+ else
+ {
+ // lookup table mode
+
+ if (blitter_direction_x)
+ {
+ // flip
+ color1 = (color & 0x0f) >> 0;
+ color2 = (color & 0xf0) >> 4;
+ }
+ else
+ {
+ // normal
+ color1 = (color & 0xf0) >> 4;
+ color2 = (color & 0x0f) >> 0;
+ }
+
+ color1 = nbmj8688_clut[color1];
+ color2 = nbmj8688_clut[color2];
+ }
+
+ if (gfxtype == GFXTYPE_PURE_16BIT && !(mjsikaku_gfxflag2 & 0x20))
+ {
+ /* 16-bit palette most significant bits */
+ if (color1 != 0xff) writeram_high(dx1, dy, color1);
+ if (color2 != 0xff) writeram_high(dx2, dy, color2);
+ }
+ else
+ {
+ /* 8-bit palette or 16-bit palette least significant bits */
+ if (color1 != 0xff) writeram_low(dx1, dy, color1);
+ if (color2 != 0xff) writeram_low(dx2, dy, color2);
+ }
+ }
+ }
+
+ nb1413m3_busyctr++;
+ }
+ }
+
+ nb1413m3_busyflag = 0;
+
+ if (gfxtype == GFXTYPE_8BIT)
+ timer_set(attotime_mul(ATTOTIME_IN_HZ(400000), nb1413m3_busyctr), 0, blitter_timer_callback);
+ else
+ timer_set(attotime_mul(ATTOTIME_IN_HZ(400000), nb1413m3_busyctr), 0, blitter_timer_callback);
+}
+
+
+/******************************************************************************
+
+
+******************************************************************************/
+
+static void common_video_start(void)
+{
+ mjsikaku_tmpbitmap = auto_bitmap_alloc(512, 256, Machine->screen[0].format);
+ mjsikaku_videoram = auto_malloc(512 * 256 * sizeof(UINT16));
+ nbmj8688_clut = auto_malloc(0x20 * sizeof(UINT8));
+ memset(mjsikaku_videoram, 0, (512 * 256 * sizeof(UINT16)));
+
+ mjsikaku_scrolly = 0; // reset because crystalg/crystal2 don't write to this register
+}
+
+VIDEO_START( mbmj8688_8bit )
+{
+ mjsikaku_gfxmode = GFXTYPE_8BIT;
+ common_video_start();
+}
+
+VIDEO_START( mbmj8688_hybrid_12bit )
+{
+ mjsikaku_gfxmode = GFXTYPE_HYBRID_12BIT;
+ common_video_start();
+}
+
+VIDEO_START( mbmj8688_pure_12bit )
+{
+ mjsikaku_gfxmode = GFXTYPE_PURE_12BIT;
+ common_video_start();
+}
+
+VIDEO_START( mbmj8688_hybrid_16bit )
+{
+ mjsikaku_gfxmode = GFXTYPE_HYBRID_16BIT;
+ common_video_start();
+}
+
+VIDEO_START( mbmj8688_pure_16bit )
+{
+ mjsikaku_gfxmode = GFXTYPE_PURE_16BIT;
+ common_video_start();
+}
+
+VIDEO_START( mbmj8688_pure_16bit_LCD )
+{
+ mjsikaku_gfxmode = GFXTYPE_PURE_16BIT;
+
+ HD61830B_ram[0] = auto_malloc(0x10000);
+ HD61830B_ram[1] = auto_malloc(0x10000);
+
+ common_video_start();
+}
+
+
+/******************************************************************************
+
+Quick and dirty implementation of the bare minimum required to elmulate the
+Hitachi HD61830B LCD controller.
+
+******************************************************************************/
+
+static void nbmj8688_HD61830B_instr_w(int chip,int offset,int data)
+{
+ HD61830B_instr[chip] = data;
+}
+
+static void nbmj8688_HD61830B_data_w(int chip,int offset,int data)
+{
+ switch (HD61830B_instr[chip])
+ {
+ case 0x0a: // set cursor address (low order)
+ HD61830B_addr[chip] = (HD61830B_addr[chip] & 0xff00) | data;
+ break;
+ case 0x0b: // set cursor address (high order)
+ HD61830B_addr[chip] = (HD61830B_addr[chip] & 0x00ff) | (data << 8);
+ break;
+ case 0x0c: // write display data
+ HD61830B_ram[chip][HD61830B_addr[chip]++] = data;
+ break;
+ default:
+logerror("HD61830B unsupported instruction %02x %02x\n",HD61830B_instr[chip],data);
+ break;
+ }
+}
+
+WRITE8_HANDLER( nbmj8688_HD61830B_0_instr_w )
+{
+ nbmj8688_HD61830B_instr_w(0,offset,data);
+}
+
+WRITE8_HANDLER( nbmj8688_HD61830B_1_instr_w )
+{
+ nbmj8688_HD61830B_instr_w(1,offset,data);
+}
+
+WRITE8_HANDLER( nbmj8688_HD61830B_both_instr_w )
+{
+ nbmj8688_HD61830B_instr_w(0,offset,data);
+ nbmj8688_HD61830B_instr_w(1,offset,data);
+}
+
+WRITE8_HANDLER( nbmj8688_HD61830B_0_data_w )
+{
+ nbmj8688_HD61830B_data_w(0,offset,data);
+}
+
+WRITE8_HANDLER( nbmj8688_HD61830B_1_data_w )
+{
+ nbmj8688_HD61830B_data_w(1,offset,data);
+}
+
+WRITE8_HANDLER( nbmj8688_HD61830B_both_data_w )
+{
+ nbmj8688_HD61830B_data_w(0,offset,data);
+ nbmj8688_HD61830B_data_w(1,offset,data);
+}
+
+
+
+/******************************************************************************
+
+
+******************************************************************************/
+
+
+VIDEO_UPDATE( mbmj8688 )
+{
+ int x, y;
+
+ if (mjsikaku_screen_refresh)
+ {
+ mjsikaku_screen_refresh = 0;
+ for (y = 0; y < 256; y++)
+ {
+ for (x = 0; x < 512; x++)
+ {
+ update_pixel(x,y);
+ }
+ }
+ }
+
+ if (mjsikaku_dispflag)
+ {
+ int scrolly;
+ if (mjsikaku_flipscreen) scrolly = mjsikaku_scrolly;
+ else scrolly = (-mjsikaku_scrolly) & 0xff;
+
+ copybitmap(bitmap, mjsikaku_tmpbitmap, 0, 0, 0, scrolly, cliprect, TRANSPARENCY_NONE, 0);
+ copybitmap(bitmap, mjsikaku_tmpbitmap, 0, 0, 0, scrolly - 256, cliprect, TRANSPARENCY_NONE, 0);
+ }
+ else
+ {
+ fillbitmap(bitmap, machine->pens[0], 0);
+ }
+ return 0;
+}
+
+
+
+VIDEO_UPDATE( mbmj8688_LCD )
+{
+ int x, y, b;
+
+ if(screen==0) video_update_mbmj8688(machine,screen,bitmap,cliprect);
+
+ if (screen==1)
+ {
+ for (y = 0;y < 64;y++)
+ {
+ for (x = 0;x < 60;x++)
+ {
+ int data = HD61830B_ram[0][y * 60 + x];
+
+ for (b = 0;b < 8;b++)
+ *BITMAP_ADDR16(bitmap, y, (8*x+b)) = (data & (1<<b)) ? 0x0000 : 0x18ff;
+ }
+ }
+ }
+
+ if (screen==2)
+ {
+ for (y = 0;y < 64;y++)
+ {
+ for (x = 0;x < 60;x++)
+ {
+ int data = HD61830B_ram[1][y * 60 + x];
+
+ for (b = 0;b < 8;b++)
+ *BITMAP_ADDR16(bitmap, y, (8*x+b)) = (data & (1<<b)) ? 0x0000 : 0x18ff;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/nbmj8891.c b/src/mame/video/nbmj8891.c
new file mode 100644
index 00000000000..959d2622ab6
--- /dev/null
+++ b/src/mame/video/nbmj8891.c
@@ -0,0 +1,569 @@
+/******************************************************************************
+
+ Video Hardware for Nichibutsu Mahjong series.
+
+ Driver by Takahiro Nogi <nogi@kt.rim.or.jp> 1999/11/05 -
+
+******************************************************************************/
+
+#include "driver.h"
+#include "nb1413m3.h"
+
+
+static int nbmj8891_scrolly;
+static int blitter_destx, blitter_desty;
+static int blitter_sizex, blitter_sizey;
+static int blitter_src_addr;
+static int blitter_direction_x, blitter_direction_y;
+static int nbmj8891_vram;
+static int nbmj8891_gfxrom;
+static int nbmj8891_dispflag;
+static int nbmj8891_flipscreen;
+static int nbmj8891_clutsel;
+static int nbmj8891_screen_refresh;
+static int gfxdraw_mode;
+
+static mame_bitmap *nbmj8891_tmpbitmap0, *nbmj8891_tmpbitmap1;
+static UINT8 *nbmj8891_videoram0, *nbmj8891_videoram1;
+static UINT8 *nbmj8891_palette;
+static UINT8 *nbmj8891_clut;
+
+
+static void nbmj8891_vramflip(int vram);
+static void nbmj8891_gfxdraw(void);
+
+
+/******************************************************************************
+
+
+******************************************************************************/
+READ8_HANDLER( nbmj8891_palette_type1_r )
+{
+ return nbmj8891_palette[offset];
+}
+
+WRITE8_HANDLER( nbmj8891_palette_type1_w )
+{
+ int r, g, b;
+
+ nbmj8891_palette[offset] = data;
+
+ if (!(offset & 1)) return;
+
+ offset &= 0x1fe;
+
+ r = ((nbmj8891_palette[offset + 0] & 0x0f) >> 0);
+ g = ((nbmj8891_palette[offset + 1] & 0xf0) >> 4);
+ b = ((nbmj8891_palette[offset + 1] & 0x0f) >> 0);
+
+ palette_set_color_rgb(Machine, (offset >> 1), pal4bit(r), pal4bit(g), pal4bit(b));
+}
+
+READ8_HANDLER( nbmj8891_palette_type2_r )
+{
+ return nbmj8891_palette[offset];
+}
+
+WRITE8_HANDLER( nbmj8891_palette_type2_w )
+{
+ int r, g, b;
+
+ nbmj8891_palette[offset] = data;
+
+ if (!(offset & 0x100)) return;
+
+ offset &= 0x0ff;
+
+ r = ((nbmj8891_palette[offset + 0x000] & 0x0f) >> 0);
+ g = ((nbmj8891_palette[offset + 0x000] & 0xf0) >> 4);
+ b = ((nbmj8891_palette[offset + 0x100] & 0x0f) >> 0);
+
+ palette_set_color_rgb(Machine, (offset & 0x0ff), pal4bit(r), pal4bit(g), pal4bit(b));
+}
+
+READ8_HANDLER( nbmj8891_palette_type3_r )
+{
+ return nbmj8891_palette[offset];
+}
+
+WRITE8_HANDLER( nbmj8891_palette_type3_w )
+{
+ int r, g, b;
+
+ nbmj8891_palette[offset] = data;
+
+ if (!(offset & 1)) return;
+
+ offset &= 0x1fe;
+
+ r = ((nbmj8891_palette[offset + 1] & 0x0f) >> 0);
+ g = ((nbmj8891_palette[offset + 0] & 0xf0) >> 4);
+ b = ((nbmj8891_palette[offset + 0] & 0x0f) >> 0);
+
+ palette_set_color_rgb(Machine, (offset >> 1), pal4bit(r), pal4bit(g), pal4bit(b));
+}
+
+WRITE8_HANDLER( nbmj8891_clutsel_w )
+{
+ nbmj8891_clutsel = data;
+}
+
+READ8_HANDLER( nbmj8891_clut_r )
+{
+ return nbmj8891_clut[offset];
+}
+
+WRITE8_HANDLER( nbmj8891_clut_w )
+{
+ nbmj8891_clut[((nbmj8891_clutsel & 0x7f) * 0x10) + (offset & 0x0f)] = data;
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+WRITE8_HANDLER( nbmj8891_blitter_w )
+{
+ switch (offset)
+ {
+ case 0x00: blitter_src_addr = (blitter_src_addr & 0xff00) | data; break;
+ case 0x01: blitter_src_addr = (blitter_src_addr & 0x00ff) | (data << 8); break;
+ case 0x02: blitter_destx = data; break;
+ case 0x03: blitter_desty = data; break;
+ case 0x04: blitter_sizex = data; break;
+ case 0x05: blitter_sizey = data;
+ /* writing here also starts the blit */
+ nbmj8891_gfxdraw();
+ break;
+ case 0x06: blitter_direction_x = (data & 0x01) ? 1 : 0;
+ blitter_direction_y = (data & 0x02) ? 1 : 0;
+ nbmj8891_flipscreen = (data & 0x04) ? 1 : 0;
+ nbmj8891_dispflag = (data & 0x08) ? 0 : 1;
+ if (gfxdraw_mode) nbmj8891_vramflip(1);
+ nbmj8891_vramflip(0);
+ break;
+ case 0x07: break;
+ }
+}
+
+WRITE8_HANDLER( nbmj8891_taiwanmb_blitter_w )
+{
+ switch (offset)
+ {
+ case 0: blitter_src_addr = (blitter_src_addr & 0xff00) | data; break;
+ case 1: blitter_src_addr = (blitter_src_addr & 0x00ff) | (data << 8); break;
+ case 2: blitter_destx = data; break;
+ case 3: blitter_desty = data; break;
+ case 4: blitter_sizex = (data - 1) & 0xff; break;
+ case 5: blitter_sizey = (data - 1) & 0xff; break;
+ }
+}
+
+WRITE8_HANDLER( nbmj8891_taiwanmb_gfxdraw_w )
+{
+// nbmj8891_gfxdraw();
+}
+
+WRITE8_HANDLER( nbmj8891_taiwanmb_gfxflag_w )
+{
+ nbmj8891_flipscreen = (data & 0x04) ? 1 : 0;
+
+ nbmj8891_vramflip(0);
+}
+
+WRITE8_HANDLER( nbmj8891_taiwanmb_mcu_w )
+{
+ static int param_old[0x10];
+ static int param_cnt = 0;
+
+ param_old[param_cnt & 0x0f] = data;
+
+ if (data == 0x00)
+ {
+ blitter_direction_x = 0;
+ blitter_direction_y = 0;
+ blitter_destx = 0;
+ blitter_desty = 0;
+ blitter_sizex = 0;
+ blitter_sizey = 0;
+ nbmj8891_dispflag = 0;
+ }
+
+/*
+ if (data == 0x02)
+ {
+ if (param_old[(param_cnt - 1) & 0x0f] == 0x18)
+ {
+ nbmj8891_dispflag = 1;
+ }
+ else if (param_old[(param_cnt - 1) & 0x0f] == 0x1a)
+ {
+ nbmj8891_dispflag = 0;
+ }
+ }
+*/
+
+ if (data == 0x04)
+ {
+ // CLUT Transfer?
+ }
+
+ if (data == 0x12)
+ {
+ if (param_old[(param_cnt - 1) & 0x0f] == 0x08)
+ {
+ blitter_direction_x = 1;
+ blitter_direction_y = 0;
+ blitter_destx += blitter_sizex + 1;
+ blitter_desty += 0;
+ blitter_sizex ^= 0xff;
+ blitter_sizey ^= 0x00;
+ }
+ else if (param_old[(param_cnt - 1) & 0x0f] == 0x0a)
+ {
+ blitter_direction_x = 0;
+ blitter_direction_y = 1;
+ blitter_destx += 0;
+ blitter_desty += blitter_sizey + 1;
+ blitter_sizex ^= 0x00;
+ blitter_sizey ^= 0xff;
+ }
+ else if (param_old[(param_cnt - 1) & 0x0f] == 0x0c)
+ {
+ blitter_direction_x = 1;
+ blitter_direction_y = 1;
+ blitter_destx += blitter_sizex + 1;
+ blitter_desty += blitter_sizey + 1;
+ blitter_sizex ^= 0xff;
+ blitter_sizey ^= 0xff;
+ }
+ else if (param_old[(param_cnt - 1) & 0x0f] == 0x0e)
+ {
+ blitter_direction_x = 0;
+ blitter_direction_y = 0;
+ blitter_destx += 0;
+ blitter_desty += 0;
+ blitter_sizex ^= 0x00;
+ blitter_sizey ^= 0x00;
+ }
+
+ nbmj8891_gfxdraw();
+ }
+
+// blitter_direction_x = 0; // for debug
+// blitter_direction_y = 0; // for debug
+ nbmj8891_dispflag = 1; // for debug
+
+ param_cnt++;
+}
+
+WRITE8_HANDLER( nbmj8891_scrolly_w )
+{
+ nbmj8891_scrolly = data;
+}
+
+WRITE8_HANDLER( nbmj8891_vramsel_w )
+{
+ /* protection - not sure about this */
+ nb1413m3_sndromregion = (data & 0x20) ? REGION_USER1 : REGION_SOUND1;
+
+ nbmj8891_vram = data;
+}
+
+WRITE8_HANDLER( nbmj8891_romsel_w )
+{
+ nbmj8891_gfxrom = (data & 0x0f);
+
+ if ((0x20000 * nbmj8891_gfxrom) > (memory_region_length(REGION_GFX1) - 1))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM BANK OVER!!");
+#endif
+ nbmj8891_gfxrom &= (memory_region_length(REGION_GFX1) / 0x20000 - 1);
+ }
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+void nbmj8891_vramflip(int vram)
+{
+ static int nbmj8891_flipscreen_old = 0;
+ int x, y;
+ UINT8 color1, color2;
+ UINT8 *vidram;
+
+ if (nbmj8891_flipscreen == nbmj8891_flipscreen_old) return;
+
+ vidram = vram ? nbmj8891_videoram1 : nbmj8891_videoram0;
+
+ for (y = 0; y < (Machine->screen[0].height / 2); y++)
+ {
+ for (x = 0; x < Machine->screen[0].width; x++)
+ {
+ color1 = vidram[(y * Machine->screen[0].width) + x];
+ color2 = vidram[((y ^ 0xff) * Machine->screen[0].width) + (x ^ 0x1ff)];
+ vidram[(y * Machine->screen[0].width) + x] = color2;
+ vidram[((y ^ 0xff) * Machine->screen[0].width) + (x ^ 0x1ff)] = color1;
+ }
+ }
+
+ nbmj8891_flipscreen_old = nbmj8891_flipscreen;
+ nbmj8891_screen_refresh = 1;
+}
+
+
+static void update_pixel0(int x, int y)
+{
+ UINT8 color = nbmj8891_videoram0[(y * Machine->screen[0].width) + x];
+ *BITMAP_ADDR16(nbmj8891_tmpbitmap0, y, x) = Machine->pens[color];
+}
+
+static void update_pixel1(int x, int y)
+{
+ UINT8 color = nbmj8891_videoram1[(y * Machine->screen[0].width) + x];
+ *BITMAP_ADDR16(nbmj8891_tmpbitmap1, y, x) = Machine->pens[(color == 0x7f) ? 0xff : color];
+}
+
+static TIMER_CALLBACK( blitter_timer_callback )
+{
+ nb1413m3_busyflag = 1;
+}
+
+static void nbmj8891_gfxdraw(void)
+{
+ UINT8 *GFX = memory_region(REGION_GFX1);
+
+ int x, y;
+ int dx1, dx2, dy1, dy2;
+ int startx, starty;
+ int sizex, sizey;
+ int skipx, skipy;
+ int ctrx, ctry;
+ UINT8 color, color1, color2;
+ int gfxaddr;
+
+ nb1413m3_busyctr = 0;
+
+ startx = blitter_destx + blitter_sizex;
+ starty = blitter_desty + blitter_sizey;
+
+ if (blitter_direction_x)
+ {
+ sizex = blitter_sizex ^ 0xff;
+ skipx = 1;
+ }
+ else
+ {
+ sizex = blitter_sizex;
+ skipx = -1;
+ }
+
+ if (blitter_direction_y)
+ {
+ sizey = blitter_sizey ^ 0xff;
+ skipy = 1;
+ }
+ else
+ {
+ sizey = blitter_sizey;
+ skipy = -1;
+ }
+
+ gfxaddr = (nbmj8891_gfxrom << 17) + (blitter_src_addr << 1);
+
+ for (y = starty, ctry = sizey; ctry >= 0; y += skipy, ctry--)
+ {
+ for (x = startx, ctrx = sizex; ctrx >= 0; x += skipx, ctrx--)
+ {
+ if ((gfxaddr > (memory_region_length(REGION_GFX1) - 1)))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM ADDRESS OVER!!");
+#endif
+ gfxaddr &= (memory_region_length(REGION_GFX1) - 1);
+ }
+
+ color = GFX[gfxaddr++];
+
+ // for hanamomo
+ if ((nb1413m3_type == NB1413M3_HANAMOMO) && ((gfxaddr >= 0x20000) && (gfxaddr < 0x28000)))
+ {
+ color |= ((color & 0x0f) << 4);
+ }
+
+ dx1 = (2 * x + 0) & 0x1ff;
+ dx2 = (2 * x + 1) & 0x1ff;
+
+ if (gfxdraw_mode)
+ {
+ // 2 layer type
+ dy1 = y & 0xff;
+ dy2 = (y + nbmj8891_scrolly) & 0xff;
+ }
+ else
+ {
+ // 1 layer type
+ dy1 = (y + nbmj8891_scrolly) & 0xff;
+ dy2 = 0;
+ }
+
+ if (!nbmj8891_flipscreen)
+ {
+ dx1 ^= 0x1ff;
+ dx2 ^= 0x1ff;
+ dy1 ^= 0xff;
+ dy2 ^= 0xff;
+ }
+
+ if (blitter_direction_x)
+ {
+ // flip
+ color1 = (color & 0x0f) >> 0;
+ color2 = (color & 0xf0) >> 4;
+ }
+ else
+ {
+ // normal
+ color1 = (color & 0xf0) >> 4;
+ color2 = (color & 0x0f) >> 0;
+ }
+
+ color1 = nbmj8891_clut[((nbmj8891_clutsel & 0x7f) << 4) + color1];
+ color2 = nbmj8891_clut[((nbmj8891_clutsel & 0x7f) << 4) + color2];
+
+ if ((!gfxdraw_mode) || (nbmj8891_vram & 0x01))
+ {
+ // layer 1
+ if (color1 != 0xff)
+ {
+ nbmj8891_videoram0[(dy1 * Machine->screen[0].width) + dx1] = color1;
+ update_pixel0(dx1, dy1);
+ }
+ if (color2 != 0xff)
+ {
+ nbmj8891_videoram0[(dy1 * Machine->screen[0].width) + dx2] = color2;
+ update_pixel0(dx2, dy1);
+ }
+ }
+ if (gfxdraw_mode && (nbmj8891_vram & 0x02))
+ {
+ // layer 2
+ if (nbmj8891_vram & 0x08)
+ {
+ // transparent enable
+ if (color1 != 0xff)
+ {
+ nbmj8891_videoram1[(dy2 * Machine->screen[0].width) + dx1] = color1;
+ update_pixel1(dx1, dy2);
+ }
+ if (color2 != 0xff)
+ {
+ nbmj8891_videoram1[(dy2 * Machine->screen[0].width) + dx2] = color2;
+ update_pixel1(dx2, dy2);
+ }
+ }
+ else
+ {
+ // transparent disable
+ nbmj8891_videoram1[(dy2 * Machine->screen[0].width) + dx1] = color1;
+ update_pixel1(dx1, dy2);
+ nbmj8891_videoram1[(dy2 * Machine->screen[0].width) + dx2] = color2;
+ update_pixel1(dx2, dy2);
+ }
+ }
+
+ nb1413m3_busyctr++;
+ }
+ }
+
+ nb1413m3_busyflag = 0;
+ timer_set(attotime_mul(ATTOTIME_IN_HZ(400000), nb1413m3_busyctr), 0, blitter_timer_callback);
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+VIDEO_START( nbmj8891_1layer )
+{
+ UINT8 *CLUT = memory_region(REGION_USER1);
+ int i;
+
+ nbmj8891_tmpbitmap0 = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ nbmj8891_videoram0 = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(char));
+ nbmj8891_palette = auto_malloc(0x200 * sizeof(char));
+ nbmj8891_clut = auto_malloc(0x800 * sizeof(char));
+ memset(nbmj8891_videoram0, 0xff, (machine->screen[0].width * machine->screen[0].height * sizeof(char)));
+ gfxdraw_mode = 0;
+
+ if (nb1413m3_type == NB1413M3_TAIWANMB)
+ for (i = 0; i < 0x0800; i++) nbmj8891_clut[i] = CLUT[i];
+}
+
+VIDEO_START( nbmj8891_2layer )
+{
+ nbmj8891_tmpbitmap0 = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ nbmj8891_tmpbitmap1 = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ nbmj8891_videoram0 = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(UINT8));
+ nbmj8891_videoram1 = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(UINT8));
+ nbmj8891_palette = auto_malloc(0x200 * sizeof(UINT8));
+ nbmj8891_clut = auto_malloc(0x800 * sizeof(UINT8));
+ memset(nbmj8891_videoram0, 0xff, (machine->screen[0].width * machine->screen[0].height * sizeof(UINT8)));
+ memset(nbmj8891_videoram1, 0xff, (machine->screen[0].width * machine->screen[0].height * sizeof(UINT8)));
+ gfxdraw_mode = 1;
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+VIDEO_UPDATE( nbmj8891 )
+{
+ int x, y;
+
+ if (nbmj8891_screen_refresh)
+ {
+ nbmj8891_screen_refresh = 0;
+ for (y = 0; y < machine->screen[0].height; y++)
+ {
+ for (x = 0; x < machine->screen[0].width; x++)
+ {
+ update_pixel0(x, y);
+ }
+ }
+ if (gfxdraw_mode)
+ {
+ for (y = 0; y < machine->screen[0].height; y++)
+ {
+ for (x = 0; x < machine->screen[0].width; x++)
+ {
+ update_pixel1(x, y);
+ }
+ }
+ }
+ }
+
+ if (nbmj8891_dispflag)
+ {
+ static int scrolly;
+ if (!nbmj8891_flipscreen) scrolly = nbmj8891_scrolly;
+ else scrolly = (-nbmj8891_scrolly) & 0xff;
+
+ if (gfxdraw_mode)
+ {
+ copyscrollbitmap(bitmap, nbmj8891_tmpbitmap0, 0, 0, 0, 0, &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ copyscrollbitmap(bitmap, nbmj8891_tmpbitmap1, 0, 0, 1, &scrolly, &machine->screen[0].visarea, TRANSPARENCY_PEN, machine->pens[0xff]);
+ }
+ else
+ {
+ copyscrollbitmap(bitmap, nbmj8891_tmpbitmap0, 0, 0, 1, &scrolly, &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ }
+ }
+ else
+ {
+ fillbitmap(bitmap, machine->pens[0xff], 0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/nbmj8991.c b/src/mame/video/nbmj8991.c
new file mode 100644
index 00000000000..6c517abd942
--- /dev/null
+++ b/src/mame/video/nbmj8991.c
@@ -0,0 +1,385 @@
+/******************************************************************************
+
+ Video Hardware for Nichibutsu Mahjong series.
+
+ Driver by Takahiro Nogi <nogi@kt.rim.or.jp> 1999/11/05 -
+
+******************************************************************************/
+
+#include "driver.h"
+#include "nb1413m3.h"
+
+
+static int nbmj8991_scrollx, nbmj8991_scrolly;
+static int blitter_destx, blitter_desty;
+static int blitter_sizex, blitter_sizey;
+static int blitter_src_addr;
+static int blitter_direction_x, blitter_direction_y;
+static int nbmj8991_gfxrom;
+static int nbmj8991_dispflag;
+static int nbmj8991_flipscreen;
+static int nbmj8991_clutsel;
+static int nbmj8991_screen_refresh;
+
+static mame_bitmap *nbmj8991_tmpbitmap;
+static UINT8 *nbmj8991_videoram;
+static UINT8 *nbmj8991_clut;
+
+
+static void nbmj8991_vramflip(void);
+static void nbmj8991_gfxdraw(void);
+static void update_pixel(int x, int y);
+
+
+/******************************************************************************
+
+
+******************************************************************************/
+
+WRITE8_HANDLER( nbmj8991_palette_type1_w )
+{
+ int r, g, b;
+
+ paletteram[offset] = data;
+
+ if (!(offset & 1)) return;
+
+ offset &= 0x1fe;
+
+ r = ((paletteram[offset + 0] & 0x0f) >> 0);
+ g = ((paletteram[offset + 1] & 0xf0) >> 4);
+ b = ((paletteram[offset + 1] & 0x0f) >> 0);
+
+ palette_set_color_rgb(Machine, (offset >> 1), pal4bit(r), pal4bit(g), pal4bit(b));
+}
+
+WRITE8_HANDLER( nbmj8991_palette_type2_w )
+{
+ int r, g, b;
+
+ paletteram[offset] = data;
+
+ if (!(offset & 1)) return;
+
+ offset &= 0x1fe;
+
+ r = ((paletteram[offset + 0] & 0x7c) >> 2);
+ g = (((paletteram[offset + 0] & 0x03) << 3) | ((paletteram[offset + 1] & 0xe0) >> 5));
+ b = ((paletteram[offset + 1] & 0x1f) >> 0);
+
+ palette_set_color_rgb(Machine, (offset / 2), pal5bit(r), pal5bit(g), pal5bit(b));
+}
+
+WRITE8_HANDLER( nbmj8991_palette_type3_w )
+{
+ int r, g, b;
+
+ paletteram[offset] = data;
+
+ if (!(offset & 1)) return;
+
+ offset &= 0x1fe;
+
+ r = ((paletteram[offset + 1] & 0x0f) >> 0);
+ g = ((paletteram[offset + 0] & 0xf0) >> 4);
+ b = ((paletteram[offset + 0] & 0x0f) >> 0);
+
+ palette_set_color_rgb(Machine, (offset >> 1), pal4bit(r), pal4bit(g), pal4bit(b));
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+WRITE8_HANDLER( nbmj8991_blitter_w )
+{
+ switch (offset)
+ {
+ case 0x00: blitter_src_addr = (blitter_src_addr & 0xff00) | data; break;
+ case 0x01: blitter_src_addr = (blitter_src_addr & 0x00ff) | (data << 8); break;
+ case 0x02: break;
+ case 0x03: break;
+ case 0x04: blitter_sizex = data; break;
+ case 0x05: blitter_sizey = data;
+ /* writing here also starts the blit */
+ nbmj8991_gfxdraw();
+ break;
+ case 0x06: blitter_direction_x = (data & 0x01) ? 1 : 0;
+ blitter_direction_y = (data & 0x02) ? 1 : 0;
+ nbmj8991_flipscreen = (data & 0x04) ? 0 : 1;
+ nbmj8991_dispflag = (data & 0x10) ? 0 : 1;
+ nbmj8991_vramflip();
+ break;
+ case 0x07: break;
+ case 0x10: blitter_destx = (blitter_destx & 0xff00) | data; break;
+ case 0x20: blitter_desty = (blitter_desty & 0xff00) | data; break;
+ case 0x30: nbmj8991_scrollx = (nbmj8991_scrollx & 0xff00) | data; break;
+ case 0x40: nbmj8991_scrolly = (nbmj8991_scrolly & 0xff00) | data; break;
+ case 0x50: blitter_destx = (blitter_destx & 0x00ff) | ((data & 0x01) << 8);
+ blitter_desty = (blitter_desty & 0x00ff) | ((data & 0x02) << 7);
+ nbmj8991_scrollx = (nbmj8991_scrollx & 0x00ff) | ((data & 0x04) << 6);
+ nbmj8991_scrolly = (nbmj8991_scrolly & 0x00ff) | ((data & 0x08) << 5);
+ break;
+ case 0x60: nbmj8991_gfxrom = data; break;
+ case 0x70: nbmj8991_clutsel = data; break;
+ }
+
+ if ((0x20000 * nbmj8991_gfxrom) > (memory_region_length(REGION_GFX1) - 1))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM BANK OVER!!");
+#endif
+ nbmj8991_gfxrom &= (memory_region_length(REGION_GFX1) / 0x20000 - 1);
+ }
+}
+
+READ8_HANDLER( nbmj8991_clut_r )
+{
+ return nbmj8991_clut[offset];
+}
+
+WRITE8_HANDLER( nbmj8991_clut_w )
+{
+ nbmj8991_clut[((nbmj8991_clutsel & 0x7f) * 0x10) + (offset & 0x0f)] = data;
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+static void nbmj8991_vramflip(void)
+{
+ static int nbmj8991_flipscreen_old = 0;
+ int x, y;
+ UINT8 color1, color2;
+
+ if (nbmj8991_flipscreen == nbmj8991_flipscreen_old) return;
+
+ for (y = 0; y < Machine->screen[0].height / 2; y++)
+ {
+ for (x = 0; x < Machine->screen[0].width / 2; x++)
+ {
+ // rotate 180 degrees ( 0, 0) - ( 511, 511)
+ color1 = nbmj8991_videoram[(y * Machine->screen[0].width) + x];
+ color2 = nbmj8991_videoram[(((Machine->screen[0].height - 1) - y) * Machine->screen[0].width) + (((Machine->screen[0].width / 2) - 1) - x)];
+ nbmj8991_videoram[(y * Machine->screen[0].width) + x] = color2;
+ nbmj8991_videoram[(((Machine->screen[0].height - 1) - y) * Machine->screen[0].width) + (((Machine->screen[0].width / 2) - 1) - x)] = color1;
+ // rotate 180 degrees ( 512, 0) - (1023, 511)
+ color1 = nbmj8991_videoram[(y * Machine->screen[0].width) + (x + (Machine->screen[0].width / 2))];
+ color2 = nbmj8991_videoram[(((Machine->screen[0].height - 1) - y) * Machine->screen[0].width) + ((((Machine->screen[0].width / 2) - 1) - x) + (Machine->screen[0].width / 2))];
+ nbmj8991_videoram[(y * Machine->screen[0].width) + (x + (Machine->screen[0].width / 2))] = color2;
+ nbmj8991_videoram[(((Machine->screen[0].height - 1) - y) * Machine->screen[0].width) + ((((Machine->screen[0].width / 2) - 1) - x) + (Machine->screen[0].width / 2))] = color1;
+ }
+ }
+
+ nbmj8991_flipscreen_old = nbmj8991_flipscreen;
+ nbmj8991_screen_refresh = 1;
+}
+
+static void update_pixel(int x, int y)
+{
+ UINT8 color = nbmj8991_videoram[(y * Machine->screen[0].width) + x];
+ *BITMAP_ADDR16(nbmj8991_tmpbitmap, y, x) = Machine->pens[color];
+}
+
+static TIMER_CALLBACK( blitter_timer_callback )
+{
+ nb1413m3_busyflag = 1;
+}
+
+static void nbmj8991_gfxdraw(void)
+{
+ UINT8 *GFX = memory_region(REGION_GFX1);
+
+ int x, y;
+ int dx1, dx2, dy;
+ int startx, starty;
+ int sizex, sizey;
+ int skipx, skipy;
+ int ctrx, ctry;
+ UINT8 color, color1, color2;
+ int gfxaddr;
+
+ nb1413m3_busyctr = 0;
+
+ if (blitter_direction_x)
+ {
+ startx = blitter_destx;
+ sizex = blitter_sizex ^ 0xff;
+ skipx = 1;
+ }
+ else
+ {
+ startx = blitter_destx + blitter_sizex;
+ sizex = blitter_sizex;
+ skipx = -1;
+ }
+
+ if (blitter_direction_y)
+ {
+ starty = blitter_desty;
+ sizey = blitter_sizey ^ 0xff;
+ skipy = 1;
+ }
+ else
+ {
+ starty = blitter_desty + blitter_sizey;
+ sizey = blitter_sizey;
+ skipy = -1;
+ }
+
+ gfxaddr = (nbmj8991_gfxrom << 17) + (blitter_src_addr << 1);
+
+ for (y = starty, ctry = sizey; ctry >= 0; y += skipy, ctry--)
+ {
+ for (x = startx, ctrx = sizex; ctrx >= 0; x += skipx, ctrx--)
+ {
+ if ((gfxaddr > (memory_region_length(REGION_GFX1) - 1)))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM ADDRESS OVER!!");
+#endif
+ gfxaddr &= (memory_region_length(REGION_GFX1) - 1);
+ }
+
+ color = GFX[gfxaddr++];
+
+ dx1 = (2 * x + 0) & 0x3ff;
+ dx2 = (2 * x + 1) & 0x3ff;
+ dy = y & 0x1ff;
+
+ if (!nbmj8991_flipscreen)
+ {
+ dx1 ^= 0x1ff;
+ dx2 ^= 0x1ff;
+ dy ^= 0x1ff;
+ }
+
+ if (blitter_direction_x)
+ {
+ // flip
+ color1 = (color & 0x0f) >> 0;
+ color2 = (color & 0xf0) >> 4;
+ }
+ else
+ {
+ // normal
+ color1 = (color & 0xf0) >> 4;
+ color2 = (color & 0x0f) >> 0;
+ }
+
+ color1 = nbmj8991_clut[((nbmj8991_clutsel & 0x7f) * 0x10) + color1];
+ color2 = nbmj8991_clut[((nbmj8991_clutsel & 0x7f) * 0x10) + color2];
+
+ if (color1 != 0xff)
+ {
+ nbmj8991_videoram[(dy * Machine->screen[0].width) + dx1] = color1;
+ update_pixel(dx1, dy);
+ }
+ if (color2 != 0xff)
+ {
+ nbmj8991_videoram[(dy * Machine->screen[0].width) + dx2] = color2;
+ update_pixel(dx2, dy);
+ }
+
+ nb1413m3_busyctr++;
+ }
+ }
+
+ nb1413m3_busyflag = 0;
+ timer_set(attotime_mul(ATTOTIME_IN_NSEC(1650), nb1413m3_busyctr), 0, blitter_timer_callback);
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+VIDEO_START( nbmj8991 )
+{
+ nbmj8991_tmpbitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ nbmj8991_videoram = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(UINT8));
+ nbmj8991_clut = auto_malloc(0x800 * sizeof(UINT8));
+ memset(nbmj8991_videoram, 0x00, (machine->screen[0].width * machine->screen[0].height * sizeof(UINT8)));
+}
+
+VIDEO_UPDATE( nbmj8991_type1 )
+{
+ int x, y;
+
+ if (nbmj8991_screen_refresh)
+ {
+ nbmj8991_screen_refresh = 0;
+
+ for (y = 0; y < machine->screen[0].height; y++)
+ {
+ for (x = 0; x < machine->screen[0].width; x++)
+ {
+ update_pixel(x, y);
+ }
+ }
+ }
+
+ if (nbmj8991_dispflag)
+ {
+ static int scrollx, scrolly;
+
+ if (nbmj8991_flipscreen)
+ {
+ scrollx = (((-nbmj8991_scrollx) + 0x000) & 0x1ff) * 2;
+ scrolly = ((-nbmj8991_scrolly) - 0x00f) & 0x1ff;
+ }
+ else
+ {
+ scrollx = (((-nbmj8991_scrollx) - 0x100) & 0x1ff) * 2;
+ scrolly = (( nbmj8991_scrolly) + 0x0f1) & 0x1ff;
+ }
+
+ copyscrollbitmap(bitmap, nbmj8991_tmpbitmap, 1, &scrollx, 1, &scrolly, &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ }
+ else
+ {
+ fillbitmap(bitmap, machine->pens[0x00], 0);
+ }
+ return 0;
+}
+
+VIDEO_UPDATE( nbmj8991_type2 )
+{
+ int x, y;
+
+ if (nbmj8991_screen_refresh)
+ {
+ nbmj8991_screen_refresh = 0;
+
+ for (y = 0; y < machine->screen[0].height; y++)
+ {
+ for (x = 0; x < machine->screen[0].width; x++)
+ {
+ update_pixel(x, y);
+ }
+ }
+ }
+
+ if (nb1413m3_inputport & 0x20)
+ {
+ static int scrollx, scrolly;
+
+ if (nbmj8991_flipscreen)
+ {
+ scrollx = (((-nbmj8991_scrollx) + 0x000) & 0x1ff) * 2;
+ scrolly = ((-nbmj8991_scrolly) - 0x00f) & 0x1ff;
+ }
+ else
+ {
+ scrollx = (((-nbmj8991_scrollx) - 0x100) & 0x1ff) * 2;
+ scrolly = (( nbmj8991_scrolly) + 0x0f1) & 0x1ff;
+ }
+
+ copyscrollbitmap(bitmap, nbmj8991_tmpbitmap, 1, &scrollx, 1, &scrolly, &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ }
+ else
+ {
+ fillbitmap(bitmap, machine->pens[0x00], 0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/nbmj9195.c b/src/mame/video/nbmj9195.c
new file mode 100644
index 00000000000..8e5695e8b1a
--- /dev/null
+++ b/src/mame/video/nbmj9195.c
@@ -0,0 +1,526 @@
+/******************************************************************************
+
+ Video Hardware for Nichibutsu Mahjong series.
+
+ Driver by Takahiro Nogi <nogi@kt.rim.or.jp> 1999/11/05 -
+ Special thanks to Tatsuyuki Satoh
+
+******************************************************************************/
+
+#include "driver.h"
+
+
+#define VRAM_MAX 2
+
+#define SCANLINE_MIN 0
+#define SCANLINE_MAX 512
+
+
+static int nbmj9195_scrollx[VRAM_MAX], nbmj9195_scrolly[VRAM_MAX];
+static int nbmj9195_scrollx_raster[VRAM_MAX][SCANLINE_MAX];
+static int nbmj9195_scanline[VRAM_MAX];
+static int blitter_destx[VRAM_MAX], blitter_desty[VRAM_MAX];
+static int blitter_sizex[VRAM_MAX], blitter_sizey[VRAM_MAX];
+static int blitter_src_addr[VRAM_MAX];
+static int blitter_direction_x[VRAM_MAX], blitter_direction_y[VRAM_MAX];
+static int nbmj9195_dispflag[VRAM_MAX];
+static int nbmj9195_flipscreen[VRAM_MAX];
+static int nbmj9195_clutmode[VRAM_MAX];
+static int nbmj9195_transparency[VRAM_MAX];
+static int nbmj9195_clutsel;
+static int nbmj9195_screen_refresh;
+static int nbmj9195_gfxflag2;
+static int gfxdraw_mode;
+static int nb19010_busyctr;
+static int nb19010_busyflag;
+
+static mame_bitmap *nbmj9195_tmpbitmap[VRAM_MAX];
+static UINT16 *nbmj9195_videoram[VRAM_MAX];
+static UINT16 *nbmj9195_videoworkram[VRAM_MAX];
+static UINT8 *nbmj9195_palette, *nbmj9195_nb22090_palette;
+static UINT8 *nbmj9195_clut[VRAM_MAX];
+
+
+static void nbmj9195_vramflip(int vram);
+static void nbmj9195_gfxdraw(int vram);
+
+
+/******************************************************************************
+
+
+******************************************************************************/
+READ8_HANDLER( nbmj9195_palette_r )
+{
+ return nbmj9195_palette[offset];
+}
+
+WRITE8_HANDLER( nbmj9195_palette_w )
+{
+ int r, g, b;
+
+ nbmj9195_palette[offset] = data;
+
+ if (offset & 1)
+ {
+ offset &= 0x1fe;
+
+ r = ((nbmj9195_palette[offset + 0] & 0x0f) >> 0);
+ g = ((nbmj9195_palette[offset + 0] & 0xf0) >> 4);
+ b = ((nbmj9195_palette[offset + 1] & 0x0f) >> 0);
+
+ palette_set_color_rgb(Machine, (offset >> 1), pal4bit(r), pal4bit(g), pal4bit(b));
+ }
+}
+
+READ8_HANDLER( nbmj9195_nb22090_palette_r )
+{
+ return nbmj9195_nb22090_palette[offset];
+}
+
+WRITE8_HANDLER( nbmj9195_nb22090_palette_w )
+{
+ int r, g, b;
+ int offs_h, offs_l;
+
+ nbmj9195_nb22090_palette[offset] = data;
+
+ offs_h = (offset / 0x0300);
+ offs_l = (offset & 0x00ff);
+
+ r = nbmj9195_nb22090_palette[(0x000 + (offs_h * 0x300) + offs_l)];
+ g = nbmj9195_nb22090_palette[(0x100 + (offs_h * 0x300) + offs_l)];
+ b = nbmj9195_nb22090_palette[(0x200 + (offs_h * 0x300) + offs_l)];
+
+ palette_set_color(Machine, ((offs_h * 0x100) + offs_l), MAKE_RGB(r, g, b));
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+static int nbmj9195_blitter_r(int vram, int offset)
+{
+ int ret;
+ UINT8 *GFXROM = memory_region(REGION_GFX1);
+
+ switch (offset)
+ {
+ case 0x00: ret = 0xfe | ((nb19010_busyflag & 0x01) ^ 0x01); break; // NB19010 Busy Flag
+ case 0x01: ret = GFXROM[blitter_src_addr[vram]]; break; // NB19010 GFX-ROM Read
+ default: ret = 0xff; break;
+ }
+
+ return ret;
+}
+
+static void nbmj9195_blitter_w(int vram, int offset, int data)
+{
+ int new_line;
+
+ switch (offset)
+ {
+ case 0x00: blitter_direction_x[vram] = (data & 0x01) ? 1 : 0;
+ blitter_direction_y[vram] = (data & 0x02) ? 1 : 0;
+ nbmj9195_clutmode[vram] = (data & 0x04) ? 1 : 0;
+ // if (data & 0x08) popmessage("Unknown GFX Flag!! (0x08)");
+ nbmj9195_transparency[vram] = (data & 0x10) ? 1 : 0;
+ // if (data & 0x20) popmessage("Unknown GFX Flag!! (0x20)");
+ nbmj9195_flipscreen[vram] = (data & 0x40) ? 0 : 1;
+ nbmj9195_dispflag[vram] = (data & 0x80) ? 1 : 0;
+ nbmj9195_vramflip(vram);
+ break;
+ case 0x01: nbmj9195_scrollx[vram] = (nbmj9195_scrollx[vram] & 0x0100) | data; break;
+ case 0x02: nbmj9195_scrollx[vram] = (nbmj9195_scrollx[vram] & 0x00ff) | ((data << 8) & 0x0100);
+ new_line = video_screen_get_vpos(0);
+ if (nbmj9195_flipscreen[vram])
+ {
+ for ( ; nbmj9195_scanline[vram] < new_line; nbmj9195_scanline[vram]++)
+ nbmj9195_scrollx_raster[vram][nbmj9195_scanline[vram]] = (((-nbmj9195_scrollx[vram]) - 0x4e) & 0x1ff) << 1;
+ }
+ else
+ {
+ for ( ; nbmj9195_scanline[vram] < new_line; nbmj9195_scanline[vram]++)
+ nbmj9195_scrollx_raster[vram][(nbmj9195_scanline[vram] ^ 0x1ff)] = (((-nbmj9195_scrollx[vram]) - 0x4e) & 0x1ff) << 1;
+ }
+ break;
+ case 0x03: nbmj9195_scrolly[vram] = (nbmj9195_scrolly[vram] & 0x0100) | data; break;
+ case 0x04: nbmj9195_scrolly[vram] = (nbmj9195_scrolly[vram] & 0x00ff) | ((data << 8) & 0x0100); break;
+ case 0x05: blitter_src_addr[vram] = (blitter_src_addr[vram] & 0xffff00) | data; break;
+ case 0x06: blitter_src_addr[vram] = (blitter_src_addr[vram] & 0xff00ff) | (data << 8); break;
+ case 0x07: blitter_src_addr[vram] = (blitter_src_addr[vram] & 0x00ffff) | (data << 16); break;
+ case 0x08: blitter_sizex[vram] = data; break;
+ case 0x09: blitter_sizey[vram] = data; break;
+ case 0x0a: blitter_destx[vram] = (blitter_destx[vram] & 0xff00) | data; break;
+ case 0x0b: blitter_destx[vram] = (blitter_destx[vram] & 0x00ff) | (data << 8); break;
+ case 0x0c: blitter_desty[vram] = (blitter_desty[vram] & 0xff00) | data; break;
+ case 0x0d: blitter_desty[vram] = (blitter_desty[vram] & 0x00ff) | (data << 8);
+ nbmj9195_gfxdraw(vram);
+ break;
+ default: break;
+ }
+}
+
+void nbmj9195_clutsel_w(int data)
+{
+ nbmj9195_clutsel = data;
+}
+
+static void nbmj9195_clut_w(int vram, int offset, int data)
+{
+ nbmj9195_clut[vram][((nbmj9195_clutsel & 0xff) * 0x10) + (offset & 0x0f)] = data;
+}
+
+void nbmj9195_gfxflag2_w(int data)
+{
+ nbmj9195_gfxflag2 = data;
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+static void nbmj9195_vramflip(int vram)
+{
+ static int nbmj9195_flipscreen_old[VRAM_MAX] = { 0, 0 };
+ int x, y;
+ UINT16 color1, color2;
+
+ if (nbmj9195_flipscreen[vram] == nbmj9195_flipscreen_old[vram]) return;
+
+ for (y = 0; y < (Machine->screen[0].height / 2); y++)
+ {
+ for (x = 0; x < Machine->screen[0].width; x++)
+ {
+ color1 = nbmj9195_videoram[vram][(y * Machine->screen[0].width) + x];
+ color2 = nbmj9195_videoram[vram][((y ^ 0x1ff) * Machine->screen[0].width) + (x ^ 0x3ff)];
+ nbmj9195_videoram[vram][(y * Machine->screen[0].width) + x] = color2;
+ nbmj9195_videoram[vram][((y ^ 0x1ff) * Machine->screen[0].width) + (x ^ 0x3ff)] = color1;
+ }
+ }
+
+ if (gfxdraw_mode == 2)
+ {
+ for (y = 0; y < (Machine->screen[0].height / 2); y++)
+ {
+ for (x = 0; x < Machine->screen[0].width; x++)
+ {
+ color1 = nbmj9195_videoworkram[vram][(y * Machine->screen[0].width) + x];
+ color2 = nbmj9195_videoworkram[vram][((y ^ 0x1ff) * Machine->screen[0].width) + (x ^ 0x3ff)];
+ nbmj9195_videoworkram[vram][(y * Machine->screen[0].width) + x] = color2;
+ nbmj9195_videoworkram[vram][((y ^ 0x1ff) * Machine->screen[0].width) + (x ^ 0x3ff)] = color1;
+ }
+ }
+ }
+
+ nbmj9195_flipscreen_old[vram] = nbmj9195_flipscreen[vram];
+ nbmj9195_screen_refresh = 1;
+}
+
+static void update_pixel(int vram, int x, int y)
+{
+ UINT16 color = nbmj9195_videoram[vram][(y * Machine->screen[0].width) + x];
+ *BITMAP_ADDR16(nbmj9195_tmpbitmap[vram], y, x) = Machine->pens[color];
+}
+
+static TIMER_CALLBACK( blitter_timer_callback )
+{
+ nb19010_busyflag = 1;
+}
+
+static void nbmj9195_gfxdraw(int vram)
+{
+ UINT8 *GFX = memory_region(REGION_GFX1);
+
+ int x, y;
+ int dx1, dx2, dy;
+ int startx, starty;
+ int sizex, sizey;
+ int skipx, skipy;
+ int ctrx, ctry;
+ UINT16 color, color1, color2;
+ int gfxaddr;
+
+ nb19010_busyctr = 0;
+
+ if ((gfxdraw_mode == 2) && (nbmj9195_clutmode[vram]))
+ {
+ // NB22090 clut256 mode
+ blitter_sizex[vram] = GFX[((blitter_src_addr[vram] + 0) & 0x00ffffff)];
+ blitter_sizey[vram] = GFX[((blitter_src_addr[vram] + 1) & 0x00ffffff)];
+ }
+
+ if (blitter_direction_x[vram])
+ {
+ startx = blitter_destx[vram];
+ sizex = blitter_sizex[vram];
+ skipx = 1;
+ }
+ else
+ {
+ startx = blitter_destx[vram] + blitter_sizex[vram];
+ sizex = blitter_sizex[vram];
+ skipx = -1;
+ }
+
+ if (blitter_direction_y[vram])
+ {
+ starty = blitter_desty[vram];
+ sizey = blitter_sizey[vram];
+ skipy = 1;
+ }
+ else
+ {
+ starty = blitter_desty[vram] + blitter_sizey[vram];
+ sizey = blitter_sizey[vram];
+ skipy = -1;
+ }
+
+ gfxaddr = ((blitter_src_addr[vram] + 2) & 0x00ffffff);
+
+ for (y = starty, ctry = sizey; ctry >= 0; y += skipy, ctry--)
+ {
+ for (x = startx, ctrx = sizex; ctrx >= 0; x += skipx, ctrx--)
+ {
+ if ((gfxaddr > (memory_region_length(REGION_GFX1) - 1)))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM ADDR OVER:%08X DX,%d,DY:%d,SX:%d,SY:%d", gfxaddr, startx, starty, sizex,sizey);
+ logerror("GFXROM ADDR OVER:%08X DX,%d,DY:%d,SX:%d,SY:%d\n", gfxaddr, startx, starty, sizex,sizey);
+#endif
+ gfxaddr &= (memory_region_length(REGION_GFX1) - 1);
+ }
+
+ color = GFX[gfxaddr++];
+
+ dx1 = (2 * x + 0) & 0x3ff;
+ dx2 = (2 * x + 1) & 0x3ff;
+ dy = y & 0x1ff;
+
+ if (!nbmj9195_flipscreen[vram])
+ {
+ dx1 ^= 0x3ff;
+ dx2 ^= 0x3ff;
+ dy ^= 0x1ff;
+ }
+
+ if (blitter_direction_x[vram])
+ {
+ // flip
+ color1 = (color & 0x0f) >> 0;
+ color2 = (color & 0xf0) >> 4;
+ }
+ else
+ {
+ // normal
+ color1 = (color & 0xf0) >> 4;
+ color2 = (color & 0x0f) >> 0;
+ }
+
+ if ((gfxdraw_mode == 2) && (nbmj9195_clutmode[vram]))
+ {
+ // clut256 mode
+
+ if (nbmj9195_gfxflag2 & 0xc0)
+ {
+ // clut256 mode 1st(low)
+ nbmj9195_videoworkram[vram][(dy * Machine->screen[0].width) + dx1] &= 0x00f0;
+ nbmj9195_videoworkram[vram][(dy * Machine->screen[0].width) + dx1] |= color1 & 0x0f;
+ nbmj9195_videoworkram[vram][(dy * Machine->screen[0].width) + dx2] &= 0x00f0;
+ nbmj9195_videoworkram[vram][(dy * Machine->screen[0].width) + dx2] |= color2 & 0x0f;
+
+ continue;
+ }
+ else
+ {
+ // clut256 mode 2nd(high)
+ nbmj9195_videoworkram[vram][(dy * Machine->screen[0].width) + dx1] &= 0x000f;
+ nbmj9195_videoworkram[vram][(dy * Machine->screen[0].width) + dx1] |= (color1 & 0x0f) << 4;
+ nbmj9195_videoworkram[vram][(dy * Machine->screen[0].width) + dx2] &= 0x000f;
+ nbmj9195_videoworkram[vram][(dy * Machine->screen[0].width) + dx2] |= (color2 & 0x0f) << 4;
+
+ nbmj9195_videoworkram[vram][(dy * Machine->screen[0].width) + dx1] += nbmj9195_clut[vram][(nbmj9195_clutsel * 0x10)];
+ nbmj9195_videoworkram[vram][(dy * Machine->screen[0].width) + dx2] += nbmj9195_clut[vram][(nbmj9195_clutsel * 0x10)];
+ }
+
+ color1 = nbmj9195_videoworkram[vram][(dy * Machine->screen[0].width) + dx1];
+ color2 = nbmj9195_videoworkram[vram][(dy * Machine->screen[0].width) + dx2];
+ }
+ else
+ {
+ // clut16 mode
+ color1 = nbmj9195_clut[vram][(nbmj9195_clutsel * 0x10) + color1];
+ color2 = nbmj9195_clut[vram][(nbmj9195_clutsel * 0x10) + color2];
+ }
+
+ if (gfxdraw_mode == 2)
+ {
+ color1 |= (0x0100 * vram);
+ color2 |= (0x0100 * vram);
+ }
+
+ if (((color1 & 0x00ff) != 0x00ff) || (!nbmj9195_transparency[vram]))
+ {
+ nbmj9195_videoram[vram][(dy * Machine->screen[0].width) + dx1] = color1;
+ update_pixel(vram, dx1, dy);
+ }
+ if (((color2 & 0x00ff) != 0x00ff) || (!nbmj9195_transparency[vram]))
+ {
+ nbmj9195_videoram[vram][(dy * Machine->screen[0].width) + dx2] = color2;
+ update_pixel(vram, dx2, dy);
+ }
+
+ nb19010_busyctr++;
+ }
+ }
+
+ if ((gfxdraw_mode == 2) && (nbmj9195_clutmode[vram]))
+ {
+ // NB22090 clut256 mode
+ blitter_src_addr[vram] = gfxaddr;
+ }
+
+ nb19010_busyflag = 0;
+
+ /* 1650ns per count */
+ timer_set(attotime_make(0, nb19010_busyctr * 1650 * ATTOSECONDS_PER_NANOSECOND), 0, blitter_timer_callback);
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+WRITE8_HANDLER( nbmj9195_blitter_0_w ) { nbmj9195_blitter_w(0, offset, data); }
+WRITE8_HANDLER( nbmj9195_blitter_1_w ) { nbmj9195_blitter_w(1, offset, data); }
+
+READ8_HANDLER( nbmj9195_blitter_0_r ) { return nbmj9195_blitter_r(0, offset); }
+READ8_HANDLER( nbmj9195_blitter_1_r ) { return nbmj9195_blitter_r(1, offset); }
+
+WRITE8_HANDLER( nbmj9195_clut_0_w ) { nbmj9195_clut_w(0, offset, data); }
+WRITE8_HANDLER( nbmj9195_clut_1_w ) { nbmj9195_clut_w(1, offset, data); }
+
+/******************************************************************************
+
+
+******************************************************************************/
+VIDEO_START( nbmj9195_1layer )
+{
+ nbmj9195_tmpbitmap[0] = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ nbmj9195_videoram[0] = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(UINT16));
+ nbmj9195_palette = auto_malloc(0x200 * sizeof(UINT8));
+ nbmj9195_clut[0] = auto_malloc(0x1000 * sizeof(UINT8));
+ memset(nbmj9195_videoram[0], 0x0000, (machine->screen[0].width * machine->screen[0].height * sizeof(UINT16)));
+ nbmj9195_scanline[0] = nbmj9195_scanline[1] = SCANLINE_MIN;
+ nb19010_busyflag = 1;
+ gfxdraw_mode = 0;
+}
+
+VIDEO_START( nbmj9195_2layer )
+{
+ nbmj9195_tmpbitmap[0] = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ nbmj9195_tmpbitmap[1] = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ nbmj9195_videoram[0] = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(UINT16));
+ nbmj9195_videoram[1] = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(UINT16));
+ nbmj9195_palette = auto_malloc(0x200 * sizeof(UINT8));
+ nbmj9195_clut[0] = auto_malloc(0x1000 * sizeof(UINT8));
+ nbmj9195_clut[1] = auto_malloc(0x1000 * sizeof(UINT8));
+ memset(nbmj9195_videoram[0], 0x0000, (machine->screen[0].width * machine->screen[0].height * sizeof(UINT16)));
+ memset(nbmj9195_videoram[1], 0x0000, (machine->screen[0].width * machine->screen[0].height * sizeof(UINT16)));
+ nbmj9195_scanline[0] = nbmj9195_scanline[1] = SCANLINE_MIN;
+ nb19010_busyflag = 1;
+ gfxdraw_mode = 1;
+}
+
+VIDEO_START( nbmj9195_nb22090 )
+{
+ nbmj9195_tmpbitmap[0] = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ nbmj9195_tmpbitmap[1] = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ nbmj9195_videoram[0] = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(UINT16));
+ nbmj9195_videoram[1] = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(UINT16));
+ nbmj9195_videoworkram[0] = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(UINT16));
+ nbmj9195_videoworkram[1] = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(UINT16));
+ nbmj9195_nb22090_palette = auto_malloc(0xc00 * sizeof(UINT8));
+ nbmj9195_clut[0] = auto_malloc(0x1000 * sizeof(UINT8));
+ nbmj9195_clut[1] = auto_malloc(0x1000 * sizeof(UINT8));
+ memset(nbmj9195_videoram[0], 0x0000, (machine->screen[0].width * machine->screen[0].height * sizeof(UINT16)));
+ memset(nbmj9195_videoram[1], 0x0000, (machine->screen[0].width * machine->screen[0].height * sizeof(UINT16)));
+ memset(nbmj9195_videoworkram[0], 0x0000, (machine->screen[0].width * machine->screen[0].height * sizeof(UINT16)));
+ memset(nbmj9195_videoworkram[1], 0x0000, (machine->screen[0].width * machine->screen[0].height * sizeof(UINT16)));
+ nbmj9195_scanline[0] = nbmj9195_scanline[1] = SCANLINE_MIN;
+ nb19010_busyflag = 1;
+ gfxdraw_mode = 2;
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+VIDEO_UPDATE( nbmj9195 )
+{
+ int i;
+ int x, y;
+ int scrolly[2];
+
+ if (nbmj9195_screen_refresh)
+ {
+ nbmj9195_screen_refresh = 0;
+
+ for (y = 0; y < machine->screen[0].height; y++)
+ {
+ for (x = 0; x < machine->screen[0].width; x++)
+ {
+ update_pixel(0, x, y);
+
+ if (gfxdraw_mode)
+ {
+ update_pixel(1, x, y);
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < 2; i++)
+ {
+ if (nbmj9195_flipscreen[i])
+ {
+ for ( ; nbmj9195_scanline[i] < SCANLINE_MAX; nbmj9195_scanline[i]++)
+ {
+ nbmj9195_scrollx_raster[i][nbmj9195_scanline[i]] = (((-nbmj9195_scrollx[i]) - 0x4e) & 0x1ff) << 1;
+ }
+ scrolly[i] = (-nbmj9195_scrolly[i]) & 0x1ff;
+ }
+ else
+ {
+ for ( ; nbmj9195_scanline[i] < SCANLINE_MAX; nbmj9195_scanline[i]++)
+ {
+ nbmj9195_scrollx_raster[i][(nbmj9195_scanline[i] ^ 0x1ff)] = (((-nbmj9195_scrollx[i]) - 0x4e) & 0x1ff) << 1;
+ }
+ scrolly[i] = nbmj9195_scrolly[i] & 0x1ff;
+ }
+ nbmj9195_scanline[i] = SCANLINE_MIN;
+ }
+
+ if (nbmj9195_dispflag[0])
+ {
+ // nbmj9195 1layer
+ copyscrollbitmap(bitmap, nbmj9195_tmpbitmap[0], SCANLINE_MAX, nbmj9195_scrollx_raster[0], 1, &scrolly[0], &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ }
+ else
+ {
+ fillbitmap(bitmap, machine->pens[0x0ff], 0);
+ }
+
+ if (nbmj9195_dispflag[1])
+ {
+ if (gfxdraw_mode == 1)
+ {
+ // nbmj9195 2layer
+ copyscrollbitmap(bitmap, nbmj9195_tmpbitmap[1], SCANLINE_MAX, nbmj9195_scrollx_raster[1], 1, &scrolly[1], &machine->screen[0].visarea, TRANSPARENCY_PEN, machine->pens[0x0ff]);
+ }
+ if (gfxdraw_mode == 2)
+ {
+ // nbmj9195 nb22090 2layer
+ copyscrollbitmap(bitmap, nbmj9195_tmpbitmap[1], SCANLINE_MAX, nbmj9195_scrollx_raster[1], 1, &scrolly[1], &machine->screen[0].visarea, TRANSPARENCY_PEN, machine->pens[0x1ff]);
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/nemesis.c b/src/mame/video/nemesis.c
new file mode 100644
index 00000000000..5e8ad3a365d
--- /dev/null
+++ b/src/mame/video/nemesis.c
@@ -0,0 +1,459 @@
+/***************************************************************************
+
+ video.c
+
+***************************************************************************/
+
+#include "driver.h"
+#include <math.h>
+
+UINT16 *nemesis_videoram1b;
+UINT16 *nemesis_videoram2b;
+UINT16 *nemesis_videoram1f;
+UINT16 *nemesis_videoram2f;
+
+UINT16 *nemesis_characterram;
+size_t nemesis_characterram_size;
+UINT16 *nemesis_xscroll1,*nemesis_xscroll2,*nemesis_yscroll;
+UINT16 *nemesis_yscroll1,*nemesis_yscroll2;
+
+static int spriteram_words;
+static int tilemap_flip;
+static int flipscreen;
+
+static tilemap *background, *foreground;
+
+static UINT8 *blank_characterdata; /* pseudo character */
+
+/* gfxram dirty flags */
+
+/* we should be able to draw sprite gfx directly without caching to GfxElements */
+
+static UINT8 *sprite_dirty[8];
+
+static const struct
+{
+ UINT8 width;
+ UINT8 height;
+ UINT8 char_type;
+}
+sprite_data[8] =
+{
+ { 32, 32, 4 }, { 16, 32, 5 }, { 32, 16, 2 }, { 64, 64, 7 },
+ { 8, 8, 0 }, { 16, 8, 6 }, { 8, 16, 3 }, { 16, 16, 1 }
+};
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code,color,flags;
+ code = nemesis_videoram1f[tile_index];
+ color = nemesis_videoram2f[tile_index];
+ flags = 0;
+ if ( color & 0x80) flags |= TILE_FLIPX;
+ if ( code & 0x0800) flags |= TILE_FLIPY;
+ if ((~code & 0x2000) || ((code & 0xc000) == 0x4000))
+ flags |= TILE_FORCE_LAYER0;
+ if (code & 0xf800) {
+ SET_TILE_INFO( 0, code&0x7ff, color&0x7f, flags );
+ } else {
+ SET_TILE_INFO( 0, 0x800, 0x00, 0 );
+ }
+ tileinfo->category = (code & 0x1000)>>12;
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code,color,flags;
+ code = nemesis_videoram1b[tile_index];
+ color = nemesis_videoram2b[tile_index];
+ flags = 0;
+ if ( color & 0x80) flags |= TILE_FLIPX;
+ if ( code & 0x0800) flags |= TILE_FLIPY;
+ if ((~code & 0x2000) || ((code & 0xc000) == 0x4000))
+ flags |= TILE_FORCE_LAYER0;
+ if (code & 0xf800) {
+ SET_TILE_INFO( 0, code&0x7ff, color&0x7f, flags );
+ } else {
+ SET_TILE_INFO( 0, 0x800, 0x00, 0 );
+ }
+ tileinfo->category = (code & 0x1000)>>12;
+}
+
+WRITE16_HANDLER( nemesis_gfx_flipx_w )
+{
+ if (ACCESSING_LSB)
+ {
+ flipscreen = data & 0x01;
+ if (flipscreen)
+ tilemap_flip |= TILEMAP_FLIPX;
+ else
+ tilemap_flip &= ~TILEMAP_FLIPX;
+
+ tilemap_set_flip(ALL_TILEMAPS, tilemap_flip);
+ }
+ else
+ {
+ if (data & 0x100)
+ {
+ cpunum_set_input_line_and_vector(1, 0, HOLD_LINE, 0xff);
+ }
+ }
+}
+
+WRITE16_HANDLER( nemesis_gfx_flipy_w )
+{
+ if (ACCESSING_LSB)
+ {
+ if (data & 0x01)
+ tilemap_flip |= TILEMAP_FLIPY;
+ else
+ tilemap_flip &= ~TILEMAP_FLIPY;
+
+ tilemap_set_flip(ALL_TILEMAPS, tilemap_flip);
+ }
+}
+
+WRITE16_HANDLER( nemesis_palette_word_w )
+{
+ int r,g,b,bit1,bit2,bit3,bit4,bit5;
+
+ COMBINE_DATA(paletteram16 + offset);
+ data = paletteram16[offset];
+
+ /* Mish, 30/11/99 - Schematics show the resistor values are:
+ 300 Ohms
+ 620 Ohms
+ 1200 Ohms
+ 2400 Ohms
+ 4700 Ohms
+
+ So the correct weights per bit are 8, 17, 33, 67, 130
+ */
+
+ #define MULTIPLIER 8 * bit1 + 17 * bit2 + 33 * bit3 + 67 * bit4 + 130 * bit5
+
+ bit1=(data >> 0)&1;
+ bit2=(data >> 1)&1;
+ bit3=(data >> 2)&1;
+ bit4=(data >> 3)&1;
+ bit5=(data >> 4)&1;
+ r = MULTIPLIER;
+ bit1=(data >> 5)&1;
+ bit2=(data >> 6)&1;
+ bit3=(data >> 7)&1;
+ bit4=(data >> 8)&1;
+ bit5=(data >> 9)&1;
+ g = MULTIPLIER;
+ bit1=(data >> 10)&1;
+ bit2=(data >> 11)&1;
+ bit3=(data >> 12)&1;
+ bit4=(data >> 13)&1;
+ bit5=(data >> 14)&1;
+ b = MULTIPLIER;
+
+ palette_set_color(Machine,offset,MAKE_RGB(r,g,b));
+}
+
+WRITE16_HANDLER( salamander_palette_word_w )
+{
+ COMBINE_DATA(paletteram16 + offset);
+ offset &= ~1;
+
+ data = ((paletteram16[offset] << 8) & 0xff00) | (paletteram16[offset+1] & 0xff);
+ palette_set_color_rgb(Machine,offset / 2,pal5bit(data >> 0),pal5bit(data >> 5),pal5bit(data >> 10));
+}
+
+WRITE16_HANDLER( nemesis_videoram1b_word_w )
+{
+ COMBINE_DATA(nemesis_videoram1b + offset);
+ tilemap_mark_tile_dirty( foreground,offset );
+}
+WRITE16_HANDLER( nemesis_videoram1f_word_w )
+{
+ COMBINE_DATA(nemesis_videoram1f + offset);
+ tilemap_mark_tile_dirty( background,offset );
+}
+
+WRITE16_HANDLER( nemesis_videoram2b_word_w )
+{
+ COMBINE_DATA(nemesis_videoram2b + offset);
+ tilemap_mark_tile_dirty( foreground,offset );
+}
+WRITE16_HANDLER( nemesis_videoram2f_word_w )
+{
+ COMBINE_DATA(nemesis_videoram2f + offset);
+ tilemap_mark_tile_dirty( background,offset );
+}
+
+
+/* we have to straighten out the 16-bit word into bytes for gfxdecode() to work */
+WRITE16_HANDLER( nemesis_characterram_word_w )
+{
+ UINT16 oldword = nemesis_characterram[offset];
+ COMBINE_DATA(nemesis_characterram + offset);
+ data = nemesis_characterram[offset];
+
+ if (oldword != data)
+ {
+ int i;
+ for (i=0; i<8; i++)
+ {
+ int w = sprite_data[i].width;
+ int h = sprite_data[i].height;
+ sprite_dirty[i][offset * 4 / (w * h)] = 1;
+ }
+ }
+}
+
+
+/* claim a palette dirty array */
+VIDEO_START( nemesis )
+{
+ int i;
+ spriteram_words = spriteram_size / 2;
+
+ background = tilemap_create(
+ get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32 );
+
+ foreground = tilemap_create(
+ get_fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32 );
+
+ tilemap_set_transparent_pen( background, 0 );
+ tilemap_set_transparent_pen( foreground, 0 );
+ tilemap_set_scroll_rows( background, 256 );
+ tilemap_set_scroll_rows( foreground, 256 );
+
+ for (i=0; i<8; i++)
+ {
+ int w = sprite_data[i].width;
+ int h = sprite_data[i].height;
+ int size = 0x20000 / (w * h);
+ sprite_dirty[i] = auto_malloc(size);
+ memset(sprite_dirty[i], 1, size);
+ }
+
+ memset(nemesis_characterram,0,nemesis_characterram_size);
+
+
+ blank_characterdata = auto_malloc(32*8/8*(2048+1));
+ memset(blank_characterdata,0x00,32*8/8*(2048+1));
+ decodechar(machine->gfx[0],0x800,(UINT8 *)blank_characterdata,
+ machine->drv->gfxdecodeinfo[0].gfxlayout);
+
+ flipscreen = 0;
+ tilemap_flip = 0;
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /*
+ * 16 bytes per sprite, in memory from 56000-56fff
+ *
+ * byte 0 : relative priority.
+ * byte 2 : size (?) value #E0 means not used., bit 0x01 is flipx
+ 0xc0 is upper 2 bits of zoom.
+ 0x38 is size.
+ * byte 4 : zoom = 0xff
+ * byte 6 : low bits sprite code.
+ * byte 8 : color + hi bits sprite code., bit 0x20 is flipy bit. bit 0x01 is high bit of X pos.
+ * byte A : X position.
+ * byte C : Y position.
+ * byte E : not used.
+ */
+
+ int adress; /* start of sprite in spriteram */
+ int sx; /* sprite X-pos */
+ int sy; /* sprite Y-pos */
+ int code; /* start of sprite in obj RAM */
+ int color; /* color of the sprite */
+ int flipx,flipy;
+ int zoom;
+ int char_type;
+ int priority;
+ int size;
+ int w,h;
+ int idx;
+
+ for (priority=256-1; priority>=0; priority--)
+ {
+ for (adress = spriteram_words-8; adress >= 0; adress -= 8)
+ {
+ if((spriteram16[adress] & 0xff)!=priority) continue;
+
+ zoom = spriteram16[adress+2] & 0xff;
+ if (!(spriteram16[adress+2] & 0xff00) && ((spriteram16[adress+3] & 0xff00) != 0xff00))
+ code = spriteram16[adress+3] + ((spriteram16[adress+4] & 0xc0) << 2);
+ else
+ code = (spriteram16[adress+3] & 0xff) + ((spriteram16[adress+4] & 0xc0) << 2);
+
+ if (zoom != 0xFF || code!=0)
+ {
+ size=spriteram16[adress+1];
+ zoom+=(size&0xc0)<<2;
+
+ sx = spriteram16[adress+5]&0xff;
+ sy = spriteram16[adress+6]&0xff;
+ if(spriteram16[adress+4]&1)
+ sx-=0x100; /* fixes left side clip */
+ color = (spriteram16[adress+4] & 0x1e) >> 1;
+ flipx = spriteram16[adress+1] & 0x01;
+ flipy = spriteram16[adress+4] & 0x20;
+
+ idx = (size >> 3) & 7;
+ w = sprite_data[idx].width;
+ h = sprite_data[idx].height;
+ code = code * 8 * 16 / (w * h);
+ char_type = sprite_data[idx].char_type;
+
+ if( zoom )
+ {
+ zoom = ((1<<16)*0x80/zoom) + 0x02ab;
+ if (flipscreen)
+ {
+ sx = 256 - ((zoom * w) >> 16) - sx;
+ sy = 256 - ((zoom * h) >> 16) - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+ pdrawgfxzoom(bitmap,machine->gfx[char_type],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0,
+ zoom,zoom,
+ 0xfff0 );
+ }
+ } /* if sprite */
+ } /* for loop */
+ } /* priority */
+}
+
+/******************************************************************************/
+
+static void update_gfx(running_machine *machine)
+{
+ int offs,code;
+ int bAnyDirty;
+
+ bAnyDirty = 0;
+ for (offs = spriteram_words - 1;offs >= 0;offs --)
+ {
+ if (sprite_dirty[4][offs])
+ {
+ decodechar(machine->gfx[0],offs,(UINT8 *)nemesis_characterram,
+ machine->drv->gfxdecodeinfo[0].gfxlayout);
+ bAnyDirty = 1;
+ sprite_dirty[4][offs] = 0;
+ }
+ }
+ if( bAnyDirty )
+ {
+ tilemap_mark_all_tiles_dirty( background );
+ tilemap_mark_all_tiles_dirty( foreground );
+ }
+
+ for (offs = 0;offs < spriteram_words;offs += 8)
+ {
+ int char_type;
+ int zoom;
+
+ zoom = spriteram16[offs+2] & 0xff;
+ if (!(spriteram16[offs+2] & 0xff00) && ((spriteram16[offs+3] & 0xff00) != 0xff00))
+ code = spriteram16[offs+3] + ((spriteram16[offs+4] & 0xc0) << 2);
+ else
+ code = (spriteram16[offs+3] & 0xff) + ((spriteram16[offs+4] & 0xc0) << 2);
+
+ if (zoom != 0xFF || code!=0)
+ {
+ int size = spriteram16[offs+1];
+ int idx = (size >> 3) & 7;
+ int w, h;
+
+ w = sprite_data[idx].width;
+ h = sprite_data[idx].height;
+ code = code * 8 * 16 / (w * h);
+ char_type = sprite_data[idx].char_type;
+ if (sprite_dirty[idx][code] == 1)
+ {
+ decodechar(machine->gfx[char_type],code,(UINT8 *)nemesis_characterram,
+ machine->drv->gfxdecodeinfo[char_type].gfxlayout);
+ sprite_dirty[idx][code] = 0;
+ }
+ }
+ }
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( nemesis )
+{
+ int offs;
+
+ update_gfx(machine);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ tilemap_set_scrolly( background, 0, (nemesis_yscroll[0x180] & 0xff) );
+
+ for (offs = 0;offs < 256;offs++)
+ {
+ tilemap_set_scrollx( background, offs,
+ (nemesis_xscroll2[offs] & 0xff) + ((nemesis_xscroll2[0x100 + offs] & 0x01) << 8) - (flipscreen ? 0x107 : 0) );
+ tilemap_set_scrollx( foreground, offs,
+ (nemesis_xscroll1[offs] & 0xff) + ((nemesis_xscroll1[0x100 + offs] & 0x01) << 8) - (flipscreen ? 0x107 : 0) );
+ }
+
+ tilemap_draw(bitmap,cliprect,background,0,1);
+ tilemap_draw(bitmap,cliprect,foreground,0,2);
+ tilemap_draw(bitmap,cliprect,background,1,4);
+ tilemap_draw(bitmap,cliprect,foreground,1,8);
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( salamand )
+{
+ int offs;
+ rectangle clip;
+
+ update_gfx(machine);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ clip.min_x = 0;
+ clip.max_x = 255;
+
+ tilemap_set_scroll_cols( background, 64 );
+ tilemap_set_scroll_cols( foreground, 64 );
+ tilemap_set_scroll_rows( background, 1 );
+ tilemap_set_scroll_rows( foreground, 1 );
+
+ for (offs = 0; offs < 64; offs++)
+ {
+ tilemap_set_scrolly( background, offs, nemesis_yscroll1[offs] );
+ tilemap_set_scrolly( foreground, offs, nemesis_yscroll2[offs] );
+ }
+
+ for (offs = cliprect->min_y; offs <= cliprect->max_y; offs++)
+ {
+ clip.min_y = offs;
+ clip.max_y = offs;
+
+ tilemap_set_scrollx( background, 0,
+ ((nemesis_xscroll2[offs] & 0xff) + ((nemesis_xscroll2[0x100 + offs] & 1) << 8)) );
+ tilemap_set_scrollx( foreground, 0,
+ ((nemesis_xscroll1[offs] & 0xff) + ((nemesis_xscroll1[0x100 + offs] & 1) << 8)) );
+
+ tilemap_draw(bitmap,&clip,foreground,0,1);
+ tilemap_draw(bitmap,&clip,background,0,2);
+ tilemap_draw(bitmap,&clip,foreground,1,4);
+ tilemap_draw(bitmap,&clip,background,1,8);
+ }
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/neogeo.c b/src/mame/video/neogeo.c
new file mode 100644
index 00000000000..eb537fa419d
--- /dev/null
+++ b/src/mame/video/neogeo.c
@@ -0,0 +1,931 @@
+/***************************************************************************
+
+ Neo-Geo hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "neogeo.h"
+#include "video/resnet.h"
+
+
+#define NUM_PENS (0x1000)
+
+
+static UINT8 *sprite_gfx;
+static UINT32 sprite_gfx_address_mask;
+static UINT16 *neogeo_videoram;
+static UINT16 *palettes[2]; /* 0x100*16 2 byte palette entries */
+static pen_t *pens;
+static UINT8 palette_bank;
+static UINT8 screen_dark;
+static UINT16 videoram_read_buffer;
+static UINT16 videoram_modulo;
+static UINT16 videoram_offset;
+
+static UINT8 fixed_layer_source;
+int neogeo_fixed_layer_bank_type; /* no need to state save */
+
+static UINT8 auto_animation_speed;
+static UINT8 auto_animation_disabled;
+static UINT8 auto_animation_counter;
+static UINT8 auto_animation_frame_counter;
+static emu_timer *auto_animation_timer;
+
+static emu_timer *sprite_line_timer;
+
+
+
+/*************************************
+ *
+ * Video RAM access
+ *
+ *************************************/
+
+static void set_videoram_offset(UINT16 data)
+{
+ videoram_offset = data;
+
+ /* the read happens right away */
+ videoram_read_buffer = neogeo_videoram[videoram_offset];
+}
+
+
+static UINT16 get_videoram_data(void)
+{
+ return videoram_read_buffer;
+}
+
+
+static void set_videoram_data(UINT16 data)
+{
+ neogeo_videoram[videoram_offset] = data;
+
+ /* auto increment/decrement the current offset - A15 is NOT effected */
+ videoram_offset = (videoram_offset & 0x8000) | ((videoram_offset + videoram_modulo) & 0x7fff);
+
+ /* read next value right away */
+ videoram_read_buffer = neogeo_videoram[videoram_offset];
+}
+
+
+static void set_videoram_modulo(UINT16 data)
+{
+ videoram_modulo = data;
+}
+
+
+static UINT16 get_videoram_modulo(void)
+{
+ return videoram_modulo;
+}
+
+
+
+/*************************************
+ *
+ * Palette handling
+ *
+ *************************************/
+
+static double rgb_weights_normal[5];
+static double rgb_weights_normal_bit15[5];
+static double rgb_weights_dark[5];
+static double rgb_weights_dark_bit15[5];
+
+static void compute_rgb_weights(void)
+{
+ static const int resistances[] = { 220, 470, 1000, 2200, 3900 };
+
+ /* compute four sets of weights - with or without the pulldowns -
+ ensuring that we use the same scaler for all */
+
+ double scaler = compute_resistor_weights(0, 0xff, -1,
+ 5, resistances, rgb_weights_normal, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0);
+
+ compute_resistor_weights(0, 0xff, scaler,
+ 5, resistances, rgb_weights_normal_bit15, 8200, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0);
+
+ compute_resistor_weights(0, 0xff, scaler,
+ 5, resistances, rgb_weights_dark, 150, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0);
+
+ compute_resistor_weights(0, 0xff, scaler,
+ 5, resistances, rgb_weights_dark_bit15, 1 / ((1.0 / 8200) + (1.0 / 150)), 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0);
+}
+
+
+static pen_t get_pen(UINT16 data)
+{
+ double *weights;
+ UINT8 r, g, b;
+
+ if (screen_dark)
+ {
+ if (data & 0x8000)
+ weights = rgb_weights_dark_bit15;
+ else
+ weights = rgb_weights_dark;
+ }
+ else
+ {
+ if (data & 0x8000)
+ weights = rgb_weights_normal_bit15;
+ else
+ weights = rgb_weights_normal;
+ }
+
+ r = combine_5_weights(weights,
+ (data >> 11) & 0x01,
+ (data >> 10) & 0x01,
+ (data >> 9) & 0x01,
+ (data >> 8) & 0x01,
+ (data >> 14) & 0x01);
+
+ g = combine_5_weights(weights,
+ (data >> 7) & 0x01,
+ (data >> 6) & 0x01,
+ (data >> 5) & 0x01,
+ (data >> 4) & 0x01,
+ (data >> 13) & 0x01);
+
+ b = combine_5_weights(weights,
+ (data >> 3) & 0x01,
+ (data >> 2) & 0x01,
+ (data >> 1) & 0x01,
+ (data >> 0) & 0x01,
+ (data >> 12) & 0x01);
+
+ return MAKE_RGB(r, g, b);
+}
+
+
+static void regenerate_pens(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_PENS; i++)
+ pens[i] = get_pen(palettes[palette_bank][i]);
+}
+
+
+void neogeo_set_palette_bank(UINT8 data)
+{
+ if (data != palette_bank)
+ {
+ palette_bank = data;
+
+ regenerate_pens();
+ }
+}
+
+
+void neogeo_set_screen_dark(UINT8 data)
+{
+ if (data != screen_dark)
+ {
+ screen_dark = data;
+
+ regenerate_pens();
+ }
+}
+
+
+READ16_HANDLER( neogeo_paletteram_r )
+{
+ return palettes[palette_bank][offset];
+}
+
+
+WRITE16_HANDLER( neogeo_paletteram_w )
+{
+ UINT16 *addr = &palettes[palette_bank][offset];
+
+ COMBINE_DATA(addr);
+
+ pens[offset] = get_pen(*addr);
+}
+
+
+
+/*************************************
+ *
+ * Auto animation
+ *
+ *************************************/
+
+static void set_auto_animation_speed(UINT8 data)
+{
+ auto_animation_speed = data;
+}
+
+
+static void set_auto_animation_disabled(UINT8 data)
+{
+ auto_animation_disabled = data;
+}
+
+
+UINT8 neogeo_get_auto_animation_counter(void)
+{
+ return auto_animation_counter;
+}
+
+
+static TIMER_CALLBACK( auto_animation_timer_callback )
+{
+ if (auto_animation_frame_counter == 0)
+ {
+ auto_animation_frame_counter = auto_animation_speed;
+
+ auto_animation_counter = auto_animation_counter + 1;
+ }
+ else
+ auto_animation_frame_counter = auto_animation_frame_counter - 1;
+
+ timer_adjust(auto_animation_timer, video_screen_get_time_until_pos(0, NEOGEO_VSSTART, 0), 0, attotime_zero);
+}
+
+
+static void create_auto_animation_timer(void)
+{
+ auto_animation_timer = timer_alloc(auto_animation_timer_callback);
+}
+
+
+static void start_auto_animation_timer(void)
+{
+ timer_adjust(auto_animation_timer, video_screen_get_time_until_pos(0, NEOGEO_VSSTART, 0), 0, attotime_zero);
+}
+
+
+
+/*************************************
+ *
+ * Fixed layer
+ *
+ *************************************/
+
+void neogeo_set_fixed_layer_source(UINT8 data)
+{
+ fixed_layer_source = data;
+}
+
+
+static void draw_fixed_layer(mame_bitmap *bitmap, int scanline)
+{
+ int x;
+
+ UINT8* gfx_base = memory_region(fixed_layer_source ? NEOGEO_REGION_FIXED_LAYER_CARTRIDGE : NEOGEO_REGION_FIXED_LAYER_BIOS);
+ UINT32 addr_mask = memory_region_length(fixed_layer_source ? NEOGEO_REGION_FIXED_LAYER_CARTRIDGE : NEOGEO_REGION_FIXED_LAYER_BIOS) - 1;
+ UINT16 *video_data = &neogeo_videoram[0x7000 | (scanline >> 3)];
+ UINT32 *pixel_addr = BITMAP_ADDR32(bitmap, scanline, NEOGEO_HBEND);
+
+int garouoffsets[32];
+int banked = fixed_layer_source && (addr_mask > 0x1ffff);
+{
+/* thanks to Mr K for the garou & kof2000 banking info */
+/* Build line banking table for Garou & MS3 before starting render */
+if (banked && neogeo_fixed_layer_bank_type == 1)
+{
+ int garoubank = 0;
+ int k = 0;
+ int y = 0;
+ while (y < 32)
+ {
+ if (neogeo_videoram[0x7500+k] == 0x0200 && (neogeo_videoram[0x7580+k] & 0xff00) == 0xff00)
+ {
+ garoubank = neogeo_videoram[0x7580+k] & 3;
+ garouoffsets[y++] = garoubank;
+ }
+ garouoffsets[y++] = garoubank;
+ k += 2;
+ }
+}
+}
+
+ for (x = 0; x < 40; x++)
+ {
+ UINT16 code_and_palette = *video_data;
+
+ UINT16 code = code_and_palette & 0x0fff;
+
+if (banked)
+{
+ int y = scanline >> 3;
+ switch (neogeo_fixed_layer_bank_type)
+ {
+ case 1:
+ /* Garou, MSlug 3 */
+ code += 0x1000 * (garouoffsets[(y-2)&31] ^ 3);
+ break;
+ case 2:
+ code += 0x1000 * (((neogeo_videoram[0x7500 + ((y-1)&31) + 32 * (x/6)] >> (5-(x%6))*2) & 3) ^ 3);
+ break;
+ }
+}
+
+ {
+ UINT8 data = 0;
+ int i;
+
+ UINT8 *gfx = &gfx_base[((code << 5) | (scanline & 0x07)) & addr_mask];
+ pen_t *char_pens = &pens[code_and_palette >> 12 << 4];
+
+ for (i = 0; i < 8; i++)
+ {
+ static const UINT32 pix_offsets[] = { 0x10, 0x18, 0x00, 0x08 };
+
+ if (i & 0x01)
+ data = data >> 4;
+ else
+ data = gfx[pix_offsets[i >> 1]];
+
+ if (data & 0x0f)
+ *pixel_addr = char_pens[data & 0x0f];
+
+ pixel_addr++;
+ }
+ }
+
+ video_data = video_data + 0x20;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Sprite hardware
+ *
+ *************************************/
+
+#define MAX_SPRITES_PER_SCREEN (381)
+#define MAX_SPRITES_PER_LINE (96)
+
+
+/* horizontal zoom table - verified on real hardware */
+static const int zoom_x_tables[][16] =
+{
+ { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0 },
+ { 0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0 },
+ { 0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0 },
+ { 0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0 },
+ { 0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0 },
+ { 0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0 },
+ { 0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0 },
+ { 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0 },
+ { 1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0 },
+ { 1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0 },
+ { 1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1 },
+ { 1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1 },
+ { 1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1 },
+ { 1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1 },
+ { 1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1 },
+ { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }
+};
+
+
+INLINE int rows_to_height(int rows)
+{
+ if ((rows == 0) || (rows > 0x20))
+ rows = 0x20;
+
+ return rows * 0x10;
+}
+
+
+INLINE int sprite_on_scanline(int scanline, int y, int rows)
+{
+ /* check if the current scanline falls inside this sprite,
+ two possible scenerios, wrap around or not */
+ int max_y = (y + rows_to_height(rows) - 1) & 0x1ff;
+
+ return (((max_y >= y) && (scanline >= y) && (scanline <= max_y)) ||
+ ((max_y < y) && ((scanline >= y) || (scanline <= max_y))));
+}
+
+
+static void draw_sprites(bitmap_t *bitmap, int scanline)
+{
+ int sprite_index;
+ int max_sprite_index;
+
+ int y = 0;
+ int x = 0;
+ int rows = 0;
+ int zoom_y = 0;
+ int zoom_x = 0;
+ UINT16 *sprite_list;
+
+ /* select the active list */
+ if (scanline & 0x01)
+ sprite_list = &neogeo_videoram[0x8680];
+ else
+ sprite_list = &neogeo_videoram[0x8600];
+
+ /* optimization -- find last non-zero entry and only draw that many +1
+ sprite. This is not 100% correct as the hardware will keep drawing
+ the #0 sprite over and over, but we need the speed */
+ for (max_sprite_index = (MAX_SPRITES_PER_LINE - 1); max_sprite_index >= 0; max_sprite_index--)
+ {
+ if (sprite_list[max_sprite_index] != 0)
+ break;
+ }
+
+ /* add the +1 now, just in case the 0 at the end is real sprite */
+ if (max_sprite_index != (MAX_SPRITES_PER_LINE - 1))
+ max_sprite_index = max_sprite_index + 1;
+
+ for (sprite_index = 0; sprite_index <= max_sprite_index; sprite_index++)
+ {
+ UINT16 sprite_number = sprite_list[sprite_index] & 0x01ff;
+
+ UINT16 y_control = neogeo_videoram[0x8200 | sprite_number];
+ UINT16 zoom_control = neogeo_videoram[0x8000 | sprite_number];
+
+ /* if chained, go to next X coordinate and get new X zoom */
+ if (y_control & 0x40)
+ {
+ x = (x + zoom_x + 1) & 0x01ff;
+ zoom_x = (zoom_control >> 8) & 0x0f;
+ }
+ /* new block */
+ else
+ {
+ y = 0x200 - (y_control >> 7);
+ x = neogeo_videoram[0x8400 | sprite_number] >> 7;
+ zoom_y = zoom_control & 0xff;
+ zoom_x = (zoom_control >> 8) & 0x0f;
+ rows = y_control & 0x3f;
+ }
+
+ /* skip if falls completely outside the screen */
+ if ((x >= 0x140) && (x <= 0x1f0))
+ continue;
+
+ /* double check the Y coordinate, in case somebody modified the sprite coordinate
+ since we buffered it */
+ if (sprite_on_scanline(scanline, y, rows))
+ {
+ int sprite_y;
+ int tile;
+ UINT8 sprite_y_and_tile;
+ offs_t attr_and_code_offs;
+ UINT16 attr;
+ UINT32 code;
+ const int *zoom_x_table;
+ UINT8 *gfx;
+ pen_t *line_pens;
+ int x_inc;
+
+ int sprite_line = (scanline - y) & 0x1ff;
+ int zoom_line = sprite_line & 0xff;
+ int invert = sprite_line & 0x100;
+
+ if (invert)
+ zoom_line ^= 0xff;
+
+ if (rows > 0x20)
+ {
+ zoom_line = zoom_line % ((zoom_y + 1) << 1);
+
+ if (zoom_line > zoom_y)
+ {
+ zoom_line = ((zoom_y + 1) << 1) - 1 - zoom_line;
+ invert = !invert;
+ }
+ }
+
+ sprite_y_and_tile = memory_region(NEOGEO_REGION_ZOOM_Y_TABLE)[(zoom_y << 8) | zoom_line];
+ sprite_y = sprite_y_and_tile & 0x0f;
+ tile = sprite_y_and_tile >> 4;
+
+ if (invert)
+ {
+ sprite_y ^= 0x0f;
+ tile ^= 0x1f;
+ }
+
+ attr_and_code_offs = (sprite_number << 6) | (tile << 1);
+ attr = neogeo_videoram[attr_and_code_offs + 1];
+ code = ((attr << 12) & 0x70000) | neogeo_videoram[attr_and_code_offs];
+
+ /* substitute auto animation bits */
+ if (!auto_animation_disabled)
+ {
+ if (attr & 0x0008)
+ code = (code & ~0x07) | (auto_animation_counter & 0x07);
+ else if (attr & 0x0004)
+ code = (code & ~0x03) | (auto_animation_counter & 0x03);
+ }
+
+ /* vertical flip? */
+ if (attr & 0x0002)
+ sprite_y ^= 0x0f;
+
+ zoom_x_table = zoom_x_tables[zoom_x];
+
+ /* compute offset in gfx ROM and mask it to the number of bits available */
+ gfx = &sprite_gfx[((code << 8) | (sprite_y << 4)) & sprite_gfx_address_mask];
+
+ line_pens = &pens[attr >> 8 << 4];
+
+ /* horizontal flip? */
+ if (attr & 0x0001)
+ {
+ gfx = gfx + 0x0f;
+ x_inc = -1;
+ }
+ else
+ x_inc = 1;
+
+ /* draw the line - no wrap-around */
+ if (x <= 0x01f0)
+ {
+ int i;
+
+ UINT32 *pixel_addr = BITMAP_ADDR32(bitmap, scanline, x + NEOGEO_HBEND);
+
+ for (i = 0; i < 0x10; i++)
+ {
+ if (*zoom_x_table)
+ {
+ if (*gfx)
+ *pixel_addr = line_pens[*gfx];
+
+ pixel_addr++;
+ }
+
+ zoom_x_table++;
+ gfx += x_inc;
+ }
+ }
+ /* wrap-around */
+ else
+ {
+ int i;
+
+ int x_save = x;
+ UINT32 *pixel_addr = BITMAP_ADDR32(bitmap, scanline, NEOGEO_HBEND);
+
+ for (i = 0; i < 0x10; i++)
+ {
+ if (*zoom_x_table)
+ {
+ if (x >= 0x200)
+ {
+ if (*gfx)
+ *pixel_addr = line_pens[*gfx];
+
+ pixel_addr++;
+ }
+
+ x++;
+ }
+
+ zoom_x_table++;
+ gfx += x_inc;
+ }
+
+ x = x_save;
+ }
+ }
+ }
+}
+
+
+static void parse_sprites(int scanline)
+{
+ UINT16 sprite_number;
+ int y = 0;
+ int rows = 0;
+ UINT16 *sprite_list;
+
+ int active_sprite_count = 0;
+
+ /* select the active list */
+ if (scanline & 0x01)
+ sprite_list = &neogeo_videoram[0x8680];
+ else
+ sprite_list = &neogeo_videoram[0x8600];
+
+ /* scan all sprites */
+ for (sprite_number = 0; sprite_number < MAX_SPRITES_PER_SCREEN; sprite_number++)
+ {
+ UINT16 y_control = neogeo_videoram[0x8200 | sprite_number];
+
+ /* if not chained, get Y position and height, otherwise use previous values */
+ if (~y_control & 0x40)
+ {
+ y = 0x200 - (y_control >> 7);
+ rows = y_control & 0x3f;
+ }
+
+ /* skip sprites with 0 rows */
+ if (rows == 0)
+ continue;
+
+ if (!sprite_on_scanline(scanline, y, rows))
+ continue;
+
+ /* sprite is on this scanline, add it to active list */
+ *sprite_list = sprite_number;
+
+ sprite_list++;
+
+ /* increment sprite count, and if we reached the max, bail out */
+ active_sprite_count++;
+
+ if (active_sprite_count == MAX_SPRITES_PER_LINE)
+ break;
+ }
+
+ /* fill the rest of the sprite list with 0, including one extra entry */
+ for (; active_sprite_count <= MAX_SPRITES_PER_LINE ; active_sprite_count++)
+ {
+ *sprite_list = 0;
+
+ sprite_list++;
+ }
+}
+
+
+static TIMER_CALLBACK( sprite_line_timer_callback )
+{
+ int scanline = param;
+
+ /* we are at the beginning of a scanline -
+ we need to draw the previous scanline and parse the sprites on the current one */
+ if (scanline != 0)
+ video_screen_update_partial(0, scanline - 1);
+
+ parse_sprites(scanline);
+
+ /* let's come back at the beginning of the next line */
+ scanline = (scanline + 1) % NEOGEO_VTOTAL;
+
+ timer_adjust(sprite_line_timer, video_screen_get_time_until_pos(0, scanline, 0), scanline, attotime_zero);
+}
+
+
+static void create_sprite_line_timer(void)
+{
+ sprite_line_timer = timer_alloc(sprite_line_timer_callback);
+}
+
+
+static void start_sprite_line_timer(void)
+{
+ timer_adjust(sprite_line_timer, video_screen_get_time_until_pos(0, 0, 0), 0, attotime_zero);
+}
+
+
+static void optimize_sprite_data(void)
+{
+ /* convert the sprite graphics data into a format that
+ allows faster blitting */
+ int i;
+ UINT8 *src;
+ UINT8 *dest;
+ UINT32 bit;
+
+ /* get mask based on the length rounded up to the nearest
+ power of 2 */
+ sprite_gfx_address_mask = 0xffffffff;
+
+ for (bit = 0x80000000; bit != 0; bit >>= 1)
+ {
+ if (((memory_region_length(NEOGEO_REGION_SPRITES) * 2) - 1) & bit)
+ break;
+
+ sprite_gfx_address_mask >>= 1;
+ }
+
+ sprite_gfx = auto_malloc(sprite_gfx_address_mask + 1);
+ memset(sprite_gfx, 0, sprite_gfx_address_mask + 1);
+
+ src = memory_region(NEOGEO_REGION_SPRITES);
+ dest = sprite_gfx;
+
+ for (i = 0; i < memory_region_length(NEOGEO_REGION_SPRITES); i += 0x80, src += 0x80)
+ {
+ int y;
+
+ for (y = 0; y < 0x10; y++)
+ {
+ int x;
+
+ for (x = 0; x < 8; x++)
+ {
+ *(dest++) = (((src[0x43 | (y << 2)] >> x) & 0x01) << 3) |
+ (((src[0x41 | (y << 2)] >> x) & 0x01) << 2) |
+ (((src[0x42 | (y << 2)] >> x) & 0x01) << 1) |
+ (((src[0x40 | (y << 2)] >> x) & 0x01) << 0);
+ }
+
+ for (x = 0; x < 8; x++)
+ {
+ *(dest++) = (((src[0x03 | (y << 2)] >> x) & 0x01) << 3) |
+ (((src[0x01 | (y << 2)] >> x) & 0x01) << 2) |
+ (((src[0x02 | (y << 2)] >> x) & 0x01) << 1) |
+ (((src[0x00 | (y << 2)] >> x) & 0x01) << 0);
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video control
+ *
+ *************************************/
+
+static UINT16 get_video_control(void)
+{
+ UINT16 ret;
+ UINT16 v_counter;
+
+ /*
+ The format of this very important location is: AAAA AAAA A??? BCCC
+
+ A is the raster line counter. mosyougi relies solely on this to do the
+ raster effects on the title screen; sdodgeb loops waiting for the top
+ bit to be 1; zedblade heavily depends on it to work correctly (it
+ checks the top bit in the IRQ2 handler).
+ B is definitely a PAL/NTSC flag. Evidence:
+ 1) trally changes the position of the speed indicator depending on
+ it (0 = lower 1 = higher).
+ 2) samsho3 sets a variable to 60 when the bit is 0 and 50 when it's 1.
+ This is obviously the video refresh rate in Hz.
+ 3) samsho3 sets another variable to 256 or 307. This could be the total
+ screen height (including vblank), or close to that.
+ Some games (e.g. lstbld2, samsho3) do this (or similar):
+ bclr #$0, $3c000e.l
+ when the bit is set, so 3c000e (whose function is unknown) has to be
+ related
+ C animation counter lower 3 bits
+ */
+
+ /* the vertical counter chain goes from 0xf8 - 0x1ff */
+ v_counter = video_screen_get_vpos(0) + 0x100;
+
+ if (v_counter >= 0x200)
+ v_counter = v_counter - NEOGEO_VTOTAL;
+
+ ret = (v_counter << 7) | (neogeo_get_auto_animation_counter() & 0x0007);
+
+ if (VERBOSE) logerror("PC %06x: video_control read (%04x)\n", activecpu_get_pc(), ret);
+
+ return ret;
+}
+
+
+static void set_video_control(UINT16 data)
+{
+ /* this does much more than this, but I'm not sure exactly what */
+ if (VERBOSE) logerror("%06x: video control write %04x\n", activecpu_get_pc(), data);
+
+ set_auto_animation_speed(data >> 8);
+ set_auto_animation_disabled(data & 0x0008);
+
+ neogeo_set_display_poisition_interrupt_control(data & 0x00f0);
+}
+
+
+READ16_HANDLER( neogeo_video_register_r )
+{
+ UINT16 ret;
+
+ /* accessing the LSB only is not mapped */
+ if (mem_mask == 0xff00)
+ ret = neogeo_unmapped_r(0, 0) & 0x00ff;
+ else
+ {
+ switch (offset)
+ {
+ default:
+ case 0x00:
+ case 0x01: ret = get_videoram_data(); break;
+ case 0x02: ret = get_videoram_modulo(); break;
+ case 0x03: ret = get_video_control(); break;
+ }
+ }
+
+ return ret;
+}
+
+
+WRITE16_HANDLER( neogeo_video_register_w )
+{
+ /* accessing the LSB only is not mapped */
+ if (mem_mask != 0xff00)
+ {
+ /* accessing the MSB only stores same data in MSB and LSB */
+ if (mem_mask == 0x00ff)
+ data = (data & 0xff00) | (data >> 8);
+
+ switch (offset)
+ {
+ case 0x00: set_videoram_offset(data); break;
+ case 0x01: set_videoram_data(data); break;
+ case 0x02: set_videoram_modulo(data); break;
+ case 0x03: set_video_control(data); break;
+ case 0x04: neogeo_set_display_counter_msb(data); break;
+ case 0x05: neogeo_set_display_counter_lsb(data); break;
+ case 0x06: neogeo_acknowledge_interrupt(data); break;
+ case 0x07: break; /* unknown, see get_video_control */
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( neogeo )
+{
+ /* allocate memory not directly mapped */
+ palettes[0] = auto_malloc(NUM_PENS * sizeof(UINT16));
+ palettes[1] = auto_malloc(NUM_PENS * sizeof(UINT16));
+ pens = auto_malloc(NUM_PENS * sizeof(pen_t));
+ neogeo_videoram = auto_malloc(0x20000);
+
+ compute_rgb_weights();
+ create_sprite_line_timer();
+ create_auto_animation_timer();
+ optimize_sprite_data();
+
+ /* initialize values that are not modified on a reset */
+ videoram_read_buffer = 0;
+ videoram_offset = 0;
+ videoram_modulo = 0;
+ auto_animation_speed = 0;
+ auto_animation_disabled = 0;
+ auto_animation_counter = 0;
+ auto_animation_frame_counter = 0;
+
+ /* register for state saving */
+ state_save_register_global_pointer(palettes[0], NUM_PENS);
+ state_save_register_global_pointer(palettes[1], NUM_PENS);
+ state_save_register_global_pointer(neogeo_videoram, 0x20000/2);
+ state_save_register_global(videoram_read_buffer);
+ state_save_register_global(videoram_modulo);
+ state_save_register_global(videoram_offset);
+ state_save_register_global(fixed_layer_source);
+ state_save_register_global(screen_dark);
+ state_save_register_global(palette_bank);
+ state_save_register_global(auto_animation_speed);
+ state_save_register_global(auto_animation_disabled);
+ state_save_register_global(auto_animation_counter);
+ state_save_register_global(auto_animation_frame_counter);
+
+ state_save_register_func_postload(regenerate_pens);
+}
+
+
+
+/*************************************
+ *
+ * Video system reset
+ *
+ *************************************/
+
+VIDEO_RESET( neogeo )
+{
+ start_sprite_line_timer();
+ start_auto_animation_timer();
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( neogeo )
+{
+ /* fill with background color first */
+ fillbitmap(bitmap, pens[0x0fff], cliprect);
+
+ draw_sprites(bitmap, cliprect->min_y);
+
+ draw_fixed_layer(bitmap, cliprect->min_y);
+
+ return 0;
+}
diff --git a/src/mame/video/news.c b/src/mame/video/news.c
new file mode 100644
index 00000000000..560c4b5f8db
--- /dev/null
+++ b/src/mame/video/news.c
@@ -0,0 +1,103 @@
+#include "driver.h"
+#include "news.h"
+
+
+UINT8 *news_fgram;
+UINT8 *news_bgram;
+
+static int bgpic;
+static tilemap *fg_tilemap, *bg_tilemap;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = (news_fgram[tile_index*2] << 8) | news_fgram[tile_index*2+1];
+ SET_TILE_INFO(
+ 0,
+ code & 0x0fff,
+ (code & 0xf000) >> 12,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = (news_bgram[tile_index*2] << 8) | news_bgram[tile_index*2+1];
+ int color = (code & 0xf000) >> 12;
+
+ code &= 0x0fff;
+ if ((code & 0x0e00) == 0x0e00) code = (code & 0x1ff) | (bgpic << 9);
+
+ SET_TILE_INFO(
+ 0,
+ code,
+ color,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( news )
+{
+
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32, 32);
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32, 32);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( news_fgram_w )
+{
+ news_fgram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset/2);
+}
+
+WRITE8_HANDLER( news_bgram_w )
+{
+ news_bgram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+WRITE8_HANDLER( news_bgpic_w )
+{
+ if (bgpic != data)
+ {
+ bgpic = data;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( news )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/ninjakd2.c b/src/mame/video/ninjakd2.c
new file mode 100644
index 00000000000..469dc76334a
--- /dev/null
+++ b/src/mame/video/ninjakd2.c
@@ -0,0 +1,158 @@
+#include "driver.h"
+
+UINT8 *ninjakd2_bg_videoram, *ninjakd2_fg_videoram;
+
+static UINT8 ninjakd2_bg_enable = 1, sprite_overdraw_enabled = 0;
+static UINT16 ninjakd2_scrollx, ninjakd2_scrolly;
+static tilemap *fg_tilemap, *bg_tilemap;
+static mame_bitmap *bitmap_sp; /* for sprite overdraw */
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = ((ninjakd2_bg_videoram[tile_index*2 + 1] & 0xc0) << 2) | ninjakd2_bg_videoram[tile_index*2];
+ int color = ninjakd2_bg_videoram[tile_index*2 + 1] & 0xf;
+ SET_TILE_INFO(0, code, color, TILE_FLIPYX((ninjakd2_bg_videoram[tile_index*2 + 1] & 0x30) >> 4));
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = ((ninjakd2_fg_videoram[tile_index*2 + 1] & 0xc0) << 2) | ninjakd2_fg_videoram[tile_index*2];
+ int color = ninjakd2_fg_videoram[tile_index*2 + 1] & 0xf;
+ SET_TILE_INFO(2, code, color, TILE_FLIPYX((ninjakd2_fg_videoram[tile_index*2 + 1] & 0x30) >> 4));
+}
+
+VIDEO_START( ninjakd2 )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 15);
+
+ bitmap_sp = auto_bitmap_alloc (machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+}
+
+WRITE8_HANDLER( ninjakd2_bgvideoram_w )
+{
+ ninjakd2_bg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset >> 1);
+}
+
+WRITE8_HANDLER( ninjakd2_fgvideoram_w )
+{
+ ninjakd2_fg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset >> 1);
+}
+
+WRITE8_HANDLER( ninjakd2_scrollx_w )
+{
+ if(offset)
+ ninjakd2_scrollx = ((ninjakd2_scrollx & 0x0ff) | data*256) & 0x1ff;
+ else
+ ninjakd2_scrollx = ((ninjakd2_scrollx & 0x100) | data) & 0x1ff;
+}
+
+WRITE8_HANDLER( ninjakd2_scrolly_w )
+{
+ if(offset)
+ ninjakd2_scrolly = ((ninjakd2_scrolly & 0x0ff) | data*256) & 0x1ff;
+ else
+ ninjakd2_scrolly = ((ninjakd2_scrolly & 0x100) | data) & 0x1ff;
+}
+
+WRITE8_HANDLER( ninjakd2_background_enable_w )
+{
+ ninjakd2_bg_enable = data & 1;
+}
+
+WRITE8_HANDLER( ninjakd2_sprite_overdraw_w )
+{
+ sprite_overdraw_enabled = data & 1;
+
+ if(sprite_overdraw_enabled)
+ fillbitmap(bitmap_sp, 15, &Machine->screen[0].visarea);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ /* Draw the sprites */
+
+ for (offs = 11 ;offs < spriteram_size; offs+=16)
+ {
+ int sx,sy,tile,color,flipx,flipy;
+
+ if (spriteram[offs+2] & 2)
+ {
+ sx = spriteram[offs+1];
+ sy = spriteram[offs];
+ if (spriteram[offs+2] & 1) sx-=256;
+ tile = spriteram[offs+3]+((spriteram[offs+2] & 0xc0)<<2);
+ flipx = spriteram[offs+2] & 0x10;
+ flipy = spriteram[offs+2] & 0x20;
+ color = spriteram[offs+4] & 0x0f;
+
+ if(sprite_overdraw_enabled && (color >= 0x0c && color <= 0x0e) )
+ {
+ /* "static" sprites */
+ drawgfx(bitmap_sp,machine->gfx[1],
+ tile,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN, 15);
+ }
+ else
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ tile,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN, 15);
+
+ /* "normal" sprites with color = 0x0f clear the "static" ones */
+ if(sprite_overdraw_enabled && color == 0x0f)
+ {
+ int x,y,offset = 0;
+ const gfx_element *gfx = machine->gfx[1];
+ UINT8 *srcgfx = gfx->gfxdata + tile * gfx->char_modulo;
+
+ for(y = 0; y < gfx->height; y++)
+ {
+ for(x = 0; x < gfx->width; x++)
+ {
+ if(srcgfx[offset] != 15)
+ {
+ *BITMAP_ADDR16(bitmap_sp, sy + y, sx + x) = 15;
+ }
+
+ offset++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(sprite_overdraw_enabled)
+ copybitmap(bitmap, bitmap_sp, 0, 0, 0, 0, cliprect, TRANSPARENCY_PEN, 15);
+}
+
+VIDEO_UPDATE( ninjakd2 )
+{
+ fillbitmap(bitmap, machine->pens[0],0);
+
+ tilemap_set_scrollx(bg_tilemap, 0, ninjakd2_scrollx);
+ tilemap_set_scrolly(bg_tilemap, 0, ninjakd2_scrolly);
+
+ if (ninjakd2_bg_enable)
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+
+ return 0;
+}
diff --git a/src/mame/video/ninjakid.c b/src/mame/video/ninjakid.c
new file mode 100644
index 00000000000..fa620866c15
--- /dev/null
+++ b/src/mame/video/ninjakid.c
@@ -0,0 +1,302 @@
+#include "driver.h"
+#include "sound/ay8910.h"
+
+static tilemap *bg_tilemap, *fg_tilemap;
+static UINT8 flipscreen;
+static UINT8 ninjakun_xscroll,ninjakun_yscroll;
+
+static UINT8 ninjakun_io_8000_ctrl[4];
+// static UINT8 old_scroll;
+
+/*******************************************************************************
+ Tilemap Callbacks
+*******************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info ){
+ UINT32 tile_number = videoram[tile_index] & 0xFF;
+ UINT8 attr = videoram[tile_index+0x400];
+ tile_number += (attr & 0x20) << 3; /* bank */
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ (attr&0xf),
+ 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info ){
+ UINT32 tile_number = videoram[tile_index+0x800] & 0xFF;
+ UINT8 attr = videoram[tile_index+0xc00];
+ tile_number += (attr & 0xC0) << 2; /* bank */
+ SET_TILE_INFO(
+ 1,
+ tile_number,
+ (attr&0xf),
+ 0);
+}
+
+WRITE8_HANDLER( ninjakid_fg_videoram_w ){
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset&0x3ff);
+}
+
+WRITE8_HANDLER( ninjakid_bg_videoram_w ){
+
+ int y = (offset + ((ninjakun_yscroll & 0xf8) << 2) ) & 0x3e0;
+ int x = (offset + (ninjakun_xscroll >> 3) ) & 0x1f;
+ int offs = x+y+(offset & 0x400);
+
+ videoram[0x800+offs] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,x+y);
+}
+
+READ8_HANDLER( ninjakid_bg_videoram_r )
+{
+ int y = (offset + ((ninjakun_yscroll & 0xf8) << 2) ) & 0x3e0;
+ int x = (offset + (ninjakun_xscroll >> 3) ) & 0x1f;
+ int offs = x+y+(offset & 0x400);
+
+ return videoram[0x800+offs];
+}
+
+/******************************************************************************/
+
+WRITE8_HANDLER( ninjakun_flipscreen_w ){
+ flipscreen = data?(TILEMAP_FLIPX|TILEMAP_FLIPY):0;
+ tilemap_set_flip( ALL_TILEMAPS,flipscreen );
+}
+
+READ8_HANDLER( ninjakun_io_8000_r ){
+ switch( offset ){
+ case 0: /* control */
+ return AY8910_read_port_0_r( 0 );
+
+ case 1: /* input read */
+ switch( ninjakun_io_8000_ctrl[0] ){
+ case 0xf:
+ return readinputport(4);
+ case 0xe:
+ return readinputport(3);
+ default:
+ return ninjakun_io_8000_ctrl[1];
+ }
+ break;
+
+ case 2: /* control */
+ return AY8910_read_port_1_r( 0 );
+
+ case 3: /* data */
+ return ninjakun_io_8000_ctrl[3];
+ }
+
+// logerror("PC=%04x; RAM[0x800%d]\n",activecpu_get_pc(),offset);
+ return 0xFF;
+}
+
+/* static void handle_scrolly( UINT8 new_scroll ){ */
+
+/* HACK!!!
+**
+** New rows are always written at fixed locations above and below the background
+** tilemaps, rather than at the logical screen boundaries with respect to scrolling.
+**
+** I don't know how this is handled by the actual NinjaKun hardware, but the
+** following is a crude approximation, yielding a playable game.
+*/
+
+/*
+ int old_row = old_scroll/8;
+ int new_row = new_scroll/8;
+ int i;
+ if( new_scroll!=old_scroll ){
+ tilemap_set_scrolly( bg_tilemap, 0, new_scroll&7 );
+
+ if ((new_row == ((old_row - 1) & 0xff)) || ((!old_row) && (new_row == 0x1f)))
+ {
+ for( i=0x400-0x21; i>=0; i-- ){
+ ninjakid_bg_videoram_w( i+0x20, videoram[0x800+i] );
+ }
+ }
+ else if ((new_row == ((old_row + 1) & 0xff)) || ((old_row == 0x1f) && (!new_row)))
+ {
+ for( i=0x20; i<0x400; i++ ){
+ ninjakid_bg_videoram_w( i-0x20, videoram[0x800+i] );
+ }
+ }
+
+ old_scroll = new_scroll;
+ }
+}
+*/
+
+
+WRITE8_HANDLER( ninjakun_io_8000_w ){
+ switch( offset ){
+ case 0x0: /* control#1 */
+ ninjakun_io_8000_ctrl[0] = data;
+ AY8910_control_port_0_w( 0, data );
+ break;
+
+ case 0x1: /* data#1 */
+ ninjakun_io_8000_ctrl[1] = data;
+ switch( ninjakun_io_8000_ctrl[0] ){
+ default:
+ AY8910_write_port_0_w( 0,data );
+ break;
+ }
+ break;
+
+ case 0x2: /* control#2 */
+ ninjakun_io_8000_ctrl[2] = data;
+ AY8910_control_port_1_w( 0, data );
+ break;
+
+ case 0x3: /* data#2 */
+ ninjakun_io_8000_ctrl[3] = data;
+ switch( ninjakun_io_8000_ctrl[2] ){
+ case 0xf:
+ tilemap_set_scrolly( bg_tilemap, 0, data );
+ ninjakun_yscroll = data;
+ break;
+ case 0xe:
+ if (flipscreen == 0)
+ tilemap_set_scrollx( bg_tilemap, 0, data-7 );
+ else
+ tilemap_set_scrollx( bg_tilemap, 0, data );
+ ninjakun_xscroll = data;
+ break;
+ default:
+ AY8910_write_port_1_w( 0,data );
+ }
+ break;
+ }
+}
+
+WRITE8_HANDLER( ninjakun_paletteram_w )
+{
+ int i;
+
+ paletteram_BBGGRRII_w(offset,data);
+
+ if (offset > 15)
+ return;
+
+ if (offset != 1)
+ {
+ for (i=0; i<16; i++)
+ {
+ paletteram_BBGGRRII_w(0x200+offset+i*16,data);
+ }
+ }
+ paletteram_BBGGRRII_w(0x200+offset*16+1,data);
+}
+
+/*******************************************************************************
+ Video Hardware Functions
+********************************************************************************
+ vh_start / vh_refresh
+*******************************************************************************/
+
+VIDEO_START( ninjakid ){
+ fg_tilemap = tilemap_create( get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+ bg_tilemap = tilemap_create( get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+ tilemap_set_transparent_pen( fg_tilemap,0 );
+
+ /* Save State Support */
+
+ state_save_register_global_array(ninjakun_io_8000_ctrl);
+ state_save_register_global(flipscreen);
+// state_save_register_global(old_scroll);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect ){
+ const UINT8 *source = spriteram;
+ const UINT8 *finish = source+0x800;
+
+ const gfx_element *gfx = machine->gfx[2];
+
+ while( source<finish ){
+ int tile_number = source[0];
+ int sx = source[1];
+ int sy = source[2];
+ int attr = source[3];
+ int flipx = attr&0x10;
+ int flipy = attr&0x20;
+ int color = attr&0x0f;
+
+ if( flipscreen ){
+ sx = 240-sx;
+ sy = 240-sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(
+ bitmap,
+ gfx,
+ tile_number,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN,0
+ );
+ if (sx>240)
+ drawgfx(
+ bitmap,
+ gfx,
+ tile_number,
+ color,
+ flipx,flipy,
+ sx-256,sy,
+ cliprect,
+ TRANSPARENCY_PEN,0
+ );
+
+ source+=0x20;
+ }
+}
+
+VIDEO_UPDATE( ninjakid )
+{
+ int offs,chr,col,px,py,x,y;
+
+ tilemap_draw( bitmap,cliprect,bg_tilemap,0,0 );
+ tilemap_draw( bitmap,cliprect,fg_tilemap,0,0 );
+ draw_sprites( machine, bitmap,cliprect );
+
+ for (y=4; y<28; y++)
+ {
+ for (x=0; x<32; x++)
+ {
+ offs = y*32+x;
+ chr = videoram[offs];
+ col = videoram[offs + 0x400];
+ chr += (col & 0x20) << 3;
+
+ if ((col & 0x10) == 0)
+ {
+
+ if (flipscreen==0)
+ {
+ px = 8*x;
+ py = 8*y;
+ }
+ else
+ {
+ px = 248-8*x;
+ py = 248-8*y;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ chr,
+ col & 0x0f,
+ flipscreen,flipscreen,
+ px,py,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+
+
+ return 0;
+}
diff --git a/src/mame/video/ninjaw.c b/src/mame/video/ninjaw.c
new file mode 100644
index 00000000000..6af356c5d87
--- /dev/null
+++ b/src/mame/video/ninjaw.c
@@ -0,0 +1,169 @@
+#include "driver.h"
+#include "video/taitoic.h"
+
+#define TC0100SCN_GFX_NUM 1
+
+struct tempsprite
+{
+ int gfx;
+ int code,color;
+ int flipx,flipy;
+ int x,y;
+ int zoomx,zoomy;
+ int primask;
+};
+static struct tempsprite *spritelist;
+
+static int taito_hide_pixels;
+
+
+
+/**********************************************************/
+
+static VIDEO_START( ninjaw_core )
+{
+ int chips;
+
+ spritelist = auto_malloc(0x1000 * sizeof(*spritelist));
+
+ chips = number_of_TC0100SCN();
+
+ assert_always(chips > 0, "we have an erroneous TC0100SCN configuration");
+
+ TC0100SCN_vh_start(machine,chips,TC0100SCN_GFX_NUM,taito_hide_pixels,0,0,0,0,0,0);
+
+ if (has_TC0110PCR())
+ TC0110PCR_vh_start();
+
+ if (has_second_TC0110PCR())
+ TC0110PCR_1_vh_start();
+
+ if (has_third_TC0110PCR())
+ TC0110PCR_2_vh_start();
+
+ /* Ensure palette from correct TC0110PCR used for each screen */
+ TC0100SCN_set_chip_colbanks(0x0,0x100,0x200);
+}
+
+VIDEO_START( ninjaw )
+{
+ taito_hide_pixels = 22;
+ video_start_ninjaw_core(machine);
+}
+
+/************************************************************
+ SPRITE DRAW ROUTINE
+************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int primask,int x_offs,int y_offs)
+{
+ int offs, data, tilenum, color, flipx, flipy;
+ int x, y, priority, invis, curx, cury;
+ int code;
+
+#ifdef MAME_DEBUG
+ int unknown=0;
+#endif
+
+ /* pdrawgfx() needs us to draw sprites front to back, so we have to build a list
+ while processing sprite ram and then draw them all at the end */
+ struct tempsprite *sprite_ptr = spritelist;
+
+ for (offs = (spriteram_size/2)-4;offs >=0;offs -= 4)
+ {
+ data = spriteram16[offs+2];
+ tilenum = data & 0x7fff;
+
+ if (!tilenum) continue;
+
+ data = spriteram16[offs+0];
+// x = (data - 8) & 0x3ff;
+ x = (data - 32) & 0x3ff; /* aligns sprites on rock outcrops and sewer hole */
+
+ data = spriteram16[offs+1];
+ y = (data - 0) & 0x1ff;
+
+ /* don't know meaning of "invis" bit (Darius: explosions of your bomb shots) */
+ data = spriteram16[offs+3];
+ flipx = (data & 0x1);
+ flipy = (data & 0x2) >> 1;
+ priority = (data & 0x4) >> 2; // 1 = low
+ if (priority != primask) continue;
+ invis = (data & 0x8) >> 3;
+ color = (data & 0x7f00) >> 8;
+
+ /* Ninjaw: this stops your player flickering black and cutting into tank sprites */
+ if (invis) continue;
+
+#ifdef MAME_DEBUG
+ if (data & 0x80f0) unknown |= (data &0x80f0);
+#endif
+
+ x -= x_offs;
+ y += y_offs;
+
+ /* sprite wrap: coords become negative at high values */
+ if (x>0x3c0) x -= 0x400;
+ if (y>0x180) y -= 0x200;
+
+ curx = x;
+ cury = y;
+ code = tilenum;
+
+ sprite_ptr->code = code;
+ sprite_ptr->color = color;
+ sprite_ptr->flipx = flipx;
+ sprite_ptr->flipy = flipy;
+ sprite_ptr->x = curx;
+ sprite_ptr->y = cury;
+
+ drawgfx(bitmap,machine->gfx[0],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+#ifdef MAME_DEBUG
+ if (unknown)
+ popmessage("unknown sprite bits: %04x",unknown);
+#endif
+}
+
+
+/**************************************************************
+ SCREEN REFRESH
+**************************************************************/
+
+VIDEO_UPDATE( ninjaw )
+{
+ int xoffs = 36*8*screen;
+
+ UINT8 layer[3], nodraw;
+
+ TC0100SCN_tilemap_update(machine);
+
+ layer[0] = TC0100SCN_bottomlayer(0);
+ layer[1] = layer[0]^1;
+ layer[2] = 2;
+
+ /* chip 0 does tilemaps on the left, chip 1 center, chip 2 the right */
+ // draw bottom layer
+ nodraw = TC0100SCN_tilemap_draw(machine,bitmap,cliprect,screen,layer[0],TILEMAP_DRAW_OPAQUE,0); /* left */
+
+ /* Ensure screen blanked even when bottom layers not drawn due to disable bit */
+ if (nodraw) fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ /* Sprites can be under/over the layer below text layer */
+ draw_sprites(machine,bitmap,cliprect,1,xoffs,8); // draw sprites with priority 1 which are under the mid layer
+
+ // draw middle layer
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,screen,layer[1],0,0);
+
+ draw_sprites(machine,bitmap,cliprect,0,xoffs,8); // draw sprites with priority 0 which are over the mid layer
+
+ // draw top(text) layer
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,screen,layer[2],0,0);
+ return 0;
+}
diff --git a/src/mame/video/nitedrvr.c b/src/mame/video/nitedrvr.c
new file mode 100644
index 00000000000..4411488da8f
--- /dev/null
+++ b/src/mame/video/nitedrvr.c
@@ -0,0 +1,81 @@
+/***************************************************************************
+
+ Atari Night Driver hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/nitedrvr.h"
+
+UINT8 *nitedrvr_hvc;
+
+static tilemap *bg_tilemap;
+
+WRITE8_HANDLER( nitedrvr_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( nitedrvr_hvc_w )
+{
+ nitedrvr_hvc[offset & 0x3f] = data;
+
+ if ((offset & 0x30) == 0x30)
+ watchdog_reset_w(0, 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] & 0x3f;
+
+ SET_TILE_INFO(0, code, 0, 0);
+}
+
+
+
+VIDEO_START( nitedrvr )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_box(running_machine *machine, mame_bitmap *bitmap, int bx, int by, int ex, int ey )
+{
+ int x, y;
+
+ for (y = by; y < ey; y++)
+ {
+ for (x = bx; x < ex; x++)
+ {
+ if ((y < 256) && (x < 256))
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[1];
+ }
+ }
+
+ return;
+}
+
+static void draw_roadway(running_machine *machine, mame_bitmap *bitmap)
+{
+ int roadway;
+
+ for (roadway = 0; roadway < 16; roadway++)
+ {
+ int bx, by, ex, ey;
+
+ bx = nitedrvr_hvc[roadway];
+ by = nitedrvr_hvc[roadway + 16];
+ ex = bx + ((nitedrvr_hvc[roadway + 32] & 0xf0) >> 4);
+ ey = by + (16 - (nitedrvr_hvc[roadway + 32] & 0x0f));
+
+ draw_box(machine, bitmap, bx, by, ex, ey);
+ }
+}
+
+VIDEO_UPDATE( nitedrvr )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_roadway(machine, bitmap);
+ return 0;
+}
diff --git a/src/mame/video/niyanpai.c b/src/mame/video/niyanpai.c
new file mode 100644
index 00000000000..f447cc8a4f6
--- /dev/null
+++ b/src/mame/video/niyanpai.c
@@ -0,0 +1,454 @@
+/******************************************************************************
+
+ Video Hardware for Nichibutsu Mahjong series.
+
+ Driver by Takahiro Nogi <nogi@kt.rim.or.jp> 2000/12/23 -
+
+******************************************************************************/
+
+#include "driver.h"
+
+
+#define VRAM_MAX 3
+
+
+static int niyanpai_scrollx[VRAM_MAX], niyanpai_scrolly[VRAM_MAX];
+static int blitter_destx[VRAM_MAX], blitter_desty[VRAM_MAX];
+static int blitter_sizex[VRAM_MAX], blitter_sizey[VRAM_MAX];
+static int blitter_src_addr[VRAM_MAX];
+static int blitter_direction_x[VRAM_MAX], blitter_direction_y[VRAM_MAX];
+static int niyanpai_dispflag[VRAM_MAX];
+static int niyanpai_flipscreen[VRAM_MAX];
+static int niyanpai_clutmode[VRAM_MAX];
+static int niyanpai_transparency[VRAM_MAX];
+static int niyanpai_clutsel[VRAM_MAX];
+static int niyanpai_screen_refresh;
+static int nb19010_busyctr;
+static int nb19010_busyflag;
+
+static mame_bitmap *niyanpai_tmpbitmap[VRAM_MAX];
+static UINT16 *niyanpai_videoram[VRAM_MAX];
+static UINT16 *niyanpai_videoworkram[VRAM_MAX];
+static UINT16 *niyanpai_palette;
+static UINT8 *niyanpai_clut[VRAM_MAX];
+
+
+static void niyanpai_vramflip(int vram);
+static void niyanpai_gfxdraw(int vram);
+
+
+/******************************************************************************
+
+
+******************************************************************************/
+READ16_HANDLER( niyanpai_palette_r )
+{
+ return niyanpai_palette[offset];
+}
+
+WRITE16_HANDLER( niyanpai_palette_w )
+{
+ int r, g, b;
+ int offs_h, offs_l;
+ UINT16 oldword = niyanpai_palette[offset];
+ UINT16 newword;
+
+ COMBINE_DATA(&niyanpai_palette[offset]);
+ newword = niyanpai_palette[offset];
+
+ if (oldword != newword)
+ {
+ offs_h = (offset / 0x180);
+ offs_l = (offset & 0x7f);
+
+ if (ACCESSING_MSB16)
+ {
+ r = ((niyanpai_palette[(0x000 + (offs_h * 0x180) + offs_l)] & 0xff00) >> 8);
+ g = ((niyanpai_palette[(0x080 + (offs_h * 0x180) + offs_l)] & 0xff00) >> 8);
+ b = ((niyanpai_palette[(0x100 + (offs_h * 0x180) + offs_l)] & 0xff00) >> 8);
+
+ palette_set_color(Machine, ((offs_h << 8) + (offs_l << 1) + 0), MAKE_RGB(r, g, b));
+ }
+
+ if (ACCESSING_LSB16)
+ {
+ r = ((niyanpai_palette[(0x000 + (offs_h * 0x180) + offs_l)] & 0x00ff) >> 0);
+ g = ((niyanpai_palette[(0x080 + (offs_h * 0x180) + offs_l)] & 0x00ff) >> 0);
+ b = ((niyanpai_palette[(0x100 + (offs_h * 0x180) + offs_l)] & 0x00ff) >> 0);
+
+ palette_set_color(Machine, ((offs_h << 8) + (offs_l << 1) + 1), MAKE_RGB(r, g, b));
+ }
+ }
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+static int niyanpai_blitter_r(int vram, int offset)
+{
+ int ret;
+ UINT8 *GFXROM = memory_region(REGION_GFX1);
+
+ switch (offset)
+ {
+ case 0x00: ret = 0xfe | ((nb19010_busyflag & 0x01) ^ 0x01); break; // NB19010 Busy Flag
+ case 0x01: ret = GFXROM[blitter_src_addr[vram]]; break; // NB19010 GFX-ROM Read
+ default: ret = 0xff; break;
+ }
+
+ return ret;
+}
+
+static void niyanpai_blitter_w(int vram, int offset, int data)
+{
+ switch (offset)
+ {
+ case 0x00: blitter_direction_x[vram] = (data & 0x01) ? 1 : 0;
+ blitter_direction_y[vram] = (data & 0x02) ? 1 : 0;
+ niyanpai_clutmode[vram] = (data & 0x04) ? 1 : 0;
+ // if (data & 0x08) popmessage("Unknown GFX Flag!! (0x08)");
+ niyanpai_transparency[vram] = (data & 0x10) ? 1 : 0;
+ // if (data & 0x20) popmessage("Unknown GFX Flag!! (0x20)");
+ niyanpai_flipscreen[vram] = (data & 0x40) ? 0 : 1;
+ niyanpai_dispflag[vram] = (data & 0x80) ? 1 : 0;
+ niyanpai_vramflip(vram);
+ break;
+ case 0x01: niyanpai_scrollx[vram] = (niyanpai_scrollx[vram] & 0x0100) | data; break;
+ case 0x02: niyanpai_scrollx[vram] = (niyanpai_scrollx[vram] & 0x00ff) | ((data << 8) & 0x0100); break;
+ case 0x03: niyanpai_scrolly[vram] = (niyanpai_scrolly[vram] & 0x0100) | data; break;
+ case 0x04: niyanpai_scrolly[vram] = (niyanpai_scrolly[vram] & 0x00ff) | ((data << 8) & 0x0100); break;
+ case 0x05: blitter_src_addr[vram] = (blitter_src_addr[vram] & 0xffff00) | data; break;
+ case 0x06: blitter_src_addr[vram] = (blitter_src_addr[vram] & 0xff00ff) | (data << 8); break;
+ case 0x07: blitter_src_addr[vram] = (blitter_src_addr[vram] & 0x00ffff) | (data << 16); break;
+ case 0x08: blitter_sizex[vram] = data; break;
+ case 0x09: blitter_sizey[vram] = data; break;
+ case 0x0a: blitter_destx[vram] = (blitter_destx[vram] & 0xff00) | data; break;
+ case 0x0b: blitter_destx[vram] = (blitter_destx[vram] & 0x00ff) | (data << 8); break;
+ case 0x0c: blitter_desty[vram] = (blitter_desty[vram] & 0xff00) | data; break;
+ case 0x0d: blitter_desty[vram] = (blitter_desty[vram] & 0x00ff) | (data << 8);
+ niyanpai_gfxdraw(vram);
+ break;
+ default: break;
+ }
+}
+
+static void niyanpai_clutsel_w(int vram, int data)
+{
+ niyanpai_clutsel[vram] = data;
+}
+
+static void niyanpai_clut_w(int vram, int offset, int data)
+{
+ niyanpai_clut[vram][((niyanpai_clutsel[vram] & 0xff) * 0x10) + (offset & 0x0f)] = data;
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+static void niyanpai_vramflip(int vram)
+{
+ static int niyanpai_flipscreen_old[VRAM_MAX] = { 0, 0, 0 };
+ int x, y;
+ UINT16 color1, color2;
+
+ if (niyanpai_flipscreen[vram] == niyanpai_flipscreen_old[vram]) return;
+
+ for (y = 0; y < (Machine->screen[0].height / 2); y++)
+ {
+ for (x = 0; x < Machine->screen[0].width; x++)
+ {
+ color1 = niyanpai_videoram[vram][(y * Machine->screen[0].width) + x];
+ color2 = niyanpai_videoram[vram][((y ^ 0x1ff) * Machine->screen[0].width) + (x ^ 0x3ff)];
+ niyanpai_videoram[vram][(y * Machine->screen[0].width) + x] = color2;
+ niyanpai_videoram[vram][((y ^ 0x1ff) * Machine->screen[0].width) + (x ^ 0x3ff)] = color1;
+ }
+ }
+
+ for (y = 0; y < (Machine->screen[0].height / 2); y++)
+ {
+ for (x = 0; x < Machine->screen[0].width; x++)
+ {
+ color1 = niyanpai_videoworkram[vram][(y * Machine->screen[0].width) + x];
+ color2 = niyanpai_videoworkram[vram][((y ^ 0x1ff) * Machine->screen[0].width) + (x ^ 0x3ff)];
+ niyanpai_videoworkram[vram][(y * Machine->screen[0].width) + x] = color2;
+ niyanpai_videoworkram[vram][((y ^ 0x1ff) * Machine->screen[0].width) + (x ^ 0x3ff)] = color1;
+ }
+ }
+
+ niyanpai_flipscreen_old[vram] = niyanpai_flipscreen[vram];
+ niyanpai_screen_refresh = 1;
+}
+
+static void update_pixel(int vram, int x, int y)
+{
+ UINT16 color = niyanpai_videoram[vram][(y * Machine->screen[0].width) + x];
+ *BITMAP_ADDR16(niyanpai_tmpbitmap[vram], y, x) = Machine->pens[color];
+}
+
+static TIMER_CALLBACK( blitter_timer_callback )
+{
+ nb19010_busyflag = 1;
+}
+
+static void niyanpai_gfxdraw(int vram)
+{
+ UINT8 *GFX = memory_region(REGION_GFX1);
+
+ int x, y;
+ int dx1, dx2, dy;
+ int startx, starty;
+ int sizex, sizey;
+ int skipx, skipy;
+ int ctrx, ctry;
+ UINT16 color, color1, color2;
+ int gfxaddr;
+
+ nb19010_busyctr = 0;
+
+ if (niyanpai_clutmode[vram])
+ {
+ // NB22090 clut256 mode
+ blitter_sizex[vram] = GFX[((blitter_src_addr[vram] + 0) & 0x00ffffff)];
+ blitter_sizey[vram] = GFX[((blitter_src_addr[vram] + 1) & 0x00ffffff)];
+ }
+
+ if (blitter_direction_x[vram])
+ {
+ startx = blitter_destx[vram];
+ sizex = blitter_sizex[vram];
+ skipx = 1;
+ }
+ else
+ {
+ startx = blitter_destx[vram] + blitter_sizex[vram];
+ sizex = blitter_sizex[vram];
+ skipx = -1;
+ }
+
+ if (blitter_direction_y[vram])
+ {
+ starty = blitter_desty[vram];
+ sizey = blitter_sizey[vram];
+ skipy = 1;
+ }
+ else
+ {
+ starty = blitter_desty[vram] + blitter_sizey[vram];
+ sizey = blitter_sizey[vram];
+ skipy = -1;
+ }
+
+ gfxaddr = ((blitter_src_addr[vram] + 2) & 0x00ffffff);
+
+ for (y = starty, ctry = sizey; ctry >= 0; y += skipy, ctry--)
+ {
+ for (x = startx, ctrx = sizex; ctrx >= 0; x += skipx, ctrx--)
+ {
+ if ((gfxaddr > (memory_region_length(REGION_GFX1) - 1)))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM ADDR OVER:%08X DX,%d,DY:%d,SX:%d,SY:%d", gfxaddr, startx, starty, sizex,sizey);
+ logerror("GFXROM ADDR OVER:%08X DX,%d,DY:%d,SX:%d,SY:%d\n", gfxaddr, startx, starty, sizex,sizey);
+#endif
+ gfxaddr &= (memory_region_length(REGION_GFX1) - 1);
+ }
+
+ color = GFX[gfxaddr++];
+
+ dx1 = (2 * x + 0) & 0x3ff;
+ dx2 = (2 * x + 1) & 0x3ff;
+ dy = y & 0x1ff;
+
+ if (!niyanpai_flipscreen[vram])
+ {
+ dx1 ^= 0x3ff;
+ dx2 ^= 0x3ff;
+ dy ^= 0x1ff;
+ }
+
+ if (blitter_direction_x[vram])
+ {
+ // flip
+ color1 = (color & 0x0f) >> 0;
+ color2 = (color & 0xf0) >> 4;
+ }
+ else
+ {
+ // normal
+ color1 = (color & 0xf0) >> 4;
+ color2 = (color & 0x0f) >> 0;
+ }
+
+ if (niyanpai_clutmode[vram])
+ {
+ // clut256 mode
+
+ if (niyanpai_clutsel[vram] & 0x80)
+ {
+ // clut256 mode 1st(low)
+ niyanpai_videoworkram[vram][(dy * Machine->screen[0].width) + dx1] &= 0x00f0;
+ niyanpai_videoworkram[vram][(dy * Machine->screen[0].width) + dx1] |= color1 & 0x0f;
+ niyanpai_videoworkram[vram][(dy * Machine->screen[0].width) + dx2] &= 0x00f0;
+ niyanpai_videoworkram[vram][(dy * Machine->screen[0].width) + dx2] |= color2 & 0x0f;
+
+ continue;
+ }
+ else
+ {
+ // clut256 mode 2nd(high)
+ niyanpai_videoworkram[vram][(dy * Machine->screen[0].width) + dx1] &= 0x000f;
+ niyanpai_videoworkram[vram][(dy * Machine->screen[0].width) + dx1] |= (color1 & 0x0f) << 4;
+ niyanpai_videoworkram[vram][(dy * Machine->screen[0].width) + dx2] &= 0x000f;
+ niyanpai_videoworkram[vram][(dy * Machine->screen[0].width) + dx2] |= (color2 & 0x0f) << 4;
+
+ // niyanpai_videoworkram[vram][(dy * Machine->screen[0].width) + dx1] += niyanpai_clut[vram][(niyanpai_clutsel[vram] * 0x10)];
+ // niyanpai_videoworkram[vram][(dy * Machine->screen[0].width) + dx2] += niyanpai_clut[vram][(niyanpai_clutsel[vram] * 0x10)];
+ }
+
+ color1 = niyanpai_videoworkram[vram][(dy * Machine->screen[0].width) + dx1];
+ color2 = niyanpai_videoworkram[vram][(dy * Machine->screen[0].width) + dx2];
+ }
+ else
+ {
+ // clut16 mode
+ color1 = niyanpai_clut[vram][(niyanpai_clutsel[vram] * 0x10) + color1];
+ color2 = niyanpai_clut[vram][(niyanpai_clutsel[vram] * 0x10) + color2];
+ }
+
+ color1 |= (0x0100 * vram);
+ color2 |= (0x0100 * vram);
+
+ if (((color1 & 0x00ff) != 0x00ff) || (!niyanpai_transparency[vram]))
+ {
+ niyanpai_videoram[vram][(dy * Machine->screen[0].width) + dx1] = color1;
+ update_pixel(vram, dx1, dy);
+ }
+ if (((color2 & 0x00ff) != 0x00ff) || (!niyanpai_transparency[vram]))
+ {
+ niyanpai_videoram[vram][(dy * Machine->screen[0].width) + dx2] = color2;
+ update_pixel(vram, dx2, dy);
+ }
+
+ nb19010_busyctr++;
+ }
+ }
+
+ if (niyanpai_clutmode[vram])
+ {
+ // NB22090 clut256 mode
+ blitter_src_addr[vram] = gfxaddr;
+ }
+
+ nb19010_busyflag = 0;
+ timer_set(attotime_mul(ATTOTIME_IN_NSEC(1650), nb19010_busyctr), 0, blitter_timer_callback);
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+WRITE16_HANDLER( niyanpai_blitter_0_w ) { niyanpai_blitter_w(0, offset, data); }
+WRITE16_HANDLER( niyanpai_blitter_1_w ) { niyanpai_blitter_w(1, offset, data); }
+WRITE16_HANDLER( niyanpai_blitter_2_w ) { niyanpai_blitter_w(2, offset, data); }
+
+READ16_HANDLER( niyanpai_blitter_0_r ) { return niyanpai_blitter_r(0, offset); }
+READ16_HANDLER( niyanpai_blitter_1_r ) { return niyanpai_blitter_r(1, offset); }
+READ16_HANDLER( niyanpai_blitter_2_r ) { return niyanpai_blitter_r(2, offset); }
+
+WRITE16_HANDLER( niyanpai_clut_0_w ) { niyanpai_clut_w(0, offset, data); }
+WRITE16_HANDLER( niyanpai_clut_1_w ) { niyanpai_clut_w(1, offset, data); }
+WRITE16_HANDLER( niyanpai_clut_2_w ) { niyanpai_clut_w(2, offset, data); }
+
+WRITE16_HANDLER( niyanpai_clutsel_0_w ) { niyanpai_clutsel_w(0, data); }
+WRITE16_HANDLER( niyanpai_clutsel_1_w ) { niyanpai_clutsel_w(1, data); }
+WRITE16_HANDLER( niyanpai_clutsel_2_w ) { niyanpai_clutsel_w(2, data); }
+
+/******************************************************************************
+
+
+******************************************************************************/
+VIDEO_START( niyanpai )
+{
+ niyanpai_tmpbitmap[0] = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ niyanpai_tmpbitmap[1] = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ niyanpai_tmpbitmap[2] = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ niyanpai_videoram[0] = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(short));
+ niyanpai_videoram[1] = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(short));
+ niyanpai_videoram[2] = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(short));
+ niyanpai_videoworkram[0] = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(short));
+ niyanpai_videoworkram[1] = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(short));
+ niyanpai_videoworkram[2] = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(short));
+ niyanpai_palette = auto_malloc(0x480 * sizeof(short));
+ niyanpai_clut[0] = auto_malloc(0x1000 * sizeof(char));
+ niyanpai_clut[1] = auto_malloc(0x1000 * sizeof(char));
+ niyanpai_clut[2] = auto_malloc(0x1000 * sizeof(char));
+ memset(niyanpai_videoram[0], 0x0000, (machine->screen[0].width * machine->screen[0].height * sizeof(short)));
+ memset(niyanpai_videoram[1], 0x0000, (machine->screen[0].width * machine->screen[0].height * sizeof(short)));
+ memset(niyanpai_videoram[2], 0x0000, (machine->screen[0].width * machine->screen[0].height * sizeof(short)));
+ memset(niyanpai_videoworkram[0], 0x0000, (machine->screen[0].width * machine->screen[0].height * sizeof(short)));
+ memset(niyanpai_videoworkram[1], 0x0000, (machine->screen[0].width * machine->screen[0].height * sizeof(short)));
+ memset(niyanpai_videoworkram[2], 0x0000, (machine->screen[0].width * machine->screen[0].height * sizeof(short)));
+ nb19010_busyflag = 1;
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+VIDEO_UPDATE( niyanpai )
+{
+ int i;
+ int x, y;
+ int scrollx[3], scrolly[3];
+
+ if (niyanpai_screen_refresh)
+ {
+ niyanpai_screen_refresh = 0;
+
+ for (y = 0; y < machine->screen[0].height; y++)
+ {
+ for (x = 0; x < machine->screen[0].width; x++)
+ {
+ update_pixel(0, x, y);
+ update_pixel(1, x, y);
+ update_pixel(2, x, y);
+ }
+ }
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ if (niyanpai_flipscreen[i])
+ {
+ scrollx[i] = (((-niyanpai_scrollx[i]) - 0x4e) & 0x1ff) << 1;
+ scrolly[i] = (-niyanpai_scrolly[i]) & 0x1ff;
+ }
+ else
+ {
+ scrollx[i] = (((-niyanpai_scrollx[i]) - 0x4e) & 0x1ff) << 1;
+ scrolly[i] = niyanpai_scrolly[i] & 0x1ff;
+ }
+ }
+
+ if (niyanpai_dispflag[0])
+ {
+ copyscrollbitmap(bitmap, niyanpai_tmpbitmap[0], 1, &scrollx[0], 1, &scrolly[0], &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ }
+ else
+ {
+ fillbitmap(bitmap, machine->pens[0x00ff], 0);
+ }
+
+ if (niyanpai_dispflag[1])
+ {
+ copyscrollbitmap(bitmap, niyanpai_tmpbitmap[1], 1, &scrollx[1], 1, &scrolly[1], &machine->screen[0].visarea, TRANSPARENCY_PEN, machine->pens[0x01ff]);
+ }
+
+ if (niyanpai_dispflag[2])
+ {
+ copyscrollbitmap(bitmap, niyanpai_tmpbitmap[2], 1, &scrollx[2], 1, &scrolly[2], &machine->screen[0].visarea, TRANSPARENCY_PEN, machine->pens[0x02ff]);
+ }
+ return 0;
+}
diff --git a/src/mame/video/nmk16.c b/src/mame/video/nmk16.c
new file mode 100644
index 00000000000..bd8260466ec
--- /dev/null
+++ b/src/mame/video/nmk16.c
@@ -0,0 +1,884 @@
+#include "driver.h"
+
+UINT16 *nmk_bgvideoram,*nmk_fgvideoram,*nmk_txvideoram;
+UINT16 *gunnail_scrollram;
+static UINT16 gunnail_scrolly;
+UINT16 tharrier_scroll;
+
+static int redraw_bitmap;
+
+static UINT16 *spriteram_old,*spriteram_old2;
+static int bgbank;
+static int videoshift;
+static int bioship_background_bank;
+static UINT8 bioship_scroll[4];
+
+static tilemap *bg_tilemap,*fg_tilemap,*tx_tilemap;
+static mame_bitmap *background_bitmap;
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+//not 100% right yet (check attract mode in raphero)
+static TILEMAP_MAPPER( bg_scan )
+{
+ /* logical (col,row) -> memory offset */
+
+ col = (col & 0xff) | ((col & 0x300)<<1);
+
+ return (row & 0x0f) + ((col & 0x6ff) << 4) + ((row & 0x70) << 8);
+}
+
+static TILEMAP_MAPPER( bg_scan_td2 )
+{
+ /* logical (col,row) -> memory offset */
+ return (row & 0x0f) + ((col & 0x3ff) << 4) + ((row & 0x70) << 10);
+}
+
+
+static TILE_GET_INFO( macross_get_bg_tile_info )
+{
+ int code = nmk_bgvideoram[tile_index];
+ SET_TILE_INFO(
+ 1,
+ (code & 0xfff) + (bgbank << 12),
+ code >> 12,
+ 0);
+}
+
+static TILE_GET_INFO( strahl_get_fg_tile_info )
+{
+ int code = nmk_fgvideoram[tile_index];
+ SET_TILE_INFO(
+ 3,
+ (code & 0xfff),
+ code >> 12,
+ 0);
+}
+
+static TILE_GET_INFO( macross_get_tx_tile_info )
+{
+ int code = nmk_txvideoram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ code & 0xfff,
+ code >> 12,
+ 0);
+}
+
+static TILE_GET_INFO( bjtwin_get_bg_tile_info )
+{
+ int code = nmk_bgvideoram[tile_index];
+ int bank = (code & 0x800) ? 1 : 0;
+ SET_TILE_INFO(
+ bank,
+ (code & 0x7ff) + ((bank) ? (bgbank << 11) : 0),
+ code >> 12,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( bioship )
+{
+ bg_tilemap = tilemap_create(macross_get_bg_tile_info,bg_scan,TILEMAP_TYPE_PEN,16,16,256,32);
+ tx_tilemap = tilemap_create(macross_get_tx_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32,32);
+ spriteram_old = auto_malloc(spriteram_size);
+ spriteram_old2 = auto_malloc(spriteram_size);
+ background_bitmap = auto_bitmap_alloc(8192,512,machine->screen[0].format);
+
+ tilemap_set_transparent_pen(bg_tilemap,15);
+ tilemap_set_transparent_pen(tx_tilemap,15);
+ bioship_background_bank=0;
+ redraw_bitmap = 1;
+
+ memset(spriteram_old,0,spriteram_size);
+ memset(spriteram_old2,0,spriteram_size);
+
+ videoshift = 0; /* 256x224 screen, no shift */
+}
+
+VIDEO_START( strahl )
+{
+ bg_tilemap = tilemap_create(macross_get_bg_tile_info,bg_scan,TILEMAP_TYPE_PEN,16,16,256,32);
+ fg_tilemap = tilemap_create(strahl_get_fg_tile_info, bg_scan,TILEMAP_TYPE_PEN,16,16,256,32);
+ tx_tilemap = tilemap_create(macross_get_tx_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32,32);
+ spriteram_old = auto_malloc(spriteram_size);
+ spriteram_old2 = auto_malloc(spriteram_size);
+
+ tilemap_set_transparent_pen(fg_tilemap,15);
+ tilemap_set_transparent_pen(tx_tilemap,15);
+
+ memset(spriteram_old,0,spriteram_size);
+ memset(spriteram_old2,0,spriteram_size);
+
+ videoshift = 0; /* 256x224 screen, no shift */
+ background_bitmap = NULL;
+}
+
+VIDEO_START( macross )
+{
+ bg_tilemap = tilemap_create(macross_get_bg_tile_info,bg_scan,TILEMAP_TYPE_PEN,16,16,256,32);
+ tx_tilemap = tilemap_create(macross_get_tx_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32,32);
+ spriteram_old = auto_malloc(spriteram_size);
+ spriteram_old2 = auto_malloc(spriteram_size);
+
+ tilemap_set_transparent_pen(tx_tilemap,15);
+
+ memset(spriteram_old,0,spriteram_size);
+ memset(spriteram_old2,0,spriteram_size);
+
+ videoshift = 0; /* 256x224 screen, no shift */
+ background_bitmap = NULL;
+}
+
+VIDEO_START( gunnail )
+{
+ bg_tilemap = tilemap_create(macross_get_bg_tile_info,bg_scan,TILEMAP_TYPE_PEN,16,16,256,32);
+ tx_tilemap = tilemap_create(macross_get_tx_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,64,32);
+ spriteram_old = auto_malloc(spriteram_size);
+ spriteram_old2 = auto_malloc(spriteram_size);
+
+ tilemap_set_transparent_pen(tx_tilemap,15);
+ tilemap_set_scroll_rows(bg_tilemap,512);
+
+ memset(spriteram_old,0,spriteram_size);
+ memset(spriteram_old2,0,spriteram_size);
+
+ videoshift = 64; /* 384x224 screen, leftmost 64 pixels have to be retrieved */
+ /* from the other side of the tilemap (!) */
+ background_bitmap = NULL;
+}
+
+VIDEO_START( macross2 )
+{
+ bg_tilemap = tilemap_create(macross_get_bg_tile_info,bg_scan,TILEMAP_TYPE_PEN,16,16,1024,128);
+ tx_tilemap = tilemap_create(macross_get_tx_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,64,32);
+ spriteram_old = auto_malloc(spriteram_size);
+ spriteram_old2 = auto_malloc(spriteram_size);
+
+ tilemap_set_transparent_pen(tx_tilemap,15);
+
+ memset(spriteram_old,0,spriteram_size);
+ memset(spriteram_old2,0,spriteram_size);
+
+ videoshift = 64; /* 384x224 screen, leftmost 64 pixels have to be retrieved */
+ /* from the other side of the tilemap (!) */
+ background_bitmap = NULL;
+}
+
+VIDEO_START( tdragon2 )
+{
+ bg_tilemap = tilemap_create(macross_get_bg_tile_info,bg_scan_td2,TILEMAP_TYPE_PEN,16,16,1024,32);
+ tx_tilemap = tilemap_create(macross_get_tx_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,64,32);
+ spriteram_old = auto_malloc(spriteram_size);
+ spriteram_old2 = auto_malloc(spriteram_size);
+
+ tilemap_set_transparent_pen(tx_tilemap,15);
+
+ memset(spriteram_old,0,spriteram_size);
+ memset(spriteram_old2,0,spriteram_size);
+
+ videoshift = 64; /* 384x224 screen, leftmost 64 pixels have to be retrieved */
+ /* from the other side of the tilemap (!) */
+ background_bitmap = NULL;
+}
+
+VIDEO_START( bjtwin )
+{
+ bg_tilemap = tilemap_create(bjtwin_get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,64,32);
+ spriteram_old = auto_malloc(spriteram_size);
+ spriteram_old2 = auto_malloc(spriteram_size);
+
+ memset(spriteram_old,0,spriteram_size);
+ memset(spriteram_old2,0,spriteram_size);
+
+ videoshift = 64; /* 384x224 screen, leftmost 64 pixels have to be retrieved */
+ /* from the other side of the tilemap (!) */
+ background_bitmap = NULL;
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ16_HANDLER( nmk_bgvideoram_r )
+{
+ return nmk_bgvideoram[offset];
+}
+
+WRITE16_HANDLER( nmk_bgvideoram_w )
+{
+ COMBINE_DATA(&nmk_bgvideoram[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+READ16_HANDLER( nmk_fgvideoram_r )
+{
+ return nmk_fgvideoram[offset];
+}
+
+WRITE16_HANDLER( nmk_fgvideoram_w )
+{
+ int oldword = nmk_fgvideoram[offset];
+ int newword = oldword;
+ COMBINE_DATA(&newword);
+
+ if (oldword != newword)
+ {
+ nmk_fgvideoram[offset] = newword;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+ }
+}
+
+READ16_HANDLER( nmk_txvideoram_r )
+{
+ return nmk_txvideoram[offset];
+}
+
+WRITE16_HANDLER( nmk_txvideoram_w )
+{
+ COMBINE_DATA(&nmk_txvideoram[offset]);
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+static int mustang_bg_xscroll;
+
+WRITE16_HANDLER( mustang_scroll_w )
+{
+// mame_printf_debug("mustang %04x %04x %04x\n",offset,data,mem_mask);
+
+ switch (data & 0xff00)
+ {
+ case 0x0000:
+ mustang_bg_xscroll = (mustang_bg_xscroll & 0x00ff) | ((data & 0x00ff)<<8);
+ break;
+
+ case 0x0100:
+ mustang_bg_xscroll = (mustang_bg_xscroll & 0xff00) | (data & 0x00ff);
+ break;
+
+ case 0x0200:
+ break;
+
+ case 0x0300:
+ break;
+
+ default:
+ break;
+ }
+
+ tilemap_set_scrollx(bg_tilemap,0,mustang_bg_xscroll - videoshift);
+}
+
+WRITE16_HANDLER( bioshipbg_scroll_w )
+{
+ static UINT8 scroll[4];
+
+ if (ACCESSING_MSB)
+ {
+ scroll[offset] = (data >> 8) & 0xff;
+
+ if (offset & 2)
+ tilemap_set_scrolly(bg_tilemap,0,scroll[2] * 256 + scroll[3]);
+ else
+ tilemap_set_scrollx(bg_tilemap,0,scroll[0] * 256 + scroll[1] - videoshift);
+ }
+}
+
+WRITE16_HANDLER( nmk_scroll_w )
+{
+ if (ACCESSING_LSB)
+ {
+ static UINT8 scroll[4];
+
+ scroll[offset] = data & 0xff;
+
+ if (offset & 2)
+ tilemap_set_scrolly(bg_tilemap,0,scroll[2] * 256 + scroll[3]);
+ else
+ tilemap_set_scrollx(bg_tilemap,0,scroll[0] * 256 + scroll[1] - videoshift);
+ }
+}
+
+WRITE16_HANDLER( nmk_scroll_2_w )
+{
+ if (ACCESSING_LSB)
+ {
+ static UINT8 scroll[4];
+
+ scroll[offset] = data & 0xff;
+
+ if (offset & 2)
+ tilemap_set_scrolly(fg_tilemap,0,scroll[2] * 256 + scroll[3]);
+ else
+ tilemap_set_scrollx(fg_tilemap,0,scroll[0] * 256 + scroll[1] - videoshift);
+ }
+}
+
+WRITE16_HANDLER( nmk_scroll_3_w )
+{
+ COMBINE_DATA(&gunnail_scrollram[offset]);
+
+// popmessage( "scroll %04x, %04x", gunnail_scrollram[0], gunnail_scrollram[0x100]);
+
+ tilemap_set_scrollx(bg_tilemap,0,gunnail_scrollram[0]-videoshift);
+ tilemap_set_scrolly(bg_tilemap,0,gunnail_scrollram[0x100]);
+}
+
+
+WRITE16_HANDLER( vandyke_scroll_w )
+{
+ static UINT16 scroll[4];
+
+ scroll[offset] = data;
+
+ tilemap_set_scrollx(bg_tilemap,0,scroll[0] * 256 + (scroll[1] >> 8));
+ tilemap_set_scrolly(bg_tilemap,0,scroll[2] * 256 + (scroll[3] >> 8));
+}
+
+WRITE16_HANDLER( manybloc_scroll_w )
+{
+ COMBINE_DATA(&gunnail_scrollram[offset]);
+
+ tilemap_set_scrollx(bg_tilemap,0,gunnail_scrollram[0x82/2]-videoshift);
+ tilemap_set_scrolly(bg_tilemap,0,gunnail_scrollram[0xc2/2]);
+}
+
+WRITE16_HANDLER( nmk_flipscreen_w )
+{
+ if (ACCESSING_LSB)
+ flip_screen_set(data & 0x01);
+}
+
+WRITE16_HANDLER( nmk_tilebank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ if (bgbank != (data & 0xff))
+ {
+ bgbank = data & 0xff;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+ }
+}
+
+WRITE16_HANDLER( bioship_scroll_w )
+{
+ if (ACCESSING_MSB)
+ bioship_scroll[offset]=data>>8;
+}
+
+WRITE16_HANDLER( bioship_bank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ if (bioship_background_bank != data)
+ {
+ bioship_background_bank = data;
+ redraw_bitmap=1;
+ }
+ }
+}
+
+WRITE16_HANDLER( gunnail_scrollx_w )
+{
+ COMBINE_DATA(&gunnail_scrollram[offset]);
+}
+
+WRITE16_HANDLER( gunnail_scrolly_w )
+{
+ COMBINE_DATA(&gunnail_scrolly);
+}
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+extern int is_blkheart;
+
+// manybloc uses extra flip bits on the sprites, but these break other games
+
+static void nmk16_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size/2;offs += 8)
+ {
+ if ((spriteram_old2[offs] & 0x0001) || (spriteram_old2[offs] && is_blkheart))
+ {
+ int sx = (spriteram_old2[offs+4] & 0x1ff) + videoshift;
+ int sy = (spriteram_old2[offs+6] & 0x1ff);
+ int code = spriteram_old2[offs+3];
+ int color = spriteram_old2[offs+7];
+ int w = (spriteram_old2[offs+1] & 0x0f);
+ int h = ((spriteram_old2[offs+1] & 0xf0) >> 4);
+ int pri = (spriteram_old2[offs] & 0xc0) >> 6;
+ int xx,yy,x;
+ int delta = 16;
+
+ if(pri != priority)
+ continue;
+
+ if (flip_screen)
+ {
+ sx = 368 - sx;
+ sy = 240 - sy;
+ delta = -16;
+ }
+
+ yy = h;
+ do
+ {
+ x = sx;
+ xx = w;
+ do
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ color,
+ flip_screen, flip_screen,
+ ((x + 16) & 0x1ff) - 16,sy & 0x1ff,
+ cliprect,TRANSPARENCY_PEN,15);
+ code++;
+ x += delta;
+ } while (--xx >= 0);
+
+ sy += delta;
+ } while (--yy >= 0);
+ }
+ }
+}
+
+/* sprites have flipping and are not delayed 2 frames */
+static void manybloc_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size/2;offs += 8)
+ {
+ if ((spriteram16[offs] & 0x0001) || (spriteram16[offs] && is_blkheart))
+ {
+ int sx = (spriteram16[offs+4] & 0x1ff) + videoshift;
+ int sy = (spriteram16[offs+6] & 0x1ff);
+ int code = spriteram16[offs+3];
+ int color = spriteram16[offs+7];
+ int w = (spriteram16[offs+1] & 0x0f);
+ int h = ((spriteram16[offs+1] & 0xf0) >> 4);
+ int pri = (spriteram16[offs] & 0xc0) >> 6;
+ /* these would break some of the nmk games ... */
+ int flipy= ((spriteram16[offs+1] & 0x0200) >> 9);
+ int flipx = ((spriteram16[offs+1] & 0x0100) >> 8);
+
+ int xx,yy,x;
+ int delta = 16;
+
+ if(pri != priority)
+ continue;
+
+ flipx ^= flip_screen;
+ flipy ^= flip_screen;
+
+ if (flip_screen)
+ {
+ sx = 368 - sx;
+ sy = 240 - sy;
+ delta = -16;
+ }
+
+ yy = h;
+ do
+ {
+ x = sx;
+ xx = w;
+ do
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx, flipy,
+ ((x + 16) & 0x1ff) - 16,sy & 0x1ff,
+ cliprect,TRANSPARENCY_PEN,15);
+
+ code++;
+ x += delta;
+ } while (--xx >= 0);
+
+ sy += delta;
+ } while (--yy >= 0);
+ }
+ }
+}
+
+static void tharrier_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size/2;offs += 8)
+ {
+ if ((spriteram16[offs] & 0x0001) || (spriteram16[offs] && is_blkheart))
+ {
+ int sx = (spriteram16[offs+4] & 0x1ff) + videoshift;
+ int sy = (spriteram16[offs+6] & 0x1ff);
+ int code = spriteram16[offs+3];
+ int color = spriteram16[offs+7];
+ int w = (spriteram16[offs+1] & 0x0f);
+ int h = ((spriteram16[offs+1] & 0xf0) >> 4);
+ int pri = (spriteram16[offs] & 0xc0) >> 6;
+ int flipy= ((spriteram16[offs+1] & 0x0200) >> 9);
+ int flipx = ((spriteram16[offs+1] & 0x0100) >> 8);
+
+ int xx,yy,x;
+ int delta = 16;
+
+ if(pri != priority)
+ continue;
+
+ flipx ^= flip_screen;
+ flipy ^= flip_screen;
+
+ if (flip_screen)
+ {
+ sx = 368 - sx;
+ sy = 240 - sy;
+ delta = -16;
+ }
+
+ yy = h;
+ sy+=flipy?(delta*h):0;
+ do
+ {
+ x = sx+(flipx?(delta*w):0);
+
+
+ xx = w;
+ do
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx, flipy,
+ ((x + 16) & 0x1ff) - 16,sy & 0x1ff,
+ cliprect,TRANSPARENCY_PEN,15);
+
+ code++;
+ x +=delta * ( flipx?-1:1 );
+
+
+ } while (--xx >= 0);
+ sy += delta * ( flipy?-1:1);
+
+ } while (--yy >= 0);
+ }
+ }
+}
+
+VIDEO_UPDATE( macross )
+{
+ tilemap_set_scrollx(tx_tilemap,0,-videoshift);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ nmk16_draw_sprites(machine, bitmap,cliprect,3);
+ nmk16_draw_sprites(machine, bitmap,cliprect,2);
+ nmk16_draw_sprites(machine, bitmap,cliprect,1);
+ nmk16_draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+extern UINT16 *nmk16_mcu_shared_ram;
+extern UINT16 *nmk16_mcu_work_ram;
+
+/*coin setting MCU simulation*/
+static void mcu_run(UINT8 dsw_setting)
+{
+ static UINT8 read_coin;
+ static UINT8 old_value;
+ static UINT8 coina,coinb;
+ UINT8 dsw_a,dsw_b;
+ /*needed because of the uncompatibility of the dsw settings.*/
+ if(dsw_setting)
+ {
+ dsw_a = (readinputport(2+dsw_setting) & 0x7);
+ dsw_b = (readinputport(2+dsw_setting) & 0x38) >> 3;
+ }
+ else
+ {
+ dsw_a = (readinputport(2) & 0x0700) >> 8;
+ dsw_b = (readinputport(2) & 0x3800) >> 11;
+ }
+
+ read_coin = old_value;
+ old_value = readinputport(0);
+
+ if(dsw_a == 0 || dsw_b == 0)
+ nmk16_mcu_work_ram[0x000/2]|=0x4000; //free_play
+
+ if(read_coin != old_value)
+ {
+ if(!(readinputport(0) & 0x01))//COIN1
+ {
+ switch(dsw_a & 7)
+ {
+ case 1: nmk16_mcu_shared_ram[0xf00/2]+=4; break;
+ case 2: nmk16_mcu_shared_ram[0xf00/2]+=3; break;
+ case 3: nmk16_mcu_shared_ram[0xf00/2]+=2; break;
+ case 4:
+ coina++;
+ if(coina >= 4)
+ {
+ coina = 0;
+ nmk16_mcu_shared_ram[0xf00/2]++;
+ }
+ break;
+ case 5:
+ coina++;
+ if(coina >= 3)
+ {
+ coina = 0;
+ nmk16_mcu_shared_ram[0xf00/2]++;
+ }
+ break;
+ case 6:
+ coina++;
+ if(coina >= 2)
+ {
+ coina = 0;
+ nmk16_mcu_shared_ram[0xf00/2]++;
+ }
+ break;
+ case 7: nmk16_mcu_shared_ram[0xf00/2]++; break;
+ }
+ }
+
+ if(!(readinputport(0) & 0x02))//COIN2
+ {
+ switch(dsw_b & 7)
+ {
+ case 1: nmk16_mcu_shared_ram[0xf00/2]+=4; break;
+ case 2: nmk16_mcu_shared_ram[0xf00/2]+=3; break;
+ case 3: nmk16_mcu_shared_ram[0xf00/2]+=2; break;
+ case 4:
+ coinb++;
+ if(coinb >= 4)
+ {
+ coinb = 0;
+ nmk16_mcu_shared_ram[0xf00/2]++;
+ }
+ break;
+ case 5:
+ coinb++;
+ if(coinb >= 3)
+ {
+ coinb = 0;
+ nmk16_mcu_shared_ram[0xf00/2]++;
+ }
+ break;
+ case 6:
+ coinb++;
+ if(coinb >= 2)
+ {
+ coinb = 0;
+ nmk16_mcu_shared_ram[0xf00/2]++;
+ }
+ break;
+ case 7: nmk16_mcu_shared_ram[0xf00/2]++; break;
+ }
+ }
+
+ if(!(readinputport(0) & 0x04))//SERVICE_COIN
+ nmk16_mcu_shared_ram[0xf00/2]++;
+
+ if(nmk16_mcu_shared_ram[0xf00/2] >= 1 && (nmk16_mcu_work_ram[0x000/2] & 0x8000))/*enable start button*/
+ {
+ /*Start a 1-player game,but don't decrement if the player 1 is already playing*/
+ if((!(readinputport(0) & 0x08)) /*START1*/
+ && (!(nmk16_mcu_work_ram[0x000/2] & 0x0200)) /*PLAYER-1 playing*/
+ )
+ nmk16_mcu_shared_ram[0xf00/2]--;
+
+ /*Start a 2-players game,but don't decrement if the player 2 is already playing*/
+ if((!(readinputport(0) & 0x10))
+ && (!(nmk16_mcu_work_ram[0x000/2] & 0x0100))
+ )
+ {
+ if(!(nmk16_mcu_work_ram[0x000/2] & 0x0200) && nmk16_mcu_shared_ram[0xf00/2] >= 2)
+ nmk16_mcu_shared_ram[0xf00/2]-=2;
+ else
+ nmk16_mcu_shared_ram[0xf00/2]--;
+ }
+ }
+
+ if(nmk16_mcu_shared_ram[0xf00/2] > 99) nmk16_mcu_shared_ram[0xf00/2] = 99;
+ }
+}
+
+VIDEO_UPDATE( tdragon )
+{
+ mcu_run(1);
+
+ tilemap_set_scrollx(tx_tilemap,0,-videoshift);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ nmk16_draw_sprites(machine, bitmap,cliprect,3);
+ nmk16_draw_sprites(machine, bitmap,cliprect,2);
+ nmk16_draw_sprites(machine, bitmap,cliprect,1);
+ nmk16_draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( hachamf )
+{
+ mcu_run(0);
+
+ tilemap_set_scrollx(tx_tilemap,0,-videoshift);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ nmk16_draw_sprites(machine, bitmap,cliprect,3);
+ nmk16_draw_sprites(machine, bitmap,cliprect,2);
+ nmk16_draw_sprites(machine, bitmap,cliprect,1);
+ nmk16_draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( manybloc )
+{
+ tilemap_set_scrollx(tx_tilemap,0,-videoshift);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ manybloc_draw_sprites(machine, bitmap,cliprect,3);
+ manybloc_draw_sprites(machine, bitmap,cliprect,2);
+ manybloc_draw_sprites(machine, bitmap,cliprect,1);
+ manybloc_draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( tharrier )
+{
+ tilemap_set_scrollx(tx_tilemap,0,-videoshift);
+ tilemap_set_scrollx(bg_tilemap,0,tharrier_scroll);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tharrier_draw_sprites(machine, bitmap,cliprect,3);
+ tharrier_draw_sprites(machine, bitmap,cliprect,2);
+ tharrier_draw_sprites(machine, bitmap,cliprect,1);
+ tharrier_draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( gunnail )
+{
+ int i;
+
+ for (i = 0;i < 256;i++)
+ {
+ tilemap_set_scrollx(bg_tilemap,(i+gunnail_scrolly) & 0x1ff,gunnail_scrollram[0] + gunnail_scrollram[i] - videoshift);
+ }
+ tilemap_set_scrolly(bg_tilemap,0,gunnail_scrolly);
+
+ video_update_macross(machine,screen,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( bioship )
+{
+ UINT16 *tilerom = (UINT16 *)memory_region(REGION_GFX5);
+ int scrollx=-(bioship_scroll[1] + bioship_scroll[0]*256);
+ int scrolly=-(bioship_scroll[3] + bioship_scroll[2]*256);
+
+ tilemap_set_scrollx(tx_tilemap,0,-videoshift);
+
+ if (redraw_bitmap)
+ {
+ int bank = bioship_background_bank * 0x2000;
+ int sx=0, sy=0, offs;
+ redraw_bitmap=0;
+
+ /* Draw background from tile rom */
+ for (offs = 0;offs <0x1000;offs++) {
+ UINT16 data = tilerom[offs+bank];
+ int numtile = data&0xfff;
+ int color = (data&0xf000)>>12;
+
+ drawgfx(background_bitmap,machine->gfx[3],
+ numtile,
+ color,
+ 0,0, /* no flip */
+ 16*sx,16*sy,
+ 0,TRANSPARENCY_NONE,0);
+
+ data = tilerom[offs+0x1000+bank];
+ numtile = data&0xfff;
+ color = (data&0xf000)>>12;
+ drawgfx(background_bitmap,machine->gfx[3],
+ numtile,
+ color,
+ 0,0, /* no flip */
+ 16*sx,(16*sy)+256,
+ 0,TRANSPARENCY_NONE,0);
+
+ sy++;
+ if (sy==16) {sy=0; sx++;}
+ }
+ }
+
+ copyscrollbitmap(bitmap,background_bitmap,1,&scrollx,1,&scrolly,cliprect,TRANSPARENCY_NONE,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ nmk16_draw_sprites(machine, bitmap,cliprect,3);
+ nmk16_draw_sprites(machine, bitmap,cliprect,2);
+ nmk16_draw_sprites(machine, bitmap,cliprect,1);
+ nmk16_draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( strahl )
+{
+ tilemap_set_scrollx(tx_tilemap,0,-videoshift);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ nmk16_draw_sprites(machine, bitmap,cliprect,3);
+ nmk16_draw_sprites(machine, bitmap,cliprect,2);
+ nmk16_draw_sprites(machine, bitmap,cliprect,1);
+ nmk16_draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( bjtwin )
+{
+ tilemap_set_scrollx(bg_tilemap,0,-videoshift);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ nmk16_draw_sprites(machine, bitmap,cliprect,3);
+ nmk16_draw_sprites(machine, bitmap,cliprect,2);
+ nmk16_draw_sprites(machine, bitmap,cliprect,1);
+ nmk16_draw_sprites(machine, bitmap,cliprect,0);
+ return 0;
+}
+
+VIDEO_EOF( nmk )
+{
+ /* looks like sprites are *two* frames ahead */
+ memcpy(spriteram_old2,spriteram_old,spriteram_size);
+ memcpy(spriteram_old,spriteram16,spriteram_size);
+}
diff --git a/src/mame/video/nova2001.c b/src/mame/video/nova2001.c
new file mode 100644
index 00000000000..35a40e6dc4c
--- /dev/null
+++ b/src/mame/video/nova2001.c
@@ -0,0 +1,194 @@
+/*******************************************************************************
+
+ Nova 2001 - Video Description:
+ --------------------------------------------------------------------------
+
+ Foreground Playfield Chars (static)
+ character code index from first set of chars
+ Foreground Playfield color modifier RAM
+ Char colors are normally taken from the first set of 16,
+ This is the pen for "color 1" for this tile (from the first 16 pens)
+
+ Background Playfield Chars (scrolling)
+ character code index from second set of chars
+ Foreground Playfield color modifier RAM
+ Char colors are normally taken from the second set of 16,
+ This is the pen for "color 1" for this tile (from the second 16 pens)
+ (Scrolling in controlled via the 8910 A and B port outputs)
+
+ Sprite memory is made of 32 byte records:
+
+ Sprite+0, 0x80 = Sprite Bank
+ Sprite+0, 0x7f = Sprite Character Code
+ Sprite+1, 0xff = X location
+ Sprite+2, 0xff = Y location
+ Sprite+3, 0x20 = Y Flip
+ Sprite+3, 0x10 = X Flip
+ Sprite+3, 0x0f = pen for "color 1" taken from the first 16 colors
+ Sprite+3, 0x80
+ Sprite+3, 0x40
+
+ All the rest are unknown and/or uneccessary.
+
+*******************************************************************************/
+
+#include "driver.h"
+
+UINT8 *nova2001_videoram2, *nova2001_colorram2;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+PALETTE_INIT( nova2001 )
+{
+ int i,j;
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int intensity,r,g,b;
+
+
+ intensity = (*color_prom >> 0) & 0x03;
+ /* red component */
+ r = (((*color_prom >> 0) & 0x0c) | intensity) * 0x11;
+ /* green component */
+ g = (((*color_prom >> 2) & 0x0c) | intensity) * 0x11;
+ /* blue component */
+ b = (((*color_prom >> 4) & 0x0c) | intensity) * 0x11;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* Color #1 is used for palette animation. */
+
+ /* To handle this, color entries 0-15 are based on */
+ /* the primary 16 colors, while color entries 16-31 */
+ /* are based on the secondary set. */
+
+ /* The only difference among 0-15 and 16-31 is that */
+ /* color #1 changes each time */
+
+ for (i = 0;i < 16;i++)
+ {
+ for (j = 0;j < 16;j++)
+ {
+ if (j == 1)
+ {
+ colortable[16*i+1] = i;
+ colortable[16*i+16*16+1] = i+16;
+ }
+ else
+ {
+ colortable[16*i+j] = j;
+ colortable[16*i+16*16+j] = j+16;
+ }
+ }
+ }
+}
+
+WRITE8_HANDLER( nova2001_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( nova2001_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( nova2001_videoram2_w )
+{
+ nova2001_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( nova2001_colorram2_w )
+{
+ nova2001_colorram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( nova2001_scroll_x_w )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, data - (flip_screen ? 0 : 7));
+}
+
+WRITE8_HANDLER( nova2001_scroll_y_w )
+{
+ tilemap_set_scrolly(bg_tilemap, 0, data);
+}
+
+WRITE8_HANDLER( nova2001_flipscreen_w )
+{
+ if (flip_screen != (~data & 0x01))
+ {
+ flip_screen_set(~data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index];
+ int color = colorram[tile_index] & 0x0f;
+
+ SET_TILE_INFO(1, code, color, 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = nova2001_videoram2[tile_index];
+ int color = nova2001_colorram2[tile_index] & 0x0f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( nova2001 )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 32)
+ {
+ int flipx = spriteram[offs+3] & 0x10;
+ int flipy = spriteram[offs+3] & 0x20;
+ int sx = spriteram[offs+1];
+ int sy = spriteram[offs+2];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[2 + ((spriteram[offs+0] & 0x80) >> 7)],
+ spriteram[offs+0] & 0x7f,
+ spriteram[offs+3] & 0x0f,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( nova2001 )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/nycaptor.c b/src/mame/video/nycaptor.c
new file mode 100644
index 00000000000..d6eb5106bd7
--- /dev/null
+++ b/src/mame/video/nycaptor.c
@@ -0,0 +1,309 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+#include "driver.h"
+
+#ifdef MAME_DEBUG
+ int nycaptor_mask=0;
+#endif
+
+static tilemap *bg_tilemap;
+static int char_bank,palette_bank,gfxctrl;
+
+UINT8 *nycaptor_scrlram;
+
+static UINT8 *nycaptor_spriteram;
+extern UINT8 *nycaptor_sharedram;
+extern int nyc_gametype;
+
+/*
+ 298 (e298) - spot (0-3) , 299 (e299) - lives
+ spot number isn't set to 0 in main menu ; lives - yes
+ sprites in main menu req priority 'type' 0
+*/
+static int nycaptor_spot(void)
+{
+ if(nyc_gametype==0 || nyc_gametype==2)
+ return nycaptor_sharedram[0x299]?nycaptor_sharedram[0x298]:0;
+ else
+ return 0;
+}
+
+WRITE8_HANDLER(nycaptor_spriteram_w)
+{
+ nycaptor_spriteram[offset]=data;
+}
+
+READ8_HANDLER(nycaptor_spriteram_r)
+{
+ return nycaptor_spriteram[offset];
+}
+
+static TILE_GET_INFO( get_tile_info )
+{
+ int pal;
+ tileinfo->category = (videoram[tile_index*2 + 1] & 0x30)>>4;
+ pal=videoram[tile_index*2+1]&0x0f;
+ tileinfo->group=0;
+ if((!nycaptor_spot())&&(pal==6))tileinfo->group=1;
+ if(((nycaptor_spot()==3)&&(pal==8))||((nycaptor_spot()==1)&&(pal==0xc)))tileinfo->group=2;
+ if((nycaptor_spot()==1)&&(tileinfo->category==2))tileinfo->group=3;
+#ifdef MAME_DEBUG
+ if(nycaptor_mask&(1<<tileinfo->category))
+ {
+ if(nycaptor_spot())pal=0xe;else pal=4;
+ }
+#endif
+
+ SET_TILE_INFO(
+ 0,
+ videoram[tile_index*2] + ((videoram[tile_index*2+1] & 0xc0) << 2) +0x400 * char_bank,
+ pal,0
+ );
+}
+
+
+VIDEO_START( nycaptor )
+{
+ nycaptor_spriteram = auto_malloc (160);
+ bg_tilemap = tilemap_create( get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+
+ tilemap_set_transmask(bg_tilemap,0,0xf800,0x7ff); //split 0
+ tilemap_set_transmask(bg_tilemap,1,0xfe00,0x01ff);//split 1
+ tilemap_set_transmask(bg_tilemap,2,0xfffc,0x0003);//split 2
+ tilemap_set_transmask(bg_tilemap,3,0xfff0,0x000f);//split 3
+
+ paletteram = auto_malloc(0x200);
+ paletteram_2 = auto_malloc(0x200);
+ tilemap_set_scroll_cols(bg_tilemap,32);
+ video_start_generic(machine);
+}
+
+WRITE8_HANDLER( nycaptor_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset>>1);
+}
+
+READ8_HANDLER( nycaptor_videoram_r )
+{
+ return videoram[offset];
+}
+
+WRITE8_HANDLER( nycaptor_palette_w )
+{
+ if(nyc_gametype==2) //colt
+ return;
+
+ if (offset & 0x100)
+ paletteram_xxxxBBBBGGGGRRRR_split2_w((offset & 0xff) + (palette_bank << 8),data);
+ else
+ paletteram_xxxxBBBBGGGGRRRR_split1_w((offset & 0xff) + (palette_bank << 8),data);
+}
+
+READ8_HANDLER( nycaptor_palette_r )
+{
+ if (offset & 0x100)
+ return paletteram_2[ (offset & 0xff) + (palette_bank << 8) ];
+ else
+ return paletteram [ (offset & 0xff) + (palette_bank << 8) ];
+}
+
+WRITE8_HANDLER( nycaptor_gfxctrl_w )
+{
+ if (gfxctrl == data)
+ return;
+ gfxctrl = data;
+
+ if(char_bank != ((data & 0x18) >> 3))
+ {
+ char_bank=((data & 0x18) >> 3);
+ tilemap_mark_all_tiles_dirty( bg_tilemap );
+ }
+ palette_bank = (data & 0x20) >> 5;
+
+}
+
+READ8_HANDLER( nycaptor_gfxctrl_r )
+{
+ return gfxctrl;
+}
+
+READ8_HANDLER( nycaptor_scrlram_r )
+{
+ return nycaptor_scrlram[offset];
+}
+
+WRITE8_HANDLER( nycaptor_scrlram_w )
+{
+ nycaptor_scrlram[offset] = data;
+ tilemap_set_scrolly(bg_tilemap, offset, data );
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect,int pri)
+{
+ int i;
+ for (i=0;i<0x20;i++)
+ {
+ int pr = nycaptor_spriteram[0x9f-i];
+ int offs = (pr & 0x1f) * 4;
+ {
+ int code,sx,sy,flipx,flipy,pal,priori;
+ code = nycaptor_spriteram[offs+2] + ((nycaptor_spriteram[offs+1] & 0x10) << 4);//1 bit wolny = 0x20
+ pal=nycaptor_spriteram[offs+1] & 0x0f;
+ sx = nycaptor_spriteram[offs+3];
+ sy = 240-nycaptor_spriteram[offs+0];
+ priori=(pr&0xe0)>>5;
+ if(priori==pri)
+ {
+#ifdef MAME_DEBUG
+ if(nycaptor_mask&(1<<(pri+4)))pal=0xd;
+#endif
+ flipx = ((nycaptor_spriteram[offs+1]&0x40)>>6);
+ flipy = ((nycaptor_spriteram[offs+1]&0x80)>>7);
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ pal,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+
+ if(nycaptor_spriteram[offs+3]>240)
+ {
+ sx = (nycaptor_spriteram[offs+3]-256);
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ pal,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+ }
+ }
+}
+
+
+
+
+
+#ifdef MAME_DEBUG
+/*
+ Keys :
+ q/w/e/r - bg priority display select
+ a/s/d/f/g/h/j/k - sprite priority display select
+ z - clear
+ x - no bg/sprite pri.
+*/
+
+#define mKEY_MASK(x,y) if (input_code_pressed_once(x)){nycaptor_mask|=y;tilemap_mark_all_tiles_dirty( bg_tilemap );}
+
+void nycaptor_setmask(void)
+{
+ mKEY_MASK(KEYCODE_Q,1); /* bg */
+ mKEY_MASK(KEYCODE_W,2);
+ mKEY_MASK(KEYCODE_E,4);
+ mKEY_MASK(KEYCODE_R,8);
+
+ mKEY_MASK(KEYCODE_A,0x10); /* sprites */
+ mKEY_MASK(KEYCODE_S,0x20);
+ mKEY_MASK(KEYCODE_D,0x40);
+ mKEY_MASK(KEYCODE_F,0x80);
+ mKEY_MASK(KEYCODE_G,0x100);
+ mKEY_MASK(KEYCODE_H,0x200);
+ mKEY_MASK(KEYCODE_J,0x400);
+ mKEY_MASK(KEYCODE_K,0x800);
+
+ if (input_code_pressed_once(KEYCODE_Z)){nycaptor_mask=0;tilemap_mark_all_tiles_dirty( bg_tilemap );} /* disable */
+ if (input_code_pressed_once(KEYCODE_X)){nycaptor_mask|=0x1000;tilemap_mark_all_tiles_dirty( bg_tilemap );} /* no layers */
+}
+#endif
+
+VIDEO_UPDATE( nycaptor )
+{
+#ifdef MAME_DEBUG
+ nycaptor_setmask();
+ if(nycaptor_mask&0x1000)
+ {
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|3,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|3,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|2,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|2,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|1,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|1,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|0,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|0,0);
+ draw_sprites(machine, bitmap,cliprect,0);
+ draw_sprites(machine, bitmap,cliprect,1);
+ draw_sprites(machine, bitmap,cliprect,2);
+ draw_sprites(machine, bitmap,cliprect,3);
+ draw_sprites(machine, bitmap,cliprect,4);
+ draw_sprites(machine, bitmap,cliprect,5);
+ draw_sprites(machine, bitmap,cliprect,6);
+ draw_sprites(machine, bitmap,cliprect,7);
+ }
+ else
+#endif
+ switch (nycaptor_spot()&3)
+ {
+ case 0:
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|3,0);
+ draw_sprites(machine, bitmap,cliprect,6);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|3,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|2,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|2,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|1,0);
+ draw_sprites(machine, bitmap,cliprect,3);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|1,0);
+ draw_sprites(machine, bitmap,cliprect,0);
+ draw_sprites(machine, bitmap,cliprect,2);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|0,0);
+ draw_sprites(machine, bitmap,cliprect,1);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|0,0);
+ break;
+
+ case 1:
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|3,0);
+ draw_sprites(machine, bitmap,cliprect,3);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|3,0);
+ draw_sprites(machine, bitmap,cliprect,2);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|2,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|1,0);
+ draw_sprites(machine, bitmap,cliprect,1);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|1,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|2,0);
+ draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|0,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|0,0);
+ break;
+
+ case 2:
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|3,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|3,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|1,0);
+ draw_sprites(machine, bitmap,cliprect,1);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|1,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|2,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|2,0);
+ draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|0,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|0,0);
+ break;
+
+ case 3:
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|1,0);
+ draw_sprites(machine, bitmap,cliprect,1);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|1,0);
+ draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1|0,0);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0|0,0);
+ break;
+ }
+ return 0;
+}
+
diff --git a/src/mame/video/offtwall.c b/src/mame/video/offtwall.c
new file mode 100644
index 00000000000..2b2dfa07cd6
--- /dev/null
+++ b/src/mame/video/offtwall.c
@@ -0,0 +1,118 @@
+/***************************************************************************
+
+ Atari "Round" hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "offtwall.h"
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data1 = atarigen_playfield[tile_index];
+ UINT16 data2 = atarigen_playfield_upper[tile_index] >> 8;
+ int code = data1 & 0x7fff;
+ int color = 0x10 + (data2 & 0x0f);
+ SET_TILE_INFO(0, code, color, (data1 >> 15) & 1);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( offtwall )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 0, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 8, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x100, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0x00ff,0,0,0 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0,0x7fff,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0x000f,0 }}, /* mask for the color */
+ {{ 0,0,0xff80,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xff80 }}, /* mask for the Y position */
+ {{ 0,0,0,0x0070 }}, /* mask for the width, in tiles*/
+ {{ 0,0,0,0x0007 }}, /* mask for the height, in tiles */
+ {{ 0,0x8000,0,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0 /* callback routine for special entries */
+ };
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8,8, 64,64);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( offtwall )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* not yet verified
+ */
+ pf[x] = mo[x];
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/ohmygod.c b/src/mame/video/ohmygod.c
new file mode 100644
index 00000000000..0a988a5629e
--- /dev/null
+++ b/src/mame/video/ohmygod.c
@@ -0,0 +1,114 @@
+#include "driver.h"
+
+
+UINT16 *ohmygod_videoram;
+
+static int spritebank;
+static tilemap *bg_tilemap;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT16 code = ohmygod_videoram[2*tile_index+1];
+ UINT16 attr = ohmygod_videoram[2*tile_index];
+ SET_TILE_INFO(
+ 0,
+ code,
+ (attr & 0x0f00) >> 8,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( ohmygod )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( ohmygod_videoram_w )
+{
+ COMBINE_DATA(&ohmygod_videoram[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( ohmygod_spritebank_w )
+{
+ if (ACCESSING_MSB)
+ spritebank = data & 0x8000;
+}
+
+WRITE16_HANDLER( ohmygod_scrollx_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrollx(bg_tilemap,0,scroll - 0x81ec);
+}
+
+WRITE16_HANDLER( ohmygod_scrolly_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrolly(bg_tilemap,0,scroll - 0x81ef);
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size/4;offs += 4)
+ {
+ int sx,sy,code,color,flipx;
+ UINT16 *sr;
+
+ sr = spritebank ? (spriteram16+spriteram_size/4) : spriteram16;
+
+ code = sr[offs+3] & 0x0fff;
+ color = sr[offs+2] & 0x000f;
+ sx = sr[offs+0] - 29;
+ sy = sr[offs+1];
+ if (sy >= 32768) sy -= 65536;
+ flipx = sr[offs+3] & 0x8000;
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,0,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( ohmygod )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/ojankohs.c b/src/mame/video/ojankohs.c
new file mode 100644
index 00000000000..276c9ebc9d2
--- /dev/null
+++ b/src/mame/video/ojankohs.c
@@ -0,0 +1,333 @@
+/******************************************************************************
+
+ Video Hardware for Video System Mahjong series.
+
+ Driver by Takahiro Nogi <nogi@kt.rim.or.jp> 2000/06/10 -
+ Driver by Uki 2001/12/10 -
+
+******************************************************************************/
+
+#include "driver.h"
+#include "cpu/z80/z80.h"
+
+
+static UINT8 *ojankohs_videoram;
+static UINT8 *ojankohs_colorram;
+static UINT8 *ojankohs_paletteram;
+static int ojankohs_gfxreg;
+static int ojankohs_flipscreen;
+static int ojankohs_scrollx, ojankohs_scrolly;
+static tilemap *ojankohs_tilemap;
+static int ojankoc_screen_refresh;
+static mame_bitmap *ojankoc_tmpbitmap;
+
+WRITE8_HANDLER( ojankoc_videoram_w );
+
+
+/******************************************************************************
+
+ Palette system
+
+******************************************************************************/
+
+PALETTE_INIT( ojankoy )
+{
+ int i;
+ int bit0, bit1, bit2, bit3, bit4, r, g, b;
+
+ for (i = 0; i < machine->drv->total_colors; i++) {
+ bit0 = (color_prom[0] >> 2) & 0x01;
+ bit1 = (color_prom[0] >> 3) & 0x01;
+ bit2 = (color_prom[0] >> 4) & 0x01;
+ bit3 = (color_prom[0] >> 5) & 0x01;
+ bit4 = (color_prom[0] >> 6) & 0x01;
+ r = 0x08 * bit0 + 0x11 * bit1 + 0x21 * bit2 + 0x43 * bit3 + 0x82 * bit4;
+ bit0 = (color_prom[machine->drv->total_colors] >> 5) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 6) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 7) & 0x01;
+ bit3 = (color_prom[0] >> 0) & 0x01;
+ bit4 = (color_prom[0] >> 1) & 0x01;
+ g = 0x08 * bit0 + 0x11 * bit1 + 0x21 * bit2 + 0x43 * bit3 + 0x82 * bit4;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ bit4 = (color_prom[machine->drv->total_colors] >> 4) & 0x01;
+ b = 0x08 * bit0 + 0x11 * bit1 + 0x21 * bit2 + 0x43 * bit3 + 0x82 * bit4;
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ color_prom++;
+ }
+}
+
+READ8_HANDLER( ojankohs_palette_r )
+{
+ return ojankohs_paletteram[offset];
+}
+
+WRITE8_HANDLER( ojankohs_palette_w )
+{
+ int r, g, b;
+
+ ojankohs_paletteram[offset] = data;
+
+ offset &= 0x7fe;
+
+ r = (ojankohs_paletteram[offset + 0] & 0x7c) >> 2;
+ g = ((ojankohs_paletteram[offset + 0] & 0x03) << 3) |
+ ((ojankohs_paletteram[offset + 1] & 0xe0) >> 5);
+ b = (ojankohs_paletteram[offset + 1] & 0x1f) >> 0;
+
+ palette_set_color_rgb(Machine,offset >> 1, pal5bit(r), pal5bit(g), pal5bit(b));
+}
+
+WRITE8_HANDLER( ccasino_palette_w )
+{
+ int r, g, b;
+
+ /* get top 8 bits of the I/O port address */
+ offset = (offset << 8) | (activecpu_get_reg(Z80_BC) >> 8);
+
+ ojankohs_paletteram[offset] = data;
+
+ offset &= 0x7fe;
+
+ r = (ojankohs_paletteram[offset + 0] & 0x7c) >> 2;
+ g = ((ojankohs_paletteram[offset + 0] & 0x03) << 3) |
+ ((ojankohs_paletteram[offset + 1] & 0xe0) >> 5);
+ b = (ojankohs_paletteram[offset + 1] & 0x1f) >> 0;
+
+ palette_set_color_rgb(Machine,offset >> 1, pal5bit(r), pal5bit(g), pal5bit(b));
+}
+
+WRITE8_HANDLER( ojankoc_palette_w )
+{
+ int r, g, b, color;
+
+ if (ojankohs_paletteram[offset] == data) return;
+
+ ojankohs_paletteram[offset] = data;
+ ojankoc_screen_refresh = 1;
+
+ color = (ojankohs_paletteram[offset & 0x1e] << 8) | ojankohs_paletteram[offset | 0x01];
+
+ r = (color >> 10) & 0x1f;
+ g = (color >> 5) & 0x1f;
+ b = (color >> 0) & 0x1f;
+
+ palette_set_color_rgb(Machine,offset >> 1, pal5bit(r), pal5bit(g), pal5bit(b));
+}
+
+
+/******************************************************************************
+
+ Tilemap system
+
+******************************************************************************/
+
+READ8_HANDLER( ojankohs_videoram_r )
+{
+ return ojankohs_videoram[offset];
+}
+
+WRITE8_HANDLER( ojankohs_videoram_w )
+{
+ ojankohs_videoram[offset] = data;
+ tilemap_mark_tile_dirty(ojankohs_tilemap, offset);
+}
+
+READ8_HANDLER( ojankohs_colorram_r )
+{
+ return ojankohs_colorram[offset];
+}
+
+WRITE8_HANDLER( ojankohs_colorram_w )
+{
+ ojankohs_colorram[offset] = data;
+ tilemap_mark_tile_dirty(ojankohs_tilemap, offset);
+}
+
+WRITE8_HANDLER( ojankohs_gfxreg_w )
+{
+ if (ojankohs_gfxreg != data) {
+ ojankohs_gfxreg = data;
+ tilemap_mark_all_tiles_dirty(ojankohs_tilemap);
+ }
+}
+
+WRITE8_HANDLER( ojankohs_flipscreen_w )
+{
+ if (ojankohs_flipscreen != (data & 0x01)) {
+
+ ojankohs_flipscreen = data & 0x01;
+
+ tilemap_set_flip(ALL_TILEMAPS, ojankohs_flipscreen ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
+
+ if (ojankohs_flipscreen) {
+ ojankohs_scrollx = -0xe0;
+ ojankohs_scrolly = -0x20;
+ }
+ else {
+ ojankohs_scrollx = 0;
+ ojankohs_scrolly = 0;
+ }
+ }
+}
+
+static TILE_GET_INFO( ojankohs_get_tile_info )
+{
+ int tile, color;
+
+ tile = ojankohs_videoram[tile_index] | ((ojankohs_colorram[tile_index] & 0x0f) << 8);
+ color = (ojankohs_colorram[tile_index] & 0xe0) >> 5;
+
+ if (ojankohs_colorram[tile_index] & 0x10) {
+ tile |= (ojankohs_gfxreg & 0x07) << 12;
+ color |= (ojankohs_gfxreg & 0xe0) >> 2;
+ }
+
+ SET_TILE_INFO(0, tile, color, 0);
+}
+
+static TILE_GET_INFO( ojankoy_get_tile_info )
+{
+ int tile, color, flipx, flipy;
+
+ tile = ojankohs_videoram[tile_index] | (ojankohs_videoram[tile_index + 0x1000] << 8);
+ color = ojankohs_colorram[tile_index] & 0x3f;
+ flipx = ((ojankohs_colorram[tile_index] & 0x40) >> 6) ? TILEMAP_FLIPX : 0;
+ flipy = ((ojankohs_colorram[tile_index] & 0x80) >> 7) ? TILEMAP_FLIPY : 0;
+
+ SET_TILE_INFO(0, tile, color, (flipx | flipy));
+}
+
+
+/******************************************************************************
+
+ Pixel system
+
+******************************************************************************/
+
+void ojankoc_flipscreen(int data)
+{
+ static int ojankoc_flipscreen_old = 0;
+ int x, y;
+ UINT8 color1, color2;
+
+ ojankohs_flipscreen = (data & 0x80) >> 7;
+
+ if (ojankohs_flipscreen == ojankoc_flipscreen_old) return;
+
+ for (y = 0; y < 0x40; y++) {
+ for (x = 0; x < 0x100; x++) {
+ color1 = ojankohs_videoram[0x0000 + ((y * 256) + x)];
+ color2 = ojankohs_videoram[0x3fff - ((y * 256) + x)];
+ ojankoc_videoram_w(0x0000 + ((y * 256) + x), color2);
+ ojankoc_videoram_w(0x3fff - ((y * 256) + x), color1);
+
+ color1 = ojankohs_videoram[0x4000 + ((y * 256) + x)];
+ color2 = ojankohs_videoram[0x7fff - ((y * 256) + x)];
+ ojankoc_videoram_w(0x4000 + ((y * 256) + x), color2);
+ ojankoc_videoram_w(0x7fff - ((y * 256) + x), color1);
+ }
+ }
+
+ ojankoc_flipscreen_old = ojankohs_flipscreen;
+}
+
+WRITE8_HANDLER( ojankoc_videoram_w )
+{
+ int i;
+ UINT8 x, y, xx, px, py ;
+ UINT8 color, color1, color2;
+
+ ojankohs_videoram[offset] = data;
+
+ color1 = ojankohs_videoram[offset & 0x3fff];
+ color2 = ojankohs_videoram[offset | 0x4000];
+
+ y = offset >> 6;
+ x = (offset & 0x3f) << 2;
+ xx = 0;
+
+ if (ojankohs_flipscreen) {
+ x = 0xfc - x;
+ y = 0xff - y;
+ xx = 3;
+ }
+
+ for (i = 0; i < 4; i++) {
+ color = ((color1 & 0x01) >> 0) | ((color1 & 0x10) >> 3) | ((color2 & 0x01) << 2) | ((color2 & 0x10) >> 1);
+
+ px = x + (i ^ xx);
+ py = y;
+
+ *BITMAP_ADDR16(ojankoc_tmpbitmap, py, px) = Machine->pens[color];
+
+ color1 >>= 1;
+ color2 >>= 1;
+ }
+}
+
+
+/******************************************************************************
+
+ Start the video hardware emulation
+
+******************************************************************************/
+
+VIDEO_START( ojankohs )
+{
+ ojankohs_tilemap = tilemap_create(ojankohs_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 4, 64, 64);
+ ojankohs_videoram = auto_malloc(0x2000);
+ ojankohs_colorram = auto_malloc(0x1000);
+ ojankohs_paletteram = auto_malloc(0x800);
+}
+
+VIDEO_START( ojankoy )
+{
+ ojankohs_tilemap = tilemap_create(ojankoy_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 4, 64, 64);
+ ojankohs_videoram = auto_malloc(0x2000);
+ ojankohs_colorram = auto_malloc(0x1000);
+ ojankohs_paletteram = auto_malloc(0x800);
+}
+
+VIDEO_START( ojankoc )
+{
+ ojankoc_tmpbitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ ojankohs_videoram = auto_malloc(0x8000);
+ ojankohs_paletteram = auto_malloc(0x20);
+}
+
+
+/******************************************************************************
+
+ Display refresh
+
+******************************************************************************/
+
+VIDEO_UPDATE( ojankohs )
+{
+ tilemap_set_scrollx(ojankohs_tilemap, 0, ojankohs_scrollx);
+ tilemap_set_scrolly(ojankohs_tilemap, 0, ojankohs_scrolly);
+
+ tilemap_draw(bitmap, cliprect, ojankohs_tilemap, 0, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( ojankoc )
+{
+ int offs;
+
+ if (ojankoc_screen_refresh)
+ {
+ /* redraw bitmap */
+ for (offs = 0; offs < 0x8000; offs++) {
+ ojankoc_videoram_w(offs, ojankohs_videoram[offs]);
+ }
+ ojankoc_screen_refresh = 0;
+ }
+
+ copybitmap(bitmap, ojankoc_tmpbitmap, 0, 0, 0, 0, cliprect, TRANSPARENCY_NONE, 0);
+ return 0;
+}
diff --git a/src/mame/video/omegaf.c b/src/mame/video/omegaf.c
new file mode 100644
index 00000000000..094df65fcb5
--- /dev/null
+++ b/src/mame/video/omegaf.c
@@ -0,0 +1,615 @@
+/***************************************************************************
+
+Functions to emulate the video hardware of the machine.
+
+This hardware of the machine is similar with that of Mutant Night.
+The difference between the two machines is that there are three BG
+layers as against just one BG layer in Mutant Night.
+
+
+Foreground RAM format ( Foreground RAM format is same as Mutant Night )
+--------------------------------------------------------------
+ +0 +1
+ xxxx xxxx ---- ---- = bottom 8 bits of tile number
+ ---- ---- xx-- ---- = top 2 bits of tile number
+ ---- ---- --x- ---- = flip X
+ ---- ---- ---x ---- = flip Y
+ ---- ---- ---- xxxx = color ( 00h - 0fh )
+
+
+Background RAM format
+--------------------------------------------------------------
+ +0 +1
+ xxxx xxxx ---- ---- = bottom 8 bits of tile number
+ ---- ---- x--- ---- = bit 9 of tile number
+ ---- ---- -x-- ---- = bit 8 of tile number
+ ---- ---- --x- ---- = bit 10 of tile number
+ ---- ---- ---x ---- = bit 11 of tile number (the most top bit)
+ ---- ---- ---- xxxx = color ( 00h - 1fh )
+
+
+Sprite RAM format ( Sprite format is same as Mutant Night )
+--------------------------------------------------------------
+ +0 +1 +2 +3 +4
+ xxxx xxxx ---- ---- ---- ---- ---- ---- ---- ---- = sprite Y position
+ ---- ---- xxxx xxxx ---- ---- ---- ---- ---- ---- = bottom 8 bits of sprite X position
+ ---- ---- ---- ---- xx-- ---- ---- ---- ---- ---- = middle 2 bits of sprite number
+ ---- ---- ---- ---- --x- ---- ---- ---- ---- ---- = flip X
+ ---- ---- ---- ---- ---x ---- ---- ---- ---- ---- = flip Y
+ ---- ---- ---- ---- ---- x--- ---- ---- ---- ---- = top bit of sprite number
+ ---- ---- ---- ---- ---- -x-- ---- ---- ---- ---- = 0:normal size (16x16) 1:big size (32x32)
+ ---- ---- ---- ---- ---- --x- ---- ---- ---- ---- = sprite on / off
+ ---- ---- ---- ---- ---- ---x ---- ---- ---- ---- = top bit of sprite X position
+ ---- ---- ---- ---- ---- ---- xxxx xxxx ---- ---- = bottom 8 bits of sprite number
+ ---- ---- ---- ---- ---- ---- ---- ---- xxxx xxxx = color
+
+
+Scroll RAM format (Omega Fighter)
+--------------------------------------------------------------
+ +0 +1
+ X ???? -xxx xxxx xxxx = scroll X (0 - 0x3ff)
+ Y ???? ---x xxxx xxxx = scroll Y (0 - 0x1ff)
+
+Scroll RAM format (Atomic Robokid)
+--------------------------------------------------------------
+ +0 +1
+ X ???? ---x xxxx xxxx = scroll X (0 - 0x1ff)
+ Y ???? ---x xxxx xxxx = scroll Y (0 - 0x1ff)
+
+
+Real screen resolution and virtual one
+--------------------------------------------------------------
+ Real Virtual
+Omega Fighter 256x192(H) 2048x512
+Atomic Robokid 256x192(H) 512x512
+
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+/**************************************************************************
+ Variables
+**************************************************************************/
+
+UINT8 *omegaf_fg_videoram;
+static UINT8 *omegaf_bg0_videoram;
+static UINT8 *omegaf_bg1_videoram;
+static UINT8 *omegaf_bg2_videoram;
+//size_t omegaf_fgvideoram_size;
+
+static int omegaf_bg0_bank = 0;
+static int omegaf_bg1_bank = 0;
+static int omegaf_bg2_bank = 0;
+
+UINT8 *omegaf_bg0_scroll_x;
+UINT8 *omegaf_bg1_scroll_x;
+UINT8 *omegaf_bg2_scroll_x;
+UINT8 *omegaf_bg0_scroll_y;
+UINT8 *omegaf_bg1_scroll_y;
+UINT8 *omegaf_bg2_scroll_y;
+
+static tilemap *fg_tilemap;
+static tilemap *bg0_tilemap;
+static tilemap *bg1_tilemap;
+static tilemap *bg2_tilemap;
+
+static int bg0_enabled = 1;
+static int bg1_enabled = 1;
+static int bg2_enabled = 1;
+
+static mame_bitmap *bitmap_sp; /* for sprite overdraw */
+static int sprite_overdraw_enabled = 0;
+
+static int scrollx_mask = 0x07ff;
+static int bank_mask = 1;
+
+
+/***************************************************************************
+ Callbacks for the tilemap code
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg0_tile_info )
+{
+ int color, tile, hi, lo;
+
+ int attrib = ( (tile_index & 0x00f) | ( (tile_index & 0x070) << 5 ) |
+ ( (tile_index & 0xf80) >> 3 ) ) << 1;
+ lo = omegaf_bg0_videoram[ attrib ];
+ hi = omegaf_bg0_videoram[ attrib | 1 ];
+ color = hi & 0x0f;
+ tile = ( ((hi & 0x80) << 2) | ((hi & 0x40) << 2) |
+ ((hi & 0x20) << 5) | ((hi & 0x10) << 7) ) | lo;
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+ tileinfo->category = 0;
+}
+
+static TILE_GET_INFO( get_bg1_tile_info )
+{
+ int color, tile, hi, lo;
+
+ int attrib = ( (tile_index & 0x00f) | ( (tile_index & 0x070) << 5 ) |
+ ( (tile_index & 0xf80) >> 3 ) ) << 1;
+ lo = omegaf_bg1_videoram[ attrib ];
+ hi = omegaf_bg1_videoram[ attrib | 1 ];
+ color = hi & 0x0f;
+ tile = ( ((hi & 0x80) << 2) | ((hi & 0x40) << 2) |
+ ((hi & 0x20) << 5) | ((hi & 0x10) << 7) ) | lo;
+ SET_TILE_INFO(
+ 1,
+ tile,
+ color,
+ 0);
+ tileinfo->category = 0;
+}
+
+static TILE_GET_INFO( get_bg2_tile_info )
+{
+ int color, tile, hi, lo;
+
+ int attrib = ( (tile_index & 0x00f) | ( (tile_index & 0x070) << 5 ) |
+ ( (tile_index & 0xf80) >> 3 ) ) << 1;
+ lo = omegaf_bg2_videoram[ attrib ];
+ hi = omegaf_bg2_videoram[ attrib | 1 ];
+ color = hi & 0x0f;
+ tile = ( ((hi & 0x80) << 2) | ((hi & 0x40) << 2) |
+ ((hi & 0x20) << 5) | ((hi & 0x10) << 7) ) | lo;
+ SET_TILE_INFO(
+ 2,
+ tile,
+ color,
+ 0);
+ tileinfo->category = 0;
+}
+
+static TILE_GET_INFO( robokid_get_bg0_tile_info )
+{
+ int color, tile, hi, lo;
+
+ int attrib = ( (tile_index & 0x00f) | ( (tile_index & 0x010) << 5 ) |
+ ( (tile_index & 0x3e0) >> 1 ) ) << 1;
+ lo = omegaf_bg0_videoram[ attrib ];
+ hi = omegaf_bg0_videoram[ attrib | 1 ];
+ color = hi & 0x0f;
+ tile = ( ((hi & 0x80) << 2) | ((hi & 0x40) << 2) |
+ ((hi & 0x20) << 5) | ((hi & 0x10) << 7) ) | lo;
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+ tileinfo->category = 0;
+}
+
+static TILE_GET_INFO( robokid_get_bg1_tile_info )
+{
+ int color, tile, hi, lo;
+
+ int attrib = ( (tile_index & 0x00f) | ( (tile_index & 0x010) << 5 ) |
+ ( (tile_index & 0x3e0) >> 1 ) ) << 1;
+ lo = omegaf_bg1_videoram[ attrib ];
+ hi = omegaf_bg1_videoram[ attrib | 1 ];
+ color = hi & 0x0f;
+ tile = ( ((hi & 0x80) << 2) | ((hi & 0x40) << 2) |
+ ((hi & 0x20) << 5) | ((hi & 0x10) << 7) ) | lo;
+ SET_TILE_INFO(
+ 1,
+ tile,
+ color,
+ 0);
+ tileinfo->category = 0;
+}
+
+static TILE_GET_INFO( robokid_get_bg2_tile_info )
+{
+ int color, tile, hi, lo;
+
+ int attrib = ( (tile_index & 0x00f) | ( (tile_index & 0x010) << 5 ) |
+ ( (tile_index & 0x3e0) >> 1 ) ) << 1;
+ lo = omegaf_bg2_videoram[ attrib ];
+ hi = omegaf_bg2_videoram[ attrib | 1 ];
+ color = hi & 0x0f;
+ tile = ( ((hi & 0x80) << 2) | ((hi & 0x40) << 2) |
+ ((hi & 0x20) << 5) | ((hi & 0x10) << 7) ) | lo;
+ SET_TILE_INFO(
+ 2,
+ tile,
+ color,
+ 0);
+ tileinfo->category = 0;
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int color, tile, hi, lo;
+
+ lo = omegaf_fg_videoram[ tile_index << 1 ];
+ hi = omegaf_fg_videoram[ (tile_index << 1) + 1 ];
+ color = hi & 0x0f;
+ tile = ( ((hi & 0x80) << 2) | ((hi & 0x40) << 2) |
+ ((hi & 0x20) << 5) | ((hi & 0x10) << 7) ) | lo;
+ SET_TILE_INFO(
+ 5,
+ tile,
+ color,
+ 0);
+ tileinfo->category = 0;
+}
+
+
+/***************************************************************************
+ Initialize and destroy video hardware emulation
+***************************************************************************/
+
+static void videoram_alloc(running_machine *machine, int size)
+{
+ /* create video ram */
+ omegaf_bg0_videoram = auto_malloc(size);
+ memset( omegaf_bg0_videoram, 0x00, size );
+
+ omegaf_bg1_videoram = auto_malloc(size);
+ memset( omegaf_bg1_videoram, 0x00, size );
+
+ omegaf_bg2_videoram = auto_malloc(size);
+ memset( omegaf_bg2_videoram, 0x00, size );
+
+ bitmap_sp = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+}
+
+VIDEO_START( omegaf )
+{
+ scrollx_mask = 0x07ff;
+ bank_mask = 7;
+
+ videoram_alloc(machine, 0x2000);
+
+ /* Info Offset Type w h col row */
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+ bg0_tilemap = tilemap_create(get_bg0_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 128, 32);
+ bg1_tilemap = tilemap_create(get_bg1_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 128, 32);
+ bg2_tilemap = tilemap_create(get_bg2_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 128, 32);
+
+ tilemap_set_transparent_pen( fg_tilemap, 15 );
+ tilemap_set_transparent_pen( bg0_tilemap, 15 );
+ tilemap_set_transparent_pen( bg1_tilemap, 15 );
+ tilemap_set_transparent_pen( bg2_tilemap, 15 );
+}
+
+VIDEO_START( robokid )
+{
+ scrollx_mask = 0x01ff;
+ bank_mask = 1;
+
+ videoram_alloc(machine, 0x0800);
+
+ /* Info Offset Type w h col row */
+ fg_tilemap = tilemap_create( get_fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+ bg0_tilemap = tilemap_create(robokid_get_bg0_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+ bg1_tilemap = tilemap_create(robokid_get_bg1_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+ bg2_tilemap = tilemap_create(robokid_get_bg2_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+
+ tilemap_set_transparent_pen( fg_tilemap, 15 );
+ tilemap_set_transparent_pen( bg1_tilemap, 15 );
+ tilemap_set_transparent_pen( bg2_tilemap, 15 );
+}
+
+
+/***************************************************************************
+ Memory handler
+***************************************************************************/
+
+WRITE8_HANDLER( omegaf_bg0_bank_w )
+{
+ omegaf_bg0_bank = data & bank_mask;
+}
+
+WRITE8_HANDLER( omegaf_bg1_bank_w )
+{
+ omegaf_bg1_bank = data & bank_mask;
+}
+
+WRITE8_HANDLER( omegaf_bg2_bank_w )
+{
+ omegaf_bg2_bank = data & bank_mask;
+}
+
+READ8_HANDLER( omegaf_bg0_videoram_r )
+{
+ return omegaf_bg0_videoram[ (omegaf_bg0_bank << 10) | offset ];
+}
+
+READ8_HANDLER( omegaf_bg1_videoram_r )
+{
+ return omegaf_bg1_videoram[ (omegaf_bg1_bank << 10) | offset ];
+}
+
+READ8_HANDLER( omegaf_bg2_videoram_r )
+{
+ return omegaf_bg2_videoram[ (omegaf_bg2_bank << 10) | offset ];
+}
+
+WRITE8_HANDLER( omegaf_bg0_videoram_w )
+{
+ int address;
+ int tile_index;
+
+ address = (omegaf_bg0_bank << 10 ) | offset;
+ omegaf_bg0_videoram[ address ] = data;
+ tile_index = ( (address & 0x001e) >> 1 ) | ( (address & 0x1c00) >> 6 ) |
+ ( (address & 0x03e0) << 2 );
+ tilemap_mark_tile_dirty( bg0_tilemap, tile_index );
+}
+
+WRITE8_HANDLER( omegaf_bg1_videoram_w )
+{
+ int address;
+ int tile_index;
+
+ address = (omegaf_bg1_bank << 10 ) | offset;
+ omegaf_bg1_videoram[ address ] = data;
+ tile_index = ( (address & 0x001e) >> 1 ) | ( (address & 0x1c00) >> 6 ) |
+ ( (address & 0x03e0) << 2 );
+ tilemap_mark_tile_dirty( bg1_tilemap, tile_index );
+}
+
+WRITE8_HANDLER( omegaf_bg2_videoram_w )
+{
+ int address;
+ int tile_index;
+
+ address = (omegaf_bg2_bank << 10 ) | offset;
+ omegaf_bg2_videoram[ address ] = data;
+ tile_index = ( (address & 0x001e) >> 1 ) | ( (address & 0x1c00) >> 6 ) |
+ ( (address & 0x03e0) << 2 );
+ tilemap_mark_tile_dirty( bg2_tilemap, tile_index );
+}
+
+WRITE8_HANDLER( robokid_bg0_videoram_w )
+{
+ int address;
+ int tile_index;
+
+ address = (omegaf_bg0_bank << 10 ) | offset;
+ omegaf_bg0_videoram[ address ] = data;
+ tile_index = ( (address & 0x001e) >> 1 ) | ( (address & 0x0400) >> 6 ) |
+ (address & 0x03e0);
+ tilemap_mark_tile_dirty( bg0_tilemap, tile_index );
+}
+
+WRITE8_HANDLER( robokid_bg1_videoram_w )
+{
+ int address;
+ int tile_index;
+
+ address = (omegaf_bg1_bank << 10 ) | offset;
+ omegaf_bg1_videoram[ address ] = data;
+ tile_index = ( (address & 0x001e) >> 1 ) | ( (address & 0x0400) >> 6 ) |
+ (address & 0x03e0);
+ tilemap_mark_tile_dirty( bg1_tilemap, tile_index );
+}
+
+WRITE8_HANDLER( robokid_bg2_videoram_w )
+{
+ int address;
+ int tile_index;
+
+ address = (omegaf_bg2_bank << 10 ) | offset;
+ omegaf_bg2_videoram[ address ] = data;
+ tile_index = ( (address & 0x001e) >> 1 ) | ( (address & 0x0400) >> 6 ) |
+ (address & 0x03e0);
+ tilemap_mark_tile_dirty( bg2_tilemap, tile_index );
+}
+
+WRITE8_HANDLER( omegaf_bg0_scrollx_w )
+{
+ int scrollx;
+
+ omegaf_bg0_scroll_x[offset] = data;
+
+ scrollx = (omegaf_bg0_scroll_x[1] << 8) | omegaf_bg0_scroll_x[0];
+ scrollx &= scrollx_mask;
+ tilemap_set_scrollx( bg0_tilemap, 0, scrollx );
+}
+
+WRITE8_HANDLER( omegaf_bg0_scrolly_w )
+{
+ int scrolly;
+
+ omegaf_bg0_scroll_y[offset] = data;
+
+ scrolly = (omegaf_bg0_scroll_y[1] << 8) | omegaf_bg0_scroll_y[0];
+ scrolly &= 0x01ff;
+ tilemap_set_scrolly( bg0_tilemap, 0, scrolly );
+}
+
+WRITE8_HANDLER( omegaf_bg1_scrollx_w )
+{
+ int scrollx;
+
+ omegaf_bg1_scroll_x[offset] = data;
+
+ scrollx = (omegaf_bg1_scroll_x[1] << 8) | omegaf_bg1_scroll_x[0];
+ scrollx &= scrollx_mask;
+ tilemap_set_scrollx( bg1_tilemap, 0, scrollx );
+}
+
+WRITE8_HANDLER( omegaf_bg1_scrolly_w )
+{
+ int scrolly;
+
+ omegaf_bg1_scroll_y[offset] = data;
+
+ scrolly = (omegaf_bg1_scroll_y[1] << 8) | omegaf_bg1_scroll_y[0];
+ scrolly &= 0x01ff;
+ tilemap_set_scrolly( bg1_tilemap, 0, scrolly );
+}
+
+WRITE8_HANDLER( omegaf_bg2_scrollx_w )
+{
+ int scrollx;
+
+ omegaf_bg2_scroll_x[offset] = data;
+
+ scrollx = (omegaf_bg2_scroll_x[1] << 8) | omegaf_bg2_scroll_x[0];
+ scrollx &= scrollx_mask;
+ tilemap_set_scrollx( bg2_tilemap, 0, scrollx );
+}
+
+WRITE8_HANDLER( omegaf_bg2_scrolly_w )
+{
+ int scrolly;
+
+ omegaf_bg2_scroll_y[offset] = data;
+
+ scrolly = (omegaf_bg2_scroll_y[1] << 8) | omegaf_bg2_scroll_y[0];
+ scrolly &= 0x01ff;
+ tilemap_set_scrolly( bg2_tilemap, 0, scrolly );
+}
+
+WRITE8_HANDLER( omegaf_fgvideoram_w )
+{
+ omegaf_fg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset >> 1);
+}
+
+WRITE8_HANDLER( omegaf_bg0_enabled_w )
+{
+ if (bg0_enabled != data)
+ bg0_enabled = data;
+}
+
+WRITE8_HANDLER( omegaf_bg1_enabled_w )
+{
+ if (bg1_enabled != data)
+ bg1_enabled = data;
+}
+
+WRITE8_HANDLER( omegaf_bg2_enabled_w )
+{
+ if (bg2_enabled != data)
+ bg2_enabled = data;
+}
+
+WRITE8_HANDLER( omegaf_sprite_overdraw_w )
+{
+ logerror( "sprite overdraw flag : %02x\n", data );
+ if (sprite_overdraw_enabled != (data & 1))
+ {
+ sprite_overdraw_enabled = data & 1;
+ fillbitmap(bitmap_sp, 15, &Machine->screen[0].visarea);
+ }
+}
+
+WRITE8_HANDLER( omegaf_flipscreen_w )
+{
+ flip_screen_set(data & 0x80);
+}
+
+/***************************************************************************
+ Screen refresh
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ /* Draw the sprites */
+ for (offs = 11 ;offs < spriteram_size; offs += 16)
+ {
+ int sx, sy, tile, color, flipx, flipy, big;
+
+ if (spriteram[offs + 2] & 2)
+ {
+ sx = spriteram[offs + 1];
+ sy = spriteram[offs];
+ if (spriteram[offs + 2] & 1)
+ sx -= 256;
+ tile = spriteram[offs + 3] |
+ ((spriteram[offs + 2] & 0xc0) << 2) |
+ ((spriteram[offs + 2] & 0x08) << 7);
+
+ big = spriteram[offs + 2] & 4;
+ if (big)
+ tile >>= 2;
+ flipx = spriteram[offs + 2] & 0x10;
+ flipy = spriteram[offs + 2] & 0x20;
+ color = spriteram[offs + 4] & 0x0f;
+
+ if(sprite_overdraw_enabled && (color & 8))
+ {
+ /* "static" sprites */
+ drawgfx(bitmap_sp,machine->gfx[(big) ? 4 : 3],
+ tile,
+ color,
+ flipx,flipy,
+ sx,sy,
+ 0,
+ TRANSPARENCY_PEN, 15);
+ }
+ else
+ {
+ drawgfx(bitmap,machine->gfx[(big) ? 4 : 3],
+ tile,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN, 15);
+
+ /* all the "normal" sprites clear the "static" ones */
+ if(sprite_overdraw_enabled)
+ {
+ int x,y,offset = 0;
+ const gfx_element *gfx = machine->gfx[(big) ? 4 : 3];
+ UINT8 *srcgfx = gfx->gfxdata + tile * gfx->char_modulo;
+
+ for(y = 0; y < gfx->height; y++)
+ {
+ for(x = 0; x < gfx->width; x++)
+ {
+ if(srcgfx[offset] != 15)
+ {
+ *BITMAP_ADDR16(bitmap_sp, sy + y, sx + x) = 15;
+ }
+
+ offset++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(sprite_overdraw_enabled)
+ copybitmap(bitmap, bitmap_sp, 0, 0, 0, 0, cliprect, TRANSPARENCY_PEN, 15);
+}
+
+VIDEO_UPDATE( omegaf )
+{
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ if (bg0_enabled) tilemap_draw(bitmap,cliprect, bg0_tilemap, 0, 0);
+ if (bg1_enabled) tilemap_draw(bitmap,cliprect, bg1_tilemap, 0, 0);
+ if (bg2_enabled) tilemap_draw(bitmap,cliprect, bg2_tilemap, 0, 0);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( robokid )
+{
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ if (bg0_enabled) tilemap_draw(bitmap,cliprect, bg0_tilemap, 0, 0);
+ if (bg1_enabled) tilemap_draw(bitmap,cliprect, bg1_tilemap, 0, 0);
+ draw_sprites(machine,bitmap,cliprect);
+ if (bg2_enabled) tilemap_draw(bitmap,cliprect, bg2_tilemap, 0, 0);
+ tilemap_draw(bitmap,cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/oneshot.c b/src/mame/video/oneshot.c
new file mode 100644
index 00000000000..d49afe33e1c
--- /dev/null
+++ b/src/mame/video/oneshot.c
@@ -0,0 +1,198 @@
+/* One Shot One Kill Video Hardware */
+
+#include "driver.h"
+
+extern UINT16 *oneshot_sprites;
+extern UINT16 *oneshot_bg_videoram;
+extern UINT16 *oneshot_mid_videoram;
+extern UINT16 *oneshot_fg_videoram;
+extern UINT16 *oneshot_scroll;
+
+extern int gun_x_p1,gun_y_p1,gun_x_p2,gun_y_p2;
+extern int gun_x_shift;
+
+
+static tilemap *oneshot_bg_tilemap;
+static tilemap *oneshot_mid_tilemap;
+static tilemap *oneshot_fg_tilemap;
+
+/* bg tilemap */
+static TILE_GET_INFO( get_oneshot_bg_tile_info )
+{
+ int tileno;
+
+ tileno = oneshot_bg_videoram[tile_index*2+1];
+
+ SET_TILE_INFO(0,tileno,0,0);
+}
+
+WRITE16_HANDLER( oneshot_bg_videoram_w )
+{
+ COMBINE_DATA(&oneshot_bg_videoram[offset]);
+ tilemap_mark_tile_dirty(oneshot_bg_tilemap,offset/2);
+}
+
+/* mid tilemap */
+static TILE_GET_INFO( get_oneshot_mid_tile_info )
+{
+ int tileno;
+
+ tileno = oneshot_mid_videoram[tile_index*2+1];
+
+ SET_TILE_INFO(0,tileno,2,0);
+}
+
+WRITE16_HANDLER( oneshot_mid_videoram_w )
+{
+ COMBINE_DATA(&oneshot_mid_videoram[offset]);
+ tilemap_mark_tile_dirty(oneshot_mid_tilemap,offset/2);
+}
+
+
+/* fg tilemap */
+static TILE_GET_INFO( get_oneshot_fg_tile_info )
+{
+ int tileno;
+
+ tileno = oneshot_fg_videoram[tile_index*2+1];
+
+ SET_TILE_INFO(0,tileno,3,0);
+}
+
+WRITE16_HANDLER( oneshot_fg_videoram_w )
+{
+ COMBINE_DATA(&oneshot_fg_videoram[offset]);
+ tilemap_mark_tile_dirty(oneshot_fg_tilemap,offset/2);
+}
+
+VIDEO_START( oneshot )
+{
+ oneshot_bg_tilemap = tilemap_create(get_oneshot_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+ oneshot_mid_tilemap = tilemap_create(get_oneshot_mid_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+ oneshot_fg_tilemap = tilemap_create(get_oneshot_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+
+ tilemap_set_transparent_pen(oneshot_bg_tilemap,0);
+ tilemap_set_transparent_pen(oneshot_mid_tilemap,0);
+ tilemap_set_transparent_pen(oneshot_fg_tilemap,0);
+}
+
+static void draw_crosshairs( mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int xpos,ypos;
+ /* get gun raw coordonates (player 1) */
+ gun_x_p1 = (readinputport(5) & 0xff) * 320 / 256;
+ gun_y_p1 = (readinputport(6) & 0xff) * 240 / 256;
+
+ /* compute the coordonates for drawing (from routine at 0x009ab0) */
+ xpos = gun_x_p1;
+ ypos = gun_y_p1;
+
+ gun_x_p1+=gun_x_shift;
+
+ gun_y_p1 -= 0x0a;
+ if (gun_y_p1 < 0)
+ gun_y_p1=0;
+
+
+ /* get gun raw coordonates (player 2) */
+ gun_x_p2 = (readinputport(7) & 0xff) * 320 / 256;
+ gun_y_p2 = (readinputport(8) & 0xff) * 240 / 256;
+ /* compute the coordonates for drawing (from routine at 0x009b6e) */
+ xpos = gun_x_p2;
+ ypos = gun_y_p2;
+
+ gun_x_p2 += gun_x_shift-0x0a;
+ if (gun_x_p2 < 0)
+ gun_x_p2=0;
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const UINT16 *source = oneshot_sprites;
+ const UINT16 *finish = source+(0x1000/2);
+ const gfx_element *gfx = machine->gfx[1];
+
+ int xpos,ypos;
+
+ while( source<finish )
+ {
+ int blockx,blocky;
+ int num = source[1] & 0xffff;
+ int xsize = (source[2] & 0x000f)+1;
+ int ysize = (source[3] & 0x000f)+1;
+
+ ypos = source[3] & 0xff80;
+ xpos = source[2] & 0xff80;
+
+ ypos = ypos >> 7;
+ xpos = xpos >> 7;
+
+
+ if (source[0] == 0x0001) break;
+
+ xpos -= 8;
+ ypos -= 6;
+
+
+ for (blockx = 0; blockx<xsize;blockx++) {
+ for (blocky = 0; blocky<ysize;blocky++) {
+
+
+ drawgfx(
+ bitmap,
+ gfx,
+ num+(blocky*xsize)+blockx,
+ 1,
+ 0,0,
+ xpos+blockx*8,ypos+blocky*8,
+ cliprect,
+ TRANSPARENCY_PEN,0
+ );
+
+ drawgfx(
+ bitmap,
+ gfx,
+ num+(blocky*xsize)+blockx,
+ 1,
+ 0,0,
+ xpos+blockx*8-0x200,ypos+blocky*8,
+ cliprect,
+ TRANSPARENCY_PEN,0
+ );
+ }
+ }
+ source += 0x4;
+ }
+
+}
+
+VIDEO_UPDATE( oneshot )
+{
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ tilemap_set_scrollx(oneshot_mid_tilemap,0, oneshot_scroll[0]-0x1f5);
+ tilemap_set_scrolly(oneshot_mid_tilemap,0, oneshot_scroll[1]);
+
+ tilemap_draw(bitmap,cliprect,oneshot_bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,oneshot_mid_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,oneshot_fg_tilemap,0,0);
+ draw_crosshairs(bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( maddonna )
+{
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ tilemap_set_scrolly(oneshot_mid_tilemap,0, oneshot_scroll[1]); // other registers aren't used so we don't know which layers they relate to
+
+ tilemap_draw(bitmap,cliprect,oneshot_mid_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,oneshot_fg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,oneshot_bg_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+// draw_crosshairs(bitmap,cliprect); // not a gun game
+
+// popmessage ("%04x %04x %04x %04x %04x %04x %04x %04x", oneshot_scroll[0],oneshot_scroll[1],oneshot_scroll[2],oneshot_scroll[3],oneshot_scroll[4],oneshot_scroll[5],oneshot_scroll[6],oneshot_scroll[7]);
+ return 0;
+}
diff --git a/src/mame/video/orbit.c b/src/mame/video/orbit.c
new file mode 100644
index 00000000000..57afc0ea392
--- /dev/null
+++ b/src/mame/video/orbit.c
@@ -0,0 +1,109 @@
+/***************************************************************************
+
+Atari Orbit video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/orbit.h"
+
+UINT8* orbit_playfield_ram;
+UINT8* orbit_sprite_ram;
+
+static tilemap* bg_tilemap;
+
+static int orbit_flip_screen;
+
+
+WRITE8_HANDLER( orbit_playfield_w )
+{
+ orbit_playfield_ram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( orbit_sprite_w )
+{
+ orbit_sprite_ram[offset] = data;
+}
+
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 code = orbit_playfield_ram[tile_index];
+
+ int flags = 0;
+
+ if (code & 0x40)
+ {
+ flags |= TILE_FLIPX;
+ }
+ if (orbit_flip_screen)
+ {
+ flags |= TILE_FLIPY;
+ }
+
+ SET_TILE_INFO(3, code & 0x3f, 0, flags);
+}
+
+
+VIDEO_START( orbit )
+{
+ bg_tilemap = tilemap_create(get_tile_info, tilemap_scan_rows, 0, 16, 16, 32, 30);
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ const UINT8* p = orbit_sprite_ram;
+
+ int i;
+
+ for (i = 0; i < 16; i++)
+ {
+ int code = *p++;
+ int vpos = *p++;
+ int hpos = *p++;
+ int flag = *p++;
+
+ int layout =
+ ((flag & 0xc0) == 0x80) ? 1 :
+ ((flag & 0xc0) == 0xc0) ? 2 : 0;
+
+ int flip_x = code & 0x40;
+ int flip_y = code & 0x80;
+
+ int zoom_x = 0x10000;
+ int zoom_y = 0x10000;
+
+ code &= 0x3f;
+
+ if (flag & 1)
+ {
+ code |= 0x40;
+ }
+ if (flag & 2)
+ {
+ zoom_x *= 2;
+ }
+
+ vpos = 240 - vpos;
+
+ hpos <<= 1;
+ vpos <<= 1;
+
+ drawgfxzoom(bitmap, machine->gfx[layout], code, 0, flip_x, flip_y,
+ hpos, vpos, cliprect, TRANSPARENCY_PEN, 0, zoom_x, zoom_y);
+ }
+}
+
+
+VIDEO_UPDATE( orbit )
+{
+ orbit_flip_screen = readinputport(3) & 8;
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/othldrby.c b/src/mame/video/othldrby.c
new file mode 100644
index 00000000000..8ca475d0be1
--- /dev/null
+++ b/src/mame/video/othldrby.c
@@ -0,0 +1,224 @@
+#include "driver.h"
+
+
+
+#define VIDEORAM_SIZE 0x1c00
+#define SPRITERAM_START 0x1800
+#define SPRITERAM_SIZE (VIDEORAM_SIZE-SPRITERAM_START)
+
+static UINT16 *vram,*buf_spriteram,*buf_spriteram2;
+
+#define VREG_SIZE 18
+static UINT16 vreg[VREG_SIZE];
+
+static tilemap *bg_tilemap[3];
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+INLINE void get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int plane)
+{
+ UINT16 attr;
+
+ tile_index = 2*tile_index + 0x800*plane;
+ attr = vram[tile_index];
+ SET_TILE_INFO(
+ 1,
+ vram[tile_index+1],
+ attr & 0x7f,
+ 0);
+ tileinfo->category = (attr & 0x0600) >> 9;
+}
+
+static TILE_GET_INFO( get_tile_info0 )
+{
+ get_tile_info(machine,tileinfo,tile_index,0);
+}
+
+static TILE_GET_INFO( get_tile_info1 )
+{
+ get_tile_info(machine,tileinfo,tile_index,1);
+}
+
+static TILE_GET_INFO( get_tile_info2 )
+{
+ get_tile_info(machine,tileinfo,tile_index,2);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( othldrby )
+{
+ bg_tilemap[0] = tilemap_create(get_tile_info0,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ bg_tilemap[1] = tilemap_create(get_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ bg_tilemap[2] = tilemap_create(get_tile_info2,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ vram = auto_malloc(VIDEORAM_SIZE * sizeof(vram[0]));
+ buf_spriteram = auto_malloc(2*SPRITERAM_SIZE * sizeof(buf_spriteram[0]));
+
+ buf_spriteram2 = buf_spriteram + SPRITERAM_SIZE;
+
+ tilemap_set_transparent_pen(bg_tilemap[0],0);
+ tilemap_set_transparent_pen(bg_tilemap[1],0);
+ tilemap_set_transparent_pen(bg_tilemap[2],0);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+static UINT32 vram_addr,vreg_addr;
+
+WRITE16_HANDLER( othldrby_videoram_addr_w )
+{
+ vram_addr = data;
+}
+
+READ16_HANDLER( othldrby_videoram_r )
+{
+ if (vram_addr < VIDEORAM_SIZE)
+ return vram[vram_addr++];
+ else
+ {
+ popmessage("GFXRAM OUT OF BOUNDS %04x",vram_addr);
+ return 0;
+ }
+}
+
+WRITE16_HANDLER( othldrby_videoram_w )
+{
+ if (vram_addr < VIDEORAM_SIZE)
+ {
+ if (vram_addr < SPRITERAM_START)
+ tilemap_mark_tile_dirty(bg_tilemap[vram_addr/0x800],(vram_addr&0x7ff)/2);
+ vram[vram_addr++] = data;
+ }
+ else
+ popmessage("GFXRAM OUT OF BOUNDS %04x",vram_addr);
+}
+
+WRITE16_HANDLER( othldrby_vreg_addr_w )
+{
+ vreg_addr = data & 0x7f; /* bit 7 is set when screen is flipped */
+}
+
+WRITE16_HANDLER( othldrby_vreg_w )
+{
+ if (vreg_addr < VREG_SIZE)
+ vreg[vreg_addr++] = data;
+ else
+ popmessage("%06x: VREG OUT OF BOUNDS %04x",activecpu_get_pc(),vreg_addr);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int priority)
+{
+ int offs;
+
+ for (offs = 0;offs < SPRITERAM_SIZE;offs += 4)
+ {
+ int x,y,color,code,sx,sy,flipx,flipy,sizex,sizey,pri;
+
+
+ pri = (buf_spriteram[offs] & 0x0600) >> 9;
+ if (pri != priority) continue;
+
+ flipx = buf_spriteram[offs] & 0x1000;
+ flipy = 0;
+ color = (buf_spriteram[offs] & 0x01fc) >> 2;
+ code = buf_spriteram[offs+1] | ((buf_spriteram[offs] & 0x0003) << 16);
+ sx = (buf_spriteram[offs+2] >> 7);
+ sy = (buf_spriteram[offs+3] >> 7);
+ sizex = (buf_spriteram[offs+2] & 0x000f) + 1;
+ sizey = (buf_spriteram[offs+3] & 0x000f) + 1;
+
+ if (flip_screen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+ sx = 246 - sx;
+ sy = 16 - sy;
+ }
+
+ for (y = 0;y < sizey;y++)
+ {
+ for (x = 0;x < sizex;x++)
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ code + x + sizex * y,
+ color,
+ flipx,flipy,
+ (sx + (flipx ? (-8*(x+1)+1) : 8*x) - vreg[6]+44) & 0x1ff,(sy + (flipy ? (-8*(y+1)+1) : 8*y) - vreg[7]-9) & 0x1ff,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( othldrby )
+{
+ int layer;
+
+
+ flip_screen_set(vreg[0x0f] & 0x80);
+
+ for (layer = 0;layer < 3;layer++)
+ {
+ if (flip_screen)
+ {
+ tilemap_set_scrollx(bg_tilemap[layer],0,vreg[2*layer]+59);
+ tilemap_set_scrolly(bg_tilemap[layer],0,vreg[2*layer+1]+248);
+ }
+ else
+ {
+ tilemap_set_scrollx(bg_tilemap[layer],0,vreg[2*layer]-58);
+ tilemap_set_scrolly(bg_tilemap[layer],0,vreg[2*layer+1]+9);
+ }
+ }
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ for (layer = 0;layer < 3;layer++)
+ tilemap_draw(bitmap,cliprect,bg_tilemap[layer],0,0);
+ draw_sprites(machine,bitmap,cliprect,0);
+ for (layer = 0;layer < 3;layer++)
+ tilemap_draw(bitmap,cliprect,bg_tilemap[layer],1,0);
+ draw_sprites(machine,bitmap,cliprect,1);
+ for (layer = 0;layer < 3;layer++)
+ tilemap_draw(bitmap,cliprect,bg_tilemap[layer],2,0);
+ draw_sprites(machine,bitmap,cliprect,2);
+ for (layer = 0;layer < 3;layer++)
+ tilemap_draw(bitmap,cliprect,bg_tilemap[layer],3,0);
+ draw_sprites(machine,bitmap,cliprect,3);
+ return 0;
+}
+
+VIDEO_EOF( othldrby )
+{
+ /* sprites need to be delayed two frames */
+ memcpy(buf_spriteram,buf_spriteram2,SPRITERAM_SIZE*sizeof(buf_spriteram[0]));
+ memcpy(buf_spriteram2,&vram[SPRITERAM_START],SPRITERAM_SIZE*sizeof(buf_spriteram[0]));
+}
diff --git a/src/mame/video/othunder.c b/src/mame/video/othunder.c
new file mode 100644
index 00000000000..380a7f35db4
--- /dev/null
+++ b/src/mame/video/othunder.c
@@ -0,0 +1,346 @@
+#include "driver.h"
+#include "video/taitoic.h"
+
+#define TC0100SCN_GFX_NUM 1
+
+UINT16 *othunder_ram;
+
+struct tempsprite
+{
+ int gfx;
+ int code,color;
+ int flipx,flipy;
+ int x,y;
+ int zoomx,zoomy;
+ int primask;
+};
+static struct tempsprite *spritelist;
+
+static int taito_hide_pixels;
+
+
+
+/**********************************************************/
+
+static VIDEO_START( othunder_core )
+{
+ /* Up to $800/8 big sprites, requires 0x100 * sizeof(*spritelist)
+ Multiply this by 32 to give room for the number of small sprites,
+ which are what actually get put in the structure. */
+
+ spritelist = auto_malloc(0x2000 * sizeof(*spritelist));
+
+ TC0100SCN_vh_start(machine,1,TC0100SCN_GFX_NUM,taito_hide_pixels,0,0,0,0,0,0);
+
+ if (has_TC0110PCR())
+ TC0110PCR_vh_start();
+}
+
+VIDEO_START( othunder )
+{
+ /* There is a problem here. 4 is correct for text layer/sprite
+ alignment, but the bg layers [or one of them] are wrong */
+
+ taito_hide_pixels = 4;
+ video_start_othunder_core(machine);
+}
+
+
+/************************************************************
+ SPRITE DRAW ROUTINE
+
+It draws a series of small tiles ("chunks") together to
+create a big sprite. The spritemap rom provides the lookup
+table for this. We look up the 16x8 sprite chunks from
+the spritemap rom, creating each 64x64 sprite as follows:
+
+ 0 1 2 3
+ 4 5 6 7
+ 8 9 10 11
+ 12 13 14 15
+ 16 17 18 19
+ 20 21 22 23
+ 24 25 26 27
+ 28 29 30 31
+
+The game makes heavy use of sprite zooming.
+
+ ***
+
+NB: unused portions of the spritemap rom contain hex FF's.
+It is a useful coding check to warn in the log if these
+are being accessed. [They can be inadvertently while
+spriteram is being tested, take no notice of that.]
+
+
+ Othunder (modified table from Raine)
+
+ Byte | Bit(s) | Description
+ -----+76543210+-------------------------------------
+ 0 |xxxxxxx.| ZoomY (0 min, 63 max - msb unused as sprites are 64x64)
+ 0 |.......x| Y position (High)
+ 1 |xxxxxxxx| Y position (Low)
+ 2 |x.......| Sprite/BG Priority (0=sprites high)
+ 2 |.x......| Flip X
+ 2 |..?????.| unknown/unused ?
+ 2 |.......x| X position (High)
+ 3 |xxxxxxxx| X position (Low)
+ 4 |xxxxxxxx| Palette bank
+ 5 |?.......| unknown/unused ?
+ 5 |.xxxxxxx| ZoomX (0 min, 63 max - msb unused as sprites are 64x64)
+ 6 |x.......| Flip Y
+ 6 |.??.....| unknown/unused ?
+ 6 |...xxxxx| Sprite Tile high (2 msbs unused - 3/4 of spritemap rom empty)
+ 7 |xxxxxxxx| Sprite Tile low
+
+********************************************************/
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,const int *primasks,int y_offs)
+{
+ UINT16 *spritemap = (UINT16 *)memory_region(REGION_USER1);
+ UINT16 tile_mask = (machine->gfx[0]->total_elements) - 1;
+ int offs, data, tilenum, color, flipx, flipy;
+ int x, y, priority, curx, cury;
+ int sprites_flipscreen = 0;
+ int zoomx, zoomy, zx, zy;
+ int sprite_chunk,map_offset,code,j,k,px,py;
+ int bad_chunks;
+
+ /* pdrawgfx() needs us to draw sprites front to back, so we have to build a list
+ while processing sprite ram and then draw them all at the end */
+ struct tempsprite *sprite_ptr = spritelist;
+
+ for (offs = (spriteram_size/2)-4;offs >=0;offs -= 4)
+ {
+ data = spriteram16[offs+0];
+ zoomy = (data & 0xfe00) >> 9;
+ y = data & 0x1ff;
+
+ data = spriteram16[offs+1];
+ flipx = (data & 0x4000) >> 14;
+ priority = (data & 0x8000) >> 15;
+ x = data & 0x1ff;
+
+ data = spriteram16[offs+2];
+ color = (data & 0xff00) >> 8;
+ zoomx = (data & 0x7f);
+
+ data = spriteram16[offs+3];
+ tilenum = data & 0x1fff; // $80000 spritemap rom maps up to $2000 64x64 sprites
+ flipy = (data & 0x8000) >> 15;
+
+ if (!tilenum) continue;
+
+ map_offset = tilenum << 5;
+
+ zoomx += 1;
+ zoomy += 1;
+
+ y += y_offs;
+
+ /* treat coords as signed */
+ if (x>0x140) x -= 0x200;
+ if (y>0x140) y -= 0x200;
+
+ bad_chunks = 0;
+
+ for (sprite_chunk=0;sprite_chunk<32;sprite_chunk++)
+ {
+ k = sprite_chunk % 4; /* 4 chunks per row */
+ j = sprite_chunk / 4; /* 8 rows */
+
+ px = k;
+ py = j;
+ if (flipx) px = 3-k; /* pick tiles back to front for x and y flips */
+ if (flipy) py = 7-j;
+
+ code = spritemap[map_offset + px + (py<<2)] &tile_mask;
+
+ if (code==0xffff)
+ {
+ bad_chunks += 1;
+ continue;
+ }
+
+ curx = x + ((k*zoomx)/4);
+ cury = y + ((j*zoomy)/8);
+
+ zx= x + (((k+1)*zoomx)/4) - curx;
+ zy= y + (((j+1)*zoomy)/8) - cury;
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 320 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ sprite_ptr->code = code;
+ sprite_ptr->color = color;
+ sprite_ptr->flipx = flipx;
+ sprite_ptr->flipy = flipy;
+ sprite_ptr->x = curx;
+ sprite_ptr->y = cury;
+ sprite_ptr->zoomx = zx << 12;
+ sprite_ptr->zoomy = zy << 13;
+
+ if (primasks)
+ {
+ sprite_ptr->primask = primasks[priority];
+ sprite_ptr++;
+ }
+ else
+ {
+ drawgfxzoom(bitmap,machine->gfx[0],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,TRANSPARENCY_PEN,0,
+ sprite_ptr->zoomx,sprite_ptr->zoomy);
+ }
+ }
+
+ if (bad_chunks)
+logerror("Sprite number %04x had %02x invalid chunks\n",tilenum,bad_chunks);
+ }
+
+ /* this happens only if primsks != NULL */
+ while (sprite_ptr != spritelist)
+ {
+ sprite_ptr--;
+
+ pdrawgfxzoom(bitmap,machine->gfx[0],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,TRANSPARENCY_PEN,0,
+ sprite_ptr->zoomx,sprite_ptr->zoomy,
+ sprite_ptr->primask);
+ }
+}
+
+
+/**************************************************************
+ SCREEN REFRESH
+**************************************************************/
+
+VIDEO_UPDATE( othunder )
+{
+ int layer[3];
+
+ TC0100SCN_tilemap_update(machine);
+
+ layer[0] = TC0100SCN_bottomlayer(0);
+ layer[1] = layer[0]^1;
+ layer[2] = 2;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* Ensure screen blanked even when bottom layer not drawn due to disable bit */
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0],TILEMAP_DRAW_OPAQUE,1);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[1],0,2);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[2],0,4);
+
+ /* Sprites can be under/over the layer below text layer */
+ {
+ static const int primasks[2] = {0xf0,0xfc};
+ draw_sprites(machine, bitmap,cliprect,primasks,3);
+ }
+
+ /* Draw artificial gun targets */
+ {
+ int rawx, rawy, centrex, centrey, screenx, screeny;
+
+ /* calculate p1 screen co-ords by matching routine at $A932 */
+ rawx = othunder_ram[0x2848/2];
+ centrex = othunder_ram[0xa046/2];
+ if (rawx <= centrex)
+ {
+ rawx = centrex - rawx;
+ screenx = rawx * othunder_ram[0xa04e/2] + (((rawx * othunder_ram[0xa050/2]) & 0xffff0000) >> 16);
+ screenx = 0xa0 - screenx;
+ if (screenx < 0) screenx = 0;
+ }
+ else
+ {
+ if (rawx > othunder_ram[0xa028/2]) rawx = othunder_ram[0xa028/2];
+ rawx -= centrex;
+ screenx = rawx * othunder_ram[0xa056/2] + (((rawx * othunder_ram[0xa058/2]) & 0xffff0000) >> 16);
+ screenx += 0xa0;
+ if (screenx > 0x140) screenx = 0x140;
+ }
+ rawy = othunder_ram[0x284a/2];
+ centrey = othunder_ram[0xa048/2];
+ if (rawy <= centrey)
+ {
+ rawy = centrey - rawy;
+ screeny = rawy * othunder_ram[0xa052/2] + (((rawy * othunder_ram[0xa054/2]) & 0xffff0000) >> 16);
+ screeny = 0x78 - screeny;
+ if (screeny < 0) screeny = 0;
+ }
+ else
+ {
+ if (rawy > othunder_ram[0xa030/2]) rawy = othunder_ram[0xa030/2];
+ rawy -= centrey;
+ screeny = rawy * othunder_ram[0xa05a/2] + (((rawy * othunder_ram[0xa05c/2]) & 0xffff0000) >> 16);
+ screeny += 0x78;
+ if (screeny > 0xf0) screeny = 0xf0;
+ }
+
+ // fudge y to show in centre of scope/hit sprite, note that screenx, screeny
+ // were confirmed to match those stored by the game at $82732, $82734
+ screeny += 2;
+
+ /* calculate p2 screen co-ords by matching routine at $AA48 */
+ rawx = othunder_ram[0x284c/2];
+ centrex = othunder_ram[0xa04a/2];
+ if (rawx <= centrex)
+ {
+ rawx = centrex - rawx;
+ screenx = rawx * othunder_ram[0xa05e/2] + (((rawx * othunder_ram[0xa060/2]) & 0xffff0000) >> 16);
+ screenx = 0xa0 - screenx;
+ if (screenx < 0) screenx = 0;
+ }
+ else
+ {
+ if (rawx > othunder_ram[0xa038/2]) rawx = othunder_ram[0xa038/2];
+ rawx -= centrex;
+ screenx = rawx * othunder_ram[0xa066/2] + (((rawx * othunder_ram[0xa068/2]) & 0xffff0000) >> 16);
+ screenx += 0xa0;
+ if (screenx > 0x140) screenx = 0x140;
+ }
+ rawy = othunder_ram[0x284e/2];
+ centrey = othunder_ram[0xa04c/2];
+ if (rawy <= centrey)
+ {
+ rawy = centrey - rawy;
+ screeny = rawy * othunder_ram[0xa062/2] + (((rawy * othunder_ram[0xa064/2]) & 0xffff0000) >> 16);
+ screeny = 0x78 - screeny;
+ if (screeny < 0) screeny = 0;
+ }
+ else
+ {
+ if (rawy > othunder_ram[0xa040/2]) rawy = othunder_ram[0xa040/2];
+ rawy -= centrey;
+ screeny = rawy * othunder_ram[0xa06a/2] + (((rawy * othunder_ram[0xa06c/2]) & 0xffff0000) >> 16);
+ screeny += 0x78;
+ if (screeny > 0xf0) screeny = 0xf0;
+ }
+
+ // fudge y to show in centre of scope/hit sprite, note that screenx, screeny
+ // were confirmed to match those stored by the game at $82736, $82738
+ screeny += 2;
+ }
+ return 0;
+}
+
diff --git a/src/mame/video/overdriv.c b/src/mame/video/overdriv.c
new file mode 100644
index 00000000000..dff509c287e
--- /dev/null
+++ b/src/mame/video/overdriv.c
@@ -0,0 +1,87 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+static int zoom_colorbase[2],road_colorbase[2],sprite_colorbase;
+
+
+/***************************************************************************
+
+ Callbacks for the K053247
+
+***************************************************************************/
+
+static void overdriv_sprite_callback(int *code,int *color,int *priority_mask)
+{
+ int pri = (*color & 0xffe0) >> 5; /* ??????? */
+ if (pri) *priority_mask = 0x02;
+ else *priority_mask = 0x00;
+
+ *color = sprite_colorbase + (*color & 0x001f);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051316
+
+***************************************************************************/
+
+static void zoom_callback_0(int *code,int *color,int *flags)
+{
+ *flags = (*color & 0x40) ? TILE_FLIPX : 0;
+ *code |= ((*color & 0x03) << 8);
+ *color = zoom_colorbase[0] + ((*color & 0x3c) >> 2);
+}
+
+static void zoom_callback_1(int *code,int *color,int *flags)
+{
+ *flags = (*color & 0x40) ? TILE_FLIPX : 0;
+ *code |= ((*color & 0x03) << 8);
+ *color = zoom_colorbase[1] + ((*color & 0x3c) >> 2);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( overdriv )
+{
+ K053251_vh_start();
+ K051316_vh_start_0(machine,REGION_GFX2,4,TRUE,0,zoom_callback_0);
+ K051316_vh_start_1(machine,REGION_GFX3,4,FALSE,0,zoom_callback_1);
+ K053247_vh_start(machine, REGION_GFX1,77,22,NORMAL_PLANE_ORDER,overdriv_sprite_callback);
+
+ K051316_wraparound_enable(0,1);
+ K051316_set_offset(0,14,-1);
+ K051316_set_offset(1,15,0);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( overdriv )
+{
+ sprite_colorbase = K053251_get_palette_index(K053251_CI0);
+ road_colorbase[1] = K053251_get_palette_index(K053251_CI1);
+ road_colorbase[0] = K053251_get_palette_index(K053251_CI2);
+ zoom_colorbase[1] = K053251_get_palette_index(K053251_CI3);
+ zoom_colorbase[0] = K053251_get_palette_index(K053251_CI4);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ K051316_zoom_draw_0(bitmap,cliprect,0,0);
+ K051316_zoom_draw_1(bitmap,cliprect,0,1);
+
+ K053247_sprites_draw(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/pacland.c b/src/mame/video/pacland.c
new file mode 100644
index 00000000000..36a2c80667f
--- /dev/null
+++ b/src/mame/video/pacland.c
@@ -0,0 +1,407 @@
+/***************************************************************************
+
+Sprite/tile priority is quite complex in this game: it is handled both
+internally to the CUS29 chip, and externally to it.
+
+The bg tilemap is always behind everything.
+
+The CUS29 mixes two 8-bit inputs, one from sprites and one from the fg
+tilemap. 0xff is the transparent color. CUS29 also takes a PRI input, telling
+which of the two color inputs has priority. Additionally, sprite pixels of
+color >= 0xf0 always have priority.
+The priority bit comes from the tilemap RAM, but through an additional filter:
+sprite pixels of color < 0x80 act as a "cookie cut" mask, handled externally,
+which overload the PRI bit, making the sprite always have priority. The external
+RAM that holds this mask contains the OR of all sprite pixels drawn at a certain
+position, therefore when sprites overlap, it is sufficient for one of them to
+have color < 0x80 to promote priority of the frontmost sprite. This is used
+to draw the light in round 19.
+
+The CUS29 outputs an 8-bit pixel color, but only the bottom 7 bits are externally
+checked to determine whether it is transparent or not; therefore, both 0xff and
+0x7f are transparent. This is again used to draw the light in round 19, because
+sprite color 0x7f will erase the tilemap and force it to be transparent.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *pacland_videoram,*pacland_videoram2,*pacland_spriteram;
+
+static UINT8 palette_bank;
+static const UINT8 *pacland_color_prom;
+
+static colortable *pacland_colortable;
+static tilemap *bg_tilemap, *fg_tilemap;
+static mame_bitmap *fg_bitmap;
+
+static UINT32 *transmask[3];
+
+static UINT16 scroll0,scroll1;
+
+/***************************************************************************
+
+ Convert the color PROMs.
+
+ Pacland has one 1024x8 and one 1024x4 palette PROM; and three 1024x8 lookup
+ table PROMs (sprites, bg tiles, fg tiles).
+ The palette has 1024 colors, but it is bank switched (4 banks) and only 256
+ colors are visible at a time. So, instead of creating a static palette, we
+ modify it when the bank switching takes place.
+ The color PROMs are connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 2.2kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ -- 1 kohm resistor -- RED
+ bit 0 -- 2.2kohm resistor -- RED
+
+ bit 3 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 1 kohm resistor -- BLUE
+ bit 0 -- 2.2kohm resistor -- BLUE
+
+***************************************************************************/
+
+static void switch_palette(running_machine *machine)
+{
+ int i;
+ const UINT8 *color_prom = pacland_color_prom + 256 * palette_bank;
+
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,bit3;
+ int r,g,b;
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[0] >> 4) & 0x01;
+ bit1 = (color_prom[0] >> 5) & 0x01;
+ bit2 = (color_prom[0] >> 6) & 0x01;
+ bit3 = (color_prom[0] >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[1024] >> 0) & 0x01;
+ bit1 = (color_prom[1024] >> 1) & 0x01;
+ bit2 = (color_prom[1024] >> 2) & 0x01;
+ bit3 = (color_prom[1024] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ color_prom++;
+
+ colortable_palette_set_color(pacland_colortable,i,MAKE_RGB(r,g,b));
+ }
+}
+
+PALETTE_INIT( pacland )
+{
+ int i;
+
+ /* allocate the colortable */
+ pacland_colortable = colortable_alloc(machine, 256);
+
+ pacland_color_prom = color_prom; /* we'll need this later */
+ /* skip the palette data, it will be initialized later */
+ color_prom += 2 * 0x400;
+ /* color_prom now points to the beginning of the lookup table */
+
+ for (i = 0;i < 0x400;i++)
+ colortable_entry_set_value(pacland_colortable, machine->gfx[0]->color_base + i, *color_prom++);
+
+ /* Background */
+ for (i = 0;i < 0x400;i++)
+ colortable_entry_set_value(pacland_colortable, machine->gfx[1]->color_base + i, *color_prom++);
+
+ /* Sprites */
+ for (i = 0;i < 0x400;i++)
+ colortable_entry_set_value(pacland_colortable, machine->gfx[2]->color_base + i, *color_prom++);
+
+ palette_bank = 0;
+ switch_palette(machine);
+
+ /* precalculate transparency masks for sprites */
+ transmask[0] = auto_malloc(64 * sizeof(transmask[0][0]));
+ transmask[1] = auto_malloc(64 * sizeof(transmask[0][0]));
+ transmask[2] = auto_malloc(64 * sizeof(transmask[0][0]));
+ for (i = 0; i < 64; i++)
+ {
+ int palentry;
+
+ /* start with no transparency */
+ transmask[0][i] = transmask[1][i] = transmask[2][i] = 0;
+
+ /* iterate over all palette entries except the last one */
+ for (palentry = 0; palentry < 0x100; palentry++)
+ {
+ UINT32 mask = colortable_get_transpen_mask(pacland_colortable, machine->gfx[2], i, palentry);
+
+ /* transmask[0] is a mask that is used to draw only high priority sprite pixels; thus, pens
+ $00-$7F are opaque, and others are transparent */
+ if (palentry >= 0x80)
+ transmask[0][i] |= mask;
+
+ /* transmask[1] is a normal drawing masking with palette entries $7F and $FF transparent */
+ if ((palentry & 0x7f) == 0x7f)
+ transmask[1][i] |= mask;
+
+ /* transmask[2] is a mask of the topmost priority sprite pixels; thus pens $F0-$FE are
+ opaque, and others are transparent */
+ if (palentry < 0xf0 || palentry == 0xff)
+ transmask[2][i] |= mask;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int offs = tile_index * 2;
+ int attr = pacland_videoram2[offs + 1];
+ int code = pacland_videoram2[offs] + ((attr & 0x01) << 8);
+ int color = ((attr & 0x3e) >> 1) + ((code & 0x1c0) >> 1);
+ int flags = TILE_FLIPYX(attr >> 6);
+
+ SET_TILE_INFO(1, code, color, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int offs = tile_index * 2;
+ int attr = pacland_videoram[offs + 1];
+ int code = pacland_videoram[offs] + ((attr & 0x01) << 8);
+ int color = ((attr & 0x1e) >> 1) + ((code & 0x1e0) >> 1);
+ int flags = TILE_FLIPYX(attr >> 6);
+
+ tileinfo->category = (attr & 0x20) ? 1 : 0;
+ tileinfo->group = color;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( pacland )
+{
+ int color;
+
+ fg_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ fillbitmap(fg_bitmap, 0xffff, NULL);
+
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_scroll_rows(fg_tilemap, 32);
+
+ /* create one group per color code; for each group, set the transparency mask
+ to correspond to the pens that are 0x7f or 0xff */
+ assert(machine->gfx[0]->total_colors <= TILEMAP_NUM_GROUPS);
+ for (color = 0; color < machine->gfx[0]->total_colors; color++)
+ {
+ UINT32 mask = colortable_get_transpen_mask(pacland_colortable, machine->gfx[0], color, 0x7f);
+ mask |= colortable_get_transpen_mask(pacland_colortable, machine->gfx[0], color, 0xff);
+ tilemap_set_transmask(fg_tilemap, color, mask, 0);
+ }
+
+ spriteram = pacland_spriteram + 0x780;
+ spriteram_2 = spriteram + 0x800;
+ spriteram_3 = spriteram_2 + 0x800;
+
+ state_save_register_global(palette_bank);
+ state_save_register_global(scroll0);
+ state_save_register_global(scroll1);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( pacland_videoram_w )
+{
+ pacland_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset / 2);
+}
+
+WRITE8_HANDLER( pacland_videoram2_w )
+{
+ pacland_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+WRITE8_HANDLER( pacland_scroll0_w )
+{
+ scroll0 = data + 256 * offset;
+}
+
+WRITE8_HANDLER( pacland_scroll1_w )
+{
+ scroll1 = data + 256 * offset;
+}
+
+WRITE8_HANDLER( pacland_bankswitch_w )
+{
+ int bankaddress;
+ UINT8 *RAM = memory_region(REGION_CPU1);
+
+ bankaddress = 0x10000 + ((data & 0x07) << 13);
+ memory_set_bankptr(1,&RAM[bankaddress]);
+
+// pbc = data & 0x20;
+
+ if (palette_bank != ((data & 0x18) >> 3))
+ {
+ palette_bank = (data & 0x18) >> 3;
+ switch_palette(Machine);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+/* the sprite generator IC is the same as Mappy */
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int whichmask)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x80;offs += 2)
+ {
+ static int gfx_offs[2][2] =
+ {
+ { 0, 1 },
+ { 2, 3 }
+ };
+ int sprite = spriteram[offs] + ((spriteram_3[offs] & 0x80) << 1);
+ int color = spriteram[offs+1] & 0x3f;
+ int sx = (spriteram_2[offs+1]) + 0x100*(spriteram_3[offs+1] & 1) - 47;
+ int sy = 256 - spriteram_2[offs] + 9;
+ int flipx = (spriteram_3[offs] & 0x01);
+ int flipy = (spriteram_3[offs] & 0x02) >> 1;
+ int sizex = (spriteram_3[offs] & 0x04) >> 2;
+ int sizey = (spriteram_3[offs] & 0x08) >> 3;
+ int x,y;
+
+ sprite &= ~sizex;
+ sprite &= ~(sizey << 1);
+
+ if (flip_screen)
+ {
+ flipx ^= 1;
+ flipy ^= 1;
+ }
+
+ sy -= 16 * sizey;
+ sy = (sy & 0xff) - 32; // fix wraparound
+
+ for (y = 0;y <= sizey;y++)
+ {
+ for (x = 0;x <= sizex;x++)
+ {
+ if (whichmask != 0)
+ drawgfx(bitmap,machine->gfx[2],
+ sprite + gfx_offs[y ^ (sizey * flipy)][x ^ (sizex * flipx)],
+ color,
+ flipx,flipy,
+ sx + 16*x,sy + 16*y,
+ cliprect,TRANSPARENCY_PENS,transmask[whichmask][color]);
+ else
+ pdrawgfx(bitmap,machine->gfx[2],
+ sprite + gfx_offs[y ^ (sizey * flipy)][x ^ (sizex * flipx)],
+ color,
+ flipx,flipy,
+ sx + 16*x,sy + 16*y,
+ cliprect,TRANSPARENCY_PENS,transmask[whichmask][color],0);
+ }
+ }
+ }
+}
+
+
+static void draw_fg(mame_bitmap *bitmap, const rectangle *cliprect, int priority )
+{
+ int y, x;
+
+ /* draw tilemap transparently over it; this will leave invalid pens (0xffff)
+ anywhere where the fg_tilemap should be transparent; note that we assume
+ the fg_bitmap has been pre-erased to 0xffff */
+ tilemap_draw(fg_bitmap, cliprect, fg_tilemap, priority, 0);
+
+ /* now copy the fg_bitmap to the destination wherever the sprite pixel allows */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ const UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+ UINT16 *src = BITMAP_ADDR16(fg_bitmap, y, 0);
+ UINT16 *dst = BITMAP_ADDR16(bitmap, y, 0);
+
+ /* only copy if the priority bitmap is 0 (no high priority sprite) and the
+ source pixel is not the invalid pen; also clear to 0xffff when finished */
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ UINT16 pix = src[x];
+ if (pix != 0xffff)
+ {
+ src[x] = 0xffff;
+ if (pri[x] == 0)
+ dst[x] = pix;
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( pacland )
+{
+ int row;
+
+ for (row = 5; row < 29; row++)
+ tilemap_set_scrollx(fg_tilemap, row, flip_screen ? scroll0-7 : scroll0);
+ tilemap_set_scrollx(bg_tilemap, 0, flip_screen ? scroll1-4 : scroll1-3);
+
+ /* draw high priority sprite pixels, setting priority bitmap to non-zero
+ wherever there is a high-priority pixel; note that we draw to the bitmap
+ which is safe because the bg_tilemap draw will overwrite everything */
+ fillbitmap(priority_bitmap, 0x00, cliprect);
+ draw_sprites(machine, bitmap, cliprect, 0);
+
+ /* draw background */
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* draw low priority fg tiles */
+ draw_fg(bitmap, cliprect, 0);
+
+ /* draw sprites with regular transparency */
+ draw_sprites(machine, bitmap, cliprect, 1);
+
+ /* draw high priority fg tiles */
+ draw_fg(bitmap, cliprect, 1);
+
+ /* draw sprite pixels with colortable values >= 0xf0, which have priority over everything */
+ draw_sprites(machine, bitmap, cliprect, 2);
+ return 0;
+}
diff --git a/src/mame/video/pacman.c b/src/mame/video/pacman.c
new file mode 100644
index 00000000000..bff584f1eb5
--- /dev/null
+++ b/src/mame/video/pacman.c
@@ -0,0 +1,603 @@
+/*************************************************************************
+
+ Namco Pac Man
+
+**************************************************************************
+
+ This file is used by the Pac Man, Pengo & Jr Pac Man drivers.
+
+ Pengo & Pac Man are almost identical, the only differences being the
+ extra gfx bank in Pengo, and the need to compensate for an hardware
+ sprite positioning "bug" in Pac Man.
+
+ Jr Pac Man has the same sprite hardware as Pac Man, the extra bank
+ from Pengo and a scrolling playfield at the expense of one color per row
+ for the playfield so it can fit in the same amount of ram.
+
+**************************************************************************/
+
+#include "driver.h"
+#include "includes/pacman.h"
+#include "video/resnet.h"
+
+static colortable *pacman_colortable;
+static tilemap *bg_tilemap;
+static UINT8 charbank;
+static UINT8 spritebank;
+static UINT8 palettebank;
+static UINT8 colortablebank;
+static UINT8 flipscreen;
+static UINT8 bgpriority;
+
+static int xoffsethack;
+UINT8 *s2650games_spriteram;
+UINT8 *s2650games_tileram;
+
+static rectangle spritevisiblearea =
+{
+ 2*8, 34*8-1,
+ 0*8, 28*8-1
+};
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+
+ Pac Man has a 32x8 palette PROM and a 256x4 color lookup table PROM.
+
+ Pengo has a 32x8 palette PROM and a 1024x4 color lookup table PROM.
+
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+
+ Jr. Pac Man has two 256x4 palette PROMs (the three msb of the address are
+ grounded, so the effective colors are only 32) and one 256x4 color lookup
+ table PROM.
+
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ bit 0 -- 470 ohm resistor -- GREEN
+
+ bit 3 -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+
+PALETTE_INIT( pacman )
+{
+ static const int resistances[3] = { 1000, 470, 220 };
+ double rweights[3], gweights[3], bweights[2];
+ int i;
+
+ /* compute the color output resistor weights */
+ compute_resistor_weights(0, 255, -1.0,
+ 3, &resistances[0], rweights, 0, 0,
+ 3, &resistances[0], gweights, 0, 0,
+ 2, &resistances[1], bweights, 0, 0);
+
+ /* allocate the colortable */
+ pacman_colortable = colortable_alloc(machine, 32);
+
+ /* create a lookup table for the palette */
+ for (i = 0; i < 32; i++)
+ {
+ int bit0, bit1, bit2;
+ int r, g, b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = combine_3_weights(rweights, bit0, bit1, bit2);
+
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = combine_3_weights(gweights, bit0, bit1, bit2);
+
+ /* blue component */
+ bit0 = (color_prom[i] >> 6) & 0x01;
+ bit1 = (color_prom[i] >> 7) & 0x01;
+ b = combine_2_weights(bweights, bit0, bit1);
+
+ colortable_palette_set_color(pacman_colortable, i, MAKE_RGB(r, g, b));
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+ color_prom += 32;
+
+ /* allocate the colortable */
+ for (i = 0; i < 64*4; i++)
+ {
+ UINT8 ctabentry = color_prom[i] & 0x0f;
+
+ /* first palette bank */
+ colortable_entry_set_value(pacman_colortable, i, ctabentry);
+
+ /* second palette bank */
+ colortable_entry_set_value(pacman_colortable, i + 64*4, 0x10 + ctabentry);
+ }
+}
+
+static TILEMAP_MAPPER( pacman_scan_rows )
+{
+ int offs;
+
+ row += 2;
+ col -= 2;
+ if (col & 0x20)
+ offs = row + ((col & 0x1f) << 5);
+ else
+ offs = col + (row << 5);
+
+ return offs;
+}
+
+static TILE_GET_INFO( pacman_get_tile_info )
+{
+ int code = videoram[tile_index] | (charbank << 8);
+ int attr = (colorram[tile_index] & 0x1f) | (colortablebank << 5) | (palettebank << 6 );
+
+ SET_TILE_INFO(0,code,attr,0);
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+static void init_save_state(void)
+{
+ state_save_register_global(charbank);
+ state_save_register_global(spritebank);
+ state_save_register_global(palettebank);
+ state_save_register_global(colortablebank);
+ state_save_register_global(flipscreen);
+ state_save_register_global(bgpriority);
+}
+
+
+VIDEO_START( pacman )
+{
+ init_save_state();
+
+ charbank = 0;
+ spritebank = 0;
+ palettebank = 0;
+ colortablebank = 0;
+ flipscreen = 0;
+ bgpriority = 0;
+
+ /* In the Pac Man based games (NOT Pengo) the first two sprites must be offset */
+ /* one pixel to the left to get a more correct placement */
+ xoffsethack = 1;
+
+ bg_tilemap = tilemap_create( pacman_get_tile_info, pacman_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 36, 28 );
+
+ tilemap_set_scrolldx( bg_tilemap, 0, 384 - 288 );
+ tilemap_set_scrolldy( bg_tilemap, 0, 264 - 224 );
+}
+
+WRITE8_HANDLER( pacman_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty( bg_tilemap, offset );
+}
+
+WRITE8_HANDLER( pacman_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty( bg_tilemap, offset );
+}
+
+WRITE8_HANDLER( pacman_flipscreen_w )
+{
+ flipscreen = data & 1;
+ tilemap_set_flip( bg_tilemap, flipscreen * ( TILEMAP_FLIPX + TILEMAP_FLIPY ) );
+}
+
+
+VIDEO_UPDATE( pacman )
+{
+ if (bgpriority != 0)
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ else
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_OPAQUE,0);
+
+ if( spriteram_size )
+ {
+ int offs;
+
+ rectangle spriteclip = spritevisiblearea;
+ sect_rect(&spriteclip, cliprect);
+
+ /* Draw the sprites. Note that it is important to draw them exactly in this */
+ /* order, to have the correct priorities. */
+ for (offs = spriteram_size - 2;offs > 2*2;offs -= 2)
+ {
+ int color;
+ int sx,sy;
+
+ sx = 272 - spriteram_2[offs + 1];
+ sy = spriteram_2[offs] - 31;
+ color = ( spriteram[offs + 1] & 0x1f ) | (colortablebank << 5) | (palettebank << 6 );
+
+ drawgfx(bitmap,machine->gfx[1],
+ ( spriteram[offs] >> 2 ) | (spritebank << 6),
+ color,
+ spriteram[offs] & 1,spriteram[offs] & 2,
+ sx,sy,
+ &spriteclip,TRANSPARENCY_PENS,
+ colortable_get_transpen_mask(pacman_colortable, machine->gfx[1], color & 0x3f, 0));
+
+ /* also plot the sprite with wraparound (tunnel in Crush Roller) */
+ drawgfx(bitmap,machine->gfx[1],
+ ( spriteram[offs] >> 2 ) | (spritebank << 6),
+ color,
+ spriteram[offs] & 1,spriteram[offs] & 2,
+ sx - 256,sy,
+ &spriteclip,TRANSPARENCY_PENS,
+ colortable_get_transpen_mask(pacman_colortable, machine->gfx[1], color & 0x3f, 0));
+ }
+ /* In the Pac Man based games (NOT Pengo) the first two sprites must be offset */
+ /* one pixel to the left to get a more correct placement */
+ for (offs = 2*2;offs >= 0;offs -= 2)
+ {
+ int color;
+ int sx,sy;
+
+ sx = 272 - spriteram_2[offs + 1];
+ sy = spriteram_2[offs] - 31;
+ color = ( spriteram[offs + 1] & 0x1f ) | (colortablebank << 5) | (palettebank << 6 );
+
+ drawgfx(bitmap,machine->gfx[1],
+ ( spriteram[offs] >> 2 ) | (spritebank << 6),
+ color,
+ spriteram[offs] & 1,spriteram[offs] & 2,
+ sx,sy + xoffsethack,
+ &spriteclip,TRANSPARENCY_PENS,
+ colortable_get_transpen_mask(pacman_colortable, machine->gfx[1], color & 0x3f, 0));
+
+ /* also plot the sprite with wraparound (tunnel in Crush Roller) */
+ drawgfx(bitmap,machine->gfx[1],
+ ( spriteram[offs] >> 2 ) | (spritebank << 6),
+ color,
+ spriteram[offs] & 2,spriteram[offs] & 1,
+ sx - 256,sy + xoffsethack,
+ &spriteclip,TRANSPARENCY_PENS,
+ colortable_get_transpen_mask(pacman_colortable, machine->gfx[1], color & 0x3f, 0));
+ }
+ }
+
+ if (bgpriority != 0)
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ return 0;
+}
+
+
+/*************************************************************************
+
+ Sega Pengo
+
+**************************************************************************/
+
+VIDEO_START( pengo )
+{
+ init_save_state();
+
+ charbank = 0;
+ spritebank = 0;
+ palettebank = 0;
+ colortablebank = 0;
+ flipscreen = 0;
+ bgpriority = 0;
+
+ xoffsethack = 0;
+
+ bg_tilemap = tilemap_create( pacman_get_tile_info, pacman_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 36, 28 );
+}
+
+WRITE8_HANDLER( pengo_palettebank_w )
+{
+ if (palettebank != data)
+ {
+ palettebank = data;
+ tilemap_mark_all_tiles_dirty( bg_tilemap );
+ }
+}
+
+WRITE8_HANDLER( pengo_colortablebank_w )
+{
+ if (colortablebank != data)
+ {
+ colortablebank = data;
+ tilemap_mark_all_tiles_dirty( bg_tilemap );
+ }
+}
+
+WRITE8_HANDLER( pengo_gfxbank_w )
+{
+ if (charbank != (data & 1))
+ {
+ spritebank = data & 1;
+ charbank = data & 1;
+ tilemap_mark_all_tiles_dirty( bg_tilemap );
+ }
+}
+
+
+/*************************************************************************
+
+Van Van
+
+**************************************************************************/
+
+WRITE8_HANDLER( vanvan_bgcolor_w )
+{
+ int c = 0xaa * (data & 1);
+ palette_set_color(Machine,0,MAKE_RGB(c,c,c));
+}
+
+
+/*************************************************************************
+
+S2650 Games
+
+**************************************************************************/
+
+static TILE_GET_INFO( s2650_get_tile_info )
+{
+ int colbank, code, attr;
+
+ colbank = s2650games_tileram[tile_index & 0x1f] & 0x3;
+
+ code = videoram[tile_index] + (colbank << 8);
+ attr = colorram[tile_index & 0x1f];
+
+ SET_TILE_INFO(0,code,attr & 0x1f,0);
+}
+
+VIDEO_START( s2650games )
+{
+ init_save_state();
+
+ charbank = 0;
+ spritebank = 0;
+ palettebank = 0;
+ colortablebank = 0;
+ flipscreen = 0;
+ bgpriority = 0;
+
+ xoffsethack = 1;
+
+ bg_tilemap = tilemap_create( s2650_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+}
+
+VIDEO_UPDATE( s2650games )
+{
+ int offs;
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ for (offs = spriteram_size - 2;offs > 2*2;offs -= 2)
+ {
+ int color;
+ int sx,sy;
+
+
+ sx = 255 - spriteram_2[offs + 1];
+ sy = spriteram_2[offs] - 15;
+ color = spriteram[offs + 1] & 0x1f;
+
+ /* TODO: ?? */
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs] >> 2) | ((s2650games_spriteram[offs] & 3) << 6),
+ color,
+ spriteram[offs] & 1,spriteram[offs] & 2,
+ sx,sy,
+ cliprect,TRANSPARENCY_PENS,
+ colortable_get_transpen_mask(pacman_colortable, machine->gfx[1], color & 0x3f, 0));
+ }
+ /* In the Pac Man based games (NOT Pengo) the first two sprites must be offset */
+ /* one pixel to the left to get a more correct placement */
+ for (offs = 2*2;offs >= 0;offs -= 2)
+ {
+ int color;
+ int sx,sy;
+
+
+ sx = 255 - spriteram_2[offs + 1];
+ sy = spriteram_2[offs] - 15;
+ color = spriteram[offs + 1] & 0x1f;
+
+ /* TODO: ?? */
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs] >> 2) | ((s2650games_spriteram[offs] & 3)<<6),
+ color,
+ spriteram[offs] & 1,spriteram[offs] & 2,
+ sx,sy + xoffsethack,
+ cliprect,TRANSPARENCY_PENS,
+ colortable_get_transpen_mask(pacman_colortable, machine->gfx[1], color & 0x3f, 0));
+ }
+ return 0;
+}
+
+WRITE8_HANDLER( s2650games_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( s2650games_colorram_w )
+{
+ int i;
+ colorram[offset & 0x1f] = data;
+ for (i = offset; i < 0x0400; i += 32)
+ tilemap_mark_tile_dirty(bg_tilemap, i);
+}
+
+WRITE8_HANDLER( s2650games_scroll_w )
+{
+ tilemap_set_scrolly(bg_tilemap, offset, data);
+}
+
+WRITE8_HANDLER( s2650games_tilesbank_w )
+{
+ s2650games_tileram[offset] = data;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+}
+
+
+/*************************************************************************
+
+Jr. Pac-Man
+
+**************************************************************************/
+
+/*
+ 0 - 31 = column 2 - 33 attr (used for all 54 rows)
+ 64 - 1791 = column 2 - 33 code (54 rows)
+1794 - 1821 = column 34 code (28 rows)
+1826 - 1853 = column 35 code (28 rows)
+1858 - 1885 = column 0 code (28 rows)
+1890 - 1917 = column 1 code (28 rows)
+1922 - 1949 = column 34 attr (28 rows)
+1954 - 1981 = column 35 attr (28 rows)
+1986 - 2013 = column 0 attr (28 rows)
+2018 - 2045 = column 1 attr (28 rows)
+*/
+
+static TILEMAP_MAPPER( jrpacman_scan_rows )
+{
+ int offs;
+
+ row += 2;
+ col -= 2;
+ if ((col & 0x20) && (row & 0x20))
+ offs = 0;
+ else if (col & 0x20)
+ offs = row + (((col&0x3) | 0x38)<< 5);
+ else
+ offs = col + (row << 5);
+ return offs;
+}
+
+static TILE_GET_INFO( jrpacman_get_tile_info )
+{
+ int color_index, code, attr;
+ if( tile_index < 1792 )
+ {
+ color_index = tile_index & 0x1f;
+ }
+ else
+ {
+ color_index = tile_index + 0x80;
+ }
+
+ code = videoram[tile_index] | (charbank << 8);
+ attr = (videoram[color_index] & 0x1f) | (colortablebank << 5) | (palettebank << 6 );
+
+ SET_TILE_INFO(0,code,attr,0);
+}
+
+static void jrpacman_mark_tile_dirty( int offset )
+{
+ if( offset < 0x20 )
+ {
+ /* line color - mark whole line as dirty */
+ int i;
+ for( i = 2 * 0x20; i < 56 * 0x20; i += 0x20 )
+ {
+ tilemap_mark_tile_dirty( bg_tilemap, offset + i );
+ }
+ }
+ else if (offset < 1792)
+ {
+ /* tiles for playfield */
+ tilemap_mark_tile_dirty( bg_tilemap, offset );
+ }
+ else
+ {
+ /* tiles & colors for top and bottom two rows */
+ tilemap_mark_tile_dirty( bg_tilemap, offset & ~0x80 );
+ }
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+VIDEO_START( jrpacman )
+{
+ init_save_state();
+
+ charbank = 0;
+ spritebank = 0;
+ palettebank = 0;
+ colortablebank = 0;
+ flipscreen = 0;
+ bgpriority = 0;
+
+ xoffsethack = 1;
+
+ bg_tilemap = tilemap_create( jrpacman_get_tile_info,jrpacman_scan_rows,TILEMAP_TYPE_PEN,8,8,36,54 );
+
+ tilemap_set_transparent_pen( bg_tilemap, 0 );
+ tilemap_set_scroll_cols( bg_tilemap, 36 );
+}
+
+WRITE8_HANDLER( jrpacman_videoram_w )
+{
+ videoram[offset] = data;
+ jrpacman_mark_tile_dirty(offset);
+}
+
+WRITE8_HANDLER( jrpacman_charbank_w )
+{
+ if (charbank != (data & 1))
+ {
+ charbank = data & 1;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+WRITE8_HANDLER( jrpacman_spritebank_w )
+{
+ spritebank = (data & 1);
+}
+
+WRITE8_HANDLER( jrpacman_scroll_w )
+{
+ int i;
+ for( i = 2; i < 34; i++ )
+ {
+ tilemap_set_scrolly( bg_tilemap, i, data );
+ }
+}
+
+WRITE8_HANDLER( jrpacman_bgpriority_w )
+{
+ bgpriority = (data & 1);
+}
diff --git a/src/mame/video/pandoras.c b/src/mame/video/pandoras.c
new file mode 100644
index 00000000000..a3ba49d5036
--- /dev/null
+++ b/src/mame/video/pandoras.c
@@ -0,0 +1,167 @@
+#include "driver.h"
+
+static int flipscreen;
+static tilemap *layer0;
+extern UINT8 *pandoras_sharedram;
+
+/***********************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Pandora's Palace has one 32x8 palette PROM and two 256x4 lookup table
+ PROMs (one for characters, one for sprites).
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( pandoras )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = *(color_prom++) & 0x0f;
+
+ /* characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = (*(color_prom++) & 0x0f) + 0x10;
+}
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info0 )
+{
+ UINT8 attr = colorram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ videoram[tile_index] + ((attr & 0x10) << 4),
+ attr & 0x0f,
+ TILE_FLIPYX((attr & 0xc0) >> 6));
+ tileinfo->category = (attr & 0x20) >> 5;
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( pandoras )
+{
+ layer0 = tilemap_create(get_tile_info0,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+}
+
+/***************************************************************************
+
+ Memory Handlers
+
+***************************************************************************/
+
+READ8_HANDLER( pandoras_vram_r )
+{
+ return videoram[offset];
+}
+
+READ8_HANDLER( pandoras_cram_r )
+{
+ return colorram[offset];
+}
+
+WRITE8_HANDLER( pandoras_vram_w )
+{
+ tilemap_mark_tile_dirty(layer0,offset);
+ videoram[offset] = data;
+}
+
+WRITE8_HANDLER( pandoras_cram_w )
+{
+ tilemap_mark_tile_dirty(layer0,offset);
+ colorram[offset] = data;
+}
+
+WRITE8_HANDLER( pandoras_scrolly_w )
+{
+ tilemap_set_scrolly(layer0,0,data);
+}
+
+WRITE8_HANDLER( pandoras_flipscreen_w )
+{
+ flipscreen = data;
+ tilemap_set_flip(ALL_TILEMAPS, flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+}
+
+/***************************************************************************
+
+ Screen Refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8* sr)
+{
+ int offs;
+
+ for (offs = 0; offs < 0x100; offs += 4)
+ {
+ int sx = sr[offs + 1];
+ int sy = 240 - sr[offs];
+ int nflipx = sr[offs + 3] & 0x40;
+ int nflipy = sr[offs + 3] & 0x80;
+
+ drawgfx(bitmap,machine->gfx[1],
+ sr[offs + 2],
+ sr[offs + 3] & 0x0f,
+ !nflipx,!nflipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_COLOR,0);
+ }
+}
+
+VIDEO_UPDATE( pandoras )
+{
+ tilemap_draw( bitmap,cliprect, layer0, 1 ,0);
+ draw_sprites( machine, bitmap,cliprect, &pandoras_sharedram[0x800] );
+ tilemap_draw( bitmap,cliprect, layer0, 0 ,0);
+ return 0;
+}
diff --git a/src/mame/video/paradise.c b/src/mame/video/paradise.c
new file mode 100644
index 00000000000..e45b091ab98
--- /dev/null
+++ b/src/mame/video/paradise.c
@@ -0,0 +1,324 @@
+/***************************************************************************
+
+ -= Paradise / Target Ball / Torus =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z with:
+
+ Q shows the background layer
+ W shows the midground layer
+ E shows the foreground layer
+ R shows the pixmap layer
+ A shows sprites
+
+ There are 4 Fixed 256 x 256 Layers.
+
+ Background tiles are 8x8x4 with a register selecting which
+ color code to use.
+
+ midground and foreground tiles are 8x8x8 with no color code.
+ Then there's a 16 color pixel layer.
+
+ Bog standard 16x16x8 sprites, apparently with no color code nor flipping.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "paradise.h"
+
+/* Variables that driver has access to: */
+
+UINT8 *paradise_vram_0,*paradise_vram_1,*paradise_vram_2;
+int paradise_sprite_inc;
+
+/* Variables only used here */
+
+static UINT8 paradise_palbank, paradise_priority;
+
+WRITE8_HANDLER( paradise_flipscreen_w )
+{
+ flip_screen_set(data ? 0 : 1);
+}
+
+WRITE8_HANDLER( tgtball_flipscreen_w )
+{
+ flip_screen_set(data ? 1 : 0);
+}
+
+
+/* 800 bytes for red, followed by 800 bytes for green & 800 bytes for blue */
+WRITE8_HANDLER( paradise_palette_w )
+{
+ paletteram[offset] = data;
+ offset %= 0x800;
+ palette_set_color_rgb(Machine,offset, paletteram[offset + 0x800 * 0],
+ paletteram[offset + 0x800 * 1],
+ paletteram[offset + 0x800 * 2] );
+}
+
+/***************************************************************************
+
+ Tilemaps
+
+ Offset:
+
+ $000.b Code (Low Bits)
+ $400.b Code (High Bits)
+
+***************************************************************************/
+
+static tilemap *tilemap_0,*tilemap_1,*tilemap_2;
+
+/* Background */
+WRITE8_HANDLER( paradise_vram_0_w )
+{
+ paradise_vram_0[offset] = data;
+ tilemap_mark_tile_dirty(tilemap_0, offset % 0x400);
+}
+
+/* 16 color tiles with paradise_palbank as color code */
+WRITE8_HANDLER( paradise_palbank_w )
+{
+ int i;
+ int bank1 = (data & 0x0e) | 1;
+ int bank2 = (data & 0xf0);
+
+ for (i = 0; i < 15; i++)
+ palette_set_color_rgb(Machine,0x800+i, paletteram[0x200 + bank2 + i + 0x800 * 0],
+ paletteram[0x200 + bank2 + i + 0x800 * 1],
+ paletteram[0x200 + bank2 + i + 0x800 * 2] );
+ if (paradise_palbank != bank1)
+ {
+ paradise_palbank = bank1;
+ tilemap_mark_all_tiles_dirty(tilemap_0);
+ }
+}
+
+static TILE_GET_INFO( get_tile_info_0 )
+{
+ int code = paradise_vram_0[tile_index] + (paradise_vram_0[tile_index + 0x400] << 8);
+ SET_TILE_INFO(1, code, paradise_palbank, 0);
+}
+
+
+/* Midground */
+WRITE8_HANDLER( paradise_vram_1_w )
+{
+ paradise_vram_1[offset] = data;
+ tilemap_mark_tile_dirty(tilemap_1, offset % 0x400);
+}
+
+static TILE_GET_INFO( get_tile_info_1 )
+{
+ int code = paradise_vram_1[tile_index] + (paradise_vram_1[tile_index + 0x400] << 8);
+ SET_TILE_INFO(2, code, 0, 0);
+}
+
+
+/* Foreground */
+WRITE8_HANDLER( paradise_vram_2_w )
+{
+ paradise_vram_2[offset] = data;
+ tilemap_mark_tile_dirty(tilemap_2, offset % 0x400);
+}
+
+static TILE_GET_INFO( get_tile_info_2 )
+{
+ int code = paradise_vram_2[tile_index] + (paradise_vram_2[tile_index + 0x400] << 8);
+ SET_TILE_INFO(3, code, 0, 0);
+}
+
+/* 256 x 256 bitmap. 4 bits per pixel so every byte encodes 2 pixels */
+
+WRITE8_HANDLER( paradise_pixmap_w )
+{
+ int x,y;
+
+ videoram[offset] = data;
+
+ x = (offset & 0x7f) << 1;
+ y = (offset >> 7);
+
+ *BITMAP_ADDR16(tmpbitmap, y, x+0) = 0x80f - (data >> 4);
+ *BITMAP_ADDR16(tmpbitmap, y, x+1) = 0x80f - (data & 0x0f);
+}
+
+
+/***************************************************************************
+
+ Vide Hardware Init
+
+***************************************************************************/
+
+VIDEO_START( paradise )
+{
+ tilemap_0 = tilemap_create( get_tile_info_0, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, 0x20,0x20 );
+
+ tilemap_1 = tilemap_create( get_tile_info_1, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, 0x20,0x20 );
+
+ tilemap_2 = tilemap_create( get_tile_info_2, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, 0x20,0x20 );
+
+ /* pixmap */
+ tmpbitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ /* paletteram and videoram (pixmap) are accessed through CPU ports, that don't
+ get memory automatically allocated for them */
+ paletteram = auto_malloc(0x1800);
+ videoram = auto_malloc(0x8000);
+
+ tilemap_set_transparent_pen(tilemap_0,0x0f);
+ tilemap_set_transparent_pen(tilemap_1,0xff);
+ tilemap_set_transparent_pen(tilemap_2,0xff);
+}
+
+
+/***************************************************************************
+
+ Sprites Drawing
+
+***************************************************************************/
+
+/* Sprites / Layers priority */
+WRITE8_HANDLER( paradise_priority_w )
+{
+ paradise_priority = data;
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int i;
+ for (i = 0; i < spriteram_size ; i += paradise_sprite_inc)
+ {
+ int code = spriteram[i+0];
+ int x = spriteram[i+1];
+ int y = spriteram[i+2] - 2;
+ int attr = spriteram[i+3];
+
+ int flipx = 0; // ?
+ int flipy = 0;
+
+ if (flip_screen) { x = 0xf0 - x; flipx = !flipx;
+ y = 0xf0 - y; flipy = !flipy; }
+
+ drawgfx(bitmap,machine->gfx[0],
+ code + (attr << 8),
+ 0,
+ flipx, flipy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN, 0xff );
+
+ /* wrap around x */
+ drawgfx(bitmap,machine->gfx[0],
+ code + (attr << 8),
+ 0,
+ flipx, flipy,
+ x - 256,y,
+ cliprect,TRANSPARENCY_PEN, 0xff );
+
+ drawgfx(bitmap,machine->gfx[0],
+ code + (attr << 8),
+ 0,
+ flipx, flipy,
+ x + 256,y,
+ cliprect,TRANSPARENCY_PEN, 0xff );
+ }
+}
+
+
+/***************************************************************************
+
+ Screen Drawing
+
+***************************************************************************/
+
+VIDEO_UPDATE( paradise )
+{
+ int layers_ctrl = -1;
+
+#ifdef MAME_DEBUG
+if (input_code_pressed(KEYCODE_Z))
+{
+ int mask = 0;
+ if (input_code_pressed(KEYCODE_Q)) mask |= 1;
+ if (input_code_pressed(KEYCODE_W)) mask |= 2;
+ if (input_code_pressed(KEYCODE_E)) mask |= 4;
+ if (input_code_pressed(KEYCODE_R)) mask |= 8;
+ if (input_code_pressed(KEYCODE_A)) mask |= 16;
+ if (mask != 0) layers_ctrl &= mask;
+}
+#endif
+
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ if (!(paradise_priority & 4)) /* Screen blanking */
+ return 0;
+
+ if (paradise_priority & 1)
+ if (layers_ctrl&16) draw_sprites(machine,bitmap,cliprect);
+
+ if (layers_ctrl&1) tilemap_draw(bitmap,cliprect, tilemap_0, 0,0);
+ if (layers_ctrl&2) tilemap_draw(bitmap,cliprect, tilemap_1, 0,0);
+ if (layers_ctrl&4) copybitmap(bitmap,tmpbitmap,flip_screen,flip_screen,0,0,cliprect,TRANSPARENCY_PEN, 0x80f);
+
+ if (paradise_priority & 2)
+ {
+ if (!(paradise_priority & 1))
+ if (layers_ctrl&16) draw_sprites(machine, bitmap,cliprect);
+ if (layers_ctrl&8) tilemap_draw(bitmap,cliprect, tilemap_2, 0,0);
+ }
+ else
+ {
+ if (layers_ctrl&8) tilemap_draw(bitmap,cliprect, tilemap_2, 0,0);
+ if (!(paradise_priority & 1))
+ if (layers_ctrl&16) draw_sprites(machine, bitmap,cliprect);
+ }
+ return 0;
+}
+
+/* no pix layer, no tilemap_0, different priority bits */
+VIDEO_UPDATE( torus )
+{
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ if (!(paradise_priority & 2)) /* Screen blanking */
+ return 0;
+
+ if (paradise_priority & 1)
+ draw_sprites(machine, bitmap,cliprect);
+
+ tilemap_draw(bitmap,cliprect, tilemap_1, 0,0);
+
+ if(paradise_priority & 4)
+ {
+ if (!(paradise_priority & 1))
+ draw_sprites(machine, bitmap,cliprect);
+
+ tilemap_draw(bitmap,cliprect, tilemap_2, 0,0);
+ }
+ else
+ {
+ tilemap_draw(bitmap,cliprect, tilemap_2, 0,0);
+
+ if (!(paradise_priority & 1))
+ draw_sprites(machine, bitmap,cliprect);
+ }
+ return 0;
+}
+
+/* I don't know how the priority bits work on this one */
+VIDEO_UPDATE( madball )
+{
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ tilemap_draw(bitmap,cliprect, tilemap_0, 0,0);
+ tilemap_draw(bitmap,cliprect, tilemap_1, 0,0);
+ tilemap_draw(bitmap,cliprect, tilemap_2, 0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
+
+
diff --git a/src/mame/video/parodius.c b/src/mame/video/parodius.c
new file mode 100644
index 00000000000..d1a81880ded
--- /dev/null
+++ b/src/mame/video/parodius.c
@@ -0,0 +1,98 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+static int layer_colorbase[3],sprite_colorbase,bg_colorbase;
+static int layerpri[3];
+
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ *code |= ((*color & 0x03) << 8) | ((*color & 0x10) << 6) | ((*color & 0x0c) << 9) | (bank << 13);
+ *color = layer_colorbase[layer] + ((*color & 0xe0) >> 5);
+}
+
+/***************************************************************************
+
+ Callbacks for the K053245
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority_mask)
+{
+ int pri = 0x20 | ((*color & 0x60) >> 2);
+ if (pri <= layerpri[2]) *priority_mask = 0;
+ else if (pri > layerpri[2] && pri <= layerpri[1]) *priority_mask = 0xf0;
+ else if (pri > layerpri[1] && pri <= layerpri[0]) *priority_mask = 0xf0|0xcc;
+ else *priority_mask = 0xf0|0xcc|0xaa;
+
+ *color = sprite_colorbase + (*color & 0x1f);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( parodius )
+{
+ K053251_vh_start();
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tile_callback);
+ K053245_vh_start(machine,0,REGION_GFX2,NORMAL_PLANE_ORDER,sprite_callback);
+}
+
+/* useful function to sort the three tile layers by priority order */
+static void sortlayers(int *layer,int *pri)
+{
+#define SWAP(a,b) \
+ if (pri[a] < pri[b]) \
+ { \
+ int t; \
+ t = pri[a]; pri[a] = pri[b]; pri[b] = t; \
+ t = layer[a]; layer[a] = layer[b]; layer[b] = t; \
+ }
+
+ SWAP(0,1)
+ SWAP(0,2)
+ SWAP(1,2)
+}
+
+VIDEO_UPDATE( parodius )
+{
+ int layer[3];
+
+
+ bg_colorbase = K053251_get_palette_index(K053251_CI0);
+ sprite_colorbase = K053251_get_palette_index(K053251_CI1);
+ layer_colorbase[0] = K053251_get_palette_index(K053251_CI2);
+ layer_colorbase[1] = K053251_get_palette_index(K053251_CI4);
+ layer_colorbase[2] = K053251_get_palette_index(K053251_CI3);
+
+ K052109_tilemap_update();
+
+ layer[0] = 0;
+ layerpri[0] = K053251_get_priority(K053251_CI2);
+ layer[1] = 1;
+ layerpri[1] = K053251_get_priority(K053251_CI4);
+ layer[2] = 2;
+ layerpri[2] = K053251_get_priority(K053251_CI3);
+
+ sortlayers(layer,layerpri);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[16 * bg_colorbase],cliprect);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[0]],0,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[1]],0,2);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[2]],0,4);
+
+ K053245_sprites_draw(0,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/pass.c b/src/mame/video/pass.c
new file mode 100644
index 00000000000..96ee38c8057
--- /dev/null
+++ b/src/mame/video/pass.c
@@ -0,0 +1,66 @@
+/* video/pass.c - see drivers/pass.c for more info */
+
+#include "driver.h"
+
+static tilemap *pass_bg_tilemap;
+static tilemap *pass_fg_tilemap;
+
+/* in drivers/pass.c */
+extern UINT16 *pass_bg_videoram;
+extern UINT16 *pass_fg_videoram;
+/* end in drivers/pass.c */
+
+/* background tilemap stuff */
+
+static TILE_GET_INFO( get_pass_bg_tile_info )
+{
+ int tileno,fx;
+
+ tileno = pass_bg_videoram[tile_index] & 0x1fff;
+ fx = (pass_bg_videoram[tile_index] & 0xc000) >> 14;
+ SET_TILE_INFO(1,tileno,0,TILE_FLIPYX(fx));
+
+}
+
+WRITE16_HANDLER( pass_bg_videoram_w )
+{
+ pass_bg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(pass_bg_tilemap,offset);
+}
+
+/* foreground 'sprites' tilemap stuff */
+
+static TILE_GET_INFO( get_pass_fg_tile_info )
+{
+ int tileno, flip;
+
+ tileno = pass_fg_videoram[tile_index] & 0x3fff;
+ flip = (pass_fg_videoram[tile_index] & 0xc000) >>14;
+
+ SET_TILE_INFO(0,tileno,0,TILE_FLIPYX(flip));
+
+}
+
+WRITE16_HANDLER( pass_fg_videoram_w )
+{
+ pass_fg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(pass_fg_tilemap,offset);
+}
+
+/* video update / start */
+
+VIDEO_UPDATE( pass )
+{
+ tilemap_draw(bitmap,cliprect,pass_bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,pass_fg_tilemap,0,0);
+
+ return 0;
+}
+
+VIDEO_START( pass )
+{
+ pass_bg_tilemap = tilemap_create(get_pass_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ pass_fg_tilemap = tilemap_create(get_pass_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 4, 4,128,64);
+
+ tilemap_set_transparent_pen(pass_fg_tilemap,255);
+}
diff --git a/src/mame/video/pastelg.c b/src/mame/video/pastelg.c
new file mode 100644
index 00000000000..8723c6d2256
--- /dev/null
+++ b/src/mame/video/pastelg.c
@@ -0,0 +1,303 @@
+/******************************************************************************
+
+ Video Hardware for Nichibutsu Mahjong series.
+
+ Driver by Takahiro Nogi 2000/06/07 -
+
+******************************************************************************/
+
+#include "driver.h"
+#include "nb1413m3.h"
+
+
+static int blitter_destx, blitter_desty;
+static int blitter_sizex, blitter_sizey;
+static int blitter_src_addr;
+static int pastelg_gfxrom;
+static int pastelg_dispflag;
+static int pastelg_flipscreen;
+static int blitter_direction_x, blitter_direction_y;
+static int pastelg_screen_refresh;
+static int pastelg_palbank;
+
+static mame_bitmap *pastelg_tmpbitmap;
+static UINT8 *pastelg_videoram;
+static UINT8 *pastelg_clut;
+
+
+static void pastelg_vramflip(void);
+static void pastelg_gfxdraw(void);
+
+
+/******************************************************************************
+
+
+******************************************************************************/
+PALETTE_INIT( pastelg )
+{
+ int i;
+ int bit0, bit1, bit2, bit3, r, g, b;
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[0] >> 4) & 0x01;
+ bit1 = (color_prom[0] >> 5) & 0x01;
+ bit2 = (color_prom[0] >> 6) & 0x01;
+ bit3 = (color_prom[0] >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( pastelg_clut_w )
+{
+ pastelg_clut[offset] = data;
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+int pastelg_blitter_src_addr_r(void)
+{
+ return blitter_src_addr;
+}
+
+WRITE8_HANDLER( pastelg_blitter_w )
+{
+ switch (offset)
+ {
+ case 0: blitter_src_addr = (blitter_src_addr & 0xff00) | data; break;
+ case 1: blitter_src_addr = (blitter_src_addr & 0x00ff) | (data << 8); break;
+ case 2: blitter_destx = data; break;
+ case 3: blitter_desty = data; break;
+ case 4: blitter_sizex = data; break;
+ case 5: blitter_sizey = data;
+ /* writing here also starts the blit */
+ pastelg_gfxdraw();
+ break;
+ case 6: blitter_direction_x = (data & 0x01) ? 1 : 0;
+ blitter_direction_y = (data & 0x02) ? 1 : 0;
+ pastelg_flipscreen = (data & 0x04) ? 0 : 1;
+ pastelg_dispflag = (data & 0x08) ? 0 : 1;
+ pastelg_vramflip();
+ break;
+ }
+}
+
+WRITE8_HANDLER( pastelg_romsel_w )
+{
+ pastelg_gfxrom = ((data & 0xc0) >> 6);
+ pastelg_palbank = ((data & 0x10) >> 4);
+ nb1413m3_sndrombank1_w(0, data);
+
+ if ((pastelg_gfxrom << 16) > (memory_region_length(REGION_GFX1) - 1))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM BANK OVER!!");
+#endif
+ pastelg_gfxrom &= (memory_region_length(REGION_GFX1) / 0x20000 - 1);
+ }
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+void pastelg_vramflip(void)
+{
+ static int pastelg_flipscreen_old = 0;
+ int x, y;
+ UINT8 color1, color2;
+
+ if (pastelg_flipscreen == pastelg_flipscreen_old) return;
+
+ for (y = 0; y < Machine->screen[0].height; y++)
+ {
+ for (x = 0; x < Machine->screen[0].width; x++)
+ {
+ color1 = pastelg_videoram[(y * Machine->screen[0].width) + x];
+ color2 = pastelg_videoram[((y ^ 0xff) * Machine->screen[0].width) + (x ^ 0xff)];
+ pastelg_videoram[(y * Machine->screen[0].width) + x] = color2;
+ pastelg_videoram[((y ^ 0xff) * Machine->screen[0].width) + (x ^ 0xff)] = color1;
+ }
+ }
+
+ pastelg_flipscreen_old = pastelg_flipscreen;
+ pastelg_screen_refresh = 1;
+}
+
+static void update_pixel(int x,int y)
+{
+ int color = pastelg_videoram[(y * Machine->screen[0].width) + x];
+ *BITMAP_ADDR16(pastelg_tmpbitmap, y, x) = Machine->pens[color];
+}
+
+static TIMER_CALLBACK( blitter_timer_callback )
+{
+ nb1413m3_busyflag = 1;
+}
+
+void pastelg_gfxdraw(void)
+{
+ UINT8 *GFX = memory_region(REGION_GFX1);
+
+ int x, y;
+ int dx, dy;
+ int startx, starty;
+ int sizex, sizey;
+ int skipx, skipy;
+ int ctrx, ctry;
+ int readflag;
+ int gfxaddr;
+ UINT8 color;
+
+ nb1413m3_busyctr = 0;
+
+ startx = blitter_destx + blitter_sizex;
+ starty = blitter_desty + blitter_sizey;
+
+ if (blitter_direction_x)
+ {
+ sizex = blitter_sizex ^ 0xff;
+ skipx = 1;
+ }
+ else
+ {
+ sizex = blitter_sizex;
+ skipx = -1;
+ }
+
+ if (blitter_direction_y)
+ {
+ sizey = blitter_sizey ^ 0xff;
+ skipy = 1;
+ }
+ else
+ {
+ sizey = blitter_sizey;
+ skipy = -1;
+ }
+
+ gfxaddr = (pastelg_gfxrom << 16) + blitter_src_addr;
+
+ readflag = 0;
+
+ for (y = starty, ctry = sizey; ctry >= 0; y += skipy, ctry--)
+ {
+ for (x = startx, ctrx = sizex; ctrx >= 0; x += skipx, ctrx--)
+ {
+ if ((gfxaddr > (memory_region_length(REGION_GFX1) - 1)))
+ {
+#ifdef MAME_DEBUG
+ popmessage("GFXROM ADDRESS OVER!!");
+#endif
+ gfxaddr = 0;
+ }
+
+ color = GFX[gfxaddr];
+
+ dx = x & 0xff;
+ dy = y & 0xff;
+
+ if (pastelg_flipscreen)
+ {
+ dx ^= 0xff;
+ dy ^= 0xff;
+ }
+
+ if (!readflag)
+ {
+ // 1st, 3rd, 5th, ... read
+ color = (color & 0x0f);
+ }
+ else
+ {
+ // 2nd, 4th, 6th, ... read
+ color = (color & 0xf0) >> 4;
+ gfxaddr++;
+ }
+
+ readflag ^= 1;
+
+ if (pastelg_clut[color] & 0xf0)
+ {
+ if (color)
+ {
+ color = ((pastelg_palbank * 0x10) + color);
+ pastelg_videoram[(dy * Machine->screen[0].width) + dx] = color;
+ update_pixel(dx, dy);
+ }
+ }
+ else
+ {
+ color = ((pastelg_palbank * 0x10) + pastelg_clut[color]);
+ pastelg_videoram[(dy * Machine->screen[0].width) + dx] = color;
+ update_pixel(dx, dy);
+ }
+
+ nb1413m3_busyctr++;
+ }
+ }
+
+ nb1413m3_busyflag = 0;
+ timer_set(attotime_mul(ATTOTIME_IN_HZ(400000), nb1413m3_busyctr), 0, blitter_timer_callback);
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+VIDEO_START( pastelg )
+{
+ pastelg_tmpbitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height,machine->screen[0].format);
+ pastelg_videoram = auto_malloc(machine->screen[0].width * machine->screen[0].height * sizeof(UINT8));
+ pastelg_clut = auto_malloc(0x10 * sizeof(UINT8));
+ memset(pastelg_videoram, 0x00, (machine->screen[0].width * machine->screen[0].height * sizeof(UINT8)));
+}
+
+/******************************************************************************
+
+
+******************************************************************************/
+VIDEO_UPDATE( pastelg )
+{
+ int x, y;
+ UINT8 color;
+
+ if (pastelg_screen_refresh)
+ {
+ pastelg_screen_refresh = 0;
+
+ for (y = 0; y < machine->screen[0].height; y++)
+ {
+ for (x = 0; x < machine->screen[0].width; x++)
+ {
+ color = pastelg_videoram[(y * machine->screen[0].width) + x];
+ *BITMAP_ADDR16(pastelg_tmpbitmap, y, x) = machine->pens[color];
+ }
+ }
+ }
+
+ if (pastelg_dispflag)
+ {
+ copybitmap(bitmap, pastelg_tmpbitmap, 0, 0, 0, 0, &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ }
+ else
+ {
+ fillbitmap(bitmap, machine->pens[0x00], 0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/pbaction.c b/src/mame/video/pbaction.c
new file mode 100644
index 00000000000..ec68041a988
--- /dev/null
+++ b/src/mame/video/pbaction.c
@@ -0,0 +1,134 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *pbaction_videoram2, *pbaction_colorram2;
+
+static int scroll;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+WRITE8_HANDLER( pbaction_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( pbaction_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( pbaction_videoram2_w )
+{
+ pbaction_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( pbaction_colorram2_w )
+{
+ pbaction_colorram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( pbaction_scroll_w )
+{
+ scroll = data - 3;
+ if (flip_screen) scroll = -scroll;
+ tilemap_set_scrollx(bg_tilemap, 0, scroll);
+ tilemap_set_scrollx(fg_tilemap, 0, scroll);
+}
+
+WRITE8_HANDLER( pbaction_flipscreen_w )
+{
+ flip_screen_set(data & 0x01);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + 0x10 * (attr & 0x70);
+ int color = attr & 0x0f;
+ int flags = (attr & 0x80) ? TILE_FLIPY : 0;
+
+ SET_TILE_INFO(1, code, color, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = pbaction_colorram2[tile_index];
+ int code = pbaction_videoram2[tile_index] + 0x10 * (attr & 0x30);
+ int color = attr & 0x0f;
+ int flags = ((attr & 0x40) ? TILE_FLIPX : 0) | ((attr & 0x80) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( pbaction )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int sx,sy,flipx,flipy;
+
+ /* if next sprite is double size, skip this one */
+ if (offs > 0 && spriteram[offs - 4] & 0x80) continue;
+
+ sx = spriteram[offs+3];
+ if (spriteram[offs] & 0x80)
+ sy = 225-spriteram[offs+2];
+ else
+ sy = 241-spriteram[offs+2];
+ flipx = spriteram[offs+1] & 0x40;
+ flipy = spriteram[offs+1] & 0x80;
+ if (flip_screen)
+ {
+ if (spriteram[offs] & 0x80)
+ {
+ sx = 224 - sx;
+ sy = 225 - sy;
+ }
+ else
+ {
+ sx = 240 - sx;
+ sy = 241 - sy;
+ }
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[(spriteram[offs] & 0x80) ? 3 : 2], /* normal or double size */
+ spriteram[offs],
+ spriteram[offs + 1] & 0x0f,
+ flipx,flipy,
+ sx + (flip_screen ? scroll : -scroll), sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( pbaction )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/pcktgal.c b/src/mame/video/pcktgal.c
new file mode 100644
index 00000000000..d19e4fbd1b6
--- /dev/null
+++ b/src/mame/video/pcktgal.c
@@ -0,0 +1,100 @@
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+PALETTE_INIT( pcktgal )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ bit3 = (color_prom[i] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[i] >> 4) & 0x01;
+ bit1 = (color_prom[i] >> 5) & 0x01;
+ bit2 = (color_prom[i] >> 6) & 0x01;
+ bit3 = (color_prom[i] >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[i + machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[i + machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[i + machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[i + machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+WRITE8_HANDLER( pcktgal_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+WRITE8_HANDLER( pcktgal_flipscreen_w )
+{
+ if (flip_screen != (data & 0x80))
+ {
+ flip_screen_set(data & 0x80);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index*2+1] + ((videoram[tile_index*2] & 0x0f) << 8);
+ int color = videoram[tile_index*2] >> 4;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( pcktgal )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ if (spriteram[offs] != 0xf8)
+ {
+ int sx,sy,flipx,flipy;
+
+
+ sx = 240 - spriteram[offs+2];
+ sy = 240 - spriteram[offs];
+
+ flipx = spriteram[offs+1] & 0x04;
+ flipy = spriteram[offs+1] & 0x02;
+ if (flip_screen) {
+ sx=240-sx;
+ sy=240-sy;
+ if (flipx) flipx=0; else flipx=1;
+ if (flipy) flipy=0; else flipy=1;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ spriteram[offs+3] + ((spriteram[offs+1] & 1) << 8),
+ (spriteram[offs+1] & 0x70) >> 4,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( pcktgal )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/pgm.c b/src/mame/video/pgm.c
new file mode 100644
index 00000000000..0f2673bea12
--- /dev/null
+++ b/src/mame/video/pgm.c
@@ -0,0 +1,352 @@
+/*** Video *******************************************************************/
+/* see drivers/pgm.c for notes on where improvements can be made */
+
+#include "driver.h"
+
+extern UINT16 *pgm_mainram, *pgm_bg_videoram, *pgm_tx_videoram, *pgm_videoregs, *pgm_rowscrollram;
+static tilemap *pgm_tx_tilemap, *pgm_bg_tilemap;
+static UINT16 *pgm_spritebufferram; // buffered spriteram
+static UINT16 *sprite_temp_render;
+
+extern UINT8 *pgm_sprite_a_region; /* = memory_region ( REGION_GFX4 ); */
+extern size_t pgm_sprite_a_region_allocate;
+
+/* Sprites - These are a pain! */
+
+/* this decodes one of the funky sprites to a bitmap so we can draw it more easily -- slow but easier to use*/
+static void pgm_prepare_sprite(int wide, int high,int palt, int boffset)
+{
+ UINT8 *bdata = memory_region ( REGION_GFX4 );
+ size_t bdatasize = memory_region_length( REGION_GFX4 )-1;
+ UINT8 *adata = pgm_sprite_a_region;
+ size_t adatasize = pgm_sprite_a_region_allocate-1;
+ int xcnt, ycnt;
+
+ UINT32 aoffset;
+ UINT16 msk;
+
+ aoffset = (bdata[(boffset+3) & bdatasize] << 24) | (bdata[(boffset+2) & bdatasize] << 16) | (bdata[(boffset+1) & bdatasize] << 8) | (bdata[(boffset+0) & bdatasize] << 0);
+ aoffset = aoffset >> 2; aoffset *= 3;
+
+ boffset += 4; /* because the first dword is the a data offset */
+
+ for (ycnt = 0 ; ycnt < high ; ycnt++) {
+ for (xcnt = 0 ; xcnt < wide ; xcnt++) {
+ int x;
+
+ msk = (( bdata[(boffset+1) & bdatasize] << 8) |( bdata[(boffset+0) & bdatasize] << 0) );
+
+ for (x=0;x<16;x++)
+ {
+ if (!(msk & 0x0001))
+ {
+ sprite_temp_render[(ycnt*(wide*16))+(xcnt*16+x)] = adata[aoffset & adatasize]+ palt*32;
+ aoffset++;
+ }
+ else
+ {
+ sprite_temp_render[(ycnt*(wide*16))+(xcnt*16+x)] = 0x8000;
+ }
+ msk >>=1;
+ }
+
+ boffset+=2;
+ }
+ }
+}
+
+
+
+static void draw_sprite_line(int wide, UINT16* dest, int xzoom, int xgrow, int yoffset, int flip, int xpos)
+{
+ int xcnt,xcntdraw;
+ int xzoombit;
+ int xoffset;
+ int xdrawpos = 0;
+
+ xcnt = 0;
+ xcntdraw = 0;
+ while (xcnt < wide*16)
+ {
+ UINT32 srcdat;
+ if (!(flip&0x01)) xoffset = xcnt;
+ else xoffset = (wide*16)-xcnt-1;
+
+ srcdat = sprite_temp_render[yoffset+xoffset];
+ xzoombit = (xzoom >> (xcnt&0x1f))&1;
+
+ if (xzoombit == 1 && xgrow ==1)
+ { // double this column
+ xdrawpos = xpos + xcntdraw;
+ if (!(srcdat&0x8000))
+ {
+ if ((xdrawpos >= 0) && (xdrawpos < 448)) dest[xdrawpos] = srcdat;
+ }
+ xcntdraw++;
+
+ xdrawpos = xpos + xcntdraw;
+
+ if (!(srcdat&0x8000))
+ {
+ if ((xdrawpos >= 0) && (xdrawpos < 448)) dest[xdrawpos] = srcdat;
+ }
+ xcntdraw++;
+ }
+ else if (xzoombit ==1 && xgrow ==0)
+ {
+ /* skip this column */
+ }
+ else //normal column
+ {
+ xdrawpos = xpos + xcntdraw;
+ if (!(srcdat&0x8000))
+ {
+ if ((xdrawpos >= 0) && (xdrawpos < 448)) dest[xdrawpos] = srcdat;
+ }
+ xcntdraw++;
+ }
+
+ xcnt++;
+
+ if (xdrawpos == 448) xcnt = wide*16;
+ }
+}
+/* this just loops over our decoded bitmap and puts it on the screen */
+static void draw_sprite_new_zoomed(int wide, int high, int xpos, int ypos, int palt, int boffset, int flip, mame_bitmap* bitmap, UINT32 xzoom, int xgrow, UINT32 yzoom, int ygrow )
+{
+ int ycnt;
+ int ydrawpos;
+ UINT16 *dest;
+ int yoffset;
+ int ycntdraw;
+ int yzoombit;
+
+ pgm_prepare_sprite( wide,high, palt, boffset );
+
+ /* now draw it */
+ ycnt = 0;
+ ycntdraw = 0;
+ while (ycnt < high)
+ {
+ yzoombit = (yzoom >> (ycnt&0x1f))&1;
+
+ if (yzoombit == 1 && ygrow == 1) // double this line
+ {
+ ydrawpos = ypos + ycntdraw;
+
+ if (!(flip&0x02)) yoffset = (ycnt*(wide*16));
+ else yoffset = ( (high-ycnt-1)*(wide*16));
+ if ((ydrawpos >= 0) && (ydrawpos < 224))
+ {
+ dest = BITMAP_ADDR16(bitmap, ydrawpos, 0);
+ draw_sprite_line(wide, dest, xzoom, xgrow, yoffset, flip, xpos);
+ }
+ ycntdraw++;
+
+ ydrawpos = ypos + ycntdraw;
+ if (!(flip&0x02)) yoffset = (ycnt*(wide*16));
+ else yoffset = ( (high-ycnt-1)*(wide*16));
+ if ((ydrawpos >= 0) && (ydrawpos < 224))
+ {
+ dest = BITMAP_ADDR16(bitmap, ydrawpos, 0);
+ draw_sprite_line(wide, dest, xzoom, xgrow, yoffset, flip, xpos);
+ }
+ ycntdraw++;
+
+ if (ydrawpos ==224) ycnt = high;
+ }
+ else if (yzoombit ==1 && ygrow == 0)
+ {
+ /* skip this line */
+ /* we should process anyway if we don't do the pre-decode.. */
+ }
+ else /* normal line */
+ {
+ ydrawpos = ypos + ycntdraw;
+
+ if (!(flip&0x02)) yoffset = (ycnt*(wide*16));
+ else yoffset = ( (high-ycnt-1)*(wide*16));
+ if ((ydrawpos >= 0) && (ydrawpos < 224))
+ {
+ dest = BITMAP_ADDR16(bitmap, ydrawpos, 0);
+ draw_sprite_line(wide, dest, xzoom, xgrow, yoffset, flip, xpos);
+ }
+ ycntdraw++;
+
+ if (ydrawpos ==224) ycnt = high;
+ }
+
+ ycnt++;
+ }
+}
+
+
+static UINT16 *pgm_sprite_source;
+
+static void draw_sprites(int priority, mame_bitmap* bitmap)
+{
+ /* ZZZZ Zxxx xxxx xxxx
+ zzzz z-yy yyyy yyyy
+ -ffp pppp Pvvv vvvv
+ vvvv vvvv vvvv vvvv
+ wwww wwwh hhhh hhhh
+ */
+
+
+ const UINT16 *finish = pgm_spritebufferram+(0xa00/2);
+
+ while( pgm_sprite_source<finish )
+ {
+ int xpos = pgm_sprite_source[0] & 0x07ff;
+ int ypos = pgm_sprite_source[1] & 0x03ff;
+ int xzom = (pgm_sprite_source[0] & 0x7800) >> 11;
+ int xgrow = (pgm_sprite_source[0] & 0x8000) >> 15;
+ int yzom = (pgm_sprite_source[1] & 0x7800) >> 11;
+ int ygrow = (pgm_sprite_source[1] & 0x8000) >> 15;
+ int palt = (pgm_sprite_source[2] & 0x1f00) >> 8;
+ int flip = (pgm_sprite_source[2] & 0x6000) >> 13;
+ int boff = ((pgm_sprite_source[2] & 0x007f) << 16) | (pgm_sprite_source[3] & 0xffff);
+ int wide = (pgm_sprite_source[4] & 0x7e00) >> 9;
+ int high = pgm_sprite_source[4] & 0x01ff;
+ int pri = (pgm_sprite_source[2] & 0x0080) >> 7;
+
+ UINT32 xzoom, yzoom;
+
+ UINT16* pgm_sprite_zoomtable = &pgm_videoregs[0x1000/2];
+
+ if (xgrow)
+ {
+ // xzom = 0xf-xzom; // would make more sense but everything gets zoomed slightly in dragon world 2 ?!
+ xzom = 0x10-xzom; // this way it doesn't but there is a bad line when zooming after the level select?
+ }
+
+ if (ygrow)
+ {
+ // yzom = 0xf-yzom; // see comment above
+ yzom = 0x10-yzom;
+ }
+
+ xzoom = (pgm_sprite_zoomtable[xzom*2]<<16)|pgm_sprite_zoomtable[xzom*2+1];
+ yzoom = (pgm_sprite_zoomtable[yzom*2]<<16)|pgm_sprite_zoomtable[yzom*2+1];
+
+ boff *= 2;
+ if (xpos > 0x3ff) xpos -=0x800;
+ if (ypos > 0x1ff) ypos -=0x400;
+
+ if (high == 0) break; /* is this right? */
+
+ if ((priority == 1) && (pri == 0)) break;
+
+ draw_sprite_new_zoomed(wide, high, xpos, ypos, palt, boff, flip, bitmap, xzoom,xgrow, yzoom,ygrow);
+
+ pgm_sprite_source += 5;
+ }
+}
+
+/* TX Layer */
+
+WRITE16_HANDLER( pgm_tx_videoram_w )
+{
+ pgm_tx_videoram[offset] = data;
+ tilemap_mark_tile_dirty(pgm_tx_tilemap,offset/2);
+}
+
+static TILE_GET_INFO( get_pgm_tx_tilemap_tile_info )
+{
+
+/* 0x904000 - 0x90ffff is the Text Overlay Ram (pgm_tx_videoram)
+ each tile uses 4 bytes, the tilemap is 64x128?
+
+ the layer uses 4bpp 8x8 tiles from the 'T' roms
+ colours from 0xA01000 - 0xA017FF
+
+ scroll registers are at 0xB05000 (Y) and 0xB06000 (X)
+
+ ---- ---- ffpp ppp- nnnn nnnn nnnn nnnn
+
+ n = tile number
+ p = palette
+ f = flip
+*/
+ int tileno,colour,flipyx; //,game;
+
+ tileno = pgm_tx_videoram[tile_index *2] & 0xffff;
+ colour = (pgm_tx_videoram[tile_index*2+1] & 0x3e) >> 1;
+ flipyx = (pgm_tx_videoram[tile_index*2+1] & 0xc0) >> 6;
+
+ if (tileno > 0xbfff) { tileno -= 0xc000 ; tileno += 0x20000; } /* not sure about this */
+
+ SET_TILE_INFO(0,tileno,colour,TILE_FLIPYX(flipyx));
+}
+
+/* BG Layer */
+
+WRITE16_HANDLER( pgm_bg_videoram_w )
+{
+ pgm_bg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(pgm_bg_tilemap,offset/2);
+}
+
+static TILE_GET_INFO( get_pgm_bg_tilemap_tile_info )
+{
+ /* pretty much the same as tx layer */
+
+ int tileno,colour,flipyx;
+
+ tileno = pgm_bg_videoram[tile_index *2] & 0xffff;
+ if (tileno > 0x7ff) tileno+=0x1000; /* Tiles 0x800+ come from the GAME Roms */
+ colour = (pgm_bg_videoram[tile_index*2+1] & 0x3e) >> 1;
+ flipyx = (pgm_bg_videoram[tile_index*2+1] & 0xc0) >> 6;
+
+ SET_TILE_INFO(1,tileno,colour,TILE_FLIPYX(flipyx));
+}
+
+
+
+/*** Video - Start / Update ****************************************************/
+
+VIDEO_START( pgm )
+{
+ pgm_tx_tilemap= tilemap_create(get_pgm_tx_tilemap_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ tilemap_set_transparent_pen(pgm_tx_tilemap,15);
+
+ pgm_bg_tilemap = tilemap_create(get_pgm_bg_tilemap_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 32, 32,64,64);
+ tilemap_set_transparent_pen(pgm_bg_tilemap,31);
+ tilemap_set_scroll_rows(pgm_bg_tilemap,64*32);
+
+ pgm_spritebufferram = auto_malloc (0xa00);
+
+ /* we render each sprite to a bitmap then copy the bitmap to screen bitmap with zooming */
+ /* easier this way because of the funky sprite format */
+ sprite_temp_render = auto_malloc(0x400*0x200*2);
+}
+
+VIDEO_UPDATE( pgm )
+{
+ int y;
+
+ fillbitmap(bitmap,get_black_pen(machine),&machine->screen[0].visarea);
+
+ pgm_sprite_source = pgm_spritebufferram;
+ draw_sprites(1, bitmap);
+
+ tilemap_set_scrolly(pgm_bg_tilemap,0, pgm_videoregs[0x2000/2]);
+
+ for (y = 0; y < 224; y++)
+ tilemap_set_scrollx(pgm_bg_tilemap,(y+pgm_videoregs[0x2000/2])&0x7ff, pgm_videoregs[0x3000/2]+pgm_rowscrollram[y]);
+
+ tilemap_draw(bitmap,cliprect,pgm_bg_tilemap,0,0);
+
+ draw_sprites(0, bitmap);
+
+ tilemap_set_scrolly(pgm_tx_tilemap,0, pgm_videoregs[0x5000/2]);
+ tilemap_set_scrollx(pgm_tx_tilemap,0, pgm_videoregs[0x6000/2]); // Check
+ tilemap_draw(bitmap,cliprect,pgm_tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_EOF( pgm )
+{
+ /* first 0xa00 of main ram = sprites, seems to be buffered, DMA? */
+ memcpy(pgm_spritebufferram,pgm_mainram,0xa00);
+}
diff --git a/src/mame/video/phoenix.c b/src/mame/video/phoenix.c
new file mode 100644
index 00000000000..555ea9565a8
--- /dev/null
+++ b/src/mame/video/phoenix.c
@@ -0,0 +1,338 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "phoenix.h"
+
+static UINT8 *videoram_pg1;
+static UINT8 *videoram_pg2;
+static UINT8 *current_videoram_pg;
+static int current_videoram_pg_index;
+static int palette_bank;
+static int cocktail_mode;
+static int pleiads_protection_question;
+static int survival_protection_value;
+static tilemap *fg_tilemap, *bg_tilemap;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Phoenix has two 256x4 palette PROMs, one containing the high bits and the
+ other the low bits (2x2x2 color space).
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 --
+ -- 270 ohm resistor -- GREEN
+ -- 270 ohm resistor -- BLUE
+ bit 0 -- 270 ohm resistor -- RED
+
+ bit 3 --
+ -- GREEN
+ -- BLUE
+ bit 0 -- RED
+
+ plus 270 ohm pullup and pulldown resistors on all lines
+
+***************************************************************************/
+
+PALETTE_INIT( phoenix )
+{
+ int i;
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ r = 0x55 * bit0 + 0xaa * bit1;
+ bit0 = (color_prom[0] >> 2) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ g = 0x55 * bit0 + 0xaa * bit1;
+ bit0 = (color_prom[0] >> 1) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ b = 0x55 * bit0 + 0xaa * bit1;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* first bank of characters use colors 0x00-0x1f and 0x40-0x5f */
+ /* second bank of characters use colors 0x20-0x3f and 0x60-0x7f */
+ for (i = 0;i < 0x40;i++)
+ {
+ int col;
+
+
+ col = ((i & 0x1c) >> 2) | ((i & 0x03) << 3) | ((i & 0x20) << 1);
+
+ COLOR(0,i) = col;
+ COLOR(1,i) = col | 0x20;
+ }
+}
+
+PALETTE_INIT( pleiads )
+{
+ int i;
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ r = 0x55 * bit0 + 0xaa * bit1;
+ bit0 = (color_prom[0] >> 2) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ g = 0x55 * bit0 + 0xaa * bit1;
+ bit0 = (color_prom[0] >> 1) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ b = 0x55 * bit0 + 0xaa * bit1;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* first bank of characters use colors 0x00-0x1f, 0x40-0x5f, 0x80-0x9f and 0xc0-0xdf */
+ /* second bank of characters use colors 0x20-0x3f, 0x60-0x7f, 0xa0-0xbf and 0xe0-0xff */
+ for (i = 0;i < 0x80;i++)
+ {
+ int col;
+
+
+ col = ((i & 0x1c) >> 2) | ((i & 0x03) << 3) | ((i & 0x60) << 1);
+
+ COLOR(0,i) = col;
+ COLOR(1,i) = col | 0x20;
+ }
+}
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code;
+
+ code = current_videoram_pg[tile_index];
+ SET_TILE_INFO(
+ 1,
+ code,
+ (code >> 5) | (palette_bank << 3),
+ (tile_index & 0x1f) ? 0 : TILE_FORCE_LAYER0); /* first row (column) is opaque */
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code;
+
+ code = current_videoram_pg[tile_index + 0x800];
+ SET_TILE_INFO(
+ 0,
+ code,
+ (code >> 5) | (palette_bank << 3),
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( phoenix )
+{
+ videoram_pg1 = auto_malloc(0x1000);
+ videoram_pg2 = auto_malloc(0x1000);
+
+ memory_configure_bank(1, 0, 1, videoram_pg1, 0);
+ memory_configure_bank(1, 1, 1, videoram_pg2, 0);
+ memory_set_bank(1, 0);
+
+ current_videoram_pg_index = -1;
+ current_videoram_pg = videoram_pg1; /* otherwise, hiscore loading crashes */
+
+
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,32,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_scrolldx(fg_tilemap,0,8);
+ tilemap_set_scrolldy(fg_tilemap,0,48);
+ tilemap_set_scrolldx(bg_tilemap,0,8);
+ tilemap_set_scrolldy(bg_tilemap,0,48);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( phoenix_videoram_w )
+{
+ UINT8 *rom = memory_region(REGION_CPU1);
+
+ current_videoram_pg[offset] = data;
+
+ if ((offset & 0x7ff) < 0x340)
+ {
+ if (offset & 0x800)
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+ else
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x3ff);
+ }
+
+ /* as part of the protecion, Survival executes code from $43a4 */
+ rom[offset + 0x4000] = data;
+}
+
+
+WRITE8_HANDLER( phoenix_videoreg_w )
+{
+ if (current_videoram_pg_index != (data & 1))
+ {
+ /* set memory bank */
+ current_videoram_pg_index = data & 1;
+ memory_set_bank(1, current_videoram_pg_index);
+ current_videoram_pg = current_videoram_pg_index ? videoram_pg2 : videoram_pg1;
+
+ cocktail_mode = current_videoram_pg_index && (input_port_3_r(0) & 0x01);
+
+ tilemap_set_flip(ALL_TILEMAPS, cocktail_mode ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ /* Phoenix has only one palette select effecting both layers */
+ if (palette_bank != ((data >> 1) & 1))
+ {
+ palette_bank = (data >> 1) & 1;
+
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( pleiads_videoreg_w )
+{
+ if (current_videoram_pg_index != (data & 1))
+ {
+ /* set memory bank */
+ current_videoram_pg_index = data & 1;
+ current_videoram_pg = current_videoram_pg_index ? videoram_pg2 : videoram_pg1;
+
+ cocktail_mode = current_videoram_pg_index && (input_port_3_r(0) & 0x01);
+
+ tilemap_set_flip(ALL_TILEMAPS, cocktail_mode ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+
+ /* the palette table is at $0420-$042f and is set by $06bc.
+ Four palette changes by level. The palette selection is
+ wrong, but the same paletter is used for both layers. */
+
+ if (palette_bank != ((data >> 1) & 3))
+ {
+ palette_bank = ((data >> 1) & 3);
+
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+
+ logerror("Palette: %02X\n", (data & 0x06) >> 1);
+ }
+
+ pleiads_protection_question = data & 0xfc;
+
+ /* send two bits to sound control C (not sure if they are there) */
+ pleiads_sound_control_c_w(offset, data);
+}
+
+
+WRITE8_HANDLER( phoenix_scroll_w )
+{
+ tilemap_set_scrollx(bg_tilemap,0,data);
+}
+
+
+READ8_HANDLER( phoenix_input_port_0_r )
+{
+ if (cocktail_mode)
+ return (input_port_0_r(0) & 0x07) | (input_port_1_r(0) & 0xf8);
+ else
+ return input_port_0_r(0);
+}
+
+READ8_HANDLER( pleiads_input_port_0_r )
+{
+ int ret = phoenix_input_port_0_r(0) & 0xf7;
+
+ /* handle Pleiads protection */
+ switch (pleiads_protection_question)
+ {
+ case 0x00:
+ case 0x20:
+ /* Bit 3 is 0 */
+ break;
+ case 0x0c:
+ case 0x30:
+ /* Bit 3 is 1 */
+ ret |= 0x08;
+ break;
+ default:
+ logerror("Unknown protection question %02X at %04X\n", pleiads_protection_question, activecpu_get_pc());
+ }
+
+ return ret;
+}
+
+READ8_HANDLER( survival_input_port_0_r )
+{
+ int ret = phoenix_input_port_0_r(0);
+
+ if (survival_protection_value)
+ {
+ ret ^= 0xf0;
+ }
+
+ return ret;
+}
+
+READ8_HANDLER( survival_protection_r )
+{
+ if (activecpu_get_pc() == 0x2017)
+ {
+ survival_protection_value ^= 1;
+ }
+
+ return survival_protection_value;
+}
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( phoenix )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/pingpong.c b/src/mame/video/pingpong.c
new file mode 100644
index 00000000000..314a274429a
--- /dev/null
+++ b/src/mame/video/pingpong.c
@@ -0,0 +1,156 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+
+/* This is strange; it's unlikely that the sprites actually have a hardware */
+/* clipping region, but I haven't found another way to have them masked by */
+/* the characters at the top and bottom of the screen. */
+static rectangle spritevisiblearea =
+{
+ 0*8, 32*8-1,
+ 4*8, 29*8-1
+};
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Ping Pong has a 32 bytes palette PROM and two 256 bytes color lookup table
+ PROMs (one for sprites, one for characters).
+ I don't know for sure how the palette PROM is connected to the RGB output,
+ but it's probably the usual:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( pingpong )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the char lookup table */
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ {
+ int code;
+ int bit0,bit1,bit2,bit3;
+
+ /* the bits of the color code are in reverse order - 0123 instead of 3210 */
+ code = *(color_prom++) & 0x0f;
+ bit0 = (code >> 0) & 1;
+ bit1 = (code >> 1) & 1;
+ bit2 = (code >> 2) & 1;
+ bit3 = (code >> 3) & 1;
+ code = (bit0 << 3) | (bit1 << 2) | (bit2 << 1) | (bit3 << 0);
+ COLOR(1,i) = code;
+ }
+
+ /* characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = (*(color_prom++) & 0x0f) + 0x10;
+}
+
+WRITE8_HANDLER( pingpong_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( pingpong_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + ((attr & 0x20) << 3);
+ int color = attr & 0x1f;
+ int flags = ((attr & 0x40) ? TILE_FLIPX : 0) | ((attr & 0x80) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( pingpong )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int sx,sy,flipx,flipy,color,schar;
+
+
+ sx = spriteram[offs + 3];
+ sy = 241 - spriteram[offs + 1];
+
+ flipx = spriteram[offs] & 0x40;
+ flipy = spriteram[offs] & 0x80;
+ color = spriteram[offs] & 0x1F;
+ schar = spriteram[offs + 2] & 0x7F;
+
+ drawgfx(bitmap,machine->gfx[1],
+ schar,
+ color,
+ flipx,flipy,
+ sx,sy,
+ &spritevisiblearea,TRANSPARENCY_COLOR,0);
+ }
+}
+
+VIDEO_UPDATE( pingpong )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/pirates.c b/src/mame/video/pirates.c
new file mode 100644
index 00000000000..ac426a61531
--- /dev/null
+++ b/src/mame/video/pirates.c
@@ -0,0 +1,117 @@
+#include "driver.h"
+
+
+UINT16 *pirates_tx_tileram, *pirates_spriteram;
+UINT16 *pirates_fg_tileram, *pirates_bg_tileram;
+UINT16 *pirates_scroll;
+
+static tilemap *tx_tilemap, *fg_tilemap, *bg_tilemap;
+
+/* Video Hardware */
+
+/* tilemaps */
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int code = pirates_tx_tileram[tile_index*2];
+ int colr = pirates_tx_tileram[tile_index*2+1];
+
+ SET_TILE_INFO(0,code,colr,0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = pirates_fg_tileram[tile_index*2];
+ int colr = pirates_fg_tileram[tile_index*2+1]+0x80;
+
+ SET_TILE_INFO(0,code,colr,0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = pirates_bg_tileram[tile_index*2];
+ int colr = pirates_bg_tileram[tile_index*2+1]+ 0x100;
+
+ SET_TILE_INFO(0,code,colr,0);
+}
+
+
+/* video start / update */
+
+VIDEO_START(pirates)
+{
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,36,32);
+
+ /* Not sure how big they can be, Pirates uses only 32 columns, Genix 44 */
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,64,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 8,8,64,32);
+
+ tilemap_set_transparent_pen(tx_tilemap,0);
+ tilemap_set_transparent_pen(fg_tilemap,0);
+}
+
+
+
+WRITE16_HANDLER( pirates_tx_tileram_w )
+{
+ COMBINE_DATA(pirates_tx_tileram+offset);
+ tilemap_mark_tile_dirty(tx_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( pirates_fg_tileram_w )
+{
+ COMBINE_DATA(pirates_fg_tileram+offset);
+ tilemap_mark_tile_dirty(fg_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( pirates_bg_tileram_w )
+{
+ COMBINE_DATA(pirates_bg_tileram+offset);
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const gfx_element *gfx = machine->gfx[1];
+ UINT16 *source = pirates_spriteram + 4;
+ UINT16 *finish = source + 0x800/2-4;
+
+ while( source<finish )
+ {
+ int xpos, ypos, flipx, flipy, code, color;
+
+ xpos = source[1] - 32;
+ ypos = source[-1]; // indeed...
+
+ if (ypos & 0x8000) break; /* end-of-list marker */
+
+ code = source[2] >> 2;
+ color = source[0] & 0xff;
+ flipx = source[2] & 2;
+ flipy = source[2] & 1;
+
+ ypos = 0xf2 - ypos;
+
+ drawgfx(bitmap,gfx,
+ code,
+ color,
+ flipx,flipy,
+ xpos,ypos,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ source+=4;
+ }
+}
+
+VIDEO_UPDATE(pirates)
+{
+ tilemap_set_scrollx(bg_tilemap,0,pirates_scroll[0]);
+ tilemap_set_scrollx(fg_tilemap,0,pirates_scroll[0]);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/pitnrun.c b/src/mame/video/pitnrun.c
new file mode 100644
index 00000000000..87ee099612b
--- /dev/null
+++ b/src/mame/video/pitnrun.c
@@ -0,0 +1,291 @@
+/***************************************************************************
+
+ - BG layer 32x128 , 8x8 tiles 4bpp , 2 palettes (2nd is black )
+ - TXT layer 32x32 , 8x8 tiles 4bpp , 2 palettes (2nd is black)
+ - Sprites 16x16 3bpp, 8 palettes (0-3 are black)
+
+ 'Special' effects :
+
+ - spotlight - gfx(BG+Sprites) outside spotlight is using black pals
+ spotlight masks are taken from ROM pr8
+ simulated using bitmaps and custom clipping rect
+
+ - lightning - BG color change (darkening ?) - simple analog circ.
+ simulated by additional palette
+
+In debug build press 'w' for spotlight and 'e' for lightning
+
+***************************************************************************/
+#include "driver.h"
+
+static int pitnrun_h_heed;
+static int pitnrun_v_heed;
+static int pitnrun_ha;
+static int pitnrun_scroll;
+static int pitnrun_char_bank;
+static int pitnrun_color_select;
+static mame_bitmap *tmp_bitmap[4];
+static tilemap *bg, *fg;
+UINT8* pitnrun_videoram2;
+
+
+static TILE_GET_INFO( get_tile_info1 )
+{
+ int code;
+ code = videoram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ code,
+ 0,
+ 0);
+}
+
+static TILE_GET_INFO( get_tile_info2 )
+{
+ int code;
+ code = pitnrun_videoram2[tile_index];
+ SET_TILE_INFO(
+ 1,
+ code + (pitnrun_char_bank<<8),
+ pitnrun_color_select&1,
+ 0);
+}
+
+WRITE8_HANDLER( pitnrun_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_all_tiles_dirty( fg );
+}
+
+WRITE8_HANDLER( pitnrun_videoram2_w )
+{
+ pitnrun_videoram2[offset] = data;
+ tilemap_mark_all_tiles_dirty( bg );
+}
+
+
+READ8_HANDLER( pitnrun_videoram_r )
+{
+ return videoram[offset];
+}
+
+READ8_HANDLER( pitnrun_videoram2_r )
+{
+ return pitnrun_videoram2[offset];
+}
+
+WRITE8_HANDLER( pitnrun_char_bank_select )
+{
+ if(pitnrun_char_bank!=data)
+ {
+ tilemap_mark_all_tiles_dirty( bg );
+ pitnrun_char_bank=data;
+ }
+}
+
+
+WRITE8_HANDLER( pitnrun_scroll_w )
+{
+ pitnrun_scroll = (pitnrun_scroll & (0xff<<((offset)?0:8))) |( data<<((offset)?8:0));
+ tilemap_set_scrollx( bg, 0, pitnrun_scroll);
+}
+
+WRITE8_HANDLER(pitnrun_ha_w)
+{
+ pitnrun_ha=data;
+}
+
+WRITE8_HANDLER(pitnrun_h_heed_w)
+{
+ pitnrun_h_heed=data;
+}
+
+WRITE8_HANDLER(pitnrun_v_heed_w)
+{
+ pitnrun_v_heed=data;
+}
+
+WRITE8_HANDLER(pitnrun_color_select_w)
+{
+ pitnrun_color_select=data;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+}
+
+static void pitnrun_spotlights(void)
+{
+ int x,y,i,b,datapix;
+ UINT8 *ROM = memory_region(REGION_USER1);
+ for(i=0;i<4;i++)
+ for(y=0;y<128;y++)
+ for(x=0;x<16;x++)
+ {
+ datapix=ROM[128*16*i+x+y*16];
+ for(b=0;b<8;b++)
+ {
+ *BITMAP_ADDR16(tmp_bitmap[i], y, x*8+(7-b)) = (datapix&1);
+ datapix>>=1;
+ }
+ }
+}
+
+
+PALETTE_INIT (pitnrun)
+{
+ int i;
+ int bit0,bit1,bit2,r,g,b;
+ for (i = 0;i < 32*3; i++)
+ {
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ /* fake bg palette for lightning effect*/
+ for(i=2*16;i<2*16+16;i++)
+ {
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ r/=3;
+ g/=3;
+ b/=3;
+
+ palette_set_color_rgb(machine,i+16,(r>0xff)?0xff:r,(g>0xff)?0xff:g,(b>0xff)?0xff:b);
+
+ }
+}
+
+VIDEO_START(pitnrun)
+{
+ fg = tilemap_create( get_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+ bg = tilemap_create( get_tile_info2,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32*4,32 );
+ tilemap_set_transparent_pen( fg, 0 );
+ tmp_bitmap[0] = auto_bitmap_alloc(128,128,machine->screen[0].format);
+ tmp_bitmap[1] = auto_bitmap_alloc(128,128,machine->screen[0].format);
+ tmp_bitmap[2] = auto_bitmap_alloc(128,128,machine->screen[0].format);
+ tmp_bitmap[3] = auto_bitmap_alloc(128,128,machine->screen[0].format);
+ pitnrun_spotlights();
+ video_start_generic(machine);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int sx, sy, flipx, flipy, offs,pal;
+
+ for (offs = 0 ; offs < 0x100; offs+=4)
+ {
+
+ pal=spriteram[offs+2]&0x3;
+
+ sy = 256-spriteram[offs+0]-16;
+ sx = spriteram[offs+3];
+ flipy = (spriteram[offs+1]&0x80)>>7;
+ flipx = (spriteram[offs+1]&0x40)>>6;
+
+ if (flip_screen_x)
+ {
+ sx = 256 - sx;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[2],
+ (spriteram[offs+1]&0x3f)+((spriteram[offs+2]&0x80)>>1)+((spriteram[offs+2]&0x40)<<1),
+ pal,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( pitnrun )
+{
+ int dx=0,dy=0;
+ rectangle myclip=*cliprect;
+
+#ifdef MAME_DEBUG
+ if (input_code_pressed_once(KEYCODE_Q))
+ {
+ UINT8 *ROM = memory_region(REGION_CPU1);
+ ROM[0x84f6]=0; /* lap 0 - normal */
+ }
+
+ if (input_code_pressed_once(KEYCODE_W))
+ {
+ UINT8 *ROM = memory_region(REGION_CPU1);
+ ROM[0x84f6]=6; /* lap 6 = spotlight */
+ }
+
+ if (input_code_pressed_once(KEYCODE_E))
+ {
+ UINT8 *ROM = memory_region(REGION_CPU1);
+ ROM[0x84f6]=2; /* lap 3 (trial 2)= lightnings */
+ ROM[0x8102]=1;
+ }
+#endif
+
+ fillbitmap(bitmap,0,cliprect);
+
+ if(!(pitnrun_ha&4))
+ tilemap_draw(bitmap,cliprect,bg, 0,0);
+ else
+ {
+ dx=128-pitnrun_h_heed+((pitnrun_ha&8)<<5)+3;
+ dy=128-pitnrun_v_heed+((pitnrun_ha&0x10)<<4);
+
+ if (flip_screen_x)
+ dx=128-dx+16;
+
+ if (flip_screen_y)
+ dy=128-dy;
+
+ myclip.min_x=dx;
+ myclip.min_y=dy;
+ myclip.max_x=dx+127;
+ myclip.max_y=dy+127;
+
+
+ if(myclip.min_y<cliprect->min_y)myclip.min_y=cliprect->min_y;
+ if(myclip.min_x<cliprect->min_x)myclip.min_x=cliprect->min_x;
+
+ if(myclip.max_y>cliprect->max_y)myclip.max_y=cliprect->max_y;
+ if(myclip.max_x>cliprect->max_x)myclip.max_x=cliprect->max_x;
+
+ tilemap_draw(bitmap,&myclip,bg, 0,0);
+ }
+
+ draw_sprites(machine,bitmap,&myclip);
+
+ if(pitnrun_ha&4)
+ copybitmap(bitmap,tmp_bitmap[pitnrun_ha&3],flip_screen_x,flip_screen_y,dx,dy,&myclip,TRANSPARENCY_PEN, 1);
+ tilemap_draw(bitmap,cliprect,fg, 0,0);
+ return 0;
+}
+
+
+
+
diff --git a/src/mame/video/pktgaldx.c b/src/mame/video/pktgaldx.c
new file mode 100644
index 00000000000..565fcc8f2b4
--- /dev/null
+++ b/src/mame/video/pktgaldx.c
@@ -0,0 +1,158 @@
+#include "driver.h"
+#include "deco16ic.h"
+
+UINT16* pcktgaldb_fgram;
+UINT16* pcktgaldb_sprites;
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+ int flipscreen=!flip_screen;
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ sprite = spriteram16[offs+1];
+ if (!sprite) continue;
+
+ y = spriteram16[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ x = spriteram16[offs+2];
+ colour = (x >>9) & 0x1f;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+ y = 240 - y;
+ x = 304 - x;
+
+ if (x>320) continue;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flipscreen)
+ {
+ y=240-y;
+ x=304-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ multi--;
+ }
+ }
+}
+
+static int pktgaldx_bank_callback(const int bank)
+{
+ return ((bank>>4) & 0x7) * 0x1000;
+}
+
+/* Video on the orginal */
+VIDEO_START(pktgaldx)
+{
+ deco16_1_video_init();
+
+ deco16_set_tilemap_bank_callback(1,pktgaldx_bank_callback);
+}
+
+VIDEO_UPDATE(pktgaldx)
+{
+ flip_screen_set( deco16_pf12_control[0]&0x80 );
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+
+ fillbitmap(bitmap,machine->pens[0x0],cliprect); /* not Confirmed */
+ fillbitmap(priority_bitmap,0,NULL);
+
+ deco16_tilemap_2_draw(bitmap,cliprect,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+ return 0;
+}
+
+/* Video for the bootleg */
+VIDEO_START(pktgaldb)
+{
+}
+
+VIDEO_UPDATE(pktgaldb)
+{
+ int x,y;
+ int offset=0;
+ int tileno;
+ int colour;
+
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ /* the bootleg seems to treat the tilemaps as sprites */
+ for (offset = 0;offset<0x1600/2;offset+=8)
+ {
+ tileno = pcktgaldb_sprites[offset+3] | (pcktgaldb_sprites[offset+2]<<16);
+ colour = pcktgaldb_sprites[offset+1]>>1;
+ x = pcktgaldb_sprites[offset+0];
+ y = pcktgaldb_sprites[offset+4];
+
+ x-=0xc2;
+ y&=0x1ff;
+ y-=8;
+
+ drawgfx(bitmap,machine->gfx[0],tileno^0x1000,colour,0,0,x,y,cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ for (offset = 0x1600/2;offset<0x2000/2;offset+=8)
+ {
+ tileno = pcktgaldb_sprites[offset+3] | (pcktgaldb_sprites[offset+2]<<16);
+ colour = pcktgaldb_sprites[offset+1]>>1;
+ x = pcktgaldb_sprites[offset+0]&0x1ff;
+ y = pcktgaldb_sprites[offset+4]&0x0ff;
+
+ x-=0xc2;
+ y&=0x1ff;
+ y-=8;
+
+ drawgfx(bitmap,machine->gfx[0],tileno^0x4000,colour,0,0,x,y,cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ for (offset = 0x2000/2;offset<0x4000/2;offset+=8)
+ {
+ tileno = pcktgaldb_sprites[offset+3] | (pcktgaldb_sprites[offset+2]<<16);
+ colour = pcktgaldb_sprites[offset+1]>>1;
+ x = pcktgaldb_sprites[offset+0]&0x1ff;
+ y = pcktgaldb_sprites[offset+4]&0x0ff;
+
+ x-=0xc2;
+ y&=0x1ff;
+ y-=8;
+
+ drawgfx(bitmap,machine->gfx[0],tileno^0x3000,colour,0,0,x,y,cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/pkunwar.c b/src/mame/video/pkunwar.c
new file mode 100644
index 00000000000..776e5732567
--- /dev/null
+++ b/src/mame/video/pkunwar.c
@@ -0,0 +1,117 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+static int flipscreen[2];
+
+
+WRITE8_HANDLER( pkunwar_flipscreen_w )
+{
+ if (flipscreen[0] != (data & 1))
+ {
+ flipscreen[0] = data & 1;
+ memset(dirtybuffer,1,videoram_size);
+ }
+ if (flipscreen[1] != (data & 2))
+ {
+ flipscreen[1] = data & 2;
+ memset(dirtybuffer,1,videoram_size);
+ }
+}
+
+
+
+VIDEO_UPDATE( pkunwar )
+{
+ int offs;
+
+
+ /* for every character in the Video RAM, check if it has been modified */
+ /* since last time and update it accordingly. */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ if (dirtybuffer[offs])
+ {
+ int sx,sy;
+
+
+ dirtybuffer[offs] = 0;
+
+ sx = offs % 32;
+ sy = offs / 32;
+ if (flipscreen[0]) sx = 31 - sx;
+ if (flipscreen[1]) sy = 31 - sy;
+
+ drawgfx(tmpbitmap,machine->gfx[0],
+ videoram[offs] + ((colorram[offs] & 0x07) << 8),
+ (colorram[offs] & 0xf0) >> 4,
+ flipscreen[0],flipscreen[1],
+ 8*sx,8*sy,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ /* copy the character mapped graphics */
+ copybitmap(bitmap,tmpbitmap,0,0,0,0,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+
+
+ /* Draw the sprites. */
+ for (offs = 0;offs < spriteram_size;offs += 32)
+ {
+ int sx,sy,flipx,flipy;
+
+
+ sx = ((spriteram[offs + 1] + 8) & 0xff) - 8;
+ sy = spriteram[offs + 2];
+ flipx = spriteram[offs] & 0x01;
+ flipy = spriteram[offs] & 0x02;
+ if (flipscreen[0])
+ {
+ sx = 240 - sx;
+ flipx = !flipx;
+ }
+ if (flipscreen[1])
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ ((spriteram[offs] & 0xfc) >> 2) + ((spriteram[offs + 3] & 0x07) << 6),
+ (spriteram[offs + 3] & 0xf0) >> 4,
+ flipx,flipy,
+ sx,sy,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+
+
+ /* redraw characters which have priority over sprites */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ if (colorram[offs] & 0x08)
+ {
+ int sx,sy;
+
+
+ sx = offs % 32;
+ sy = offs / 32;
+ if (flipscreen[0]) sx = 31 - sx;
+ if (flipscreen[1]) sy = 31 - sy;
+
+ drawgfx(bitmap,machine->gfx[0],
+ videoram[offs] + ((colorram[offs] & 0x07) << 8),
+ (colorram[offs] & 0xf0) >> 4,
+ flipscreen[0],flipscreen[1],
+ 8*sx,8*sy,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/playch10.c b/src/mame/video/playch10.c
new file mode 100644
index 00000000000..3bd6795a8d2
--- /dev/null
+++ b/src/mame/video/playch10.c
@@ -0,0 +1,174 @@
+#include "driver.h"
+#include "video/ppu2c0x.h"
+
+/* from machine */
+extern int pc10_sdcs; /* ShareD Chip Select */
+extern int pc10_dispmask; /* Display Mask */
+extern int pc10_gun_controller; /* whether we need to draw a crosshair or not */
+extern int pc10_int_detect;
+extern int pc10_game_mode;
+extern int pc10_dispmask_old;
+
+/* from common.c */
+extern int system_bios;
+
+static tilemap *bg_tilemap;
+
+WRITE8_HANDLER( playch10_videoram_w )
+{
+ if (pc10_sdcs)
+ {
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+ }
+}
+
+PALETTE_INIT( playch10 )
+{
+ int i;
+
+ for (i = 0; i < 256; i++)
+ {
+ int bit0, bit1, bit2, bit3, r, g, b;
+
+ /* red component */
+
+ bit0 = ~(color_prom[0] >> 0) & 0x01;
+ bit1 = ~(color_prom[0] >> 1) & 0x01;
+ bit2 = ~(color_prom[0] >> 2) & 0x01;
+ bit3 = ~(color_prom[0] >> 3) & 0x01;
+
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ /* green component */
+ bit0 = ~(color_prom[256] >> 0) & 0x01;
+ bit1 = ~(color_prom[256] >> 1) & 0x01;
+ bit2 = ~(color_prom[256] >> 2) & 0x01;
+ bit3 = ~(color_prom[256] >> 3) & 0x01;
+
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ /* blue component */
+
+ bit0 = ~(color_prom[2*256] >> 0) & 0x01;
+ bit1 = ~(color_prom[2*256] >> 1) & 0x01;
+ bit2 = ~(color_prom[2*256] >> 2) & 0x01;
+ bit3 = ~(color_prom[2*256] >> 3) & 0x01;
+
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+
+ ppu2c0x_init_palette(machine, 256 );
+}
+
+static void ppu_irq( int num, int *ppu_regs )
+{
+ cpunum_set_input_line(1, INPUT_LINE_NMI, PULSE_LINE );
+ pc10_int_detect = 1;
+}
+
+/* our ppu interface */
+/* things like mirroring and whether to use vrom or vram */
+/* can be set by calling 'ppu2c0x_override_hardware_options' */
+
+static const ppu2c0x_interface ppu_interface =
+{
+ PPU_2C03B, /* type */
+ 1, /* num */
+ { REGION_GFX2 }, /* vrom gfx region */
+ { 1 }, /* gfxlayout num */
+ { 256 }, /* color base */
+ { PPU_MIRROR_NONE }, /* mirroring */
+ { ppu_irq } /* irq */
+};
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int offs = tile_index * 2;
+ int code = videoram[offs] + ((videoram[offs + 1] & 0x07) << 8);
+ int color = (videoram[offs + 1] >> 3) & 0x1f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( playch10 )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ ppu2c0x_init(machine, &ppu_interface );
+}
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( playch10 )
+{
+ /* Dual monitor version */
+ if(system_bios == 1)
+ {
+ /* On Playchoice 10 single monitor, this bit toggles */
+ /* between PPU and BIOS display. */
+ /* We support the multi-monitor layout. In this case, */
+ /* if the bit is not set, then we should display */
+ /* the PPU portion. */
+
+ if ( screen == 0 )
+ {
+ if ( !pc10_dispmask )
+ {
+ /* render the ppu */
+ ppu2c0x_render( 0, bitmap, 0, 0, 0, 0 );
+ }
+ else
+ fillbitmap(bitmap, 0, cliprect);
+ }
+ else
+ {
+ /* When the bios is accessing vram, the video circuitry can't access it */
+
+ if ( !pc10_sdcs )
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ else
+ fillbitmap(bitmap, 0, cliprect);
+ }
+ }
+ else /* Single Monitor version */
+ {
+ rectangle top_monitor = machine->screen[0].visarea;
+
+ top_monitor.max_y = ( top_monitor.max_y - top_monitor.min_y ) / 2;
+
+ if(pc10_dispmask_old != pc10_dispmask)
+ {
+ pc10_dispmask_old = pc10_dispmask;
+
+ if(pc10_dispmask)
+ pc10_game_mode ^= 1;
+ }
+
+
+ if ( pc10_game_mode )
+ {
+ /* render the ppu */
+ ppu2c0x_render( 0, bitmap, 0, 0, 0, 0 );
+ }
+ else
+ {
+ /* When the bios is accessing vram, the video circuitry can't access it */
+
+ if ( !pc10_sdcs )
+ {
+ tilemap_draw(bitmap, &top_monitor, bg_tilemap, 0, 0);
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/playmark.c b/src/mame/video/playmark.c
new file mode 100644
index 00000000000..577ac076305
--- /dev/null
+++ b/src/mame/video/playmark.c
@@ -0,0 +1,477 @@
+#include "driver.h"
+
+UINT16 *bigtwin_bgvideoram;
+UINT16 *wbeachvl_videoram1,*wbeachvl_videoram2,*wbeachvl_videoram3;
+UINT16 *wbeachvl_rowscroll;
+
+static int bgscrollx,bgscrolly,bg_enable,bg_full_size;
+static int fgscrollx,fg_rowscroll_enable;
+static tilemap *tx_tilemap,*fg_tilemap,*bg_tilemap;
+
+static int xoffset = 0;
+static int yoffset = 0;
+static int txt_tile_offset = 0;
+static int pri_masks[3];
+static UINT16 playmark_scroll[7];
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( bigtwin_get_tx_tile_info )
+{
+ UINT16 code = wbeachvl_videoram1[2*tile_index];
+ UINT16 color = wbeachvl_videoram1[2*tile_index+1];
+ SET_TILE_INFO(
+ 2,
+ code,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( bigtwin_get_fg_tile_info )
+{
+ UINT16 code = wbeachvl_videoram2[2*tile_index];
+ UINT16 color = wbeachvl_videoram2[2*tile_index+1];
+ SET_TILE_INFO(
+ 1,
+ code,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( wbeachvl_get_tx_tile_info )
+{
+ UINT16 code = wbeachvl_videoram1[2*tile_index];
+ UINT16 color = wbeachvl_videoram1[2*tile_index+1];
+
+ SET_TILE_INFO(
+ 2,
+ code,
+ color / 4,
+ 0);
+}
+
+static TILE_GET_INFO( wbeachvl_get_fg_tile_info )
+{
+ UINT16 code = wbeachvl_videoram2[2*tile_index];
+ UINT16 color = wbeachvl_videoram2[2*tile_index+1];
+
+ SET_TILE_INFO(
+ 1,
+ code & 0x7fff,
+ color / 4 + 8,
+ (code & 0x8000) ? TILE_FLIPX : 0);
+}
+
+static TILE_GET_INFO( wbeachvl_get_bg_tile_info )
+{
+ UINT16 code = wbeachvl_videoram3[2*tile_index];
+ UINT16 color = wbeachvl_videoram3[2*tile_index+1];
+
+ SET_TILE_INFO(
+ 1,
+ code & 0x7fff,
+ color / 4,
+ (code & 0x8000) ? TILE_FLIPX : 0);
+}
+
+static TILE_GET_INFO( hrdtimes_get_tx_tile_info )
+{
+ int code = wbeachvl_videoram1[tile_index] & 0x03ff;
+ int colr = wbeachvl_videoram1[tile_index] & 0xe000;
+
+ SET_TILE_INFO(2,code + txt_tile_offset,colr >> 13,0);
+}
+
+static TILE_GET_INFO( hrdtimes_get_fg_tile_info )
+{
+ int code = wbeachvl_videoram2[tile_index] & 0x1fff;
+ int colr = wbeachvl_videoram2[tile_index] & 0xe000;
+
+ SET_TILE_INFO(1,code + 0x2000,(colr >> 13) + 8,0);
+}
+
+static TILE_GET_INFO( hrdtimes_get_bg_tile_info )
+{
+ int code = wbeachvl_videoram3[tile_index] & 0x1fff;
+ int colr = wbeachvl_videoram3[tile_index] & 0xe000;
+
+ SET_TILE_INFO(1,code,colr >> 13,0);
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( bigtwin )
+{
+ tx_tilemap = tilemap_create(bigtwin_get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ fg_tilemap = tilemap_create(bigtwin_get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,32,32);
+
+ tilemap_set_transparent_pen(tx_tilemap,0);
+
+ pri_masks[0] = 0;
+ pri_masks[1] = 0;
+ pri_masks[2] = 0;
+}
+
+
+VIDEO_START( wbeachvl )
+{
+ tx_tilemap = tilemap_create(wbeachvl_get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ fg_tilemap = tilemap_create(wbeachvl_get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ bg_tilemap = tilemap_create(wbeachvl_get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,64,32);
+
+ tilemap_set_transparent_pen(tx_tilemap,0);
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ pri_masks[0] = 0xfff0;
+ pri_masks[1] = 0xfffc;
+ pri_masks[2] = 0;
+}
+
+VIDEO_START( excelsr )
+{
+ tx_tilemap = tilemap_create(bigtwin_get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ fg_tilemap = tilemap_create(bigtwin_get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,32,32);
+
+ tilemap_set_transparent_pen(tx_tilemap,0);
+
+ pri_masks[0] = 0;
+ pri_masks[1] = 0xfffc;
+ pri_masks[2] = 0xfff0;
+}
+
+VIDEO_START( hotmind )
+{
+ tx_tilemap = tilemap_create(hrdtimes_get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,64);
+ fg_tilemap = tilemap_create(hrdtimes_get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ bg_tilemap = tilemap_create(hrdtimes_get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,32,32);
+
+ tilemap_set_transparent_pen(tx_tilemap,0);
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ tilemap_set_scrolldx(tx_tilemap, -14, -14);
+ tilemap_set_scrolldx(fg_tilemap, -14, -14);
+ tilemap_set_scrolldx(bg_tilemap, -14, -14);
+
+ xoffset = -9;
+ yoffset = -8;
+ txt_tile_offset = 0x9000;
+
+ pri_masks[0] = 0xfff0;
+ pri_masks[1] = 0xfffc;
+ pri_masks[2] = 0;
+}
+
+VIDEO_START( hrdtimes )
+{
+ tx_tilemap = tilemap_create(hrdtimes_get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,64);
+ fg_tilemap = tilemap_create(hrdtimes_get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ bg_tilemap = tilemap_create(hrdtimes_get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,32,32);
+
+ tilemap_set_transparent_pen(tx_tilemap,0);
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ tilemap_set_scrolldx(tx_tilemap, -14, -14);
+ tilemap_set_scrolldx(fg_tilemap, -10, -10);
+ tilemap_set_scrolldx(bg_tilemap, -12, -12);
+
+ xoffset = -8;
+ yoffset = -8;
+ txt_tile_offset = 0xfc00;
+
+ pri_masks[0] = 0xfff0;
+ pri_masks[1] = 0xfffc;
+ pri_masks[2] = 0;
+}
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( wbeachvl_txvideoram_w )
+{
+ COMBINE_DATA(&wbeachvl_videoram1[offset]);
+ tilemap_mark_tile_dirty(tx_tilemap,offset / 2);
+}
+
+WRITE16_HANDLER( wbeachvl_fgvideoram_w )
+{
+ COMBINE_DATA(&wbeachvl_videoram2[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset / 2);
+}
+
+WRITE16_HANDLER( wbeachvl_bgvideoram_w )
+{
+ COMBINE_DATA(&wbeachvl_videoram3[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset / 2);
+}
+
+WRITE16_HANDLER( hrdtimes_txvideoram_w )
+{
+ COMBINE_DATA(&wbeachvl_videoram1[offset]);
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+WRITE16_HANDLER( hrdtimes_fgvideoram_w )
+{
+ COMBINE_DATA(&wbeachvl_videoram2[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE16_HANDLER( hrdtimes_bgvideoram_w )
+{
+ COMBINE_DATA(&wbeachvl_videoram3[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+
+WRITE16_HANDLER( bigtwin_paletteram_w )
+{
+ int r,g,b,val;
+
+ COMBINE_DATA(&paletteram16[offset]);
+
+ val = paletteram16[offset];
+ r = (val >> 11) & 0x1e;
+ g = (val >> 7) & 0x1e;
+ b = (val >> 3) & 0x1e;
+
+ r |= ((val & 0x08) >> 3);
+ g |= ((val & 0x04) >> 2);
+ b |= ((val & 0x02) >> 1);
+
+ palette_set_color_rgb(Machine,offset,pal5bit(r),pal5bit(g),pal5bit(b));
+}
+
+WRITE16_HANDLER( bigtwin_scroll_w )
+{
+ data = COMBINE_DATA(&playmark_scroll[offset]);
+
+ switch (offset)
+ {
+ case 0: tilemap_set_scrollx(tx_tilemap,0,data+2); break;
+ case 1: tilemap_set_scrolly(tx_tilemap,0,data); break;
+ case 2: bgscrollx = -(data+4); break;
+ case 3: bgscrolly = (-data) & 0x1ff;
+ bg_enable = data & 0x0200;
+ bg_full_size = data & 0x0400;
+ break;
+ case 4: tilemap_set_scrollx(fg_tilemap,0,data+6); break;
+ case 5: tilemap_set_scrolly(fg_tilemap,0,data); break;
+ }
+}
+
+WRITE16_HANDLER( wbeachvl_scroll_w )
+{
+ data = COMBINE_DATA(&playmark_scroll[offset]);
+
+ switch (offset)
+ {
+ case 0: tilemap_set_scrollx(tx_tilemap,0,data+2); break;
+ case 1: tilemap_set_scrolly(tx_tilemap,0,data); break;
+ case 2: fgscrollx = data+4;break;
+ case 3: tilemap_set_scrolly(fg_tilemap,0,data & 0x3ff);
+ fg_rowscroll_enable = data & 0x0800;
+ break;
+ case 4: tilemap_set_scrollx(bg_tilemap,0,data+6); break;
+ case 5: tilemap_set_scrolly(bg_tilemap,0,data); break;
+ }
+}
+
+WRITE16_HANDLER( excelsr_scroll_w )
+{
+ data = COMBINE_DATA(&playmark_scroll[offset]);
+
+ switch (offset)
+ {
+ case 0: tilemap_set_scrollx(tx_tilemap,0,data+2); break;
+ case 1: tilemap_set_scrolly(tx_tilemap,0,data); break;
+ case 2: bgscrollx = -data; break;
+ case 3: bgscrolly = (-data+2)& 0x1ff;
+ bg_enable = data & 0x0200;
+ bg_full_size = data & 0x0400;
+ break;
+ case 4: tilemap_set_scrollx(fg_tilemap,0,data+6); break;
+ case 5: tilemap_set_scrolly(fg_tilemap,0,data); break;
+ }
+}
+
+WRITE16_HANDLER( hrdtimes_scroll_w )
+{
+ data = COMBINE_DATA(&playmark_scroll[offset]);
+
+ switch (offset)
+ {
+ case 0: tilemap_set_scrollx(tx_tilemap,0,data); break;
+ case 1: tilemap_set_scrolly(tx_tilemap,0,data); break;
+ case 2: tilemap_set_scrollx(fg_tilemap,0,data); break;
+ case 3: tilemap_set_scrolly(fg_tilemap,0,data); break;
+ case 4: tilemap_set_scrollx(bg_tilemap,0,data); break;
+ case 5: tilemap_set_scrolly(bg_tilemap,0,data); break;
+ }
+}
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int codeshift)
+{
+ int offs, start_offset = spriteram_size/2 - 4;
+ int height = machine->gfx[0]->height;
+ int colordiv = machine->gfx[0]->color_granularity / 16;
+
+ // find the "end of list" to draw the sprites in reverse order
+ for (offs = 4;offs < spriteram_size/2;offs += 4)
+ {
+ if (spriteram16[offs+3-4] == 0x2000) /* end of list marker */
+ {
+ start_offset = offs - 4;
+ break;
+ }
+ }
+
+ for (offs = start_offset;offs >= 4;offs -= 4)
+ {
+ int sx,sy,code,color,flipx,pri;
+
+ sy = spriteram16[offs+3-4]; /* -4? what the... ??? */
+
+ flipx = sy & 0x4000;
+ sx = (spriteram16[offs+1] & 0x01ff) - 16-7;
+ sy = (256-8-height - sy) & 0xff;
+ code = spriteram16[offs+2] >> codeshift;
+ color = ((spriteram16[offs+1] & 0x3e00) >> 9) / colordiv;
+ pri = (spriteram16[offs+1] & 0x8000) >> 15;
+
+ if(!pri && (color & 0x0c) == 0x0c)
+ pri = 2;
+
+ pdrawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,0,
+ sx + xoffset,sy + yoffset,
+ cliprect,TRANSPARENCY_PEN,0,pri_masks[pri]);
+ }
+}
+
+static void draw_bitmap(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int x,y,count;
+ int color;
+ UINT8 *pri;
+
+ count = 0;
+ for (y=0;y<512;y++)
+ {
+ for (x=0;x<512;x++)
+ {
+ color = bigtwin_bgvideoram[count] & 0xff;
+
+ if(color)
+ {
+ if(bg_full_size)
+ {
+ *BITMAP_ADDR16(bitmap, (y + bgscrolly) & 0x1ff, (x + bgscrollx) & 0x1ff) = machine->pens[0x100 + color];
+
+ pri = BITMAP_ADDR8(priority_bitmap, (y + bgscrolly) & 0x1ff, 0);
+ pri[(x + bgscrollx) & 0x1ff] |= 2;
+ }
+ else
+ {
+ /* 50% size */
+ if(!(x % 2) && !(y % 2))
+ {
+ *BITMAP_ADDR16(bitmap, (y / 2 + bgscrolly) & 0x1ff, (x / 2 + bgscrollx) & 0x1ff) = machine->pens[0x100 + color];
+
+ pri = BITMAP_ADDR8(priority_bitmap, (y / 2 + bgscrolly) & 0x1ff, 0);
+ pri[(x / 2 + bgscrollx) & 0x1ff] |= 2;
+ }
+ }
+ }
+
+ count++;
+ }
+ }
+}
+
+VIDEO_UPDATE( bigtwin )
+{
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ if (bg_enable)
+ draw_bitmap(machine, bitmap, cliprect);
+ draw_sprites(machine, bitmap,cliprect,4);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( excelsr )
+{
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,1);
+ if (bg_enable)
+ draw_bitmap(machine, bitmap, cliprect);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,4);
+ draw_sprites(machine,bitmap,cliprect,2);
+ return 0;
+}
+
+VIDEO_UPDATE( wbeachvl )
+{
+ if (fg_rowscroll_enable)
+ {
+ int i;
+
+ tilemap_set_scroll_rows(fg_tilemap,512);
+ for (i = 0;i < 256;i++)
+ tilemap_set_scrollx(fg_tilemap,i+1,wbeachvl_rowscroll[8*i]);
+ }
+ else
+ {
+ tilemap_set_scroll_rows(fg_tilemap,1);
+ tilemap_set_scrollx(fg_tilemap,0,fgscrollx);
+ }
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,1);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,2);
+ draw_sprites(machine,bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( hrdtimes )
+{
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ // video enabled
+ if(playmark_scroll[6] & 1)
+ {
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,1);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,2);
+ draw_sprites(machine,bitmap,cliprect,2);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ }
+ else
+ {
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ }
+ return 0;
+}
diff --git a/src/mame/video/plygonet.c b/src/mame/video/plygonet.c
new file mode 100644
index 00000000000..61791394388
--- /dev/null
+++ b/src/mame/video/plygonet.c
@@ -0,0 +1,93 @@
+/*
+ Polygonet Commanders (Konami, 1993)
+
+ Video hardware emulation
+
+ Currently contains: TTL text plane (probably not complete, needs banking? colors?)
+ Needs: PSAC2 roz plane, polygons
+*/
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+/* TTL text plane stuff */
+
+static int ttl_gfx_index;
+static tilemap *ttl_tilemap;
+static UINT16 ttl_vram[0x800];
+
+/* TTL text plane */
+
+static TILE_GET_INFO( ttl_get_tile_info )
+{
+ int attr, code;
+
+ code = ttl_vram[tile_index]&0xff;
+ attr = 0;
+
+ SET_TILE_INFO(ttl_gfx_index, code, attr, 0);
+}
+
+READ32_HANDLER( polygonet_ttl_ram_r )
+{
+ UINT32 *vram = (UINT32 *)ttl_vram;
+
+ return(vram[offset]);
+}
+
+WRITE32_HANDLER( polygonet_ttl_ram_w )
+{
+ UINT32 *vram = (UINT32 *)ttl_vram;
+
+ COMBINE_DATA(&vram[offset]);
+
+ tilemap_mark_tile_dirty(ttl_tilemap, offset*2);
+ tilemap_mark_tile_dirty(ttl_tilemap, offset*2+1);
+}
+
+VIDEO_START( polygonet )
+{
+ static const gfx_layout charlayout =
+ {
+ 8, 8, // 8x8
+ 4096, // # of tiles
+ 4, // 4bpp
+ { 0, 1, 2, 3 }, // plane offsets
+ { 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4 }, // X offsets
+ { 0*8*4, 1*8*4, 2*8*4, 3*8*4, 4*8*4, 5*8*4, 6*8*4, 7*8*4 }, // Y offsets
+ 8*8*4
+ };
+
+ /* find first empty slot to decode gfx */
+ for (ttl_gfx_index = 0; ttl_gfx_index < MAX_GFX_ELEMENTS; ttl_gfx_index++)
+ if (machine->gfx[ttl_gfx_index] == 0)
+ break;
+
+ assert(ttl_gfx_index != MAX_GFX_ELEMENTS);
+
+ // decode the ttl layer's gfx
+ machine->gfx[ttl_gfx_index] = allocgfx(&charlayout);
+ decodegfx(machine->gfx[ttl_gfx_index], memory_region(REGION_GFX1), 0, machine->gfx[ttl_gfx_index]->total_elements);
+
+ if (machine->drv->color_table_len)
+ machine->gfx[ttl_gfx_index]->total_colors = machine->drv->color_table_len / 16;
+ else
+ machine->gfx[ttl_gfx_index]->total_colors = machine->drv->total_colors / 16;
+
+ // create the tilemap
+ ttl_tilemap = tilemap_create(ttl_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ tilemap_set_transparent_pen(ttl_tilemap, 0);
+
+ state_save_register_global_array(ttl_vram);
+}
+
+VIDEO_UPDATE( polygonet )
+{
+ fillbitmap(priority_bitmap, 0, NULL);
+ fillbitmap(bitmap, get_black_pen(machine), &machine->screen[0].visarea);
+
+ tilemap_draw(bitmap, cliprect, ttl_tilemap, 0, 1<<0);
+ return 0;
+}
+
diff --git a/src/mame/video/pokechmp.c b/src/mame/video/pokechmp.c
new file mode 100644
index 00000000000..3090fc400ff
--- /dev/null
+++ b/src/mame/video/pokechmp.c
@@ -0,0 +1,74 @@
+/* Poke Champ */
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+WRITE8_HANDLER( pokechmp_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+WRITE8_HANDLER( pokechmp_flipscreen_w )
+{
+ if (flip_screen != (data & 0x80))
+ {
+ flip_screen_set(data & 0x80);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index*2+1] + ((videoram[tile_index*2] & 0x3f) << 8);
+ int color = videoram[tile_index*2] >> 6;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( pokechmp )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ if (spriteram[offs] != 0xf8)
+ {
+ int sx,sy,flipx,flipy;
+
+
+ sx = 240 - spriteram[offs+2];
+ sy = 240 - spriteram[offs];
+
+ flipx = spriteram[offs+1] & 0x04;
+ flipy = spriteram[offs+1] & 0x02;
+ if (flip_screen) {
+ sx=240-sx;
+ sy=240-sy;
+ if (flipx) flipx=0; else flipx=1;
+ if (flipy) flipy=0; else flipy=1;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ spriteram[offs+3] + ((spriteram[offs+1] & 1) << 8),
+ (spriteram[offs+1] & 0x70) >> 4,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( pokechmp )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/polepos.c b/src/mame/video/polepos.c
new file mode 100644
index 00000000000..ff89c0c01b4
--- /dev/null
+++ b/src/mame/video/polepos.c
@@ -0,0 +1,532 @@
+#include "driver.h"
+
+UINT16 *polepos_view16_memory;
+UINT16 *polepos_road16_memory;
+UINT16 *polepos_sprite16_memory;
+UINT16 *polepos_alpha16_memory;
+
+/* modified vertical position built from three nibbles (12 bit)
+ * of ROMs 136014-142, 136014-143, 136014-144
+ * The value RVP (road vertical position, lower 12 bits) is added
+ * to this value and the upper 10 bits of the result are used to
+ * address the playfield video memory (AB0 - AB9).
+ */
+static UINT16 polepos_vertical_position_modifier[256];
+
+static UINT16 road16_vscroll;
+
+static colortable *polepos_colortable;
+static tilemap *bg_tilemap,*tx_tilemap;
+static int polepos_chacl;
+
+int polepos_gear_bit;
+
+/***************************************************************************
+
+ Convert the color PROMs.
+
+ Pole Position has three 256x4 palette PROMs (one per gun)
+ and a lot ;-) of 256x4 lookup table PROMs.
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+
+PALETTE_INIT( polepos )
+{
+ int i, j;
+
+ /* allocate the colortable */
+ polepos_colortable = colortable_alloc(machine, 128);
+
+ /*******************************************************
+ * Color PROMs
+ * Sheet 15B: middle, 136014-137,138,139
+ * Inputs: MUX0 ... MUX3, ALPHA/BACK, SPRITE/BACK, 128V, COMPBLANK
+ *
+ * Note that we only decode the lower 128 colors because
+ * the upper 128 are all black and used during the
+ * horizontal and vertical blanking periods.
+ * The purpose of the 128V input is to use a different palette for the
+ * background and for the road; it is irrelevant for alpha and
+ * sprites because their palette is the same in both halves.
+ * Anyway, we emulate that to a certain extent, using different
+ * colortables for the two halves of the screen. We don't support the
+ * palette change in the middle of a sprite, however.
+ * Also, note that priority encoding is done is such a way that alpha
+ * will use palette bank 2 or 3 depending on whether there is a sprite
+ * below the pixel or not. That would be tricky to emulate, and it's
+ * not needed because of course the two banks are the same.
+ *******************************************************/
+ for (i = 0; i < 128; i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ /* Sheet 15B: 136014-0137 red component */
+ bit0 = (color_prom[0x000 + i] >> 0) & 1;
+ bit1 = (color_prom[0x000 + i] >> 1) & 1;
+ bit2 = (color_prom[0x000 + i] >> 2) & 1;
+ bit3 = (color_prom[0x000 + i] >> 3) & 1;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ /* Sheet 15B: 136014-0138 green component */
+ bit0 = (color_prom[0x100 + i] >> 0) & 1;
+ bit1 = (color_prom[0x100 + i] >> 1) & 1;
+ bit2 = (color_prom[0x100 + i] >> 2) & 1;
+ bit3 = (color_prom[0x100 + i] >> 3) & 1;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ /* Sheet 15B: 136014-0139 blue component */
+ bit0 = (color_prom[0x200 + i] >> 0) & 1;
+ bit1 = (color_prom[0x200 + i] >> 1) & 1;
+ bit2 = (color_prom[0x200 + i] >> 2) & 1;
+ bit3 = (color_prom[0x200 + i] >> 3) & 1;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ colortable_palette_set_color(polepos_colortable,i,MAKE_RGB(r,g,b));
+ }
+
+ /*******************************************************
+ * Alpha colors (colors 0x000-0x1ff)
+ * Sheet 15B: top left, 136014-140
+ * Inputs: SHFT0, SHFT1 and CHA8* ... CHA13*
+ *******************************************************/
+ for (i = 0; i < 64*4; i++)
+ {
+ int color = color_prom[0x300 + i];
+ colortable_entry_set_value(polepos_colortable, 0x0000 + i, (color != 15) ? (0x020 + color) : 0x2f);
+ colortable_entry_set_value(polepos_colortable, 0x0100 + i, (color != 15) ? (0x060 + color) : 0x2f);
+ }
+
+ /*******************************************************
+ * Background colors (colors 0x200-0x2ff)
+ * Sheet 13A: left, 136014-141
+ * Inputs: SHFT2, SHFT3 and CHA8 ... CHA13
+ * The background is only in the top half of the screen
+ *******************************************************/
+ for (i = 0; i < 64*4; i++)
+ {
+ int color = color_prom[0x400 + i];
+ colortable_entry_set_value(polepos_colortable, 0x0200 + i, 0x000 + color);
+ }
+
+ /*******************************************************
+ * Sprite colors (colors 0x300-0xaff)
+ * Sheet 14B: right, 136014-146
+ * Inputs: CUSTOM0 ... CUSTOM3 and DATA0 ... DATA5
+ *******************************************************/
+ for (i = 0; i < 64*16; i++)
+ {
+ int color = color_prom[0xc00 + i];
+ colortable_entry_set_value(polepos_colortable, 0x0300 + i, (color != 15) ? (0x010 + color) : 0x1f);
+ colortable_entry_set_value(polepos_colortable, 0x0700 + i, (color != 15) ? (0x050 + color) : 0x1f);
+ }
+
+ /*******************************************************
+ * Road colors (colors 0xb00-0x0eff)
+ * Sheet 13A: bottom left, 136014-145
+ * Inputs: R1 ... R6 and CHA0 ... CHA3
+ * The road is only in the bottom half of the screen
+ *******************************************************/
+ for (i = 0; i < 64*16; i++)
+ {
+ int color = color_prom[0x800 + i];
+ colortable_entry_set_value(polepos_colortable, 0x0b00 + i, 0x040 + color);
+ }
+
+ /* 136014-142, 136014-143, 136014-144 Vertical position modifiers */
+ for (i = 0; i < 256; i++)
+ {
+ j = color_prom[0x500 + i] + (color_prom[0x600 + i] << 4) + (color_prom[0x700 + i] << 8);
+ polepos_vertical_position_modifier[i] = j;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( bg_get_tile_info )
+{
+ UINT16 word = polepos_view16_memory[tile_index];
+ int code = (word & 0xff) | ((word & 0x4000) >> 6);
+ int color = (word & 0x3f00) >> 8;
+ SET_TILE_INFO(
+ 1,
+ code,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( tx_get_tile_info )
+{
+ UINT16 word = polepos_alpha16_memory[tile_index];
+ int code = (word & 0xff) | ((word & 0x4000) >> 6);
+ int color = (word & 0x3f00) >> 8;
+
+ /* I assume the purpose of CHACL is to allow the Z80 to control
+ the display (therefore using only the bottom 8 bits of tilemap RAM)
+ in case the Z8002 is not working. */
+ if (polepos_chacl == 0)
+ {
+ code &= 0xff;
+ color = 0;
+ }
+
+ /* 128V input to the palette PROM */
+ if (tile_index >= 32*16) color |= 0x40;
+
+ SET_TILE_INFO(
+ 0,
+ code,
+ color,
+ 0);
+ tileinfo->group = color;
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( polepos )
+{
+ bg_tilemap = tilemap_create(bg_get_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,64,16);
+ tx_tilemap = tilemap_create(tx_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ colortable_configure_tilemap_groups(polepos_colortable, tx_tilemap, machine->gfx[0], 0x2f);
+}
+
+
+/***************************************************************************
+
+ Sprite memory
+
+***************************************************************************/
+
+READ16_HANDLER( polepos_sprite16_r )
+{
+ return polepos_sprite16_memory[offset];
+}
+
+WRITE16_HANDLER( polepos_sprite16_w )
+{
+ COMBINE_DATA(&polepos_sprite16_memory[offset]);
+}
+
+READ8_HANDLER( polepos_sprite_r )
+{
+ return polepos_sprite16_memory[offset] & 0xff;
+}
+
+WRITE8_HANDLER( polepos_sprite_w )
+{
+ polepos_sprite16_memory[offset] = (polepos_sprite16_memory[offset] & 0xff00) | data;
+}
+
+
+/***************************************************************************
+
+ Road memory
+
+***************************************************************************/
+
+READ16_HANDLER( polepos_road16_r )
+{
+ return polepos_road16_memory[offset];
+}
+
+WRITE16_HANDLER( polepos_road16_w )
+{
+ COMBINE_DATA(&polepos_road16_memory[offset]);
+}
+
+READ8_HANDLER( polepos_road_r )
+{
+ return polepos_road16_memory[offset] & 0xff;
+}
+
+WRITE8_HANDLER( polepos_road_w )
+{
+ polepos_road16_memory[offset] = (polepos_road16_memory[offset] & 0xff00) | data;
+}
+
+WRITE16_HANDLER( polepos_road16_vscroll_w )
+{
+ COMBINE_DATA(&road16_vscroll);
+}
+
+
+/***************************************************************************
+
+ View memory
+
+***************************************************************************/
+
+READ16_HANDLER( polepos_view16_r )
+{
+ return polepos_view16_memory[offset];
+}
+
+WRITE16_HANDLER( polepos_view16_w )
+{
+ COMBINE_DATA(&polepos_view16_memory[offset]);
+ if (offset < 0x400)
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+READ8_HANDLER( polepos_view_r )
+{
+ return polepos_view16_memory[offset] & 0xff;
+}
+
+WRITE8_HANDLER( polepos_view_w )
+{
+ polepos_view16_memory[offset] = (polepos_view16_memory[offset] & 0xff00) | data;
+ if (offset < 0x400)
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE16_HANDLER( polepos_view16_hscroll_w )
+{
+ static UINT16 scroll;
+
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrollx(bg_tilemap,0,scroll);
+}
+
+WRITE8_HANDLER( polepos_chacl_w )
+{
+ if (polepos_chacl != (data & 1))
+ {
+ polepos_chacl = data & 1;
+ tilemap_mark_all_tiles_dirty(tx_tilemap);
+ }
+}
+
+
+/***************************************************************************
+
+ Alpha memory
+
+***************************************************************************/
+
+READ16_HANDLER( polepos_alpha16_r )
+{
+ return polepos_alpha16_memory[offset];
+}
+
+WRITE16_HANDLER( polepos_alpha16_w )
+{
+ COMBINE_DATA(&polepos_alpha16_memory[offset]);
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+READ8_HANDLER( polepos_alpha_r )
+{
+ return polepos_alpha16_memory[offset] & 0xff;
+}
+
+WRITE8_HANDLER( polepos_alpha_w )
+{
+ polepos_alpha16_memory[offset] = (polepos_alpha16_memory[offset] & 0xff00) | data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_road(running_machine *machine, mame_bitmap *bitmap)
+{
+ const UINT8 *road_control = memory_region(REGION_GFX5);
+ const UINT8 *road_bits1 = memory_region(REGION_GFX5) + 0x2000;
+ const UINT8 *road_bits2 = memory_region(REGION_GFX5) + 0x4000;
+ int x, y, i;
+
+ /* loop over the lower half of the screen */
+ for (y = 128; y < 256; y++)
+ {
+ int xoffs, yoffs, xscroll, roadpal;
+ UINT8 scanline[256 + 8];
+ UINT8 *dest = scanline;
+ const pen_t *colortable;
+
+ /* first add the vertical position modifier and the vertical scroll */
+ yoffs = ((polepos_vertical_position_modifier[y] + road16_vscroll) >> 3) & 0x1ff;
+
+ /* then use that as a lookup into the road memory */
+ roadpal = polepos_road16_memory[yoffs] & 15;
+
+ /* this becomes the palette base for the scanline */
+ colortable = &machine->pens[0x0b00 + (roadpal << 6)];
+
+ /* now fetch the horizontal scroll offset for this scanline */
+ xoffs = polepos_road16_memory[0x380 + (y & 0x7f)] & 0x3ff;
+
+ /* the road is drawn in 8-pixel chunks, so round downward and adjust the base */
+ /* note that we assume there is at least 8 pixels of slop on the left/right */
+ xscroll = xoffs & 7;
+ xoffs &= ~7;
+
+ /* loop over 8-pixel chunks */
+ for (x = 0; x < 256 / 8 + 1; x++, xoffs += 8)
+ {
+ /* if the 0x200 bit of the xoffset is set, a special pin on the custom */
+ /* chip is set and the /CE and /OE for the road chips is disabled */
+ if (xoffs & 0x200)
+ {
+ /* in this case, it looks like we just fill with 0 */
+ for (i = 0; i < 8; i++)
+ *dest++ = 0;
+ }
+
+ /* otherwise, we clock in the bits and compute the road value */
+ else
+ {
+ /* the road ROM offset comes from the current scanline and the X offset */
+ int romoffs = ((y & 0x07f) << 6) + ((xoffs & 0x1f8) >> 3);
+
+ /* fetch the current data from the road ROMs */
+ int control = road_control[romoffs];
+ int bits1 = road_bits1[romoffs];
+ int bits2 = road_bits2[(romoffs & 0xfff) | ((romoffs & 0x1000) >> 1)];
+
+ /* extract the road value and the carry-in bit */
+ int roadval = control & 0x3f;
+ int carin = control >> 7;
+
+ /* draw this 8-pixel chunk */
+ for (i = 8; i > 0; i--)
+ {
+ int bits = BIT(bits1,i) + (BIT(bits2,i) << 1);
+ if (!carin && bits) bits++;
+ *dest++ = roadval & 0x3f;
+ roadval += bits;
+ }
+ }
+ }
+
+ /* draw the scanline */
+ draw_scanline8(bitmap, 0, y, 256, &scanline[xscroll], colortable, -1);
+ }
+}
+
+static void zoom_sprite(running_machine *machine, mame_bitmap *bitmap,int big,
+ UINT32 code,UINT32 color,int flipx,int sx,int sy,
+ int sizex,int sizey)
+{
+ const gfx_element *gfx = machine->gfx[big ? 3 : 2];
+ UINT8 *gfxdata = gfx->gfxdata + (code % gfx->total_elements) * gfx->char_modulo;
+ UINT8 *scaling_rom = memory_region(REGION_GFX6);
+ UINT32 transmask = colortable_get_transpen_mask(polepos_colortable, gfx, color, 0x1f);
+ int coloroffs = gfx->color_base + color * gfx->color_granularity;
+ int x,y;
+
+ if (flipx) flipx = big ? 0x1f : 0x0f;
+
+ for (y = 0;y <= sizey;y++)
+ {
+ int yy = (sy + y) & 0x1ff;
+
+ /* the following should be a reasonable reproduction of how the real hardware works */
+ if (yy >= 0x10 && yy < 0xf0)
+ {
+ int dy = scaling_rom[(y << 6) + sizey] & 0x1f;
+ int xx = sx & 0x3ff;
+ int siz = 0;
+ int offs = 0;
+ UINT8 *src;
+
+ if (!big) dy >>= 1;
+ src = gfxdata + dy * gfx->line_modulo;
+
+ for (x = (big ? 0x40 : 0x20);x > 0;x--)
+ {
+ if (xx < 0x100)
+ {
+ int pen = src[offs/2 ^ flipx];
+
+ if (!((transmask >> pen) & 1))
+ *BITMAP_ADDR16(bitmap, yy, xx) = pen + coloroffs;
+ }
+ offs++;
+
+ siz = siz+1+sizex;
+ if (siz & 0x40)
+ {
+ siz &= 0x3f;
+ xx = (xx+1) & 0x3ff;
+ }
+ }
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ UINT16 *posmem = &polepos_sprite16_memory[0x380];
+ UINT16 *sizmem = &polepos_sprite16_memory[0x780];
+ int i;
+
+ for (i = 0; i < 64; i++, posmem += 2, sizmem += 2)
+ {
+ int sx = (posmem[1] & 0x3ff) - 0x40 + 4;
+ int sy = 512 - (posmem[0] & 0x1ff) + 1; // sprites are buffered and delayed by one scanline
+ int sizex = (sizmem[1] & 0x3f00) >> 8;
+ int sizey = (sizmem[0] & 0x3f00) >> 8;
+ int code = sizmem[0] & 0x7f;
+ int flipx = sizmem[0] & 0x80;
+ int color = sizmem[1] & 0x3f;
+
+ /* 128V input to the palette PROM */
+ if (sy >= 128) color |= 0x40;
+
+ zoom_sprite(machine, bitmap, (sizmem[0] & 0x8000) ? 1 : 0,
+ code,
+ color,
+ flipx,
+ sx, sy,
+ sizex,sizey);
+ }
+}
+
+
+VIDEO_UPDATE( polepos )
+{
+ rectangle clip = *cliprect;
+ clip.max_y = 127;
+ tilemap_draw(bitmap,&clip,bg_tilemap,0,0);
+ draw_road(machine, bitmap);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+/* following code should be enabled only in a debug build */
+/* original arcade doesn't work in this way */
+#ifdef MAME_DEBUG
+ {
+ int in = readinputport( 0 );
+ static int lastin;
+
+ if ((in ^ lastin) & polepos_gear_bit)
+ popmessage((in & polepos_gear_bit) ? "LO" : "HI");
+
+ lastin = in;
+ }
+#endif
+ return 0;
+}
diff --git a/src/mame/video/policetr.c b/src/mame/video/policetr.c
new file mode 100644
index 00000000000..129a3464f10
--- /dev/null
+++ b/src/mame/video/policetr.c
@@ -0,0 +1,370 @@
+/***************************************************************************
+
+ P&P Marketing Police Trainer hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "cpu/mips/r3000.h"
+#include "policetr.h"
+
+
+/* constants */
+#define SRCBITMAP_WIDTH 4096
+
+#define DSTBITMAP_WIDTH 512
+#define DSTBITMAP_HEIGHT 256
+
+
+/* local variables */
+static UINT32 palette_offset;
+static UINT8 palette_index;
+static UINT8 palette_data[3];
+
+static rectangle render_clip;
+static UINT8 *srcbitmap;
+static UINT8 *dstbitmap;
+
+static UINT16 src_xoffs, src_yoffs;
+static UINT16 dst_xoffs, dst_yoffs;
+static UINT8 video_latch;
+
+static UINT32 srcbitmap_height_mask;
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( policetr )
+{
+ /* the source bitmap is in ROM */
+ srcbitmap = memory_region(REGION_GFX1);
+
+ /* compute the height */
+ srcbitmap_height_mask = (memory_region_length(REGION_GFX1) / SRCBITMAP_WIDTH) - 1;
+
+ /* the destination bitmap is not directly accessible to the CPU */
+ dstbitmap = auto_malloc(DSTBITMAP_WIDTH * DSTBITMAP_HEIGHT);
+}
+
+
+
+/*************************************
+ *
+ * Display list processor
+ *
+ *************************************/
+
+static void render_display_list(offs_t offset)
+{
+ /* mask against the R3000 address space */
+ offset &= 0x1fffffff;
+
+ /* loop over all items */
+ while (offset != 0x1fffffff)
+ {
+ UINT32 *entry = &policetr_rambase[offset / 4];
+ UINT32 srcx = entry[0] & 0xfffffff;
+ UINT32 srcy = entry[1] & ((srcbitmap_height_mask << 16) | 0xffff);
+ UINT32 srcxstep = entry[2];
+ UINT32 srcystep = entry[3];
+ int dstw = (entry[4] & 0x1ff) + 1;
+ int dsth = ((entry[4] >> 12) & 0x1ff) + 1;
+ int dstx = entry[5] & 0x1ff;
+ int dsty = (entry[5] >> 12) & 0x1ff;
+ UINT8 mask = ~entry[6] >> 16;
+ UINT8 color = (entry[6] >> 24) & ~mask;
+ UINT32 curx, cury;
+ int x, y;
+
+ if (dstx > render_clip.max_x)
+ {
+ dstw -= (512 - dstx);
+ dstx = 0;
+ }
+ /* apply X clipping */
+ if (dstx < render_clip.min_x)
+ {
+ srcx += srcxstep * (render_clip.min_x - dstx);
+ dstw -= render_clip.min_x - dstx;
+ dstx = render_clip.min_x;
+ }
+ if (dstx + dstw > render_clip.max_x)
+ dstw = render_clip.max_x - dstx + 1;
+
+ /* apply Y clipping */
+ if (dsty < render_clip.min_y)
+ {
+ srcy += srcystep * (render_clip.min_y - dsty);
+ dsth -= render_clip.min_y - dsty;
+ dsty = render_clip.min_y;
+ }
+ if (dsty + dsth > render_clip.max_y)
+ dsth = render_clip.max_y - dsty + 1;
+
+ /* special case for fills */
+ if (srcxstep == 0 && srcystep == 0)
+ {
+ /* prefetch the pixel */
+ UINT8 pixel = srcbitmap[((srcy >> 16) * srcbitmap_height_mask) * SRCBITMAP_WIDTH + (srcx >> 16) % SRCBITMAP_WIDTH];
+ pixel = color | (pixel & mask);
+
+ /* loop over rows and columns */
+ if (dstw > 0)
+ for (y = 0; y < dsth; y++)
+ {
+ UINT8 *dst = &dstbitmap[(dsty + y) * DSTBITMAP_WIDTH + dstx];
+ memset(dst, pixel, dstw);
+ }
+ }
+
+ /* otherwise, standard render */
+ else
+ {
+ /* loop over rows */
+ for (y = 0, cury = srcy; y < dsth; y++, cury += srcystep)
+ {
+ UINT8 *src = &srcbitmap[((cury >> 16) & srcbitmap_height_mask) * SRCBITMAP_WIDTH];
+ UINT8 *dst = &dstbitmap[(dsty + y) * DSTBITMAP_WIDTH + dstx];
+
+ /* loop over columns */
+ for (x = 0, curx = srcx; x < dstw; x++, curx += srcxstep)
+ {
+ UINT8 pixel = src[(curx >> 16) % SRCBITMAP_WIDTH];
+ if (pixel)
+ dst[x] = color | (pixel & mask);
+ }
+ }
+ }
+
+ /* advance to the next link */
+ offset = entry[7] & 0x1fffffff;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video controller writes
+ *
+ *************************************/
+
+WRITE32_HANDLER( policetr_video_w )
+{
+ /* we assume 4-byte accesses */
+ if (mem_mask)
+ logerror("%08X: policetr_video_w access with mask %08X\n", activecpu_get_previouspc(), ~mem_mask);
+
+ /* 4 offsets */
+ switch (offset)
+ {
+ /* offset 0 specifies the start address of a display list */
+ case 0:
+ render_display_list(data);
+ break;
+
+ /* offset 1 specifies a latch value in the upper 8 bits */
+ case 1:
+ video_latch = data >> 24;
+ break;
+
+ /* offset 2 has various meanings based on the latch */
+ case 2:
+ {
+ switch (video_latch)
+ {
+ /* latch 0x04 specifies the source X offset for a source bitmap pixel read */
+ case 0x04:
+ src_xoffs = data >> 16;
+ break;
+
+ /* latch 0x14 specifies the source Y offset for a source bitmap pixel read */
+ case 0x14:
+ src_yoffs = data >> 16;
+ break;
+
+ /* latch 0x20 specifies the top/left corners of the render cliprect */
+ case 0x20:
+ render_clip.min_y = (data >> 12) & 0xfff;
+ render_clip.min_x = data & 0xfff;
+ break;
+
+ /* latch 0x30 specifies the bottom/right corners of the render cliprect */
+ case 0x30:
+ render_clip.max_y = (data >> 12) & 0xfff;
+ render_clip.max_x = data & 0xfff;
+ break;
+
+ /* latch 0x50 allows a direct write to the destination bitmap */
+ case 0x50:
+ if (ACCESSING_MSB32 && dst_xoffs < DSTBITMAP_WIDTH && dst_yoffs < DSTBITMAP_HEIGHT)
+ dstbitmap[dst_yoffs * DSTBITMAP_WIDTH + dst_xoffs] = data >> 24;
+ break;
+
+ /* log anything else */
+ default:
+ logerror("%08X: policetr_video_w(2) = %08X & %08X with latch %02X\n", activecpu_get_previouspc(), data, ~mem_mask, video_latch);
+ break;
+ }
+ break;
+ }
+
+ /* offset 3 has various meanings based on the latch */
+ case 3:
+ {
+ switch (video_latch)
+ {
+ /* latch 0x00 is unknown; 0, 1, and 2 get written into the upper 12 bits before rendering */
+ case 0x00:
+ if (data != (0 << 20) && data != (1 << 20) && data != (2 << 20))
+ logerror("%08X: policetr_video_w(3) = %08X & %08X with latch %02X\n", activecpu_get_previouspc(), data, ~mem_mask, video_latch);
+ break;
+
+ /* latch 0x10 specifies destination bitmap X and Y offsets */
+ case 0x10:
+ dst_yoffs = (data >> 12) & 0xfff;
+ dst_xoffs = data & 0xfff;
+ break;
+
+ /* latch 0x20 is unknown; either 0xef or 0x100 is written every IRQ4 */
+ case 0x20:
+ if (data != (0x100 << 12) && data != (0xef << 12))
+ logerror("%08X: policetr_video_w(3) = %08X & %08X with latch %02X\n", activecpu_get_previouspc(), data, ~mem_mask, video_latch);
+ break;
+
+ /* latch 0x40 is unknown; a 0 is written every IRQ4 */
+ case 0x40:
+ if (data != 0)
+ logerror("%08X: policetr_video_w(3) = %08X & %08X with latch %02X\n", activecpu_get_previouspc(), data, ~mem_mask, video_latch);
+ break;
+
+ /* latch 0x50 clears IRQ4 */
+ case 0x50:
+ cpunum_set_input_line(0, R3000_IRQ4, CLEAR_LINE);
+ break;
+
+ /* latch 0x60 clears IRQ5 */
+ case 0x60:
+ cpunum_set_input_line(0, R3000_IRQ5, CLEAR_LINE);
+ break;
+
+ /* log anything else */
+ default:
+ logerror("%08X: policetr_video_w(3) = %08X & %08X with latch %02X\n", activecpu_get_previouspc(), data, ~mem_mask, video_latch);
+ break;
+ }
+ break;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video controller reads
+ *
+ *************************************/
+
+READ32_HANDLER( policetr_video_r )
+{
+ int inputval;
+
+ /* the value read is based on the latch */
+ switch (video_latch)
+ {
+ /* latch 0x00 is player 1's gun X coordinate */
+ case 0x00:
+ inputval = ((readinputport(3) & 0xff) * Machine->screen[0].width) >> 8;
+ inputval += 0x50;
+ return (inputval << 20) | 0x20000000;
+
+ /* latch 0x01 is player 1's gun Y coordinate */
+ case 0x01:
+ inputval = ((readinputport(4) & 0xff) * Machine->screen[0].height) >> 8;
+ inputval += 0x17;
+ return (inputval << 20);
+
+ /* latch 0x02 is player 2's gun X coordinate */
+ case 0x02:
+ inputval = ((readinputport(5) & 0xff) * Machine->screen[0].width) >> 8;
+ inputval += 0x50;
+ return (inputval << 20) | 0x20000000;
+
+ /* latch 0x03 is player 2's gun Y coordinate */
+ case 0x03:
+ inputval = ((readinputport(6) & 0xff) * Machine->screen[0].height) >> 8;
+ inputval += 0x17;
+ return (inputval << 20);
+
+ /* latch 0x04 is the pixel value in the ROM at the specified address */
+ case 0x04:
+ return srcbitmap[(src_yoffs & srcbitmap_height_mask) * SRCBITMAP_WIDTH + src_xoffs % SRCBITMAP_WIDTH] << 24;
+
+ /* latch 0x50 is read at IRQ 4; the top 2 bits are checked. If they're not 0,
+ they skip the rest of the interrupt processing */
+ case 0x50:
+ return 0;
+ }
+
+ /* log anything else */
+ logerror("%08X: policetr_video_r with latch %02X\n", activecpu_get_previouspc(), video_latch);
+ return 0;
+}
+
+
+
+
+/*************************************
+ *
+ * Palette access
+ *
+ *************************************/
+
+WRITE32_HANDLER( policetr_palette_offset_w )
+{
+ if (!(mem_mask & 0x00ff0000))
+ {
+ palette_offset = (data >> 16) & 0xff;
+ palette_index = 0;
+ }
+}
+
+
+WRITE32_HANDLER( policetr_palette_data_w )
+{
+ if (!(mem_mask & 0x00ff0000))
+ {
+ palette_data[palette_index] = (data >> 16) & 0xff;
+ if (++palette_index == 3)
+ {
+ palette_set_color(Machine, palette_offset, MAKE_RGB(palette_data[0], palette_data[1], palette_data[2]));
+ palette_index = 0;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( policetr )
+{
+ int width = cliprect->max_x - cliprect->min_x + 1;
+ int y;
+
+ /* render all the scanlines from the dstbitmap to MAME's bitmap */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ draw_scanline8(bitmap, cliprect->min_x, y, width, &dstbitmap[DSTBITMAP_WIDTH * y + cliprect->min_x], NULL, -1);
+
+ return 0;
+}
diff --git a/src/mame/video/polyplay.c b/src/mame/video/polyplay.c
new file mode 100644
index 00000000000..7a85b46793e
--- /dev/null
+++ b/src/mame/video/polyplay.c
@@ -0,0 +1,71 @@
+/***************************************************************************
+
+ Poly-Play
+ (c) 1985 by VEB Polytechnik Karl-Marx-Stadt
+
+ video hardware
+
+ driver written by Martin Buchholz (buchholz@mail.uni-greifswald.de)
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *polyplay_characterram;
+static UINT8 dirtycharacter[256];
+
+
+
+PALETTE_INIT( polyplay )
+{
+ palette_set_color(machine,0,MAKE_RGB(0x00,0x00,0x00));
+ palette_set_color(machine,1,MAKE_RGB(0xff,0xff,0xff));
+
+ palette_set_color(machine,2,MAKE_RGB(0x00,0x00,0x00));
+ palette_set_color(machine,3,MAKE_RGB(0xff,0x00,0x00));
+ palette_set_color(machine,4,MAKE_RGB(0x00,0xff,0x00));
+ palette_set_color(machine,5,MAKE_RGB(0xff,0xff,0x00));
+ palette_set_color(machine,6,MAKE_RGB(0x00,0x00,0xff));
+ palette_set_color(machine,7,MAKE_RGB(0xff,0x00,0xff));
+ palette_set_color(machine,8,MAKE_RGB(0x00,0xff,0xff));
+ palette_set_color(machine,9,MAKE_RGB(0xff,0xff,0xff));
+}
+
+
+WRITE8_HANDLER( polyplay_characterram_w )
+{
+ if (polyplay_characterram[offset] != data)
+ {
+ dirtycharacter[((offset >> 3) & 0x7f) | 0x80] = 1;
+
+ polyplay_characterram[offset] = data;
+ }
+}
+
+
+VIDEO_UPDATE( polyplay )
+{
+ offs_t offs;
+
+
+ for (offs = 0; offs < videoram_size; offs++)
+ {
+ int sx = (offs & 0x3f) << 3;
+ int sy = offs >> 6 << 3;
+ UINT8 code = videoram[offs];
+
+ if (dirtycharacter[code])
+ {
+ decodechar(machine->gfx[1], code & 0x7f, polyplay_characterram, machine->drv->gfxdecodeinfo[1].gfxlayout);
+
+ dirtycharacter[code] = 0;
+ }
+
+ drawgfx(bitmap,machine->gfx[(code >> 7) & 0x01],
+ code, 0, 0, 0, sx, sy,
+ &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/poolshrk.c b/src/mame/video/poolshrk.c
new file mode 100644
index 00000000000..68277e2a1b0
--- /dev/null
+++ b/src/mame/video/poolshrk.c
@@ -0,0 +1,55 @@
+/***************************************************************************
+
+Atari Poolshark video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/poolshrk.h"
+
+UINT8* poolshrk_playfield_ram;
+UINT8* poolshrk_hpos_ram;
+UINT8* poolshrk_vpos_ram;
+
+static tilemap* bg_tilemap;
+
+
+static TILE_GET_INFO( get_tile_info )
+{
+ SET_TILE_INFO(1, poolshrk_playfield_ram[tile_index] & 0x3f, 0, 0);
+}
+
+
+VIDEO_START( poolshrk )
+{
+ bg_tilemap = tilemap_create(get_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(bg_tilemap, 0);
+}
+
+
+VIDEO_UPDATE( poolshrk )
+{
+ int i;
+
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ /* draw sprites */
+
+ for (i = 0; i < 16; i++)
+ {
+ int hpos = poolshrk_hpos_ram[i];
+ int vpos = poolshrk_vpos_ram[i];
+
+ drawgfx(bitmap, machine->gfx[0], i, (i == 0) ? 0 : 1, 0, 0,
+ 248 - hpos, vpos - 15, cliprect, TRANSPARENCY_PEN, 0);
+ }
+
+ /* draw playfield */
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/pooyan.c b/src/mame/video/pooyan.c
new file mode 100644
index 00000000000..82b0c5b8df2
--- /dev/null
+++ b/src/mame/video/pooyan.c
@@ -0,0 +1,134 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Pooyan has one 32x8 palette PROM and two 256x4 lookup table PROMs
+ (one for characters, one for sprites).
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( pooyan )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the char lookup table */
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = *(color_prom++) & 0x0f;
+
+ /* characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = (*(color_prom++) & 0x0f) + 0x10;
+}
+
+WRITE8_HANDLER( pooyan_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( pooyan_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( pooyan_flipscreen_w )
+{
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + 8 * (attr & 0x20);
+ int color = attr & 0x0f;
+ int flags = ((attr & 0x40) ? TILE_FLIPX : 0) | ((attr & 0x80) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( pooyan )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 2)
+ {
+ /* TRANSPARENCY_COLOR is needed for the scores */
+ /* Sprite flipscreen is supported by software */
+ drawgfx(bitmap,machine->gfx[1],
+ spriteram[offs + 1],
+ spriteram_2[offs] & 0x0f,
+ spriteram_2[offs] & 0x40, ~spriteram_2[offs] & 0x80,
+ 240-spriteram[offs], spriteram_2[offs + 1],
+ cliprect,
+ TRANSPARENCY_COLOR, 0);
+ }
+}
+
+VIDEO_UPDATE( pooyan )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/popeye.c b/src/mame/video/popeye.c
new file mode 100644
index 00000000000..84b1fcc18a4
--- /dev/null
+++ b/src/mame/video/popeye.c
@@ -0,0 +1,388 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *popeye_background_pos;
+UINT8 *popeye_palettebank;
+static UINT8 *popeye_bitmapram;
+static size_t popeye_bitmapram_size = 0x2000;
+
+static mame_bitmap *tmpbitmap2;
+static int invertmask;
+static int bitmap_type;
+enum { TYPE_SKYSKIPR, TYPE_POPEYE };
+
+#define BGRAM_SIZE 0x2000
+
+static tilemap *fg_tilemap;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Popeye has four color PROMS:
+ - 32x8 char palette
+ - 32x8 background palette
+ - two 256x4 sprite palette
+
+ The char and sprite PROMs are connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE (inverted)
+ -- 470 ohm resistor -- BLUE (inverted)
+ -- 220 ohm resistor -- GREEN (inverted)
+ -- 470 ohm resistor -- GREEN (inverted)
+ -- 1 kohm resistor -- GREEN (inverted)
+ -- 220 ohm resistor -- RED (inverted)
+ -- 470 ohm resistor -- RED (inverted)
+ bit 0 -- 1 kohm resistor -- RED (inverted)
+
+ The background PROM is connected to the RGB output this way:
+
+ bit 7 -- 470 ohm resistor -- BLUE (inverted)
+ -- 680 ohm resistor -- BLUE (inverted) (1300 ohm in Sky Skipper)
+ -- 470 ohm resistor -- GREEN (inverted)
+ -- 680 ohm resistor -- GREEN (inverted)
+ -- 1.2kohm resistor -- GREEN (inverted)
+ -- 470 ohm resistor -- RED (inverted)
+ -- 680 ohm resistor -- RED (inverted)
+ bit 0 -- 1.2kohm resistor -- RED (inverted)
+
+ The bootleg is the same, but the outputs are not inverted.
+
+***************************************************************************/
+static void convert_color_prom(running_machine *machine,UINT16 *colortable,const UINT8 *color_prom)
+{
+ int i,pal_index;
+
+
+ /* palette entries 0-15 are directly used by the background and changed at runtime */
+ pal_index = 16;
+ color_prom += 32;
+
+ /* characters */
+ for (i = 0;i < 16;i++)
+ {
+ int prom_offs = i | ((i & 8) << 1); /* address bits 3 and 4 are tied together */
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = ((color_prom[prom_offs] ^ invertmask) >> 0) & 0x01;
+ bit1 = ((color_prom[prom_offs] ^ invertmask) >> 1) & 0x01;
+ bit2 = ((color_prom[prom_offs] ^ invertmask) >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = ((color_prom[prom_offs] ^ invertmask) >> 3) & 0x01;
+ bit1 = ((color_prom[prom_offs] ^ invertmask) >> 4) & 0x01;
+ bit2 = ((color_prom[prom_offs] ^ invertmask) >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = ((color_prom[prom_offs] ^ invertmask) >> 6) & 0x01;
+ bit2 = ((color_prom[prom_offs] ^ invertmask) >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,pal_index++,MAKE_RGB(r,g,b));
+ }
+
+ color_prom += 32;
+
+ /* sprites */
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = ((color_prom[0] ^ invertmask) >> 0) & 0x01;
+ bit1 = ((color_prom[0] ^ invertmask) >> 1) & 0x01;
+ bit2 = ((color_prom[0] ^ invertmask) >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = ((color_prom[0] ^ invertmask) >> 3) & 0x01;
+ bit1 = ((color_prom[256] ^ invertmask) >> 0) & 0x01;
+ bit2 = ((color_prom[256] ^ invertmask) >> 1) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = ((color_prom[256] ^ invertmask) >> 2) & 0x01;
+ bit2 = ((color_prom[256] ^ invertmask) >> 3) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,pal_index++,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+
+
+ /* palette entries 0-15 are directly used by the background */
+
+ for (i = 0;i < 16;i++) /* characters */
+ {
+ *(colortable++) = 0; /* since chars are transparent, the PROM only */
+ /* stores the non transparent color */
+ *(colortable++) = i + 16;
+ }
+ for (i = 0;i < 256;i++) /* sprites */
+ {
+ *(colortable++) = i + 16+16;
+ }
+}
+
+PALETTE_INIT( popeye )
+{
+ invertmask = 0xff;
+
+ convert_color_prom(machine,colortable,color_prom);
+}
+
+PALETTE_INIT( popeyebl )
+{
+ invertmask = 0x00;
+
+ convert_color_prom(machine,colortable,color_prom);
+}
+
+static void set_background_palette(running_machine *machine,int bank)
+{
+ int i;
+ UINT8 *color_prom = memory_region(REGION_PROMS) + 16 * bank;
+
+ for (i = 0;i < 16;i++)
+ {
+ int bit0,bit1,bit2;
+ int r,g,b;
+
+ /* red component */
+ bit0 = ((*color_prom ^ invertmask) >> 0) & 0x01;
+ bit1 = ((*color_prom ^ invertmask) >> 1) & 0x01;
+ bit2 = ((*color_prom ^ invertmask) >> 2) & 0x01;
+ r = 0x1c * bit0 + 0x31 * bit1 + 0x47 * bit2;
+ /* green component */
+ bit0 = ((*color_prom ^ invertmask) >> 3) & 0x01;
+ bit1 = ((*color_prom ^ invertmask) >> 4) & 0x01;
+ bit2 = ((*color_prom ^ invertmask) >> 5) & 0x01;
+ g = 0x1c * bit0 + 0x31 * bit1 + 0x47 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = ((*color_prom ^ invertmask) >> 6) & 0x01;
+ bit2 = ((*color_prom ^ invertmask) >> 7) & 0x01;
+ if (bitmap_type == TYPE_SKYSKIPR)
+ {
+ /* Sky Skipper has different weights */
+ bit0 = bit1;
+ bit1 = 0;
+ }
+ b = 0x1c * bit0 + 0x31 * bit1 + 0x47 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( popeye_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( popeye_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( popeye_bitmap_w )
+{
+ int sx,sy,x,y,colour;
+
+ popeye_bitmapram[offset] = data;
+
+ if (bitmap_type == TYPE_SKYSKIPR)
+ {
+ sx = 8 * (offset % 128);
+ sy = 8 * (offset / 128);
+
+ if (flip_screen)
+ sy = 512-8 - sy;
+
+ colour = Machine->pens[data & 0x0f];
+ for (y = 0; y < 8; y++)
+ {
+ for (x = 0; x < 8; x++)
+ {
+ *BITMAP_ADDR16(tmpbitmap2, sy+y, sx+x) = colour;
+ }
+ }
+ }
+ else
+ {
+ sx = 8 * (offset % 64);
+ sy = 4 * (offset / 64);
+
+ if (flip_screen)
+ sy = 512-4 - sy;
+
+ colour = Machine->pens[data & 0x0f];
+ for (y = 0; y < 4; y++)
+ {
+ for (x = 0; x < 8; x++)
+ {
+ *BITMAP_ADDR16(tmpbitmap2, sy+y, sx+x) = colour;
+ }
+ }
+ }
+}
+
+WRITE8_HANDLER( skyskipr_bitmap_w )
+{
+ offset = ((offset & 0xfc0) << 1) | (offset & 0x03f);
+ if (data & 0x80)
+ offset |= 0x40;
+
+ popeye_bitmap_w(offset,data);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = videoram[tile_index];
+ int color = colorram[tile_index] & 0x0f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( skyskipr )
+{
+ popeye_bitmapram = auto_malloc(popeye_bitmapram_size);
+
+ tmpbitmap2 = auto_bitmap_alloc(1024,1024,machine->screen[0].format); /* actually 1024x512 but not rolling over vertically? */
+
+ bitmap_type = TYPE_SKYSKIPR;
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+VIDEO_START( popeye )
+{
+ popeye_bitmapram = auto_malloc(popeye_bitmapram_size);
+
+ tmpbitmap2 = auto_bitmap_alloc(512,512,machine->screen[0].format);
+
+ bitmap_type = TYPE_POPEYE;
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+ static int lastflip = 0;
+
+ if (lastflip != flip_screen)
+ {
+ for (offs = 0;offs < popeye_bitmapram_size;offs++)
+ popeye_bitmap_w(offs,popeye_bitmapram[offs]);
+
+ lastflip = flip_screen;
+ }
+
+ set_background_palette(machine, (*popeye_palettebank & 0x08) >> 3);
+
+ if (popeye_background_pos[1] == 0) /* no background */
+ {
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ }
+ else
+ {
+ /* copy the background graphics */
+ int scrollx = 200 - popeye_background_pos[0] - 256*(popeye_background_pos[2]&1); /* ??? */
+ int scrolly = 2 * (256 - popeye_background_pos[1]);
+
+ if (bitmap_type == TYPE_SKYSKIPR)
+ scrollx = 2*scrollx - 512;
+
+ if (flip_screen)
+ {
+ if (bitmap_type == TYPE_POPEYE)
+ scrollx = -scrollx;
+ scrolly = -scrolly;
+ }
+
+ copyscrollbitmap(bitmap,tmpbitmap2,1,&scrollx,1,&scrolly,cliprect,TRANSPARENCY_NONE,0);
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int code,color,flipx,flipy,sx,sy;
+
+ /*
+ * offs+3:
+ * bit 7 ?
+ * bit 6 ?
+ * bit 5 ?
+ * bit 4 MSB of sprite code
+ * bit 3 vertical flip
+ * bit 2 sprite bank
+ * bit 1 \ color (with bit 2 as well)
+ * bit 0 /
+ */
+
+ code = (spriteram[offs + 2] & 0x7f) + ((spriteram[offs + 3] & 0x10) << 3)
+ + ((spriteram[offs + 3] & 0x04) << 6);
+ color = (spriteram[offs + 3] & 0x07) + 8*(*popeye_palettebank & 0x07);
+ if (bitmap_type == TYPE_SKYSKIPR)
+ {
+ /* Two of the PROM address pins are tied together and one is not connected... */
+ color = (color & 0x0f) | ((color & 0x08) << 1);
+ }
+
+ flipx = spriteram[offs + 2] & 0x80;
+ flipy = spriteram[offs + 3] & 0x08;
+
+ sx = 2*(spriteram[offs])-8;
+ sy = 2*(256-spriteram[offs + 1]);
+
+ if (flip_screen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+ sx = 496 - sx;
+ sy = 496 - sy;
+ }
+
+ if (spriteram[offs] != 0)
+ drawgfx(bitmap,machine->gfx[1],
+ code ^ 0x1ff,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( popeye )
+{
+ draw_background(machine, bitmap, cliprect);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/popper.c b/src/mame/video/popper.c
new file mode 100644
index 00000000000..5b2b1cd5030
--- /dev/null
+++ b/src/mame/video/popper.c
@@ -0,0 +1,244 @@
+/*
+Popper
+Omori Electric CAD (OEC) 1983
+*/
+
+#include "driver.h"
+
+static tilemap *popper_p123_tilemap, *popper_p0_tilemap, *popper_ol_p123_tilemap, *popper_ol_p0_tilemap;
+UINT8 *popper_videoram, *popper_attribram, *popper_ol_videoram, *popper_ol_attribram, *popper_spriteram;
+size_t popper_spriteram_size;
+static INT32 popper_flipscreen, popper_e002, popper_gfx_bank;
+static rectangle tilemap_clip;
+
+PALETTE_INIT( popper )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors; i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x97 * bit1 + 0x68 * bit2;
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( popper_ol_videoram_w )
+{
+ popper_ol_videoram[offset] = data;
+ tilemap_mark_tile_dirty(popper_ol_p123_tilemap,offset);
+ tilemap_mark_tile_dirty(popper_ol_p0_tilemap,offset);
+}
+
+WRITE8_HANDLER( popper_videoram_w )
+{
+ popper_videoram[offset] = data;
+ tilemap_mark_tile_dirty(popper_p123_tilemap,offset);
+ tilemap_mark_tile_dirty(popper_p0_tilemap,offset);
+}
+
+WRITE8_HANDLER( popper_ol_attribram_w )
+{
+ popper_ol_attribram[offset] = data;
+ tilemap_mark_tile_dirty(popper_ol_p123_tilemap,offset);
+ tilemap_mark_tile_dirty(popper_ol_p0_tilemap,offset);
+}
+
+WRITE8_HANDLER( popper_attribram_w )
+{
+ popper_attribram[offset] = data;
+ tilemap_mark_tile_dirty(popper_p123_tilemap,offset);
+ tilemap_mark_tile_dirty(popper_p0_tilemap,offset);
+}
+
+WRITE8_HANDLER( popper_flipscreen_w )
+{
+ popper_flipscreen = data;
+ tilemap_set_flip( ALL_TILEMAPS,popper_flipscreen?(TILEMAP_FLIPX|TILEMAP_FLIPY):0 );
+
+ tilemap_clip = Machine->screen[0].visarea;
+
+ if (popper_flipscreen)
+ tilemap_clip.min_x=tilemap_clip.max_x-15;
+ else
+ tilemap_clip.max_x=15;
+}
+
+WRITE8_HANDLER( popper_e002_w )
+{
+ popper_e002 = data;
+}
+
+WRITE8_HANDLER( popper_gfx_bank_w )
+{
+ if (popper_gfx_bank != data)
+ {
+ popper_gfx_bank = data;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_popper_p123_tile_info )
+{
+ UINT32 tile_number = popper_videoram[tile_index];
+ UINT8 attr = popper_attribram[tile_index];
+ tile_number += popper_gfx_bank << 8;
+
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ (attr&0xf),
+ 0);
+ tileinfo->group = (attr & 0x80)>>7;
+}
+
+static TILE_GET_INFO( get_popper_p0_tile_info )
+{
+ UINT32 tile_number = popper_videoram[tile_index];
+ UINT8 attr = popper_attribram[tile_index];
+ tile_number += popper_gfx_bank << 8;
+
+ //pen 0 only in front if colour set as well
+ tileinfo->group = (attr&0x70) ? ((attr & 0x80)>>7) : 0;
+
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ ((attr&0x70)>>4)+8,
+ 0);
+}
+
+static TILE_GET_INFO( get_popper_ol_p123_tile_info )
+{
+ UINT32 tile_number = popper_ol_videoram[tile_index];
+ UINT8 attr = popper_ol_attribram[tile_index];
+ tile_number += popper_gfx_bank << 8;
+
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ (attr&0xf),
+ 0);
+ tileinfo->group = (attr & 0x80)>>7;
+}
+
+static TILE_GET_INFO( get_popper_ol_p0_tile_info )
+{
+ UINT32 tile_number = popper_ol_videoram[tile_index];
+ UINT8 attr = popper_ol_attribram[tile_index];
+ tile_number += popper_gfx_bank << 8;
+
+ //pen 0 only in front if colour set as well
+ tileinfo->group = (attr&0x70) ? ((attr & 0x80)>>7) : 0;
+
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ ((attr&0x70)>>4)+8,
+ 0);
+}
+
+VIDEO_START( popper )
+{
+ popper_p123_tilemap = tilemap_create( get_popper_p123_tile_info, tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,33,32 );
+ popper_p0_tilemap = tilemap_create( get_popper_p0_tile_info, tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,33,32 );
+ popper_ol_p123_tilemap = tilemap_create( get_popper_ol_p123_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,2 ,32 );
+ popper_ol_p0_tilemap = tilemap_create( get_popper_ol_p0_tile_info, tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,2 ,32 );
+
+ tilemap_set_transmask(popper_p123_tilemap, 0,0x0f,0x01);
+ tilemap_set_transmask(popper_p123_tilemap, 1,0x01,0x0f);
+ tilemap_set_transmask(popper_p0_tilemap, 0,0x0f,0x0e);
+ tilemap_set_transmask(popper_p0_tilemap, 1,0x0e,0x0f);
+ tilemap_set_transmask(popper_ol_p123_tilemap,0,0x0f,0x01);
+ tilemap_set_transmask(popper_ol_p123_tilemap,1,0x01,0x0f);
+ tilemap_set_transmask(popper_ol_p0_tilemap, 0,0x0f,0x0e);
+ tilemap_set_transmask(popper_ol_p0_tilemap, 1,0x0e,0x0f);
+
+ tilemap_clip = machine->screen[0].visarea;
+
+ state_save_register_global(popper_flipscreen);
+// state_save_register_global(popper_e002);
+ state_save_register_global(popper_gfx_bank);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs,sx,sy,flipx,flipy;
+
+ for (offs = 0; offs < popper_spriteram_size-4; offs += 4)
+ {
+ //if y position is in the current strip
+ if(popper_spriteram[offs+1] && (((popper_spriteram[offs]+(popper_flipscreen?2:0))&0xf0) == (0x0f-offs/0x80)<<4))
+ {
+ //offs y pos
+ //offs+1 sprite number
+ //offs+2
+ //76543210
+ //x------- flipy
+ //-x------ flipx
+ //--xx---- unused
+ //----xxxx colour
+ //offs+3 x pos
+
+ sx = popper_spriteram[offs+3];
+ sy = 240-popper_spriteram[offs];
+ flipx = (popper_spriteram[offs+2]&0x40)>>6;
+ flipy = (popper_spriteram[offs+2]&0x80)>>7;
+
+ if (popper_flipscreen)
+ {
+ sx = 248 - sx;
+ sy = 242 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ popper_spriteram[offs+1],
+ (popper_spriteram[offs+2]&0x0f),
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( popper )
+{
+ rectangle finalclip = tilemap_clip;
+ sect_rect(&finalclip, cliprect);
+
+ //attribram
+ //76543210
+ //x------- draw over sprites
+ //-xxx---- colour for pen 0 (from second prom?)
+ //----xxxx colour for pens 1,2,3
+
+ tilemap_draw( bitmap,cliprect,popper_p123_tilemap, TILEMAP_DRAW_LAYER1,0 );
+ tilemap_draw( bitmap,cliprect,popper_p0_tilemap, TILEMAP_DRAW_LAYER1,0 );
+ tilemap_draw( bitmap,&finalclip,popper_ol_p123_tilemap,TILEMAP_DRAW_LAYER1,0 );
+ tilemap_draw( bitmap,&finalclip,popper_ol_p0_tilemap, TILEMAP_DRAW_LAYER1,0 );
+
+ draw_sprites(machine, bitmap,cliprect);
+
+ tilemap_draw( bitmap,cliprect,popper_p123_tilemap, TILEMAP_DRAW_LAYER0,0 );
+ tilemap_draw( bitmap,cliprect,popper_p0_tilemap, TILEMAP_DRAW_LAYER0,0 );
+ tilemap_draw( bitmap,&finalclip,popper_ol_p123_tilemap,TILEMAP_DRAW_LAYER0,0 );
+ tilemap_draw( bitmap,&finalclip,popper_ol_p0_tilemap, TILEMAP_DRAW_LAYER0,0 );
+ return 0;
+}
diff --git a/src/mame/video/portrait.c b/src/mame/video/portrait.c
new file mode 100644
index 00000000000..3d89a0348ec
--- /dev/null
+++ b/src/mame/video/portrait.c
@@ -0,0 +1,171 @@
+/***************************************************************************
+
+ Portraits
+ video hardware emulation
+
+***************************************************************************/
+
+#include "driver.h"
+
+int portrait_scroll;
+UINT8 *portrait_bgvideoram, *portrait_fgvideoram;
+static tilemap *foreground, *background;
+
+WRITE8_HANDLER( portrait_bgvideo_write )
+{
+ tilemap_mark_tile_dirty(background,offset/2);
+ portrait_bgvideoram[offset] = data;
+}
+
+WRITE8_HANDLER( portrait_fgvideo_write )
+{
+ tilemap_mark_tile_dirty(foreground,offset/2);
+ portrait_fgvideoram[offset] = data;
+}
+
+INLINE void get_tile_info( running_machine *machine, tile_data *tileinfo, int tile_index, const UINT8 *source )
+{
+ int attr = source[tile_index*2+0];
+ int tilenum = source[tile_index*2+1];
+ int flags = 0;
+ int color = 0;
+
+ /* or 0x10 ? */
+ if( attr & 0x20 ) flags = TILE_FLIPY;
+
+ switch( attr & 7 )
+ {
+ case 1:
+ tilenum += 0x200;
+ break;
+ case 3:
+ tilenum += 0x300;
+ break;
+ case 5:
+ tilenum += 0x100;
+ break;
+ }
+
+ SET_TILE_INFO( 0, tilenum, color, flags );
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ get_tile_info( machine, tileinfo, tile_index, portrait_bgvideoram );
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ get_tile_info( machine, tileinfo, tile_index, portrait_fgvideoram );
+}
+
+VIDEO_START( portrait )
+{
+ background = tilemap_create( get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 32, 32 );
+ foreground = tilemap_create( get_fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 32, 32 );
+
+ tilemap_set_transparent_pen( foreground, 0 );
+}
+
+#if 0
+/* probably not right */
+PALETTE_INIT( portrait )
+{
+ int i,bit1,bit2,r,g,b;
+
+ for (i = 0;i < 0x800;i++)
+ {
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 0) & 0x01;
+ r = 0x47 * bit1 + 0x97 * bit2;
+ bit1 = (color_prom[i] >> 3) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ g = 0x47 * bit1 + 0x97 * bit2;
+ bit1 = (color_prom[i] >> 5) & 0x01;
+ bit2 = (color_prom[i] >> 4) & 0x01;
+ b = 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+#endif
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 *source = spriteram;
+ UINT8 *finish = source + 0x200;
+
+ while( source < finish )
+ {
+ int sy = source[0];
+ int sx = source[1];
+ int attr = source[2];
+ /* xx-x---- ?
+ * --x----- flipy
+ * ----x--- msb source[0]
+ * -----x-- msb source[1]
+ */
+ int tilenum = source[3];
+ int color = 0;
+ int fy = attr & 0x20;
+
+ if(attr & 0x04) sx |= 0x100;
+
+ if(attr & 0x08) sy |= 0x100;
+
+ sx += (source - spriteram) - 8;
+ sx &= 0x1ff;
+
+ sy = (512 - 64) - sy;
+
+ /* wrong! */
+ switch( attr & 0xc0 )
+ {
+ case 0:
+ break;
+
+ case 0x40:
+ sy -= portrait_scroll;
+ break;
+
+ case 0x80:
+ sy -= portrait_scroll;
+ break;
+
+ case 0xc0:
+ break;
+
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ tilenum,color,
+ 0,fy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ source += 0x10;
+ }
+}
+
+VIDEO_UPDATE( portrait )
+{
+ rectangle cliprect_scroll, cliprect_no_scroll;
+
+ cliprect_scroll = cliprect_no_scroll = *cliprect;
+
+ cliprect_no_scroll.min_x = cliprect_no_scroll.max_x - 111;
+ cliprect_scroll.max_x = cliprect_scroll.min_x + 319;
+
+ tilemap_set_scrolly(background, 0, 0);
+ tilemap_set_scrolly(foreground, 0, 0);
+ tilemap_draw(bitmap, &cliprect_no_scroll, background, 0, 0);
+ tilemap_draw(bitmap, &cliprect_no_scroll, foreground, 0, 0);
+
+ tilemap_set_scrolly(background, 0, portrait_scroll);
+ tilemap_set_scrolly(foreground, 0, portrait_scroll);
+ tilemap_draw(bitmap, &cliprect_scroll, background, 0, 0);
+ tilemap_draw(bitmap, &cliprect_scroll, foreground, 0, 0);
+
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/powerins.c b/src/mame/video/powerins.c
new file mode 100644
index 00000000000..629c768919e
--- /dev/null
+++ b/src/mame/video/powerins.c
@@ -0,0 +1,373 @@
+/***************************************************************************
+
+ -= Power Instinct =-
+ (C) 1993 Atlus
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z with:
+
+ Q shows layer 1
+ W shows layer 2
+ A shows the sprites
+
+ Keys can be used togheter!
+
+ [ 2 Scrolling Layers ]
+
+ Each Layer is made of various pages of 256x256 pixels.
+
+ [Layer 0]
+ Pages: 16x2
+ Tiles: 16x16x4
+ Scroll: X,Y
+
+ [Layer 1]
+ Pages: 2x1
+ Tiles: 8x8x4
+ Scroll: No
+
+ [ 256 Sprites ]
+
+ Each sprite is made of a variable amount of 16x16 tiles.
+ Size can therefore vary from 16x16 (1 tile) to 256x256
+ (16x16 tiles)
+
+
+**************************************************************************/
+
+#include "driver.h"
+
+/* Variables that driver has access to: */
+UINT16 *powerins_vram_0, *powerins_vctrl_0;
+UINT16 *powerins_vram_1, *powerins_vctrl_1;
+//UINT16 *powerins_vregs;
+
+/* Variables only used here: */
+static tilemap *tilemap_0, *tilemap_1;
+static int tile_bank;
+
+
+
+/***************************************************************************
+
+ Hardware registers access
+
+***************************************************************************/
+
+
+WRITE16_HANDLER( powerins_flipscreen_w )
+{
+ if (ACCESSING_LSB) flip_screen_set( data & 1 );
+}
+
+WRITE16_HANDLER( powerins_tilebank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ if (data != tile_bank)
+ {
+ tile_bank = data; // Tiles Bank (VRAM 0)
+ tilemap_mark_all_tiles_dirty(tilemap_0);
+ }
+ }
+}
+
+
+
+/***************************************************************************
+
+ Palette
+
+***************************************************************************/
+
+
+WRITE16_HANDLER( powerins_paletteram16_w )
+{
+ /* byte 0 byte 1 */
+ /* RRRR GGGG BBBB RGBx */
+ /* 4321 4321 4321 000x */
+
+ UINT16 newword = COMBINE_DATA(&paletteram16[offset]);
+
+ int r = ((newword >> 11) & 0x1E ) | ((newword >> 3) & 0x01);
+ int g = ((newword >> 7) & 0x1E ) | ((newword >> 2) & 0x01);
+ int b = ((newword >> 3) & 0x1E ) | ((newword >> 1) & 0x01);
+
+ palette_set_color_rgb( Machine,offset, pal5bit(r),pal5bit(g),pal5bit(b) );
+}
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+
+/***************************************************************************
+ [ Tiles Format VRAM 0]
+
+Offset:
+
+0.w fedc ---- ---- ---- Color Low Bits
+ ---- b--- ---- ---- Color High Bit
+ ---- -a98 7654 3210 Code (Banked)
+
+
+***************************************************************************/
+
+/* Layers are made of 256x256 pixel pages */
+#define TILES_PER_PAGE_X (0x10)
+#define TILES_PER_PAGE_Y (0x10)
+#define TILES_PER_PAGE (TILES_PER_PAGE_X * TILES_PER_PAGE_Y)
+
+#define DIM_NX_0 (0x100)
+#define DIM_NY_0 (0x20)
+
+
+static TILE_GET_INFO( get_tile_info_0 )
+{
+ UINT16 code = powerins_vram_0[tile_index];
+ SET_TILE_INFO(
+ 0,
+ (code & 0x07ff) + (tile_bank*0x800),
+ ((code & 0xf000) >> (16-4)) + ((code & 0x0800) >> (11-4)),
+ 0);
+}
+
+WRITE16_HANDLER( powerins_vram_0_w )
+{
+ COMBINE_DATA(&powerins_vram_0[offset]);
+ tilemap_mark_tile_dirty(tilemap_0, offset);
+}
+
+static TILEMAP_MAPPER( powerins_get_memory_offset_0 )
+{
+ return (col * TILES_PER_PAGE_Y) +
+
+ (row % TILES_PER_PAGE_Y) +
+ (row / TILES_PER_PAGE_Y) * (TILES_PER_PAGE * 16);
+}
+
+
+
+/***************************************************************************
+ [ Tiles Format VRAM 1]
+
+Offset:
+
+0.w fedc ---- ---- ---- Color
+ ---- ba98 7654 3210 Code
+
+
+***************************************************************************/
+
+#define DIM_NX_1 (0x40)
+#define DIM_NY_1 (0x20)
+
+static TILE_GET_INFO( get_tile_info_1 )
+{
+ UINT16 code = powerins_vram_1[tile_index];
+ SET_TILE_INFO(
+ 1,
+ code & 0x0fff,
+ (code & 0xf000) >> (16-4),
+ 0);
+}
+
+WRITE16_HANDLER( powerins_vram_1_w )
+{
+ COMBINE_DATA(&powerins_vram_1[offset]);
+ tilemap_mark_tile_dirty(tilemap_1, offset);
+}
+
+
+
+
+
+/***************************************************************************
+
+
+ Vh_Start
+
+
+***************************************************************************/
+
+VIDEO_START( powerins )
+{
+ tilemap_0 = tilemap_create( get_tile_info_0,
+ powerins_get_memory_offset_0,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ DIM_NX_0, DIM_NY_0 );
+
+ tilemap_1 = tilemap_create( get_tile_info_1,
+ tilemap_scan_cols,
+ TILEMAP_TYPE_PEN,
+ 8,8,
+ DIM_NX_1, DIM_NY_1 );
+
+ tilemap_set_scroll_rows(tilemap_0,1);
+ tilemap_set_scroll_cols(tilemap_0,1);
+
+ tilemap_set_scroll_rows(tilemap_1,1);
+ tilemap_set_scroll_cols(tilemap_1,1);
+ tilemap_set_transparent_pen(tilemap_1,15);
+}
+
+
+
+
+
+
+/***************************************************************************
+
+
+ Sprites Drawing
+
+
+***************************************************************************/
+
+
+
+/* --------------------------[ Sprites Format ]----------------------------
+
+Offset: Format: Value:
+
+ 00 fedc ba98 7654 321- -
+ ---- ---- ---- ---0 Display this sprite
+
+ 02 fed- ---- ---- ---- -
+ ---c ---- ---- ---- Flip X
+ ---- ba9- ---- ---- -
+ ---- ---8 ---- ---- Code High Bit
+ ---- ---- 7654 ---- Number of tiles along Y, minus 1 (1-16)
+ ---- ---- ---- 3210 Number of tiles along X, minus 1 (1-16)
+
+ 04 Unused?
+
+ 06 f--- ---- ---- ---- -
+ -edc ba98 7654 3210 Code Low Bits
+
+ 08 X
+
+ 0A Unused?
+
+ 0C Y
+
+ 0E fedc ba98 76-- ---- -
+ ---- ---- --54 3210 Color
+
+
+------------------------------------------------------------------------ */
+
+#define SIGN_EXTEND_POS(_var_) {_var_ &= 0x3ff; if (_var_ > 0x1ff) _var_ -= 0x400;}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ UINT16 *source = spriteram16 + 0x8000/2;
+ UINT16 *finish = spriteram16 + 0x9000/2;
+
+ int screen_w = machine->screen[0].width;
+ int screen_h = machine->screen[0].height;
+
+ for ( ; source < finish; source += 16/2 )
+ {
+ int x,y,inc;
+
+ int attr = source[ 0x0/2 ];
+ int size = source[ 0x2/2 ];
+ int code = source[ 0x6/2 ];
+ int sx = source[ 0x8/2 ];
+ int sy = source[ 0xc/2 ];
+ int color = source[ 0xe/2 ];
+
+ int flipx = size & 0x1000;
+ int flipy = 0; // ??
+
+ int dimx = ((size >> 0) & 0xf ) + 1;
+ int dimy = ((size >> 4) & 0xf ) + 1;
+
+ if (!(attr&1)) continue;
+
+ SIGN_EXTEND_POS(sx)
+ SIGN_EXTEND_POS(sy)
+
+ /* Handle flip_screen. Apply a global offset of 32 pixels along x too */
+
+ if (flip_screen)
+ { sx = screen_w - sx - dimx*16 - 32; flipx = !flipx;
+ sy = screen_h - sy - dimy*16; flipy = !flipy;
+ code += dimx*dimy-1; inc = -1; }
+ else
+ { sx += 32; inc = +1; }
+
+ code = (code & 0x7fff) + ( (size & 0x0100) << 7 );
+
+ for (x = 0 ; x < dimx ; x++)
+ {
+ for (y = 0 ; y < dimy ; y++)
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx, flipy,
+ sx + x*16,
+ sy + y*16,
+ cliprect,TRANSPARENCY_PEN,15);
+
+ code += inc;
+ }
+ }
+
+
+ }
+}
+
+
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+
+VIDEO_UPDATE( powerins )
+{
+ int layers_ctrl = -1;
+
+ int scrollx = (powerins_vctrl_0[2/2]&0xff) + (powerins_vctrl_0[0/2]&0xff)*256;
+ int scrolly = (powerins_vctrl_0[6/2]&0xff) + (powerins_vctrl_0[4/2]&0xff)*256;
+
+ tilemap_set_scrollx( tilemap_0, 0, scrollx - 0x20);
+ tilemap_set_scrolly( tilemap_0, 0, scrolly );
+
+ tilemap_set_scrollx( tilemap_1, 0, -0x20); // fixed offset
+ tilemap_set_scrolly( tilemap_1, 0, 0x00);
+
+#ifdef MAME_DEBUG
+if (input_code_pressed(KEYCODE_Z))
+{
+ int msk = 0;
+
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+// if (input_code_pressed(KEYCODE_E)) msk |= 4;
+ if (input_code_pressed(KEYCODE_A)) msk |= 8;
+ if (msk != 0) layers_ctrl &= msk;
+}
+#endif
+
+ if (layers_ctrl&1) tilemap_draw(bitmap,cliprect, tilemap_0, 0, 0);
+ else fillbitmap(bitmap,machine->pens[0],cliprect);
+ if (layers_ctrl&8) draw_sprites(machine,bitmap,cliprect);
+ if (layers_ctrl&2) tilemap_draw(bitmap,cliprect, tilemap_1, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/ppu2c0x.c b/src/mame/video/ppu2c0x.c
new file mode 100644
index 00000000000..e0cd1e15fa0
--- /dev/null
+++ b/src/mame/video/ppu2c0x.c
@@ -0,0 +1,1578 @@
+/******************************************************************************
+
+ Nintendo 2C0x PPU emulation.
+
+ Written by Ernesto Corvi.
+ This code is heavily based on Brad Oliver's MESS implementation.
+
+******************************************************************************/
+
+/******************************************************************************
+
+Current known bugs
+
+General:
+
+* PPU timing is imprecise for updates that happen mid-scanline. Some games
+ may demand more precision.
+
+NES-specific:
+
+* Micro Machines has minor rendering glitches (needs better timing).
+
+* Mach Rider has minor road rendering glitches (needs better timing).
+
+******************************************************************************/
+
+#include <math.h>
+#include "driver.h"
+#include "profiler.h"
+#include "video/ppu2c0x.h"
+
+/* constant definitions */
+#define VISIBLE_SCREEN_WIDTH (32*8) /* Visible screen width */
+#define VISIBLE_SCREEN_HEIGHT (30*8) /* Visible screen height */
+#define VIDEORAM_SIZE 0x4000 /* videoram size */
+#define SPRITERAM_SIZE 0x100 /* spriteram size */
+#define SPRITERAM_MASK (0x100-1) /* spriteram size */
+#define CHARGEN_NUM_CHARS 512 /* max number of characters handled by the chargen */
+
+/* default monochromatic colortable */
+static const pen_t default_colortable_mono[] =
+{
+ 0,1,2,3,
+ 0,1,2,3,
+ 0,1,2,3,
+ 0,1,2,3,
+ 0,1,2,3,
+ 0,1,2,3,
+ 0,1,2,3,
+ 0,1,2,3,
+};
+
+/* default colortable */
+static const pen_t default_colortable[] =
+{
+ 0,1,2,3,
+ 0,5,6,7,
+ 0,9,10,11,
+ 0,13,14,15,
+ 0,17,18,19,
+ 0,21,22,23,
+ 0,25,26,27,
+ 0,29,30,31,
+};
+
+/* our chip state */
+typedef struct {
+ running_machine *machine; /* execution context */
+ mame_bitmap *bitmap; /* target bitmap */
+ UINT8 *videoram; /* video ram */
+ UINT8 *spriteram; /* sprite ram */
+ pen_t *colortable; /* color table modified at run time */
+ pen_t *colortable_mono; /* monochromatic color table modified at run time */
+ UINT8 *dirtychar; /* an array flagging dirty characters */
+ int chars_are_dirty; /* master flag to check if theres any dirty character */
+ emu_timer *scanline_timer; /* scanline timer */
+ emu_timer *hblank_timer; /* hblank period at end of each scanline */
+ emu_timer *nmi_timer; /* NMI timer */
+ int scanline; /* scanline count */
+ ppu2c0x_scanline_cb scanline_callback_proc; /* optional scanline callback */
+ ppu2c0x_hblank_cb hblank_callback_proc; /* optional hblank callback */
+ ppu2c0x_vidaccess_cb vidaccess_callback_proc;/* optional video access callback */
+ int has_videorom; /* whether we access a video rom or not */
+ int videorom_banks; /* number of banks in the videorom (if available) */
+ int regs[PPU_MAX_REG]; /* registers */
+ int refresh_data; /* refresh-related */
+ int refresh_latch; /* refresh-related */
+ int x_fine; /* refresh-related */
+ int toggle; /* used to latch hi-lo scroll */
+ int add; /* vram increment amount */
+ int videoram_addr; /* videoram address pointer */
+ int addr_latch; /* videoram address latch */
+ int data_latch; /* latched videoram data */
+ int buffered_data;
+ int tile_page; /* current tile page */
+ int sprite_page; /* current sprite page */
+ int back_color; /* background color */
+ UINT8 *ppu_page[4]; /* ppu pages */
+ int nes_vram[8]; /* keep track of 8 .5k vram pages to speed things up */
+ int scan_scale; /* scan scale */
+ int scanlines_per_frame; /* number of scanlines per frame */
+ int mirror_state;
+ rgb_t palette[64*4]; /* palette for this chip */
+} ppu2c0x_chip;
+
+/* our local copy of the interface */
+static ppu2c0x_interface *intf;
+
+/* chips state - allocated at init time */
+static ppu2c0x_chip *chips = 0;
+
+static void update_scanline(int num );
+
+static TIMER_CALLBACK( scanline_callback );
+static TIMER_CALLBACK( hblank_callback );
+static TIMER_CALLBACK( nmi_callback );
+
+void (*ppu_latch)( offs_t offset );
+
+
+/*************************************
+ *
+ * PPU Palette Initialization
+ *
+ *************************************/
+void ppu2c0x_init_palette(running_machine *machine, int first_entry )
+{
+
+ /* This routine builds a palette using a transformation from */
+ /* the YUV (Y, B-Y, R-Y) to the RGB color space */
+
+ /* The NES has a 64 color palette */
+ /* 16 colors, with 4 luminance levels for each color */
+ /* The 16 colors circle around the YUV color space, */
+
+ int colorIntensity, colorNum, colorEmphasis;
+
+ double R, G, B;
+
+ double tint = 0.22; /* adjust to taste */
+ double hue = 287.0;
+
+ double Kr = 0.2989;
+ double Kb = 0.1145;
+ double Ku = 2.029;
+ double Kv = 1.140;
+
+ double brightness[3][4] =
+ {
+ { 0.50, 0.75, 1.0, 1.0 },
+ { 0.29, 0.45, 0.73, 0.9 },
+ { 0, 0.24, 0.47, 0.77 }
+ };
+
+ /* Loop through the emphasis modes (8 total) */
+ for (colorEmphasis = 0; colorEmphasis < 8; colorEmphasis ++)
+ {
+ double r_mod = 0.0;
+ double g_mod = 0.0;
+ double b_mod = 0.0;
+
+ switch (colorEmphasis)
+ {
+ case 0: r_mod = 1.0; g_mod = 1.0; b_mod = 1.0; break;
+ case 1: r_mod = 1.24; g_mod = .915; b_mod = .743; break;
+ case 2: r_mod = .794; g_mod = 1.09; b_mod = .882; break;
+ case 3: r_mod = .905; g_mod = 1.03; b_mod = 1.28; break;
+ case 4: r_mod = .741; g_mod = .987; b_mod = 1.0; break;
+ case 5: r_mod = 1.02; g_mod = .908; b_mod = .979; break;
+ case 6: r_mod = 1.02; g_mod = .98; b_mod = .653; break;
+ case 7: r_mod = .75; g_mod = .75; b_mod = .75; break;
+ }
+
+ /* loop through the 4 intensities */
+ for (colorIntensity = 0; colorIntensity < 4; colorIntensity++)
+ {
+ /* loop through the 16 colors */
+ for (colorNum = 0; colorNum < 16; colorNum++)
+ {
+ double sat;
+ double y, u, v;
+ double rad;
+
+ switch (colorNum)
+ {
+ case 0:
+ sat = 0; rad = 0;
+ y = brightness[0][colorIntensity];
+ break;
+
+ case 13:
+ sat = 0; rad = 0;
+ y = brightness[2][colorIntensity];
+ break;
+
+ case 14:
+ case 15:
+ sat = 0; rad = 0; y = 0;
+ break;
+
+ default:
+ sat = tint;
+ rad = M_PI * ((colorNum * 30 + hue) / 180.0);
+ y = brightness[1][colorIntensity];
+ break;
+ }
+
+ u = sat * cos( rad );
+ v = sat * sin( rad );
+
+ /* Transform to RGB */
+ R = ( y + Kv * v ) * 255.0;
+ G = ( y - ( Kb * Ku * u + Kr * Kv * v) / (1 - Kb - Kr) ) * 255.0;
+ B = ( y + Ku * u ) * 255.0;
+
+ /* Clipping, in case of saturation */
+ if ( R < 0 )
+ R = 0;
+ if ( R > 255 )
+ R = 255;
+ if ( G < 0 )
+ G = 0;
+ if ( G > 255 )
+ G = 255;
+ if ( B < 0 )
+ B = 0;
+ if ( B > 255 )
+ B = 255;
+
+ /* Round, and set the value */
+ palette_set_color_rgb(machine, first_entry++, floor(R+.5), floor(G+.5), floor(B+.5));
+ }
+ }
+ }
+
+ /* color tables are modified at run-time, and are initialized on 'ppu2c0x_reset' */
+}
+
+/* the charlayout we use for the chargen */
+static gfx_layout ppu_charlayout =
+{
+ 8,8, /* 8*8 characters */
+ 512, /* 512 characters - modified at runtime */
+ 2, /* 2 bits per pixel */
+ { 8*8, 0 }, /* the two bitplanes are separated */
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
+ 16*8 /* every char takes 16 consecutive bytes */
+};
+
+/*************************************
+ *
+ * PPU Initialization and Disposal
+ *
+ *************************************/
+void ppu2c0x_init(running_machine *machine, const ppu2c0x_interface *interface )
+{
+ int i;
+
+ /* keep a local copy of the interface */
+ intf = auto_malloc(sizeof(*interface));
+ memcpy(intf, interface, sizeof(*interface));
+
+ /* safety check */
+ assert_always ( intf->num > 0, "Invalid intf->num" );
+
+ chips = auto_malloc( intf->num * sizeof( ppu2c0x_chip ) );
+ memset(chips, 0, intf->num * sizeof( ppu2c0x_chip ));
+
+ /* intialize our virtual chips */
+ for( i = 0; i < intf->num; i++ )
+ {
+ chips[i].machine = machine;
+
+ switch (intf->type)
+ {
+ case PPU_2C02:
+ chips[i].scanlines_per_frame = PPU_NTSC_SCANLINES_PER_FRAME;
+ break;
+ case PPU_2C03B:
+ chips[i].scanlines_per_frame = PPU_NTSC_SCANLINES_PER_FRAME;
+ break;
+ case PPU_2C04:
+ chips[i].scanlines_per_frame = PPU_NTSC_SCANLINES_PER_FRAME;
+ break;
+ case PPU_2C05:
+ chips[i].scanlines_per_frame = PPU_NTSC_SCANLINES_PER_FRAME;
+ break;
+ case PPU_2C07:
+ chips[i].scanlines_per_frame = PPU_PAL_SCANLINES_PER_FRAME;
+ break;
+ default:
+ chips[i].scanlines_per_frame = PPU_NTSC_SCANLINES_PER_FRAME;
+ break;
+ }
+
+ /* initialize the scanline handling portion */
+ chips[i].scanline_timer = timer_alloc(scanline_callback);
+ chips[i].hblank_timer = timer_alloc(hblank_callback);
+ chips[i].nmi_timer = timer_alloc(nmi_callback);
+ chips[i].scanline = 0;
+ chips[i].scan_scale = 1;
+
+ /* allocate a screen bitmap, videoram and spriteram, a dirtychar array and the monochromatic colortable */
+ chips[i].bitmap = auto_bitmap_alloc( VISIBLE_SCREEN_WIDTH, VISIBLE_SCREEN_HEIGHT, machine->screen[0].format );
+ chips[i].videoram = auto_malloc( VIDEORAM_SIZE );
+ chips[i].spriteram = auto_malloc( SPRITERAM_SIZE );
+ chips[i].dirtychar = auto_malloc( CHARGEN_NUM_CHARS );
+ chips[i].colortable = auto_malloc( sizeof( default_colortable ) );
+ chips[i].colortable_mono = auto_malloc( sizeof( default_colortable_mono ) );
+
+ /* clear videoram & spriteram */
+ memset( chips[i].videoram, 0, VIDEORAM_SIZE );
+ memset( chips[i].spriteram, 0, SPRITERAM_SIZE );
+
+ /* set all characters dirty */
+ memset( chips[i].dirtychar, 1, CHARGEN_NUM_CHARS );
+
+ /* initialize the video ROM portion, if available */
+ if ( ( intf->vrom_region[i] != REGION_INVALID ) && ( memory_region( intf->vrom_region[i] ) != 0 ) )
+ {
+ /* mark that we have a videorom */
+ chips[i].has_videorom = 1;
+
+ /* find out how many banks */
+ chips[i].videorom_banks = memory_region_length( intf->vrom_region[i] ) / 0x2000;
+
+ /* tweak the layout accordingly */
+ ppu_charlayout.total = chips[i].videorom_banks * CHARGEN_NUM_CHARS;
+ }
+ else
+ {
+ chips[i].has_videorom = chips[i].videorom_banks = 0;
+
+ /* we need to reset this in case of mame running multisession */
+ ppu_charlayout.total = CHARGEN_NUM_CHARS;
+ }
+
+ /* now create the gfx region */
+ {
+ UINT8 *src = chips[i].has_videorom ? memory_region( intf->vrom_region[i] ) : chips[i].videoram;
+ machine->gfx[intf->gfx_layout_number[i]] = allocgfx( &ppu_charlayout );
+ decodegfx( machine->gfx[intf->gfx_layout_number[i]], src, 0, machine->gfx[intf->gfx_layout_number[i]]->total_elements );
+ machine->gfx[intf->gfx_layout_number[i]]->total_colors = 8;
+ }
+
+ /* setup our videoram handlers based on mirroring */
+ ppu2c0x_set_mirroring( i, intf->mirroring[i] );
+ }
+}
+
+static TIMER_CALLBACK( hblank_callback )
+{
+ int num = param;
+ ppu2c0x_chip* this_ppu = &chips[num];
+ int *ppu_regs = &chips[num].regs[0];
+
+ int blanked = ( ppu_regs[PPU_CONTROL1] & ( PPU_CONTROL1_BACKGROUND | PPU_CONTROL1_SPRITES ) ) == 0;
+ int vblank = ((this_ppu->scanline >= PPU_VBLANK_FIRST_SCANLINE-1) && (this_ppu->scanline < this_ppu->scanlines_per_frame-1)) ? 1 : 0;
+
+// update_scanline (num);
+
+ if (this_ppu->hblank_callback_proc)
+ (*this_ppu->hblank_callback_proc) (num, this_ppu->scanline, vblank, blanked);
+
+ timer_adjust(chips[num].hblank_timer, attotime_never, num, attotime_never);
+}
+
+static TIMER_CALLBACK( nmi_callback )
+{
+ int num = param;
+ int *ppu_regs = &chips[num].regs[0];
+
+ // Actually fire the VMI
+ if (intf->nmi_handler[num])
+ (*intf->nmi_handler[num]) (num, ppu_regs);
+
+ timer_adjust(chips[num].nmi_timer, attotime_never, num, attotime_never);
+}
+
+static void draw_background(const int num, UINT8 *line_priority )
+{
+ /* cache some values locally */
+ mame_bitmap *bitmap = chips[num].bitmap;
+ const int *ppu_regs = &chips[num].regs[0];
+ const int scanline = chips[num].scanline;
+ const int refresh_data = chips[num].refresh_data;
+ const int gfx_bank = intf->gfx_layout_number[num];
+ const int total_elements = chips[num].machine->gfx[gfx_bank]->total_elements;
+ const int *nes_vram = &chips[num].nes_vram[0];
+ const int tile_page = chips[num].tile_page;
+ const int char_modulo = chips[num].machine->gfx[gfx_bank]->char_modulo;
+ const int line_modulo = chips[num].machine->gfx[gfx_bank]->line_modulo;
+ UINT8 *gfx_data = chips[num].machine->gfx[gfx_bank]->gfxdata;
+ UINT8 **ppu_page = chips[num].ppu_page;
+ int start_x = ( chips[num].x_fine ^ 0x07 ) - 7;
+ UINT16 back_pen;
+ UINT16 *dest;
+
+ UINT8 scroll_x_coarse, scroll_y_coarse, scroll_y_fine, color_mask;
+ int x, tile_index, start, i;
+
+ const pen_t *color_table;
+ const pen_t *paldata;
+ const UINT8 *sd;
+
+ int tilecount=0;
+
+ /* setup the color mask and colortable to use */
+ if ( ppu_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO )
+ {
+ color_mask = 0xf0;
+ color_table = chips[num].colortable_mono;
+ }
+ else
+ {
+ color_mask = 0xff;
+ color_table = chips[num].colortable;
+ }
+
+ /* cache the background pen */
+ back_pen = chips[num].machine->pens[(chips[num].back_color & color_mask)+intf->color_base[num]];
+
+ /* determine where in the nametable to start drawing from */
+ /* based on the current scanline and scroll regs */
+ scroll_x_coarse = refresh_data & 0x1f;
+ scroll_y_coarse = ( refresh_data & 0x3e0 ) >> 5;
+ scroll_y_fine = ( refresh_data & 0x7000 ) >> 12;
+
+ x = scroll_x_coarse;
+
+ /* get the tile index */
+ tile_index = ( ( refresh_data & 0xc00 ) | 0x2000 ) + scroll_y_coarse * 32;
+
+ /* set up dest */
+ dest = ((UINT16 *) bitmap->base) + (bitmap->rowpixels * scanline) + start_x;
+
+ /* draw the 32 or 33 tiles that make up a line */
+ while ( tilecount <34)
+ {
+ int color_byte;
+ int color_bits;
+ int pos;
+ int index1;
+ int page, page2, address;
+ int index2;
+ UINT16 pen;
+
+ index1 = tile_index + x;
+
+ /* Figure out which byte in the color table to use */
+ pos = ( ( index1 & 0x380 ) >> 4 ) | ( ( index1 & 0x1f ) >> 2 );
+ page = (index1 & 0x0c00) >> 10;
+ address = 0x3c0 + pos;
+ color_byte = ppu_page[page][address];
+
+ /* figure out which bits in the color table to use */
+ color_bits = ( ( index1 & 0x40 ) >> 4 ) + ( index1 & 0x02 );
+
+ address = index1 & 0x3ff;
+ page2 = ppu_page[page][address];
+ index2 = nes_vram[ ( page2 >> 6 ) | tile_page ] + ( page2 & 0x3f );
+
+ //27/12/2002
+ if( ppu_latch )
+ {
+ (*ppu_latch)(( tile_page << 10 ) | ( page2 << 4 ));
+ }
+
+ if(start_x < VISIBLE_SCREEN_WIDTH )
+ {
+ paldata = &color_table[ 4 * ( ( ( color_byte >> color_bits ) & 0x03 ) ) ];
+ start = ( index2 % total_elements ) * char_modulo + scroll_y_fine * line_modulo;
+ sd = &gfx_data[start];
+
+ /* render the pixel */
+ for( i = 0; i < 8; i++ )
+ {
+ if ( ( start_x+i ) >= 0 && ( start_x+i ) < VISIBLE_SCREEN_WIDTH )
+ {
+ if ( sd[i] )
+ {
+ pen = paldata[sd[i]];
+ line_priority[ start_x+i ] |= 0x02;
+ }
+ else
+ {
+ pen = back_pen;
+ }
+ *dest = pen;
+ }
+ dest++;
+ }
+
+ start_x += 8;
+
+ /* move to next tile over and toggle the horizontal name table if necessary */
+ x++;
+ if ( x > 31 )
+ {
+ x = 0;
+ tile_index ^= 0x400;
+ }
+ }
+ tilecount++;
+ }
+
+ /* if the left 8 pixels for the background are off, blank 'em */
+ if ( !( ppu_regs[PPU_CONTROL1] & PPU_CONTROL1_BACKGROUND_L8 ) )
+ {
+ dest = ((UINT16 *) bitmap->base) + (bitmap->rowpixels * scanline);
+ for( i = 0; i < 8; i++ )
+ {
+ *(dest++) = back_pen;
+ line_priority[ i ] ^= 0x02;
+ }
+ }
+}
+
+static void draw_sprites(const int num, UINT8 *line_priority )
+{
+ /* cache some values locally */
+ mame_bitmap *bitmap = chips[num].bitmap;
+ const int scanline = chips[num].scanline;
+ const int gfx_bank = intf->gfx_layout_number[num];
+ const int total_elements = chips[num].machine->gfx[gfx_bank]->total_elements;
+ const int sprite_page = chips[num].sprite_page;
+ const int char_modulo = chips[num].machine->gfx[gfx_bank]->char_modulo;
+ const int line_modulo = chips[num].machine->gfx[gfx_bank]->line_modulo;
+ const UINT8 *sprite_ram = chips[num].spriteram;
+ pen_t *color_table = chips[num].colortable;
+ UINT8 *gfx_data = chips[num].machine->gfx[gfx_bank]->gfxdata;
+ int *ppu_regs = &chips[num].regs[0];
+
+ int spriteXPos, spriteYPos, spriteIndex;
+ int tile, index1, page;
+ int pri;
+
+ int flipx, flipy, color;
+ int size;
+ int spriteCount = 0;
+ int sprite_line;
+ int drawn;
+ int start;
+
+ int first_pixel;
+
+ const pen_t *paldata;
+ const UINT8 *sd;
+ int pixel;
+
+ /* determine if the sprites are 8x8 or 8x16 */
+ size = ( ppu_regs[PPU_CONTROL0] & PPU_CONTROL0_SPRITE_SIZE ) ? 16 : 8;
+
+ first_pixel = (ppu_regs[PPU_CONTROL1] & PPU_CONTROL1_SPRITES_L8)? 0: 8;
+
+ for( spriteIndex = 0; spriteIndex < SPRITERAM_SIZE; spriteIndex += 4 )
+ {
+ spriteYPos = sprite_ram[spriteIndex] + 1;
+ spriteXPos = sprite_ram[spriteIndex+3];
+
+ // The sprite collision acts funny on the last pixel of a scanline.
+ // The various scanline latches update while the last few pixels
+ // are being drawn. Since we don't do cycle-by-cycle PPU emulation,
+ // we fudge it a bit here so that sprite 0 collisions are detected
+ // when, e.g., sprite x is 254, sprite y is 29 and we're rendering
+ // at the end of scanline 28.
+ // Battletoads needs this level of precision to be playable.
+ if ((spriteIndex == 0) && (spriteXPos == 254))
+ {
+ spriteYPos --;
+ /* set the "sprite 0 hit" flag if appropriate */
+ if (line_priority[spriteXPos] & 0x02)
+ ppu_regs[PPU_STATUS] |= PPU_STATUS_SPRITE0_HIT;
+ }
+
+ /* if the sprite isn't visible, skip it */
+ if ( ( spriteYPos + size <= scanline ) || ( spriteYPos > scanline ) )
+ continue;
+
+ /* clear our drawn flag */
+ drawn = 0;
+
+ tile = sprite_ram[spriteIndex+1];
+ color = ( sprite_ram[spriteIndex+2] & 0x03 ) + 4;
+ pri = sprite_ram[spriteIndex+2] & 0x20;
+ flipx = sprite_ram[spriteIndex+2] & 0x40;
+ flipy = sprite_ram[spriteIndex+2] & 0x80;
+
+ if ( size == 16 )
+ {
+ /* if it's 8x16 and odd-numbered, draw the other half instead */
+ if ( tile & 0x01 )
+ {
+ tile &= ~0x01;
+ tile |= 0x100;
+ }
+ /* note that the sprite page value has no effect on 8x16 sprites */
+ page = tile >> 6;
+ }
+ else
+ page = ( tile >> 6 ) | sprite_page;
+
+
+ index1 = chips[num].nes_vram[page] + ( tile & 0x3f );
+
+ if ( ppu_latch )
+ (*ppu_latch)(( sprite_page << 10 ) | ( (tile & 0xff) << 4 ));
+
+ /* compute the character's line to draw */
+ sprite_line = scanline - spriteYPos;
+
+ if ( flipy )
+ sprite_line = ( size - 1 ) - sprite_line;
+
+ paldata = &color_table[4 * color];
+ start = ( index1 % total_elements ) * char_modulo + sprite_line * line_modulo;
+ sd = &gfx_data[start];
+
+ if ( pri )
+ {
+ /* draw the low-priority sprites */
+
+ for ( pixel = 0; pixel < 8; pixel++ )
+ {
+ UINT8 pixelData = flipx ? sd[7-pixel] : sd[pixel];
+
+ /* is this pixel non-transparent? */
+ if ( spriteXPos + pixel >= first_pixel)
+ {
+ if (pixelData)
+ {
+ /* has the background (or another sprite) already been drawn here? */
+ if ( !line_priority[ spriteXPos + pixel ] )
+ {
+ /* no, draw */
+ if ( ( spriteXPos + pixel ) < VISIBLE_SCREEN_WIDTH )
+ *BITMAP_ADDR16(bitmap, scanline, spriteXPos + pixel) = paldata[pixelData];
+ drawn = 1;
+ }
+ /* indicate that a sprite was drawn at this location, even if it's not seen */
+ if ( ( spriteXPos + pixel ) < VISIBLE_SCREEN_WIDTH )
+ line_priority[ spriteXPos + pixel ] |= 0x01;
+ }
+
+ /* set the "sprite 0 hit" flag if appropriate */
+ if ( spriteIndex == 0 && (pixelData & 0x03) && ((spriteXPos + pixel) < 255) && ( line_priority[ spriteXPos + pixel ] & 0x02 ))
+ ppu_regs[PPU_STATUS] |= PPU_STATUS_SPRITE0_HIT;
+ }
+ }
+ }
+ else
+ {
+ /* draw the high-priority sprites */
+
+ for ( pixel = 0; pixel < 8; pixel++ )
+ {
+ UINT8 pixelData = flipx ? sd[7-pixel] : sd[pixel];
+
+ /* is this pixel non-transparent? */
+ if ( spriteXPos + pixel >= first_pixel)
+ {
+ if (pixelData)
+ {
+ /* has another sprite been drawn here? */
+ if ( !( line_priority[ spriteXPos + pixel ] & 0x01 ) )
+ {
+ /* no, draw */
+ if ( ( spriteXPos + pixel ) < VISIBLE_SCREEN_WIDTH )
+ {
+ *BITMAP_ADDR16(bitmap, scanline, spriteXPos + pixel) = paldata[pixelData];
+ line_priority[ spriteXPos + pixel ] |= 0x01;
+ }
+ drawn = 1;
+ }
+ }
+
+ /* set the "sprite 0 hit" flag if appropriate */
+ if ( spriteIndex == 0 && (pixelData & 0x03) && ((spriteXPos + pixel) < 255) && ( line_priority[ spriteXPos + pixel ] & 0x02 ))
+ ppu_regs[PPU_STATUS] |= PPU_STATUS_SPRITE0_HIT;
+ }
+ }
+ }
+
+ if ( drawn )
+ {
+ /* if there are more than 8 sprites on this line, set the flag */
+ spriteCount++;
+ if ( spriteCount == 8 )
+ {
+ ppu_regs[PPU_STATUS] |= PPU_STATUS_8SPRITES;
+// logerror ("> 8 sprites, scanline: %d\n", scanline);
+
+ /* the real NES only draws up to 8 sprites - the rest should be invisible */
+ break;
+ }
+ }
+ }
+}
+
+/*************************************
+ *
+ * Scanline Rendering and Update
+ *
+ *************************************/
+static void render_scanline(int num)
+{
+ UINT8 line_priority[VISIBLE_SCREEN_WIDTH];
+ int *ppu_regs = &chips[num].regs[0];
+
+ /* lets see how long it takes */
+ profiler_mark(PROFILER_USER1+num);
+
+ /* clear the line priority for this scanline */
+ memset( line_priority, 0, VISIBLE_SCREEN_WIDTH );
+
+ /* clear the sprite count for this line */
+ ppu_regs[PPU_STATUS] &= ~PPU_STATUS_8SPRITES;
+
+ /* see if we need to render the background */
+ if ( ppu_regs[PPU_CONTROL1] & PPU_CONTROL1_BACKGROUND )
+ draw_background(num, line_priority );
+ else
+ {
+ mame_bitmap *bitmap = chips[num].bitmap;
+ const int scanline = chips[num].scanline;
+ UINT8 color_mask;
+ UINT16 back_pen;
+ int i;
+
+ /* setup the color mask and colortable to use */
+ if ( ppu_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO )
+ color_mask = 0xf0;
+ else
+ color_mask = 0xff;
+
+ /* cache the background pen */
+ back_pen = chips[num].machine->pens[(chips[num].back_color & color_mask)+intf->color_base[num]];
+
+ // Fill this scanline with the background pen.
+ for (i = 0; i < bitmap->width; i ++)
+ *BITMAP_ADDR16(bitmap, scanline, i) = back_pen;
+ }
+
+ /* if sprites are on, draw them */
+ if ( ppu_regs[PPU_CONTROL1] & PPU_CONTROL1_SPRITES )
+ draw_sprites( num, line_priority );
+
+ /* done updating, whew */
+ profiler_mark(PROFILER_END);
+}
+
+static void update_scanline(int num )
+{
+ ppu2c0x_chip* this_ppu;
+ int scanline = chips[num].scanline;
+ int *ppu_regs = &chips[num].regs[0];
+
+ this_ppu = &chips[num];
+
+ if ( scanline <= PPU_BOTTOM_VISIBLE_SCANLINE )
+ {
+ /* Render this scanline if appropriate */
+ if ( ppu_regs[PPU_CONTROL1] & ( PPU_CONTROL1_BACKGROUND | PPU_CONTROL1_SPRITES ) )
+ {
+ /* If background or sprites are enabled, copy the ppu address latch */
+ /* Copy only the scroll x-coarse and the x-overflow bit */
+ this_ppu->refresh_data &= ~0x041f;
+ this_ppu->refresh_data |= ( this_ppu->refresh_latch & 0x041f );
+
+//logerror(" updating refresh_data: %04x (scanline: %d)\n", this_ppu->refresh_data, this_ppu->scanline);
+ render_scanline( num );
+ }
+ else
+ {
+ mame_bitmap *bitmap = this_ppu->bitmap;
+ const int scanline = this_ppu->scanline;
+ UINT8 color_mask;
+ UINT16 back_pen;
+ int i;
+
+ /* setup the color mask and colortable to use */
+ if ( ppu_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO )
+ color_mask = 0xf0;
+ else
+ color_mask = 0xff;
+
+ /* cache the background pen */
+ if (this_ppu->videoram_addr >= 0x3f00)
+ {
+ // If the PPU's VRAM address happens to point into palette ram space while
+ // both the sprites and background are disabled, the PPU paints the scanline
+ // with the palette entry at the VRAM address instead of the usual background
+ // pen. Micro Machines makes use of this feature.
+ int penNum;
+ if (this_ppu->videoram_addr & 0x03)
+ {
+ penNum = this_ppu->videoram[this_ppu->videoram_addr & 0x3f1f] & 0x3f;
+ }
+ else
+ {
+ penNum = this_ppu->videoram[this_ppu->videoram_addr & 0x3f00] & 0x3f;
+ }
+ back_pen = chips[num].machine->pens[penNum + intf->color_base[num]];
+ }
+ else
+ back_pen = chips[num].machine->pens[(this_ppu->back_color & color_mask)+intf->color_base[num]];
+
+ // Fill this scanline with the background pen.
+ for (i = 0; i < bitmap->width; i ++)
+ *BITMAP_ADDR16(bitmap, scanline, i) = back_pen;
+ }
+
+ /* increment the fine y-scroll */
+ this_ppu->refresh_data += 0x1000;
+
+ /* if it's rolled, increment the coarse y-scroll */
+ if ( this_ppu->refresh_data & 0x8000 )
+ {
+ UINT16 tmp;
+ tmp = ( this_ppu->refresh_data & 0x03e0 ) + 0x20;
+ this_ppu->refresh_data &= 0x7c1f;
+ /* handle bizarro scrolling rollover at the 30th (not 32nd) vertical tile */
+ if ( tmp == 0x03c0 )
+ {
+ this_ppu->refresh_data ^= 0x0800;
+ }
+ else
+ {
+ this_ppu->refresh_data |= ( tmp & 0x03e0 );
+ }
+//logerror("updating refresh_data: %04x\n", this_ppu->refresh_data);
+ }
+ }
+
+}
+
+static TIMER_CALLBACK( scanline_callback )
+{
+ int num = param;
+ ppu2c0x_chip* this_ppu = &chips[num];
+ int *ppu_regs = &chips[num].regs[0];
+ int i;
+ int blanked = ( ppu_regs[PPU_CONTROL1] & ( PPU_CONTROL1_BACKGROUND | PPU_CONTROL1_SPRITES ) ) == 0;
+ int vblank = ((this_ppu->scanline >= PPU_VBLANK_FIRST_SCANLINE-1) && (this_ppu->scanline < this_ppu->scanlines_per_frame-1)) ? 1 : 0;
+ int next_scanline;
+
+ /* if a callback is available, call it */
+ if ( this_ppu->scanline_callback_proc )
+ (*this_ppu->scanline_callback_proc)( num, this_ppu->scanline, vblank, blanked );
+
+ /* update the scanline that just went by */
+ update_scanline( num );
+
+ /* increment our scanline count */
+ this_ppu->scanline++;
+
+//logerror("starting scanline %d (MAME %d, beam %d)\n", this_ppu->scanline, video_screen_get_vpos(0), video_screen_get_hpos(0));
+
+ /* Note: this is called at the _end_ of each scanline */
+ if (this_ppu->scanline == PPU_VBLANK_FIRST_SCANLINE)
+ {
+logerror("vlbank starting\n");
+ /* We just entered VBLANK */
+ ppu_regs[PPU_STATUS] |= PPU_STATUS_VBLANK;
+
+ /* If NMI's are set to be triggered, go for it */
+ if (ppu_regs[PPU_CONTROL0] & PPU_CONTROL0_NMI)
+ {
+ // We need an ever-so-slight delay between entering vblank and firing an NMI - enough so that
+ // a game can read the high bit of $2002 before the NMI is called (potentially resetting the bit
+ // via a read from $2002 in the NMI handler).
+ // B-Wings is an example game that needs this.
+ timer_adjust(this_ppu->nmi_timer, ATTOTIME_IN_CYCLES(4, 0), num, attotime_never);
+ }
+ }
+
+ /* decode any dirty chars if we're using vram */
+
+ /* first, check the master dirty char flag */
+ if ( !this_ppu->has_videorom && this_ppu->chars_are_dirty )
+ {
+ /* cache some values */
+ UINT8 *dirtyarray = this_ppu->dirtychar;
+ UINT8 *vram = this_ppu->videoram;
+ gfx_element *gfx = chips[num].machine->gfx[intf->gfx_layout_number[num]];
+
+ /* then iterate and decode */
+ for( i = 0; i < CHARGEN_NUM_CHARS; i++ )
+ {
+ if ( dirtyarray[i] )
+ {
+ decodechar( gfx, i, vram, &ppu_charlayout);
+ dirtyarray[i] = 0;
+ }
+ }
+
+ this_ppu->chars_are_dirty = 0;
+ }
+
+ if ( this_ppu->scanline == this_ppu->scanlines_per_frame - 1 )
+ {
+logerror("vlbank ending\n");
+ /* clear the vblank & sprite hit flag */
+ ppu_regs[PPU_STATUS] &= ~( PPU_STATUS_VBLANK | PPU_STATUS_SPRITE0_HIT );
+ }
+
+ /* see if we rolled */
+ else if ( this_ppu->scanline == this_ppu->scanlines_per_frame )
+ {
+ /* if background or sprites are enabled, copy the ppu address latch */
+ if ( !blanked )
+ this_ppu->refresh_data = this_ppu->refresh_latch;
+
+ /* reset the scanline count */
+ this_ppu->scanline = 0;
+//logerror(" sprite 0 x: %d y: %d num: %d\n", this_ppu->spriteram[3], this_ppu->spriteram[0]+1, this_ppu->spriteram[1]);
+ }
+
+ next_scanline = this_ppu->scanline+1;
+ if (next_scanline == this_ppu->scanlines_per_frame)
+ next_scanline = 0;
+
+ // Call us back when the hblank starts for this scanline
+ timer_adjust(this_ppu->hblank_timer, ATTOTIME_IN_CYCLES(86.67, 0), num, attotime_never); // ??? FIXME - hardcoding NTSC, need better calculation
+
+ // trigger again at the start of the next scanline
+ timer_adjust(this_ppu->scanline_timer, video_screen_get_time_until_pos(0, next_scanline * this_ppu->scan_scale, 0), num, attotime_zero);
+}
+
+/*************************************
+ *
+ * PPU Reset
+ *
+ *************************************/
+void ppu2c0x_reset(int num, int scan_scale )
+{
+ int i;
+
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU(reset): Attempting to access an unmapped chip\n" );
+ return;
+ }
+
+ /* reset the scanline count */
+ chips[num].scanline = 0;
+
+ /* set the scan scale (this is for dual monitor vertical setups) */
+ chips[num].scan_scale = scan_scale;
+
+ timer_adjust(chips[num].nmi_timer, attotime_never, num, attotime_never);
+
+ // Call us back when the hblank starts for this scanline
+ timer_adjust(chips[num].hblank_timer, ATTOTIME_IN_CYCLES(86.67, 0), num, attotime_never); // ??? FIXME - hardcoding NTSC, need better calculation
+
+ // Call us back at the start of the next scanline
+ timer_adjust(chips[num].scanline_timer, video_screen_get_time_until_pos(0, 1, 0), num, attotime_zero);
+
+ /* reset the callbacks */
+ chips[num].scanline_callback_proc = 0;
+ chips[num].vidaccess_callback_proc = 0;
+
+ for( i = 0; i < PPU_MAX_REG; i++ )
+ chips[num].regs[i] = 0;
+
+ /* initialize the rest of the members */
+ chips[num].refresh_data = 0;
+ chips[num].refresh_latch = 0;
+ chips[num].x_fine = 0;
+ chips[num].toggle = 0;
+ chips[num].add = 1;
+ chips[num].videoram_addr = 0;
+ chips[num].addr_latch = 0;
+ chips[num].data_latch = 0;
+ chips[num].tile_page = 0;
+ chips[num].sprite_page = 0;
+ chips[num].back_color = 0;
+ chips[num].chars_are_dirty = 1;
+
+ /* initialize the color tables */
+ {
+ int color_base = intf->color_base[num];
+
+ for( i = 0; i < ARRAY_LENGTH( default_colortable_mono ); i++ )
+ {
+ /* monochromatic table */
+ chips[num].colortable_mono[i] = chips[num].machine->pens[default_colortable_mono[i] + color_base];
+
+ /* color table */
+ chips[num].colortable[i] = chips[num].machine->pens[default_colortable[i] + color_base];
+ }
+ }
+
+ /* set the vram bank-switch values to the default */
+ for( i = 0; i < 8; i++ )
+ chips[num].nes_vram[i] = i * 64;
+
+ if ( chips[num].has_videorom )
+ ppu2c0x_set_videorom_bank( num, 0, 8, 0, 512 );
+}
+
+
+/*************************************
+ *
+ * PPU Registers Read
+ *
+ *************************************/
+int ppu2c0x_r( int num, offs_t offset )
+{
+ ppu2c0x_chip* this_ppu;
+
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU %d(r): Attempting to access an unmapped chip\n", num );
+ return 0;
+ }
+
+ this_ppu = &chips[num];
+
+ if ( offset >= PPU_MAX_REG )
+ {
+ logerror( "PPU %d(r): Attempting to read past the chip\n", num );
+ offset &= PPU_MAX_REG - 1;
+ }
+
+ // see which register to read
+ switch( offset & 7 )
+ {
+ case PPU_STATUS:
+ // The top 3 bits of the status register are the only ones that report data. The
+ // remainder contain whatever was last in the PPU data latch.
+ this_ppu->data_latch = this_ppu->regs[PPU_STATUS] | (this_ppu->data_latch & 0x1f);
+
+ // Reset hi/lo scroll toggle
+ this_ppu->toggle = 0;
+
+ // If the vblank bit is set, clear all status bits but the 2 sprite flags
+ if (this_ppu->data_latch & PPU_STATUS_VBLANK)
+ this_ppu->regs[PPU_STATUS] &= 0x60;
+ break;
+
+ case PPU_SPRITE_DATA:
+ this_ppu->data_latch = this_ppu->spriteram[this_ppu->regs[PPU_SPRITE_ADDRESS]];
+ break;
+
+ case PPU_DATA:
+ if ( this_ppu->videoram_addr >= 0x3f00 )
+ {
+ this_ppu->data_latch = this_ppu->videoram[this_ppu->videoram_addr & 0x3F1F];
+ if (this_ppu->regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO)
+ this_ppu->data_latch &= 0x30;
+ }
+ else
+ this_ppu->data_latch = this_ppu->buffered_data;
+
+ if ( ppu_latch )
+ (*ppu_latch)( this_ppu->videoram_addr & 0x3fff );
+
+ if ( ( this_ppu->videoram_addr >= 0x2000 ) && ( this_ppu->videoram_addr <= 0x3fff ) )
+ this_ppu->buffered_data = this_ppu->ppu_page[ ( this_ppu->videoram_addr & 0xc00) >> 10][ this_ppu->videoram_addr & 0x3ff ];
+ else
+ this_ppu->buffered_data = this_ppu->videoram[ this_ppu->videoram_addr & 0x3fff ];
+
+ this_ppu->videoram_addr += this_ppu->add;
+ break;
+
+ default:
+ break;
+ }
+
+ return this_ppu->data_latch;
+}
+
+
+/*************************************
+ *
+ * PPU Registers Write
+ *
+ *************************************/
+void ppu2c0x_w( int num, offs_t offset, UINT8 data )
+{
+ ppu2c0x_chip* this_ppu;
+ int color_base;
+
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU(w): Attempting to access an unmapped chip\n" );
+ return;
+ }
+
+ this_ppu = &chips[num];
+ color_base = intf->color_base[num];
+
+ if ( offset >= PPU_MAX_REG )
+ {
+ logerror( "PPU: Attempting to write past the chip\n" );
+ offset &= PPU_MAX_REG - 1;
+ }
+
+#ifdef MAME_DEBUG
+ if (this_ppu->scanline <= PPU_BOTTOM_VISIBLE_SCANLINE)
+ logerror(" PPU register %d write %02x during non-vblank scanline %d (MAME %d, beam pos: %d)\n", offset, data, this_ppu->scanline, video_screen_get_vpos(0), video_screen_get_hpos(0));
+#endif
+
+ switch( offset & 7 )
+ {
+ case PPU_CONTROL0:
+ this_ppu->regs[PPU_CONTROL0] = data;
+
+ /* update the name table number on our refresh latches */
+ this_ppu->refresh_latch &= 0x73ff;
+ this_ppu->refresh_latch |= ( data & 3 ) << 10;
+
+ /* the char ram bank points either 0x0000 or 0x1000 (page 0 or page 4) */
+ this_ppu->tile_page = ( data & PPU_CONTROL0_CHR_SELECT ) >> 2;
+ this_ppu->sprite_page = ( data & PPU_CONTROL0_SPR_SELECT ) >> 1;
+
+ this_ppu->add = ( data & PPU_CONTROL0_INC ) ? 32 : 1;
+//logerror(" control0 write: %02x (scanline: %d)\n", data, this_ppu->scanline);
+ break;
+
+ case PPU_CONTROL1:
+ /* if color intensity has changed, change all the color tables to reflect them */
+ if ( ( data & PPU_CONTROL1_COLOR_EMPHASIS ) != ( this_ppu->regs[PPU_CONTROL1] & PPU_CONTROL1_COLOR_EMPHASIS ) )
+ {
+ int i;
+ for (i = 0; i <= 0x1f; i ++)
+ {
+ UINT8 oldColor = this_ppu->videoram[i+0x3f00];
+
+ this_ppu->colortable[i] = chips[num].machine->pens[color_base + oldColor + (data & PPU_CONTROL1_COLOR_EMPHASIS)*2];
+ }
+ }
+
+//logerror(" control1 write: %02x (scanline: %d)\n", data, this_ppu->scanline);
+ this_ppu->regs[PPU_CONTROL1] = data;
+ break;
+
+ case PPU_SPRITE_ADDRESS:
+ this_ppu->regs[PPU_SPRITE_ADDRESS] = data;
+ break;
+
+ case PPU_SPRITE_DATA:
+ // If the PPU is currently rendering the screen, 0xff is written instead of the desired data.
+ if (this_ppu->scanline <= PPU_BOTTOM_VISIBLE_SCANLINE)
+ data = 0xff;
+ this_ppu->spriteram[this_ppu->regs[PPU_SPRITE_ADDRESS]] = data;
+ this_ppu->regs[PPU_SPRITE_ADDRESS] = ( this_ppu->regs[PPU_SPRITE_ADDRESS] + 1 ) & 0xff;
+ break;
+
+ case PPU_SCROLL:
+ if ( this_ppu->toggle )
+ {
+ /* second write */
+ this_ppu->refresh_latch &= 0x0c1f;
+ this_ppu->refresh_latch |= ( data & 0xf8 ) << 2;
+ this_ppu->refresh_latch |= ( data & 0x07 ) << 12;
+//logerror(" scroll write 2: %d, %04x (scanline: %d)\n", data, this_ppu->refresh_latch, this_ppu->scanline);
+ }
+ else
+ {
+ /* first write */
+ this_ppu->refresh_latch &= 0x7fe0;
+ this_ppu->refresh_latch |= (data & 0xf8) >> 3;
+
+ this_ppu->x_fine = data & 7;
+//logerror(" scroll write 1: %d, %04x (scanline: %d)\n", data, this_ppu->refresh_latch, this_ppu->scanline);
+ }
+
+ this_ppu->toggle ^= 1;
+ break;
+
+ case PPU_ADDRESS:
+ if ( this_ppu->toggle )
+ {
+ /* second write */
+ this_ppu->refresh_latch &= 0x7f00;
+ this_ppu->refresh_latch |= data;
+ this_ppu->refresh_data = this_ppu->refresh_latch;
+
+ this_ppu->videoram_addr = this_ppu->refresh_latch;
+//logerror(" vram addr write 2: %02x, %04x (scanline: %d)\n", data, this_ppu->refresh_latch, this_ppu->scanline);
+ }
+ else
+ {
+ /* first write */
+ this_ppu->refresh_latch &= 0x00ff;
+ this_ppu->refresh_latch |= ( data & 0x3f ) << 8;
+//logerror(" vram addr write 1: %02x, %04x (scanline: %d)\n", data, this_ppu->refresh_latch, this_ppu->scanline);
+ }
+
+ this_ppu->toggle ^= 1;
+ break;
+
+ case PPU_DATA:
+ {
+ int tempAddr = this_ppu->videoram_addr & 0x3fff;
+
+ if ( ppu_latch )
+ (*ppu_latch)( tempAddr );
+
+ /* if there's a callback, call it now */
+ if ( this_ppu->vidaccess_callback_proc )
+ data = (*this_ppu->vidaccess_callback_proc)( num, tempAddr, data );
+
+ /* see if it's on the chargen portion */
+ if ( tempAddr < 0x2000 )
+ {
+ /* if we have a videorom mapped there, dont write and log the problem */
+ if ( this_ppu->has_videorom )
+ {
+ /* if there is a vidaccess callback, assume it coped with it */
+ if ( this_ppu->vidaccess_callback_proc == NULL )
+ logerror( "PPU: Attempting to write to the chargen when there's a ROM there!\n" );
+ }
+ else
+ {
+ /* store the data */
+ this_ppu->videoram[tempAddr] = data;
+
+ /* setup the master dirty switch */
+ this_ppu->chars_are_dirty = 1;
+
+ /* mark the char dirty */
+ this_ppu->dirtychar[tempAddr >> 4] = 1;
+ }
+ }
+
+ else if ( tempAddr >= 0x3f00 )
+ {
+ int colorEmphasis = (this_ppu->regs[PPU_CONTROL1] & PPU_CONTROL1_COLOR_EMPHASIS) * 2;
+
+ /* store the data */
+ if (tempAddr & 0x03)
+ this_ppu->videoram[tempAddr & 0x3F1F] = data;
+ else
+ {
+ this_ppu->videoram[0x3F10+(tempAddr&0xF)] = data;
+ this_ppu->videoram[0x3F00+(tempAddr&0xF)] = data;
+ }
+
+ /* As usual, some games attempt to write values > the number of colors so we must mask the data. */
+ data &= 0x3f;
+
+ if ( tempAddr & 0x03 )
+ {
+ this_ppu->colortable[ tempAddr & 0x1f ] = chips[num].machine->pens[color_base + data + colorEmphasis];
+ this_ppu->colortable_mono[tempAddr & 0x1f] = chips[num].machine->pens[color_base + (data & 0xf0) + colorEmphasis];
+ }
+
+ /* The only valid background colors are writes to 0x3f00 and 0x3f10 */
+ /* and even then, they are mirrors of each other. */
+ if ( ( tempAddr & 0x0f ) == 0 )
+ {
+ int i;
+
+ this_ppu->back_color = data;
+ for( i = 0; i < 32; i += 4 )
+ {
+ this_ppu->colortable[ i ] = chips[num].machine->pens[color_base + data + colorEmphasis];
+ this_ppu->colortable_mono[i] = chips[num].machine->pens[color_base + (data & 0xf0) + colorEmphasis];
+ }
+ }
+ }
+
+ /* everything else */
+ /* writes to $3000-$3eff are mirrors of $2000-$2eff */
+ else
+ {
+ int page = ( tempAddr & 0x0c00) >> 10;
+ int address = tempAddr & 0x3ff;
+
+ this_ppu->ppu_page[page][address] = data;
+ }
+
+ /* increment the address */
+ this_ppu->videoram_addr += this_ppu->add;
+ }
+ break;
+
+ default:
+ /* ignore other registers writes */
+ break;
+ }
+}
+
+/*************************************
+ *
+ * Sprite DMA
+ *
+ *************************************/
+void ppu2c0x_spriteram_dma (int num, const UINT8 page)
+{
+ int i;
+ int address = page << 8;
+
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU(w): Attempting to access an unmapped chip\n" );
+ return;
+ }
+
+//logerror(" sprite DMA: %d (scanline: %d)\n", page, chips[num].scanline);
+ for (i = 0; i < SPRITERAM_SIZE; i++)
+ {
+ UINT8 spriteData = program_read_byte_8 (address + i);
+ ppu2c0x_w (num, PPU_SPRITE_DATA, spriteData);
+ }
+
+ // should last 513 CPU cycles.
+ activecpu_adjust_icount(-513);
+
+ // ????TODO : need to account for PPU rendering - this is roughly 4.5 scanlines eaten up.
+ // Because the DMA is only useful during vblank, this may not be strictly necessary since
+ // the scanline timers should catch us up before drawing actually happens.
+#if 0
+ scanline_callback(Machine, num);
+ scanline_callback(Machine, num);
+ scanline_callback(Machine, num);
+ scanline_callback(Machine, num);
+#endif
+}
+
+/*************************************
+ *
+ * PPU Rendering
+ *
+ *************************************/
+void ppu2c0x_render( int num, mame_bitmap *bitmap, int flipx, int flipy, int sx, int sy )
+{
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU(render): Attempting to access an unmapped chip\n" );
+ return;
+ }
+
+ copybitmap( bitmap, chips[num].bitmap, flipx, flipy, sx, sy, 0, TRANSPARENCY_NONE, 0 );
+}
+
+/*************************************
+ *
+ * PPU VideoROM banking
+ *
+ *************************************/
+void ppu2c0x_set_videorom_bank( int num, int start_page, int num_pages, int bank, int bank_size )
+{
+ int i;
+
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU(set vrom bank): Attempting to access an unmapped chip\n" );
+ return;
+ }
+
+ if ( !chips[num].has_videorom )
+ {
+ logerror( "PPU(set vrom bank): Attempting to switch videorom banks and no rom is mapped\n" );
+ return;
+ }
+
+ bank &= ( chips[num].videorom_banks * ( CHARGEN_NUM_CHARS / bank_size ) ) - 1;
+
+ for( i = start_page; i < ( start_page + num_pages ); i++ )
+ chips[num].nes_vram[i] = bank * bank_size + 64 * ( i - start_page );
+
+ {
+ int vram_start = start_page * 0x400;
+ int count = num_pages * 0x400;
+ int rom_start = bank * bank_size * 16;
+
+ memcpy( &chips[num].videoram[vram_start], &memory_region( intf->vrom_region[num] )[rom_start], count );
+ }
+}
+
+/*************************************
+ *
+ * Utility functions
+ *
+ *************************************/
+int ppu2c0x_get_pixel( int num, int x, int y )
+{
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU(get_pixel): Attempting to access an unmapped chip\n" );
+ return 0;
+ }
+
+ if ( x >= VISIBLE_SCREEN_WIDTH )
+ x = VISIBLE_SCREEN_WIDTH - 1;
+
+ if ( y >= VISIBLE_SCREEN_HEIGHT )
+ y = VISIBLE_SCREEN_HEIGHT - 1;
+
+ return *BITMAP_ADDR16(chips[num].bitmap, y, x);
+}
+
+int ppu2c0x_get_colorbase( int num )
+{
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU(get_colorbase): Attempting to access an unmapped chip\n" );
+ return 0;
+ }
+
+ return intf->color_base[num];
+}
+
+int ppu2c0x_get_current_scanline( int num )
+{
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU(get_colorbase): Attempting to access an unmapped chip\n" );
+ return 0;
+ }
+
+ return chips[num].scanline;
+}
+
+void ppu2c0x_set_mirroring( int num, int mirroring )
+{
+ ppu2c0x_chip* this_ppu;
+
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU %d: Attempting to access an unmapped chip\n", num );
+ return;
+ }
+
+ this_ppu = &chips[num];
+
+ // Once we've set 4-screen mirroring, do not change. Some games
+ // (notably Gauntlet) use mappers that can change the mirroring
+ // state, but are also hard-coded for 4-screen VRAM.
+ if (this_ppu->mirror_state == PPU_MIRROR_4SCREEN)
+ return;
+
+ /* setup our videoram handlers based on mirroring */
+ switch( mirroring )
+ {
+ case PPU_MIRROR_VERT:
+ this_ppu->ppu_page[0] = &(this_ppu->videoram[0x2000]);
+ this_ppu->ppu_page[1] = &(this_ppu->videoram[0x2400]);
+ this_ppu->ppu_page[2] = &(this_ppu->videoram[0x2000]);
+ this_ppu->ppu_page[3] = &(this_ppu->videoram[0x2400]);
+ break;
+
+ case PPU_MIRROR_HORZ:
+ this_ppu->ppu_page[0] = &(this_ppu->videoram[0x2000]);
+ this_ppu->ppu_page[1] = &(this_ppu->videoram[0x2000]);
+ this_ppu->ppu_page[2] = &(this_ppu->videoram[0x2400]);
+ this_ppu->ppu_page[3] = &(this_ppu->videoram[0x2400]);
+ break;
+
+ case PPU_MIRROR_HIGH:
+ this_ppu->ppu_page[0] = &(this_ppu->videoram[0x2400]);
+ this_ppu->ppu_page[1] = &(this_ppu->videoram[0x2400]);
+ this_ppu->ppu_page[2] = &(this_ppu->videoram[0x2400]);
+ this_ppu->ppu_page[3] = &(this_ppu->videoram[0x2400]);
+ break;
+
+ case PPU_MIRROR_LOW:
+ this_ppu->ppu_page[0] = &(this_ppu->videoram[0x2000]);
+ this_ppu->ppu_page[1] = &(this_ppu->videoram[0x2000]);
+ this_ppu->ppu_page[2] = &(this_ppu->videoram[0x2000]);
+ this_ppu->ppu_page[3] = &(this_ppu->videoram[0x2000]);
+ break;
+
+ case PPU_MIRROR_NONE:
+ case PPU_MIRROR_4SCREEN:
+ default:
+ this_ppu->ppu_page[0] = &(this_ppu->videoram[0x2000]);
+ this_ppu->ppu_page[1] = &(this_ppu->videoram[0x2400]);
+ this_ppu->ppu_page[2] = &(this_ppu->videoram[0x2800]);
+ this_ppu->ppu_page[3] = &(this_ppu->videoram[0x2c00]);
+ break;
+ }
+
+ this_ppu->mirror_state = mirroring;
+}
+
+#ifdef UNUSED_FUNCTION
+void ppu2c0x_set_nmi_callback( int num, ppu2c0x_nmi_cb cb )
+{
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU(set_nmi_callback): Attempting to access an unmapped chip\n" );
+ return;
+ }
+
+ intf->nmi_handler[num] = cb;
+}
+#endif
+
+void ppu2c0x_set_scanline_callback( int num, ppu2c0x_scanline_cb cb )
+{
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU(set_scanline_callback): Attempting to access an unmapped chip\n" );
+ return;
+ }
+
+ chips[num].scanline_callback_proc = cb;
+}
+
+void ppu2c0x_set_hblank_callback( int num, ppu2c0x_hblank_cb cb )
+{
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU(set_scanline_callback): Attempting to access an unmapped chip\n" );
+ return;
+ }
+
+ chips[num].hblank_callback_proc = cb;
+}
+
+void ppu2c0x_set_vidaccess_callback( int num, ppu2c0x_vidaccess_cb cb )
+{
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU(set_vidaccess_callback): Attempting to access an unmapped chip\n" );
+ return;
+ }
+
+ chips[num].vidaccess_callback_proc = cb;
+}
+
+void ppu2c0x_set_scanlines_per_frame( int num, int scanlines )
+{
+ /* check bounds */
+ if ( num >= intf->num )
+ {
+ logerror( "PPU(set_scanlines_per_frame): Attempting to access an unmapped chip\n" );
+ return;
+ }
+
+ chips[num].scanlines_per_frame = scanlines;
+}
+
+/*************************************
+ *
+ * Accesors
+ *
+ *************************************/
+
+READ8_HANDLER( ppu2c0x_0_r )
+{
+ return ppu2c0x_r( 0, offset );
+}
+
+READ8_HANDLER( ppu2c0x_1_r )
+{
+ return ppu2c0x_r( 1, offset );
+}
+
+WRITE8_HANDLER( ppu2c0x_0_w )
+{
+ ppu2c0x_w( 0, offset, data );
+}
+
+WRITE8_HANDLER( ppu2c0x_1_w )
+{
+ ppu2c0x_w( 1, offset, data );
+}
diff --git a/src/mame/video/ppu2c0x.h b/src/mame/video/ppu2c0x.h
new file mode 100644
index 00000000000..4df8724abaf
--- /dev/null
+++ b/src/mame/video/ppu2c0x.h
@@ -0,0 +1,129 @@
+/******************************************************************************
+
+ Nintendo 2C0x PPU emulation.
+
+ Written by Ernesto Corvi.
+ This code is heavily based on Brad Oliver's MESS implementation.
+
+******************************************************************************/
+#ifndef __PPU_2C03B_H__
+#define __PPU_2C03B_H__
+
+/* increment to use more chips */
+#define MAX_PPU 2
+
+/* mirroring types */
+#define PPU_MIRROR_NONE 0
+#define PPU_MIRROR_VERT 1
+#define PPU_MIRROR_HORZ 2
+#define PPU_MIRROR_HIGH 3
+#define PPU_MIRROR_LOW 4
+#define PPU_MIRROR_4SCREEN 5 // Same effect as NONE, but signals that we should never mirror
+
+/* registers definition */
+enum
+{
+ PPU_CONTROL0 = 0,
+ PPU_CONTROL1,
+ PPU_STATUS,
+ PPU_SPRITE_ADDRESS,
+ PPU_SPRITE_DATA,
+ PPU_SCROLL,
+ PPU_ADDRESS,
+ PPU_DATA,
+ PPU_MAX_REG
+};
+
+/* bit definitions for (some of) the registers */
+enum
+{
+ PPU_CONTROL0_INC = 0x04,
+ PPU_CONTROL0_SPR_SELECT = 0x08,
+ PPU_CONTROL0_CHR_SELECT = 0x10,
+ PPU_CONTROL0_SPRITE_SIZE = 0x20,
+ PPU_CONTROL0_NMI = 0x80,
+
+ PPU_CONTROL1_DISPLAY_MONO = 0x01,
+ PPU_CONTROL1_BACKGROUND_L8 = 0x02,
+ PPU_CONTROL1_SPRITES_L8 = 0x04,
+ PPU_CONTROL1_BACKGROUND = 0x08,
+ PPU_CONTROL1_SPRITES = 0x10,
+ PPU_CONTROL1_COLOR_EMPHASIS = 0xe0,
+
+ PPU_STATUS_8SPRITES = 0x20,
+ PPU_STATUS_SPRITE0_HIT = 0x40,
+ PPU_STATUS_VBLANK = 0x80
+};
+
+enum
+{
+ PPU_NTSC_SCANLINES_PER_FRAME = 262,
+ PPU_PAL_SCANLINES_PER_FRAME = 312,
+
+ PPU_BOTTOM_VISIBLE_SCANLINE = 239,
+ PPU_VBLANK_FIRST_SCANLINE = 241,
+ PPU_VBLANK_LAST_SCANLINE_NTSC = 260,
+ PPU_VBLANK_LAST_SCANLINE_PAL = 310
+
+ // Both the sacnline immediately before and immediately after VBLANK
+ // are non-rendering and non-vblank.
+};
+
+typedef enum
+{
+ PPU_2C02, // NTSC NES
+ PPU_2C03B, // Playchoice 10
+ PPU_2C04, // Vs. Unisystem
+ PPU_2C05, // Vs. Unisystem, Famicom Titler
+ PPU_2C07 // PAL NES
+} ppu_t;
+
+/* callback datatypes */
+typedef void (*ppu2c0x_scanline_cb)( int num, int scanline, int vblank, int blanked );
+typedef void (*ppu2c0x_hblank_cb)( int num, int scanline, int vblank, int blanked );
+typedef void (*ppu2c0x_nmi_cb)( int num, int *ppu_regs );
+typedef int (*ppu2c0x_vidaccess_cb)( int num, int address, int data );
+
+typedef struct _ppu2c0x_interface ppu2c0x_interface;
+struct _ppu2c0x_interface
+{
+ ppu_t type; // model/version of the PPU
+ int num; /* number of chips ( 1 to MAX_PPU ) */
+ int vrom_region[MAX_PPU]; /* region id of gfx vrom (or REGION_INVALID if none) */
+ int gfx_layout_number[MAX_PPU]; /* gfx layout number used by each chip */
+ int color_base[MAX_PPU]; /* color base to use per ppu */
+ int mirroring[MAX_PPU]; /* mirroring options (PPU_MIRROR_* flag) */
+ ppu2c0x_nmi_cb nmi_handler[MAX_PPU]; /* NMI handler */
+};
+
+/* routines */
+void ppu2c0x_init_palette(running_machine *machine, int first_entry );
+void ppu2c0x_init(running_machine *machine, const ppu2c0x_interface *interface );
+
+void ppu2c0x_reset( int num, int scan_scale );
+void ppu2c0x_set_videorom_bank( int num, int start_page, int num_pages, int bank, int bank_size );
+void ppu2c0x_spriteram_dma(int num, const UINT8 page );
+void ppu2c0x_render( int num, mame_bitmap *bitmap, int flipx, int flipy, int sx, int sy );
+int ppu2c0x_get_pixel( int num, int x, int y );
+int ppu2c0x_get_colorbase( int num );
+int ppu2c0x_get_current_scanline( int num );
+void ppu2c0x_set_mirroring( int num, int mirroring );
+void ppu2c0x_set_scanline_callback( int num, ppu2c0x_scanline_cb cb );
+void ppu2c0x_set_hblank_callback( int num, ppu2c0x_scanline_cb cb );
+void ppu2c0x_set_vidaccess_callback( int num, ppu2c0x_vidaccess_cb cb );
+void ppu2c0x_set_scanlines_per_frame( int num, int scanlines );
+
+//27/12/2002
+extern void (*ppu_latch)( offs_t offset );
+
+void ppu2c0x_w( int num, offs_t offset, UINT8 data );
+int ppu2c0x_r( int num, offs_t offset );
+
+/* accesors */
+READ8_HANDLER( ppu2c0x_0_r );
+READ8_HANDLER( ppu2c0x_1_r );
+
+WRITE8_HANDLER( ppu2c0x_0_w );
+WRITE8_HANDLER( ppu2c0x_1_w );
+
+#endif /* __PPU_2C0X_H__ */
diff --git a/src/mame/video/prehisle.c b/src/mame/video/prehisle.c
new file mode 100644
index 00000000000..7984511d293
--- /dev/null
+++ b/src/mame/video/prehisle.c
@@ -0,0 +1,154 @@
+/***************************************************************************
+
+ Prehistoric Isle video routines
+
+ Emulation by Bryan McPhail, mish@tendril.co.uk
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT16 *prehisle_bg_videoram16;
+
+static UINT16 invert_controls;
+
+static tilemap *bg2_tilemap, *bg_tilemap, *fg_tilemap;
+
+
+WRITE16_HANDLER( prehisle_bg_videoram16_w )
+{
+ COMBINE_DATA(&prehisle_bg_videoram16[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE16_HANDLER( prehisle_fg_videoram16_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+READ16_HANDLER( prehisle_control16_r )
+{
+ switch (offset)
+ {
+ case 0x08: return readinputport(1); // Player 2
+ case 0x10: return readinputport(2); // Coins, Tilt, Service
+ case 0x20: return readinputport(0) ^ invert_controls; // Player 1
+ case 0x21: return readinputport(3); // DIPs
+ case 0x22: return readinputport(4); // DIPs + VBLANK
+ default: return 0;
+ }
+}
+
+WRITE16_HANDLER( prehisle_control16_w )
+{
+ int scroll = 0;
+
+ COMBINE_DATA(&scroll);
+
+ switch (offset)
+ {
+ case 0x00: tilemap_set_scrolly(bg_tilemap, 0, scroll); break;
+ case 0x08: tilemap_set_scrollx(bg_tilemap, 0, scroll); break;
+ case 0x10: tilemap_set_scrolly(bg2_tilemap, 0, scroll); break;
+ case 0x18: tilemap_set_scrollx(bg2_tilemap, 0, scroll); break;
+ case 0x23: invert_controls = data ? 0x00ff : 0x0000; break;
+ case 0x28: coin_counter_w(0, data & 1); break;
+ case 0x29: coin_counter_w(1, data & 1); break;
+ case 0x30: flip_screen_set(data & 0x01); break;
+ }
+}
+
+static TILE_GET_INFO( get_bg2_tile_info )
+{
+ UINT8 *tilerom = memory_region(REGION_GFX5);
+
+ int offs = tile_index * 2;
+ int attr = tilerom[offs + 1] + (tilerom[offs] << 8);
+ int code = (attr & 0x7ff) | 0x800;
+ int color = attr >> 12;
+ int flags = (attr & 0x800) ? TILE_FLIPX : 0;
+
+ SET_TILE_INFO(1, code, color, flags);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = prehisle_bg_videoram16[tile_index];
+ int code = attr & 0x7ff;
+ int color = attr >> 12;
+ int flags = (attr & 0x800) ? TILE_FLIPY : 0;
+
+ SET_TILE_INFO(2, code, color, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = videoram16[tile_index];
+ int code = attr & 0xfff;
+ int color = attr >> 12;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( prehisle )
+{
+ bg2_tilemap = tilemap_create(get_bg2_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 16, 16, 1024, 32);
+
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 16, 16, 256, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(bg_tilemap, 15);
+ tilemap_set_transparent_pen(fg_tilemap, 15);
+
+ /* register for saving */
+ state_save_register_global(invert_controls);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int foreground )
+{
+ int offs;
+
+ for (offs = 0; offs < 1024; offs += 4)
+ {
+ int attr = spriteram16[offs + 2];
+ int code = attr & 0x1fff;
+ int color = spriteram16[offs + 3] >> 12;
+ int priority = (color < 0x4);
+ int flipx = attr & 0x4000;
+ int flipy = attr & 0x8000;
+ int sx = spriteram16[offs + 1];
+ int sy = spriteram16[offs];
+
+ if (sx & 0x200) sx = -(0xff - (sx & 0xff)); // wraparound
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if ((foreground && priority) || (!foreground && !priority))
+ {
+ drawgfx(bitmap, machine->gfx[3], code, color, flipx, flipy, sx, sy,
+ cliprect, TRANSPARENCY_PEN, 15);
+ }
+ }
+}
+
+VIDEO_UPDATE( prehisle )
+{
+ tilemap_draw(bitmap, cliprect, bg2_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect, 0);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect, 1);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/psikyo.c b/src/mame/video/psikyo.c
new file mode 100644
index 00000000000..650585760b5
--- /dev/null
+++ b/src/mame/video/psikyo.c
@@ -0,0 +1,599 @@
+/***************************************************************************
+
+ -= Psikyo Games =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z with:
+
+ Q shows layer 0
+ W shows layer 1
+ A shows the sprites
+
+ Keys can be used together!
+
+
+ [ 2 Scrolling Layers ]
+
+ - Dynamic Size
+ - Line Scroll
+
+ Layer Sizes: 512 x 2048 ( $20 x $80 tiles)
+ 1024 x 1048 ( $40 x $40 tiles)
+ 2048 x 512 ( $80 x $20 tiles)
+ 4096 x 256 ($100 x $10 tiles)
+
+ Tengai uses all four above
+
+ Tiles: 16x16x4
+ Color Codes: 8
+
+
+ [ ~ $300 Multi-Tile Sprites With Zoom ]
+
+
+ Each sprite is made of 16x16 tiles, up to 8x8 tiles.
+
+ There are $300 sprites, followed by a list of the indexes
+ of the sprites to actually display ($400 max). The list is
+ terminated by the special index value FFFF.
+
+ The tile code specified for a sprite is actually fed to a
+ ROM holding a look-up table with the real tile code to display.
+
+ Sprites can be shrinked up to ~50% following a linear curve of
+ sizes.
+
+
+ Since the tilemaps can change size its safest to allocate all
+ the possible sizes at startup, as opposed to during the emulation
+
+ By doing it this way theres no chance of a memory allocation
+ failing during gameplay and crashing MAME
+
+**************************************************************************/
+
+#include "driver.h"
+
+/* Variables that driver has access to: */
+
+UINT32 *psikyo_vram_0, *psikyo_vram_1, *psikyo_vregs;
+int psikyo_ka302c_banking;
+
+/* Variables only used here: */
+
+static tilemap *tilemap_0_size0, *tilemap_0_size1, *tilemap_0_size2, *tilemap_0_size3,
+ *tilemap_1_size0, *tilemap_1_size1, *tilemap_1_size2, *tilemap_1_size3;
+static UINT8 tilemap_0_bank, tilemap_1_bank;
+static UINT32 *spritebuf1, *spritebuf2;
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+ [ Tiles Format ]
+
+Offset:
+
+0000.w fed- ---- ---- ---- Color
+ ---c ba98 7654 3210 Code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info_0 )
+{
+ UINT16 code = ((UINT16 *)psikyo_vram_0)[BYTE_XOR_BE(tile_index)];
+ SET_TILE_INFO(
+ 1,
+ (code & 0x1fff) + 0x2000*tilemap_0_bank,
+ (code >> 13) & 7,
+ 0);
+}
+
+static TILE_GET_INFO( get_tile_info_1 )
+{
+ UINT16 code = ((UINT16 *)psikyo_vram_1)[BYTE_XOR_BE(tile_index)];
+ SET_TILE_INFO(
+ 1,
+ (code & 0x1fff) + 0x2000*tilemap_1_bank,
+ ((code >> 13) & 7) + 0x40, // So we only have to decode the gfx once.
+ 0);
+}
+
+
+WRITE32_HANDLER( psikyo_vram_0_w )
+{
+ COMBINE_DATA(&psikyo_vram_0[offset]);
+ if (ACCESSING_MSW32)
+ {
+ tilemap_mark_tile_dirty(tilemap_0_size0, offset*2);
+ tilemap_mark_tile_dirty(tilemap_0_size1, offset*2);
+ tilemap_mark_tile_dirty(tilemap_0_size2, offset*2);
+ tilemap_mark_tile_dirty(tilemap_0_size3, offset*2);
+ }
+
+ if (ACCESSING_LSW32)
+ {
+ tilemap_mark_tile_dirty(tilemap_0_size0, offset*2+1);
+ tilemap_mark_tile_dirty(tilemap_0_size1, offset*2+1);
+ tilemap_mark_tile_dirty(tilemap_0_size2, offset*2+1);
+ tilemap_mark_tile_dirty(tilemap_0_size3, offset*2+1);
+ }
+}
+
+WRITE32_HANDLER( psikyo_vram_1_w )
+{
+ COMBINE_DATA(&psikyo_vram_1[offset]);
+ if (ACCESSING_MSW32)
+ {
+ tilemap_mark_tile_dirty(tilemap_1_size0, offset*2);
+ tilemap_mark_tile_dirty(tilemap_1_size1, offset*2);
+ tilemap_mark_tile_dirty(tilemap_1_size2, offset*2);
+ tilemap_mark_tile_dirty(tilemap_1_size3, offset*2);
+ }
+
+ if (ACCESSING_LSW32)
+ {
+ tilemap_mark_tile_dirty(tilemap_1_size0, offset*2+1);
+ tilemap_mark_tile_dirty(tilemap_1_size1, offset*2+1);
+ tilemap_mark_tile_dirty(tilemap_1_size2, offset*2+1);
+ tilemap_mark_tile_dirty(tilemap_1_size3, offset*2+1);
+ }
+}
+
+void psikyo_switch_banks( int tmap, int bank )
+{
+ if((tmap==0) && (bank != tilemap_0_bank))
+ {
+ tilemap_0_bank = bank;
+ tilemap_mark_all_tiles_dirty(tilemap_0_size0);
+ tilemap_mark_all_tiles_dirty(tilemap_0_size1);
+ tilemap_mark_all_tiles_dirty(tilemap_0_size2);
+ tilemap_mark_all_tiles_dirty(tilemap_0_size3);
+ }
+ else if((tmap==1) && (bank != tilemap_1_bank))
+ {
+ tilemap_1_bank = bank;
+ tilemap_mark_all_tiles_dirty(tilemap_1_size0);
+ tilemap_mark_all_tiles_dirty(tilemap_1_size1);
+ tilemap_mark_all_tiles_dirty(tilemap_1_size2);
+ tilemap_mark_all_tiles_dirty(tilemap_1_size3);
+ }
+}
+
+
+VIDEO_START( psikyo )
+{
+ /* The Hardware is Capable of Changing the Dimensions of the Tilemaps, its safer to create
+ the various sized tilemaps now as opposed to later */
+
+ tilemap_0_size0 = tilemap_create( get_tile_info_0,
+ tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ 0x20, 0x80 );
+ tilemap_0_size1 = tilemap_create( get_tile_info_0,
+ tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ 0x40, 0x40 );
+
+ tilemap_0_size2 = tilemap_create( get_tile_info_0,
+ tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ 0x80, 0x20 );
+
+ tilemap_0_size3 = tilemap_create( get_tile_info_0,
+ tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ 0x100, 0x10 );
+
+ tilemap_1_size0 = tilemap_create( get_tile_info_1,
+ tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ 0x20, 0x80 );
+
+ tilemap_1_size1 = tilemap_create( get_tile_info_1,
+ tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ 0x40, 0x40 );
+
+ tilemap_1_size2 = tilemap_create( get_tile_info_1,
+ tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ 0x80, 0x20 );
+
+ tilemap_1_size3 = tilemap_create( get_tile_info_1,
+ tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ 0x100, 0x10 );
+
+ spritebuf1 = auto_malloc(0x2000);
+ spritebuf2 = auto_malloc(0x2000);
+
+ tilemap_set_scroll_rows(tilemap_0_size0,0x80*16); // line scrolling
+ tilemap_set_scroll_cols(tilemap_0_size0,1);
+
+ tilemap_set_scroll_rows(tilemap_0_size1,0x40*16); // line scrolling
+ tilemap_set_scroll_cols(tilemap_0_size1,1);
+
+ tilemap_set_scroll_rows(tilemap_0_size2,0x20*16); // line scrolling
+ tilemap_set_scroll_cols(tilemap_0_size2,1);
+
+ tilemap_set_scroll_rows(tilemap_0_size3,0x10*16); // line scrolling
+ tilemap_set_scroll_cols(tilemap_0_size3,1);
+
+ tilemap_set_scroll_rows(tilemap_1_size0,0x80*16); // line scrolling
+ tilemap_set_scroll_cols(tilemap_1_size0,1);
+
+ tilemap_set_scroll_rows(tilemap_1_size1,0x40*16); // line scrolling
+ tilemap_set_scroll_cols(tilemap_1_size1,1);
+
+ tilemap_set_scroll_rows(tilemap_1_size2,0x20*16); // line scrolling
+ tilemap_set_scroll_cols(tilemap_1_size2,1);
+
+ tilemap_set_scroll_rows(tilemap_1_size3,0x10*16); // line scrolling
+ tilemap_set_scroll_cols(tilemap_1_size3,1);
+}
+
+
+
+/***************************************************************************
+
+ Sprites Drawing
+
+Offset: Value:
+
+0000/2.w Y/X + Y/X Size
+
+ fedc ---- ---- ---- Zoom Y/X ???
+ ---- ba9- ---- ---- Tiles along Y/X
+ ---- ---8 7654 3210 Position
+
+
+0004.w Color + Flags
+
+ f--- ---- ---- ---- Flip Y
+ -e-- ---- ---- ---- Flip X
+ --d- ---- ---- ---- ? USED
+ ---c ba98 ---- ---- Color
+ ---- ---- 76-- ---- Priority
+ ---- ---- --54 321- -
+ ---- ---- ---- ---0 Code High Bit
+
+
+0006.w Code Low Bits
+
+ (Code goes into a LUT in ROM where
+ the real tile code is.)
+
+
+Note: Not all sprites are displayed: in the top part of spriteram
+ (e.g. 401800-401fff) there's the list of sprites indexes to
+ actually display, terminated by FFFF.
+
+ The last entry (e.g. 401ffe) is special and holds some flags:
+
+ fedc ba98 7654 ----
+ ---- ---- ---- 32-- Transparent Pen select? 10 for 0xf, 01 for 0x0.
+ ---- ---- ---- --1-
+ ---- ---- ---- ---0 Sprites Disable
+
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int trans_pen)
+{
+ /* tile layers 0 & 1 have priorities 1 & 2 */
+ static const int pri[] = { 0, 0xfc, 0xff, 0xff };
+
+ int offs;
+
+ UINT16 *spritelist = (UINT16 *)(spritebuf2 + 0x1800/4);
+
+ UINT8 *TILES = memory_region(REGION_USER1); // Sprites LUT
+ int TILES_LEN = memory_region_length(REGION_USER1);
+
+ int width = machine->screen[0].width;
+ int height = machine->screen[0].height;
+
+ /* Exit if sprites are disabled */
+ if ( spritelist[ BYTE_XOR_BE((0x800-2)/2) ] & 1 ) return;
+
+ /* Look for "end of sprites" marker in the sprites list */
+ for ( offs = 0/2 ; offs < (0x800-2)/2 ; offs += 2/2 ) // skip last "sprite"
+ {
+ UINT16 sprite = spritelist[ BYTE_XOR_BE(offs) ];
+ if (sprite == 0xffff) break;
+ }
+ offs -= 2/2;
+
+ // fprintf(stderr, "\n");
+ for ( ; offs >= 0/2 ; offs -= 2/2 )
+ {
+ UINT32 *source;
+ int sprite;
+
+ int x,y, attr,code, flipx,flipy, nx,ny, zoomx,zoomy;
+ int dx,dy, xstart,ystart, xend,yend, xinc,yinc;
+
+ /* Get next entry in the list */
+ sprite = spritelist[ BYTE_XOR_BE(offs) ];
+
+ sprite %= 0x300;
+ source = &spritebuf2[ sprite*8/4 ];
+
+ /* Draw this sprite */
+
+ y = source[ 0/4 ] >> 16;
+ x = source[ 0/4 ] & 0xffff;
+ attr = source[ 4/4 ] >> 16;
+ code = source[ 4/4 ] & 0x1ffff;
+
+ flipx = attr & 0x4000;
+ flipy = attr & 0x8000;
+
+ zoomx = ((x & 0xf000) >> 12);
+ zoomy = ((y & 0xf000) >> 12);
+ nx = ((x & 0x0e00) >> 9) + 1;
+ ny = ((y & 0x0e00) >> 9) + 1;
+ x = ((x & 0x01ff));
+ y = ((y & 0x00ff)) - (y & 0x100);
+
+ /* 180-1ff are negative coordinates. Note that $80 pixels is
+ the maximum extent of a sprite, which can therefore be moved
+ out of screen without problems */
+ if (x >= 0x180) x -= 0x200;
+
+ x += (nx*zoomx+2)/4;
+ y += (ny*zoomy+2)/4;
+
+ zoomx = 32 - zoomx;
+ zoomy = 32 - zoomy;
+
+
+ if (flip_screen)
+ {
+ x = width - x - (nx * zoomx)/2;
+ y = height - y - (ny * zoomy)/2;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if (flipx) { xstart = nx-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = nx; xinc = +1; }
+
+ if (flipy) { ystart = ny-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = ny; yinc = +1; }
+
+ for (dy = ystart; dy != yend; dy += yinc)
+ {
+ for (dx = xstart; dx != xend; dx += xinc)
+ {
+ int addr = (code*2) & (TILES_LEN-1);
+
+ if (zoomx == 32 && zoomy == 32)
+ pdrawgfx(bitmap,machine->gfx[0],
+ TILES[addr+1] * 256 + TILES[addr],
+ attr >> 8,
+ flipx, flipy,
+ x + dx * 16, y + dy * 16,
+ cliprect,TRANSPARENCY_PEN,trans_pen,
+ pri[(attr & 0xc0) >> 6]);
+ else
+ pdrawgfxzoom(bitmap,machine->gfx[0],
+ TILES[addr+1] * 256 + TILES[addr],
+ attr >> 8,
+ flipx, flipy,
+ x + (dx * zoomx) / 2, y + (dy * zoomy) / 2,
+ cliprect,TRANSPARENCY_PEN,trans_pen,
+ zoomx << 11,zoomy << 11,
+ pri[(attr & 0xc0) >> 6]);
+
+ code++;
+ }
+ }
+ }
+}
+
+
+
+
+/***************************************************************************
+
+ Screen Drawing
+
+***************************************************************************/
+
+static int tilemap_width( int size )
+{
+ if(size==0) return 0x80*16;
+ else if(size==1) return 0x40*16;
+ else if(size==2) return 0x20*16;
+ else return 0x10*16;
+}
+
+VIDEO_UPDATE( psikyo )
+{
+ int i, layers_ctrl = -1;
+
+ UINT32 tm0size, tm1size;
+
+ UINT32 layer0_scrollx, layer0_scrolly;
+ UINT32 layer1_scrollx, layer1_scrolly;
+ UINT32 layer0_ctrl = psikyo_vregs[ 0x412/4 ];
+ UINT32 layer1_ctrl = psikyo_vregs[ 0x416/4 ];
+ UINT32 spr_ctrl = spritebuf2[ 0x1ffe/4 ];
+
+ tilemap *tmptilemap0, *tmptilemap1;
+
+ flip_screen_set(~readinputport(2) & 1); // hardwired to a DSW bit
+
+ /* Layers enable (not quite right) */
+
+ /* bit 0 : layer enable
+ 1 : opaque tiles (used in Gunbird attract mode)
+ 2 : ?
+ 3 : transparent colour (0 or 15)
+ 4- 5: ?
+ 6- 7: tilemap size
+ 8 : per-line rowscroll
+ 9 : per-tile rowscroll
+ 10 : tilebank (btlkroad/gunbird/s1945jn only)
+ 11-15: ? */
+
+/*
+ gunbird: L:00d0-04d0 S:0008 (00e1 04e1 0009 or 00e2 04e2 000a, for a blink, on scene transitions)
+ sngkace: L:00d0-00d0 S:0008 (00d1 00d1 0009, for a blink, on scene transitions)
+ s1945: L:00d0-04d0 S:0008
+ btlkrodj: L:0120-0510 S:0008 (0121 0511 0009, for a blink, on scene transitions)
+ tengai: L:0178-0508 S:0004 <-- Transpen is 0 as opposed to 15.
+
+ tengai:
+ L:01f8-05c8, 1 needs size 0, 2 needs size 0 Title
+ L:00f8-05c8, 1 needs size 0, 2 needs size 0 No RowScroll on layer 0
+ L:01b8-05c8, 1 needs size 3, 2 needs size 0
+ L:0178-0508, 1 needs size ?, 2 needs size 1 Psikyo logo
+ L:0178-0508, 1 needs size 2, 2 needs size 1 Intro
+ L:0178-0548, 1 needs size 2, 2 needs size ? Test
+ L:0178-0588, 2 needs size 3 More Intro
+*/
+
+ /* For gfx banking for s1945jn/gunbird/btlkroad */
+ if(psikyo_ka302c_banking)
+ {
+ psikyo_switch_banks(0, (layer0_ctrl&0x400)>>10);
+ psikyo_switch_banks(1, (layer1_ctrl&0x400)>>10);
+ }
+
+ switch((layer0_ctrl & 0x00c0)>>6) {
+ case 0:
+ tm0size=1;
+ break;
+ case 1:
+ tm0size=2;
+ break;
+ case 2:
+ tm0size=3;
+ break;
+ default:
+ tm0size=0;
+ break;
+ }
+
+ switch((layer1_ctrl & 0x00c0)>>6) {
+ case 0:
+ tm1size=1;
+ break;
+ case 1:
+ tm1size=2;
+ break;
+ case 2:
+ tm1size=3;
+ break;
+ default:
+ tm1size=0;
+ break;
+ }
+
+ if(tm0size==0) tmptilemap0 = tilemap_0_size0;
+ else if (tm0size==1) tmptilemap0 = tilemap_0_size1;
+ else if (tm0size==2) tmptilemap0 = tilemap_0_size2;
+ else tmptilemap0 = tilemap_0_size3;
+
+ if(tm1size==0) tmptilemap1 = tilemap_1_size0;
+ else if (tm1size==1) tmptilemap1 = tilemap_1_size1;
+ else if (tm1size==2) tmptilemap1 = tilemap_1_size2;
+ else tmptilemap1 = tilemap_1_size3;
+
+ tilemap_set_enable(tmptilemap0, ~layer0_ctrl & 1);
+
+ tilemap_set_enable(tmptilemap1, ~layer1_ctrl & 1);
+
+ /* Layers scrolling */
+
+ layer0_scrolly = psikyo_vregs[ 0x402/4 ];
+ layer0_scrollx = psikyo_vregs[ 0x406/4 ];
+ layer1_scrolly = psikyo_vregs[ 0x40a/4 ];
+ layer1_scrollx = psikyo_vregs[ 0x40e/4 ];
+
+ tilemap_set_scrolly(tmptilemap0, 0, layer0_scrolly );
+
+ tilemap_set_scrolly(tmptilemap1, 0, layer1_scrolly );
+
+ for (i=0; i<256; i++) /* 256 screen lines */
+ {
+ int x0 = 0, x1 = 0;
+
+ /* layer 0 */
+ if (layer0_ctrl & 0x0300)
+ {
+ if (layer0_ctrl & 0x0200)
+ /* per-tile rowscroll */
+ x0 = ((UINT16 *)psikyo_vregs)[BYTE_XOR_BE(0x000/2 + i/16)];
+ else
+ /* per-line rowscroll */
+ x0 = ((UINT16 *)psikyo_vregs)[BYTE_XOR_BE(0x000/2 + i)];
+ }
+
+ tilemap_set_scrollx(
+ tmptilemap0,
+ (i+layer0_scrolly) % tilemap_width(tm0size),
+ layer0_scrollx + x0 );
+
+
+ /* layer 1 */
+ if (layer1_ctrl & 0x0300)
+ {
+ if (layer1_ctrl & 0x0200)
+ /* per-tile rowscroll */
+ x1 = ((UINT16 *)psikyo_vregs)[BYTE_XOR_BE(0x200/2 + i/16)];
+ else
+ /* per-line rowscroll */
+ x1 = ((UINT16 *)psikyo_vregs)[BYTE_XOR_BE(0x200/2 + i)];
+ }
+
+ tilemap_set_scrollx(
+ tmptilemap1,
+ (i+layer1_scrolly) % tilemap_width(tm1size),
+ layer1_scrollx + x1 );
+ }
+
+ tilemap_set_transparent_pen(tilemap_0_size0,(layer0_ctrl & 8 ?0:15));
+ tilemap_set_transparent_pen(tilemap_0_size1,(layer0_ctrl & 8 ?0:15));
+ tilemap_set_transparent_pen(tilemap_0_size2,(layer0_ctrl & 8 ?0:15));
+ tilemap_set_transparent_pen(tilemap_0_size3,(layer0_ctrl & 8 ?0:15));
+
+ tilemap_set_transparent_pen(tilemap_1_size0,(layer1_ctrl & 8 ?0:15));
+ tilemap_set_transparent_pen(tilemap_1_size1,(layer1_ctrl & 8 ?0:15));
+ tilemap_set_transparent_pen(tilemap_1_size2,(layer1_ctrl & 8 ?0:15));
+ tilemap_set_transparent_pen(tilemap_1_size3,(layer1_ctrl & 8 ?0:15));
+
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ if (layers_ctrl & 1)
+ tilemap_draw(bitmap,cliprect,tmptilemap0, layer0_ctrl & 2 ? TILEMAP_DRAW_OPAQUE : 0, 1);
+
+ if (layers_ctrl & 2)
+ tilemap_draw(bitmap,cliprect,tmptilemap1, layer1_ctrl & 2 ? TILEMAP_DRAW_OPAQUE : 0, 2);
+
+ if (layers_ctrl & 4)
+ draw_sprites(machine, bitmap,cliprect,(spr_ctrl & 4 ? 0 : 15));
+
+ return 0;
+}
+
+VIDEO_EOF( psikyo )
+{
+ memcpy(spritebuf2, spritebuf1, 0x2000);
+ memcpy(spritebuf1, spriteram32, 0x2000);
+}
diff --git a/src/mame/video/psikyo4.c b/src/mame/video/psikyo4.c
new file mode 100644
index 00000000000..139a945aa0e
--- /dev/null
+++ b/src/mame/video/psikyo4.c
@@ -0,0 +1,144 @@
+/*
+
+Psikyo PS6807 (PS4):
+See src/drivers/psikyo4.c for more info
+
+Each sprite has a flag denoting the screen to which it should be drawn.
+
+*/
+
+/*
+Vid Regs:
+
+0x3003fe4 -- ??xx???? vblank? 86??0000 always?
+0x3003fe8 -- c0c0???? flipscreen for screen 1 and 2 resp.
+ ????8080 Screen size select
+0x3003fec -- a0000xxx always? is in two working games. 0x00000fff is bank select for gfx test
+0x3003ff0 -- 000000ff brightness for screen 1, ffffff00 are probably seperate rgb brightness (not used)
+0x3003ff4 -- ffffff00 screen 1 clear colour
+0x3003ff8 -- 000000ff brightness for screen 2, ffffff00 are probably seperate rgb brightness (not used)
+0x3003ffc -- ffffff00 screen 2 clear colour
+
+HotDebut: 86010000 00009998 80000000 Small Screen
+LodeRnDF: 86010000 00009998 a0000000 Small Screen
+
+HotGmck: 86010000 1f201918 a0000000 Large Screen
+HgKairak: 86010000 1f201918 a0000000 Large Screen
+*/
+
+#include "driver.h"
+
+/* defined in drivers/psikyo4.c */
+extern UINT32 *psikyo4_vidregs;
+
+/* --- SPRITES --- */
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT32 scr )
+{
+ /*- Sprite Format 0x0000 - 0x2bff -**
+
+ 0 hhhh --yy yyyy yyyy | wwww --xx xxxx xxxx 1 Ffpp pppp ---- -nnn | nnnn nnnn nnnn nnnn
+
+ y = ypos
+ x = xpos
+
+ h = height
+ w = width
+
+ f = flip (x)
+ F = flip (y) Unused?
+
+ n = tile number
+
+ p = palette
+
+ **- End Sprite Format -*/
+
+ const gfx_element *gfx = machine->gfx[0];
+ UINT32 *source = spriteram32;
+ UINT16 *list = (UINT16 *)spriteram32 + 0x2c00/2 + 0x04/2; /* 0x2c00/0x2c02 what are these for, pointers? one for each screen */
+ UINT16 listlen=(0xc00/2 - 0x04/2), listcntr=0;
+ int flipscreen1, flipscreen2;
+
+ flipscreen1 = (((psikyo4_vidregs[1]>>30)&2) == 2) ? 1 : 0;
+ flipscreen2 = (((psikyo4_vidregs[1]>>22)&2) == 2) ? 1 : 0;
+
+ while( listcntr < listlen )
+ {
+ UINT16 listdat, sprnum, thisscreen;
+
+ listdat = list[BYTE_XOR_BE(listcntr)];
+ sprnum = (listdat & 0x03ff) * 2;
+
+ thisscreen = 0;
+ if ((listdat & 0x2000) == scr) thisscreen = 1;
+
+ /* start drawing */
+ if (!(listdat & 0x8000) && thisscreen) /* draw only selected screen */
+ {
+ int loopnum=0, i, j;
+ UINT32 xpos, ypos, tnum, wide, high, colr, flipx, flipy;
+ int xstart, ystart, xend, yend, xinc, yinc;
+
+ ypos = (source[sprnum+0] & 0x03ff0000) >> 16;
+ xpos = (source[sprnum+0] & 0x000003ff) >> 00;
+
+ high = ((source[sprnum+0] & 0xf0000000) >> (12+16)) + 1;
+ wide = ((source[sprnum+0] & 0x0000f000) >> 12) + 1;
+
+ tnum = (source[sprnum+1] & 0x0007ffff) >> 00;
+
+ colr = (source[sprnum+1] & 0x3f000000) >> 24;
+ if(scr) colr += 0x40; /* Use second copy of palette which is dimmed appropriately */
+
+ flipx = (source[sprnum+1] & 0x40000000);
+ flipy = (source[sprnum+1] & 0x80000000); /* Guess */
+
+ if(ypos & 0x200) ypos -= 0x400;
+ if(xpos & 0x200) xpos -= 0x400;
+
+ if((!scr && flipscreen1) || (scr && flipscreen2))
+ {
+ ypos = machine->screen[0].visarea.max_y+1 - ypos - high*16; /* Screen Height depends on game */
+ xpos = 40*8 - xpos - wide*16;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if (flipx) { xstart = wide-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = wide; xinc = +1; }
+
+ if (flipy) { ystart = high-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = high; yinc = +1; }
+
+ for (j = ystart; j != yend; j += yinc) {
+ for (i = xstart; i != xend; i += xinc) {
+ drawgfx(bitmap,gfx,tnum+loopnum,colr,flipx,flipy,xpos+16*i,ypos+16*j,cliprect,TRANSPARENCY_PEN,0);
+ loopnum++;
+ }
+ }
+ }
+ /* end drawing */
+ listcntr++;
+ if (listdat & 0x4000) break;
+ }
+}
+
+VIDEO_UPDATE( psikyo4 )
+{
+ if (screen==0)
+ {
+ fillbitmap(bitmap, machine->pens[0x1000], cliprect);
+ draw_sprites(machine, bitmap, cliprect, 0x0000);
+ }
+ else if (screen==1)
+ {
+ fillbitmap(bitmap, machine->pens[0x1001], cliprect);
+ draw_sprites(machine, bitmap, cliprect, 0x2000);
+ }
+ return 0;
+}
+
+VIDEO_START( psikyo4 )
+{
+ machine->gfx[0]->color_granularity=32; /* 256 colour sprites with palette selectable on 32 colour boundaries */
+}
diff --git a/src/mame/video/psikyosh.c b/src/mame/video/psikyosh.c
new file mode 100644
index 00000000000..cde52334007
--- /dev/null
+++ b/src/mame/video/psikyosh.c
@@ -0,0 +1,1158 @@
+/*
+
+Psikyo PS6406B (PS3v1/PS5/PS5v2):
+See src/drivers/psikyosh.c for more info
+
+Hardware is extremely flexible (and luckily underused :)
+
+3 Types of tilemaps:
+1. Normal
+Used everywhere (Types 0x0a and 0x0b where 0x0b uses alternate registers to control scroll/bank/alpha/columnzoom)
+
+2. Seems to be two interleaved layers in each
+Used for text layers in daraku (Type 0x0c and 0x0d)
+
+3. Has 224 values for rowscroll (And implicit zoom?)/columnscroll/rowzoom/per-row priority/per-row alpha/per-row bank
+Used in S1945II test+level 7 and S1945III levels 7+8
+(i.e instead of using 0x13f0+0x17f0 registers it uses a block as indicated by the type)
+
+There are 32 data banks of 0x800 bytes starting at 0x3000000
+The first 8 are continuous and used for sprites.
+
+Bank Offset Purpose
+0 0000 Sprites
+1 8000 "
+2 1000 "
+3 1800 "
+4 2000 "
+5 2800 "
+6 3000 "
+7 3800 Sprite List
+---
+8 4000 Pre Lineblend (0x000, 224 values) and Post Lineblend (0x400, 224 values)
+9 4800 Unknown
+a 5000 Tilemap XScroll/YScroll
+b 5800 Tilemap Priority/Zoom/AlphaBlending/Bank
+
+c 6000 General Purpose banks for either tilemaps (can optionally use two consecutive banks)
+ Or To contain RowScroll/ColumnScroll (0x000, 224 values) followed by Priority/Zoom/AlphaBlending/Bank (0x400, 224 values)
+...
+1f f800 "
+*/
+
+/*
+BG Scroll/Priority/Zoom/Alpha/Tilebank:
+Either at 0x30053f0/4/8 (For 0a/0c/0d), 0x3005bf0/4/8 (For 0b) Or per-line in a bank (For 0e-1f)
+ 0x?vvv?xxx - v = vertical scroll - x = x scroll
+Either at 0x30057f0/4/8 (For 0a/0c/0d), 0x3005ff0/4/8 (For 0b) Or per-line in a bank (For 0e-1f)
+ 0xppzzaabb - p = priority, z = zoom/expand(00 is none), a = alpha value/effect, b = tilebank (used when register below = 0x0a)
+
+
+Vid Regs:
+
+0x00 -- alpha values for sprites. sbomberb = 0000 3830
+0x04 -- " " " " sbomberb = 2820 1810.
+
+0x08 -- 0xff00 priority values for sprites, 4-bits per value, c0 is vert game (Controls whether row/line effects?), 0x000f is priority for per-line post-blending
+
+0x0c -- ????c0?? -c0 is flip screen
+0x10 -- 00aa2000? always? -gb2 tested- 00000fff Controls gfx data available to be read by SH-2 for verification
+0x14 -- 83ff000e? always? -gb2 tested-
+0x18 -- double buffer/mode for tilemaps. As follows for the different tilemaps: 112233--
+ 0a = normal 0b = alt buffer
+ 0c/0d are used by daraku for text layers. same as above except bank is still controlled by registers and seems to contain two 16x16 timemaps with alternate columns from each.
+ 0e-1f indicates layer uses row and/or line scroll. values come from associated bank, tiles from 2 below i.e bank c-1d
+ Bit 0x80 indicates use of line effects.
+0x1c -- ????123- enable bits 8 is enable. 4 indicates 8bpp tiles. 1 is size select for tilemap
+*/
+
+/*
+TODO:
+
+pre and post line-blending hooked-up, is there a toggle for row/column? Does the pre actually have a configurable priority like the post?
+
+row scroll+zoom / column scroll+zoom (s1945ii test, level 7 and s1945iii use a whole block of ram for scrolling/zooming, -dh
+(224 values for both x and y scroll + zoom) Also used for daraku text layers, again only yscroll differ
+Also, xscroll values are always the same, maybe the hw can't do simultaneous line/columnscroll. -pjp
+
+figure out how the daraku text layers work correctly, dimensions are different (even more tilemaps needed)
+daraku seems to use tilemaps only for text layer (hi-scores, insert coin, warning message, test mode, psikyo (c)) how this is used is uncertain,
+
+flip screen, located but not implemented. wait until tilemaps.
+
+the stuff might be converted to use the tilemaps once all the features is worked out ...
+complicated by the fact that the whole tilemap will have to be marked dirty each time the bank changes (this can happen once per frame, unless a tilemap is allocated for each bank.
+18 + 9 = 27 tilemaps (including both sizes, possibly another 8 if the large tilemaps can start on odd banks).
+Would also need to support TRANSPARENCY_ALPHARANGE
+
+sol divide doesn't seem to make much use of tilemaps at all, it uses them to fade between scenes in the intro
+
+*/
+
+#include "driver.h"
+#include "profiler.h"
+#include "psikyosh.h"
+
+/* Needed for psikyosh_drawgfxzoom */
+static mame_bitmap *zoom_bitmap, *z_bitmap;
+
+/* Psikyo PS6406B */
+/* --- BACKGROUNDS --- */
+
+/* 'Normal' layers, no line/columnscroll. No per-line effects */
+static void draw_bglayer(running_machine *machine, int layer, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ gfx_element *gfx;
+ int offs=0, sx, sy;
+ int scrollx, scrolly, bank, alpha, alphamap, trans, size, width;
+
+ if ( BG_TYPE(layer) == BG_NORMAL_ALT )
+ {
+ bank = (psikyosh_bgram[0x1ff0/4 + (layer*0x04)/4] & 0x000000ff) >> 0;
+ alpha = (psikyosh_bgram[0x1ff0/4 + (layer*0x04)/4] & 0x00003f00) >> 8;
+ alphamap =(psikyosh_bgram[0x1ff0/4 + (layer*0x04)/4] & 0x00008000) >> 15;
+ scrollx = (psikyosh_bgram[0x1bf0/4 + (layer*0x04)/4] & 0x000001ff) >> 0;
+ scrolly = (psikyosh_bgram[0x1bf0/4 + (layer*0x04)/4] & 0x03ff0000) >> 16;
+ }
+ else /* BG_NORMAL */
+ {
+ bank = (psikyosh_bgram[0x17f0/4 + (layer*0x04)/4] & 0x000000ff) >> 0;
+ alpha = (psikyosh_bgram[0x17f0/4 + (layer*0x04)/4] & 0x00003f00) >> 8;
+ alphamap =(psikyosh_bgram[0x17f0/4 + (layer*0x04)/4] & 0x00008000) >> 15;
+ scrollx = (psikyosh_bgram[0x13f0/4 + (layer*0x04)/4] & 0x000001ff) >> 0;
+ scrolly = (psikyosh_bgram[0x13f0/4 + (layer*0x04)/4] & 0x03ff0000) >> 16;
+ }
+
+ if ( BG_TYPE(layer) == BG_SCROLL_0D ) scrollx += 0x08; /* quick kludge until using rowscroll */
+
+ gfx = BG_DEPTH_8BPP(layer) ? machine->gfx[1] : machine->gfx[0];
+ size = BG_LARGE(layer) ? 32 : 16;
+ width = BG_LARGE(layer) ? 0x200 : 0x100;
+
+ if(alphamap) { /* alpha values are per-pen */
+ trans = TRANSPARENCY_ALPHARANGE;
+ } else if(alpha) {
+ trans = TRANSPARENCY_ALPHA;
+ alpha = ((0x3f-alpha)*0xff)/0x3f; /* 0x3f-0x00 maps to 0x00-0xff */
+ alpha_set_level(alpha);
+ } else {
+ trans = TRANSPARENCY_PEN;
+ }
+
+ if((bank>=0x0c) && (bank<=0x1f)) /* shouldn't happen, 20 banks of 0x800 bytes */
+ {
+ for (sy=0; sy<size; sy++)
+ {
+ for (sx=0; sx<32; sx++)
+ {
+ int tileno, colour;
+
+ tileno = (psikyosh_bgram[(bank*0x800)/4 + offs - 0x4000/4] & 0x0007ffff); /* seems to take into account spriteram, hence -0x4000 */
+ colour = (psikyosh_bgram[(bank*0x800)/4 + offs - 0x4000/4] & 0xff000000) >> 24;
+
+ drawgfx(bitmap,gfx,tileno,colour,0,0,(16*sx+scrollx)&0x1ff,((16*sy+scrolly)&(width-1)),cliprect,trans,0); /* normal */
+ if(scrollx)
+ drawgfx(bitmap,gfx,tileno,colour,0,0,((16*sx+scrollx)&0x1ff)-0x200,((16*sy+scrolly)&(width-1)),cliprect,trans,0); /* wrap x */
+ if(scrolly)
+ drawgfx(bitmap,gfx,tileno,colour,0,0,(16*sx+scrollx)&0x1ff,((16*sy+scrolly)&(width-1))-width,cliprect,trans,0); /* wrap y */
+ if(scrollx && scrolly)
+ drawgfx(bitmap,gfx,tileno,colour,0,0,((16*sx+scrollx)&0x1ff)-0x200,((16*sy+scrolly)&(width-1))-width,cliprect,trans,0); /* wrap xy */
+
+ offs++;
+ }
+ }
+ }
+}
+
+/* This is a complete bodge for the daraku text layers. There is not enough info to be sure how it is supposed to work */
+/* It appears that there are row/column scroll values for 2 seperate layers, just drawing it twice using one of each of the sets of values for now */
+static void draw_bglayertext(running_machine *machine, int layer, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ gfx_element *gfx;
+ int offs, sx, sy;
+ int scrollx, scrolly, bank, size, width, scrollbank,trans,alpha,alphamap;
+
+ scrollbank = BG_TYPE(layer); /* Scroll bank appears to be same as layer type */
+
+ gfx = BG_DEPTH_8BPP(layer) ? machine->gfx[1] : machine->gfx[0];
+ size = BG_LARGE(layer) ? 32 : 16;
+ width = BG_LARGE(layer) ? 0x200 : 0x100;
+
+ /* Use first values from the first set of scroll values */
+ bank = (psikyosh_bgram[(scrollbank*0x800)/4 + 0x400/4 - 0x4000/4] & 0x000000ff) >> 0;
+ alpha = (psikyosh_bgram[(scrollbank*0x800)/4 + 0x400/4 - 0x4000/4] & 0x00003f00) >> 8;
+ alphamap =(psikyosh_bgram[(scrollbank*0x800)/4 + 0x400/4 - 0x4000/4] & 0x00008000) >> 15;
+ scrollx = (psikyosh_bgram[(scrollbank*0x800)/4 - 0x4000/4] & 0x000001ff) >> 0;
+ scrolly = (psikyosh_bgram[(scrollbank*0x800)/4 - 0x4000/4] & 0x03ff0000) >> 16;
+
+ if(alphamap) { /* alpha values are per-pen */
+ trans = TRANSPARENCY_ALPHARANGE;
+ } else if(alpha) {
+ trans = TRANSPARENCY_ALPHA;
+ alpha = ((0x3f-alpha)*0xff)/0x3f; /* 0x3f-0x00 maps to 0x00-0xff */
+ alpha_set_level(alpha);
+ } else {
+ trans = TRANSPARENCY_PEN;
+ }
+
+
+ if((bank>=0x0c) && (bank<=0x1f)) { /* shouldn't happen, 20 banks of 0x800 bytes */
+ offs=0;
+ for ( sy=0; sy<size; sy++) {
+ for (sx=0; sx<32; sx++) {
+ int tileno, colour;
+
+ tileno = (psikyosh_bgram[(bank*0x800)/4 + offs - 0x4000/4] & 0x0007ffff); /* seems to take into account spriteram, hence -0x4000 */
+ colour = (psikyosh_bgram[(bank*0x800)/4 + offs - 0x4000/4] & 0xff000000) >> 24;
+
+ drawgfx(bitmap,gfx,tileno,colour,0,0,(16*sx+scrollx)&0x1ff,((16*sy+scrolly)&(width-1)),cliprect,trans,0); /* normal */
+ if(scrollx)
+ drawgfx(bitmap,gfx,tileno,colour,0,0,((16*sx+scrollx)&0x1ff)-0x200,((16*sy+scrolly)&(width-1)),cliprect,trans,0); /* wrap x */
+ if(scrolly)
+ drawgfx(bitmap,gfx,tileno,colour,0,0,(16*sx+scrollx)&0x1ff,((16*sy+scrolly)&(width-1))-width,cliprect,trans,0); /* wrap y */
+ if(scrollx && scrolly)
+ drawgfx(bitmap,gfx,tileno,colour,0,0,((16*sx+scrollx)&0x1ff)-0x200,((16*sy+scrolly)&(width-1))-width,cliprect,trans,0); /* wrap xy */
+
+ offs++;
+ }}}
+
+ /* Use first values from the second set of scroll values */
+ bank = (psikyosh_bgram[(scrollbank*0x800)/4 + 0x400/4 + 0x20/4 - 0x4000/4] & 0x000000ff) >> 0;
+ alpha = (psikyosh_bgram[(scrollbank*0x800)/4 + 0x400/4 + 0x20/4 - 0x4000/4] & 0x00003f00) >> 8;
+ alphamap =(psikyosh_bgram[(scrollbank*0x800)/4 + 0x400/4 + 0x20/4 - 0x4000/4] & 0x00008000) >> 15;
+ scrollx = (psikyosh_bgram[(scrollbank*0x800)/4 - 0x4000/4 + 0x20/4] & 0x000001ff) >> 0;
+ scrolly = (psikyosh_bgram[(scrollbank*0x800)/4 - 0x4000/4 + 0x20/4] & 0x03ff0000) >> 16;
+
+ if(alphamap) { /* alpha values are per-pen */
+ trans = TRANSPARENCY_ALPHARANGE;
+ } else if(alpha) {
+ trans = TRANSPARENCY_ALPHA;
+ alpha = ((0x3f-alpha)*0xff)/0x3f; /* 0x3f-0x00 maps to 0x00-0xff */
+ alpha_set_level(alpha);
+ } else {
+ trans = TRANSPARENCY_PEN;
+ }
+
+ if((bank>=0x0c) && (bank<=0x1f)) { /* shouldn't happen, 20 banks of 0x800 bytes */
+ offs=0;
+ for ( sy=0; sy<size; sy++) {
+ for (sx=0; sx<32; sx++) {
+ int tileno, colour;
+
+ tileno = (psikyosh_bgram[(bank*0x800)/4 + offs - 0x4000/4] & 0x0007ffff); /* seems to take into account spriteram, hence -0x4000 */
+ colour = (psikyosh_bgram[(bank*0x800)/4 + offs - 0x4000/4] & 0xff000000) >> 24;
+
+ drawgfx(bitmap,gfx,tileno,colour,0,0,(16*sx+scrollx)&0x1ff,((16*sy+scrolly)&(width-1)),cliprect,trans,0); /* normal */
+ if(scrollx)
+ drawgfx(bitmap,gfx,tileno,colour,0,0,((16*sx+scrollx)&0x1ff)-0x200,((16*sy+scrolly)&(width-1)),cliprect,trans,0); /* wrap x */
+ if(scrolly)
+ drawgfx(bitmap,gfx,tileno,colour,0,0,(16*sx+scrollx)&0x1ff,((16*sy+scrolly)&(width-1))-width,cliprect,trans,0); /* wrap y */
+ if(scrollx && scrolly)
+ drawgfx(bitmap,gfx,tileno,colour,0,0,((16*sx+scrollx)&0x1ff)-0x200,((16*sy+scrolly)&(width-1))-width,cliprect,trans,0); /* wrap xy */
+
+ offs++;
+ }}}
+}
+
+/* Row Scroll and/or Column Scroll/Zoom, has per-column Alpha/Bank/Priority. This isn't correct, just testing */
+/* For now I'm just using the first alpha/bank/priority values and sodding the rest of it */
+static void draw_bglayerscroll(running_machine *machine, int layer, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ gfx_element *gfx;
+ int offs, sx, sy;
+ int scrollx, scrolly, bank, alpha, alphamap, trans, size, width, scrollbank;
+
+ scrollbank = BG_TYPE(layer); /* Scroll bank appears to be same as layer type */
+
+// bank = BG_TYPE(layer) - 0x02; /* This is an assumption which seems to hold true so far, although the bank seems to be selectable per-line */
+
+ /* Take the following details from the info for the first row, the same for every row in all cases so far */
+ bank = (psikyosh_bgram[(scrollbank*0x800)/4 + 0x400/4 - 0x4000/4] & 0x000000ff) >> 0;
+ alpha = (psikyosh_bgram[(scrollbank*0x800)/4 + 0x400/4 - 0x4000/4] & 0x00003f00) >> 8;
+ alphamap =(psikyosh_bgram[(scrollbank*0x800)/4 + 0x400/4 - 0x4000/4] & 0x00008000) >> 15;
+
+ /* Just to get things moving :) */
+ scrollx =(psikyosh_bgram[(scrollbank*0x800)/4 - 0x4000/4] & 0x000001ff) >> 0;
+ scrolly = 0; // ColumnZoom is combined with ColumnScroll values :(
+
+ gfx = BG_DEPTH_8BPP(layer) ? machine->gfx[1] : machine->gfx[0];
+ size = BG_LARGE(layer) ? 32 : 16;
+ width = BG_LARGE(layer) ? 0x200 : 0x100;
+
+ if(alphamap) { /* alpha values are per-pen */
+ trans = TRANSPARENCY_ALPHARANGE;
+ } else if(alpha) {
+ trans = TRANSPARENCY_ALPHA;
+ alpha = ((0x3f-alpha)*0xff)/0x3f; /* 0x3f-0x00 maps to 0x00-0xff */
+ alpha_set_level(alpha);
+ } else {
+ trans = TRANSPARENCY_PEN;
+ }
+
+ if((bank>=0x0c) && (bank<=0x1f)) /* shouldn't happen, 20 banks of 0x800 bytes */
+ {
+/* Looks better with blending and one scroll value than with 1D linescroll and no zoom */
+#if 0
+ int bg_scrollx[256], bg_scrolly[512];
+ fillbitmap(zoom_bitmap, get_black_pen(machine), NULL);
+ for (offs=0; offs<(0x400/4); offs++) /* 224 values for each */
+ {
+ bg_scrollx[offs] = (psikyosh_bgram[(scrollbank*0x800)/4 + offs - 0x4000/4] & 0x000001ff) >> 0;
+ bg_scrolly[2*offs] = (psikyosh_bgram[(scrollbank*0x800)/4 + offs - 0x4000/4] & 0x03ff0000) >> 16;
+ bg_scrolly[2*offs+1] = (psikyosh_bgram[(scrollbank*0x800)/4 + offs - 0x4000/4] & 0x03ff0000) >> 16;
+ }
+#endif
+
+ offs=0;
+ for ( sy=0; sy<size; sy++)
+ {
+ for (sx=0; sx<32; sx++)
+ {
+ int tileno, colour;
+
+ tileno = (psikyosh_bgram[(bank*0x800)/4 + offs - 0x4000/4] & 0x0007ffff); /* seems to take into account spriteram, hence -0x4000 */
+ colour = (psikyosh_bgram[(bank*0x800)/4 + offs - 0x4000/4] & 0xff000000) >> 24;
+
+// drawgfx(zoom_bitmap,gfx,tileno,colour,0,0,(16*sx)&0x1ff,((16*sy)&(width-1)),NULL,TRANSPARENCY_PEN,0);
+
+ drawgfx(bitmap,gfx,tileno,colour,0,0,(16*sx+scrollx)&0x1ff,((16*sy+scrolly)&(width-1)),cliprect,trans,0); /* normal */
+ if(scrollx)
+ drawgfx(bitmap,gfx,tileno,colour,0,0,((16*sx+scrollx)&0x1ff)-0x200,((16*sy+scrolly)&(width-1)),cliprect,trans,0); /* wrap x */
+ if(scrolly)
+ drawgfx(bitmap,gfx,tileno,colour,0,0,(16*sx+scrollx)&0x1ff,((16*sy+scrolly)&(width-1))-width,cliprect,trans,0); /* wrap y */
+ if(scrollx && scrolly)
+ drawgfx(bitmap,gfx,tileno,colour,0,0,((16*sx+scrollx)&0x1ff)-0x200,((16*sy+scrolly)&(width-1))-width,cliprect,trans,0); /* wrap xy */
+
+ offs++;
+ }
+ }
+ /* Only ever seems to use one linescroll value, ok for now */
+ /* Disabled for now, as they doesn't even support alpha :( */
+// copyscrollbitmap(bitmap,zoom_bitmap,1,bg_scrollx,512,bg_scrolly,cliprect,TRANSPARENCY_PEN,0);
+// copyscrollbitmap(bitmap,zoom_bitmap,256,bg_scrollx,0,bg_scrolly,cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+/* 3 BG layers, with priority */
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8 req_pri )
+{
+ int i;
+
+#if 0
+#ifdef MAME_DEBUG
+ popmessage ("Pri %d=%02x-%s %d=%02x-%s %d=%02x-%s",
+ 0, BG_TYPE(0), BG_LAYER_ENABLE(0)?"y":"n",
+ 1, BG_TYPE(1), BG_LAYER_ENABLE(1)?"y":"n",
+ 2, BG_TYPE(2), BG_LAYER_ENABLE(2)?"y":"n");
+#endif
+#endif
+
+ /* 1st-3rd layers */
+ for(i=0; i<3; i++)
+ {
+ if ( !BG_LAYER_ENABLE(i) )
+ continue;
+
+ switch(BG_TYPE(i))
+ {
+ case BG_NORMAL:
+ if(((psikyosh_bgram[0x17f0/4 + (i*0x04)/4] & 0xff000000) >> 24) == req_pri)
+ draw_bglayer(machine, i, bitmap, cliprect);
+ break;
+ case BG_NORMAL_ALT:
+ if(((psikyosh_bgram[0x1ff0/4 + (i*0x04)/4] & 0xff000000) >> 24) == req_pri)
+ draw_bglayer(machine, i, bitmap, cliprect);
+ break;
+ case BG_SCROLL_0C: // Using normal for now
+ case BG_SCROLL_0D: // Using normal for now
+ if(((psikyosh_bgram[(BG_TYPE(i)*0x800)/4 + 0x400/4 - 0x4000/4] & 0xff000000) >> 24) == req_pri)
+ draw_bglayertext(machine, i, bitmap, cliprect);
+ break;
+ case BG_SCROLL_ZOOM:
+ /* 0x10 - 0x1f */
+ case 0x10: case 0x11: case 0x12: case 0x13:
+ case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+ case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ if(((psikyosh_bgram[(BG_TYPE(i)*0x800)/4 + 0x400/4 - 0x4000/4] & 0xff000000) >> 24) == req_pri)
+ draw_bglayerscroll(machine, i, bitmap, cliprect);
+ break;
+ default:
+ popmessage ("Unknown layer type %02x", BG_TYPE(i));
+ }
+ }
+}
+
+/* --- SPRITES --- */
+
+/* 32-bit ONLY */
+/* zoomx/y are pixel slopes in 6.10 floating point, not scale. 0x400 is 1:1 */
+/* high/wide are number of tiles wide/high up to max size of zoom_bitmap in either direction */
+/* code is index of first tile and incremented across rows then down columns (adjusting for flip obviously) */
+/* sx and sy is top-left of entire sprite regardless of flip */
+/* Note that Level 5-4 of sbomberb boss is perfect! (Alpha blended zoomed) as well as S1945II logo */
+/* pixel is only plotted if z is >= priority_buffer[y][x] */
+static void psikyosh_drawgfxzoom( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ UINT32 code,UINT32 color,int flipx,int flipy,int offsx,int offsy,
+ const rectangle *clip,int transparency,int transparent_color,
+ int zoomx, int zoomy, int wide, int high, UINT32 z)
+{
+ rectangle myclip; /* Clip to screen boundaries */
+ int code_offset = 0;
+ int xtile, ytile, xpixel, ypixel;
+
+ if (!zoomx || !zoomy) return;
+
+ profiler_mark(PROFILER_DRAWGFX);
+
+ assert(transparency == TRANSPARENCY_PEN || transparency == TRANSPARENCY_ALPHA || transparency == TRANSPARENCY_ALPHARANGE);
+ assert(dest_bmp->bpp == 32);
+
+ /* KW 991012 -- Added code to force clip to bitmap boundary */
+ if(clip)
+ {
+ myclip.min_x = clip->min_x;
+ myclip.max_x = clip->max_x;
+ myclip.min_y = clip->min_y;
+ myclip.max_y = clip->max_y;
+
+ if (myclip.min_x < 0) myclip.min_x = 0;
+ if (myclip.max_x >= dest_bmp->width) myclip.max_x = dest_bmp->width-1;
+ if (myclip.min_y < 0) myclip.min_y = 0;
+ if (myclip.max_y >= dest_bmp->height) myclip.max_y = dest_bmp->height-1;
+
+ clip=&myclip;
+ }
+
+ /* Temporary fallback for non-zoomed, needs z-buffer. Note that this is probably a lot slower than drawgfx.c, especially if there was seperate code for flipped cases */
+ if (zoomx == 0x400 && zoomy == 0x400)
+ {
+ int xstart, ystart, xend, yend, xinc, yinc;
+
+ if (flipx) { xstart = wide-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = wide; xinc = +1; }
+
+ if (flipy) { ystart = high-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = high; yinc = +1; }
+
+ /* Start drawing */
+ if( gfx )
+ {
+ for (ytile = ystart; ytile != yend; ytile += yinc )
+ {
+ for (xtile = xstart; xtile != xend; xtile += xinc )
+ {
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+ int source_base = ((code + code_offset++) % gfx->total_elements) * gfx->height;
+
+ int x_index_base, y_index, sx, sy, ex, ey;
+
+ if (flipx) { x_index_base = gfx->width-1; }
+ else { x_index_base = 0; }
+
+ if (flipy) { y_index = gfx->height-1; }
+ else { y_index = 0; }
+
+ /* start coordinates */
+ sx = offsx + xtile*gfx->width;
+ sy = offsy + ytile*gfx->height;
+
+ /* end coordinates */
+ ex = sx + gfx->width;
+ ey = sy + gfx->height;
+
+ if( clip )
+ {
+ if( sx < clip->min_x)
+ { /* clip left */
+ int pixels = clip->min_x-sx;
+ sx += pixels;
+ x_index_base += xinc*pixels;
+ }
+ if( sy < clip->min_y )
+ { /* clip top */
+ int pixels = clip->min_y-sy;
+ sy += pixels;
+ y_index += yinc*pixels;
+ }
+ /* NS 980211 - fixed incorrect clipping */
+ if( ex > clip->max_x+1 )
+ { /* clip right */
+ int pixels = ex-clip->max_x-1;
+ ex -= pixels;
+ }
+ if( ey > clip->max_y+1 )
+ { /* clip bottom */
+ int pixels = ey-clip->max_y-1;
+ ey -= pixels;
+ }
+ }
+
+ if( ex>sx )
+ { /* skip if inner loop doesn't draw anything */
+ int y;
+
+ /* case 1: TRANSPARENCY_PEN */
+ if (transparency == TRANSPARENCY_PEN)
+ {
+ if( z > 0 )
+ {
+ UINT8 *source = gfx->gfxdata + (source_base + y_index)*gfx->line_modulo + x_index_base;
+ UINT32 *dest = (UINT32 *)dest_bmp->base + sy*dest_bmp->rowpixels + sx;
+ UINT16 *pri = (UINT16 *)z_bitmap->base + sy*z_bitmap->rowpixels + sx;
+ int src_modulo = yinc*gfx->line_modulo - xinc*(ex-sx);
+ int dst_modulo = dest_bmp->rowpixels - (ex-sx);
+
+ for( y=sy; y<ey; y++ )
+ {
+ int x;
+ for( x=sx; x<ex; x++ )
+ {
+ if(z >= *pri)
+ {
+ int c = *source;
+ if( c != transparent_color )
+ {
+ *dest = pal[c];
+ *pri = z;
+ }
+ }
+ dest++;
+ pri++;
+ source += xinc;
+ }
+ dest += dst_modulo;
+ pri += dst_modulo;
+ source += src_modulo;
+ }
+ }
+ else
+ {
+ UINT8 *source = gfx->gfxdata + (source_base + y_index)*gfx->line_modulo + x_index_base;
+ UINT32 *dest = (UINT32 *)dest_bmp->base + sy*dest_bmp->rowpixels + sx;
+ int src_modulo = yinc*gfx->line_modulo - xinc*(ex-sx);
+ int dst_modulo = dest_bmp->rowpixels - (ex-sx);
+
+ for( y=sy; y<ey; y++ )
+ {
+ int x;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = *source;
+ if( c != transparent_color ) *dest = pal[c];
+
+ dest++;
+ source += xinc;
+ }
+ dest += dst_modulo;
+ source += src_modulo;
+ }
+ }
+ }
+
+ /* case 6: TRANSPARENCY_ALPHA */
+ if (transparency == TRANSPARENCY_ALPHA)
+ {
+ if ( z > 0 )
+ {
+ UINT8 *source = gfx->gfxdata + (source_base + y_index)*gfx->line_modulo + x_index_base;
+ UINT32 *dest = (UINT32 *)dest_bmp->base + sy*dest_bmp->rowpixels + sx;
+ UINT16 *pri = (UINT16 *)z_bitmap->base + sy*z_bitmap->rowpixels + sx;
+ int src_modulo = yinc*gfx->line_modulo - xinc*(ex-sx);
+ int dst_modulo = dest_bmp->rowpixels - (ex-sx);
+
+ for( y=sy; y<ey; y++ )
+ {
+ int x;
+ for( x=sx; x<ex; x++ )
+ {
+ if(z >= *pri)
+ {
+ int c = *source;
+ if( c != transparent_color )
+ {
+ *dest = alpha_blend32(*dest, pal[c]);
+ *pri = z;
+ }
+ }
+ dest++;
+ pri++;
+ source += xinc;
+ }
+ dest += dst_modulo;
+ pri += dst_modulo;
+ source += src_modulo;
+ }
+ }
+ else
+ {
+ UINT8 *source = gfx->gfxdata + (source_base + y_index)*gfx->line_modulo + x_index_base;
+ UINT32 *dest = (UINT32 *)dest_bmp->base + sy*dest_bmp->rowpixels + sx;
+ int src_modulo = yinc*gfx->line_modulo - xinc*(ex-sx);
+ int dst_modulo = dest_bmp->rowpixels - (ex-sx);
+
+ for( y=sy; y<ey; y++ )
+ {
+ int x;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = *source;
+ if( c != transparent_color ) *dest = alpha_blend32(*dest, pal[c]);
+
+ dest++;
+ source += xinc;
+ }
+ dest += dst_modulo;
+ source += src_modulo;
+ }
+ }
+ }
+
+ /* pjp 31/5/02 */
+ /* case 7: TRANSPARENCY_ALPHARANGE */
+ if (transparency == TRANSPARENCY_ALPHARANGE)
+ {
+ if ( z > 0 )
+ {
+ UINT8 *source = gfx->gfxdata + (source_base + y_index)*gfx->line_modulo + x_index_base;
+ UINT32 *dest = (UINT32 *)dest_bmp->base + sy*dest_bmp->rowpixels + sx;
+ UINT16 *pri = (UINT16 *)z_bitmap->base + sy*z_bitmap->rowpixels + sx;
+ int src_modulo = yinc*gfx->line_modulo - xinc*(ex-sx);
+ int dst_modulo = dest_bmp->rowpixels - (ex-sx);
+
+ for( y=sy; y<ey; y++ )
+ {
+ int x;
+ for( x=sx; x<ex; x++ )
+ {
+ if(z >= *pri)
+ {
+ int c = *source;
+ if( c != transparent_color )
+ {
+ if( gfx_alpharange_table[c] == 0xff )
+ *dest = pal[c];
+ else
+ *dest = alpha_blend_r32(*dest, pal[c], gfx_alpharange_table[c]);
+
+ *pri = z;
+ }
+ }
+ dest++;
+ pri++;
+ source += xinc;
+ }
+ dest += dst_modulo;
+ pri += dst_modulo;
+ source += src_modulo;
+ }
+ }
+ else
+ {
+ UINT8 *source = gfx->gfxdata + (source_base + y_index)*gfx->line_modulo + x_index_base;
+ UINT32 *dest = (UINT32 *)dest_bmp->base + sy*dest_bmp->rowpixels + sx;
+ int src_modulo = yinc*gfx->line_modulo - xinc*(ex-sx);
+ int dst_modulo = dest_bmp->rowpixels - (ex-sx);
+
+ for( y=sy; y<ey; y++ )
+ {
+ int x;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = *source;
+ if( c != transparent_color )
+ {
+ if( gfx_alpharange_table[c] == 0xff )
+ *dest = pal[c];
+ else
+ *dest = alpha_blend_r32(*dest, pal[c], gfx_alpharange_table[c]);
+ }
+ dest++;
+ source += xinc;
+ }
+ dest += dst_modulo;
+ source += src_modulo;
+ }
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+ else /* Zoomed */
+ {
+ /* Make a copy of complete sprite at top-left of zoom_bitmap */
+ /* Because I'm too slow to get it to work on the fly */
+ for(ytile=0; ytile<high; ytile++)
+ {
+ for(xtile=0; xtile<wide; xtile++)
+ {
+ int source_base = ((code + code_offset++) % gfx->total_elements) * gfx->height;
+ for( ypixel=0; ypixel<gfx->height; ypixel++ )
+ {
+ UINT8 *source = gfx->gfxdata + (source_base+ypixel) * gfx->line_modulo;
+ UINT8 *dest = BITMAP_ADDR8(zoom_bitmap, ypixel + ytile*gfx->height, 0);
+
+ for( xpixel=0; xpixel<gfx->width; xpixel++ )
+ {
+ dest[xpixel + xtile*gfx->width] = source[xpixel];
+ }
+ }
+ }
+ }
+
+ /* Start drawing */
+ if( gfx )
+ {
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+
+ int sprite_screen_height = ((high*gfx->height*(0x400*0x400))/zoomy + 0x200)>>10; /* Round up to nearest pixel */
+ int sprite_screen_width = ((wide*gfx->width*(0x400*0x400))/zoomx + 0x200)>>10;
+
+ if (sprite_screen_width && sprite_screen_height)
+ {
+ /* start coordinates */
+ int sx = offsx;
+ int sy = offsy;
+
+ /* end coordinates */
+ int ex = sx + sprite_screen_width;
+ int ey = sy + sprite_screen_height;
+
+ int x_index_base;
+ int y_index;
+
+ int dx, dy;
+
+ if( flipx ) { x_index_base = (sprite_screen_width-1)*zoomx; dx = -zoomx; }
+ else { x_index_base = 0; dx = zoomx; }
+
+ if( flipy ) { y_index = (sprite_screen_height-1)*zoomy; dy = -zoomy; }
+ else { y_index = 0; dy = zoomy; }
+
+ if( clip )
+ {
+ if( sx < clip->min_x)
+ { /* clip left */
+ int pixels = clip->min_x-sx;
+ sx += pixels;
+ x_index_base += pixels*dx;
+ }
+ if( sy < clip->min_y )
+ { /* clip top */
+ int pixels = clip->min_y-sy;
+ sy += pixels;
+ y_index += pixels*dy;
+ }
+ /* NS 980211 - fixed incorrect clipping */
+ if( ex > clip->max_x+1 )
+ { /* clip right */
+ int pixels = ex-clip->max_x-1;
+ ex -= pixels;
+ }
+ if( ey > clip->max_y+1 )
+ { /* clip bottom */
+ int pixels = ey-clip->max_y-1;
+ ey -= pixels;
+ }
+ }
+
+ if( ex>sx )
+ { /* skip if inner loop doesn't draw anything */
+ int y;
+
+ /* case 1: TRANSPARENCY_PEN */
+ /* Note: adjusted to >>10 and draws from zoom_bitmap not gfx */
+ if (transparency == TRANSPARENCY_PEN)
+ {
+ if( z > 0 )
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = BITMAP_ADDR8(zoom_bitmap, y_index>>10, 0);
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+ UINT16 *pri = BITMAP_ADDR16(z_bitmap, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ if(z >= pri[x])
+ {
+ int c = source[x_index>>10];
+ if( c != transparent_color )
+ {
+ dest[x] = pal[c];
+ pri[x] = z;
+ }
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = BITMAP_ADDR8(zoom_bitmap, y_index>>10, 0);
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>10];
+ if( c != transparent_color ) dest[x] = pal[c];
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 6: TRANSPARENCY_ALPHA */
+ if (transparency == TRANSPARENCY_ALPHA)
+ {
+ if( z > 0 )
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = BITMAP_ADDR8(zoom_bitmap, y_index>>10, 0);
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+ UINT16 *pri = BITMAP_ADDR16(z_bitmap, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ if(z >= pri[x])
+ {
+ int c = source[x_index>>10];
+ if( c != transparent_color )
+ {
+ dest[x] = alpha_blend32(dest[x], pal[c]);
+ pri[x] = z;
+ }
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = BITMAP_ADDR8(zoom_bitmap, y_index>>10, 0);
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>10];
+ if( c != transparent_color ) dest[x] = alpha_blend32(dest[x], pal[c]);
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 7: TRANSPARENCY_ALPHARANGE */
+ if (transparency == TRANSPARENCY_ALPHARANGE)
+ {
+ if( z > 0 )
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = BITMAP_ADDR8(zoom_bitmap, y_index>>10, 0);
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+ UINT16 *pri = BITMAP_ADDR16(z_bitmap, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ if(z >= pri[x])
+ {
+ int c = source[x_index>>10];
+ if( c != transparent_color )
+ {
+ if( gfx_alpharange_table[c] == 0xff )
+ dest[x] = pal[c];
+ else
+ dest[x] = alpha_blend_r32(dest[x], pal[c], gfx_alpharange_table[c]);
+
+ pri[x] = z;
+ }
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = BITMAP_ADDR8(zoom_bitmap, y_index>>10, 0);
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>10];
+ if( c != transparent_color )
+ {
+ if( gfx_alpharange_table[c] == 0xff )
+ dest[x] = pal[c];
+ else
+ dest[x] = alpha_blend_r32(dest[x], pal[c], gfx_alpharange_table[c]);
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ profiler_mark(PROFILER_END);
+}
+
+#define SPRITE_PRI(n) (((psikyosh_vidregs[2] << (4*n)) & 0xf0000000 ) >> 28)
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8 req_pri )
+{
+ /*- Sprite Format 0x0000 - 0x37ff -**
+
+ 0 ---- --yy yyyy yyyy | ---- --xx xxxx xxxx 1 F--- hhhh ZZZZ ZZZZ | fPPP wwww zzzz zzzz
+ 2 pppp pppp -aaa -nnn | nnnn nnnn nnnn nnnn 3 ---- ---- ---- ---- | ---- ---- ---- ----
+
+ y = ypos
+ x = xpos
+
+ h = height
+ w = width
+
+ F = flip (y)
+ f = flip (x)
+
+ Z = zoom (y)
+ z = zoom (x)
+
+ n = tile number
+
+ p = palette
+
+ a = alpha blending, selects which of the 8 alpha values in vid_regs[0-1] to use
+
+ P = priority
+ Points to a 4-bit entry in vid_regs[2] which provides a priority comparable with the bg layer's priorities.
+ However, sprite-sprite priority needs to be preserved.
+ daraku and soldivid only use the lsb
+
+ **- End Sprite Format -*/
+
+ const gfx_element *gfx;
+ UINT32 *src = buffered_spriteram32; /* Use buffered spriteram */
+ UINT16 *list = (UINT16 *)src + 0x3800/2;
+ UINT16 listlen=0x800/2, listcntr=0;
+ UINT16 *zoom_table = (UINT16 *)psikyosh_zoomram;
+ UINT8 *alpha_table = (UINT8 *)psikyosh_vidregs;
+
+ while( listcntr < listlen )
+ {
+ UINT32 listdat, sprnum, xpos, ypos, high, wide, flpx, flpy, zoomx, zoomy, tnum, colr, dpth;
+ UINT32 pri, alpha, alphamap, trans;
+
+ listdat = list[BYTE_XOR_BE(listcntr)];
+ sprnum = (listdat & 0x03ff) * 4;
+
+ pri = (src[sprnum+1] & 0x00003000) >> 12; // & 0x00007000/0x00003000 ?
+ pri = SPRITE_PRI(pri);
+
+ if(pri == req_pri)
+ {
+ ypos = (src[sprnum+0] & 0x03ff0000) >> 16;
+ xpos = (src[sprnum+0] & 0x000003ff) >> 00;
+
+ if(ypos & 0x200) ypos -= 0x400;
+ if(xpos & 0x200) xpos -= 0x400;
+
+ high = ((src[sprnum+1] & 0x0f000000) >> 24) + 1;
+ wide = ((src[sprnum+1] & 0x00000f00) >> 8) + 1;
+
+ flpy = (src[sprnum+1] & 0x80000000) >> 31;
+ flpx = (src[sprnum+1] & 0x00008000) >> 15;
+
+ zoomy = (src[sprnum+1] & 0x00ff0000) >> 16;
+ zoomx = (src[sprnum+1] & 0x000000ff) >> 00;
+
+ tnum = (src[sprnum+2] & 0x0007ffff) >> 00;
+ dpth = (src[sprnum+2] & 0x00800000) >> 23;
+ colr = (src[sprnum+2] & 0xff000000) >> 24;
+
+ alpha = (src[sprnum+2] & 0x00700000) >> 20;
+
+ alphamap = (alpha_table[BYTE4_XOR_BE(alpha)] & 0x80)? 1:0;
+ alpha = alpha_table[BYTE4_XOR_BE(alpha)] & 0x3f;
+
+ gfx = dpth ? machine->gfx[1] : machine->gfx[0];
+
+ if(alphamap) { /* alpha values are per-pen */
+ trans = TRANSPARENCY_ALPHARANGE;
+ } else if(alpha) {
+ alpha = ((0x3f-alpha)*0xff)/0x3f; /* 0x3f-0x00 maps to 0x00-0xff */
+ trans = TRANSPARENCY_ALPHA;
+ alpha_set_level(alpha);
+ } else {
+ trans = TRANSPARENCY_PEN;
+ }
+
+ /* start drawing */
+ if( zoom_table[BYTE_XOR_BE(zoomy)] && zoom_table[BYTE_XOR_BE(zoomx)] ) /* Avoid division-by-zero when table contains 0 (Uninitialised/Bug) */
+ {
+ psikyosh_drawgfxzoom(bitmap,gfx,tnum,colr,flpx,flpy,xpos,ypos,cliprect,trans,0,
+ (UINT32)zoom_table[BYTE_XOR_BE(zoomx)], (UINT32)zoom_table[BYTE_XOR_BE(zoomy)], wide, high, listcntr);
+
+#if 0
+#ifdef MAME_DEBUG
+ if (input_code_pressed(KEYCODE_Z)) /* Display some info on each sprite */
+ {
+ char buf[10];
+ int x, y;
+
+ sprintf(buf, "%X",xdim/16); /* Display Zoom in 16.16 */
+ if (machine->gamedrv->flags & ORIENTATION_SWAP_XY) {
+ x = ypos;
+ y = machine->screen[0].visarea.max_x - xpos; /* ORIENTATION_FLIP_Y */
+ }
+ else {
+ x = xpos;
+ y = ypos;
+ }
+ ui_draw_text(buf, x, y);
+ }
+#endif
+#endif
+ }
+ /* end drawing */
+ }
+ listcntr++;
+ if (listdat & 0x4000) break;
+ }
+}
+
+VIDEO_START( psikyosh )
+{
+ zoom_bitmap = auto_bitmap_alloc(16*16, 16*16, BITMAP_FORMAT_INDEXED8);
+
+ /* Need 16-bit z-buffer */
+ z_bitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+
+ machine->gfx[1]->color_granularity=16; /* 256 colour sprites with palette selectable on 16 colour boundaries */
+
+ { /* Pens 0xc0-0xff have a gradient of alpha values associated with them */
+ int i;
+ for (i=0; i<0xc0; i++)
+ gfx_alpharange_table[i] = 0xff;
+ for (i=0; i<0x40; i++) {
+ int alpha = ((0x3f-i)*0xff)/0x3f;
+ gfx_alpharange_table[i+0xc0] = alpha;
+ }
+ }
+
+}
+
+static void psikyosh_prelineblend( mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ /* There are 224 values for pre-lineblending. Using one for every row currently */
+ /* I suspect that it should be blended against black by the amount specified as
+ gnbarich sets the 0x000000ff to 0x7f in test mode whilst the others use 0x80.
+ As it's only used in testmode I'll just leave it as a toggle for now */
+ UINT32 *dstline;
+ UINT32 *linefill = psikyosh_bgram; /* Per row */
+ int x,y;
+
+ assert(bitmap->bpp == 32);
+
+ profiler_mark(PROFILER_USER1);
+ for (y = cliprect->min_y; y <= cliprect->max_y; y += 1) {
+
+ dstline = BITMAP_ADDR32(bitmap, y, 0);
+
+ if(linefill[y]&0xff) /* Row */
+ for (x = cliprect->min_x; x <= cliprect->max_x; x += 1)
+ dstline[x] = linefill[y]>>8;
+ }
+ profiler_mark(PROFILER_END);
+}
+
+static void psikyosh_postlineblend( mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ /* There are 224 values for post-lineblending. Using one for every row currently */
+ UINT32 *dstline;
+ UINT32 *lineblend = psikyosh_bgram+0x400/4; /* Per row */
+ int x,y;
+
+ assert(bitmap->bpp == 32);
+
+ profiler_mark(PROFILER_USER2);
+ for (y = cliprect->min_y; y <= cliprect->max_y; y += 1) {
+
+ dstline = BITMAP_ADDR32(bitmap, y, 0);
+
+ if(lineblend[y]&0x80) /* Row */
+ {
+ for (x = cliprect->min_x; x <= cliprect->max_x; x += 1)
+ dstline[x] = lineblend[y]>>8;
+ }
+ else if(lineblend[y]&0x7f) /* Row */
+ {
+ for (x = cliprect->min_x; x <= cliprect->max_x; x += 1)
+ dstline[x] = alpha_blend_r32(dstline[x], lineblend[y]>>8, 2*(lineblend[y]&0x7f));
+ }
+ }
+ profiler_mark(PROFILER_END);
+}
+
+VIDEO_UPDATE( psikyosh ) /* Note the z-buffer on each sprite to get correct priority */
+{
+ int i;
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ fillbitmap(z_bitmap,0,cliprect); /* z-buffer */
+
+ psikyosh_prelineblend(bitmap, cliprect);
+
+ for (i=0; i<=7; i++) {
+ draw_sprites(machine, bitmap, cliprect, i); // When same priority bg's have higher pri
+ draw_background(machine, bitmap, cliprect, i);
+ if((psikyosh_vidregs[2]&0xf) == i) psikyosh_postlineblend(bitmap, cliprect);
+ }
+ return 0;
+}
+
+VIDEO_EOF( psikyosh )
+{
+ buffer_spriteram32_w(0,0,0);
+}
+
+/*popmessage ("Regs %08x %08x %08x\n %08x %08x %08x",
+ psikyosh_bgram[0x17f0/4], psikyosh_bgram[0x17f4/4], psikyosh_bgram[0x17f8/4],
+ psikyosh_bgram[0x1ff0/4], psikyosh_bgram[0x1ff4/4], psikyosh_bgram[0x1ff8/4]);*/
+/*popmessage ("Regs %08x %08x %08x\n %08x %08x %08x",
+ psikyosh_bgram[0x13f0/4], psikyosh_bgram[0x13f4/4], psikyosh_bgram[0x13f8/4],
+ psikyosh_bgram[0x1bf0/4], psikyosh_bgram[0x1bf4/4], psikyosh_bgram[0x1bf8/4]);*/
+/*popmessage ("Regs %08x %08x %08x %08x %08x %08x %08x %08x",
+ psikyosh_vidregs[0], psikyosh_vidregs[1],
+ psikyosh_vidregs[2], psikyosh_vidregs[3],
+ psikyosh_vidregs[4], psikyosh_vidregs[5],
+ psikyosh_vidregs[6], psikyosh_vidregs[7]);*/
diff --git a/src/mame/video/psx.c b/src/mame/video/psx.c
new file mode 100644
index 00000000000..d294e8bdccd
--- /dev/null
+++ b/src/mame/video/psx.c
@@ -0,0 +1,3925 @@
+/***************************************************************************
+
+ PSX GPU
+
+ Preliminary software renderer by smf.
+ Thanks to Ryan Holtz, Pete B & Farfetch'd.
+
+ Supports:
+ type 1 1024x1024 framebuffer (CXD8538Q)
+ type 2 1024x512 framebuffer (CXD8561Q)
+ type 2 1024x1024 framebuffer (CXD8514Q/CXD8561Q/CXD8654Q)
+
+ Debug Keys:
+ M toggles mesh viewer.
+ V toggles vram viewer.
+ I toggles interleave in vram viewer.
+
+***************************************************************************/
+
+#include <stdarg.h>
+#include "driver.h"
+#include "includes/psx.h"
+
+#define STOP_ON_ERROR ( 0 )
+
+#define VERBOSE_LEVEL ( 0 )
+
+INLINE void verboselog( int n_level, const char *s_fmt, ... )
+{
+ if( VERBOSE_LEVEL >= n_level )
+ {
+ va_list v;
+ char buf[ 32768 ];
+ va_start( v, s_fmt );
+ vsprintf( buf, s_fmt, v );
+ va_end( v );
+ if( cpu_getactivecpu() != -1 )
+ {
+ logerror( "%08x: %s", activecpu_get_pc(), buf );
+ }
+ else
+ {
+ logerror( "(timer) : %s", buf );
+ }
+ }
+}
+
+struct FLATVERTEX
+{
+ PAIR n_coord;
+};
+
+struct GOURAUDVERTEX
+{
+ PAIR n_bgr;
+ PAIR n_coord;
+};
+
+struct FLATTEXTUREDVERTEX
+{
+ PAIR n_coord;
+ PAIR n_texture;
+};
+
+struct GOURAUDTEXTUREDVERTEX
+{
+ PAIR n_bgr;
+ PAIR n_coord;
+ PAIR n_texture;
+};
+
+static union
+{
+ UINT32 n_entry[ 16 ];
+
+ struct
+ {
+ PAIR n_cmd;
+ struct FLATVERTEX vertex[ 2 ];
+ PAIR n_size;
+ } MoveImage;
+
+ struct
+ {
+ PAIR n_bgr;
+ PAIR n_coord;
+ PAIR n_size;
+ } FlatRectangle;
+
+ struct
+ {
+ PAIR n_bgr;
+ PAIR n_coord;
+ } FlatRectangle8x8;
+
+ struct
+ {
+ PAIR n_bgr;
+ PAIR n_coord;
+ } FlatRectangle16x16;
+
+ struct
+ {
+ PAIR n_bgr;
+ PAIR n_coord;
+ PAIR n_texture;
+ } Sprite8x8;
+
+ struct
+ {
+ PAIR n_bgr;
+ PAIR n_coord;
+ PAIR n_texture;
+ } Sprite16x16;
+
+ struct
+ {
+ PAIR n_bgr;
+ PAIR n_coord;
+ PAIR n_texture;
+ PAIR n_size;
+ } FlatTexturedRectangle;
+
+ struct
+ {
+ PAIR n_bgr;
+ struct FLATVERTEX vertex[ 4 ];
+ } FlatPolygon;
+
+ struct
+ {
+ struct GOURAUDVERTEX vertex[ 4 ];
+ } GouraudPolygon;
+
+ struct
+ {
+ PAIR n_bgr;
+ struct FLATVERTEX vertex[ 2 ];
+ } MonochromeLine;
+
+ struct
+ {
+ struct GOURAUDVERTEX vertex[ 2 ];
+ } GouraudLine;
+
+ struct
+ {
+ PAIR n_bgr;
+ struct FLATTEXTUREDVERTEX vertex[ 4 ];
+ } FlatTexturedPolygon;
+
+ struct
+ {
+ struct GOURAUDTEXTUREDVERTEX vertex[ 4 ];
+ } GouraudTexturedPolygon;
+
+ struct
+ {
+ PAIR n_bgr;
+ struct FLATVERTEX vertex;
+ } Dot;
+} m_packet;
+
+static struct PSXGPU
+{
+ INT32 n_tx;
+ INT32 n_ty;
+ INT32 n_abr;
+ INT32 n_tp;
+ INT32 n_ix;
+ INT32 n_iy;
+ INT32 n_ti;
+} psxgpu;
+
+static UINT16 *m_p_vram;
+static UINT32 m_n_vram_size;
+static UINT32 m_n_gpu_buffer_offset;
+static UINT32 m_n_vramx;
+static UINT32 m_n_vramy;
+static UINT32 m_n_twy;
+static UINT32 m_n_twx;
+static UINT32 m_n_twh;
+static UINT32 m_n_tww;
+static UINT32 m_n_drawarea_x1;
+static UINT32 m_n_drawarea_y1;
+static UINT32 m_n_drawarea_x2;
+static UINT32 m_n_drawarea_y2;
+static UINT32 m_n_horiz_disstart;
+static UINT32 m_n_horiz_disend;
+static UINT32 m_n_vert_disstart;
+static UINT32 m_n_vert_disend;
+static UINT32 m_b_reverseflag;
+static INT32 m_n_drawoffset_x;
+static INT32 m_n_drawoffset_y;
+static UINT32 m_n_displaystartx;
+static UINT32 m_n_displaystarty;
+static UINT32 m_n_gpustatus;
+static UINT32 m_n_gpuinfo;
+static UINT32 m_n_lightgun_x;
+static UINT32 m_n_lightgun_y;
+static UINT32 m_n_screenwidth;
+static UINT32 m_n_screenheight;
+
+#define MAX_LEVEL ( 32 )
+#define MID_LEVEL ( ( MAX_LEVEL / 2 ) << 8 )
+#define MAX_SHADE ( 0x100 )
+#define MID_SHADE ( 0x80 )
+
+static int m_n_gputype;
+
+static UINT16 *m_p_p_vram[ 1024 ];
+
+static UINT16 m_p_n_redshade[ MAX_LEVEL * MAX_SHADE ];
+static UINT16 m_p_n_greenshade[ MAX_LEVEL * MAX_SHADE ];
+static UINT16 m_p_n_blueshade[ MAX_LEVEL * MAX_SHADE ];
+static UINT16 m_p_n_redlevel[ 0x10000 ];
+static UINT16 m_p_n_greenlevel[ 0x10000 ];
+static UINT16 m_p_n_bluelevel[ 0x10000 ];
+
+static UINT16 m_p_n_f025[ MAX_LEVEL * MAX_SHADE ];
+static UINT16 m_p_n_f05[ MAX_LEVEL * MAX_SHADE ];
+static UINT16 m_p_n_f1[ MAX_LEVEL * MAX_SHADE ];
+static UINT16 m_p_n_redb05[ 0x10000 ];
+static UINT16 m_p_n_greenb05[ 0x10000 ];
+static UINT16 m_p_n_blueb05[ 0x10000 ];
+static UINT16 m_p_n_redb1[ 0x10000 ];
+static UINT16 m_p_n_greenb1[ 0x10000 ];
+static UINT16 m_p_n_blueb1[ 0x10000 ];
+static UINT16 m_p_n_redaddtrans[ MAX_LEVEL * MAX_LEVEL ];
+static UINT16 m_p_n_greenaddtrans[ MAX_LEVEL * MAX_LEVEL ];
+static UINT16 m_p_n_blueaddtrans[ MAX_LEVEL * MAX_LEVEL ];
+static UINT16 m_p_n_redsubtrans[ MAX_LEVEL * MAX_LEVEL ];
+static UINT16 m_p_n_greensubtrans[ MAX_LEVEL * MAX_LEVEL ];
+static UINT16 m_p_n_bluesubtrans[ MAX_LEVEL * MAX_LEVEL ];
+static UINT16 m_p_n_nextpointlist4[] = { 1, 3, 0, 2 };
+static UINT16 m_p_n_prevpointlist4[] = { 2, 0, 3, 1 };
+static UINT16 m_p_n_nextpointlist3[] = { 1, 2, 0 };
+static UINT16 m_p_n_prevpointlist3[] = { 2, 0, 1 };
+
+static UINT16 m_p_n_g0r0[ 0x10000 ];
+static UINT16 m_p_n_b0[ 0x10000 ];
+static UINT16 m_p_n_r1[ 0x10000 ];
+static UINT16 m_p_n_b1g1[ 0x10000 ];
+
+#define SINT11( x ) ( ( (INT32)( x ) << 21 ) >> 21 )
+
+#define ADJUST_COORD( a ) \
+ a.w.l = COORD_X( a ) + m_n_drawoffset_x; \
+ a.w.h = COORD_Y( a ) + m_n_drawoffset_y;
+
+#define COORD_X( a ) ( (INT16)a.w.l )
+#define COORD_Y( a ) ( (INT16)a.w.h )
+#define SIZE_W( a ) ( a.w.l )
+#define SIZE_H( a ) ( a.w.h )
+#define BGR_C( a ) ( a.b.h3 )
+#define BGR_B( a ) ( a.b.h2 )
+#define BGR_G( a ) ( a.b.h )
+#define BGR_R( a ) ( a.b.l )
+#define TEXTURE_V( a ) ( (UINT8)a.b.h )
+#define TEXTURE_U( a ) ( (UINT8)a.b.l )
+
+PALETTE_INIT( psx )
+{
+ UINT32 n_colour;
+
+ for( n_colour = 0; n_colour < 0x10000; n_colour++ )
+ {
+ palette_set_color_rgb( machine, n_colour, pal5bit(n_colour >> 0), pal5bit(n_colour >> 5), pal5bit(n_colour >> 10) );
+ }
+}
+
+#if defined( MAME_DEBUG )
+
+#define DEBUG_COORDS ( 10 )
+static mame_bitmap *debugmesh;
+static int m_b_debugclear;
+static int m_b_debugmesh;
+static int m_n_debugskip;
+static int m_b_debugtexture;
+static int m_n_debuginterleave;
+static int m_n_debugcoord;
+static int m_n_debugcoordx[ DEBUG_COORDS ];
+static int m_n_debugcoordy[ DEBUG_COORDS ];
+
+#define DEBUG_MAX ( 512 )
+
+static void DebugMeshInit( void )
+{
+ m_b_debugmesh = 0;
+ m_b_debugtexture = 0;
+ m_n_debuginterleave = -1;
+ m_b_debugclear = 1;
+ m_n_debugcoord = 0;
+ m_n_debugskip = 0;
+ debugmesh = auto_bitmap_alloc( Machine->screen[0].width, Machine->screen[0].height, BITMAP_FORMAT_INDEXED16 );
+}
+
+static void DebugMesh( int n_coordx, int n_coordy )
+{
+ int n_coord;
+ int n_colour;
+
+ if( m_b_debugclear )
+ {
+ fillbitmap( debugmesh, 0x0000, NULL );
+ m_b_debugclear = 0;
+ }
+
+ if( m_n_debugcoord < DEBUG_COORDS )
+ {
+ n_coordx += m_n_displaystartx;
+ n_coordy += m_n_displaystarty;
+
+ n_coordx *= 511;
+ n_coordx /= DEBUG_MAX - 1;
+ n_coordx += 256;
+ n_coordy *= 511;
+ n_coordy /= DEBUG_MAX - 1;
+ n_coordy += 256;
+
+ m_n_debugcoordx[ m_n_debugcoord ] = n_coordx;
+ m_n_debugcoordy[ m_n_debugcoord ] = n_coordy;
+ m_n_debugcoord++;
+ }
+
+ n_colour = 0x1f;
+ for( n_coord = 0; n_coord < m_n_debugcoord; n_coord++ )
+ {
+ if( n_coordx != m_n_debugcoordx[ n_coord ] ||
+ n_coordy != m_n_debugcoordy[ n_coord ] )
+ {
+ break;
+ }
+ }
+ if( n_coord == m_n_debugcoord && m_n_debugcoord > 1 )
+ {
+ n_colour = 0xffff;
+ }
+ for( n_coord = 0; n_coord < m_n_debugcoord; n_coord++ )
+ {
+ PAIR n_x;
+ PAIR n_y;
+ INT32 n_xstart;
+ INT32 n_ystart;
+ INT32 n_xend;
+ INT32 n_yend;
+ INT32 n_xlen;
+ INT32 n_ylen;
+ INT32 n_len;
+ INT32 n_dx;
+ INT32 n_dy;
+
+ n_xstart = m_n_debugcoordx[ n_coord ];
+ n_xend = n_coordx;
+ if( n_xend > n_xstart )
+ {
+ n_xlen = n_xend - n_xstart;
+ }
+ else
+ {
+ n_xlen = n_xstart - n_xend;
+ }
+
+ n_ystart = m_n_debugcoordy[ n_coord ];
+ n_yend = n_coordy;
+ if( n_yend > n_ystart )
+ {
+ n_ylen = n_yend - n_ystart;
+ }
+ else
+ {
+ n_ylen = n_ystart - n_yend;
+ }
+
+ if( n_xlen > n_ylen )
+ {
+ n_len = n_xlen;
+ }
+ else
+ {
+ n_len = n_ylen;
+ }
+
+ n_x.w.h = n_xstart; n_x.w.l = 0;
+ n_y.w.h = n_ystart; n_y.w.l = 0;
+
+ if( n_len == 0 )
+ {
+ n_len = 1;
+ }
+
+ n_dx = (INT32)( ( n_xend << 16 ) - n_x.d ) / n_len;
+ n_dy = (INT32)( ( n_yend << 16 ) - n_y.d ) / n_len;
+ while( n_len > 0 )
+ {
+ if( (INT16)n_x.w.h >= 0 &&
+ (INT16)n_y.w.h >= 0 &&
+ (INT16)n_x.w.h <= Machine->screen[0].width - 1 &&
+ (INT16)n_y.w.h <= Machine->screen[0].height - 1 )
+ {
+ if( *BITMAP_ADDR16(debugmesh, n_y.w.h, n_x.w.h) != 0xffff )
+ {
+ *BITMAP_ADDR16(debugmesh, n_y.w.h, n_x.w.h) = n_colour;
+ }
+ }
+ n_x.d += n_dx;
+ n_y.d += n_dy;
+ n_len--;
+ }
+ }
+}
+
+static void DebugMeshEnd( void )
+{
+ m_n_debugcoord = 0;
+}
+
+static void DebugCheckKeys( void )
+{
+ if( input_code_pressed_once( KEYCODE_M ) )
+ {
+ m_b_debugmesh = !m_b_debugmesh;
+ }
+ if( input_code_pressed_once( KEYCODE_V ) )
+ {
+ m_b_debugtexture = !m_b_debugtexture;
+ }
+ if( m_b_debugmesh || m_b_debugtexture )
+ {
+ video_screen_set_visarea(0, 0, Machine->screen[0].width - 1, 0, Machine->screen[0].height - 1 );
+ }
+ else
+ {
+ video_screen_set_visarea(0, 0, m_n_screenwidth - 1, 0, m_n_screenheight - 1 );
+ }
+
+ if( input_code_pressed_once( KEYCODE_I ) )
+ {
+ if( m_b_debugtexture )
+ {
+ m_n_debuginterleave++;
+ if( m_n_debuginterleave == 2 )
+ {
+ m_n_debuginterleave = -1;
+ }
+ if( m_n_debuginterleave == -1 )
+ {
+ popmessage( "interleave off" );
+ }
+ else if( m_n_debuginterleave == 0 )
+ {
+ popmessage( "4 bit interleave" );
+ }
+ else if( m_n_debuginterleave == 1 )
+ {
+ popmessage( "8 bit interleave" );
+ }
+ }
+ else
+ {
+ m_n_debugskip++;
+ if( m_n_debugskip > 15 )
+ {
+ m_n_debugskip = 0;
+ }
+ popmessage( "debug skip %d", m_n_debugskip );
+ }
+ }
+
+#if 0
+ if( input_code_pressed_once( KEYCODE_D ) )
+ {
+ FILE *f;
+ int n_x;
+ f = fopen( "dump.txt", "w" );
+ for( n_y = 256; n_y < 512; n_y++ )
+ {
+ for( n_x = 640; n_x < 1024; n_x++ )
+ {
+ fprintf( f, "%04u,%04u = %04x\n", n_y, n_x, m_p_p_vram[ n_y ][ n_x ] );
+ }
+ }
+ fclose( f );
+ }
+ if( input_code_pressed_once( KEYCODE_S ) )
+ {
+ FILE *f;
+ popmessage( "saving..." );
+ f = fopen( "VRAM.BIN", "wb" );
+ for( n_y = 0; n_y < 1024; n_y++ )
+ {
+ fwrite( m_p_p_vram[ n_y ], 1024 * 2, 1, f );
+ }
+ fclose( f );
+ }
+ if( input_code_pressed_once( KEYCODE_L ) )
+ {
+ FILE *f;
+ popmessage( "loading..." );
+ f = fopen( "VRAM.BIN", "rb" );
+ for( n_y = 0; n_y < 1024; n_y++ )
+ {
+ fread( m_p_p_vram[ n_y ], 1024 * 2, 1, f );
+ }
+ fclose( f );
+ }
+#endif
+}
+
+static int DebugMeshDisplay( mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ if( m_b_debugmesh )
+ {
+ copybitmap( bitmap, debugmesh, 0, 0, 0, 0, cliprect, TRANSPARENCY_NONE, 0 );
+ }
+ m_b_debugclear = 1;
+ return m_b_debugmesh;
+}
+
+static int DebugTextureDisplay( mame_bitmap *bitmap )
+{
+ UINT32 n_y;
+
+ if( m_b_debugtexture )
+ {
+ for( n_y = 0; n_y < Machine->screen[0].height; n_y++ )
+ {
+ int n_x;
+ int n_xi;
+ int n_yi;
+ UINT16 p_n_interleave[ 1024 ];
+
+ for( n_x = 0; n_x < Machine->screen[0].width; n_x++ )
+ {
+ if( m_n_debuginterleave == 0 )
+ {
+ n_xi = ( n_x & ~0x3c ) + ( ( n_y << 2 ) & 0x3c );
+ n_yi = ( n_y & ~0xf ) + ( ( n_x >> 2 ) & 0xf );
+ }
+ else if( m_n_debuginterleave == 1 )
+ {
+ n_xi = ( n_x & ~0x78 ) + ( ( n_x << 3 ) & 0x40 ) + ( ( n_y << 3 ) & 0x38 ); \
+ n_yi = ( n_y & ~0x7 ) + ( ( n_x >> 4 ) & 0x7 ); \
+ }
+ else
+ {
+ n_xi = n_x;
+ n_yi = n_y;
+ }
+ p_n_interleave[ n_x ] = m_p_p_vram[ n_yi ][ n_xi ];
+ }
+ draw_scanline16( bitmap, 0, n_y, Machine->screen[0].width, p_n_interleave, Machine->pens, -1 );
+ }
+ }
+ return m_b_debugtexture;
+}
+
+#endif
+
+static void updatevisiblearea( void )
+{
+ rectangle visarea;
+ float refresh;
+
+ if( ( m_n_gpustatus & ( 1 << 0x14 ) ) != 0 )
+ {
+ /* pal */
+ refresh = 50;
+ switch( ( m_n_gpustatus >> 0x13 ) & 1 )
+ {
+ case 0:
+ m_n_screenheight = 256;
+ break;
+ case 1:
+ m_n_screenheight = 512;
+ break;
+ }
+ }
+ else
+ {
+ /* ntsc */
+ refresh = 60;
+ switch( ( m_n_gpustatus >> 0x13 ) & 1 )
+ {
+ case 0:
+ m_n_screenheight = 240;
+ break;
+ case 1:
+ m_n_screenheight = 480;
+ break;
+ }
+ }
+ switch( ( m_n_gpustatus >> 0x11 ) & 3 )
+ {
+ case 0:
+ switch( ( m_n_gpustatus >> 0x10 ) & 1 )
+ {
+ case 0:
+ m_n_screenwidth = 256;
+ break;
+ case 1:
+ m_n_screenwidth = 368;
+ break;
+ }
+ break;
+ case 1:
+ switch( ( m_n_gpustatus >> 0x10 ) & 1 )
+ {
+ case 0:
+ m_n_screenwidth = 320;
+ break;
+ case 1:
+ m_n_screenwidth = 384;
+ break;
+ }
+ break;
+ case 2:
+ m_n_screenwidth = 512;
+ break;
+ case 3:
+ m_n_screenwidth = 640;
+ break;
+ }
+ visarea.min_x = visarea.min_y = 0;
+ visarea.max_x = m_n_screenwidth - 1;
+ visarea.max_y = m_n_screenheight - 1;
+ video_screen_configure(0, m_n_screenwidth, m_n_screenheight, &visarea, HZ_TO_ATTOSECONDS(refresh));
+}
+
+static void psx_gpu_init( void )
+{
+ int n_line;
+ int n_level;
+ int n_level2;
+ int n_shade;
+ int n_shaded;
+
+#if defined( MAME_DEBUG )
+ DebugMeshInit();
+#endif
+
+ m_n_gpustatus = 0x14802000;
+ m_n_gpuinfo = 0;
+ m_n_gpu_buffer_offset = 0;
+ m_n_lightgun_x = 0;
+ m_n_lightgun_y = 0;
+
+ m_n_vram_size = Machine->screen[0].width * Machine->screen[0].height;
+ m_p_vram = auto_malloc( m_n_vram_size * 2 );
+ memset( m_p_vram, 0x00, m_n_vram_size * 2 );
+
+ for( n_line = 0; n_line < 1024; n_line++ )
+ {
+ m_p_p_vram[ n_line ] = &m_p_vram[ ( n_line % Machine->screen[0].height ) * Machine->screen[0].width ];
+ }
+
+ for( n_level = 0; n_level < MAX_LEVEL; n_level++ )
+ {
+ for( n_shade = 0; n_shade < MAX_SHADE; n_shade++ )
+ {
+ /* shaded */
+ n_shaded = ( n_level * n_shade ) / MID_SHADE;
+ if( n_shaded > MAX_LEVEL - 1 )
+ {
+ n_shaded = MAX_LEVEL - 1;
+ }
+ m_p_n_redshade[ ( n_level * MAX_SHADE ) | n_shade ] = n_shaded;
+ m_p_n_greenshade[ ( n_level * MAX_SHADE ) | n_shade ] = n_shaded << 5;
+ m_p_n_blueshade[ ( n_level * MAX_SHADE ) | n_shade ] = n_shaded << 10;
+
+ /* 1/4 x transparency */
+ n_shaded = ( n_level * n_shade ) / MID_SHADE;
+ n_shaded >>= 2;
+ if( n_shaded > MAX_LEVEL - 1 )
+ {
+ n_shaded = MAX_LEVEL - 1;
+ }
+ m_p_n_f025[ ( n_level * MAX_SHADE ) | n_shade ] = n_shaded;
+
+ /* 1/2 x transparency */
+ n_shaded = ( n_level * n_shade ) / MID_SHADE;
+ n_shaded >>= 1;
+ if( n_shaded > MAX_LEVEL - 1 )
+ {
+ n_shaded = MAX_LEVEL - 1;
+ }
+ m_p_n_f05[ ( n_level * MAX_SHADE ) | n_shade ] = n_shaded;
+
+ /* 1 x transparency */
+ n_shaded = ( n_level * n_shade ) / MID_SHADE;
+ if( n_shaded > MAX_LEVEL - 1 )
+ {
+ n_shaded = MAX_LEVEL - 1;
+ }
+ m_p_n_f1[ ( n_level * MAX_SHADE ) | n_shade ] = n_shaded;
+ }
+ }
+
+ for( n_level = 0; n_level < 0x10000; n_level++ )
+ {
+ m_p_n_redlevel[ n_level ] = ( n_level & ( MAX_LEVEL - 1 ) ) * MAX_SHADE;
+ m_p_n_greenlevel[ n_level ] = ( ( n_level >> 5 ) & ( MAX_LEVEL - 1 ) ) * MAX_SHADE;
+ m_p_n_bluelevel[ n_level ] = ( ( n_level >> 10 ) & ( MAX_LEVEL - 1 ) ) * MAX_SHADE;
+
+ /* 0.5 * background */
+ m_p_n_redb05[ n_level ] = ( ( n_level & ( MAX_LEVEL - 1 ) ) / 2 ) * MAX_LEVEL;
+ m_p_n_greenb05[ n_level ] = ( ( ( n_level >> 5 ) & ( MAX_LEVEL - 1 ) ) / 2 ) * MAX_LEVEL;
+ m_p_n_blueb05[ n_level ] = ( ( ( n_level >> 10 ) & ( MAX_LEVEL - 1 ) ) / 2 ) * MAX_LEVEL;
+
+ /* 1 * background */
+ m_p_n_redb1[ n_level ] = ( n_level & ( MAX_LEVEL - 1 ) ) * MAX_LEVEL;
+ m_p_n_greenb1[ n_level ] = ( ( n_level >> 5 ) & ( MAX_LEVEL - 1 ) ) * MAX_LEVEL;
+ m_p_n_blueb1[ n_level ] = ( ( n_level >> 10 ) & ( MAX_LEVEL - 1 ) ) * MAX_LEVEL;
+
+ /* 24bit to 15 bit conversion */
+ m_p_n_g0r0[ n_level ] = ( ( ( n_level >> 11 ) & ( MAX_LEVEL - 1 ) ) << 5 ) | ( ( ( n_level >> 3 ) & ( MAX_LEVEL - 1 ) ) << 0 );
+ m_p_n_b0[ n_level ] = ( ( n_level >> 3 ) & ( MAX_LEVEL - 1 ) ) << 10;
+ m_p_n_r1[ n_level ] = ( ( n_level >> 11 ) & ( MAX_LEVEL - 1 ) ) << 0;
+ m_p_n_b1g1[ n_level ] = ( ( ( n_level >> 11 ) & ( MAX_LEVEL - 1 ) ) << 10 ) | ( ( ( n_level >> 3 ) & ( MAX_LEVEL - 1 ) ) << 5 );
+ }
+
+ for( n_level = 0; n_level < MAX_LEVEL; n_level++ )
+ {
+ for( n_level2 = 0; n_level2 < MAX_LEVEL; n_level2++ )
+ {
+ /* add transparency */
+ n_shaded = ( n_level + n_level2 );
+ if( n_shaded > MAX_LEVEL - 1 )
+ {
+ n_shaded = MAX_LEVEL - 1;
+ }
+ m_p_n_redaddtrans[ ( n_level * MAX_LEVEL ) | n_level2 ] = n_shaded;
+ m_p_n_greenaddtrans[ ( n_level * MAX_LEVEL ) | n_level2 ] = n_shaded << 5;
+ m_p_n_blueaddtrans[ ( n_level * MAX_LEVEL ) | n_level2 ] = n_shaded << 10;
+
+ /* sub transparency */
+ n_shaded = ( n_level - n_level2 );
+ if( n_shaded < 0 )
+ {
+ n_shaded = 0;
+ }
+ m_p_n_redsubtrans[ ( n_level * MAX_LEVEL ) | n_level2 ] = n_shaded;
+ m_p_n_greensubtrans[ ( n_level * MAX_LEVEL ) | n_level2 ] = n_shaded << 5;
+ m_p_n_bluesubtrans[ ( n_level * MAX_LEVEL ) | n_level2 ] = n_shaded << 10;
+ }
+ }
+
+ // icky!!!
+ state_save_register_memory( "globals", 0, "m_packet", (UINT8 *)&m_packet, 1, sizeof( m_packet ) );
+
+ state_save_register_global_pointer( m_p_vram, m_n_vram_size );
+ state_save_register_global( m_n_gpu_buffer_offset );
+ state_save_register_global( m_n_vramx );
+ state_save_register_global( m_n_vramy );
+ state_save_register_global( m_n_twy );
+ state_save_register_global( m_n_twx );
+ state_save_register_global( m_n_tww );
+ state_save_register_global( m_n_drawarea_x1 );
+ state_save_register_global( m_n_drawarea_y1 );
+ state_save_register_global( m_n_drawarea_x2 );
+ state_save_register_global( m_n_drawarea_y2 );
+ state_save_register_global( m_n_horiz_disstart );
+ state_save_register_global( m_n_horiz_disend );
+ state_save_register_global( m_n_vert_disstart );
+ state_save_register_global( m_n_vert_disend );
+ state_save_register_global( m_b_reverseflag );
+ state_save_register_global( m_n_drawoffset_x );
+ state_save_register_global( m_n_drawoffset_y );
+ state_save_register_global( m_n_displaystartx );
+ state_save_register_global( m_n_displaystarty );
+ state_save_register_global( m_n_gpustatus );
+ state_save_register_global( m_n_gpuinfo );
+ state_save_register_global( m_n_lightgun_x );
+ state_save_register_global( m_n_lightgun_y );
+ state_save_register_global( psxgpu.n_tx );
+ state_save_register_global( psxgpu.n_ty );
+ state_save_register_global( psxgpu.n_abr );
+ state_save_register_global( psxgpu.n_tp );
+ state_save_register_global( psxgpu.n_ix );
+ state_save_register_global( psxgpu.n_iy );
+ state_save_register_global( psxgpu.n_ti );
+
+ state_save_register_func_postload( updatevisiblearea );
+}
+
+VIDEO_START( psx_type1 )
+{
+ m_n_gputype = 1;
+ psx_gpu_init();
+}
+
+VIDEO_START( psx_type2 )
+{
+ m_n_gputype = 2;
+ psx_gpu_init();
+}
+
+VIDEO_UPDATE( psx )
+{
+ UINT32 n_x;
+ UINT32 n_y;
+ int n_top;
+ int n_line;
+ int n_lines;
+ int n_left;
+ int n_column;
+ int n_columns;
+ int n_displaystartx;
+ int n_overscantop;
+ int n_overscanleft;
+
+#if defined( MAME_DEBUG )
+ if( DebugMeshDisplay( bitmap, cliprect ) )
+ {
+ return 0;
+ }
+ if( DebugTextureDisplay( bitmap ) )
+ {
+ return 0;
+ }
+#endif
+
+ if( ( m_n_gpustatus & ( 1 << 0x17 ) ) != 0 )
+ {
+ /* todo: only draw to necessary area */
+ fillbitmap( bitmap, 0, cliprect );
+ }
+ else
+ {
+ if( m_b_reverseflag )
+ {
+ n_displaystartx = ( 1023 - m_n_displaystartx );
+ /* todo: make this flip the screen, in the meantime.. */
+ n_displaystartx -= ( m_n_screenwidth - 1 );
+ }
+ else
+ {
+ n_displaystartx = m_n_displaystartx;
+ }
+
+ if( ( m_n_gpustatus & ( 1 << 0x14 ) ) != 0 )
+ {
+ /* pal */
+ n_overscantop = 0x23;
+ n_overscanleft = 0x27e;
+ }
+ else
+ {
+ /* ntsc */
+ n_overscantop = 0x10;
+ n_overscanleft = 0x260;
+ }
+
+ n_top = (INT32)m_n_vert_disstart - n_overscantop;
+ n_lines = (INT32)m_n_vert_disend - (INT32)m_n_vert_disstart;
+ if( n_top < 0 )
+ {
+ n_y = -n_top;
+ n_lines += n_top;
+ }
+ else
+ {
+ /* todo: draw top border */
+ n_y = 0;
+ }
+ if( ( m_n_gpustatus & ( 1 << 0x16 ) ) != 0 )
+ {
+ /* interlaced */
+ n_lines *= 2;
+ }
+ if( n_lines > m_n_screenheight - ( n_y + n_top ) )
+ {
+ n_lines = m_n_screenheight - ( n_y + n_top );
+ }
+ else
+ {
+ /* todo: draw bottom border */
+ }
+
+ n_left = ( ( (INT32)m_n_horiz_disstart - n_overscanleft ) * (INT32)m_n_screenwidth ) / 2560;
+ n_columns = ( ( ( (INT32)m_n_horiz_disend - m_n_horiz_disstart ) * (INT32)m_n_screenwidth ) / 2560 );
+ if( n_left < 0 )
+ {
+ n_x = -n_left;
+ n_columns += n_left;
+ }
+ else
+ {
+ /* todo: draw left border */
+ n_x = 0;
+ }
+ if( n_columns > m_n_screenwidth - ( n_x + n_left ) )
+ {
+ n_columns = m_n_screenwidth - ( n_x + n_left );
+ }
+ else
+ {
+ /* todo: draw right border */
+ }
+
+ if( ( m_n_gpustatus & ( 1 << 0x15 ) ) != 0 )
+ {
+ /* 24bit */
+ n_line = n_lines;
+ while( n_line > 0 )
+ {
+ UINT16 *p_n_src = m_p_p_vram[ n_y + m_n_displaystarty ] + n_x + n_displaystartx;
+ UINT16 *p_n_dest = BITMAP_ADDR16(bitmap, n_y + n_top, n_x + n_left);
+
+ n_column = n_columns;
+ while( n_column > 0 )
+ {
+ UINT32 n_g0r0 = *( p_n_src++ );
+ UINT32 n_r1b0 = *( p_n_src++ );
+ UINT32 n_b1g1 = *( p_n_src++ );
+
+ *( p_n_dest++ ) = m_p_n_g0r0[ n_g0r0 ] | m_p_n_b0[ n_r1b0 ];
+ n_column--;
+ if( n_column > 0 )
+ {
+ *( p_n_dest++ ) = m_p_n_r1[ n_r1b0 ] | m_p_n_b1g1[ n_b1g1 ];
+ n_column--;
+ }
+ }
+ n_y++;
+ n_line--;
+ }
+ }
+ else
+ {
+ /* 15bit */
+ n_line = n_lines;
+ while( n_line > 0 )
+ {
+ draw_scanline16( bitmap, n_x + n_left, n_y + n_top, n_columns, m_p_p_vram[ n_y + m_n_displaystarty ] + n_x + n_displaystartx, machine->pens, -1 );
+ n_y++;
+ n_line--;
+ }
+ }
+ }
+ return 0;
+}
+
+#define WRITE_PIXEL( p ) *( p_vram ) = p
+
+/*
+type 1
+f e| d| c b| a 9| 8 7| 6 5| 4| 3 2 1 0
+ |ti| | tp| abr| ty| | tx
+*/
+
+/*
+type 2
+f e| d c| b| a 9| 8 7| 6 5| 4| 3 2 1 0
+ |iy|ix|ty| | tp| abr|ty| tx
+*/
+
+INLINE void decode_tpage( struct PSXGPU *p_psxgpu, UINT32 tpage )
+{
+ if( m_n_gputype == 2 )
+ {
+ m_n_gpustatus = ( m_n_gpustatus & 0xfffff800 ) | ( tpage & 0x7ff );
+
+ p_psxgpu->n_tx = ( tpage & 0x0f ) << 6;
+ p_psxgpu->n_ty = ( ( tpage & 0x10 ) << 4 ) | ( ( tpage & 0x800 ) >> 2 );
+ p_psxgpu->n_abr = ( tpage & 0x60 ) >> 5;
+ p_psxgpu->n_tp = ( tpage & 0x180 ) >> 7;
+ p_psxgpu->n_ix = ( tpage & 0x1000 ) >> 12;
+ p_psxgpu->n_iy = ( tpage & 0x2000 ) >> 13;
+ p_psxgpu->n_ti = 0;
+ if( ( tpage & ~0x39ff ) != 0 )
+ {
+ verboselog( 1, "not handled: draw mode %08x\n", tpage & ~0x39ff );
+ }
+ if( p_psxgpu->n_tp == 3 )
+ {
+ verboselog( 0, "not handled: tp == 3\n" );
+ }
+ }
+ else
+ {
+ m_n_gpustatus = ( m_n_gpustatus & 0xffffe000 ) | ( tpage & 0x1fff );
+
+ p_psxgpu->n_tx = ( tpage & 0x0f ) << 6;
+ p_psxgpu->n_ty = ( ( tpage & 0x60 ) << 3 );
+ p_psxgpu->n_abr = ( tpage & 0x180 ) >> 7;
+ p_psxgpu->n_tp = ( tpage & 0x600 ) >> 9;
+ p_psxgpu->n_ti = ( tpage & 0x2000 ) >> 13;
+ p_psxgpu->n_ix = 0;
+ p_psxgpu->n_iy = 0;
+ if( ( tpage & ~0x27ef ) != 0 )
+ {
+ verboselog( 1, "not handled: draw mode %08x\n", tpage & ~0x27ef );
+ }
+ if( p_psxgpu->n_tp == 3 )
+ {
+ verboselog( 0, "not handled: tp == 3\n" );
+ }
+ else if( p_psxgpu->n_tp == 2 && p_psxgpu->n_ti != 0 )
+ {
+ verboselog( 0, "not handled: interleaved 15 bit texture\n" );
+ }
+ }
+}
+
+#define SPRITESETUP \
+ if( psxgpu.n_iy != 0 ) \
+ { \
+ n_dv = -1; \
+ } \
+ else \
+ { \
+ n_dv = 1; \
+ } \
+ if( psxgpu.n_ix != 0 ) \
+ { \
+ n_du = -1; \
+ } \
+ else \
+ { \
+ n_du = 1; \
+ }
+
+#define TRANSPARENCYSETUP \
+ p_n_f = m_p_n_f1; \
+ p_n_redb = m_p_n_redb1; \
+ p_n_greenb = m_p_n_greenb1; \
+ p_n_blueb = m_p_n_blueb1; \
+ p_n_redtrans = m_p_n_redaddtrans; \
+ p_n_greentrans = m_p_n_greenaddtrans; \
+ p_n_bluetrans = m_p_n_blueaddtrans; \
+ \
+ switch( n_cmd & 0x02 ) \
+ { \
+ case 0x02: \
+ switch( psxgpu.n_abr ) \
+ { \
+ case 0x00: \
+ p_n_f = m_p_n_f05; \
+ p_n_redb = m_p_n_redb05; \
+ p_n_greenb = m_p_n_greenb05; \
+ p_n_blueb = m_p_n_blueb05; \
+ p_n_redtrans = m_p_n_redaddtrans; \
+ p_n_greentrans = m_p_n_greenaddtrans; \
+ p_n_bluetrans = m_p_n_blueaddtrans; \
+ verboselog( 2, "Transparency Mode: 0.5*B + 0.5*F\n" ); \
+ break; \
+ case 0x01: \
+ p_n_f = m_p_n_f1; \
+ p_n_redb = m_p_n_redb1; \
+ p_n_greenb = m_p_n_greenb1; \
+ p_n_blueb = m_p_n_blueb1; \
+ p_n_redtrans = m_p_n_redaddtrans; \
+ p_n_greentrans = m_p_n_greenaddtrans; \
+ p_n_bluetrans = m_p_n_blueaddtrans; \
+ verboselog( 2, "Transparency Mode: 1.0*B + 1.0*F\n" ); \
+ break; \
+ case 0x02: \
+ p_n_f = m_p_n_f1; \
+ p_n_redb = m_p_n_redb1; \
+ p_n_greenb = m_p_n_greenb1; \
+ p_n_blueb = m_p_n_blueb1; \
+ p_n_redtrans = m_p_n_redsubtrans; \
+ p_n_greentrans = m_p_n_greensubtrans; \
+ p_n_bluetrans = m_p_n_bluesubtrans; \
+ verboselog( 2, "Transparency Mode: 1.0*B - 1.0*F\n" ); \
+ break; \
+ case 0x03: \
+ p_n_f = m_p_n_f025; \
+ p_n_redb = m_p_n_redb1; \
+ p_n_greenb = m_p_n_greenb1; \
+ p_n_blueb = m_p_n_blueb1; \
+ p_n_redtrans = m_p_n_redaddtrans; \
+ p_n_greentrans = m_p_n_greenaddtrans; \
+ p_n_bluetrans = m_p_n_blueaddtrans; \
+ verboselog( 2, "Transparency Mode: 1.0*B + 0.25*F\n" ); \
+ break; \
+ } \
+ break; \
+ }
+
+#define SOLIDSETUP \
+ TRANSPARENCYSETUP
+
+#define TEXTURESETUP \
+ n_tx = psxgpu.n_tx; \
+ n_ty = psxgpu.n_ty; \
+ p_clut = m_p_p_vram[ n_cluty ] + n_clutx; \
+ switch( psxgpu.n_tp ) \
+ { \
+ case 0: \
+ n_tx += m_n_twx >> 2; \
+ n_ty += m_n_twy; \
+ break; \
+ case 1: \
+ n_tx += m_n_twx >> 1; \
+ n_ty += m_n_twy; \
+ break; \
+ case 2: \
+ n_tx += m_n_twx >> 0; \
+ n_ty += m_n_twy; \
+ break; \
+ } \
+ TRANSPARENCYSETUP
+
+#define FLATPOLYGONUPDATE
+#define FLATRECTANGEUPDATE
+#define GOURAUDPOLYGONUPDATE \
+ n_r.d += n_dr; \
+ n_g.d += n_dg; \
+ n_b.d += n_db;
+
+#define SOLIDFILL( PIXELUPDATE ) \
+ if( n_distance > ( (INT32)m_n_drawarea_x2 - n_x ) + 1 ) \
+ { \
+ n_distance = ( m_n_drawarea_x2 - n_x ) + 1; \
+ } \
+ p_vram = m_p_p_vram[ n_y ] + n_x; \
+ \
+ switch( n_cmd & 0x02 ) \
+ { \
+ case 0x00: \
+ /* transparency off */ \
+ while( n_distance > 0 ) \
+ { \
+ WRITE_PIXEL( \
+ m_p_n_redshade[ MID_LEVEL | n_r.w.h ] | \
+ m_p_n_greenshade[ MID_LEVEL | n_g.w.h ] | \
+ m_p_n_blueshade[ MID_LEVEL | n_b.w.h ] ); \
+ p_vram++; \
+ PIXELUPDATE \
+ n_distance--; \
+ } \
+ break; \
+ case 0x02: \
+ /* transparency on */ \
+ while( n_distance > 0 ) \
+ { \
+ WRITE_PIXEL( \
+ p_n_redtrans[ p_n_f[ MID_LEVEL | n_r.w.h ] | p_n_redb[ *( p_vram ) ] ] | \
+ p_n_greentrans[ p_n_f[ MID_LEVEL | n_g.w.h ] | p_n_greenb[ *( p_vram ) ] ] | \
+ p_n_bluetrans[ p_n_f[ MID_LEVEL | n_b.w.h ] | p_n_blueb[ *( p_vram ) ] ] ); \
+ p_vram++; \
+ PIXELUPDATE \
+ n_distance--; \
+ } \
+ break; \
+ } \
+
+#define FLATTEXTUREDPOLYGONUPDATE \
+ n_u.d += n_du; \
+ n_v.d += n_dv;
+
+#define GOURAUDTEXTUREDPOLYGONUPDATE \
+ n_r.d += n_dr; \
+ n_g.d += n_dg; \
+ n_b.d += n_db; \
+ n_u.d += n_du; \
+ n_v.d += n_dv;
+
+#define FLATTEXTUREDRECTANGLEUPDATE \
+ n_u += n_du;
+
+#define TEXTURE4BIT( TXV, TXU ) \
+ while( n_distance > 0 ) \
+ { \
+ n_bgr = p_clut[ ( *( m_p_p_vram[ n_ty + TXV ] + n_tx + ( TXU >> 2 ) ) >> ( ( TXU & 0x03 ) << 2 ) ) & 0x0f ];
+
+#define TEXTURE8BIT( TXV, TXU ) \
+ while( n_distance > 0 ) \
+ { \
+ n_bgr = p_clut[ ( *( m_p_p_vram[ n_ty + TXV ] + n_tx + ( TXU >> 1 ) ) >> ( ( TXU & 0x01 ) << 3 ) ) & 0xff ];
+
+#define TEXTURE15BIT( TXV, TXU ) \
+ while( n_distance > 0 ) \
+ { \
+ n_bgr = *( m_p_p_vram[ n_ty + TXV ] + n_tx + TXU );
+
+#define TEXTUREWINDOW4BIT( TXV, TXU ) TEXTURE4BIT( ( TXV & m_n_twh ), ( TXU & m_n_tww ) )
+#define TEXTUREWINDOW8BIT( TXV, TXU ) TEXTURE8BIT( ( TXV & m_n_twh ), ( TXU & m_n_tww ) )
+#define TEXTUREWINDOW15BIT( TXV, TXU ) TEXTURE15BIT( ( TXV & m_n_twh ), ( TXU & m_n_tww ) )
+
+#define TEXTUREINTERLEAVED4BIT( TXV, TXU ) \
+ while( n_distance > 0 ) \
+ { \
+ int n_xi = ( ( TXU >> 2 ) & ~0x3c ) + ( ( TXV << 2 ) & 0x3c ); \
+ int n_yi = ( TXV & ~0xf ) + ( ( TXU >> 4 ) & 0xf ); \
+ n_bgr = p_clut[ ( *( m_p_p_vram[ n_ty + n_yi ] + n_tx + n_xi ) >> ( ( TXU & 0x03 ) << 2 ) ) & 0x0f ];
+
+#define TEXTUREINTERLEAVED8BIT( TXV, TXU ) \
+ while( n_distance > 0 ) \
+ { \
+ int n_xi = ( ( TXU >> 1 ) & ~0x78 ) + ( ( TXU << 2 ) & 0x40 ) + ( ( TXV << 3 ) & 0x38 ); \
+ int n_yi = ( TXV & ~0x7 ) + ( ( TXU >> 5 ) & 0x7 ); \
+ n_bgr = p_clut[ ( *( m_p_p_vram[ n_ty + n_yi ] + n_tx + n_xi ) >> ( ( TXU & 0x01 ) << 3 ) ) & 0xff ];
+
+#define TEXTUREINTERLEAVED15BIT( TXV, TXU ) \
+ while( n_distance > 0 ) \
+ { \
+ int n_xi = TXU; \
+ int n_yi = TXV; \
+ n_bgr = *( m_p_p_vram[ n_ty + n_yi ] + n_tx + n_xi );
+
+#define TEXTUREWINDOWINTERLEAVED4BIT( TXV, TXU ) TEXTUREINTERLEAVED4BIT( ( TXV & m_n_twh ), ( TXU & m_n_tww ) )
+#define TEXTUREWINDOWINTERLEAVED8BIT( TXV, TXU ) TEXTUREINTERLEAVED8BIT( ( TXV & m_n_twh ), ( TXU & m_n_tww ) )
+#define TEXTUREWINDOWINTERLEAVED15BIT( TXV, TXU ) TEXTUREINTERLEAVED15BIT( ( TXV & m_n_twh ), ( TXU & m_n_tww ) )
+
+#define SHADEDPIXEL( PIXELUPDATE ) \
+ if( n_bgr != 0 ) \
+ { \
+ WRITE_PIXEL( \
+ m_p_n_redshade[ m_p_n_redlevel[ n_bgr ] | n_r.w.h ] | \
+ m_p_n_greenshade[ m_p_n_greenlevel[ n_bgr ] | n_g.w.h ] | \
+ m_p_n_blueshade[ m_p_n_bluelevel[ n_bgr ] | n_b.w.h ] ); \
+ } \
+ p_vram++; \
+ PIXELUPDATE \
+ n_distance--; \
+ }
+
+#define TRANSPARENTPIXEL( PIXELUPDATE ) \
+ if( n_bgr != 0 ) \
+ { \
+ if( ( n_bgr & 0x8000 ) != 0 ) \
+ { \
+ WRITE_PIXEL( \
+ p_n_redtrans[ p_n_f[ m_p_n_redlevel[ n_bgr ] | n_r.w.h ] | p_n_redb[ *( p_vram ) ] ] | \
+ p_n_greentrans[ p_n_f[ m_p_n_greenlevel[ n_bgr ] | n_g.w.h ] | p_n_greenb[ *( p_vram ) ] ] | \
+ p_n_bluetrans[ p_n_f[ m_p_n_bluelevel[ n_bgr ] | n_b.w.h ] | p_n_blueb[ *( p_vram ) ] ] ); \
+ } \
+ else \
+ { \
+ WRITE_PIXEL( \
+ m_p_n_redshade[ m_p_n_redlevel[ n_bgr ] | n_r.w.h ] | \
+ m_p_n_greenshade[ m_p_n_greenlevel[ n_bgr ] | n_g.w.h ] | \
+ m_p_n_blueshade[ m_p_n_bluelevel[ n_bgr ] | n_b.w.h ] ); \
+ } \
+ } \
+ p_vram++; \
+ PIXELUPDATE \
+ n_distance--; \
+ }
+
+#define TEXTUREFILL( PIXELUPDATE, TXU, TXV ) \
+ if( n_distance > ( (INT32)m_n_drawarea_x2 - n_x ) + 1 ) \
+ { \
+ n_distance = ( m_n_drawarea_x2 - n_x ) + 1; \
+ } \
+ p_vram = m_p_p_vram[ n_y ] + n_x; \
+ \
+ if( psxgpu.n_ti != 0 ) \
+ { \
+ /* interleaved texture */ \
+ if( m_n_twh != 255 || \
+ m_n_tww != 255 || \
+ m_n_twx != 0 || \
+ m_n_twy != 0 ) \
+ { \
+ /* texture window */ \
+ switch( n_cmd & 0x02 ) \
+ { \
+ case 0x00: \
+ /* shading */ \
+ switch( psxgpu.n_tp ) \
+ { \
+ case 0: \
+ /* 4 bit clut */ \
+ TEXTUREWINDOWINTERLEAVED4BIT( TXV, TXU ) \
+ SHADEDPIXEL( PIXELUPDATE ) \
+ break; \
+ case 1: \
+ /* 8 bit clut */ \
+ TEXTUREWINDOWINTERLEAVED8BIT( TXV, TXU ) \
+ SHADEDPIXEL( PIXELUPDATE ) \
+ break; \
+ case 2: \
+ /* 15 bit */ \
+ TEXTUREWINDOWINTERLEAVED15BIT( TXV, TXU ) \
+ SHADEDPIXEL( PIXELUPDATE ) \
+ break; \
+ } \
+ break; \
+ case 0x02: \
+ /* semi transparency */ \
+ switch( psxgpu.n_tp ) \
+ { \
+ case 0: \
+ /* 4 bit clut */ \
+ TEXTUREWINDOWINTERLEAVED4BIT( TXV, TXU ) \
+ TRANSPARENTPIXEL( PIXELUPDATE ) \
+ break; \
+ case 1: \
+ /* 8 bit clut */ \
+ TEXTUREWINDOWINTERLEAVED8BIT( TXV, TXU ) \
+ TRANSPARENTPIXEL( PIXELUPDATE ) \
+ break; \
+ case 2: \
+ /* 15 bit */ \
+ TEXTUREWINDOWINTERLEAVED15BIT( TXV, TXU ) \
+ TRANSPARENTPIXEL( PIXELUPDATE ) \
+ break; \
+ } \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* no texture window */ \
+ switch( n_cmd & 0x02 ) \
+ { \
+ case 0x00: \
+ /* shading */ \
+ switch( psxgpu.n_tp ) \
+ { \
+ case 0: \
+ /* 4 bit clut */ \
+ TEXTUREINTERLEAVED4BIT( TXV, TXU ) \
+ SHADEDPIXEL( PIXELUPDATE ) \
+ break; \
+ case 1: \
+ /* 8 bit clut */ \
+ TEXTUREINTERLEAVED8BIT( TXV, TXU ) \
+ SHADEDPIXEL( PIXELUPDATE ) \
+ break; \
+ case 2: \
+ /* 15 bit */ \
+ TEXTUREINTERLEAVED15BIT( TXV, TXU ) \
+ SHADEDPIXEL( PIXELUPDATE ) \
+ break; \
+ } \
+ break; \
+ case 0x02: \
+ /* semi transparency */ \
+ switch( psxgpu.n_tp ) \
+ { \
+ case 0: \
+ /* 4 bit clut */ \
+ TEXTUREINTERLEAVED4BIT( TXV, TXU ) \
+ TRANSPARENTPIXEL( PIXELUPDATE ) \
+ break; \
+ case 1: \
+ /* 8 bit clut */ \
+ TEXTUREINTERLEAVED8BIT( TXV, TXU ) \
+ TRANSPARENTPIXEL( PIXELUPDATE ) \
+ break; \
+ case 2: \
+ /* 15 bit */ \
+ TEXTUREINTERLEAVED15BIT( TXV, TXU ) \
+ TRANSPARENTPIXEL( PIXELUPDATE ) \
+ break; \
+ } \
+ break; \
+ } \
+ } \
+ } \
+ else \
+ { \
+ /* standard texture */ \
+ if( m_n_twh != 255 || \
+ m_n_tww != 255 || \
+ m_n_twx != 0 || \
+ m_n_twy != 0 ) \
+ { \
+ /* texture window */ \
+ switch( n_cmd & 0x02 ) \
+ { \
+ case 0x00: \
+ /* shading */ \
+ switch( psxgpu.n_tp ) \
+ { \
+ case 0: \
+ /* 4 bit clut */ \
+ TEXTUREWINDOW4BIT( TXV, TXU ) \
+ SHADEDPIXEL( PIXELUPDATE ) \
+ break; \
+ case 1: \
+ /* 8 bit clut */ \
+ TEXTUREWINDOW8BIT( TXV, TXU ) \
+ SHADEDPIXEL( PIXELUPDATE ) \
+ break; \
+ case 2: \
+ /* 15 bit */ \
+ TEXTUREWINDOW15BIT( TXV, TXU ) \
+ SHADEDPIXEL( PIXELUPDATE ) \
+ break; \
+ } \
+ break; \
+ case 0x02: \
+ /* semi transparency */ \
+ switch( psxgpu.n_tp ) \
+ { \
+ case 0: \
+ /* 4 bit clut */ \
+ TEXTUREWINDOW4BIT( TXV, TXU ) \
+ TRANSPARENTPIXEL( PIXELUPDATE ) \
+ break; \
+ case 1: \
+ /* 8 bit clut */ \
+ TEXTUREWINDOW8BIT( TXV, TXU ) \
+ TRANSPARENTPIXEL( PIXELUPDATE ) \
+ break; \
+ case 2: \
+ /* 15 bit */ \
+ TEXTUREWINDOW15BIT( TXV, TXU ) \
+ TRANSPARENTPIXEL( PIXELUPDATE ) \
+ break; \
+ } \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* no texture window */ \
+ switch( n_cmd & 0x02 ) \
+ { \
+ case 0x00: \
+ /* shading */ \
+ switch( psxgpu.n_tp ) \
+ { \
+ case 0: \
+ TEXTURE4BIT( TXV, TXU ) \
+ SHADEDPIXEL( PIXELUPDATE ) \
+ break; \
+ case 1: \
+ /* 8 bit clut */ \
+ TEXTURE8BIT( TXV, TXU ) \
+ SHADEDPIXEL( PIXELUPDATE ) \
+ break; \
+ case 2: \
+ /* 15 bit */ \
+ TEXTURE15BIT( TXV, TXU ) \
+ SHADEDPIXEL( PIXELUPDATE ) \
+ break; \
+ } \
+ break; \
+ case 0x02: \
+ /* semi transparency */ \
+ switch( psxgpu.n_tp ) \
+ { \
+ case 0: \
+ /* 4 bit clut */ \
+ TEXTURE4BIT( TXV, TXU ) \
+ TRANSPARENTPIXEL( PIXELUPDATE ) \
+ break; \
+ case 1: \
+ /* 8 bit clut */ \
+ TEXTURE8BIT( TXV, TXU ) \
+ TRANSPARENTPIXEL( PIXELUPDATE ) \
+ break; \
+ case 2: \
+ /* 15 bit */ \
+ TEXTURE15BIT( TXV, TXU ) \
+ TRANSPARENTPIXEL( PIXELUPDATE ) \
+ break; \
+ } \
+ break; \
+ } \
+ } \
+ }
+
+static void FlatPolygon( int n_points )
+{
+ INT16 n_y;
+ INT16 n_x;
+
+ UINT16 *p_n_f;
+ UINT16 *p_n_redb;
+ UINT16 *p_n_greenb;
+ UINT16 *p_n_blueb;
+ UINT16 *p_n_redtrans;
+ UINT16 *p_n_greentrans;
+ UINT16 *p_n_bluetrans;
+
+ PAIR n_r;
+ PAIR n_g;
+ PAIR n_b;
+ PAIR n_cx1;
+ PAIR n_cx2;
+ INT32 n_dx1;
+ INT32 n_dx2;
+
+ UINT8 n_cmd;
+
+ INT32 n_distance;
+
+ UINT16 n_point;
+ UINT16 n_rightpoint;
+ UINT16 n_leftpoint;
+ UINT16 *p_n_rightpointlist;
+ UINT16 *p_n_leftpointlist;
+
+ UINT16 *p_vram;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 1 )
+ {
+ return;
+ }
+ for( n_point = 0; n_point < n_points; n_point++ )
+ {
+ DebugMesh( COORD_X( m_packet.FlatPolygon.vertex[ n_point ].n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.FlatPolygon.vertex[ n_point ].n_coord ) + m_n_drawoffset_y );
+ }
+ DebugMeshEnd();
+#endif
+
+ n_cmd = BGR_C( m_packet.FlatPolygon.n_bgr );
+
+ n_cx1.d = 0;
+ n_cx2.d = 0;
+
+ SOLIDSETUP
+
+ n_r.w.h = BGR_R( m_packet.FlatPolygon.n_bgr ); n_r.w.l = 0;
+ n_g.w.h = BGR_G( m_packet.FlatPolygon.n_bgr ); n_g.w.l = 0;
+ n_b.w.h = BGR_B( m_packet.FlatPolygon.n_bgr ); n_b.w.l = 0;
+
+ if( n_points == 4 )
+ {
+ p_n_rightpointlist = m_p_n_nextpointlist4;
+ p_n_leftpointlist = m_p_n_prevpointlist4;
+ }
+ else
+ {
+ p_n_rightpointlist = m_p_n_nextpointlist3;
+ p_n_leftpointlist = m_p_n_prevpointlist3;
+ }
+
+ for( n_point = 0; n_point < n_points; n_point++ )
+ {
+ ADJUST_COORD( m_packet.FlatPolygon.vertex[ n_point ].n_coord );
+ }
+
+ n_leftpoint = 0;
+ for( n_point = 1; n_point < n_points; n_point++ )
+ {
+ if( COORD_Y( m_packet.FlatPolygon.vertex[ n_point ].n_coord ) < COORD_Y( m_packet.FlatPolygon.vertex[ n_leftpoint ].n_coord ) ||
+ ( COORD_Y( m_packet.FlatPolygon.vertex[ n_point ].n_coord ) == COORD_Y( m_packet.FlatPolygon.vertex[ n_leftpoint ].n_coord ) &&
+ COORD_X( m_packet.FlatPolygon.vertex[ n_point ].n_coord ) < COORD_X( m_packet.FlatPolygon.vertex[ n_leftpoint ].n_coord ) ) )
+ {
+ n_leftpoint = n_point;
+ }
+ }
+ n_rightpoint = n_leftpoint;
+
+ n_dx1 = 0;
+ n_dx2 = 0;
+
+ n_y = COORD_Y( m_packet.FlatPolygon.vertex[ n_rightpoint ].n_coord );
+
+ for( ;; )
+ {
+ if( n_y == COORD_Y( m_packet.FlatPolygon.vertex[ n_leftpoint ].n_coord ) )
+ {
+ while( n_y == COORD_Y( m_packet.FlatPolygon.vertex[ p_n_leftpointlist[ n_leftpoint ] ].n_coord ) )
+ {
+ n_leftpoint = p_n_leftpointlist[ n_leftpoint ];
+ if( n_leftpoint == n_rightpoint )
+ {
+ break;
+ }
+ }
+ n_cx1.w.h = COORD_X( m_packet.FlatPolygon.vertex[ n_leftpoint ].n_coord ); n_cx1.w.l = 0;
+ n_leftpoint = p_n_leftpointlist[ n_leftpoint ];
+ n_distance = COORD_Y( m_packet.FlatPolygon.vertex[ n_leftpoint ].n_coord ) - n_y;
+ if( n_distance < 1 )
+ {
+ break;
+ }
+ n_dx1 = (INT32)( ( COORD_X( m_packet.FlatPolygon.vertex[ n_leftpoint ].n_coord ) << 16 ) - n_cx1.d ) / n_distance;
+ }
+ if( n_y == COORD_Y( m_packet.FlatPolygon.vertex[ n_rightpoint ].n_coord ) )
+ {
+ while( n_y == COORD_Y( m_packet.FlatPolygon.vertex[ p_n_rightpointlist[ n_rightpoint ] ].n_coord ) )
+ {
+ n_rightpoint = p_n_rightpointlist[ n_rightpoint ];
+ if( n_rightpoint == n_leftpoint )
+ {
+ break;
+ }
+ }
+ n_cx2.w.h = COORD_X( m_packet.FlatPolygon.vertex[ n_rightpoint ].n_coord ); n_cx2.w.l = 0;
+ n_rightpoint = p_n_rightpointlist[ n_rightpoint ];
+ n_distance = COORD_Y( m_packet.FlatPolygon.vertex[ n_rightpoint ].n_coord ) - n_y;
+ if( n_distance < 1 )
+ {
+ break;
+ }
+ n_dx2 = (INT32)( ( COORD_X( m_packet.FlatPolygon.vertex[ n_rightpoint ].n_coord ) << 16 ) - n_cx2.d ) / n_distance;
+ }
+ if( (INT16)n_cx1.w.h != (INT16)n_cx2.w.h && n_y >= (INT32)m_n_drawarea_y1 && n_y <= (INT32)m_n_drawarea_y2 )
+ {
+ if( (INT16)n_cx1.w.h < (INT16)n_cx2.w.h )
+ {
+ n_x = n_cx1.w.h;
+ n_distance = (INT16)n_cx2.w.h - n_x;
+ }
+ else
+ {
+ n_x = n_cx2.w.h;
+ n_distance = (INT16)n_cx1.w.h - n_x;
+ }
+
+ if( ( (INT32)m_n_drawarea_x1 - n_x ) > 0 )
+ {
+ n_distance -= ( m_n_drawarea_x1 - n_x );
+ n_x = m_n_drawarea_x1;
+ }
+ SOLIDFILL( FLATPOLYGONUPDATE )
+ }
+ n_cx1.d += n_dx1;
+ n_cx2.d += n_dx2;
+ n_y++;
+ }
+}
+
+static void FlatTexturedPolygon( int n_points )
+{
+ INT16 n_y;
+ INT16 n_x;
+ int n_tx;
+ int n_ty;
+
+ UINT8 n_cmd;
+
+ UINT32 n_clutx;
+ UINT32 n_cluty;
+
+ UINT16 *p_n_f;
+ UINT16 *p_n_redb;
+ UINT16 *p_n_greenb;
+ UINT16 *p_n_blueb;
+ UINT16 *p_n_redtrans;
+ UINT16 *p_n_greentrans;
+ UINT16 *p_n_bluetrans;
+
+ PAIR n_r;
+ PAIR n_g;
+ PAIR n_b;
+ PAIR n_u;
+ PAIR n_v;
+
+ PAIR n_cx1;
+ PAIR n_cx2;
+ PAIR n_cu1;
+ PAIR n_cv1;
+ PAIR n_cu2;
+ PAIR n_cv2;
+ INT32 n_du;
+ INT32 n_dv;
+ INT32 n_dx1;
+ INT32 n_dx2;
+ INT32 n_du1;
+ INT32 n_dv1;
+ INT32 n_du2;
+ INT32 n_dv2;
+
+ INT32 n_distance;
+ UINT16 n_point;
+ UINT16 n_rightpoint;
+ UINT16 n_leftpoint;
+ UINT16 *p_n_rightpointlist;
+ UINT16 *p_n_leftpointlist;
+ UINT16 *p_clut;
+ UINT16 *p_vram;
+ UINT32 n_bgr;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 2 )
+ {
+ return;
+ }
+ for( n_point = 0; n_point < n_points; n_point++ )
+ {
+ DebugMesh( COORD_X( m_packet.FlatTexturedPolygon.vertex[ n_point ].n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_point ].n_coord ) + m_n_drawoffset_y );
+ }
+ DebugMeshEnd();
+#endif
+
+ n_cmd = BGR_C( m_packet.FlatTexturedPolygon.n_bgr );
+
+ n_clutx = ( m_packet.FlatTexturedPolygon.vertex[ 0 ].n_texture.w.h & 0x3f ) << 4;
+ n_cluty = ( m_packet.FlatTexturedPolygon.vertex[ 0 ].n_texture.w.h >> 6 ) & 0x3ff;
+
+ n_r.d = 0;
+ n_g.d = 0;
+ n_b.d = 0;
+ n_cx1.d = 0;
+ n_cu1.d = 0;
+ n_cv1.d = 0;
+ n_cx2.d = 0;
+ n_cu2.d = 0;
+ n_cv2.d = 0;
+
+ decode_tpage( &psxgpu, m_packet.FlatTexturedPolygon.vertex[ 1 ].n_texture.w.h );
+ TEXTURESETUP
+
+ switch( n_cmd & 0x01 )
+ {
+ case 0:
+ n_r.w.h = BGR_R( m_packet.FlatTexturedPolygon.n_bgr ); n_r.w.l = 0;
+ n_g.w.h = BGR_G( m_packet.FlatTexturedPolygon.n_bgr ); n_g.w.l = 0;
+ n_b.w.h = BGR_B( m_packet.FlatTexturedPolygon.n_bgr ); n_b.w.l = 0;
+ break;
+ case 1:
+ n_r.w.h = 0x80; n_r.w.l = 0;
+ n_g.w.h = 0x80; n_g.w.l = 0;
+ n_b.w.h = 0x80; n_b.w.l = 0;
+ break;
+ }
+
+ if( n_points == 4 )
+ {
+ p_n_rightpointlist = m_p_n_nextpointlist4;
+ p_n_leftpointlist = m_p_n_prevpointlist4;
+ }
+ else
+ {
+ p_n_rightpointlist = m_p_n_nextpointlist3;
+ p_n_leftpointlist = m_p_n_prevpointlist3;
+ }
+
+ for( n_point = 0; n_point < n_points; n_point++ )
+ {
+ ADJUST_COORD( m_packet.FlatTexturedPolygon.vertex[ n_point ].n_coord );
+ }
+
+ n_leftpoint = 0;
+ for( n_point = 1; n_point < n_points; n_point++ )
+ {
+ if( COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_point ].n_coord ) < COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_coord ) ||
+ ( COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_point ].n_coord ) == COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_coord ) &&
+ COORD_X( m_packet.FlatTexturedPolygon.vertex[ n_point ].n_coord ) < COORD_X( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_coord ) ) )
+ {
+ n_leftpoint = n_point;
+ }
+ }
+ n_rightpoint = n_leftpoint;
+
+ n_dx1 = 0;
+ n_dx2 = 0;
+ n_du1 = 0;
+ n_du2 = 0;
+ n_dv1 = 0;
+ n_dv2 = 0;
+
+ n_y = COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_coord );
+
+ for( ;; )
+ {
+ if( n_y == COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_coord ) )
+ {
+ while( n_y == COORD_Y( m_packet.FlatTexturedPolygon.vertex[ p_n_leftpointlist[ n_leftpoint ] ].n_coord ) )
+ {
+ n_leftpoint = p_n_leftpointlist[ n_leftpoint ];
+ if( n_leftpoint == n_rightpoint )
+ {
+ break;
+ }
+ }
+ n_cx1.w.h = COORD_X( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_coord ); n_cx1.w.l = 0;
+ n_cu1.w.h = TEXTURE_U( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_texture ); n_cu1.w.l = 0;
+ n_cv1.w.h = TEXTURE_V( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_texture ); n_cv1.w.l = 0;
+ n_leftpoint = p_n_leftpointlist[ n_leftpoint ];
+ n_distance = COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_coord ) - n_y;
+ if( n_distance < 1 )
+ {
+ break;
+ }
+ n_dx1 = (INT32)( ( COORD_X( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_coord ) << 16 ) - n_cx1.d ) / n_distance;
+ n_du1 = (INT32)( ( TEXTURE_U( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_texture ) << 16 ) - n_cu1.d ) / n_distance;
+ n_dv1 = (INT32)( ( TEXTURE_V( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_texture ) << 16 ) - n_cv1.d ) / n_distance;
+ }
+ if( n_y == COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_coord ) )
+ {
+ while( n_y == COORD_Y( m_packet.FlatTexturedPolygon.vertex[ p_n_rightpointlist[ n_rightpoint ] ].n_coord ) )
+ {
+ n_rightpoint = p_n_rightpointlist[ n_rightpoint ];
+ if( n_rightpoint == n_leftpoint )
+ {
+ break;
+ }
+ }
+ n_cx2.w.h = COORD_X( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_coord ); n_cx2.w.l = 0;
+ n_cu2.w.h = TEXTURE_U( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_texture ); n_cu2.w.l = 0;
+ n_cv2.w.h = TEXTURE_V( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_texture ); n_cv2.w.l = 0;
+ n_rightpoint = p_n_rightpointlist[ n_rightpoint ];
+ n_distance = COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_coord ) - n_y;
+ if( n_distance < 1 )
+ {
+ break;
+ }
+ n_dx2 = (INT32)( ( COORD_X( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_coord ) << 16 ) - n_cx2.d ) / n_distance;
+ n_du2 = (INT32)( ( TEXTURE_U( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_texture ) << 16 ) - n_cu2.d ) / n_distance;
+ n_dv2 = (INT32)( ( TEXTURE_V( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_texture ) << 16 ) - n_cv2.d ) / n_distance;
+ }
+ if( (INT16)n_cx1.w.h != (INT16)n_cx2.w.h && n_y >= (INT32)m_n_drawarea_y1 && n_y <= (INT32)m_n_drawarea_y2 )
+ {
+ if( (INT16)n_cx1.w.h < (INT16)n_cx2.w.h )
+ {
+ n_x = n_cx1.w.h;
+ n_distance = (INT16)n_cx2.w.h - n_x;
+
+ n_u.d = n_cu1.d;
+ n_v.d = n_cv1.d;
+ n_du = (INT32)( n_cu2.d - n_cu1.d ) / n_distance;
+ n_dv = (INT32)( n_cv2.d - n_cv1.d ) / n_distance;
+ }
+ else
+ {
+ n_x = n_cx2.w.h;
+ n_distance = (INT16)n_cx1.w.h - n_x;
+
+ n_u.d = n_cu2.d;
+ n_v.d = n_cv2.d;
+ n_du = (INT32)( n_cu1.d - n_cu2.d ) / n_distance;
+ n_dv = (INT32)( n_cv1.d - n_cv2.d ) / n_distance;
+ }
+
+ if( ( (INT32)m_n_drawarea_x1 - n_x ) > 0 )
+ {
+ n_u.d += n_du * ( m_n_drawarea_x1 - n_x );
+ n_v.d += n_dv * ( m_n_drawarea_x1 - n_x );
+ n_distance -= ( m_n_drawarea_x1 - n_x );
+ n_x = m_n_drawarea_x1;
+ }
+ TEXTUREFILL( FLATTEXTUREDPOLYGONUPDATE, n_u.w.h, n_v.w.h );
+ }
+ n_cx1.d += n_dx1;
+ n_cu1.d += n_du1;
+ n_cv1.d += n_dv1;
+ n_cx2.d += n_dx2;
+ n_cu2.d += n_du2;
+ n_cv2.d += n_dv2;
+ n_y++;
+ }
+}
+
+static void GouraudPolygon( int n_points )
+{
+ INT16 n_y;
+ INT16 n_x;
+
+ UINT16 *p_n_f;
+ UINT16 *p_n_redb;
+ UINT16 *p_n_greenb;
+ UINT16 *p_n_blueb;
+ UINT16 *p_n_redtrans;
+ UINT16 *p_n_greentrans;
+ UINT16 *p_n_bluetrans;
+
+ UINT8 n_cmd;
+
+ PAIR n_r;
+ PAIR n_g;
+ PAIR n_b;
+ PAIR n_cx1;
+ PAIR n_cx2;
+ PAIR n_cr1;
+ PAIR n_cg1;
+ PAIR n_cb1;
+ PAIR n_cr2;
+ PAIR n_cg2;
+ PAIR n_cb2;
+ INT32 n_dr;
+ INT32 n_dg;
+ INT32 n_db;
+ INT32 n_dx1;
+ INT32 n_dx2;
+ INT32 n_dr1;
+ INT32 n_dg1;
+ INT32 n_db1;
+ INT32 n_dr2;
+ INT32 n_dg2;
+ INT32 n_db2;
+
+ INT32 n_distance;
+
+ UINT16 n_point;
+ UINT16 n_rightpoint;
+ UINT16 n_leftpoint;
+ UINT16 *p_n_rightpointlist;
+ UINT16 *p_n_leftpointlist;
+
+ UINT16 *p_vram;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 3 )
+ {
+ return;
+ }
+ for( n_point = 0; n_point < n_points; n_point++ )
+ {
+ DebugMesh( COORD_X( m_packet.GouraudPolygon.vertex[ n_point ].n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.GouraudPolygon.vertex[ n_point ].n_coord ) + m_n_drawoffset_y );
+ }
+ DebugMeshEnd();
+#endif
+
+ n_cmd = BGR_C( m_packet.GouraudPolygon.vertex[ 0 ].n_bgr );
+
+ n_cx1.d = 0;
+ n_cr1.d = 0;
+ n_cg1.d = 0;
+ n_cb1.d = 0;
+ n_cx2.d = 0;
+ n_cr2.d = 0;
+ n_cg2.d = 0;
+ n_cb2.d = 0;
+
+ SOLIDSETUP
+
+ if( n_points == 4 )
+ {
+ p_n_rightpointlist = m_p_n_nextpointlist4;
+ p_n_leftpointlist = m_p_n_prevpointlist4;
+ }
+ else
+ {
+ p_n_rightpointlist = m_p_n_nextpointlist3;
+ p_n_leftpointlist = m_p_n_prevpointlist3;
+ }
+
+ for( n_point = 0; n_point < n_points; n_point++ )
+ {
+ ADJUST_COORD( m_packet.GouraudPolygon.vertex[ n_point ].n_coord );
+ }
+
+ n_leftpoint = 0;
+ for( n_point = 1; n_point < n_points; n_point++ )
+ {
+ if( COORD_Y( m_packet.GouraudPolygon.vertex[ n_point ].n_coord ) < COORD_Y( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_coord ) ||
+ ( COORD_Y( m_packet.GouraudPolygon.vertex[ n_point ].n_coord ) == COORD_Y( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_coord ) &&
+ COORD_X( m_packet.GouraudPolygon.vertex[ n_point ].n_coord ) < COORD_X( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_coord ) ) )
+ {
+ n_leftpoint = n_point;
+ }
+ }
+ n_rightpoint = n_leftpoint;
+
+ n_dx1 = 0;
+ n_dx2 = 0;
+ n_dr1 = 0;
+ n_dr2 = 0;
+ n_dg1 = 0;
+ n_dg2 = 0;
+ n_db1 = 0;
+ n_db2 = 0;
+
+ n_y = COORD_Y( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_coord );
+
+ for( ;; )
+ {
+ if( n_y == COORD_Y( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_coord ) )
+ {
+ while( n_y == COORD_Y( m_packet.GouraudPolygon.vertex[ p_n_leftpointlist[ n_leftpoint ] ].n_coord ) )
+ {
+ n_leftpoint = p_n_leftpointlist[ n_leftpoint ];
+ if( n_leftpoint == n_rightpoint )
+ {
+ break;
+ }
+ }
+ n_cx1.w.h = COORD_X( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_coord ); n_cx1.w.l = 0;
+ n_cr1.w.h = BGR_R( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_bgr ); n_cr1.w.l = 0;
+ n_cg1.w.h = BGR_G( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_bgr ); n_cg1.w.l = 0;
+ n_cb1.w.h = BGR_B( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_bgr ); n_cb1.w.l = 0;
+ n_leftpoint = p_n_leftpointlist[ n_leftpoint ];
+ n_distance = COORD_Y( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_coord ) - n_y;
+ if( n_distance < 1 )
+ {
+ break;
+ }
+ n_dx1 = (INT32)( ( COORD_X( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_coord ) << 16 ) - n_cx1.d ) / n_distance;
+ n_dr1 = (INT32)( ( BGR_R( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_bgr ) << 16 ) - n_cr1.d ) / n_distance;
+ n_dg1 = (INT32)( ( BGR_G( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_bgr ) << 16 ) - n_cg1.d ) / n_distance;
+ n_db1 = (INT32)( ( BGR_B( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_bgr ) << 16 ) - n_cb1.d ) / n_distance;
+ }
+ if( n_y == COORD_Y( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_coord ) )
+ {
+ while( n_y == COORD_Y( m_packet.GouraudPolygon.vertex[ p_n_rightpointlist[ n_rightpoint ] ].n_coord ) )
+ {
+ n_rightpoint = p_n_rightpointlist[ n_rightpoint ];
+ if( n_rightpoint == n_leftpoint )
+ {
+ break;
+ }
+ }
+ n_cx2.w.h = COORD_X( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_coord ); n_cx2.w.l = 0;
+ n_cr2.w.h = BGR_R( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_bgr ); n_cr2.w.l = 0;
+ n_cg2.w.h = BGR_G( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_bgr ); n_cg2.w.l = 0;
+ n_cb2.w.h = BGR_B( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_bgr ); n_cb2.w.l = 0;
+ n_rightpoint = p_n_rightpointlist[ n_rightpoint ];
+ n_distance = COORD_Y( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_coord ) - n_y;
+ if( n_distance < 1 )
+ {
+ break;
+ }
+ n_dx2 = (INT32)( ( COORD_X( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_coord ) << 16 ) - n_cx2.d ) / n_distance;
+ n_dr2 = (INT32)( ( BGR_R( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_bgr ) << 16 ) - n_cr2.d ) / n_distance;
+ n_dg2 = (INT32)( ( BGR_G( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_bgr ) << 16 ) - n_cg2.d ) / n_distance;
+ n_db2 = (INT32)( ( BGR_B( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_bgr ) << 16 ) - n_cb2.d ) / n_distance;
+ }
+ if( (INT16)n_cx1.w.h != (INT16)n_cx2.w.h && n_y >= (INT32)m_n_drawarea_y1 && n_y <= (INT32)m_n_drawarea_y2 )
+ {
+ if( (INT16)n_cx1.w.h < (INT16)n_cx2.w.h )
+ {
+ n_x = n_cx1.w.h;
+ n_distance = (INT16)n_cx2.w.h - n_x;
+
+ n_r.d = n_cr1.d;
+ n_g.d = n_cg1.d;
+ n_b.d = n_cb1.d;
+ n_dr = (INT32)( n_cr2.d - n_cr1.d ) / n_distance;
+ n_dg = (INT32)( n_cg2.d - n_cg1.d ) / n_distance;
+ n_db = (INT32)( n_cb2.d - n_cb1.d ) / n_distance;
+ }
+ else
+ {
+ n_x = n_cx2.w.h;
+ n_distance = (INT16)n_cx1.w.h - n_x;
+
+ n_r.d = n_cr2.d;
+ n_g.d = n_cg2.d;
+ n_b.d = n_cb2.d;
+ n_dr = (INT32)( n_cr1.d - n_cr2.d ) / n_distance;
+ n_dg = (INT32)( n_cg1.d - n_cg2.d ) / n_distance;
+ n_db = (INT32)( n_cb1.d - n_cb2.d ) / n_distance;
+ }
+
+ if( ( (INT32)m_n_drawarea_x1 - n_x ) > 0 )
+ {
+ n_r.d += n_dr * ( m_n_drawarea_x1 - n_x );
+ n_g.d += n_dg * ( m_n_drawarea_x1 - n_x );
+ n_b.d += n_db * ( m_n_drawarea_x1 - n_x );
+ n_distance -= ( m_n_drawarea_x1 - n_x );
+ n_x = m_n_drawarea_x1;
+ }
+ SOLIDFILL( GOURAUDPOLYGONUPDATE )
+ }
+ n_cx1.d += n_dx1;
+ n_cr1.d += n_dr1;
+ n_cg1.d += n_dg1;
+ n_cb1.d += n_db1;
+ n_cx2.d += n_dx2;
+ n_cr2.d += n_dr2;
+ n_cg2.d += n_dg2;
+ n_cb2.d += n_db2;
+ n_y++;
+ }
+}
+
+static void GouraudTexturedPolygon( int n_points )
+{
+ INT16 n_y;
+ INT16 n_x;
+ int n_tx;
+ int n_ty;
+
+ UINT8 n_cmd;
+
+ UINT32 n_clutx;
+ UINT32 n_cluty;
+
+ UINT16 *p_n_f;
+ UINT16 *p_n_redb;
+ UINT16 *p_n_greenb;
+ UINT16 *p_n_blueb;
+ UINT16 *p_n_redtrans;
+ UINT16 *p_n_greentrans;
+ UINT16 *p_n_bluetrans;
+
+ PAIR n_r;
+ PAIR n_g;
+ PAIR n_b;
+ PAIR n_u;
+ PAIR n_v;
+
+ PAIR n_cx1;
+ PAIR n_cx2;
+ PAIR n_cu1;
+ PAIR n_cv1;
+ PAIR n_cu2;
+ PAIR n_cv2;
+ PAIR n_cr1;
+ PAIR n_cg1;
+ PAIR n_cb1;
+ PAIR n_cr2;
+ PAIR n_cg2;
+ PAIR n_cb2;
+ INT32 n_dr;
+ INT32 n_dg;
+ INT32 n_db;
+ INT32 n_du;
+ INT32 n_dv;
+ INT32 n_dx1;
+ INT32 n_dx2;
+ INT32 n_dr1;
+ INT32 n_dg1;
+ INT32 n_db1;
+ INT32 n_dr2;
+ INT32 n_dg2;
+ INT32 n_db2;
+ INT32 n_du1;
+ INT32 n_dv1;
+ INT32 n_du2;
+ INT32 n_dv2;
+
+ INT32 n_distance;
+ UINT16 n_point;
+ UINT16 n_rightpoint;
+ UINT16 n_leftpoint;
+ UINT16 *p_n_rightpointlist;
+ UINT16 *p_n_leftpointlist;
+ UINT16 *p_clut;
+ UINT16 *p_vram;
+ UINT32 n_bgr;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 4 )
+ {
+ return;
+ }
+ for( n_point = 0; n_point < n_points; n_point++ )
+ {
+ DebugMesh( COORD_X( m_packet.GouraudTexturedPolygon.vertex[ n_point ].n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_point ].n_coord ) + m_n_drawoffset_y );
+ }
+ DebugMeshEnd();
+#endif
+
+ n_cmd = BGR_C( m_packet.GouraudTexturedPolygon.vertex[ 0 ].n_bgr );
+
+ n_clutx = ( m_packet.GouraudTexturedPolygon.vertex[ 0 ].n_texture.w.h & 0x3f ) << 4;
+ n_cluty = ( m_packet.GouraudTexturedPolygon.vertex[ 0 ].n_texture.w.h >> 6 ) & 0x3ff;
+
+ n_cx1.d = 0;
+ n_cr1.d = 0;
+ n_cg1.d = 0;
+ n_cb1.d = 0;
+ n_cu1.d = 0;
+ n_cv1.d = 0;
+ n_cx2.d = 0;
+ n_cr2.d = 0;
+ n_cg2.d = 0;
+ n_cb2.d = 0;
+ n_cu2.d = 0;
+ n_cv2.d = 0;
+
+ decode_tpage( &psxgpu, m_packet.GouraudTexturedPolygon.vertex[ 1 ].n_texture.w.h );
+ TEXTURESETUP
+
+ if( n_points == 4 )
+ {
+ p_n_rightpointlist = m_p_n_nextpointlist4;
+ p_n_leftpointlist = m_p_n_prevpointlist4;
+ }
+ else
+ {
+ p_n_rightpointlist = m_p_n_nextpointlist3;
+ p_n_leftpointlist = m_p_n_prevpointlist3;
+ }
+
+ for( n_point = 0; n_point < n_points; n_point++ )
+ {
+ ADJUST_COORD( m_packet.GouraudTexturedPolygon.vertex[ n_point ].n_coord );
+ }
+
+ n_leftpoint = 0;
+ for( n_point = 1; n_point < n_points; n_point++ )
+ {
+ if( COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_point ].n_coord ) < COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_coord ) ||
+ ( COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_point ].n_coord ) == COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_coord ) &&
+ COORD_X( m_packet.GouraudTexturedPolygon.vertex[ n_point ].n_coord ) < COORD_X( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_coord ) ) )
+ {
+ n_leftpoint = n_point;
+ }
+ }
+ n_rightpoint = n_leftpoint;
+
+ n_dx1 = 0;
+ n_dx2 = 0;
+ n_du1 = 0;
+ n_du2 = 0;
+ n_dr1 = 0;
+ n_dr2 = 0;
+ n_dg1 = 0;
+ n_dg2 = 0;
+ n_db1 = 0;
+ n_db2 = 0;
+ n_dv1 = 0;
+ n_dv2 = 0;
+
+ n_y = COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_coord );
+
+ for( ;; )
+ {
+ if( n_y == COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_coord ) )
+ {
+ while( n_y == COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ p_n_leftpointlist[ n_leftpoint ] ].n_coord ) )
+ {
+ n_leftpoint = p_n_leftpointlist[ n_leftpoint ];
+ if( n_leftpoint == n_rightpoint )
+ {
+ break;
+ }
+ }
+ n_cx1.w.h = COORD_X( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_coord ); n_cx1.w.l = 0;
+ switch( n_cmd & 0x01 )
+ {
+ case 0x00:
+ n_cr1.w.h = BGR_R( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_bgr ); n_cr1.w.l = 0;
+ n_cg1.w.h = BGR_G( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_bgr ); n_cg1.w.l = 0;
+ n_cb1.w.h = BGR_B( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_bgr ); n_cb1.w.l = 0;
+ break;
+ case 0x01:
+ n_cr1.w.h = 0x80; n_cr1.w.l = 0;
+ n_cg1.w.h = 0x80; n_cg1.w.l = 0;
+ n_cb1.w.h = 0x80; n_cb1.w.l = 0;
+ break;
+ }
+ n_cu1.w.h = TEXTURE_U( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_texture ); n_cu1.w.l = 0;
+ n_cv1.w.h = TEXTURE_V( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_texture ); n_cv1.w.l = 0;
+ n_leftpoint = p_n_leftpointlist[ n_leftpoint ];
+ n_distance = COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_coord ) - n_y;
+ if( n_distance < 1 )
+ {
+ break;
+ }
+ n_dx1 = (INT32)( ( COORD_X( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_coord ) << 16 ) - n_cx1.d ) / n_distance;
+ switch( n_cmd & 0x01 )
+ {
+ case 0x00:
+ n_dr1 = (INT32)( ( BGR_R( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_bgr ) << 16 ) - n_cr1.d ) / n_distance;
+ n_dg1 = (INT32)( ( BGR_G( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_bgr ) << 16 ) - n_cg1.d ) / n_distance;
+ n_db1 = (INT32)( ( BGR_B( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_bgr ) << 16 ) - n_cb1.d ) / n_distance;
+ break;
+ case 0x01:
+ n_dr1 = 0;
+ n_dg1 = 0;
+ n_db1 = 0;
+ break;
+ }
+ n_du1 = (INT32)( ( TEXTURE_U( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_texture ) << 16 ) - n_cu1.d ) / n_distance;
+ n_dv1 = (INT32)( ( TEXTURE_V( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_texture ) << 16 ) - n_cv1.d ) / n_distance;
+ }
+ if( n_y == COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_coord ) )
+ {
+ while( n_y == COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ p_n_rightpointlist[ n_rightpoint ] ].n_coord ) )
+ {
+ n_rightpoint = p_n_rightpointlist[ n_rightpoint ];
+ if( n_rightpoint == n_leftpoint )
+ {
+ break;
+ }
+ }
+ n_cx2.w.h = COORD_X( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_coord ); n_cx2.w.l = 0;
+ switch( n_cmd & 0x01 )
+ {
+ case 0x00:
+ n_cr2.w.h = BGR_R( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_bgr ); n_cr2.w.l = 0;
+ n_cg2.w.h = BGR_G( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_bgr ); n_cg2.w.l = 0;
+ n_cb2.w.h = BGR_B( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_bgr ); n_cb2.w.l = 0;
+ break;
+ case 0x01:
+ n_cr2.w.h = 0x80; n_cr2.w.l = 0;
+ n_cg2.w.h = 0x80; n_cg2.w.l = 0;
+ n_cb2.w.h = 0x80; n_cb2.w.l = 0;
+ break;
+ }
+ n_cu2.w.h = TEXTURE_U( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_texture ); n_cu2.w.l = 0;
+ n_cv2.w.h = TEXTURE_V( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_texture ); n_cv2.w.l = 0;
+ n_rightpoint = p_n_rightpointlist[ n_rightpoint ];
+ n_distance = COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_coord ) - n_y;
+ if( n_distance < 1 )
+ {
+ break;
+ }
+ n_dx2 = (INT32)( ( COORD_X( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_coord ) << 16 ) - n_cx2.d ) / n_distance;
+ switch( n_cmd & 0x01 )
+ {
+ case 0x00:
+ n_dr2 = (INT32)( ( BGR_R( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_bgr ) << 16 ) - n_cr2.d ) / n_distance;
+ n_dg2 = (INT32)( ( BGR_G( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_bgr ) << 16 ) - n_cg2.d ) / n_distance;
+ n_db2 = (INT32)( ( BGR_B( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_bgr ) << 16 ) - n_cb2.d ) / n_distance;
+ break;
+ case 0x01:
+ n_dr2 = 0;
+ n_dg2 = 0;
+ n_db2 = 0;
+ break;
+ }
+ n_du2 = (INT32)( ( TEXTURE_U( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_texture ) << 16 ) - n_cu2.d ) / n_distance;
+ n_dv2 = (INT32)( ( TEXTURE_V( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_texture ) << 16 ) - n_cv2.d ) / n_distance;
+ }
+ if( (INT16)n_cx1.w.h != (INT16)n_cx2.w.h && n_y >= (INT32)m_n_drawarea_y1 && n_y <= (INT32)m_n_drawarea_y2 )
+ {
+ if( (INT16)n_cx1.w.h < (INT16)n_cx2.w.h )
+ {
+ n_x = n_cx1.w.h;
+ n_distance = (INT16)n_cx2.w.h - n_x;
+
+ n_r.d = n_cr1.d;
+ n_g.d = n_cg1.d;
+ n_b.d = n_cb1.d;
+ n_u.d = n_cu1.d;
+ n_v.d = n_cv1.d;
+ n_dr = (INT32)( n_cr2.d - n_cr1.d ) / n_distance;
+ n_dg = (INT32)( n_cg2.d - n_cg1.d ) / n_distance;
+ n_db = (INT32)( n_cb2.d - n_cb1.d ) / n_distance;
+ n_du = (INT32)( n_cu2.d - n_cu1.d ) / n_distance;
+ n_dv = (INT32)( n_cv2.d - n_cv1.d ) / n_distance;
+ }
+ else
+ {
+ n_x = n_cx2.w.h;
+ n_distance = (INT16)n_cx1.w.h - n_x;
+
+ n_r.d = n_cr2.d;
+ n_g.d = n_cg2.d;
+ n_b.d = n_cb2.d;
+ n_u.d = n_cu2.d;
+ n_v.d = n_cv2.d;
+ n_dr = (INT32)( n_cr1.d - n_cr2.d ) / n_distance;
+ n_dg = (INT32)( n_cg1.d - n_cg2.d ) / n_distance;
+ n_db = (INT32)( n_cb1.d - n_cb2.d ) / n_distance;
+ n_du = (INT32)( n_cu1.d - n_cu2.d ) / n_distance;
+ n_dv = (INT32)( n_cv1.d - n_cv2.d ) / n_distance;
+ }
+
+ if( ( (INT32)m_n_drawarea_x1 - n_x ) > 0 )
+ {
+ n_r.d += n_dr * ( m_n_drawarea_x1 - n_x );
+ n_g.d += n_dg * ( m_n_drawarea_x1 - n_x );
+ n_b.d += n_db * ( m_n_drawarea_x1 - n_x );
+ n_u.d += n_du * ( m_n_drawarea_x1 - n_x );
+ n_v.d += n_dv * ( m_n_drawarea_x1 - n_x );
+ n_distance -= ( m_n_drawarea_x1 - n_x );
+ n_x = m_n_drawarea_x1;
+ }
+ TEXTUREFILL( GOURAUDTEXTUREDPOLYGONUPDATE, n_u.w.h, n_v.w.h );
+ }
+ n_cx1.d += n_dx1;
+ n_cr1.d += n_dr1;
+ n_cg1.d += n_dg1;
+ n_cb1.d += n_db1;
+ n_cu1.d += n_du1;
+ n_cv1.d += n_dv1;
+ n_cx2.d += n_dx2;
+ n_cr2.d += n_dr2;
+ n_cg2.d += n_dg2;
+ n_cb2.d += n_db2;
+ n_cu2.d += n_du2;
+ n_cv2.d += n_dv2;
+ n_y++;
+ }
+}
+
+static void MonochromeLine( void )
+{
+ PAIR n_x;
+ PAIR n_y;
+ INT32 n_dx;
+ INT32 n_dy;
+ INT32 n_dr;
+ INT32 n_dg;
+ INT32 n_db;
+ INT32 n_len;
+ INT32 n_xlen;
+ INT32 n_ylen;
+ INT32 n_xstart;
+ INT32 n_ystart;
+ INT32 n_xend;
+ INT32 n_yend;
+ UINT32 n_r;
+ UINT32 n_g;
+ UINT32 n_b;
+ UINT16 *p_vram;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 5 )
+ {
+ return;
+ }
+ DebugMesh( COORD_X( m_packet.MonochromeLine.vertex[ 0 ].n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.MonochromeLine.vertex[ 0 ].n_coord ) + m_n_drawoffset_y );
+ DebugMesh( COORD_X( m_packet.MonochromeLine.vertex[ 1 ].n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.MonochromeLine.vertex[ 1 ].n_coord ) + m_n_drawoffset_y );
+ DebugMeshEnd();
+#endif
+
+ n_xstart = COORD_X( m_packet.MonochromeLine.vertex[ 0 ].n_coord ) + m_n_drawoffset_x;
+ n_xend = COORD_X( m_packet.MonochromeLine.vertex[ 1 ].n_coord ) + m_n_drawoffset_x;
+ n_ystart = COORD_Y( m_packet.MonochromeLine.vertex[ 0 ].n_coord ) + m_n_drawoffset_y;
+ n_yend = COORD_Y( m_packet.MonochromeLine.vertex[ 1 ].n_coord ) + m_n_drawoffset_y;
+
+ n_r = BGR_R( m_packet.MonochromeLine.n_bgr );
+ n_g = BGR_G( m_packet.MonochromeLine.n_bgr );
+ n_b = BGR_B( m_packet.MonochromeLine.n_bgr );
+
+ if( n_xend > n_xstart )
+ {
+ n_xlen = n_xend - n_xstart;
+ }
+ else
+ {
+ n_xlen = n_xstart - n_xend;
+ }
+
+ if( n_yend > n_ystart )
+ {
+ n_ylen = n_yend - n_ystart;
+ }
+ else
+ {
+ n_ylen = n_ystart - n_yend;
+ }
+
+ if( n_xlen > n_ylen )
+ {
+ n_len = n_xlen;
+ }
+ else
+ {
+ n_len = n_ylen;
+ }
+
+ if( n_len == 0 )
+ {
+ n_len = 1;
+ }
+
+ n_x.w.h = n_xstart; n_x.w.l = 0;
+ n_y.w.h = n_ystart; n_y.w.l = 0;
+
+ n_dx = (INT32)( ( n_xend << 16 ) - n_x.d ) / n_len;
+ n_dy = (INT32)( ( n_yend << 16 ) - n_y.d ) / n_len;
+ n_dr = 0;
+ n_dg = 0;
+ n_db = 0;
+
+ while( n_len > 0 )
+ {
+ if( (INT16)n_x.w.h >= (INT32)m_n_drawarea_x1 &&
+ (INT16)n_y.w.h >= (INT32)m_n_drawarea_y1 &&
+ (INT16)n_x.w.h <= (INT32)m_n_drawarea_x2 &&
+ (INT16)n_y.w.h <= (INT32)m_n_drawarea_y2 )
+ {
+ p_vram = m_p_p_vram[ n_y.w.h ] + n_x.w.h;
+ WRITE_PIXEL(
+ m_p_n_redshade[ MID_LEVEL | n_r ] |
+ m_p_n_greenshade[ MID_LEVEL | n_g ] |
+ m_p_n_blueshade[ MID_LEVEL | n_b ] );
+ }
+ n_x.d += n_dx;
+ n_y.d += n_dy;
+ n_len--;
+ }
+}
+
+static void GouraudLine( void )
+{
+ PAIR n_x;
+ PAIR n_y;
+ INT32 n_dx;
+ INT32 n_dy;
+ INT32 n_dr;
+ INT32 n_dg;
+ INT32 n_db;
+ INT32 n_distance;
+ INT32 n_xlen;
+ INT32 n_ylen;
+ INT32 n_xstart;
+ INT32 n_ystart;
+ INT32 n_xend;
+ INT32 n_yend;
+ PAIR n_r;
+ PAIR n_g;
+ PAIR n_b;
+ PAIR n_cr1;
+ PAIR n_cg1;
+ PAIR n_cb1;
+ PAIR n_cr2;
+ PAIR n_cg2;
+ PAIR n_cb2;
+ UINT16 *p_vram;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 6 )
+ {
+ return;
+ }
+ DebugMesh( COORD_X( m_packet.GouraudLine.vertex[ 0 ].n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.GouraudLine.vertex[ 0 ].n_coord ) + m_n_drawoffset_y );
+ DebugMesh( COORD_X( m_packet.GouraudLine.vertex[ 1 ].n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.GouraudLine.vertex[ 1 ].n_coord ) + m_n_drawoffset_y );
+ DebugMeshEnd();
+#endif
+
+ n_xstart = COORD_X( m_packet.GouraudLine.vertex[ 0 ].n_coord ) + m_n_drawoffset_x;
+ n_ystart = COORD_Y( m_packet.GouraudLine.vertex[ 0 ].n_coord ) + m_n_drawoffset_y;
+ n_cr1.w.h = BGR_R( m_packet.GouraudLine.vertex[ 0 ].n_bgr ); n_cr1.w.l = 0;
+ n_cg1.w.h = BGR_G( m_packet.GouraudLine.vertex[ 0 ].n_bgr ); n_cg1.w.l = 0;
+ n_cb1.w.h = BGR_B( m_packet.GouraudLine.vertex[ 0 ].n_bgr ); n_cb1.w.l = 0;
+
+ n_xend = COORD_X( m_packet.GouraudLine.vertex[ 1 ].n_coord ) + m_n_drawoffset_x;
+ n_yend = COORD_Y( m_packet.GouraudLine.vertex[ 1 ].n_coord ) + m_n_drawoffset_y;
+ n_cr2.w.h = BGR_R( m_packet.GouraudLine.vertex[ 1 ].n_bgr ); n_cr1.w.l = 0;
+ n_cg2.w.h = BGR_G( m_packet.GouraudLine.vertex[ 1 ].n_bgr ); n_cg1.w.l = 0;
+ n_cb2.w.h = BGR_B( m_packet.GouraudLine.vertex[ 1 ].n_bgr ); n_cb1.w.l = 0;
+
+ n_x.w.h = n_xstart; n_x.w.l = 0;
+ n_y.w.h = n_ystart; n_y.w.l = 0;
+ n_r.d = n_cr1.d;
+ n_g.d = n_cg1.d;
+ n_b.d = n_cb1.d;
+
+ if( n_xend > n_xstart )
+ {
+ n_xlen = n_xend - n_xstart;
+ }
+ else
+ {
+ n_xlen = n_xstart - n_xend;
+ }
+
+ if( n_yend > n_ystart )
+ {
+ n_ylen = n_yend - n_ystart;
+ }
+ else
+ {
+ n_ylen = n_ystart - n_yend;
+ }
+
+ if( n_xlen > n_ylen )
+ {
+ n_distance = n_xlen;
+ }
+ else
+ {
+ n_distance = n_ylen;
+ }
+
+ if( n_distance == 0 )
+ {
+ n_distance = 1;
+ }
+
+ n_dx = (INT32)( ( n_xend << 16 ) - n_x.d ) / n_distance;
+ n_dy = (INT32)( ( n_yend << 16 ) - n_y.d ) / n_distance;
+ n_dr = (INT32)( n_cr2.d - n_cr1.d ) / n_distance;
+ n_dg = (INT32)( n_cg2.d - n_cg1.d ) / n_distance;
+ n_db = (INT32)( n_cb2.d - n_cb1.d ) / n_distance;
+
+ while( n_distance > 0 )
+ {
+ if( (INT16)n_x.w.h >= (INT32)m_n_drawarea_x1 &&
+ (INT16)n_y.w.h >= (INT32)m_n_drawarea_y1 &&
+ (INT16)n_x.w.h <= (INT32)m_n_drawarea_x2 &&
+ (INT16)n_y.w.h <= (INT32)m_n_drawarea_y2 )
+ {
+ p_vram = m_p_p_vram[ n_y.w.h ] + n_x.w.h;
+ WRITE_PIXEL(
+ m_p_n_redshade[ MID_LEVEL | n_r.w.h ] |
+ m_p_n_greenshade[ MID_LEVEL | n_g.w.h ] |
+ m_p_n_blueshade[ MID_LEVEL | n_b.w.h ] );
+ }
+ n_x.d += n_dx;
+ n_y.d += n_dy;
+ n_r.d += n_dr;
+ n_g.d += n_dg;
+ n_b.d += n_db;
+ n_distance--;
+ }
+}
+
+static void FrameBufferRectangleDraw( void )
+{
+ PAIR n_r;
+ PAIR n_g;
+ PAIR n_b;
+ INT32 n_distance;
+ INT32 n_h;
+ INT16 n_y;
+ INT16 n_x;
+ UINT16 *p_vram;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 7 )
+ {
+ return;
+ }
+ DebugMesh( COORD_X( m_packet.FlatRectangle.n_coord ), COORD_Y( m_packet.FlatRectangle.n_coord ) );
+ DebugMesh( COORD_X( m_packet.FlatRectangle.n_coord ) + SIZE_W( m_packet.FlatRectangle.n_size ), COORD_Y( m_packet.FlatRectangle.n_coord ) );
+ DebugMesh( COORD_X( m_packet.FlatRectangle.n_coord ), COORD_Y( m_packet.FlatRectangle.n_coord ) + SIZE_H( m_packet.FlatRectangle.n_size ) );
+ DebugMesh( COORD_X( m_packet.FlatRectangle.n_coord ) + SIZE_W( m_packet.FlatRectangle.n_size ), COORD_Y( m_packet.FlatRectangle.n_coord ) + SIZE_H( m_packet.FlatRectangle.n_size ) );
+ DebugMeshEnd();
+#endif
+
+ n_r.w.h = BGR_R( m_packet.FlatRectangle.n_bgr ); n_r.w.l = 0;
+ n_g.w.h = BGR_G( m_packet.FlatRectangle.n_bgr ); n_g.w.l = 0;
+ n_b.w.h = BGR_B( m_packet.FlatRectangle.n_bgr ); n_b.w.l = 0;
+
+ n_y = COORD_Y( m_packet.FlatRectangle.n_coord );
+ n_h = SIZE_H( m_packet.FlatRectangle.n_size );
+
+ while( n_h > 0 )
+ {
+ n_x = COORD_X( m_packet.FlatRectangle.n_coord );
+
+ n_distance = SIZE_W( m_packet.FlatRectangle.n_size );
+ while( n_distance > 0 )
+ {
+ p_vram = m_p_p_vram[ n_y & 1023 ] + ( n_x & 1023 );
+ WRITE_PIXEL(
+ m_p_n_redshade[ MID_LEVEL | n_r.w.h ] |
+ m_p_n_greenshade[ MID_LEVEL | n_g.w.h ] |
+ m_p_n_blueshade[ MID_LEVEL | n_b.w.h ] );
+ n_x++;
+ n_distance--;
+ }
+ n_y++;
+ n_h--;
+ }
+}
+
+static void FlatRectangle( void )
+{
+ INT16 n_y;
+ INT16 n_x;
+
+ UINT8 n_cmd;
+
+ UINT16 *p_n_f;
+ UINT16 *p_n_redb;
+ UINT16 *p_n_greenb;
+ UINT16 *p_n_blueb;
+ UINT16 *p_n_redtrans;
+ UINT16 *p_n_greentrans;
+ UINT16 *p_n_bluetrans;
+
+ PAIR n_r;
+ PAIR n_g;
+ PAIR n_b;
+
+ INT32 n_distance;
+ INT32 n_h;
+ UINT16 *p_vram;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 8 )
+ {
+ return;
+ }
+ DebugMesh( COORD_X( m_packet.FlatRectangle.n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.FlatRectangle.n_coord ) + m_n_drawoffset_y );
+ DebugMesh( COORD_X( m_packet.FlatRectangle.n_coord ) + m_n_drawoffset_x + SIZE_W( m_packet.FlatRectangle.n_size ), COORD_Y( m_packet.FlatRectangle.n_coord ) + m_n_drawoffset_y );
+ DebugMesh( COORD_X( m_packet.FlatRectangle.n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.FlatRectangle.n_coord ) + m_n_drawoffset_y + SIZE_H( m_packet.FlatRectangle.n_size ) );
+ DebugMesh( COORD_X( m_packet.FlatRectangle.n_coord ) + m_n_drawoffset_x + SIZE_W( m_packet.FlatRectangle.n_size ), COORD_Y( m_packet.FlatRectangle.n_coord ) + m_n_drawoffset_y + SIZE_H( m_packet.FlatRectangle.n_size ) );
+ DebugMeshEnd();
+#endif
+
+ n_cmd = BGR_C( m_packet.FlatRectangle.n_bgr );
+
+ SOLIDSETUP
+
+ n_r.w.h = BGR_R( m_packet.FlatRectangle.n_bgr ); n_r.w.l = 0;
+ n_g.w.h = BGR_G( m_packet.FlatRectangle.n_bgr ); n_g.w.l = 0;
+ n_b.w.h = BGR_B( m_packet.FlatRectangle.n_bgr ); n_b.w.l = 0;
+
+ n_y = COORD_Y( m_packet.FlatRectangle.n_coord ) + m_n_drawoffset_y;
+ n_h = SIZE_H( m_packet.FlatRectangle.n_size );
+
+ while( n_h > 0 )
+ {
+ n_x = COORD_X( m_packet.FlatRectangle.n_coord ) + m_n_drawoffset_x;
+
+ n_distance = SIZE_W( m_packet.FlatRectangle.n_size );
+ if( n_distance > 0 && n_y >= (INT32)m_n_drawarea_y1 && n_y <= (INT32)m_n_drawarea_y2 )
+ {
+ if( ( (INT32)m_n_drawarea_x1 - n_x ) > 0 )
+ {
+ n_distance -= ( m_n_drawarea_x1 - n_x );
+ n_x = m_n_drawarea_x1;
+ }
+ SOLIDFILL( FLATRECTANGEUPDATE )
+ }
+ n_y++;
+ n_h--;
+ }
+}
+
+static void FlatRectangle8x8( void )
+{
+ INT16 n_y;
+ INT16 n_x;
+
+ UINT8 n_cmd;
+
+ UINT16 *p_n_f;
+ UINT16 *p_n_redb;
+ UINT16 *p_n_greenb;
+ UINT16 *p_n_blueb;
+ UINT16 *p_n_redtrans;
+ UINT16 *p_n_greentrans;
+ UINT16 *p_n_bluetrans;
+
+ PAIR n_r;
+ PAIR n_g;
+ PAIR n_b;
+
+ INT32 n_distance;
+ INT32 n_h;
+ UINT16 *p_vram;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 9 )
+ {
+ return;
+ }
+ DebugMesh( COORD_X( m_packet.FlatRectangle8x8.n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.FlatRectangle8x8.n_coord ) + m_n_drawoffset_y );
+ DebugMesh( COORD_X( m_packet.FlatRectangle8x8.n_coord ) + m_n_drawoffset_x + 8, COORD_Y( m_packet.FlatRectangle8x8.n_coord ) + m_n_drawoffset_y );
+ DebugMesh( COORD_X( m_packet.FlatRectangle8x8.n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.FlatRectangle8x8.n_coord ) + m_n_drawoffset_y + 8 );
+ DebugMesh( COORD_X( m_packet.FlatRectangle8x8.n_coord ) + m_n_drawoffset_x + 8, COORD_Y( m_packet.FlatRectangle8x8.n_coord ) + m_n_drawoffset_y + 8 );
+ DebugMeshEnd();
+#endif
+
+ n_cmd = BGR_C( m_packet.FlatRectangle8x8.n_bgr );
+
+ SOLIDSETUP
+
+ n_r.w.h = BGR_R( m_packet.FlatRectangle8x8.n_bgr ); n_r.w.l = 0;
+ n_g.w.h = BGR_G( m_packet.FlatRectangle8x8.n_bgr ); n_g.w.l = 0;
+ n_b.w.h = BGR_B( m_packet.FlatRectangle8x8.n_bgr ); n_b.w.l = 0;
+
+ n_y = COORD_Y( m_packet.FlatRectangle8x8.n_coord ) + m_n_drawoffset_y;
+ n_h = 8;
+
+ while( n_h > 0 )
+ {
+ n_x = COORD_X( m_packet.FlatRectangle8x8.n_coord ) + m_n_drawoffset_x;
+
+ n_distance = 8;
+ if( n_distance > 0 && n_y >= (INT32)m_n_drawarea_y1 && n_y <= (INT32)m_n_drawarea_y2 )
+ {
+ if( ( (INT32)m_n_drawarea_x1 - n_x ) > 0 )
+ {
+ n_distance -= ( m_n_drawarea_x1 - n_x );
+ n_x = m_n_drawarea_x1;
+ }
+ SOLIDFILL( FLATRECTANGEUPDATE )
+ }
+ n_y++;
+ n_h--;
+ }
+}
+
+static void FlatRectangle16x16( void )
+{
+ INT16 n_y;
+ INT16 n_x;
+
+ UINT8 n_cmd;
+
+ UINT16 *p_n_f;
+ UINT16 *p_n_redb;
+ UINT16 *p_n_greenb;
+ UINT16 *p_n_blueb;
+ UINT16 *p_n_redtrans;
+ UINT16 *p_n_greentrans;
+ UINT16 *p_n_bluetrans;
+
+ PAIR n_r;
+ PAIR n_g;
+ PAIR n_b;
+
+ INT32 n_distance;
+ INT32 n_h;
+ UINT16 *p_vram;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 10 )
+ {
+ return;
+ }
+ DebugMesh( COORD_X( m_packet.FlatRectangle16x16.n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.FlatRectangle16x16.n_coord ) + m_n_drawoffset_y );
+ DebugMesh( COORD_X( m_packet.FlatRectangle16x16.n_coord ) + m_n_drawoffset_x + 16, COORD_Y( m_packet.FlatRectangle16x16.n_coord ) + m_n_drawoffset_y );
+ DebugMesh( COORD_X( m_packet.FlatRectangle16x16.n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.FlatRectangle16x16.n_coord ) + m_n_drawoffset_y + 16 );
+ DebugMesh( COORD_X( m_packet.FlatRectangle16x16.n_coord ) + m_n_drawoffset_x + 16, COORD_Y( m_packet.FlatRectangle16x16.n_coord ) + m_n_drawoffset_y + 16 );
+ DebugMeshEnd();
+#endif
+
+ n_cmd = BGR_C( m_packet.FlatRectangle16x16.n_bgr );
+
+ SOLIDSETUP
+
+ n_r.w.h = BGR_R( m_packet.FlatRectangle16x16.n_bgr ); n_r.w.l = 0;
+ n_g.w.h = BGR_G( m_packet.FlatRectangle16x16.n_bgr ); n_g.w.l = 0;
+ n_b.w.h = BGR_B( m_packet.FlatRectangle16x16.n_bgr ); n_b.w.l = 0;
+
+ n_y = COORD_Y( m_packet.FlatRectangle16x16.n_coord ) + m_n_drawoffset_y;
+ n_h = 16;
+
+ while( n_h > 0 )
+ {
+ n_x = COORD_X( m_packet.FlatRectangle16x16.n_coord ) + m_n_drawoffset_x;
+
+ n_distance = 16;
+ if( n_distance > 0 && n_y >= (INT32)m_n_drawarea_y1 && n_y <= (INT32)m_n_drawarea_y2 )
+ {
+ if( ( (INT32)m_n_drawarea_x1 - n_x ) > 0 )
+ {
+ n_distance -= ( m_n_drawarea_x1 - n_x );
+ n_x = m_n_drawarea_x1;
+ }
+ SOLIDFILL( FLATRECTANGEUPDATE )
+ }
+ n_y++;
+ n_h--;
+ }
+}
+
+static void FlatTexturedRectangle( void )
+{
+ INT16 n_y;
+ INT16 n_x;
+ int n_tx;
+ int n_ty;
+
+ UINT8 n_cmd;
+
+ UINT32 n_clutx;
+ UINT32 n_cluty;
+
+ UINT16 *p_n_f;
+ UINT16 *p_n_redb;
+ UINT16 *p_n_greenb;
+ UINT16 *p_n_blueb;
+ UINT16 *p_n_redtrans;
+ UINT16 *p_n_greentrans;
+ UINT16 *p_n_bluetrans;
+
+ PAIR n_r;
+ PAIR n_g;
+ PAIR n_b;
+ UINT8 n_u;
+ UINT8 n_v;
+ int n_du;
+ int n_dv;
+
+ INT16 n_distance;
+ UINT32 n_h;
+ UINT16 *p_vram;
+ UINT16 *p_clut;
+ UINT16 n_bgr;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 11 )
+ {
+ return;
+ }
+ DebugMesh( COORD_X( m_packet.FlatTexturedRectangle.n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.FlatTexturedRectangle.n_coord ) + m_n_drawoffset_y );
+ DebugMesh( COORD_X( m_packet.FlatTexturedRectangle.n_coord ) + m_n_drawoffset_x + SIZE_W( m_packet.FlatTexturedRectangle.n_size ), COORD_Y( m_packet.FlatTexturedRectangle.n_coord ) + m_n_drawoffset_y );
+ DebugMesh( COORD_X( m_packet.FlatTexturedRectangle.n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.FlatTexturedRectangle.n_coord ) + m_n_drawoffset_y + SIZE_H( m_packet.FlatTexturedRectangle.n_size ) );
+ DebugMesh( COORD_X( m_packet.FlatTexturedRectangle.n_coord ) + m_n_drawoffset_x + SIZE_W( m_packet.FlatTexturedRectangle.n_size ), COORD_Y( m_packet.FlatTexturedRectangle.n_coord ) + m_n_drawoffset_y + SIZE_H( m_packet.FlatTexturedRectangle.n_size ) );
+ DebugMeshEnd();
+#endif
+
+ n_cmd = BGR_C( m_packet.FlatTexturedRectangle.n_bgr );
+
+ n_clutx = ( m_packet.FlatTexturedRectangle.n_texture.w.h & 0x3f ) << 4;
+ n_cluty = ( m_packet.FlatTexturedRectangle.n_texture.w.h >> 6 ) & 0x3ff;
+
+ n_r.d = 0;
+ n_g.d = 0;
+ n_b.d = 0;
+
+ TEXTURESETUP
+ SPRITESETUP
+
+ switch( n_cmd & 0x01 )
+ {
+ case 0:
+ n_r.w.h = BGR_R( m_packet.FlatTexturedRectangle.n_bgr ); n_r.w.l = 0;
+ n_g.w.h = BGR_G( m_packet.FlatTexturedRectangle.n_bgr ); n_g.w.l = 0;
+ n_b.w.h = BGR_B( m_packet.FlatTexturedRectangle.n_bgr ); n_b.w.l = 0;
+ break;
+ case 1:
+ n_r.w.h = 0x80; n_r.w.l = 0;
+ n_g.w.h = 0x80; n_g.w.l = 0;
+ n_b.w.h = 0x80; n_b.w.l = 0;
+ break;
+ }
+
+ n_v = TEXTURE_V( m_packet.FlatTexturedRectangle.n_texture );
+ n_y = COORD_Y( m_packet.FlatTexturedRectangle.n_coord ) + m_n_drawoffset_y;
+ n_h = SIZE_H( m_packet.FlatTexturedRectangle.n_size );
+
+ while( n_h > 0 )
+ {
+ n_x = COORD_X( m_packet.FlatTexturedRectangle.n_coord ) + m_n_drawoffset_x;
+ n_u = TEXTURE_U( m_packet.FlatTexturedRectangle.n_texture );
+
+ n_distance = SIZE_W( m_packet.FlatTexturedRectangle.n_size );
+ if( n_distance > 0 && n_y >= (INT32)m_n_drawarea_y1 && n_y <= (INT32)m_n_drawarea_y2 )
+ {
+ if( ( (INT32)m_n_drawarea_x1 - n_x ) > 0 )
+ {
+ n_u += ( m_n_drawarea_x1 - n_x ) * n_du;
+ n_distance -= ( m_n_drawarea_x1 - n_x );
+ n_x = m_n_drawarea_x1;
+ }
+ TEXTUREFILL( FLATTEXTUREDRECTANGLEUPDATE, n_u, n_v );
+ }
+ n_v += n_dv;
+ n_y++;
+ n_h--;
+ }
+}
+
+static void Sprite8x8( void )
+{
+ INT16 n_y;
+ INT16 n_x;
+ int n_tx;
+ int n_ty;
+
+ UINT8 n_cmd;
+
+ UINT32 n_clutx;
+ UINT32 n_cluty;
+
+ UINT16 *p_n_f;
+ UINT16 *p_n_redb;
+ UINT16 *p_n_greenb;
+ UINT16 *p_n_blueb;
+ UINT16 *p_n_redtrans;
+ UINT16 *p_n_greentrans;
+ UINT16 *p_n_bluetrans;
+
+ PAIR n_r;
+ PAIR n_g;
+ PAIR n_b;
+ UINT8 n_u;
+ UINT8 n_v;
+ int n_du;
+ int n_dv;
+
+ INT16 n_distance;
+ UINT32 n_h;
+ UINT16 *p_vram;
+ UINT16 *p_clut;
+ UINT16 n_bgr;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 12 )
+ {
+ return;
+ }
+ DebugMesh( COORD_X( m_packet.Sprite8x8.n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.Sprite8x8.n_coord ) + m_n_drawoffset_y );
+ DebugMesh( COORD_X( m_packet.Sprite8x8.n_coord ) + m_n_drawoffset_x + 7, COORD_Y( m_packet.Sprite8x8.n_coord ) + m_n_drawoffset_y );
+ DebugMesh( COORD_X( m_packet.Sprite8x8.n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.Sprite8x8.n_coord ) + m_n_drawoffset_y + 7 );
+ DebugMesh( COORD_X( m_packet.Sprite8x8.n_coord ) + m_n_drawoffset_x + 7, COORD_Y( m_packet.Sprite8x8.n_coord ) + m_n_drawoffset_y + 7 );
+ DebugMeshEnd();
+#endif
+
+ n_cmd = BGR_C( m_packet.Sprite8x8.n_bgr );
+
+ n_clutx = ( m_packet.Sprite8x8.n_texture.w.h & 0x3f ) << 4;
+ n_cluty = ( m_packet.Sprite8x8.n_texture.w.h >> 6 ) & 0x3ff;
+
+ n_r.d = 0;
+ n_g.d = 0;
+ n_b.d = 0;
+
+ TEXTURESETUP
+ SPRITESETUP
+
+ switch( n_cmd & 0x01 )
+ {
+ case 0:
+ n_r.w.h = BGR_R( m_packet.Sprite8x8.n_bgr ); n_r.w.l = 0;
+ n_g.w.h = BGR_G( m_packet.Sprite8x8.n_bgr ); n_g.w.l = 0;
+ n_b.w.h = BGR_B( m_packet.Sprite8x8.n_bgr ); n_b.w.l = 0;
+ break;
+ case 1:
+ n_r.w.h = 0x80; n_r.w.l = 0;
+ n_g.w.h = 0x80; n_g.w.l = 0;
+ n_b.w.h = 0x80; n_b.w.l = 0;
+ break;
+ }
+
+ n_v = TEXTURE_V( m_packet.Sprite8x8.n_texture );
+ n_y = COORD_Y( m_packet.Sprite8x8.n_coord ) + m_n_drawoffset_y;
+ n_h = 8;
+
+ while( n_h > 0 )
+ {
+ n_x = COORD_X( m_packet.Sprite8x8.n_coord ) + m_n_drawoffset_x;
+ n_u = TEXTURE_U( m_packet.Sprite8x8.n_texture );
+
+ n_distance = 8;
+ if( n_distance > 0 && n_y >= (INT32)m_n_drawarea_y1 && n_y <= (INT32)m_n_drawarea_y2 )
+ {
+ if( ( (INT32)m_n_drawarea_x1 - n_x ) > 0 )
+ {
+ n_u += ( m_n_drawarea_x1 - n_x ) * n_du;
+ n_distance -= ( m_n_drawarea_x1 - n_x );
+ n_x = m_n_drawarea_x1;
+ }
+ TEXTUREFILL( FLATTEXTUREDRECTANGLEUPDATE, n_u, n_v );
+ }
+ n_v += n_dv;
+ n_y++;
+ n_h--;
+ }
+}
+
+static void Sprite16x16( void )
+{
+ INT16 n_y;
+ INT16 n_x;
+ int n_tx;
+ int n_ty;
+
+ UINT8 n_cmd;
+
+ UINT32 n_clutx;
+ UINT32 n_cluty;
+
+ UINT16 *p_n_f;
+ UINT16 *p_n_redb;
+ UINT16 *p_n_greenb;
+ UINT16 *p_n_blueb;
+ UINT16 *p_n_redtrans;
+ UINT16 *p_n_greentrans;
+ UINT16 *p_n_bluetrans;
+
+ PAIR n_r;
+ PAIR n_g;
+ PAIR n_b;
+ UINT8 n_u;
+ UINT8 n_v;
+ int n_du;
+ int n_dv;
+
+ INT16 n_distance;
+ UINT32 n_h;
+ UINT16 *p_vram;
+ UINT16 *p_clut;
+ UINT16 n_bgr;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 13 )
+ {
+ return;
+ }
+ DebugMesh( COORD_X( m_packet.Sprite16x16.n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.Sprite16x16.n_coord ) + m_n_drawoffset_y );
+ DebugMesh( COORD_X( m_packet.Sprite16x16.n_coord ) + m_n_drawoffset_x + 7, COORD_Y( m_packet.Sprite16x16.n_coord ) + m_n_drawoffset_y );
+ DebugMesh( COORD_X( m_packet.Sprite16x16.n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.Sprite16x16.n_coord ) + m_n_drawoffset_y + 7 );
+ DebugMesh( COORD_X( m_packet.Sprite16x16.n_coord ) + m_n_drawoffset_x + 7, COORD_Y( m_packet.Sprite16x16.n_coord ) + m_n_drawoffset_y + 7 );
+ DebugMeshEnd();
+#endif
+
+ n_cmd = BGR_C( m_packet.Sprite16x16.n_bgr );
+
+ n_clutx = ( m_packet.Sprite16x16.n_texture.w.h & 0x3f ) << 4;
+ n_cluty = ( m_packet.Sprite16x16.n_texture.w.h >> 6 ) & 0x3ff;
+
+ n_r.d = 0;
+ n_g.d = 0;
+ n_b.d = 0;
+
+ TEXTURESETUP
+ SPRITESETUP
+
+ switch( n_cmd & 0x01 )
+ {
+ case 0:
+ n_r.w.h = BGR_R( m_packet.Sprite16x16.n_bgr ); n_r.w.l = 0;
+ n_g.w.h = BGR_G( m_packet.Sprite16x16.n_bgr ); n_g.w.l = 0;
+ n_b.w.h = BGR_B( m_packet.Sprite16x16.n_bgr ); n_b.w.l = 0;
+ break;
+ case 1:
+ n_r.w.h = 0x80; n_r.w.l = 0;
+ n_g.w.h = 0x80; n_g.w.l = 0;
+ n_b.w.h = 0x80; n_b.w.l = 0;
+ break;
+ }
+
+ n_v = TEXTURE_V( m_packet.Sprite16x16.n_texture );
+ n_y = COORD_Y( m_packet.Sprite16x16.n_coord ) + m_n_drawoffset_y;
+ n_h = 16;
+
+ while( n_h > 0 )
+ {
+ n_x = COORD_X( m_packet.Sprite16x16.n_coord ) + m_n_drawoffset_x;
+ n_u = TEXTURE_U( m_packet.Sprite16x16.n_texture );
+
+ n_distance = 16;
+ if( n_distance > 0 && n_y >= (INT32)m_n_drawarea_y1 && n_y <= (INT32)m_n_drawarea_y2 )
+ {
+ if( ( (INT32)m_n_drawarea_x1 - n_x ) > 0 )
+ {
+ n_u += ( m_n_drawarea_x1 - n_x ) * n_du;
+ n_distance -= ( m_n_drawarea_x1 - n_x );
+ n_x = m_n_drawarea_x1;
+ }
+ TEXTUREFILL( FLATTEXTUREDRECTANGLEUPDATE, n_u, n_v );
+ }
+ n_v += n_dv;
+ n_y++;
+ n_h--;
+ }
+}
+
+static void Dot( void )
+{
+ INT32 n_x;
+ INT32 n_y;
+ UINT32 n_r;
+ UINT32 n_g;
+ UINT32 n_b;
+ UINT16 *p_vram;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 14 )
+ {
+ return;
+ }
+ DebugMesh( COORD_X( m_packet.Dot.vertex.n_coord ) + m_n_drawoffset_x, COORD_Y( m_packet.Dot.vertex.n_coord ) + m_n_drawoffset_y );
+ DebugMeshEnd();
+#endif
+
+ n_r = BGR_R( m_packet.Dot.n_bgr );
+ n_g = BGR_G( m_packet.Dot.n_bgr );
+ n_b = BGR_B( m_packet.Dot.n_bgr );
+ n_x = COORD_X( m_packet.Dot.vertex.n_coord ) + m_n_drawoffset_x;
+ n_y = COORD_Y( m_packet.Dot.vertex.n_coord ) + m_n_drawoffset_y;
+
+ if( (INT16)n_x >= (INT32)m_n_drawarea_x1 &&
+ (INT16)n_y >= (INT32)m_n_drawarea_y1 &&
+ (INT16)n_x <= (INT32)m_n_drawarea_x2 &&
+ (INT16)n_y <= (INT32)m_n_drawarea_y2 )
+ {
+ p_vram = m_p_p_vram[ n_y ] + n_x;
+ WRITE_PIXEL(
+ m_p_n_redshade[ MID_LEVEL | n_r ] |
+ m_p_n_greenshade[ MID_LEVEL | n_g ] |
+ m_p_n_blueshade[ MID_LEVEL | n_b ] );
+ }
+}
+
+static void MoveImage( void )
+{
+ INT16 n_w;
+ INT16 n_h;
+ INT16 n_srcx;
+ INT16 n_srcy;
+ INT16 n_dsty;
+ INT16 n_dstx;
+ UINT16 *p_vram;
+
+#if defined( MAME_DEBUG )
+ if( m_n_debugskip == 15 )
+ {
+ return;
+ }
+ DebugMesh( COORD_X( m_packet.MoveImage.vertex[ 1 ].n_coord ), COORD_Y( m_packet.MoveImage.vertex[ 1 ].n_coord ) );
+ DebugMesh( COORD_X( m_packet.MoveImage.vertex[ 1 ].n_coord ) + SIZE_W( m_packet.MoveImage.n_size ), COORD_Y( m_packet.MoveImage.vertex[ 1 ].n_coord ) );
+ DebugMesh( COORD_X( m_packet.MoveImage.vertex[ 1 ].n_coord ), COORD_Y( m_packet.MoveImage.vertex[ 1 ].n_coord ) + SIZE_H( m_packet.MoveImage.n_size ) );
+ DebugMesh( COORD_X( m_packet.MoveImage.vertex[ 1 ].n_coord ) + SIZE_W( m_packet.MoveImage.n_size ), COORD_Y( m_packet.MoveImage.vertex[ 1 ].n_coord ) + SIZE_H( m_packet.MoveImage.n_size ) );
+ DebugMeshEnd();
+#endif
+
+ n_srcy = COORD_Y( m_packet.MoveImage.vertex[ 0 ].n_coord );
+ n_dsty = COORD_Y( m_packet.MoveImage.vertex[ 1 ].n_coord );
+ n_h = SIZE_H( m_packet.MoveImage.n_size );
+
+ while( n_h > 0 )
+ {
+ n_srcx = COORD_X( m_packet.MoveImage.vertex[ 0 ].n_coord );
+ n_dstx = COORD_X( m_packet.MoveImage.vertex[ 1 ].n_coord );
+ n_w = SIZE_W( m_packet.MoveImage.n_size );
+ while( n_w > 0 )
+ {
+ p_vram = m_p_p_vram[ n_dsty & 1023 ] + ( n_dstx & 1023 );
+ WRITE_PIXEL( *( m_p_p_vram[ n_srcy & 1023 ] + ( n_srcx & 1023 ) ) );
+ n_srcx++;
+ n_dstx++;
+ n_w--;
+ }
+ n_srcy++;
+ n_dsty++;
+ n_h--;
+ }
+}
+
+void psx_gpu_write( UINT32 *p_ram, INT32 n_size )
+{
+ while( n_size > 0 )
+ {
+ UINT32 data = *( p_ram );
+
+ verboselog( 2, "PSX Packet #%u %08x\n", m_n_gpu_buffer_offset, data );
+ m_packet.n_entry[ m_n_gpu_buffer_offset ] = data;
+ switch( m_packet.n_entry[ 0 ] >> 24 )
+ {
+ case 0x00:
+ verboselog( 1, "not handled: GPU Command 0x00: (%08x)\n", data );
+ break;
+ case 0x01:
+ verboselog( 1, "not handled: clear cache\n" );
+ break;
+ case 0x02:
+ if( m_n_gpu_buffer_offset < 2 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: frame buffer rectangle %u,%u %u,%u\n", m_packet.n_entry[ 0 ] >> 24,
+ m_packet.n_entry[ 1 ] & 0xffff, m_packet.n_entry[ 1 ] >> 16, m_packet.n_entry[ 2 ] & 0xffff, m_packet.n_entry[ 2 ] >> 16 );
+ FrameBufferRectangleDraw();
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ if( m_n_gpu_buffer_offset < 3 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: monochrome 3 point polygon\n", m_packet.n_entry[ 0 ] >> 24 );
+ FlatPolygon( 3 );
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ if( m_n_gpu_buffer_offset < 6 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: textured 3 point polygon\n", m_packet.n_entry[ 0 ] >> 24 );
+ FlatTexturedPolygon( 3 );
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ if( m_n_gpu_buffer_offset < 4 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: monochrome 4 point polygon\n", m_packet.n_entry[ 0 ] >> 24 );
+ FlatPolygon( 4 );
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ if( m_n_gpu_buffer_offset < 8 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: textured 4 point polygon\n", m_packet.n_entry[ 0 ] >> 24 );
+ FlatTexturedPolygon( 4 );
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ if( m_n_gpu_buffer_offset < 5 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: gouraud 3 point polygon\n", m_packet.n_entry[ 0 ] >> 24 );
+ GouraudPolygon( 3 );
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ if( m_n_gpu_buffer_offset < 8 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: gouraud textured 3 point polygon\n", m_packet.n_entry[ 0 ] >> 24 );
+ GouraudTexturedPolygon( 3 );
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ if( m_n_gpu_buffer_offset < 7 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: gouraud 4 point polygon\n", m_packet.n_entry[ 0 ] >> 24 );
+ GouraudPolygon( 4 );
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ if( m_n_gpu_buffer_offset < 11 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: gouraud textured 4 point polygon\n", m_packet.n_entry[ 0 ] >> 24 );
+ GouraudTexturedPolygon( 4 );
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ if( m_n_gpu_buffer_offset < 2 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: monochrome line\n", m_packet.n_entry[ 0 ] >> 24 );
+ MonochromeLine();
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x48:
+ case 0x4a:
+ case 0x4c:
+ if( m_n_gpu_buffer_offset < 3 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: monochrome polyline\n", m_packet.n_entry[ 0 ] >> 24 );
+ MonochromeLine();
+ if( ( m_packet.n_entry[ 3 ] & 0xf000f000 ) != 0x50005000 )
+ {
+ m_packet.n_entry[ 1 ] = m_packet.n_entry[ 2 ];
+ m_packet.n_entry[ 2 ] = m_packet.n_entry[ 3 ];
+ m_n_gpu_buffer_offset = 3;
+ }
+ else
+ {
+ m_n_gpu_buffer_offset = 0;
+ }
+ }
+ break;
+ case 0x50:
+ case 0x52:
+ if( m_n_gpu_buffer_offset < 3 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: gouraud line\n", m_packet.n_entry[ 0 ] >> 24 );
+ GouraudLine();
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x58:
+ case 0x5c:
+ case 0x5e:
+ if( m_n_gpu_buffer_offset < 5 &&
+ ( m_n_gpu_buffer_offset != 4 || ( m_packet.n_entry[ 4 ] & 0xf000f000 ) != 0x50005000 ) )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: gouraud polyline\n", m_packet.n_entry[ 0 ] >> 24 );
+ GouraudLine();
+ if( ( m_packet.n_entry[ 4 ] & 0xf000f000 ) != 0x50005000 )
+ {
+ m_packet.n_entry[ 0 ] = ( m_packet.n_entry[ 0 ] & 0xff000000 ) | ( m_packet.n_entry[ 2 ] & 0x00ffffff );
+ m_packet.n_entry[ 1 ] = m_packet.n_entry[ 3 ];
+ m_packet.n_entry[ 2 ] = m_packet.n_entry[ 4 ];
+ m_packet.n_entry[ 3 ] = m_packet.n_entry[ 5 ];
+ m_n_gpu_buffer_offset = 4;
+ }
+ else
+ {
+ m_n_gpu_buffer_offset = 0;
+ }
+ }
+ break;
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ if( m_n_gpu_buffer_offset < 2 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: rectangle %d,%d %d,%d\n",
+ m_packet.n_entry[ 0 ] >> 24,
+ (INT16)( m_packet.n_entry[ 1 ] & 0xffff ), (INT16)( m_packet.n_entry[ 1 ] >> 16 ),
+ (INT16)( m_packet.n_entry[ 2 ] & 0xffff ), (INT16)( m_packet.n_entry[ 2 ] >> 16 ) );
+ FlatRectangle();
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ if( m_n_gpu_buffer_offset < 3 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: sprite %d,%d %u,%u %08x, %08x\n",
+ m_packet.n_entry[ 0 ] >> 24,
+ (INT16)( m_packet.n_entry[ 1 ] & 0xffff ), (INT16)( m_packet.n_entry[ 1 ] >> 16 ),
+ m_packet.n_entry[ 3 ] & 0xffff, m_packet.n_entry[ 3 ] >> 16,
+ m_packet.n_entry[ 0 ], m_packet.n_entry[ 2 ] );
+ FlatTexturedRectangle();
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x68:
+ case 0x6a:
+ if( m_n_gpu_buffer_offset < 1 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: dot %d,%d %08x\n",
+ m_packet.n_entry[ 0 ] >> 24,
+ (INT16)( m_packet.n_entry[ 1 ] & 0xffff ), (INT16)( m_packet.n_entry[ 1 ] >> 16 ),
+ m_packet.n_entry[ 0 ] & 0xffffff );
+ Dot();
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x70:
+ case 0x71:
+ /* 8*8 rectangle */
+ if( m_n_gpu_buffer_offset < 1 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: 16x16 rectangle %08x %08x\n", m_packet.n_entry[ 0 ] >> 24,
+ m_packet.n_entry[ 0 ], m_packet.n_entry[ 1 ] );
+ FlatRectangle8x8();
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ if( m_n_gpu_buffer_offset < 2 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: 8x8 sprite %08x %08x %08x\n", m_packet.n_entry[ 0 ] >> 24,
+ m_packet.n_entry[ 0 ], m_packet.n_entry[ 1 ], m_packet.n_entry[ 2 ] );
+ Sprite8x8();
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x78:
+ case 0x79:
+ /* 16*16 rectangle */
+ if( m_n_gpu_buffer_offset < 1 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: 16x16 rectangle %08x %08x\n", m_packet.n_entry[ 0 ] >> 24,
+ m_packet.n_entry[ 0 ], m_packet.n_entry[ 1 ] );
+ FlatRectangle16x16();
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x7c:
+ case 0x7d:
+ case 0x7e:
+ case 0x7f:
+ if( m_n_gpu_buffer_offset < 2 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: 16x16 sprite %08x %08x %08x\n", m_packet.n_entry[ 0 ] >> 24,
+ m_packet.n_entry[ 0 ], m_packet.n_entry[ 1 ], m_packet.n_entry[ 2 ] );
+ Sprite16x16();
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0x80:
+ if( m_n_gpu_buffer_offset < 3 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "move image in frame buffer %08x %08x %08x %08x\n", m_packet.n_entry[ 0 ], m_packet.n_entry[ 1 ], m_packet.n_entry[ 2 ], m_packet.n_entry[ 3 ] );
+ MoveImage();
+ m_n_gpu_buffer_offset = 0;
+ }
+ break;
+ case 0xa0:
+ if( m_n_gpu_buffer_offset < 3 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ UINT32 n_pixel;
+ for( n_pixel = 0; n_pixel < 2; n_pixel++ )
+ {
+ UINT16 *p_vram;
+
+ verboselog( 2, "send image to framebuffer ( pixel %u,%u = %u )\n",
+ ( m_n_vramx + m_packet.n_entry[ 1 ] ) & 1023,
+ ( m_n_vramy + ( m_packet.n_entry[ 1 ] >> 16 ) ) & 1023,
+ data & 0xffff );
+
+ p_vram = m_p_p_vram[ ( m_n_vramy + ( m_packet.n_entry[ 1 ] >> 16 ) ) & 1023 ] + ( ( m_n_vramx + m_packet.n_entry[ 1 ] ) & 1023 );
+ WRITE_PIXEL( data & 0xffff );
+ m_n_vramx++;
+ if( m_n_vramx >= ( m_packet.n_entry[ 2 ] & 0xffff ) )
+ {
+ m_n_vramx = 0;
+ m_n_vramy++;
+ if( m_n_vramy >= ( m_packet.n_entry[ 2 ] >> 16 ) )
+ {
+ verboselog( 1, "%02x: send image to framebuffer %u,%u %u,%u\n", m_packet.n_entry[ 0 ] >> 24,
+ m_packet.n_entry[ 1 ] & 0xffff, ( m_packet.n_entry[ 1 ] >> 16 ),
+ m_packet.n_entry[ 2 ] & 0xffff, ( m_packet.n_entry[ 2 ] >> 16 ) );
+ m_n_gpu_buffer_offset = 0;
+ m_n_vramx = 0;
+ m_n_vramy = 0;
+ break;
+ }
+ }
+ data >>= 16;
+ }
+ }
+ break;
+ case 0xc0:
+ if( m_n_gpu_buffer_offset < 2 )
+ {
+ m_n_gpu_buffer_offset++;
+ }
+ else
+ {
+ verboselog( 1, "%02x: copy image from frame buffer\n", m_packet.n_entry[ 0 ] >> 24 );
+ m_n_gpustatus |= ( 1L << 0x1b );
+ }
+ break;
+ case 0xe1:
+ verboselog( 1, "%02x: draw mode %06x\n", m_packet.n_entry[ 0 ] >> 24,
+ m_packet.n_entry[ 0 ] & 0xffffff );
+ decode_tpage( &psxgpu, m_packet.n_entry[ 0 ] & 0xffffff );
+ break;
+ case 0xe2:
+ m_n_twy = ( ( ( m_packet.n_entry[ 0 ] >> 15 ) & 0x1f ) << 3 );
+ m_n_twx = ( ( ( m_packet.n_entry[ 0 ] >> 10 ) & 0x1f ) << 3 );
+ m_n_twh = 255 - ( ( ( m_packet.n_entry[ 0 ] >> 5 ) & 0x1f ) << 3 );
+ m_n_tww = 255 - ( ( m_packet.n_entry[ 0 ] & 0x1f ) << 3 );
+ verboselog( 1, "%02x: texture window %u,%u %u,%u\n", m_packet.n_entry[ 0 ] >> 24,
+ m_n_twx, m_n_twy, m_n_tww, m_n_twh );
+ break;
+ case 0xe3:
+ m_n_drawarea_x1 = m_packet.n_entry[ 0 ] & 1023;
+ if( m_n_gputype == 2 )
+ {
+ m_n_drawarea_y1 = ( m_packet.n_entry[ 0 ] >> 10 ) & 1023;
+ }
+ else
+ {
+ m_n_drawarea_y1 = ( m_packet.n_entry[ 0 ] >> 12 ) & 1023;
+ }
+ verboselog( 1, "%02x: drawing area top left %d,%d\n", m_packet.n_entry[ 0 ] >> 24,
+ m_n_drawarea_x1, m_n_drawarea_y1 );
+ break;
+ case 0xe4:
+ m_n_drawarea_x2 = m_packet.n_entry[ 0 ] & 1023;
+ if( m_n_gputype == 2 )
+ {
+ m_n_drawarea_y2 = ( m_packet.n_entry[ 0 ] >> 10 ) & 1023;
+ }
+ else
+ {
+ m_n_drawarea_y2 = ( m_packet.n_entry[ 0 ] >> 12 ) & 1023;
+ }
+ verboselog( 1, "%02x: drawing area bottom right %d,%d\n", m_packet.n_entry[ 0 ] >> 24,
+ m_n_drawarea_x2, m_n_drawarea_y2 );
+ break;
+ case 0xe5:
+ m_n_drawoffset_x = SINT11( m_packet.n_entry[ 0 ] & 2047 );
+ if( m_n_gputype == 2 )
+ {
+ m_n_drawoffset_y = SINT11( ( m_packet.n_entry[ 0 ] >> 11 ) & 2047 );
+ }
+ else
+ {
+ m_n_drawoffset_y = SINT11( ( m_packet.n_entry[ 0 ] >> 12 ) & 2047 );
+ }
+ verboselog( 1, "%02x: drawing offset %d,%d\n", m_packet.n_entry[ 0 ] >> 24,
+ m_n_drawoffset_x, m_n_drawoffset_y );
+ break;
+ case 0xe6:
+ m_n_gpustatus &= ~( 3L << 0xb );
+ m_n_gpustatus |= ( data & 0x03 ) << 0xb;
+ if( ( m_packet.n_entry[ 0 ] & 3 ) != 0 )
+ {
+ verboselog( 1, "not handled: mask setting %d\n", m_packet.n_entry[ 0 ] & 3 );
+ }
+ else
+ {
+ verboselog( 1, "mask setting %d\n", m_packet.n_entry[ 0 ] & 3 );
+ }
+ break;
+ default:
+#if defined( MAME_DEBUG )
+ popmessage( "unknown GPU packet %08x", m_packet.n_entry[ 0 ] );
+#endif
+ verboselog( 0, "unknown GPU packet %08x (%08x)\n", m_packet.n_entry[ 0 ], data );
+#if ( STOP_ON_ERROR )
+ m_n_gpu_buffer_offset = 1;
+#endif
+ break;
+ }
+ p_ram++;
+ n_size--;
+ }
+}
+
+WRITE32_HANDLER( psx_gpu_w )
+{
+ switch( offset )
+ {
+ case 0x00:
+ psx_gpu_write( &data, 1 );
+ break;
+ case 0x01:
+ switch( data >> 24 )
+ {
+ case 0x00:
+ verboselog( 1, "reset gpu\n" );
+ m_n_gpu_buffer_offset = 0;
+ m_n_gpustatus = 0x14802000;
+ m_n_drawarea_x1 = 0;
+ m_n_drawarea_y1 = 0;
+ m_n_drawarea_x2 = 1023;
+ m_n_drawarea_y2 = 1023;
+ m_n_drawoffset_x = 0;
+ m_n_drawoffset_y = 0;
+ m_n_displaystartx = 0;
+ m_n_displaystarty = 0;
+ m_n_horiz_disstart = 0x260;
+ m_n_horiz_disend = 0xc60;
+ m_n_vert_disstart = 0x010;
+ m_n_vert_disend = 0x100;
+ m_n_vramx = 0;
+ m_n_vramy = 0;
+ m_n_twx = 0;
+ m_n_twy = 0;
+ m_n_twh = 255;
+ m_n_tww = 255;
+ updatevisiblearea();
+ break;
+ case 0x01:
+ verboselog( 1, "not handled: reset command buffer\n" );
+ m_n_gpu_buffer_offset = 0;
+ break;
+ case 0x02:
+ verboselog( 1, "not handled: reset irq\n" );
+ break;
+ case 0x03:
+ m_n_gpustatus &= ~( 1L << 0x17 );
+ m_n_gpustatus |= ( data & 0x01 ) << 0x17;
+ break;
+ case 0x04:
+ verboselog( 1, "dma setup %d\n", data & 3 );
+ m_n_gpustatus &= ~( 3L << 0x1d );
+ m_n_gpustatus |= ( data & 0x03 ) << 0x1d;
+ m_n_gpustatus &= ~( 1L << 0x19 );
+ if( ( data & 3 ) == 1 || ( data & 3 ) == 2 )
+ {
+ m_n_gpustatus |= ( 1L << 0x19 );
+ }
+ break;
+ case 0x05:
+ m_n_displaystartx = data & 1023;
+ if( m_n_gputype == 2 )
+ {
+ m_n_displaystarty = ( data >> 10 ) & 1023;
+ }
+ else
+ {
+ m_n_displaystarty = ( data >> 12 ) & 1023;
+ }
+ verboselog( 1, "start of display area %d %d\n", m_n_displaystartx, m_n_displaystarty );
+ break;
+ case 0x06:
+ m_n_horiz_disstart = data & 4095;
+ m_n_horiz_disend = ( data >> 12 ) & 4095;
+ verboselog( 1, "horizontal display range %d %d\n", m_n_horiz_disstart, m_n_horiz_disend );
+ break;
+ case 0x07:
+ m_n_vert_disstart = data & 1023;
+ m_n_vert_disend = ( data >> 10 ) & 2047;
+ verboselog( 1, "vertical display range %d %d\n", m_n_vert_disstart, m_n_vert_disend );
+ break;
+ case 0x08:
+ verboselog( 1, "display mode %02x\n", data & 0xff );
+ m_n_gpustatus &= ~( 127L << 0x10 );
+ m_n_gpustatus |= ( data & 0x3f ) << 0x11; /* width 0 + height + videmode + isrgb24 + isinter */
+ m_n_gpustatus |= ( ( data & 0x40 ) >> 0x06 ) << 0x10; /* width 1 */
+ if( m_n_gputype == 1 )
+ {
+ m_b_reverseflag = ( data >> 7 ) & 1;
+ }
+ updatevisiblearea();
+ break;
+ case 0x09:
+ verboselog( 1, "not handled: GPU Control 0x09: %08x\n", data );
+ break;
+ case 0x0d:
+ verboselog( 1, "reset lightgun coordinates %08x\n", data );
+ m_n_lightgun_x = 0;
+ m_n_lightgun_y = 0;
+ break;
+ case 0x10:
+ switch( data & 0xff )
+ {
+ case 0x03:
+ if( m_n_gputype == 2 )
+ {
+ m_n_gpuinfo = m_n_drawarea_x1 | ( m_n_drawarea_y1 << 10 );
+ }
+ else
+ {
+ m_n_gpuinfo = m_n_drawarea_x1 | ( m_n_drawarea_y1 << 12 );
+ }
+ verboselog( 1, "GPU Info - Draw area top left %08x\n", m_n_gpuinfo );
+ break;
+ case 0x04:
+ if( m_n_gputype == 2 )
+ {
+ m_n_gpuinfo = m_n_drawarea_x2 | ( m_n_drawarea_y2 << 10 );
+ }
+ else
+ {
+ m_n_gpuinfo = m_n_drawarea_x2 | ( m_n_drawarea_y2 << 12 );
+ }
+ verboselog( 1, "GPU Info - Draw area bottom right %08x\n", m_n_gpuinfo );
+ break;
+ case 0x05:
+ if( m_n_gputype == 2 )
+ {
+ m_n_gpuinfo = ( m_n_drawoffset_x & 2047 ) | ( ( m_n_drawoffset_y & 2047 ) << 11 );
+ }
+ else
+ {
+ m_n_gpuinfo = ( m_n_drawoffset_x & 2047 ) | ( ( m_n_drawoffset_y & 2047 ) << 12 );
+ }
+ verboselog( 1, "GPU Info - Draw offset %08x\n", m_n_gpuinfo );
+ break;
+ case 0x07:
+ m_n_gpuinfo = m_n_gputype;
+ verboselog( 1, "GPU Info - GPU Type %08x\n", m_n_gpuinfo );
+ break;
+ case 0x08:
+ m_n_gpuinfo = m_n_lightgun_x | ( m_n_lightgun_y << 16 );
+ verboselog( 1, "GPU Info - lightgun coordinates %08x\n", m_n_gpuinfo );
+ break;
+ default:
+ verboselog( 0, "GPU Info - unknown request (%08x)\n", data );
+ m_n_gpuinfo = 0;
+ break;
+ }
+ break;
+ case 0x20:
+ verboselog( 1, "not handled: GPU Control 0x20: %08x\n", data );
+ break;
+ default:
+#if defined( MAME_DEBUG )
+ popmessage( "unknown GPU command %08x", data );
+#endif
+ verboselog( 0, "gpu_w( %08x ) unknown GPU command\n", data );
+ break;
+ }
+ break;
+ default:
+ verboselog( 0, "gpu_w( %08x, %08x, %08x ) unknown register\n", offset, data, mem_mask );
+ break;
+ }
+}
+
+
+void psx_gpu_read( UINT32 *p_ram, INT32 n_size )
+{
+ while( n_size > 0 )
+ {
+ if( ( m_n_gpustatus & ( 1L << 0x1b ) ) != 0 )
+ {
+ UINT32 n_pixel;
+ PAIR data;
+
+ verboselog( 2, "copy image from frame buffer ( %d, %d )\n", m_n_vramx, m_n_vramy );
+ data.d = 0;
+ for( n_pixel = 0; n_pixel < 2; n_pixel++ )
+ {
+ data.w.l = data.w.h;
+ data.w.h = *( m_p_p_vram[ m_n_vramy + ( m_packet.n_entry[ 1 ] >> 16 ) ] + m_n_vramx + ( m_packet.n_entry[ 1 ] & 0xffff ) );
+ m_n_vramx++;
+ if( m_n_vramx >= ( m_packet.n_entry[ 2 ] & 0xffff ) )
+ {
+ m_n_vramx = 0;
+ m_n_vramy++;
+ if( m_n_vramy >= ( m_packet.n_entry[ 2 ] >> 16 ) )
+ {
+ verboselog( 1, "copy image from frame buffer end\n" );
+ m_n_gpustatus &= ~( 1L << 0x1b );
+ m_n_gpu_buffer_offset = 0;
+ m_n_vramx = 0;
+ m_n_vramy = 0;
+ if( n_pixel == 0 )
+ {
+ data.w.l = data.w.h;
+ data.w.h = 0;
+ }
+ break;
+ }
+ }
+ }
+ *( p_ram ) = data.d;
+ }
+ else
+ {
+ verboselog( 2, "read GPU info (%08x)\n", m_n_gpuinfo );
+ *( p_ram ) = m_n_gpuinfo;
+ }
+ p_ram++;
+ n_size--;
+ }
+}
+
+READ32_HANDLER( psx_gpu_r )
+{
+ UINT32 data;
+
+ switch( offset )
+ {
+ case 0x00:
+ psx_gpu_read( &data, 1 );
+ break;
+ case 0x01:
+ verboselog( 1, "read GPU status (%08x)\n", m_n_gpustatus );
+ data = m_n_gpustatus;
+ break;
+ default:
+ verboselog( 0, "gpu_r( %08x, %08x ) unknown register\n", offset, mem_mask );
+ data = 0;
+ break;
+ }
+ return data;
+}
+
+INTERRUPT_GEN( psx_vblank )
+{
+#if defined( MAME_DEBUG )
+ DebugCheckKeys();
+#endif
+
+ m_n_gpustatus ^= ( 1L << 31 );
+ psx_irq_set( 0x0001 );
+}
+
+void psx_gpu_reset( void )
+{
+ psx_gpu_w( 1, 0, 0 );
+}
+
+void psx_lightgun_set( int n_x, int n_y )
+{
+ m_n_lightgun_x = n_x;
+ m_n_lightgun_y = n_y;
+}
diff --git a/src/mame/video/psychic5.c b/src/mame/video/psychic5.c
new file mode 100644
index 00000000000..860038eed92
--- /dev/null
+++ b/src/mame/video/psychic5.c
@@ -0,0 +1,467 @@
+/***************************************************************************
+ Psychic 5
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "jalblend.c"
+
+#define BG_SCROLLX_LSB 0x308
+#define BG_SCROLLX_MSB 0x309
+#define BG_SCROLLY_LSB 0x30a
+#define BG_SCROLLY_MSB 0x30b
+#define BG_SCREEN_MODE 0x30c
+#define BG_PAL_INTENSITY_RG 0x1fe
+#define BG_PAL_INTENSITY_BU 0x1ff
+
+static int ps5_vram_page;
+static int bg_clip_mode;
+static int title_screen;
+
+/* Paged RAM 0 */
+static UINT8 *psychic5_bg_videoram;
+static UINT8 *ps5_dummy_bg_ram;
+
+/* Paged RAM 1 */
+static UINT8 *ps5_io_ram;
+static UINT8 *ps5_palette_ram;
+static UINT8 *psychic5_fg_videoram;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+MACHINE_RESET( psychic5 )
+{
+ bg_clip_mode = -10;
+ flip_screen_set(0);
+}
+
+WRITE8_HANDLER( psychic5_vram_page_select_w )
+{
+ ps5_vram_page = data;
+}
+
+READ8_HANDLER( psychic5_vram_page_select_r )
+{
+ return ps5_vram_page;
+}
+
+WRITE8_HANDLER( psychic5_title_screen_w )
+{
+ title_screen = data & 0x01;
+}
+
+static void psychic5_paletteram_w(int color_offs, int offset, int data)
+{
+ int r,g,b,a,val;
+
+ ps5_palette_ram[offset] = data;
+
+ /* red component */
+ r = (ps5_palette_ram[offset & ~1] >> 4) & 0x0f ;
+
+ /* green component */
+ g = (ps5_palette_ram[offset & ~1]) & 0x0f ;
+
+ /* blue component */
+ b = (ps5_palette_ram[offset | 1] >> 4) & 0x0f ;
+
+ /* "alpha" component */
+ val = (ps5_palette_ram[offset | 1] & 0x0f) & 0x0f ;
+ a = (val << 4) | val ;
+
+ jal_blend_table[(offset / 2)-color_offs] = a ;
+
+ palette_set_color_rgb(Machine,(offset / 2)-color_offs,pal4bit(r),pal4bit(g),pal4bit(b));
+}
+
+static void set_background_palette_intensity(running_machine *machine)
+{
+ int i,r,g,b,val,lo,hi,ir,ig,ib,ix;
+
+ /* red,green,blue intensites */
+ ir = ps5_palette_ram[BG_PAL_INTENSITY_RG] >> 4 ; ir = (ir << 4) | ir ;
+ ig = ps5_palette_ram[BG_PAL_INTENSITY_RG] & 15 ; ig = (ig << 4) | ig ;
+ ib = ps5_palette_ram[BG_PAL_INTENSITY_BU] >> 4 ; ib = (ib << 4) | ib ;
+ ix = ps5_palette_ram[0x1ff] & 0x0f ;
+
+ /* for all of the background palette */
+ for (i = 0; i < 0x100; i++)
+ {
+ lo = ps5_palette_ram[0x400+i*2];
+ hi = ps5_palette_ram[0x400+i*2+1];
+
+ /* red component */
+ val = (lo >> 4) & 0x0f;
+ r = (val << 4) | val ;
+
+ /* green component */
+ val = (lo & 15) & 0x0f;
+ g = (val << 4) | val ;
+
+ /* blue component */
+ val = (hi >> 4) & 0x0f;
+ b = (val << 4) | val ;
+
+ /* Grey background enable */
+ if (ps5_io_ram[BG_SCREEN_MODE] & 0x02)
+ {
+ val = (UINT8)((r + g + b) / 3); /* Grey */
+
+ if (ix != 0x0) /* Tint the grey */
+ {
+ UINT32 result = jal_blend_func(MAKE_RGB(val,val,val), MAKE_RGB(ir, ig, ib), jal_blend_table[0xff]) ;
+ palette_set_color(machine, 0x100+i, result) ;
+ }
+ else /* Just leave plain grey */
+ {
+ palette_set_color(machine,0x100+i,MAKE_RGB(val,val,val));
+ }
+ }
+ else
+ {
+ /* Seems fishy, but the title screen would be black otherwise... */
+ if (!title_screen)
+ {
+ if (ix != 0x0) /* Tint the world */
+ {
+ UINT32 result = jal_blend_func(MAKE_RGB(r, g, b), MAKE_RGB(ir, ig, ib), jal_blend_table[0xff]) ;
+ palette_set_color(machine, 0x100+i, result) ;
+ }
+ else /* Leave the world as-is */
+ {
+ palette_set_color(machine,0x100+i,MAKE_RGB(r,g,b)) ;
+ }
+ }
+ }
+ }
+}
+
+
+static WRITE8_HANDLER( psychic5_bg_videoram_w )
+{
+ psychic5_bg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+static WRITE8_HANDLER( psychic5_fg_videoram_w )
+{
+ psychic5_fg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset / 2);
+}
+
+READ8_HANDLER( psychic5_paged_ram_r )
+{
+ int val;
+
+ if (!ps5_vram_page)
+ {
+ if (offset < 0x1000)
+ return psychic5_bg_videoram[offset];
+ else
+ return ps5_dummy_bg_ram[offset & 0xfff];
+ }
+ else
+ {
+ if (offset < 0x400)
+ {
+ val = 0;
+ switch(offset)
+ {
+ case 0x00:
+ val = input_port_0_r(0);
+ break;
+ case 0x01:
+ val = input_port_1_r(0);
+ break;
+ case 0x02:
+ val = input_port_2_r(0);
+ break;
+ case 0x03:
+ val = input_port_3_r(0);
+ break;
+ case 0x04:
+ val = input_port_4_r(0);
+ break;
+ default:
+ val = ps5_io_ram[offset];
+ }
+ return (val);
+ }
+ else if (offset < 0x1000)
+ {
+ return ps5_palette_ram[offset-0x400];
+ }
+ else
+ {
+ return psychic5_fg_videoram[offset & 0xfff];
+ }
+ }
+ return 0;
+}
+
+WRITE8_HANDLER( psychic5_paged_ram_w )
+{
+ if (!ps5_vram_page)
+ {
+ if (offset < 0x1000)
+ psychic5_bg_videoram_w(offset,data);
+ else
+ ps5_dummy_bg_ram[offset & 0xfff] = data;
+ }
+ else
+ {
+ if (offset < 0x400)
+ {
+ ps5_io_ram[offset] = data;
+ }
+ else if (offset < 0x600)
+ {
+ psychic5_paletteram_w(000, offset-0x400, data);
+ }
+ else if (offset > 0x5ff && offset< 0x800)
+ {
+ ps5_palette_ram[offset-0x400] = data;
+ }
+ else if (offset > 0x7ff && offset < 0xa00)
+ {
+ psychic5_paletteram_w(256, offset-0x400, data);
+ }
+ else if (offset > 0x9ff && offset < 0xc00)
+ {
+ psychic5_paletteram_w(256, offset-0x400, data);
+ }
+ else if (offset < 0x1000)
+ {
+ ps5_palette_ram[offset-0x400] = data;
+ }
+ else
+ {
+ psychic5_fg_videoram_w(offset & 0xfff, data);
+ }
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int offs = tile_index * 2;
+ int attr = psychic5_bg_videoram[offs + 1];
+ int code = psychic5_bg_videoram[offs] + ((attr & 0xc0) << 2);
+ int color = attr & 0x0f;
+ int flags = ((attr & 0x10) ? TILE_FLIPX : 0) + ((attr & 0x20) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(1, code, color, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int offs = tile_index * 2;
+ int attr = psychic5_fg_videoram[offs + 1];
+ int code = psychic5_fg_videoram[offs] + ((attr & 0xc0) << 2);
+ int color = attr & 0x0f;
+ int flags = ((attr & 0x10) ? TILE_FLIPX : 0) + ((attr & 0x20) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(2, code, color, flags);
+}
+
+VIDEO_START( psychic5 )
+{
+ psychic5_bg_videoram = auto_malloc(0x1000);
+ psychic5_fg_videoram = auto_malloc(0x1000);
+ ps5_dummy_bg_ram = auto_malloc(0x1000);
+ ps5_io_ram = auto_malloc(0x400);
+ ps5_palette_ram = auto_malloc(0xc00);
+ jal_blend_table = auto_malloc(0xc00);
+
+ memset(psychic5_bg_videoram, 0,0x1000);
+ memset(psychic5_fg_videoram,0,0x1000);
+ memset(ps5_dummy_bg_ram,0,0x1000);
+ memset(ps5_io_ram,0,0x400);
+ memset(ps5_palette_ram,0,0xc00);
+ memset(jal_blend_table,0,0xc00) ;
+
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 16, 16, 64, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 15);
+}
+
+#define DRAW_SPRITE(code, sx, sy) jal_blend_drawgfx(bitmap, machine->gfx[0], code, color, flipx, flipy, sx, sy, cliprect, TRANSPARENCY_PEN, 15);
+/* #define DRAW_SPRITE(code, sx, sy) drawgfx(bitmap, machine->gfx[0], code, color, flipx, flipy, sx, sy, cliprect, TRANSPARENCY_PEN, 15); */
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ if (title_screen)
+ return;
+ else
+ bg_clip_mode = -10;
+
+ for (offs = 11; offs < spriteram_size; offs += 16)
+ {
+ int tileofs0, tileofs1, tileofs2, tileofs3, temp1, temp2;
+ int attr = spriteram[offs + 2];
+ int code = spriteram[offs + 3] + ((attr & 0xc0) << 2);
+ int color = spriteram[offs + 4] & 0x0f;
+ int flipx = attr & 0x10;
+ int flipy = attr & 0x20;
+ int sx = spriteram[offs + 1];
+ int sy = spriteram[offs];
+ int size32 = attr & 0x08;
+
+ if (attr & 0x01) sx -= 256;
+ if (attr & 0x04) sy -= 256;
+
+ if (flip_screen)
+ {
+ sx = 224 - sx;
+ sy = 224 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if (flipy)
+ {
+ tileofs0 = 1; tileofs1 = 0; tileofs2 = 3; tileofs3 = 2;
+ }
+ else
+ {
+ tileofs0 = 0; tileofs1 = 1; tileofs2 = 2; tileofs3 = 3;
+ }
+
+ if (flipx)
+ {
+ temp1 = tileofs0;
+ temp2 = tileofs1;
+ tileofs0 = tileofs2;
+ tileofs1 = tileofs3;
+ tileofs2 = temp1;
+ tileofs3 = temp2;
+ }
+
+ if (size32)
+ {
+ DRAW_SPRITE(code + tileofs0, sx, sy)
+ DRAW_SPRITE(code + tileofs1, sx, sy + 16)
+ DRAW_SPRITE(code + tileofs2, sx + 16, sy)
+ DRAW_SPRITE(code + tileofs3, sx + 16, sy + 16)
+ }
+ else
+ {
+ if (flip_screen)
+ DRAW_SPRITE(code, sx + 16, sy + 16)
+ else
+ DRAW_SPRITE(code, sx, sy)
+ }
+ }
+}
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int bg_scrollx = (ps5_io_ram[BG_SCROLLX_LSB] + ((ps5_io_ram[BG_SCROLLX_MSB] & 0x03) << 8)) & 0x3ff;
+ int bg_scrolly = (ps5_io_ram[BG_SCROLLY_LSB] + ((ps5_io_ram[BG_SCROLLY_MSB] & 0x01) << 8)) & 0x1ff;
+
+ tilemap_set_scrollx(bg_tilemap, 0, bg_scrollx);
+ tilemap_set_scrolly(bg_tilemap, 0, bg_scrolly);
+
+ set_background_palette_intensity(machine);
+
+ if (ps5_io_ram[BG_SCREEN_MODE] & 0x01) /* background enable */
+ {
+ if (title_screen)
+ {
+ rectangle clip = *cliprect;
+
+ int sx1 = spriteram[12]; /* sprite 0 */
+ int sy1 = spriteram[11];
+ int tile = spriteram[14];
+ int sy2 = spriteram[11+128]; /* sprite 8 */
+
+ if (bg_clip_mode >=0 && bg_clip_mode < 3 && sy1==240) bg_clip_mode = 0;
+ if (bg_clip_mode > 2 && bg_clip_mode < 5 && sy2==240) bg_clip_mode = -10;
+ if (bg_clip_mode > 4 && bg_clip_mode < 7 && sx1==240) bg_clip_mode = 0;
+ if (bg_clip_mode > 6 && bg_clip_mode < 9 && (sx1==240 || sx1==0)) bg_clip_mode = -10;
+
+ if (sy1!=240 && sy1!=0 && bg_clip_mode<=0)
+ {
+ if (sy1 > 128)
+ bg_clip_mode = 1;
+ else
+ bg_clip_mode = 2;
+ }
+
+ if (sy2!=240 && sy2!=0 && bg_clip_mode<=0)
+ {
+ if (sy2 > 128)
+ bg_clip_mode = 3;
+ else
+ bg_clip_mode = 4;
+ }
+
+ if (sx1!=240 && sx1!=0 && bg_clip_mode<=0 && tile==0x3c)
+ {
+ if (sx1 > 128)
+ bg_clip_mode = 5;
+ else
+ bg_clip_mode = 6;
+ }
+
+ if (sx1!=240 && sx1!=0 && bg_clip_mode<=0 && tile==0x1c)
+ {
+ if (sx1 > 128)
+ bg_clip_mode = 7;
+ else
+ bg_clip_mode = 8;
+ }
+
+ if (bg_clip_mode)
+ {
+ if (bg_clip_mode == 1)
+ clip.min_y = sy1;
+ else if (bg_clip_mode == 2)
+ clip.max_y = sy1;
+ else if (bg_clip_mode == 3)
+ clip.max_y = sy2;
+ else if (bg_clip_mode == 4)
+ clip.min_y = sy2;
+ else if (bg_clip_mode == 5)
+ clip.min_x = sx1;
+ else if (bg_clip_mode == 6)
+ clip.max_x = sx1;
+ else if (bg_clip_mode == 7)
+ clip.max_x = sx1;
+ else if (bg_clip_mode == 8)
+ clip.min_x = sx1;
+ else if (bg_clip_mode == -10)
+ {
+ clip.min_x = 0;
+ clip.min_y = 0;
+ clip.max_x = 0;
+ clip.max_y = 0;
+ }
+
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ tilemap_draw(bitmap, &clip, bg_tilemap, 0, 0);
+ }
+ else
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ }
+ else
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ }
+ else
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+}
+
+VIDEO_UPDATE( psychic5 )
+{
+ draw_background(machine, bitmap, cliprect);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/punchout.c b/src/mame/video/punchout.c
new file mode 100644
index 00000000000..211d72b0a9c
--- /dev/null
+++ b/src/mame/video/punchout.c
@@ -0,0 +1,438 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+static tilemap *toptilemap;
+static tilemap *bottilemap;
+static tilemap *spr1tilemap;
+static tilemap *spr2tilemap;
+static tilemap *fgtilemap;
+
+UINT8 *punchout_videoram2;
+UINT8 *armwrest_videoram3;
+UINT8 *punchout_bigsprite1ram;
+UINT8 *punchout_bigsprite2ram;
+UINT8 *punchout_scroll;
+UINT8 *punchout_bigsprite1;
+UINT8 *punchout_bigsprite2;
+UINT8 *punchout_palettebank;
+
+static UINT8 top_palette_bank,bottom_palette_bank;
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Punch Out has a six 512x4 palette PROMs (one per gun; three for the top
+ monitor chars, three for everything else).
+ The PROMs are connected to the RGB output this way:
+
+ bit 3 -- 240 ohm resistor -- inverter -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- inverter -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- inverter -- RED/GREEN/BLUE
+ bit 0 -- 2 kohm resistor -- inverter -- RED/GREEN/BLUE
+
+***************************************************************************/
+static void convert_palette(running_machine *machine,const UINT8 *color_prom)
+{
+ int i;
+
+
+ for (i = 0;i < 1024;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 255 - (0x10 * bit0 + 0x21 * bit1 + 0x46 * bit2 + 0x88 * bit3);
+ bit0 = (color_prom[1024] >> 0) & 0x01;
+ bit1 = (color_prom[1024] >> 1) & 0x01;
+ bit2 = (color_prom[1024] >> 2) & 0x01;
+ bit3 = (color_prom[1024] >> 3) & 0x01;
+ g = 255 - (0x10 * bit0 + 0x21 * bit1 + 0x46 * bit2 + 0x88 * bit3);
+ bit0 = (color_prom[2*1024] >> 0) & 0x01;
+ bit1 = (color_prom[2*1024] >> 1) & 0x01;
+ bit2 = (color_prom[2*1024] >> 2) & 0x01;
+ bit3 = (color_prom[2*1024] >> 3) & 0x01;
+ b = 255 - (0x10 * bit0 + 0x21 * bit1 + 0x46 * bit2 + 0x88 * bit3);
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* reserve the last color for the transparent pen (none of the game colors has */
+ /* these RGB components) */
+ palette_set_color(machine,1024,MAKE_RGB(240,240,240));
+}
+
+
+/* these depend on jumpers on the board and change from game to game */
+static int gfx0inv,gfx1inv,gfx2inv,gfx3inv;
+
+PALETTE_INIT( punchout )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + (offs)])
+
+
+ convert_palette(machine,color_prom);
+
+
+ /* top monitor chars */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i ^ gfx0inv) = i;
+
+ /* bottom monitor chars */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i ^ gfx1inv) = i + 512;
+
+ /* big sprite #1 */
+ for (i = 0;i < TOTAL_COLORS(2);i++)
+ {
+ if (i % 8 == 0) COLOR(2,i ^ gfx2inv) = 1024; /* transparent */
+ else COLOR(2,i ^ gfx2inv) = i + 512;
+ }
+
+ /* big sprite #2 */
+ for (i = 0;i < TOTAL_COLORS(3);i++)
+ {
+ if (i % 4 == 0) COLOR(3,i ^ gfx3inv) = 1024; /* transparent */
+ else COLOR(3,i ^ gfx3inv) = i + 512;
+ }
+}
+
+PALETTE_INIT( armwrest )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + (offs)])
+
+
+ convert_palette(machine,color_prom);
+
+
+ /* top monitor / bottom monitor backround chars */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = i;
+
+ /* bottom monitor foreground chars */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = i + 512;
+
+ /* big sprite #1 */
+ for (i = 0;i < TOTAL_COLORS(2);i++)
+ {
+ if (i % 8 == 7) COLOR(2,i) = 1024; /* transparent */
+ else COLOR(2,i) = i + 512;
+ }
+
+ /* big sprite #2 - pen order is inverted */
+ for (i = 0;i < TOTAL_COLORS(3);i++)
+ {
+ if (i % 4 == 3) COLOR(3,i ^ 3) = 1024; /* transparent */
+ else COLOR(3,i ^ 3) = i + 512;
+ }
+}
+
+
+
+DRIVER_INIT( punchout )
+{
+ gfx0inv = 0x03;
+ gfx1inv = 0xfc;
+ gfx2inv = 0xff;
+ gfx3inv = 0xfc;
+}
+
+DRIVER_INIT( spnchout )
+{
+ gfx0inv = 0x00;
+ gfx1inv = 0xff;
+ gfx2inv = 0xff;
+ gfx3inv = 0xff;
+}
+
+DRIVER_INIT( spnchotj )
+{
+ gfx0inv = 0xfc;
+ gfx1inv = 0xff;
+ gfx2inv = 0xff;
+ gfx3inv = 0xff;
+}
+
+DRIVER_INIT( armwrest )
+{
+}
+
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+static TILE_GET_INFO( top_get_info )
+{
+ int code = videoram[tile_index*2] + 256 * (videoram[tile_index*2 + 1] & 0x03);
+ int color = ((videoram[tile_index*2 + 1] & 0x7c) >> 2) + 64 * top_palette_bank;
+ int flipx = videoram[tile_index*2 + 1] & 0x80;
+ SET_TILE_INFO(0, code, color, flipx ? TILE_FLIPX : 0);
+}
+
+static TILE_GET_INFO( bot_get_info )
+{
+ int code = punchout_videoram2[tile_index*2] + 256 * (punchout_videoram2[tile_index*2 + 1] & 0x03);
+ int color = ((punchout_videoram2[tile_index*2 + 1] & 0x7c) >> 2) + 64 * bottom_palette_bank;
+ int flipx = punchout_videoram2[tile_index*2 + 1] & 0x80;
+ SET_TILE_INFO(1, code, color, flipx ? TILE_FLIPX : 0);
+}
+
+static TILE_GET_INFO( bs1_get_info )
+{
+ int code = punchout_bigsprite1ram[tile_index*4] + 256 * (punchout_bigsprite1ram[tile_index*4 + 1] & 0x1f);
+ int color = (punchout_bigsprite1ram[tile_index*4 + 3] & 0x1f) + 32 * bottom_palette_bank;
+ int flipx = punchout_bigsprite1ram[tile_index*4 + 3] & 0x80;
+ SET_TILE_INFO(2, code, color, flipx ? TILE_FLIPX : 0);
+}
+
+static TILE_GET_INFO( bs2_get_info )
+{
+ int code = punchout_bigsprite2ram[tile_index*4] + 256 * (punchout_bigsprite2ram[tile_index*4 + 1] & 0x0f);
+ int color = (punchout_bigsprite2ram[tile_index*4 + 3] & 0x3f) + 64 * bottom_palette_bank;
+ int flipx = punchout_bigsprite2ram[tile_index*4 + 3] & 0x80;
+ SET_TILE_INFO(3, code, color, flipx ? TILE_FLIPX : 0);
+}
+
+VIDEO_START( punchout )
+{
+ toptilemap = tilemap_create(top_get_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+ bottilemap = tilemap_create(bot_get_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ tilemap_set_scroll_rows(bottilemap, 32);
+
+ spr1tilemap = tilemap_create(bs1_get_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 16,32);
+ spr2tilemap = tilemap_create(bs2_get_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 16,32);
+
+ fgtilemap = NULL;
+}
+
+
+
+static TILE_GET_INFO( armwrest_top_get_info )
+{
+ int code = videoram[tile_index*2] + 256 * (videoram[tile_index*2 + 1] & 0x03) +
+ 8 * (videoram[tile_index*2 + 1] & 0x80);
+ int color = ((videoram[tile_index*2 + 1] & 0x7c) >> 2) + 64 * top_palette_bank;
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static TILE_GET_INFO( armwrest_bot_get_info )
+{
+ int code = punchout_videoram2[tile_index*2] + 256 * (punchout_videoram2[tile_index*2 + 1] & 0x03);
+ int color = 128 + ((punchout_videoram2[tile_index*2 + 1] & 0x7c) >> 2) + 64 * bottom_palette_bank;
+ int flipx = punchout_videoram2[tile_index*2 + 1] & 0x80;
+ SET_TILE_INFO(0, code, color, flipx ? TILE_FLIPX : 0);
+}
+
+static TILEMAP_MAPPER( armwrest_bs1_scan )
+{
+ int halfcols = num_cols/2;
+ return (col/halfcols)*(halfcols*num_rows) + row*halfcols + col%halfcols;
+}
+
+static TILE_GET_INFO( armwrest_fg_get_info )
+{
+ int code = armwrest_videoram3[tile_index*2] + 256 * (armwrest_videoram3[tile_index*2 + 1] & 0x07);
+ int color = ((armwrest_videoram3[tile_index*2 + 1] & 0xf8) >> 3) + 32 * bottom_palette_bank;
+ int flipx = armwrest_videoram3[tile_index*2 + 1] & 0x80;
+ SET_TILE_INFO(1, code, color, flipx ? TILE_FLIPX : 0);
+}
+
+VIDEO_START( armwrest )
+{
+ toptilemap = tilemap_create(armwrest_top_get_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+ bottilemap = tilemap_create(armwrest_bot_get_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+
+ spr1tilemap = tilemap_create(bs1_get_info, armwrest_bs1_scan, TILEMAP_TYPE_PEN, 8,8, 32,16);
+ spr2tilemap = tilemap_create(bs2_get_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 16,32);
+
+ fgtilemap = tilemap_create(armwrest_fg_get_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+ tilemap_set_transparent_pen(fgtilemap, 7);
+}
+
+
+
+WRITE8_HANDLER( punchout_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(toptilemap, offset/2);
+}
+
+WRITE8_HANDLER( punchout_videoram2_w )
+{
+ punchout_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(bottilemap, offset/2);
+}
+
+WRITE8_HANDLER( armwrest_videoram3_w )
+{
+ armwrest_videoram3[offset] = data;
+ tilemap_mark_tile_dirty(fgtilemap, offset/2);
+}
+
+WRITE8_HANDLER( punchout_bigsprite1ram_w )
+{
+ punchout_bigsprite1ram[offset] = data;
+ tilemap_mark_tile_dirty(spr1tilemap, offset/4);
+}
+
+WRITE8_HANDLER( punchout_bigsprite2ram_w )
+{
+ punchout_bigsprite2ram[offset] = data;
+ tilemap_mark_tile_dirty(spr2tilemap, offset/4);
+}
+
+
+
+WRITE8_HANDLER( punchout_palettebank_w )
+{
+ *punchout_palettebank = data;
+
+ if (top_palette_bank != ((data >> 1) & 0x01))
+ {
+ top_palette_bank = (data >> 1) & 0x01;
+ tilemap_mark_all_tiles_dirty(toptilemap);
+ }
+ if (bottom_palette_bank != ((data >> 0) & 0x01))
+ {
+ bottom_palette_bank = (data >> 0) & 0x01;
+ if (fgtilemap != NULL)
+ tilemap_mark_all_tiles_dirty(fgtilemap);
+ tilemap_mark_all_tiles_dirty(bottilemap);
+ tilemap_mark_all_tiles_dirty(spr1tilemap);
+ tilemap_mark_all_tiles_dirty(spr2tilemap);
+ }
+}
+
+
+
+static void draw_big_sprite(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int zoom;
+
+ zoom = punchout_bigsprite1[0] + 256 * (punchout_bigsprite1[1] & 0x0f);
+ if (zoom)
+ {
+ mame_bitmap *sprbitmap = tilemap_get_pixmap(spr1tilemap);
+ int sx,sy;
+ UINT32 startx,starty;
+ int incxx,incyy;
+
+ sx = 4096 - (punchout_bigsprite1[2] + 256 * (punchout_bigsprite1[3] & 0x0f));
+ if (sx > 4096-4*127) sx -= 4096;
+
+ sy = -(punchout_bigsprite1[4] + 256 * (punchout_bigsprite1[5] & 1));
+ if (sy <= -256 + zoom/0x40) sy += 512;
+ sy += 12;
+
+ incxx = zoom << 6;
+ incyy = zoom << 6;
+
+ startx = -sx * 0x4000;
+ starty = -sy * 0x10000;
+ startx += 3740 * zoom; /* adjustment to match the screen shots */
+ starty -= 178 * zoom; /* and make the hall of fame picture nice */
+
+ if (punchout_bigsprite1[6] & 1) /* flip x */
+ {
+ startx = (sprbitmap->width << 16) - startx - 1;
+ incxx = -incxx;
+ }
+
+ copyrozbitmap(bitmap,sprbitmap,
+ startx,starty + 0x200*(2) * zoom,
+ incxx,0,0,incyy, /* zoom, no rotation */
+ 0, /* no wraparound */
+ cliprect,TRANSPARENCY_COLOR,1024,0);
+ }
+}
+
+static void drawbs2(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ mame_bitmap *sprbitmap = tilemap_get_pixmap(spr2tilemap);
+ int sx,sy;
+
+ sx = 512 - (punchout_bigsprite2[0] + 256 * (punchout_bigsprite2[1] & 1));
+ if (sx > 512-127) sx -= 512;
+ sx -= 55; /* adjustment to match the screen shots */
+
+ sy = -punchout_bigsprite2[2] + 256 * (punchout_bigsprite2[3] & 1);
+ sy += 3; /* adjustment to match the screen shots */
+
+ copybitmap(bitmap,sprbitmap,
+ punchout_bigsprite2[4] & 1,0,
+ sx,sy,
+ cliprect,TRANSPARENCY_COLOR,1024);
+}
+
+VIDEO_UPDATE( punchout )
+{
+ if (screen == 1)
+ {
+ tilemap_draw(bitmap, cliprect, toptilemap, 0, 0);
+
+ if (punchout_bigsprite1[7] & 1) /* display in top monitor */
+ draw_big_sprite(bitmap, cliprect);
+ }
+ else
+ {
+ int offs;
+
+ /* copy the character mapped graphics */
+ for (offs = 0;offs < 32;offs++)
+ tilemap_set_scrollx(bottilemap, offs, 58 + punchout_scroll[2*offs] + 256 * (punchout_scroll[2*offs + 1] & 0x01));
+
+ tilemap_draw(bitmap, cliprect, bottilemap, 0, 0);
+
+ if (punchout_bigsprite1[7] & 2) /* display in bottom monitor */
+ draw_big_sprite(bitmap, cliprect);
+ drawbs2(bitmap, cliprect);
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( armwrest )
+{
+ if (screen == 1)
+ {
+ tilemap_draw(bitmap, cliprect, toptilemap, 0, 0);
+
+ if (punchout_bigsprite1[7] & 1) /* display in top monitor */
+ draw_big_sprite(bitmap, cliprect);
+ }
+ else
+ {
+ tilemap_draw(bitmap, cliprect, bottilemap, 0, 0);
+
+ if (punchout_bigsprite1[7] & 2) /* display in bottom monitor */
+ draw_big_sprite(bitmap, cliprect);
+ drawbs2(bitmap, cliprect);
+
+ tilemap_draw(bitmap, cliprect, fgtilemap, 0, 0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/pushman.c b/src/mame/video/pushman.c
new file mode 100644
index 00000000000..0037e396136
--- /dev/null
+++ b/src/mame/video/pushman.c
@@ -0,0 +1,119 @@
+#include "driver.h"
+
+static tilemap *bg_tilemap,*tx_tilemap;
+static UINT16 control[2];
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( background_scan_rows )
+{
+ /* logical (col,row) -> memory offset */
+ return ((col & 0x7)) + ((7-(row & 0x7)) << 3) + ((col & 0x78) <<3) + ((0x38-(row&0x38))<<7);
+}
+
+static TILE_GET_INFO( get_back_tile_info )
+{
+ UINT8 *bgMap = memory_region(REGION_GFX4);
+ int tile;
+
+ tile=bgMap[tile_index<<1]+(bgMap[(tile_index<<1)+1]<<8);
+ SET_TILE_INFO(
+ 2,
+ (tile&0xff)|((tile&0x4000)>>6),
+ (tile>>8)&0xf,
+ (tile&0x2000)?TILE_FLIPX:0);
+}
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ int tile = videoram16[tile_index];
+ SET_TILE_INFO(
+ 0,
+ (tile&0xff)|((tile&0xc000)>>6)|((tile&0x2000)>>3),
+ (tile>>8)&0xf,
+ (tile&0x1000)?TILE_FLIPY:0); /* not used? from Tiger Road */
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( pushman )
+{
+ bg_tilemap = tilemap_create(get_back_tile_info,background_scan_rows,TILEMAP_TYPE_PEN, 32,32,128,64);
+ tx_tilemap = tilemap_create(get_text_tile_info,tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32,32);
+
+ tilemap_set_transparent_pen(tx_tilemap,3);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( pushman_scroll_w )
+{
+ COMBINE_DATA(&control[offset]);
+}
+
+WRITE16_HANDLER( pushman_videoram_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs,x,y,color,sprite,flipx,flipy;
+
+ for (offs = 0x0800-4;offs >=0;offs -= 4)
+ {
+ /* Don't draw empty sprite table entries */
+ x = spriteram16[offs+3]&0x1ff;
+ if (x==0x180) continue;
+ if (x>0xff) x=0-(0x200-x);
+ y = 240-spriteram16[offs+2];
+ color = ((spriteram16[offs+1]>>2)&0xf);
+ sprite = spriteram16[offs]&0x7ff;
+ /* ElSemi - Sprite flip info */
+ flipx=spriteram16[offs+1]&2;
+ flipy=spriteram16[offs+1]&1; /* flip y untested */
+
+ drawgfx(bitmap,machine->gfx[1],
+ sprite,
+ color,flipx,flipy,x,y,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+VIDEO_UPDATE( pushman )
+{
+ /* Setup the tilemaps */
+ tilemap_set_scrollx( bg_tilemap,0, control[0] );
+ tilemap_set_scrolly( bg_tilemap,0, 0xf00-control[1] );
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/qdrmfgp.c b/src/mame/video/qdrmfgp.c
new file mode 100644
index 00000000000..50a6be09f39
--- /dev/null
+++ b/src/mame/video/qdrmfgp.c
@@ -0,0 +1,69 @@
+/***************************************************************************
+
+ video.c
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+int qdrmfgp_get_palette(void);
+
+
+
+static void tile_callback(int layer, int *code, int *color, int *flags)
+{
+ *color = ((*color>>2) & 0x0f) | qdrmfgp_get_palette();
+}
+
+static void gp2_tile_callback(int layer, int *code, int *color, int *flags)
+{
+ *color = (*color>>1) & 0x7f;
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( qdrmfgp )
+{
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_4dj, 1, NULL, tile_callback, 0);
+
+ K056832_set_LayerAssociation(0);
+
+ K056832_set_LayerOffset(0, 2, 0);
+ K056832_set_LayerOffset(1, 4, 0);
+ K056832_set_LayerOffset(2, 6, 0);
+ K056832_set_LayerOffset(3, 8, 0);
+}
+
+VIDEO_START( qdrmfgp2 )
+{
+ K056832_vh_start(machine, REGION_GFX1, K056832_BPP_4dj, 1, NULL, gp2_tile_callback, 0);
+
+ K056832_set_LayerAssociation(0);
+
+ K056832_set_LayerOffset(0, 3, 1);
+ K056832_set_LayerOffset(1, 5, 1);
+ K056832_set_LayerOffset(2, 7, 1);
+ K056832_set_LayerOffset(3, 9, 1);
+}
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( qdrmfgp )
+{
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ K056832_tilemap_draw(machine, bitmap,cliprect, 3, 0, 1);
+ K056832_tilemap_draw(machine, bitmap,cliprect, 2, 0, 2);
+ K056832_tilemap_draw(machine, bitmap,cliprect, 1, 0, 4);
+ K056832_tilemap_draw(machine, bitmap,cliprect, 0, 0, 8);
+ return 0;
+}
diff --git a/src/mame/video/qix.c b/src/mame/video/qix.c
new file mode 100644
index 00000000000..809310e61dc
--- /dev/null
+++ b/src/mame/video/qix.c
@@ -0,0 +1,334 @@
+/***************************************************************************
+
+ Taito Qix hardware
+
+ driver by John Butler, Ed Mueller, Aaron Giles
+
+***************************************************************************/
+
+#include "driver.h"
+#include "qix.h"
+#include "video/crtc6845.h"
+
+
+/* Constants */
+#define SCANLINE_INCREMENT 1
+
+
+/* Globals */
+UINT8 *qix_videoaddress;
+UINT8 qix_cocktail_flip;
+
+
+/* Local variables */
+static UINT8 vram_mask;
+static UINT8 qix_palettebank;
+static UINT8 leds;
+static emu_timer *scanline_timer;
+static UINT8 scanline_latch;
+
+
+
+/*************************************
+ *
+ * Static function prototypes
+ *
+ *************************************/
+
+static void qix_display_enable_changed(int display_enabled);
+
+static TIMER_CALLBACK( scanline_callback );
+
+static void *qix_begin_update(running_machine *machine,
+ int screen,
+ mame_bitmap *bitmap,
+ const rectangle *cliprect);
+
+static void qix_update_row(mame_bitmap *bitmap,
+ const rectangle *cliprect,
+ UINT16 ma,
+ UINT8 ra,
+ UINT16 y,
+ UINT8 x_count,
+ void *param);
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+static const crtc6845_interface crtc6845_intf =
+{
+ 0, /* screen we are acting on */
+ QIX_CHARACTER_CLOCK, /* the clock (pin 21) of the chip */
+ 8, /* number of pixels per video memory address */
+ qix_begin_update, /* before pixel update callback */
+ qix_update_row, /* row update callback */
+ 0, /* after pixel update callback */
+ qix_display_enable_changed /* call back for display state changes */
+};
+
+
+VIDEO_START( qix )
+{
+ /* configure the CRT controller */
+ crtc6845_config(0, &crtc6845_intf);
+
+ /* allocate memory for the full video RAM */
+ videoram = auto_malloc(256 * 256);
+
+ /* initialize the mask for games that don't use it */
+ vram_mask = 0xff;
+
+ /* allocate a timer */
+ scanline_timer = timer_alloc(scanline_callback);
+ timer_adjust(scanline_timer, video_screen_get_time_until_pos(0, 1, 0), 1, attotime_zero);
+
+ /* set up save states */
+ state_save_register_global_pointer(videoram, 256 * 256);
+ state_save_register_global(qix_cocktail_flip);
+ state_save_register_global(vram_mask);
+ state_save_register_global(qix_palettebank);
+ state_save_register_global(leds);
+}
+
+
+
+/*************************************
+ *
+ * Scanline caching
+ *
+ *************************************/
+
+static TIMER_CALLBACK( scanline_callback )
+{
+ int scanline = param;
+
+ /* force a partial update */
+ video_screen_update_partial(0, scanline - 1);
+
+ /* set a timer for the next increment */
+ scanline += SCANLINE_INCREMENT;
+ if (scanline > machine->screen[0].visarea.max_y)
+ scanline = SCANLINE_INCREMENT;
+ timer_adjust(scanline_timer, video_screen_get_time_until_pos(0, scanline, 0), scanline, attotime_zero);
+}
+
+
+
+/*************************************
+ *
+ * Current scanline read
+ *
+ *************************************/
+
+static void qix_display_enable_changed(int display_enabled)
+{
+ /* on the rising edge, latch the scanline */
+ if (display_enabled)
+ {
+ UINT16 ma = crtc6845_get_ma(0);
+ UINT8 ra = crtc6845_get_ra(0);
+
+ /* RA0-RA2 goes to D0-D2 and MA5-MA9 goes to D3-D7 */
+ scanline_latch = ((ma >> 2) & 0xf8) | (ra & 0x07);
+ }
+}
+
+
+READ8_HANDLER( qix_scanline_r )
+{
+ return scanline_latch;
+}
+
+
+
+/*************************************
+ *
+ * Video RAM mask
+ *
+ *************************************/
+
+WRITE8_HANDLER( slither_vram_mask_w )
+{
+ /* Slither appears to extend the basic hardware by providing */
+ /* a mask register which controls which data bits get written */
+ /* to video RAM */
+ vram_mask = data;
+}
+
+
+
+/*************************************
+ *
+ * Direct video RAM read/write
+ *
+ * The screen is 256x256 with eight
+ * bit pixels (64K). The screen is
+ * divided into two halves each half
+ * mapped by the video CPU at
+ * $0000-$7FFF. The high order bit
+ * of the address latch at $9402
+ * specifies which half of the screen
+ * is being accessed.
+ *
+ *************************************/
+
+READ8_HANDLER( qix_videoram_r )
+{
+ /* add in the upper bit of the address latch */
+ offset += (qix_videoaddress[0] & 0x80) << 8;
+ return videoram[offset];
+}
+
+
+WRITE8_HANDLER( qix_videoram_w )
+{
+ /* add in the upper bit of the address latch */
+ offset += (qix_videoaddress[0] & 0x80) << 8;
+
+ /* blend the data */
+ videoram[offset] = (videoram[offset] & ~vram_mask) | (data & vram_mask);
+}
+
+
+
+/*************************************
+ *
+ * Latched video RAM read/write
+ *
+ * The address latch works as follows.
+ * When the video CPU accesses $9400,
+ * the screen address is computed by
+ * using the values at $9402 (high
+ * byte) and $9403 (low byte) to get
+ * a value between $0000-$FFFF. The
+ * value at that location is either
+ * returned or written.
+ *
+ *************************************/
+
+READ8_HANDLER( qix_addresslatch_r )
+{
+ /* compute the value at the address latch */
+ offset = (qix_videoaddress[0] << 8) | qix_videoaddress[1];
+ return videoram[offset];
+}
+
+
+
+WRITE8_HANDLER( qix_addresslatch_w )
+{
+ /* compute the value at the address latch */
+ offset = (qix_videoaddress[0] << 8) | qix_videoaddress[1];
+
+ /* blend the data */
+ videoram[offset] = (videoram[offset] & ~vram_mask) | (data & vram_mask);
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM
+ *
+ *************************************/
+
+WRITE8_HANDLER( qix_paletteram_w )
+{
+ /* this conversion table should be about right. It gives a reasonable */
+ /* gray scale in the test screen, and the red, green and blue squares */
+ /* in the same screen are barely visible, as the manual requires. */
+ static UINT8 table[16] =
+ {
+ 0x00, /* value = 0, intensity = 0 */
+ 0x12, /* value = 0, intensity = 1 */
+ 0x24, /* value = 0, intensity = 2 */
+ 0x49, /* value = 0, intensity = 3 */
+ 0x12, /* value = 1, intensity = 0 */
+ 0x24, /* value = 1, intensity = 1 */
+ 0x49, /* value = 1, intensity = 2 */
+ 0x92, /* value = 1, intensity = 3 */
+ 0x5b, /* value = 2, intensity = 0 */
+ 0x6d, /* value = 2, intensity = 1 */
+ 0x92, /* value = 2, intensity = 2 */
+ 0xdb, /* value = 2, intensity = 3 */
+ 0x7f, /* value = 3, intensity = 0 */
+ 0x91, /* value = 3, intensity = 1 */
+ 0xb6, /* value = 3, intensity = 2 */
+ 0xff /* value = 3, intensity = 3 */
+ };
+ int bits, intensity, red, green, blue;
+
+ /* set the palette RAM value */
+ paletteram[offset] = data;
+
+ /* compute R, G, B from the table */
+ intensity = (data >> 0) & 0x03;
+ bits = (data >> 6) & 0x03;
+ red = table[(bits << 2) | intensity];
+ bits = (data >> 4) & 0x03;
+ green = table[(bits << 2) | intensity];
+ bits = (data >> 2) & 0x03;
+ blue = table[(bits << 2) | intensity];
+
+ /* update the palette */
+ palette_set_color(Machine, offset, MAKE_RGB(red, green, blue));
+}
+
+
+WRITE8_HANDLER( qix_palettebank_w )
+{
+ /* set the bank value */
+ if (qix_palettebank != (data & 3))
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+ qix_palettebank = data & 3;
+ }
+
+ /* LEDs are in the upper 6 bits */
+ leds = ~data & 0xfc;
+}
+
+
+
+/*************************************
+ *
+ * CRTC callbacks for updating
+ * the screen
+ *
+ *************************************/
+
+static void *qix_begin_update(running_machine *machine, int screen,
+ mame_bitmap *bitmap, const rectangle *cliprect)
+{
+#if 0
+ // note the confusing bit order!
+ popmessage("self test leds: %d%d %d%d%d%d",BIT(leds,7),BIT(leds,5),BIT(leds,6),BIT(leds,4),BIT(leds,2),BIT(leds,3));
+#endif
+
+ /* return the pens we are going to use to update the display */
+ return (void *)&machine->pens[qix_palettebank * 256];
+}
+
+
+static void qix_update_row(mame_bitmap *bitmap, const rectangle *cliprect,
+ UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, void *param)
+{
+ UINT16 x;
+ UINT8 scanline[256];
+
+ pen_t *pens = (pen_t *)param;
+
+ /* the memory is hooked up to the MA, RA lines this way */
+ offs_t offs = ((ma << 6) & 0xf800) | ((ra << 8) & 0x0700);
+ offs_t offs_xor = qix_cocktail_flip ? 0xffff : 0;
+
+ for (x = 0; x < x_count * 8; x++)
+ scanline[x] = videoram[(offs + x) ^ offs_xor];
+
+ draw_scanline8(bitmap, 0, y, x_count * 8, scanline, pens, -1);
+}
diff --git a/src/mame/video/quasar.c b/src/mame/video/quasar.c
new file mode 100644
index 00000000000..555340c9fc7
--- /dev/null
+++ b/src/mame/video/quasar.c
@@ -0,0 +1,283 @@
+/***************************************************************************
+
+ video\quasar.c
+
+ Functions to emulate the video hardware of the machine.
+
+ Zaccaria S2650 games share various levels of design with the Century Video
+ System (CVS) games, and hence some routines are shared from there.
+
+ Shooting seems to mix custom boards from Zaccaria and sound boards from CVS
+ hinting at a strong link between the two companies.
+
+ Zaccaria are an italian company, Century were based in Manchester UK
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/s2636.h"
+#include "cpu/s2650/s2650.h"
+
+#ifdef LSB_FIRST
+#define BL0 0
+#define BL1 1
+#define BL2 2
+#define BL3 3
+#define WL0 0
+#define WL1 1
+#else
+#define BL0 3
+#define BL1 2
+#define BL2 1
+#define BL3 0
+#define WL0 1
+#define WL1 0
+#endif
+
+// All defined in video/cvs.c
+
+VIDEO_START( cvs );
+
+extern UINT8 *cvs_bullet_ram;
+
+extern mame_bitmap *cvs_collision_bitmap;
+extern mame_bitmap *cvs_collision_background;
+
+
+extern int cvs_collision_register;
+
+
+// Used here
+//static int scroll[8];
+//static int scroll_reg = 0;
+
+UINT8 *quasar_effectram;
+int quasar_effectcontrol;
+
+static mame_bitmap *effect_bitmap;
+
+PALETTE_INIT( quasar )
+{
+ int i,col,map;
+
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ // Standard 1 bit per colour palette (background and sprites)
+
+ for(col = 0;col < 8; col++)
+ {
+ palette_set_color_rgb(machine,col,pal1bit(col >> 0),pal1bit(col >> 1),pal1bit(col >> 2));
+ }
+
+ // Address 0-2 from graphic rom
+ // 3-5 from colour ram
+ // 6-8 from sprite chips (Used for priority)
+
+ for(col = 0; col < 512; col++)
+ {
+ COLOR(0,col) = color_prom[col] & 7;
+ }
+
+ /* Background for collision */
+
+ COLOR(0,512) = 0; // Black
+ for(col=1;col<8;col++) // White
+ COLOR(0,512+col) = 7;
+
+ /* Effects Colour Map */
+
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = BIT(i,0);
+ bit1 = BIT(i,1);
+ bit2 = BIT(i,2);
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = BIT(i,3);
+ bit1 = BIT(i,4);
+ bit2 = BIT(i,5);
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = BIT(i,6);
+ bit1 = BIT(i,7);
+ b = 0x4f * bit0 + 0xa8 * bit1;
+
+ // Intensity 1
+ palette_set_color_rgb(machine,256+i,r>>2,g>>2,b>>2);
+
+ // Intensity 2
+ palette_set_color_rgb(machine,512+i,(r>>2)+(r>>3),(g>>2)+(g>>3),(b>>2)+(b>>2));
+
+ // Intensity 3
+ palette_set_color_rgb(machine,768+i,r>>1,g>>1,b>>1);
+ }
+
+ /* Sprites */
+
+ for(map=0;map<8;map++)
+ {
+ COLOR(0,map*2 + 2072) = 0;
+ COLOR(0,map*2 + 2073) = 8 + map;
+ }
+
+ /* Set Sprite chip offsets */
+
+ s2636_x_offset = -26;
+ s2636_y_offset = 3;
+
+ memset(s2636_1_dirty,0,sizeof(s2636_1_dirty));
+ memset(s2636_2_dirty,0,sizeof(s2636_2_dirty));
+ memset(s2636_3_dirty,0,sizeof(s2636_3_dirty));
+}
+
+VIDEO_START( quasar )
+{
+ quasar_effectram = auto_malloc(0x400);
+
+ effect_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ video_start_cvs(machine);
+}
+
+VIDEO_UPDATE( quasar )
+{
+ int offs,character;
+ int sx,sy, ox, oy;
+ int forecolor;
+
+ /* for every character in the Video RAM, check if it has been modified */
+ /* since last time and update it accordingly. */
+
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ character = videoram[offs];
+
+ sx = (offs % 32) * 8;
+ sy = (offs / 32) * 8;
+
+ // While we have the current character code, draw the effects layer
+ // intensity / on and off controlled by latch
+
+ if (quasar_effectcontrol == 0x30)
+ forecolor = 0;
+ else
+ forecolor = quasar_effectram[offs] + (256 * (((quasar_effectcontrol >> 4) ^ 3) & 3));
+
+ for(ox=0;ox<8;ox++)
+ for(oy=0;oy<8;oy++)
+ *BITMAP_ADDR16(effect_bitmap, sy+oy, sx+ox) = forecolor;
+
+ /* Main Screen */
+
+ drawgfx(tmpbitmap,machine->gfx[0],
+ character,
+ colorram[offs],
+ 0,0,
+ sx,sy,
+ 0,TRANSPARENCY_NONE,0);
+
+
+ /* background for Collision Detection (it can only hit certain items) */
+
+ if((colorram[offs] & 7) == 0)
+ {
+ drawgfx(cvs_collision_background,machine->gfx[0],
+ character,
+ 64,
+ 0,0,
+ sx,sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ /* Update screen */
+
+ copybitmap(bitmap,effect_bitmap,0,0,0,0,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ copybitmap(bitmap,tmpbitmap,0,0,0,0,&machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+
+ /* 2636's */
+
+ fillbitmap(s2636_1_bitmap,0,0);
+ s2636_update_bitmap(machine,s2636_1_bitmap,s2636_1_ram,s2636_1_dirty,2,cvs_collision_bitmap);
+
+ fillbitmap(s2636_2_bitmap,0,0);
+ s2636_update_bitmap(machine,s2636_2_bitmap,s2636_2_ram,s2636_2_dirty,3,cvs_collision_bitmap);
+
+ fillbitmap(s2636_3_bitmap,0,0);
+ s2636_update_bitmap(machine,s2636_3_bitmap,s2636_3_ram,s2636_3_dirty,4,cvs_collision_bitmap);
+
+ /* Bullet Hardware */
+
+ for (offs = 8; offs < 256; offs++ )
+ {
+ if(cvs_bullet_ram[offs] != 0)
+ {
+ int ct;
+ for(ct=0;ct<1;ct++)
+ {
+ int bx=255-9-cvs_bullet_ram[offs]-ct;
+
+ /* Bullet/Object Collision */
+
+ if (*BITMAP_ADDR8(s2636_1_bitmap, offs, bx) != 0) cvs_collision_register |= 4;
+ if (*BITMAP_ADDR8(s2636_3_bitmap, offs, bx) != 0) cvs_collision_register |= 8;
+
+ *BITMAP_ADDR16(bitmap, offs, bx) = machine->pens[7];
+ }
+ }
+ }
+
+ /* Update 2636 images */
+
+ {
+ UINT32 S1,S2,S3,SB,pen;
+
+ for(sx=255;sx>7;sx--)
+ {
+ UINT32 *sp1 = (UINT32 *)BITMAP_ADDR8(s2636_1_bitmap, sx, 0);
+ UINT32 *sp2 = (UINT32 *)BITMAP_ADDR8(s2636_2_bitmap, sx, 0);
+ UINT32 *sp3 = (UINT32 *)BITMAP_ADDR8(s2636_3_bitmap, sx, 0);
+ UINT64 *dst = (UINT64 *)BITMAP_ADDR16(bitmap, sx, 0);
+ UINT8 *spb = (UINT8 *)BITMAP_ADDR8(cvs_collision_background, sx, 0);
+
+ for(offs=0;offs<62;offs++)
+ {
+ S1 = (*sp1++);
+ S2 = (*sp2++);
+ S3 = (*sp3++);
+
+ pen = S1 | S2 | S3;
+
+ if(pen)
+ {
+ UINT16 *address = (UINT16 *)dst;
+ if (pen & 0xff000000) address[BL3] = machine->pens[(pen >> 24) & 15];
+ if (pen & 0x00ff0000) address[BL2] = machine->pens[(pen >> 16) & 15];
+ if (pen & 0x0000ff00) address[BL1] = machine->pens[(pen >> 8) & 15];
+ if (pen & 0x000000ff) address[BL0] = machine->pens[(pen & 15)];
+
+ /* Collision Detection */
+
+ SB = 0;
+ if (spb[BL3] != machine->pens[0]) SB = 0x08000000;
+ if (spb[BL2] != machine->pens[0]) SB |= 0x00080000;
+ if (spb[BL1] != machine->pens[0]) SB |= 0x00000800;
+ if (spb[BL0] != machine->pens[0]) SB |= 0x00000008;
+
+ if (SB)
+ {
+ if (S1 & SB) cvs_collision_register |= 1;
+ if (S3 & SB) cvs_collision_register |= 2;
+ }
+ }
+
+ dst++;
+ spb+=4;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/quizdna.c b/src/mame/video/quizdna.c
new file mode 100644
index 00000000000..adba3c0d13e
--- /dev/null
+++ b/src/mame/video/quizdna.c
@@ -0,0 +1,202 @@
+/******************************************************************************
+
+Quiz DNA no Hanran (c) 1992 Face
+Quiz Gakuen Paradise (c) 1991 NMK
+Quiz Gekiretsu Scramble (Gakuen Paradise 2) (c) 1993 Face
+
+Video hardware
+ driver by Uki
+
+******************************************************************************/
+
+#include "driver.h"
+
+static UINT8 *quizdna_bg_ram;
+static UINT8 *quizdna_fg_ram;
+
+static tilemap *quizdna_bg_tilemap;
+static tilemap *quizdna_fg_tilemap;
+
+static UINT8 quizdna_bg_xscroll[2];
+
+static int quizdna_flipscreen = -1;
+static int quizdna_video_enable;
+
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = quizdna_bg_ram[tile_index*2] + quizdna_bg_ram[tile_index*2+1]*0x100 ;
+ int col = quizdna_bg_ram[tile_index*2+0x1000] & 0x7f;
+
+ if (code>0x7fff)
+ code &= 0x83ff;
+
+ SET_TILE_INFO(1, code, col, 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code,col,x,y;
+ UINT8 *FG = memory_region(REGION_USER1);
+
+ x = tile_index & 0x1f;
+ y = FG[(tile_index >> 5) & 0x1f] & 0x3f;
+ code = y & 1;
+
+ y >>= 1;
+
+ col = quizdna_fg_ram[x*2 + y*0x40 + 1];
+ code += (quizdna_fg_ram[x*2 + y*0x40] + (col & 0x1f) * 0x100) * 2;
+ col >>= 5;
+ col = (col & 3) | ((col & 4) << 1);
+
+ SET_TILE_INFO(0, code, col, 0);
+}
+
+
+VIDEO_START( quizdna )
+{
+ quizdna_bg_ram = auto_malloc(0x2000);
+ quizdna_fg_ram = auto_malloc(0x1000);
+
+ quizdna_bg_tilemap = tilemap_create( get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32 );
+ quizdna_fg_tilemap = tilemap_create( get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,8,32,32 );
+
+ tilemap_set_transparent_pen( quizdna_fg_tilemap,0 );
+}
+
+WRITE8_HANDLER( quizdna_bg_ram_w )
+{
+ UINT8 *RAM = memory_region(REGION_CPU1);
+ quizdna_bg_ram[offset] = data;
+ RAM[0x12000+offset] = data;
+
+ tilemap_mark_tile_dirty(quizdna_bg_tilemap, (offset & 0xfff) / 2 );
+}
+
+WRITE8_HANDLER( quizdna_fg_ram_w )
+{
+ int i;
+ int offs = offset & 0xfff;
+ UINT8 *RAM = memory_region(REGION_CPU1);
+
+ RAM[0x10000+offs] = data;
+ RAM[0x11000+offs] = data; /* mirror */
+ quizdna_fg_ram[offs] = data;
+
+ for (i=0; i<32; i++)
+ tilemap_mark_tile_dirty(quizdna_fg_tilemap, ((offs/2) & 0x1f) + i*0x20 );
+}
+
+WRITE8_HANDLER( quizdna_bg_yscroll_w )
+{
+ tilemap_set_scrolldy( quizdna_bg_tilemap, 255-data, 255-data+1 );
+}
+
+WRITE8_HANDLER( quizdna_bg_xscroll_w )
+{
+ int x;
+ quizdna_bg_xscroll[offset] = data;
+ x = ~(quizdna_bg_xscroll[0] + quizdna_bg_xscroll[1]*0x100) & 0x1ff;
+
+ tilemap_set_scrolldx( quizdna_bg_tilemap, x+64, x-64+10 );
+}
+
+WRITE8_HANDLER( quizdna_screen_ctrl_w )
+{
+ int tmp = (data & 0x10) >> 4;
+ quizdna_video_enable = data & 0x20;
+
+ coin_counter_w(0, data & 1);
+
+ if (quizdna_flipscreen == tmp)
+ return;
+
+ quizdna_flipscreen = tmp;
+
+ flip_screen_set(tmp);
+ tilemap_set_scrolldx( quizdna_fg_tilemap, 64, -64 +16);
+}
+
+WRITE8_HANDLER( paletteram_xBGR_RRRR_GGGG_BBBB_w )
+{
+ int r,g,b,d0,d1;
+ int offs = offset & ~1;
+
+ paletteram[offset] = data;
+
+ d0 = paletteram[offs];
+ d1 = paletteram[offs+1];
+
+ r = ((d1 << 1) & 0x1e) | ((d1 >> 4) & 1);
+ g = ((d0 >> 3) & 0x1e) | ((d1 >> 5) & 1);
+ b = ((d0 << 1) & 0x1e) | ((d1 >> 6) & 1);
+
+ palette_set_color_rgb(Machine,offs/2,pal5bit(r),pal5bit(g),pal5bit(b));
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0; offs<spriteram_size; offs+=8)
+ {
+ int i;
+
+ int x = spriteram[offs + 3]*0x100 + spriteram[offs + 2] + 64 - 8;
+ int y = (spriteram[offs + 1] & 1)*0x100 + spriteram[offs + 0];
+ int code = (spriteram[offs + 5] * 0x100 + spriteram[offs + 4]) & 0x3fff;
+ int col = spriteram[offs + 6];
+ int fx = col & 0x80;
+ int fy = col & 0x40;
+ int ysize = (spriteram[offs + 1] & 0xc0) >> 6;
+ int dy = 0x10;
+ col &= 0x1f;
+
+ if (quizdna_flipscreen)
+ {
+ x -= 7;
+ y += 1;
+ }
+
+ x &= 0x1ff;
+ if (x>0x1f0)
+ x -= 0x200;
+
+ if (fy)
+ {
+ dy = -0x10;
+ y += 0x10 * ysize;
+ }
+
+ if (code >= 0x2100)
+ code &= 0x20ff;
+
+ for (i=0; i<ysize+1; i++)
+ {
+ y &= 0x1ff;
+
+ drawgfx(bitmap,machine->gfx[2],
+ code ^ i,
+ col,
+ fx,fy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ y += dy;
+ }
+ }
+}
+
+VIDEO_UPDATE( quizdna )
+{
+ if (quizdna_video_enable)
+ {
+ tilemap_draw(bitmap, cliprect, quizdna_bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, quizdna_fg_tilemap, 0, 0);
+ }
+ else
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+}
diff --git a/src/mame/video/quizpani.c b/src/mame/video/quizpani.c
new file mode 100644
index 00000000000..c139beb367e
--- /dev/null
+++ b/src/mame/video/quizpani.c
@@ -0,0 +1,91 @@
+/************************************************************************
+
+ Quiz Panicuru Fantasy video hardware
+
+************************************************************************/
+
+#include "driver.h"
+
+UINT16 *quizpani_bg_videoram, *quizpani_txt_videoram;
+UINT16 *quizpani_scrollreg;
+
+static tilemap *bg_tilemap, *txt_tilemap;
+
+static int quizpani_bgbank = 0, quizpani_txtbank = 0;
+
+static TILEMAP_MAPPER( bg_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (row & 0x0f) + ((col & 0xff) << 4) + ((row & 0x70) << 8);
+}
+
+static TILE_GET_INFO( bg_tile_info )
+{
+ int code = quizpani_bg_videoram[tile_index];
+
+ SET_TILE_INFO(
+ 1,
+ (code & 0xfff) + (0x1000 * quizpani_bgbank),
+ code >> 12,
+ 0);
+}
+
+static TILE_GET_INFO( txt_tile_info )
+{
+ int code = quizpani_txt_videoram[tile_index];
+
+ SET_TILE_INFO(
+ 0,
+ (code & 0xfff) + (0x1000 * quizpani_txtbank),
+ code >> 12,
+ 0);
+}
+
+WRITE16_HANDLER( quizpani_bg_videoram_w )
+{
+ quizpani_bg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE16_HANDLER( quizpani_txt_videoram_w )
+{
+ quizpani_txt_videoram[offset] = data;
+ tilemap_mark_tile_dirty(txt_tilemap, offset);
+}
+
+WRITE16_HANDLER( quizpani_tilesbank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ if(quizpani_txtbank != (data & 0x30)>>4)
+ {
+ quizpani_txtbank = (data & 0x30)>>4;
+ tilemap_mark_all_tiles_dirty(txt_tilemap);
+ }
+
+ if(quizpani_bgbank != (data & 3))
+ {
+ quizpani_bgbank = data & 3;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+ }
+}
+
+VIDEO_START( quizpani )
+{
+ bg_tilemap = tilemap_create(bg_tile_info, bg_scan,TILEMAP_TYPE_PEN,16,16,256,32);
+ txt_tilemap = tilemap_create(txt_tile_info,bg_scan,TILEMAP_TYPE_PEN,16,16,256,32);
+ tilemap_set_transparent_pen(txt_tilemap,15);
+}
+
+VIDEO_UPDATE( quizpani )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, quizpani_scrollreg[0] - 64);
+ tilemap_set_scrolly(bg_tilemap, 0, quizpani_scrollreg[1] + 16);
+ tilemap_set_scrollx(txt_tilemap, 0, quizpani_scrollreg[2] - 64);
+ tilemap_set_scrolly(txt_tilemap, 0, quizpani_scrollreg[3] + 16);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,txt_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/raiden.c b/src/mame/video/raiden.c
new file mode 100644
index 00000000000..c404229e98a
--- /dev/null
+++ b/src/mame/video/raiden.c
@@ -0,0 +1,164 @@
+
+#include "driver.h"
+
+static tilemap *bg_layer,*fg_layer,*tx_layer;
+UINT16 *raiden_back_data,*raiden_fore_data,*raiden_scroll_ram;
+
+static int flipscreen,alternate;
+
+/******************************************************************************/
+
+WRITE16_HANDLER( raiden_background_w )
+{
+ COMBINE_DATA(&raiden_back_data[offset]);
+ tilemap_mark_tile_dirty(bg_layer, offset);
+}
+
+WRITE16_HANDLER( raiden_foreground_w )
+{
+ COMBINE_DATA(&raiden_fore_data[offset]);
+ tilemap_mark_tile_dirty(fg_layer, offset);
+}
+
+WRITE16_HANDLER( raiden_text_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty(tx_layer, offset);
+}
+
+static TILE_GET_INFO( get_back_tile_info )
+{
+ int tile=raiden_back_data[tile_index];
+ int color=tile >> 12;
+
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 1,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_fore_tile_info )
+{
+ int tile=raiden_fore_data[tile_index];
+ int color=tile >> 12;
+
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 2,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ int tiledata = videoram16[tile_index];
+ int tile = (tiledata & 0xff) | ((tiledata >> 6) & 0x300);
+ int color = (tiledata >> 8) & 0x0f;
+
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+VIDEO_START( raiden )
+{
+ bg_layer = tilemap_create(get_back_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 16,16,32,32);
+ fg_layer = tilemap_create(get_fore_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,32,32);
+ tx_layer = tilemap_create(get_text_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32,32);
+ alternate=0;
+
+ tilemap_set_transparent_pen(fg_layer,15);
+ tilemap_set_transparent_pen(tx_layer,15);
+}
+
+VIDEO_START( raidena )
+{
+ bg_layer = tilemap_create(get_back_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 16,16,32,32);
+ fg_layer = tilemap_create(get_fore_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,32,32);
+ tx_layer = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ alternate=1;
+
+ tilemap_set_transparent_pen(fg_layer,15);
+ tilemap_set_transparent_pen(tx_layer,15);
+}
+
+WRITE16_HANDLER( raiden_control_w )
+{
+ /* All other bits unknown - could be playfield enables */
+
+ /* Flipscreen */
+ if (offset==3 && ACCESSING_LSB) {
+ flipscreen=data&0x2;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int pri_mask)
+{
+ int offs,fx,fy,x,y,color,sprite;
+
+ for (offs = 0x1000/2-4;offs >= 0;offs -= 4)
+ {
+ if (!(pri_mask&(buffered_spriteram16[offs+2]>>8))) continue;
+
+ fx = buffered_spriteram16[offs+0] & 0x2000;
+ fy = buffered_spriteram16[offs+0] & 0x4000;
+ color = (buffered_spriteram16[offs+0] & 0x0f00) >> 8;
+ y = buffered_spriteram16[offs+0] & 0x00ff;
+
+ sprite = buffered_spriteram16[offs+1];
+ sprite &= 0x0fff;
+
+ x = buffered_spriteram16[offs+2] & 0xff;
+ if (buffered_spriteram16[offs+2] & 0x100) x=0-(0x100-x);
+
+ if (flipscreen) {
+ x=240-x;
+ y=240-y;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ }
+
+ drawgfx(bitmap,machine->gfx[3],
+ sprite,
+ color,fx,fy,x,y,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+VIDEO_UPDATE( raiden )
+{
+ /* Setup the tilemaps, alternate version has different scroll positions */
+ if (!alternate) {
+ tilemap_set_scrollx( bg_layer,0, raiden_scroll_ram[0]);
+ tilemap_set_scrolly( bg_layer,0, raiden_scroll_ram[1]);
+ tilemap_set_scrollx( fg_layer,0, raiden_scroll_ram[2]);
+ tilemap_set_scrolly( fg_layer,0, raiden_scroll_ram[3]);
+ }
+ else {
+ tilemap_set_scrolly( bg_layer,0, ((raiden_scroll_ram[0x01]&0x30)<<4)+((raiden_scroll_ram[0x02]&0x7f)<<1)+((raiden_scroll_ram[0x02]&0x80)>>7) );
+ tilemap_set_scrollx( bg_layer,0, ((raiden_scroll_ram[0x09]&0x30)<<4)+((raiden_scroll_ram[0x0a]&0x7f)<<1)+((raiden_scroll_ram[0x0a]&0x80)>>7) );
+ tilemap_set_scrolly( fg_layer,0, ((raiden_scroll_ram[0x11]&0x30)<<4)+((raiden_scroll_ram[0x12]&0x7f)<<1)+((raiden_scroll_ram[0x12]&0x80)>>7) );
+ tilemap_set_scrollx( fg_layer,0, ((raiden_scroll_ram[0x19]&0x30)<<4)+((raiden_scroll_ram[0x1a]&0x7f)<<1)+((raiden_scroll_ram[0x1a]&0x80)>>7) );
+ }
+
+ tilemap_draw(bitmap,cliprect,bg_layer,0,0);
+
+ /* Draw sprites underneath foreground */
+ draw_sprites(machine,bitmap,cliprect,0x40);
+ tilemap_draw(bitmap,cliprect,fg_layer,0,0);
+
+ /* Rest of sprites */
+ draw_sprites(machine,bitmap,cliprect,0x80);
+
+ /* Text layer */
+ tilemap_draw(bitmap,cliprect,tx_layer,0,0);
+ return 0;
+}
diff --git a/src/mame/video/raiders5.c b/src/mame/video/raiders5.c
new file mode 100644
index 00000000000..2a660b61388
--- /dev/null
+++ b/src/mame/video/raiders5.c
@@ -0,0 +1,233 @@
+/*******************************************************************************
+
+Raiders5 (c) 1985 Taito / UPL
+
+Video hardware driver by Uki
+
+ 02/Jun/2001 -
+
+*******************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *raiders5_foreground_videoram;
+UINT8 *raiders5_foreground_colorram;
+UINT8 *raiders5_background_videoram;
+UINT8 *raiders5_background_colorram;
+UINT8 *raiders5_spriteram;
+size_t raiders5_spriteram_size;
+
+
+static UINT8 raiders5_scroll_x;
+static UINT8 raiders5_scroll_y;
+static UINT8 raiders5_flip_screen;
+
+static tilemap *background_tilemap;
+static tilemap *foreground_tilemap;
+
+
+
+/*************************************
+ *
+ * Callbacks for the TileMap code
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_background_tile_info )
+{
+ UINT8 bank = ((raiders5_background_colorram[tile_index] >> 1) & 0x01) + 3; /* ? */
+
+ UINT16 code = raiders5_background_videoram[tile_index] |
+ ((raiders5_background_colorram[tile_index] & 0x01) << 8);
+
+ UINT8 color = raiders5_background_colorram[tile_index] >> 4;
+
+ SET_TILE_INFO(bank, code, color, 0);
+}
+
+
+static TILE_GET_INFO( get_foreground_tile_info )
+{
+ UINT16 code = raiders5_foreground_videoram[tile_index];
+
+ UINT8 color = raiders5_foreground_colorram[tile_index] >> 4;
+
+ SET_TILE_INFO(2, code, color, 0);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( raiders5 )
+{
+ background_tilemap = tilemap_create(get_background_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ foreground_tilemap = tilemap_create(get_foreground_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_scrolldx(background_tilemap, 7, 0);
+
+ tilemap_set_transparent_pen(foreground_tilemap, 0);
+}
+
+
+
+/*************************************
+ *
+ * Memory handlers
+ *
+ *************************************/
+
+WRITE8_HANDLER( raiders5_scroll_x_w )
+{
+ raiders5_scroll_x = data;
+}
+
+
+WRITE8_HANDLER( raiders5_scroll_y_w )
+{
+ raiders5_scroll_y = data;
+}
+
+
+WRITE8_HANDLER( raiders5_flip_screen_w )
+{
+ raiders5_flip_screen = data & 0x01;
+
+ tilemap_set_flip(ALL_TILEMAPS, (raiders5_flip_screen ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0));
+}
+
+
+WRITE8_HANDLER( raiders5_foreground_videoram_w )
+{
+ raiders5_foreground_videoram[offset] = data;
+ tilemap_mark_tile_dirty(foreground_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( raiders5_foreground_colorram_w )
+{
+ raiders5_foreground_colorram[offset] = data;
+ tilemap_mark_tile_dirty(foreground_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( raiders5_background_videoram_w )
+{
+ offs_t y = (offset + ((raiders5_scroll_y & 0xf8) << 2)) & 0x3e0;
+ offs_t x = (offset + (raiders5_scroll_x >> 3)) & 0x1f;
+
+ raiders5_background_videoram[y | x] = data;
+ tilemap_mark_tile_dirty(background_tilemap, y | x);
+}
+
+
+READ8_HANDLER( raiders5_background_videoram_r )
+{
+ offs_t y = (offset + ((raiders5_scroll_y & 0xf8) << 2)) & 0x3e0;
+ offs_t x = (offset + (raiders5_scroll_x >> 3)) & 0x1f;
+
+ return raiders5_background_videoram[y | x];
+}
+
+
+WRITE8_HANDLER( raiders5_background_colorram_w )
+{
+ offs_t y = (offset + ((raiders5_scroll_y & 0xf8) << 2)) & 0x3e0;
+ offs_t x = (offset + (raiders5_scroll_x >> 3)) & 0x1f;
+
+ raiders5_background_colorram[y | x] = data;
+ tilemap_mark_tile_dirty(background_tilemap, y | x);
+}
+
+
+READ8_HANDLER( raiders5_background_colorram_r )
+{
+ offs_t y = (offset + ((raiders5_scroll_y & 0xf8) << 2)) & 0x3e0;
+ offs_t x = (offset + (raiders5_scroll_x >> 3)) & 0x1f;
+
+ return raiders5_background_colorram[y | x];
+}
+
+
+WRITE8_HANDLER( raiders5_paletteram_w )
+{
+ paletteram_BBGGRRII_w(offset, data);
+
+ if (offset < 0x10)
+ {
+ if (offset != 1)
+ {
+ int i;
+
+ for (i = 0; i < 0x10; i++)
+ {
+ paletteram_BBGGRRII_w(offset + (i * 0x10) + 0x0200, data);
+ }
+ }
+
+ paletteram_BBGGRRII_w((offset * 0x10) + 0x0201, data);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ offs_t offs;
+
+ for (offs = 0; offs < raiders5_spriteram_size; offs += 32)
+ {
+ UINT8 bank = (raiders5_spriteram[offs + 3] >> 1) & 0x01;
+
+ UINT8 code = ((raiders5_spriteram[offs + 3] << 6) & 0x40) | (raiders5_spriteram[offs + 0] >> 2);
+
+ UINT8 color = raiders5_spriteram[offs + 3] >> 4;
+
+ int flip_y = ((raiders5_spriteram[offs + 0] >> 1) & 0x01) ^ raiders5_flip_screen;
+ int flip_x = ((raiders5_spriteram[offs + 0] >> 0) & 0x01) ^ raiders5_flip_screen;
+
+ UINT8 y = raiders5_spriteram[offs + 2];
+ UINT8 x = raiders5_spriteram[offs + 1];
+
+ if (raiders5_flip_screen)
+ {
+ y = 240 - y;
+ x = 240 - x;
+ }
+
+ drawgfx(bitmap,machine->gfx[bank],
+ code, color, flip_x, flip_y,
+ x, y, cliprect, TRANSPARENCY_PEN, 0);
+
+ /* draw it wrapped around */
+ drawgfx(bitmap,machine->gfx[bank],
+ code, color, flip_x, flip_y,
+ x - 0x100, y, cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+
+VIDEO_UPDATE( raiders5 )
+{
+ tilemap_set_scrolly(background_tilemap, 0, raiders5_scroll_y);
+ tilemap_set_scrollx(background_tilemap, 0, raiders5_scroll_x);
+
+ tilemap_draw(bitmap, cliprect, background_tilemap, 0, 0);
+
+ draw_sprites(machine, bitmap, cliprect);
+
+ tilemap_draw(bitmap, cliprect, foreground_tilemap, 0, 0);
+
+ return 0;
+}
diff --git a/src/mame/video/rallyx.c b/src/mame/video/rallyx.c
new file mode 100644
index 00000000000..2337d08b0fe
--- /dev/null
+++ b/src/mame/video/rallyx.c
@@ -0,0 +1,581 @@
+/***************************************************************************
+
+The video mixer of this hardware is peculiar.
+
+There are two 16-colors palette banks: the first is used for characters and
+sprites, the second for "bullets".
+
+When a bullet is on screen, it selects the second palette bank and replaces
+the bottom 2 bits of the tile palette entry with its own, while leaving the
+other 2 bits untouched. Therefore, in theory a bullet could have 4 different
+colors depending on the color of the background it is drawn over; but none
+of the games use this peculiarity, since the bullet palette is just the same
+colors repeated four time. This is NOT emulated.
+
+When there is a sprite under the bullet, the palette bank is changed, but the
+palette entry number is NOT changed; therefore, the sprite pixels that are
+covered by the bullet just change bank. This is emulated by first drawing the
+bullets normally, then drawing the sprites (with pdrawgfx so they are not
+drawn over high priority tiles), then drawing the pullets again in
+TRANSPARENCY_PEN_TABLE mode, so that bullets not covered by sprites remain
+the same while the others alter the sprite color.
+
+
+The tile/sprite priority is controlled by the top bit of the tile color code.
+This feature seems to be disabled in Jungler, probably because that game
+needs more color combination to render its graphics.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+UINT8 *rallyx_videoram,*rallyx_radarattr;
+
+static UINT8 *rallyx_radarx,*rallyx_radary;
+static int video_type, spriteram_base;
+
+static tilemap *bg_tilemap,*fg_tilemap;
+
+#define MAX_STARS 1000
+#define STARS_COLOR_BASE 32
+
+static int stars_enable;
+
+struct star
+{
+ int x,y,color;
+};
+static struct star stars[MAX_STARS];
+static int total_stars;
+
+
+enum
+{
+ TYPE_RALLYX,
+ TYPE_JUNGLER,
+ TYPE_TACTCIAN,
+ TYPE_LOCOMOTN,
+ TYPE_COMMSEGA
+};
+
+
+DRIVER_INIT( rallyx )
+{
+ video_type = TYPE_RALLYX;
+}
+
+DRIVER_INIT( jungler )
+{
+ video_type = TYPE_JUNGLER;
+}
+
+DRIVER_INIT( tactcian )
+{
+ video_type = TYPE_TACTCIAN;
+}
+
+DRIVER_INIT( locomotn )
+{
+ video_type = TYPE_LOCOMOTN;
+}
+
+DRIVER_INIT( commsega )
+{
+ video_type = TYPE_COMMSEGA;
+}
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs.
+
+ Rally X has one 32x8 palette PROM and one 256x4 color lookup table PROM.
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+ In Rally-X there is a 1 kohm pull-down on B only, in Locomotion the
+ 1 kohm pull-down is an all three RGB outputs.
+
+***************************************************************************/
+PALETTE_INIT( rallyx )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < 32;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ if (video_type == TYPE_RALLYX)
+ {
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ }
+ else
+ {
+ bit0 = (*color_prom >> 6) & 0x01;
+ bit1 = (*color_prom >> 7) & 0x01;
+ b = 0x50 * bit0 + 0xab * bit1;
+ }
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* character lookup table */
+ /* sprites use the same color lookup table as characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = *(color_prom++) & 0x0f;
+
+ /* radar dots lookup table */
+ /* they use colors 16-19 */
+ for (i = 0;i < 4;i++)
+ COLOR(2,i) = 16 + i;
+
+ /* Rally X doesn't have the optional starfield generator */
+ if (video_type != TYPE_RALLYX)
+ {
+ /* now the stars */
+ for (i = 0;i < 64;i++)
+ {
+ int bits,r,g,b;
+ static const int map[4] = { 0x00, 0x47, 0x97, 0xde };
+
+ bits = (i >> 0) & 0x03;
+ r = map[bits];
+ bits = (i >> 2) & 0x03;
+ g = map[bits];
+ bits = (i >> 4) & 0x03;
+ b = map[bits];
+
+ palette_set_color(machine,i + 32,MAKE_RGB(r,g,b));
+ }
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/* the video RAM has space for 32x32 tiles and is only partially used for the radar */
+static TILEMAP_MAPPER( fg_tilemap_scan )
+{
+ return col + (row << 5);
+}
+
+
+INLINE void rallyx_get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int ram_offs)
+{
+ UINT8 attr = rallyx_videoram[ram_offs + tile_index + 0x800];
+ tileinfo->category = (attr & 0x20) >> 5;
+ SET_TILE_INFO(
+ 0,
+ rallyx_videoram[ram_offs + tile_index],
+ attr & 0x3f,
+ TILE_FLIPYX(attr >> 6) ^ TILE_FLIPX);
+}
+
+static TILE_GET_INFO( rallyx_bg_get_tile_info )
+{
+ rallyx_get_tile_info(machine,tileinfo,tile_index,0x400);
+}
+
+static TILE_GET_INFO( rallyx_fg_get_tile_info )
+{
+ rallyx_get_tile_info(machine,tileinfo,tile_index,0x000);
+}
+
+
+INLINE void locomotn_get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int ram_offs)
+{
+ UINT8 attr = rallyx_videoram[ram_offs + tile_index + 0x800];
+ int code = rallyx_videoram[ram_offs + tile_index];
+ code = (code & 0x7f) + 2*(attr & 0x40) + 2*(code & 0x80);
+ tileinfo->category = (attr & 0x20) >> 5;
+ SET_TILE_INFO(
+ 0,
+ code,
+ attr & 0x3f,
+ (attr & 0x80) ? (TILE_FLIPX | TILE_FLIPY) : 0);
+}
+
+static TILE_GET_INFO( locomotn_bg_get_tile_info )
+{
+ locomotn_get_tile_info(machine,tileinfo,tile_index,0x400);
+}
+
+static TILE_GET_INFO( locomotn_fg_get_tile_info )
+{
+ locomotn_get_tile_info(machine,tileinfo,tile_index,0x000);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( rallyx )
+{
+ int i;
+
+ if (video_type == TYPE_RALLYX || video_type == TYPE_JUNGLER)
+ {
+ bg_tilemap = tilemap_create(rallyx_bg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ fg_tilemap = tilemap_create(rallyx_fg_get_tile_info,fg_tilemap_scan, TILEMAP_TYPE_PEN,8,8, 8,32);
+ }
+ else
+ {
+ bg_tilemap = tilemap_create(locomotn_bg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ fg_tilemap = tilemap_create(locomotn_fg_get_tile_info,fg_tilemap_scan, TILEMAP_TYPE_PEN,8,8, 8,32);
+ }
+
+ /* the scrolling tilemap is slightly misplaced in Rally X */
+ if (video_type == TYPE_RALLYX)
+ tilemap_set_scrolldx(bg_tilemap,3,3);
+
+ /* commsega has more sprites and bullets than the other games */
+ if (video_type == TYPE_COMMSEGA)
+ spriteram_base = 0x00;
+ else
+ spriteram_base = 0x14;
+ spriteram = rallyx_videoram + 0x00;
+ spriteram_2 = spriteram + 0x800;
+ rallyx_radarx = rallyx_videoram + 0x20;
+ rallyx_radary = rallyx_radarx + 0x800;
+
+ for (i = 0;i < 16;i++)
+ machine->shadow_table[i] = i+16;
+ for (i = 16;i < 32;i++)
+ machine->shadow_table[i] = i;
+ for (i = 0;i < 3;i++)
+ gfx_drawmode_table[i] = DRAWMODE_SHADOW;
+ gfx_drawmode_table[3] = DRAWMODE_NONE;
+
+
+ /* Rally X doesn't have the optional starfield generator */
+ if (video_type != TYPE_RALLYX)
+ {
+ int generator;
+ int x,y;
+
+ /* precalculate the star background */
+ /* this comes from the Galaxian hardware, Bosconian is probably different */
+ total_stars = 0;
+ generator = 0;
+
+ for (y = 0;y < 256;y++)
+ {
+ for (x = 0;x < 288;x++)
+ {
+ int bit1,bit2;
+
+
+ generator <<= 1;
+ bit1 = (~generator >> 17) & 1;
+ bit2 = (generator >> 5) & 1;
+
+ if (bit1 ^ bit2) generator |= 1;
+
+ if (((~generator >> 16) & 1) &&
+ (generator & 0xfe) == 0xfe)
+ {
+ int color;
+
+ color = (~(generator >> 8)) & 0x3f;
+ if (color && total_stars < MAX_STARS)
+ {
+ stars[total_stars].x = x;
+ stars[total_stars].y = y;
+ stars[total_stars].color = machine->pens[color + STARS_COLOR_BASE];
+
+ total_stars++;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( rallyx_videoram_w )
+{
+ rallyx_videoram[offset] = data;
+ if (offset & 0x400)
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+ else
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( rallyx_scrollx_w )
+{
+ tilemap_set_scrollx(bg_tilemap,0,data);
+}
+
+WRITE8_HANDLER( rallyx_scrolly_w )
+{
+ tilemap_set_scrolly(bg_tilemap,0,data);
+}
+
+WRITE8_HANDLER( tactcian_starson_w )
+{
+ stars_enable = data & 1;
+}
+
+
+
+static void plot_star(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int x, int y, int color)
+{
+ int bpen = machine->pens[0];
+
+ if (y < cliprect->min_y ||
+ y > cliprect->max_y ||
+ x < cliprect->min_x ||
+ x > cliprect->max_x)
+ return;
+
+ if (flip_screen_x)
+ {
+ x = 255 - x;
+ }
+ if (flip_screen_y)
+ {
+ y = 255 - y;
+ }
+
+ if (*BITMAP_ADDR16(bitmap, y, x) == bpen)
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[STARS_COLOR_BASE + color];
+}
+
+static void draw_stars(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = 0;offs < total_stars;offs++)
+ {
+ int x,y;
+
+
+ x = stars[offs].x;
+ y = stars[offs].y;
+
+ if ((y & 0x01) ^ ((x >> 3) & 0x01))
+ {
+ plot_star(machine, bitmap, cliprect, x, y, stars[offs].color);
+ }
+ }
+}
+
+
+static void rallyx_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int displacement )
+{
+ int offs;
+
+ for (offs = 0x20-2;offs >= spriteram_base;offs -= 2)
+ {
+ int sx = spriteram[offs + 1] + ((spriteram_2[offs + 1] & 0x80) << 1) - displacement;
+ int sy = 241 - spriteram_2[offs] - displacement;
+ int flipx = spriteram[offs] & 1;
+ int flipy = spriteram[offs] & 2;
+ if (flip_screen) sx -= 2*displacement;
+
+ pdrawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs] & 0xfc) >> 2,
+ spriteram_2[offs + 1] & 0x3f,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_COLOR,0,0x02);
+ }
+}
+
+static void locomotn_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int displacement )
+{
+ int offs;
+
+ for (offs = 0x20-2;offs >= spriteram_base;offs -= 2)
+ {
+ int sx = spriteram[offs + 1] + ((spriteram_2[offs + 1] & 0x80) << 1);
+ int sy = 241 - spriteram_2[offs] - displacement;
+ int flip = spriteram[offs] & 2;
+
+ /* handle reduced visible area in some games */
+ if (flip_screen && machine->screen[0].visarea.max_x == 32*8-1) sx += 32;
+
+ pdrawgfx(bitmap,machine->gfx[1],
+ ((spriteram[offs] & 0x7c) >> 2) + 0x20*(spriteram[offs] & 0x01) + ((spriteram[offs] & 0x80) >> 1),
+ spriteram_2[offs + 1] & 0x3f,
+ flip,flip,
+ sx,sy,
+ cliprect,TRANSPARENCY_COLOR,0,0x02);
+ }
+}
+
+static void rallyx_draw_bullets(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int transparency )
+{
+ int offs;
+
+ for (offs = spriteram_base; offs < 0x20;offs++)
+ {
+ int x,y;
+
+ x = rallyx_radarx[offs] + ((~rallyx_radarattr[offs & 0x0f] & 0x01) << 8);
+ y = 253 - rallyx_radary[offs];
+ if (flip_screen) x -= 3;
+
+ drawgfx(bitmap,machine->gfx[2],
+ ((rallyx_radarattr[offs & 0x0f] & 0x0e) >> 1) ^ 0x07,
+ 0,
+ 0,0,
+ x,y,
+ cliprect,transparency,3);
+ }
+}
+
+static void jungler_draw_bullets(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int transparency )
+{
+ int offs;
+
+ for (offs = spriteram_base; offs < 0x20;offs++)
+ {
+ int x,y;
+
+ x = rallyx_radarx[offs] + ((~rallyx_radarattr[offs & 0x0f] & 0x08) << 5);
+ y = 253 - rallyx_radary[offs];
+
+ drawgfx(bitmap,machine->gfx[2],
+ (rallyx_radarattr[offs & 0x0f] & 0x07) ^ 0x07,
+ 0,
+ 0,0,
+ x,y,
+ cliprect,transparency,3);
+ }
+}
+
+static void locomotn_draw_bullets(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int transparency )
+{
+ int offs;
+
+ for (offs = spriteram_base; offs < 0x20;offs++)
+ {
+ int x,y;
+
+
+ /* it looks like in commsega the addresses used are
+ a000-a003 a004-a00f
+ 8020-8023 8034-803f
+ 8820-8823 8834-883f
+ so 8024-8033 and 8824-8833 are not used
+ */
+
+ x = rallyx_radarx[offs] + ((~rallyx_radarattr[offs & 0x0f] & 0x08) << 5);
+ y = 252 - rallyx_radary[offs];
+
+ /* handle reduced visible area in some games */
+ if (flip_screen && machine->screen[0].visarea.max_x == 32*8-1) x += 32;
+
+ drawgfx(bitmap,machine->gfx[2],
+ (rallyx_radarattr[offs & 0x0f] & 0x07) ^ 0x07,
+ 0,
+ 0,0,
+ x,y,
+ cliprect,transparency,3);
+ }
+}
+
+
+VIDEO_UPDATE( rallyx )
+{
+ /* the radar tilemap is just 8x32. We rely on the tilemap code to repeat it across
+ the screen, and clip it to only the position where it is supposed to be shown */
+ rectangle fg_clip = *cliprect;
+ rectangle bg_clip = *cliprect;
+ if (flip_screen)
+ {
+ bg_clip.min_x = 8*8;
+ fg_clip.max_x = 8*8-1;
+ }
+ else
+ {
+ bg_clip.max_x = 28*8-1;
+ fg_clip.min_x = 28*8;
+ }
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,&bg_clip,bg_tilemap,0,0);
+ tilemap_draw(bitmap,&fg_clip,fg_tilemap,0,0);
+ /* tile priority doesn't seem to be supported in Jungler */
+ tilemap_draw(bitmap,&bg_clip,bg_tilemap,1,video_type == TYPE_JUNGLER ? 0 : 1);
+ tilemap_draw(bitmap,&fg_clip,fg_tilemap,1,video_type == TYPE_JUNGLER ? 0 : 1);
+
+ switch (video_type)
+ {
+ case TYPE_RALLYX:
+ rallyx_draw_bullets(machine, bitmap,cliprect,TRANSPARENCY_PEN);
+ rallyx_draw_sprites(machine, bitmap,cliprect,1);
+ rallyx_draw_bullets(machine, bitmap,cliprect,TRANSPARENCY_PEN_TABLE);
+ break;
+
+ case TYPE_JUNGLER:
+ jungler_draw_bullets(machine, bitmap,cliprect,TRANSPARENCY_PEN);
+ rallyx_draw_sprites(machine, bitmap,cliprect,0);
+ jungler_draw_bullets(machine, bitmap,cliprect,TRANSPARENCY_PEN_TABLE);
+ break;
+
+ case TYPE_TACTCIAN:
+ case TYPE_LOCOMOTN:
+ case TYPE_COMMSEGA:
+ locomotn_draw_bullets(machine, bitmap,cliprect,TRANSPARENCY_PEN);
+ locomotn_draw_sprites(machine, bitmap,cliprect,0);
+ locomotn_draw_bullets(machine, bitmap,cliprect,TRANSPARENCY_PEN_TABLE);
+ break;
+ }
+
+ /* Rally X doesn't have the optional starfield generator */
+ if (video_type != TYPE_RALLYX)
+ if (stars_enable) draw_stars(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/rampart.c b/src/mame/video/rampart.c
new file mode 100644
index 00000000000..44983762684
--- /dev/null
+++ b/src/mame/video/rampart.c
@@ -0,0 +1,212 @@
+/***************************************************************************
+
+ Atari Rampart hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "rampart.h"
+
+
+
+/*************************************
+ *
+ * Globals we own
+ *
+ *************************************/
+
+UINT16 *rampart_bitmap;
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static UINT8 *pfdirty;
+static mame_bitmap *pfbitmap;
+static int xdim, ydim;
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( rampart )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 0, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 8, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x100, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0x00ff,0,0,0 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0,0x7fff,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0x000f,0 }}, /* mask for the color */
+ {{ 0,0,0xff80,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xff80 }}, /* mask for the Y position */
+ {{ 0,0,0,0x0070 }}, /* mask for the width, in tiles*/
+ {{ 0,0,0,0x0007 }}, /* mask for the height, in tiles */
+ {{ 0,0x8000,0,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0, /* callback routine for special entries */
+ };
+
+ /* initialize the playfield */
+ rampart_bitmap_init(machine, 43*8, 30*8);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+
+ /* set the intial scroll offset */
+ atarimo_set_xscroll(0, -4);
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( rampart )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ rampart_bitmap_render(machine, bitmap, cliprect);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* not yet verified
+ */
+ pf[x] = mo[x];
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Bitmap initialization
+ *
+ *************************************/
+
+void rampart_bitmap_init(running_machine *machine, int _xdim, int _ydim)
+{
+ /* set the dimensions */
+ xdim = _xdim;
+ ydim = _ydim;
+
+ /* allocate dirty map */
+ pfdirty = auto_malloc(sizeof(pfdirty[0]) * ydim);
+ memset(pfdirty, 1, sizeof(pfdirty[0]) * ydim);
+
+ /* allocate playfield bitmap */
+ pfbitmap = auto_bitmap_alloc(xdim, ydim, machine->screen[0].format);
+}
+
+
+
+/*************************************
+ *
+ * Bitmap RAM write handler
+ *
+ *************************************/
+
+WRITE16_HANDLER( rampart_bitmap_w )
+{
+ int oldword = rampart_bitmap[offset];
+ int newword = oldword;
+ int x, y;
+
+ COMBINE_DATA(&newword);
+ if (oldword != newword)
+ {
+ rampart_bitmap[offset] = newword;
+
+ /* track color usage */
+ x = offset % 256;
+ y = offset / 256;
+ if (x < xdim && y < ydim)
+ pfdirty[y] = 1;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Bitmap rendering
+ *
+ *************************************/
+
+void rampart_bitmap_render(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int x, y;
+
+ /* update any dirty scanlines */
+ for (y = 0; y < ydim; y++)
+ if (pfdirty[y])
+ {
+ const UINT16 *src = &rampart_bitmap[256 * y];
+ UINT8 scanline[512];
+ UINT8 *dst = scanline;
+
+ /* regenerate the line */
+ for (x = 0; x < xdim / 2; x++)
+ {
+ int bits = *src++;
+ *dst++ = bits >> 8;
+ *dst++ = bits;
+ }
+ pfdirty[y] = 0;
+
+ /* draw it */
+ draw_scanline8(pfbitmap, 0, y, xdim, scanline, machine->pens, -1);
+ }
+
+ /* copy the cached bitmap */
+ copybitmap(bitmap, pfbitmap, 0, 0, 0, 0, cliprect, TRANSPARENCY_NONE, 0);
+}
diff --git a/src/mame/video/rastan.c b/src/mame/video/rastan.c
new file mode 100644
index 00000000000..f7d867da9d8
--- /dev/null
+++ b/src/mame/video/rastan.c
@@ -0,0 +1,222 @@
+/***************************************************************************
+ Functions to emulate similar video hardware on these Taito games:
+
+ - rastan
+ - operation wolf
+ - rainbow islands
+ - jumping (bootleg)
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/taitoic.h"
+
+
+static UINT16 sprite_ctrl = 0;
+static UINT16 sprites_flipscreen = 0;
+
+/***************************************************************************/
+
+VIDEO_START( rastan )
+{
+ /* (chips, gfxnum, x_offs, y_offs, y_invert, opaque, dblwidth) */
+ PC080SN_vh_start(1,0,0,0,0,0,0);
+ PC090OJ_vh_start(1,0,0,0);
+}
+
+VIDEO_START( opwolf )
+{
+ PC080SN_vh_start(1,1,0,0,0,0,0);
+ PC090OJ_vh_start(0,0,0,0);
+}
+
+VIDEO_START( rainbow )
+{
+ /* (chips, gfxnum, x_offs, y_offs, y_invert, opaque, dblwidth) */
+ PC080SN_vh_start(1,1,0,0,0,0,0);
+ PC090OJ_vh_start(0,0,0,0);
+}
+
+VIDEO_START( jumping )
+{
+ PC080SN_vh_start(1,1,0,0,1,0,0);
+
+ PC080SN_set_trans_pen(0,1,15);
+
+ /* not 100% sure Jumping needs to save both... */
+ state_save_register_global(sprite_ctrl);
+ state_save_register_global(sprites_flipscreen);
+}
+
+
+WRITE16_HANDLER( rastan_spritectrl_w )
+{
+ /* bits 5-7 are the sprite palette bank */
+ PC090OJ_sprite_ctrl = (data & 0xe0) >> 5;
+
+ /* bit 4 unused */
+
+ /* bits 0 and 1 are coin lockout */
+ coin_lockout_w(1,~data & 0x01);
+ coin_lockout_w(0,~data & 0x02);
+
+ /* bits 2 and 3 are the coin counters */
+ coin_counter_w(1,data & 0x04);
+ coin_counter_w(0,data & 0x08);
+}
+
+WRITE16_HANDLER( rainbow_spritectrl_w )
+{
+ if (offset == 0)
+ {
+ /* bits 0 and 1 always set */
+ /* bits 5-7 are the sprite palette bank */
+ /* other bits unknown */
+
+ PC090OJ_sprite_ctrl = (data & 0xe0) >> 5;
+ }
+}
+
+WRITE16_HANDLER( jumping_spritectrl_w )
+{
+ if (offset == 0)
+ {
+ /* bits 0 and 1 are set after 15 seconds */
+ /* bits 5-7 are the sprite palette bank */
+ /* other bits unknown */
+
+ sprite_ctrl = data;
+ }
+}
+
+
+
+/***************************************************************************/
+
+VIDEO_UPDATE( rastan )
+{
+ int layer[2];
+
+ PC080SN_tilemap_update();
+
+ layer[0] = 0;
+ layer[1] = 1;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ PC080SN_tilemap_draw(bitmap,cliprect,0,layer[0],TILEMAP_DRAW_OPAQUE,1);
+ PC080SN_tilemap_draw(bitmap,cliprect,0,layer[1],0,2);
+
+ PC090OJ_draw_sprites(machine,bitmap,cliprect,0);
+ return 0;
+}
+
+/***************************************************************************/
+
+VIDEO_UPDATE( opwolf )
+{
+ int layer[2];
+
+ PC080SN_tilemap_update();
+
+ layer[0] = 0;
+ layer[1] = 1;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ PC080SN_tilemap_draw(bitmap,cliprect,0,layer[0],TILEMAP_DRAW_OPAQUE,1);
+ PC080SN_tilemap_draw(bitmap,cliprect,0,layer[1],0,2);
+
+ PC090OJ_draw_sprites(machine,bitmap,cliprect,1);
+
+// if (input_port_5_word_r(0,0xffff))
+
+// popmessage("%d %d",input_port_5_word_r(0,0xffff),input_port_6_word_r(0,0xffff));
+
+ return 0;
+}
+
+/***************************************************************************/
+
+VIDEO_UPDATE( rainbow )
+{
+ int layer[2];
+
+ PC080SN_tilemap_update();
+
+ layer[0] = 0;
+ layer[1] = 1;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ PC080SN_tilemap_draw(bitmap,cliprect,0,layer[0],TILEMAP_DRAW_OPAQUE,1);
+ PC080SN_tilemap_draw(bitmap,cliprect,0,layer[1],0,2);
+
+ PC090OJ_draw_sprites(machine,bitmap,cliprect,1);
+ return 0;
+}
+
+/***************************************************************************
+
+Jumping uses different sprite controller
+than rainbow island. - values are remapped
+at address 0x2EA in the code. Apart from
+physical layout, the main change is that
+the Y settings are active low.
+
+*/
+
+VIDEO_UPDATE( jumping )
+{
+ int offs,layer[2];
+ int sprite_colbank = (sprite_ctrl & 0xe0) >> 1;
+
+ PC080SN_tilemap_update();
+
+ /* Override values, or foreground layer is in wrong position */
+ PC080SN_set_scroll(0,1,16,0);
+
+ layer[0] = 0;
+ layer[1] = 1;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ PC080SN_tilemap_draw(bitmap,cliprect,0,layer[0],TILEMAP_DRAW_OPAQUE,0);
+
+ /* Draw the sprites. 128 sprites in total */
+ for (offs = spriteram_size/2-8; offs >= 0; offs -= 8)
+ {
+ int tile = spriteram16[offs];
+ if (tile < machine->gfx[1]->total_elements)
+ {
+ int sx,sy,color,data1;
+
+ sy = ((spriteram16[offs+1] - 0xfff1) ^ 0xffff) & 0x1ff;
+ if (sy > 400) sy = sy - 512;
+ sx = (spriteram16[offs+2] - 0x38) & 0x1ff;
+ if (sx > 400) sx = sx - 512;
+
+ data1 = spriteram16[offs+3];
+ color = (spriteram16[offs+4] & 0x0f) | sprite_colbank;
+
+ drawgfx(bitmap,machine->gfx[0],
+ tile,
+ color,
+ data1 & 0x40, data1 & 0x80,
+ sx,sy+1,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+
+ PC080SN_tilemap_draw(bitmap,cliprect,0,layer[1],0,0);
+
+#if 0
+ {
+ char buf[80];
+ sprintf(buf,"sprite_ctrl: %04x",sprite_ctrl);
+ popmessage(buf);
+ }
+#endif
+ return 0;
+}
+
diff --git a/src/mame/video/realbrk.c b/src/mame/video/realbrk.c
new file mode 100644
index 00000000000..c9427d2646d
--- /dev/null
+++ b/src/mame/video/realbrk.c
@@ -0,0 +1,638 @@
+/***************************************************************************
+
+ -= Billiard Academy Real Break =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+ This hardware provides for:
+
+ - 2 scrolling background layers, 1024 x 512 in size
+ made of 16 x 16 tiles with 256 colors
+
+ - 1 text layer (fixed?), 512 x 256 in size
+ made of 8 x 8 tiles with 16 colors
+
+ - 0x300 sprites made of 16x16 tiles, both 256 or 16 colors
+ per tile and from 1 to 32x32 (more?) tiles per sprite.
+ Sprites can zoom / shrink / rotate
+
+
+***************************************************************************/
+
+#include "driver.h"
+#include "realbrk.h"
+
+//UINT16 *realbrk_vram_0, *realbrk_vram_1, *realbrk_vram_2, *realbrk_vregs;
+UINT16 *realbrk_vram_0, *realbrk_vram_1, *realbrk_vram_2, *realbrk_vregs, *realbrk_vram_0ras, *realbrk_vram_1ras;
+static mame_bitmap *tmpbitmap0 = NULL;
+static mame_bitmap *tmpbitmap1 = NULL;
+
+static int disable_video;
+
+WRITE16_HANDLER( realbrk_flipscreen_w )
+{
+ if (ACCESSING_LSB)
+ {
+ coin_counter_w(0, data & 0x0001);
+ coin_counter_w(1, data & 0x0004);
+
+ flip_screen_set( data & 0x0080);
+ }
+
+ if (ACCESSING_MSB)
+ {
+ disable_video = data & 0x8000;
+ }
+}
+
+WRITE16_HANDLER( dai2kaku_flipscreen_w )
+{
+ disable_video = 0;
+}
+
+/***************************************************************************
+
+ Tilemaps
+
+
+***************************************************************************/
+
+static tilemap *tilemap_0,*tilemap_1, // Backgrounds
+ *tilemap_2; // Text
+
+
+/***************************************************************************
+
+ Background Tilemaps
+
+ Offset: Bits: Value:
+
+ 0.w f--- ---- ---- ---- Flip Y
+ -e-- ---- ---- ---- Flip X
+ --dc ba98 7--- ----
+ ---- ---- -654 3210 Color
+
+ 2.w Code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info_0 )
+{
+ UINT16 attr = realbrk_vram_0[tile_index * 2 + 0];
+ UINT16 code = realbrk_vram_0[tile_index * 2 + 1];
+ SET_TILE_INFO(
+ 0,
+ code,
+ attr & 0x7f,
+ TILE_FLIPYX( attr >> 14 ));
+}
+
+static TILE_GET_INFO( get_tile_info_1 )
+{
+ UINT16 attr = realbrk_vram_1[tile_index * 2 + 0];
+ UINT16 code = realbrk_vram_1[tile_index * 2 + 1];
+ SET_TILE_INFO(
+ 0,
+ code,
+ attr & 0x7f,
+ TILE_FLIPYX( attr >> 14 ));
+}
+
+WRITE16_HANDLER( realbrk_vram_0_w )
+{
+ COMBINE_DATA(&realbrk_vram_0[offset]);
+ tilemap_mark_tile_dirty(tilemap_0,offset/2);
+}
+
+WRITE16_HANDLER( realbrk_vram_1_w )
+{
+ COMBINE_DATA(&realbrk_vram_1[offset]);
+ tilemap_mark_tile_dirty(tilemap_1,offset/2);
+}
+
+/***************************************************************************
+
+ Text Tilemap
+
+ Offset: Bits: Value:
+
+ 0.w fedc ---- ---- ---- Color
+ ---- ba98 7654 3210 Code
+
+ The full palette of 0x8000 colors can be used by this tilemap since
+ a video register selects the higher bits of the color code.
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info_2 )
+{
+ UINT16 code = realbrk_vram_2[tile_index];
+ SET_TILE_INFO(
+ 1,
+ code & 0x0fff,
+ ((code & 0xf000) >> 12) | ((realbrk_vregs[0xa/2] & 0x7f) << 4),
+ 0);
+}
+
+WRITE16_HANDLER( realbrk_vram_2_w )
+{
+ COMBINE_DATA(&realbrk_vram_2[offset]);
+ tilemap_mark_tile_dirty(tilemap_2,offset);
+}
+
+
+
+/***************************************************************************
+
+
+ Video Hardware Init
+
+
+***************************************************************************/
+
+VIDEO_START(realbrk)
+{
+ /* Backgrounds */
+ tilemap_0 = tilemap_create( get_tile_info_0, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ 0x40, 0x20);
+
+ tilemap_1 = tilemap_create( get_tile_info_1, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ 0x40, 0x20);
+
+ /* Text */
+ tilemap_2 = tilemap_create( get_tile_info_2, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 8,8,
+ 0x40, 0x20);
+
+ tilemap_set_transparent_pen(tilemap_0,0);
+ tilemap_set_transparent_pen(tilemap_1,0);
+ tilemap_set_transparent_pen(tilemap_2,0);
+
+ tmpbitmap0 = auto_bitmap_alloc( 32,
+ 32,
+ machine->screen[0].format);
+
+ tmpbitmap1 = auto_bitmap_alloc( 32,
+ 32,
+ machine->screen[0].format);
+}
+
+/***************************************************************************
+
+ Sprites Drawing
+
+ Sprites RAM is 0x4000 bytes long with each sprite needing 16 bytes.
+
+ Not all sprites must be displayed: there is a list of words at offset
+ 0x3000. If the high bit of a word is 0 the low bits form the index
+ of a sprite to be drawn. 0x300 items of the list seem to be used.
+
+ Each sprite is made of several 16x16 tiles (from 1 to 32x32) and
+ can be zoomed / shrinked in size.
+
+ There are two set of tiles: with 256 or 16 colors.
+
+ Offset: Bits: Value:
+
+ 0.w Y
+
+ 2.w X
+
+ 4.w fedc ba98 ---- ---- Number of tiles along Y, minus 1 (5 bits or more ?)
+ ---- ---- 7654 3210 Number of tiles along X, minus 1 (5 bits or more ?)
+
+ 6.w fedc ba98 ---- ---- Zoom factor along Y (0x40 = no zoom)
+ ---- ---- 7654 3210 Zoom factor along X (0x40 = no zoom)
+
+ 8.w fe-- ---- ---- ----
+ --d- ---- ---- ---- Flip Y
+ ---c ---- ---- ---- Flip X
+ ---- ---- --54 ---- Rotation
+ ---- ba98 76-- 3210 Priority?
+
+ A.w fedc b--- ---- ----
+ ---- -a98 7654 3210 Color
+
+ C.w fedc ba9- ---- ----
+ ---- ---8 ---- ----
+ ---- ---- 7654 321-
+ ---- ---- ---- ---0 1 = Use 16 color sprites, 0 = Use 256 color sprites
+
+ E.w Code
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ int max_x = machine->screen[0].width;
+ int max_y = machine->screen[0].height;
+
+ rectangle spritetile_clip;
+ spritetile_clip.min_x = 0;
+ spritetile_clip.min_y = 0;
+ spritetile_clip.max_x = 32;
+ spritetile_clip.max_y = 32;
+
+ for ( offs = 0x3000/2; offs < 0x3600/2; offs += 2/2 )
+ {
+ int sx, sy, dim, zoom, flip, color, attr, code, flipx, flipy, gfx, rot;
+
+ int x, xdim, xnum, xstart, xend, xinc;
+ int y, ydim, ynum, ystart, yend, yinc;
+
+ UINT16 *s;
+
+ if (spriteram16[offs] & 0x8000) continue;
+
+ s = &spriteram16[(spriteram16[offs] & 0x3ff) * 16/2];
+
+ sy = s[ 0 ];
+ sx = s[ 1 ];
+ dim = s[ 2 ];
+ zoom = s[ 3 ];
+ flip = s[ 4 ];
+ color = s[ 5 ];
+ attr = s[ 6 ];
+ code = s[ 7 ];
+
+ xnum = ((dim >> 0) & 0x1f) + 1;
+ ynum = ((dim >> 8) & 0x1f) + 1;
+
+ flipx = flip & 0x0100;
+ flipy = flip & 0x0200;
+ rot = flip & 0x0030;
+
+ gfx = (attr & 0x0001) + 2;
+
+ sx = ((sx & 0x1ff) - (sx & 0x200)) << 16;
+ sy = ((sy & 0x0ff) - (sy & 0x100)) << 16;
+
+ xdim = ((zoom & 0x00ff) >> 0) << (16-6+4);
+ ydim = ((zoom & 0xff00) >> 8) << (16-6+4);
+
+ if (flip_screen_x) { flipx = !flipx; sx = (max_x << 16) - sx - xnum * xdim; }
+ if (flip_screen_y) { flipy = !flipy; sy = (max_y << 16) - sy - ynum * ydim; }
+
+ if (flipx) { xstart = xnum-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = xnum; xinc = +1; }
+
+ if (flipy) { ystart = ynum-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = ynum; yinc = +1; }
+
+
+ // The positioning of the rotated sprites makes it look as if
+ // the sprite source is scanned in a constant pattern left to right,
+ // top to bottom, and the destination plotting pattern is varied.
+ // copyrozbitmap works the other way.
+
+ // Rotating a sprite when drawgfxzoom draws a tile at a time means
+ // - rotating each sprite tile
+ // - transforming each tile position
+ // - compensating for the offset introduced by the difference in
+ // scanning patterns between the original mechanism and copyrozbitmap
+
+
+ for (y = ystart; y != yend; y += yinc)
+ {
+ for (x = xstart; x != xend; x += xinc)
+ {
+ int currx = (sx + x * xdim) / 0x10000;
+ int curry = (sy + y * ydim) / 0x10000;
+
+ int scalex = (sx + (x + 1) * xdim) / 0x10000 - currx;
+ int scaley = (sy + (y + 1) * ydim) / 0x10000 - curry;
+
+ // buffer the tile and rotate it into bitmap
+ if( rot )
+ {
+ fillbitmap( tmpbitmap0, machine->pens[0], &spritetile_clip );
+ fillbitmap( tmpbitmap1, machine->pens[0], &spritetile_clip );
+ drawgfxzoom( tmpbitmap0,machine->gfx[gfx],
+ code++,
+ color,
+ flipx, flipy,
+ 0,0,
+ &spritetile_clip,TRANSPARENCY_PEN,0,
+ (rot & 1 ? scaley : scalex) << 12, (rot & 1 ? scalex : scaley) << 12);
+
+ // peek at the unrotated sprite
+ // copybitmap( bitmap,tmpbitmap0, 0,0, 50+(x * xdim/0x10000),50+(y * ydim/0x10000), cliprect, TRANSPARENCY_PEN, 0 );
+ }
+
+ switch( rot )
+ {
+ case 0x10: // rot 90
+ copyrozbitmap( tmpbitmap1, tmpbitmap0,
+ (UINT32)0<<16,
+ (UINT32)16<<16,
+ 0 << 16,
+ -1 << 16,
+ 1 << 16,
+ 0 << 16,
+ 0, cliprect, TRANSPARENCY_PEN, 0, 0 );
+
+ currx = (sx - (y+1) * ydim) / 0x10000;
+ curry = (sy + x * xdim) / 0x10000;
+
+ copybitmap( bitmap,tmpbitmap1, 0,0, currx,curry, cliprect, TRANSPARENCY_PEN, 0 );
+ break;
+
+ case 0x20: // rot 180
+ copyrozbitmap( tmpbitmap1, tmpbitmap0,
+ (UINT32)16<<16,
+ (UINT32)16<<16,
+ -1 << 16,
+ 0 << 16,
+ 0 << 16,
+ -1 << 16,
+ 0, cliprect, TRANSPARENCY_PEN, 0, 0 );
+
+ currx = (sx - (x+1) * xdim) / 0x10000;
+ curry = (sy - (y+1) * ydim) / 0x10000;
+
+ copybitmap( bitmap,tmpbitmap1, 0,0, currx,curry, cliprect, TRANSPARENCY_PEN, 0 );
+ break;
+
+ case 0x30: // rot 270
+ copyrozbitmap( tmpbitmap1, tmpbitmap0,
+ (UINT32)16<<16,
+ (UINT32)0<<16,
+ 0 << 16,
+ 1 << 16,
+ -1 << 16,
+ 0 << 16,
+ 0, cliprect, TRANSPARENCY_PEN, 0, 0 );
+
+ currx = (sx + y * ydim) / 0x10000;
+ curry = (sy - (x+1) * xdim) / 0x10000;
+
+ copybitmap( bitmap,tmpbitmap1, 0,0, currx,curry, cliprect, TRANSPARENCY_PEN, 0 );
+ break;
+
+ default:
+ drawgfxzoom( bitmap,machine->gfx[gfx],
+ code++,
+ color,
+ flipx, flipy,
+ currx, curry,
+ cliprect,TRANSPARENCY_PEN,0,
+ scalex << 12, scaley << 12);
+ break;
+ }
+
+ }
+ }
+ }
+}
+
+/* DaiDaiKakumei */
+/* layer : 0== bghigh<spr 1== bglow<spr<bghigh 2==spr<bglow 3==boarder */
+static void dai2kaku_draw_sprites( mame_bitmap *bitmap,const rectangle *cliprect, int layer)
+{
+ int offs;
+
+ int max_x = Machine->screen[0].width;
+ int max_y = Machine->screen[0].height;
+
+ for ( offs = 0x3000/2; offs < 0x3600/2; offs += 2/2 )
+ {
+ int sx, sy, dim, zoom, flip, color, attr, code, flipx, flipy, gfx;
+
+ int x, xdim, xnum, xstart, xend, xinc;
+ int y, ydim, ynum, ystart, yend, yinc;
+
+ UINT16 *s;
+
+ if (spriteram16[offs] & 0x8000) continue;
+
+ s = &spriteram16[(spriteram16[offs] & 0x3ff) * 16/2];
+
+ sy = s[ 0 ];
+ sx = s[ 1 ];
+ dim = s[ 2 ];
+ zoom = s[ 3 ];
+ flip = s[ 4 ];
+ color = s[ 5 ];
+ attr = s[ 6 ];
+ code = s[ 7 ];
+
+ if(( flip & 0x03 ) != layer ) continue;
+
+ xnum = ((dim >> 0) & 0x1f) + 1;
+ ynum = ((dim >> 8) & 0x1f) + 1;
+
+ flipx = flip & 0x0100;
+ flipy = flip & 0x0200;
+
+ gfx = (attr & 0x0001) + 2;
+
+ sx = ((sx & 0x1ff) - (sx & 0x200)) << 16;
+ sy = ((sy & 0x0ff) - (sy & 0x100)) << 16;
+
+ xdim = ((zoom & 0x00ff) >> 0) << (16-6+4);
+ ydim = ((zoom & 0xff00) >> 8) << (16-6+4);
+
+ if (flip_screen_x) { flipx = !flipx; sx = (max_x << 16) - sx - xnum * xdim; }
+ if (flip_screen_y) { flipy = !flipy; sy = (max_y << 16) - sy - ynum * ydim; }
+
+ if (flipx) { xstart = xnum-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = xnum; xinc = +1; }
+
+ if (flipy) { ystart = ynum-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = ynum; yinc = +1; }
+
+ for (y = ystart; y != yend; y += yinc)
+ {
+ for (x = xstart; x != xend; x += xinc)
+ {
+ int currx = (sx + x * xdim) / 0x10000;
+ int curry = (sy + y * ydim) / 0x10000;
+
+ int scalex = (sx + (x + 1) * xdim) / 0x10000 - currx;
+ int scaley = (sy + (y + 1) * ydim) / 0x10000 - curry;
+
+ drawgfxzoom( bitmap,Machine->gfx[gfx],
+ code++,
+ color,
+ flipx, flipy,
+ currx, curry,
+ cliprect,TRANSPARENCY_PEN,0,
+ scalex << 12, scaley << 12);
+ }
+ }
+ }
+}
+
+
+/***************************************************************************
+
+ Screen Drawing
+
+ Video Registers:
+
+ Offset: Bits: Value:
+
+ 0.w Background 0 Scroll Y
+
+ 2.w Background 0 Scroll X
+
+ 4.w Background 1 Scroll Y
+
+ 6.w Background 1 Scroll X
+
+ 8.w fedc ba98 ---- ---- ? bit f = flip
+ ---- ---- 7654 3210
+
+ A.w fedc ba98 7--- ----
+ ---- ---- -654 3210 Color codes high bits for the text tilemap
+
+ C.w f--- ---- ---- ----
+ -edc ba98 7654 3210 Index of the background color
+
+***************************************************************************/
+
+WRITE16_HANDLER( realbrk_vregs_w )
+{
+ UINT16 old_data = realbrk_vregs[offset];
+ UINT16 new_data = COMBINE_DATA(&realbrk_vregs[offset]);
+ if (new_data != old_data)
+ {
+ if (offset == 0xa/2)
+ tilemap_mark_all_tiles_dirty(tilemap_0);
+ }
+}
+
+VIDEO_UPDATE(realbrk)
+{
+ int layers_ctrl = -1;
+
+ tilemap_set_scrolly(tilemap_0, 0, realbrk_vregs[0x0/2]);
+ tilemap_set_scrollx(tilemap_0, 0, realbrk_vregs[0x2/2]);
+
+ tilemap_set_scrolly(tilemap_1, 0, realbrk_vregs[0x4/2]);
+ tilemap_set_scrollx(tilemap_1, 0, realbrk_vregs[0x6/2]);
+
+#ifdef MAME_DEBUG
+if ( input_code_pressed(KEYCODE_Z) )
+{ int msk = 0;
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+ if (input_code_pressed(KEYCODE_E)) msk |= 4;
+ if (input_code_pressed(KEYCODE_A)) msk |= 8;
+ if (msk != 0) layers_ctrl &= msk; }
+#endif
+
+ if (disable_video)
+ {
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ return 0;
+ }
+ else
+ fillbitmap(bitmap,machine->pens[realbrk_vregs[0xc/2] & 0x7fff],cliprect);
+
+ if (layers_ctrl & 2) tilemap_draw(bitmap,cliprect,tilemap_1,0,0);
+ if (layers_ctrl & 1) tilemap_draw(bitmap,cliprect,tilemap_0,0,0);
+
+ if (layers_ctrl & 8) draw_sprites(machine,bitmap,cliprect);
+
+ if (layers_ctrl & 4) tilemap_draw(bitmap,cliprect,tilemap_2,0,0);
+
+// popmessage("%04x",realbrk_vregs[0x8/2]);
+ return 0;
+}
+
+/* DaiDaiKakumei */
+VIDEO_UPDATE(dai2kaku)
+{
+ int layers_ctrl = -1;
+ int offs, bgx0, bgy0, bgx1, bgy1;
+
+ bgy0 = realbrk_vregs[0x0/2];
+ bgx0 = realbrk_vregs[0x2/2];
+ bgy1 = realbrk_vregs[0x4/2];
+ bgx1 = realbrk_vregs[0x6/2];
+
+ // bg0
+ tilemap_set_scroll_rows(tilemap_0,512);
+ tilemap_set_scroll_cols(tilemap_0,1);
+ if( realbrk_vregs[8/2] & (0x0100)){
+ for(offs=0; offs<(512); offs++) {
+ tilemap_set_scrollx( tilemap_0, offs, bgx0 - (realbrk_vram_1ras[offs]&0x3ff) );
+ }
+ } else {
+ for(offs=0; offs<(512); offs++) {
+ tilemap_set_scrollx( tilemap_0, offs, bgx0 );
+ }
+ }
+ tilemap_set_scrolly( tilemap_0, 0, bgy0 );
+
+ // bg1
+ tilemap_set_scroll_rows(tilemap_1,512);
+ tilemap_set_scroll_cols(tilemap_1,1);
+ if( realbrk_vregs[8/2] & (0x0001)){
+ for(offs=0; offs<(512); offs++) {
+ tilemap_set_scrollx( tilemap_1, offs, bgx1 - (realbrk_vram_1ras[offs]&0x3ff) );
+ }
+ } else {
+ for(offs=0; offs<(512); offs++) {
+ tilemap_set_scrollx( tilemap_1, offs, bgx1 );
+ }
+ }
+ tilemap_set_scrolly( tilemap_1, 0, bgy1 );
+
+#ifdef MAME_DEBUG
+if ( input_code_pressed(KEYCODE_Z) )
+{ int msk = 0;
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+ if (input_code_pressed(KEYCODE_E)) msk |= 4;
+ if (input_code_pressed(KEYCODE_A)) msk |= 8;
+ if (msk != 0) layers_ctrl &= msk; }
+#endif
+
+ if (disable_video)
+ {
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ return 0;
+ }
+ else
+ fillbitmap(bitmap,machine->pens[realbrk_vregs[0xc/2] & 0x7fff],cliprect);
+
+
+
+ // spr 0
+ if (layers_ctrl & 8) dai2kaku_draw_sprites(bitmap,cliprect,2);
+
+ // bglow
+ if( realbrk_vregs[8/2] & (0x8000)){
+ if (layers_ctrl & 1) tilemap_draw(bitmap,cliprect,tilemap_0,0,0);
+ } else {
+ if (layers_ctrl & 2) tilemap_draw(bitmap,cliprect,tilemap_1,0,0);
+ }
+
+ // spr 1
+ if (layers_ctrl & 8) dai2kaku_draw_sprites(bitmap,cliprect,1);
+
+ // bghigh
+ if( realbrk_vregs[8/2] & (0x8000)){
+ if (layers_ctrl & 2) tilemap_draw(bitmap,cliprect,tilemap_1,0,0);
+ } else {
+ if (layers_ctrl & 1) tilemap_draw(bitmap,cliprect,tilemap_0,0,0);
+ }
+
+ // spr 2
+ if (layers_ctrl & 8) dai2kaku_draw_sprites(bitmap,cliprect,0);
+
+ // fix
+ if (layers_ctrl & 4) tilemap_draw(bitmap,cliprect,tilemap_2,0,0);
+
+// usrintf_showmessage("%04x",realbrk_vregs[0x8/2]);
+ return 0;
+}
diff --git a/src/mame/video/redalert.c b/src/mame/video/redalert.c
new file mode 100644
index 00000000000..f02522a3f25
--- /dev/null
+++ b/src/mame/video/redalert.c
@@ -0,0 +1,304 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *redalert_backram;
+UINT8 *redalert_spriteram1;
+UINT8 *redalert_spriteram2;
+UINT8 *redalert_spriteram3;
+UINT8 *redalert_characterram;
+UINT8 *redalert_characterram2;
+
+static UINT8 redalert_dirtyback[0x400];
+static UINT8 redalert_dirtycharacter[0x100];
+static UINT8 redalert_dirtycharacter2[0x100];
+static UINT8 redalert_backcolor[0x400];
+
+
+/* There might be a color PROM that dictates this? */
+/* These guesses are based on comparing the color bars on the test
+ screen with the picture in the manual */
+static UINT8 color_lookup[] = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,
+ 1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+ 1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
+};
+
+static int backcolor, flip=0;
+
+WRITE8_HANDLER( redalert_c040_w )
+{
+ /* Only seems to load D0-D3 into a flip-flop. */
+ /* D0/D1 seem to head off to unconnected circuits */
+ /* D2 connects to a "NL" line, and NOTted to a "NH" line */
+ /* D3 connects to a "YI" line */
+
+ /*
+ D0 == 1 -> 1 player
+ D1 == 1 and D0 == 1 -> 2 players
+ */
+ flip = !(data & 0x04);
+}
+
+WRITE8_HANDLER( redalert_backcolor_w )
+{
+ /* Only seems to load D0-D2 into a flip-flop. */
+ /* Outputs feed into RAM which seems to feed to RGB lines. */
+ backcolor = data & 0x07;
+}
+
+WRITE8_HANDLER( demoneye_c040_w )
+{
+ /*
+ D0 == 1 -> 1 player
+ D1 == 1 and D0 == 1 -> 2 players
+ */
+ flip = data & 0x04;
+}
+
+/***************************************************************************
+redalert_backram_w
+***************************************************************************/
+
+WRITE8_HANDLER( redalert_backram_w )
+{
+ int charnum;
+
+ charnum = offset / 8 % 0x400;
+
+ if ((redalert_backram[offset] != data) ||
+ (redalert_backcolor[charnum] != backcolor))
+ {
+ redalert_dirtyback[charnum] = 1;
+ dirtybuffer[charnum] = 1;
+ redalert_backcolor[charnum] = backcolor;
+
+ redalert_backram[offset] = data;
+ }
+}
+
+/***************************************************************************
+redalert_spriteram1_w
+***************************************************************************/
+
+WRITE8_HANDLER( redalert_spriteram1_w )
+{
+ if (redalert_spriteram1[offset] != data)
+ {
+ redalert_dirtycharacter[((offset / 8) % 0x80) + 0x80] = 1;
+
+ redalert_spriteram1[offset] = data;
+ }
+}
+
+/***************************************************************************
+redalert_spriteram2_w
+***************************************************************************/
+
+WRITE8_HANDLER( redalert_spriteram2_w )
+{
+ if (redalert_spriteram2[offset] != data)
+ {
+
+ redalert_dirtycharacter[((offset / 8) % 0x80) + 0x80] = 1;
+
+ redalert_spriteram2[offset] = data;
+ }
+}
+
+/***************************************************************************
+redalert_characterram_w
+***************************************************************************/
+
+WRITE8_HANDLER( redalert_characterram_w )
+{
+ if (redalert_characterram[offset] != data)
+ {
+ redalert_dirtycharacter[((offset / 8) % 0x80)] = 1;
+
+ redalert_characterram[offset] = data;
+ }
+}
+
+WRITE8_HANDLER( redalert_characterram2_w )
+{
+ if (redalert_characterram2[offset] != data)
+ {
+ redalert_dirtycharacter[((offset / 8) % 0x80)] = 1;
+
+ redalert_characterram2[offset] = data;
+ }
+}
+
+WRITE8_HANDLER( redalert_spriteram3_w )
+{
+ if (redalert_spriteram3[offset] != data)
+ {
+ redalert_dirtycharacter2[((offset / 8) % 0x80) + 0x80] = 1;
+
+ redalert_spriteram3[offset] = data;
+ }
+
+}
+
+
+VIDEO_UPDATE( redalert )
+{
+ int offs,i;
+
+ /* for every character in the Video RAM, check if it has been modified */
+ /* since last time and update it accordingly. */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int charcode;
+ int stat_transparent;
+
+
+ charcode = videoram[offs];
+
+ if (dirtybuffer[offs] || redalert_dirtycharacter[charcode] || redalert_dirtycharacter2[charcode])
+ {
+ int sx,sy,color;
+
+
+ /* decode modified background */
+ if (redalert_dirtyback[offs] == 1)
+ {
+ decodechar(machine->gfx[0],offs,redalert_backram,
+ machine->drv->gfxdecodeinfo[0].gfxlayout);
+ redalert_dirtyback[offs] = 2;
+ }
+
+ /* decode modified characters */
+ if (redalert_dirtycharacter[charcode] == 1)
+ {
+ if (charcode < 0x80)
+ decodechar(machine->gfx[1],charcode,redalert_characterram,
+ machine->drv->gfxdecodeinfo[1].gfxlayout);
+ else
+ decodechar(machine->gfx[2],charcode-0x80,redalert_spriteram1,
+ machine->drv->gfxdecodeinfo[2].gfxlayout);
+ redalert_dirtycharacter[charcode] = 2;
+ }
+
+ if (redalert_dirtycharacter2[charcode] == 1)
+ {
+ decodechar(machine->gfx[3],charcode-0x80,redalert_spriteram3,
+ machine->drv->gfxdecodeinfo[3].gfxlayout);
+ redalert_dirtycharacter2[charcode] = 2;
+ }
+
+ dirtybuffer[offs] = 0;
+
+ sx = 31 - offs / 32;
+ sy = offs % 32;
+
+ stat_transparent = TRANSPARENCY_NONE;
+
+ /* First layer of color */
+ if (charcode >= 0xC0)
+ {
+ stat_transparent = TRANSPARENCY_COLOR;
+
+ color = color_lookup[charcode];
+
+ drawgfx(tmpbitmap,machine->gfx[2],
+ charcode-0x80,
+ color,
+ 0,0,
+ 8*sx,8*sy,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+
+ if( redalert_dirtycharacter2[charcode] != 0 )
+ drawgfx(tmpbitmap,machine->gfx[3],
+ charcode-0x80,
+ color,
+ 0,0,
+ 8*sx,8*sy,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+
+ }
+
+ /* Second layer - background */
+ color = redalert_backcolor[offs];
+ drawgfx(tmpbitmap,machine->gfx[0],
+ offs,
+ color,
+ 0,0,
+ 8*sx,8*sy,
+ &machine->screen[0].visarea,stat_transparent,0);
+
+ /* Third layer - alphanumerics & sprites */
+ if (charcode < 0x80)
+ {
+ color = color_lookup[charcode];
+ drawgfx(tmpbitmap,machine->gfx[1],
+ charcode,
+ color,
+ 0,0,
+ 8*sx,8*sy,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+ }
+ else if (charcode < 0xC0)
+ {
+ color = color_lookup[charcode];
+ drawgfx(tmpbitmap,machine->gfx[2],
+ charcode-0x80,
+ color,
+ 0,0,
+ 8*sx,8*sy,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+
+ if( redalert_dirtycharacter2[charcode] != 0 )
+ drawgfx(tmpbitmap,machine->gfx[3],
+ charcode-0x80,
+ color,
+ 0,0,
+ 8*sx,8*sy,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+
+ }
+
+ }
+ }
+
+ for (i = 0;i < 256;i++)
+ {
+ if (redalert_dirtycharacter[i] == 2)
+ redalert_dirtycharacter[i] = 0;
+
+ if (redalert_dirtycharacter2[i] == 2)
+ redalert_dirtycharacter2[i] = 0;
+ }
+
+ for (i = 0;i < 0x400;i++)
+ {
+ if (redalert_dirtyback[i] == 2)
+ redalert_dirtyback[i] = 0;
+ }
+
+ /* copy the character mapped graphics */
+ copybitmap(bitmap,tmpbitmap,flip,flip,0,0,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+
+ return 0;
+}
diff --git a/src/mame/video/redclash.c b/src/mame/video/redclash.c
new file mode 100644
index 00000000000..9bdc16912d6
--- /dev/null
+++ b/src/mame/video/redclash.c
@@ -0,0 +1,417 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static int star_speed;
+static int gfxbank;
+
+static tilemap *fg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ I'm using the same palette conversion as Lady Bug, but the Zero Hour
+ schematics show a different resistor network.
+
+***************************************************************************/
+PALETTE_INIT( redclash )
+{
+ int i;
+
+ for (i = 0;i < 32;i++)
+ {
+ int bit1,bit2,r,g,b;
+
+
+ bit1 = (color_prom[i] >> 0) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ r = 0x47 * bit1 + 0x97 * bit2;
+ bit1 = (color_prom[i] >> 2) & 0x01;
+ bit2 = (color_prom[i] >> 6) & 0x01;
+ g = 0x47 * bit1 + 0x97 * bit2;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x47 * bit1 + 0x97 * bit2;
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ /* This is for the stars colors */
+ for (i = 32;i < 64;i++)
+ {
+ int bit1,bit2,r,g,b;
+
+ bit2 = (i >> 4) & 0x01;
+ bit1 = (i >> 3) & 0x01;
+ b = 0x47 * bit1 + 0x97 * bit2;
+ bit2 = (i >> 2) & 0x01;
+ bit1 = (i >> 1) & 0x01;
+ g = 0x47 * bit1 + 0x97 * bit2;
+ bit1 = i & 0x01;
+ r = 0x47 * bit1;
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ /* characters */
+ for (i = 0;i < 8;i++)
+ {
+ colortable[4 * i] = 0;
+ colortable[4 * i + 1] = i + 0x08;
+ colortable[4 * i + 2] = i + 0x10;
+ colortable[4 * i + 3] = i + 0x18;
+ }
+
+ /* sprites */
+ for (i = 0;i < 4 * 8;i++)
+ {
+ int bit0,bit1,bit2,bit3;
+
+
+ /* low 4 bits are for sprite n */
+ bit0 = (color_prom[i + 32] >> 3) & 0x01;
+ bit1 = (color_prom[i + 32] >> 2) & 0x01;
+ bit2 = (color_prom[i + 32] >> 1) & 0x01;
+ bit3 = (color_prom[i + 32] >> 0) & 0x01;
+ colortable[i + 4 * 8] = 1 * bit0 + 2 * bit1 + 4 * bit2 + 8 * bit3;
+
+ /* high 4 bits are for sprite n + 8 */
+ bit0 = (color_prom[i + 32] >> 7) & 0x01;
+ bit1 = (color_prom[i + 32] >> 6) & 0x01;
+ bit2 = (color_prom[i + 32] >> 5) & 0x01;
+ bit3 = (color_prom[i + 32] >> 4) & 0x01;
+ colortable[i + 4 * 16] = 1 * bit0 + 2 * bit1 + 4 * bit2 + 8 * bit3;
+ }
+}
+
+WRITE8_HANDLER( redclash_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( redclash_gfxbank_w )
+{
+ if (gfxbank != (data & 0x01))
+ {
+ gfxbank = data & 0x01;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( redclash_flipscreen_w )
+{
+ flip_screen_set(data & 0x01);
+}
+
+void redclash_set_stars_enable( UINT8 on ); //temp
+void redclash_set_stars_speed( UINT8 speed ); //temp
+
+/*
+star_speed:
+0 = unused
+1 = unused
+2 = forward fast
+3 = forward medium
+4 = forward slow
+5 = backwards slow
+6 = backwards medium
+7 = backwards fast
+*/
+WRITE8_HANDLER( redclash_star0_w )
+{
+ star_speed = (star_speed & ~1) | ((data & 1) << 0);
+ redclash_set_stars_speed(star_speed);
+}
+
+WRITE8_HANDLER( redclash_star1_w )
+{
+ star_speed = (star_speed & ~2) | ((data & 1) << 1);
+ redclash_set_stars_speed(star_speed);
+}
+WRITE8_HANDLER( redclash_star2_w )
+{
+ star_speed = (star_speed & ~4) | ((data & 1) << 2);
+ redclash_set_stars_speed(star_speed);
+}
+WRITE8_HANDLER( redclash_star_reset_w )
+{
+ redclash_set_stars_enable(1);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = videoram[tile_index];
+ int color = (videoram[tile_index] & 0x70) >> 4; // ??
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( redclash )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int i, offs;
+
+ for (offs = spriteram_size - 0x20;offs >= 0;offs -= 0x20)
+ {
+ i = 0;
+ while (i < 0x20 && spriteram[offs + i] != 0)
+ i += 4;
+
+ while (i > 0)
+ {
+ i -= 4;
+
+ if (spriteram[offs + i] & 0x80)
+ {
+ int color = spriteram[offs + i + 2] & 0x0f;
+ int sx = spriteram[offs + i + 3];
+ int sy = offs / 4 + (spriteram[offs + i] & 0x07);
+
+
+ switch ((spriteram[offs + i] & 0x18) >> 3)
+ {
+ case 3: /* 24x24 */
+ {
+ int code = ((spriteram[offs + i + 1] & 0xf0) >> 4) + ((gfxbank & 1) << 4);
+
+ drawgfx(bitmap,machine->gfx[3],
+ code,
+ color,
+ 0,0,
+ sx,sy - 16,
+ cliprect,TRANSPARENCY_PEN,0);
+ /* wraparound */
+ drawgfx(bitmap,machine->gfx[3],
+ code,
+ color,
+ 0,0,
+ sx - 256,sy - 16,
+ cliprect,TRANSPARENCY_PEN,0);
+ break;
+ }
+
+ case 2: /* 16x16 */
+ if (spriteram[offs + i] & 0x20) /* zero hour spaceships */
+ {
+ int code = ((spriteram[offs + i + 1] & 0xf8) >> 3) + ((gfxbank & 1) << 5);
+ int bank = (spriteram[offs + i + 1] & 0x02) >> 1;
+
+ drawgfx(bitmap,machine->gfx[4+bank],
+ code,
+ color,
+ 0,0,
+ sx,sy - 16,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ int code = ((spriteram[offs + i + 1] & 0xf0) >> 4) + ((gfxbank & 1) << 4);
+
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ color,
+ 0,0,
+ sx,sy - 16,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ break;
+
+ case 1: /* 8x8 */
+ drawgfx(bitmap,machine->gfx[1],
+ spriteram[offs + i + 1],// + 4 * (spriteram[offs + i + 2] & 0x10),
+ color,
+ 0,0,
+ sx,sy - 16,
+ cliprect,TRANSPARENCY_PEN,0);
+ break;
+
+ case 0:
+popmessage("unknown sprite size 0");
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void draw_bullets(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = 0; offs < 0x20; offs++)
+ {
+// sx = videoram[offs];
+ int sx = 8 * offs + (videoram[offs] & 0x07); /* ?? */
+ int sy = 0xff - videoram[offs + 0x20];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ }
+
+ if (sx >= cliprect->min_x && sx <= cliprect->max_x &&
+ sy >= cliprect->min_y && sy <= cliprect->max_y)
+ *BITMAP_ADDR16(bitmap, sy, sx) = machine->pens[0x0e];
+ }
+}
+
+/*
+ * These functions emulate the star generator board
+ * All this comes from the schematics for Zero Hour
+ *
+ * It has a 17-bit LFSR which has a period of 2^17-1 clocks
+ * (This is one pixel shy of "two screens" worth.)
+ * So, there are two starfields drawn on alternate frames
+ * These will scroll at a rate controlled by the speed register
+ *
+ * I'm basically doing the same thing by drawing each
+ * starfield on alternate frames, and then offseting them
+ */
+
+static UINT8 stars_enable = 0;
+static UINT8 stars_speed = 0;
+static UINT32 stars_state = 0;
+static UINT16 stars_offset = 0;
+
+/* This line can reset the LFSR to zero and disables the star generator */
+void redclash_set_stars_enable( UINT8 on )
+{
+ if ((stars_enable == 0) && (on == 1))
+ {
+ stars_offset = 0;
+ }
+ stars_enable = on;
+}
+
+/* This sets up which starfield to draw and the offset, */
+/* To be called from VIDEO_EOF() */
+
+void redclash_update_stars_state(void)
+{
+ static UINT8 count = 0;
+
+ if (stars_enable == 0)
+ return;
+
+ count++;
+ count%=2;
+
+ if (count == 0)
+ {
+ stars_offset += ((stars_speed*2) - 0x09);
+ stars_offset %= 256*256;
+ stars_state = 0;
+ }
+ else
+ {
+ stars_state = 0x1fc71;
+ }
+}
+
+/* Set the speed register (3 bits) */
+
+/*
+ * 0 left/down fastest (-9/2 pix per frame)
+ * 1 left/down faster (-7/2 pix per frame)
+ * 2 left/down fast (-5/2 pix per frame)
+ * 3 left/down medium (-3/2 pix per frame)
+ * 4 left/down slow (-1/2 pix per frame)
+ * 5 right/up slow (+1/2 pix per frame)
+ * 6 right/up medium (+3/2 pix per frame)
+ * 7 right/up fast (+5/2 pix per frame)
+ */
+
+void redclash_set_stars_speed( UINT8 speed )
+{
+ stars_speed = speed;
+}
+
+/* Draw the stars */
+
+/* Space Raider doesn't use the Va bit, and it is also set up to */
+/* window the stars to a certain x range */
+
+void redclash_draw_stars(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8 palette_offset, UINT8 sraider, UINT8 firstx, UINT8 lastx)
+{
+ int i;
+ UINT8 tempbit, feedback, star_color, xloc, yloc;
+ UINT32 state;
+ UINT8 hcond,vcond;
+
+ if (stars_enable == 0)
+ return;
+
+ state = stars_state;
+
+ for(i=0;i<256*256;i++)
+ {
+ xloc = (stars_offset+i)%256;
+ yloc = ((stars_offset+i)/256)%256;
+
+ if ((state & 0x10000) == 0)
+ tempbit = 1;
+ else
+ tempbit = 0;
+ if ((state & 0x00020) != 0)
+ feedback = tempbit ^ 1;
+ else
+ feedback = tempbit ^ 0;
+
+ hcond = ((xloc+8) & 0x10) >> 4;
+
+ // sraider doesn't have Va hooked up
+ if (sraider)
+ vcond = 1;
+ else
+ vcond = yloc & 0x01;
+
+ if (xloc >= cliprect->min_x && xloc <= cliprect->max_x &&
+ yloc >= cliprect->min_y && yloc <= cliprect->max_y)
+ {
+ if ((hcond ^ vcond) == 0)
+ {
+ /* enable condition */
+ if (((state & 0x000ff) == 0x000ff) && (feedback == 0))
+ {
+ /* used by space raider */
+ if ((xloc>=firstx) && (xloc<=lastx))
+ {
+ star_color = (state >> 9) & 0x1f;
+ *BITMAP_ADDR16(bitmap, yloc, xloc) = machine->pens[palette_offset+star_color];
+ }
+ }
+ }
+ }
+
+ /* update LFSR state */
+ state = ((state<<1) & 0x1fffe) | feedback;
+ }
+}
+
+VIDEO_EOF( redclash )
+{
+ redclash_update_stars_state();
+}
+
+VIDEO_UPDATE( redclash )
+{
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ redclash_draw_stars(machine, bitmap, cliprect, 32, 0, 0x00, 0xff);
+ draw_sprites(machine, bitmap, cliprect);
+ draw_bullets(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/relief.c b/src/mame/video/relief.c
new file mode 100644
index 00000000000..ca81d6961b2
--- /dev/null
+++ b/src/mame/video/relief.c
@@ -0,0 +1,173 @@
+/***************************************************************************
+
+ Atari "Round" hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "relief.h"
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data1 = atarigen_playfield[tile_index];
+ UINT16 data2 = atarigen_playfield_upper[tile_index] & 0xff;
+ int code = data1 & 0x7fff;
+ int color = 0x20 + (data2 & 0x0f);
+ SET_TILE_INFO(0, code, color, (data1 >> 15) & 1);
+}
+
+
+static TILE_GET_INFO( get_playfield2_tile_info )
+{
+ UINT16 data1 = atarigen_playfield2[tile_index];
+ UINT16 data2 = atarigen_playfield_upper[tile_index] >> 8;
+ int code = data1 & 0x7fff;
+ int color = data2 & 0x0f;
+ SET_TILE_INFO(0, code, color, (data1 >> 15) & 1);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( relief )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 1, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 8, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x100, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0x00ff,0,0,0 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0,0x7fff,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0x000f,0 }}, /* mask for the color */
+ {{ 0,0,0xff80,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xff80 }}, /* mask for the Y position */
+ {{ 0,0,0,0x0070 }}, /* mask for the width, in tiles*/
+ {{ 0,0,0,0x0007 }}, /* mask for the height, in tiles */
+ {{ 0,0x8000,0,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0 /* callback routine for special entries */
+ };
+
+ /* blend the MO graphics */
+ atarigen_blend_gfx(machine, 1, 2, 0x0f, 0x10);
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8,8, 64,64);
+
+ /* initialize the second playfield */
+ atarigen_playfield2_tilemap = tilemap_create(get_playfield2_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8,8, 64,64);
+ tilemap_set_transparent_pen(atarigen_playfield2_tilemap, 0);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( relief )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ fillbitmap(priority_bitmap, 0, cliprect);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield2_tilemap, 0, 1);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ UINT8 *pri = (UINT8 *)priority_bitmap->base + priority_bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* verified from the GALs on the real PCB; equations follow
+ *
+ * --- PF/M is 1 if playfield has priority, or 0 if MOs have priority
+ * PF/M = PFXS
+ *
+ * --- CS0 is set to 1 if the MO is transparent
+ * CS0=!MPX0*!MPX1*!MPX2*!MPX3
+ *
+ * --- CS1 is 1 to select playfield pixels or 0 to select MO pixels
+ * !CS1=MPX5*MPX6*MPX7*!CS0
+ * +!MPX4*MPX5*MPX6*MPX7
+ * +PFXS*!CS0
+ * +!MPX4*PFXS
+ *
+ * --- CRA10 is the 0x200 bit of the color RAM index; set for the top playfield only
+ * CRA10:=CS1*PFXS
+ *
+ * --- CRA9 is the 0x100 bit of the color RAM index; set for MOs only
+ * !CA9:=CS1
+ *
+ * --- CRA8-1 are the low 8 bits of the color RAM index; set as expected
+ */
+ int cs0 = 0;
+ int cs1 = 1;
+
+ /* compute the CS0 signal */
+ cs0 = ((mo[x] & 0x0f) == 0);
+
+ /* compute the CS1 signal */
+ if ((!cs0 && (mo[x] & 0xe0) == 0xe0) ||
+ ((mo[x] & 0xf0) == 0xe0) ||
+ (!pri[x] && !cs0) ||
+ (!pri[x] && !(mo[x] & 0x10)))
+ cs1 = 0;
+
+ /* MO is displayed if cs1 == 0 */
+ if (!cs1)
+ pf[x] = mo[x];
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/renegade.c b/src/mame/video/renegade.c
new file mode 100644
index 00000000000..156f7d4e078
--- /dev/null
+++ b/src/mame/video/renegade.c
@@ -0,0 +1,143 @@
+/***************************************************************************
+
+ Renegade Video Hardware
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *renegade_videoram2;
+static INT32 renegade_scrollx;
+static tilemap *bg_tilemap;
+static tilemap *fg_tilemap;
+
+WRITE8_HANDLER( renegade_videoram_w )
+{
+ videoram[offset] = data;
+ offset = offset % (64 * 16);
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( renegade_videoram2_w )
+{
+ renegade_videoram2[offset] = data;
+ offset = offset % (32 * 32);
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( renegade_flipscreen_w )
+{
+ flip_screen_set(~data & 0x01);
+}
+
+WRITE8_HANDLER( renegade_scroll0_w )
+{
+ renegade_scrollx = (renegade_scrollx & 0xff00) | data;
+}
+
+WRITE8_HANDLER( renegade_scroll1_w )
+{
+ renegade_scrollx = (renegade_scrollx & 0xff) | (data << 8);
+}
+
+static TILE_GET_INFO( get_bg_tilemap_info )
+{
+ const UINT8 *source = &videoram[tile_index];
+ UINT8 attributes = source[0x400]; /* CCC??BBB */
+ SET_TILE_INFO(
+ 1 + (attributes & 0x7),
+ source[0],
+ attributes >> 5,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tilemap_info )
+{
+ const UINT8 *source = &renegade_videoram2[tile_index];
+ UINT8 attributes = source[0x400];
+ SET_TILE_INFO(
+ 0,
+ (attributes & 3) * 256 + source[0],
+ attributes >> 6,
+ 0);
+}
+
+static void all_tiles_dirty(void)
+{
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ tilemap_mark_all_tiles_dirty(fg_tilemap);
+}
+
+VIDEO_START( renegade )
+{
+ bg_tilemap = tilemap_create(get_bg_tilemap_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 64, 16);
+ fg_tilemap = tilemap_create(get_fg_tilemap_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+ tilemap_set_scrolldx(bg_tilemap, 256, 0);
+
+ state_save_register_global(renegade_scrollx);
+ state_save_register_func_postload(all_tiles_dirty);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 *source = spriteram;
+ UINT8 *finish = source + 96 * 4;
+
+ while (source < finish)
+ {
+ int sy = 240 - source[0];
+
+ if (sy >= 16)
+ {
+ int attributes = source[1]; /* SFCCBBBB */
+ int sx = source[3];
+ int sprite_number = source[2];
+ int sprite_bank = 9 + (attributes & 0xf);
+ int color = (attributes >> 4) & 0x3;
+ int xflip = attributes & 0x40;
+
+ if (sx > 248)
+ sx -= 256;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ xflip = !xflip;
+ }
+
+ if (attributes & 0x80) /* big sprite */
+ {
+ sprite_number &= ~1;
+ drawgfx(bitmap, machine->gfx[sprite_bank],
+ sprite_number + 1,
+ color,
+ xflip, flip_screen,
+ sx, sy + (flip_screen ? -16 : 16),
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+ else
+ {
+ sy += (flip_screen ? -16 : 16);
+ }
+ drawgfx(bitmap, machine->gfx[sprite_bank],
+ sprite_number,
+ color,
+ xflip, flip_screen,
+ sx, sy,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+ source += 4;
+ }
+}
+
+VIDEO_UPDATE( renegade )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, renegade_scrollx);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0 , 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0 , 0);
+ return 0;
+}
diff --git a/src/mame/video/retofinv.c b/src/mame/video/retofinv.c
new file mode 100644
index 00000000000..5bb7c21df11
--- /dev/null
+++ b/src/mame/video/retofinv.c
@@ -0,0 +1,247 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *retofinv_bg_videoram;
+UINT8 *retofinv_fg_videoram;
+UINT8 *retofinv_sharedram;
+
+static int fg_bank,bg_bank;
+static tilemap *bg_tilemap,*fg_tilemap;
+
+
+
+PALETTE_INIT( retofinv )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ bit0 = (color_prom[i + 0*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[i + 0*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[i + 0*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[i + 0*machine->drv->total_colors] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[i + 1*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[i + 1*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[i + 1*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[i + 1*machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ bit0 = (color_prom[i + 2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[i + 2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[i + 2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[i + 2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ color_prom += 3*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* fg chars (1bpp) */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ {
+ if (i % 2)
+ COLOR(0,i) = i/2;
+ else
+ COLOR(0,i) = 0;
+ }
+
+ /* sprites */
+ for(i = 0;i < TOTAL_COLORS(2);i++)
+ COLOR(2,i) = BITSWAP8(color_prom[i],4,5,6,7,3,2,1,0);
+
+ /* bg tiles */
+ for(i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = BITSWAP8(color_prom[TOTAL_COLORS(2) + i],4,5,6,7,3,2,1,0);
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/* convert from 32x32 to 36x28 */
+static TILEMAP_MAPPER( tilemap_scan )
+{
+ row += 2;
+ col -= 2;
+ if (col & 0x20)
+ return ((col & 0x1f) << 5) + row;
+ else
+ return (row << 5) + col;
+}
+
+static TILE_GET_INFO( bg_get_tile_info )
+{
+ SET_TILE_INFO(
+ 1,
+ retofinv_bg_videoram[tile_index] + 256 * bg_bank,
+ retofinv_bg_videoram[0x400 + tile_index] & 0x3f,
+ 0);
+}
+
+static TILE_GET_INFO( fg_get_tile_info )
+{
+ /* not sure about the transparency thing, but it makes sense */
+ SET_TILE_INFO(
+ 0,
+ retofinv_fg_videoram[tile_index] + 256 * fg_bank,
+ retofinv_fg_videoram[0x400 + tile_index],
+ (tile_index < 0x40 || tile_index >= 0x3c0) ? TILE_FORCE_LAYER0 : 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( retofinv )
+{
+ bg_tilemap = tilemap_create(bg_get_tile_info,tilemap_scan,TILEMAP_TYPE_PEN,8,8,36,28);
+ fg_tilemap = tilemap_create(fg_get_tile_info,tilemap_scan,TILEMAP_TYPE_COLORTABLE,8,8,36,28);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ spriteram = retofinv_sharedram + 0x0780;
+ spriteram_2 = retofinv_sharedram + 0x0f80;
+ spriteram_3 = retofinv_sharedram + 0x1780;
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( retofinv_bg_videoram_w )
+{
+ retofinv_bg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( retofinv_fg_videoram_w )
+{
+ retofinv_fg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( retofinv_gfx_ctrl_w )
+{
+ switch (offset)
+ {
+ case 0:
+ flip_screen_set(data & 1);
+ break;
+
+ case 1:
+ if (fg_bank != (data & 1))
+ {
+ fg_bank = data & 1;
+ tilemap_mark_all_tiles_dirty(fg_tilemap);
+ }
+ break;
+
+ case 2:
+ if (bg_bank != (data & 1))
+ {
+ bg_bank = data & 1;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap)
+{
+ int offs;
+ static rectangle spritevisiblearea =
+ {
+ 2*8, 34*8-1,
+ 0*8, 28*8-1
+ };
+
+ for (offs = 0;offs < 0x80;offs += 2)
+ {
+ static int gfx_offs[2][2] =
+ {
+ { 0, 1 },
+ { 2, 3 }
+ };
+ int sprite = spriteram[offs];
+ int color = spriteram[offs+1] & 0x3f;
+ int sx = ((spriteram_2[offs+1] << 1) + ((spriteram_3[offs+1] & 0x80) >> 7)) - 39;
+ int sy = 256 - ((spriteram_2[offs] << 1) + ((spriteram_3[offs] & 0x80) >> 7)) + 1;
+ /* not sure about the flipping, it's hardly ever used (mostly for shots) */
+ int flipx = (spriteram_3[offs] & 0x01);
+ int flipy = (spriteram_3[offs] & 0x02) >> 1;
+ int sizey = (spriteram_3[offs] & 0x04) >> 2;
+ int sizex = (spriteram_3[offs] & 0x08) >> 3;
+ int x,y;
+
+ sprite &= ~sizex;
+ sprite &= ~(sizey << 1);
+
+ if (flip_screen)
+ {
+ flipx ^= 1;
+ flipy ^= 1;
+ }
+
+ sy -= 16 * sizey;
+ sy = (sy & 0xff) - 32; // fix wraparound
+
+ for (y = 0;y <= sizey;y++)
+ {
+ for (x = 0;x <= sizex;x++)
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ sprite + gfx_offs[y ^ (sizey * flipy)][x ^ (sizex * flipx)],
+ color,
+ flipx,flipy,
+ sx + 16*x,sy + 16*y,
+ &spritevisiblearea,TRANSPARENCY_COLOR,0xff);
+ }
+ }
+ }
+}
+
+
+
+VIDEO_UPDATE( retofinv )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/rockola.c b/src/mame/video/rockola.c
new file mode 100644
index 00000000000..1f34917b6a9
--- /dev/null
+++ b/src/mame/video/rockola.c
@@ -0,0 +1,310 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *rockola_videoram2;
+UINT8 *rockola_charram;
+
+static int charbank;
+static int backcolor;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+static rgb_t palette[64];
+
+#define TOTAL_COLORS(gfxn) (Machine->gfx[gfxn]->total_colors * Machine->gfx[gfxn]->color_granularity)
+#define COLOR(gfxn,offs) (Machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs)
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Zarzon has a different PROM layout from the others.
+
+***************************************************************************/
+PALETTE_INIT( rockola )
+{
+ int i;
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ /* red component */
+
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* green component */
+
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* blue component */
+
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette[i] = MAKE_RGB(r, g, b);
+
+ color_prom++;
+ }
+
+ backcolor = 0; /* background color can be changed by the game */
+
+ for (i = 0; i < TOTAL_COLORS(0); i++)
+ palette_set_color(machine, COLOR(0, i), palette[i]);
+
+ for (i = 0; i < TOTAL_COLORS(1); i++)
+ {
+ if (i % 4 == 0)
+ palette_set_color(machine, COLOR(1, i), palette[4 * backcolor + 0x20]);
+ else
+ palette_set_color(machine, COLOR(1, i), palette[i + 0x20]);
+ }
+}
+
+WRITE8_HANDLER( rockola_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( rockola_videoram2_w )
+{
+ rockola_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( rockola_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( rockola_charram_w )
+{
+ if (rockola_charram[offset] != data)
+ {
+ rockola_charram[offset] = data;
+ tilemap_mark_all_tiles_dirty(fg_tilemap);
+ }
+}
+
+WRITE8_HANDLER( rockola_flipscreen_w )
+{
+ int bank;
+
+ /* bits 0-2 select background color */
+
+ if (backcolor != (data & 7))
+ {
+ int i;
+
+ backcolor = data & 7;
+
+ for (i = 0;i < 32;i += 4)
+ palette_set_color(Machine, COLOR(1, i), palette[4 * backcolor + 0x20]);
+ }
+
+ /* bit 3 selects char bank */
+
+ bank = (~data & 0x08) >> 3;
+
+ if (charbank != bank)
+ {
+ charbank = bank;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ /* bit 7 flips screen */
+
+ if (flip_screen != (data & 0x80))
+ {
+ flip_screen_set(data & 0x80);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( rockola_scrollx_w )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, data);
+}
+
+WRITE8_HANDLER( rockola_scrolly_w )
+{
+ tilemap_set_scrolly(bg_tilemap, 0, data);
+}
+
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + 256 * charbank;
+ int color = (colorram[tile_index] & 0x38) >> 3;
+
+ SET_TILE_INFO(1, code, color, 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = rockola_videoram2[tile_index];
+ int color = colorram[tile_index] & 0x07;
+
+ decodechar(machine->gfx[0], code, rockola_charram,
+ machine->drv->gfxdecodeinfo[0].gfxlayout);
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( rockola )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+VIDEO_UPDATE( rockola )
+{
+ tilemap_draw(bitmap, &machine->screen[0].visarea, bg_tilemap, 0, 0);
+ tilemap_draw(bitmap, &machine->screen[0].visarea, fg_tilemap, 0, 0);
+ return 0;
+}
+
+/* Satan of Saturn */
+
+PALETTE_INIT( satansat )
+{
+ int i;
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ /* red component */
+
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* green component */
+
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* blue component */
+
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette[i] = MAKE_RGB(r, g, b);
+
+ color_prom++;
+ }
+
+ backcolor = 0; /* background color can be changed by the game */
+
+ for (i = 0; i < TOTAL_COLORS(0); i++)
+ palette_set_color(machine, COLOR(0, i), palette[4 * (i % 4) + (i / 4)]);
+
+ for (i = 0; i < TOTAL_COLORS(1); i++)
+ {
+ if (i % 4 == 0)
+ palette_set_color(machine, COLOR(1, i), palette[backcolor + 0x10]);
+ else
+ palette_set_color(machine, COLOR(1, i), palette[4 * (i % 4) + (i / 4) + 0x10]);
+ }
+}
+
+WRITE8_HANDLER( satansat_b002_w )
+{
+ /* bit 0 flips screen */
+
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ /* bit 1 enables interrups */
+ /* it controls only IRQs, not NMIs. Here I am affecting both, which */
+ /* is wrong. */
+
+ interrupt_enable_w(0,data & 0x02);
+
+ /* other bits unused */
+}
+
+WRITE8_HANDLER( satansat_backcolor_w )
+{
+ /* bits 0-1 select background color. Other bits unused. */
+
+ if (backcolor != (data & 0x03))
+ {
+ int i;
+
+ backcolor = data & 0x03;
+
+ for (i = 0; i < 16; i += 4)
+ palette_set_color(Machine, COLOR(1, i), palette[backcolor + 0x10]);
+ }
+}
+
+static TILE_GET_INFO( satansat_get_bg_tile_info )
+{
+ int code = videoram[tile_index];
+ int color = (colorram[tile_index] & 0x0c) >> 2;
+
+ SET_TILE_INFO(1, code, color, 0);
+}
+
+static TILE_GET_INFO( satansat_get_fg_tile_info )
+{
+ int code = rockola_videoram2[tile_index];
+ int color = colorram[tile_index] & 0x03;
+
+ decodechar(machine->gfx[0], code, rockola_charram,
+ machine->drv->gfxdecodeinfo[0].gfxlayout);
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( satansat )
+{
+ bg_tilemap = tilemap_create(satansat_get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ fg_tilemap = tilemap_create(satansat_get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
diff --git a/src/mame/video/rockrage.c b/src/mame/video/rockrage.c
new file mode 100644
index 00000000000..61528c7d53b
--- /dev/null
+++ b/src/mame/video/rockrage.c
@@ -0,0 +1,95 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+static int layer_colorbase[2];
+static int rockrage_vreg;
+
+PALETTE_INIT( rockrage )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ /* build the lookup table for sprites. Palette is dynamic. */
+ for (i = 0;i < TOTAL_COLORS(0)/2; i++){
+ COLOR(0,i) = 0x00 + (color_prom[i] & 0x0f);
+ COLOR(0,(TOTAL_COLORS(0)/2)+i) = 0x10 + (color_prom[0x100+i] & 0x0f);
+ }
+}
+
+/***************************************************************************
+
+ Callback for the K007342
+
+***************************************************************************/
+
+static void tile_callback(int layer, int bank, int *code, int *color, int *flags)
+{
+ if (layer == 1)
+ *code |= ((*color & 0x40) << 2) | ((bank & 0x01) << 9);
+ else
+ *code |= ((*color & 0x40) << 2) | ((bank & 0x03) << 10) | ((rockrage_vreg & 0x04) << 7) | ((rockrage_vreg & 0x08) << 9);
+ *color = layer_colorbase[layer] + (*color & 0x0f);
+}
+
+/***************************************************************************
+
+ Callback for the K007420
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color)
+{
+ *code |= ((*color & 0x40) << 2) | ((*color & 0x80) << 1)*((rockrage_vreg & 0x03) << 1);
+ *code = (*code << 2) | ((*color & 0x30) >> 4);
+ *color = 0;
+}
+
+
+WRITE8_HANDLER( rockrage_vreg_w ){
+ /* bits 4-7: unused */
+ /* bit 3: bit 4 of bank # (layer 0) */
+ /* bit 2: bit 1 of bank # (layer 0) */
+ /* bits 0-1: sprite bank select */
+
+ if ((data & 0x0c) != (rockrage_vreg & 0x0c))
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+
+ rockrage_vreg = data;
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( rockrage )
+{
+ layer_colorbase[0] = 0x00;
+ layer_colorbase[1] = 0x10;
+
+ K007342_vh_start(0,tile_callback);
+ K007420_vh_start(machine,1,sprite_callback);
+
+ K007420_set_banklimit(0x3ff); // bladestl and battlnts may also need this
+}
+
+
+/***************************************************************************
+
+ Screen Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( rockrage )
+{
+ K007342_tilemap_update();
+
+ K007342_tilemap_draw( bitmap,cliprect, 0, TILEMAP_DRAW_OPAQUE ,0);
+ K007420_sprites_draw( bitmap,cliprect );
+ K007342_tilemap_draw( bitmap,cliprect, 0, 1 | TILEMAP_DRAW_OPAQUE ,0);
+ K007342_tilemap_draw( bitmap,cliprect, 1, 0 ,0);
+ K007342_tilemap_draw( bitmap,cliprect, 1, 1 ,0);
+ return 0;
+}
diff --git a/src/mame/video/rocnrope.c b/src/mame/video/rocnrope.c
new file mode 100644
index 00000000000..3c2e12b0f52
--- /dev/null
+++ b/src/mame/video/rocnrope.c
@@ -0,0 +1,130 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Roc'n Rope has one 32x8 palette PROM and two 256x4 lookup table PROMs
+ (one for characters, one for sprites).
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( rocnrope )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = *(color_prom++) & 0x0f;
+
+ /* characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = *(color_prom++) & 0x0f;
+}
+
+WRITE8_HANDLER( rocnrope_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( rocnrope_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( rocnrope_flipscreen_w )
+{
+ if (flip_screen != (~data & 0x01))
+ {
+ flip_screen_set(~data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + 2 * (attr & 0x80);
+ int color = attr & 0x0f;
+ int flags = ((attr & 0x40) ? TILE_FLIPX : 0) | ((attr & 0x20) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( rocnrope )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = spriteram_size - 2;offs >= 0;offs -= 2)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ spriteram[offs + 1],
+ spriteram_2[offs] & 0x0f,
+ spriteram_2[offs] & 0x40,~spriteram_2[offs] & 0x80,
+ 240-spriteram[offs],spriteram_2[offs + 1],
+ cliprect,TRANSPARENCY_COLOR,0);
+ }
+}
+
+VIDEO_UPDATE( rocnrope )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/rohga.c b/src/mame/video/rohga.c
new file mode 100644
index 00000000000..0ba9ea20806
--- /dev/null
+++ b/src/mame/video/rohga.c
@@ -0,0 +1,545 @@
+/***************************************************************************
+
+ Rohga Video emulation - Bryan McPhail, mish@tendril.co.uk
+
+***************************************************************************/
+
+#include "driver.h"
+#include "deco16ic.h"
+
+static UINT16 * rohga_spriteram;
+
+/******************************************************************************/
+
+WRITE16_HANDLER( rohga_buffer_spriteram16_w )
+{
+ // Spriteram seems to be triple buffered (no sprite lag on real pcb, but there
+ // is on driver with only double buffering)
+ memcpy(rohga_spriteram, buffered_spriteram16, 0x800);
+ memcpy(buffered_spriteram16, spriteram16, 0x800);
+}
+
+static int wizdfire_bank_callback(const int bank)
+{
+ return ((bank>>4)&0x3)<<12;
+}
+
+VIDEO_START( rohga )
+{
+ rohga_spriteram = (UINT16*)auto_malloc(0x800);
+
+ deco16_2_video_init(0);
+
+ deco16_set_tilemap_bank_callback(0,wizdfire_bank_callback);
+ deco16_set_tilemap_bank_callback(1,wizdfire_bank_callback);
+ deco16_set_tilemap_bank_callback(2,wizdfire_bank_callback);
+ deco16_set_tilemap_bank_callback(3,wizdfire_bank_callback);
+}
+
+VIDEO_START( wizdfire )
+{
+ deco16_2_video_init(0);
+
+ deco16_set_tilemap_bank_callback(0,wizdfire_bank_callback);
+ deco16_set_tilemap_bank_callback(1,wizdfire_bank_callback);
+ deco16_set_tilemap_bank_callback(2,wizdfire_bank_callback);
+ deco16_set_tilemap_bank_callback(3,wizdfire_bank_callback);
+
+ deco16_pf1_rowscroll=deco16_pf2_rowscroll=0;
+
+ alpha_set_level(0x80);
+}
+
+VIDEO_START( nitrobal )
+{
+ deco16_2_video_init_half_width();
+
+ deco16_set_tilemap_bank_callback(0,wizdfire_bank_callback);
+ deco16_set_tilemap_bank_callback(1,wizdfire_bank_callback);
+ deco16_set_tilemap_bank_callback(2,wizdfire_bank_callback);
+ deco16_set_tilemap_bank_callback(3,wizdfire_bank_callback);
+
+ deco16_set_tilemap_colour_base(2,0);
+ deco16_set_tilemap_colour_mask(2,0);
+ deco16_set_tilemap_colour_base(3,0);
+ deco16_set_tilemap_colour_mask(3,0);
+
+ alpha_set_level(0x80);
+}
+
+/******************************************************************************/
+
+static void rohga_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, const UINT16 *spriteptr, int is_schmeisr)
+{
+ int offs;
+
+ for (offs = 0x400-4;offs >= 0;offs -= 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult,pri=0;
+ sprite = spriteptr[offs+1];
+ if (!sprite) continue;
+
+ x = spriteptr[offs+2];
+
+ /* Sprite/playfield priority */
+ switch (x&0x6000) {
+ case 0x0000: pri=0; break;
+ case 0x4000: pri=0xf0; break;
+ case 0x6000: pri=0xf0|0xcc; break;
+ case 0x2000: pri=0;//0xf0|0xcc; break; /* Perhaps 0xf0|0xcc|0xaa (Sprite under bottom layer) */
+ }
+
+ y = spriteptr[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ // Sprite colour is different between Rohga (6bpp) and Schmeisr (4bpp plus wire mods on pcb)
+ if (is_schmeisr)
+ {
+ colour = ((x >> 9) &0xf)<<2;
+ if (x&0x8000)
+ colour++;
+ }
+ else
+ {
+ colour = (x >> 9) &0xf;
+ }
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen) {
+ x=304-x;
+ y=240-y;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=-16;
+ }
+ else mult=+16;
+
+ while (multi >= 0)
+ {
+ pdrawgfx(bitmap,machine->gfx[3],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0,pri);
+
+ multi--;
+ }
+ }
+}
+
+static void wizdfire_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT16 *spriteptr, int mode, int bank)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+ int trans=TRANSPARENCY_PEN;
+
+ sprite = spriteptr[offs+1];
+ if (!sprite) continue;
+
+ x = spriteptr[offs+2];
+
+ /*
+ Sprite/playfield priority - we can't use pdrawgfx because we need alpha'd sprites overlaid
+ over non-alpha'd sprites, plus sprites underneath and above an alpha'd background layer.
+
+ Hence, we rely on the hardware sorting everything correctly and not relying on any orthoganality
+ effects (it doesn't seem to), and instead draw seperate passes for each sprite priority. :(
+ */
+ switch (mode) {
+ case 4:
+ if ((x&0xc000)!=0xc000)
+ continue;
+ break;
+ case 3:
+ if ((x&0xc000)!=0x8000)
+ continue;
+ break;
+ case 2:
+ if ((x&0x8000)!=0x8000)
+ continue;
+ break;
+ case 1:
+ case 0:
+ default:
+ if ((x&0x8000)!=0)
+ continue;
+ break;
+ }
+
+ y = spriteptr[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+ colour = (x >> 9) &0x1f;
+
+ if (bank==4 && colour&0x10) {
+ trans=TRANSPARENCY_ALPHA;
+ colour&=0xf;
+ }
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen) {
+ x=304-x;
+ y=240-y;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=-16;
+ }
+ else
+ mult=+16;
+
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[bank],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,trans,0);
+
+ multi--;
+ }
+ }
+}
+
+static void nitrobal_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, const UINT16 *spriteptr, int gfxbank)
+{
+ int offs,end,inc;
+
+ /*
+ Alternate format from most 16 bit games - same as Captain America and Mutant Fighter
+
+ Word 0:
+ 0x8000: Y flip
+ 0x4000: X flip
+ 0x2000: Flash (Sprite toggles on/off every frame)
+ 0x1fff: Y value
+ Word 1:
+ 0xffff: X value
+ Word 2:
+ 0xf000: Block height
+ 0x0f00: Block width
+ 0x00e0: Unused?
+
+sprites1:
+ bit 0x40 set for under PF2
+ bit 0x20 set on others...
+ bit 0x80 set in game pf3 (split)
+
+Sprites 2:
+ bit 0x10 set on alpha sprites..
+ bit 0x80 set is above pf2 else under pf2
+
+ 0x001f: Colour
+ Word 3:
+ 0xffff: Sprite value
+ */
+
+ offs=0x3fc;
+ end=-4;
+ inc=-4;
+
+ while (offs!=end)
+ {
+ int x,y,sprite,colour,fx,fy,w,h,sx,sy,x_mult,y_mult,tilemap_pri,sprite_pri;
+ int trans=TRANSPARENCY_PEN;
+
+ sprite = spriteptr[offs+3];
+ if (!sprite) {
+ offs+=inc;
+ continue;
+ }
+
+ sx = spriteptr[offs+1];
+
+ h = (spriteptr[offs+2]&0xf000)>>12;
+ w = (spriteptr[offs+2]&0x0f00)>> 8;
+
+ sy = spriteptr[offs];
+ if ((sy&0x2000) && (cpu_getcurrentframe() & 1)) {
+ offs+=inc;
+ continue;
+ }
+
+ colour = (spriteptr[offs+2] >>0) & 0x1f;
+
+ // PRIORITIES - TODO
+ if (gfxbank==3) {
+ /* Sprite chip 1 */
+ switch (spriteptr[offs+2]&0xe0) {
+// case 0xc0: colour=rand()%0xff; tilemap_pri=256; break; //todo
+ case 0xc0: tilemap_pri=8; break; //? under other sprites
+ case 0x80: tilemap_pri=32; break; //? under other sprites
+ case 0x20: tilemap_pri=32; break; /* Over pf2 and under other sprite chip */
+ case 0x40: tilemap_pri=8; break; /* Under pf2 and under other sprite chip */
+ case 0xa0: tilemap_pri=32; break;
+ case 0:
+ tilemap_pri=128; break;
+ default:
+ tilemap_pri=128;
+ break;
+ }
+
+/*
+Intro:
+ 0x40 is under pf2 and other sprites
+ 0x20 is under pf2
+
+Level 1
+ 0xa0 means under other sprites and pf2?
+
+Level 2 (tank scene)
+
+ Chip 1:
+
+ 0x20 set means under pf2 else above??
+ 0x80 set means under other sprites else above
+
+Level 3:
+ 0xc0 means under other sprites and pf2 check??
+ 0x40 means under pf2
+ 0xa0 means under pf2..
+
+ always over other sprites..?
+
+
+PRI MODE 2: (Level 4)
+sprite 1:
+ mode 0xa0 is under pf2 (sprites unknown)
+ mode 0x40 is under pf2 (sprites unknown)
+
+sprite 2:
+
+ mode 0x40 is under pf2
+ mode 0 is under pf2
+
+
+Level 5 (Space, pri mode 1)
+
+sprite 1:
+ mode 0x80 is over pf2 and over other sprites
+
+
+
+sprite 2:
+
+ mode 0 is over pf2
+
+ */
+
+ sprite_pri=1;
+ } else {
+ /* Sprite chip 2 (with alpha blending) */
+
+ /* Sprite above playfield 2, but still below other sprite chip */
+// if (spriteptr[offs+2]&0x80)
+ tilemap_pri=64;
+// else
+// tilemap_pri=8;
+
+ if (deco16_priority)
+ tilemap_pri=8;
+ else
+ tilemap_pri=64;
+
+ sprite_pri=2;
+ }
+
+ if (gfxbank==4 && colour&0x10) {
+ trans=TRANSPARENCY_ALPHA;
+ colour&=0xf;
+ }
+
+ fx = (spriteptr[offs+0]&0x4000);
+ fy = (spriteptr[offs+0]&0x8000);
+
+ if (!flip_screen) { /* Inverted from Mutant Fighter! */
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+
+ sx = sx & 0x01ff;
+ sy = sy & 0x01ff;
+ if (sx>0x180) sx=-(0x200 - sx);
+ if (sy>0x180) sy=-(0x200 - sy);
+
+ if (fx) { x_mult=-16; sx+=16*w; } else { x_mult=16; sx-=16; }
+ if (fy) { y_mult=-16; sy+=16*h; } else { y_mult=16; sy-=16; }
+ } else {
+ sx = sx & 0x01ff;
+ sy = sy & 0x01ff;
+ if (sx&0x100) sx=-(0x100 - (sx&0xff));
+ if (sy&0x100) sy=-(0x100 - (sy&0xff));
+ sx = 304 - sx;
+ sy = 240 - sy;
+ if (sx >= 432) sx -= 512;
+ if (sy >= 384) sy -= 512;
+ if (fx) { x_mult=-16; sx+=16; } else { x_mult=16; sx-=16*w; }
+ if (fy) { y_mult=-16; sy+=16; } else { y_mult=16; sy-=16*h; }
+ }
+
+ for (x=0; x<w; x++) {
+ for (y=0; y<h; y++) {
+ deco16_pdrawgfx(bitmap,machine->gfx[gfxbank],
+ sprite + y + h * x,
+ colour,
+ fx,fy,
+ sx + x_mult * (w-x),sy + y_mult * (h-y),
+ cliprect,trans,0,tilemap_pri,sprite_pri,1);
+ }
+ }
+
+ offs+=inc;
+ }
+}
+
+/******************************************************************************/
+
+static void update_rohga(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int is_schmeisr)
+{
+ /* Update playfields */
+ flip_screen_set( deco16_pf12_control[0]&0x80 );
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+ deco16_pf34_update(deco16_pf3_rowscroll,deco16_pf4_rowscroll);
+
+ /* Draw playfields */
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[768],cliprect);
+
+ switch (deco16_priority&3)
+ {
+ case 0:
+ if (deco16_priority&4)
+ {
+ // Draw as 1 8BPP layer
+ deco16_tilemap_34_combine_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,3);
+ }
+ else
+ {
+ // Draw as 2 4BPP layers
+ deco16_tilemap_4_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,1);
+ deco16_tilemap_3_draw(bitmap,cliprect,0,2);
+ }
+ deco16_tilemap_2_draw(bitmap,cliprect,0,4);
+ break;
+ case 1:
+ deco16_tilemap_4_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,1);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,2);
+ deco16_tilemap_3_draw(bitmap,cliprect,0,4);
+ break;
+ case 2:
+ deco16_tilemap_2_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,1);
+ deco16_tilemap_4_draw(bitmap,cliprect,0,2);
+ deco16_tilemap_3_draw(bitmap,cliprect,0,4);
+ break;
+ }
+
+ rohga_draw_sprites(machine,bitmap,cliprect,rohga_spriteram,is_schmeisr);
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+}
+
+VIDEO_UPDATE( rohga )
+{
+ update_rohga(machine, bitmap, cliprect, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( schmeisr )
+{
+ // The Schmeisr pcb has wire mods which seem to remap sprite palette indices.
+ // Otherwise video update is the same as Rohga.
+ update_rohga(machine, bitmap, cliprect, 1);
+ return 0;
+}
+
+VIDEO_UPDATE( wizdfire )
+{
+ /* Update playfields */
+ flip_screen_set( deco16_pf12_control[0]&0x80 );
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+ deco16_pf34_update(deco16_pf3_rowscroll,deco16_pf4_rowscroll);
+
+ /* Draw playfields - Palette of 2nd playfield chip visible if playfields turned off */
+ fillbitmap(bitmap,machine->pens[512],&machine->screen[0].visarea);
+
+ deco16_tilemap_4_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ wizdfire_draw_sprites(machine,bitmap,cliprect,buffered_spriteram16,4,3);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,0);
+ wizdfire_draw_sprites(machine,bitmap,cliprect,buffered_spriteram16,3,3);
+
+ if ((deco16_priority&0x1f)==0x1f) /* Wizdfire has bit 0x40 always set, Dark Seal 2 doesn't?! */
+ deco16_tilemap_3_draw(bitmap,cliprect,TILEMAP_DRAW_ALPHA,0);
+ else
+ deco16_tilemap_3_draw(bitmap,cliprect,0,0);
+
+ /* See notes in wizdfire_draw_sprites about this */
+ wizdfire_draw_sprites(machine,bitmap,cliprect,buffered_spriteram16,0,3);
+ wizdfire_draw_sprites(machine,bitmap,cliprect,buffered_spriteram16_2,2,4);
+ wizdfire_draw_sprites(machine,bitmap,cliprect,buffered_spriteram16_2,1,4);
+
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( nitrobal )
+{
+ /* Update playfields */
+ flip_screen_set( deco16_pf12_control[0]&0x80 );
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+ deco16_pf34_update(deco16_pf3_rowscroll,deco16_pf4_rowscroll);
+
+ /* Draw playfields - Palette of 2nd playfield chip visible if playfields turned off */
+ fillbitmap(bitmap,machine->pens[512],&machine->screen[0].visarea);
+ fillbitmap(priority_bitmap,0,NULL);
+ deco16_clear_sprite_priority_bitmap();
+
+ /* pf3 and pf4 are combined into a single 8bpp bitmap */
+ deco16_tilemap_34_combine_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+
+ deco16_tilemap_2_draw(bitmap,cliprect,0,16);
+ nitrobal_draw_sprites(machine,bitmap,cliprect,buffered_spriteram16,3);
+ nitrobal_draw_sprites(machine,bitmap,cliprect,buffered_spriteram16_2,4);
+
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+ return 0;
+}
diff --git a/src/mame/video/rollerg.c b/src/mame/video/rollerg.c
new file mode 100644
index 00000000000..7832f4f5d3d
--- /dev/null
+++ b/src/mame/video/rollerg.c
@@ -0,0 +1,76 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+static int bg_colorbase,sprite_colorbase,zoom_colorbase;
+
+
+
+/***************************************************************************
+
+ Callbacks for the K053245
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority_mask)
+{
+#if 0
+if (input_code_pressed(KEYCODE_Q) && (*color & 0x80)) *color = rand();
+if (input_code_pressed(KEYCODE_W) && (*color & 0x40)) *color = rand();
+if (input_code_pressed(KEYCODE_E) && (*color & 0x20)) *color = rand();
+if (input_code_pressed(KEYCODE_R) && (*color & 0x10)) *color = rand();
+#endif
+ *priority_mask = (*color & 0x10) ? 0 : 0x02;
+ *color = sprite_colorbase + (*color & 0x0f);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051316
+
+***************************************************************************/
+
+static void zoom_callback(int *code,int *color,int *flags)
+{
+ *flags = TILE_FLIPYX((*color & 0xc0) >> 6);
+ *code |= ((*color & 0x0f) << 8);
+ *color = zoom_colorbase + ((*color & 0x30) >> 4);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( rollerg )
+{
+ bg_colorbase = 16;
+ sprite_colorbase = 16;
+ zoom_colorbase = 0;
+
+ K053245_vh_start(machine,0,REGION_GFX1,NORMAL_PLANE_ORDER,sprite_callback);
+ K051316_vh_start_0(machine,REGION_GFX2,4,FALSE,0,zoom_callback);
+
+ K051316_set_offset(0, 22, 1);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( rollerg )
+{
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[16 * bg_colorbase],cliprect);
+ K051316_zoom_draw_0(bitmap,cliprect,0,1);
+ K053245_sprites_draw(0,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/rollrace.c b/src/mame/video/rollrace.c
new file mode 100644
index 00000000000..978c5756a25
--- /dev/null
+++ b/src/mame/video/rollrace.c
@@ -0,0 +1,170 @@
+#include "driver.h"
+
+
+static int ra_charbank[2] = { 0,0 };
+static int ra_bkgpage = 0;
+static int ra_bkgflip = 0;
+static int ra_chrbank = 0;
+static int ra_bkgpen = 0;
+static int ra_bkgcol = 0;
+static int ra_flipy = 0;
+static int ra_flipx = 0;
+static int ra_spritebank =0 ;
+
+#define RA_FGCHAR_BASE 0
+#define RA_BGCHAR_BASE 4
+#define RA_SP_BASE 5
+
+WRITE8_HANDLER( rollrace_charbank_w)
+{
+
+ ra_charbank[offset&1] = data;
+ ra_chrbank = ra_charbank[0] | (ra_charbank[1] << 1) ;
+}
+
+
+WRITE8_HANDLER( rollrace_bkgpen_w)
+{
+ ra_bkgpen = data;
+}
+
+WRITE8_HANDLER(rollrace_spritebank_w)
+{
+ ra_spritebank = data;
+}
+
+WRITE8_HANDLER(rollrace_backgroundpage_w)
+{
+
+ ra_bkgpage = data & 0x1f;
+ ra_bkgflip = ( data & 0x80 ) >> 7;
+
+ /* 0x80 flip vertical */
+}
+
+WRITE8_HANDLER( rollrace_backgroundcolor_w )
+{
+ ra_bkgcol = data;
+}
+
+WRITE8_HANDLER( rollrace_flipy_w )
+{
+ ra_flipy = data & 0x01;
+}
+
+WRITE8_HANDLER( rollrace_flipx_w )
+{
+ ra_flipx = data & 0x01;
+}
+
+VIDEO_UPDATE( rollrace )
+{
+
+ int offs;
+ int sx, sy;
+ int scroll;
+ int col;
+
+ /* fill in background colour*/
+ fillbitmap(bitmap,machine->pens[ra_bkgpen],&machine->screen[0].visarea);
+
+ /* draw road */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ if(!(ra_bkgflip))
+ {
+ sy = ( 31 - offs / 32 ) ;
+ }
+ else
+ sy = ( offs / 32 ) ;
+
+ sx = ( offs%32 ) ;
+
+ if(ra_flipx)
+ sx = 31-sx ;
+
+ if(ra_flipy)
+ sy = 31-sy ;
+
+ drawgfx(bitmap,
+ machine->gfx[RA_BGCHAR_BASE],
+ memory_region(REGION_USER1)[offs + ( ra_bkgpage * 1024 )] \
+ + ((( memory_region(REGION_USER1)[offs + 0x4000 + ( ra_bkgpage * 1024 )] & 0xc0 ) >> 6 ) * 256 ) ,
+ ra_bkgcol,
+ ra_flipx,(ra_bkgflip^ra_flipy),
+ sx*8,sy*8,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+
+
+ }
+
+
+
+
+ /* sprites */
+ for ( offs = 0x80-4 ; offs >=0x0 ; offs -= 4)
+ {
+ int s_flipy = 0;
+ int bank = 0;
+
+ sy=spriteram[offs] - 16;
+ sx=spriteram[offs+3] - 16;
+
+ if(sx && sy)
+ {
+
+ if(ra_flipx)
+ sx = 224 - sx;
+ if(ra_flipy)
+ sy = 224 - sy;
+
+ if(spriteram[offs+1] & 0x80)
+ s_flipy = 1;
+
+ bank = (( spriteram[offs+1] & 0x40 ) >> 6 ) ;
+
+ if(bank)
+ bank += ra_spritebank;
+
+ drawgfx(bitmap, machine->gfx[ RA_SP_BASE + bank ],
+ spriteram[offs+1] & 0x3f ,
+ spriteram[offs+2] & 0x1f,
+ ra_flipx,!(s_flipy^ra_flipy),
+ sx,sy,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ }
+
+
+
+
+ /* draw foreground characters */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+
+ sx = offs % 32;
+ sy = offs / 32;
+
+ scroll = ( 8 * sy + colorram[2 * sx] ) % 256;
+ col = colorram[ sx * 2 + 1 ]&0x1f;
+
+ if (!ra_flipy)
+ {
+ scroll = (248 - scroll) % 256;
+ }
+
+ if (ra_flipx) sx = 31 - sx;
+
+ drawgfx(bitmap,machine->gfx[RA_FGCHAR_BASE + ra_chrbank] ,
+ videoram[ offs ] ,
+ col,
+ ra_flipx,ra_flipy,
+ 8*sx,scroll,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+
+ }
+
+
+
+ return 0;
+}
diff --git a/src/mame/video/route16.c b/src/mame/video/route16.c
new file mode 100644
index 00000000000..5d7947f3930
--- /dev/null
+++ b/src/mame/video/route16.c
@@ -0,0 +1,195 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "sound/sn76477.h"
+
+
+UINT8 *route16_videoram1;
+UINT8 *route16_videoram2;
+size_t route16_videoram_size;
+//int route16_hardware;
+
+static UINT8 flipscreen;
+static UINT8 palette_1;
+static UINT8 palette_2;
+
+
+
+/*************************************
+ *
+ * Memory handlers
+ *
+ *************************************/
+
+WRITE8_HANDLER( route16_out0_w )
+{
+ palette_1 = data & 0x1f;
+
+ coin_counter_w(0, (data >> 5) & 0x01);
+}
+
+
+WRITE8_HANDLER( route16_out1_w )
+{
+ palette_2 = data & 0x1f;
+
+ flipscreen = (data >> 5) & 0x01;
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+static pen_t route16_make_pen(UINT8 color)
+{
+ return MAKE_RGB(pal1bit((color >> 0) & 0x01),
+ pal1bit((color >> 1) & 0x01),
+ pal1bit((color >> 2) & 0x01));
+
+}
+
+
+static pen_t ttmajng_make_pen(UINT8 color)
+{
+ return MAKE_RGB(pal1bit((color >> 2) & 0x01),
+ pal1bit((color >> 1) & 0x01),
+ pal1bit((color >> 0) & 0x01));
+
+}
+
+
+/*
+ * Game observation shows that Route 16 can blank each
+ * bitmap by setting bit 1 of the palette register.
+ * Since the schematics are missing the relevant pages, I
+ * cannot confirm how this works, but I am 99% sure the bit 1
+ * would be connected to A7 of the color PROM. Since the
+ * color PROMs contain 0 in the upper half, this would produce
+ * a black output.
+ */
+
+VIDEO_UPDATE( route16 )
+{
+ offs_t offs;
+
+ UINT8 *color_prom1 = &memory_region(REGION_PROMS)[0x000];
+ UINT8 *color_prom2 = &memory_region(REGION_PROMS)[0x100];
+
+ for (offs = 0; offs < route16_videoram_size; offs++)
+ {
+ int i;
+
+ UINT8 y = offs >> 6;
+ UINT8 x = offs << 2;
+
+ UINT8 data1 = route16_videoram1[offs];
+ UINT8 data2 = route16_videoram2[offs];
+
+ for (i = 0; i < 4; i++)
+ {
+ UINT8 color1 = color_prom1[((palette_1 << 6) & 0x80) |
+ (palette_1 << 2) |
+ ((data1 >> 3) & 0x02) |
+ ((data1 >> 0) & 0x01)];
+
+ /* bit 7 of the 2nd color is the OR of the 1st color bits 0 and 1 - this is a guess */
+ UINT8 color2 = color_prom2[((palette_2 << 6) & 0x80) | (((color1 << 6) & 0x80) | ((color1 << 7) & 0x80)) |
+ (palette_2 << 2) |
+ ((data2 >> 3) & 0x02) |
+ ((data2 >> 0) & 0x01)];
+
+ /* the final color is the OR of the two colors (verified) */
+ UINT8 final_color = color1 | color2;
+
+ pen_t pen = route16_make_pen(final_color);
+
+ if (flipscreen)
+ *BITMAP_ADDR32(bitmap, 255 - y, 255 - x) = pen;
+ else
+ *BITMAP_ADDR32(bitmap, y, x) = pen;
+
+ x = x + 1;
+ data1 = data1 >> 1;
+ data2 = data2 >> 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * The Stratovox video connections have been verified from the schematics
+ */
+
+static int video_update_stratvox_ttmahjng(mame_bitmap *bitmap,
+ const rectangle *cliprect,
+ pen_t (*make_pen)(UINT8))
+{
+ offs_t offs;
+
+ UINT8 *color_prom1 = &memory_region(REGION_PROMS)[0x000];
+ UINT8 *color_prom2 = &memory_region(REGION_PROMS)[0x100];
+
+ for (offs = 0; offs < route16_videoram_size; offs++)
+ {
+ int i;
+
+ UINT8 y = offs >> 6;
+ UINT8 x = offs << 2;
+
+ UINT8 data1 = route16_videoram1[offs];
+ UINT8 data2 = route16_videoram2[offs];
+
+ for (i = 0; i < 4; i++)
+ {
+ UINT8 color1 = color_prom1[(palette_1 << 2) |
+ ((data1 >> 3) & 0x02) |
+ ((data1 >> 0) & 0x01)];
+
+ /* bit 7 of the 2nd color is the OR of the 1st color bits 0 and 1 (verified) */
+ UINT8 color2 = color_prom2[(((data1 << 3) & 0x80) | ((data1 << 7) & 0x80)) |
+ (palette_2 << 2) |
+ ((data2 >> 3) & 0x02) |
+ ((data2 >> 0) & 0x01)];
+
+ /* the final color is the OR of the two colors */
+ UINT8 final_color = color1 | color2;
+
+ pen_t pen = make_pen(final_color);
+
+ if (flipscreen)
+ *BITMAP_ADDR32(bitmap, 255 - y, 255 - x) = pen;
+ else
+ *BITMAP_ADDR32(bitmap, y, x) = pen;
+
+ x = x + 1;
+ data1 = data1 >> 1;
+ data2 = data2 >> 1;
+ }
+ }
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( stratvox )
+{
+ return video_update_stratvox_ttmahjng(bitmap, cliprect, route16_make_pen);
+}
+
+
+VIDEO_UPDATE( ttmahjng )
+{
+ return video_update_stratvox_ttmahjng(bitmap, cliprect, ttmajng_make_pen);
+}
diff --git a/src/mame/video/rpunch.c b/src/mame/video/rpunch.c
new file mode 100644
index 00000000000..5202994618d
--- /dev/null
+++ b/src/mame/video/rpunch.c
@@ -0,0 +1,291 @@
+/***************************************************************************
+
+ video/rpunch.c
+
+ Functions to emulate the video hardware of the machine.
+
+****************************************************************************/
+
+#include "driver.h"
+
+
+#define BITMAP_WIDTH 304
+#define BITMAP_HEIGHT 224
+#define BITMAP_XOFFSET 4
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+UINT16 *rpunch_bitmapram;
+size_t rpunch_bitmapram_size;
+
+int rpunch_sprite_palette;
+
+static tilemap *background[2];
+
+static UINT16 videoflags;
+static UINT8 crtc_register;
+static emu_timer *crtc_timer;
+static UINT8 bins, gins;
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_bg0_tile_info )
+{
+ int data = videoram16[tile_index];
+ int code;
+ if (videoflags & 0x0400) code = (data & 0x0fff) | 0x2000;
+ else code = (data & 0x1fff);
+
+ SET_TILE_INFO(
+ 0,
+ code,
+ ((videoflags & 0x0010) >> 1) | ((data >> 13) & 7),
+ 0);
+}
+
+static TILE_GET_INFO( get_bg1_tile_info )
+{
+ int data = videoram16[videoram_size / 4 + tile_index];
+ int code;
+ if (videoflags & 0x0800) code = (data & 0x0fff) | 0x2000;
+ else code = (data & 0x1fff);
+
+ SET_TILE_INFO(
+ 1,
+ code,
+ ((videoflags & 0x0020) >> 2) | ((data >> 13) & 7),
+ 0);
+}
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+static TIMER_CALLBACK( crtc_interrupt_gen )
+{
+ cpunum_set_input_line(0, 1, HOLD_LINE);
+ if (param != 0)
+ timer_adjust(crtc_timer, attotime_make(0, machine->screen[0].refresh / param), 0, attotime_make(0, machine->screen[0].refresh / param));
+}
+
+
+VIDEO_START( rpunch )
+{
+ /* allocate tilemaps for the backgrounds */
+ background[0] = tilemap_create(get_bg0_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 8,8,64,64);
+ background[1] = tilemap_create(get_bg1_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ /* configure the tilemaps */
+ tilemap_set_transparent_pen(background[1],15);
+
+ if (rpunch_bitmapram)
+ memset(rpunch_bitmapram, 0xff, rpunch_bitmapram_size);
+
+ /* reset the timer */
+ crtc_timer = timer_alloc(crtc_interrupt_gen);
+}
+
+
+
+/*************************************
+ *
+ * Write handlers
+ *
+ *************************************/
+
+WRITE16_HANDLER( rpunch_videoram_w )
+{
+ int tmap = offset >> 12;
+ int tile_index = offset & 0xfff;
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty(background[tmap],tile_index);
+}
+
+
+WRITE16_HANDLER( rpunch_videoreg_w )
+{
+ int oldword = videoflags;
+ COMBINE_DATA(&videoflags);
+
+ if (videoflags != oldword)
+ {
+ /* invalidate tilemaps */
+ if ((oldword ^ videoflags) & 0x0410)
+ tilemap_mark_all_tiles_dirty(background[0]);
+ if ((oldword ^ videoflags) & 0x0820)
+ tilemap_mark_all_tiles_dirty(background[1]);
+ }
+}
+
+
+WRITE16_HANDLER( rpunch_scrollreg_w )
+{
+ if (ACCESSING_LSB && ACCESSING_MSB)
+ switch (offset)
+ {
+ case 0:
+ tilemap_set_scrolly(background[0], 0, data & 0x1ff);
+ break;
+
+ case 1:
+ tilemap_set_scrollx(background[0], 0, data & 0x1ff);
+ break;
+
+ case 2:
+ tilemap_set_scrolly(background[1], 0, data & 0x1ff);
+ break;
+
+ case 3:
+ tilemap_set_scrollx(background[1], 0, data & 0x1ff);
+ break;
+ }
+}
+
+
+WRITE16_HANDLER( rpunch_crtc_data_w )
+{
+ if (ACCESSING_LSB)
+ {
+ data &= 0xff;
+ switch (crtc_register)
+ {
+ /* only register we know about.... */
+ case 0x0b:
+ timer_adjust(crtc_timer, video_screen_get_time_until_pos(0, Machine->screen[0].visarea.max_y + 1, 0), (data == 0xc0) ? 2 : 1, attotime_zero);
+ break;
+
+ default:
+ logerror("CRTC register %02X = %02X\n", crtc_register, data & 0xff);
+ break;
+ }
+ }
+}
+
+
+WRITE16_HANDLER( rpunch_crtc_register_w )
+{
+ if (ACCESSING_LSB)
+ crtc_register = data & 0xff;
+}
+
+
+WRITE16_HANDLER( rpunch_ins_w )
+{
+ if (ACCESSING_LSB)
+ {
+ if (offset == 0)
+ {
+ gins = data & 0x3f;
+ logerror("GINS = %02X\n", data & 0x3f);
+ }
+ else
+ {
+ bins = data & 0x3f;
+ logerror("BINS = %02X\n", data & 0x3f);
+ }
+ }
+}
+
+
+/*************************************
+ *
+ * Sprite routines
+ *
+ *************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int start, int stop)
+{
+ int offs;
+
+ start *= 4;
+ stop *= 4;
+
+ /* draw the sprites */
+ for (offs = start; offs < stop; offs += 4)
+ {
+ int data1 = spriteram16[offs + 1];
+ int code = data1 & 0x7ff;
+
+ int data0 = spriteram16[offs + 0];
+ int data2 = spriteram16[offs + 2];
+ int x = (data2 & 0x1ff) + 8;
+ int y = 513 - (data0 & 0x1ff);
+ int xflip = data1 & 0x1000;
+ int yflip = data1 & 0x0800;
+ int color = ((data1 >> 13) & 7) | ((videoflags & 0x0040) >> 3);
+
+ if (x >= BITMAP_WIDTH) x -= 512;
+ if (y >= BITMAP_HEIGHT) y -= 512;
+
+ drawgfx(bitmap, machine->gfx[2],
+ code, color + (rpunch_sprite_palette / 16), xflip, yflip, x, y, cliprect, TRANSPARENCY_PEN, 15);
+ }
+}
+
+
+/*************************************
+ *
+ * Bitmap routines
+ *
+ *************************************/
+
+static void draw_bitmap(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int colourbase;
+ int xxx=512/4;
+ int yyy=256;
+ int x,y,count;
+
+ colourbase = 512 + ((videoflags & 15) * 16);
+
+ count = 0;
+
+ for (y=0;y<yyy;y++)
+ {
+ for(x=0;x<xxx;x++)
+ {
+ int coldat;
+ coldat = (rpunch_bitmapram[count]>>12)&0xf; if (coldat!=15) *BITMAP_ADDR16(bitmap, y, ((x*4+0)-4)&0x1ff) = coldat+colourbase;
+ coldat = (rpunch_bitmapram[count]>>8 )&0xf; if (coldat!=15) *BITMAP_ADDR16(bitmap, y, ((x*4+1)-4)&0x1ff) = coldat+colourbase;
+ coldat = (rpunch_bitmapram[count]>>4 )&0xf; if (coldat!=15) *BITMAP_ADDR16(bitmap, y, ((x*4+2)-4)&0x1ff) = coldat+colourbase;
+ coldat = (rpunch_bitmapram[count]>>0 )&0xf; if (coldat!=15) *BITMAP_ADDR16(bitmap, y, ((x*4+3)-4)&0x1ff) = coldat+colourbase;
+ count++;
+ }
+ }
+}
+
+
+/*************************************
+ *
+ * Main screen refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( rpunch )
+{
+ int effbins;
+
+ /* this seems like the most plausible explanation */
+ effbins = (bins > gins) ? gins : bins;
+
+ tilemap_draw(bitmap,cliprect, background[0], 0,0);
+ draw_sprites(machine, bitmap,cliprect, 0, effbins);
+ tilemap_draw(bitmap,cliprect, background[1], 0,0);
+ draw_sprites(machine, bitmap,cliprect, effbins, gins);
+ if (rpunch_bitmapram)
+ draw_bitmap(bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/runaway.c b/src/mame/video/runaway.c
new file mode 100644
index 00000000000..0f94d91daa8
--- /dev/null
+++ b/src/mame/video/runaway.c
@@ -0,0 +1,159 @@
+/***************************************************************************
+
+ Atari Runaway video emulation
+
+****************************************************************************/
+
+#include "driver.h"
+
+
+static tilemap *bg_tilemap;
+
+UINT8* runaway_video_ram;
+UINT8* runaway_sprite_ram;
+
+static int tile_bank = 0;
+
+
+
+WRITE8_HANDLER( runaway_paletteram_w )
+{
+ int R =
+ 0x21 * ((~data >> 2) & 1) +
+ 0x47 * ((~data >> 3) & 1) +
+ 0x97 * ((~data >> 4) & 1);
+
+ int G =
+ 0x21 * ((~data >> 5) & 1) +
+ 0x47 * ((~data >> 6) & 1) +
+ 0x97 * ((~data >> 7) & 1);
+
+ int B =
+ 0x21 * 0 +
+ 0x47 * ((~data >> 0) & 1) +
+ 0x97 * ((~data >> 1) & 1);
+
+ palette_set_color(Machine, offset, MAKE_RGB(R, G, B));
+}
+
+
+
+WRITE8_HANDLER( runaway_video_ram_w )
+{
+ runaway_video_ram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+
+WRITE8_HANDLER( runaway_tile_bank_w )
+{
+ if ((data & 1) != tile_bank)
+ {
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ tile_bank = data & 1;
+}
+
+
+static TILE_GET_INFO( runaway_get_tile_info )
+{
+ UINT8 code = runaway_video_ram[tile_index];
+
+ SET_TILE_INFO(0, ((code & 0x3f) << 1) | ((code & 0x40) >> 6) | (tile_bank << 7), 0, (code & 0x80) ? TILE_FLIPY : 0);
+}
+
+
+static TILE_GET_INFO( qwak_get_tile_info )
+{
+ UINT8 code = runaway_video_ram[tile_index];
+
+ SET_TILE_INFO(0, ((code & 0x7f) << 1) | ((code & 0x80) >> 7), 0, 0);
+}
+
+
+
+VIDEO_START( runaway )
+{
+ bg_tilemap = tilemap_create(runaway_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 30);
+}
+
+
+VIDEO_START( qwak )
+{
+ bg_tilemap = tilemap_create(qwak_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 30);
+}
+
+
+
+VIDEO_UPDATE( runaway )
+{
+ int i;
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ for (i = 0; i < 16; i++)
+ {
+ unsigned code = runaway_sprite_ram[i] & 0x3f;
+
+ int x = runaway_sprite_ram[i + 0x20];
+ int y = runaway_sprite_ram[i + 0x10];
+
+ int flipx = runaway_sprite_ram[i] & 0x40;
+ int flipy = runaway_sprite_ram[i] & 0x80;
+
+ code |= (runaway_sprite_ram[i + 0x30] << 2) & 0x1c0;
+
+ drawgfx(bitmap, machine->gfx[1],
+ code,
+ 0,
+ flipx, flipy,
+ x, 240 - y,
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ drawgfx(bitmap, machine->gfx[1],
+ code,
+ 0,
+ flipx, flipy,
+ x - 256, 240 - y,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( qwak )
+{
+ int i;
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ for (i = 0; i < 16; i++)
+ {
+ unsigned code = runaway_sprite_ram[i] & 0x7f;
+
+ int x = runaway_sprite_ram[i + 0x20];
+ int y = runaway_sprite_ram[i + 0x10];
+
+ int flipx = 0;
+ int flipy = runaway_sprite_ram[i] & 0x80;
+
+ code |= (runaway_sprite_ram[i + 0x30] << 2) & 0x1c0;
+
+ drawgfx(bitmap, machine->gfx[1],
+ code,
+ 0,
+ flipx, flipy,
+ x, 240 - y,
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ drawgfx(bitmap, machine->gfx[1],
+ code,
+ 0,
+ flipx, flipy,
+ x - 256, 240 - y,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/rungun.c b/src/mame/video/rungun.c
new file mode 100644
index 00000000000..2fd3de7aa61
--- /dev/null
+++ b/src/mame/video/rungun.c
@@ -0,0 +1,130 @@
+/*
+ Run and Gun
+ (c) 1993 Konami
+
+ Video hardware emulation.
+
+ Driver by R. Belmont
+*/
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+static int ttl_gfx_index;
+static tilemap *ttl_tilemap, *rng_936_tilemap;
+static UINT16 ttl_vram[0x1000];
+
+static int sprite_colorbase;
+extern UINT16 *rng_936_videoram;
+
+/* TTL text plane stuff */
+
+static TILE_GET_INFO( ttl_get_tile_info )
+{
+ UINT32 *lvram = (UINT32 *)ttl_vram;
+ int attr, code;
+
+ code = (lvram[tile_index]>>16)&0xffff;
+ code |= (lvram[tile_index]&0x0f)<<8; /* tile "bank" */
+
+ attr = ((lvram[tile_index]&0xf0)>>4); /* palette */
+
+ SET_TILE_INFO(ttl_gfx_index, code, attr, 0);
+}
+
+static void rng_sprite_callback(int *code, int *color, int *priority_mask)
+{
+ *color = sprite_colorbase | (*color & 0x001f);
+}
+
+READ16_HANDLER( ttl_ram_r )
+{
+ return(ttl_vram[offset]);
+}
+
+WRITE16_HANDLER( ttl_ram_w )
+{
+ COMBINE_DATA(&ttl_vram[offset]);
+}
+
+/* 53936 (PSAC2) rotation/zoom plane */
+
+WRITE16_HANDLER(rng_936_videoram_w)
+{
+ COMBINE_DATA(&rng_936_videoram[offset]);
+ tilemap_mark_tile_dirty(rng_936_tilemap, offset/2);
+}
+
+static TILE_GET_INFO( get_rng_936_tile_info )
+{
+ int tileno, colour, flipx;
+
+ tileno = rng_936_videoram[tile_index*2+1] & 0x3fff;
+ flipx = (rng_936_videoram[tile_index*2+1] & 0xc000) >> 14;
+
+ colour = 0x10 + (rng_936_videoram[tile_index*2] & 0x000f);
+
+ SET_TILE_INFO(0, tileno, colour, TILE_FLIPYX(flipx));
+}
+
+
+VIDEO_START(rng)
+{
+ static const gfx_layout charlayout =
+ {
+ 8, 8, // 8x8
+ 4096, // # of tiles
+ 4, // 4bpp
+ { 0, 1, 2, 3 }, // plane offsets
+ { 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4 }, // X offsets
+ { 0*8*4, 1*8*4, 2*8*4, 3*8*4, 4*8*4, 5*8*4, 6*8*4, 7*8*4 }, // Y offsets
+ 8*8*4
+ };
+
+ K055673_vh_start(machine, REGION_GFX2, 1, -8, 15, rng_sprite_callback);
+
+ K053936_wraparound_enable(0, 0);
+ K053936_set_offset(0, 34, 9);
+
+ rng_936_tilemap = tilemap_create(get_rng_936_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 128, 128);
+ tilemap_set_transparent_pen(rng_936_tilemap, 0);
+
+ /* find first empty slot to decode gfx */
+ for (ttl_gfx_index = 0; ttl_gfx_index < MAX_GFX_ELEMENTS; ttl_gfx_index++)
+ if (machine->gfx[ttl_gfx_index] == 0)
+ break;
+
+ assert(ttl_gfx_index != MAX_GFX_ELEMENTS);
+
+ // decode the ttl layer's gfx
+ machine->gfx[ttl_gfx_index] = allocgfx(&charlayout);
+ decodegfx(machine->gfx[ttl_gfx_index], memory_region(REGION_GFX3), 0, machine->gfx[ttl_gfx_index]->total_elements);
+
+ if (machine->drv->color_table_len)
+ machine->gfx[ttl_gfx_index]->total_colors = machine->drv->color_table_len / 16;
+ else
+ machine->gfx[ttl_gfx_index]->total_colors = machine->drv->total_colors / 16;
+
+ // create the tilemap
+ ttl_tilemap = tilemap_create(ttl_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ tilemap_set_transparent_pen(ttl_tilemap, 0);
+
+ state_save_register_global_array(ttl_vram);
+
+ sprite_colorbase = 0x20;
+}
+
+VIDEO_UPDATE(rng)
+{
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ K053936_0_zoom_draw(bitmap, cliprect, rng_936_tilemap, 0, 0);
+
+ K053247_sprites_draw(machine, bitmap, cliprect);
+
+ tilemap_mark_all_tiles_dirty(ttl_tilemap);
+ tilemap_draw(bitmap, cliprect, ttl_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/sauro.c b/src/mame/video/sauro.c
new file mode 100644
index 00000000000..14715804ab9
--- /dev/null
+++ b/src/mame/video/sauro.c
@@ -0,0 +1,217 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *tecfri_videoram;
+UINT8 *tecfri_colorram;
+UINT8 *tecfri_videoram2;
+UINT8 *tecfri_colorram2;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+/* General */
+
+WRITE8_HANDLER( tecfri_videoram_w )
+{
+ tecfri_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( tecfri_colorram_w )
+{
+ tecfri_colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( tecfri_videoram2_w )
+{
+ tecfri_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( tecfri_colorram2_w )
+{
+ tecfri_colorram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( tecfri_scroll_bg_w )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, data);
+}
+
+static TILE_GET_INFO( get_tile_info_bg )
+{
+ int code = tecfri_videoram[tile_index] + ((tecfri_colorram[tile_index] & 0x07) << 8);
+ int color = (tecfri_colorram[tile_index] >> 4) & 0x0f;
+ int flags = tecfri_colorram[tile_index] & 0x08 ? TILE_FLIPX : 0;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+static TILE_GET_INFO( get_tile_info_fg )
+{
+ int code = tecfri_videoram2[tile_index] + ((tecfri_colorram2[tile_index] & 0x07) << 8);
+ int color = (tecfri_colorram2[tile_index] >> 4) & 0x0f;
+ int flags = tecfri_colorram2[tile_index] & 0x08 ? TILE_FLIPX : 0;
+
+ SET_TILE_INFO(1, code, color, flags);
+}
+
+/* Sauro */
+
+static int scroll2_map [8] = {2, 1, 4, 3, 6, 5, 0, 7};
+static int scroll2_map_flip[8] = {0, 7, 2, 1, 4, 3, 6, 5};
+
+WRITE8_HANDLER( sauro_scroll_fg_w )
+{
+ int *map = (flip_screen ? scroll2_map_flip : scroll2_map);
+ int scroll = (data & 0xf8) | map[data & 7];
+
+ tilemap_set_scrollx(fg_tilemap, 0, scroll);
+}
+
+VIDEO_START( sauro )
+{
+ bg_tilemap = tilemap_create(get_tile_info_bg, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ fg_tilemap = tilemap_create(get_tile_info_fg, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+static void sauro_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs,code,sx,sy,color,flipx;
+
+ for (offs = 3;offs < spriteram_size - 1;offs += 4)
+ {
+ sy = spriteram[offs];
+ if (sy == 0xf8) continue;
+
+ code = spriteram[offs+1] + ((spriteram[offs+3] & 0x03) << 8);
+ sx = spriteram[offs+2];
+ sy = 236 - sy;
+ color = (spriteram[offs+3] >> 4) & 0x0f;
+
+ // I'm not really sure how this bit works
+ if (spriteram[offs+3] & 0x08)
+ {
+ if (sx > 0xc0)
+ {
+ // Sign extend
+ sx = (signed int)(signed char)sx;
+ }
+ }
+ else
+ {
+ if (sx < 0x40) continue;
+ }
+
+ flipx = spriteram[offs+3] & 0x04;
+
+ if (flip_screen)
+ {
+ flipx = !flipx;
+ sx = (235 - sx) & 0xff; // The &0xff is not 100% percent correct
+ sy = 240 - sy;
+ }
+
+ drawgfx(bitmap, machine->gfx[2],
+ code,
+ color,
+ flipx,flip_screen,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( sauro )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ sauro_draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
+
+/* Tricky Doc */
+
+WRITE8_HANDLER ( trckydoc_spriteram_mirror_w )
+{
+ spriteram[offset] = data;
+}
+
+VIDEO_START( trckydoc )
+{
+ bg_tilemap = tilemap_create(get_tile_info_bg, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void trckydoc_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs,code,sy,color,flipx,sx;
+
+ /* Weird, sprites entries don't start on DWORD boundary */
+ for (offs = 3;offs < spriteram_size - 1;offs += 4)
+ {
+ sy = spriteram[offs];
+
+ if(spriteram[offs+3] & 0x08)
+ {
+ /* needed by the elevator cable (2nd stage), balls bouncing (3rd stage) and maybe other things */
+ sy += 6;
+ }
+
+ code = spriteram[offs+1] + ((spriteram[offs+3] & 0x01) << 8);
+
+ sx = spriteram[offs+2]-2;
+ color = (spriteram[offs+3] >> 4) & 0x0f;
+
+ sy = 236 - sy;
+
+ /* similar to sauro but different bit is used .. */
+ if (spriteram[offs+3] & 0x02)
+ {
+ if (sx > 0xc0)
+ {
+ /* Sign extend */
+ sx = (signed int)(signed char)sx;
+ }
+ }
+ else
+ {
+ if (sx < 0x40) continue;
+ }
+
+ flipx = spriteram[offs+3] & 0x04;
+
+ if (flip_screen)
+ {
+ flipx = !flipx;
+ sx = (235 - sx) & 0xff; /* The &0xff is not 100% percent correct */
+ sy = 240 - sy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1],
+ code,
+ color,
+ flipx,flip_screen,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( trckydoc )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ trckydoc_draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/sbasketb.c b/src/mame/video/sbasketb.c
new file mode 100644
index 00000000000..409c15f1698
--- /dev/null
+++ b/src/mame/video/sbasketb.c
@@ -0,0 +1,173 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+//UINT8 *sbasketb_scroll;
+UINT8 *sbasketb_palettebank;
+UINT8 *sbasketb_spriteram_select;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Super Basketball has three 256x4 palette PROMs (one per gun) and two 256x4
+ lookup table PROMs (one for characters, one for sprites).
+ I don't know for sure how the palette PROMs are connected to the RGB
+ output, but it's probably the usual:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+PALETTE_INIT( sbasketb )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the character lookup table */
+
+
+ /* characters use colors 240-255 */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = (*(color_prom++) & 0x0f) + 240;
+
+ /* sprites use colors 0-256 (?) in 16 banks */
+ for (i = 0;i < TOTAL_COLORS(1)/16;i++)
+ {
+ int j;
+
+
+ for (j = 0;j < 16;j++)
+ COLOR(1,i + j * TOTAL_COLORS(1)/16) = (*color_prom & 0x0f) + 16 * j;
+
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( sbasketb_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( sbasketb_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( sbasketb_flipscreen_w )
+{
+ if (flip_screen != data)
+ {
+ flip_screen_set(data);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( sbasketb_scroll_w )
+{
+ int col;
+
+ for (col = 6; col < 32; col++)
+ {
+ tilemap_set_scrolly(bg_tilemap, col, data);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + ((colorram[tile_index] & 0x20) << 3);
+ int color = colorram[tile_index] & 0x0f;
+ int flags = ((colorram[tile_index] & 0x40) ? TILE_FLIPX : 0) | ((colorram[tile_index] & 0x80) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( sbasketb )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs = (*sbasketb_spriteram_select & 0x01) * 0x100;
+ int i;
+
+ for (i = 0; i < 64; i++, offs += 4)
+ {
+ int sx = spriteram[offs + 2];
+ int sy = spriteram[offs + 3];
+
+ if (sx || sy)
+ {
+ int code = spriteram[offs + 0] | ((spriteram[offs + 1] & 0x20) << 3);
+ int color = (spriteram[offs + 1] & 0x0f) + 16 * *sbasketb_palettebank;
+ int flipx = spriteram[offs + 1] & 0x40;
+ int flipy = spriteram[offs + 1] & 0x80;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code, color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+ }
+}
+
+VIDEO_UPDATE( sbasketb )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/sbrkout.c b/src/mame/video/sbrkout.c
new file mode 100644
index 00000000000..66bfc01dc3e
--- /dev/null
+++ b/src/mame/video/sbrkout.c
@@ -0,0 +1,58 @@
+/*************************************************************************
+
+ Atari Super Breakout hardware
+
+*************************************************************************/
+
+#include "driver.h"
+#include "includes/sbrkout.h"
+
+UINT8 *sbrkout_horiz_ram;
+UINT8 *sbrkout_vert_ram;
+
+static tilemap *bg_tilemap;
+
+WRITE8_HANDLER( sbrkout_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = (videoram[tile_index] & 0x80) ? videoram[tile_index] : 0;
+
+ SET_TILE_INFO(0, code, 0, 0);
+}
+
+VIDEO_START( sbrkout )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_balls(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int ball;
+
+ for (ball=2; ball>=0; ball--)
+ {
+ int code = ((sbrkout_vert_ram[ball * 2 + 1] & 0x80) >> 7);
+ int sx = 31 * 8 - sbrkout_horiz_ram[ball * 2];
+ int sy = 30 * 8 - sbrkout_vert_ram[ball * 2];
+
+ drawgfx(bitmap, machine->gfx[1],
+ code, 0,
+ 0, 0,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( sbrkout )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_balls(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/sbugger.c b/src/mame/video/sbugger.c
new file mode 100644
index 00000000000..f1ebb08c3ff
--- /dev/null
+++ b/src/mame/video/sbugger.c
@@ -0,0 +1,60 @@
+/* Space Bugger - Video Hardware */
+
+#include "driver.h"
+
+extern UINT8* sbugger_videoram, *sbugger_videoram_attr;
+
+static tilemap *sbugger_tilemap;
+
+static TILE_GET_INFO( get_sbugger_tile_info )
+{
+ int tileno, color;
+
+ tileno = sbugger_videoram[tile_index];
+ color = sbugger_videoram_attr[tile_index];
+
+ SET_TILE_INFO(0,tileno,color,0);
+}
+
+WRITE8_HANDLER( sbugger_videoram_w )
+{
+ sbugger_videoram[offset] = data;
+ tilemap_mark_tile_dirty(sbugger_tilemap,offset);
+}
+
+WRITE8_HANDLER( sbugger_videoram_attr_w )
+{
+ sbugger_videoram_attr[offset] = data;
+ tilemap_mark_tile_dirty(sbugger_tilemap,offset);
+}
+
+VIDEO_START(sbugger)
+{
+ sbugger_tilemap = tilemap_create(get_sbugger_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 16,64,16);
+}
+
+VIDEO_UPDATE(sbugger)
+{
+ tilemap_draw(bitmap,cliprect,sbugger_tilemap,0,0);
+ return 0;
+}
+
+/* not right but so we can see things ok */
+PALETTE_INIT(sbugger)
+{
+ /* just some random colours for now */
+ int i;
+
+ for (i = 0;i < 256;i++)
+ {
+ int r = mame_rand(machine)|0x80;
+ int g = mame_rand(machine)|0x80;
+ int b = mame_rand(machine)|0x80;
+ if (i == 0) r = g = b = 0;
+
+ palette_set_color(machine,i*2+1,MAKE_RGB(r,g,b));
+ palette_set_color(machine,i*2,MAKE_RGB(0,0,0));
+
+ }
+
+}
diff --git a/src/mame/video/scotrsht.c b/src/mame/video/scotrsht.c
new file mode 100644
index 00000000000..c919099770e
--- /dev/null
+++ b/src/mame/video/scotrsht.c
@@ -0,0 +1,169 @@
+#include "driver.h"
+
+UINT8 *scotrsht_scroll;
+
+static tilemap *bg_tilemap;
+static int scotrsht_charbank = 0;
+static int scotrsht_palette_bank = 0;
+
+/* Similar as Iron Horse */
+PALETTE_INIT( scotrsht )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the character lookup table */
+
+
+ /* there are eight 16 colors palette banks; sprites use colors 0x00-0x7f and */
+ /* characters 0x80-0xff. */
+ for (i = 0;i < TOTAL_COLORS(0)/8;i++)
+ {
+ int j;
+
+
+ for (j = 0;j < 8;j++)
+ COLOR(0,i + j * TOTAL_COLORS(0)/8) = (*color_prom & 0x0f) + 16 * j + 0x80;
+
+ color_prom++;
+ }
+
+ for (i = 0;i < TOTAL_COLORS(1)/8;i++)
+ {
+ int j;
+
+
+ for (j = 0;j < 8;j++)
+ COLOR(1,i + j * TOTAL_COLORS(1)/8) = (*color_prom & 0x0f) + 16 * j;
+
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( scotrsht_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( scotrsht_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( scotrsht_charbank_w )
+{
+ if (scotrsht_charbank != (data & 0x01))
+ {
+ scotrsht_charbank = data & 0x01;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ /* other bits unknown */
+}
+
+WRITE8_HANDLER( scotrsht_palettebank_w )
+{
+ if(scotrsht_palette_bank != ((data & 0x70) >> 4))
+ {
+ scotrsht_palette_bank = ((data & 0x70) >> 4);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ coin_counter_w(0, data & 1);
+ coin_counter_w(1, data & 2);
+
+ // data & 4 unknown
+}
+
+
+static TILE_GET_INFO( scotrsht_get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + (scotrsht_charbank << 9) + ((attr & 0x40) << 2);
+ int color = (attr & 0x0f) + scotrsht_palette_bank * 16;
+ int flag = 0;
+
+ if(attr & 0x10) flag |= TILE_FLIPX;
+ if(attr & 0x20) flag |= TILE_FLIPY;
+
+ // data & 0x80 -> tile priority?
+
+ SET_TILE_INFO(0, code, color, flag);
+}
+
+/* Same as Jailbreak + palette bank */
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int i;
+
+ for (i = 0; i < spriteram_size; i += 4)
+ {
+ int attr = spriteram[i + 1]; // attributes = ?tyxcccc
+ int code = spriteram[i] + ((attr & 0x40) << 2);
+ int color = (attr & 0x0f) + scotrsht_palette_bank * 16;
+ int flipx = attr & 0x10;
+ int flipy = attr & 0x20;
+ int sx = spriteram[i + 2] - ((attr & 0x80) << 1);
+ int sy = spriteram[i + 3];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy,
+ sx, sy, cliprect, TRANSPARENCY_COLOR, scotrsht_palette_bank * 16);
+ }
+}
+
+VIDEO_START( scotrsht )
+{
+ bg_tilemap = tilemap_create(scotrsht_get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ tilemap_set_scroll_cols(bg_tilemap, 64);
+}
+
+VIDEO_UPDATE( scotrsht )
+{
+ int col;
+
+ for (col = 0; col < 32; col++)
+ tilemap_set_scrolly(bg_tilemap, col, scotrsht_scroll[col]);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/sderby.c b/src/mame/video/sderby.c
new file mode 100644
index 00000000000..c9cc5e5f485
--- /dev/null
+++ b/src/mame/video/sderby.c
@@ -0,0 +1,142 @@
+#include "driver.h"
+
+static tilemap *sderby_tilemap;
+extern UINT16 *sderby_videoram;
+
+static tilemap *sderby_md_tilemap;
+extern UINT16 *sderby_md_videoram;
+
+static tilemap *sderby_fg_tilemap;
+extern UINT16 *sderby_fg_videoram;
+
+/* BG Layer */
+
+static TILE_GET_INFO( get_sderby_tile_info )
+{
+ int tileno,colour;
+
+ tileno = sderby_videoram[tile_index*2];
+ colour = sderby_videoram[tile_index*2+1] & 0x0f;
+
+ SET_TILE_INFO(1,tileno,colour,0);
+}
+
+WRITE16_HANDLER( sderby_videoram_w )
+{
+ COMBINE_DATA(&sderby_videoram[offset]);
+ tilemap_mark_tile_dirty(sderby_tilemap,offset/2);
+}
+
+/* MD Layer */
+
+static TILE_GET_INFO( get_sderby_md_tile_info )
+{
+ int tileno,colour;
+
+ tileno = sderby_md_videoram[tile_index*2];
+ colour = sderby_md_videoram[tile_index*2+1] & 0x0f;
+
+ SET_TILE_INFO(1,tileno,colour+16,0);
+}
+
+WRITE16_HANDLER( sderby_md_videoram_w )
+{
+ COMBINE_DATA(&sderby_md_videoram[offset]);
+ tilemap_mark_tile_dirty(sderby_md_tilemap,offset/2);
+}
+
+/* FG Layer */
+
+static TILE_GET_INFO( get_sderby_fg_tile_info )
+{
+ int tileno,colour;
+
+ tileno = sderby_fg_videoram[tile_index*2];
+ colour = sderby_fg_videoram[tile_index*2+1] & 0x0f;
+
+ SET_TILE_INFO(0,tileno,colour+32,0);
+}
+
+WRITE16_HANDLER( sderby_fg_videoram_w )
+{
+ COMBINE_DATA(&sderby_fg_videoram[offset]);
+ tilemap_mark_tile_dirty(sderby_fg_tilemap,offset/2);
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int codeshift)
+{
+ int offs;
+ int height = machine->gfx[0]->height;
+ int colordiv = machine->gfx[0]->color_granularity / 16;
+
+ for (offs = 4;offs < spriteram_size/2;offs += 4)
+ {
+ int sx,sy,code,color,flipx;
+
+ sy = spriteram16[offs+3-4]; /* -4? what the... ??? */
+ if (sy == 0x2000) return; /* end of list marker */
+
+ flipx = sy & 0x4000;
+ sx = (spriteram16[offs+1] & 0x01ff) - 16-7;
+ sy = (256-8-height - sy) & 0xff;
+ code = spriteram16[offs+2] >> codeshift;
+ color = (spriteram16[offs+1] & 0x3e00) >> 9;
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color/colordiv+48,
+ flipx,0,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+VIDEO_START( sderby )
+{
+ sderby_tilemap = tilemap_create(get_sderby_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+ sderby_md_tilemap = tilemap_create(get_sderby_md_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+
+ tilemap_set_transparent_pen(sderby_md_tilemap,0);
+
+ sderby_fg_tilemap = tilemap_create(get_sderby_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ tilemap_set_transparent_pen(sderby_fg_tilemap,0);
+}
+
+VIDEO_UPDATE( sderby )
+{
+ tilemap_draw(bitmap,cliprect,sderby_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,sderby_md_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,sderby_fg_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( pmroulet )
+{
+ tilemap_draw(bitmap,cliprect,sderby_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,sderby_md_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,sderby_fg_tilemap,0,0);
+ return 0;
+}
+
+
+WRITE16_HANDLER( sderby_scroll_w )
+{
+ static UINT16 scroll[6];
+
+
+ data = COMBINE_DATA(&scroll[offset]);
+
+ switch (offset)
+ {
+ case 0: tilemap_set_scrollx(sderby_fg_tilemap,0,data+2);break;
+ case 1: tilemap_set_scrolly(sderby_fg_tilemap,0,data-8);break;
+ case 2: tilemap_set_scrollx(sderby_md_tilemap,0,data+4);break;
+ case 3: tilemap_set_scrolly(sderby_md_tilemap,0,data-8);break;
+ case 4: tilemap_set_scrollx(sderby_tilemap,0,data+6); break;
+ case 5: tilemap_set_scrolly(sderby_tilemap,0,data-8); break;
+ }
+}
diff --git a/src/mame/video/segag80r.c b/src/mame/video/segag80r.c
new file mode 100644
index 00000000000..c91bcddb311
--- /dev/null
+++ b/src/mame/video/segag80r.c
@@ -0,0 +1,865 @@
+/***************************************************************************
+
+ Sega G-80 raster hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "segag80r.h"
+#include "rescap.h"
+#include "video/resnet.h"
+
+UINT8 segag80r_background_pcb;
+
+static double rweights[3], gweights[3], bweights[2];
+
+static UINT8 *dirtychar;
+static UINT8 video_control;
+static UINT8 video_flip;
+static UINT8 vblank_latch;
+
+static tilemap *spaceod_bg_htilemap;
+static tilemap *spaceod_bg_vtilemap;
+static UINT16 spaceod_hcounter;
+static UINT16 spaceod_vcounter;
+static UINT8 spaceod_fixed_color;
+static UINT8 spaceod_bg_control;
+static UINT8 spaceod_bg_detect;
+static UINT8 spaceod_bg_detect_tile_color = 1;
+
+static tilemap *bg_tilemap;
+static UINT8 bg_enable;
+static UINT8 bg_char_bank;
+static UINT16 bg_scrollx, bg_scrolly;
+
+static UINT8 pignewt_bg_color_offset;
+
+
+
+/*************************************
+ *
+ * VBLANK handling
+ *
+ *************************************/
+
+static TIMER_CALLBACK( vblank_latch_clear )
+{
+ vblank_latch = 0;
+}
+
+
+static void vblank_latch_set(void)
+{
+ /* set a timer to mimic the 555 timer that drives the EDGINT signal */
+ /* the 555 is run in monostable mode with R=56000 and C=1000pF */
+ vblank_latch = 1;
+ timer_set(PERIOD_OF_555_MONOSTABLE(CAP_P(1000), RES_K(56)), 0, vblank_latch_clear);
+
+ /* latch the current flip state at the same time */
+ video_flip = video_control & 1;
+}
+
+
+INTERRUPT_GEN( segag80r_vblank_start )
+{
+ vblank_latch_set();
+
+ /* if interrupts are enabled, clock one */
+ if (video_control & 0x04)
+ irq0_line_hold();
+}
+
+
+INTERRUPT_GEN( sindbadm_vblank_start )
+{
+ vblank_latch_set();
+
+ /* interrupts appear to always be enabled, but they have a manual */
+ /* acknowledge rather than an automatic ack; they are also not masked */
+ /* by bit 2 of video_control like a standard G80 */
+ irq0_line_assert();
+}
+
+
+
+/*************************************
+ *
+ * Palette conversion
+ *
+ *************************************/
+
+static void g80_set_palette_entry(int entry, UINT8 data)
+{
+ int bit0, bit1, bit2;
+ int r, g, b;
+
+ /* extract the raw RGB bits */
+ r = (data & 0x07) >> 0;
+ g = (data & 0x38) >> 3;
+ b = (data & 0xc0) >> 6;
+
+ /* red component */
+ bit0 = (r >> 0) & 0x01;
+ bit1 = (r >> 1) & 0x01;
+ bit2 = (r >> 2) & 0x01;
+ r = combine_3_weights(rweights, bit0, bit1, bit2);
+
+ /* green component */
+ bit0 = (g >> 0) & 0x01;
+ bit1 = (g >> 1) & 0x01;
+ bit2 = (g >> 2) & 0x01;
+ g = combine_3_weights(gweights, bit0, bit1, bit2);
+
+ /* blue component */
+ bit0 = (b >> 0) & 0x01;
+ bit1 = (b >> 1) & 0x01;
+ b = combine_2_weights(bweights, bit0, bit1);
+
+ palette_set_color(Machine, entry, MAKE_RGB(r, g, b));
+}
+
+
+static void spaceod_bg_init_palette(running_machine *machine)
+{
+ static const int resistances[2] = { 1800, 1200 };
+ double trweights[2], tgweights[2], tbweights[2];
+ int i;
+
+ /* compute the color output resistor weights at startup */
+ compute_resistor_weights(0, 255, -1.0,
+ 2, resistances, trweights, 220, 0,
+ 2, resistances, tgweights, 220, 0,
+ 2, resistances, tbweights, 220, 0);
+
+ /* initialize the fixed background palette */
+ for (i = 0; i < 64; i++)
+ {
+ int bit0, bit1;
+ int r, g, b;
+
+ /* extract the raw RGB bits */
+ r = (i & 0x30) >> 4;
+ g = (i & 0x0c) >> 2;
+ b = (i & 0x03) >> 0;
+
+ /* red component */
+ bit0 = (r >> 0) & 0x01;
+ bit1 = (r >> 1) & 0x01;
+ r = combine_2_weights(trweights, bit0, bit1);
+
+ /* green component */
+ bit0 = (g >> 0) & 0x01;
+ bit1 = (g >> 1) & 0x01;
+ g = combine_2_weights(tgweights, bit0, bit1);
+
+ /* blue component */
+ bit0 = (b >> 0) & 0x01;
+ bit1 = (b >> 1) & 0x01;
+ b = combine_2_weights(tbweights, bit0, bit1);
+
+ palette_set_color(machine, 64 + i, MAKE_RGB(r, g, b));
+ }
+}
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( spaceod_get_tile_info )
+{
+ int code = memory_region(REGION_GFX2)[tile_index + 0x1000 * (spaceod_bg_control >> 6)];
+ SET_TILE_INFO(1, code + 0x100 * ((spaceod_bg_control >> 2) & 1), 0, 0);
+}
+
+
+static TILEMAP_MAPPER( spaceod_scan_rows )
+{
+ /* this works for both horizontal and vertical tilemaps */
+ /* which are 4 32x32 sections */
+ return (row & 31) * 32 + (col & 31) + ((row >> 5) * 32*32) + ((col >> 5) * 32*32);
+}
+
+
+static TILE_GET_INFO( bg_get_tile_info )
+{
+ int code = memory_region(REGION_GFX2)[tile_index];
+ SET_TILE_INFO(1, code + 0x100 * bg_char_bank, code >> 4, 0);
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( segag80r )
+{
+ static const int rg_resistances[3] = { 4700, 2400, 1200 };
+ static const int b_resistances[2] = { 2000, 1000 };
+
+ /* compute the color output resistor weights at startup */
+ compute_resistor_weights(0, 255, -1.0,
+ 3, rg_resistances, rweights, 220, 0,
+ 3, rg_resistances, gweights, 220, 0,
+ 2, b_resistances, bweights, 220, 0);
+
+ /* allocate paletteram */
+ dirtychar = auto_malloc(256);
+ memset(dirtychar, 1, 256);
+
+ /* allocate paletteram */
+ paletteram = auto_malloc(0x80);
+
+ /* initialize the particulars for each type of background PCB */
+ switch (segag80r_background_pcb)
+ {
+ /* nothing to do here */
+ case G80_BACKGROUND_NONE:
+ break;
+
+ /* create a fixed background palette and two tilemaps, one horizontally scrolling */
+ /* and one vertically scrolling */
+ case G80_BACKGROUND_SPACEOD:
+ spaceod_bg_init_palette(machine);
+ spaceod_bg_htilemap = tilemap_create(spaceod_get_tile_info, spaceod_scan_rows, TILEMAP_TYPE_PEN, 8,8, 128,32);
+ spaceod_bg_vtilemap = tilemap_create(spaceod_get_tile_info, spaceod_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,128);
+ break;
+
+ /* background tilemap is effectively 1 screen x n screens */
+ case G80_BACKGROUND_MONSTERB:
+ bg_tilemap = tilemap_create(bg_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,memory_region_length(REGION_GFX2) / 32);
+ break;
+
+ /* background tilemap is effectively 4 screens x n screens */
+ case G80_BACKGROUND_PIGNEWT:
+ case G80_BACKGROUND_SINDBADM:
+ bg_tilemap = tilemap_create(bg_get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 128,memory_region_length(REGION_GFX2) / 128);
+ break;
+ }
+
+ /* register for save states */
+ state_save_register_global_pointer(paletteram, 0x80);
+
+ state_save_register_global(video_control);
+ state_save_register_global(video_flip);
+ state_save_register_global(vblank_latch);
+
+ state_save_register_global(spaceod_hcounter);
+ state_save_register_global(spaceod_vcounter);
+ state_save_register_global(spaceod_fixed_color);
+ state_save_register_global(spaceod_bg_control);
+ state_save_register_global(spaceod_bg_detect);
+
+ state_save_register_global(bg_enable);
+ state_save_register_global(bg_char_bank);
+ state_save_register_global(bg_scrollx);
+ state_save_register_global(bg_scrolly);
+
+ state_save_register_global(pignewt_bg_color_offset);
+}
+
+
+
+/*************************************
+ *
+ * Video RAM write
+ *
+ *************************************/
+
+WRITE8_HANDLER( segag80r_videoram_w )
+{
+ /* accesses to the upper half of VRAM go to paletteram if selected */
+ if ((offset & 0x1000) && (video_control & 0x02))
+ {
+ offset &= 0x3f;
+ paletteram[offset] = data;
+ g80_set_palette_entry(offset, data);
+ return;
+ }
+
+ /* all other accesses go to videoram */
+ videoram[offset] = data;
+
+ /* track which characters are dirty */
+ if (offset & 0x800)
+ dirtychar[(offset & 0x7ff) / 8] = TRUE;
+}
+
+
+
+/*************************************
+ *
+ * Video I board port accesses
+ *
+ *************************************/
+
+READ8_HANDLER( segag80r_video_port_r )
+{
+ if (offset == 0)
+ {
+ logerror("%04X:segag80r_video_port_r(%d)\n", activecpu_get_pc(), offset);
+ return 0xff;
+ }
+ else
+ {
+ /*
+ D0 = 555 timer output from U10 (goes to EDGINT as well)
+ D1 = current latched FLIP state
+ D2 = interrupt enable state
+ D3 = n/c
+ */
+ return (vblank_latch << 0) | (video_flip << 1) | (video_control & 0x04) | 0xf8;
+ }
+}
+
+
+WRITE8_HANDLER( segag80r_video_port_w )
+{
+ if (offset == 0)
+ {
+ logerror("%04X:segag80r_video_port_w(%d) = %02X\n", activecpu_get_pc(), offset, data);
+ }
+ else
+ {
+ /*
+ D0 = FLIP (latched at VSYNC)
+ D1 = if low, allows writes to the upper 4k of video RAM
+ = if high, allows writes to palette RAM
+ D2 = interrupt enable
+ D3 = n/c (used as flip by many background boards)
+ */
+ video_control = data;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Space Odyssey background borad
+ * port accesses
+ *
+ *************************************/
+
+READ8_HANDLER( spaceod_back_port_r )
+{
+ /* force an update to get the current detection value */
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ return 0xfe | spaceod_bg_detect;
+}
+
+
+WRITE8_HANDLER( spaceod_back_port_w )
+{
+ switch (offset & 7)
+ {
+ /* port 0: latches D0-D7 into LS377 at U39 (SH4)
+
+ d0 = counter direction: controls U/D on LS191 counters
+ d1 = horizontal (0) or vertical (1) scrolling
+ d2 = character bank (0/1)
+ d6 = background ROM select 0
+ d7 = background ROM select 1
+ */
+ case 0:
+ if ((spaceod_bg_control ^ data) & 0xc4)
+ {
+ tilemap_mark_all_tiles_dirty(spaceod_bg_htilemap);
+ tilemap_mark_all_tiles_dirty(spaceod_bg_vtilemap);
+ }
+ spaceod_bg_control = data;
+ break;
+
+ /* port 1: loads both H and V counters with 0 */
+ case 1:
+ spaceod_hcounter = 0;
+ spaceod_vcounter = 0;
+ break;
+
+ /* port 2: clocks either the H or V counters (based on port 0:d1) */
+ /* either up or down (based on port 0:d0) */
+ case 2:
+ if (!(spaceod_bg_control & 0x02))
+ {
+ if (!(spaceod_bg_control & 0x01))
+ spaceod_hcounter++;
+ else
+ spaceod_hcounter--;
+ }
+ else
+ {
+ if (!(spaceod_bg_control & 0x01))
+ spaceod_vcounter++;
+ else
+ spaceod_vcounter--;
+ }
+ break;
+
+ /* port 3: clears the background detection flag */
+ case 3:
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ spaceod_bg_detect = 0;
+ break;
+
+ /* port 4: enables (0)/disables (1) the background */
+ case 4:
+ bg_enable = data & 1;
+ break;
+
+ /* port 5: specifies fixed background color */
+ /* top two bits are not connected */
+ case 5:
+ spaceod_fixed_color = data & 0x3f;
+ break;
+
+ /* port 6: latches D0-D7 into LS377 at U37 -> CN1-11/12/13/14/15/16/17/18 */
+ /* port 7: latches D0-D5 into LS174 at U40 -> CN2-1/2/3/4/5/6 */
+ case 6:
+ case 7:
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Monster Bash background board
+ * accesses
+ *
+ *************************************/
+
+WRITE8_HANDLER( monsterb_videoram_w )
+{
+ /* accesses to the the area $f040-$f07f go to background palette if */
+ /* the palette access enable bit is set */
+ if ((offset & 0x1fc0) == 0x1040 && (video_control & 0x40))
+ {
+ offs_t paloffs = offset & 0x3f;
+ paletteram[paloffs | 0x40] = data;
+ g80_set_palette_entry(paloffs | 0x40, data);
+ /* note that since the background board is not integrated with the main board */
+ /* writes here also write through to regular videoram */
+ }
+
+ /* handle everything else */
+ segag80r_videoram_w(offset, data);
+}
+
+
+WRITE8_HANDLER( monsterb_back_port_w )
+{
+ switch (offset & 7)
+ {
+ /* port 0: not used (looks like latches for C7-C10 = background color) */
+ case 0:
+ break;
+
+ /* port 1: not used (looks like comparator tile color value for collision detect) */
+ case 1:
+ break;
+
+ /* port 2: not connected */
+ /* port 3: not connected */
+ case 2:
+ case 3:
+ break;
+
+ /* port 4: main control latch
+
+ d0 = CG0 - BG MSB ROM bank select bit 0
+ d1 = CG1 - BG MSB ROM bank select bit 1
+ d2 = CG2 - BG LSB ROM bank select bit 0
+ d3 = CG3 - BG LSB ROM bank select bit 1
+ d4 = SCN0 - background select bit 0
+ d5 = SCN1 - background select bit 1
+ d6 = SCN2 - background select bit 2
+ d7 = BKGEN - background enable
+ */
+ case 4:
+ if ((bg_char_bank ^ data) & 0x0f)
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ bg_char_bank = data & 0x0f;
+ bg_scrolly = (data << 4) & 0x700;
+ bg_enable = data & 0x80;
+ break;
+
+ /* port 5: not connected */
+ case 5:
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Pig Newton/Monster Bash 2-board
+ * background accesses
+ *
+ *************************************/
+
+WRITE8_HANDLER( pignewt_videoram_w )
+{
+ /* accesses to the the area $f040-$f07f go to background palette if */
+ /* the palette access enable bit is set */
+ if ((offset & 0x1fc0) == 0x1040 && (video_control & 0x02))
+ {
+ offs_t paloffs = offset & 0x3f;
+ paletteram[paloffs | 0x40] = data;
+ g80_set_palette_entry(paloffs | 0x40, data);
+ return;
+ }
+
+ /* handle everything else */
+ segag80r_videoram_w(offset, data);
+}
+
+
+WRITE8_HANDLER( pignewt_back_color_w )
+{
+ /* it is not really known what this does */
+ if (offset == 0)
+ pignewt_bg_color_offset = data;
+ else
+ logerror("pignewt_back_color_w(%d) = %02X\n", pignewt_bg_color_offset, data);
+}
+
+
+WRITE8_HANDLER( pignewt_back_port_w )
+{
+ switch (offset & 7)
+ {
+ /* port 0: scroll offset low */
+ case 0:
+ bg_scrollx = (bg_scrollx & 0x300) | data;
+ break;
+
+ /* port 1: scroll offset high */
+ case 1:
+ bg_scrollx = (bg_scrollx & 0x0ff) | ((data << 8) & 0x300);
+ bg_enable = data & 0x80;
+ break;
+
+ /* port 2: scroll offset low */
+ case 2:
+ bg_scrolly = (bg_scrolly & 0x300) | data;
+ break;
+
+ /* port 3: scroll offset high */
+ case 3:
+ bg_scrolly = (bg_scrolly & 0x0ff) | ((data << 8) & 0x300);
+ break;
+
+ /* port 4: background character bank control
+
+ d0 = CG0 - BG MSB ROM bank select bit 0
+ d1 = CG1 - BG MSB ROM bank select bit 1
+ d2 = CG2 - BG LSB ROM bank select bit 0
+ d3 = CG3 - BG LSB ROM bank select bit 1
+
+ at least, that's the theory; however, monster2 sets this = 0x03 wanting
+ bank 1, so I'm assuming that only d3 and d0 really matter
+ */
+ case 4:
+ data = (data & 0x09) | ((data >> 2) & 0x02) | ((data << 2) & 0x04);
+ if ((bg_char_bank ^ data) & 0x0f)
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ bg_char_bank = data & 0x0f;
+ break;
+
+ /* port 5: not connected? */
+ case 5:
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Sindbad Mystery background accesses
+ *
+ *************************************/
+
+WRITE8_HANDLER( sindbadm_videoram_w )
+{
+ /* accesses to the the area $f000-$f03f go to background palette if */
+ /* the palette access enable bit is set */
+ if ((offset & 0x1fc0) == 0x1000 && (video_control & 0x02))
+ {
+ offs_t paloffs = offset & 0x3f;
+ paletteram[paloffs | 0x40] = data;
+ g80_set_palette_entry(paloffs | 0x40, data);
+ return;
+ }
+
+ /* handle everything else */
+ segag80r_videoram_w(offset, data);
+}
+
+
+WRITE8_HANDLER( sindbadm_back_port_w )
+{
+ switch (offset & 3)
+ {
+ /* port 0: irq ack */
+ case 0:
+ cpunum_set_input_line(0, 0, CLEAR_LINE);
+ break;
+
+ /* port 1: background control
+
+ d0 = BG ROM bank select bit 0
+ d1 = BG ROM bank select bit 1
+ d2 = BG page select (X scroll bit 0)
+ d3 = BG page select (X scroll bit 1)
+ d4 = BG page select (Y scroll bit 0)
+ d5 = BG page select (Y scroll bit 1)
+ d6 = BG page select (Y scroll bit 2)
+ d7 = BG enable
+ */
+ case 1:
+ bg_enable = data & 0x80;
+ bg_scrollx = (data << 6) & 0x300;
+ bg_scrolly = (data << 4) & 0x700;
+ if ((bg_char_bank ^ data) & 0x03)
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ bg_char_bank = data & 0x03;
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video I videoram rendering
+ *
+ *************************************/
+
+static void draw_videoram(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, const UINT8 *transparent_pens)
+{
+ int flipmask = video_flip ? 0x1f : 0x00;
+ int x, y;
+
+ /* iterate over the screen and draw visible tiles */
+ for (y = cliprect->min_y / 8; y <= cliprect->max_y / 8; y++)
+ {
+ int effy = video_flip ? 27 - y : y;
+ for (x = cliprect->min_x / 8; x <= cliprect->max_x / 8; x++)
+ {
+ int offs = effy * 32 + (x ^ flipmask);
+ UINT8 tile = videoram[offs];
+
+ /* if the tile is dirty, decode it */
+ if (dirtychar[tile])
+ {
+ decodechar(machine->gfx[0], tile, &videoram[0x800], machine->drv->gfxdecodeinfo[0].gfxlayout);
+ dirtychar[tile] = 0;
+ }
+
+ /* draw the tile */
+ drawgfx(bitmap, machine->gfx[0], tile, tile >> 4, video_flip, video_flip, x*8, y*8, cliprect, TRANSPARENCY_PENS, transparent_pens[tile >> 4]);
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Space Odyssey background rendering
+ *
+ *************************************/
+
+static void draw_background_spaceod(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ mame_bitmap *pixmap = tilemap_get_pixmap(!(spaceod_bg_control & 0x02) ? spaceod_bg_htilemap : spaceod_bg_vtilemap);
+ int flipmask = (spaceod_bg_control & 0x01) ? 0xff : 0x00;
+ int xoffset = (spaceod_bg_control & 0x02) ? 0x10 : 0x00;
+ int xmask = pixmap->width - 1;
+ int ymask = pixmap->height - 1;
+ int x, y;
+
+ /* The H and V counters on this board are independent of the ones on */
+ /* the main board. The H counter starts counting from 0 when EXT BLK */
+ /* goes to 0; this coincides with H=0, so that's fine. However, the V */
+ /* counter starts counting from 0 when VSYNC=0, which happens at line */
+ /* 240, giving us an offset of (262-240) = 22 scanlines. */
+
+ /* now fill in the background wherever there are black pixels */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ int effy = (y + spaceod_vcounter + 22) ^ flipmask;
+ UINT16 *src = (UINT16 *)pixmap->base + (effy & ymask) * pixmap->rowpixels;
+ UINT16 *dst = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+
+ /* loop over horizontal pixels */
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ int effx = ((x + spaceod_hcounter) ^ flipmask) + xoffset;
+ UINT8 fgpix = paletteram[dst[x]];
+ UINT8 bgpix = src[effx & xmask] & 0x3f;
+
+ /* the background detect flag is set if:
+ - bgpix != 0 AND
+ - fgpix != 0 AND
+ - the original tile color == DIP switches
+ */
+ if (bgpix != 0 && fgpix != 0 && (dst[x] >> 2) == spaceod_bg_detect_tile_color)
+ spaceod_bg_detect = 1;
+
+ /* the background graphics are only displayed if:
+ - fgpix == 0 AND
+ - !EXTBLK (not blanked) AND
+ - bg_enable == 0
+ */
+ if (fgpix == 0 && bg_enable == 0)
+ dst[x] = bgpix | spaceod_fixed_color | 0x40;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Draw a background with only page
+ * granular scrolling
+ *
+ *************************************/
+
+static void draw_background_page_scroll(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ mame_bitmap *pixmap = tilemap_get_pixmap(bg_tilemap);
+ int flipmask = (video_control & 0x08) ? 0xff : 0x00;
+ int xmask = pixmap->width - 1;
+ int ymask = pixmap->height - 1;
+ int x, y;
+
+ /* if disabled, draw nothing */
+ if (!bg_enable)
+ {
+ fillbitmap(bitmap, 0, cliprect);
+ return;
+ }
+
+ /* now fill in the background wherever there are black pixels */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ int effy = bg_scrolly + (((y ^ flipmask) + (flipmask & 0xe0)) & 0xff);
+ UINT16 *src = (UINT16 *)pixmap->base + (effy & ymask) * pixmap->rowpixels;
+ UINT16 *dst = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+
+ /* loop over horizontal pixels */
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ int effx = bg_scrollx + (x ^ flipmask);
+ dst[x] = src[effx & xmask];
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Draw a background with full pixel
+ * level scrolling
+ *
+ *************************************/
+
+static void draw_background_full_scroll(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ mame_bitmap *pixmap = tilemap_get_pixmap(bg_tilemap);
+ int flipmask = (video_control & 0x08) ? 0x3ff : 0x000;
+ int xmask = pixmap->width - 1;
+ int ymask = pixmap->height - 1;
+ int x, y;
+
+ /* if disabled, draw nothing */
+ if (!bg_enable)
+ {
+ fillbitmap(bitmap, 0, cliprect);
+ return;
+ }
+
+ /* now fill in the background wherever there are black pixels */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ int effy = (y + bg_scrolly) ^ flipmask;
+ UINT16 *src = (UINT16 *)pixmap->base + (effy & ymask) * pixmap->rowpixels;
+ UINT16 *dst = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+
+ /* loop over horizontal pixels */
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ int effx = (x + bg_scrollx) ^ flipmask;
+ dst[x] = src[effx & xmask];
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Generic video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( segag80r )
+{
+ UINT8 transparent_pens[16];
+
+ switch (segag80r_background_pcb)
+ {
+ /* foreground: opaque */
+ /* background: none */
+ case G80_BACKGROUND_NONE:
+ memset(transparent_pens, 0, 16);
+ draw_videoram(machine, bitmap, cliprect, transparent_pens);
+ break;
+
+ /* foreground: visible except where black */
+ /* background: Space Odyssey special */
+ /* we draw the foreground first, then the background to do collision detection */
+ case G80_BACKGROUND_SPACEOD:
+ memset(transparent_pens, 0, 16);
+ draw_videoram(machine, bitmap, cliprect, transparent_pens);
+ draw_background_spaceod(bitmap, cliprect);
+ break;
+
+ /* foreground: visible except for pen 0 (this disagrees with schematics) */
+ /* background: page-granular scrolling */
+ case G80_BACKGROUND_MONSTERB:
+ memset(transparent_pens, 1, 16);
+ draw_background_page_scroll(bitmap, cliprect);
+ draw_videoram(machine, bitmap, cliprect, transparent_pens);
+ break;
+
+ /* foreground: visible except for pen 0 */
+ /* background: full scrolling */
+ case G80_BACKGROUND_PIGNEWT:
+ memset(transparent_pens, 1, 16);
+ draw_background_full_scroll(bitmap, cliprect);
+ draw_videoram(machine, bitmap, cliprect, transparent_pens);
+ break;
+
+ /* foreground: visible except for pen 0 */
+ /* background: page-granular scrolling */
+ case G80_BACKGROUND_SINDBADM:
+ memset(transparent_pens, 1, 16);
+ draw_background_page_scroll(bitmap, cliprect);
+ draw_videoram(machine, bitmap, cliprect, transparent_pens);
+ break;
+ }
+ return 0;
+}
diff --git a/src/mame/video/segag80v.c b/src/mame/video/segag80v.c
new file mode 100644
index 00000000000..42634261adf
--- /dev/null
+++ b/src/mame/video/segag80v.c
@@ -0,0 +1,343 @@
+/*************************************************************************
+
+ Sega vector hardware
+
+*************************************************************************/
+
+#include "driver.h"
+#include "avgdvg.h"
+#include "video/vector.h"
+#include "includes/segag80v.h"
+#include <math.h>
+
+#define VECTOR_CLOCK 15468480 /* master clock */
+#define U34_CLOCK (VECTOR_CLOCK/3) /* clock for interrupt chain */
+#define VCL_CLOCK (U34_CLOCK/2) /* clock for vector generator */
+#define U51_CLOCK (VCL_CLOCK/16) /* clock for phase generator */
+#define IRQ_CLOCK (U34_CLOCK/0x1f788) /* 40Hz interrupt */
+
+
+static int min_x, min_y;
+
+
+/*
+
+ Vector system is clocked by a 15-phase clock.
+
+ The counter is a LS161 4-bit binary counter at U51, and its output
+ goes to a LS154 1-of-16 decoder at U50.
+
+ Each phase various things happen. The phases are:
+
+ 0 -> (sheet 7/7) clocks CD7 in
+
+ 1 -> (sheet 5/7) loads CD0-7 into counters at U15/U16
+ (sheet 6/7) clear LS175 flip flops at U35, U36, U37, U38
+
+ 2 -> (sheet 5/7) loads CD0-3 into counter at U17
+
+ 3 -> (sheet 5/7) loads CD0-7 into counters at U18/U19
+
+ 4 -> (sheet 5/7) loads CD0-3 into counter at U20
+
+ 5 ->
+
+ 6 ->
+
+ 7 -> (sheet 6/7) at end, latches CD0-7 into LS374 tri-state flip flop at U55 (SYM angle)
+
+ 8 -> (sheet 6/7) at end, latches CD0-1 into LS74 flip flops at U26 (upper SYM angle)
+
+ 9 -> (sheet 4/7) at end, latches CD0-7 into 25LS14 multiplier X input at U8 (scale)
+
+ 10 -> (sheet 4/7) at end, latches CD0-CD7 into LS374 tri-state flip flop at U2 (attributes)
+ (sheet 7/7) at end, latches CD7 into U52 (low), which sets the preload value
+ for the LS161 at U51 to be either 0 (if CD7==1) or 10 (if CD7==0)
+
+ 11 -> (sheet 4/7) at end, starts multiply circuit
+
+ 12 -> (sheet 6/7) at end, latches CD0-7 into LS374 tri-state flip flop at U56 (VEC angle)
+
+ 13 -> (sheet 6/7) at end, latches output from 2708 PROM into tri-state flip flop at U48
+ (sheet 6/7) at end, latches bit $200 of angle into D/UX output
+
+ 14 -> (sheet 6/7) at end, latches output from 2708 PROM into tri-state flip flop at U49
+ (sheet 6/7) at end, latches bit $200 of angle into D/UY output
+ (sheet 7/7) signals /PE on the LS161 at U51, loading the new value for the state clock
+ (sheet 7/7) sets up the DRAW signal to clock on the next VCL edge
+
+ 15 ->
+
+
+
+ PROM inputs:
+ A0 = GND
+ A1-A8 = sum of VEC angle and SYM angle (low 8 bits)
+ A9 = sum of bit 8 of VEC angle and SYM angle, plus 1 for phase 13
+
+
+*/
+
+
+INLINE int adjust_xy(int rawx, int rawy, int *outx, int *outy)
+{
+ int clipped = FALSE;
+
+ /* first apply the XOR at 0x200 */
+ *outx = (rawx & 0x7ff) ^ 0x200;
+ *outy = (rawy & 0x7ff) ^ 0x200;
+
+ /* apply clipping logic to X */
+ if ((*outx & 0x600) == 0x200)
+ *outx = 0x000, clipped = TRUE;
+ else if ((*outx & 0x600) == 0x400)
+ *outx = 0x3ff, clipped = TRUE;
+ else
+ *outx &= 0x3ff;
+
+ /* apply clipping logic to Y */
+ if ((*outy & 0x600) == 0x200)
+ *outy = 0x000, clipped = TRUE;
+ else if ((*outy & 0x600) == 0x400)
+ *outy = 0x3ff, clipped = TRUE;
+ else
+ *outy &= 0x3ff;
+
+ /* convert into .16 values */
+ *outx = (*outx - (min_x - 512)) << 16;
+ *outy = (*outy - (min_y - 512)) << 16;
+ return clipped;
+}
+
+
+static void sega_generate_vector_list(void)
+{
+ UINT8 *sintable = memory_region(REGION_PROMS);
+ double total_time = 1.0 / (double)IRQ_CLOCK;
+ UINT16 symaddr = 0;
+
+ vector_clear_list();
+
+ /* Loop until we run out of time. */
+ while (total_time > 0)
+ {
+ UINT16 curx, cury, xaccum, yaccum;
+ UINT16 vecaddr, symangle;
+ UINT8 scale, draw;
+
+ /* The "draw" flag is clocked at the end of phase 0. */
+ draw = vectorram[symaddr++ & 0xfff];
+
+ /* The low byte of the X coordinate is latched into the */
+ /* up/down counters at U15/U16 during phase 1. */
+ curx = vectorram[symaddr++ & 0xfff];
+
+ /* The low 3 bits of the high byte of the X coordinate are */
+ /* latched into the up/down counter at U17 during phase 2. */
+ /* Bit 2 of the input is latched as both bit 2 and 3. */
+ curx |= (vectorram[symaddr++ & 0xfff] & 7) << 8;
+ curx |= (curx << 1) & 0x800;
+
+ /* The low byte of the Y coordinate is latched into the */
+ /* up/down counters at U18/U19 during phase 3. */
+ cury = vectorram[symaddr++ & 0xfff];
+
+ /* The low 3 bits of the high byte of the X coordinate are */
+ /* latched into the up/down counter at U17 during phase 4. */
+ /* Bit 2 of the input is latched as both bit 2 and 3. */
+ cury |= (vectorram[symaddr++ & 0xfff] & 7) << 8;
+ cury |= (cury << 1) & 0x800;
+
+ /* The low byte of the vector address is latched into the */
+ /* counters at U10/U11 during phase 5. */
+ vecaddr = vectorram[symaddr++ & 0xfff];
+
+ /* The low 4 bits of the high byte of the vector address is */
+ /* latched into the counter at U12 during phase 6. */
+ vecaddr |= (vectorram[symaddr++ & 0xfff] & 0xf) << 8;
+
+ /* The low byte of the symbol angle is latched into the tri- */
+ /* state flip flop at U55 at the end of phase 7. */
+ symangle = vectorram[symaddr++ & 0xfff];
+
+ /* The low 2 bits of the high byte of the symbol angle are */
+ /* latched into flip flops at U26 at the end of phase 8. */
+ symangle |= (vectorram[symaddr++ & 0xfff] & 3) << 8;
+
+ /* The scale is latched in phase 9 as the X input to the */
+ /* 25LS14 multiplier at U8. */
+ scale = vectorram[symaddr++ & 0xfff];
+
+ /* Account for the 10 phases so far. */
+ total_time -= 10.0 / (double)U51_CLOCK;
+
+ /* Skip the rest if we're not drawing this symbol. */
+ if (draw & 1)
+ {
+ int adjx, adjy, clipped;
+
+ /* Add a starting point to the vector list. */
+ clipped = adjust_xy(curx, cury, &adjx, &adjy);
+ if (!clipped)
+ vector_add_point(adjx, adjy, 0, 0);
+
+ /* Loop until we run out of time. */
+ while (total_time > 0)
+ {
+ UINT16 vecangle, length, deltax, deltay;
+ UINT8 attrib, intensity;
+ UINT32 color;
+
+ /* The 'attribute' byte is latched at the end of phase 10 into */
+ /* the tri-state flip flop at U2. The low bit controls whether */
+ /* or not the beam is enabled. Bits 1-6 control the RGB color */
+ /* (2 bits per component). In addition, bit 7 of this value is */
+ /* latched into U52, which controls the pre-load value for the */
+ /* phase generator. If bit 7 is high, then the phase generator */
+ /* will reset back to 0 and draw a new symbol; if bit 7 is low */
+ /* the phase generator will reset back to 10 and draw another */
+ /* vector. */
+ attrib = vectorram[vecaddr++ & 0xfff];
+
+ /* The length of the vector is loaded into the shift registers */
+ /* at U6/U7 during phase 11. During phase 12, the 25LS14 */
+ /* multiplier at U8 is used to multiply the length by the */
+ /* scale that was loaded during phase 9. The length is clocked */
+ /* bit by bit out of U6/U7 and the result is clocked into the */
+ /* other side. After the multiply, the 9 MSBs are loaded into */
+ /* the counter chain at U15/16/17 and are used to count how */
+ /* long to draw the vector. */
+ length = (vectorram[vecaddr++ & 0xfff] * scale) >> 7;
+
+ /* The vector angle low byte is latched at the end of phase 12 */
+ /* into the tri-state flip flop at U56. */
+ vecangle = vectorram[vecaddr++ & 0xfff];
+
+ /* The vector angle high byte is preset on the CD bus during */
+ /* phases 13 and 14, and is used as inputs to the adder at */
+ /* U46. */
+ vecangle |= (vectorram[vecaddr++ & 0xfff] & 3) << 8;
+
+ /* The X increment value is looked up first (phase 13). The */
+ /* sum of the latched symbol angle and the vector angle is */
+ /* used as input to the PROM at U39. A0 is tied to ground. */
+ /* A1-A9 map to bits 0-8 of the summed angles. The output from */
+ /* the PROM is latched into U48. */
+ deltax = sintable[((vecangle + symangle) & 0x1ff) << 1];
+
+ /* The Y increment value is looked up second (phase 14). The */
+ /* angle sum is used once again as the input to the PROM, but */
+ /* this time an additional 0x100 is effectively added to it */
+ /* before it is used; this separates sin from cos. The output */
+ /* from the PROM is latched into U49. */
+ deltay = sintable[((vecangle + symangle + 0x100) & 0x1ff) << 1];
+
+ /* Account for the 4 phases for data fetching. */
+ total_time -= 4.0 / (double)U51_CLOCK;
+
+ /* Compute color/intensity values from the attributes */
+ color = VECTOR_COLOR222((attrib >> 1) & 0x3f);
+ if ((attrib & 1) && color)
+ intensity = 0xff;
+ else
+ intensity = 0;
+
+ /* Loop over the length of the vector. */
+ clipped = adjust_xy(curx, cury, &adjx, &adjy);
+ xaccum = yaccum = 0;
+ while (length-- != 0 && total_time > 0)
+ {
+ int newclip;
+
+ /* The adders at U44/U45 are used as X accumulators. The value */
+ /* from U48 is repeatedly added to itself here. The carry out */
+ /* of bit 8 clocks the up/down counters at U15/U16/U17. Bit 7 */
+ /* of the input value from U48 is used as a carry in to round */
+ /* small values downward and larger values upward. */
+ xaccum += deltax + (deltax >> 7);
+
+ /* Bit 9 of the summed angles controls the direction the up/ */
+ /* down counters at U15/U16/U17. */
+ if (((vecangle + symangle) & 0x200) == 0)
+ curx += xaccum >> 8;
+ else
+ curx -= xaccum >> 8;
+ xaccum &= 0xff;
+
+ /* The adders at U46/U47 are used as Y accumulators. The value */
+ /* from U49 is repeatedly added to itself here. The carry out */
+ /* of bit 8 clocks the up/down counters at U18/U19/U20. Bit 7 */
+ /* of the input value from U49 is used as a carry in to round */
+ /* small values downward and larger values upward. */
+ yaccum += deltay + (deltay >> 7);
+
+ /* Bit 9 of the summed angles controls the direction the up/ */
+ /* down counters at U18/U19/U20. */
+ if (((vecangle + symangle + 0x100) & 0x200) == 0)
+ cury += yaccum >> 8;
+ else
+ cury -= yaccum >> 8;
+ yaccum &= 0xff;
+
+ /* Apply the clipping from the DAC circuit. If the values clip */
+ /* the beam is turned off, but the computations continue right */
+ /* on going. */
+ newclip = adjust_xy(curx, cury, &adjx, &adjy);
+ if (newclip != clipped)
+ {
+ /* if we're just becoming unclipped, add an empty point */
+ if (!newclip)
+ vector_add_point(adjx, adjy, 0, 0);
+
+ /* otherwise, add a colored point */
+ else
+ vector_add_point(adjx, adjy, color, intensity);
+ }
+ clipped = newclip;
+
+ /* account for vector drawing time */
+ total_time -= 1.0 / (double)VCL_CLOCK;
+ }
+
+ /* We're done; if we are not clipped, add a final point. */
+ if (!clipped)
+ vector_add_point(adjx, adjy, color, intensity);
+
+ /* if the high bit of the attribute is set, we break out of */
+ /* this loop and fetch another symbol */
+ if (attrib & 0x80)
+ break;
+ }
+ }
+
+ /* if the high bit of the draw flag is set, we break out of this loop */
+ /* and stop the rendering altogether for this frame. */
+ if (draw & 0x80)
+ break;
+ }
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( sega )
+{
+ assert_always(vectorram_size != 0, "vectorram==0");
+
+ min_x =machine->screen[0].visarea.min_x;
+ min_y =machine->screen[0].visarea.min_y;
+
+ video_start_vector(machine);
+}
+
+
+VIDEO_UPDATE( sega )
+{
+ sega_generate_vector_list();
+ video_update_vector(machine,screen,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/segahang.c b/src/mame/video/segahang.c
new file mode 100644
index 00000000000..0edaa671cfe
--- /dev/null
+++ b/src/mame/video/segahang.c
@@ -0,0 +1,93 @@
+/***************************************************************************
+
+ Sega Hang On hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "segaic16.h"
+#include "includes/system16.h"
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( hangon )
+{
+ /* compute palette info */
+ segaic16_palette_init(0x800);
+
+ /* initialize the tile/text layers */
+ segaic16_tilemap_init(0, SEGAIC16_TILEMAP_HANGON, 0x000, 0, 2);
+
+ /* initialize the sprites */
+ segaic16_sprites_init(0, SEGAIC16_SPRITES_HANGON, 0x400, 0);
+
+ /* initialize the road */
+ segaic16_road_init(0, SEGAIC16_ROAD_HANGON, 0x038, 0x7c0, 0x7c0, 0);
+}
+
+
+VIDEO_START( sharrier )
+{
+ /* compute palette info */
+ segaic16_palette_init(0x800);
+
+ /* initialize the tile/text layers */
+ segaic16_tilemap_init(0, SEGAIC16_TILEMAP_HANGON, 0x000, 0, 2);
+
+ /* initialize the sprites */
+ segaic16_sprites_init(0, SEGAIC16_SPRITES_SHARRIER, 0x400, 0);
+
+ /* initialize the road */
+ segaic16_road_init(0, SEGAIC16_ROAD_SHARRIER, 0x038, 0x7c0, 0x7c0, 0);
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( hangon )
+{
+ /* if no drawing is happening, fill with black and get out */
+ if (!segaic16_display_enable)
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* reset priorities */
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ /* draw the low priority road layer */
+ segaic16_road_draw(0, bitmap, cliprect, SEGAIC16_ROAD_BACKGROUND);
+
+ /* draw background */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 0, 0x01);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 1, 0x02);
+
+ /* draw foreground */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_FOREGROUND, 0, 0x02);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_FOREGROUND, 1, 0x04);
+
+ /* draw the high priority road */
+ segaic16_road_draw(0, bitmap, cliprect, SEGAIC16_ROAD_FOREGROUND);
+
+ /* text layer */
+ /* note that we inflate the priority of the text layer to prevent sprites */
+ /* from drawing over the high scores */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_TEXT, 0, 0x08);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_TEXT, 1, 0x08);
+
+ /* draw the sprites */
+ segaic16_sprites_draw(0, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/segaic16.c b/src/mame/video/segaic16.c
new file mode 100644
index 00000000000..c18f57dea06
--- /dev/null
+++ b/src/mame/video/segaic16.c
@@ -0,0 +1,3588 @@
+/***************************************************************************
+
+ Sega 16-bit common hardware
+
+****************************************************************************
+
+ Hang On
+ -------
+ Control Board (834-5668):
+ 315-5011 -- sprite line comparitor
+ 315-5012 -- sprite generator control
+ 315-5049 (x2) -- tilemaps
+ 315-5107 (PAL x2) -- horizontal timing control
+ 315-5108 -- vertical timing control
+ 315-5122 (PAL) -- timing
+
+ Enduro Racer
+ ------------
+ CPU Side (171-5319):
+ 315-5164 (PAL)
+ 315-5165 (PAL)
+ 315-5166 (PAL)
+ 315-5167 (PAL)
+
+ Video Side (171-5320):
+ 315-5049 (x2) -- tilemaps
+ 315-5011 -- sprite line comparitor
+ 315-5012 -- sprite generator control
+ 315-5106 (PAL)
+ 315-5107 (PAL)
+ 315-5108 (PAL)
+ 315-5168 (PAL)
+ 315-5170 (PAL)
+ 315-5171 (PAL)
+ 315-5172 (PAL)
+
+ Pre-System 16
+ -------------
+ Main Board (171-5335):
+ 315-5011 -- sprite line comparitor
+ 315-5012 -- sprite generator control
+ 315-5049 (x2) -- tilemaps
+ 315-5107 (PAL) -- display timing
+ 315-5108 (PAL) -- display timing
+ 315-5141 (PAL) -- Z80 address decoding
+ 315-5143 (PAL) -- sprite-related?
+ 315-5144 (PAL) -- sprite-related?
+ 315-5147 (PAL) -- unknown, DTACK-related
+ 315-5149 (PAL) -- video mixing
+ 315-5193 (PAL) -- 68000/MCU interface & address decoding
+ 315-5202 (PAL) -- 68000/MCU interface & address decoding
+
+ Sega System 16A
+ ---------------
+ Bottom Board (171-5307):
+ 315-5011 -- sprite line comparitor
+ 315-5012 -- sprite generator control
+ 315-5049 (x2) -- tilemaps
+ 315-5107 (PAL) -- display timing
+ 315-5108 (PAL) -- display timing
+ 315-5143 (PAL) -- sprite-related?
+ 315-5144 (PAL) -- sprite-related?
+ 315-5145 (PAL)
+
+ Top Board (171-5306):
+ 315-5141 (PAL) -- Z80 address decoding
+ 315-5142 (PAL)
+ 315-5149 (PAL) -- video mixing
+ 315-5150 (PAL)
+
+ Sega System 16B
+ ---------------
+ Main Board (171-5357):
+ 315-5195 -- memory mapper
+ 315-5196 -- sprite generator
+ 315-5197 -- tilemap generator
+ 315-5213 (PAL) -- sprite-related
+ 315-5214 (PAL) -- unknown
+
+ ROM Board (171-5521):
+ 315-5298 (PAL)
+
+ ROM Board (171-5704):
+ 315-5298 (PAL)
+
+ ROM Board (171-5797):
+ 315-5248 -- hardware multiplier
+ 315-5250 -- compare/timer
+ 315-5298 (PAL)
+
+ Sega System 18
+ --------------
+ Main Board (171-5873B):
+ 315-5242 -- color encoder
+ 315-5296 -- I/O chip
+ 315-5313 -- VDP
+ 315-5360 -- memory mapper?
+ 315-5361 -- sprite generator
+ 315-5362 -- tilemap generator
+ 315-5373 (PAL) -- video mixing
+ 315-5374 (PAL) -- sprite timing
+ 315-5375 (PAL) -- system timing
+ 315-5389 (PAL) -- VDP sync
+ 315-5390 (PAL)
+ 315-5391 (PAL) -- Z80 address decoding
+
+ Main Board (171-5873-02B):
+ 315-5242 -- color encoder
+ 315-5296 -- I/O chip
+ 315-5313 -- VDP
+ 315-5360 -- memory mapper?
+ 315-5361 -- sprite generator
+ 315-5362 -- tilemap generator
+ 315-5374 (PAL) -- sprite timing
+ 315-5375 (PAL) -- system timing
+ 315-5389 (PAL) -- VDP sync
+ 315-5391 (PAL) -- Z80 address decoding
+ 315-5430 (PAL) -- video mixing
+
+ ROM Board (171-5987A):
+ 315-5436 -- tile/sprite banking
+
+ Sega System C
+ -------------
+ Main Board:
+ 315-5242 -- color encoder
+ 315-5296 -- I/O chip
+ 315-5313 -- VDP
+ 315-5393 (PAL)
+ 315-5394 (PAL)
+ 315-5395 (PAL)
+
+ Super Hang On
+ -------------
+ CPU Board 171-5376-01:
+ 315-5195 -- memory mapper
+ 315-5218 -- PCM sound controller
+ 315-5155 (PAL x2) -- road bit extraction
+ 315-5222 (PAL) -- road mixing
+ 315-5223a (PAL)
+ 315-5224 (PAL)
+ 315-5225 (PAL)
+ 315-5226 (PAL)
+
+ VIDEO Board: (not the same as out run !) 171-5480
+ 315-5196 -- sprite generator
+ 315-5197 -- tilemap generator
+ 315-5213 (PAL) -- sprite-related
+ 315-5242 -- color encoder
+ 315-5251 (PAL)
+
+ Out Run
+ -------
+ CPU Board 837-6063-01:
+ 315-5195 -- memory mapper
+ 315-5218 -- PCM sound controller
+ 315-5155 (PAL x2) -- road bit extraction
+ 315-5222 (PAL) -- road mixing
+ 315-5223a (PAL)
+ 315-5224 (PAL)
+ 315-5225 (PAL)
+ 315-5226 (PAL)
+
+ VIDEO Board: 837-6064, 171-5377-01
+ 315-5197 -- tilemap generator
+ 315-5211 -- sprite generator
+ 315-5227a (PAL)
+ 315-5228 (PAL)
+ 315-5242 -- color encoder
+
+ Sega System 32
+ --------------
+ Main Board (317-5964):
+ 315-5242 -- color encoder
+ 315-5296 -- I/O chip
+ 315-5385
+ 315-5386 -- tilemap generator
+ 315-5387 -- sprite generator
+ 315-5388 -- video mixing
+ 315-5441 (PAL)
+ 315-5476
+
+ X-Board
+ -------
+ Main Board:
+ 315-5197 -- tilemap generator
+ 315-5211A -- sprite generator
+ 315-5218 -- PCM sound controller
+ 315-5242 -- color encoder
+ 315-5248 (x2) -- hardware multiplier
+ 315-5249 (x2) -- hardware divider
+ 315-5250 (x2) -- compare/timer
+ 315-5275 -- road generator
+ 315-5278 (PAL) -- sprite ROM bank control
+ 315-5279 (PAL) -- video mixing (Afterburner)
+ 315-5280 (PAL) -- Z80 address decoding
+ 315-5290 (PAL) -- main CPU address decoding
+ 315-5291 (PAL) -- main CPU address decoding
+ 315-5304 (PAL) -- video mixing (Line of Fire)
+
+ Y-Board
+ -------
+ Main Board (837-6565):
+ 315-5218 -- PCM sound controller
+ 315-5248 (x3) -- hardware multiplier
+ 315-5249 (x3) -- hardware divider
+ 315-5280 (PAL) -- Z80 address decoding
+ 315-5296 -- I/O chip
+ 315-5314 (PAL)
+ 315-5315 (PAL)
+ 315-5316 (PAL)
+ 315-5317 (PAL)
+ 315-5318 (PAL)
+ 315-5328 (PAL)
+
+ Video Board (837-6566):
+ 315-5196 -- sprite generator
+ 315-5213 (PAL) -- sprite-related
+ 315-5242 -- color encoder
+ 315-5305 -- sprite generator
+ 315-5306 (x2) -- video sync and rotation
+ 315-5312 -- video mixing
+ 315-5319 (PAL)
+ 315-5325 (PAL)
+
+
+ Custom parts
+ ------------
+ SYS1 SYS2 HANG ENDU PR16 S16A S16B SY18 SHNG ORUN XBRD YBRD SYSC SY24 SY32
+ 315-5011: xx xx xx xx xx xx -- sprite line comparitor
+ 315-5012: xx xx xx xx xx xx -- sprite generator control
+ 315-5049: xx x2 x2 x2 x2 -- tilemap generator
+ 315-5195: xx xx xx -- memory mapper
+ 315-5196: xx xx xx -- sprite genereator
+ 315-5197: xx xx xx xx -- tilemap generator
+ 315-5211: xx -- sprite generator
+ 315-5211A: xx -- sprite generator
+ 315-5218: xx xx xx xx -- PCM sound controller
+ 315-5242: xx xx xx xx xx xx xx xx -- color encoder
+ 315-5248: xx x2 x3 -- hardware multiplier
+ 315-5249: x2 x3 -- hardware divider
+ 315-5250: xx x2 -- compare/timer
+ 315-5275: xx -- road generator
+ 315-5296: xx xx xx xx -- I/O chip
+ 315-5305: xx --
+ 315-5312: xx -- video mixing
+ 315-5313: xx xx -- VDP
+ 315-5360: xx -- memory mapper
+ 315-5361: xx -- sprite generator
+ 315-5362: xx -- tilemap generator
+ 315-5385: xx -- ???
+ 315-5386: xx -- tilemap generator
+ 315-5387: xx -- sprite generator
+ 315-5388: xx -- video mixing
+ 315-5436: xx -- sprite/tile banking
+ 315-5476: xx -- ????
+
+****************************************************************************
+
+ Sega system16 and friends hardware
+
+ CPU Tiles Sprites Priority Color SCPU Sound Other
+System C 68000 315-5313 315-5242 z80 ym3438 315-5296(IO)
+Space Harrier 68000x2 (c) z80 ym2203 pcm(b)
+System 16B 68000 315-5197 315-5196 GAL (c) z80 ym2151 upd7759 315-5195
+After Burner 68000x2 315-5197 315-5211A GAL 315-5242 z80 ym2151 315-5218 315-5250(a) 315-5248(x2) 315-5249(x2) 315-5275(road)
+System 18 68000 315-536x 315-536x 315-5242 z80 ym3834(x2) RF5c68(d) 315-3296(IO) 315-5313(vdp)
+System 24 68000x2 315-5292 315-5293 315-5294 315-5242 ym2151 dac 315-5195(x3) 315-5296(IO)
+Galaxy Force 68000x3 315-5296+ 315-5312 315-5242 z80 ym2151 315-5218 315-5296(IO)
+System 32 V60 315-5386A 315-5387 315-5388 315-5242 z80 ym3834(x2) RF5c68(d) 315-5296(IO)
+
+a) 315-5250: 68000 glue and address decoding
+
+b) 8x8-bit voices entirely in TTL. The 315-5218 is believed to be the
+ integrated version of that
+
+c) Resistor network and latches believed to be equivalent to the 315-5242
+
+d) Also seen as 315-5476A and ASSP 5c105 and ASSP 5c68a
+
+Quick review of the system16 hardware:
+
+ Hang-on hardware:
+ The first one. Two tilemap planes, one sprite plane, one road
+ plane. The shadow capability doesn't seem to be used, the
+ highlight/shadow switch in the 5242-equivalent is global for all
+ colors.
+
+ Space harrier hardware:
+ Similar to hang-on, with per-color highlight/shadow selection, and
+ the shadows are used.
+
+ System16a / Pre-system16:
+ Space harrier without the road generator.
+
+ System16b:
+ 4-layer tilemap hardware in two pairs, with selection between each
+ members on the pairs on a 8-lines basis. Slightly better sprites.
+
+ System18
+ System 16b plus a genesis vdp.
+
+ Outrun:
+ System 16b tilemaps, frame buffered sprites with better zooming
+ capabilities, and a road generator able to handle two roads
+ simultaneously.
+
+ Super hang-on:
+ Outrun lite, with System 16b sprites instead of the frame buffered
+ sprites, and only one of the two roads is actually used.
+
+ X-Board:
+ Outrun with a better fillrate and an even more flexible road
+ generator.
+
+ Y-Board:
+ New design, with two sprite planes and no tilemaps. The back
+ sprite plane has a huge fillrate and the capability to have its
+ frame buffer completely rotated. Also, it has a palette
+ indirection capability to allows for easier palette rotations.
+ The front sprite plane is System 16b.
+
+ System24:
+ The odd one out. Medium resolution. Entirely ram-based, no
+ graphics roms. 4-layer tilemap hardware in two pairs, selection
+ on a 8-pixels basis. Tile-based sprites(!) organised as a linked
+ list. The tilemap chip has been reused for model1 and model2,
+ probably because they had it handy and it handles medium res.
+
+ System32:
+ 5-layer tilemap hardware consisting of 4 independant rom-based
+ layers with linescroll, lineselection, linezoom and window
+ clipping capability and one simpler ram-based text plane. Mixed
+ ram/rom sprite engine with palette indirection, per-color priority
+ (thankfully not actually used). The sprite list includes jumping
+ and clipping capabilities, and advanced hot-spot positioning. The
+ mixer chip adds totally dynamic priorities, alpha-blending of the
+ tilemaps, per-component color control, and some other funnies we
+ have not been able to decypher.
+
+ ST-V (also know as Titan or the Saturn console):
+ The ultimate 2D system. Even more advanced tilemaps, with 6-dof
+ roz support, alpha up to the wazoo and other niceties, known as
+ the vdp2. Ths sprite engine, vdp1, allows for any 4-point
+ streching of the sprites, actually giving polygonal 3D
+ capabilities. Interestingly, the mixer capabilities took a hit,
+ with no real per-sprite mixer priority, which could be considered
+ annoying for a 2D system. It still allowed some beauties like
+ Radiant Silvergun.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "segaic16.h"
+#include "video/resnet.h"
+
+
+
+/*************************************
+ *
+ * Debugging
+ *
+ *************************************/
+
+#define PRINT_UNUSUAL_MODES (0)
+
+
+
+/*************************************
+ *
+ * Type definitions
+ *
+ *************************************/
+
+struct palette_info
+{
+ INT32 entries; /* number of entries (not counting shadows) */
+ UINT8 normal[32]; /* RGB translations for normal pixels */
+ UINT8 shadow[32]; /* RGB translations for shadowed pixels */
+ UINT8 hilight[32]; /* RGB translations for hilighted pixels */
+};
+
+
+struct tilemap_callback_info
+{
+ UINT16 * rambase; /* base of RAM for this tilemap page */
+ const UINT8 * bank; /* pointer to bank array */
+ UINT16 banksize; /* size of banks */
+};
+
+
+struct tilemap_info
+{
+ UINT8 index; /* index of this structure */
+ UINT8 type; /* type of tilemap (see segaic16.h for details) */
+ UINT8 numpages; /* number of allocated pages */
+ UINT8 flip; /* screen flip? */
+ UINT8 rowscroll, colscroll; /* are rowscroll/colscroll enabled (if external enables are used) */
+ UINT8 bank[8]; /* indexes of the tile banks */
+ UINT16 banksize; /* number of tiles per bank */
+ UINT16 latched_xscroll[4]; /* latched X scroll values */
+ UINT16 latched_yscroll[4]; /* latched Y scroll values */
+ UINT16 latched_pageselect[4]; /* latched page select values */
+ INT32 xoffs; /* X scroll offset */
+ tilemap *tilemaps[16]; /* up to 16 tilemap pages */
+ tilemap *textmap; /* a single text tilemap */
+ struct tilemap_callback_info tilemap_info[16]; /* callback info for 16 tilemap pages */
+ struct tilemap_callback_info textmap_info; /* callback info for a single textmap page */
+ void (*reset)(struct tilemap_info *info);/* reset callback */
+ void (*draw_layer)(running_machine *machine, struct tilemap_info *info, mame_bitmap *bitmap, const rectangle *cliprect, int which, int flags, int priority);
+ UINT16 * textram; /* pointer to textram pointer */
+ UINT16 * tileram; /* pointer to tileram pointer */
+};
+
+
+struct sprite_info
+{
+ UINT8 index; /* index of this structure */
+ UINT8 type; /* type of sprite system (see segaic16.h for details) */
+ UINT8 flip; /* screen flip? */
+ UINT8 shadow; /* shadow or hilight? */
+ UINT8 bank[16]; /* banking redirection */
+ UINT16 colorbase; /* base color index */
+ INT32 ramsize; /* size of sprite RAM */
+ INT32 xoffs; /* X scroll offset */
+ void (*draw)(struct sprite_info *info, mame_bitmap *bitmap, const rectangle *cliprect);
+ UINT16 * spriteram; /* pointer to spriteram pointer */
+ UINT16 * buffer; /* buffered spriteram for those that use it */
+};
+
+
+struct road_info
+{
+ UINT8 index; /* index of this structure */
+ UINT8 type; /* type of road system (see segaic16.h for details) */
+ UINT8 control; /* control register value */
+ UINT16 colorbase1; /* color base for road ROM data */
+ UINT16 colorbase2; /* color base for road background data */
+ UINT16 colorbase3; /* color base for sky data */
+ INT32 xoffs; /* X scroll offset */
+ void (*draw)(struct road_info *info, mame_bitmap *bitmap, const rectangle *cliprect, int priority);
+ UINT16 * roadram; /* pointer to roadram pointer */
+ UINT16 * buffer; /* buffered roadram pointer */
+ UINT8 * gfx; /* expanded road graphics */
+};
+
+
+struct rotate_info
+{
+ UINT8 index; /* index of this structure */
+ UINT8 type; /* type of rotate system (see segaic16.h for details) */
+ UINT16 colorbase; /* base color index */
+ INT32 ramsize; /* size of rotate RAM */
+ UINT16 * rotateram; /* pointer to rotateram pointer */
+ UINT16 * buffer; /* buffered data */
+};
+
+
+
+/*************************************
+ *
+ * Globals
+ *
+ *************************************/
+
+UINT8 segaic16_display_enable;
+UINT16 *segaic16_tileram_0;
+UINT16 *segaic16_textram_0;
+UINT16 *segaic16_spriteram_0;
+UINT16 *segaic16_spriteram_1;
+UINT16 *segaic16_roadram_0;
+UINT16 *segaic16_rotateram_0;
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static struct palette_info palette;
+static struct tilemap_info bg_tilemap[SEGAIC16_MAX_TILEMAPS];
+static struct sprite_info sprites[SEGAIC16_MAX_SPRITES];
+static struct road_info road[SEGAIC16_MAX_ROADS];
+static struct rotate_info rotate[SEGAIC16_MAX_ROTATE];
+
+
+/*************************************
+ *
+ * Misc functions
+ *
+ *************************************/
+
+void segaic16_set_display_enable(int enable)
+{
+ enable = (enable != 0);
+ if (segaic16_display_enable != enable)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ segaic16_display_enable = enable;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Palette computation
+ *
+ *************************************/
+
+/*
+ Color generation details
+
+ Each color is made up of 5 bits, connected through one or more resistors like so:
+
+ Bit 0 = 1 x 3.9K ohm
+ Bit 1 = 1 x 2.0K ohm
+ Bit 2 = 1 x 1.0K ohm
+ Bit 3 = 2 x 1.0K ohm
+ Bit 4 = 4 x 1.0K ohm
+
+ Another data bit is connected by a tristate buffer to the color output through a
+ 470 ohm resistor. The buffer allows the resistor to have no effect (tristate),
+ halve brightness (pull-down) or double brightness (pull-up). The data bit source
+ is bit 15 of each color RAM entry.
+*/
+
+void segaic16_palette_init(int entries)
+{
+ static const int resistances_normal[6] = { 3900, 2000, 1000, 1000/2, 1000/4, 0 };
+ static const int resistances_sh[6] = { 3900, 2000, 1000, 1000/2, 1000/4, 470 };
+ double weights[2][6];
+ int i;
+
+ /* compute the number of palette entries */
+ palette.entries = entries;
+
+ /* compute weight table for regular palette entries */
+ compute_resistor_weights(0, 255, -1.0,
+ 6, resistances_normal, weights[0], 0, 0,
+ 0, NULL, NULL, 0, 0,
+ 0, NULL, NULL, 0, 0);
+
+ /* compute weight table for shadow/hilight palette entries */
+ compute_resistor_weights(0, 255, -1.0,
+ 6, resistances_sh, weights[1], 0, 0,
+ 0, NULL, NULL, 0, 0,
+ 0, NULL, NULL, 0, 0);
+
+ /* compute R, G, B for each weight */
+ for (i = 0; i < 32; i++)
+ {
+ int i4 = (i >> 4) & 1;
+ int i3 = (i >> 3) & 1;
+ int i2 = (i >> 2) & 1;
+ int i1 = (i >> 1) & 1;
+ int i0 = (i >> 0) & 1;
+
+ palette.normal[i] = combine_6_weights(weights[0], i0, i1, i2, i3, i4, 0);
+ palette.shadow[i] = combine_6_weights(weights[1], i0, i1, i2, i3, i4, 0);
+ palette.hilight[i] = combine_6_weights(weights[1], i0, i1, i2, i3, i4, 1);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Palette accessors
+ *
+ *************************************/
+
+WRITE16_HANDLER( segaic16_paletteram_w )
+{
+ UINT16 newval;
+ int r, g, b;
+
+ /* get the new value */
+ newval = paletteram16[offset];
+ COMBINE_DATA(&newval);
+ paletteram16[offset] = newval;
+
+ /* byte 0 byte 1 */
+ /* sBGR BBBB GGGG RRRR */
+ /* x000 4321 4321 4321 */
+ r = ((newval >> 12) & 0x01) | ((newval << 1) & 0x1e);
+ g = ((newval >> 13) & 0x01) | ((newval >> 3) & 0x1e);
+ b = ((newval >> 14) & 0x01) | ((newval >> 7) & 0x1e);
+
+ /* normal colors */
+ palette_set_color_rgb(Machine, offset + 0 * palette.entries, palette.normal[r], palette.normal[g], palette.normal[b]);
+ palette_set_color_rgb(Machine, offset + 1 * palette.entries, palette.shadow[r], palette.shadow[g], palette.shadow[b]);
+ palette_set_color_rgb(Machine, offset + 2 * palette.entries, palette.hilight[r], palette.hilight[g], palette.hilight[b]);
+}
+
+
+
+/*************************************
+ *
+ * Draw a split tilemap in up to
+ * four pieces
+ *
+ *************************************/
+
+static void segaic16_draw_virtual_tilemap(running_machine *machine, struct tilemap_info *info, mame_bitmap *bitmap, const rectangle *cliprect, UINT16 pages, UINT16 xscroll, UINT16 yscroll, UINT32 flags, UINT32 priority)
+{
+ int leftmin = -1, leftmax = -1, rightmin = -1, rightmax = -1;
+ int topmin = -1, topmax = -1, bottommin = -1, bottommax = -1;
+ rectangle pageclip;
+ int page;
+
+ /* which half/halves of the virtual tilemap do we intersect in the X direction? */
+ if (xscroll < 64*8 - machine->screen[0].width)
+ {
+ leftmin = 0;
+ leftmax = machine->screen[0].width - 1;
+ rightmin = -1;
+ }
+ else if (xscroll < 64*8)
+ {
+ leftmin = 0;
+ leftmax = 64*8 - xscroll - 1;
+ rightmin = leftmax + 1;
+ rightmax = machine->screen[0].width - 1;
+ }
+ else if (xscroll < 128*8 - machine->screen[0].width)
+ {
+ rightmin = 0;
+ rightmax = machine->screen[0].width - 1;
+ leftmin = -1;
+ }
+ else
+ {
+ rightmin = 0;
+ rightmax = 128*8 - xscroll - 1;
+ leftmin = rightmax + 1;
+ leftmax = machine->screen[0].width - 1;
+ }
+
+ /* which half/halves of the virtual tilemap do we intersect in the Y direction? */
+ if (yscroll < 32*8 - machine->screen[0].height)
+ {
+ topmin = 0;
+ topmax = machine->screen[0].height - 1;
+ bottommin = -1;
+ }
+ else if (yscroll < 32*8)
+ {
+ topmin = 0;
+ topmax = 32*8 - yscroll - 1;
+ bottommin = topmax + 1;
+ bottommax = machine->screen[0].height - 1;
+ }
+ else if (yscroll < 64*8 - machine->screen[0].height)
+ {
+ bottommin = 0;
+ bottommax = machine->screen[0].height - 1;
+ topmin = -1;
+ }
+ else
+ {
+ bottommin = 0;
+ bottommax = 64*8 - yscroll - 1;
+ topmin = bottommax + 1;
+ topmax = machine->screen[0].height - 1;
+ }
+
+ /* if the tilemap is flipped, we need to flip our sense within each quadrant */
+ if (info->flip)
+ {
+ if (leftmin != -1)
+ {
+ int temp = leftmin;
+ leftmin = machine->screen[0].width - 1 - leftmax;
+ leftmax = machine->screen[0].width - 1 - temp;
+ }
+ if (rightmin != -1)
+ {
+ int temp = rightmin;
+ rightmin = machine->screen[0].width - 1 - rightmax;
+ rightmax = machine->screen[0].width - 1 - temp;
+ }
+ if (topmin != -1)
+ {
+ int temp = topmin;
+ topmin = machine->screen[0].height - 1 - topmax;
+ topmax = machine->screen[0].height - 1 - temp;
+ }
+ if (bottommin != -1)
+ {
+ int temp = bottommin;
+ bottommin = machine->screen[0].height - 1 - bottommax;
+ bottommax = machine->screen[0].height - 1 - temp;
+ }
+ }
+
+ /* draw the upper-left chunk */
+ if (leftmin != -1 && topmin != -1)
+ {
+ pageclip.min_x = (leftmin < cliprect->min_x) ? cliprect->min_x : leftmin;
+ pageclip.max_x = (leftmax > cliprect->max_x) ? cliprect->max_x : leftmax;
+ pageclip.min_y = (topmin < cliprect->min_y) ? cliprect->min_y : topmin;
+ pageclip.max_y = (topmax > cliprect->max_y) ? cliprect->max_y : topmax;
+ if (pageclip.min_x <= pageclip.max_x && pageclip.min_y <= pageclip.max_y)
+ {
+ page = (pages >> 0) & 0xf;
+ tilemap_set_scrollx(info->tilemaps[page], 0, xscroll);
+ tilemap_set_scrolly(info->tilemaps[page], 0, yscroll);
+ tilemap_draw(bitmap, &pageclip, info->tilemaps[page], flags, priority);
+ }
+ }
+
+ /* draw the upper-right chunk */
+ if (rightmin != -1 && topmin != -1)
+ {
+ pageclip.min_x = (rightmin < cliprect->min_x) ? cliprect->min_x : rightmin;
+ pageclip.max_x = (rightmax > cliprect->max_x) ? cliprect->max_x : rightmax;
+ pageclip.min_y = (topmin < cliprect->min_y) ? cliprect->min_y : topmin;
+ pageclip.max_y = (topmax > cliprect->max_y) ? cliprect->max_y : topmax;
+ if (pageclip.min_x <= pageclip.max_x && pageclip.min_y <= pageclip.max_y)
+ {
+ page = (pages >> 4) & 0xf;
+ tilemap_set_scrollx(info->tilemaps[page], 0, xscroll);
+ tilemap_set_scrolly(info->tilemaps[page], 0, yscroll);
+ tilemap_draw(bitmap, &pageclip, info->tilemaps[page], flags, priority);
+ }
+ }
+
+ /* draw the lower-left chunk */
+ if (leftmin != -1 && bottommin != -1)
+ {
+ pageclip.min_x = (leftmin < cliprect->min_x) ? cliprect->min_x : leftmin;
+ pageclip.max_x = (leftmax > cliprect->max_x) ? cliprect->max_x : leftmax;
+ pageclip.min_y = (bottommin < cliprect->min_y) ? cliprect->min_y : bottommin;
+ pageclip.max_y = (bottommax > cliprect->max_y) ? cliprect->max_y : bottommax;
+ if (pageclip.min_x <= pageclip.max_x && pageclip.min_y <= pageclip.max_y)
+ {
+ page = (pages >> 8) & 0xf;
+ tilemap_set_scrollx(info->tilemaps[page], 0, xscroll);
+ tilemap_set_scrolly(info->tilemaps[page], 0, yscroll);
+ tilemap_draw(bitmap, &pageclip, info->tilemaps[page], flags, priority);
+ }
+ }
+
+ /* draw the lower-right chunk */
+ if (rightmin != -1 && bottommin != -1)
+ {
+ pageclip.min_x = (rightmin < cliprect->min_x) ? cliprect->min_x : rightmin;
+ pageclip.max_x = (rightmax > cliprect->max_x) ? cliprect->max_x : rightmax;
+ pageclip.min_y = (bottommin < cliprect->min_y) ? cliprect->min_y : bottommin;
+ pageclip.max_y = (bottommax > cliprect->max_y) ? cliprect->max_y : bottommax;
+ if (pageclip.min_x <= pageclip.max_x && pageclip.min_y <= pageclip.max_y)
+ {
+ page = (pages >> 12) & 0xf;
+ tilemap_set_scrollx(info->tilemaps[page], 0, xscroll);
+ tilemap_set_scrolly(info->tilemaps[page], 0, yscroll);
+ tilemap_draw(bitmap, &pageclip, info->tilemaps[page], flags, priority);
+ }
+ }
+}
+
+
+
+/*******************************************************************************************
+ *
+ * Hang On/System 16A-style tilemaps
+ *
+ * 4 total pages (Hang On)
+ * 8 total pages (System 16A)
+ * Column/rowscroll enabled via external signals
+ *
+ * Tile format:
+ * Bits Usage
+ * ??------ -------- Unknown
+ * --b----- -------- Tile bank select
+ * ---p---- -------- Tile priority versus sprites
+ * ----cccc ccc----- Tile color palette
+ * ----nnnn nnnnnnnn Tile index
+ *
+ * Text format:
+ * Bits Usage
+ * ????---- -------- Unknown
+ * ----p--- -------- Priority
+ * -----ccc -------- Tile color palette
+ * -------- nnnnnnnn Tile index
+ *
+ * Text RAM:
+ * Offset Bits Usage
+ * E8C -aaa-bbb -ccc-ddd Background tilemap page select (screen flipped)
+ * E8E -aaa-bbb -ccc-ddd Foreground tilemap page select (screen flipped)
+ * E9C -aaa-bbb -ccc-ddd Background tilemap page select
+ * E9E -aaa-bbb -ccc-ddd Foreground tilemap page select
+ * F24 -------- vvvvvvvv Foreground tilemap vertical scroll
+ * F26 -------- vvvvvvvv Background tilemap vertical scroll
+ * F30-F7D -------- vvvvvvvv Foreground tilemap per-16-pixel-column vertical scroll (every 2 words)
+ * F32-F7F -------- vvvvvvvv Background tilemap per-16-pixel-column vertical scroll (every 2 words)
+ * F80-FED -------h hhhhhhhh Foreground tilemap per-8-pixel-row horizontal scroll (every 2 words)
+ * F82-FEF -------h hhhhhhhh Background tilemap per-8-pixel-row horizontal scroll (every 2 words)
+ * FF8 -------h hhhhhhhh Foreground tilemap horizontal scroll
+ * FFA -------h hhhhhhhh Background tilemap horizontal scroll
+ *
+ *******************************************************************************************/
+
+static TILE_GET_INFO( segaic16_tilemap_16a_tile_info )
+{
+ const struct tilemap_callback_info *info = param;
+ UINT16 data = info->rambase[tile_index];
+ int code = ((data >> 1) & 0x1000) | (data & 0xfff);
+ int color = (data >> 5) & 0x7f;
+
+ SET_TILE_INFO(0, code, color, 0);
+ tileinfo->category = (data >> 12) & 1;
+}
+
+
+static TILE_GET_INFO( segaic16_tilemap_16a_text_info )
+{
+ const struct tilemap_callback_info *info = param;
+ UINT16 data = info->rambase[tile_index];
+ int color = (data >> 8) & 0x07;
+ int code = data & 0xff;
+
+ SET_TILE_INFO(0, code, color, 0);
+ tileinfo->category = (data >> 11) & 1;
+}
+
+
+static void segaic16_tilemap_16a_draw_layer(running_machine *machine, struct tilemap_info *info, mame_bitmap *bitmap, const rectangle *cliprect, int which, int flags, int priority)
+{
+ UINT16 *textram = info->textram;
+
+ /* note that the scrolling for these games can only scroll as much as the top-left */
+ /* page; in order to scroll beyond that they swap pages and reset the scroll value */
+ UINT16 xscroll = textram[0xff8/2 + which] & 0x1ff;
+ UINT16 yscroll = textram[0xf24/2 + which] & 0x0ff;
+ UINT16 pages = textram[(info->flip ? 0xe8e/2 : 0xe9e/2) - which];
+ int x, y;
+
+ /* pages are swapped along the X direction, and there are only 8 of them */
+ pages = ((pages >> 4) & 0x0707) | ((pages << 4) & 0x7070);
+ if (info->numpages == 4)
+ pages &= 0x3333;
+
+ /* column AND row scroll */
+ if (info->colscroll && info->rowscroll)
+ {
+ if (PRINT_UNUSUAL_MODES) mame_printf_debug("Column AND row scroll\n");
+
+ /* loop over row chunks */
+ for (y = cliprect->min_y & ~7; y <= cliprect->max_y; y += 8)
+ {
+ int rowscrollindex = (info->flip ? (216 - y) : y) / 8;
+ rectangle rowcolclip;
+
+ /* adjust to clip this row only */
+ rowcolclip.min_y = (y < cliprect->min_y) ? cliprect->min_y : y;
+ rowcolclip.max_y = (y + 7 > cliprect->max_y) ? cliprect->max_y : y + 7;
+
+ /* loop over column chunks */
+ for (x = cliprect->min_x & ~15; x <= cliprect->max_x; x += 16)
+ {
+ UINT16 effxscroll, effyscroll;
+
+ /* adjust to clip this column only */
+ rowcolclip.min_x = (x < cliprect->min_x) ? cliprect->min_x : x;
+ rowcolclip.max_x = (x + 15 > cliprect->max_x) ? cliprect->max_x : x + 15;
+
+ /* get the effective scroll values */
+ effxscroll = textram[0xf80/2 + rowscrollindex * 2 + which] & 0x1ff;
+ effyscroll = textram[0xf30/2 + (x/16) * 2 + which] & 0x0ff;
+
+ /* adjust the xscroll for flipped screen */
+ if (info->flip)
+ effxscroll += 17;
+
+ /* draw the chunk */
+ effxscroll = (0xc8 - effxscroll + info->xoffs) & 0x3ff;
+ effyscroll = effyscroll & 0x1ff;
+ segaic16_draw_virtual_tilemap(machine, info, bitmap, &rowcolclip, pages, effxscroll, effyscroll, flags, priority);
+ }
+ }
+ }
+ else if (info->colscroll)
+ {
+ if (PRINT_UNUSUAL_MODES) mame_printf_debug("Column scroll\n");
+
+ /* loop over column chunks */
+ for (x = cliprect->min_x & ~15; x <= cliprect->max_x; x += 16)
+ {
+ rectangle colclip = *cliprect;
+ UINT16 effxscroll, effyscroll;
+
+ /* adjust to clip this row only */
+ colclip.min_x = (x < cliprect->min_x) ? cliprect->min_x : x;
+ colclip.max_x = (x + 15 > cliprect->max_x) ? cliprect->max_x : x + 15;
+
+ /* get the effective scroll values */
+ effxscroll = xscroll;
+ effyscroll = textram[0xf30/2 + (x/16) * 2 + which] & 0x0ff;
+
+ /* adjust the xscroll for flipped screen */
+ if (info->flip)
+ effxscroll += 17;
+
+ /* draw the chunk */
+ effxscroll = (0xc8 - effxscroll + info->xoffs) & 0x3ff;
+ effyscroll = effyscroll & 0x1ff;
+ segaic16_draw_virtual_tilemap(machine, info, bitmap, &colclip, pages, effxscroll, effyscroll, flags, priority);
+ }
+ }
+ else if (info->rowscroll)
+ {
+ if (PRINT_UNUSUAL_MODES) mame_printf_debug("Row scroll\n");
+
+ /* loop over row chunks */
+ for (y = cliprect->min_y & ~7; y <= cliprect->max_y; y += 8)
+ {
+ int rowscrollindex = (info->flip ? (216 - y) : y) / 8;
+ rectangle rowclip = *cliprect;
+ UINT16 effxscroll, effyscroll;
+
+ /* adjust to clip this row only */
+ rowclip.min_y = (y < cliprect->min_y) ? cliprect->min_y : y;
+ rowclip.max_y = (y + 7 > cliprect->max_y) ? cliprect->max_y : y + 7;
+
+ /* get the effective scroll values */
+ effxscroll = textram[0xf80/2 + rowscrollindex * 2 + which] & 0x1ff;
+ effyscroll = yscroll;
+
+ /* adjust the xscroll for flipped screen */
+ if (info->flip)
+ effxscroll += 17;
+
+ /* draw the chunk */
+ effxscroll = (0xc8 - effxscroll + info->xoffs) & 0x3ff;
+ effyscroll = effyscroll & 0x1ff;
+ segaic16_draw_virtual_tilemap(machine, info, bitmap, &rowclip, pages, effxscroll, effyscroll, flags, priority);
+ }
+ }
+ else
+ {
+ /* adjust the xscroll for flipped screen */
+ if (info->flip)
+ xscroll += 17;
+ xscroll = (0xc8 - xscroll + info->xoffs) & 0x3ff;
+ yscroll = yscroll & 0x1ff;
+ segaic16_draw_virtual_tilemap(machine, info, bitmap, cliprect, pages, xscroll, yscroll, flags, priority);
+ }
+}
+
+
+
+/*******************************************************************************************
+ *
+ * System 16B-style tilemaps
+ *
+ * 16 total pages
+ * Column/rowscroll enabled via bits in text layer
+ * Alternate tilemap support
+ *
+ * Tile format:
+ * Bits Usage
+ * p------- -------- Tile priority versus sprites
+ * -??----- -------- Unknown
+ * ---ccccc cc------ Tile color palette
+ * ---nnnnn nnnnnnnn Tile index
+ *
+ * Text format:
+ * Bits Usage
+ * p------- -------- Tile priority versus sprites
+ * -???---- -------- Unknown
+ * ----ccc- -------- Tile color palette
+ * -------n nnnnnnnn Tile index
+ *
+ * Alternate tile format:
+ * Bits Usage
+ * p------- -------- Tile priority versus sprites
+ * -??----- -------- Unknown
+ * ----cccc ccc----- Tile color palette
+ * ---nnnnn nnnnnnnn Tile index
+ *
+ * Alternate text format:
+ * Bits Usage
+ * p------- -------- Tile priority versus sprites
+ * -???---- -------- Unknown
+ * -----ccc -------- Tile color palette
+ * -------- nnnnnnnn Tile index
+ *
+ * Text RAM:
+ * Offset Bits Usage
+ * E80 aaaabbbb ccccdddd Foreground tilemap page select
+ * E82 aaaabbbb ccccdddd Background tilemap page select
+ * E84 aaaabbbb ccccdddd Alternate foreground tilemap page select
+ * E86 aaaabbbb ccccdddd Alternate background tilemap page select
+ * E90 c------- -------- Foreground tilemap column scroll enable
+ * -------v vvvvvvvv Foreground tilemap vertical scroll
+ * E92 c------- -------- Background tilemap column scroll enable
+ * -------v vvvvvvvv Background tilemap vertical scroll
+ * E94 -------v vvvvvvvv Alternate foreground tilemap vertical scroll
+ * E96 -------v vvvvvvvv Alternate background tilemap vertical scroll
+ * E98 r------- -------- Foreground tilemap row scroll enable
+ * ------hh hhhhhhhh Foreground tilemap horizontal scroll
+ * E9A r------- -------- Background tilemap row scroll enable
+ * ------hh hhhhhhhh Background tilemap horizontal scroll
+ * E9C ------hh hhhhhhhh Alternate foreground tilemap horizontal scroll
+ * E9E ------hh hhhhhhhh Alternate background tilemap horizontal scroll
+ * F16-F3F -------- vvvvvvvv Foreground tilemap per-16-pixel-column vertical scroll
+ * F56-F7F -------- vvvvvvvv Background tilemap per-16-pixel-column vertical scroll
+ * F80-FB7 a------- -------- Foreground tilemap per-8-pixel-row alternate tilemap enable
+ * -------h hhhhhhhh Foreground tilemap per-8-pixel-row horizontal scroll
+ * FC0-FF7 a------- -------- Background tilemap per-8-pixel-row alternate tilemap enable
+ * -------h hhhhhhhh Background tilemap per-8-pixel-row horizontal scroll
+ *
+ *******************************************************************************************/
+
+static TILE_GET_INFO( segaic16_tilemap_16b_tile_info )
+{
+ const struct tilemap_callback_info *info = param;
+ UINT16 data = info->rambase[tile_index];
+ int color = (data >> 6) & 0x7f;
+ int code = data & 0x1fff;
+
+ code = info->bank[code / info->banksize] * info->banksize + code % info->banksize;
+
+ SET_TILE_INFO(0, code, color, 0);
+ tileinfo->category = (data >> 15) & 1;
+}
+
+
+static TILE_GET_INFO( segaic16_tilemap_16b_text_info )
+{
+ const struct tilemap_callback_info *info = param;
+ UINT16 data = info->rambase[tile_index];
+ int bank = info->bank[0];
+ int color = (data >> 9) & 0x07;
+ int code = data & 0x1ff;
+
+ SET_TILE_INFO(0, bank * info->banksize + code, color, 0);
+ tileinfo->category = (data >> 15) & 1;
+}
+
+
+static TILE_GET_INFO( segaic16_tilemap_16b_alt_tile_info )
+{
+ const struct tilemap_callback_info *info = param;
+ UINT16 data = info->rambase[tile_index];
+ int color = (data >> 5) & 0x7f;
+ int code = data & 0x1fff;
+
+ code = info->bank[code / info->banksize] * info->banksize + code % info->banksize;
+
+ SET_TILE_INFO(0, code, color, 0);
+ tileinfo->category = (data >> 15) & 1;
+}
+
+
+static TILE_GET_INFO( segaic16_tilemap_16b_alt_text_info )
+{
+ const struct tilemap_callback_info *info = param;
+ UINT16 data = info->rambase[tile_index];
+ int bank = info->bank[0];
+ int color = (data >> 8) & 0x07;
+ int code = data & 0xff;
+
+ SET_TILE_INFO(0, bank * info->banksize + code, color, 0);
+ tileinfo->category = (data >> 15) & 1;
+}
+
+
+static void segaic16_tilemap_16b_draw_layer(running_machine *machine, struct tilemap_info *info, mame_bitmap *bitmap, const rectangle *cliprect, int which, int flags, int priority)
+{
+ UINT16 *textram = info->textram;
+ UINT16 xscroll, yscroll, pages;
+ int x, y;
+
+ /* get global values */
+ xscroll = info->latched_xscroll[which];
+ yscroll = info->latched_yscroll[which];
+ pages = info->latched_pageselect[which];
+
+ /* column scroll? */
+ if (yscroll & 0x8000)
+ {
+ if (PRINT_UNUSUAL_MODES) mame_printf_debug("Column AND row scroll\n");
+
+ /* loop over row chunks */
+ for (y = cliprect->min_y & ~7; y <= cliprect->max_y; y += 8)
+ {
+ int rowscrollindex = (info->flip ? (216 - y) : y) / 8;
+ rectangle rowcolclip;
+
+ /* adjust to clip this row only */
+ rowcolclip.min_y = (y < cliprect->min_y) ? cliprect->min_y : y;
+ rowcolclip.max_y = (y + 7 > cliprect->max_y) ? cliprect->max_y : y + 7;
+
+ /* loop over column chunks */
+ for (x = ((cliprect->min_x + 8) & ~15) - 8; x <= cliprect->max_x; x += 16)
+ {
+ UINT16 effxscroll, effyscroll, rowscroll;
+ UINT16 effpages = pages;
+
+ /* adjust to clip this column only */
+ rowcolclip.min_x = (x < cliprect->min_x) ? cliprect->min_x : x;
+ rowcolclip.max_x = (x + 15 > cliprect->max_x) ? cliprect->max_x : x + 15;
+
+ /* get the effective scroll values */
+ rowscroll = textram[0xf80/2 + 0x40/2 * which + rowscrollindex];
+ effxscroll = (xscroll & 0x8000) ? rowscroll : xscroll;
+ effyscroll = textram[0xf16/2 + 0x40/2 * which + (x+8)/16];
+
+ /* are we using an alternate? */
+ if (rowscroll & 0x8000)
+ {
+ effxscroll = info->latched_xscroll[which + 2];
+ effyscroll = info->latched_yscroll[which + 2];
+ effpages = info->latched_pageselect[which + 2];
+ }
+
+ /* draw the chunk */
+ effxscroll = (0xc0 - effxscroll + info->xoffs) & 0x3ff;
+ effyscroll = effyscroll & 0x1ff;
+ segaic16_draw_virtual_tilemap(machine, info, bitmap, &rowcolclip, effpages, effxscroll, effyscroll, flags, priority);
+ }
+ }
+ }
+ else
+ {
+ if (PRINT_UNUSUAL_MODES) mame_printf_debug("Row scroll\n");
+
+ /* loop over row chunks */
+ for (y = cliprect->min_y & ~7; y <= cliprect->max_y; y += 8)
+ {
+ int rowscrollindex = (info->flip ? (216 - y) : y) / 8;
+ rectangle rowclip = *cliprect;
+ UINT16 effxscroll, effyscroll, rowscroll;
+ UINT16 effpages = pages;
+
+ /* adjust to clip this row only */
+ rowclip.min_y = (y < cliprect->min_y) ? cliprect->min_y : y;
+ rowclip.max_y = (y + 7 > cliprect->max_y) ? cliprect->max_y : y + 7;
+
+ /* get the effective scroll values */
+ rowscroll = textram[0xf80/2 + 0x40/2 * which + rowscrollindex];
+ effxscroll = (xscroll & 0x8000) ? rowscroll : xscroll;
+ effyscroll = yscroll;
+
+ /* are we using an alternate? */
+ if (rowscroll & 0x8000)
+ {
+ effxscroll = info->latched_xscroll[which + 2];
+ effyscroll = info->latched_yscroll[which + 2];
+ effpages = info->latched_pageselect[which + 2];
+ }
+
+ /* draw the chunk */
+ effxscroll = (0xc0 - effxscroll + info->xoffs) & 0x3ff;
+ effyscroll = effyscroll & 0x1ff;
+ segaic16_draw_virtual_tilemap(machine, info, bitmap, &rowclip, effpages, effxscroll, effyscroll, flags, priority);
+ }
+ }
+}
+
+
+static TIMER_CALLBACK( segaic16_tilemap_16b_latch_values )
+{
+ struct tilemap_info *info = &bg_tilemap[param];
+ UINT16 *textram = info->textram;
+ int i;
+
+ /* latch the scroll and page select values */
+ for (i = 0; i < 4; i++)
+ {
+ info->latched_pageselect[i] = textram[0xe80/2 + i];
+ info->latched_yscroll[i] = textram[0xe90/2 + i];
+ info->latched_xscroll[i] = textram[0xe98/2 + i];
+ }
+
+ /* set a timer to do this again next frame */
+ timer_set(video_screen_get_time_until_pos(0, 261, 0), param, segaic16_tilemap_16b_latch_values);
+}
+
+
+static void segaic16_tilemap_16b_reset(struct tilemap_info *info)
+{
+ /* set a timer to latch values on scanline 261 */
+ timer_set(video_screen_get_time_until_pos(0, 261, 0), info->index, segaic16_tilemap_16b_latch_values);
+}
+
+
+
+/*************************************
+ *
+ * General tilemap initialization
+ *
+ *************************************/
+
+void segaic16_tilemap_init(int which, int type, int colorbase, int xoffs, int numbanks)
+{
+ struct tilemap_info *info = &bg_tilemap[which];
+ tile_get_info_callback get_text_info;
+ tile_get_info_callback get_tile_info;
+ int pagenum;
+ int i;
+
+ /* reset the tilemap info */
+ memset(info, 0, sizeof(*info));
+ info->index = which;
+ info->type = type;
+ for (i = 0; i < numbanks; i++)
+ info->bank[i] = i;
+ info->banksize = 0x2000 / numbanks;
+ info->xoffs = xoffs;
+
+ /* set up based on which tilemap */
+ switch (which)
+ {
+ case 0:
+ info->textram = segaic16_textram_0;
+ info->tileram = segaic16_tileram_0;
+ break;
+
+ default:
+ fatalerror("Invalid tilemap index specified in segaic16_tilemap_init");
+ }
+
+ /* determine the parameters of the tilemaps */
+ switch (type)
+ {
+ case SEGAIC16_TILEMAP_HANGON:
+ get_text_info = segaic16_tilemap_16a_text_info;
+ get_tile_info = segaic16_tilemap_16a_tile_info;
+ info->numpages = 4;
+ info->draw_layer = segaic16_tilemap_16a_draw_layer;
+ info->reset = NULL;
+ break;
+
+ case SEGAIC16_TILEMAP_16A:
+ get_text_info = segaic16_tilemap_16a_text_info;
+ get_tile_info = segaic16_tilemap_16a_tile_info;
+ info->numpages = 8;
+ info->draw_layer = segaic16_tilemap_16a_draw_layer;
+ info->reset = NULL;
+ break;
+
+ case SEGAIC16_TILEMAP_16B:
+ get_text_info = segaic16_tilemap_16b_text_info;
+ get_tile_info = segaic16_tilemap_16b_tile_info;
+ info->numpages = 16;
+ info->draw_layer = segaic16_tilemap_16b_draw_layer;
+ info->reset = segaic16_tilemap_16b_reset;
+ break;
+
+ case SEGAIC16_TILEMAP_16B_ALT:
+ get_text_info = segaic16_tilemap_16b_alt_text_info;
+ get_tile_info = segaic16_tilemap_16b_alt_tile_info;
+ info->numpages = 16;
+ info->draw_layer = segaic16_tilemap_16b_draw_layer;
+ info->reset = segaic16_tilemap_16b_reset;
+ break;
+
+ default:
+ fatalerror("Invalid tilemap type specified in segaic16_tilemap_init");
+ }
+
+ /* create the tilemap for the text layer */
+ info->textmap = tilemap_create(get_text_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,28);
+
+ /* configure it */
+ info->textmap_info.rambase = info->textram;
+ info->textmap_info.bank = info->bank;
+ info->textmap_info.banksize = info->banksize;
+ tilemap_set_user_data(info->textmap, &info->textmap_info);
+ tilemap_set_palette_offset(info->textmap, colorbase);
+ tilemap_set_transparent_pen(info->textmap, 0);
+ tilemap_set_scrolldx(info->textmap, -192 + xoffs, -170 + xoffs);
+ tilemap_set_scrolldy(info->textmap, 0, 38);
+
+ /* create the tilemaps for the tile pages */
+ for (pagenum = 0; pagenum < info->numpages; pagenum++)
+ {
+ /* each page is 64x32 */
+ info->tilemaps[pagenum] = tilemap_create(get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+
+ /* configure the tilemap */
+ info->tilemap_info[pagenum].rambase = info->tileram + pagenum * 64*32;
+ info->tilemap_info[pagenum].bank = info->bank;
+ info->tilemap_info[pagenum].banksize = info->banksize;
+ tilemap_set_user_data(info->tilemaps[pagenum], &info->tilemap_info[pagenum]);
+ tilemap_set_palette_offset(info->tilemaps[pagenum], colorbase);
+ tilemap_set_transparent_pen(info->tilemaps[pagenum], 0);
+ tilemap_set_scrolldx(info->tilemaps[pagenum], 0, 22);
+ tilemap_set_scrolldy(info->tilemaps[pagenum], 0, 38);
+ }
+}
+
+
+
+/*************************************
+ *
+ * General tilemap rendering
+ *
+ *************************************/
+
+void segaic16_tilemap_draw(running_machine *machine, int which, mame_bitmap *bitmap, const rectangle *cliprect, int map, int priority, int priority_mark)
+{
+ struct tilemap_info *info = &bg_tilemap[which];
+
+ /* text layer is a special common case */
+ if (map == SEGAIC16_TILEMAP_TEXT)
+ tilemap_draw(bitmap, cliprect, info->textmap, priority, priority_mark);
+
+ /* other layers are handled differently per-system */
+ else
+ (*info->draw_layer)(machine, info, bitmap, cliprect, map, priority, priority_mark);
+}
+
+
+
+/*************************************
+ *
+ * General tilemap reset
+ *
+ *************************************/
+
+void segaic16_tilemap_reset(int which)
+{
+ struct tilemap_info *info = &bg_tilemap[which];
+
+ if (info->reset)
+ (*info->reset)(info);
+}
+
+
+
+/*************************************
+ *
+ * General tilemap banking
+ *
+ *************************************/
+
+void segaic16_tilemap_set_bank(int which, int banknum, int offset)
+{
+ struct tilemap_info *info = &bg_tilemap[which];
+
+ if (info->bank[banknum] != offset)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ info->bank[banknum] = offset;
+ tilemap_mark_all_tiles_dirty(NULL);
+ }
+}
+
+
+
+/*************************************
+ *
+ * General tilemap screen flipping
+ *
+ *************************************/
+
+void segaic16_tilemap_set_flip(int which, int flip)
+{
+ struct tilemap_info *info = &bg_tilemap[which];
+ int pagenum;
+
+ flip = (flip != 0);
+ if (info->flip != flip)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ info->flip = flip;
+ tilemap_set_flip(info->textmap, flip ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
+ for (pagenum = 0; pagenum < info->numpages; pagenum++)
+ tilemap_set_flip(info->tilemaps[pagenum], flip ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
+ }
+}
+
+
+
+/*************************************
+ *
+ * General tilemap row scroll enable
+ *
+ *************************************/
+
+void segaic16_tilemap_set_rowscroll(int which, int enable)
+{
+ struct tilemap_info *info = &bg_tilemap[which];
+
+ enable = (enable != 0);
+ if (info->rowscroll != enable)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ info->rowscroll = enable;
+ }
+}
+
+
+
+/*************************************
+ *
+ * General tilemap column scroll enable
+ *
+ *************************************/
+
+void segaic16_tilemap_set_colscroll(int which, int enable)
+{
+ struct tilemap_info *info = &bg_tilemap[which];
+
+ enable = (enable != 0);
+ if (info->colscroll != enable)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ info->colscroll = enable;
+ }
+}
+
+
+
+/*************************************
+ *
+ * General tilemap write handlers
+ *
+ *************************************/
+
+WRITE16_HANDLER( segaic16_tileram_0_w )
+{
+ COMBINE_DATA(&segaic16_tileram_0[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap[0].tilemaps[offset / (64*32)], offset % (64*32));
+}
+
+
+WRITE16_HANDLER( segaic16_textram_0_w )
+{
+ /* certain ranges need immediate updates */
+ if (offset >= 0xe80/2)
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ COMBINE_DATA(&segaic16_textram_0[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap[0].textmap, offset);
+}
+
+
+
+/*******************************************************************************************
+ *
+ * Hang On-style sprites
+ *
+ * Offs Bits Usage
+ * +0 bbbbbbbb -------- Bottom scanline of sprite - 1
+ * +0 -------- tttttttt Top scanline of sprite - 1
+ * +2 bbbb---- -------- Sprite bank
+ * +2 -------x xxxxxxxx X position of sprite (position $BD is screen position 0)
+ * +4 pppppppp pppppppp Signed 16-bit pitch value between scanlines
+ * +6 -ooooooo oooooooo Offset within selected sprite bank
+ * +6 f------- -------- Horizontal flip: read the data backwards if set
+ * +8 --cccccc -------- Sprite color palette
+ * +8 -------- zzzzzz-- Zoom factor
+ * +8 -------- ------pp Sprite priority
+ * +E dddddddd dddddddd Scratch space for current address
+ *
+ * Special notes:
+ *
+ * There is an interaction between the horizonal flip bit and the offset.
+ * The offset is maintained as a 16-bit value, even though only the lower
+ * 15 bits are used for the address. The top bit is used to control flipping.
+ * This means that if the low 15 bits overflow during rendering, the sprite
+ * data will be read backwards after the overflow. This is important to
+ * emulate correctly as many games make use of this feature to render sprites
+ * at the beginning of a bank.
+ *
+ *******************************************************************************************/
+
+#define hangon_draw_pixel() \
+ /* only draw if onscreen, not 0 or 15 */ \
+ if (pix != 0 && pix != 15) \
+ { \
+ /* are we high enough priority to be visible? */ \
+ if (sprpri > pri[x]) \
+ { \
+ /* shadow/hilight mode? */ \
+ if (color == info->colorbase + (0x3f << 4)) \
+ dest[x] += info->shadow ? palette.entries*2 : palette.entries; \
+ \
+ /* regular draw */ \
+ else \
+ dest[x] = pix | color; \
+ } \
+ \
+ /* always mark priority so no one else draws here */ \
+ pri[x] = 0xff; \
+ } \
+
+static void segaic16_sprites_hangon_draw(struct sprite_info *info, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 numbanks = memory_region_length(REGION_GFX2) / 0x10000;
+ const UINT16 *spritebase = (const UINT16 *)memory_region(REGION_GFX2);
+ const UINT8 *zoom = (const UINT8 *)memory_region(REGION_PROMS);
+ UINT16 *data;
+
+ /* first scan forward to find the end of the list */
+ for (data = info->spriteram; data < info->spriteram + info->ramsize/2; data += 8)
+ if ((data[0] >> 8) > 0xf0)
+ break;
+
+ /* now scan backwards and render the sprites in order */
+ for (data -= 8; data >= info->spriteram; data -= 8)
+ {
+ int bottom = (data[0] >> 8) + 1;
+ int top = (data[0] & 0xff) + 1;
+ int bank = info->bank[(data[1] >> 12) & 0xf];
+ int xpos = (data[1] & 0x1ff) - 0xbd;
+ int pitch = (INT16)data[2];
+ UINT16 addr = data[3];
+ int color = info->colorbase + (((data[4] >> 8) & 0x3f) << 4);
+ int vzoom = (data[4] >> 2) & 0x3f;
+ int hzoom = vzoom << 1;
+ int sprpri = 1 << ((data[4] >> 0) & 0x3);
+ int x, y, pix, zaddr, zmask;
+ const UINT16 *spritedata;
+
+ /* initialize the end address to the start address */
+ data[7] = addr;
+
+ /* if hidden, or top greater than/equal to bottom, or invalid bank, punt */
+ if ((top >= bottom) || bank == 255)
+ continue;
+
+ /* clamp to within the memory region size */
+ if (numbanks)
+ bank %= numbanks;
+ spritedata = spritebase + 0x8000 * bank;
+
+ /* determine the starting zoom address and mask */
+ zaddr = (vzoom & 0x38) << 5;
+ zmask = 1 << (vzoom & 7);
+
+ /* loop from top to bottom */
+ for (y = top; y < bottom; y++)
+ {
+ /* advance a row */
+ addr += pitch;
+
+ /* if the zoom bit says so, add pitch a second time */
+ if (zoom[zaddr++] & zmask)
+ addr += pitch;
+
+ /* skip drawing if not within the cliprect */
+ if (y >= cliprect->min_y && y <= cliprect->max_y)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+ int xacc = 0x00;
+
+ /* note that the System 16A sprites have a design flaw that allows the address */
+ /* to carry into the flip flag, which is the topmost bit -- it is very important */
+ /* to emulate this as the games compensate for it */
+
+ /* non-flipped case */
+ if (!(addr & 0x8000))
+ {
+ /* start at the word before because we preincrement below */
+ data[7] = addr - 1;
+ for (x = xpos; x <= cliprect->max_x; )
+ {
+ UINT16 pixels = spritedata[++data[7] & 0x7fff];
+
+ /* draw four pixels */
+ pix = (pixels >> 12) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) hangon_draw_pixel(); x++; }
+ pix = (pixels >> 8) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) hangon_draw_pixel(); x++; }
+ pix = (pixels >> 4) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) hangon_draw_pixel(); x++; }
+ pix = (pixels >> 0) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) hangon_draw_pixel(); x++; }
+
+ /* stop if the last pixel in the group was 0xf */
+ if (pix == 15)
+ break;
+ }
+ }
+
+ /* flipped case */
+ else
+ {
+ /* start at the word after because we predecrement below */
+ data[7] = addr + 1;
+ for (x = xpos; x <= cliprect->max_x; )
+ {
+ UINT16 pixels = spritedata[--data[7] & 0x7fff];
+
+ /* draw four pixels */
+ pix = (pixels >> 0) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) hangon_draw_pixel(); x++; }
+ pix = (pixels >> 4) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) hangon_draw_pixel(); x++; }
+ pix = (pixels >> 8) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) hangon_draw_pixel(); x++; }
+ pix = (pixels >> 12) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) hangon_draw_pixel(); x++; }
+
+ /* stop if the last pixel in the group was 0xf */
+ if (pix == 15)
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+/*******************************************************************************************
+ *
+ * Space Harrier-style sprites
+ *
+ * Offs Bits Usage
+ * +0 bbbbbbbb -------- Bottom scanline of sprite - 1
+ * +0 -------- tttttttt Top scanline of sprite - 1
+ * +2 bbbb---- -------- Sprite bank
+ * +2 -------x xxxxxxxx X position of sprite (position $BD is screen position 0)
+ * +4 s------- -------- Sprite shadow enable (0=enable, 1=disable)
+ * +4 -p------ -------- Sprite priority
+ * +4 --cccccc -------- Sprite color palette
+ * +4 -------- -ppppppp Signed 7-bit pitch value between scanlines
+ * +6 f------- -------- Horizontal flip: read the data backwards if set
+ * +6 -ooooooo oooooooo Offset within selected sprite bank
+ * +8 --zzzzzz -------- Horizontal zoom factor
+ * +8 -------- --zzzzzz Vertical zoom factor
+ * +E dddddddd dddddddd Scratch space for current address
+ *
+ * Special notes:
+ *
+ * There is an interaction between the horizonal flip bit and the offset.
+ * The offset is maintained as a 16-bit value, even though only the lower
+ * 15 bits are used for the address. The top bit is used to control flipping.
+ * This means that if the low 15 bits overflow during rendering, the sprite
+ * data will be read backwards after the overflow. This is important to
+ * emulate correctly as many games make use of this feature to render sprites
+ * at the beginning of a bank.
+ *
+ *******************************************************************************************/
+
+#define sharrier_draw_pixel() \
+ /* only draw if onscreen, not 0 or 15 */ \
+ if (pix != 0 && pix != 15) \
+ { \
+ /* are we high enough priority to be visible? */ \
+ if (sprpri > pri[x]) \
+ { \
+ /* shadow/hilight mode? */ \
+ if (shadow && pix == 0xa) \
+ dest[x] += (paletteram16[dest[x]] & 0x8000) ? palette.entries*2 : palette.entries; \
+ \
+ /* regular draw */ \
+ else \
+ dest[x] = pix | color; \
+ } \
+ \
+ /* always mark priority so no one else draws here */ \
+ pri[x] = 0xff; \
+ } \
+
+static void segaic16_sprites_sharrier_draw(struct sprite_info *info, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 numbanks = memory_region_length(REGION_GFX2) / 0x20000;
+ const UINT32 *spritebase = (const UINT32 *)memory_region(REGION_GFX2);
+ const UINT8 *zoom = (const UINT8 *)memory_region(REGION_PROMS);
+ UINT16 *data;
+
+ /* first scan forward to find the end of the list */
+ for (data = info->spriteram; data < info->spriteram + info->ramsize/2; data += 8)
+ if ((data[0] >> 8) > 0xf0)
+ break;
+
+ /* now scan backwards and render the sprites in order */
+ for (data -= 8; data >= info->spriteram; data -= 8)
+ {
+ int bottom = (data[0] >> 8) + 1;
+ int top = (data[0] & 0xff) + 1;
+ int bank = info->bank[(data[1] >> 12) & 0x7];
+ int xpos = (data[1] & 0x1ff) - 0xbd;
+ int shadow = (~data[2] >> 15) & 1;
+ int sprpri = ((data[2] >> 14) & 1) ? (1<<3) : (1<<1);
+ int color = info->colorbase + (((data[2] >> 8) & 0x3f) << 4);
+ int pitch = (INT16)(data[2] << 9) >> 9;
+ UINT16 addr = data[3];
+ int hzoom = ((data[4] >> 8) & 0x3f) << 1;
+ int vzoom = (data[4] >> 0) & 0x3f;
+ int x, y, pix, zaddr, zmask;
+ const UINT32 *spritedata;
+
+ /* initialize the end address to the start address */
+ data[7] = addr;
+
+ /* if hidden, or top greater than/equal to bottom, or invalid bank, punt */
+ if ((top >= bottom) || bank == 255)
+ continue;
+
+ /* clamp to within the memory region size */
+ if (numbanks)
+ bank %= numbanks;
+ spritedata = spritebase + 0x8000 * bank;
+
+ /* determine the starting zoom address and mask */
+ zaddr = (vzoom & 0x38) << 5;
+ zmask = 1 << (vzoom & 7);
+
+ /* loop from top to bottom */
+ for (y = top; y < bottom; y++)
+ {
+ /* advance a row */
+ addr += pitch;
+
+ /* if the zoom bit says so, add pitch a second time */
+ if (zoom[zaddr++] & zmask)
+ addr += pitch;
+
+ /* skip drawing if not within the cliprect */
+ if (y >= cliprect->min_y && y <= cliprect->max_y)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+ int xacc = 0x00;
+
+ /* note that the System 16A sprites have a design flaw that allows the address */
+ /* to carry into the flip flag, which is the topmost bit -- it is very important */
+ /* to emulate this as the games compensate for it */
+
+ /* non-flipped case */
+ if (!(addr & 0x8000))
+ {
+ /* start at the word before because we preincrement below */
+ data[7] = addr - 1;
+ for (x = xpos; x <= cliprect->max_x; )
+ {
+ UINT32 pixels = spritedata[++data[7] & 0x7fff];
+
+ /* draw 8 pixels */
+ pix = (pixels >> 28) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+ pix = (pixels >> 24) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+ pix = (pixels >> 20) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+ pix = (pixels >> 16) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+ pix = (pixels >> 12) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+ pix = (pixels >> 8) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+ pix = (pixels >> 4) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+ pix = (pixels >> 0) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+
+ /* stop if the last pixel in the group was 0xf */
+ if (pix == 15)
+ break;
+ }
+ }
+
+ /* flipped case */
+ else
+ {
+ /* start at the word after because we predecrement below */
+ data[7] = addr + 1;
+ for (x = xpos; x <= cliprect->max_x; )
+ {
+ UINT32 pixels = spritedata[--data[7] & 0x7fff];
+
+ /* draw 8 pixels */
+ pix = (pixels >> 0) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+ pix = (pixels >> 4) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+ pix = (pixels >> 8) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+ pix = (pixels >> 12) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+ pix = (pixels >> 16) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+ pix = (pixels >> 20) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+ pix = (pixels >> 24) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+ pix = (pixels >> 28) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect->min_x) sharrier_draw_pixel(); x++; }
+
+ /* stop if the last pixel in the group was 0xf */
+ if (pix == 15)
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+/*******************************************************************************************
+ *
+ * System 16A-style sprites
+ *
+ * Offs Bits Usage
+ * +0 bbbbbbbb -------- Bottom scanline of sprite - 1
+ * +0 -------- tttttttt Top scanline of sprite - 1
+ * +2 -------x xxxxxxxx X position of sprite (position $BD is screen position 0)
+ * +4 pppppppp pppppppp Signed 16-bit pitch value between scanlines
+ * +6 -ooooooo oooooooo Offset within selected sprite bank
+ * +6 f------- -------- Horizontal flip: read the data backwards if set
+ * +8 --cccccc -------- Sprite color palette
+ * +8 -------- -bbb---- Sprite bank
+ * +8 -------- ------pp Sprite priority
+ * +E dddddddd dddddddd Scratch space for current address
+ *
+ * Special notes:
+ *
+ * There is an interaction between the horizonal flip bit and the offset.
+ * The offset is maintained as a 16-bit value, even though only the lower
+ * 15 bits are used for the address. The top bit is used to control flipping.
+ * This means that if the low 15 bits overflow during rendering, the sprite
+ * data will be read backwards after the overflow. This is important to
+ * emulate correctly as many games make use of this feature to render sprites
+ * at the beginning of a bank.
+ *
+ *******************************************************************************************/
+
+#define system16a_draw_pixel() \
+ /* only draw if onscreen, not 0 or 15 */ \
+ if (x >= cliprect->min_x && x <= cliprect->max_x && pix != 0 && pix != 15) \
+ { \
+ /* are we high enough priority to be visible? */ \
+ if (sprpri > pri[x]) \
+ { \
+ /* shadow/hilight mode? */ \
+ if (color == info->colorbase + (0x3f << 4)) \
+ dest[x] += (paletteram16[dest[x]] & 0x8000) ? palette.entries*2 : palette.entries; \
+ \
+ /* regular draw */ \
+ else \
+ dest[x] = pix | color; \
+ } \
+ \
+ /* always mark priority so no one else draws here */ \
+ pri[x] = 0xff; \
+ } \
+
+static void segaic16_sprites_16a_draw(struct sprite_info *info, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 numbanks = memory_region_length(REGION_GFX2) / 0x10000;
+ const UINT16 *spritebase = (const UINT16 *)memory_region(REGION_GFX2);
+ UINT16 *data;
+
+ /* first scan forward to find the end of the list */
+ for (data = info->spriteram; data < info->spriteram + info->ramsize/2; data += 8)
+ if ((data[0] >> 8) > 0xf0)
+ break;
+
+ /* now scan backwards and render the sprites in order */
+ for (data -= 8; data >= info->spriteram; data -= 8)
+ {
+ int bottom = (data[0] >> 8) + 1;
+ int top = (data[0] & 0xff) + 1;
+ int xpos = (data[1] & 0x1ff) - 0xbd;
+ int pitch = (INT16)data[2];
+ UINT16 addr = data[3];
+ int color = info->colorbase + (((data[4] >> 8) & 0x3f) << 4);
+ int bank = info->bank[(data[4] >> 4) & 0x7];
+ int sprpri = 1 << ((data[4] >> 0) & 0x3);
+ const UINT16 *spritedata;
+ int x, y, pix, xdelta = 1;
+
+ /* initialize the end address to the start address */
+ data[7] = addr;
+
+ /* if hidden, or top greater than/equal to bottom, or invalid bank, punt */
+ if ((top >= bottom) || bank == 255)
+ continue;
+
+ /* clamp to within the memory region size */
+ if (numbanks)
+ bank %= numbanks;
+ spritedata = spritebase + 0x8000 * bank;
+
+ /* adjust positions for screen flipping */
+ if (info->flip)
+ {
+ int temp = top;
+ top = 224 - bottom;
+ bottom = 224 - temp;
+ xpos = 320 - xpos;
+ xdelta = -1;
+ }
+
+ /* loop from top to bottom */
+ for (y = top; y < bottom; y++)
+ {
+ /* advance a row */
+ addr += pitch;
+
+ /* skip drawing if not within the cliprect */
+ if (y >= cliprect->min_y && y <= cliprect->max_y)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+
+ /* note that the System 16A sprites have a design flaw that allows the address */
+ /* to carry into the flip flag, which is the topmost bit -- it is very important */
+ /* to emulate this as the games compensate for it */
+
+ /* non-flipped case */
+ if (!(addr & 0x8000))
+ {
+ /* start at the word before because we preincrement below */
+ data[7] = addr - 1;
+ for (x = xpos; ((xpos - x) & 0x1ff) != 1; )
+ {
+ UINT16 pixels = spritedata[++data[7] & 0x7fff];
+
+ /* draw four pixels */
+ pix = (pixels >> 12) & 0xf; system16a_draw_pixel(); x += xdelta;
+ pix = (pixels >> 8) & 0xf; system16a_draw_pixel(); x += xdelta;
+ pix = (pixels >> 4) & 0xf; system16a_draw_pixel(); x += xdelta;
+ pix = (pixels >> 0) & 0xf; system16a_draw_pixel(); x += xdelta;
+
+ /* stop if the last pixel in the group was 0xf */
+ if (pix == 15)
+ break;
+ }
+ }
+
+ /* flipped case */
+ else
+ {
+ /* start at the word after because we predecrement below */
+ data[7] = addr + 1;
+ for (x = xpos; ((xpos - x) & 0x1ff) != 1; )
+ {
+ UINT16 pixels = spritedata[--data[7] & 0x7fff];
+
+ /* draw four pixels */
+ pix = (pixels >> 0) & 0xf; system16a_draw_pixel(); x += xdelta;
+ pix = (pixels >> 4) & 0xf; system16a_draw_pixel(); x += xdelta;
+ pix = (pixels >> 8) & 0xf; system16a_draw_pixel(); x += xdelta;
+ pix = (pixels >> 12) & 0xf; system16a_draw_pixel(); x += xdelta;
+
+ /* stop if the last pixel in the group was 0xf */
+ if (pix == 15)
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+/*******************************************************************************************
+ *
+ * System 16B-style sprites
+ *
+ * Offs Bits Usage
+ * +0 bbbbbbbb -------- Bottom scanline of sprite - 1
+ * +0 -------- tttttttt Top scanline of sprite - 1
+ * +2 -------x xxxxxxxx X position of sprite (position $BD is screen position 0)
+ * +4 e------- -------- Signify end of sprite list
+ * +4 -h------ -------- Hide this sprite
+ * +4 -------f -------- Horizontal flip: read the data backwards if set
+ * +4 -------- pppppppp Signed 8-bit pitch value between scanlines
+ * +6 oooooooo oooooooo Offset within selected sprite bank
+ * +8 ----bbbb -------- Sprite bank
+ * +8 -------- pp------ Sprite priority, relative to tilemaps
+ * +8 -------- --cccccc Sprite color palette
+ * +A ------vv vvv----- Vertical zoom factor (0 = full size, 0x10 = half size)
+ * +A -------- ---hhhhh Horizontal zoom factor (0 = full size, 0x10 = half size)
+ * +E dddddddd dddddddd Scratch space for current address
+ *
+ * Note that the zooming described below is 100% accurate to the real board.
+ *
+ *******************************************************************************************/
+
+#define system16b_draw_pixel() \
+ /* only draw if onscreen, not 0 or 15 */ \
+ if (x >= cliprect->min_x && x <= cliprect->max_x && pix != 0 && pix != 15) \
+ { \
+ /* are we high enough priority to be visible? */ \
+ if (sprpri > pri[x]) \
+ { \
+ /* shadow/hilight mode? */ \
+ if (color == info->colorbase + (0x3f << 4)) \
+ dest[x] += (paletteram16[dest[x]] & 0x8000) ? palette.entries*2 : palette.entries; \
+ \
+ /* regular draw */ \
+ else \
+ dest[x] = pix | color; \
+ } \
+ \
+ /* always mark priority so no one else draws here */ \
+ pri[x] = 0xff; \
+ } \
+
+static void segaic16_sprites_16b_draw(struct sprite_info *info, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 numbanks;
+ const UINT16 *spritebase;
+ UINT16 *data;
+
+ if (!memory_region(REGION_GFX2))
+ return;
+
+ spritebase = (const UINT16 *)memory_region(REGION_GFX2);
+ numbanks = memory_region_length(REGION_GFX2) / 0x20000;
+
+ /* first scan forward to find the end of the list */
+ for (data = info->spriteram; data < info->spriteram + info->ramsize/2; data += 8)
+ if (data[2] & 0x8000)
+ break;
+
+ /* now scan backwards and render the sprites in order */
+ for (data -= 8; data >= info->spriteram; data -= 8)
+ {
+ int bottom = data[0] >> 8;
+ int top = data[0] & 0xff;
+ int xpos = (data[1] & 0x1ff) - 0xb8;
+ int hide = data[2] & 0x4000;
+ int flip = data[2] & 0x100;
+ int pitch = (INT8)(data[2] & 0xff);
+ UINT16 addr = data[3];
+ int bank = info->bank[(data[4] >> 8) & 0xf];
+ int sprpri = 1 << ((data[4] >> 6) & 0x3);
+ int color = info->colorbase + ((data[4] & 0x3f) << 4);
+ int vzoom = (data[5] >> 5) & 0x1f;
+ int hzoom = data[5] & 0x1f;
+ const UINT16 *spritedata;
+ int x, y, pix, xdelta = 1;
+
+ /* initialize the end address to the start address */
+ data[7] = addr;
+
+ /* if hidden, or top greater than/equal to bottom, or invalid bank, punt */
+ if (hide || (top >= bottom) || bank == 255)
+ continue;
+
+ /* clamp to within the memory region size */
+ if (numbanks)
+ bank %= numbanks;
+ spritedata = spritebase + 0x10000 * bank;
+
+ /* reset the yzoom counter */
+ data[5] &= 0x03ff;
+
+ /* adjust positions for screen flipping */
+ if (info->flip)
+ {
+ int temp = top;
+ top = 224 - bottom;
+ bottom = 224 - temp;
+ xpos = 320 - xpos;
+ xdelta = -1;
+ }
+
+ /* loop from top to bottom */
+ for (y = top; y < bottom; y++)
+ {
+ /* advance a row */
+ addr += pitch;
+
+ /* accumulate zoom factors; if we carry into the high bit, skip an extra row */
+ data[5] += vzoom << 10;
+ if (data[5] & 0x8000)
+ {
+ addr += pitch;
+ data[5] &= ~0x8000;
+ }
+
+ /* skip drawing if not within the cliprect */
+ if (y >= cliprect->min_y && y <= cliprect->max_y)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+ int xacc;
+
+ /* compute the initial X zoom accumulator; this is verified on the real PCB */
+ xacc = 4 * hzoom;
+
+ /* non-flipped case */
+ if (!flip)
+ {
+ /* start at the word before because we preincrement below */
+ data[7] = addr - 1;
+ for (x = xpos; ((xpos - x) & 0x1ff) != 1; )
+ {
+ UINT16 pixels = spritedata[++data[7]];
+
+ /* draw four pixels */
+ pix = (pixels >> 12) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { system16b_draw_pixel(); x += xdelta; }
+ pix = (pixels >> 8) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { system16b_draw_pixel(); x += xdelta; }
+ pix = (pixels >> 4) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { system16b_draw_pixel(); x += xdelta; }
+ pix = (pixels >> 0) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { system16b_draw_pixel(); x += xdelta; }
+
+ /* stop if the last pixel in the group was 0xf */
+ if (pix == 15)
+ break;
+ }
+ }
+
+ /* flipped case */
+ else
+ {
+ /* start at the word after because we predecrement below */
+ data[7] = addr + 1;
+ for (x = xpos; ((xpos - x) & 0x1ff) != 1; )
+ {
+ UINT16 pixels = spritedata[--data[7]];
+
+ /* draw four pixels */
+ pix = (pixels >> 0) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { system16b_draw_pixel(); x += xdelta; }
+ pix = (pixels >> 4) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { system16b_draw_pixel(); x += xdelta; }
+ pix = (pixels >> 8) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { system16b_draw_pixel(); x += xdelta; }
+ pix = (pixels >> 12) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { system16b_draw_pixel(); x += xdelta; }
+
+ /* stop if the last pixel in the group was 0xf */
+ if (pix == 15)
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/*******************************************************************************************
+ *
+ * The Y-board variant has different mixing properties. The sprite implementation itself
+ * is identical, however.
+ *
+ *******************************************************************************************/
+
+#define yboard_16b_draw_pixel() \
+ /* only draw if onscreen, not 0 or 15 */ \
+ if (x >= cliprect->min_x && x <= cliprect->max_x && pix != 0 && pix != 15) \
+ { \
+ /* are we high enough priority to be visible? */ \
+ if ((sprpri & 0x1f) < (pri[x] & 0x1f)) \
+ { \
+ /* shadow/hilight mode? */ \
+ if (pix == 14) \
+ dest[x] += (paletteram16[dest[x]] & 0x8000) ? palette.entries*2 : palette.entries; \
+ \
+ /* regular draw */ \
+ else \
+ dest[x] = pix | color; \
+ } \
+ \
+ /* always mark priority so no one else draws here */ \
+ pri[x] = 0; \
+ } \
+
+static void segaic16_sprites_yboard_16b_draw(struct sprite_info *info, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 numbanks = memory_region_length(REGION_GFX2) / 0x20000;
+ const UINT16 *spritebase = (const UINT16 *)memory_region(REGION_GFX2);
+ UINT16 *data;
+
+ /* first scan forward to find the end of the list */
+ for (data = info->spriteram; data < info->spriteram + info->ramsize/2; data += 8)
+ if (data[2] & 0x8000)
+ break;
+
+ /* now scan backwards and render the sprites in order */
+ for (data -= 8; data >= info->spriteram; data -= 8)
+ {
+ int bottom = data[0] >> 8;
+ int top = data[0] & 0xff;
+ int xpos = (data[1] & 0x1ff) - 0xb8;
+ int sprpri = (data[1] >> 8) & 0x1e; // 0x00 = high, 0x7f = low -- 0x71 = ship in gforce, 0x31 = strike fighter logo
+ int hide = data[2] & 0x4000;
+ int flip = data[2] & 0x100;
+ int pitch = (INT8)(data[2] & 0xff);
+ UINT16 addr = data[3];
+ int bank = info->bank[(data[4] >> 8) & 0xf];
+ int color = info->colorbase + ((data[4] & 0x7f) << 4);
+ int vzoom = (data[5] >> 5) & 0x1f;
+ int hzoom = data[5] & 0x1f;
+ const UINT16 *spritedata;
+ int x, y, pix, xdelta = 1;
+
+ /* initialize the end address to the start address */
+ data[7] = addr;
+
+ /* if hidden, or top greater than/equal to bottom, or invalid bank, punt */
+ if (hide || (top >= bottom) || bank == 255)
+ continue;
+
+ /* clamp to within the memory region size */
+ if (numbanks)
+ bank %= numbanks;
+ spritedata = spritebase + 0x10000 * bank;
+
+ /* reset the yzoom counter */
+ data[5] &= 0x03ff;
+
+ /* adjust positions for screen flipping */
+ if (info->flip)
+ {
+ int temp = top;
+ top = 224 - bottom;
+ bottom = 224 - temp;
+ xpos = 320 - xpos;
+ xdelta = -1;
+ }
+
+ /* loop from top to bottom */
+ for (y = top; y < bottom; y++)
+ {
+ /* advance a row */
+ addr += pitch;
+
+ /* accumulate zoom factors; if we carry into the high bit, skip an extra row */
+ data[5] += vzoom << 10;
+ if (data[5] & 0x8000)
+ {
+ addr += pitch;
+ data[5] &= ~0x8000;
+ }
+
+ /* skip drawing if not within the cliprect */
+ if (y >= cliprect->min_y && y <= cliprect->max_y)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+ int xacc;
+
+ /* compute the initial X zoom accumulator; this is verified on the real PCB */
+ xacc = 4 * hzoom;
+
+ /* non-flipped case */
+ if (!flip)
+ {
+ /* start at the word before because we preincrement below */
+ data[7] = addr - 1;
+ for (x = xpos; ((xpos - x) & 0x1ff) != 1; )
+ {
+ UINT16 pixels = spritedata[++data[7]];
+
+ /* draw four pixels */
+ pix = (pixels >> 12) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { yboard_16b_draw_pixel(); x += xdelta; }
+ pix = (pixels >> 8) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { yboard_16b_draw_pixel(); x += xdelta; }
+ pix = (pixels >> 4) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { yboard_16b_draw_pixel(); x += xdelta; }
+ pix = (pixels >> 0) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { yboard_16b_draw_pixel(); x += xdelta; }
+
+ /* stop if the last pixel in the group was 0xf */
+ if (pix == 15)
+ break;
+ }
+ }
+
+ /* flipped case */
+ else
+ {
+ /* start at the word after because we predecrement below */
+ data[7] = addr + 1;
+ for (x = xpos; ((xpos - x) & 0x1ff) != 1; )
+ {
+ UINT16 pixels = spritedata[--data[7]];
+
+ /* draw four pixels */
+ pix = (pixels >> 0) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { yboard_16b_draw_pixel(); x += xdelta; }
+ pix = (pixels >> 4) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { yboard_16b_draw_pixel(); x += xdelta; }
+ pix = (pixels >> 8) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { yboard_16b_draw_pixel(); x += xdelta; }
+ pix = (pixels >> 12) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { yboard_16b_draw_pixel(); x += xdelta; }
+
+ /* stop if the last pixel in the group was 0xf */
+ if (pix == 15)
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+/*******************************************************************************************
+ *
+ * Out Run/X-Board-style sprites
+ *
+ * Offs Bits Usage
+ * +0 e------- -------- Signify end of sprite list
+ * +0 -h-h---- -------- Hide this sprite if either bit is set
+ * +0 ----bbb- -------- Sprite bank
+ * +0 -------t tttttttt Top scanline of sprite + 256
+ * +2 oooooooo oooooooo Offset within selected sprite bank
+ * +4 ppppppp- -------- Signed 7-bit pitch value between scanlines
+ * +4 -------x xxxxxxxx X position of sprite (position $BE is screen position 0)
+ * +6 -s------ -------- Enable shadows
+ * +6 --pp---- -------- Sprite priority, relative to tilemaps
+ * +6 ------vv vvvvvvvv Vertical zoom factor (0x200 = full size, 0x100 = half size, 0x300 = 2x size)
+ * +8 y------- -------- Render from top-to-bottom (1) or bottom-to-top (0) on screen
+ * +8 -f------ -------- Horizontal flip: read the data backwards if set
+ * +8 --x----- -------- Render from left-to-right (1) or right-to-left (0) on screen
+ * +8 ------hh hhhhhhhh Horizontal zoom factor (0x200 = full size, 0x100 = half size, 0x300 = 2x size)
+ * +E dddddddd dddddddd Scratch space for current address
+ *
+ * Out Run only:
+ * +A hhhhhhhh -------- Height in scanlines - 1
+ * +A -------- -ccccccc Sprite color palette
+ *
+ * X-Board only:
+ * +A ----hhhh hhhhhhhh Height in scanlines - 1
+ * +C -------- cccccccc Sprite color palette
+ *
+ *******************************************************************************************/
+
+#define outrun_draw_pixel() \
+ /* only draw if onscreen, not 0 or 15 */ \
+ if (x >= cliprect->min_x && x <= cliprect->max_x && pix != 0 && pix != 15) \
+ { \
+ /* are we high enough priority to be visible? */ \
+ if (sprpri > pri[x]) \
+ { \
+ /* shadow/hilight mode? */ \
+ if (shadow && pix == 0xa) \
+ dest[x] += (paletteram16[dest[x]] & 0x8000) ? palette.entries*2 : palette.entries; \
+ \
+ /* regular draw */ \
+ else \
+ dest[x] = pix | color; \
+ } \
+ \
+ /* always mark priority so no one else draws here */ \
+ pri[x] = 0xff; \
+ } \
+
+static void segaic16_sprites_outrun_draw(struct sprite_info *info, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 numbanks = memory_region_length(REGION_GFX2) / 0x40000;
+ const UINT32 *spritebase = (const UINT32 *)memory_region(REGION_GFX2);
+ UINT16 *data;
+
+ /* first scan forward to find the end of the list */
+ for (data = info->buffer; data < info->buffer + info->ramsize/2; data += 8)
+ if (data[0] & 0x8000)
+ break;
+
+ /* now scan backwards and render the sprites in order */
+ for (data -= 8; data >= info->buffer; data -= 8)
+ {
+ int hide = (data[0] & 0x5000);
+ int bank = (data[0] >> 9) & 7;
+ int top = (data[0] & 0x1ff) - 0x100;
+ UINT16 addr = data[1];
+ int pitch = (INT16)((data[2] >> 1) | ((data[4] & 0x1000) << 3)) >> 8;
+ int xpos = data[2] & 0x1ff;
+ int shadow = (data[3] >> 14) & 1;
+ int sprpri = 1 << ((data[3] >> 12) & 3);
+ int vzoom = data[3] & 0x7ff;
+ int ydelta = (data[4] & 0x8000) ? 1 : -1;
+ int flip = (~data[4] >> 14) & 1;
+ int xdelta = (data[4] & 0x2000) ? 1 : -1;
+ int hzoom = data[4] & 0x7ff;
+ int height = ((info->type == SEGAIC16_SPRITES_OUTRUN) ? (data[5] >> 8) : (data[5] & 0xfff)) + 1;
+ int color = info->colorbase + (((info->type == SEGAIC16_SPRITES_OUTRUN) ? (data[5] & 0x7f) : (data[6] & 0xff)) << 4);
+ int x, y, ytarget, yacc = 0, pix;
+ const UINT32 *spritedata;
+
+ /* adjust X coordinate */
+ /* note: the threshhold below is a guess. If it is too high, rachero will draw garbage */
+ /* If it is too low, smgp won't draw the bottom part of the road */
+ if (xpos < 0x80 && xdelta < 0)
+ xpos += 0x200;
+ xpos -= 0xbe;
+
+ /* initialize the end address to the start address */
+ data[7] = addr;
+
+ /* if hidden, or top greater than/equal to bottom, or invalid bank, punt */
+ if (hide || height == 0)
+ continue;
+
+ /* clamp to within the memory region size */
+ if (numbanks)
+ bank %= numbanks;
+ spritedata = spritebase + 0x10000 * bank;
+
+ /* clamp to a maximum of 8x (not 100% confirmed) */
+ if (vzoom < 0x40) vzoom = 0x40;
+ if (hzoom < 0x40) hzoom = 0x40;
+
+ /* loop from top to bottom */
+ ytarget = top + ydelta * height;
+ for (y = top; y != ytarget; y += ydelta)
+ {
+ /* skip drawing if not within the cliprect */
+ if (y >= cliprect->min_y && y <= cliprect->max_y)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+ int xacc = 0;
+
+ /* non-flipped case */
+ if (!flip)
+ {
+ /* start at the word before because we preincrement below */
+ data[7] = addr - 1;
+ for (x = xpos; (xdelta > 0 && x <= cliprect->max_x) || (xdelta < 0 && x >= cliprect->min_x); )
+ {
+ UINT32 pixels = spritedata[++data[7]];
+
+ /* draw four pixels */
+ pix = (pixels >> 28) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+ pix = (pixels >> 24) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+ pix = (pixels >> 20) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+ pix = (pixels >> 16) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+ pix = (pixels >> 12) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+ pix = (pixels >> 8) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+ pix = (pixels >> 4) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+ pix = (pixels >> 0) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+
+ /* stop if the second-to-last pixel in the group was 0xf */
+ if ((pixels & 0x000000f0) == 0x000000f0)
+ break;
+ }
+ }
+
+ /* flipped case */
+ else
+ {
+ /* start at the word after because we predecrement below */
+ data[7] = addr + 1;
+ for (x = xpos; (xdelta > 0 && x <= cliprect->max_x) || (xdelta < 0 && x >= cliprect->min_x); )
+ {
+ UINT32 pixels = spritedata[--data[7]];
+
+ /* draw four pixels */
+ pix = (pixels >> 0) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+ pix = (pixels >> 4) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+ pix = (pixels >> 8) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+ pix = (pixels >> 12) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+ pix = (pixels >> 16) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+ pix = (pixels >> 20) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+ pix = (pixels >> 24) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+ pix = (pixels >> 28) & 0xf; while (xacc < 0x200) { outrun_draw_pixel(); x += xdelta; xacc += hzoom; } xacc -= 0x200;
+
+ /* stop if the second-to-last pixel in the group was 0xf */
+ if ((pixels & 0x0f000000) == 0x0f000000)
+ break;
+ }
+ }
+ }
+
+ /* accumulate zoom factors; if we carry into the high bit, skip an extra row */
+ yacc += vzoom;
+ addr += pitch * (yacc >> 9);
+ yacc &= 0x1ff;
+ }
+ }
+}
+
+
+
+/*******************************************************************************************
+ *
+ * Y-Board-style sprites
+ *
+ * Offs Bits Usage
+ * +0 e------- -------- Signify end of sprite list
+ * +0 -----iii iiiiiiii Address of indirection table (/16)
+ * +2 bbbb---- -------- Upper 4 bits of bank index
+ * +2 ----xxxx xxxxxxxx X position of sprite (position $600 is screen position 0)
+ * +4 bbbb---- -------- Lower 4 bits of bank index
+ * +4 ----yyyy yyyyyyyy Y position of sprite (position $600 is screen position 0)
+ * +6 oooooooo oooooooo Offset within selected sprite bank
+ * +8 hhhhhhhh hhhhhhhh Height of sprite
+ * +A -y------ -------- Render from top-to-bottom (1) or bottom-to-top (0) on screen
+ * +A --f----- -------- Horizontal flip: read the data backwards if set
+ * +A ---x---- -------- Render from left-to-right (1) or right-to-left (0) on screen
+ * +A -----zzz zzzzzzzz Zoom factor
+ * +C -ccc---- -------- Sprite color
+ * +C ----rrrr -------- Sprite priority
+ * +C -------- pppppppp Signed 8-bit pitch value between scanlines
+ * +E ----nnnn nnnnnnnn Index of next sprite
+ *
+ * In addition to these parameters, the sprite area is clipped using scanline extents
+ * stored for every pair of scanlines in the rotation RAM. It's a bit of a cheat for us
+ * to poke our nose into the rotation structure, but there are no known cases of Y-board
+ * sprites without rotation RAM.
+ *
+ *******************************************************************************************/
+
+#define yboard_draw_pixel() \
+ /* only draw if onscreen */ \
+ if (x >= minx && x <= maxx && ind < 0x1fe) \
+ dest[x] = ind | colorpri; \
+
+static void segaic16_sprites_yboard_draw(struct sprite_info *info, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 numbanks = memory_region_length(REGION_GFX1) / 0x80000;
+ const UINT64 *spritebase = (const UINT64 *)memory_region(REGION_GFX1);
+ const UINT16 *rotatebase = rotate[0].buffer ? rotate[0].buffer : rotate[0].rotateram;
+ UINT8 visited[0x1000];
+ UINT16 *data;
+ int next = 0;
+ int y;
+
+ /* reset the visited list */
+ memset(visited, 0, sizeof(visited));
+
+ /* clear out any scanlines we might be using */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ if (!(rotatebase[y & ~1] & 0xc000))
+ memset(BITMAP_ADDR16(bitmap, y, cliprect->min_x), 0xff, (cliprect->max_x - cliprect->min_x + 1) * sizeof(UINT16));
+
+ /* now scan backwards and render the sprites in order */
+ for (data = info->spriteram; !(data[0] & 0x8000) && !visited[next]; data = info->spriteram + next * 8)
+ {
+ int hide = (data[0] & 0x5000);
+ UINT16 *indirect = info->spriteram + ((data[0] & 0x7ff) << 4);
+ int bank = ((data[1] >> 8) & 0x10) | ((data[2] >> 12) & 0x0f);
+ int xpos = (data[1] & 0xfff) - 0x600;
+ int top = (data[2] & 0xfff) - 0x600;
+ UINT16 addr = data[3];
+ int height = data[4];
+ int ydelta = (data[5] & 0x4000) ? 1 : -1;
+ int flip = (~data[5] >> 13) & 1;
+ int xdelta = (data[5] & 0x1000) ? 1 : -1;
+ int zoom = data[5] & 0x7ff;
+ int colorpri= (data[6] << 1) & 0xfe00;
+ int pitch = (INT8)data[6];
+ int x, y, ytarget, yacc = 0, pix, ind;
+ const UINT64 *spritedata;
+ UINT16 offs;
+
+ /* note that we've visited this entry and get the offset of the next one */
+ visited[next] = 1;
+ next = data[7] & 0xfff;
+
+ /* if hidden, or top greater than/equal to bottom, or invalid bank, punt */
+ if (hide || height == 0)
+ continue;
+
+ /* clamp to within the memory region size */
+ if (numbanks)
+ bank %= numbanks;
+ spritedata = spritebase + 0x10000 * bank;
+
+ /* clamp to a maximum of 8x (not 100% confirmed) */
+ if (zoom == 0) zoom = 1;
+
+ /* loop from top to bottom */
+ ytarget = top + ydelta * height;
+ for (y = top; y != ytarget; y += ydelta)
+ {
+ /* skip drawing if not within the cliprect */
+ if (y >= cliprect->min_y && y <= cliprect->max_y)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ int minx = rotatebase[y & ~1];
+ int maxx = rotatebase[y | 1];
+ int xacc = 0;
+
+ /* bit 0x8000 from rotate RAM means that Y is above the top of the screen */
+ if ((minx & 0x8000) && ydelta < 0)
+ break;
+
+ /* bit 0x4000 from rotate RAM means that Y is below the bottom of the screen */
+ if ((minx & 0x4000) && ydelta > 0)
+ break;
+
+ /* if either bit is set, skip the rest for this scanline */
+ if (!(minx & 0xc000))
+ {
+ /* clamp min/max to the cliprect */
+ minx -= 0x600;
+ maxx -= 0x600;
+ if (minx < cliprect->min_x)
+ minx = cliprect->min_x;
+ if (maxx > cliprect->max_x)
+ maxx = cliprect->max_x;
+
+ /* non-flipped case */
+ if (!flip)
+ {
+ /* start at the word before because we preincrement below */
+ offs = addr - 1;
+ for (x = xpos; (xdelta > 0 && x <= maxx) || (xdelta < 0 && x >= minx); )
+ {
+ UINT64 pixels = spritedata[++offs];
+
+ /* draw four pixels */
+ pix = (pixels >> 60) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 56) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 52) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 48) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 44) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 40) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 36) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 32) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 28) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 24) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 20) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 16) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 12) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 8) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 4) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 0) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+
+ /* stop if the second-to-last pixel in the group was 0xf */
+ if (pix == 0x0f)
+ break;
+ }
+ }
+
+ /* flipped case */
+ else
+ {
+ /* start at the word after because we predecrement below */
+ offs = addr + 1;
+ for (x = xpos; (xdelta > 0 && x <= maxx) || (xdelta < 0 && x >= minx); )
+ {
+ UINT64 pixels = spritedata[--offs];
+
+ /* draw four pixels */
+ pix = (pixels >> 0) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 4) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 8) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 12) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 16) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 20) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 24) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 28) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 32) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 36) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 40) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 44) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 48) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 52) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 56) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+ pix = (pixels >> 60) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { yboard_draw_pixel(); x += xdelta; xacc += zoom; } xacc -= 0x200;
+
+ /* stop if the second-to-last pixel in the group was 0xf */
+ if (pix == 0x0f)
+ break;
+ }
+ }
+ }
+ }
+
+ /* accumulate zoom factors; if we carry into the high bit, skip an extra row */
+ yacc += zoom;
+ addr += pitch * (yacc >> 9);
+ yacc &= 0x1ff;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * General sprite initialization
+ *
+ *************************************/
+
+void segaic16_sprites_init(int which, int type, int colorbase, int xoffs)
+{
+ struct sprite_info *info = &sprites[which];
+ int i, buffer = 0;
+
+ /* reset the sprite info */
+ memset(info, 0, sizeof(*info));
+ info->index = which;
+ info->type = type;
+ for (i = 0; i < 16; i++)
+ info->bank[i] = i;
+ info->colorbase = colorbase;
+ info->xoffs = xoffs;
+
+ /* set up based on which sprite system */
+ switch (which)
+ {
+ case 0:
+ info->spriteram = segaic16_spriteram_0;
+ break;
+
+ case 1:
+ info->spriteram = segaic16_spriteram_1;
+ break;
+
+ default:
+ fatalerror("Invalid sprite index specified in segaic16_sprites_init");
+ }
+
+ /* determine the parameters of the sprites */
+ switch (type)
+ {
+ case SEGAIC16_SPRITES_HANGON:
+ info->draw = segaic16_sprites_hangon_draw;
+ info->ramsize = 0x800;
+ break;
+
+ case SEGAIC16_SPRITES_16A:
+ info->draw = segaic16_sprites_16a_draw;
+ info->ramsize = 0x800;
+ break;
+
+ case SEGAIC16_SPRITES_16B:
+ info->draw = segaic16_sprites_16b_draw;
+ info->ramsize = 0x800;
+ break;
+
+ case SEGAIC16_SPRITES_SHARRIER:
+ info->draw = segaic16_sprites_sharrier_draw;
+ info->ramsize = 0x1000;
+ break;
+
+ case SEGAIC16_SPRITES_OUTRUN:
+ case SEGAIC16_SPRITES_XBOARD:
+ info->draw = segaic16_sprites_outrun_draw;
+ info->ramsize = 0x1000;
+ buffer = 1;
+ break;
+
+ case SEGAIC16_SPRITES_YBOARD:
+ info->draw = segaic16_sprites_yboard_draw;
+ info->ramsize = 0x10000;
+ break;
+
+ case SEGAIC16_SPRITES_YBOARD_16B:
+ info->draw = segaic16_sprites_yboard_16b_draw;
+ info->ramsize = 0x800;
+ break;
+
+ default:
+ fatalerror("Invalid sprite system specified in segaic16_sprites_init");
+ }
+
+ /* if the sprites need buffering, allocate memory for the buffer */
+ if (buffer)
+ info->buffer = auto_malloc(info->ramsize);
+
+ state_save_register_item("segaic16_sp", which, info->flip);
+ state_save_register_item("segaic16_sp", which, info->shadow);
+ state_save_register_item_array("segaic16_sp", which, info->bank);
+ state_save_register_item("segaic16_sp", which, info->colorbase);
+ state_save_register_item("segaic16_sp", which, info->xoffs);
+ if (buffer)
+ state_save_register_item_pointer("segaic16_sp", which, ((UINT8 *) info->buffer), info->ramsize);
+}
+
+
+
+/*************************************
+ *
+ * General sprite drawing
+ *
+ *************************************/
+
+void segaic16_sprites_draw(int which, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ struct sprite_info *info = &sprites[which];
+ (*info->draw)(info, bitmap, cliprect);
+}
+
+
+
+/*************************************
+ *
+ * General sprite banking
+ *
+ *************************************/
+
+void segaic16_sprites_set_bank(int which, int banknum, int offset)
+{
+ struct sprite_info *info = &sprites[which];
+
+ if (info->bank[banknum] != offset)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ info->bank[banknum] = offset;
+ }
+}
+
+
+
+/*************************************
+ *
+ * General sprite screen flipping
+ *
+ *************************************/
+
+void segaic16_sprites_set_flip(int which, int flip)
+{
+ struct sprite_info *info = &sprites[which];
+
+ flip = (flip != 0);
+ if (info->flip != flip)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ info->flip = flip;
+ }
+}
+
+
+
+/*************************************
+ *
+ * General sprite shadows
+ *
+ *************************************/
+
+void segaic16_sprites_set_shadow(int which, int shadow)
+{
+ struct sprite_info *info = &sprites[which];
+
+ shadow = (shadow != 0);
+ if (info->shadow != shadow)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ info->shadow = shadow;
+ }
+}
+
+
+
+/*************************************
+ *
+ * General sprite buffer control
+ *
+ *************************************/
+
+static void segaic16_sprites_buffer(struct sprite_info *info)
+{
+ if (info->buffer)
+ {
+ UINT32 *src = (UINT32 *)info->spriteram;
+ UINT32 *dst = (UINT32 *)info->buffer;
+ int i;
+
+ /* swap the halves of the sprite RAM */
+ for (i = 0; i < info->ramsize/4; i++)
+ {
+ UINT32 temp = *src;
+ *src++ = *dst;
+ *dst++ = temp;
+ }
+
+ /* hack for thunderblade */
+ *info->spriteram = 0xffff;
+ }
+
+ /* we will render the sprites when the video update happens */
+}
+
+
+WRITE16_HANDLER( segaic16_sprites_draw_0_w )
+{
+ segaic16_sprites_buffer(&sprites[0]);
+}
+
+
+WRITE16_HANDLER( segaic16_sprites_draw_1_w )
+{
+ segaic16_sprites_buffer(&sprites[1]);
+}
+
+
+
+/*******************************************************************************************
+ *
+ * Hang On/Space Harrier-style road chip
+ *
+ * Road RAM:
+ * Offset Bits Usage
+ * 000-1FF ----pp-- -------- road priority versus tilemaps and sprites
+ * ------s- -------- (Hang On only) Stripe coloring enable (1=enable)
+ * ------s- -------- (Space Harrier only) Solid color fill (1=solid, 0=from ROM)
+ * -------m -------- mirror enable (1=enable)
+ * -------- iiiiiiii index for other tables
+ * -------- rrrrrrrr road ROM line select
+ * 200-3FF ----hhhh hhhhhhhh horizontal scroll
+ * 400-5FF --bbbbbb -------- background color (colorset 0)
+ * -------- --bbbbbb background color (colorset 1)
+ * 600-7FF -------- s------- stripe color index (colorset 1)
+ * -------- -s------ stripe color index (colorset 0)
+ * -------- --a----- pixel value 2 color index (colorset 1)
+ * -------- ---a---- pixel value 2 color index (colorset 0)
+ * -------- ----b--- pixel value 1 color index (colorset 1)
+ * -------- -----b-- pixel value 1 color index (colorset 0)
+ * -------- ------c- pixel value 0 color index (colorset 1)
+ * -------- -------c pixel value 0 color index (colorset 0)
+ *
+ * Logic:
+ * First, the scanline is used to index into the table at 000-1FF
+ *
+ * The index is taken from the low 8 bits of the table value from 000-1FF
+ *
+ * The horizontal scroll value is looked up using the index in the table at
+ * 200-3FF
+ *
+ * The background color information is looked up using the index in the table at 400-5FF.
+ *
+ * The pixel color information is looked up using the index in the table at 600-7FF.
+ *
+ *******************************************************************************************/
+
+static void segaic16_road_hangon_decode(struct road_info *info)
+{
+ int x, y;
+
+ /* allocate memory for the unpacked road data */
+ info->gfx = auto_malloc(256 * 512);
+
+ /* loop over rows */
+ for (y = 0; y < 256; y++)
+ {
+ UINT8 *src = memory_region(REGION_GFX3) + ((y & 0xff) * 0x40) % memory_region_length(REGION_GFX3);
+ UINT8 *dst = info->gfx + y * 512;
+
+ /* loop over columns */
+ for (x = 0; x < 512; x++)
+ dst[x] = (((src[x/8] >> (~x & 7)) & 1) << 0) | (((src[x/8 + 0x4000] >> (~x & 7)) & 1) << 1);
+ }
+}
+
+
+static void segaic16_road_hangon_draw(struct road_info *info, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ UINT16 *roadram = info->roadram;
+ int x, y;
+
+ /* loop over scanlines */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ int control = roadram[0x000 + y];
+ int hpos = roadram[0x100 + (control & 0xff)];
+ int color0 = roadram[0x200 + (control & 0xff)];
+ int color1 = roadram[0x300 + (control & 0xff)];
+ int ff9j1, ff9j2, ctr9m, ctr9n9p, ctr9n9p_ena, ss8j, plycont;
+ UINT8 *src;
+
+ /* the PLYCONT signal controls the road layering */
+ plycont = (control >> 10) & 3;
+
+ /* skip layers we aren't supposed to be drawing */
+ if ((plycont == 0 && priority != SEGAIC16_ROAD_BACKGROUND) ||
+ (plycont != 0 && priority != SEGAIC16_ROAD_FOREGROUND))
+ continue;
+
+ /* compute the offset of the road graphics for this line */
+ src = info->gfx + (0x000 + (control & 0xff)) * 512;
+
+ /* initialize the 4-bit counter at 9M, which counts bits within each road byte */
+ ctr9m = hpos & 7;
+
+ /* initialize the two 4-bit counters at 9P (low) and 9N (high), which count road data bytes */
+ ctr9n9p = (hpos >> 3) & 0xff;
+
+ /* initialize the flip-flop at 9J (lower half), which controls the counting direction */
+ ff9j1 = (hpos >> 11) & 1;
+
+ /* initialize the flip-flop at 9J (upper half), which controls the background color */
+ ff9j2 = 1;
+
+ /* initialize the serial shifter at 8S, which delays several signals after we flip */
+ ss8j = 0;
+
+ /* draw this scanline from the beginning */
+ for (x = -24; x <= cliprect->max_x; x++)
+ {
+ int md, color, select;
+
+ /* ---- the following logic all happens constantly ---- */
+
+ /* the enable is controlled by the value in the counter at 9M */
+ ctr9n9p_ena = (ctr9m == 7);
+
+ /* if we carried out of the 9P/9N counters, we will forcibly clear the flip-flop at 9J (lower half) */
+ if ((ctr9n9p & 0xff) == 0xff)
+ ff9j1 = 0;
+
+ /* if the control word bit 8 is clear, we will forcibly set the flip-flop at 9J (lower half) */
+ if (!(control & 0x100))
+ ff9j1 = 1;
+
+ /* for the Hang On/Super Hang On case only: if the control word bit 9 is clear, we will forcibly */
+ /* set the flip-flip at 9J (upper half) */
+ if (info->type == SEGAIC16_ROAD_HANGON && !(control & 0x200))
+ ff9j2 = 1;
+
+ /* ---- now process the pixel ---- */
+ md = 3;
+
+ /* the Space Harrier/Enduro Racer hardware has a tweak that maps the control word bit 9 to the */
+ /* /CE line on the road ROM; use this to effectively disable the road data */
+ if (info->type != SEGAIC16_ROAD_SHARRIER || !(control & 0x200))
+
+ /* the /OE line on the road ROM is linked to the AND of bits 2 & 3 of the counter at 9N */
+ if ((ctr9n9p & 0xc0) == 0xc0)
+ {
+ /* note that the pixel logic is hidden in a custom at 9S; this is just a guess */
+ if (ss8j & 1)
+ md = src[((ctr9n9p & 0x3f) << 3) | ctr9m];
+ else
+ md = src[((ctr9n9p & 0x3f) << 3) | (ctr9m ^ 7)];
+ }
+
+ /* "select" is a made-up signal that comes from bit 3 of the serial shifter and is */
+ /* used in several places for color selection */
+ select = (ss8j >> 3) & 1;
+
+ /* check the flip-flop at 9J (upper half) to determine if we should use the background color; */
+ /* the output of this is ANDed with M0 and M1 so it only affects pixels with a value of 3; */
+ /* this is done by the AND gates at 9L and 7K */
+ if (ff9j2 && md == 3)
+ {
+ /* in this case, the "select" signal is used to select which background color to use */
+ /* since the color0 control word contains two selections */
+ color = (color0 >> (select ? 0 : 8)) & 0x3f;
+ color |= info->colorbase2;
+ }
+
+ /* if we're not using the background color, we select pixel data from an alternate path */
+ else
+ {
+ /* the AND gates at 7L, 9K, and 7K clamp the pixel value to 0 if bit 7 of the color 1 */
+ /* signal is 1 and if the pixel value is 3 (both M0 and M1 == 1) */
+ if ((color1 & 0x80) && md == 3)
+ md = 0;
+
+ /* the pixel value plus the "select" line combine to form a mux into the low 8 bits of color1 */
+ color = (color1 >> ((md << 1) | select)) & 1;
+
+ /* this value becomes the low bit of the final color; the "select" line itself and the pixel */
+ /* value form the other bits */
+ color |= select << 3;
+ color |= md << 1;
+ color |= info->colorbase1;
+ }
+
+ /* write the pixel if we're past the minimum clip */
+ if (x >= cliprect->min_x)
+ dest[x] = color;
+
+ /* ---- the following logic all happens on the 6M clock ---- */
+
+ /* clock the counter at 9M */
+ ctr9m = (ctr9m + 1) & 7;
+
+ /* if enabled, clock on the two cascaded 4-bit counters at 9P and 9N */
+ if (ctr9n9p_ena)
+ {
+ if (ff9j1)
+ ctr9n9p++;
+ else
+ ctr9n9p--;
+ }
+
+ /* clock the flip-flop at 9J (upper half) */
+ ff9j2 = !(!ff9j1 && (ss8j & 0x80));
+
+ /* clock the serial shift register at 8J */
+ ss8j = (ss8j << 1) | ff9j1;
+ }
+ }
+}
+
+
+
+/*******************************************************************************************
+ *
+ * Out Run/X-Board-style road chip
+ *
+ * Road control register:
+ * Bits Usage
+ * -------- -----d-- (X-board only) Direct scanline mode (1) or indirect mode (0)
+ * -------- ------pp Road enable/priorities:
+ * 0 = road 0 only visible
+ * 1 = both roads visible, road 0 has priority
+ * 2 = both roads visible, road 1 has priority
+ * 3 = road 1 only visible
+ *
+ * Road RAM:
+ * Offset Bits Usage
+ * 000-1FF ----s--- -------- Road 0: Solid fill (1) or ROM fill
+ * -------- -ccccccc Road 0: Solid color (if solid fill)
+ * -------i iiiiiiii Road 0: Index for other tables (if in indirect mode)
+ * -------r rrrrrrr- Road 0: Road ROM line select
+ * 200-3FF ----s--- -------- Road 1: Solid fill (1) or ROM fill
+ * -------- -ccccccc Road 1: Solid color (if solid fill)
+ * -------i iiiiiiii Road 1: Index for other tables (if in indirect mode)
+ * -------r rrrrrrr- Road 1: Road ROM line select
+ * 400-7FF ----hhhh hhhhhhhh Road 0: horizontal scroll
+ * 800-BFF ----hhhh hhhhhhhh Road 1: horizontal scroll
+ * C00-FFF ----bbbb -------- Background color index
+ * -------- s------- Road 1: stripe color index
+ * -------- -a------ Road 1: pixel value 2 color index
+ * -------- --b----- Road 1: pixel value 1 color index
+ * -------- ---c---- Road 1: pixel value 0 color index
+ * -------- ----s--- Road 0: stripe color index
+ * -------- -----a-- Road 0: pixel value 2 color index
+ * -------- ------b- Road 0: pixel value 1 color index
+ * -------- -------c Road 0: pixel value 0 color index
+ *
+ * Logic:
+ * First, the scanline is used to index into the tables at 000-1FF/200-3FF
+ * - if solid fill, the background is filled with the specified color index
+ * - otherwise, the remaining tables are used
+ *
+ * If indirect mode is selected, the index is taken from the low 9 bits of the
+ * table value from 000-1FF/200-3FF
+ * If direct scanline mode is selected, the index is set equal to the scanline
+ * for road 0, or the scanline + 256 for road 1
+ *
+ * The horizontal scroll value is looked up using the index in the tables at
+ * 400-7FF/800-BFF
+ *
+ * The color information is looked up using the index in the table at C00-FFF. Note
+ * that the same table is used for both roads.
+ *
+ *
+ * Out Run road priorities are controlled by a PAL that maps as indicated below.
+ * This was used to generate the priority_map. It is assumed that X-board is the
+ * same, though this logic is locked inside a Sega custom.
+ *
+ * RRC0 = CENTA & (RDA == 3) & !RRC2
+ * | CENTB & (RDB == 3) & RRC2
+ * | (RDA == 1) & !RRC2
+ * | (RDB == 1) & RRC2
+ *
+ * RRC1 = CENTA & (RDA == 3) & !RRC2
+ * | CENTB & (RDB == 3) & RRC2
+ * | (RDA == 2) & !RRC2
+ * | (RDB == 2) & RRC2
+ *
+ * RRC2 = !/HSYNC & IIQ
+ * | (CTRL == 3)
+ * | !CENTA & (RDA == 3) & !CENTB & (RDB == 3) & (CTRL == 2)
+ * | CENTB & (RDB == 3) & (CTRL == 2)
+ * | !CENTA & (RDA == 3) & !M2 & (CTRL == 2)
+ * | !CENTA & (RDA == 3) & !M3 & (CTRL == 2)
+ * | !M0 & (RDB == 0) & (CTRL == 2)
+ * | !M1 & (RDB == 0) & (CTRL == 2)
+ * | !CENTA & (RDA == 3) & CENTB & (RDB == 3) & (CTRL == 1)
+ * | !M0 & CENTB & (RDB == 3) & (CTRL == 1)
+ * | !M1 & CENTB & (RDB == 3) & (CTRL == 1)
+ * | !CENTA & M0 & (RDB == 0) & (CTRL == 1)
+ * | !CENTA & M1 & (RDB == 0) & (CTRL == 1)
+ * | !CENTA & (RDA == 3) & (RDB == 1) & (CTRL == 1)
+ * | !CENTA & (RDA == 3) & (RDB == 2) & (CTRL == 1)
+ *
+ * RRC3 = VA11 & VB11
+ * | VA11 & (CTRL == 0)
+ * | (CTRL == 3) & VB11
+ *
+ * RRC4 = !CENTA & (RDA == 3) & !CENTB & (RDB == 3)
+ * | VA11 & VB11
+ * | VA11 & (CTRL == 0)
+ * | (CTRL == 3) & VB11
+ * | !CENTB & (RDB == 3) & (CTRL == 3)
+ * | !CENTA & (RDA == 3) & (CTRL == 0)
+ *
+ *******************************************************************************************/
+
+static void segaic16_road_outrun_decode(struct road_info *info)
+{
+ int x, y;
+
+ /* allocate memory for the unpacked road data */
+ info->gfx = auto_malloc((256 * 2 + 1) * 512);
+
+ /* loop over rows */
+ for (y = 0; y < 256 * 2; y++)
+ {
+ UINT8 *src = memory_region(REGION_GFX3) + ((y & 0xff) * 0x40 + (y >> 8) * 0x8000) % memory_region_length(REGION_GFX3);
+ UINT8 *dst = info->gfx + y * 512;
+
+ /* loop over columns */
+ for (x = 0; x < 512; x++)
+ {
+ dst[x] = (((src[x/8] >> (~x & 7)) & 1) << 0) | (((src[x/8 + 0x4000] >> (~x & 7)) & 1) << 1);
+
+ /* pre-mark road data in the "stripe" area with a high bit */
+ if (x >= 256-8 && x < 256 && dst[x] == 3)
+ dst[x] |= 4;
+ }
+ }
+
+ /* set up a dummy road in the last entry */
+ memset(info->gfx + 256 * 2 * 512, 3, 512);
+}
+
+
+static void segaic16_road_outrun_draw(struct road_info *info, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ UINT16 *roadram = info->buffer;
+ int x, y;
+
+ /* loop over scanlines */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ static const UINT8 priority_map[2][8] =
+ {
+ { 0x80,0x81,0x81,0x87,0,0,0,0x00 },
+ { 0x81,0x81,0x81,0x8f,0,0,0,0x80 }
+//
+// Original guesses from X-board priorities:
+// { 0x80,0x81,0x81,0x83,0,0,0,0x00 },
+// { 0x81,0x87,0x87,0x8f,0,0,0,0x00 }
+ };
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ int data0 = roadram[0x000 + y];
+ int data1 = roadram[0x100 + y];
+
+ /* background case: look for solid fill scanlines */
+ if (priority == SEGAIC16_ROAD_BACKGROUND)
+ {
+ int color = -1;
+
+ /* based on the info->control, we can figure out which sky to draw */
+ switch (info->control & 3)
+ {
+ case 0:
+ if (data0 & 0x800)
+ color = data0 & 0x7f;
+ break;
+
+ case 1:
+ if (data0 & 0x800)
+ color = data0 & 0x7f;
+ else if (data1 & 0x800)
+ color = data1 & 0x7f;
+ break;
+
+ case 2:
+ if (data1 & 0x800)
+ color = data1 & 0x7f;
+ else if (data0 & 0x800)
+ color = data0 & 0x7f;
+ break;
+
+ case 3:
+ if (data1 & 0x800)
+ color = data1 & 0x7f;
+ break;
+ }
+
+ /* fill the scanline with color */
+ if (color != -1)
+ {
+ color |= info->colorbase3;
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ dest[x] = color;
+ }
+ }
+
+ /* foreground case: render from ROM */
+ else
+ {
+ int hpos0, hpos1, color0, color1;
+ int control = info->control & 3;
+ UINT16 color_table[32];
+ UINT8 *src0, *src1;
+ UINT8 bgcolor;
+
+ /* if both roads are low priority, skip */
+ if ((data0 & 0x800) && (data1 & 0x800))
+ continue;
+
+ /* get road 0 data */
+ src0 = (data0 & 0x800) ? info->gfx + 256 * 2 * 512 : (info->gfx + (0x000 + ((data0 >> 1) & 0xff)) * 512);
+ hpos0 = (roadram[0x200 + ((info->control & 4) ? y : (data0 & 0x1ff))]) & 0xfff;
+ color0 = roadram[0x600 + ((info->control & 4) ? y : (data0 & 0x1ff))];
+
+ /* get road 1 data */
+ src1 = (data1 & 0x800) ? info->gfx + 256 * 2 * 512 : (info->gfx + (0x100 + ((data1 >> 1) & 0xff)) * 512);
+ hpos1 = (roadram[0x400 + ((info->control & 4) ? (0x100 + y) : (data1 & 0x1ff))]) & 0xfff;
+ color1 = roadram[0x600 + ((info->control & 4) ? (0x100 + y) : (data1 & 0x1ff))];
+
+ /* determine the 5 colors for road 0 */
+ color_table[0x00] = info->colorbase1 ^ 0x00 ^ ((color0 >> 0) & 1);
+ color_table[0x01] = info->colorbase1 ^ 0x02 ^ ((color0 >> 1) & 1);
+ color_table[0x02] = info->colorbase1 ^ 0x04 ^ ((color0 >> 2) & 1);
+ bgcolor = (color0 >> 8) & 0xf;
+ color_table[0x03] = (data0 & 0x200) ? color_table[0x00] : (info->colorbase2 ^ 0x00 ^ bgcolor);
+ color_table[0x07] = info->colorbase1 ^ 0x06 ^ ((color0 >> 3) & 1);
+
+ /* determine the 5 colors for road 1 */
+ color_table[0x10] = info->colorbase1 ^ 0x08 ^ ((color1 >> 4) & 1);
+ color_table[0x11] = info->colorbase1 ^ 0x0a ^ ((color1 >> 5) & 1);
+ color_table[0x12] = info->colorbase1 ^ 0x0c ^ ((color1 >> 6) & 1);
+ bgcolor = (color1 >> 8) & 0xf;
+ color_table[0x13] = (data1 & 0x200) ? color_table[0x10] : (info->colorbase2 ^ 0x10 ^ bgcolor);
+ color_table[0x17] = info->colorbase1 ^ 0x0e ^ ((color1 >> 7) & 1);
+
+ /* draw the road */
+ switch (control)
+ {
+ case 0:
+ if (data0 & 0x800)
+ continue;
+ hpos0 = (hpos0 - (0x5f8 + info->xoffs)) & 0xfff;
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ int pix0 = (hpos0 < 0x200) ? src0[hpos0] : 3;
+ dest[x] = color_table[0x00 + pix0];
+ hpos0 = (hpos0 + 1) & 0xfff;
+ }
+ break;
+
+ case 1:
+ hpos0 = (hpos0 - (0x5f8 + info->xoffs)) & 0xfff;
+ hpos1 = (hpos1 - (0x5f8 + info->xoffs)) & 0xfff;
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ int pix0 = (hpos0 < 0x200) ? src0[hpos0] : 3;
+ int pix1 = (hpos1 < 0x200) ? src1[hpos1] : 3;
+ if ((priority_map[0][pix0] >> pix1) & 1)
+ dest[x] = color_table[0x10 + pix1];
+ else
+ dest[x] = color_table[0x00 + pix0];
+ hpos0 = (hpos0 + 1) & 0xfff;
+ hpos1 = (hpos1 + 1) & 0xfff;
+ }
+ break;
+
+ case 2:
+ hpos0 = (hpos0 - (0x5f8 + info->xoffs)) & 0xfff;
+ hpos1 = (hpos1 - (0x5f8 + info->xoffs)) & 0xfff;
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ int pix0 = (hpos0 < 0x200) ? src0[hpos0] : 3;
+ int pix1 = (hpos1 < 0x200) ? src1[hpos1] : 3;
+ if ((priority_map[1][pix0] >> pix1) & 1)
+ dest[x] = color_table[0x10 + pix1];
+ else
+ dest[x] = color_table[0x00 + pix0];
+ hpos0 = (hpos0 + 1) & 0xfff;
+ hpos1 = (hpos1 + 1) & 0xfff;
+ }
+ break;
+
+ case 3:
+ if (data1 & 0x800)
+ continue;
+ hpos1 = (hpos1 - (0x5f8 + info->xoffs)) & 0xfff;
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ int pix1 = (hpos1 < 0x200) ? src1[hpos1] : 3;
+ dest[x] = color_table[0x10 + pix1];
+ hpos1 = (hpos1 + 1) & 0xfff;
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * General road initialization
+ *
+ *************************************/
+
+void segaic16_road_init(int which, int type, int colorbase1, int colorbase2, int colorbase3, int xoffs)
+{
+ struct road_info *info = &road[which];
+
+ /* reset the tilemap info */
+ memset(info, 0, sizeof(*info));
+ info->index = which;
+ info->type = type;
+ info->colorbase1 = colorbase1;
+ info->colorbase2 = colorbase2;
+ info->colorbase3 = colorbase3;
+ info->xoffs = xoffs;
+
+ /* set up based on which road generator */
+ switch (which)
+ {
+ case 0:
+ info->roadram = segaic16_roadram_0;
+ break;
+
+ default:
+ fatalerror("Invalid road index specified in segaic16_road_init");
+ }
+
+ /* determine the parameters of the road */
+ switch (type)
+ {
+ case SEGAIC16_ROAD_HANGON:
+ case SEGAIC16_ROAD_SHARRIER:
+ info->draw = segaic16_road_hangon_draw;
+ segaic16_road_hangon_decode(info);
+ break;
+
+ case SEGAIC16_ROAD_OUTRUN:
+ case SEGAIC16_ROAD_XBOARD:
+ info->buffer = auto_malloc(0x1000);
+ info->draw = segaic16_road_outrun_draw;
+ segaic16_road_outrun_decode(info);
+ break;
+
+ default:
+ fatalerror("Invalid road system specified in segaic16_road_init");
+ }
+}
+
+
+
+/*************************************
+ *
+ * General road drawing
+ *
+ *************************************/
+
+void segaic16_road_draw(int which, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ struct road_info *info = &road[which];
+ (*info->draw)(info, bitmap, cliprect, priority);
+}
+
+
+
+/*************************************
+ *
+ * General road control read/write
+ *
+ *************************************/
+
+READ16_HANDLER( segaic16_road_control_0_r )
+{
+ struct road_info *info = &road[0];
+
+ if (info->buffer)
+ {
+ UINT32 *src = (UINT32 *)info->roadram;
+ UINT32 *dst = (UINT32 *)info->buffer;
+ int i;
+
+ /* swap the halves of the road RAM */
+ for (i = 0; i < 0x1000/4; i++)
+ {
+ UINT32 temp = *src;
+ *src++ = *dst;
+ *dst++ = temp;
+ }
+ }
+
+ return 0xffff;
+}
+
+
+WRITE16_HANDLER( segaic16_road_control_0_w )
+{
+ if (ACCESSING_LSB)
+ {
+ road[0].control = data & ((road[0].type == SEGAIC16_ROAD_OUTRUN) ? 3 : 7);
+ }
+}
+
+
+
+/*************************************
+ *
+ * General rotation initialization
+ *
+ *************************************/
+
+void segaic16_rotate_init(int which, int type, int colorbase)
+{
+ struct rotate_info *info = &rotate[which];
+
+ /* reset the tilemap info */
+ memset(info, 0, sizeof(*info));
+ info->index = which;
+ info->type = type;
+ info->colorbase = colorbase;
+
+ /* set up based on which road generator */
+ switch (which)
+ {
+ case 0:
+ info->rotateram = segaic16_rotateram_0;
+ break;
+
+ default:
+ fatalerror("Invalid rotate index specified in segaic16_rotate_init");
+ }
+
+ /* determine the parameters of the rotate */
+ switch (type)
+ {
+ case SEGAIC16_ROTATE_YBOARD:
+ info->ramsize = 0x800;
+ break;
+
+ default:
+ fatalerror("Invalid rotate system specified in segaic16_rotate_init");
+ }
+
+ /* allocate a buffer for swapping */
+ info->buffer = auto_malloc(info->ramsize);
+
+ state_save_register_item("segaic16_rot", which, info->colorbase);
+ state_save_register_item_pointer("segaic16_rot", which, ((UINT8 *) info->buffer), info->ramsize);
+}
+
+
+
+/*************************************
+ *
+ * General rotation drawing
+ *
+ *************************************/
+
+void segaic16_rotate_draw(int which, mame_bitmap *bitmap, const rectangle *cliprect, mame_bitmap *srcbitmap)
+{
+ struct rotate_info *info = &rotate[which];
+ INT32 currx = (info->buffer[0x3f0] << 16) | info->buffer[0x3f1];
+ INT32 curry = (info->buffer[0x3f2] << 16) | info->buffer[0x3f3];
+ INT32 dyy = (info->buffer[0x3f4] << 16) | info->buffer[0x3f5];
+ INT32 dxx = (info->buffer[0x3f6] << 16) | info->buffer[0x3f7];
+ INT32 dxy = (info->buffer[0x3f8] << 16) | info->buffer[0x3f9];
+ INT32 dyx = (info->buffer[0x3fa] << 16) | info->buffer[0x3fb];
+ int x, y;
+
+ /* advance forward based on the clip rect */
+ currx += dxx * (cliprect->min_x + 27) + dxy * cliprect->min_y;
+ curry += dyx * (cliprect->min_x + 27) + dyy * cliprect->min_y;
+
+ /* loop over screen Y coordinates */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ UINT16 *src = (UINT16 *)srcbitmap->base;
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+ INT32 tx = currx;
+ INT32 ty = curry;
+
+ /* loop over screen X coordinates */
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ /* fetch the pixel from the source bitmap */
+ int sx = (tx >> 14) & 0x1ff;
+ int sy = (ty >> 14) & 0x1ff;
+ int pix = src[sy * srcbitmap->rowpixels + sx];
+
+ /* non-zero pixels get written; everything else is the scanline color */
+ if (pix != 0xffff)
+ {
+ *dest++ = (pix & 0x1ff) | ((pix >> 6) & 0x200) | ((pix >> 3) & 0xc00) | 0x1000;
+ *pri++ = (pix >> 8) | 1;
+ }
+ else
+ {
+ *dest++ = info->colorbase + sy;
+ *pri++ = 0xff;
+ }
+
+ /* advance the source X/Y pointers */
+ tx += dxx;
+ ty += dyx;
+ }
+
+ /* advance the source X/Y pointers */
+ currx += dxy;
+ curry += dyy;
+ }
+}
+
+
+
+/*************************************
+ *
+ * General road control read/write
+ *
+ *************************************/
+
+READ16_HANDLER( segaic16_rotate_control_0_r )
+{
+ struct rotate_info *info = &rotate[0];
+
+ if (info->buffer)
+ {
+ UINT32 *src = (UINT32 *)info->rotateram;
+ UINT32 *dst = (UINT32 *)info->buffer;
+ int i;
+
+ /* swap the halves of the rotation RAM */
+ for (i = 0; i < info->ramsize/4; i++)
+ {
+ UINT32 temp = *src;
+ *src++ = *dst;
+ *dst++ = temp;
+ }
+ }
+
+ return 0xffff;
+}
diff --git a/src/mame/video/segaic16.h b/src/mame/video/segaic16.h
new file mode 100644
index 00000000000..302da204e16
--- /dev/null
+++ b/src/mame/video/segaic16.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+
+ Sega 16-bit common hardware
+
+***************************************************************************/
+
+/* globals */
+extern UINT8 segaic16_display_enable;
+extern UINT16 *segaic16_tileram_0;
+extern UINT16 *segaic16_textram_0;
+extern UINT16 *segaic16_spriteram_0;
+extern UINT16 *segaic16_spriteram_1;
+extern UINT16 *segaic16_roadram_0;
+extern UINT16 *segaic16_rotateram_0;
+
+/* misc functions */
+void segaic16_set_display_enable(int enable);
+
+/* palette handling */
+void segaic16_palette_init(int entries);
+WRITE16_HANDLER( segaic16_paletteram_w );
+
+/* tilemap systems */
+#define SEGAIC16_MAX_TILEMAPS 1
+
+#define SEGAIC16_TILEMAP_HANGON 0
+#define SEGAIC16_TILEMAP_16A 1
+#define SEGAIC16_TILEMAP_16B 2
+#define SEGAIC16_TILEMAP_16B_ALT 3
+
+#define SEGAIC16_TILEMAP_FOREGROUND 0
+#define SEGAIC16_TILEMAP_BACKGROUND 1
+#define SEGAIC16_TILEMAP_TEXT 2
+
+void segaic16_tilemap_init(int which, int type, int colorbase, int xoffs, int numbanks);
+void segaic16_tilemap_reset(int which);
+void segaic16_tilemap_draw(running_machine *machine, int which, mame_bitmap *bitmap, const rectangle *cliprect, int map, int priority, int priority_mark);
+void segaic16_tilemap_set_bank(int which, int banknum, int offset);
+void segaic16_tilemap_set_flip(int which, int flip);
+void segaic16_tilemap_set_rowscroll(int which, int enable);
+void segaic16_tilemap_set_colscroll(int which, int enable);
+
+WRITE16_HANDLER( segaic16_tileram_0_w );
+WRITE16_HANDLER( segaic16_textram_0_w );
+
+/* sprite systems */
+#define SEGAIC16_MAX_SPRITES 2
+
+#define SEGAIC16_SPRITES_HANGON 0
+#define SEGAIC16_SPRITES_16A 1
+#define SEGAIC16_SPRITES_16B 2
+#define SEGAIC16_SPRITES_SHARRIER 3
+#define SEGAIC16_SPRITES_OUTRUN 4
+#define SEGAIC16_SPRITES_XBOARD 5
+#define SEGAIC16_SPRITES_YBOARD 6
+#define SEGAIC16_SPRITES_YBOARD_16B 7
+
+void segaic16_sprites_init(int which, int type, int colorbase, int xoffs);
+void segaic16_sprites_draw(int which, mame_bitmap *bitmap, const rectangle *cliprect);
+void segaic16_sprites_set_bank(int which, int banknum, int offset);
+void segaic16_sprites_set_flip(int which, int flip);
+void segaic16_sprites_set_shadow(int which, int shadow);
+WRITE16_HANDLER( segaic16_sprites_draw_0_w );
+WRITE16_HANDLER( segaic16_sprites_draw_1_w );
+
+/* road systems */
+#define SEGAIC16_MAX_ROADS 1
+
+#define SEGAIC16_ROAD_HANGON 0
+#define SEGAIC16_ROAD_SHARRIER 1
+#define SEGAIC16_ROAD_OUTRUN 2
+#define SEGAIC16_ROAD_XBOARD 3
+
+#define SEGAIC16_ROAD_BACKGROUND 0
+#define SEGAIC16_ROAD_FOREGROUND 1
+
+void segaic16_road_init(int which, int type, int colorbase1, int colorbase2, int colorbase3, int xoffs);
+void segaic16_road_draw(int which, mame_bitmap *bitmap, const rectangle *cliprect, int priority);
+READ16_HANDLER( segaic16_road_control_0_r );
+WRITE16_HANDLER( segaic16_road_control_0_w );
+
+/* rotation systems */
+#define SEGAIC16_MAX_ROTATE 1
+
+#define SEGAIC16_ROTATE_YBOARD 0
+
+void segaic16_rotate_init(int which, int type, int colorbase);
+void segaic16_rotate_draw(int which, mame_bitmap *bitmap, const rectangle *cliprect, mame_bitmap *srcbitmap);
+READ16_HANDLER( segaic16_rotate_control_0_r );
diff --git a/src/mame/video/segaic24.c b/src/mame/video/segaic24.c
new file mode 100644
index 00000000000..b0790cdc178
--- /dev/null
+++ b/src/mame/video/segaic24.c
@@ -0,0 +1,895 @@
+/*
+ Sega system24 hardware
+
+System 24 68000x2 315-5292 315-5293 315-5294 315-5242 ym2151 dac 315-5195(x3) 315-5296(IO)
+
+ System24:
+ The odd one out. Medium resolution. Entirely ram-based, no
+ graphics roms. 4-layer tilemap hardware in two pairs, selection
+ on a 8-pixels basis. Tile-based sprites(!) organised as a linked
+ list. The tilemap chip has been reused for model1 and model2,
+ probably because they had it handy and it handles medium res.
+
+*/
+
+/*
+ * System 16 color palette formats
+ */
+
+
+/* system24temp_ functions / variables are from shared rewrite files,
+ once the rest of the rewrite is complete they can be removed, I
+ just made a copy & renamed them for now to avoid any conflicts
+*/
+
+#include "driver.h"
+#include "segaic24.h"
+
+
+static void set_color(running_machine *machine, int color, UINT8 r, UINT8 g, UINT8 b, int highlight)
+{
+ palette_set_color (machine, color, MAKE_RGB(r, g, b));
+
+ if(highlight) {
+ r = 255-0.6*(255-r);
+ g = 255-0.6*(255-g);
+ b = 255-0.6*(255-b);
+ } else {
+ r = 0.6*r;
+ g = 0.6*g;
+ b = 0.6*b;
+ }
+ palette_set_color(machine,color+machine->drv->total_colors/2, MAKE_RGB(r, g, b));
+}
+
+// 315-5242
+WRITE16_HANDLER (system24temp_sys16_paletteram1_w)
+{
+ int r, g, b;
+ COMBINE_DATA (paletteram16 + offset);
+ data = paletteram16[offset];
+
+ r = (data & 0x00f) << 4;
+ if(data & 0x1000)
+ r |= 8;
+
+ g = data & 0x0f0;
+ if(data & 0x2000)
+ g |= 8;
+
+ b = (data & 0xf00) >> 4;
+ if(data & 0x4000)
+ b |= 8;
+
+ r |= r >> 5;
+ g |= g >> 5;
+ b |= b >> 5;
+ set_color(Machine, offset, r, g, b, data & 0x8000);
+}
+
+// - System 24
+
+enum {SYS24_TILES = 0x4000};
+
+static UINT16 *sys24_char_ram, *sys24_tile_ram;
+static UINT16 sys24_tile_mask;
+static UINT8 *sys24_char_dirtymap;
+static int sys24_char_dirty, sys24_char_gfx_index;
+static tilemap *sys24_tile_layer[4];
+
+#ifdef LSB_FIRST
+static const gfx_layout sys24_char_layout = {
+ 8, 8,
+ SYS24_TILES,
+ 4,
+ { 0, 1, 2, 3 },
+ { 2*4, 3*4, 0*4, 1*4, 6*4, 7*4, 4*4, 5*4 },
+ { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 },
+ 8*32
+};
+#else
+static const gfx_layout sys24_char_layout = {
+ 8, 8,
+ SYS24_TILES,
+ 4,
+ { 0, 1, 2, 3 },
+ { 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4 },
+ { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 },
+ 8*32
+};
+#endif
+
+static TILE_GET_INFO( sys24_tile_info_0s )
+{
+ UINT16 val = sys24_tile_ram[tile_index];
+ tileinfo->category = (val & 0x8000) != 0;
+ SET_TILE_INFO(sys24_char_gfx_index, val & sys24_tile_mask, (val >> 7) & 0xff, 0);
+}
+
+static TILE_GET_INFO( sys24_tile_info_0w )
+{
+ UINT16 val = sys24_tile_ram[tile_index|0x1000];
+ tileinfo->category = (val & 0x8000) != 0;
+ SET_TILE_INFO(sys24_char_gfx_index, val & sys24_tile_mask, (val >> 7) & 0xff, 0);
+}
+
+static TILE_GET_INFO( sys24_tile_info_1s )
+{
+ UINT16 val = sys24_tile_ram[tile_index|0x2000];
+ tileinfo->category = (val & 0x8000) != 0;
+ SET_TILE_INFO(sys24_char_gfx_index, val & sys24_tile_mask, (val >> 7) & 0xff, 0);
+}
+
+static TILE_GET_INFO( sys24_tile_info_1w )
+{
+ UINT16 val = sys24_tile_ram[tile_index|0x3000];
+ tileinfo->category = (val & 0x8000) != 0;
+ SET_TILE_INFO(sys24_char_gfx_index, val & sys24_tile_mask, (val >> 7) & 0xff, 0);
+}
+
+static void sys24_tile_dirtyall(void)
+{
+ memset(sys24_char_dirtymap, 1, SYS24_TILES);
+ sys24_char_dirty = 1;
+}
+
+void sys24_tile_vh_start(running_machine *machine, UINT16 tile_mask)
+{
+ sys24_tile_mask = tile_mask;
+
+ for(sys24_char_gfx_index = 0; sys24_char_gfx_index < MAX_GFX_ELEMENTS; sys24_char_gfx_index++)
+ if (machine->gfx[sys24_char_gfx_index] == 0)
+ break;
+ assert(sys24_char_gfx_index != MAX_GFX_ELEMENTS);
+
+ sys24_char_ram = auto_malloc(0x80000);
+
+ sys24_tile_ram = auto_malloc(0x10000);
+
+ sys24_char_dirtymap = auto_malloc(SYS24_TILES);
+
+ sys24_tile_layer[0] = tilemap_create(sys24_tile_info_0s, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ sys24_tile_layer[1] = tilemap_create(sys24_tile_info_0w, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ sys24_tile_layer[2] = tilemap_create(sys24_tile_info_1s, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+ sys24_tile_layer[3] = tilemap_create(sys24_tile_info_1w, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+
+ tilemap_set_transparent_pen(sys24_tile_layer[0], 0);
+ tilemap_set_transparent_pen(sys24_tile_layer[1], 0);
+ tilemap_set_transparent_pen(sys24_tile_layer[2], 0);
+ tilemap_set_transparent_pen(sys24_tile_layer[3], 0);
+
+ memset(sys24_char_ram, 0, 0x80000);
+ memset(sys24_tile_ram, 0, 0x10000);
+ memset(sys24_char_dirtymap, 1, SYS24_TILES);
+ sys24_char_dirty = 1;
+
+ machine->gfx[sys24_char_gfx_index] = allocgfx(&sys24_char_layout);
+
+ if (machine->drv->color_table_len)
+ machine->gfx[sys24_char_gfx_index]->total_colors = machine->drv->color_table_len / 16;
+ else
+ machine->gfx[sys24_char_gfx_index]->total_colors = machine->drv->total_colors / 16;
+
+ state_save_register_global_pointer(sys24_tile_ram, 0x10000/2);
+ state_save_register_global_pointer(sys24_char_ram, 0x80000/2);
+ state_save_register_func_postload(sys24_tile_dirtyall);
+}
+
+void sys24_tile_update(running_machine *machine)
+{
+ if(sys24_char_dirty) {
+ int i;
+ for(i=0; i<SYS24_TILES; i++) {
+ if(sys24_char_dirtymap[i]) {
+ sys24_char_dirtymap[i] = 0;
+ decodechar(machine->gfx[sys24_char_gfx_index], i, (UINT8 *)sys24_char_ram, &sys24_char_layout);
+ }
+ }
+ tilemap_mark_all_tiles_dirty(sys24_tile_layer[0]);
+ tilemap_mark_all_tiles_dirty(sys24_tile_layer[1]);
+ tilemap_mark_all_tiles_dirty(sys24_tile_layer[2]);
+ tilemap_mark_all_tiles_dirty(sys24_tile_layer[3]);
+ sys24_char_dirty = 0;
+ }
+}
+
+static void sys24_tile_draw_rect(running_machine *machine, mame_bitmap *bm, mame_bitmap *tm, mame_bitmap *dm, const UINT16 *mask,
+ UINT16 tpri, UINT8 lpri, int win, int sx, int sy, int xx1, int yy1, int xx2, int yy2)
+{
+ int y;
+ const UINT16 *source = ((UINT16 *)bm->base) + sx + sy*bm->rowpixels;
+ const UINT8 *trans = ((UINT8 *) tm->base) + sx + sy*tm->rowpixels;
+ UINT8 *prib = priority_bitmap->base;
+ UINT16 *dest = dm->base;
+
+ tpri |= TILEMAP_PIXEL_LAYER0;
+
+ dest += yy1*dm->rowpixels + xx1;
+ prib += yy1*priority_bitmap->rowpixels + xx1;
+ mask += yy1*4;
+ yy2 -= yy1;
+
+ while(xx1 >= 128) {
+ xx1 -= 128;
+ xx2 -= 128;
+ mask++;
+ }
+
+ for(y=0; y<yy2; y++) {
+ const UINT16 *src = source;
+ const UINT8 *srct = trans;
+ UINT16 *dst = dest;
+ UINT8 *pr = prib;
+ const UINT16 *mask1 = mask;
+ int llx = xx2;
+ int cur_x = xx1;
+
+ while(llx > 0) {
+ UINT16 m = *mask1++;
+
+ if(win)
+ m = ~m;
+
+ if(!cur_x && llx>=128) {
+ // Fast paths for the 128-pixels without side clipping case
+
+ if(!m) {
+ // 1- 128 pixels from this layer
+ int x;
+ for(x=0; x<128; x++) {
+ if(*srct++ == tpri) {
+ *dst = *src;
+ *pr |= lpri;
+ }
+ src++;
+ dst++;
+ pr++;
+ }
+
+ } else if(m == 0xffff) {
+ // 2- 128 pixels from the other layer
+ src += 128;
+ srct += 128;
+ dst += 128;
+ pr += 128;
+
+ } else {
+ // 3- 128 pixels from both layers
+ int x;
+ for(x=0; x<128; x+=8) {
+ if(!(m & 0x8000)) {
+ int xx;
+ for(xx=0; xx<8; xx++)
+ if(srct[xx] == tpri) {
+ dst[xx] = src[xx];
+ pr[xx] |= lpri;
+ }
+ }
+ src += 8;
+ srct += 8;
+ dst += 8;
+ pr += 8;
+ m <<= 1;
+ }
+ }
+ } else {
+ // Clipped path
+ int llx1 = llx >= 128 ? 128 : llx;
+
+ if(!m) {
+ // 1- 128 pixels from this layer
+ int x;
+ for(x = cur_x; x<llx1; x++) {
+ if(*srct++ == tpri) {
+ *dst = *src;
+ *pr |= lpri;
+ }
+ src++;
+ dst++;
+ pr++;
+ }
+
+ } else if(m == 0xffff) {
+ // 2- 128 pixels from the other layer
+ src += 128 - cur_x;
+ srct += 128 - cur_x;
+ dst += 128 - cur_x;
+ pr += 128 - cur_x;
+
+ } else {
+ // 3- 128 pixels from both layers
+ int x;
+ for(x=cur_x; x<llx1; x++) {
+ if(*srct++ == tpri && !(m & (0x8000 >> (x >> 3)))) {
+ *dst = *src;
+ *pr |= lpri;
+ }
+
+ src++;
+ dst++;
+ pr++;
+ }
+ }
+ }
+ llx -= 128;
+ cur_x = 0;
+ }
+ source += bm->rowpixels;
+ trans += tm->rowpixels;
+ dest += dm->rowpixels;
+ prib += priority_bitmap->rowpixels;
+ mask += 4;
+ }
+}
+
+
+// The rgb version is used by model 1 & 2 which do not need to care
+// about sprite priority hence the lack of support for the
+// priority_bitmap
+
+static void sys24_tile_draw_rect_rgb(running_machine *machine, mame_bitmap *bm, mame_bitmap *tm, mame_bitmap *dm, const UINT16 *mask,
+ UINT16 tpri, UINT8 lpri, int win, int sx, int sy, int xx1, int yy1, int xx2, int yy2)
+{
+ int y;
+ const UINT16 *source = ((UINT16 *)bm->base) + sx + sy*bm->rowpixels;
+ const UINT8 *trans = ((UINT8 *) tm->base) + sx + sy*tm->rowpixels;
+ UINT16 *dest = dm->base;
+ const pen_t *pens = machine->pens;
+
+ tpri |= TILEMAP_PIXEL_LAYER0;
+
+ dest += yy1*dm->rowpixels + xx1;
+ mask += yy1*4;
+ yy2 -= yy1;
+
+ while(xx1 >= 128) {
+ xx1 -= 128;
+ xx2 -= 128;
+ mask++;
+ }
+
+ for(y=0; y<yy2; y++) {
+ const UINT16 *src = source;
+ const UINT8 *srct = trans;
+ UINT16 *dst = dest;
+ const UINT16 *mask1 = mask;
+ int llx = xx2;
+ int cur_x = xx1;
+
+ while(llx > 0) {
+ UINT16 m = *mask1++;
+
+ if(win)
+ m = ~m;
+
+ if(!cur_x && llx>=128) {
+ // Fast paths for the 128-pixels without side clipping case
+
+ if(!m) {
+ // 1- 128 pixels from this layer
+ int x;
+ for(x=0; x<128; x++) {
+ if(*srct++ == tpri)
+ *dst = pens[*src];
+ src++;
+ dst++;
+ }
+
+ } else if(m == 0xffff) {
+ // 2- 128 pixels from the other layer
+ src += 128;
+ srct += 128;
+ dst += 128;
+
+ } else {
+ // 3- 128 pixels from both layers
+ int x;
+ for(x=0; x<128; x+=8) {
+ if(!(m & 0x8000)) {
+ int xx;
+ for(xx=0; xx<8; xx++)
+ if(srct[xx] == tpri)
+ dst[xx] = pens[src[xx]];
+ }
+ src += 8;
+ srct += 8;
+ dst += 8;
+ m <<= 1;
+ }
+ }
+ } else {
+ // Clipped path
+ int llx1 = llx >= 128 ? 128 : llx;
+
+ if(!m) {
+ // 1- 128 pixels from this layer
+ int x;
+ for(x = cur_x; x<llx1; x++) {
+ if(*srct++ == tpri)
+ *dst = pens[*src];
+ src++;
+ dst++;
+ }
+
+ } else if(m == 0xffff) {
+ // 2- 128 pixels from the other layer
+ src += 128 - cur_x;
+ srct += 128 - cur_x;
+ dst += 128 - cur_x;
+
+ } else {
+ // 3- 128 pixels from both layers
+ int x;
+ for(x=cur_x; x<llx1; x++) {
+ if(*srct++ == tpri && !(m & (0x8000 >> (x >> 3))))
+ *dst = pens[*src];
+
+ src++;
+ dst++;
+ }
+ }
+ }
+ llx -= 128;
+ cur_x = 0;
+ }
+ source += bm->rowpixels;
+ trans += tm->rowpixels;
+ dest += dm->rowpixels;
+ mask += 4;
+ }
+}
+
+void sys24_tile_draw(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int layer, int lpri, int flags)
+{
+ UINT16 hscr = sys24_tile_ram[0x5000+(layer >> 1)];
+ UINT16 vscr = sys24_tile_ram[0x5004+(layer >> 1)];
+ UINT16 ctrl = sys24_tile_ram[0x5004+((layer >> 1) & 2)];
+ UINT16 *mask = sys24_tile_ram + (layer & 4 ? 0x6800 : 0x6000);
+ UINT16 tpri = layer & 1;
+
+ lpri = 1 << lpri;
+ layer >>= 1;
+
+ // Layer disable
+ if(vscr & 0x8000)
+ return;
+
+ if(ctrl & 0x6000) {
+ // Special window/scroll modes
+ if(layer & 1)
+ return;
+
+ tilemap_set_scrolly(sys24_tile_layer[layer], 0, +(vscr & 0x1ff));
+ tilemap_set_scrolly(sys24_tile_layer[layer|1], 0, +(vscr & 0x1ff));
+
+ if(hscr & 0x8000) {
+ //#ifdef MAME_DEBUG
+ popmessage("Linescroll with special mode %04x", ctrl);
+ // return;
+ //#endif
+ } else {
+ tilemap_set_scrollx(sys24_tile_layer[layer], 0, -(hscr & 0x1ff));
+ tilemap_set_scrollx(sys24_tile_layer[layer|1], 0, -(hscr & 0x1ff));
+ }
+
+ switch((ctrl & 0x6000) >> 13) {
+ case 1: {
+ rectangle c1 = *cliprect;
+ rectangle c2 = *cliprect;
+ UINT16 v;
+ v = (-vscr) & 0x1ff;
+ if(c1.max_y >= v)
+ c1.max_y = v-1;
+ if(c2.min_y < v)
+ c2.min_y = v;
+ if(!((-vscr) & 0x200))
+ layer ^= 1;
+
+ tilemap_draw(bitmap, &c1, sys24_tile_layer[layer], tpri, lpri);
+ tilemap_draw(bitmap, &c2, sys24_tile_layer[layer^1], tpri, lpri);
+ break;
+ }
+ case 2: {
+ rectangle c1 = *cliprect;
+ rectangle c2 = *cliprect;
+ UINT16 h;
+ h = (+hscr) & 0x1ff;
+ if(c1.max_x >= h)
+ c1.max_x = h-1;
+ if(c2.min_x < h)
+ c2.min_x = h;
+ if(!((+hscr) & 0x200))
+ layer ^= 1;
+
+ tilemap_draw(bitmap, &c1, sys24_tile_layer[layer], tpri, lpri);
+ tilemap_draw(bitmap, &c2, sys24_tile_layer[layer^1], tpri, lpri);
+ break;
+ }
+ case 3:
+ //#ifdef MAME_DEBUG
+ popmessage("Mode 3, please scream");
+ //#endif
+ break;
+ };
+
+ } else {
+ mame_bitmap *bm, *tm;
+ void (*draw)(running_machine *machine, mame_bitmap *, mame_bitmap *, mame_bitmap *, const UINT16 *,
+ UINT16, UINT8, int, int, int, int, int, int, int);
+ int win = layer & 1;
+
+ if(bitmap->format != BITMAP_FORMAT_INDEXED16)
+ draw = sys24_tile_draw_rect_rgb;
+ else
+ draw = sys24_tile_draw_rect;
+
+ bm = tilemap_get_pixmap(sys24_tile_layer[layer]);
+ tm = tilemap_get_flagsmap(sys24_tile_layer[layer]);
+
+ if(hscr & 0x8000) {
+ int y;
+ UINT16 *hscrtb = sys24_tile_ram + 0x4000 + 0x200*layer;
+ vscr &= 0x1ff;
+
+ for(y=0; y<384; y++) {
+ // Whether it's tilemap-relative or screen-relative is unknown
+ hscr = (-hscrtb[vscr]) & 0x1ff;
+ if(hscr + 496 <= 512) {
+ // Horizontal split unnecessary
+ draw(machine, bm, tm, bitmap, mask, tpri, lpri, win, hscr, vscr, 0, y, 496, y+1);
+ } else {
+ // Horizontal split necessary
+ draw(machine, bm, tm, bitmap, mask, tpri, lpri, win, hscr, vscr, 0, y, 512-hscr, y+1);
+ draw(machine, bm, tm, bitmap, mask, tpri, lpri, win, 0, vscr, 512-hscr, y, 496, y+1);
+ }
+ vscr = (vscr + 1) & 0x1ff;
+ }
+ } else {
+ hscr = (-hscr) & 0x1ff;
+ vscr = (+vscr) & 0x1ff;
+
+ if(hscr + 496 <= 512) {
+ // Horizontal split unnecessary
+ if(vscr + 384 <= 512) {
+ // Vertical split unnecessary
+ draw(machine, bm, tm, bitmap, mask, tpri, lpri, win, hscr, vscr, 0, 0, 496, 384);
+ } else {
+ // Vertical split necessary
+ draw(machine, bm, tm, bitmap, mask, tpri, lpri, win, hscr, vscr, 0, 0, 496, 512-vscr);
+ draw(machine, bm, tm, bitmap, mask, tpri, lpri, win, hscr, 0, 0, 512-vscr, 496, 384);
+
+ }
+ } else {
+ // Horizontal split necessary
+ if(vscr + 384 <= 512) {
+ // Vertical split unnecessary
+ draw(machine, bm, tm, bitmap, mask, tpri, lpri, win, hscr, vscr, 0, 0, 512-hscr, 384);
+ draw(machine, bm, tm, bitmap, mask, tpri, lpri, win, 0, vscr, 512-hscr, 0, 496, 384);
+ } else {
+ // Vertical split necessary
+ draw(machine, bm, tm, bitmap, mask, tpri, lpri, win, hscr, vscr, 0, 0, 512-hscr, 512-vscr);
+ draw(machine, bm, tm, bitmap, mask, tpri, lpri, win, 0, vscr, 512-hscr, 0, 496, 512-vscr);
+ draw(machine, bm, tm, bitmap, mask, tpri, lpri, win, hscr, 0, 0, 512-vscr, 512-hscr, 384);
+ draw(machine, bm, tm, bitmap, mask, tpri, lpri, win, 0, 0, 512-hscr, 512-vscr, 496, 384);
+ }
+ }
+ }
+ }
+}
+
+READ16_HANDLER(sys24_tile_r)
+{
+ return sys24_tile_ram[offset];
+}
+
+READ16_HANDLER(sys24_char_r)
+{
+ return sys24_char_ram[offset];
+}
+
+WRITE16_HANDLER(sys24_tile_w)
+{
+ COMBINE_DATA(sys24_tile_ram + offset);
+ if(offset < 0x4000)
+ tilemap_mark_tile_dirty(sys24_tile_layer[offset >> 12], offset & 0xfff);
+}
+
+WRITE16_HANDLER(sys24_char_w)
+{
+ UINT16 old = sys24_char_ram[offset];
+ COMBINE_DATA(sys24_char_ram + offset);
+ if(old != sys24_char_ram[offset]) {
+ sys24_char_dirtymap[offset / 16] = 1;
+ sys24_char_dirty = 1;
+ }
+}
+
+READ32_HANDLER(sys24_tile32_r)
+{
+ return sys24_tile_r(offset*2, mem_mask&0xffff) | sys24_tile_r((offset*2)+1, mem_mask>>16)<<16;
+}
+
+READ32_HANDLER(sys24_char32_r)
+{
+ return sys24_char_r(offset*2, mem_mask&0xffff) | sys24_char_r((offset*2)+1, mem_mask>>16)<<16;
+}
+
+WRITE32_HANDLER(sys24_tile32_w)
+{
+ sys24_tile_w(offset*2, data&0xffff, mem_mask&0xffff);
+ sys24_tile_w((offset*2)+1, data>>16, mem_mask>>16);
+}
+
+WRITE32_HANDLER(sys24_char32_w)
+{
+ sys24_char_w(offset*2, data&0xffff, mem_mask&0xffff);
+ sys24_char_w((offset*2)+1, data>>16, mem_mask>>16);
+}
+
+// - System 24
+
+static UINT16 *sys24_sprite_ram;
+
+void sys24_sprite_vh_start(void)
+{
+ sys24_sprite_ram = auto_malloc(0x40000);
+
+ state_save_register_global_pointer(sys24_sprite_ram, 0x40000/2);
+ // kc = 0;
+}
+
+/* System24 sprites
+ Normal sprite:
+ 0 00Znnnnn nnnnnnnn zoom mode (1 = separate x and y), next sprite
+ 1 xxxxxxxx yyyyyyyy zoom x, zoom y (zoom y is used for both when mode = 0)
+ 2 --TTTTTT TTTTTTTT sprite number
+ 3 -CCCCCCC CCCCCCCC indirect palette base
+ 4 FSSSYYYY YYYYYYYY flipy, y size, top
+ 5 FSSSXXXX XXXXXXXX flipx, x size, left
+
+ Clip?
+ 0 01-nnnnn nnnnnnnn next sprite
+ 1 ???????? ????????
+
+ Skipped entry
+ 0 10-nnnnn nnnnnnnn next sprite
+
+ End of sprite list
+ 0 11------ --------
+*/
+
+void sys24_sprite_draw(mame_bitmap *bitmap, const rectangle *cliprect, const int *spri)
+{
+ UINT16 curspr = 0;
+ int countspr = 0;
+ int seen;
+ UINT8 pmt[4];
+ int i;
+ UINT16 *sprd[0x2000], *clip[0x2000];
+ UINT16 *cclip = 0;
+
+ for(i=0; i<4; i++)
+ pmt[i] = 0xff << (1+spri[3-i]);
+
+ for(seen = 0; seen < 0x2000; seen++) {
+ UINT16 *source;
+ UINT16 type;
+
+ source = sys24_sprite_ram + (curspr << 3);
+
+ if(curspr == 0 && source[0] == 0)
+ break;
+
+ curspr = source[0];
+ type = curspr & 0xc000;
+ curspr &= 0x1fff;
+
+ if(type == 0xc000)
+ break;
+
+ if(type == 0x8000)
+ continue;
+
+ if(type == 0x4000) {
+ cclip = source;
+ continue;
+ }
+
+ sprd[countspr] = source;
+ clip[countspr] = cclip;
+
+ countspr++;
+ if(!curspr)
+ break;
+ }
+
+ for(countspr--; countspr >= 0; countspr--) {
+ UINT16 *source, *pix;
+ int x, y, sx, sy;
+ int px, py;
+ UINT16 colors[16];
+ int flipx, flipy;
+ int zoomx, zoomy;
+ UINT8 pm[16];
+ // int dump;
+ int xmod, ymod;
+ int min_x, min_y, max_x, max_y;
+
+ UINT32 addoffset;
+ UINT32 newoffset;
+ UINT32 offset;
+
+ source = sprd[countspr];
+ cclip = clip[countspr];
+
+ if(cclip) {
+ min_y = (cclip[2] & 511);
+ min_x = (cclip[3] & 511) - 8;
+ max_y = (cclip[4] & 511);
+ max_x = (cclip[5] & 511) - 8;
+ } else {
+ min_x = 0;
+ max_x = 495;
+ min_y = 0;
+ max_y = 383;
+ }
+
+
+ if(min_x < cliprect->min_x)
+ min_x = cliprect->min_x;
+ if(min_y < cliprect->min_y)
+ min_y = cliprect->min_y;
+ if(max_x > cliprect->max_x)
+ max_x = cliprect->max_x;
+ if(max_y > cliprect->max_y)
+ max_y = cliprect->max_y;
+
+ if(!(source[0] & 0x2000))
+ zoomx = zoomy = source[1] & 0xff;
+ else {
+ zoomx = source[1] >> 8;
+ zoomy = source[1] & 0xff;
+ }
+ if(!zoomx)
+ zoomx = 0x3f;
+ if(!zoomy)
+ zoomy = 0x3f;
+
+ zoomx++;
+ zoomy++;
+
+ x = source[5] & 0xfff;
+ flipx = source[5] & 0x8000;
+ if(x & 0x800)
+ x -= 0x1000;
+ sx = 1 << ((source[5] & 0x7000) >> 12);
+
+ x -= 8;
+
+ y = source[4] & 0xfff;
+ if(y & 0x800)
+ y -= 0x1000;
+ flipy = source[4] & 0x8000;
+ sy = 1 << ((source[4] & 0x7000) >> 12);
+
+ pix = &sys24_sprite_ram[(source[3] & 0x3fff)* 0x8];
+ for(px=0; px<8; px++) {
+ int c;
+ c = pix[px] >> 8;
+ pm[px*2] = pmt[c>>6];
+ if(c>1)
+ c |= 0x1000;
+ colors[px*2] = c;
+
+ c = pix[px] & 0xff;
+ pm[px*2+1] = pmt[c>>6];
+ if(c>1)
+ c |= 0x1000;
+ colors[px*2+1] = c;
+ }
+
+ offset = (source[2] & 0x7fff) * 0x10;
+
+ xmod = 0x20;
+ ymod = 0x20;
+ for(py=0; py<sy; py++) {
+ int xmod1 = xmod;
+ int xpos1 = x;
+ int ypos1 = y, ymod1 = ymod;
+ for(px=0; px<sx; px++) {
+ int xmod2 = xmod1, xpos2 = xpos1;
+ int zy;
+ addoffset = 0x10*(flipx ? sx-px-1 : px) + 0x10*sx*(flipy ? sy-py-1 : py) + (flipy ? 7*2 : 0);
+ newoffset = offset + addoffset;
+
+ ymod1 = ymod;
+ ypos1 = y;
+ for(zy=0; zy<8; zy++) {
+
+ ymod1 += zoomy;
+ while(ymod1 >= 0x40) {
+ if(ypos1 >= min_y && ypos1 <= max_y) {
+ int zx;
+ xmod2 = xmod1;
+ xpos2 = xpos1;
+
+ for(zx=0; zx<8; zx++) {
+ xmod2 += zoomx;
+ while(xmod2 >= 0x40) {
+ if(xpos2 >= min_x && xpos2 <= max_x) {
+ int zx1 = flipx ? 7-zx : zx;
+ UINT32 neweroffset = (newoffset+(zx1>>2))&0x1ffff; // crackdown sometimes attempts to use data past the end of spriteram
+ int c = (sys24_sprite_ram[neweroffset] >> (((~zx1) & 3) << 2)) & 0xf;
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, ypos1, xpos2);
+ if(!(*pri & pm[c])) {
+ c = colors[c];
+ if(c) {
+ UINT16 *dst = BITMAP_ADDR16(bitmap, ypos1, xpos2);
+ if(c==1)
+ *dst = (*dst) | 0x2000;
+ else
+ *dst = c;
+ *pri = 0xff;
+ }
+ }
+ }
+ xmod2 -= 0x40;
+ xpos2++;
+ }
+ }
+ }
+ ymod1 -= 0x40;
+ ypos1++;
+ }
+ if(flipy)
+ newoffset -= 2;
+ else
+ newoffset += 2;
+ }
+
+ xpos1 = xpos2;
+ xmod1 = xmod2;
+ }
+ y = ypos1;
+ ymod = ymod1;
+ }
+ }
+}
+
+
+WRITE16_HANDLER(sys24_sprite_w)
+{
+ COMBINE_DATA(sys24_sprite_ram + offset);
+}
+
+READ16_HANDLER(sys24_sprite_r)
+{
+ return sys24_sprite_ram[offset];
+}
+
+// Programmable mixers
+// System 24
+
+static UINT16 sys24_mixer_reg[0x10];
+
+void sys24_mixer_vh_start(void)
+{
+ memset(sys24_mixer_reg, 0, sizeof(sys24_mixer_reg));
+ state_save_register_global_array(sys24_mixer_reg);
+}
+
+WRITE16_HANDLER (sys24_mixer_w)
+{
+ COMBINE_DATA(sys24_mixer_reg + offset);
+}
+
+READ16_HANDLER (sys24_mixer_r)
+{
+ return sys24_mixer_reg[offset];
+}
+
+int sys24_mixer_get_reg(int reg)
+{
+ return sys24_mixer_reg[reg];
+}
+
diff --git a/src/mame/video/segaic24.h b/src/mame/video/segaic24.h
new file mode 100644
index 00000000000..2c7e3edf83f
--- /dev/null
+++ b/src/mame/video/segaic24.h
@@ -0,0 +1,45 @@
+#ifndef __SEGAIC_H
+#define __SEGAIC_H
+
+/* system24temp_ functions / variables are from shared rewrite files,
+ once the rest of the rewrite is complete they can be removed, I
+ just made a copy & renamed them for now to avoid any conflicts
+*/
+
+//#include "vmixer.h"
+
+WRITE16_HANDLER (system24temp_sys16_paletteram1_w);
+
+// Tilemaps
+// System24
+void sys24_tile_vh_start(running_machine *machine, UINT16 tile_mask);
+void sys24_tile_update(running_machine *machine);
+void sys24_tile_draw(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int layer, int pri, int flags);
+
+READ16_HANDLER(sys24_tile_r);
+READ16_HANDLER(sys24_char_r);
+WRITE16_HANDLER(sys24_tile_w);
+WRITE16_HANDLER(sys24_char_w);
+
+READ32_HANDLER(sys24_tile32_r);
+READ32_HANDLER(sys24_char32_r);
+WRITE32_HANDLER(sys24_tile32_w);
+WRITE32_HANDLER(sys24_char32_w);
+
+// Sprites
+// System24
+void sys24_sprite_vh_start(void);
+void sys24_sprite_draw(mame_bitmap *bitmap, const rectangle *cliprect, const int *spri);
+
+WRITE16_HANDLER (sys24_sprite_w);
+READ16_HANDLER (sys24_sprite_r);
+
+// Programmable mixers
+// System24
+void sys24_mixer_vh_start(void);
+int sys24_mixer_get_reg(int reg);
+
+WRITE16_HANDLER (sys24_mixer_w);
+READ16_HANDLER (sys24_mixer_r);
+
+#endif
diff --git a/src/mame/video/segaorun.c b/src/mame/video/segaorun.c
new file mode 100644
index 00000000000..05c5155d616
--- /dev/null
+++ b/src/mame/video/segaorun.c
@@ -0,0 +1,122 @@
+/***************************************************************************
+
+ Sega Outrun hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "segaic16.h"
+#include "includes/system16.h"
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( shangon )
+{
+ /* compute palette info */
+ segaic16_palette_init(0x1000);
+
+ /* initialize the tile/text layers */
+ segaic16_tilemap_init(0, SEGAIC16_TILEMAP_16B_ALT, 0x000, 0, 2);
+
+ /* initialize the sprites */
+ segaic16_sprites_init(0, SEGAIC16_SPRITES_16B, 0x400, 0);
+
+ /* initialize the road */
+ segaic16_road_init(0, SEGAIC16_ROAD_OUTRUN, 0x7f6, 0x7c0, 0x7c0, 0);
+}
+
+
+VIDEO_START( outrun )
+{
+ /* compute palette info */
+ segaic16_palette_init(0x1000);
+
+ /* initialize the tile/text layers */
+ segaic16_tilemap_init(0, SEGAIC16_TILEMAP_16B, 0x000, 0, 2);
+
+ /* initialize the sprites */
+ segaic16_sprites_init(0, SEGAIC16_SPRITES_OUTRUN, 0x800, 0);
+
+ /* initialize the road */
+ segaic16_road_init(0, SEGAIC16_ROAD_OUTRUN, 0x400, 0x420, 0x780, 0);
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( shangon )
+{
+ /* reset priorities */
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ /* draw the low priority road layer */
+ segaic16_road_draw(0, bitmap, cliprect, SEGAIC16_ROAD_BACKGROUND);
+
+ /* draw background */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 0, 0x01);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 1, 0x02);
+
+ /* draw foreground */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_FOREGROUND, 0, 0x02);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_FOREGROUND, 1, 0x04);
+
+ /* draw the high priority road */
+ segaic16_road_draw(0, bitmap, cliprect, SEGAIC16_ROAD_FOREGROUND);
+
+ /* text layer */
+ /* note that we inflate the priority of the text layer to prevent sprites */
+ /* from drawing over the high scores */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_TEXT, 0, 0x08);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_TEXT, 1, 0x08);
+
+ /* draw the sprites */
+ segaic16_sprites_draw(0, bitmap, cliprect);
+ return 0;
+}
+
+
+VIDEO_UPDATE( outrun )
+{
+ /* if no drawing is happening, fill with black and get out */
+ if (!segaic16_display_enable)
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* reset priorities */
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ /* draw the low priority road layer */
+ segaic16_road_draw(0, bitmap, cliprect, SEGAIC16_ROAD_BACKGROUND);
+
+ /* draw background */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 0, 0x01);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 1, 0x02);
+
+ /* draw foreground */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_FOREGROUND, 0, 0x02);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_FOREGROUND, 1, 0x04);
+
+ /* draw the high priority road */
+ segaic16_road_draw(0, bitmap, cliprect, SEGAIC16_ROAD_FOREGROUND);
+
+ /* text layer */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_TEXT, 0, 0x04);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_TEXT, 1, 0x08);
+
+ /* draw the sprites */
+ segaic16_sprites_draw(0, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/segas16a.c b/src/mame/video/segas16a.c
new file mode 100644
index 00000000000..1c5eff3f412
--- /dev/null
+++ b/src/mame/video/segas16a.c
@@ -0,0 +1,70 @@
+/***************************************************************************
+
+ Sega System 16A hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "segaic16.h"
+#include "includes/system16.h"
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( system16a )
+{
+ /* compute palette info */
+ segaic16_palette_init(0x800);
+
+ /* initialize the tile/text layers */
+ segaic16_tilemap_init(0, SEGAIC16_TILEMAP_16A, 0x000, 0, 1);
+
+ /* initialize the sprites */
+ segaic16_sprites_init(0, SEGAIC16_SPRITES_16A, 0x400, 0);
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( system16a )
+{
+ /* if no drawing is happening, fill with black and get out */
+ if (!segaic16_display_enable)
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* reset priorities */
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ /* draw background opaquely first, not setting any priorities */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 0 | TILEMAP_DRAW_OPAQUE, 0x00);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 1 | TILEMAP_DRAW_OPAQUE, 0x00);
+
+ /* draw background again, just to set the priorities on non-transparent pixels */
+ segaic16_tilemap_draw(machine, 0, NULL, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 0, 0x01);
+ segaic16_tilemap_draw(machine, 0, NULL, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 1, 0x02);
+
+ /* draw foreground */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_FOREGROUND, 0, 0x02);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_FOREGROUND, 1, 0x04);
+
+ /* text layer */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_TEXT, 0, 0x04);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_TEXT, 1, 0x08);
+
+ /* draw the sprites */
+ segaic16_sprites_draw(0, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/segas16b.c b/src/mame/video/segas16b.c
new file mode 100644
index 00000000000..a8a0fe484ba
--- /dev/null
+++ b/src/mame/video/segas16b.c
@@ -0,0 +1,82 @@
+/***************************************************************************
+
+ Sega System 16B hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "segaic16.h"
+#include "includes/system16.h"
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+static void video_start_common(int type)
+{
+ /* compute palette info */
+ segaic16_palette_init(0x800);
+
+ /* initialize the tile/text layers */
+ segaic16_tilemap_init(0, type, 0x000, 0, 2);
+
+ /* initialize the sprites */
+ segaic16_sprites_init(0, SEGAIC16_SPRITES_16B, 0x400, 0);
+}
+
+
+VIDEO_START( system16b )
+{
+ video_start_common(SEGAIC16_TILEMAP_16B);
+}
+
+
+VIDEO_START( timscanr )
+{
+ video_start_common(SEGAIC16_TILEMAP_16B_ALT);
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( system16b )
+{
+ /* if no drawing is happening, fill with black and get out */
+ if (!segaic16_display_enable)
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* reset priorities */
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ /* draw background opaquely first, not setting any priorities */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 0 | TILEMAP_DRAW_OPAQUE, 0x00);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 1 | TILEMAP_DRAW_OPAQUE, 0x00);
+
+ /* draw background again, just to set the priorities on non-transparent pixels */
+ segaic16_tilemap_draw(machine, 0, NULL, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 0, 0x01);
+ segaic16_tilemap_draw(machine, 0, NULL, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 1, 0x02);
+
+ /* draw foreground */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_FOREGROUND, 0, 0x02);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_FOREGROUND, 1, 0x04);
+
+ /* text layer */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_TEXT, 0, 0x04);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_TEXT, 1, 0x08);
+
+ /* draw the sprites */
+ segaic16_sprites_draw(0, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/segas18.c b/src/mame/video/segas18.c
new file mode 100644
index 00000000000..af0ce9e96d9
--- /dev/null
+++ b/src/mame/video/segas18.c
@@ -0,0 +1,257 @@
+/***************************************************************************
+
+ Sega System 18 hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "segaic16.h"
+#include "includes/system16.h"
+
+
+
+/*************************************
+ *
+ * Debugging
+ *
+ *************************************/
+
+#define DEBUG_VDP (0)
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static mame_bitmap *tempbitmap;
+
+static UINT8 grayscale_enable;
+static UINT8 vdp_enable;
+static UINT8 vdp_mixing;
+
+
+
+/*************************************
+ *
+ * Prototypes
+ *
+ *************************************/
+
+extern void start_system18_vdp(void);
+extern void update_system18_vdp(mame_bitmap *bitmap, const rectangle *cliprect);
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( system18 )
+{
+ /* compute palette info */
+ segaic16_palette_init(0x800);
+
+ /* initialize the tile/text layers */
+ segaic16_tilemap_init(0, SEGAIC16_TILEMAP_16B, 0x000, 0, 8);
+
+ /* initialize the sprites */
+ segaic16_sprites_init(0, SEGAIC16_SPRITES_16B, 0x400, 0);
+
+ /* create the VDP */
+ start_system18_vdp();
+
+ /* create a temp bitmap to draw the VDP data into */
+ tempbitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+}
+
+
+
+/*************************************
+ *
+ * Miscellaneous setters
+ *
+ *************************************/
+
+void system18_set_grayscale(int enable)
+{
+ enable = (enable != 0);
+ if (enable != grayscale_enable)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ grayscale_enable = enable;
+// mame_printf_debug("Grayscale = %02X\n", enable);
+ }
+}
+
+
+void system18_set_vdp_enable(int enable)
+{
+ enable = (enable != 0);
+ if (enable != vdp_enable)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ vdp_enable = enable;
+#if DEBUG_VDP
+ mame_printf_debug("VDP enable = %02X\n", enable);
+#endif
+ }
+}
+
+
+void system18_set_vdp_mixing(int mixing)
+{
+ if (mixing != vdp_mixing)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ vdp_mixing = mixing;
+#if DEBUG_VDP
+ mame_printf_debug("VDP mixing = %02X\n", mixing);
+#endif
+ }
+}
+
+
+
+/*************************************
+ *
+ * VDP drawing
+ *
+ *************************************/
+
+static void draw_vdp(mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int x, y;
+
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *src = BITMAP_ADDR16(tempbitmap, y, 0);
+ UINT16 *dst = BITMAP_ADDR16(bitmap, y, 0);
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ UINT16 pix = src[x];
+ if (pix != 0xffff)
+ {
+ dst[x] = pix;
+ pri[x] |= priority;
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( system18 )
+{
+ int vdppri, vdplayer;
+
+/*
+ Current understanding of VDP mixing:
+
+ mixing = 0x00:
+ astorm: layer = 0, pri = 0x00 or 0x01
+ lghost: layer = 0, pri = 0x00 or 0x01
+
+ mixing = 0x01:
+ ddcrew: layer = 0, pri = 0x00 or 0x01 or 0x02
+
+ mixing = 0x02:
+ never seen
+
+ mixing = 0x03:
+ ddcrew: layer = 1, pri = 0x00 or 0x01 or 0x02
+
+ mixing = 0x04:
+ astorm: layer = 2 or 3, pri = 0x00 or 0x01 or 0x02
+ mwalk: layer = 2 or 3, pri = 0x00 or 0x01 or 0x02
+
+ mixing = 0x05:
+ ddcrew: layer = 2, pri = 0x04
+ wwally: layer = 2, pri = 0x04
+
+ mixing = 0x06:
+ never seen
+
+ mixing = 0x07:
+ cltchitr: layer = 1 or 2 or 3, pri = 0x02 or 0x04 or 0x08
+ mwalk: layer = 3, pri = 0x04 or 0x08
+*/
+ vdplayer = (vdp_mixing >> 1) & 3;
+ vdppri = (vdp_mixing & 1) ? (1 << vdplayer) : 0;
+
+#if DEBUG_VDP
+ if (input_code_pressed(KEYCODE_Q)) vdplayer = 0;
+ if (input_code_pressed(KEYCODE_W)) vdplayer = 1;
+ if (input_code_pressed(KEYCODE_E)) vdplayer = 2;
+ if (input_code_pressed(KEYCODE_R)) vdplayer = 3;
+ if (input_code_pressed(KEYCODE_A)) vdppri = 0x00;
+ if (input_code_pressed(KEYCODE_S)) vdppri = 0x01;
+ if (input_code_pressed(KEYCODE_D)) vdppri = 0x02;
+ if (input_code_pressed(KEYCODE_F)) vdppri = 0x04;
+ if (input_code_pressed(KEYCODE_G)) vdppri = 0x08;
+#endif
+
+ /* if no drawing is happening, fill with black and get out */
+ if (!segaic16_display_enable)
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* if the VDP is enabled, update our tempbitmap */
+ if (vdp_enable)
+ update_system18_vdp(tempbitmap, cliprect);
+
+ /* reset priorities */
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ /* draw background opaquely first, not setting any priorities */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 0 | TILEMAP_DRAW_OPAQUE, 0x00);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 1 | TILEMAP_DRAW_OPAQUE, 0x00);
+ if (vdp_enable && vdplayer == 0) draw_vdp(bitmap, cliprect, vdppri);
+
+ /* draw background again to draw non-transparent pixels over the VDP and set the priority */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 0, 0x01);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 1, 0x02);
+ if (vdp_enable && vdplayer == 1) draw_vdp(bitmap, cliprect, vdppri);
+
+ /* draw foreground */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_FOREGROUND, 0, 0x02);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_FOREGROUND, 1, 0x04);
+ if (vdp_enable && vdplayer == 2) draw_vdp(bitmap, cliprect, vdppri);
+
+ /* text layer */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_TEXT, 0, 0x04);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_TEXT, 1, 0x08);
+ if (vdp_enable && vdplayer == 3) draw_vdp(bitmap, cliprect, vdppri);
+
+ /* draw the sprites */
+ segaic16_sprites_draw(0, bitmap, cliprect);
+
+#if DEBUG_VDP
+ if (vdp_enable && input_code_pressed(KEYCODE_V))
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ update_system18_vdp(bitmap, cliprect);
+ }
+ if (vdp_enable && input_code_pressed(KEYCODE_B))
+ {
+ FILE *f = fopen("vdp.bin", "w");
+ fwrite(tempbitmap->base, 1, tempbitmap->rowpixels * (tempbitmap->bpp / 8) * tempbitmap->height, f);
+ fclose(f);
+ }
+#endif
+ return 0;
+}
diff --git a/src/mame/video/segas32.c b/src/mame/video/segas32.c
new file mode 100644
index 00000000000..8596bfbad08
--- /dev/null
+++ b/src/mame/video/segas32.c
@@ -0,0 +1,2847 @@
+/*
+ Open questions:
+
+ - In f1en, the scrolling text in attract mode is very jumpy. Whatever
+ double buffering they are using seems to be out of sync with the sprite
+ rendering.
+
+ - In radr, NBG1 should be opaque on select screen, and NBG3 should be
+ opaque while driving. How is this controlled?
+
+ - In radr, they use $1A0 as the X center for zooming; however, this
+ contradicts the theory that bit 9 is a sign bit. For now, the code
+ assumes that the X center has 10 bits of resolution.
+
+ - In svf (the field) and radr (on the field), they use tilemap-specific
+ flip in conjunction with rowscroll AND rowselect. According to Charles,
+ in this case, the rowselect lookups should be done in reverse order,
+ but this results in an incorrect display. For now, we assume there is
+ a bug in the procedure and implement it so that it looks correct.
+
+
+ Information extracted from below, and from Modeler:
+
+ Tile format:
+ Bits Usage
+ y------- -------- Tile Y flip
+ -x------ -------- Tile X flip
+ --?----- -------- Unknown
+ ---ccccc cccc---- Tile color palette
+ ---nnnnn nnnnnnnn Tile index
+
+ Text format:
+ Bits Usage
+ ccccccc- -------- Tile color palette
+ -------n nnnnnnnn Tile index
+
+ Text RAM:
+ Offset Bits Usage
+ $31FF00 : w--- ---- ---- ---- : Screen width (0= 320, 1= 412)
+ ---- f--- ---- ---- : Bitmap format (1= 8bpp, 0= 4bpp)
+ ---- -t-- ---- ---- : Tile banking related
+ ---- --f- ---- ---- : 1= All layers X+Y flip
+ ---- ---- ---- 4--- : 1= X+Y flip for NBG3
+ ---- ---- ---- -2-- : 1= X+Y flip for NBG2
+ ---- ---- ---- --1- : 1= X+Y flip for NBG1
+ ---- ---- ---- ---0 : 1= X+Y flip for NBG0
+ $31FF02 : x--- ---- --x- ---- : Bitmap layer enable (?)
+ ---1 ---- ---- ---- : 1= NBG1 page wrapping disable
+ ---- 0--- ---- ---- : 1= NBG0 page wrapping disable
+ ---- ---- --b- ---- : 1= Bitmap layer disable
+ ---- ---- ---t ---- : 1= Text layer disable
+ ---- ---- ---- 3--- : 1= NBG3 layer disable
+ ---- ---- ---- -2-- : 1= NBG2 layer disable
+ ---- ---- ---- --1- : 1= NBG1 layer disable
+ ---- ---- ---- ---0 : 1= NBG0 layer disable
+
+ F02 cccccccc -------- Per-layer clipping modes (see Modeler)
+ -------- ----d--- Disable tilemap layer 3
+ -------- -----d-- Disable tilemap layer 2
+ -------- ------d- Disable tilemap layer 1
+ -------- -------d Disable tilemap layer 0
+ F04 tttttttt -------- Rowscroll/select table page number
+ -------- ----s--- Enable rowselect for tilemap layer 3
+ -------- -----s-- Enable rowselect for tilemap layer 2
+ -------- ------c- Enable rowscroll for tilemap layer 3
+ -------- -------c Enable rowscroll for tilemap layer 2
+ F06 cccc---- -------- Layer 3 clip select
+ ----cccc -------- Layer 2 clip select
+ -------- cccc---- Layer 1 clip select
+ -------- ----cccc Layer 0 clip select
+ F12 ------xx xxxxxxxx Layer 0 X scroll
+ F16 -------y yyyyyyyy Layer 0 Y scroll
+ F1A ------xx xxxxxxxx Layer 1 X scroll
+ F1E -------y yyyyyyyy Layer 1 Y scroll
+ F22 ------xx xxxxxxxx Layer 2 X scroll
+ F26 -------y yyyyyyyy Layer 2 Y scroll
+ F2A ------xx xxxxxxxx Layer 3 X scroll
+ F2E -------y yyyyyyyy Layer 3 Y scroll
+ F30 ------xx xxxxxxxx Layer 0 X offset (Modeler says X center)
+ F32 -------y yyyyyyyy Layer 0 Y offset (Modeler says Y center)
+ F34 ------xx xxxxxxxx Layer 1 X offset
+ F36 -------y yyyyyyyy Layer 1 Y offset
+ F38 ------xx xxxxxxxx Layer 2 X offset
+ F3A -------y yyyyyyyy Layer 2 Y offset
+ F3C ------xx xxxxxxxx Layer 3 X offset
+ F3E -------y yyyyyyyy Layer 3 Y offset
+ F40 -wwwwwww -------- Layer 0 upper-right page select
+ -------- -wwwwwww Layer 0 upper-left page select
+ F42 -wwwwwww -------- Layer 0 lower-right page select
+ -------- -wwwwwww Layer 0 lower-left page select
+ F44 -wwwwwww -------- Layer 1 upper-right page select
+ -------- -wwwwwww Layer 1 upper-left page select
+ F46 -wwwwwww -------- Layer 1 lower-right page select
+ -------- -wwwwwww Layer 2 upper-left page select
+ F48 -wwwwwww -------- Layer 2 upper-right page select
+ -------- -wwwwwww Layer 2 lower-left page select
+ F4A -wwwwwww -------- Layer 2 lower-right page select
+ -------- -wwwwwww Layer 3 upper-left page select
+ -wwwwwww -------- Layer 3 upper-right page select
+ F4E -------- -wwwwwww Layer 3 lower-left page select
+ -wwwwwww -------- Layer 3 lower-right page select
+ F50 xxxxxxxx xxxxxxxx Layer 0 X step increment (0x200 = 1.0)
+ F52 yyyyyyyy yyyyyyyy Layer 0 Y step increment (0x200 = 1.0)
+ F54 xxxxxxxx xxxxxxxx Layer 1 X step increment (0x200 = 1.0)
+ F56 yyyyyyyy yyyyyyyy Layer 1 Y step increment (0x200 = 1.0)
+ F58 xxxxxxxx xxxxxxxx Layer 2 X step increment (0x200 = 1.0)
+ F5A yyyyyyyy yyyyyyyy Layer 2 Y step increment (0x200 = 1.0)
+ F5C -------- tttt---- Text layer page select (page = 64 + t*8)
+ -------- -----bbb Text layer tile bank
+
+ $31FF5E : e--- ---- ---- ---- : Select backdrop color per 1= line, 0= screen
+ ---x xxxx ---- ---- : Affects color in screen mode
+ ---d dddd dddd dddd : Offset in CRAM for line mode
+
+ F60 xxxxxxxx xxxxxxxx Clip rect 0, left
+ F62 yyyyyyyy yyyyyyyy Clip rect 0, top
+ F64 xxxxxxxx xxxxxxxx Clip rect 0, right
+ F66 yyyyyyyy yyyyyyyy Clip rect 0, bottom
+ F68 xxxxxxxx xxxxxxxx Clip rect 1, left
+ F6A yyyyyyyy yyyyyyyy Clip rect 1, top
+ F6C xxxxxxxx xxxxxxxx Clip rect 1, right
+ F6E yyyyyyyy yyyyyyyy Clip rect 1, bottom
+ F70 xxxxxxxx xxxxxxxx Clip rect 2, left
+ F72 yyyyyyyy yyyyyyyy Clip rect 2, top
+ F74 xxxxxxxx xxxxxxxx Clip rect 2, right
+ F76 yyyyyyyy yyyyyyyy Clip rect 2, bottom
+ F78 xxxxxxxx xxxxxxxx Clip rect 3, left
+ F7A yyyyyyyy yyyyyyyy Clip rect 3, top
+ F7C xxxxxxxx xxxxxxxx Clip rect 3, right
+ F7E yyyyyyyy yyyyyyyy Clip rect 3, bottom
+
+ $31FF88 : ---- ---x xxxx xxxx : Bitmap X scroll
+ $31FF8A : ---- ---y yyyy yyyy : Bitmap Y scroll (bit 8 ONLY available when format is 4bpp)
+ $31FF8C : ---- ---b bbbb b--- : Bitmap palette base? (bit 3 ONLY available when format is 4bpp)
+
+ $31FF8E : ---- ---- --b- ---- : 1= Bitmap layer disable
+ ---- ---- ---3 ---- : 1= NBG3 layer disable
+ ---- ---- ---- 2--- : 1= NBG2 layer disable
+ ---- ---- ---- -1-- : 1= NBG1 layer disable
+ ---- ---- ---- --0- : 1= NBG0 layer disable
+ ---- ---- ---- ---t : 1= Text layer disable
+*/
+
+#include "driver.h"
+#include "profiler.h"
+#include "segas32.h"
+
+
+
+/*************************************
+ *
+ * Debugging
+ *
+ *************************************/
+
+#define SHOW_CLIPS 0
+#define QWERTY_LAYER_ENABLE 0
+#define PRINTF_MIXER_DATA 0
+#define SHOW_ALPHA 0
+#define LOG_SPRITES 0
+
+
+
+/*************************************
+ *
+ * Constants
+ *
+ *************************************/
+
+#define MIXER_LAYER_TEXT 0
+#define MIXER_LAYER_NBG0 1
+#define MIXER_LAYER_NBG1 2
+#define MIXER_LAYER_NBG2 3
+#define MIXER_LAYER_NBG3 4
+#define MIXER_LAYER_BITMAP 5
+#define MIXER_LAYER_SPRITES 6
+#define MIXER_LAYER_BACKGROUND 7
+#define MIXER_LAYER_SPRITES_2 8 /* semi-kludge to have a frame buffer for sprite backlayer */
+#define MIXER_LAYER_MULTISPR 9
+#define MIXER_LAYER_MULTISPR_2 10
+
+#define TILEMAP_CACHE_SIZE 32
+
+
+
+/*************************************
+ *
+ * Helper macros
+ *
+ *************************************/
+
+#ifdef LSB_FIRST
+#define SWAP_HALVES(x) (x)
+#else
+#define SWAP_HALVES(x) (((x) >> 16) | ((x) << 16))
+#endif
+
+
+
+/*************************************
+ *
+ * Type definitions
+ *
+ *************************************/
+
+struct layer_info
+{
+ mame_bitmap * bitmap;
+ UINT8 * transparent;
+};
+
+
+struct extents_list
+{
+ UINT8 scan_extent[256];
+ UINT16 extent[32][16];
+};
+
+
+struct cache_entry
+{
+ struct cache_entry * next;
+ tilemap * tmap;
+ UINT8 page;
+ UINT8 bank;
+};
+
+
+
+/*************************************
+ *
+ * Globals
+ *
+ *************************************/
+
+UINT16 *system32_videoram;
+UINT16 *system32_spriteram;
+UINT16 *system32_paletteram[2];
+UINT16 system32_displayenable[2];
+UINT16 system32_tilebank_external;
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static UINT8 is_multi32;
+
+/* tilemap cache */
+static struct cache_entry *cache_head;
+
+/* mixer data */
+static struct layer_info layer_data[11];
+static UINT16 mixer_control[2][0x40];
+static UINT16 *solid_0000;
+static UINT16 *solid_ffff;
+
+/* sprite data */
+static UINT8 sprite_render_count;
+static UINT8 sprite_control_latched[8];
+static UINT8 sprite_control[8];
+static UINT32 *spriteram_32bit;
+
+
+
+/*************************************
+ *
+ * Prototypes
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_tile_info );
+static void sprite_erase_buffer(void);
+static void sprite_swap_buffers(void);
+static void sprite_render_list(void);
+
+
+
+
+/*************************************
+ *
+ * Video start
+ *
+ *************************************/
+
+static void common_start(int multi32)
+{
+ int tmap;
+
+ /* remember whether or not we are multi32 */
+ is_multi32 = multi32;
+
+ /* allocate a copy of spriteram in 32-bit format */
+ spriteram_32bit = auto_malloc(0x20000);
+
+ /* allocate the tilemap cache */
+ cache_head = NULL;
+ for (tmap = 0; tmap < TILEMAP_CACHE_SIZE; tmap++)
+ {
+ struct cache_entry *entry = auto_malloc(sizeof(struct cache_entry));
+
+ entry->tmap = tilemap_create(get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,16, 32,16);
+ entry->page = 0xff;
+ entry->bank = 0;
+ entry->next = cache_head;
+ tilemap_set_user_data(entry->tmap, entry);
+
+ cache_head = entry;
+ }
+
+ /* allocate the bitmaps (a few extra for multi32) */
+ for (tmap = 0; tmap < 9 + 2 * multi32; tmap++)
+ {
+ layer_data[tmap].bitmap = auto_bitmap_alloc(416, 224, BITMAP_FORMAT_INDEXED16);
+ layer_data[tmap].transparent = auto_malloc(sizeof(layer_data[tmap].transparent[0]) * 256);
+ memset(layer_data[tmap].transparent, 0, sizeof(layer_data[tmap].transparent[0]) * 256);
+ }
+
+ /* allocate pre-rendered solid lines of 0's and ffff's */
+ solid_0000 = auto_malloc(sizeof(solid_0000[0]) * 512);
+ memset(solid_0000, 0x00, sizeof(solid_0000[0]) * 512);
+ solid_ffff = auto_malloc(sizeof(solid_ffff[0]) * 512);
+ memset(solid_ffff, 0xff, sizeof(solid_ffff[0]) * 512);
+
+ /* initialize videoram */
+ system32_videoram[0x1ff00/2] = 0x8000;
+}
+
+
+VIDEO_START( system32 )
+{
+ common_start(0);
+}
+
+
+VIDEO_START( multi32 )
+{
+ common_start(1);
+}
+
+
+
+/*************************************
+ *
+ * Sprite management
+ *
+ *************************************/
+
+static TIMER_CALLBACK( update_sprites )
+{
+ /* if automatic mode is selected, do it every frame (0) or every other frame (1) */
+ if (!(sprite_control[3] & 2))
+ {
+ /* if we count down to the start, process the automatic swapping, but only after a short delay */
+ if (sprite_render_count-- == 0)
+ {
+ sprite_control[0] = 3;
+ sprite_render_count = sprite_control[3] & 1;
+ }
+ }
+
+ /* look for pending commands */
+ if (sprite_control[0] & 2)
+ sprite_erase_buffer();
+ if (sprite_control[0] & 1)
+ {
+ sprite_swap_buffers();
+ sprite_render_list();
+ }
+ sprite_control[0] = 0;
+}
+
+
+void system32_set_vblank(int state)
+{
+ /* at the end of VBLANK is when automatic sprite rendering happens */
+ if (!state)
+ timer_set(ATTOTIME_IN_USEC(50), 1, update_sprites);
+}
+
+
+
+/*************************************
+ *
+ * Common palette handling
+ *
+ *************************************/
+
+INLINE UINT16 xBBBBBGGGGGRRRRR_to_xBGRBBBBGGGGRRRR(UINT16 value)
+{
+ int r = (value >> 0) & 0x1f;
+ int g = (value >> 5) & 0x1f;
+ int b = (value >> 10) & 0x1f;
+ value = (value & 0x8000) | ((b & 0x01) << 14) | ((g & 0x01) << 13) | ((r & 0x01) << 12);
+ value |= ((b & 0x1e) << 7) | ((g & 0x1e) << 3) | ((r & 0x1e) >> 1);
+ return value;
+}
+
+
+INLINE UINT16 xBGRBBBBGGGGRRRR_to_xBBBBBGGGGGRRRRR(UINT16 value)
+{
+ int r = ((value >> 12) & 0x01) | ((value << 1) & 0x1e);
+ int g = ((value >> 13) & 0x01) | ((value >> 3) & 0x1e);
+ int b = ((value >> 14) & 0x01) | ((value >> 7) & 0x1e);
+ return (value & 0x8000) | (b << 10) | (g << 5) | (r << 0);
+}
+
+
+INLINE void update_color(int offset, UINT16 data)
+{
+ /* note that since we use this RAM directly, we don't technically need */
+ /* to call palette_set_color() at all; however, it does give us that */
+ /* nice display when you hit F4, which is useful for debugging */
+
+ /* set the color */
+ palette_set_color_rgb(Machine, offset, pal5bit(data >> 0), pal5bit(data >> 5), pal5bit(data >> 10));
+}
+
+
+INLINE UINT16 common_paletteram_r(int which, offs_t offset)
+{
+ int convert;
+
+ /* the lower half of palette RAM is formatted xBBBBBGGGGGRRRRR */
+ /* the upper half of palette RAM is formatted xBGRBBBBGGGGRRRR */
+ /* we store everything if the first format, and convert accesses to the other format */
+ /* on the fly */
+ convert = (offset & 0x4000);
+ offset &= 0x3fff;
+
+ if (!convert)
+ return system32_paletteram[which][offset];
+ else
+ return xBBBBBGGGGGRRRRR_to_xBGRBBBBGGGGRRRR(system32_paletteram[which][offset]);
+}
+
+
+static void common_paletteram_w(int which, offs_t offset, UINT16 data, UINT16 mem_mask)
+{
+ UINT16 value;
+ int convert;
+
+ /* the lower half of palette RAM is formatted xBBBBBGGGGGRRRRR */
+ /* the upper half of palette RAM is formatted xBGRBBBBGGGGRRRR */
+ /* we store everything if the first format, and convert accesses to the other format */
+ /* on the fly */
+ convert = (offset & 0x4000);
+ offset &= 0x3fff;
+
+ /* read, modify, and write the new value, updating the palette */
+ value = system32_paletteram[which][offset];
+ if (convert) value = xBBBBBGGGGGRRRRR_to_xBGRBBBBGGGGRRRR(value);
+ COMBINE_DATA(&value);
+ if (convert) value = xBGRBBBBGGGGRRRR_to_xBBBBBGGGGGRRRRR(value);
+ system32_paletteram[which][offset] = value;
+ update_color(0x4000*which + offset, value);
+
+ /* if blending is enabled, writes go to both halves of palette RAM */
+ if (mixer_control[which][0x4e/2] & 0x0880)
+ {
+ offset ^= 0x2000;
+
+ /* read, modify, and write the new value, updating the palette */
+ value = system32_paletteram[which][offset];
+ if (convert) value = xBBBBBGGGGGRRRRR_to_xBGRBBBBGGGGRRRR(value);
+ COMBINE_DATA(&value);
+ if (convert) value = xBGRBBBBGGGGRRRR_to_xBBBBBGGGGGRRRRR(value);
+ system32_paletteram[which][offset] = value;
+ update_color(0x4000*which + offset, value);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM access
+ *
+ *************************************/
+
+READ16_HANDLER( system32_paletteram_r )
+{
+ return common_paletteram_r(0, offset);
+}
+
+
+WRITE16_HANDLER( system32_paletteram_w )
+{
+ common_paletteram_w(0, offset, data, mem_mask);
+}
+
+
+READ32_HANDLER( multi32_paletteram_0_r )
+{
+ return common_paletteram_r(0, offset*2+0) |
+ (common_paletteram_r(0, offset*2+1) << 16);
+}
+
+
+WRITE32_HANDLER( multi32_paletteram_0_w )
+{
+ if ((mem_mask & 0x0000ffff) != 0x0000ffff)
+ common_paletteram_w(0, offset*2+0, data, mem_mask);
+ if ((mem_mask & 0xffff0000) != 0xffff0000)
+ common_paletteram_w(0, offset*2+1, data >> 16, mem_mask >> 16);
+}
+
+
+READ32_HANDLER( multi32_paletteram_1_r )
+{
+ return common_paletteram_r(1, offset*2+0) |
+ (common_paletteram_r(1, offset*2+1) << 16);
+}
+
+
+WRITE32_HANDLER( multi32_paletteram_1_w )
+{
+ if ((mem_mask & 0x0000ffff) != 0x0000ffff)
+ common_paletteram_w(1, offset*2+0, data, mem_mask);
+ if ((mem_mask & 0xffff0000) != 0xffff0000)
+ common_paletteram_w(1, offset*2+1, data >> 16, mem_mask >> 16);
+}
+
+
+
+/*************************************
+ *
+ * Video RAM access
+ *
+ *************************************/
+
+READ16_HANDLER( system32_videoram_r )
+{
+ return system32_videoram[offset];
+}
+
+
+WRITE16_HANDLER( system32_videoram_w )
+{
+ COMBINE_DATA(&system32_videoram[offset]);
+
+ /* if we are not in the control area, just update any affected tilemaps */
+ if (offset < 0x1ff00/2)
+ {
+ struct cache_entry *entry;
+ int page = offset / 0x200;
+ offset %= 0x200;
+
+ /* scan the cache for a matching pages */
+ for (entry = cache_head; entry != NULL; entry = entry->next)
+ if (entry->page == page)
+ tilemap_mark_tile_dirty(entry->tmap, offset);
+ }
+}
+
+
+READ32_HANDLER( multi32_videoram_r )
+{
+ return system32_videoram[offset*2+0] |
+ (system32_videoram[offset*2+1] << 16);
+}
+
+
+WRITE32_HANDLER( multi32_videoram_w )
+{
+ if ((mem_mask & 0x0000ffff) != 0x0000ffff)
+ system32_videoram_w(offset*2+0, data, mem_mask);
+ if ((mem_mask & 0xffff0000) != 0xffff0000)
+ system32_videoram_w(offset*2+1, data >> 16, mem_mask >> 16);
+}
+
+
+
+/*************************************
+ *
+ * Sprite control registers
+ *
+ *************************************/
+
+READ16_HANDLER( system32_sprite_control_r )
+{
+ switch (offset)
+ {
+ case 0:
+ /* D1 : Seems to be '1' only during an erase in progress, this
+ occurs very briefly though.
+ D0 : Selected frame buffer (0= A, 1= B) */
+ return 0xfffc | (layer_data[MIXER_LAYER_SPRITES].bitmap < layer_data[MIXER_LAYER_SPRITES_2].bitmap);
+
+ case 1:
+ /* D1 : ?
+ D0 : ?
+
+ Values seem to be:
+
+ 0 = Unknown (relates to *approaching* out of time condition)
+ 1 = Normal status
+ 2 = Overdraw (rendering time is over but end-of-list command not read yet)
+ 3 = Never occurs
+
+ Condition 2 can occur during rendering or list processing. */
+ return 0xfffc | 1;
+
+ case 2:
+ /* D1 : 1= Vertical flip, 0= Normal orientation
+ D0 : 1= Horizontal flip, 0= Normal orientation */
+ return 0xfffc | sprite_control_latched[2];
+
+ case 3:
+ /* D1 : 1= Manual mode, 0= Automatic mode
+ D0 : 1= 30 Hz update, 0= 60 Hz update (automatic mode only) */
+ return 0xfffc | sprite_control_latched[3];
+
+ case 4:
+ /* D1 : ?
+ D0 : ? */
+ return 0xfffc | sprite_control_latched[4];
+
+ case 5:
+ /* D1 : ?
+ D0 : ? */
+ return 0xfffc | sprite_control_latched[5];
+
+ case 6:
+ /* D0 : 1= 416 pixels
+ 0= 320 pixels */
+ return 0xfffc | (sprite_control_latched[6] & 1);
+
+ case 7:
+ /* D1 : ?
+ D0 : ? */
+ return 0xfffc;
+ }
+ return 0xffff;
+}
+
+
+WRITE16_HANDLER( system32_sprite_control_w )
+{
+ if (ACCESSING_LSB)
+ sprite_control[offset & 7] = data;
+}
+
+
+READ32_HANDLER( multi32_sprite_control_r )
+{
+ return system32_sprite_control_r(offset*2+0, mem_mask) |
+ (system32_sprite_control_r(offset*2+1, mem_mask >> 16) << 16);
+}
+
+
+WRITE32_HANDLER( multi32_sprite_control_w )
+{
+ if ((mem_mask & 0x0000ffff) != 0x0000ffff)
+ system32_sprite_control_w(offset*2+0, data, mem_mask);
+ if ((mem_mask & 0xffff0000) != 0xffff0000)
+ system32_sprite_control_w(offset*2+1, data >> 16, mem_mask >> 16);
+}
+
+
+
+/*************************************
+ *
+ * Sprite RAM access
+ *
+ *************************************/
+
+READ16_HANDLER( system32_spriteram_r )
+{
+ return system32_spriteram[offset];
+}
+
+
+WRITE16_HANDLER( system32_spriteram_w )
+{
+ COMBINE_DATA(&system32_spriteram[offset]);
+ spriteram_32bit[offset/2] =
+ ((system32_spriteram[offset | 1] >> 8 ) & 0x000000ff) |
+ ((system32_spriteram[offset | 1] << 8 ) & 0x0000ff00) |
+ ((system32_spriteram[offset & ~1] << 8 ) & 0x00ff0000) |
+ ((system32_spriteram[offset & ~1] << 24) & 0xff000000);
+}
+
+
+READ32_HANDLER( multi32_spriteram_r )
+{
+ return system32_spriteram[offset*2+0] |
+ (system32_spriteram[offset*2+1] << 16);
+}
+
+
+WRITE32_HANDLER( multi32_spriteram_w )
+{
+ data = SWAP_HALVES(data);
+ mem_mask = SWAP_HALVES(mem_mask);
+ COMBINE_DATA((UINT32 *)&system32_spriteram[offset*2]);
+ spriteram_32bit[offset/2] =
+ ((system32_spriteram[offset | 1] >> 8 ) & 0x000000ff) |
+ ((system32_spriteram[offset | 1] << 8 ) & 0x0000ff00) |
+ ((system32_spriteram[offset & ~1] << 8 ) & 0x00ff0000) |
+ ((system32_spriteram[offset & ~1] << 24) & 0xff000000);
+}
+
+
+
+/*************************************
+ *
+ * Mixer control registers
+ *
+ *************************************/
+
+READ16_HANDLER( system32_mixer_r )
+{
+ return mixer_control[0][offset];
+}
+
+WRITE16_HANDLER( system32_mixer_w )
+{
+ COMBINE_DATA(&mixer_control[0][offset]);
+}
+
+
+WRITE32_HANDLER( multi32_mixer_0_w )
+{
+ data = SWAP_HALVES(data);
+ mem_mask = SWAP_HALVES(mem_mask);
+ COMBINE_DATA((UINT32 *)&mixer_control[0][offset*2]);
+}
+
+
+WRITE32_HANDLER( multi32_mixer_1_w )
+{
+ data = SWAP_HALVES(data);
+ mem_mask = SWAP_HALVES(mem_mask);
+ COMBINE_DATA((UINT32 *)&mixer_control[1][offset*2]);
+}
+
+
+
+/*************************************
+ *
+ * Tilemap cache
+ *
+ *************************************/
+
+static tilemap *find_cache_entry(int page, int bank)
+{
+ struct cache_entry *entry, *prev;
+
+ /* scan the list for a matching entry */
+ prev = NULL;
+ entry = cache_head;
+ while (1)
+ {
+ if (entry->page == page && entry->bank == bank)
+ {
+ /* move us to the head before returning */
+ if (prev)
+ {
+ prev->next = entry->next;
+ entry->next = cache_head;
+ cache_head = entry;
+ }
+ return entry->tmap;
+ }
+
+ /* stop on the last entry */
+ if (entry->next == NULL)
+ break;
+ prev = entry;
+ entry = entry->next;
+ }
+
+ /* okay, we didn't find one; take over this last entry */
+ entry->page = page;
+ entry->bank = bank;
+ tilemap_mark_all_tiles_dirty(entry->tmap);
+
+ /* move it to the head */
+ prev->next = entry->next;
+ entry->next = cache_head;
+ cache_head = entry;
+
+ return entry->tmap;
+}
+
+
+
+/*************************************
+ *
+ * Tilemap callback
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ struct cache_entry *entry = param;
+ UINT16 data = system32_videoram[(entry->page & 0x7f) * 0x200 + tile_index];
+ SET_TILE_INFO(0, (entry->bank << 13) + (data & 0x1fff), (data >> 4) & 0x1ff, (data >> 14) & 3);
+}
+
+
+
+/*************************************
+ *
+ * Clipping extents computation
+ *
+ *************************************/
+
+static int compute_clipping_extents(running_machine *machine, int scrnum, int enable, int clipout, int clipmask, const rectangle *cliprect, struct extents_list *list)
+{
+ int flip = (system32_videoram[0x1ff00/2] >> 9) & 1;
+ rectangle tempclip;
+ rectangle clips[5];
+ int sorted[5];
+ int i, j, y;
+
+ /* expand our cliprect to exclude the bottom-right */
+ tempclip = *cliprect;
+ tempclip.max_x++;
+ tempclip.max_y++;
+
+ /* create the 0th entry */
+ list->extent[0][0] = tempclip.min_x;
+ list->extent[0][1] = tempclip.max_x;
+
+ /* simple case if not enabled */
+ if (!enable)
+ {
+ memset(&list->scan_extent[tempclip.min_y], 0, sizeof(list->scan_extent[0]) * (tempclip.max_y - tempclip.min_y));
+ return 1;
+ }
+
+ /* extract the from videoram into locals, and apply the cliprect */
+ for (i = 0; i < 5; i++)
+ {
+ if (!flip)
+ {
+ clips[i].min_x = system32_videoram[0x1ff60/2 + i * 4] & 0x1ff;
+ clips[i].min_y = system32_videoram[0x1ff62/2 + i * 4] & 0x0ff;
+ clips[i].max_x = (system32_videoram[0x1ff64/2 + i * 4] & 0x1ff) + 1;
+ clips[i].max_y = (system32_videoram[0x1ff66/2 + i * 4] & 0x0ff) + 1;
+ }
+ else
+ {
+ clips[i].max_x = (machine->screen[scrnum].visarea.max_x + 1) - (system32_videoram[0x1ff60/2 + i * 4] & 0x1ff);
+ clips[i].max_y = (machine->screen[scrnum].visarea.max_y + 1) - (system32_videoram[0x1ff62/2 + i * 4] & 0x0ff);
+ clips[i].min_x = (machine->screen[scrnum].visarea.max_x + 1) - ((system32_videoram[0x1ff64/2 + i * 4] & 0x1ff) + 1);
+ clips[i].min_y = (machine->screen[scrnum].visarea.max_y + 1) - ((system32_videoram[0x1ff66/2 + i * 4] & 0x0ff) + 1);
+ }
+ sect_rect(&clips[i], &tempclip);
+ sorted[i] = i;
+ }
+
+ /* bubble sort them by min_x */
+ for (i = 0; i < 5; i++)
+ for (j = i + 1; j < 5; j++)
+ if (clips[sorted[i]].min_x > clips[sorted[j]].min_x) { int temp = sorted[i]; sorted[i] = sorted[j]; sorted[j] = temp; }
+
+ /* create all valid extent combinations */
+ for (i = 1; i < 32; i++)
+ if (i & clipmask)
+ {
+ UINT16 *extent = &list->extent[i][0];
+
+ /* start off with an entry at tempclip.min_x */
+ *extent++ = tempclip.min_x;
+
+ /* loop in sorted order over extents */
+ for (j = 0; j < 5; j++)
+ if (i & (1 << sorted[j]))
+ {
+ const rectangle *cur = &clips[sorted[j]];
+
+ /* see if this intersects our last extent */
+ if (extent != &list->extent[i][1] && cur->min_x <= extent[-1])
+ {
+ if (cur->max_x > extent[-1])
+ extent[-1] = cur->max_x;
+ }
+
+ /* otherwise, just append to the list */
+ else
+ {
+ *extent++ = cur->min_x;
+ *extent++ = cur->max_x;
+ }
+ }
+
+ /* append an ending entry */
+ *extent++ = tempclip.max_x;
+ }
+
+ /* loop over scanlines and build extents */
+ for (y = tempclip.min_y; y < tempclip.max_y; y++)
+ {
+ int sect = 0;
+
+ /* figure out all the clips that intersect this scanline */
+ for (i = 0; i < 5; i++)
+ if ((clipmask & (1 << i)) && y >= clips[i].min_y && y < clips[i].max_y)
+ sect |= 1 << i;
+ list->scan_extent[y] = sect;
+ }
+
+ return clipout;
+}
+
+
+
+/*************************************
+ *
+ * Zooming tilemaps (NBG0/1)
+ *
+ *************************************/
+
+INLINE void get_tilemaps(int bgnum, tilemap **tilemaps)
+{
+ int tilebank, page;
+
+ /* determine the current tilebank */
+ if (is_multi32)
+ tilebank = (system32_tilebank_external >> (2*bgnum)) & 3;
+ else
+ tilebank = ((system32_tilebank_external & 1) << 1) | ((system32_videoram[0x1ff00/2] & 0x400) >> 10);
+
+ /* find the cache entries */
+ page = (system32_videoram[0x1ff40/2 + 2 * bgnum + 0] >> 0) & 0x7f;
+ tilemaps[0] = find_cache_entry(page, tilebank);
+ page = (system32_videoram[0x1ff40/2 + 2 * bgnum + 0] >> 8) & 0x7f;
+ tilemaps[1] = find_cache_entry(page, tilebank);
+ page = (system32_videoram[0x1ff40/2 + 2 * bgnum + 1] >> 0) & 0x7f;
+ tilemaps[2] = find_cache_entry(page, tilebank);
+ page = (system32_videoram[0x1ff40/2 + 2 * bgnum + 1] >> 8) & 0x7f;
+ tilemaps[3] = find_cache_entry(page, tilebank);
+}
+
+
+static void update_tilemap_zoom(running_machine *machine, int scrnum, struct layer_info *layer, const rectangle *cliprect, int bgnum)
+{
+ int clipenable, clipout, clips, clipdraw_start;
+ mame_bitmap *bitmap = layer->bitmap;
+ struct extents_list clip_extents;
+ tilemap *tilemaps[4];
+ UINT32 srcx, srcx_start, srcy;
+ UINT32 srcxstep, srcystep;
+ int dstxstep, dstystep;
+ int flip, opaque;
+ int x, y;
+
+ /* get the tilemaps */
+ get_tilemaps(bgnum, tilemaps);
+
+ /* configure the layer */
+ opaque = 0;
+//opaque = (system32_videoram[0x1ff8e/2] >> (8 + bgnum)) & 1;
+//if (input_code_pressed(KEYCODE_Z) && bgnum == 0) opaque = 1;
+//if (input_code_pressed(KEYCODE_X) && bgnum == 1) opaque = 1;
+
+ /* determine if we're flipped */
+ flip = ((system32_videoram[0x1ff00/2] >> 9) ^ (system32_videoram[0x1ff00/2] >> bgnum)) & 1;
+
+ /* determine the clipping */
+ clipenable = (system32_videoram[0x1ff02/2] >> (11 + bgnum)) & 1;
+ clipout = (system32_videoram[0x1ff02/2] >> (6 + bgnum)) & 1;
+ clips = (system32_videoram[0x1ff06/2] >> (4 * bgnum)) & 0x0f;
+ clipdraw_start = compute_clipping_extents(machine, scrnum, clipenable, clipout, clips, cliprect, &clip_extents);
+
+ /* extract the X/Y step values (these are in destination space!) */
+ dstxstep = system32_videoram[0x1ff50/2 + 2 * bgnum] & 0xfff;
+ if (system32_videoram[0x1ff00/2] & 0x4000)
+ dstystep = system32_videoram[0x1ff52/2 + 2 * bgnum] & 0xfff;
+ else
+ dstystep = dstxstep;
+
+ /* clamp the zoom factors */
+ if (dstxstep < 0x80)
+ dstxstep = 0x80;
+ if (dstystep < 0x80)
+ dstystep = 0x80;
+
+ /* compute high-precision reciprocals (in 12.20 format) */
+ srcxstep = (0x200 << 20) / dstxstep;
+ srcystep = (0x200 << 20) / dstystep;
+
+ /* start with the fractional scroll offsets, in source coordinates */
+ srcx_start = (system32_videoram[0x1ff12/2 + 4 * bgnum] & 0x3ff) << 20;
+ srcx_start += (system32_videoram[0x1ff10/2 + 4 * bgnum] & 0xff00) << 4;
+ srcy = (system32_videoram[0x1ff16/2 + 4 * bgnum] & 0x1ff) << 20;
+ srcy += (system32_videoram[0x1ff14/2 + 4 * bgnum] & 0xfe00) << 4;
+
+ /* then account for the destination center coordinates */
+ srcx_start -= ((INT16)(system32_videoram[0x1ff30/2 + 2 * bgnum] << 6) >> 6) * srcxstep;
+ srcy -= ((INT16)(system32_videoram[0x1ff32/2 + 2 * bgnum] << 7) >> 7) * srcystep;
+
+ /* finally, account for destination top,left coordinates */
+ srcx_start += cliprect->min_x * srcxstep;
+ srcy += cliprect->min_y * srcystep;
+
+ /* if we're flipped, simply adjust the start/step parameters */
+ if (flip)
+ {
+ srcx_start += (machine->screen[scrnum].visarea.max_x - 2 * cliprect->min_x) * srcxstep;
+ srcy += (machine->screen[scrnum].visarea.max_y - 2 * cliprect->min_y) * srcystep;
+ srcxstep = -srcxstep;
+ srcystep = -srcystep;
+ }
+
+ /* loop over the target rows */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *extents = &clip_extents.extent[clip_extents.scan_extent[y]][0];
+ UINT16 *dst = BITMAP_ADDR16(bitmap, y, 0);
+ int clipdraw = clipdraw_start;
+
+ /* optimize for the case where we are clipped out */
+ if (clipdraw || extents[1] <= cliprect->max_x)
+ {
+ mame_bitmap *tm0, *tm1;
+ int transparent = 0;
+ UINT16 *src[2];
+
+ /* look up the pages and get their source pixmaps */
+ tm0 = tilemap_get_pixmap(tilemaps[((srcy >> 27) & 2) + 0]);
+ tm1 = tilemap_get_pixmap(tilemaps[((srcy >> 27) & 2) + 1]);
+ src[0] = BITMAP_ADDR16(tm0, (srcy >> 20) & 0xff, 0);
+ src[1] = BITMAP_ADDR16(tm1, (srcy >> 20) & 0xff, 0);
+
+ /* loop over extents */
+ srcx = srcx_start;
+ while (1)
+ {
+ /* if we're drawing on this extent, draw it */
+ if (clipdraw)
+ {
+ for (x = extents[0]; x < extents[1]; x++)
+ {
+ UINT16 pix = src[(srcx >> 29) & 1][(srcx >> 20) & 0x1ff];
+ srcx += srcxstep;
+ if ((pix & 0x0f) == 0 && !opaque)
+ pix = 0, transparent++;
+ dst[x] = pix;
+ }
+ }
+
+ /* otherwise, clear to zero */
+ else
+ {
+ int pixels = extents[1] - extents[0];
+ memset(&dst[extents[0]], 0, pixels * sizeof(dst[0]));
+ srcx += srcxstep * pixels;
+ transparent += pixels;
+ }
+
+ /* stop at the end */
+ if (extents[1] > cliprect->max_x)
+ break;
+
+ /* swap states and advance to the next extent */
+ clipdraw = !clipdraw;
+ extents++;
+ }
+
+ layer->transparent[y] = (transparent == cliprect->max_x - cliprect->min_x + 1);
+ }
+ else
+ layer->transparent[y] = 1;
+
+ /* advance in Y */
+ srcy += srcystep;
+ }
+
+ /* enable this code below to display zoom information */
+#if 0
+ if (dstxstep != 0x200 || dstystep != 0x200)
+ popmessage("Zoom=%03X,%03X Cent=%03X,%03X", dstxstep, dstystep,
+ system32_videoram[0x1ff30/2 + 2 * bgnum],
+ system32_videoram[0x1ff32/2 + 2 * bgnum]);
+#endif
+}
+
+
+
+/*************************************
+ *
+ * Rowscroll/select tilemaps (NBG2/3)
+ *
+ *************************************/
+
+static void update_tilemap_rowscroll(running_machine *machine, int scrnum, struct layer_info *layer, const rectangle *cliprect, int bgnum)
+{
+ int clipenable, clipout, clips, clipdraw_start;
+ mame_bitmap *bitmap = layer->bitmap;
+ struct extents_list clip_extents;
+ tilemap *tilemaps[4];
+ int rowscroll, rowselect;
+ int xscroll, yscroll;
+ UINT16 *table;
+ int srcx, srcy;
+ int flip, opaque;
+ int x, y;
+
+ /* get the tilemaps */
+ get_tilemaps(bgnum, tilemaps);
+
+ /* configure the layer */
+ opaque = 0;
+//opaque = (system32_videoram[0x1ff8e/2] >> (8 + bgnum)) & 1;
+//if (input_code_pressed(KEYCODE_C) && bgnum == 2) opaque = 1;
+//if (input_code_pressed(KEYCODE_V) && bgnum == 3) opaque = 1;
+
+ /* determine if we're flipped */
+ flip = ((system32_videoram[0x1ff00/2] >> 9) ^ (system32_videoram[0x1ff00/2] >> bgnum)) & 1;
+
+ /* determine the clipping */
+ clipenable = (system32_videoram[0x1ff02/2] >> (11 + bgnum)) & 1;
+ clipout = (system32_videoram[0x1ff02/2] >> (6 + bgnum)) & 1;
+ clips = (system32_videoram[0x1ff06/2] >> (4 * bgnum)) & 0x0f;
+ clipdraw_start = compute_clipping_extents(machine, scrnum, clipenable, clipout, clips, cliprect, &clip_extents);
+
+ /* determine if row scroll and/or row select is enabled */
+ rowscroll = (system32_videoram[0x1ff04/2] >> (bgnum - 2)) & 1;
+ rowselect = (system32_videoram[0x1ff04/2] >> bgnum) & 1;
+ if ((system32_videoram[0x1ff04/2] >> (bgnum + 2)) & 1)
+ rowscroll = rowselect = 0;
+
+ /* get a pointer to the table */
+ table = &system32_videoram[(system32_videoram[0x1ff04/2] >> 10) * 0x400];
+
+ /* start with screen-wide X and Y scrolls */
+ xscroll = (system32_videoram[0x1ff12/2 + 4 * bgnum] & 0x3ff) - (system32_videoram[0x1ff30/2 + 2 * bgnum] & 0x1ff);
+ yscroll = (system32_videoram[0x1ff16/2 + 4 * bgnum] & 0x1ff);
+
+ /* render the tilemap into its bitmap */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *extents = &clip_extents.extent[clip_extents.scan_extent[y]][0];
+ UINT16 *dst = BITMAP_ADDR16(bitmap, y, 0);
+ int clipdraw = clipdraw_start;
+
+ /* optimize for the case where we are clipped out */
+ if (clipdraw || extents[1] <= cliprect->max_x)
+ {
+ mame_bitmap *tm0, *tm1;
+ int transparent = 0;
+ UINT16 *src[2];
+ int srcxstep;
+
+ /* if we're not flipped, things are straightforward */
+ if (!flip)
+ {
+ /* get starting scroll values */
+ srcx = cliprect->min_x + xscroll;
+ srcxstep = 1;
+ srcy = yscroll + y;
+
+ /* apply row scroll/select */
+ if (rowscroll)
+ srcx += table[0x000 + 0x100 * (bgnum - 2) + y] & 0x3ff;
+ if (rowselect)
+ srcy = (yscroll + table[0x200 + 0x100 * (bgnum - 2) + y]) & 0x1ff;
+ }
+
+ /* otherwise, we have to do some contortions */
+ else
+ {
+ /* get starting scroll values */
+ srcx = cliprect->max_x + xscroll;
+ srcxstep = -1;
+ srcy = yscroll + machine->screen[scrnum].visarea.max_y - y;
+
+ /* apply row scroll/select */
+ if (rowscroll)
+ srcx += table[0x000 + 0x100 * (bgnum - 2) + y] & 0x3ff;
+ if (rowselect)
+ srcy = (yscroll + table[0x200 + 0x100 * (bgnum - 2) + y]) & 0x1ff;
+ }
+
+ /* look up the pages and get their source pixmaps */
+ tm0 = tilemap_get_pixmap(tilemaps[((srcy >> 7) & 2) + 0]);
+ tm1 = tilemap_get_pixmap(tilemaps[((srcy >> 7) & 2) + 1]);
+ src[0] = BITMAP_ADDR16(tm0, srcy & 0xff, 0);
+ src[1] = BITMAP_ADDR16(tm1, srcy & 0xff, 0);
+
+ /* loop over extents */
+ while (1)
+ {
+ /* if we're drawing on this extent, draw it */
+ if (clipdraw)
+ {
+ for (x = extents[0]; x < extents[1]; x++, srcx += srcxstep)
+ {
+ UINT16 pix = src[(srcx >> 9) & 1][srcx & 0x1ff];
+ if ((pix & 0x0f) == 0 && !opaque)
+ pix = 0, transparent++;
+ dst[x] = pix;
+ }
+ }
+
+ /* otherwise, clear to zero */
+ else
+ {
+ int pixels = extents[1] - extents[0];
+ memset(&dst[extents[0]], 0, pixels * sizeof(dst[0]));
+ srcx += srcxstep * pixels;
+ transparent += pixels;
+ }
+
+ /* stop at the end */
+ if (extents[1] > cliprect->max_x)
+ break;
+
+ /* swap states and advance to the next extent */
+ clipdraw = !clipdraw;
+ extents++;
+ }
+
+ layer->transparent[y] = (transparent == cliprect->max_x - cliprect->min_x + 1);
+ }
+ else
+ layer->transparent[y] = 1;
+ }
+
+ /* enable this code below to display scroll information */
+#if 0
+ if (rowscroll || rowselect)
+ popmessage("Scroll=%d Select=%d Table@%06X",
+ rowscroll, rowselect, (system32_videoram[0x1ff04/2] >> 10) * 0x800);
+#endif
+}
+
+
+
+/*************************************
+ *
+ * Text layer
+ *
+ *************************************/
+
+static void update_tilemap_text(running_machine *machine, int scrnum, struct layer_info *layer, const rectangle *cliprect)
+{
+ mame_bitmap *bitmap = layer->bitmap;
+ UINT16 *tilebase;
+ UINT16 *gfxbase;
+ int startx, starty;
+ int endx, endy;
+ int x, y, iy;
+ int flip;
+
+ /* determine if we're flipped */
+ flip = (system32_videoram[0x1ff00/2] >> 9) & 1;
+
+ /* determine the base of the tilemap and graphics data */
+ tilebase = &system32_videoram[((system32_videoram[0x1ff5c/2] >> 4) & 0x1f) * 0x800];
+ gfxbase = &system32_videoram[(system32_videoram[0x1ff5c/2] & 7) * 0x2000];
+
+ /* compute start/end tile numbers */
+ startx = cliprect->min_x / 8;
+ starty = cliprect->min_y / 8;
+ endx = cliprect->max_x / 8;
+ endy = cliprect->max_y / 8;
+
+ /* loop over tiles */
+ for (y = starty; y <= endy; y++)
+ for (x = startx; x <= endx; x++)
+ {
+ int tile = tilebase[y * 64 + x];
+ UINT16 *src = &gfxbase[(tile & 0x1ff) * 16];
+ int color = (tile & 0xfe00) >> 5;
+
+ /* non-flipped case */
+ if (!flip)
+ {
+ UINT16 *dst = BITMAP_ADDR16(bitmap, y * 8, x * 8);
+
+ /* loop over rows */
+ for (iy = 0; iy < 8; iy++)
+ {
+ int pixels = *src++;
+ int pix;
+
+ pix = (pixels >> 4) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[0] = pix;
+
+ pix = (pixels >> 0) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[1] = pix;
+
+ pix = (pixels >> 12) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[2] = pix;
+
+ pix = (pixels >> 8) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[3] = pix;
+
+ pixels = *src++;
+
+ pix = (pixels >> 4) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[4] = pix;
+
+ pix = (pixels >> 0) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[5] = pix;
+
+ pix = (pixels >> 12) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[6] = pix;
+
+ pix = (pixels >> 8) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[7] = pix;
+
+ dst += bitmap->rowpixels;
+ }
+ }
+
+ /* flipped case */
+ else
+ {
+ int effdstx = machine->screen[scrnum].visarea.max_x - x * 8;
+ int effdsty = machine->screen[scrnum].visarea.max_y - y * 8;
+ UINT16 *dst = BITMAP_ADDR16(bitmap, effdsty, effdstx);
+
+ /* loop over rows */
+ for (iy = 0; iy < 8; iy++)
+ {
+ int pixels = *src++;
+ int pix;
+
+ pix = (pixels >> 4) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[0] = pix;
+
+ pix = (pixels >> 0) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[-1] = pix;
+
+ pix = (pixels >> 12) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[-2] = pix;
+
+ pix = (pixels >> 8) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[-3] = pix;
+
+ pix = *src++;
+
+ pix = (pixels >> 4) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[-4] = pix;
+
+ pix = (pixels >> 0) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[-5] = pix;
+
+ pix = (pixels >> 12) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[-6] = pix;
+
+ pix = (pixels >> 8) & 0x0f;
+ if (pix)
+ pix += color;
+ dst[-7] = pix;
+
+ dst -= bitmap->rowpixels;
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Bitmap layer
+ *
+ *************************************/
+
+static void update_bitmap(running_machine *machine, int scrnum, struct layer_info *layer, const rectangle *cliprect)
+{
+ int clipenable, clipout, clips, clipdraw_start;
+ mame_bitmap *bitmap = layer->bitmap;
+ struct extents_list clip_extents;
+ int xscroll, yscroll;
+ int color;
+ int x, y;
+ int bpp;
+
+ /* configure the layer */
+ bpp = (system32_videoram[0x1ff00/2] & 0x0800) ? 8 : 4;
+
+ /* determine the clipping */
+ clipenable = (system32_videoram[0x1ff02/2] >> 15) & 1;
+ clipout = (system32_videoram[0x1ff02/2] >> 10) & 1;
+ clips = 0x10;
+ clipdraw_start = compute_clipping_extents(machine, scrnum, clipenable, clipout, clips, cliprect, &clip_extents);
+
+ /* determine x/y scroll */
+ xscroll = system32_videoram[0x1ff88/2] & 0x1ff;
+ yscroll = system32_videoram[0x1ff8a/2] & 0x1ff;
+ color = (system32_videoram[0x1ff8c/2] << 4) & 0x1fff0 & ~((1 << bpp) - 1);
+
+ /* loop over target rows */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *extents = &clip_extents.extent[clip_extents.scan_extent[y]][0];
+ UINT16 *dst = BITMAP_ADDR16(bitmap, y, 0);
+ int clipdraw = clipdraw_start;
+
+ /* optimize for the case where we are clipped out */
+ if (clipdraw || extents[1] <= cliprect->max_x)
+ {
+ int transparent = 0;
+
+ /* loop over extents */
+ while (1)
+ {
+ /* if we're drawing on this extent, draw it */
+ if (clipdraw)
+ {
+ /* 8bpp mode case */
+ if (bpp == 8)
+ {
+ UINT8 *src = (UINT8 *)&system32_videoram[512/2 * ((y + yscroll) & 0xff)];
+ for (x = extents[0]; x < extents[1]; x++)
+ {
+ int effx = (x + xscroll) & 0x1ff;
+ int pix = src[BYTE_XOR_LE(effx)] + color;
+ if ((pix & 0xff) == 0)
+ pix = 0, transparent++;
+ dst[x] = pix;
+ }
+ }
+
+ /* 4bpp mode case */
+ else
+ {
+ UINT16 *src = &system32_videoram[512/4 * ((y + yscroll) & 0x1ff)];
+ for (x = extents[0]; x < extents[1]; x++)
+ {
+ int effx = (x + xscroll) & 0x1ff;
+ int pix = ((src[effx / 4] >> (4 * (effx & 3))) & 0x0f) + color;
+ if ((pix & 0x0f) == 0)
+ pix = 0, transparent++;
+ dst[x] = pix;
+ }
+ }
+ }
+
+ /* otherwise, clear to zero */
+ else
+ {
+ int pixels = extents[1] - extents[0];
+ memset(&dst[extents[0]], 0, pixels * sizeof(dst[0]));
+ transparent += pixels;
+ }
+
+ /* stop at the end */
+ if (extents[1] > cliprect->max_x)
+ break;
+
+ /* swap states and advance to the next extent */
+ clipdraw = !clipdraw;
+ extents++;
+ }
+
+ layer->transparent[y] = (transparent == cliprect->max_x - cliprect->min_x + 1);
+ }
+ else
+ layer->transparent[y] = 1;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Master tilemap chip updater
+ *
+ *************************************/
+
+static void update_background(struct layer_info *layer, const rectangle *cliprect)
+{
+ mame_bitmap *bitmap = layer->bitmap;
+ int x, y;
+
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *dst = BITMAP_ADDR16(bitmap, y, 0);
+ int color;
+
+ /* determine the color */
+ if (system32_videoram[0x1ff5e/2] & 0x8000)
+ color = (system32_videoram[0x1ff5e/2] & 0x1fff) + y;
+ else
+ color = system32_videoram[0x1ff5e/2] & 0x1e00;
+
+ /* if the color doesn't match, fill */
+ if (dst[cliprect->min_x] != color)
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ dst[x] = color;
+ }
+}
+
+
+static UINT8 update_tilemaps(running_machine *machine, int scrnum, const rectangle *cliprect)
+{
+ int enable0 = !(system32_videoram[0x1ff02/2] & 0x0001) && !(system32_videoram[0x1ff8e/2] & 0x0002);
+ int enable1 = !(system32_videoram[0x1ff02/2] & 0x0002) && !(system32_videoram[0x1ff8e/2] & 0x0004);
+ int enable2 = !(system32_videoram[0x1ff02/2] & 0x0004) && !(system32_videoram[0x1ff8e/2] & 0x0008) && !(system32_videoram[0x1ff00/2] & 0x1000);
+ int enable3 = !(system32_videoram[0x1ff02/2] & 0x0008) && !(system32_videoram[0x1ff8e/2] & 0x0010) && !(system32_videoram[0x1ff00/2] & 0x2000);
+ int enablet = !(system32_videoram[0x1ff02/2] & 0x0010) && !(system32_videoram[0x1ff8e/2] & 0x0001);
+ int enableb = !(system32_videoram[0x1ff02/2] & 0x0020) && !(system32_videoram[0x1ff8e/2] & 0x0020);
+
+ /* update any tilemaps */
+ if (enable0)
+ update_tilemap_zoom(machine, scrnum, &layer_data[MIXER_LAYER_NBG0], cliprect, 0);
+ if (enable1)
+ update_tilemap_zoom(machine, scrnum, &layer_data[MIXER_LAYER_NBG1], cliprect, 1);
+ if (enable2)
+ update_tilemap_rowscroll(machine, scrnum, &layer_data[MIXER_LAYER_NBG2], cliprect, 2);
+ if (enable3)
+ update_tilemap_rowscroll(machine, scrnum, &layer_data[MIXER_LAYER_NBG3], cliprect, 3);
+ if (enablet)
+ update_tilemap_text(machine, scrnum, &layer_data[MIXER_LAYER_TEXT], cliprect);
+ if (enableb)
+ update_bitmap(machine, scrnum, &layer_data[MIXER_LAYER_BITMAP], cliprect);
+ update_background(&layer_data[MIXER_LAYER_BACKGROUND], cliprect);
+
+ return (enablet << 0) | (enable0 << 1) | (enable1 << 2) | (enable2 << 3) | (enable3 << 4) | (enableb << 5);
+}
+
+
+
+/*************************************
+ *
+ * Sprite buffer management
+ *
+ *************************************/
+
+static void sprite_erase_buffer(void)
+{
+ /* erase the visible sprite buffer and clear the checksums */
+ fillbitmap(layer_data[MIXER_LAYER_SPRITES].bitmap, 0xffff, NULL);
+
+ /* for multi32, erase the other buffer as well */
+ if (is_multi32)
+ fillbitmap(layer_data[MIXER_LAYER_MULTISPR].bitmap, 0xffff, NULL);
+}
+
+
+static void sprite_swap_buffers(void)
+{
+ /* swap between the two sprite buffers */
+ struct layer_info temp;
+ temp = layer_data[MIXER_LAYER_SPRITES];
+ layer_data[MIXER_LAYER_SPRITES] = layer_data[MIXER_LAYER_SPRITES_2];
+ layer_data[MIXER_LAYER_SPRITES_2] = temp;
+
+ /* for multi32, swap the other buffer as well */
+ if (is_multi32)
+ {
+ temp = layer_data[MIXER_LAYER_MULTISPR];
+ layer_data[MIXER_LAYER_MULTISPR] = layer_data[MIXER_LAYER_MULTISPR_2];
+ layer_data[MIXER_LAYER_MULTISPR_2] = temp;
+ }
+
+ /* latch any pending info */
+ memcpy(sprite_control_latched, sprite_control, sizeof(sprite_control_latched));
+}
+
+
+
+/*************************************
+ *
+ * Sprite render
+ *
+ *************************************/
+
+/*******************************************************************************************
+ *
+ * System 32-style sprites
+ *
+ * Offs Bits Usage
+ * +0 cc------ -------- Command (00=sprite, 01=clip, 02=jump, 03=end)
+ * +0 --i----- -------- Indirect palette enable
+ * +0 ---l---- -------- Indirect palette is inline in spriteram
+ * +0 ----s--- -------- Shadow sprite
+ * +0 -----r-- -------- Graphics from spriteram
+ * +0 ------8- -------- 8bpp sprite
+ * +0 -------o -------- Opaque (no transparency)
+ * +0 -------- y------- Flip Y
+ * +0 -------- -x------ Flip X
+ * +0 -------- --Y----- Apply Y offset from last jump
+ * +0 -------- ---X---- Apply X offset from last jump
+ * +0 -------- ----aa-- Y alignment (00=center, 10=start, 01=end)
+ * +0 -------- ------AA X alignment (00=center, 10=start, 01=end)
+ * +2 hhhhhhhh -------- Source data height
+ * +2 -------- wwwwwwww Source data width
+ * +4 rrrr---- -------- Low bits of ROM bank
+ * +4 -----hhh hhhhhhhh Onscreen height
+ * +6 -5--4--- -------- Bits 5 + 4 of ROM bank
+ * +6 -----www wwwwwwww Onscreen width
+ * +8 ----yyyy yyyyyyyy Y position
+ * +A ----xxxx xxxxxxxx X position
+ * +C oooooooo oooooooo Offset within selected sprite bank
+ * +E -----ppp pppp---- Palette
+ * +E -------- ----rrrr Priority?
+ *
+ *******************************************************************************************/
+
+#define sprite_draw_pixel_16(trans) \
+ /* only draw if onscreen, not 0 or 15 */ \
+ if (x >= clipin->min_x && x <= clipin->max_x && \
+ (!do_clipout || x < clipout->min_x || x > clipout->max_x) && \
+ pix != trans) \
+ { \
+ if (!indirect) \
+ { \
+ if (pix != 0) \
+ { \
+ if (!shadow) \
+ dest[x] = color | pix; \
+ else \
+ dest[x] &= 0x7fff; \
+ } \
+ } \
+ else \
+ { \
+ int indpix = indtable[pix]; \
+ if ((indpix & transmask) != transmask) \
+ { \
+ if (!shadow) \
+ dest[x] = indpix; \
+ else \
+ dest[x] &= 0x7fff; \
+ } \
+ } \
+ }
+
+#define sprite_draw_pixel_256(trans) \
+ /* only draw if onscreen, not 0 or 15 */ \
+ if (x >= clipin->min_x && x <= clipin->max_x && \
+ (!do_clipout || x < clipout->min_x || x > clipout->max_x) && \
+ pix != trans) \
+ { \
+ if (!indirect) \
+ { \
+ if (pix != 0) \
+ { \
+ if (!shadow) \
+ dest[x] = color | pix; \
+ else \
+ dest[x] &= 0x7fff; \
+ } \
+ } \
+ else \
+ { \
+ int indpix = (indtable[pix >> 4]) | (pix & 0x0f); \
+ if ((indpix & transmask) != transmask) \
+ { \
+ if (!shadow) \
+ dest[x] = indpix; \
+ else \
+ dest[x] &= 0x7fff; \
+ } \
+ } \
+ }
+
+static int draw_one_sprite(UINT16 *data, int xoffs, int yoffs, const rectangle *clipin, const rectangle *clipout)
+{
+ static const int transparency_masks[4][4] =
+ {
+ { 0x7fff, 0x3fff, 0x1fff, 0x0fff },
+ { 0x3fff, 0x1fff, 0x0fff, 0x07ff },
+ { 0x3fff, 0x1fff, 0x0fff, 0x07ff },
+ { 0x1fff, 0x0fff, 0x07ff, 0x03ff }
+ };
+
+ mame_bitmap *bitmap = layer_data[(!is_multi32 || !(data[3] & 0x0800)) ? MIXER_LAYER_SPRITES_2 : MIXER_LAYER_MULTISPR_2].bitmap;
+ UINT8 numbanks = memory_region_length(REGION_GFX2) / 0x400000;
+ const UINT32 *spritebase = (const UINT32 *)memory_region(REGION_GFX2);
+
+ int indirect = data[0] & 0x2000;
+ int indlocal = data[0] & 0x1000;
+ int shadow = (data[0] & 0x0800) && (sprite_control_latched[0x0a/2] & 1);
+ int fromram = data[0] & 0x0400;
+ int bpp8 = data[0] & 0x0200;
+ int transp = (data[0] & 0x0100) ? 0 : (bpp8 ? 0xff : 0x0f);
+ int flipy = data[0] & 0x0080;
+ int flipx = data[0] & 0x0040;
+ int offsety = data[0] & 0x0020;
+ int offsetx = data[0] & 0x0010;
+ int adjusty = (data[0] >> 2) & 3;
+ int adjustx = (data[0] >> 0) & 3;
+ int srch = (data[1] >> 8);
+ int srcw = bpp8 ? (data[1] & 0x3f) : ((data[1] >> 1) & 0x3f);
+ int bank = is_multi32 ?
+ ((data[3] & 0x2000) >> 13) | ((data[3] & 0x8000) >> 14) :
+ ((data[3] & 0x0800) >> 11) | ((data[3] & 0x4000) >> 13);
+ int dsth = data[2] & 0x3ff;
+ int dstw = data[3] & 0x3ff;
+ int ypos = (INT16)(data[4] << 4) >> 4;
+ int xpos = (INT16)(data[5] << 4) >> 4;
+ UINT32 addr = data[6] | ((data[2] & 0xf000) << 4);
+ int color = 0x8000 | (data[7] & (bpp8 ? 0x7f00 : 0x7ff0));
+ int hzoom, vzoom;
+ int xdelta = 1, ydelta = 1;
+ int x, y, xtarget, ytarget, yacc = 0, pix, transmask;
+ const UINT32 *spritedata;
+ UINT32 addrmask, curaddr;
+ UINT16 indtable[16];
+
+ /* if hidden, or top greater than/equal to bottom, or invalid bank, punt */
+ if (srcw == 0 || srch == 0 || dstw == 0 || dsth == 0)
+ goto bail;
+
+ /* determine the transparency mask for pixels */
+ transmask = transparency_masks[sprite_control_latched[0x08/2] & 3][sprite_control_latched[0x0a/2] & 3];
+ if (bpp8)
+ transmask &= 0xfff0;
+
+ /* create the local palette for the indirect case */
+ if (indirect)
+ {
+ UINT16 *src = indlocal ? &data[8] : &system32_spriteram[8 * (data[7] & 0x1fff)];
+ for (x = 0; x < 16; x++)
+ indtable[x] = (src[x] & (bpp8 ? 0xfff0 : 0xffff)) | ((sprite_control_latched[0x0a/2] & 1) ? 0x8000 : 0x0000);
+ }
+
+ /* clamp to within the memory region size */
+ if (fromram)
+ {
+ spritedata = spriteram_32bit;
+ addrmask = (0x20000 / 4) - 1;
+ }
+ else
+ {
+ if (numbanks)
+ bank %= numbanks;
+ spritedata = spritebase + 0x100000 * bank;
+ addrmask = 0xfffff;
+ }
+
+ /* compute X/Y deltas */
+ hzoom = (((bpp8 ? 4 : 8) * srcw) << 16) / dstw;
+ vzoom = (srch << 16) / dsth;
+
+ /* adjust the starting X position */
+ if (offsetx)
+ xpos += xoffs;
+ switch (adjustx)
+ {
+ case 0:
+ case 3: xpos -= (dstw - 1) / 2; break;
+ case 1: xpos -= dstw - 1; break;
+ case 2: break;
+ }
+
+ /* adjust the starting Y position */
+ if (offsety)
+ ypos += yoffs;
+ switch (adjusty)
+ {
+ case 0:
+ case 3: ypos -= (dsth - 1) / 2; break;
+ case 1: ypos -= dsth - 1; break;
+ case 2: break;
+ }
+
+ /* adjust for flipping */
+ if (flipx)
+ {
+ xpos += dstw - 1;
+ xdelta = -1;
+ }
+ if (flipy)
+ {
+ ypos += dsth - 1;
+ ydelta = -1;
+ }
+
+ /* compute target X,Y positions for loops */
+ xtarget = xpos + xdelta * dstw;
+ ytarget = ypos + ydelta * dsth;
+
+ /* adjust target x for clipping */
+ if (xdelta > 0 && xtarget > clipin->max_x)
+ {
+ xtarget = clipin->max_x + 1;
+ if (xpos >= xtarget)
+ goto bail;
+ }
+ if (xdelta < 0 && xtarget < clipin->min_x)
+ {
+ xtarget = clipin->min_x - 1;
+ if (xpos <= xtarget)
+ goto bail;
+ }
+
+ /* loop from top to bottom */
+ for (y = ypos; y != ytarget; y += ydelta)
+ {
+ /* skip drawing if not within the inclusive cliprect */
+ if (y >= clipin->min_y && y <= clipin->max_y)
+ {
+ int do_clipout = (y >= clipout->min_y && y <= clipout->max_y);
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ int xacc = 0;
+
+ /* 4bpp case */
+ if (!bpp8)
+ {
+ /* start at the word before because we preincrement below */
+ curaddr = addr - 1;
+ for (x = xpos; x != xtarget; )
+ {
+ UINT32 pixels = spritedata[++curaddr & addrmask];
+
+ /* draw four pixels */
+ pix = (pixels >> 28) & 0xf; while (xacc < 0x10000 && x != xtarget) { sprite_draw_pixel_16(transp) x += xdelta; xacc += hzoom; } xacc -= 0x10000;
+ pix = (pixels >> 24) & 0xf; while (xacc < 0x10000 && x != xtarget) { sprite_draw_pixel_16(0); x += xdelta; xacc += hzoom; } xacc -= 0x10000;
+ pix = (pixels >> 20) & 0xf; while (xacc < 0x10000 && x != xtarget) { sprite_draw_pixel_16(0); x += xdelta; xacc += hzoom; } xacc -= 0x10000;
+ pix = (pixels >> 16) & 0xf; while (xacc < 0x10000 && x != xtarget) { sprite_draw_pixel_16(0); x += xdelta; xacc += hzoom; } xacc -= 0x10000;
+ pix = (pixels >> 12) & 0xf; while (xacc < 0x10000 && x != xtarget) { sprite_draw_pixel_16(0); x += xdelta; xacc += hzoom; } xacc -= 0x10000;
+ pix = (pixels >> 8) & 0xf; while (xacc < 0x10000 && x != xtarget) { sprite_draw_pixel_16(0); x += xdelta; xacc += hzoom; } xacc -= 0x10000;
+ pix = (pixels >> 4) & 0xf; while (xacc < 0x10000 && x != xtarget) { sprite_draw_pixel_16(0); x += xdelta; xacc += hzoom; } xacc -= 0x10000;
+ pix = (pixels >> 0) & 0xf; while (xacc < 0x10000 && x != xtarget) { sprite_draw_pixel_16(transp); x += xdelta; xacc += hzoom; } xacc -= 0x10000;
+
+ /* check for end code */
+ if (transp != 0 && pix == 0x0f)
+ break;
+ }
+ }
+
+ /* 8bpp case */
+ else
+ {
+ /* start at the word before because we preincrement below */
+ curaddr = addr - 1;
+ for (x = xpos; x != xtarget; )
+ {
+ UINT32 pixels = spritedata[++curaddr & addrmask];
+
+ /* draw four pixels */
+ pix = (pixels >> 24) & 0xff; while (xacc < 0x10000 && x != xtarget) { sprite_draw_pixel_256(transp); x += xdelta; xacc += hzoom; } xacc -= 0x10000;
+ pix = (pixels >> 16) & 0xff; while (xacc < 0x10000 && x != xtarget) { sprite_draw_pixel_256(0); x += xdelta; xacc += hzoom; } xacc -= 0x10000;
+ pix = (pixels >> 8) & 0xff; while (xacc < 0x10000 && x != xtarget) { sprite_draw_pixel_256(0); x += xdelta; xacc += hzoom; } xacc -= 0x10000;
+ pix = (pixels >> 0) & 0xff; while (xacc < 0x10000 && x != xtarget) { sprite_draw_pixel_256(transp); x += xdelta; xacc += hzoom; } xacc -= 0x10000;
+
+ /* check for end code */
+ if (transp != 0 && pix == 0xff)
+ break;
+ }
+ }
+ }
+
+ /* accumulate zoom factors; if we carry into the high bit, skip an extra row */
+ yacc += vzoom;
+ addr += srcw * (yacc >> 16);
+ yacc &= 0xffff;
+ }
+
+ /* if we had an enabled inline indirect palette, we skip two entries */
+bail:
+ return (indirect && indlocal) ? 2 : 0;
+}
+
+
+
+static void sprite_render_list(void)
+{
+ rectangle outerclip, clipin, clipout;
+ int xoffs = 0, yoffs = 0;
+ int numentries = 0;
+ int spritenum = 0;
+ UINT16 *sprite;
+
+ profiler_mark(PROFILER_USER2);
+
+ logerror("----\n");
+
+ /* compute the outer clip */
+ outerclip.min_x = outerclip.min_y = 0;
+ outerclip.max_x = (sprite_control_latched[0x0c/2] & 1) ? 415 : 319;
+ outerclip.max_y = 223;
+
+ /* initialize the cliprects */
+ clipin = outerclip;
+ clipout.min_x = clipout.min_y = 0;
+ clipout.max_x = clipout.max_y = -1;
+
+ /* now draw */
+ while (numentries++ < 0x20000/16)
+ {
+ /* top two bits are a command */
+ sprite = &system32_spriteram[8 * (spritenum & 0x1fff)];
+ switch (sprite[0] >> 14)
+ {
+ /* command 0 = draw sprite */
+ case 0:
+ spritenum += 1 + draw_one_sprite(sprite, xoffs, yoffs, &clipin, &clipout);
+ break;
+
+ /* command 1 = set clipping */
+ case 1:
+
+ /* set the inclusive cliprect */
+ if (sprite[0] & 0x1000)
+ {
+ clipin.min_y = (INT16)(sprite[0] << 4) >> 4;
+ clipin.max_y = (INT16)(sprite[1] << 4) >> 4;
+ clipin.min_x = (INT16)(sprite[2] << 4) >> 4;
+ clipin.max_x = (INT16)(sprite[3] << 4) >> 4;
+ sect_rect(&clipin, &outerclip);
+ }
+
+ /* set the exclusive cliprect */
+ if (sprite[0] & 0x2000)
+ {
+ clipout.min_y = (INT16)(sprite[4] << 4) >> 4;
+ clipout.max_y = (INT16)(sprite[5] << 4) >> 4;
+ clipout.min_x = (INT16)(sprite[6] << 4) >> 4;
+ clipout.max_x = (INT16)(sprite[7] << 4) >> 4;
+ }
+
+ /* advance to the next entry */
+ spritenum++;
+ break;
+
+ /* command 2 = jump to position, and set X offset */
+ case 2:
+
+ /* set the global offset */
+ if (sprite[0] & 0x2000)
+ {
+ yoffs = (INT16)(sprite[1] << 4) >> 4;
+ xoffs = (INT16)(sprite[2] << 4) >> 4;
+ }
+ spritenum = sprite[0] & 0x1fff;
+ break;
+
+ /* command 3 = done */
+ case 3:
+ numentries = 0x20000/16;
+ break;
+ }
+ }
+
+ profiler_mark(PROFILER_END);
+}
+
+
+
+/*************************************
+ *
+ * Mixer layer render
+ *
+ *************************************/
+
+INLINE UINT8 compute_color_offsets(int which, int layerbit, int layerflag)
+{
+ int mode = ((mixer_control[which][0x3e/2] & 0x8000) >> 14) | (layerbit & 1);
+
+ switch (mode)
+ {
+ case 0:
+ case 3:
+ default:
+ return !layerflag;
+
+ case 1:
+ /* fix me -- these are grayscale modes */
+ return 2;
+
+ case 2:
+ return (!layerflag) ? 2 : 0;
+ }
+}
+
+INLINE UINT16 compute_sprite_blend(UINT8 encoding)
+{
+ int value = encoding & 0xf;
+
+ switch ((encoding >> 4) & 3)
+ {
+ /* blend if priority == value */
+ case 0: return 1 << value;
+
+ /* blend if priority <= value */
+ case 1: return (1 << value) | ((1 << value) - 1);
+
+ /* blend if priority >= value */
+ case 2: return ~((1 << value) - 1) & 0xffff;
+
+ /* blend always */
+ default:
+ case 3: return 0xffff;
+ }
+}
+
+INLINE UINT16 *get_layer_scanline(int layer, int scanline)
+{
+ if (layer_data[layer].transparent[scanline])
+ return (layer == MIXER_LAYER_SPRITES) ? solid_ffff : solid_0000;
+ return BITMAP_ADDR16(layer_data[layer].bitmap, scanline, 0);
+}
+
+static void mix_all_layers(int which, int xoffs, mame_bitmap *bitmap, const rectangle *cliprect, UINT8 enablemask)
+{
+ int blendenable = mixer_control[which][0x4e/2] & 0x0800;
+ int blendfactor = (mixer_control[which][0x4e/2] >> 8) & 7;
+ struct mixer_layer_info
+ {
+ UINT16 palbase; /* palette base from control reg */
+ UINT16 sprblendmask; /* mask of sprite priorities this layer blends with */
+ UINT8 blendmask; /* mask of layers this layer blends with */
+ UINT8 index; /* index of this layer (MIXER_LAYER_XXX) */
+ UINT8 effpri; /* effective priority = (priority << 3) | layer_priority */
+ UINT8 mixshift; /* shift from control reg */
+ UINT8 coloroffs; /* color offset index */
+ } layerorder[16][8], layersort[8];
+ struct layer_info temp_sprite_save = { 0 };
+ UINT8 sprgroup_shift, sprgroup_mask, sprgroup_or;
+ int numlayers, laynum, groupnum;
+ int rgboffs[3][3];
+ int sprpixmask, sprshadowmask;
+ int sprx, spry, sprx_start;
+ int sprdx, sprdy;
+ int sprshadow;
+ int x, y, i;
+
+ /* if we are the second monitor on multi32, swap in the proper sprite bank */
+ if (which == 1)
+ {
+ temp_sprite_save = layer_data[MIXER_LAYER_SPRITES];
+ layer_data[MIXER_LAYER_SPRITES] = layer_data[MIXER_LAYER_MULTISPR];
+ }
+
+ /* extract the RGB offsets */
+ rgboffs[0][0] = (INT8)(mixer_control[which][0x40/2] << 2) >> 2;
+ rgboffs[0][1] = (INT8)(mixer_control[which][0x42/2] << 2) >> 2;
+ rgboffs[0][2] = (INT8)(mixer_control[which][0x44/2] << 2) >> 2;
+ rgboffs[1][0] = (INT8)(mixer_control[which][0x46/2] << 2) >> 2;
+ rgboffs[1][1] = (INT8)(mixer_control[which][0x48/2] << 2) >> 2;
+ rgboffs[1][2] = (INT8)(mixer_control[which][0x4a/2] << 2) >> 2;
+ rgboffs[2][0] = 0;
+ rgboffs[2][1] = 0;
+ rgboffs[2][2] = 0;
+
+ /* determine the sprite grouping parameters first */
+ switch (mixer_control[which][0x4c/2] & 0x0f)
+ {
+ default:
+ case 0x0: sprgroup_shift = 14; sprgroup_mask = 0x00; sprgroup_or = 0x01; break;
+ case 0x1: sprgroup_shift = 14; sprgroup_mask = 0x01; sprgroup_or = 0x02; break;
+ case 0x2: sprgroup_shift = 13; sprgroup_mask = 0x03; sprgroup_or = 0x04; break;
+ case 0x3: sprgroup_shift = 12; sprgroup_mask = 0x07; sprgroup_or = 0x08; break;
+
+ case 0x4: sprgroup_shift = 14; sprgroup_mask = 0x01; sprgroup_or = 0x00; break;
+ case 0x5: sprgroup_shift = 13; sprgroup_mask = 0x03; sprgroup_or = 0x00; break;
+ case 0x6: sprgroup_shift = 12; sprgroup_mask = 0x07; sprgroup_or = 0x00; break;
+ case 0x7: sprgroup_shift = 11; sprgroup_mask = 0x0f; sprgroup_or = 0x00; break;
+
+ case 0x8: sprgroup_shift = 14; sprgroup_mask = 0x01; sprgroup_or = 0x00; break;
+ case 0x9: sprgroup_shift = 13; sprgroup_mask = 0x03; sprgroup_or = 0x00; break;
+ case 0xa: sprgroup_shift = 12; sprgroup_mask = 0x07; sprgroup_or = 0x00; break;
+ case 0xb: sprgroup_shift = 11; sprgroup_mask = 0x0f; sprgroup_or = 0x00; break;
+
+ case 0xc: sprgroup_shift = 13; sprgroup_mask = 0x01; sprgroup_or = 0x00; break;
+ case 0xd: sprgroup_shift = 12; sprgroup_mask = 0x03; sprgroup_or = 0x00; break;
+ case 0xe: sprgroup_shift = 11; sprgroup_mask = 0x07; sprgroup_or = 0x00; break;
+ case 0xf: sprgroup_shift = 10; sprgroup_mask = 0x0f; sprgroup_or = 0x00; break;
+ }
+ sprshadowmask = (mixer_control[which][0x4c/2] & 0x04) ? 0x8000 : 0x0000;
+ sprpixmask = ((1 << sprgroup_shift) - 1) & 0x3fff;
+ sprshadow = 0x7ffe & sprpixmask;
+
+ /* extract info about TEXT, NBG0-3, and BITMAP layers, which all follow the same pattern */
+ numlayers = 0;
+ for (laynum = MIXER_LAYER_TEXT; laynum <= MIXER_LAYER_BITMAP; laynum++)
+ {
+ int priority = mixer_control[which][0x20/2 + laynum] & 0x0f;
+ if ((enablemask & (1 << laynum)) && priority != 0)
+ {
+ layersort[numlayers].index = laynum;
+ layersort[numlayers].effpri = (priority << 3) | (6 - laynum);
+ layersort[numlayers].palbase = (mixer_control[which][0x20/2 + laynum] & 0x00f0) << 6;
+ layersort[numlayers].mixshift = (mixer_control[which][0x20/2 + laynum] >> 8) & 3;
+ layersort[numlayers].blendmask = blendenable ? ((mixer_control[which][0x30/2 + laynum] >> 6) & 0xff) : 0;
+ layersort[numlayers].sprblendmask = compute_sprite_blend(mixer_control[which][0x30/2 + laynum] & 0x3f);
+ layersort[numlayers].coloroffs = compute_color_offsets(which, (mixer_control[which][0x3e/2] >> laynum) & 1, (mixer_control[which][0x30/2 + laynum] >> 14) & 1);
+ numlayers++;
+ }
+ }
+
+ /* extract info about the BACKGROUND layer */
+ layersort[numlayers].index = MIXER_LAYER_BACKGROUND;
+ layersort[numlayers].effpri = (1 << 3) | 0;
+ layersort[numlayers].palbase = (mixer_control[which][0x2c/2] & 0x00f0) << 6;
+ layersort[numlayers].mixshift = (mixer_control[which][0x2c/2] >> 8) & 3;
+ layersort[numlayers].blendmask = 0;
+ layersort[numlayers].sprblendmask = 0;
+ layersort[numlayers].coloroffs = compute_color_offsets(which, (mixer_control[which][0x3e/2] >> 8) & 1, (mixer_control[which][0x3e/2] >> 14) & 1);
+ numlayers++;
+
+ /* now bubble sort the list by effective priority */
+ for (laynum = 0; laynum < numlayers; laynum++)
+ for (i = laynum + 1; i < numlayers; i++)
+ if (layersort[i].effpri > layersort[laynum].effpri)
+ {
+ struct mixer_layer_info temp = layersort[i];
+ layersort[i] = layersort[laynum];
+ layersort[laynum] = temp;
+ }
+
+ /* for each possible sprite group, insert the sprites into the list at the appropriate point */
+ for (groupnum = 0; groupnum <= sprgroup_mask; groupnum++)
+ {
+ int effgroup = sprgroup_or | groupnum;
+ int priority = mixer_control[which][0x00/2 + effgroup] & 0x0f;
+ int effpri = (priority << 3) | 7;
+ int sprindex = numlayers;
+ int dstnum = 0;
+
+ /* make a copy of the sorted list, finding a location for the sprite entry */
+ for (laynum = 0; laynum < numlayers; laynum++)
+ {
+ if (effpri > layersort[laynum].effpri && sprindex == numlayers)
+ sprindex = dstnum++;
+ layerorder[groupnum][dstnum++] = layersort[laynum];
+ }
+
+ /* build the sprite entry */
+ layerorder[groupnum][sprindex].index = MIXER_LAYER_SPRITES;
+ layerorder[groupnum][sprindex].effpri = effpri;
+ if ((mixer_control[which][0x4c/2] & 3) != 3)
+ layerorder[groupnum][sprindex].palbase = (mixer_control[which][0x00/2 + effgroup] & 0x00f0) << 6;
+ else
+ layerorder[groupnum][sprindex].palbase = (mixer_control[which][0x4c/2] & 0x00f0) << 6;
+ layerorder[groupnum][sprindex].mixshift = (mixer_control[which][0x00/2 + effgroup] >> 8) & 3;
+ layerorder[groupnum][sprindex].blendmask = 0;
+ layerorder[groupnum][sprindex].sprblendmask = 0;
+ layerorder[groupnum][sprindex].coloroffs = compute_color_offsets(which, (mixer_control[which][0x3e/2] >> 6) & 1, (mixer_control[which][0x4c/2] >> 15) & 1);
+ }
+/*
+{
+ static const char *layname[] = { "TEXT", "NBG0", "NBG1", "NBG2", "NBG3", "BITM", "SPRI", "LINE" };
+ for (groupnum = 0; groupnum <= sprgroup_mask; groupnum++)
+ {
+ mame_printf_debug("%X: ", groupnum);
+ for (i = 0; i <= numlayers; i++)
+ mame_printf_debug("%s(%02X) ", layname[layerorder[groupnum][i].index], layerorder[groupnum][i].effpri);
+ mame_printf_debug("\n");
+ }
+}*/
+
+ /* based on the sprite controller flip bits, the data is scanned to us in different */
+ /* directions; account for this */
+ if (sprite_control_latched[0x04/2] & 1)
+ {
+ sprx_start = cliprect->max_x;
+ sprdx = -1;
+ }
+ else
+ {
+ sprx_start = cliprect->min_x;
+ sprdx = 1;
+ }
+
+ if (sprite_control_latched[0x04/2] & 2)
+ {
+ spry = cliprect->max_y;
+ sprdy = -1;
+ }
+ else
+ {
+ spry = cliprect->min_y;
+ sprdy = 1;
+ }
+
+ /* loop over rows */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++, spry += sprdy)
+ {
+ UINT32 *dest = BITMAP_ADDR32(bitmap, y, xoffs);
+ UINT16 *layerbase[8];
+
+ /* get the starting address for each layer */
+ layerbase[MIXER_LAYER_TEXT] = get_layer_scanline(MIXER_LAYER_TEXT, y);
+ layerbase[MIXER_LAYER_NBG0] = get_layer_scanline(MIXER_LAYER_NBG0, y);
+ layerbase[MIXER_LAYER_NBG1] = get_layer_scanline(MIXER_LAYER_NBG1, y);
+ layerbase[MIXER_LAYER_NBG2] = get_layer_scanline(MIXER_LAYER_NBG2, y);
+ layerbase[MIXER_LAYER_NBG3] = get_layer_scanline(MIXER_LAYER_NBG3, y);
+ layerbase[MIXER_LAYER_BITMAP] = get_layer_scanline(MIXER_LAYER_BITMAP, y);
+ layerbase[MIXER_LAYER_SPRITES] = get_layer_scanline(MIXER_LAYER_SPRITES, spry);
+ layerbase[MIXER_LAYER_BACKGROUND] = get_layer_scanline(MIXER_LAYER_BACKGROUND, y);
+
+ /* loop over columns */
+ for (x = cliprect->min_x, sprx = sprx_start; x <= cliprect->max_x; x++, sprx += sprdx)
+ {
+ struct mixer_layer_info *first;
+ int *rgbdelta;
+ int firstpix;
+ int sprpix, sprgroup;
+ int r, g, b;
+ int shadow = 0;
+
+ /* first grab the current sprite pixel and determine the group */
+ sprpix = layerbase[MIXER_LAYER_SPRITES][sprx];
+ sprgroup = (sprpix >> sprgroup_shift) & sprgroup_mask;
+
+ /* now scan the layers to find the topmost non-transparent pixel */
+ for (first = &layerorder[sprgroup][0]; ; first++)
+ {
+ laynum = first->index;
+
+ /* non-sprite layers are treated similarly */
+ if (laynum != MIXER_LAYER_SPRITES)
+ {
+ firstpix = layerbase[laynum][x] & 0x1fff;
+ if (firstpix != 0 || laynum == MIXER_LAYER_BACKGROUND)
+ break;
+ }
+
+ /* sprite layers are special */
+ else
+ {
+ firstpix = sprpix;
+ shadow = ~firstpix & sprshadowmask;
+ if ((firstpix & 0x7fff) != 0x7fff)
+ {
+ firstpix &= sprpixmask;
+ if ((firstpix & 0x7ffe) != sprshadow)
+ break;
+ shadow = 1;
+ }
+ }
+ }
+
+ /* adjust the first pixel */
+ firstpix = system32_paletteram[which][(first->palbase + ((firstpix >> first->mixshift) & 0xfff0) + (firstpix & 0x0f)) & 0x3fff];
+
+ /* compute R, G, B */
+ rgbdelta = &rgboffs[first->coloroffs][0];
+ r = ((firstpix >> 0) & 0x1f) + rgbdelta[0];
+ g = ((firstpix >> 5) & 0x1f) + rgbdelta[1];
+ b = ((firstpix >> 10) & 0x1f) + rgbdelta[2];
+
+ /* if there are potential blends, keep looking */
+ if (first->blendmask != 0)
+ {
+ struct mixer_layer_info *second;
+ int secondpix;
+
+ /* now scan the layers to find the topmost non-transparent pixel */
+ for (second = first + 1; ; second++)
+ {
+ laynum = second->index;
+
+ /* non-sprite layers are treated similarly */
+ if (laynum != MIXER_LAYER_SPRITES)
+ {
+ secondpix = layerbase[laynum][x] & 0x1fff;
+ if (secondpix != 0 || laynum == MIXER_LAYER_BACKGROUND)
+ break;
+ }
+
+ /* sprite layers are special */
+ else
+ {
+ secondpix = sprpix;
+ shadow = ~secondpix & sprshadowmask;
+ if ((secondpix & 0x7fff) != 0x7fff)
+ {
+ secondpix &= sprpixmask;
+ if ((secondpix & 0x7ffe) != sprshadow)
+ break;
+ shadow = 1;
+ }
+ }
+ }
+
+ /* are we blending with that layer? */
+ if ((first->blendmask & (1 << laynum)) &&
+ (laynum != MIXER_LAYER_SPRITES || (first->sprblendmask & (1 << sprgroup))))
+ {
+ /* adjust the second pixel */
+ secondpix = system32_paletteram[which][(second->palbase + ((secondpix >> second->mixshift) & 0xfff0) + (secondpix & 0x0f)) & 0x3fff];
+
+ /* compute first RGB */
+ r *= 7 - blendfactor;
+ g *= 7 - blendfactor;
+ b *= 7 - blendfactor;
+
+ /* add in second RGB */
+ rgbdelta = &rgboffs[second->coloroffs][0];
+ r += (((secondpix >> 0) & 0x1f) + rgbdelta[0]) * (blendfactor + 1);
+ g += (((secondpix >> 5) & 0x1f) + rgbdelta[1]) * (blendfactor + 1);
+ b += (((secondpix >> 10) & 0x1f) + rgbdelta[2]) * (blendfactor + 1);
+
+ /* shift off the extra bits */
+ r >>= 3;
+ g >>= 3;
+ b >>= 3;
+ }
+ }
+
+ /* apply shadow/hilight */
+ if (shadow)
+ {
+ r >>= 1;
+ g >>= 1;
+ b >>= 1;
+ }
+
+ /* clamp and combine */
+ if (r > 31)
+ firstpix = 31 << (16+3);
+ else if (r > 0)
+ firstpix = r << (16+3);
+ else
+ firstpix = 0;
+
+ if (g > 31)
+ firstpix |= 31 << (8+3);
+ else if (g > 0)
+ firstpix |= g << (8+3);
+
+ if (b > 31)
+ firstpix |= 31 << (0+3);
+ else if (b > 0)
+ firstpix |= b << (0+3);
+ dest[x] = firstpix;
+ }
+ }
+
+ /* if we are the second monitor on multi32, swap back the sprite layer */
+ if (which == 1)
+ layer_data[MIXER_LAYER_SPRITES] = temp_sprite_save;
+}
+
+
+
+/*************************************
+ *
+ * Master update routine
+ *
+ *************************************/
+
+static void print_mixer_data(int which)
+{
+#if PRINTF_MIXER_DATA
+ static int count = 0;
+ if (++count > 60 * 5)
+ {
+ mame_printf_debug("\n");
+ mame_printf_debug("OP: %04X\n", system32_videoram[0x1ff8e/2]);
+ mame_printf_debug("SC: %04X %04X %04X %04X - %04X %04X %04X %04X\n",
+ sprite_control_latched[0x00],
+ sprite_control_latched[0x01],
+ sprite_control_latched[0x02],
+ sprite_control_latched[0x03],
+ sprite_control_latched[0x04],
+ sprite_control_latched[0x05],
+ sprite_control_latched[0x06],
+ sprite_control_latched[0x07]);
+ mame_printf_debug("00: %04X %04X %04X %04X - %04X %04X %04X %04X - %04X %04X %04X %04X - %04X %04X %04X %04X\n",
+ mixer_control[which][0x00],
+ mixer_control[which][0x01],
+ mixer_control[which][0x02],
+ mixer_control[which][0x03],
+ mixer_control[which][0x04],
+ mixer_control[which][0x05],
+ mixer_control[which][0x06],
+ mixer_control[which][0x07],
+ mixer_control[which][0x08],
+ mixer_control[which][0x09],
+ mixer_control[which][0x0a],
+ mixer_control[which][0x0b],
+ mixer_control[which][0x0c],
+ mixer_control[which][0x0d],
+ mixer_control[which][0x0e],
+ mixer_control[which][0x0f]);
+ mame_printf_debug("20: %04X %04X %04X %04X - %04X %04X %04X %04X - %04X %04X %04X %04X - %04X %04X %04X %04X\n",
+ mixer_control[which][0x10],
+ mixer_control[which][0x11],
+ mixer_control[which][0x12],
+ mixer_control[which][0x13],
+ mixer_control[which][0x14],
+ mixer_control[which][0x15],
+ mixer_control[which][0x16],
+ mixer_control[which][0x17],
+ mixer_control[which][0x18],
+ mixer_control[which][0x19],
+ mixer_control[which][0x1a],
+ mixer_control[which][0x1b],
+ mixer_control[which][0x1c],
+ mixer_control[which][0x1d],
+ mixer_control[which][0x1e],
+ mixer_control[which][0x1f]);
+ mame_printf_debug("40: %04X %04X %04X %04X - %04X %04X %04X %04X - %04X %04X %04X %04X - %04X %04X %04X %04X\n",
+ mixer_control[which][0x20],
+ mixer_control[which][0x21],
+ mixer_control[which][0x22],
+ mixer_control[which][0x23],
+ mixer_control[which][0x24],
+ mixer_control[which][0x25],
+ mixer_control[which][0x26],
+ mixer_control[which][0x27],
+ mixer_control[which][0x28],
+ mixer_control[which][0x29],
+ mixer_control[which][0x2a],
+ mixer_control[which][0x2b],
+ mixer_control[which][0x2c],
+ mixer_control[which][0x2d],
+ mixer_control[which][0x2e],
+ mixer_control[which][0x2f]);
+ count = 0;
+ }
+#endif
+}
+
+VIDEO_UPDATE( system32 )
+{
+ UINT8 enablemask;
+
+ /* update the visible area */
+ if (system32_videoram[0x1ff00/2] & 0x8000)
+ video_screen_set_visarea(screen, 0, 52*8-1, 0, 28*8-1);
+ else
+ video_screen_set_visarea(screen, 0, 40*8-1, 0, 28*8-1);
+
+ /* if the display is off, punt */
+ if (!system32_displayenable[screen])
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* update the tilemaps */
+ profiler_mark(PROFILER_USER1);
+ enablemask = update_tilemaps(machine, screen, cliprect);
+ profiler_mark(PROFILER_END);
+
+ /* debugging */
+#if QWERTY_LAYER_ENABLE
+ if (input_code_pressed(KEYCODE_Q)) enablemask = 0x01;
+ if (input_code_pressed(KEYCODE_W)) enablemask = 0x02;
+ if (input_code_pressed(KEYCODE_E)) enablemask = 0x04;
+ if (input_code_pressed(KEYCODE_R)) enablemask = 0x08;
+ if (input_code_pressed(KEYCODE_T)) enablemask = 0x10;
+ if (input_code_pressed(KEYCODE_Y)) enablemask = 0x20;
+#endif
+
+ /* do the mixing */
+ profiler_mark(PROFILER_USER3);
+ mix_all_layers(0, 0, bitmap, cliprect, enablemask);
+ profiler_mark(PROFILER_END);
+
+#if LOG_SPRITES
+{
+ if (input_code_pressed(KEYCODE_L))
+ {
+ FILE *f = fopen("sprite.txt", "w");
+ int x, y;
+
+ for (y = machine->screen[screen].visarea.min_y; y <= machine->screen[screen].visarea.max_y; y++)
+ {
+ UINT16 *src = get_layer_scanline(MIXER_LAYER_SPRITES, y);
+ for (x = machine->screen[screen].visarea.min_x; x <= machine->screen[screen].visarea.max_x; x++)
+ fprintf(f, "%04X ", *src++);
+ fprintf(f, "\n");
+ }
+ fclose(f);
+
+ f = fopen("nbg0.txt", "w");
+ for (y = machine->screen[screen].visarea.min_y; y <= machine->screen[screen].visarea.max_y; y++)
+ {
+ UINT16 *src = get_layer_scanline(MIXER_LAYER_NBG0, y);
+ for (x = machine->screen[screen].visarea.min_x; x <= machine->screen[screen].visarea.max_x; x++)
+ fprintf(f, "%04X ", *src++);
+ fprintf(f, "\n");
+ }
+ fclose(f);
+
+ f = fopen("nbg1.txt", "w");
+ for (y = machine->screen[screen].visarea.min_y; y <= machine->screen[screen].visarea.max_y; y++)
+ {
+ UINT16 *src = get_layer_scanline(MIXER_LAYER_NBG1, y);
+ for (x = machine->screen[screen].visarea.min_x; x <= machine->screen[screen].visarea.max_x; x++)
+ fprintf(f, "%04X ", *src++);
+ fprintf(f, "\n");
+ }
+ fclose(f);
+
+ f = fopen("nbg2.txt", "w");
+ for (y = machine->screen[screen].visarea.min_y; y <= machine->screen[screen].visarea.max_y; y++)
+ {
+ UINT16 *src = get_layer_scanline(MIXER_LAYER_NBG2, y);
+ for (x = machine->screen[screen].visarea.min_x; x <= machine->screen[screen].visarea.max_x; x++)
+ fprintf(f, "%04X ", *src++);
+ fprintf(f, "\n");
+ }
+ fclose(f);
+
+ f = fopen("nbg3.txt", "w");
+ for (y = machine->screen[screen].visarea.min_y; y <= machine->screen[screen].visarea.max_y; y++)
+ {
+ UINT16 *src = get_layer_scanline(MIXER_LAYER_NBG3, y);
+ for (x = machine->screen[screen].visarea.min_x; x <= machine->screen[screen].visarea.max_x; x++)
+ fprintf(f, "%04X ", *src++);
+ fprintf(f, "\n");
+ }
+ fclose(f);
+ }
+}
+#endif
+
+#if SHOW_ALPHA
+{
+ static const char *layername[] = { "TEXT ", "NBG0 ", "NBG1 ", "NBG2 ", "NBG3 ", "BITMAP " };
+ char temp[100];
+ int count = 0, i;
+ sprintf(temp, "ALPHA(%d):", (mixer_control[which][0x4e/2] >> 8) & 7);
+ for (i = 0; i < 6; i++)
+ if (enablemask & (1 << i))
+ if ((mixer_control[which][0x30/2 + i] & 0x1010) == 0x1010)
+ {
+ count++;
+ strcat(temp, layername[i]);
+ }
+ if (count)
+ popmessage("%s", temp);
+}
+#endif
+
+#if SHOW_CLIPS
+{
+ int showclip = -1;
+
+// if (input_code_pressed(KEYCODE_V))
+// showclip = 0;
+// if (input_code_pressed(KEYCODE_B))
+// showclip = 1;
+// if (input_code_pressed(KEYCODE_N))
+// showclip = 2;
+// if (input_code_pressed(KEYCODE_M))
+// showclip = 3;
+// if (showclip != -1)
+for (showclip = 0; showclip < 4; showclip++)
+ {
+ int flip = (system32_videoram[0x1ff00/2] >> 9) & 1;
+ int clips = (system32_videoram[0x1ff06/2] >> (4 * showclip)) & 0x0f;
+ if (((system32_videoram[0x1ff02/2] >> (11 + showclip)) & 1) && clips)
+ {
+ int i, x, y;
+ for (i = 0; i < 4; i++)
+ if (clips & (1 << i))
+ {
+ rectangle rect;
+ pen_t white = get_white_pen(machine);
+ if (!flip)
+ {
+ rect.min_x = system32_videoram[0x1ff60/2 + i * 4] & 0x1ff;
+ rect.min_y = system32_videoram[0x1ff62/2 + i * 4] & 0x0ff;
+ rect.max_x = (system32_videoram[0x1ff64/2 + i * 4] & 0x1ff) + 1;
+ rect.max_y = (system32_videoram[0x1ff66/2 + i * 4] & 0x0ff) + 1;
+ }
+ else
+ {
+ rect.max_x = (machine->screen[screen].visarea.max_x + 1) - (system32_videoram[0x1ff60/2 + i * 4] & 0x1ff);
+ rect.max_y = (machine->screen[screen].visarea.max_y + 1) - (system32_videoram[0x1ff62/2 + i * 4] & 0x0ff);
+ rect.min_x = (machine->screen[screen].visarea.max_x + 1) - ((system32_videoram[0x1ff64/2 + i * 4] & 0x1ff) + 1);
+ rect.min_y = (machine->screen[screen].visarea.max_y + 1) - ((system32_videoram[0x1ff66/2 + i * 4] & 0x0ff) + 1);
+ }
+ sect_rect(&rect, &machine->screen[screen].visarea);
+
+ if (rect.min_y <= rect.max_y && rect.min_x <= rect.max_x)
+ {
+ for (y = rect.min_y; y <= rect.max_y; y++)
+ {
+ bitmap->plot(bitmap, rect.min_x, y, white);
+ bitmap->plot(bitmap, rect.max_x, y, white);
+ }
+ for (x = rect.min_x; x <= rect.max_x; x++)
+ {
+ bitmap->plot(bitmap, x, rect.min_y, white);
+ bitmap->plot(bitmap, x, rect.max_y, white);
+ }
+ }
+ }
+ }
+ }
+}
+#endif
+
+ print_mixer_data(0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( multi32 )
+{
+ UINT8 enablemask;
+
+ /* update the visible area */
+ if (system32_videoram[0x1ff00/2] & 0x8000)
+ video_screen_set_visarea(screen, 0, 52*8-1, 0, 28*8-1);
+ else
+ video_screen_set_visarea(screen, 0, 40*8-1, 0, 28*8-1);
+
+ /* if the display is off, punt */
+ if (!system32_displayenable[screen])
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* update the tilemaps */
+ profiler_mark(PROFILER_USER1);
+ enablemask = update_tilemaps(machine, screen, cliprect);
+ profiler_mark(PROFILER_END);
+
+ /* debugging */
+#if QWERTY_LAYER_ENABLE
+ if (input_code_pressed(KEYCODE_Q)) enablemask = 0x01;
+ if (input_code_pressed(KEYCODE_W)) enablemask = 0x02;
+ if (input_code_pressed(KEYCODE_E)) enablemask = 0x04;
+ if (input_code_pressed(KEYCODE_R)) enablemask = 0x08;
+ if (input_code_pressed(KEYCODE_T)) enablemask = 0x10;
+ if (input_code_pressed(KEYCODE_Y)) enablemask = 0x20;
+#endif
+
+ /* do the mixing */
+ profiler_mark(PROFILER_USER3);
+ mix_all_layers(screen, 0, bitmap, cliprect, enablemask);
+ profiler_mark(PROFILER_END);
+
+ if (!input_code_pressed(KEYCODE_M)) print_mixer_data(0);
+ else print_mixer_data(1);
+#if LOG_SPRITES
+{
+ if (input_code_pressed(KEYCODE_L))
+ {
+ FILE *f = fopen("sprite.txt", "w");
+ int x, y;
+
+ for (y = machine->screen[screen].visarea.min_y; y <= machine->screen[screen].visarea.max_y; y++)
+ {
+ UINT16 *src = get_layer_scanline(MIXER_LAYER_SPRITES, y);
+ for (x = machine->screen[screen].visarea.min_x; x <= machine->screen[screen].visarea.max_x; x++)
+ fprintf(f, "%04X ", *src++);
+ fprintf(f, "\n");
+ }
+ fclose(f);
+ }
+}
+#endif
+
+ return 0;
+}
+
+
+/*
+
+Blending registers:
+
+?--- ---- ---- ---- Unknown
+-c-- ---- ---- ---- Color selection
+--l- ---- ---- ---- 1= blend with line color
+---s ---- ---- ---- 1= blend with sprites, under certain conditions
+---- b--- ---- ---- 1= blend with bitmap
+---- -3-- ---- ---- 1= blend with NBG3
+---- --2- ---- ---- 1= blend with NBG2
+---- ---1 ---- ---- 1= blend with NBG1
+---- ---- 0--- ---- 1= blend with NBG0
+---- ---- -t-- ---- 1= blend with text
+---- ---- --mm ---- sprite priority comparison (see below)
+---- ---- ---- vvvv sprite priority comparison value
+
+If sprite blending is enabled, blending is only performed if the
+underlying sprite pixel's group priority matches certain criteria.
+These criteria are specified in the low 6 bits of the register.
+If SPGP refers to the sprite pixel group prioity, then:
+
+ if (mm == 00) blending is performed only if (vvvv == SPGP)
+ if (mm == 01) blending is performed only if (vvvv >= SPGP)
+ if (mm == 10) blending is performed only if (vvvv <= SPGP)
+ if (mm == 11) blending is performed regardless of SPGP
+
+
+
+ equal priority order =
+
+ sprite
+ text
+ nbg0
+ nbg1
+ nbg2
+ nbg3
+ bitmap
+ line
+
+
+
+arescue:
+SC: 0003 0000 0000 0002 - 0002 0003 0000 0000
+00: 0011 0014 0018 001F - 0014 0015 0016 0017 - 0018 0019 001A 001B - 001C 001D 001E 001F
+20: 000E 0141 0142 014E - 0146 000F 0000 0000 - 4000 4000 5008 5008 - 4000 4000 4000 4000
+40: 0040 0040 0040 0000 - 0000 0000 BE4D 0C00 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+alien3:
+SC: 0000 0000 0000 0000 - 0001 0003 0000 0000
+00: 0011 0017 001B 001F - 0014 0015 0016 0017 - 0018 0019 001A 001B - 001C 001D 001E 001F
+20: 000E 014C 014A 0147 - 0144 000B 0000 0000 - 0000 0000 1008 103C - 0000 4000 0000 0000
+40: FFEB FFEB FFEB 0000 - 0000 0000 BE4D 0C00 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+arabfgt:
+SC: 0000 0000 0000 0000 - 0000 0000 0000 0000
+00: 000E 000A 0008 0006 - 0000 0000 0000 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+20: 007F 036D 036F 0366 - 0367 004F 0051 0050 - 0000 4000 57B0 4000 - 4000 0000 0000 4000
+40: 0000 0000 0000 0000 - 0000 0000 8049 0F00 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+brival:
+SC: 0000 0000 0000 0000 - 0000 0000 0001 0000
+00: 000E 000A 0008 0006 - 0000 0000 0000 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+20: 007F 036D 036F 036C - 0367 004F 0051 0050 - 0000 4000 7FF0 4000 - 4000 0000 0000 4000
+40: 0000 0000 0000 0000 - 0000 0000 8049 0B00 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+darkedge:
+SC: 0000 0000 0000 0000 - 0001 0003 0000 0000
+00: 000E 000C 0008 000E - 0000 0000 0000 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+20: 007F 025D 025B 0259 - 0257 007E 0071 0070 - 4000 0000 0000 0000 - 0000 0000 0000 0000
+40: 0020 0020 0020 0020 - 0020 0020 3E4D 0C00 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+dbzvrvs:
+SC: 0000 0000 0000 0000 - 0001 0000 0000 0000
+00: 000D 000B 0009 000F - 0000 0000 0000 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+20: 007E 036C 036C 036A - 036A 007C 0073 0072 - 4000 0000 0000 0000 - 0000 0000 0000 0000
+40: 0000 0000 0000 0000 - 0000 0000 3E01 0300 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+f1en:
+SC: 0000 0000 0000 0000 - 0000 0000 0000 0000
+00: 000E 000A 0008 0006 - 0000 0000 0000 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+20: 007F 0361 0361 0361 - 036F 0041 0051 0050 - 4000 4000 4300 571B - 5216 0000 0000 0000
+40: 0000 0000 0000 0000 - 0000 0000 3E49 0021 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+ga2j: - 8 priorities + shadow
+SC: 0000 0000 0000 0000 - 0002 0003 0000 0000
+00: 000F 000D 000B 0009 - 0007 0007 0005 0003 - 000F 000D 000B 0009 - 0007 0007 0005 0003
+20: 003E 014E 0142 014C - 0148 003E 0030 0030 - 4000 5119 4099 4000 - 4000 4000 4000 C000
+40: 0000 0000 0000 0000 - 0000 0000 924E 0B00 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+harddunk:
+SC: 0003 0000 0000 0000 - 0001 0001 0000 0000
+00: 000A 0006 000E 000A - 0000 0000 0000 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+20: 007F 036D 0000 036C - 0000 0074 0072 0070 - 0000 4000 4000 4000 - 4000 0000 0000 4000
+40: 0000 0000 0000 0000 - 0000 0000 9E05 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+holo:
+SC: 0003 0000 0000 0000 - 0002 0003 0000 0000
+00: 0011 0014 0018 001F - 0014 0015 0016 0017 - 0018 0019 001A 001B - 001C 001D 001E 001F
+20: 000F 0146 0143 014E - 014E 000E 0000 0000 - 4000 4000 5008 5008 - 4000 4000 4000 C000
+40: FF00 FF00 FF00 0000 - 0000 0000 BE4D 0C00 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+jpark:
+SC: 0000 0000 0000 0000 - 0000 0003 0000 0000
+00: 000A 000D 0007 0006 - 0000 0000 0000 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+20: 007F 0368 036B 036E - 0369 007F 0077 0076 - 0000 4100 4200 15B0 - 0100 0000 0000 8010
+40: 0000 0000 0000 0000 - 0000 0000 9E4C 0B00 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+orunners:
+SC: 0003 0000 0000 0000 - 0001 0003 0000 0000
+00: 000E 000A 0006 0002 - 000E 000A 0006 0002 - 000E 000A 0006 0002 - 000E 000A 0006 0002
+20: 003C 0141 0000 0142 - 0000 0038 0030 0030 - 5030 4000 4000 4000 - 4000 4000 4000 C000
+40: 0000 0000 0000 0000 - 0000 0000 BE4D 0A00 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+radm: - 8 priorities + shadow
+SC: 0000 0000 0000 0000 - 0001 0002 0000 0000
+00: 000E 000E 000A 0008 - 0006 0004 0002 0000 - 000E 000C 000A 0008 - 0006 0004 0002 0000
+20: 007F 0367 0369 036B - 036D 0071 0071 0070 - 4000 100E 100E 100E - 100E 0000 0000 0000
+40: 0000 0000 0000 0000 - 0000 0000 3E49 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+radr: - 4 priorities
+SC: 0000 0000 0000 0000 - 0001 0002 0000 0000
+00: 000E 000A 0008 0006 - 0000 0000 0000 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+20: 007F 036E 036C 036D - 0367 0078 0071 0070 - 4000 4000 4300 571B - 5216 0000 0000 0000
+40: 0000 0000 0000 0000 - 0000 0000 3E49 0B00 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+scross:
+SC: 0003 0000 0000 0002 - 0001 0001 0000 0000
+00: 001B 0017 001D 001F - 0010 0010 0010 0010 - 0010 0010 0010 0010 - 0010 0010 0010 0010
+20: 000E 015A 0000 0156 - 0000 0000 0000 0000 - 4000 4000 4000 4000 - 4000 4000 4000 C000
+40: 0000 0000 0000 0000 - 0000 0000 BE1D 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+slipstrm:
+SC: 0003 0000 00FC 0002 - 0001 0003 0001 0000
+00: 004D 004D 004D 004A - 0000 0000 0000 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+20: 007F 0108 010E 010B - 0109 0000 0000 0000 - 4030 4030 4030 7C90 - 4030 4000 0000 C040
+40: 0000 0000 0000 001F - 001F 001F 7F0D 0C00 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+sonic: - 4 priorities
+SC: 0000 0000 0000 0000 - 0001 0002 0000 0000
+00: 003E 003B 003C 0036 - 0030 0030 0030 0030 - 0030 0030 0030 0030 - 0030 0030 0030 0030
+20: 002F 020E 020B 0208 - 0207 0021 0021 0020 - 0000 400B 4300 471B - 4216 0000 0000 0000
+40: 0000 0000 0000 0000 - 0000 0000 3E49 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+spidman: - 8 priorities + shadow
+SC: 0000 0000 0000 0000 - 0002 0003 0000 0000
+00: 000E 000C 000A 0008 - 0006 0004 0002 0000 - 000E 000C 000A 0008 - 0006 0004 0002 0000
+20: 003F 0149 0149 014C - 0140 003E 0030 0030 - 4000 4000 4000 4000 - 4000 4000 4000 C000
+40: 0000 0000 0000 0000 - 0000 0000 BE4E 0F00 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+svf: - 4 priorities
+SC: 0003 0000 0000 0002 - 0002 0003 0000 0000
+00: 0014 0012 0018 001E - 0014 0015 0016 0017 - 0018 0019 001A 001B - 001C 001D 001E 001E
+20: 000F 0143 0141 0142 - 0142 000E 0000 0000 - 4000 4000 5008 5008 - 5008 4000 4000 C001
+40: 00FF 00FF 00FF 0000 - 0000 0000 BE4D 0900 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+titlef:
+SC: 0003 0000 0000 0000 - 0001 0001 0000 0000
+00: 000E 0002 0005 000F - 0000 0000 0000 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+20: 007F 0366 0000 0364 - 0000 0070 0071 0070 - 0000 4000 4000 4000 - 4000 0000 0000 4000
+40: 0000 0000 0000 0000 - 0000 0000 9E05 0000 - 0000 0000 0000 0000 - 0000 0000 0000 0000
+
+*/
diff --git a/src/mame/video/segasyse.c b/src/mame/video/segasyse.c
new file mode 100644
index 00000000000..023a885ed54
--- /dev/null
+++ b/src/mame/video/segasyse.c
@@ -0,0 +1,563 @@
+/*******************************************************************************
+ Sega System E (834-5803) Driver (video/segasyse.c)
+********************************************************************************
+ driver by David Haywood
+
+ this is currently only used by megaplay, and will soon be obsolete.
+
+*******************************************************************************/
+
+#include "driver.h"
+
+/*-- Variables --*/
+
+#define CHIPS 2 /* There are 2 VDP Chips */
+
+static UINT8 vdp_cmdpart[CHIPS]; /* VDP Command Part Counter */
+static UINT16 vdp_command[CHIPS]; /* VDP Command Word */
+
+static UINT8 vdp_accessmode[CHIPS]; /* VDP Access Mode (VRAM, CRAM) */
+static UINT16 vdp_accessaddr[CHIPS]; /* VDP Access Address */
+static UINT8 vdp_readbuffer[CHIPS]; /* VDP Read Buffer */
+
+static UINT8 *segae_vdp_vram[CHIPS]; /* Pointer to VRAM */
+static UINT8 *vdp_cram[CHIPS]; /* Pointer to the VDP's CRAM */
+UINT8 *segae_vdp_regs[CHIPS]; /* Pointer to the VDP's Registers */
+
+static UINT8 segae_vdp_vrambank[CHIPS]; /* Current VRAM Bank number (from writes to Port 0xf7) */
+
+static UINT8 *cache_bitmap; /* 8bpp bitmap with raw pen values */
+
+static int palette_base; // needed for megatech for now..
+
+UINT8 segae_vintpending;
+UINT8 segae_hintpending;
+
+/*-- Prototypes --*/
+
+static void vdp_start(running_machine *machine, UINT8 chip );
+
+static void vdp_processcmd(UINT8 chip, UINT16 cmd);
+static void vdp_setregister(UINT8 chip, UINT16 cmd);
+
+static void draw_tiles_line(UINT8 *dest, int line, UINT8 chip, UINT8 pri);
+static void draw_sprite_line(UINT8 *dest, UINT8 chip, UINT8 line);
+static void segae_drawscanline(int line, int chips, int blank);
+
+static void draw_8pix_solid16(UINT8 *dest, UINT8 chip, UINT16 tile, UINT8 line, UINT8 flipx, UINT8 col);
+static void draw_8pix(UINT8 *dest, UINT8 chip, UINT16 tile, UINT8 line, UINT8 flipx, UINT8 col);
+static void draw_8pix_sprite(UINT8 *dest, UINT8 chip, UINT16 tile, UINT8 line);
+
+/*******************************************************************************
+ vhstart, vhstop and vhrefresh functions
+*******************************************************************************/
+
+/* starts vdp for bios screen only */
+void megaplay_start_video_normal(running_machine *machine)
+{
+ palette_base = 0x40;
+
+ vdp_start(machine, 0);
+
+ cache_bitmap = auto_malloc( (16+256+16) * 192); /* 16 pixels either side to simplify drawing */
+}
+
+void megaplay_update_video_normal(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int miny = (cliprect->min_y < 16) ? 16 : cliprect->min_y;
+ int maxy = (cliprect->max_y > 16+192-1) ? 16+192-1 : cliprect->max_y;
+ int i;
+
+ /*- Draw from cache_bitmap to screen -*/
+
+ for (i = miny; i <= maxy;i++)
+ segae_drawscanline(i-16,0,0);
+
+ for (i = miny;i <= maxy;i++)
+ draw_scanline8(bitmap,32,i,256,&cache_bitmap[(i-16) * (16+256+16) +24],&machine->pens[palette_base],0);
+
+}
+
+/*******************************************************************************
+ VDP Start / Stop Functions
+********************************************************************************
+ note: we really should check after each allocation to make sure it was
+ successful then if one allocation fails we can free up the previous ones
+*******************************************************************************/
+
+static void vdp_start(running_machine *machine, UINT8 chip)
+{
+ UINT8 temp;
+
+ /*- VRAM -*/
+
+ segae_vdp_vram[chip] = auto_malloc(0x8000); /* 32kb (2 banks) */
+ segae_vdp_vrambank[chip] = 0;
+
+ /*- CRAM -*/
+
+ vdp_cram[chip] = auto_malloc(0x20);
+
+ /*- VDP Registers -*/
+
+ segae_vdp_regs[chip] = auto_malloc(0x20);
+
+ /*- Clear Memory -*/
+
+ memset(segae_vdp_vram[chip], 0, 0x8000);
+ memset(vdp_cram[chip], 0, 0x20);
+ memset(segae_vdp_regs[chip], 0, 0x20);
+
+ /*- Set Up Some Default Values */
+
+ vdp_accessaddr[chip] = 0;
+ vdp_accessmode[chip] = 0;
+ vdp_cmdpart[chip] = 0;
+ vdp_command[chip] = 0;
+
+ /*- Black the Palette -*/
+
+ for (temp=0;temp<32;temp++)
+ palette_set_color(machine, temp + 32*chip+palette_base, MAKE_RGB(0, 0, 0));
+
+ /* Save State Stuff (based on video/taitoic.c) */
+
+ state_save_register_item_pointer("VDP", chip, segae_vdp_vram[chip], 0x8000);
+ state_save_register_item_pointer("VDP", chip, vdp_cram[chip], 0x20);
+ state_save_register_item_pointer("VDP", chip, segae_vdp_regs[chip], 0x20);
+ state_save_register_item("VDP", chip, vdp_cmdpart[chip]);
+ state_save_register_item("VDP", chip, vdp_command[chip]);
+ state_save_register_item("VDP", chip, vdp_accessmode[chip]);
+ state_save_register_item("VDP", chip, vdp_accessaddr[chip]);
+ state_save_register_item("VDP", chip, segae_vdp_vrambank[chip]);
+}
+
+/*******************************************************************************
+ Core VDP Functions
+*******************************************************************************/
+
+/*-- Reads --*/
+
+/***************************************
+ segae_vdp_ctrl_r ( UINT8 chip )
+****************************************
+ reading the vdp control port will
+ return the following
+
+ bit:
+ 7 - vert int pending
+ 6 - line int pending
+ 5 - sprite collision (non 0 pixels) *not currently emulated (not needed by these games)*
+ 4 - always 0
+ 3 - always 0
+ 2 - always 0
+ 1 - always 0
+ 0 - always 0
+
+ bits 5,6,7 are cleared after a read
+***************************************/
+
+UINT8 segae_vdp_ctrl_r ( UINT8 chip )
+{
+ UINT8 temp;
+
+ temp = 0;
+
+ temp |= (segae_vintpending << 7);
+ temp |= (segae_hintpending << 6);
+
+ segae_hintpending = segae_vintpending = 0;
+
+ return temp;
+}
+
+UINT8 segae_vdp_data_r ( UINT8 chip )
+{
+ UINT8 temp;
+
+ vdp_cmdpart[chip] = 0;
+
+ temp = vdp_readbuffer[chip];
+
+ if (vdp_accessmode[chip]==0x03) { /* CRAM Access */
+ /* error CRAM can't be read!! */
+ } else { /* VRAM */
+ vdp_readbuffer[chip] = segae_vdp_vram[chip][ segae_vdp_vrambank[chip]*0x4000 + vdp_accessaddr[chip] ];
+ vdp_accessaddr[chip] += 1;
+ vdp_accessaddr[chip] &= 0x3fff;
+ }
+ return temp;
+}
+
+/*-- Writes --*/
+
+void segae_vdp_ctrl_w ( UINT8 chip, UINT8 data )
+{
+ if (!vdp_cmdpart[chip]) {
+ vdp_cmdpart[chip] = 1;
+ vdp_command[chip] = data;
+ } else {
+ vdp_cmdpart[chip] = 0;
+ vdp_command[chip] |= (data << 8);
+ vdp_processcmd (chip, vdp_command[chip]);
+ }
+}
+
+void segae_vdp_data_w ( UINT8 chip, UINT8 data )
+{
+ vdp_cmdpart[chip] = 0;
+
+ if (vdp_accessmode[chip]==0x03) { /* CRAM Access */
+ UINT8 r,g,b, temp;
+
+ temp = vdp_cram[chip][vdp_accessaddr[chip]];
+
+ vdp_cram[chip][vdp_accessaddr[chip]] = data;
+
+ if (temp != data) {
+ r = (vdp_cram[chip][vdp_accessaddr[chip]] & 0x03) >> 0;
+ g = (vdp_cram[chip][vdp_accessaddr[chip]] & 0x0c) >> 2;
+ b = (vdp_cram[chip][vdp_accessaddr[chip]] & 0x30) >> 4;
+
+ palette_set_color_rgb(Machine, vdp_accessaddr[chip] + 32*chip+palette_base, pal2bit(r), pal2bit(g), pal2bit(b));
+ }
+
+ vdp_accessaddr[chip] += 1;
+ vdp_accessaddr[chip] &= 0x1f;
+ } else { /* VRAM Accesses */
+ segae_vdp_vram[chip][ segae_vdp_vrambank[chip]*0x4000 + vdp_accessaddr[chip] ] = data;
+ vdp_accessaddr[chip] += 1;
+ vdp_accessaddr[chip] &= 0x3fff;
+ }
+}
+
+/*-- Associated Functions --*/
+
+/***************************************
+ vdp_processcmd
+****************************************
+
+general command format
+
+ M M A A A A A A A A A A A A A A M=Mode, A=Address
+
+ the command will be one of 3 things according to the upper
+ 4 bits
+
+ 0 0 - - - - - - - - - - - - - - VRAM Acess Mode (Special Read)
+
+ 0 1 - - - - - - - - - - - - - - VRAM Acesss Mode
+
+ 1 0 0 0 - - - - - - - - - - - - VDP Register Set (current mode & address _not_ changed)
+
+ 1 0 x x - - - - - - - - - - - - VRAM Access Mode (0x1000 - 0x3FFF only, x x is anything but 0 0)
+
+ 1 1 - - - - - - - - - - - - - - CRAM Access Mode
+
+***************************************/
+
+static void vdp_processcmd (UINT8 chip, UINT16 cmd)
+{
+ if ( (cmd & 0xf000) == 0x8000 ) { /* 1 0 0 0 - - - - - - - - - - - - VDP Register Set */
+ vdp_setregister (chip, cmd);
+ } else { /* Anything Else */
+ vdp_accessmode[chip] = (cmd & 0xc000) >> 14;
+ vdp_accessaddr[chip] = (cmd & 0x3fff);
+
+ if ((vdp_accessmode[chip]==0x03) && (vdp_accessaddr[chip] > 0x1f) ) { /* Check Address is valid for CRAM */
+ /* Illegal, CRAM isn't this large! */
+ vdp_accessaddr[chip] &= 0x1f;
+ }
+
+ if (vdp_accessmode[chip] == 0x00) { /* 0 0 - - - - - - - - - - - - - - VRAM Acess Mode (Special Read) */
+ vdp_readbuffer[chip] = segae_vdp_vram[chip][ segae_vdp_vrambank[chip]*0x4000 + vdp_accessaddr[chip] ];
+ vdp_accessaddr[chip] += 1;
+ vdp_accessaddr[chip] &= 0x3fff;
+ }
+ }
+}
+
+/***************************************
+ vdp_setregister
+
+ general command format
+
+ 1 0 0 0 R R R R D D D D D D D D 1/0 = Fixed Values, R = Register # / Address, D = Data
+
+***************************************/
+
+static void vdp_setregister(UINT8 chip, UINT16 cmd)
+{
+ UINT8 regnumber;
+ UINT8 regdata;
+
+ regnumber = (cmd & 0x0f00) >> 8;
+ regdata = (cmd & 0x00ff);
+
+ if (regnumber < 11) {
+ segae_vdp_regs[chip][regnumber] = regdata;
+ } else {
+ /* Illegal, there aren't this many registers! */
+ }
+}
+
+/*******************************************************************************
+ System E Drawing Capabilities Notes
+********************************************************************************
+ Display Consists of
+
+ VDP0 Backdrop Color (?)
+ VDP0 Tiles (Low)
+ VDP0 Sprites
+ VDP0 Tiles (High)
+ VDP1 Tiles (Low)
+ VDP1 Sprites
+ VDP1 Tiles (High)
+
+ each vdp has its on vram, etc etc.
+
+ the tilemaps are 256x224 in size, 256x192 of this is visible, the tiles
+ are 8x8 pixels, so 32x28 of 8x8 tiles make a 256x224 tilemap.
+
+ the tiles are 4bpp (16 colours), video ram can hold upto 512 tile gfx
+
+ tile references are 16 bits (3 bits unused, 1 bit priority, 1 bit palette,
+ 2 bits for flip, 9 bits for tile number)
+
+ tilemaps can be scrolled horizontally, the top 16 lines of the display can
+ have horinzontal scrolling disabled
+
+ tilemaps can be scrolled vertically, the right 64 lines of the display can
+ have the vertical scrolling disabled
+
+ the leftmost 8 line of the display can be blanked
+
+*******************************************************************************/
+
+void segae_drawscanline(int line, int chips, int blank)
+{
+
+ UINT8* dest;
+
+ if (video_skip_this_frame())
+ return;
+
+ dest = cache_bitmap + (16+256+16) * line;
+
+ /* This should be cleared to bg colour, but which vdp determines that !, neither seems to be right, maybe its always the same col? */
+ memset(dest, 0, 16+256+16);
+
+ if (segae_vdp_regs[0][1] & 0x40) {
+ draw_tiles_line (dest+16, line, 0,0);
+ draw_sprite_line(dest+16, 0, line);
+ draw_tiles_line (dest+16, line, 0,1);
+ }
+
+ if (chips>0) /* we don't want to do this on megatech */
+ {
+ if (segae_vdp_regs[1][1] & 0x40) {
+ draw_tiles_line (dest+16, line, 1,0);
+ draw_sprite_line(dest+16, 1, line);
+ draw_tiles_line (dest+16, line, 1,1);
+ }
+ }
+
+ /* FIX ME!! */
+ if (blank)
+ {
+ if (strcmp(Machine->gamedrv->name,"tetrisse")) /* and we really don't want to do it on tetrise */
+ memset(dest+16, 32+16, 8); /* Clear Leftmost column, there should be a register for this like on the SMS i imagine */
+ /* on the SMS this is bit 5 of register 0 (according to CMD's SMS docs) for system E this */ /* appears to be incorrect, most games need it blanked 99% of the time so we blank it */
+ }
+}
+
+/*-- Drawing a line of tiles --*/
+
+static void draw_tiles_line(UINT8 *dest, int line, UINT8 chip, UINT8 pri)
+{
+ /* todo: fix vscrolling (or is it something else causing the glitch on the hi-score screen of hangonjr, seems to be .. */
+
+ UINT8 hscroll;
+ UINT8 vscroll;
+ UINT16 tmbase;
+ UINT8 tilesline, tilesline2;
+ UINT8 coloffset, coloffset2;
+ UINT8 loopcount;
+
+ hscroll = (256-segae_vdp_regs[chip][8]);
+ vscroll = segae_vdp_regs[chip][9];
+ if (vscroll > 224) vscroll %= 224;
+
+ tmbase = (segae_vdp_regs[chip][2] & 0x0e) << 10;
+ tmbase += (segae_vdp_vrambank[chip] * 0x4000);
+
+ tilesline = (line + vscroll) >> 3;
+ tilesline2= (line + vscroll) % 8;
+
+
+ coloffset = (hscroll >> 3);
+ coloffset2= (hscroll % 8);
+
+ dest -= coloffset2;
+
+ for (loopcount=0;loopcount<33;loopcount++) {
+
+ UINT16 vram_offset, vram_word;
+ UINT16 tile_no;
+ UINT8 palette, priority, flipx, flipy;
+
+ vram_offset = tmbase
+ + (2 * (32*tilesline + ((coloffset+loopcount)&0x1f) ) );
+ vram_word = segae_vdp_vram[chip][vram_offset] | (segae_vdp_vram[chip][vram_offset+1] << 8);
+
+ tile_no = (vram_word & 0x01ff);
+ flipx = (vram_word & 0x0200) >> 9;
+ flipy = (vram_word & 0x0400) >> 10;
+ palette = (vram_word & 0x0800) >> 11;
+ priority= (vram_word & 0x1000) >> 12;
+
+ tilesline2= (line + vscroll) % 8;
+ if (flipy) tilesline2 = 7-tilesline2;
+
+ if (priority == pri) {
+ if (chip == 0) draw_8pix_solid16(dest, chip, tile_no,tilesline2,flipx,palette);
+ else draw_8pix(dest, chip, tile_no,tilesline2,flipx,palette);
+ }
+ dest+=8;
+ }
+}
+
+static void draw_sprite_line(UINT8 *dest, UINT8 chip, UINT8 line)
+{
+ int nosprites;
+ int loopcount;
+
+ UINT16 spritebase;
+
+ nosprites = 63; // if there is no end marker we draw everything (ridleofp)
+
+ spritebase = (segae_vdp_regs[chip][5] & 0x7e) << 7;
+ spritebase += (segae_vdp_vrambank[chip] * 0x4000);
+
+ /*- find out how many sprites there are -*/
+
+ for (loopcount=0;loopcount<64;loopcount++) {
+ UINT8 ypos;
+
+ ypos = segae_vdp_vram[chip][spritebase+loopcount];
+
+ if (ypos==208) {
+ nosprites=loopcount;
+ break;
+ }
+ }
+
+ /*- draw sprites IN REVERSE ORDER -*/
+
+ for (loopcount = nosprites; loopcount >= 0;loopcount--) {
+ int ypos;
+ UINT8 sheight;
+
+ ypos = segae_vdp_vram[chip][spritebase+loopcount] +1;
+
+ if (segae_vdp_regs[chip][1] & 0x02) sheight=16; else sheight=8;
+
+ if ( (line >= ypos) && (line < ypos+sheight) ) {
+ int xpos;
+ UINT8 sprnum;
+ UINT8 spline;
+
+ spline = line - ypos;
+
+ xpos = segae_vdp_vram[chip][spritebase+0x80+ (2*loopcount)];
+ sprnum = segae_vdp_vram[chip][spritebase+0x81+ (2*loopcount)];
+
+ if (segae_vdp_regs[chip][6] & 0x04)
+ sprnum += 0x100;
+
+ draw_8pix_sprite(dest+xpos, chip, sprnum, spline);
+
+ }
+ }
+}
+
+static void draw_8pix_solid16(UINT8 *dest, UINT8 chip, UINT16 tile, UINT8 line, UINT8 flipx, UINT8 col)
+{
+
+ UINT32 pix8 = *(UINT32 *)&segae_vdp_vram[chip][(32)*tile + (4)*line + (0x4000) * segae_vdp_vrambank[chip]];
+ UINT8 pix, coladd;
+
+ if (!pix8 && !col) return; /*note only the colour 0 of each vdp is transparent NOT colour 16???, fixes sky in HangonJr */
+
+ coladd = 16*col;
+
+ if (flipx) {
+ pix = ((pix8 >> 0) & 0x01) | ((pix8 >> 7) & 0x02) | ((pix8 >> 14) & 0x04) | ((pix8 >> 21) & 0x08) ; pix+= coladd ; if (pix) dest[0] = pix+ 32*chip;
+ pix = ((pix8 >> 1) & 0x01) | ((pix8 >> 8) & 0x02) | ((pix8 >> 15) & 0x04) | ((pix8 >> 22) & 0x08) ; pix+= coladd ; if (pix) dest[1] = pix+ 32*chip;
+ pix = ((pix8 >> 2) & 0x01) | ((pix8 >> 9) & 0x02) | ((pix8 >> 16) & 0x04) | ((pix8 >> 23) & 0x08) ; pix+= coladd ; if (pix) dest[2] = pix+ 32*chip;
+ pix = ((pix8 >> 3) & 0x01) | ((pix8 >>10) & 0x02) | ((pix8 >> 17) & 0x04) | ((pix8 >> 24) & 0x08) ; pix+= coladd ; if (pix) dest[3] = pix+ 32*chip;
+ pix = ((pix8 >> 4) & 0x01) | ((pix8 >>11) & 0x02) | ((pix8 >> 18) & 0x04) | ((pix8 >> 25) & 0x08) ; pix+= coladd ; if (pix) dest[4] = pix+ 32*chip;
+ pix = ((pix8 >> 5) & 0x01) | ((pix8 >>12) & 0x02) | ((pix8 >> 19) & 0x04) | ((pix8 >> 26) & 0x08) ; pix+= coladd ; if (pix) dest[5] = pix+ 32*chip;
+ pix = ((pix8 >> 6) & 0x01) | ((pix8 >>13) & 0x02) | ((pix8 >> 20) & 0x04) | ((pix8 >> 27) & 0x08) ; pix+= coladd ; if (pix) dest[6] = pix+ 32*chip;
+ pix = ((pix8 >> 7) & 0x01) | ((pix8 >>14) & 0x02) | ((pix8 >> 21) & 0x04) | ((pix8 >> 28) & 0x08) ; pix+= coladd ; if (pix) dest[7] = pix+ 32*chip;
+ } else {
+ pix = ((pix8 >> 7) & 0x01) | ((pix8 >>14) & 0x02) | ((pix8 >> 21) & 0x04) | ((pix8 >> 28) & 0x08) ; pix+= coladd ; if (pix) dest[0] = pix+ 32*chip;
+ pix = ((pix8 >> 6) & 0x01) | ((pix8 >>13) & 0x02) | ((pix8 >> 20) & 0x04) | ((pix8 >> 27) & 0x08) ; pix+= coladd ; if (pix) dest[1] = pix+ 32*chip;
+ pix = ((pix8 >> 5) & 0x01) | ((pix8 >>12) & 0x02) | ((pix8 >> 19) & 0x04) | ((pix8 >> 26) & 0x08) ; pix+= coladd ; if (pix) dest[2] = pix+ 32*chip;
+ pix = ((pix8 >> 4) & 0x01) | ((pix8 >>11) & 0x02) | ((pix8 >> 18) & 0x04) | ((pix8 >> 25) & 0x08) ; pix+= coladd ; if (pix) dest[3] = pix+ 32*chip;
+ pix = ((pix8 >> 3) & 0x01) | ((pix8 >>10) & 0x02) | ((pix8 >> 17) & 0x04) | ((pix8 >> 24) & 0x08) ; pix+= coladd ; if (pix) dest[4] = pix+ 32*chip;
+ pix = ((pix8 >> 2) & 0x01) | ((pix8 >> 9) & 0x02) | ((pix8 >> 16) & 0x04) | ((pix8 >> 23) & 0x08) ; pix+= coladd ; if (pix) dest[5] = pix+ 32*chip;
+ pix = ((pix8 >> 1) & 0x01) | ((pix8 >> 8) & 0x02) | ((pix8 >> 15) & 0x04) | ((pix8 >> 22) & 0x08) ; pix+= coladd ; if (pix) dest[6] = pix+ 32*chip;
+ pix = ((pix8 >> 0) & 0x01) | ((pix8 >> 7) & 0x02) | ((pix8 >> 14) & 0x04) | ((pix8 >> 21) & 0x08) ; pix+= coladd ; if (pix) dest[7] = pix+ 32*chip;
+ }
+}
+
+static void draw_8pix(UINT8 *dest, UINT8 chip, UINT16 tile, UINT8 line, UINT8 flipx, UINT8 col)
+{
+
+ UINT32 pix8 = *(UINT32 *)&segae_vdp_vram[chip][(32)*tile + (4)*line + (0x4000) * segae_vdp_vrambank[chip]];
+ UINT8 pix, coladd;
+
+ if (!pix8) return;
+
+ coladd = 16*col+32*chip;
+
+ if (flipx) {
+ pix = ((pix8 >> 0) & 0x01) | ((pix8 >> 7) & 0x02) | ((pix8 >> 14) & 0x04) | ((pix8 >> 21) & 0x08) ; if (pix) dest[0] = pix+ coladd;
+ pix = ((pix8 >> 1) & 0x01) | ((pix8 >> 8) & 0x02) | ((pix8 >> 15) & 0x04) | ((pix8 >> 22) & 0x08) ; if (pix) dest[1] = pix+ coladd;
+ pix = ((pix8 >> 2) & 0x01) | ((pix8 >> 9) & 0x02) | ((pix8 >> 16) & 0x04) | ((pix8 >> 23) & 0x08) ; if (pix) dest[2] = pix+ coladd;
+ pix = ((pix8 >> 3) & 0x01) | ((pix8 >>10) & 0x02) | ((pix8 >> 17) & 0x04) | ((pix8 >> 24) & 0x08) ; if (pix) dest[3] = pix+ coladd;
+ pix = ((pix8 >> 4) & 0x01) | ((pix8 >>11) & 0x02) | ((pix8 >> 18) & 0x04) | ((pix8 >> 25) & 0x08) ; if (pix) dest[4] = pix+ coladd;
+ pix = ((pix8 >> 5) & 0x01) | ((pix8 >>12) & 0x02) | ((pix8 >> 19) & 0x04) | ((pix8 >> 26) & 0x08) ; if (pix) dest[5] = pix+ coladd;
+ pix = ((pix8 >> 6) & 0x01) | ((pix8 >>13) & 0x02) | ((pix8 >> 20) & 0x04) | ((pix8 >> 27) & 0x08) ; if (pix) dest[6] = pix+ coladd;
+ pix = ((pix8 >> 7) & 0x01) | ((pix8 >>14) & 0x02) | ((pix8 >> 21) & 0x04) | ((pix8 >> 28) & 0x08) ; if (pix) dest[7] = pix+ coladd;
+ } else {
+ pix = ((pix8 >> 7) & 0x01) | ((pix8 >>14) & 0x02) | ((pix8 >> 21) & 0x04) | ((pix8 >> 28) & 0x08) ; if (pix) dest[0] = pix+ coladd;
+ pix = ((pix8 >> 6) & 0x01) | ((pix8 >>13) & 0x02) | ((pix8 >> 20) & 0x04) | ((pix8 >> 27) & 0x08) ; if (pix) dest[1] = pix+ coladd;
+ pix = ((pix8 >> 5) & 0x01) | ((pix8 >>12) & 0x02) | ((pix8 >> 19) & 0x04) | ((pix8 >> 26) & 0x08) ; if (pix) dest[2] = pix+ coladd;
+ pix = ((pix8 >> 4) & 0x01) | ((pix8 >>11) & 0x02) | ((pix8 >> 18) & 0x04) | ((pix8 >> 25) & 0x08) ; if (pix) dest[3] = pix+ coladd;
+ pix = ((pix8 >> 3) & 0x01) | ((pix8 >>10) & 0x02) | ((pix8 >> 17) & 0x04) | ((pix8 >> 24) & 0x08) ; if (pix) dest[4] = pix+ coladd;
+ pix = ((pix8 >> 2) & 0x01) | ((pix8 >> 9) & 0x02) | ((pix8 >> 16) & 0x04) | ((pix8 >> 23) & 0x08) ; if (pix) dest[5] = pix+ coladd;
+ pix = ((pix8 >> 1) & 0x01) | ((pix8 >> 8) & 0x02) | ((pix8 >> 15) & 0x04) | ((pix8 >> 22) & 0x08) ; if (pix) dest[6] = pix+ coladd;
+ pix = ((pix8 >> 0) & 0x01) | ((pix8 >> 7) & 0x02) | ((pix8 >> 14) & 0x04) | ((pix8 >> 21) & 0x08) ; if (pix) dest[7] = pix+ coladd;
+ }
+}
+
+static void draw_8pix_sprite(UINT8 *dest, UINT8 chip, UINT16 tile, UINT8 line)
+{
+
+ UINT32 pix8 = *(UINT32 *)&segae_vdp_vram[chip][(32)*tile + (4)*line + (0x4000) * segae_vdp_vrambank[chip]];
+ UINT8 pix;
+
+ if (!pix8) return; /*note only the colour 0 of each vdp is transparent NOT colour 16, fixes sky in HangonJr */
+
+ pix = ((pix8 >> 7) & 0x01) | ((pix8 >>14) & 0x02) | ((pix8 >> 21) & 0x04) | ((pix8 >> 28) & 0x08) ; if (pix) dest[0] = pix+16+32*chip;
+ pix = ((pix8 >> 6) & 0x01) | ((pix8 >>13) & 0x02) | ((pix8 >> 20) & 0x04) | ((pix8 >> 27) & 0x08) ; if (pix) dest[1] = pix+16+32*chip;
+ pix = ((pix8 >> 5) & 0x01) | ((pix8 >>12) & 0x02) | ((pix8 >> 19) & 0x04) | ((pix8 >> 26) & 0x08) ; if (pix) dest[2] = pix+16+32*chip;
+ pix = ((pix8 >> 4) & 0x01) | ((pix8 >>11) & 0x02) | ((pix8 >> 18) & 0x04) | ((pix8 >> 25) & 0x08) ; if (pix) dest[3] = pix+16+32*chip;
+ pix = ((pix8 >> 3) & 0x01) | ((pix8 >>10) & 0x02) | ((pix8 >> 17) & 0x04) | ((pix8 >> 24) & 0x08) ; if (pix) dest[4] = pix+16+32*chip;
+ pix = ((pix8 >> 2) & 0x01) | ((pix8 >> 9) & 0x02) | ((pix8 >> 16) & 0x04) | ((pix8 >> 23) & 0x08) ; if (pix) dest[5] = pix+16+32*chip;
+ pix = ((pix8 >> 1) & 0x01) | ((pix8 >> 8) & 0x02) | ((pix8 >> 15) & 0x04) | ((pix8 >> 22) & 0x08) ; if (pix) dest[6] = pix+16+32*chip;
+ pix = ((pix8 >> 0) & 0x01) | ((pix8 >> 7) & 0x02) | ((pix8 >> 14) & 0x04) | ((pix8 >> 21) & 0x08) ; if (pix) dest[7] = pix+16+32*chip;
+
+}
diff --git a/src/mame/video/segaxbd.c b/src/mame/video/segaxbd.c
new file mode 100644
index 00000000000..6015a109517
--- /dev/null
+++ b/src/mame/video/segaxbd.c
@@ -0,0 +1,102 @@
+/***************************************************************************
+
+ Sega X-board hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "segaic16.h"
+#include "includes/system16.h"
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static UINT8 road_priority;
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( xboard )
+{
+ /* compute palette info */
+ segaic16_palette_init(0x2000);
+
+ /* initialize the tile/text layers */
+ segaic16_tilemap_init(0, SEGAIC16_TILEMAP_16B, 0x1c00, 0, 2);
+
+ /* initialize the sprites */
+ segaic16_sprites_init(0, SEGAIC16_SPRITES_XBOARD, 0x000, 0);
+
+ /* initialize the road */
+ segaic16_road_init(0, SEGAIC16_ROAD_XBOARD, 0x1700, 0x1720, 0x1780, -166);
+}
+
+
+
+/*************************************
+ *
+ * Miscellaneous setters
+ *
+ *************************************/
+
+void xboard_set_road_priority(int priority)
+{
+ /* this is only set at init time */
+ road_priority = priority;
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( xboard )
+{
+ /* if no drawing is happening, fill with black and get out */
+ if (!segaic16_display_enable)
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* reset priorities */
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ /* draw the low priority road layer */
+ segaic16_road_draw(0, bitmap, cliprect, SEGAIC16_ROAD_BACKGROUND);
+ if (road_priority == 0)
+ segaic16_road_draw(0, bitmap, cliprect, SEGAIC16_ROAD_FOREGROUND);
+
+ /* draw background */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 0, 0x01);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_BACKGROUND, 1, 0x02);
+
+ /* draw foreground */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_FOREGROUND, 0, 0x02);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_FOREGROUND, 1, 0x04);
+
+ /* draw the high priority road */
+ if (road_priority == 1)
+ segaic16_road_draw(0, bitmap, cliprect, SEGAIC16_ROAD_FOREGROUND);
+
+ /* text layer */
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_TEXT, 0, 0x04);
+ segaic16_tilemap_draw(machine, 0, bitmap, cliprect, SEGAIC16_TILEMAP_TEXT, 1, 0x08);
+
+ /* draw the sprites */
+ segaic16_sprites_draw(0, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/segaybd.c b/src/mame/video/segaybd.c
new file mode 100644
index 00000000000..4ed05f710ef
--- /dev/null
+++ b/src/mame/video/segaybd.c
@@ -0,0 +1,75 @@
+/***************************************************************************
+
+ Sega Y-board hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "segaic16.h"
+#include "includes/system16.h"
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static mame_bitmap *yboard_bitmap;
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( yboard )
+{
+ /* compute palette info */
+ segaic16_palette_init(0x2000);
+
+ /* allocate a bitmap for the yboard layer */
+ yboard_bitmap = auto_bitmap_alloc(512, 512, BITMAP_FORMAT_INDEXED16);
+
+ /* initialize the sprites */
+ segaic16_sprites_init(0, SEGAIC16_SPRITES_YBOARD_16B, 0x800, 0);
+ segaic16_sprites_init(1, SEGAIC16_SPRITES_YBOARD, 0x1000, 0);
+
+ /* initialize the rotation layer */
+ segaic16_rotate_init(0, SEGAIC16_ROTATE_YBOARD, 0x000);
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( yboard )
+{
+ rectangle yboard_clip;
+
+ /* if no drawing is happening, fill with black and get out */
+ if (!segaic16_display_enable)
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* draw the yboard sprites */
+ yboard_clip.min_x = yboard_clip.min_y = 0;
+ yboard_clip.max_x = yboard_clip.max_y = 511;
+ segaic16_sprites_draw(1, yboard_bitmap, &yboard_clip);
+
+ /* apply rotation */
+ segaic16_rotate_draw(0, bitmap, cliprect, yboard_bitmap);
+
+ /* draw the 16B sprites */
+ segaic16_sprites_draw(0, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/seibuspi.c b/src/mame/video/seibuspi.c
new file mode 100644
index 00000000000..c32ffa22530
--- /dev/null
+++ b/src/mame/video/seibuspi.c
@@ -0,0 +1,665 @@
+#include "driver.h"
+
+static tilemap *text_layer;
+static tilemap *back_layer;
+static tilemap *mid_layer;
+static tilemap *fore_layer;
+
+UINT32 *spi_scrollram;
+
+static UINT32 layer_bank;
+static UINT32 layer_enable;
+static UINT32 video_dma_length;
+static UINT32 video_dma_address;
+
+static int rf2_layer_bank[3];
+extern UINT32 *spimainram;
+static UINT32 *tilemap_ram;
+static UINT32 *palette_ram;
+static UINT32 *sprite_ram;
+
+static int mid_layer_offset;
+static int fore_layer_offset;
+static int text_layer_offset;
+
+static UINT32 bg_fore_layer_position;
+
+static UINT8 alpha_table[6144];
+
+READ32_HANDLER( spi_layer_bank_r )
+{
+ return layer_bank;
+}
+
+WRITE32_HANDLER( spi_layer_bank_w )
+{
+ COMBINE_DATA( &layer_bank );
+
+ if (layer_bank & 0x80000000) {
+ fore_layer_offset = 0x1000 / 4;
+ mid_layer_offset = 0x2000 / 4;
+ text_layer_offset = 0x3000 / 4;
+ }
+ else {
+ fore_layer_offset = 0x800 / 4;
+ mid_layer_offset = 0x1000 / 4;
+ text_layer_offset = 0x1800 / 4;
+ }
+}
+
+void rf2_set_layer_banks(int banks)
+{
+ if (rf2_layer_bank[0] != BIT(banks,0))
+ {
+ rf2_layer_bank[0] = BIT(banks,0);
+ tilemap_mark_all_tiles_dirty(back_layer);
+ }
+
+ if (rf2_layer_bank[1] != BIT(banks,1))
+ {
+ rf2_layer_bank[1] = BIT(banks,1);
+ tilemap_mark_all_tiles_dirty(mid_layer);
+ }
+
+ if (rf2_layer_bank[2] != BIT(banks,2))
+ {
+ rf2_layer_bank[2] = BIT(banks,2);
+ tilemap_mark_all_tiles_dirty(fore_layer);
+ }
+}
+
+#ifdef UNUSED_FUNCTION
+READ32_HANDLER( spi_layer_enable_r )
+{
+ return layer_enable;
+}
+#endif
+
+WRITE32_HANDLER( spi_layer_enable_w )
+{
+ COMBINE_DATA( &layer_enable );
+ tilemap_set_enable(back_layer, (layer_enable & 0x1) ^ 0x1);
+ tilemap_set_enable(mid_layer, ((layer_enable >> 1) & 0x1) ^ 0x1);
+ tilemap_set_enable(fore_layer, ((layer_enable >> 2) & 0x1) ^ 0x1);
+}
+
+WRITE32_HANDLER( tilemap_dma_start_w )
+{
+ if (video_dma_address != 0)
+ {
+ int i;
+ int index = (video_dma_address / 4) - 0x200;
+
+ if (layer_bank & 0x80000000)
+ {
+ /* back layer */
+ for (i=0; i < 0x800/4; i++) {
+ UINT32 tile = spimainram[index];
+ if (tilemap_ram[i] != tile) {
+ tilemap_ram[i] = tile;
+ tilemap_mark_tile_dirty( back_layer, (i * 2) );
+ tilemap_mark_tile_dirty( back_layer, (i * 2) + 1 );
+ }
+ index++;
+ }
+
+ /* back layer row scroll */
+ memcpy(&tilemap_ram[0x800/4], &spimainram[index], 0x800/4);
+ index += 0x800/4;
+
+ /* fore layer */
+ for (i=0; i < 0x800/4; i++) {
+ UINT32 tile = spimainram[index];
+ if (tilemap_ram[i+fore_layer_offset] != tile) {
+ tilemap_ram[i+fore_layer_offset] = tile;
+ tilemap_mark_tile_dirty( fore_layer, (i * 2) );
+ tilemap_mark_tile_dirty( fore_layer, (i * 2) + 1 );
+ }
+ index++;
+ }
+
+ /* fore layer row scroll */
+ memcpy(&tilemap_ram[0x1800/4], &spimainram[index], 0x800/4);
+ index += 0x800/4;
+
+ /* mid layer */
+ for (i=0; i < 0x800/4; i++) {
+ UINT32 tile = spimainram[index];
+ if (tilemap_ram[i+mid_layer_offset] != tile) {
+ tilemap_ram[i+mid_layer_offset] = tile;
+ tilemap_mark_tile_dirty( mid_layer, (i * 2) );
+ tilemap_mark_tile_dirty( mid_layer, (i * 2) + 1 );
+ }
+ index++;
+ }
+
+ /* mid layer row scroll */
+ memcpy(&tilemap_ram[0x1800/4], &spimainram[index], 0x800/4);
+ index += 0x800/4;
+
+ /* text layer */
+ for (i=0; i < 0x1000/4; i++) {
+ UINT32 tile = spimainram[index];
+ if (tilemap_ram[i+text_layer_offset] != tile) {
+ tilemap_ram[i+text_layer_offset] = tile;
+ tilemap_mark_tile_dirty( text_layer, (i * 2) );
+ tilemap_mark_tile_dirty( text_layer, (i * 2) + 1 );
+ }
+ index++;
+ }
+ }
+ else
+ {
+ /* back layer */
+ for (i=0; i < 0x800/4; i++) {
+ UINT32 tile = spimainram[index];
+ if (tilemap_ram[i] != tile) {
+ tilemap_ram[i] = tile;
+ tilemap_mark_tile_dirty( back_layer, (i * 2) );
+ tilemap_mark_tile_dirty( back_layer, (i * 2) + 1 );
+ }
+ index++;
+ }
+
+ /* fore layer */
+ for (i=0; i < 0x800/4; i++) {
+ UINT32 tile = spimainram[index];
+ if (tilemap_ram[i+fore_layer_offset] != tile) {
+ tilemap_ram[i+fore_layer_offset] = tile;
+ tilemap_mark_tile_dirty( fore_layer, (i * 2) );
+ tilemap_mark_tile_dirty( fore_layer, (i * 2) + 1 );
+ }
+ index++;
+ }
+
+ /* mid layer */
+ for (i=0; i < 0x800/4; i++) {
+ UINT32 tile = spimainram[index];
+ if (tilemap_ram[i+mid_layer_offset] != tile) {
+ tilemap_ram[i+mid_layer_offset] = tile;
+ tilemap_mark_tile_dirty( mid_layer, (i * 2) );
+ tilemap_mark_tile_dirty( mid_layer, (i * 2) + 1 );
+ }
+ index++;
+ }
+
+ /* text layer */
+ for (i=0; i < 0x1000/4; i++) {
+ UINT32 tile = spimainram[index];
+ if (tilemap_ram[i+text_layer_offset] != tile) {
+ tilemap_ram[i+text_layer_offset] = tile;
+ tilemap_mark_tile_dirty( text_layer, (i * 2) );
+ tilemap_mark_tile_dirty( text_layer, (i * 2) + 1 );
+ }
+ index++;
+ }
+ }
+ }
+}
+
+WRITE32_HANDLER( palette_dma_start_w )
+{
+ if (video_dma_address != 0)
+ {
+ int i;
+ for (i=0; i < ((video_dma_length+1) * 2) / 4; i++)
+ {
+ UINT32 color = spimainram[(video_dma_address / 4) + i - 0x200];
+ if (palette_ram[i] != color) {
+ palette_ram[i] = color;
+ palette_set_color_rgb( Machine, (i * 2), pal5bit(palette_ram[i] >> 0), pal5bit(palette_ram[i] >> 5), pal5bit(palette_ram[i] >> 10) );
+ palette_set_color_rgb( Machine, (i * 2) + 1, pal5bit(palette_ram[i] >> 16), pal5bit(palette_ram[i] >> 21), pal5bit(palette_ram[i] >> 26) );
+ }
+ }
+ }
+}
+
+WRITE32_HANDLER( sprite_dma_start_w )
+{
+ if (video_dma_address != 0)
+ {
+ memcpy( sprite_ram, &spimainram[(video_dma_address / 4) - 0x200], 0x1000);
+ }
+}
+
+WRITE32_HANDLER( video_dma_length_w )
+{
+ COMBINE_DATA( &video_dma_length );
+}
+
+WRITE32_HANDLER( video_dma_address_w )
+{
+ COMBINE_DATA( &video_dma_address );
+}
+
+static void draw_blend_gfx(mame_bitmap *bitmap, const rectangle *cliprect, const gfx_element *gfx, UINT32 code, UINT32 color, int flipx, int flipy, int sx, int sy)
+{
+ UINT8 *dp;
+ int i, j;
+ int x1, x2;
+ int y1, y2;
+ int px, py;
+ int xd = 1, yd = 1;
+
+ int width = gfx->width;
+ int height = gfx->height;
+
+ x1 = sx;
+ x2 = sx + width - 1;
+ y1 = sy;
+ y2 = sy + height - 1;
+
+ if (x1 > cliprect->max_x || x2 < cliprect->min_x)
+ {
+ return;
+ }
+ if (y1 > cliprect->max_y || y2 < cliprect->min_y)
+ {
+ return;
+ }
+
+ px = 0;
+ py = 0;
+
+ if (flipx)
+ {
+ xd = -xd;
+ px = width - 1;
+ }
+ if (flipy)
+ {
+ yd = -yd;
+ py = height - 1;
+ }
+
+ // clip x
+ if (x1 < cliprect->min_x)
+ {
+ if (flipx)
+ {
+ px = width - (cliprect->min_x - x1) - 1;
+ }
+ else
+ {
+ px = (cliprect->min_x - x1);
+ }
+ x1 = cliprect->min_x;
+ }
+ if (x2 > cliprect->max_x)
+ {
+ x2 = cliprect->max_x;
+ }
+
+ // clip y
+ if (y1 < cliprect->min_y)
+ {
+ if (flipy)
+ {
+ py = height - (cliprect->min_y - y1) - 1;
+ }
+ else
+ {
+ py = (cliprect->min_y - y1);
+ }
+ y1 = cliprect->min_y;
+ }
+ if (y2 > cliprect->max_y)
+ {
+ y2 = cliprect->max_y;
+ }
+
+ if (gfx->total_elements <= 0x10000)
+ {
+ code &= 0xffff;
+ }
+
+ dp = gfx->gfxdata + code * gfx->char_modulo;
+
+ // draw
+ for (j=y1; j <= y2; j++)
+ {
+ UINT16 *p = BITMAP_ADDR16(bitmap, j, 0);
+ int dp_i = (py * width) + px;
+ py += yd;
+
+ for (i=x1; i <= x2; i++)
+ {
+ UINT8 pen = dp[dp_i];
+ if (pen != 0x3f)
+ {
+ int global_pen = pen + color*64;
+ UINT8 alpha = alpha_table[global_pen];
+ if (alpha)
+ {
+ p[i] = alpha_blend16(p[i], Machine->remapped_colortable[gfx->color_base + global_pen]);
+ }
+ else
+ {
+ p[i] = Machine->remapped_colortable[gfx->color_base + global_pen];
+ }
+ }
+ dp_i += xd;
+ }
+ }
+}
+
+static int sprite_xtable[2][8] =
+{
+ { 0*16, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16 },
+ { 7*16, 6*16, 5*16, 4*16, 3*16, 2*16, 1*16, 0*16 }
+};
+static int sprite_ytable[2][8] =
+{
+ { 0*16, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16 },
+ { 7*16, 6*16, 5*16, 4*16, 3*16, 2*16, 1*16, 0*16 }
+};
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri_mask)
+{
+ INT16 xpos, ypos;
+ int tile_num, color;
+ int width, height;
+ int flip_x = 0, flip_y = 0;
+ int a;
+ int priority;
+ int x,y, x1, y1;
+ const gfx_element *gfx = machine->gfx[2];
+
+ if( layer_enable & 0x10 )
+ return;
+
+ for( a = 0x400 - 2; a >= 0; a -= 2 ) {
+ tile_num = (sprite_ram[a + 0] >> 16) & 0xffff;
+ if( sprite_ram[a + 1] & 0x1000 )
+ tile_num |= 0x10000;
+
+ if( !tile_num )
+ continue;
+
+ priority = (sprite_ram[a + 0] >> 6) & 0x3;
+ if( pri_mask != priority )
+ continue;
+
+ xpos = sprite_ram[a + 1] & 0x3ff;
+ if( xpos & 0x200 )
+ xpos |= 0xfc00;
+ ypos = (sprite_ram[a + 1] >> 16) & 0x1ff;
+ if( ypos & 0x100 )
+ ypos |= 0xfe00;
+ color = (sprite_ram[a + 0] & 0x3f);
+
+ width = ((sprite_ram[a + 0] >> 8) & 0x7) + 1;
+ height = ((sprite_ram[a + 0] >> 12) & 0x7) + 1;
+ flip_x = (sprite_ram[a + 0] >> 11) & 0x1;
+ flip_y = (sprite_ram[a + 0] >> 15) & 0x1;
+ x1 = 0;
+ y1 = 0;
+
+ if( flip_x ) {
+ x1 = 8 - width;
+ width = width + x1;
+ }
+ if( flip_y ) {
+ y1 = 8 - height;
+ height = height + y1;
+ }
+
+ for( x=x1; x < width; x++ ) {
+ for( y=y1; y < height; y++ ) {
+ draw_blend_gfx(bitmap, cliprect, gfx, tile_num, color, flip_x, flip_y, xpos + sprite_xtable[flip_x][x], ypos + sprite_ytable[flip_y][y]);
+
+ /* xpos seems to wrap-around to 0 at 512 */
+ if( (xpos + (16 * x) + 16) >= 512 ) {
+ draw_blend_gfx(bitmap, cliprect, gfx, tile_num, color, flip_x, flip_y, xpos - 512 + sprite_xtable[flip_x][x], ypos + sprite_ytable[flip_y][y]);
+ }
+
+ tile_num++;
+ }
+ }
+ }
+}
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ int offs = tile_index / 2;
+ int tile = (tilemap_ram[offs + text_layer_offset] >> ((tile_index & 0x1) ? 16 : 0)) & 0xffff;
+ int color = (tile >> 12) & 0xf;
+
+ tile &= 0xfff;
+
+ SET_TILE_INFO(0, tile, color, 0);
+}
+
+static TILE_GET_INFO( get_back_tile_info )
+{
+ int offs = tile_index / 2;
+ int tile = (tilemap_ram[offs] >> ((tile_index & 0x1) ? 16 : 0)) & 0xffff;
+ int color = (tile >> 13) & 0x7;
+
+ tile &= 0x1fff;
+
+ if( rf2_layer_bank[0] )
+ tile |= 0x4000;
+
+ SET_TILE_INFO(1, tile, color, 0);
+}
+
+static TILE_GET_INFO( get_mid_tile_info )
+{
+ int offs = tile_index / 2;
+ int tile = (tilemap_ram[offs + mid_layer_offset] >> ((tile_index & 0x1) ? 16 : 0)) & 0xffff;
+ int color = (tile >> 13) & 0x7;
+
+ tile &= 0x1fff;
+ tile |= 0x2000;
+
+ if( rf2_layer_bank[1] )
+ tile |= 0x4000;
+
+ SET_TILE_INFO(1, tile, color + 16, 0);
+}
+
+static TILE_GET_INFO( get_fore_tile_info )
+{
+ int offs = tile_index / 2;
+ int tile = (tilemap_ram[offs + fore_layer_offset] >> ((tile_index & 0x1) ? 16 : 0)) & 0xffff;
+ int color = (tile >> 13) & 0x7;
+
+ tile &= 0x1fff;
+ tile |= bg_fore_layer_position;
+
+ if( rf2_layer_bank[2] )
+ tile |= 0x4000;
+
+ tile |= ((layer_bank >> 27) & 0x1) << 13;
+
+ SET_TILE_INFO(1, tile, color + 8, 0);
+}
+
+VIDEO_START( spi )
+{
+ int i;
+ int region_length;
+
+ text_layer = tilemap_create( get_text_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8,64,32 );
+ back_layer = tilemap_create( get_back_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 16,16,32,32 );
+ mid_layer = tilemap_create( get_mid_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 16,16,32,32 );
+ fore_layer = tilemap_create( get_fore_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 16,16,32,32 );
+
+ tilemap_set_transparent_pen(text_layer, 31);
+ tilemap_set_transparent_pen(mid_layer, 63);
+ tilemap_set_transparent_pen(fore_layer, 63);
+
+ tilemap_ram = auto_malloc(0x4000);
+ palette_ram = auto_malloc(0x3000);
+ sprite_ram = auto_malloc(0x1000);
+ memset(tilemap_ram, 0, 0x4000);
+ memset(palette_ram, 0, 0x3000);
+ memset(sprite_ram, 0, 0x1000);
+
+ for (i=0; i < 6144; i++) {
+ palette_set_color(machine, i, MAKE_RGB(0, 0, 0));
+ }
+
+ memset(alpha_table, 0, 6144 * sizeof(UINT8));
+
+ // sprites
+ //for (i = 1792; i < 1808; i++) { alpha_table[i] = 1; } // breaks rdft
+ for (i = 1840; i < 1856; i++) { alpha_table[i] = 1; }
+ for (i = 1920; i < 1952; i++) { alpha_table[i] = 1; }
+ //for (i = 1984; i < 2048; i++) { alpha_table[i] = 1; } // breaks batlball
+ //for (i = 3840; i < 3904; i++) { alpha_table[i] = 1; } // breaks rdft
+ for (i = 4032; i < 4096; i++) { alpha_table[i] = 1; }
+
+ // mid layer
+ for (i = 4960; i < 4992; i++) { alpha_table[i] = 1; } // breaks ejanhs
+ for (i = 5040; i < 5056; i++) { alpha_table[i] = 1; } // breaks ejanhs
+ for (i = 5104; i < 5120; i++) { alpha_table[i] = 1; }
+ // fore layer
+ for (i = 5552; i < 5568; i++) { alpha_table[i] = 1; } // breaks ejanhs
+ for (i = 5616; i < 5632; i++) { alpha_table[i] = 1; } // breaks ejanhs
+ // text layer
+ for (i = 6000; i < 6016; i++) { alpha_table[i] = 1; }
+ for (i = 6128; i < 6144; i++) { alpha_table[i] = 1; }
+
+ region_length = memory_region_length(REGION_GFX2);
+
+ if (region_length <= 0x300000)
+ {
+ bg_fore_layer_position = 0x2000;
+ }
+ else if (region_length <= 0x600000)
+ {
+ bg_fore_layer_position = 0x4000;
+ }
+ else
+ {
+ bg_fore_layer_position = 0x8000;
+ }
+}
+
+#ifdef UNUSED_FUNCTION
+static void set_rowscroll(tilemap *layer, int scroll, INT16* rows)
+{
+ int i;
+ int x = spi_scrollram[scroll] & 0xffff;
+ int y = (spi_scrollram[scroll] >> 16) & 0xffff;
+ tilemap_set_scroll_rows(layer, 512);
+ for( i=0; i < 512; i++ ) {
+ tilemap_set_scrollx(layer, i, x + rows[i]);
+ }
+ tilemap_set_scrolly(layer, 0, y);
+}
+
+static void set_scroll(tilemap *layer, int scroll)
+{
+ int x = spi_scrollram[scroll] & 0xffff;
+ int y = (spi_scrollram[scroll] >> 16) & 0xffff;
+ tilemap_set_scrollx(layer, 0, x);
+ tilemap_set_scrolly(layer, 0, y);
+}
+#endif
+
+
+static void combine_tilemap(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, tilemap *tile, int x, int y, int opaque, INT16 *rowscroll)
+{
+ int i,j;
+ UINT16 *s;
+ UINT16 *d;
+ UINT8 *t;
+ UINT32 xscroll_mask, yscroll_mask;
+ mame_bitmap *pen_bitmap;
+ mame_bitmap *flags_bitmap;
+
+ pen_bitmap = tilemap_get_pixmap(tile);
+ flags_bitmap = tilemap_get_flagsmap(tile);
+ xscroll_mask = pen_bitmap->width - 1;
+ yscroll_mask = pen_bitmap->height - 1;
+
+ alpha_set_level(0x7f);
+
+ for (j=cliprect->min_y; j <= cliprect->max_y; j++)
+ {
+ int rx = x;
+ if (rowscroll)
+ {
+ rx += rowscroll[(j+y) & yscroll_mask];
+ }
+
+ d = BITMAP_ADDR16(bitmap, j, 0);
+ s = BITMAP_ADDR16(pen_bitmap, (j+y) & yscroll_mask, 0);
+ t = BITMAP_ADDR8(flags_bitmap, (j+y) & yscroll_mask, 0);
+ for (i=cliprect->min_x+rx; i <= cliprect->max_x+rx; i++)
+ {
+ if (opaque || (t[i & xscroll_mask] & (TILEMAP_PIXEL_LAYER0 | TILEMAP_PIXEL_LAYER1)))
+ {
+ UINT16 pen = s[i & xscroll_mask];
+ UINT8 alpha = alpha_table[pen];
+ if (alpha)
+ {
+ *d = alpha_blend16(*d, machine->remapped_colortable[pen]);
+ }
+ else
+ {
+ *d = machine->remapped_colortable[pen];
+ }
+ }
+ ++d;
+ }
+ }
+}
+
+
+
+VIDEO_UPDATE( spi )
+{
+ INT16 *back_rowscroll, *mid_rowscroll, *fore_rowscroll;
+ if( layer_bank & 0x80000000 ) {
+ back_rowscroll = (INT16*)&tilemap_ram[0x200];
+ mid_rowscroll = (INT16*)&tilemap_ram[0x600];
+ fore_rowscroll = (INT16*)&tilemap_ram[0xa00];
+ } else {
+ back_rowscroll = NULL;
+ mid_rowscroll = NULL;
+ fore_rowscroll = NULL;
+ }
+
+ if( layer_enable & 0x1 )
+ fillbitmap(bitmap, 0, cliprect);
+
+ if (!(layer_enable & 0x1))
+ {
+ combine_tilemap(machine, bitmap, cliprect, back_layer, spi_scrollram[0] & 0xffff, (spi_scrollram[0] >> 16) & 0xffff, 1, back_rowscroll);
+ }
+
+ draw_sprites(machine, bitmap, cliprect, 0);
+
+ // if fore layer is enabled, draw priority 1 sprites behind mid layer
+ if (!(layer_enable & 0x4))
+ {
+ draw_sprites(machine, bitmap, cliprect, 1);
+ }
+
+ if (!(layer_enable & 0x2))
+ {
+ combine_tilemap(machine, bitmap, cliprect, mid_layer, spi_scrollram[1] & 0xffff, (spi_scrollram[1] >> 16) & 0xffff, 0, mid_rowscroll);
+ }
+
+ // if fore layer is disabled, draw priority 1 sprites above mid layer
+ if ((layer_enable & 0x4))
+ {
+ draw_sprites(machine, bitmap, cliprect, 1);
+ }
+
+ draw_sprites(machine, bitmap, cliprect, 2);
+
+ if (!(layer_enable & 0x4))
+ {
+ combine_tilemap(machine, bitmap, cliprect, fore_layer, spi_scrollram[2] & 0xffff, (spi_scrollram[2] >> 16) & 0xffff, 0, fore_rowscroll);
+ }
+
+ draw_sprites(machine, bitmap, cliprect, 3);
+
+ combine_tilemap(machine, bitmap, cliprect, text_layer, 0, 0, 0, NULL);
+ return 0;
+}
diff --git a/src/mame/video/seicross.c b/src/mame/video/seicross.c
new file mode 100644
index 00000000000..b13db973d8b
--- /dev/null
+++ b/src/mame/video/seicross.c
@@ -0,0 +1,149 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *seicross_row_scroll;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Seicross has two 32x8 palette PROMs, connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( seicross )
+{
+ int i;
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (color_prom[i] >> 6) & 0x01;
+ bit1 = (color_prom[i] >> 7) & 0x01;
+ b = 0x4f * bit0 + 0xa8 * bit1;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+WRITE8_HANDLER( seicross_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( seicross_colorram_w )
+{
+ /* bit 5 of the address is not used for color memory. There is just */
+ /* 512k of memory; every two consecutive rows share the same memory */
+ /* region. */
+ offset &= 0xffdf;
+
+ colorram[offset] = data;
+ colorram[offset + 0x20] = data;
+
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+ tilemap_mark_tile_dirty(bg_tilemap, offset + 0x20);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + ((colorram[tile_index] & 0x10) << 4);
+ int color = colorram[tile_index] & 0x0f;
+ int flags = ((colorram[tile_index] & 0x40) ? TILE_FLIPX : 0) | ((colorram[tile_index] & 0x80) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( seicross )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int x = spriteram[offs + 3];
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs] & 0x3f) + ((spriteram[offs + 1] & 0x10) << 2) + 128,
+ spriteram[offs + 1] & 0x0f,
+ spriteram[offs] & 0x40,spriteram[offs] & 0x80,
+ x,240-spriteram[offs + 2],
+ cliprect,TRANSPARENCY_PEN,0);
+ if(x>0xf0)
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs] & 0x3f) + ((spriteram[offs + 1] & 0x10) << 2) + 128,
+ spriteram[offs + 1] & 0x0f,
+ spriteram[offs] & 0x40,spriteram[offs] & 0x80,
+ x-256,240-spriteram[offs + 2],
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ for (offs = spriteram_2_size - 4;offs >= 0;offs -= 4)
+ {
+ int x = spriteram_2[offs + 3];
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram_2[offs] & 0x3f) + ((spriteram_2[offs + 1] & 0x10) << 2),
+ spriteram_2[offs + 1] & 0x0f,
+ spriteram_2[offs] & 0x40,spriteram_2[offs] & 0x80,
+ x,240-spriteram_2[offs + 2],
+ cliprect,TRANSPARENCY_PEN,0);
+ if(x>0xf0)
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram_2[offs] & 0x3f) + ((spriteram_2[offs + 1] & 0x10) << 2),
+ spriteram_2[offs + 1] & 0x0f,
+ spriteram_2[offs] & 0x40,spriteram_2[offs] & 0x80,
+ x-256,240-spriteram_2[offs + 2],
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( seicross )
+{
+ int col;
+
+ for (col = 0; col < 32; col++)
+ {
+ tilemap_set_scrolly(bg_tilemap, col, seicross_row_scroll[col]);
+ }
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/sengokmj.c b/src/mame/video/sengokmj.c
new file mode 100644
index 00000000000..c89cc38dc79
--- /dev/null
+++ b/src/mame/video/sengokmj.c
@@ -0,0 +1,129 @@
+/******************************************************************************************
+
+Sengoku Mahjong Video Hardware section
+
+*******************************************************************************************/
+
+#include "driver.h"
+
+static tilemap *bg_tilemap,*md_tilemap,*fg_tilemap,*tx_tilemap;
+UINT16 *sengokmj_bgvram,*sengokmj_mdvram,*sengokmj_fgvram,*sengokmj_txvram;
+
+WRITE16_HANDLER( sengokmj_bgvram_w )
+{
+ COMBINE_DATA(&sengokmj_bgvram[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE16_HANDLER( sengokmj_mdvram_w )
+{
+ COMBINE_DATA(&sengokmj_mdvram[offset]);
+ tilemap_mark_tile_dirty(md_tilemap,offset);
+}
+
+WRITE16_HANDLER( sengokmj_fgvram_w )
+{
+ COMBINE_DATA(&sengokmj_fgvram[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE16_HANDLER( sengokmj_txvram_w )
+{
+ COMBINE_DATA(&sengokmj_txvram[offset]);
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+static TILE_GET_INFO( sengoku_bg_tile_info )
+{
+ int tile = sengokmj_bgvram[tile_index];
+ int color = (tile >> 12) & 0x0f;
+ SET_TILE_INFO(1, tile & 0xfff, color, 0);
+}
+
+static TILE_GET_INFO( sengoku_md_tile_info )
+{
+ int tile = sengokmj_mdvram[tile_index];
+ int color = (tile >> 12) & 0x0f;
+ SET_TILE_INFO(1, (tile & 0xfff) + 0x1000, color + 0x10, 0);
+}
+
+static TILE_GET_INFO( sengoku_fg_tile_info )
+{
+ int tile = sengokmj_fgvram[tile_index];
+ int color = (tile >> 12) & 0x0f;
+ SET_TILE_INFO(1, (tile & 0xfff) + 0x2000, color + 0x20, 0);
+}
+
+static TILE_GET_INFO( sengoku_tx_tile_info )
+{
+ int tile = sengokmj_txvram[tile_index];
+ int color = (tile >> 12) & 0x0f;
+ SET_TILE_INFO(2, (tile & 0xfff) + 0x3000, color, 0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int pri)
+{
+ int offs,fx,fy,x,y,color,sprite;
+ int dx,dy,ax,ay;
+
+ for (offs = 0x400-4;offs >= 0;offs -= 4)
+ {
+ if ((spriteram16[offs+0]&0x8000)!=0x8000) continue;
+ sprite = spriteram16[offs+1];
+ if ((sprite>>14)!=pri) continue;
+ sprite &= 0x1fff;
+
+ y = spriteram16[offs+3];
+ x = 128 + spriteram16[offs+2];
+
+ if (x&0x8000) x=0-(0x200-(x&0x1ff));
+ //else x&=0x1ff;
+ if (y&0x8000) y=0-(0x200-(y&0x1ff));
+ //else y&=0x1ff;
+
+ color = spriteram16[offs+0]&0x3f;
+ fx = spriteram16[offs+0]&0x40;
+ fy = 0; /* To do - probably 0x2000 */
+ dy = ((spriteram16[offs+0]&0x0380)>>7) + 1;
+ dx = ((spriteram16[offs+0]&0x1c00)>>10) + 1;
+
+ for (ax=0; ax<dx; ax++)
+ for (ay=0; ay<dy; ay++) {
+ if (!fx)
+ drawgfx(bitmap,machine->gfx[0],
+ sprite++,
+ color,fx,fy,x+ax*16,y+ay*16,
+ cliprect,TRANSPARENCY_PEN,15);
+ else
+ drawgfx(bitmap,machine->gfx[0],
+ sprite++,
+ color,fx,fy,x+(dx-1-ax)*16,y+ay*16,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+}
+
+VIDEO_START( sengokmj )
+{
+ bg_tilemap = tilemap_create(sengoku_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,32,16);
+ md_tilemap = tilemap_create(sengoku_md_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,16);
+ fg_tilemap = tilemap_create(sengoku_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,16);
+ tx_tilemap = tilemap_create(sengoku_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+
+ tilemap_set_transparent_pen(md_tilemap,15);
+ tilemap_set_transparent_pen(fg_tilemap,15);
+ tilemap_set_transparent_pen(tx_tilemap,15);
+}
+
+VIDEO_UPDATE( sengokmj )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect, 2);
+ draw_sprites(machine, bitmap,cliprect, 1);
+ tilemap_draw(bitmap,cliprect,md_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect, 0);
+ draw_sprites(machine, bitmap,cliprect, 3);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/senjyo.c b/src/mame/video/senjyo.c
new file mode 100644
index 00000000000..ff24496b901
--- /dev/null
+++ b/src/mame/video/senjyo.c
@@ -0,0 +1,411 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "machine/segacrpt.h"
+
+UINT8 *senjyo_fgscroll;
+UINT8 *senjyo_scrollx1,*senjyo_scrolly1;
+UINT8 *senjyo_scrollx2,*senjyo_scrolly2;
+UINT8 *senjyo_scrollx3,*senjyo_scrolly3;
+UINT8 *senjyo_fgvideoram,*senjyo_fgcolorram;
+UINT8 *senjyo_bg1videoram,*senjyo_bg2videoram,*senjyo_bg3videoram;
+UINT8 *senjyo_radarram;
+UINT8 *senjyo_bgstripesram;
+
+static tilemap *fg_tilemap,*bg1_tilemap,*bg2_tilemap,*bg3_tilemap;
+
+static int senjyo, scrollhack;
+static int senjyo_bgstripes;
+
+
+DRIVER_INIT( starforc )
+{
+ senjyo = 0;
+ scrollhack = 1;
+}
+DRIVER_INIT( starfore )
+{
+ /* encrypted CPU */
+ suprloco_decode();
+
+ senjyo = 0;
+ scrollhack = 0;
+}
+DRIVER_INIT( senjyo )
+{
+ senjyo = 1;
+ scrollhack = 0;
+}
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 attr = senjyo_fgcolorram[tile_index];
+ int flags = (attr & 0x80) ? TILE_FLIPY : 0;
+
+ if (senjyo && (tile_index & 0x1f) >= 32-8)
+ flags |= TILE_FORCE_LAYER0;
+
+ SET_TILE_INFO(
+ 0,
+ senjyo_fgvideoram[tile_index] + ((attr & 0x10) << 4),
+ attr & 0x07,
+ flags);
+}
+
+static TILE_GET_INFO( senjyo_bg1_tile_info )
+{
+ UINT8 code = senjyo_bg1videoram[tile_index];
+ SET_TILE_INFO(
+ 1,
+ code,
+ (code & 0x70) >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( starforc_bg1_tile_info )
+{
+ /* Star Force has more tiles in bg1, so to get a uniform color code spread */
+ /* they wired bit 7 of the tile code in place of bit 4 to get the color code */
+ static int colormap[8] = { 0,2,4,6,1,3,5,7 };
+ UINT8 code = senjyo_bg1videoram[tile_index];
+ SET_TILE_INFO(
+ 1,
+ code,
+ colormap[(code & 0xe0) >> 5],
+ 0);
+}
+
+static TILE_GET_INFO( get_bg2_tile_info )
+{
+ UINT8 code = senjyo_bg2videoram[tile_index];
+ SET_TILE_INFO(
+ 2,
+ code,
+ (code & 0xe0) >> 5,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg3_tile_info )
+{
+ UINT8 code = senjyo_bg3videoram[tile_index];
+ SET_TILE_INFO(
+ 3,
+ code,
+ (code & 0xe0) >> 5,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( senjyo )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ if (senjyo)
+ {
+ bg1_tilemap = tilemap_create(senjyo_bg1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,16,32);
+ bg2_tilemap = tilemap_create(get_bg2_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,16,48); /* only 16x32 used by Star Force */
+ bg3_tilemap = tilemap_create(get_bg3_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,16,56); /* only 16x32 used by Star Force */
+ }
+ else
+ {
+ bg1_tilemap = tilemap_create(starforc_bg1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,16,32);
+ bg2_tilemap = tilemap_create(get_bg2_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,16,32); /* only 16x32 used by Star Force */
+ bg3_tilemap = tilemap_create(get_bg3_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,16,32); /* only 16x32 used by Star Force */
+ }
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_transparent_pen(bg1_tilemap,0);
+ tilemap_set_transparent_pen(bg2_tilemap,0);
+ tilemap_set_transparent_pen(bg3_tilemap,0);
+ tilemap_set_scroll_cols(fg_tilemap,32);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( senjyo_fgvideoram_w )
+{
+ senjyo_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+WRITE8_HANDLER( senjyo_fgcolorram_w )
+{
+ senjyo_fgcolorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+WRITE8_HANDLER( senjyo_bg1videoram_w )
+{
+ senjyo_bg1videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg1_tilemap,offset);
+}
+WRITE8_HANDLER( senjyo_bg2videoram_w )
+{
+ senjyo_bg2videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg2_tilemap,offset);
+}
+WRITE8_HANDLER( senjyo_bg3videoram_w )
+{
+ senjyo_bg3videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg3_tilemap,offset);
+}
+
+WRITE8_HANDLER( senjyo_bgstripes_w )
+{
+ *senjyo_bgstripesram = data;
+}
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_bgbitmap(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int x,y,pen,strwid,count;
+
+
+ if (senjyo_bgstripes == 0xff) /* off */
+ {
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ }
+ else
+ {
+ pen = 0;
+ count = 0;
+ strwid = senjyo_bgstripes;
+ if (strwid == 0) strwid = 0x100;
+ if (flip_screen) strwid ^= 0xff;
+
+ for (x = 0;x < 256;x++)
+ {
+ if (flip_screen)
+ {
+ for (y = 0;y < 256;y++)
+ *BITMAP_ADDR16(bitmap, y, 255 - x) = machine->pens[384 + pen];
+ }
+ else
+ {
+ for (y = 0;y < 256;y++)
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[384 + pen];
+ }
+
+ count += 0x10;
+ if (count >= strwid)
+ {
+ pen = (pen + 1) & 0x0f;
+ count -= strwid;
+ }
+ }
+ }
+}
+
+static void draw_radar(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs,x;
+
+ for (offs = 0;offs < 0x400;offs++)
+ {
+ if (senjyo_radarram[offs])
+ {
+ for (x = 0;x < 8;x++)
+ {
+ if (senjyo_radarram[offs] & (1 << x))
+ {
+ int sx, sy;
+
+ sx = (8 * (offs % 8) + x) + 256-64;
+ sy = ((offs & 0x1ff) / 8) + 96;
+
+ if (flip_screen)
+ {
+ sx = 255 - sx;
+ sy = 255 - sy;
+ }
+
+ if (sy >= cliprect->min_y && sy <= cliprect->max_y &&
+ sx >= cliprect->min_x && sx <= cliprect->max_x)
+ *BITMAP_ADDR16(bitmap, sy, sx) = machine->pens[offs < 0x200 ? 512 : 513];
+ }
+ }
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int priority)
+{
+ int offs;
+
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int big,sx,sy,flipx,flipy;
+
+ if (((spriteram[offs+1] & 0x30) >> 4) == priority)
+ {
+ if (senjyo) /* Senjyo */
+ big = (spriteram[offs] & 0x80);
+ else /* Star Force */
+ big = ((spriteram[offs] & 0xc0) == 0xc0);
+ sx = spriteram[offs+3];
+ if (big)
+ sy = 224-spriteram[offs+2];
+ else
+ sy = 240-spriteram[offs+2];
+ flipx = spriteram[offs+1] & 0x40;
+ flipy = spriteram[offs+1] & 0x80;
+
+ if (flip_screen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+
+ if (big)
+ {
+ sx = 224 - sx;
+ sy = 226 - sy;
+ }
+ else
+ {
+ sx = 240 - sx;
+ sy = 242 - sy;
+ }
+ }
+
+
+ drawgfx(bitmap,machine->gfx[big ? 5 : 4],
+ spriteram[offs],
+ spriteram[offs + 1] & 0x07,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( senjyo )
+{
+ int i;
+
+
+ /* two colors for the radar dots (verified on the real board) */
+ palette_set_color(machine,512,MAKE_RGB(0xff,0x00,0x00)); /* red for enemies */
+ palette_set_color(machine,513,MAKE_RGB(0xff,0xff,0x00)); /* yellow for player */
+
+ {
+ int scrollx,scrolly;
+
+ for (i = 0;i < 32;i++)
+ tilemap_set_scrolly(fg_tilemap,i,senjyo_fgscroll[i]);
+
+ scrollx = senjyo_scrollx1[0];
+ scrolly = senjyo_scrolly1[0] + 256 * senjyo_scrolly1[1];
+ if (flip_screen)
+ scrollx = -scrollx;
+ tilemap_set_scrollx(bg1_tilemap,0,scrollx);
+ tilemap_set_scrolly(bg1_tilemap,0,scrolly);
+
+ scrollx = senjyo_scrollx2[0];
+ scrolly = senjyo_scrolly2[0] + 256 * senjyo_scrolly2[1];
+ if (scrollhack) /* Star Force, but NOT the encrypted version */
+ {
+ scrollx = senjyo_scrollx1[0];
+ scrolly = senjyo_scrolly1[0] + 256 * senjyo_scrolly1[1];
+ }
+ if (flip_screen)
+ scrollx = -scrollx;
+ tilemap_set_scrollx(bg2_tilemap,0,scrollx);
+ tilemap_set_scrolly(bg2_tilemap,0,scrolly);
+
+ scrollx = senjyo_scrollx3[0];
+ scrolly = senjyo_scrolly3[0] + 256 * senjyo_scrolly3[1];
+ if (flip_screen)
+ scrollx = -scrollx;
+ tilemap_set_scrollx(bg3_tilemap,0,scrollx);
+ tilemap_set_scrolly(bg3_tilemap,0,scrolly);
+ }
+
+ draw_bgbitmap(machine, bitmap,cliprect);
+ draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,bg3_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect,1);
+ tilemap_draw(bitmap,cliprect,bg2_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect,2);
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect,3);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ draw_radar(machine, bitmap,cliprect);
+
+#if 0
+{
+ char baf[80];
+
+ sprintf(baf,"%02x %02x %02x %02x %02x %02x %02x %02x",
+ senjyo_scrolly3[0x00],
+ senjyo_scrolly3[0x01],
+ senjyo_scrolly3[0x02],
+ senjyo_scrolly3[0x03],
+ senjyo_scrolly3[0x04],
+ senjyo_scrolly3[0x05],
+ senjyo_scrolly3[0x06],
+ senjyo_scrolly3[0x07]);
+ ui_draw_text(baf,0,0);
+ sprintf(baf,"%02x %02x %02x %02x %02x %02x %02x %02x",
+ senjyo_scrolly3[0x08],
+ senjyo_scrolly3[0x09],
+ senjyo_scrolly3[0x0a],
+ senjyo_scrolly3[0x0b],
+ senjyo_scrolly3[0x0c],
+ senjyo_scrolly3[0x0d],
+ senjyo_scrolly3[0x0e],
+ senjyo_scrolly3[0x0f]);
+ ui_draw_text(baf,0,10);
+ sprintf(baf,"%02x %02x %02x %02x %02x %02x %02x %02x",
+ senjyo_scrolly3[0x10],
+ senjyo_scrolly3[0x11],
+ senjyo_scrolly3[0x12],
+ senjyo_scrolly3[0x13],
+ senjyo_scrolly3[0x14],
+ senjyo_scrolly3[0x15],
+ senjyo_scrolly3[0x16],
+ senjyo_scrolly3[0x17]);
+ ui_draw_text(baf,0,20);
+ sprintf(baf,"%02x %02x %02x %02x %02x %02x %02x %02x",
+ senjyo_scrolly3[0x18],
+ senjyo_scrolly3[0x19],
+ senjyo_scrolly3[0x1a],
+ senjyo_scrolly3[0x1b],
+ senjyo_scrolly3[0x1c],
+ senjyo_scrolly3[0x1d],
+ senjyo_scrolly3[0x1e],
+ senjyo_scrolly3[0x1f]);
+ ui_draw_text(baf,0,30);
+}
+#endif
+ return 0;
+}
diff --git a/src/mame/video/seta.c b/src/mame/video/seta.c
new file mode 100644
index 00000000000..c45565fea6b
--- /dev/null
+++ b/src/mame/video/seta.c
@@ -0,0 +1,965 @@
+/***************************************************************************
+
+ -= Seta Hardware =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z with:
+
+ Q shows layer 0
+ W shows layer 1
+ A shows the sprites
+
+ Keys can be used together!
+
+
+ [ 0, 1 Or 2 Scrolling Layers ]
+
+ Each layer consists of 2 tilemaps: only one can be displayed at a
+ given time (the games usually flip continuously between the two).
+ The two tilemaps share the same scrolling registers.
+
+ Layer Size: 1024 x 512
+ Tiles: 16x16x4 (16x16x6 in some games)
+ Tile Format:
+
+ Offset + 0x0000:
+ f--- ---- ---- ---- Flip X
+ -e-- ---- ---- ---- Flip Y
+ --dc ba98 7654 3210 Code
+
+ Offset + 0x1000:
+
+ fedc ba98 765- ---- -
+ ---- ---- ---4 3210 Color
+
+ The other tilemap for this layer (always?) starts at
+ Offset + 0x2000.
+
+
+ [ 1024 Sprites ]
+
+ Sprites are 16x16x4. They are just like those in "The Newzealand Story",
+ "Revenge of DOH" etc (tnzs.c). Obviously they're hooked to a 16 bit
+ CPU here, so they're mapped a bit differently in memory. Additionally,
+ there are two banks of sprites. The game can flip between the two to
+ do double buffering, writing to a bit of a control register(see below)
+
+
+ Spriteram16_2 + 0x000.w
+
+ f--- ---- ---- ---- Flip X
+ -e-- ---- ---- ---- Flip Y
+ --dc ba-- ---- ---- -
+ ---- --98 7654 3210 Code (Lower bits)
+
+ Spriteram16_2 + 0x400.w
+
+ fedc b--- ---- ---- Color
+ ---- -a9- ---- ---- Code (Upper Bits)
+ ---- ---8 7654 3210 X
+
+ Spriteram16 + 0x000.w
+
+ fedc ba98 ---- ---- -
+ ---- ---- 7654 3210 Y
+
+
+
+ [ Floating Tilemap ]
+
+ There's a floating tilemap made of vertical colums composed of 2x16
+ "sprites". Each 32 consecutive "sprites" define a column.
+
+ For column I:
+
+ Spriteram16_2 + 0x800 + 0x40 * I:
+
+ f--- ---- ---- ---- Flip X
+ -e-- ---- ---- ---- Flip Y
+ --dc b--- ---- ---- -
+ ---- --98 7654 3210 Code (Lower bits)
+
+ Spriteram16_2 + 0xc00 + 0x40 * I:
+
+ fedc b--- ---- ---- Color
+ ---- -a9- ---- ---- Code (Upper Bits)
+ ---- ---8 7654 3210 -
+
+ Each column has a variable horizontal position and a vertical scrolling
+ value (see also the Sprite Control Registers). For column I:
+
+
+ Spriteram16 + 0x400 + 0x20 * I:
+
+ fedc ba98 ---- ---- -
+ ---- ---- 7654 3210 Y
+
+ Spriteram16 + 0x408 + 0x20 * I:
+
+ fedc ba98 ---- ---- -
+ ---- ---- 7654 3210 Low Bits Of X
+
+
+
+ [ Sprites Control Registers ]
+
+
+ Spriteram16 + 0x601.b
+
+ 7--- ---- 0
+ -6-- ---- Flip Screen
+ --5- ---- 0
+ ---4 ---- 1 (Sprite Enable?)
+ ---- 3210 ???
+
+ Spriteram16 + 0x603.b
+
+ 7--- ---- 0
+ -6-- ---- Sprite Bank
+ --5- ---- 0 = Sprite Buffering (blandia,msgundam,qzkklogy)
+ ---4 ---- 0
+ ---- 3210 Columns To Draw (1 is the special value for 16)
+
+ Spriteram16 + 0x605.b
+
+ 7654 3210 High Bit Of X For Columns 7-0
+
+ Spriteram16 + 0x607.b
+
+ 7654 3210 High Bit Of X For Columns f-8
+
+
+
+
+***************************************************************************/
+
+#include "driver.h"
+#include "sound/x1_010.h"
+#include "seta.h"
+
+/* Variables only used here */
+
+static tilemap *tilemap_0, *tilemap_1; // Layer 0
+static tilemap *tilemap_2, *tilemap_3; // Layer 1
+static int tilemaps_flip;
+
+/* Variables used elsewhere */
+
+int seta_tiles_offset;
+
+UINT16 *seta_vram_0, *seta_vctrl_0;
+UINT16 *seta_vram_2, *seta_vram_3, *seta_vctrl_2;
+UINT16 *seta_vregs;
+
+UINT16 *seta_workram; // Used for zombraid crosshair hack
+
+static int twineagl_tilebank[4];
+static int seta_samples_bank;
+
+struct x_offset
+{
+ /* 2 values, for normal and flipped */
+ const char *gamename;
+ int sprite_offs[2];
+ int tilemap_offs[2];
+};
+
+/* note that drgnunit, stg and qzkklogy run on the same board, yet they need different alignment */
+static struct x_offset game_offsets[] =
+{
+ /* only sprites */
+ { "tndrcade", { -1, 0 } }, // correct (wall at beginning of game)
+ { "tndrcadj", { -1, 0 } }, // correct (wall at beginning of game)
+ { "wits", { 0, 0 } }, // unknown
+ { "thunderl", { 0, 0 } }, // unknown
+ { "wiggie", { 0, 0 } }, // some problems but they seem y co-ordinate related?
+ { "blockcar", { 0, 0 } }, // unknown
+ { "umanclub", { 0, 0 } }, // unknown
+ { "atehate", { 0, 0 } }, // correct (test grid)
+ { "kiwame", { 0,-16 } }, // correct (test grid)
+ { "krzybowl", { 0, 0 } }, // correct (test grid)
+
+ /* 1 layer */
+ { "twineagl", { 0, 0 }, { 0, -3 } }, // unknown
+ { "downtown", { 1, 0 }, { -1, 0 } }, // sprites correct (test grid), tilemap unknown but at least -1 non-flipped to fix glitches later in the game
+ { "usclssic", { 1, 2 }, { 0, -1 } }, // correct (test grid and bg)
+ { "calibr50", { -1, 2 }, { -3, -2 } }, // correct (test grid and roof in animation at beginning of game)
+ { "arbalest", { 0, 1 }, { -2, -1 } }, // correct (test grid and landing pad at beginning of game)
+ { "metafox", { 0, 0 }, { 16,-19 } }, // sprites unknown, tilemap correct (test grid)
+ { "drgnunit", { 2, 2 }, { -2, -2 } }, // correct (test grid and I/O test)
+ { "stg", { 0, 0 }, { -2, -2 } }, // sprites correct? (panel), tilemap correct (test grid)
+ { "qzkklogy", { 1, 1 }, { -1, -1 } }, // correct (timer, test grid)
+ { "qzkklgy2", { 0, 0 }, { -1, -3 } }, // sprites unknown, tilemaps correct (test grid)
+
+ /* 2 layers */
+ { "rezon", { 0, 0 }, { -2, -2 } }, // correct (test grid)
+ { "blandia", { 0, 8 }, { -2, 6 } }, // correct (test grid, startup bg)
+ { "blandiap", { 0, 8 }, { -2, 6 } }, // correct (test grid, startup bg)
+ { "zingzip", { 0, 0 }, { -1, -2 } }, // sprites unknown, tilemaps correct (test grid)
+ { "eightfrc", { 3, 4 }, { 0, 0 } }, // unknown
+ { "daioh", { 1, 1 }, { -1, -1 } }, // correct? (launch window and test grid are right, but planet is wrong)
+ { "msgundam", { 0, 0 }, { -2, -2 } }, // correct (test grid, banpresto logo)
+ { "msgunda1", { 0, 0 }, { -2, -2 } }, // correct (test grid, banpresto logo)
+ { "oisipuzl", { 0, 0 }, { -1, -1 } }, // correct (test mode) flip screen not supported?
+ { "triplfun", { 0, 0 }, { -1, -1 } }, // correct (test mode) flip screen not supported?
+ { "wrofaero", { 0, 0 }, { 0, 0 } }, // unknown
+ { "jjsquawk", { 1, 1 }, { -1, -1 } }, // correct (test mode)
+ { "kamenrid", { 0, 0 }, { -2, -2 } }, // correct (map, banpresto logo)
+ { "extdwnhl", { 0, 0 }, { -2, -2 } }, // correct (test grid, background images)
+ { "sokonuke", { 0, 0 }, { -2, -2 } }, // correct (game selection, test grid)
+ { "gundhara", { 0, 0 }, { 0, 0 } }, // unknown, flip screen not supported?
+ { "zombraid", { 0, 0 }, { -2, -2 } }, // correct for normal, flip screen not working yet
+ { "madshark", { 0, 0 }, { 0, 0 } }, // unknown (wrong when flipped, but along y)
+ { "utoukond", { 0, 0 }, { -2, 0 } }, // unknown (wrong when flipped, but along y)
+ { "crazyfgt", { 0, 0 }, { -2, 0 } }, // wrong (empty background column in title screen, but aligned sprites in screen select)
+ { NULL }
+};
+
+static struct x_offset *global_offsets;
+
+
+/* ---- 3--- Coin #1 Lock Out
+ ---- -2-- Coin #0 Lock Out
+ ---- --1- Coin #1 Counter
+ ---- ---0 Coin #0 Counter */
+
+void seta_coin_lockout_w(int data)
+{
+ static int seta_coin_lockout = 1;
+ static const game_driver *seta_driver = NULL;
+ static const char *seta_nolockout[8] = { "blandia", "gundhara", "kamenrid", "zingzip", "eightfrc", "extdwnhl", "sokonuke", "zombraid"};
+
+ /* Only compute seta_coin_lockout when confronted with a new gamedrv */
+ if (seta_driver != Machine->gamedrv)
+ {
+ int i;
+ seta_driver = Machine->gamedrv;
+
+ seta_coin_lockout = 1;
+ for (i=0; i<ARRAY_LENGTH(seta_nolockout); i++)
+ {
+ if (strcmp(seta_driver->name, seta_nolockout[i]) == 0 ||
+ strcmp(seta_driver->parent, seta_nolockout[i]) == 0)
+ {
+ seta_coin_lockout = 0;
+ break;
+ }
+ }
+ }
+
+ coin_counter_w (0, (( data) >> 0) & 1 );
+ coin_counter_w (1, (( data) >> 1) & 1 );
+
+ /* blandia, gundhara, kamenrid & zingzip haven't the coin lockout device */
+ if ( !seta_coin_lockout )
+ return;
+ coin_lockout_w (0, ((~data) >> 2) & 1 );
+ coin_lockout_w (1, ((~data) >> 3) & 1 );
+}
+
+
+WRITE16_HANDLER( seta_vregs_w )
+{
+ COMBINE_DATA(&seta_vregs[offset]);
+ switch (offset)
+ {
+ case 0/2:
+
+/* fedc ba98 76-- ----
+ ---- ---- --5- ---- Sound Enable
+ ---- ---- ---4 ---- toggled in IRQ1 by many games, irq acknowledge?
+ [original comment for the above: ?? 1 in oisipuzl, sokonuke (layers related)]
+ ---- ---- ---- 3--- Coin #1 Lock Out
+ ---- ---- ---- -2-- Coin #0 Lock Out
+ ---- ---- ---- --1- Coin #1 Counter
+ ---- ---- ---- ---0 Coin #0 Counter */
+ if (ACCESSING_LSB)
+ {
+ seta_coin_lockout_w (data & 0x0f);
+ if (sndti_exists(SOUND_X1_010, 0))
+ seta_sound_enable_w (data & 0x20);
+ coin_counter_w(0,data & 0x01);
+ coin_counter_w(1,data & 0x02);
+ }
+ break;
+
+ case 2/2:
+ if (ACCESSING_LSB)
+ {
+ int new_bank;
+
+ /* Partly handled in vh_screenrefresh:
+
+ fedc ba98 76-- ----
+ ---- ---- --54 3--- Samples Bank (in blandia, eightfrc, zombraid)
+ ---- ---- ---- -2--
+ ---- ---- ---- --1- Sprites Above Frontmost Layer
+ ---- ---- ---- ---0 Layer 0 Above Layer 1
+ */
+
+ new_bank = (data >> 3) & 0x7;
+
+ if (new_bank != seta_samples_bank)
+ {
+ UINT8 *rom = memory_region(REGION_SOUND1);
+ int samples_len = memory_region_length(REGION_SOUND1);
+ int addr;
+
+ seta_samples_bank = new_bank;
+
+ if (samples_len == 0x240000) /* blandia, eightfrc */
+ {
+ addr = 0x40000 * new_bank;
+ if (new_bank >= 3) addr += 0x40000;
+
+ if ( (samples_len > 0x100000) && ((addr+0x40000) <= samples_len) )
+ memcpy(&rom[0xc0000],&rom[addr],0x40000);
+ else
+ logerror("PC %06X - Invalid samples bank %02X !\n", activecpu_get_pc(), new_bank);
+ }
+ else if (samples_len == 0x480000) /* zombraid */
+ {
+ /* bank 1 is never explicitly selected, 0 is used in its place */
+ if (new_bank == 0) new_bank = 1;
+ addr = 0x80000 * new_bank;
+ if (new_bank > 0) addr += 0x80000;
+
+ memcpy(&rom[0x80000],&rom[addr],0x80000);
+ }
+ }
+
+ }
+ break;
+
+
+ case 4/2: // ?
+ break;
+ }
+}
+
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+ [ Tiles Format ]
+
+Offset + 0x0000:
+ f--- ---- ---- ---- Flip X
+ -e-- ---- ---- ---- Flip Y
+ --dc ba98 7654 3210 Code
+
+Offset + 0x1000:
+
+ fedc ba98 765- ---- -
+ ---- ---- ---4 3210 Color
+
+
+ [ TileMaps Control Registers]
+
+Offset + 0x0: Scroll X
+Offset + 0x2: Scroll Y
+Offset + 0x4:
+ fedc ba98 7654 3210 -
+ ---- ---- ---- 3--- Tilemap Select (There Are 2 Tilemaps Per Layer)
+ ---- ---- ---- -21- 0 (1 only in eightfrc, when flip is on!)
+ ---- ---- ---- ---0 ?
+
+***************************************************************************/
+
+INLINE void twineagl_tile_info( running_machine *machine, tile_data *tileinfo, int tile_index, UINT16 *vram )
+{
+ UINT16 code = vram[ tile_index ];
+ UINT16 attr = vram[ tile_index + 0x800 ];
+ if ((code & 0x3e00) == 0x3e00)
+ code = (code & 0xc07f) | ((twineagl_tilebank[(code & 0x0180) >> 7] >> 1) << 7);
+ SET_TILE_INFO( 1, (code & 0x3fff), attr & 0x1f, TILE_FLIPXY((code & 0xc000) >> 14) );
+}
+
+static TILE_GET_INFO( twineagl_get_tile_info_0 ) { twineagl_tile_info( machine, tileinfo, tile_index, seta_vram_0 + 0x0000 ); }
+static TILE_GET_INFO( twineagl_get_tile_info_1 ) { twineagl_tile_info( machine, tileinfo, tile_index, seta_vram_0 + 0x1000 ); }
+
+
+INLINE void get_tile_info( running_machine *machine, tile_data *tileinfo, int tile_index, int layer, UINT16 *vram )
+{
+ UINT16 code = vram[ tile_index ];
+ UINT16 attr = vram[ tile_index + 0x800 ];
+ SET_TILE_INFO( 1 + layer, seta_tiles_offset + (code & 0x3fff), attr & 0x1f, TILE_FLIPXY((code & 0xc000) >> 14) );
+}
+
+static TILE_GET_INFO( get_tile_info_0 ) { get_tile_info( machine, tileinfo, tile_index, 0, seta_vram_0 + 0x0000 ); }
+static TILE_GET_INFO( get_tile_info_1 ) { get_tile_info( machine, tileinfo, tile_index, 0, seta_vram_0 + 0x1000 ); }
+static TILE_GET_INFO( get_tile_info_2 ) { get_tile_info( machine, tileinfo, tile_index, 1, seta_vram_2 + 0x0000 ); }
+static TILE_GET_INFO( get_tile_info_3 ) { get_tile_info( machine, tileinfo, tile_index, 1, seta_vram_2 + 0x1000 ); }
+
+
+WRITE16_HANDLER( seta_vram_0_w )
+{
+ COMBINE_DATA(&seta_vram_0[offset]);
+ if (offset & 0x1000)
+ tilemap_mark_tile_dirty(tilemap_1, offset & 0x7ff);
+ else
+ tilemap_mark_tile_dirty(tilemap_0, offset & 0x7ff);
+}
+
+WRITE16_HANDLER( seta_vram_2_w )
+{
+ COMBINE_DATA(&seta_vram_2[offset]);
+ if (offset & 0x1000)
+ tilemap_mark_tile_dirty(tilemap_3, offset & 0x7ff);
+ else
+ tilemap_mark_tile_dirty(tilemap_2, offset & 0x7ff);
+}
+
+WRITE16_HANDLER( twineagl_tilebank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ data &= 0xff;
+ if (twineagl_tilebank[offset] != data)
+ {
+ twineagl_tilebank[offset] = data;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+ }
+}
+
+
+
+static void find_offsets(running_machine *machine)
+{
+ global_offsets = game_offsets;
+ while (global_offsets->gamename && strcmp(machine->gamedrv->name,global_offsets->gamename))
+ global_offsets++;
+}
+
+/* 2 layers */
+VIDEO_START( seta_2_layers )
+{
+ /* Each layer consists of 2 tilemaps: only one can be displayed
+ at any given time */
+
+ /* layer 0 */
+ tilemap_0 = tilemap_create( get_tile_info_0, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 64,32 );
+
+ tilemap_1 = tilemap_create( get_tile_info_1, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 64,32 );
+
+
+ /* layer 1 */
+ tilemap_2 = tilemap_create( get_tile_info_2, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 64,32 );
+
+ tilemap_3 = tilemap_create( get_tile_info_3, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 64,32 );
+
+ tilemaps_flip = 0;
+
+ tilemap_set_transparent_pen(tilemap_0,0);
+ tilemap_set_transparent_pen(tilemap_1,0);
+ tilemap_set_transparent_pen(tilemap_2,0);
+ tilemap_set_transparent_pen(tilemap_3,0);
+
+ find_offsets(machine);
+ seta_samples_bank = -1; // set the samples bank to an out of range value at start-up
+}
+
+
+/* 1 layer */
+VIDEO_START( seta_1_layer )
+{
+ /* Each layer consists of 2 tilemaps: only one can be displayed
+ at any given time */
+
+ /* layer 0 */
+ tilemap_0 = tilemap_create( get_tile_info_0, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 64,32 );
+
+ tilemap_1 = tilemap_create( get_tile_info_1, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 64,32 );
+
+
+ /* NO layer 1 */
+ tilemap_2 = 0;
+ tilemap_3 = 0;
+
+ tilemaps_flip = 0;
+
+ tilemap_set_transparent_pen(tilemap_0,0);
+ tilemap_set_transparent_pen(tilemap_1,0);
+
+ find_offsets(machine);
+ seta_samples_bank = -1; // set the samples bank to an out of range value at start-up
+}
+
+VIDEO_START( twineagl_1_layer )
+{
+ /* Each layer consists of 2 tilemaps: only one can be displayed
+ at any given time */
+
+ /* layer 0 */
+ tilemap_0 = tilemap_create( twineagl_get_tile_info_0, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 64,32 );
+
+ tilemap_1 = tilemap_create( twineagl_get_tile_info_1, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 64,32 );
+
+
+ /* NO layer 1 */
+ tilemap_2 = 0;
+ tilemap_3 = 0;
+
+ tilemaps_flip = 0;
+
+ tilemap_set_transparent_pen(tilemap_0,0);
+ tilemap_set_transparent_pen(tilemap_1,0);
+
+ find_offsets(machine);
+ seta_samples_bank = -1; // set the samples bank to an out of range value at start-up
+}
+
+
+/* NO layers, only sprites */
+VIDEO_START( seta_no_layers )
+{
+ tilemap_0 = 0;
+ tilemap_1 = 0;
+ tilemap_2 = 0;
+ tilemap_3 = 0;
+ find_offsets(machine);
+ seta_samples_bank = -1; // set the samples bank to an out of range value at start-up
+}
+
+VIDEO_START( oisipuzl_2_layers )
+{
+ video_start_seta_2_layers(machine);
+ tilemaps_flip = 1;
+}
+
+
+/***************************************************************************
+
+
+ Palette Init Functions
+
+
+***************************************************************************/
+
+
+/* 2 layers, 6 bit deep. The color codes have a 16 color granularity.
+
+ One layer repeats every 16 colors to fill the 64 colors for the 6bpp gfx
+
+ The other uses the first 64 colors of the palette regardless of
+ the color code!
+*/
+PALETTE_INIT( blandia )
+{
+ int color, pen;
+ for( color = 0; color < 32; color++ )
+ for( pen = 0; pen < 64; pen++ )
+ {
+ colortable[color * 64 + pen + 16*32] = (pen % 16) + color * 0x10 + 16*32*1;
+ colortable[color * 64 + pen + 16*32+64*32] = pen + 16*32*2;
+ }
+}
+
+
+
+/* layers have 6 bits per pixel, but the color code has a 16 colors granularity,
+ even if the low 2 bits are ignored (so there are only 4 different palettes) */
+PALETTE_INIT( gundhara )
+{
+ int color, pen;
+ for( color = 0; color < 32; color++ )
+ for( pen = 0; pen < 64; pen++ )
+ {
+ colortable[color * 64 + pen + 32*16 + 32*64*0] = (((color&~3) * 16 + pen)%(32*16)) + 32*16*2;
+ colortable[color * 64 + pen + 32*16 + 32*64*1] = (((color&~3) * 16 + pen)%(32*16)) + 32*16*1;
+ }
+}
+
+
+
+/* layers have 6 bits per pixel, but the color code has a 16 colors granularity */
+PALETTE_INIT( jjsquawk )
+{
+ int color, pen;
+ for( color = 0; color < 32; color++ )
+ for( pen = 0; pen < 64; pen++ )
+ {
+ colortable[color * 64 + pen + 32*16 + 32*64*0] = ((color * 16 + pen)%(32*16)) + 32*16*2;
+ colortable[color * 64 + pen + 32*16 + 32*64*1] = ((color * 16 + pen)%(32*16)) + 32*16*1;
+ }
+}
+
+
+/* layer 0 is 6 bit per pixel, but the color code has a 16 colors granularity */
+PALETTE_INIT( zingzip )
+{
+ int color, pen;
+ for( color = 0; color < 32; color++ )
+ for( pen = 0; pen < 64; pen++ )
+ colortable[color * 64 + pen + 32*16*2] = ((color * 16 + pen)%(32*16)) + 32*16*2;
+}
+
+
+
+
+PALETTE_INIT( usclssic )
+{
+ int color, pen;
+ int x;
+
+ /* DECODE PROM */
+ for (x = 0x000; x < 0x200 ; x++)
+ {
+ int data;
+
+ data = (color_prom[x*2] <<8) | color_prom[x*2+1];
+
+ if (x>=0x100) palette_set_color_rgb(machine,x,pal5bit(data >> 10),pal5bit(data >> 5),pal5bit(data >> 0));
+ else palette_set_color_rgb(machine,x+0x300,pal5bit(data >> 10),pal5bit(data >> 5),pal5bit(data >> 0));
+ }
+
+ for( color = 0; color < 32; color++ )
+ for( pen = 0; pen < 64; pen++ )
+ colortable[color * 64 + pen + 512] = ((((color & 0x1f) * 16 + pen)%512)+512);
+
+}
+
+
+
+
+
+/***************************************************************************
+
+
+ Sprites Drawing
+
+
+***************************************************************************/
+
+
+static void draw_sprites_map(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs, col;
+ int xoffs, yoffs;
+
+ int total_color_codes = machine->drv->gfxdecodeinfo[0].total_color_codes;
+
+ int ctrl = spriteram16[ 0x600/2 ];
+ int ctrl2 = spriteram16[ 0x602/2 ];
+
+ int flip = ctrl & 0x40;
+ int numcol = ctrl2 & 0x000f;
+
+ /* Sprites Banking and/or Sprites Buffering */
+ UINT16 *src = spriteram16_2 + ( ((ctrl2 ^ (~ctrl2<<1)) & 0x40) ? 0x2000/2 : 0 );
+
+ int upper = ( spriteram16[ 0x604/2 ] & 0xFF ) +
+ ( spriteram16[ 0x606/2 ] & 0xFF ) * 256;
+
+ int max_y = 0xf0;
+
+ int col0; /* Kludge, needed for krzybowl and kiwame */
+ switch (ctrl & 0x0f)
+ {
+ case 0x01: col0 = 0x4; break; // krzybowl
+ case 0x06: col0 = 0x8; break; // kiwame
+
+ default: col0 = 0x0;
+ }
+
+ xoffs = 0;
+ yoffs = flip ? 1 : -1;
+
+ /* Number of columns to draw - the value 1 seems special, meaning:
+ draw every column */
+ if (numcol == 1)
+ numcol = 16;
+
+
+ /* The first column is the frontmost, see twineagl test mode
+ BM 071204 - first column frontmost breaks superman.
+ */
+// for ( col = numcol - 1 ; col >= 0; col -- )
+ for ( col = 0 ; col < numcol; col ++ )
+ {
+ int x = spriteram16[(col * 0x20 + 0x08 + 0x400)/2] & 0xff;
+ int y = spriteram16[(col * 0x20 + 0x00 + 0x400)/2] & 0xff;
+
+ /* draw this column */
+ for ( offs = 0 ; offs < 0x40/2; offs += 2/2 )
+ {
+ int code = src[((col+col0)&0xf) * 0x40/2 + offs + 0x800/2];
+ int color = src[((col+col0)&0xf) * 0x40/2 + offs + 0xc00/2];
+
+ int flipx = code & 0x8000;
+ int flipy = code & 0x4000;
+
+ int bank = (color & 0x0600) >> 9;
+
+/*
+twineagl: 010 02d 0f 10 (ship)
+tndrcade: 058 02d 07 18 (start of game - yes, flip on!)
+arbalest: 018 02d 0f 10 (logo)
+metafox : 018 021 0f f0 (bomb)
+zingzip : 010 02c 00 0f (bomb)
+wrofaero: 010 021 00 ff (test mode)
+thunderl: 010 06c 00 ff (always?)
+krzybowl: 011 028 c0 ff (game)
+kiwame : 016 021 7f 00 (logo)
+oisipuzl: 059 020 00 00 (game - yes, flip on!)
+
+superman: 010 021 07 38 (game)
+twineagl: 000 027 00 0f (test mode)
+*/
+
+ int sx = x + xoffs + (offs & 1) * 16;
+ int sy = -(y + yoffs) + (offs / 2) * 16;
+
+ if (upper & (1 << col)) sx += 256;
+
+ if (flip)
+ {
+ sy = max_y - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ color = ( color >> (16-5) ) % total_color_codes;
+ code = (code & 0x3fff) + (bank * 0x4000);
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx, flipy,
+ ((sx + 0x10) & 0x1ff) - 0x10,((sy + 8) & 0x0ff) - 8,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ /* next column */
+ }
+
+}
+
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+ int xoffs, yoffs;
+
+ int total_color_codes = machine->drv->gfxdecodeinfo[0].total_color_codes;
+
+ int ctrl = spriteram16[ 0x600/2 ];
+ int ctrl2 = spriteram16[ 0x602/2 ];
+
+ int flip = ctrl & 0x40;
+
+ /* Sprites Banking and/or Sprites Buffering */
+ UINT16 *src = spriteram16_2 + ( ((ctrl2 ^ (~ctrl2<<1)) & 0x40) ? 0x2000/2 : 0 );
+
+ int max_y = 0xf0;
+
+
+ draw_sprites_map(machine,bitmap,cliprect);
+
+
+ xoffs = global_offsets->sprite_offs[flip ? 1 : 0];
+ yoffs = -2;
+
+ for ( offs = (0x400-2)/2 ; offs >= 0/2; offs -= 2/2 )
+ {
+ int code = src[offs + 0x000/2];
+ int x = src[offs + 0x400/2];
+
+ int y = spriteram16[offs + 0x000/2] & 0xff;
+
+ int flipx = code & 0x8000;
+ int flipy = code & 0x4000;
+
+ int bank = (x & 0x0600) >> 9;
+ int color = ( x >> (16-5) ) % total_color_codes;
+
+ if (flip)
+ {
+ y = (0x100 - machine->screen[0].height) + max_y - y;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ code = (code & 0x3fff) + (bank * 0x4000);
+
+ y = max_y - y;
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx, flipy,
+ ((x + xoffs + 0x10) & 0x1ff) - 0x10,((y - yoffs + 8) & 0x0ff) - 8,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+}
+
+
+
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+/* For games without tilemaps */
+VIDEO_UPDATE( seta_no_layers )
+{
+ fillbitmap(bitmap,machine->pens[0x1f0],cliprect);
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+
+/* For games with 1 or 2 tilemaps */
+VIDEO_UPDATE( seta )
+{
+ int layers_ctrl = -1;
+ int enab_0, enab_1, x_0, x_1, y_0, y_1;
+
+ int order = 0;
+ int flip = (spriteram16[ 0x600/2 ] & 0x40) >> 6;
+
+ int vis_dimy = machine->screen[0].visarea.max_y - machine->screen[0].visarea.min_y + 1;
+
+ flip ^= tilemaps_flip;
+
+ tilemap_set_flip(ALL_TILEMAPS, flip ? (TILEMAP_FLIPX|TILEMAP_FLIPY) : 0 );
+
+ x_0 = seta_vctrl_0[ 0/2 ];
+ y_0 = seta_vctrl_0[ 2/2 ];
+ enab_0 = seta_vctrl_0[ 4/2 ];
+
+ /* Only one tilemap per layer is enabled! */
+ tilemap_set_enable(tilemap_0, (!(enab_0 & 0x0008)) /*&& (enab_0 & 0x0001)*/ );
+ tilemap_set_enable(tilemap_1, ( (enab_0 & 0x0008)) /*&& (enab_0 & 0x0001)*/ );
+
+ /* the hardware wants different scroll values when flipped */
+
+ /* bg x scroll flip
+ metafox 0000 025d = 0, $400-$1a3 = $400 - $190 - $13
+ eightfrc ffe8 0272
+ fff0 0260 = -$10, $400-$190 -$10
+ ffe8 0272 = -$18, $400-$190 -$18 + $1a */
+
+ x_0 += 0x10 - global_offsets->tilemap_offs[flip ? 1 : 0];
+ y_0 -= (256 - vis_dimy)/2;
+ if (flip)
+ {
+ x_0 = -x_0 - 512;
+ y_0 = y_0 - vis_dimy;
+ }
+
+ tilemap_set_scrollx (tilemap_0, 0, x_0);
+ tilemap_set_scrollx (tilemap_1, 0, x_0);
+ tilemap_set_scrolly (tilemap_0, 0, y_0);
+ tilemap_set_scrolly (tilemap_1, 0, y_0);
+
+ if (tilemap_2)
+ {
+ x_1 = seta_vctrl_2[ 0/2 ];
+ y_1 = seta_vctrl_2[ 2/2 ];
+ enab_1 = seta_vctrl_2[ 4/2 ];
+
+ tilemap_set_enable(tilemap_2, (!(enab_1 & 0x0008)) /*&& (enab_1 & 0x0001)*/ );
+ tilemap_set_enable(tilemap_3, ( (enab_1 & 0x0008)) /*&& (enab_1 & 0x0001)*/ );
+
+ x_1 += 0x10 - global_offsets->tilemap_offs[flip ? 1 : 0];
+ y_1 -= (256 - vis_dimy)/2;
+ if (flip)
+ {
+ x_1 = -x_1 - 512;
+ y_1 = y_1 - vis_dimy;
+ }
+
+ tilemap_set_scrollx (tilemap_2, 0, x_1);
+ tilemap_set_scrollx (tilemap_3, 0, x_1);
+ tilemap_set_scrolly (tilemap_2, 0, y_1);
+ tilemap_set_scrolly (tilemap_3, 0, y_1);
+
+ order = seta_vregs[ 2/2 ];
+ }
+
+
+#ifdef MAME_DEBUG
+if (input_code_pressed(KEYCODE_Z))
+{ int msk = 0;
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+ if (input_code_pressed(KEYCODE_A)) msk |= 8;
+ if (msk != 0) layers_ctrl &= msk;
+
+ if (tilemap_2) popmessage("VR:%04X-%04X-%04X L0:%04X L1:%04X",seta_vregs[0],seta_vregs[1],seta_vregs[2],seta_vctrl_0[4/2],seta_vctrl_2[4/2]);
+ else if (tilemap_0) popmessage("L0:%04X",seta_vctrl_0[4/2]);
+}
+#endif
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ if (order & 1) // swap the layers?
+ {
+ if (tilemap_2)
+ {
+ if (layers_ctrl & 2) tilemap_draw(bitmap,cliprect, tilemap_2, TILEMAP_DRAW_OPAQUE, 0);
+ if (layers_ctrl & 2) tilemap_draw(bitmap,cliprect, tilemap_3, TILEMAP_DRAW_OPAQUE, 0);
+ }
+
+ if (order & 2) // layer-sprite priority?
+ {
+ if (layers_ctrl & 8) draw_sprites(machine,bitmap,cliprect);
+ if (layers_ctrl & 1) tilemap_draw(bitmap,cliprect, tilemap_0, 0, 0);
+ if (layers_ctrl & 1) tilemap_draw(bitmap,cliprect, tilemap_1, 0, 0);
+ }
+ else
+ {
+ if (layers_ctrl & 1) tilemap_draw(bitmap,cliprect, tilemap_0, 0, 0);
+ if (layers_ctrl & 1) tilemap_draw(bitmap,cliprect, tilemap_1, 0, 0);
+ if (layers_ctrl & 8) draw_sprites(machine, bitmap,cliprect);
+ }
+ }
+ else
+ {
+ if (layers_ctrl & 1) tilemap_draw(bitmap,cliprect, tilemap_0, TILEMAP_DRAW_OPAQUE, 0);
+ if (layers_ctrl & 1) tilemap_draw(bitmap,cliprect, tilemap_1, TILEMAP_DRAW_OPAQUE, 0);
+
+ if (order & 2) // layer-sprite priority?
+ {
+ if (layers_ctrl & 8) draw_sprites(machine, bitmap,cliprect);
+
+ if (tilemap_2)
+ {
+ if (layers_ctrl & 2) tilemap_draw(bitmap,cliprect, tilemap_2, 0, 0);
+ if (layers_ctrl & 2) tilemap_draw(bitmap,cliprect, tilemap_3, 0, 0);
+ }
+ }
+ else
+ {
+ if (tilemap_2)
+ {
+ if (layers_ctrl & 2) tilemap_draw(bitmap,cliprect, tilemap_2, 0, 0);
+ if (layers_ctrl & 2) tilemap_draw(bitmap,cliprect, tilemap_3, 0, 0);
+ }
+
+ if (layers_ctrl & 8) draw_sprites(machine, bitmap,cliprect);
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/seta2.c b/src/mame/video/seta2.c
new file mode 100644
index 00000000000..1f33316dd4f
--- /dev/null
+++ b/src/mame/video/seta2.c
@@ -0,0 +1,390 @@
+/***************************************************************************
+
+ -= Newer Seta Hardware =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+ This hardware only generates sprites. But they're of various types,
+ including some large "floating tilemap" ones.
+
+ Sprites RAM is 0x40000 bytes long. All games write the sprites list
+ at offset 0x3000. Each entry in the list holds data for a multi-sprite
+ of up to 256 single-sprites. The list looks like this:
+
+ Offset: Bits: Value:
+
+ 0.w f--- ---- ---- ---- Last sprite
+ -edc ---- ---- ---- ?
+ ---c ---- ---- ---- 0 = Each sprite specifies its size, 1 = use the size in the following words
+ ---- b--- ---- ---- ?
+ ---- -a98 ---- ---- tile color depth
+ ---- ---- 7654 3210 Number of sprites - 1
+
+ 2.w fedc ---- ---- ---- Number of tiles?
+ ---- ba-- ---- ---- Number of tiles along X (1 << n)
+ ---- --98 7654 3210 X displacement
+
+ 4.w fedc ---- ---- ---- Number of tiles?
+ ---- ba-- ---- ---- Number of tiles along Y (1 << n)
+ ---- --98 7654 3210 Y displacement
+
+ 6.w f--- ---- ---- ---- Single-sprite(s) type: tile (0) or row of tiles (1)
+ -edc ba98 7654 3210 Offset of the single-sprite(s) data
+
+
+ A single-sprite can be a tile or some horizontal rows of tiles.
+
+ Tile case:
+
+ 0.w fedc ---- ---- ---- Number of tiles?
+ ---- ba-- ---- ---- Number of tiles along X (1 << n)
+ ---- --98 7654 3210 X
+
+ 2.w fedc ---- ---- ---- Number of tiles?
+ ---- ba-- ---- ---- Number of tiles along Y (1 << n)
+ ---- --98 7654 3210 Y
+
+ 4.w fedc ba98 765- ---- Color code (16 color steps)
+ ---- ---- ---4 ---- Flip X
+ ---- ---- ---- 3--- Flip Y
+ ---- ---- ---- -210 Code (high bits)
+
+ 6.w Code (low bits)
+
+
+ Row case:
+
+ 0.w fedc ba-- ---- ----
+ ---- --98 7654 3210 X
+
+ 2.w fedc ba-- ---- ---- Number of rows - 1
+ ---- --98 7654 3210 Y
+
+ 4.w f--- ---- ---- ---- Tile size: 8x8 (0) or 16x16 (1)
+ -edc ba-- ---- ---- "Tilemap" page
+ ---- --98 7654 3210 "Tilemap" Scroll X
+
+ 6.w fedc ba9- ---- ----
+ ---- ---8 7654 3210 "Tilemap" Scroll Y
+
+***************************************************************************/
+
+#include "driver.h"
+#include "seta.h"
+
+UINT16 *seta2_vregs;
+
+static int yoffset;
+
+/***************************************************************************
+
+
+ Video Registers
+
+ Offset: Bits: Value:
+
+ 0/2/4/6 ? Horizontal
+ 8/a/c/e ? Vertical
+
+ 10
+ 12 Offset X?
+ 14 Zoom X? low bits
+ 16 Zoom X? high bits *
+
+ 18
+ 1a Offset Y?
+ 1c Zoom Y? low bits
+ 1e Zoom Y? high bits
+
+ 30 fedc ba98 7654 321-
+ ---- ---- ---- ---0 Disable video
+
+ 32..3f ?
+
+
+ * A value of 1 is means no zoom, a value of 2 will halve the size.
+ It's unknown whether a value less than 1 means magnification (probably yes)
+
+***************************************************************************/
+
+WRITE16_HANDLER( seta2_vregs_w )
+{
+ /* 02/04 = horizontal display start/end
+ mj4simai = 0065/01E5 (0180 visible area)
+ myangel = 005D/01D5 (0178 visible area)
+ pzlbowl = 0058/01D8 (0180 visible area)
+ penbros = 0065/01A5 (0140 visible area)
+ grdians = 0059/0188 (012f visible area)
+ 06 = horizontal total?
+ mj4simai = 0204
+ myangel = 0200
+ pzlbowl = 0204
+ penbros = 01c0
+ grdians = 019a
+ */
+
+ COMBINE_DATA(&seta2_vregs[offset]);
+ switch( offset*2 )
+ {
+ case 0x1c: // FLIP SCREEN (myangel) <- this is actually zoom
+ flip_screen_set( data & 1 );
+ if (data & ~1) logerror("CPU #0 PC %06X: flip screen unknown bits %04X\n",activecpu_get_pc(),data);
+ break;
+ case 0x2a: // FLIP X (pzlbowl)
+ flip_screen_x_set( data & 1 );
+ if (data & ~1) logerror("CPU #0 PC %06X: flipx unknown bits %04X\n",activecpu_get_pc(),data);
+ break;
+ case 0x2c: // FLIP Y (pzlbowl)
+ flip_screen_y_set( data & 1 );
+ if (data & ~1) logerror("CPU #0 PC %06X: flipy unknown bits %04X\n",activecpu_get_pc(),data);
+ break;
+
+ case 0x30: // BLANK SCREEN (pzlbowl, myangel)
+ if (data & ~1) logerror("CPU #0 PC %06X: blank unknown bits %04X\n",activecpu_get_pc(),data);
+ break;
+
+ default:
+ logerror("CPU #0 PC %06X: Video Reg %02X <- %04X\n",activecpu_get_pc(),offset*2,data);
+ }
+}
+
+
+/***************************************************************************
+
+
+ Sprites Drawing
+
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ /* Sprites list */
+
+ UINT16 *s1 = buffered_spriteram16 + 0x3000/2;
+ UINT16 *end = &buffered_spriteram16[spriteram_size/2];
+
+ for ( ; s1 < end; s1+=4 )
+ {
+ int gfx;
+ int num = s1[0];
+ int xoffs = s1[1];
+ int yoffs = s1[2];
+ int sprite = s1[3];
+
+ /* Single-sprite address */
+ UINT16 *s2 = &buffered_spriteram16[(sprite & 0x7fff) * 4];
+
+ /* Single-sprite tile size */
+ int global_sizex = xoffs & 0x0c00;
+ int global_sizey = yoffs & 0x0c00;
+
+ int use_global_size = num & 0x1000;
+
+ xoffs &= 0x3ff;
+ yoffs &= 0x3ff;
+
+ /* Color depth */
+ switch (num & 0x0700)
+ {
+ default:
+ popmessage("unknown gfxset %x",(num & 0x0700)>>8);
+ gfx = mame_rand(machine)&3; break;
+ case 0x0700: // 8bpp tiles (76543210)
+ gfx = 3; break;
+ case 0x0600: // 6bpp tiles (--543210) (myangel sliding blocks test)
+ gfx = 2; break;
+ case 0x0500: // 4bpp tiles (3210----)
+ gfx = 1; break;
+ case 0x0400: // 4bpp tiles (----3210)
+ gfx = 0; break;
+// case 0x0300:
+// unknown
+ case 0x0200: // 3bpp tiles? (-----210) (myangel "Graduate Tests")
+ gfx = 4; break;
+ case 0x0100: // 2bpp tiles??? (--10----) (myangel2 question bubble, myangel endgame)
+ gfx = 5; break;
+ case 0x0000: // no idea!
+ gfx = 0; break;
+ }
+
+ /* Number of single-sprites */
+ num = (num & 0x00ff) + 1;
+
+ for( ; num > 0; num--,s2+=4 )
+ {
+ if (s2 >= end) break;
+
+// "tilemap" sprite
+
+ if (sprite & 0x8000)
+ {
+ rectangle clip;
+ int dx,x,y;
+ int flipx;
+ int flipy;
+ int sx = s2[0];
+ int sy = s2[1];
+ int scrollx = s2[2];
+ int scrolly = s2[3];
+ int tilesize = (scrollx & 0x8000) >> 15;
+ int page = (scrollx & 0x7c00) >> 10;
+ int height = ((sy & 0xfc00) >> 10) + 1;
+
+ sx &= 0x3ff;
+ sy &= 0x1ff;
+ scrollx &= 0x3ff;
+ scrolly &= 0x1ff;
+
+ clip.min_y = (sy + yoffs) & 0x1ff;
+ clip.max_y = clip.min_y + height * 0x10 - 1;
+
+ if (clip.min_y > cliprect->max_y) continue;
+ if (clip.max_y < cliprect->min_y) continue;
+
+ clip.min_x = cliprect->min_x;
+ clip.max_x = cliprect->max_x;
+
+ if (clip.min_y < cliprect->min_y) clip.min_y = cliprect->min_y;
+ if (clip.max_y > cliprect->max_y) clip.max_y = cliprect->max_y;
+
+ dx = sx + (scrollx & 0x3ff) + xoffs + 0x10;
+
+ /* Draw the rows */
+ /* I don't think the following is entirely correct (when using 16x16
+ tiles x should probably loop from 0 to 0x20) but it seems to work
+ fine in all the games we have for now. */
+ for (y = 0; y < (0x40 >> tilesize); y++)
+ {
+ int py = ((scrolly - (y+1) * (8 << tilesize) + 0x10) & 0x1ff) - 0x10 - yoffset;
+
+ if (py < clip.min_y - 0x10) continue;
+ if (py > clip.max_y) continue;
+
+ for (x = 0; x < 0x40;x++)
+ {
+ int px = ((dx + x * (8 << tilesize) + 0x10) & 0x3ff) - 0x10;
+ int tx, ty;
+ int attr, code, color;
+ UINT16 *s3;
+
+ if (px < clip.min_x - 0x10) continue;
+ if (px > clip.max_x) continue;
+
+ s3 = &buffered_spriteram16[2 * ((page * 0x2000/4) + ((y & 0x1f) << 6) + (x & 0x03f))];
+
+ attr = s3[0];
+ code = s3[1] + ((attr & 0x0007) << 16);
+ flipx = (attr & 0x0010);
+ flipy = (attr & 0x0008);
+ color = (attr & 0xffe0) >> 5;
+
+ if (tilesize) code &= ~3;
+
+ for (ty = 0; ty <= tilesize; ty++)
+ {
+ for (tx = 0; tx <= tilesize; tx++)
+ {
+ drawgfx(bitmap, machine->gfx[gfx],
+ code ^ tx ^ (ty<<1),
+ color,
+ flipx, flipy,
+ px + (flipx ? tilesize-tx : tx) * 8, py + (flipy ? tilesize-ty : ty) * 8,
+ cliprect,TRANSPARENCY_PEN,0 );
+ }
+ }
+
+ }
+ }
+ }
+ else
+// "normal" sprite
+ {
+ int sx = s2[0];
+ int sy = s2[1];
+ int attr = s2[2];
+ int code = s2[3] + ((attr & 0x0007) << 16);
+ int flipx = (attr & 0x0010);
+ int flipy = (attr & 0x0008);
+ int color = (attr & 0xffe0) >> 5;
+
+ int sizex = use_global_size ? global_sizex : sx;
+ int sizey = use_global_size ? global_sizey : sy;
+ int x,y;
+ sizex = (1 << ((sizex & 0x0c00)>> 10))-1;
+ sizey = (1 << ((sizey & 0x0c00)>> 10))-1;
+
+
+ sx += xoffs;
+ sy += yoffs;
+
+ sx = (sx & 0x1ff) - (sx & 0x200);
+ sy &= 0x1ff;
+ sy -= yoffset;
+
+ code &= ~((sizex+1) * (sizey+1) - 1); // see myangel, myangel2 and grdians
+
+ for (y = 0; y <= sizey; y++)
+ {
+ for (x = 0; x <= sizex; x++)
+ {
+ drawgfx(bitmap, machine->gfx[gfx],
+ code++,
+ color,
+ flipx, flipy,
+ sx + (flipx ? sizex-x : x) * 8, sy + (flipy ? sizey-y : y) * 8,
+ cliprect,TRANSPARENCY_PEN,0 );
+ }
+ }
+ }
+ }
+
+ if (s1[0] & 0x8000) break; /* end of list marker */
+ } /* sprite list */
+}
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+VIDEO_START( seta2 )
+{
+ machine->gfx[2]->color_granularity = 16;
+ machine->gfx[3]->color_granularity = 16;
+ machine->gfx[4]->color_granularity = 16;
+ machine->gfx[5]->color_granularity = 16;
+
+ buffered_spriteram16 = auto_malloc(spriteram_size);
+
+ yoffset = 0;
+}
+
+VIDEO_START( seta2_offset )
+{
+ video_start_seta2(machine);
+
+ yoffset = 0x10;
+}
+
+VIDEO_UPDATE( seta2 )
+{
+ /* Black or pens[0]? */
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ if (seta2_vregs[0x30/2] & 1) return 0; // BLANK SCREEN
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_EOF( seta2 )
+{
+ /* Buffer sprites by 1 frame */
+ memcpy(buffered_spriteram16,spriteram16,spriteram_size);
+}
diff --git a/src/mame/video/sf.c b/src/mame/video/sf.c
new file mode 100644
index 00000000000..d358cdcf846
--- /dev/null
+++ b/src/mame/video/sf.c
@@ -0,0 +1,240 @@
+#include "driver.h"
+
+
+UINT16 *sf_objectram,*sf_videoram;
+
+static int sf_active = 0;
+
+static tilemap *bg_tilemap, *fg_tilemap, *tx_tilemap;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 *base = memory_region(REGION_GFX5) + 2*tile_index;
+ int attr = base[0x10000];
+ int color = base[0];
+ int code = (base[0x10000+1]<<8) | base[1];
+ SET_TILE_INFO(
+ 0,
+ code,
+ color,
+ TILE_FLIPYX(attr & 3));
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 *base = memory_region(REGION_GFX5) + 0x20000 + 2*tile_index;
+ int attr = base[0x10000];
+ int color = base[0];
+ int code = (base[0x10000+1]<<8) | base[1];
+ SET_TILE_INFO(
+ 1,
+ code,
+ color,
+ TILE_FLIPYX(attr & 3));
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int code = sf_videoram[tile_index];
+ SET_TILE_INFO(
+ 3,
+ code & 0x3ff,
+ code>>12,
+ TILE_FLIPYX((code & 0xc00)>>10));
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( sf )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 16,16,2048,16);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,2048,16);
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8, 64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,15);
+ tilemap_set_transparent_pen(tx_tilemap,3);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( sf_videoram_w )
+{
+ COMBINE_DATA(&sf_videoram[offset]);
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+WRITE16_HANDLER( sf_bg_scroll_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrollx(bg_tilemap,0,scroll);
+}
+
+WRITE16_HANDLER( sf_fg_scroll_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrollx(fg_tilemap,0,scroll);
+}
+
+WRITE16_HANDLER( sf_gfxctrl_w )
+{
+/* b0 = reset, or maybe "set anyway" */
+/* b1 = pulsed when control6.b6==0 until it's 1 */
+/* b2 = active when dip 8 (flip) on */
+/* b3 = active character plane */
+/* b4 = unused */
+/* b5 = active background plane */
+/* b6 = active middle plane */
+/* b7 = active sprites */
+ if (ACCESSING_LSB)
+ {
+ sf_active = data & 0xff;
+ flip_screen_set(data & 0x04);
+ tilemap_set_enable(tx_tilemap,data & 0x08);
+ tilemap_set_enable(bg_tilemap,data & 0x20);
+ tilemap_set_enable(fg_tilemap,data & 0x40);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+INLINE int sf_invert(int nb)
+{
+ static int delta[4] = {0x00, 0x18, 0x18, 0x00};
+ return nb ^ delta[(nb >> 3) & 3];
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0x1000-0x20;offs >= 0;offs -= 0x20)
+ {
+ int c = sf_objectram[offs];
+ int attr = sf_objectram[offs+1];
+ int sy = sf_objectram[offs+2];
+ int sx = sf_objectram[offs+3];
+ int color = attr & 0x000f;
+ int flipx = attr & 0x0100;
+ int flipy = attr & 0x0200;
+
+ if (attr & 0x400) /* large sprite */
+ {
+ int c1,c2,c3,c4,t;
+
+ if (flip_screen)
+ {
+ sx = 480 - sx;
+ sy = 224 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ c1 = c;
+ c2 = c+1;
+ c3 = c+16;
+ c4 = c+17;
+
+ if (flipx)
+ {
+ t = c1; c1 = c2; c2 = t;
+ t = c3; c3 = c4; c4 = t;
+ }
+ if (flipy)
+ {
+ t = c1; c1 = c3; c3 = t;
+ t = c2; c2 = c4; c4 = t;
+ }
+
+ drawgfx(bitmap,
+ machine->gfx[2],
+ sf_invert(c1),
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect, TRANSPARENCY_PEN, 15);
+ drawgfx(bitmap,
+ machine->gfx[2],
+ sf_invert(c2),
+ color,
+ flipx,flipy,
+ sx+16,sy,
+ cliprect, TRANSPARENCY_PEN, 15);
+ drawgfx(bitmap,
+ machine->gfx[2],
+ sf_invert(c3),
+ color,
+ flipx,flipy,
+ sx,sy+16,
+ cliprect, TRANSPARENCY_PEN, 15);
+ drawgfx(bitmap,
+ machine->gfx[2],
+ sf_invert(c4),
+ color,
+ flipx,flipy,
+ sx+16,sy+16,
+ cliprect, TRANSPARENCY_PEN, 15);
+ }
+ else
+ {
+ if (flip_screen)
+ {
+ sx = 496 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,
+ machine->gfx[2],
+ sf_invert(c),
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect, TRANSPARENCY_PEN, 15);
+ }
+ }
+}
+
+
+VIDEO_UPDATE( sf )
+{
+ if (sf_active & 0x20)
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ else
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+
+ if (sf_active & 0x80)
+ draw_sprites(machine,bitmap,cliprect);
+
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/shadfrce.c b/src/mame/video/shadfrce.c
new file mode 100644
index 00000000000..1b99dddacf7
--- /dev/null
+++ b/src/mame/video/shadfrce.c
@@ -0,0 +1,180 @@
+#include "driver.h"
+
+static tilemap *shadfrce_fgtilemap, *shadfrce_bg0tilemap, *shadfrce_bg1tilemap;
+extern UINT16 *shadfrce_fgvideoram, *shadfrce_bg0videoram, *shadfrce_bg1videoram, *shadfrce_spvideoram;
+/* extern UINT16 *shadfrce_videoregs; */
+
+static UINT16 *shadfrce_spvideoram_old; /* I *think* the sprites need to be delayed anyway */
+
+
+static TILE_GET_INFO( get_shadfrce_fgtile_info )
+{
+
+ /* ---- ---- tttt tttt ---- ---- pppp TTTT */
+ int tileno, colour;
+
+ tileno = (shadfrce_fgvideoram[tile_index *2] & 0x00ff) | ((shadfrce_fgvideoram[tile_index *2+1] & 0x000f) << 8);
+ colour = (shadfrce_fgvideoram[tile_index *2+1] & 0x00f0) >>4;
+
+ SET_TILE_INFO(0,tileno,colour*4,0);
+}
+
+WRITE16_HANDLER( shadfrce_fgvideoram_w )
+{
+ shadfrce_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(shadfrce_fgtilemap,offset/2);
+}
+
+static TILE_GET_INFO( get_shadfrce_bg0tile_info )
+{
+
+ /* ---- ---- ---- cccc --TT TTTT TTTT TTTT */
+ int tileno, colour,fyx;
+
+ tileno = (shadfrce_bg0videoram[tile_index *2+1] & 0x3fff);
+ colour = shadfrce_bg0videoram[tile_index *2] & 0x001f;
+ if (colour & 0x10) colour ^= 0x30; /* skip hole */
+ fyx = (shadfrce_bg0videoram[tile_index *2] & 0x00c0) >>6;
+
+ SET_TILE_INFO(2,tileno,colour,TILE_FLIPYX(fyx));
+}
+
+WRITE16_HANDLER( shadfrce_bg0videoram_w )
+{
+ shadfrce_bg0videoram[offset] = data;
+ tilemap_mark_tile_dirty(shadfrce_bg0tilemap,offset/2);
+}
+
+static TILE_GET_INFO( get_shadfrce_bg1tile_info )
+{
+ int tileno, colour;
+
+ tileno = (shadfrce_bg1videoram[tile_index] & 0x0fff);
+ colour = (shadfrce_bg1videoram[tile_index] & 0xf000) >> 12;
+
+ SET_TILE_INFO(2,tileno,colour+64,0);
+}
+
+WRITE16_HANDLER( shadfrce_bg1videoram_w )
+{
+ shadfrce_bg1videoram[offset] = data;
+ tilemap_mark_tile_dirty(shadfrce_bg1tilemap,offset);
+}
+
+
+
+
+VIDEO_START( shadfrce )
+{
+ shadfrce_fgtilemap = tilemap_create(get_shadfrce_fgtile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ tilemap_set_transparent_pen(shadfrce_fgtilemap,0);
+
+ shadfrce_bg0tilemap = tilemap_create(get_shadfrce_bg0tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+ tilemap_set_transparent_pen(shadfrce_bg0tilemap,0);
+
+ shadfrce_bg1tilemap = tilemap_create(get_shadfrce_bg1tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+
+ shadfrce_spvideoram_old = auto_malloc(spriteram_size);
+}
+
+WRITE16_HANDLER ( shadfrce_bg0scrollx_w )
+{
+ tilemap_set_scrollx( shadfrce_bg0tilemap, 0, data & 0x1ff );
+}
+
+WRITE16_HANDLER ( shadfrce_bg0scrolly_w )
+{
+ tilemap_set_scrolly( shadfrce_bg0tilemap, 0, data & 0x1ff );
+}
+
+WRITE16_HANDLER ( shadfrce_bg1scrollx_w )
+{
+ tilemap_set_scrollx( shadfrce_bg1tilemap, 0, data & 0x1ff );
+}
+
+WRITE16_HANDLER ( shadfrce_bg1scrolly_w )
+{
+ tilemap_set_scrolly( shadfrce_bg1tilemap, 0, data & 0x1ff );
+}
+
+
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+
+ /* | ---- ---- hhhf Fe-Y | ---- ---- yyyy yyyy | ---- ---- TTTT TTTT | ---- ---- tttt tttt |
+ | ---- ---- -pCc cccX | ---- ---- xxxx xxxx | ---- ---- ---- ---- | ---- ---- ---- ---- | */
+
+ /* h = height
+ f = flipx
+ F = flipy
+ e = enable
+ Yy = Y Position
+ Tt = Tile No.
+ Xx = X Position
+ Cc = color
+ P = priority
+ */
+
+ const gfx_element *gfx = machine->gfx[1];
+ UINT16 *finish = shadfrce_spvideoram_old;
+ UINT16 *source = finish + 0x2000/2 - 8;
+ int hcount;
+ while( source>=finish )
+ {
+ int ypos = 0x100 - (((source[0] & 0x0003) << 8) | (source[1] & 0x00ff));
+ int xpos = (((source[4] & 0x0001) << 8) | (source[5] & 0x00ff)) + 1;
+ int tile = ((source[2] & 0x00ff) << 8) | (source[3] & 0x00ff);
+ int height = (source[0] & 0x00e0) >> 5;
+ int enable = ((source[0] & 0x0004));
+ int flipx = ((source[0] & 0x0010) >> 4);
+ int flipy = ((source[0] & 0x0008) >> 3);
+ int pal = ((source[4] & 0x003e));
+ int pri_mask = (source[4] & 0x0040) ? 0x02 : 0x00;
+
+ if (pal & 0x20) pal ^= 0x60; /* skip hole */
+
+ height++;
+ if (enable) {
+ for (hcount=0;hcount<height;hcount++) {
+ pdrawgfx(bitmap,gfx,tile+hcount,pal,flipx,flipy,xpos,ypos-hcount*16-16,cliprect,TRANSPARENCY_PEN,0,pri_mask);
+ pdrawgfx(bitmap,gfx,tile+hcount,pal,flipx,flipy,xpos-0x200,ypos-hcount*16-16,cliprect,TRANSPARENCY_PEN,0,pri_mask);
+ pdrawgfx(bitmap,gfx,tile+hcount,pal,flipx,flipy,xpos,ypos-hcount*16-16+0x200,cliprect,TRANSPARENCY_PEN,0,pri_mask);
+ pdrawgfx(bitmap,gfx,tile+hcount,pal,flipx,flipy,xpos-0x200,ypos-hcount*16-16+0x200,cliprect,TRANSPARENCY_PEN,0,pri_mask);
+ }
+ }
+ source-=8;
+ }
+}
+
+VIDEO_UPDATE( shadfrce )
+{
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,shadfrce_bg1tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,shadfrce_bg0tilemap,0,1);
+
+ draw_sprites(machine, bitmap,cliprect);
+
+ tilemap_draw(bitmap,cliprect,shadfrce_fgtilemap, 0,0);
+
+/*
+ popmessage ("Regs %04x %04x %04x %04x %04x %04x %04x",
+ shadfrce_videoregs[0],
+ shadfrce_videoregs[1],
+ shadfrce_videoregs[2],
+ shadfrce_videoregs[3],
+ shadfrce_videoregs[4],
+ shadfrce_videoregs[5],
+ shadfrce_videoregs[6]);
+*/
+
+ return 0;
+}
+
+VIDEO_EOF( shadfrce )
+{
+ /* looks like sprites are *two* frames ahead */
+ memcpy(shadfrce_spvideoram_old,shadfrce_spvideoram,spriteram_size);
+}
diff --git a/src/mame/video/shangha3.c b/src/mame/video/shangha3.c
new file mode 100644
index 00000000000..94e15386cf8
--- /dev/null
+++ b/src/mame/video/shangha3.c
@@ -0,0 +1,268 @@
+/***************************************************************************
+
+Custom blitter GA9201 KA01-0249 (120pin IC)
+
+
+This is a tile-based blitter that writes to a frame buffer. The buffer is
+never cleared, so stuff drawn is left over from frame to frame until it is
+overwritten.
+
+Tiles are stored in ROM and have a fixed 16x16 size. The blitter can draw them
+as single sprites (composed of one or more tiles in the horizontal direction),
+or as larger sprites whose tile codes are picked from a tilemap in RAM.
+
+Sprites can be zoomed, distorted and rotated.
+
+Shadows are supported on pen 14 (shangha3 makes heavy use of them) but it's not
+clear how they are turned on and off. heberpop definitely doesn't use them,
+pen 14 is supposed to be solid black (outlines).
+
+The chip addresses 0x100000 bytes of memory, containing both the command list,
+tilemap, and spare RAM to be used by the CPU.
+
+The command list starts at a variable point in memory, set by
+shangha3_gfxlist_addr_w(), and always ends at 0x0fffff.
+
+Large sprites refer to a single tilemap starting at 0x000000, the command list
+contains the coordinates of the place in the tilemap to pick data from.
+
+The commands list is processed when shangha3_blitter_go_w() is written to, so
+it is not processed automatically every frame.
+
+The commands have a fixed length of 16 words. The format is as follows:
+
+Word | Bit(s) | Use
+-----+-fedcba9876543210-+----------------
+ 0 | ---------------- | unused?
+ 1 | xxxx------------ | high bits of tile #; for tilemaps, this is applied to all tiles
+ 1 | ----xxxxxxxxxxxx | low bits of tile #; probably unused for tilemaps
+ 2 | ---xxxxxxxxx---- | x coordinate of destination top left corner
+ 3 | ---xxxxxxxxx---- | y coordinate of destination top left corner
+ 4 | ------------x--- | 0 = use code as-is 1 = fetch codes from tilemap RAM
+ 4 | -------------x-- | 1 = draw "compressed" tilemap, as if tiles were 8x8 instead of 16x16
+ 4 | --------------x- | flip y
+ 4 | ---------------x | flip x
+ 5 | --------x------- | unknown (used by blocken)
+ 5 | ---------xxx---- | high bits of color #; for tilemaps, this is applied to all tiles
+ 5 | ------------xxxx | low bits of color #; probably unused for tilemaps
+ 6 | xxxxxxxxxxxxxxxx | width-1 of destination rectangle \ if *both* of these are 0,
+ 7 | xxxxxxxxxxxxxxxx | height-1 of destination rectangle / disable sprite
+ 8 | xxxxxxxxxxxxxxxx | x coordinate*0x10 of source top left corner (tilemaps only?)
+ 9 | xxxxxxxxxxxxxxxx | y coordinate*0x10 of source top left corner (tilemaps only?)
+ a | xxxxxxxxxxxxxxxx | x zoom
+ b | xxxxxxxxxxxxxxxx | rotation
+ c | xxxxxxxxxxxxxxxx | rotation
+ d | xxxxxxxxxxxxxxxx | x zoom
+ e | ---------------- | unknown
+ f | ---------------- | unknown
+
+***************************************************************************/
+
+#include "driver.h"
+#include "profiler.h"
+
+
+UINT16 *shangha3_ram;
+size_t shangha3_ram_size;
+
+int shangha3_do_shadows;
+
+static UINT16 gfxlist_addr;
+static mame_bitmap *rawbitmap;
+
+
+
+VIDEO_START( shangha3 )
+{
+ rawbitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ if (shangha3_do_shadows)
+ {
+ int i;
+
+ /* Prepare the shadow table */
+ /* We draw in a raw bitmap so we don't have to remap pens through machine->pens */
+ for (i = 0;i < 14;i++)
+ gfx_drawmode_table[i] = DRAWMODE_SOURCE;
+ gfx_drawmode_table[14] = DRAWMODE_SHADOW;
+ for (i = 0;i < 128;i++)
+ machine->shadow_table[machine->pens[i]] = machine->pens[i+128];
+ }
+}
+
+
+
+WRITE16_HANDLER( shangha3_flipscreen_w )
+{
+ if (ACCESSING_LSB)
+ {
+ /* bit 7 flips screen, the rest seems to always be set to 0x7e */
+ flip_screen_set(data & 0x80);
+
+ if ((data & 0x7f) != 0x7e) popmessage("flipscreen_w %02x",data);
+ }
+}
+
+WRITE16_HANDLER( shangha3_gfxlist_addr_w )
+{
+ COMBINE_DATA(&gfxlist_addr);
+}
+
+
+WRITE16_HANDLER( shangha3_blitter_go_w )
+{
+ int offs;
+
+
+ profiler_mark(PROFILER_VIDEO);
+
+ for (offs = gfxlist_addr << 3;offs < shangha3_ram_size/2;offs += 16)
+ {
+ int sx,sy,x,y,code,color,flipx,flipy,sizex,sizey,zoomx,zoomy;
+
+
+ code = shangha3_ram[offs+1];
+ color = shangha3_ram[offs+5] & 0x7f;
+ flipx = shangha3_ram[offs+4] & 0x01;
+ flipy = shangha3_ram[offs+4] & 0x02;
+ sx = (shangha3_ram[offs+2] & 0x1ff0) >> 4;
+ if (sx >= 0x180) sx -= 0x200;
+ sy = (shangha3_ram[offs+3] & 0x1ff0) >> 4;
+ if (sy >= 0x100) sy -= 0x200;
+ sizex = shangha3_ram[offs+6];
+ sizey = shangha3_ram[offs+7];
+ zoomx = shangha3_ram[offs+10];
+ zoomy = shangha3_ram[offs+13];
+
+ if (flip_screen)
+ {
+ sx = 383 - sx - sizex;
+ sy = 255 - sy - sizey;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if ((sizex || sizey)
+ /* avoid garbage on startup */
+&& sizex < 512 && sizey < 256 && zoomx < 0x1f0 && zoomy < 0x1f0)
+ {
+ rectangle myclip;
+
+//if (shangha3_ram[offs+11] || shangha3_ram[offs+12])
+//logerror("offs %04x: sx %04x sy %04x zoom %04x %04x %04x %04x fx %d fy %d\n",offs,sx,sy,zoomx,shangha3_ram[offs+11]),shangha3_ram[offs+12],zoomy,flipx,flipy);
+
+ myclip.min_x = sx;
+ myclip.max_x = sx + sizex;
+ myclip.min_y = sy;
+ myclip.max_y = sy + sizey;
+
+ if (shangha3_ram[offs+4] & 0x08) /* tilemap */
+ {
+ int srcx,srcy,dispx,dispy,w,h,condensed;
+
+ condensed = shangha3_ram[offs+4] & 0x04;
+
+ srcx = shangha3_ram[offs+8]/16;
+ srcy = shangha3_ram[offs+9]/16;
+ dispx = srcx & 0x0f;
+ dispy = srcy & 0x0f;
+
+ h = (sizey+15)/16+1;
+ w = (sizex+15)/16+1;
+
+ if (condensed)
+ {
+ h *= 2;
+ w *= 2;
+ srcx /= 8;
+ srcy /= 8;
+ }
+ else
+ {
+ srcx /= 16;
+ srcy /= 16;
+ }
+
+ for (y = 0;y < h;y++)
+ {
+ for (x = 0;x < w;x++)
+ {
+ int dx,dy,tile;
+
+ if (condensed)
+ {
+ int addr = ((y+srcy) & 0x1f) +
+ 0x20 * ((x+srcx) & 0xff);
+ tile = shangha3_ram[addr];
+ dx = 8*x*(0x200-zoomx)/0x100 - dispx;
+ dy = 8*y*(0x200-zoomy)/0x100 - dispy;
+ }
+ else
+ {
+ int addr = ((y+srcy) & 0x0f) +
+ 0x10 * ((x+srcx) & 0xff) +
+ 0x100 * ((y+srcy) & 0x10);
+ tile = shangha3_ram[addr];
+ dx = 16*x*(0x200-zoomx)/0x100 - dispx;
+ dy = 16*y*(0x200-zoomy)/0x100 - dispy;
+ }
+
+ if (flipx) dx = sx + sizex-15 - dx;
+ else dx = sx + dx;
+ if (flipy) dy = sy + sizey-15 - dy;
+ else dy = sy + dy;
+
+ drawgfx(rawbitmap,Machine->gfx[0],
+ (tile & 0x0fff) | (code & 0xf000),
+ (tile >> 12) | (color & 0x70),
+ flipx,flipy,
+ dx,dy,
+ &myclip,TRANSPARENCY_PEN,15);
+ }
+ }
+ }
+ else /* sprite */
+ {
+ int w;
+
+if (zoomx <= 1 && zoomy <= 1)
+ drawgfxzoom(rawbitmap,Machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ &myclip,shangha3_do_shadows ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,15,
+ 0x1000000,0x1000000);
+else
+{
+ w = (sizex+15)/16;
+
+ for (x = 0;x < w;x++)
+ {
+ drawgfxzoom(rawbitmap,Machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ sx + 16*x,sy,
+ &myclip,shangha3_do_shadows ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN,15,
+ (0x200-zoomx)*0x100,(0x200-zoomy)*0x100);
+
+ if ((code & 0x000f) == 0x0f)
+ code = (code + 0x100) & 0xfff0;
+ else
+ code++;
+ }
+}
+ }
+ }
+ }
+
+ profiler_mark(PROFILER_END);
+}
+
+
+VIDEO_UPDATE( shangha3 )
+{
+ copybitmap(bitmap,rawbitmap,0,0,0,0,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ return 0;
+}
diff --git a/src/mame/video/shangkid.c b/src/mame/video/shangkid.c
new file mode 100644
index 00000000000..df9514a9353
--- /dev/null
+++ b/src/mame/video/shangkid.c
@@ -0,0 +1,298 @@
+/* video/shangkid */
+
+#include "driver.h"
+#include "cpu/z80/z80.h"
+
+static tilemap *background;
+UINT8 *shangkid_videoreg;
+int shangkid_gfx_type;
+
+
+
+static TILE_GET_INFO( get_bg_tile_info ){
+ int attributes = videoram[tile_index+0x800];
+ int tile_number = videoram[tile_index]+0x100*(attributes&0x3);
+ int color;
+
+ if( shangkid_gfx_type==1 )
+ {
+ /* Shanghai Kid:
+ ------xx bank
+ -----x-- flipx
+ xxxxx--- color
+ */
+ color = attributes>>3;
+ color = (color&0x03)|((color&0x1c)<<1);
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ color,
+ (attributes&0x04)?TILE_FLIPX:0);
+ }
+ else
+ {
+ /* Chinese Hero:
+ ------xx bank
+ -xxxxx-- color
+ x------- flipx?
+ */
+ color = (attributes>>2)&0x1f;
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ color,
+ (attributes&0x80)?TILE_FLIPX:0);
+ }
+
+ tileinfo->category =
+ (memory_region( REGION_PROMS )[0x800+color*4]==2)?1:0;
+}
+
+VIDEO_START( shangkid )
+{
+ background = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+}
+
+WRITE8_HANDLER( shangkid_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty( background, offset&0x7ff );
+}
+
+static void draw_sprite(running_machine *machine, const UINT8 *source, mame_bitmap *bitmap, const rectangle *cliprect ){
+ const gfx_element *gfx;
+ int transparent_pen;
+ int bank_index;
+ int c,r;
+ int width,height;
+ int sx,sy;
+
+ int ypos = 209 - source[0];
+ int tile = source[1]&0x3f;
+ int xflip = (source[1]&0x40)?1:0;
+ int yflip = (source[1]&0x80)?1:0;
+ int bank = source[2]&0x3f;
+ int xsize = (source[2]&0x40)?1:0;
+ int ysize = (source[2]&0x80)?1:0;
+ int yscale = source[3]&0x07; /* 0x0 = smallest; 0x7 = biggest */
+ int xpos = ((source[4]+source[5]*255)&0x1ff)-23;
+ int color = source[6]&0x3f;
+ int xscale = source[7]&0x07; /* 0x0 = smallest; 0x7 = biggest */
+
+ /* adjust placement for small sprites */
+ if( xsize==0 && xflip ) xpos -= 16;
+ if( ysize==0 && yflip==0 ) ypos += 16;
+
+ if( shangkid_gfx_type == 1 )
+ {
+ /* Shanghai Kid */
+ switch( bank&0x30 )
+ {
+ case 0x00:
+ case 0x10:
+ tile += 0x40*(bank&0xf);
+ break;
+
+ case 0x20:
+ tile += 0x40*((bank&0x3)|0x10);
+ break;
+
+ case 0x30:
+ tile += 0x40*((bank&0x3)|0x14);
+ break;
+ }
+ bank_index = 0;
+ transparent_pen = 3;
+ }
+ else
+ {
+ /* Chinese Hero */
+ color >>= 1;
+ switch( bank>>2 )
+ {
+ case 0x0: bank_index = 0; break;
+ case 0x9: bank_index = 1; break;
+ case 0x6: bank_index = 2; break;
+ case 0xf: bank_index = 3; break;
+ default:
+ bank_index = 0;
+ break;
+ }
+
+ if( bank&0x01 ) tile += 0x40;
+ transparent_pen = 7;
+ }
+
+ gfx = machine->gfx[1+bank_index];
+
+ width = (xscale+1)*2;
+ height = (yscale+1)*2;
+
+ /* center zoomed sprites */
+ xpos += (16-width)*(xsize+1)/2;
+ ypos += (16-height)*(ysize+1)/2;
+
+ for( r=0; r<=ysize; r++ )
+ {
+ for( c=0; c<=xsize; c++ )
+ {
+ sx = xpos+(c^xflip)*width;
+ sy = ypos+(r^yflip)*height;
+ drawgfxzoom(
+ bitmap,
+ gfx,
+ tile+c*8+r,
+ color,
+ xflip,yflip,
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN,transparent_pen,
+ (width<<16)/16, (height<<16)/16 );
+ }
+ }
+}
+
+static void shangkid_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ const UINT8 *source, *finish;
+
+ finish = spriteram;
+ source = spriteram+0x200;
+ while( source>finish ){
+ source -= 8;
+ draw_sprite(machine, source, bitmap,cliprect );
+ }
+}
+
+VIDEO_UPDATE( shangkid )
+{
+ int flipscreen = shangkid_videoreg[1]&0x80;
+ tilemap_set_flip( background, flipscreen?(TILEMAP_FLIPX|TILEMAP_FLIPY):0 );
+ tilemap_set_scrollx( background,0,shangkid_videoreg[0]-40 );
+ tilemap_set_scrolly( background,0,shangkid_videoreg[2]+0x10 );
+
+ tilemap_draw( bitmap,cliprect,background,0,0 );
+ shangkid_draw_sprites( machine, bitmap,cliprect );
+ tilemap_draw( bitmap,cliprect,background,1,0 ); /* high priority tiles */
+ return 0;
+}
+
+
+PALETTE_INIT( dynamski )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int data = color_prom[i] + 256 * color_prom[i+32];
+ palette_set_color_rgb(machine,i,pal5bit(data >> 1),pal5bit(data >> 6),pal5bit(data >> 11));
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = (color_prom[i] & 0x0f) + 0x10;
+ color_prom += 0x100;
+
+ /* characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = (color_prom[i] & 0x0f);
+}
+
+
+static void dynamski_draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri )
+{
+ int i;
+ int sx,sy;
+ int tile;
+ int attr;
+ int temp;
+
+ int transparency = pri?TRANSPARENCY_PEN:TRANSPARENCY_NONE;
+
+ for( i=0; i<0x400; i++ )
+ {
+ sx = (i%32)*8;
+ sy = (i/32)*8;
+
+ if( sy<16 )
+ {
+ temp = sx;
+ sx = sy+256+16;
+ sy = temp;
+ }
+ else if( sy>=256-16 )
+ {
+ temp = sx;
+ sx = sy-256+16;
+ sy = temp;
+ }
+ else
+ {
+ sx+=16;
+ }
+
+ tile = videoram[i];
+ attr = videoram[i+0x400];
+ /*
+ x---.---- priority?
+ -xx-.---- bank
+ */
+ if( pri==0 || (attr>>7)==pri )
+ {
+ tile += ((attr>>5)&0x3)*256;
+ drawgfx(
+ bitmap,
+ machine->gfx[0],
+ tile,
+ attr & 0x0f,
+ 0,0,//xflip,yflip,
+ sx,sy,
+ cliprect,
+ transparency,3 );
+ }
+ }
+}
+
+static void dynamski_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int i;
+ int sx,sy;
+ int tile;
+ int bank;
+ int attr;
+ int color;
+ for( i=0x7e; i>=0x00; i-=2 )
+ {
+ bank = videoram[0x1b80+i];
+ attr = videoram[0x1b81+i];
+ tile = videoram[0xb80+i];
+ color = videoram[0xb81+i];
+ sy = 240-videoram[0x1380+i];
+
+ sx = videoram[0x1381+i]-64+8+16;
+ if( attr&1 ) sx += 0x100;
+
+ drawgfx(
+ bitmap,
+ machine->gfx[1],
+ bank*0x40 + (tile&0x3f),
+ color,
+ tile&0x80,tile&0x40, /* flipx,flipy */
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN,3 );
+ }
+}
+
+VIDEO_UPDATE( dynamski )
+{
+ dynamski_draw_background( machine, bitmap,cliprect, 0 );
+ dynamski_draw_sprites(machine, bitmap,cliprect );
+ dynamski_draw_background( machine, bitmap,cliprect, 1 );
+ return 0;
+}
diff --git a/src/mame/video/shaolins.c b/src/mame/video/shaolins.c
new file mode 100644
index 00000000000..5a017421875
--- /dev/null
+++ b/src/mame/video/shaolins.c
@@ -0,0 +1,195 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+extern UINT8 shaolins_nmi_enable;
+
+static int palettebank;
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Shao-lin's Road has three 256x4 palette PROMs (one per gun) and two 256x4
+ lookup table PROMs (one for characters, one for sprites).
+ I don't know for sure how the palette PROMs are connected to the RGB
+ output, but it's probably the usual:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+PALETTE_INIT( shaolins )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the character lookup table */
+
+
+ /* there are eight 32 colors palette banks; sprites use colors 0-15 and */
+ /* characters 16-31 of each bank. */
+ for (i = 0;i < TOTAL_COLORS(0)/8;i++)
+ {
+ int j;
+
+
+ for (j = 0;j < 8;j++)
+ COLOR(0,i + j * TOTAL_COLORS(0)/8) = (*color_prom & 0x0f) + 32 * j + 16;
+
+ color_prom++;
+ }
+
+ for (i = 0;i < TOTAL_COLORS(1)/8;i++)
+ {
+ int j;
+
+
+ for (j = 0;j < 8;j++)
+ {
+ /* preserve transparency */
+ if ((*color_prom & 0x0f) == 0) COLOR(1,i + j * TOTAL_COLORS(1)/8) = 0;
+ else COLOR(1,i + j * TOTAL_COLORS(1)/8) = (*color_prom & 0x0f) + 32 * j;
+ }
+
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( shaolins_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( shaolins_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( shaolins_palettebank_w )
+{
+ if (palettebank != (data & 0x07))
+ {
+ palettebank = data & 0x07;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( shaolins_scroll_w )
+{
+ int col;
+
+ for (col = 4; col < 32; col++)
+ {
+ tilemap_set_scrolly(bg_tilemap, col, data + 1);
+ }
+}
+
+WRITE8_HANDLER( shaolins_nmi_w )
+{
+ shaolins_nmi_enable = data;
+
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + ((attr & 0x40) << 2);
+ int color = (attr & 0x0f) + 16 * palettebank;
+ int flags = (attr & 0x20) ? TILE_FLIPY : 0;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( shaolins )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_scroll_cols(bg_tilemap, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size-32; offs >= 0; offs-=32 ) /* max 24 sprites */
+ {
+ if (spriteram[offs] && spriteram[offs + 6]) /* stop rogue sprites on high score screen */
+ {
+ int code = spriteram[offs + 8];
+ int color = (spriteram[offs + 9] & 0x0f) + 16 * palettebank;
+ int flipx = !(spriteram[offs + 9] & 0x40);
+ int flipy = spriteram[offs + 9] & 0x80;
+ int sx = 240 - spriteram[offs + 6];
+ int sy = 248 - spriteram[offs + 4];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 248 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1],
+ code, color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_COLOR, 0);
+ /* transparency_color, otherwise sprites in test mode are not visible */
+ }
+ }
+}
+
+VIDEO_UPDATE( shaolins )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/shisen.c b/src/mame/video/shisen.c
new file mode 100644
index 00000000000..7b8ad5bde8e
--- /dev/null
+++ b/src/mame/video/shisen.c
@@ -0,0 +1,65 @@
+#include "driver.h"
+
+static int gfxbank;
+
+static tilemap *bg_tilemap;
+
+WRITE8_HANDLER( sichuan2_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+WRITE8_HANDLER( sichuan2_bankswitch_w )
+{
+ int bankaddress;
+ int bank;
+ UINT8 *RAM = memory_region(REGION_CPU1);
+
+ if (data & 0xc0) logerror("bank switch %02x\n",data);
+
+ /* bits 0-2 select ROM bank */
+ bankaddress = 0x10000 + (data & 0x07) * 0x4000;
+ memory_set_bankptr(1, &RAM[bankaddress]);
+
+ /* bits 3-5 select gfx bank */
+ bank = (data & 0x38) >> 3;
+
+ if (gfxbank != bank)
+ {
+ gfxbank = bank;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ /* bits 6-7 unknown */
+}
+
+WRITE8_HANDLER( sichuan2_paletteram_w )
+{
+ paletteram[offset] = data;
+
+ offset &= 0xff;
+
+ palette_set_color_rgb(Machine, offset, pal5bit(paletteram[offset + 0x000]), pal5bit(paletteram[offset + 0x100]), pal5bit(paletteram[offset + 0x200]));
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int offs = tile_index * 2;
+ int code = videoram[offs] + ((videoram[offs + 1] & 0x0f) << 8) + (gfxbank << 12);
+ int color = (videoram[offs + 1] & 0xf0) >> 4;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( sichuan2 )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+}
+
+VIDEO_UPDATE( sichuan2 )
+{
+ tilemap_draw(bitmap, &machine->screen[0].visarea, bg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/shootout.c b/src/mame/video/shootout.c
new file mode 100644
index 00000000000..ee265317a8d
--- /dev/null
+++ b/src/mame/video/shootout.c
@@ -0,0 +1,175 @@
+/*
+ Video Hardware for Shoot Out
+ prom GB09.K6 may be related to background tile-sprite priority
+*/
+
+#include "driver.h"
+
+static tilemap *background, *foreground;
+extern UINT8 *shootout_textram;
+
+
+PALETTE_INIT( shootout )
+{
+ int i;
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+
+
+static TILE_GET_INFO( get_bg_tile_info ){
+ int attributes = videoram[tile_index+0x400]; /* CCCC -TTT */
+ int tile_number = videoram[tile_index] + 256*(attributes&7);
+ int color = attributes>>4;
+ SET_TILE_INFO(
+ 2,
+ tile_number,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info ){
+ int attributes = shootout_textram[tile_index+0x400]; /* CCCC --TT */
+ int tile_number = shootout_textram[tile_index] + 256*(attributes&0x3);
+ int color = attributes>>4;
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ color,
+ 0);
+}
+
+WRITE8_HANDLER( shootout_videoram_w ){
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty( background, offset&0x3ff );
+}
+WRITE8_HANDLER( shootout_textram_w ){
+ shootout_textram[offset] = data;
+ tilemap_mark_tile_dirty( foreground, offset&0x3ff );
+}
+
+VIDEO_START( shootout ){
+ background = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ foreground = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ tilemap_set_transparent_pen( foreground, 0 );
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int bank_bits ){
+ static int bFlicker;
+ const gfx_element *gfx = machine->gfx[1];
+ const UINT8 *source = spriteram+127*4;
+ int count;
+
+ bFlicker = !bFlicker;
+
+ for( count=0; count<128; count++ ){
+ int attributes = source[1];
+ /*
+ 76543210
+ xxx----- bank
+ ---x---- vertical size
+ ----x--- priority
+ -----x-- horizontal flip
+ ------x- flicker
+ -------x enable
+ */
+ if ( attributes & 0x01 ){ /* visible */
+ if( bFlicker || (attributes&0x02)==0 ){
+ int priority_mask = (attributes&0x08)?0x2:0;
+ int sx = (240 - source[2])&0xff;
+ int sy = (240 - source[0])&0xff;
+ int vx, vy;
+ int number = source[3] | ((attributes<<bank_bits)&0x700);
+ int flipx = (attributes & 0x04);
+ int flipy = 0;
+
+ if (flip_screen) {
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if( attributes & 0x10 ){ /* double height */
+ number = number&(~1);
+ sy -= 16;
+
+ vx = sx;
+ vy = sy;
+ if (flip_screen) {
+ vx = 240 - vx;
+ vy = 240 - vy;
+ }
+
+ pdrawgfx(bitmap,gfx,
+ number,
+ 0 /*color*/,
+ flipx,flipy,
+ vx,vy,
+ cliprect,TRANSPARENCY_PEN,0,
+ priority_mask);
+
+ number++;
+ sy += 16;
+ }
+
+ vx = sx;
+ vy = sy;
+ if (flip_screen) {
+ vx = 240 - vx;
+ vy = 240 - vy;
+ }
+
+ pdrawgfx(bitmap,gfx,
+ number,
+ 0 /*color*/,
+ flipx,flipy,
+ vx,vy,
+ cliprect,TRANSPARENCY_PEN,0,
+ priority_mask);
+ }
+ }
+ source -= 4;
+ }
+}
+
+VIDEO_UPDATE( shootout )
+{
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,background,0,0);
+ tilemap_draw(bitmap,cliprect,foreground,0,1);
+ draw_sprites(machine, bitmap,cliprect,3/*bank bits */);
+ return 0;
+}
+
+VIDEO_UPDATE( shootouj )
+{
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,background,0,0);
+ tilemap_draw(bitmap,cliprect,foreground,0,1);
+ draw_sprites(machine, bitmap,cliprect,2/*bank bits*/);
+ return 0;
+}
diff --git a/src/mame/video/shuuz.c b/src/mame/video/shuuz.c
new file mode 100644
index 00000000000..252a0af283d
--- /dev/null
+++ b/src/mame/video/shuuz.c
@@ -0,0 +1,140 @@
+/***************************************************************************
+
+ Atari Shuuz hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "shuuz.h"
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data1 = atarigen_playfield[tile_index];
+ UINT16 data2 = atarigen_playfield_upper[tile_index] >> 8;
+ int code = data1 & 0x3fff;
+ int color = data2 & 0x0f;
+ SET_TILE_INFO(0, code, color, (data1 >> 15) & 1);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( shuuz )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 1, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 8, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x000, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0x00ff,0,0,0 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0,0x7fff,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0x000f,0 }}, /* mask for the color */
+ {{ 0,0,0xff80,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xff80 }}, /* mask for the Y position */
+ {{ 0,0,0,0x0070 }}, /* mask for the width, in tiles*/
+ {{ 0,0,0,0x0007 }}, /* mask for the height, in tiles */
+ {{ 0,0x8000,0,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0 /* callback routine for special entries */
+ };
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8,8, 64,64);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( shuuz )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* verified from the GALs on the real PCB; equations follow
+ *
+ * --- O13 is 1 if (PFS7-4 == 0xf)
+ * O13=PFS6*PFS7*(PFS5&PFS4)
+ *
+ * --- PF/M is 1 if MOs have priority, or 0 if playfield has priority
+ * MO/PF=!PFS7*!(LBD7&LBD6)*!M1*!O13
+ * +!PFS7*!(LBD7&LBD6)*!M2*!O13
+ * +!PFS7*!(LBD7&LBD6)*!M3*!O13
+ * +PFS7*(LBD7&LBD6)*!M1*!O13
+ * +PFS7*(LBD7&LBD6)*!M2*!O13
+ * +PFS7*(LBD7&LBD6)*!M3*!O13
+ *
+ */
+ int o13 = ((pf[x] & 0xf0) == 0xf0);
+ int mopf = 0;
+
+ /* compute the MO/PF signal */
+ if ((!(pf[x] & 0x80) && ((mo[x] & 0xc0) != 0xc0) && ((mo[x] & 0x0e) != 0x00) && !o13) ||
+ ((pf[x] & 0x80) && ((mo[x] & 0xc0) == 0xc0) && ((mo[x] & 0x0e) != 0x00) && !o13))
+ mopf = 1;
+
+ /* if MO/PF is 1, we draw the MO */
+ if (mopf)
+ pf[x] = mo[x];
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/sidearms.c b/src/mame/video/sidearms.c
new file mode 100644
index 00000000000..701042a6f78
--- /dev/null
+++ b/src/mame/video/sidearms.c
@@ -0,0 +1,363 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+extern int sidearms_gameid;
+
+UINT8 *sidearms_bg_scrollx;
+UINT8 *sidearms_bg_scrolly;
+
+static UINT8 *tilerom;
+static int bgon, objon, staron, charon, flipon;
+static UINT32 hflop_74a_n, hcount_191, vcount_191, latch_374;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+WRITE8_HANDLER( sidearms_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( sidearms_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( sidearms_c804_w )
+{
+ /* bits 0 and 1 are coin counters */
+ coin_counter_w(0, data & 0x01);
+ coin_counter_w(1, data & 0x02);
+
+ /* bit 2 and 3 lock the coin chutes */
+ if (!sidearms_gameid || sidearms_gameid==3)
+ {
+ coin_lockout_w(0, !(data & 0x04));
+ coin_lockout_w(1, !(data & 0x08));
+ }
+ else
+ {
+ coin_lockout_w(0, data & 0x04);
+ coin_lockout_w(1, data & 0x08);
+ }
+
+ /* bit 4 resets the sound CPU */
+ if (data & 0x10)
+ {
+ cpunum_set_input_line(1, INPUT_LINE_RESET, PULSE_LINE);
+ }
+
+ /* bit 5 enables starfield */
+ if (staron != (data & 0x20))
+ {
+ staron = data & 0x20;
+ hflop_74a_n = 1;
+ hcount_191 = vcount_191 = 0;
+ }
+
+ /* bit 6 enables char layer */
+ charon = data & 0x40;
+
+ /* bit 7 flips screen */
+ if (flipon != (data & 0x80))
+ {
+ flipon = data & 0x80;
+ flip_screen_set(flipon);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( sidearms_gfxctrl_w )
+{
+ objon = data & 0x01;
+ bgon = data & 0x02;
+}
+
+WRITE8_HANDLER( sidearms_star_scrollx_w )
+{
+ UINT32 last_state = hcount_191;
+
+ hcount_191++;
+ hcount_191 &= 0x1ff;
+
+ // invert 74LS74A(flipflop) output on 74LS191(hscan counter) carry's rising edge
+ if (hcount_191 & ~last_state & 0x100)
+ hflop_74a_n ^= 1;
+}
+
+WRITE8_HANDLER( sidearms_star_scrolly_w )
+{
+ vcount_191++;
+ vcount_191 &= 0xff;
+}
+
+
+static TILE_GET_INFO( get_sidearms_bg_tile_info )
+{
+ int code, attr, color, flags;
+
+ code = tilerom[tile_index];
+ attr = tilerom[tile_index + 1];
+ code |= attr<<8 & 0x100;
+ color = attr>>3 & 0x1f;
+ flags = attr>>1 & 0x03;
+
+ SET_TILE_INFO(1, code, color, flags);
+}
+
+static TILE_GET_INFO( get_philko_bg_tile_info )
+{
+ int code, attr, color, flags;
+
+ code = tilerom[tile_index];
+ attr = tilerom[tile_index + 1];
+ code |= (((attr>>6 & 0x02) | (attr & 0x01)) * 0x100);
+ color = attr>>3 & 0x0f;
+ flags = attr>>1 & 0x03;
+
+ SET_TILE_INFO(1, code, color, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + (attr<<2 & 0x300);
+ int color = attr & 0x3f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static TILEMAP_MAPPER( sidearms_tilemap_scan )
+{
+ /* logical (col,row) -> memory offset */
+ int offset = ((row << 7) + col) << 1;
+
+ /* swap bits 1-7 and 8-10 of the address to compensate for the funny layout of the ROM data */
+ return ((offset & 0xf801) | ((offset & 0x0700) >> 7) | ((offset & 0x00fe) << 3)) & 0x7fff;
+}
+
+VIDEO_START( sidearms )
+{
+ tilerom = memory_region(REGION_GFX4);
+
+ if (!sidearms_gameid)
+ {
+ bg_tilemap = tilemap_create(get_sidearms_bg_tile_info, sidearms_tilemap_scan,
+ TILEMAP_TYPE_PEN, 32, 32, 128, 128);
+
+ tilemap_set_transparent_pen(bg_tilemap, 15);
+ }
+ else
+ {
+ bg_tilemap = tilemap_create(get_philko_bg_tile_info, sidearms_tilemap_scan,TILEMAP_TYPE_PEN, 32, 32, 128, 128);
+ }
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 64);
+
+ tilemap_set_transparent_pen(fg_tilemap, 3);
+
+ hflop_74a_n = 1;
+ latch_374 = vcount_191 = hcount_191 = 0;
+
+ flipon = charon = staron = objon = bgon = 0;
+}
+
+static void draw_sprites_region(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int start_offset, int end_offset )
+{
+ const gfx_element *gfx = machine->gfx[2];
+ int offs, attr, color, code, x, y, flipx, flipy;
+
+ flipy = flipx = flipon;
+
+ for (offs = end_offset - 32; offs >= start_offset; offs -= 32)
+ {
+ y = buffered_spriteram[offs + 2];
+ if (!y || buffered_spriteram[offs + 5] == 0xc3) continue;
+
+ attr = buffered_spriteram[offs + 1];
+ color = attr & 0xf;
+ code = buffered_spriteram[offs] + ((attr << 3) & 0x700);
+ x = buffered_spriteram[offs + 3] + ((attr << 4) & 0x100);
+
+ if (flipon)
+ {
+ x = (62 * 8) - x;
+ y = (30 * 8) - y;
+ }
+
+ drawgfx(bitmap, gfx,
+ code, color,
+ flipx, flipy,
+ x, y,
+ cliprect,
+ TRANSPARENCY_PEN, 15);
+ }
+}
+
+static void sidearms_draw_starfield( mame_bitmap *bitmap )
+{
+ int x, y, i;
+ UINT32 hadd_283, vadd_283, _hflop_74a_n, _hcount_191, _vcount_191;
+ UINT8 *sf_rom;
+ UINT16 *lineptr;
+ int pixadv, lineadv;
+
+ // clear starfield background
+ lineptr = BITMAP_ADDR16(bitmap, 16, 64);
+ lineadv = bitmap->rowpixels;
+
+ for (i=224; i; i--) { memset(lineptr, 0, 768); lineptr += lineadv; }
+
+ // bail if not Side Arms or the starfield has been disabled
+ if (sidearms_gameid || !staron) return;
+
+ // init and cache some global vars in stack frame
+ hadd_283 = 0;
+
+ _hflop_74a_n = hflop_74a_n;
+ _vcount_191 = vcount_191;
+ _hcount_191 = hcount_191 & 0xff;
+
+ sf_rom = memory_region(REGION_USER1);
+
+#if 0 // old loop (for reference; easier to read)
+ if (!flipon)
+ {
+ lineptr = bitmap->base;
+ pixadv = 1;
+ lineadv = lineadv - 512;
+ }
+ else
+ {
+ lineptr = BITMAP_ADDR16(bitmap, 255, 512 - 1);
+ pixadv = -1;
+ lineadv = -lineadv + 512;
+ }
+
+ for (y=0; y<256; y++) // 8-bit V-clock input
+ {
+ for (x=0; x<512; lineptr+=pixadv,x++) // 9-bit H-clock input
+ {
+ i = hadd_283; // store horizontal adder's previous state in i
+ hadd_283 = _hcount_191 + (x & 0xff); // add lower 8 bits and preserve carry
+
+ if (x<64 || x>447 || y<16 || y>239) continue; // clip rejection
+
+ vadd_283 = _vcount_191 + y; // add lower 8 bits and discard carry (later)
+
+ if (!((vadd_283 ^ (x>>3)) & 4)) continue; // logic rejection 1
+ if ((vadd_283 | (hadd_283>>1)) & 2) continue; // logic rejection 2
+
+ // latch data from starfield EPROM on rising edge of 74LS374's clock input
+ if (!(~i & 0x1f))
+ {
+ i = vadd_283<<4 & 0xff0; // to starfield EPROM A04-A11 (8 bits)
+ i |= (_hflop_74a_n^(hadd_283>>8)) << 3; // to starfield EPROM A03 (1 bit)
+ i |= hadd_283>>5 & 7; // to starfield EPROM A00-A02 (3 bits)
+ latch_374 = sf_rom[i + 0x3000]; // lines A12-A13 are always high
+ }
+
+ if ((~((latch_374^hadd_283)^1) & 0x1f)) continue; // logic rejection 3
+
+ *lineptr = (UINT16)(latch_374>>5 | 0x378); // to color mixer
+ }
+ lineptr += lineadv;
+ }
+#else // optimized loop
+ if (!flipon)
+ {
+ lineptr = BITMAP_ADDR16(bitmap, 16, 64);
+ pixadv = 1;
+ lineadv = lineadv - 384;
+ }
+ else
+ {
+ lineptr = BITMAP_ADDR16(bitmap, 239, 512 - 64 - 1);
+ pixadv = -1;
+ lineadv = -lineadv + 384;
+ }
+
+ for (y=16; y<240; y++) // 8-bit V-clock input (clipped against vertical visible area)
+ {
+ // inner loop pre-entry conditioning
+ hadd_283 = (_hcount_191 + 64) & ~0x1f;
+ vadd_283 = _vcount_191 + y;
+
+ i = vadd_283<<4 & 0xff0; // to starfield EPROM A04-A11 (8 bits)
+ i |= (_hflop_74a_n^(hadd_283>>8)) << 3; // to starfield EPROM A03 (1 bit)
+ i |= hadd_283>>5 & 7; // to starfield EPROM A00-A02 (3 bits)
+ latch_374 = sf_rom[i + 0x3000]; // lines A12-A13 are always high
+
+ hadd_283 = _hcount_191 + 63;
+
+ for (x=64; x<448; lineptr+=pixadv,x++) // 9-bit H-clock input (clipped against horizontal visible area)
+ {
+ i = hadd_283; // store horizontal adder's previous state in i
+ hadd_283 = _hcount_191 + (x & 0xff); // add lower 8 bits and preserve carry
+ vadd_283 = _vcount_191 + y; // add lower 8 bits and discard carry (later)
+
+ if (!((vadd_283 ^ (x>>3)) & 4)) continue; // logic rejection 1
+ if ((vadd_283 | (hadd_283>>1)) & 2) continue; // logic rejection 2
+
+ // latch data from starfield EPROM on rising edge of 74LS374's clock input
+ if (!(~i & 0x1f))
+ {
+ i = vadd_283<<4 & 0xff0; // to starfield EPROM A04-A11 (8 bits)
+ i |= (_hflop_74a_n^(hadd_283>>8)) << 3; // to starfield EPROM A03 (1 bit)
+ i |= hadd_283>>5 & 7; // to starfield EPROM A00-A02 (3 bits)
+ latch_374 = sf_rom[i + 0x3000]; // lines A12-A13 are always high
+ }
+
+ if ((~((latch_374^hadd_283)^1) & 0x1f)) continue; // logic rejection 3
+
+ *lineptr = (UINT16)(latch_374>>5 | 0x378); // to color mixer
+ }
+ lineptr += lineadv;
+ }
+#endif
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ if (sidearms_gameid == 2 || sidearms_gameid == 3) // Dyger and Whizz have simple front-to-back sprite priority
+ draw_sprites_region(machine, bitmap, cliprect, 0x0000, 0x1000);
+ else
+ {
+ draw_sprites_region(machine, bitmap, cliprect, 0x0700, 0x0800);
+ draw_sprites_region(machine, bitmap, cliprect, 0x0e00, 0x1000);
+ draw_sprites_region(machine, bitmap, cliprect, 0x0800, 0x0f00);
+ draw_sprites_region(machine, bitmap, cliprect, 0x0000, 0x0700);
+ }
+}
+
+VIDEO_UPDATE( sidearms )
+{
+ sidearms_draw_starfield(bitmap);
+
+ tilemap_set_scrollx(bg_tilemap, 0, sidearms_bg_scrollx[0] + (sidearms_bg_scrollx[1] << 8 & 0xf00));
+ tilemap_set_scrolly(bg_tilemap, 0, sidearms_bg_scrolly[0] + (sidearms_bg_scrolly[1] << 8 & 0xf00));
+
+ if (bgon)
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ if (objon)
+ draw_sprites(machine, bitmap, cliprect);
+
+ if (charon)
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
+
+VIDEO_EOF( sidearms )
+{
+ buffer_spriteram_w(0, 0);
+}
diff --git a/src/mame/video/sidepckt.c b/src/mame/video/sidepckt.c
new file mode 100644
index 00000000000..7f5b0163fa3
--- /dev/null
+++ b/src/mame/video/sidepckt.c
@@ -0,0 +1,149 @@
+#include "driver.h"
+
+
+static tilemap *bg_tilemap;
+static int flipscreen;
+
+
+PALETTE_INIT( sidepckt )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 4) & 0x01;
+ bit1 = (color_prom[i] >> 5) & 0x01;
+ bit2 = (color_prom[i] >> 6) & 0x01;
+ bit3 = (color_prom[i] >> 7) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* green component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ bit3 = (color_prom[i] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* blue component */
+ bit0 = (color_prom[i + machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[i + machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[i + machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[i + machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 attr = colorram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ videoram[tile_index] + ((attr & 0x07) << 8),
+ ((attr & 0x10) >> 3) | ((attr & 0x20) >> 5),
+ TILE_FLIPX);
+ tileinfo->group = (attr & 0x80) >> 7;
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( sidepckt )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transmask(bg_tilemap,0,0xff,0x00); /* split type 0 is totally transparent in front half */
+ tilemap_set_transmask(bg_tilemap,1,0x01,0xfe); /* split type 1 has pen 0 transparent in front half */
+
+ tilemap_set_flip(ALL_TILEMAPS,TILEMAP_FLIPX);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( sidepckt_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( sidepckt_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( sidepckt_flipscreen_w )
+{
+ flipscreen = data;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? TILEMAP_FLIPY : TILEMAP_FLIPX);
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size; offs += 4)
+ {
+ int sx,sy,code,color,flipx,flipy;
+
+ code = spriteram[offs+3] + ((spriteram[offs+1] & 0x03) << 8);
+ color = (spriteram[offs+1] & 0xf0) >> 4;
+
+ sx = spriteram[offs+2]-2;
+ sy = spriteram[offs];
+
+ flipx = spriteram[offs+1] & 0x08;
+ flipy = spriteram[offs+1] & 0x04;
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ /* wraparound */
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx-256,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+VIDEO_UPDATE( sidepckt )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0,0);
+ return 0;
+}
diff --git a/src/mame/video/silkroad.c b/src/mame/video/silkroad.c
new file mode 100644
index 00000000000..233757a49a2
--- /dev/null
+++ b/src/mame/video/silkroad.c
@@ -0,0 +1,189 @@
+#include "driver.h"
+
+/* Sprites probably need to be delayed */
+/* Some scroll layers may need to be offset slightly? */
+/* Check Sprite Colours after redump */
+/* Clean Up */
+/* is theres a bg colour register? */
+
+static tilemap *fg_tilemap,*fg2_tilemap,*fg3_tilemap;
+extern UINT32 *silkroad_vidram,*silkroad_vidram2,*silkroad_vidram3, *silkroad_sprram, *silkroad_regs;
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri )
+{
+ const gfx_element *gfx = machine->gfx[0];
+ UINT32 *source = silkroad_sprram;
+ UINT32 *finish = source + 0x1000/4;
+ UINT32 *maxspr = source;
+
+ while( maxspr<finish )
+ {
+ int attr = (maxspr[1] & 0x0000ffff);
+
+ if ( (attr & 0xff00) == 0xff00 ) break;
+ maxspr+=2;
+ }
+
+ finish = maxspr-2;
+
+ while( finish>=source )
+ {
+
+ int xpos = (finish[0] & 0x01ff0000) >> 16;
+ int ypos = (finish[0] & 0x0000ffff);
+ int tileno = (finish[1] & 0xffff0000) >> 16;
+ int attr = (finish[1] & 0x0000ffff);
+
+ int flipx = (attr & 0x0080);
+
+ int width = (attr & 0x0f00) >> 8;
+ int wcount;
+ int color = (attr & 0x003f) ;
+
+ int priority = (attr & 0x1000) >> 12;
+
+ if ( (attr & 0x8000) == 0x8000 ) tileno+=0x10000;
+
+ width += 1;
+
+
+ if (priority == pri){
+
+ if (!flipx) {
+ for (wcount=0;wcount<width;wcount++) {
+ drawgfx(bitmap,gfx,tileno+wcount,color,0,0,xpos+wcount*16+8,ypos,cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ } else {
+
+ for (wcount=width;wcount>0;wcount--) {
+ drawgfx(bitmap,gfx,tileno+(width-wcount),color,1,0,xpos+wcount*16-16+8,ypos,cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ }
+ }
+ finish-=2;
+ }
+}
+
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+
+ int code = ((silkroad_vidram[tile_index] & 0xffff0000) >> 16 );
+ int color = ((silkroad_vidram[tile_index] & 0x000001f));
+ int flipx = ((silkroad_vidram[tile_index] & 0x0000080) >> 7);
+
+ code += 0x18000;
+
+ SET_TILE_INFO(
+ 0,
+ code,
+ color,
+ TILE_FLIPYX(flipx));
+}
+
+
+
+WRITE32_HANDLER( silkroad_fgram_w )
+{
+ COMBINE_DATA(&silkroad_vidram[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+static TILE_GET_INFO( get_fg2_tile_info )
+{
+ int code = ((silkroad_vidram2[tile_index] & 0xffff0000) >> 16 );
+ int color = ((silkroad_vidram2[tile_index] & 0x000001f));
+ int flipx = ((silkroad_vidram2[tile_index] & 0x0000080) >> 7);
+ code += 0x18000;
+ SET_TILE_INFO(
+ 0,
+ code,
+ color,
+ TILE_FLIPYX(flipx));
+}
+
+
+
+WRITE32_HANDLER( silkroad_fgram2_w )
+{
+ COMBINE_DATA(&silkroad_vidram2[offset]);
+ tilemap_mark_tile_dirty(fg2_tilemap,offset);
+}
+
+static TILE_GET_INFO( get_fg3_tile_info )
+{
+ int code = ((silkroad_vidram3[tile_index] & 0xffff0000) >> 16 );
+ int color = ((silkroad_vidram3[tile_index] & 0x000001f));
+ int flipx = ((silkroad_vidram3[tile_index] & 0x0000080) >> 7);
+ code += 0x18000;
+ SET_TILE_INFO(
+ 0,
+ code,
+ color,
+ TILE_FLIPYX(flipx));
+}
+
+
+
+WRITE32_HANDLER( silkroad_fgram3_w )
+{
+ COMBINE_DATA(&silkroad_vidram3[offset]);
+ tilemap_mark_tile_dirty(fg3_tilemap,offset);
+}
+
+
+
+VIDEO_START(silkroad)
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64, 64);
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ fg2_tilemap = tilemap_create(get_fg2_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64, 64);
+ tilemap_set_transparent_pen(fg2_tilemap,0);
+
+ fg3_tilemap = tilemap_create(get_fg3_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64, 64);
+ tilemap_set_transparent_pen(fg3_tilemap,0);
+}
+
+static int enable1=1,enable2=1,enable3=1;
+
+VIDEO_UPDATE(silkroad)
+{
+ fillbitmap(bitmap,0x7c0,&machine->screen[0].visarea);
+
+ tilemap_set_scrollx( fg_tilemap, 0, ((silkroad_regs[0] & 0xffff0000) >> 16) );
+ tilemap_set_scrolly( fg_tilemap, 0, (silkroad_regs[0] & 0x0000ffff) >> 0 );
+
+ tilemap_set_scrolly( fg3_tilemap, 0, (silkroad_regs[1] & 0xffff0000) >> 16 );
+ tilemap_set_scrollx( fg3_tilemap, 0, (silkroad_regs[2] & 0xffff0000) >> 16 );
+
+ tilemap_set_scrolly( fg2_tilemap, 0, ((silkroad_regs[5] & 0xffff0000) >> 16));
+ tilemap_set_scrollx( fg2_tilemap, 0, (silkroad_regs[2] & 0x0000ffff) >> 0 );
+
+/*
+ if (input_code_pressed(KEYCODE_A)) enable1 ^= 1;
+ if (input_code_pressed(KEYCODE_S)) enable2 ^= 1;
+ if (input_code_pressed(KEYCODE_D)) enable3 ^= 1;
+*/
+
+ if(enable1) tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+
+ draw_sprites(machine, bitmap,cliprect,0);
+ if(enable2) tilemap_draw(bitmap,cliprect,fg2_tilemap,0,0);
+
+ draw_sprites(machine, bitmap,cliprect,1);
+ if(enable3) tilemap_draw(bitmap,cliprect,fg3_tilemap,0,0);
+
+/*
+ popmessage ("Regs %08x %08x %08x %08x %08x",
+ silkroad_regs[0],
+ silkroad_regs[1],
+ silkroad_regs[2],
+ silkroad_regs[4],
+ silkroad_regs[5]
+ );
+*/
+ return 0;
+}
diff --git a/src/mame/video/simpl156.c b/src/mame/video/simpl156.c
new file mode 100644
index 00000000000..48ad5f4cb33
--- /dev/null
+++ b/src/mame/video/simpl156.c
@@ -0,0 +1,156 @@
+/* Simple 156 based board
+
+*/
+
+#include "driver.h"
+#include "deco16ic.h"
+
+/*
+
+offs +0
+-------- --------
+ fFb ssy yyyyyyyy
+
+s = size (multipart)
+f = flipy
+b = flash
+F = flipx
+y = ypos
+
+offs +1
+-------- --------
+tttttttt tttttttt
+
+t = sprite tile
+
+offs +2
+-------- --------
+ppcccccx xxxxxxxx
+
+c = colour palette
+p = priority
+x = xpos
+
+*/
+
+/* spriteram is really 16-bit.. this can be changed to use 16-bit ram like the tilemaps
+ its the same sprite chip Data East used on many, many 16-bit era titles */
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ flip_screen = 1;
+
+ for (offs = (0x1400/4)-4;offs >= 0;offs -= 4) // 0x1400 for charlien
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult, pri;
+
+ sprite = spriteram32[offs+1]&0xffff;
+
+ y = spriteram32[offs]&0xffff;
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ x = spriteram32[offs+2]&0xffff;
+ colour = (x >>9) & 0x1f;
+
+ pri = (x&0xc000); // 2 bits or 1?
+
+ switch (pri&0xc000) {
+ case 0x0000: pri=0; break;
+ case 0x4000: pri=0xf0; break;
+ case 0x8000: pri=0xf0|0xcc; break;
+ case 0xc000: pri=0xf0|0xcc; break; /* or 0xf0|0xcc|0xaa ? */
+ }
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+ y = 240 - y;
+ x = 304 - x;
+
+ if (x>320) continue;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen)
+ {
+ y=240-y;
+ x=304-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ pdrawgfx(bitmap,machine->gfx[2],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0,pri);
+
+ multi--;
+ }
+ }
+}
+
+
+VIDEO_UPDATE( simpl156 )
+{
+ fillbitmap(priority_bitmap,0,NULL);
+
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+
+ fillbitmap(bitmap,machine->pens[256],cliprect);
+
+ deco16_tilemap_2_draw(bitmap,cliprect,0,2);
+ deco16_tilemap_1_draw(bitmap,cliprect,0,4);
+
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
+
+static int simpl156_bank_callback(const int bank)
+{
+ return ((bank>>4)&0x7) * 0x1000;
+}
+
+
+VIDEO_START( simpl156 )
+{
+ /* allocate the ram as 16-bit (we do it here because the CPU is 32-bit) */
+ deco16_pf1_data = auto_malloc(0x2000);
+ deco16_pf2_data = auto_malloc(0x2000);
+ deco16_pf1_rowscroll = auto_malloc(0x800);
+ deco16_pf2_rowscroll = auto_malloc(0x800);
+ deco16_pf12_control = auto_malloc(0x10);
+ paletteram16 = auto_malloc(0x1000);
+
+ /* and register the allocated ram so that save states still work */
+ state_save_register_global_pointer(deco16_pf1_data, 0x2000/2);
+ state_save_register_global_pointer(deco16_pf2_data, 0x2000/2);
+ state_save_register_global_pointer(deco16_pf1_rowscroll, 0x800/2);
+ state_save_register_global_pointer(deco16_pf2_rowscroll, 0x800/2);
+ state_save_register_global_pointer(deco16_pf12_control, 0x10/2);
+ state_save_register_global_pointer(paletteram16, 0x1000/2);
+
+ deco16_1_video_init();
+
+ deco16_set_tilemap_bank_callback(0, simpl156_bank_callback);
+ deco16_set_tilemap_bank_callback(1, simpl156_bank_callback);
+}
diff --git a/src/mame/video/simpsons.c b/src/mame/video/simpsons.c
new file mode 100644
index 00000000000..13bf7ecbea8
--- /dev/null
+++ b/src/mame/video/simpsons.c
@@ -0,0 +1,181 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+static int bg_colorbase,sprite_colorbase,layer_colorbase[3];
+UINT8 *simpsons_xtraram;
+static int layerpri[3];
+
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ *code |= ((*color & 0x3f) << 8) | (bank << 14);
+ *color = layer_colorbase[layer] + ((*color & 0xc0) >> 6);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K053247
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority_mask)
+{
+ int pri = (*color & 0x0f80) >> 6; /* ??????? */
+ if (pri <= layerpri[2]) *priority_mask = 0;
+ else if (pri > layerpri[2] && pri <= layerpri[1]) *priority_mask = 0xf0;
+ else if (pri > layerpri[1] && pri <= layerpri[0]) *priority_mask = 0xf0|0xcc;
+ else *priority_mask = 0xf0|0xcc|0xaa;
+
+ *color = sprite_colorbase + (*color & 0x001f);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( simpsons )
+{
+ K053251_vh_start();
+
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tile_callback);
+ K053247_vh_start(machine,REGION_GFX2,53,23,NORMAL_PLANE_ORDER,sprite_callback);
+}
+
+/***************************************************************************
+
+ Extra video banking
+
+***************************************************************************/
+
+static READ8_HANDLER( simpsons_K052109_r )
+{
+ return K052109_r(offset + 0x2000);
+}
+
+static WRITE8_HANDLER( simpsons_K052109_w )
+{
+ K052109_w(offset + 0x2000,data);
+}
+
+static READ8_HANDLER( simpsons_K053247_r )
+{
+ int offs;
+
+ if (offset < 0x1000)
+ {
+ offs = offset >> 1;
+
+ if (offset & 1)
+ return(spriteram16[offs] & 0xff);
+ else
+ return(spriteram16[offs] >> 8);
+ }
+ else return simpsons_xtraram[offset - 0x1000];
+}
+
+static WRITE8_HANDLER( simpsons_K053247_w )
+{
+ int offs;
+
+ if (offset < 0x1000)
+ {
+ offs = offset >> 1;
+
+ if (offset & 1)
+ spriteram16[offs] = (spriteram16[offs] & 0xff00) | data;
+ else
+ spriteram16[offs] = (spriteram16[offs] & 0x00ff) | (data<<8);
+ }
+ else simpsons_xtraram[offset - 0x1000] = data;
+}
+
+void simpsons_video_banking(int bank)
+{
+ if (bank & 1)
+ {
+ memory_install_read8_handler(0, ADDRESS_SPACE_PROGRAM, 0x0000, 0x0fff, 0, 0, paletteram_r);
+ memory_install_write8_handler(0, ADDRESS_SPACE_PROGRAM, 0x0000, 0x0fff, 0, 0, paletteram_xBBBBBGGGGGRRRRR_be_w);
+ }
+ else
+ {
+ memory_install_read8_handler(0, ADDRESS_SPACE_PROGRAM, 0x0000, 0x0fff, 0, 0, K052109_r);
+ memory_install_write8_handler(0, ADDRESS_SPACE_PROGRAM, 0x0000, 0x0fff, 0, 0, K052109_w);
+ }
+
+ if (bank & 2)
+ {
+ memory_install_read8_handler(0, ADDRESS_SPACE_PROGRAM, 0x2000, 0x3fff, 0, 0, simpsons_K053247_r);
+ memory_install_write8_handler(0, ADDRESS_SPACE_PROGRAM, 0x2000, 0x3fff, 0, 0, simpsons_K053247_w);
+ }
+ else
+ {
+ memory_install_read8_handler(0, ADDRESS_SPACE_PROGRAM, 0x2000, 0x3fff, 0, 0, simpsons_K052109_r);
+ memory_install_write8_handler(0, ADDRESS_SPACE_PROGRAM, 0x2000, 0x3fff, 0, 0, simpsons_K052109_w);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+/* useful function to sort the three tile layers by priority order */
+static void sortlayers(int *layer,int *pri)
+{
+#define SWAP(a,b) \
+ if (pri[a] < pri[b]) \
+ { \
+ int t; \
+ t = pri[a]; pri[a] = pri[b]; pri[b] = t; \
+ t = layer[a]; layer[a] = layer[b]; layer[b] = t; \
+ }
+
+ SWAP(0,1)
+ SWAP(0,2)
+ SWAP(1,2)
+}
+
+VIDEO_UPDATE( simpsons )
+{
+ int layer[3];
+
+
+ bg_colorbase = K053251_get_palette_index(K053251_CI0);
+ sprite_colorbase = K053251_get_palette_index(K053251_CI1);
+ layer_colorbase[0] = K053251_get_palette_index(K053251_CI2);
+ layer_colorbase[1] = K053251_get_palette_index(K053251_CI3);
+ layer_colorbase[2] = K053251_get_palette_index(K053251_CI4);
+
+ K052109_tilemap_update();
+
+ layer[0] = 0;
+ layerpri[0] = K053251_get_priority(K053251_CI2);
+ layer[1] = 1;
+ layerpri[1] = K053251_get_priority(K053251_CI3);
+ layer[2] = 2;
+ layerpri[2] = K053251_get_priority(K053251_CI4);
+
+ sortlayers(layer,layerpri);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[16 * bg_colorbase],cliprect);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[0]],0,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[1]],0,2);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[2]],0,4);
+
+ K053247_sprites_draw(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/skullxbo.c b/src/mame/video/skullxbo.c
new file mode 100644
index 00000000000..a492c16b347
--- /dev/null
+++ b/src/mame/video/skullxbo.c
@@ -0,0 +1,309 @@
+/***************************************************************************
+
+ Atari Skull & Crossbones hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "includes/skullxbo.h"
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha[tile_index];
+ int code = (data ^ 0x400) & 0x7ff;
+ int color = (data >> 11) & 0x0f;
+ int opaque = data & 0x8000;
+ SET_TILE_INFO(2, code, color, opaque ? TILE_FORCE_LAYER0 : 0);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data1 = atarigen_playfield[tile_index];
+ UINT16 data2 = atarigen_playfield_upper[tile_index] & 0xff;
+ int code = data1 & 0x7fff;
+ int color = data2 & 0x0f;
+ SET_TILE_INFO(1, code, color, (data1 >> 15) & 1);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( skullxbo )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 0, /* index to which gfx system */
+ 2, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 8, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x000, /* base palette entry */
+ 0x200, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0x00ff,0,0,0 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0,0x7fff,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0x000f,0 }}, /* mask for the color */
+ {{ 0,0,0xffc0,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xff80 }}, /* mask for the Y position */
+ {{ 0,0,0,0x0070 }}, /* mask for the width, in tiles*/
+ {{ 0,0,0,0x000f }}, /* mask for the height, in tiles */
+ {{ 0,0x8000,0,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0,0,0x0030,0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0, /* callback routine for special entries */
+ };
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 16,8, 64,64);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,8, 64,32);
+ tilemap_set_transparent_pen(atarigen_alpha_tilemap, 0);
+}
+
+
+
+/*************************************
+ *
+ * Video data latch
+ *
+ *************************************/
+
+WRITE16_HANDLER( skullxbo_xscroll_w )
+{
+ /* combine data */
+ UINT16 oldscroll = *atarigen_xscroll;
+ UINT16 newscroll = oldscroll;
+ COMBINE_DATA(&newscroll);
+
+ /* if something changed, force an update */
+ if (oldscroll != newscroll)
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ /* adjust the actual scrolls */
+ tilemap_set_scrollx(atarigen_playfield_tilemap, 0, 2 * (newscroll >> 7));
+ atarimo_set_xscroll(0, 2 * (newscroll >> 7));
+
+ /* update the data */
+ *atarigen_xscroll = newscroll;
+}
+
+
+WRITE16_HANDLER( skullxbo_yscroll_w )
+{
+ /* combine data */
+ int scanline = video_screen_get_vpos(0);
+ UINT16 oldscroll = *atarigen_yscroll;
+ UINT16 newscroll = oldscroll;
+ UINT16 effscroll;
+ COMBINE_DATA(&newscroll);
+
+ /* if something changed, force an update */
+ if (oldscroll != newscroll)
+ video_screen_update_partial(0, scanline);
+
+ /* adjust the effective scroll for the current scanline */
+ if (scanline > Machine->screen[0].visarea.max_y)
+ scanline = 0;
+ effscroll = (newscroll >> 7) - scanline;
+
+ /* adjust the actual scrolls */
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, effscroll);
+ atarimo_set_yscroll(0, effscroll & 0x1ff);
+
+ /* update the data */
+ *atarigen_yscroll = newscroll;
+}
+
+
+
+/*************************************
+ *
+ * Motion object bank handler
+ *
+ *************************************/
+
+WRITE16_HANDLER( skullxbo_mobmsb_w )
+{
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ atarimo_set_bank(0, (offset >> 9) & 1);
+}
+
+
+
+/*************************************
+ *
+ * Playfield latch write handler
+ *
+ *************************************/
+
+WRITE16_HANDLER( skullxbo_playfieldlatch_w )
+{
+ atarigen_set_playfield_latch(data);
+}
+
+
+
+/*************************************
+ *
+ * Periodic playfield updater
+ *
+ *************************************/
+
+void skullxbo_scanline_update(int scanline)
+{
+ UINT16 *base = &atarigen_alpha[(scanline / 8) * 64 + 42];
+ int x;
+
+ /* keep in range */
+ if (base >= &atarigen_alpha[0x7c0])
+ return;
+
+ /* special case: scanline 0 should re-latch the previous raw scroll */
+ if (scanline == 0)
+ {
+ int newscroll = (*atarigen_yscroll >> 7) & 0x1ff;
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, newscroll);
+ atarimo_set_yscroll(0, newscroll);
+ }
+
+ /* update the current parameters */
+ for (x = 42; x < 64; x++)
+ {
+ UINT16 data = *base++;
+ UINT16 command = data & 0x000f;
+
+ /* only command I've ever seen */
+ if (command == 0x0d)
+ {
+ /* a new vscroll latches the offset into a counter; we must adjust for this */
+ int newscroll = ((data >> 7) - scanline) & 0x1ff;
+
+ /* force a partial update with the previous scroll */
+ video_screen_update_partial(0, scanline - 1);
+
+ /* update the new scroll */
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, newscroll);
+ atarimo_set_yscroll(0, newscroll);
+
+ /* make sure we change this value so that writes to the scroll register */
+ /* know whether or not they are a different scroll */
+ *atarigen_yscroll = data;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( skullxbo )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* verified from the GALs on the real PCB; equations follow
+
+ --- O17 is an intermediate value
+ O17=PFPIX3*PFPAL2S*PFPAL3S
+
+ --- CRAM.A10 controls the high bit of the palette select; used for shadows
+ CRAM.A10=BA11*CRAMD
+ +!CRAMD*!LBPRI0*!LBPRI1*!O17*(LBPIX==1)*(ANPIX==0)
+ +!CRAMD*LBPRI0*!LBPRI1*(LBPIX==1)*(ANPIX==0)*!PFPAL3S
+ +!CRAMD*LBPRI1*(LBPIX==1)*(ANPIX==0)*!PFPAL2S*!PFPAL3S
+ +!CRAMD*!PFPIX3*(LBPIX==1)*(ANPIX==0)
+
+ --- SA and SB are the mux select lines:
+ --- 0 = motion objects
+ --- 1 = playfield
+ --- 2 = alpha
+ --- 3 = color RAM access from CPU
+ !SA=!CRAMD*(ANPIX!=0)
+ +!CRAMD*!LBPRI0*!LBPRI1*!O17*(LBPIX!=1)*(LBPIX!=0)
+ +!CRAMD*LBPRI0*!LBPRI1*(LBPIX!=1)*(LBPIX!=0)*!PFPAL3S
+ +!CRAMD*LBPRI1*(LBPIX!=1)*(LBPIX!=0)*!PFPAL2S*!PFPAL3S
+ +!CRAMD*!PFPIX3*(LBPIX!=1)*(LBPIX!=0)
+
+ !SB=!CRAMD*(ANPIX==0)
+ +!CRAMD*LBMISC*(LBPIX!=0)
+
+ */
+ int mopriority = mo[x] >> ATARIMO_PRIORITY_SHIFT;
+ int mopix = mo[x] & 0x1f;
+ int pfcolor = (pf[x] >> 4) & 0x0f;
+ int pfpix = pf[x] & 0x0f;
+ int o17 = ((pf[x] & 0xc8) == 0xc8);
+
+ /* implement the equations */
+ if ((mopriority == 0 && !o17 && mopix >= 2) ||
+ (mopriority == 1 && mopix >= 2 && !(pfcolor & 0x08)) ||
+ ((mopriority & 2) && mopix >= 2 && !(pfcolor & 0x0c)) ||
+ (!(pfpix & 8) && mopix >= 2))
+ pf[x] = mo[x] & ATARIMO_DATA_MASK;
+
+ if ((mopriority == 0 && !o17 && mopix == 1) ||
+ (mopriority == 1 && mopix == 1 && !(pfcolor & 0x08)) ||
+ ((mopriority & 2) && mopix == 1 && !(pfcolor & 0x0c)) ||
+ (!(pfpix & 8) && mopix == 1))
+ pf[x] |= 0x400;
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+
+ /* add the alpha on top */
+ tilemap_draw(bitmap, cliprect, atarigen_alpha_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/skychut.c b/src/mame/video/skychut.c
new file mode 100644
index 00000000000..c4f09b6f608
--- /dev/null
+++ b/src/mame/video/skychut.c
@@ -0,0 +1,138 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+ (c) 12/2/1998 Lee Taylor
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+UINT8 *iremm15_chargen;
+static int bottomline;
+
+
+WRITE8_HANDLER( skychut_colorram_w )
+{
+ colorram[offset] = data;
+}
+
+WRITE8_HANDLER( skychut_ctrl_w )
+{
+//popmessage("%02x",data);
+
+ /* I have NO IDEA if this is correct or not */
+ bottomline = ~data & 0x20;
+}
+
+
+VIDEO_UPDATE( skychut )
+{
+ int offs;
+
+ fillbitmap(bitmap,machine->pens[7],cliprect);
+
+ for (offs = 0;offs < 0x400;offs++)
+ {
+ int mask=iremm15_chargen[offs];
+ int x = offs / 256;
+ int y = offs % 256;
+ int col = 0;
+
+ switch (x)
+ {
+ case 0: x = 4*8; col = 3; break;
+ case 1: x = 26*8; col = 3; break;
+ case 2: x = 7*8; col = 5; break;
+ case 3: x = 6*8; col = 5; break;
+ }
+
+ if (x >= cliprect->min_x && x+7 <= cliprect->max_x
+ && y >= cliprect->min_y && y <= cliprect->max_y)
+ {
+ if (mask&0x80) *BITMAP_ADDR16(bitmap, y, x+0) = col;
+ if (mask&0x40) *BITMAP_ADDR16(bitmap, y, x+1) = col;
+ if (mask&0x20) *BITMAP_ADDR16(bitmap, y, x+2) = col;
+ if (mask&0x10) *BITMAP_ADDR16(bitmap, y, x+3) = col;
+ if (mask&0x08) *BITMAP_ADDR16(bitmap, y, x+4) = col;
+ if (mask&0x04) *BITMAP_ADDR16(bitmap, y, x+5) = col;
+ if (mask&0x02) *BITMAP_ADDR16(bitmap, y, x+6) = col;
+ if (mask&0x01) *BITMAP_ADDR16(bitmap, y, x+7) = col;
+ }
+ }
+
+ if (bottomline)
+ {
+ int y;
+
+ for (y = cliprect->min_y;y <= cliprect->max_y;y++)
+ {
+ *BITMAP_ADDR16(bitmap, y, 16) = 0;
+ }
+ }
+
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int sx,sy;
+
+ sx = 31 - offs / 32;
+ sy = offs % 32;
+
+ drawgfx(bitmap,machine->gfx[0],
+ videoram[offs],
+ colorram[offs],
+ 0,0,
+ 8*sx,8*sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
+
+
+static void iremm15_drawgfx(mame_bitmap *bitmap, int ch,
+ INT16 color, INT16 back, int x, int y)
+{
+ UINT8 mask;
+ int i;
+
+ for (i=0; i<8; i++, y++) {
+ mask=iremm15_chargen[ch*8+i];
+ *BITMAP_ADDR16(bitmap, y, x+0) = mask&0x80?color:back;
+ *BITMAP_ADDR16(bitmap, y, x+1) = mask&0x40?color:back;
+ *BITMAP_ADDR16(bitmap, y, x+2) = mask&0x20?color:back;
+ *BITMAP_ADDR16(bitmap, y, x+3) = mask&0x10?color:back;
+ *BITMAP_ADDR16(bitmap, y, x+4) = mask&0x08?color:back;
+ *BITMAP_ADDR16(bitmap, y, x+5) = mask&0x04?color:back;
+ *BITMAP_ADDR16(bitmap, y, x+6) = mask&0x02?color:back;
+ *BITMAP_ADDR16(bitmap, y, x+7) = mask&0x01?color:back;
+ }
+}
+
+
+VIDEO_UPDATE( iremm15 )
+{
+ int offs;
+
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int sx,sy;
+
+
+ sx = 31 - offs / 32;
+ sy = offs % 32;
+
+ iremm15_drawgfx(tmpbitmap,
+ videoram[offs],
+ machine->pens[colorram[offs] & 7],
+ machine->pens[7], // space beam not color 0
+ 8*sx,8*sy);
+ }
+
+ copybitmap(bitmap,tmpbitmap,0,0,0,0,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ return 0;
+}
+
diff --git a/src/mame/video/skydiver.c b/src/mame/video/skydiver.c
new file mode 100644
index 00000000000..6db6205a9c0
--- /dev/null
+++ b/src/mame/video/skydiver.c
@@ -0,0 +1,212 @@
+/***************************************************************************
+
+ Atari Sky Diver hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "skydiver.h"
+#include "sound/discrete.h"
+
+
+UINT8 *skydiver_videoram;
+
+static tilemap *bg_tilemap;
+static int width = 0;
+
+
+MACHINE_RESET( skydiver )
+{
+ /* reset all latches */
+ skydiver_start_lamp_1_w(0, 0);
+ skydiver_start_lamp_2_w(0, 0);
+ skydiver_lamp_s_w(0, 0);
+ skydiver_lamp_k_w(0, 0);
+ skydiver_lamp_y_w(0, 0);
+ skydiver_lamp_d_w(0, 0);
+ output_set_value("lampi", 0);
+ output_set_value("lampv", 0);
+ output_set_value("lampe", 0);
+ output_set_value("lampr", 0);
+ skydiver_width_w(0, 0);
+ skydiver_coin_lockout_w(0, 0);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 code = skydiver_videoram[tile_index];
+ SET_TILE_INFO(0, code & 0x3f, code >> 6, 0);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( skydiver )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+}
+
+
+/*************************************
+ *
+ * Memory handlers
+ *
+ *************************************/
+
+WRITE8_HANDLER( skydiver_videoram_w )
+{
+ skydiver_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+READ8_HANDLER( skydiver_wram_r )
+{
+ return skydiver_videoram[offset | 0x380];
+}
+
+WRITE8_HANDLER( skydiver_wram_w )
+{
+ skydiver_videoram[offset | 0x0380] = data;
+}
+
+
+WRITE8_HANDLER( skydiver_width_w )
+{
+ width = offset;
+}
+
+
+WRITE8_HANDLER( skydiver_coin_lockout_w )
+{
+ coin_lockout_global_w(!offset);
+}
+
+
+WRITE8_HANDLER( skydiver_start_lamp_1_w )
+{
+ set_led_status(0, offset);
+}
+
+WRITE8_HANDLER( skydiver_start_lamp_2_w )
+{
+ set_led_status(1, offset);
+}
+
+
+WRITE8_HANDLER( skydiver_lamp_s_w )
+{
+ output_set_value("lamps", offset);
+}
+
+WRITE8_HANDLER( skydiver_lamp_k_w )
+{
+ output_set_value("lampk", offset);
+}
+
+WRITE8_HANDLER( skydiver_lamp_y_w )
+{
+ output_set_value("lampy", offset);
+}
+
+WRITE8_HANDLER( skydiver_lamp_d_w )
+{
+ output_set_value("lampd", offset);
+}
+
+WRITE8_HANDLER( skydiver_2000_201F_w )
+{
+ int bit = offset & 0x01;
+
+ watchdog_reset_w(0,0);
+
+ switch (offset & 0x0e)
+ {
+ case (0x02):
+ output_set_value("lampi", bit);
+ break;
+ case (0x04):
+ output_set_value("lampv", bit);
+ break;
+ case (0x06):
+ output_set_value("lampe", bit);
+ break;
+ case (0x08):
+ output_set_value("lampr", bit);
+ break;
+ case (0x0a):
+ discrete_sound_w(SKYDIVER_OCT1_EN, bit);
+ break;
+ case (0x0c):
+ discrete_sound_w(SKYDIVER_OCT2_EN, bit);
+ break;
+ case (0x0e):
+ discrete_sound_w(SKYDIVER_NOISE_RST, bit);
+ break;
+ }
+}
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int pic;
+
+
+ /* draw each one of our four motion objects, the two PLANE sprites
+ can be drawn double width */
+ for (pic = 3; pic >= 0; pic--)
+ {
+ int sx,sy;
+ int charcode;
+ int xflip, yflip;
+ int color;
+ int wide;
+
+ sx = 29*8 - skydiver_videoram[pic + 0x0390];
+ sy = 30*8 - skydiver_videoram[pic*2 + 0x0398];
+ charcode = skydiver_videoram[pic*2 + 0x0399];
+ xflip = charcode & 0x10;
+ yflip = charcode & 0x08;
+ wide = (~pic & 0x02) && width;
+ charcode = (charcode & 0x07) | ((charcode & 0x60) >> 2);
+ color = pic & 0x01;
+
+ if (wide)
+ {
+ sx -= 8;
+ }
+
+ drawgfxzoom(bitmap,machine->gfx[1],
+ charcode, color,
+ xflip,yflip,sx,sy,
+ cliprect,TRANSPARENCY_PEN,0,
+ wide ? 0x20000 : 0x10000, 0x10000);
+ }
+}
+
+
+VIDEO_UPDATE( skydiver )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/skyfox.c b/src/mame/video/skyfox.c
new file mode 100644
index 00000000000..eda5ef103dd
--- /dev/null
+++ b/src/mame/video/skyfox.c
@@ -0,0 +1,294 @@
+/***************************************************************************
+
+ -= Sky Fox / Exerizer =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+ [ 1 Background ]
+
+ The stars in the background are not tile based (I think!) and
+ their rendering is entirely guesswork for now..
+
+ I draw a star for each horizontal line using 2 bytes in the
+ background rom:
+
+ - the first byte seems a color / shape info
+ - the second byte seems a position info
+
+ The rom holds 4 chunks of $2000 bytes. Most of the data does not
+ change between chunks, while the remaining part (which is rendered
+ to what seems a "milky way") pulsates in color and/or shape
+ to simulate the shimmering of stars (?!) if we draw one chunk only
+ and cycle through the four. Indeed, there's a register cycling
+ through 4 values.
+
+ Since the result kind of matches a screenshot we have, I feel the
+ drawn result is not that far from reality. On the other hand we
+ have a random arrangement of stars, so it's hard to tell for sure..
+
+ [ 256 Sprites ]
+
+ Sprites are 8 planes deep and can be 8x8, 16x16 or 32x32 pixels
+ in size. They are stored as 32x32x8 tiles in the ROMs.
+
+
+***************************************************************************/
+#include "driver.h"
+
+/* Variables only used here: */
+
+static UINT8 vreg[8];
+
+
+/* Variables that driver has access to: */
+
+int skyfox_bg_pos, skyfox_bg_ctrl;
+
+
+
+/***************************************************************************
+
+ Memory Handlers
+
+***************************************************************************/
+
+#ifdef UNUSED_FUNCTION
+READ8_HANDLER( skyfox_vregs_r ) // for debug
+{
+ return vreg[offset];
+}
+#endif
+
+WRITE8_HANDLER( skyfox_vregs_w )
+{
+ vreg[offset] = data;
+
+ switch (offset)
+ {
+ case 0: skyfox_bg_ctrl = data; break;
+ case 1: soundlatch_w(0,data); break;
+ case 2: break;
+ case 3: break;
+ case 4: break;
+ case 5: break;
+ case 6: break;
+ case 7: break;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ There are three 256x4 palette PROMs (one per gun).
+ I don't know the exact values of the resistors between the RAM and the
+ RGB output. I assumed these values (the same as Commando)
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+
+PALETTE_INIT( skyfox )
+{
+ int i;
+
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ bit3 = (color_prom[i] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* green component */
+ bit0 = (color_prom[i + 256] >> 0) & 0x01;
+ bit1 = (color_prom[i + 256] >> 1) & 0x01;
+ bit2 = (color_prom[i + 256] >> 2) & 0x01;
+ bit3 = (color_prom[i + 256] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* blue component */
+ bit0 = (color_prom[i + 2*256] >> 0) & 0x01;
+ bit1 = (color_prom[i + 2*256] >> 1) & 0x01;
+ bit2 = (color_prom[i + 2*256] >> 2) & 0x01;
+ bit3 = (color_prom[i + 2*256] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ /* Grey scale for the background??? */
+ for (i = 0; i < 256; i++)
+ {
+ palette_set_color(machine,i+256,MAKE_RGB(i,i,i));
+ }
+}
+
+
+
+/***************************************************************************
+
+ Sprites Drawing
+
+Offset: Value:
+
+03 Code: selects one of the 32x32 tiles in the ROMs.
+ (Tiles $80-ff are bankswitched to cover $180 tiles)
+
+02 Code + Attr
+
+ 7654 ---- Code (low 4 bits)
+ 8x8 sprites use bits 7654 (since there are 16 8x8 tiles in the 32x32 one)
+ 16x16 sprites use bits --54 (since there are 4 16x16 tiles in the 32x32 one)
+ 32x32 sprites use no bits (since the 32x32 tile is already selected)
+
+ 7--- 3--- Size
+ 1--- 1--- : 32x32 sprites
+ 0--- 1--- : 16x16 sprites
+ 8x8 sprites otherwise
+
+ ---- -2-- Flip Y
+ ---- --1- Flip X
+ ---- ---0 X Low Bit
+
+00 Y
+
+01 X (High 8 Bits)
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ int width = machine->screen[0].width;
+ int height = machine->screen[0].height;
+
+ /* The 32x32 tiles in the 80-ff range are bankswitched */
+ int shift = (skyfox_bg_ctrl & 0x80) ? (4-1) : 4;
+
+ for (offs = 0; offs < spriteram_size; offs += 4)
+ {
+ int xstart, ystart, xend, yend;
+ int xinc, yinc, dx, dy;
+ int low_code, high_code, n;
+
+ int y = spriteram[offs+0];
+ int x = spriteram[offs+1];
+ int code = spriteram[offs+2] + spriteram[offs+3] * 256;
+ int flipx = code & 0x2;
+ int flipy = code & 0x4;
+
+ x = x * 2 + (code & 1); // add the least significant bit
+
+ high_code = ((code >> 4) & 0x7f0) +
+ ((code & 0x8000) >> shift);
+
+ switch( code & 0x88 )
+ {
+ case 0x88: n = 4; low_code = 0; break;
+ case 0x08: n = 2; low_code = ((code&0x20)?8:0) + ((code&0x10)?2:0); break;
+ default: n = 1; low_code = (code >> 4) & 0xf;
+ }
+
+#define DRAW_SPRITE(DX,DY,CODE) \
+ drawgfx(bitmap,machine->gfx[0], \
+ (CODE), \
+ 0, \
+ flipx,flipy, \
+ x + (DX),y + (DY), \
+ cliprect,TRANSPARENCY_PEN, 0xff); \
+
+ if (skyfox_bg_ctrl & 1) // flipscreen
+ {
+ x = width - x - (n-1)*8;
+ y = height - y - (n-1)*8;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if (flipx) { xstart = n-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = n; xinc = +1; }
+
+ if (flipy) { ystart = n-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = n; yinc = +1; }
+
+
+ code = low_code + high_code;
+
+ for (dy = ystart; dy != yend; dy += yinc)
+ {
+ for (dx = xstart; dx != xend; dx += xinc)
+ DRAW_SPRITE( dx*8, dy*8, code++);
+
+ if (n==2) code+=2;
+ }
+ }
+}
+
+
+
+
+
+/***************************************************************************
+
+ Background Rendering
+
+***************************************************************************/
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 *RAM = memory_region(REGION_GFX2);
+ int x,y,i;
+
+ /* The foreground stars (sprites) move at twice this speed when
+ the bg scroll rate [e.g. (skyfox_bg_reg >> 1) & 7] is 4 */
+ int pos = (skyfox_bg_pos >> 4) & (512*2-1);
+
+ for (i = 0 ; i < 0x1000; i++)
+ {
+ int pen,offs,j;
+
+ offs = (i*2+((skyfox_bg_ctrl>>4)&0x3)*0x2000) % 0x8000;
+
+ pen = RAM[offs];
+ x = RAM[offs+1]*2 + (i&1) + pos + ((i & 8)?512:0);
+ y = ((i/8)/2)*8 + (i%8);
+
+ if (skyfox_bg_ctrl & 1) // flipscreen
+ {
+ x = 512 * 2 - (x%(512*2));
+ y = 256 - (y%256);
+ }
+
+ for (j = 0 ; j <= ((pen&0x80)?0:3); j++)
+ *BITMAP_ADDR16(bitmap,
+ ( ((j/2)&1) + y ) % 256,
+ ( (j&1) + x ) % 512) = machine->pens[256+(pen&0x7f)];
+ }
+}
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+
+VIDEO_UPDATE( skyfox )
+{
+ fillbitmap(bitmap,machine->pens[255],cliprect); // the bg is black
+ draw_background(machine, bitmap, cliprect);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/skykid.c b/src/mame/video/skykid.c
new file mode 100644
index 00000000000..bcfab2cd593
--- /dev/null
+++ b/src/mame/video/skykid.c
@@ -0,0 +1,273 @@
+#include "driver.h"
+
+UINT8 *skykid_textram, *skykid_videoram, *skykid_spriteram;
+
+static tilemap *bg_tilemap,*tx_tilemap;
+static UINT8 priority;
+static UINT16 scroll_x,scroll_y;
+
+
+/***************************************************************************
+
+ Convert the color PROMs.
+
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+
+PALETTE_INIT( skykid )
+{
+ int i;
+ int bit0,bit1,bit2,bit3,r,g,b;
+ int totcolors = machine->drv->total_colors;
+
+ for (i = 0; i < totcolors; i++)
+ {
+ /* red component */
+ bit0 = (color_prom[totcolors*0] >> 0) & 0x01;
+ bit1 = (color_prom[totcolors*0] >> 1) & 0x01;
+ bit2 = (color_prom[totcolors*0] >> 2) & 0x01;
+ bit3 = (color_prom[totcolors*0] >> 3) & 0x01;
+ r = 0x0e*bit0 + 0x1f*bit1 + 0x43*bit2 + 0x8f*bit3;
+
+ /* green component */
+ bit0 = (color_prom[totcolors*1] >> 0) & 0x01;
+ bit1 = (color_prom[totcolors*1] >> 1) & 0x01;
+ bit2 = (color_prom[totcolors*1] >> 2) & 0x01;
+ bit3 = (color_prom[totcolors*1] >> 3) & 0x01;
+ g = 0x0e*bit0 + 0x1f*bit1 + 0x43*bit2 + 0x8f*bit3;
+
+ /* blue component */
+ bit0 = (color_prom[totcolors*2] >> 0) & 0x01;
+ bit1 = (color_prom[totcolors*2] >> 1) & 0x01;
+ bit2 = (color_prom[totcolors*2] >> 2) & 0x01;
+ bit3 = (color_prom[totcolors*2] >> 3) & 0x01;
+ b = 0x0e*bit0 + 0x1f*bit1 + 0x43*bit2 + 0x8f*bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* text palette */
+ for (i = 0; i < 64*4; i++)
+ *(colortable++) = i;
+
+ color_prom += 2*totcolors;
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* tiles lookup table */
+ for (i = 0; i < 128*4; i++)
+ *(colortable++) = *(color_prom++);
+
+ /* sprites lookup table */
+ for (i = 0;i < 64*8;i++)
+ *(colortable++) = *(color_prom++);
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/* convert from 32x32 to 36x28 */
+static TILEMAP_MAPPER( tx_tilemap_scan )
+{
+ int offs;
+
+ row += 2;
+ col -= 2;
+ if (col & 0x20)
+ offs = row + ((col & 0x1f) << 5);
+ else
+ offs = col + (row << 5);
+
+ return offs;
+}
+
+static TILE_GET_INFO( tx_get_tile_info )
+{
+ /* the hardware has two character sets, one normal and one flipped. When
+ screen is flipped, character flip is done by selecting the 2nd character set.
+ We reproduce this here, but since the tilemap system automatically flips
+ characters when screen is flipped, we have to flip them back. */
+ SET_TILE_INFO(
+ 0,
+ skykid_textram[tile_index] | (flip_screen ? 0x100 : 0),
+ skykid_textram[tile_index + 0x400] & 0x3f,
+ flip_screen ? (TILE_FLIPY | TILE_FLIPX) : 0);
+}
+
+
+static TILE_GET_INFO( bg_get_tile_info )
+{
+ int code = skykid_videoram[tile_index];
+ int attr = skykid_videoram[tile_index+0x800];
+
+ SET_TILE_INFO(
+ 1,
+ code + ((attr & 0x01) << 8),
+ ((attr & 0x7e) >> 1) | ((attr & 0x01) << 6),
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( skykid )
+{
+ tx_tilemap = tilemap_create(tx_get_tile_info,tx_tilemap_scan, TILEMAP_TYPE_PEN,8,8,36,28);
+ bg_tilemap = tilemap_create(bg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,32);
+
+ tilemap_set_transparent_pen(tx_tilemap, 0);
+
+ spriteram = skykid_spriteram + 0x780;
+ spriteram_2 = spriteram + 0x0800;
+ spriteram_3 = spriteram_2 + 0x0800;
+
+ state_save_register_global(priority);
+ state_save_register_global(scroll_x);
+ state_save_register_global(scroll_y);
+ state_save_register_global(flip_screen);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ8_HANDLER( skykid_videoram_r )
+{
+ return skykid_videoram[offset];
+}
+
+WRITE8_HANDLER( skykid_videoram_w )
+{
+ skykid_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x7ff);
+}
+
+READ8_HANDLER( skykid_textram_r )
+{
+ return skykid_textram[offset];
+}
+
+WRITE8_HANDLER( skykid_textram_w )
+{
+ skykid_textram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( skykid_scroll_x_w )
+{
+ scroll_x = offset;
+}
+
+WRITE8_HANDLER( skykid_scroll_y_w )
+{
+ scroll_y = offset;
+}
+
+WRITE8_HANDLER( skykid_flipscreen_priority_w )
+{
+ priority = data;
+ flip_screen_set(offset & 1);
+}
+
+
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+/* the sprite generator IC is the same as Mappy */
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x80;offs += 2)
+ {
+ static int gfx_offs[2][2] =
+ {
+ { 0, 1 },
+ { 2, 3 }
+ };
+ int sprite = spriteram[offs] + ((spriteram_3[offs] & 0x80) << 1);
+ int color = (spriteram[offs+1] & 0x3f);
+ int sx = (spriteram_2[offs+1]) + 0x100*(spriteram_3[offs+1] & 1) - 71;
+ int sy = 256 - spriteram_2[offs] - 7;
+ int flipx = (spriteram_3[offs] & 0x01);
+ int flipy = (spriteram_3[offs] & 0x02) >> 1;
+ int sizex = (spriteram_3[offs] & 0x04) >> 2;
+ int sizey = (spriteram_3[offs] & 0x08) >> 3;
+ int x,y;
+
+ sprite &= ~sizex;
+ sprite &= ~(sizey << 1);
+
+ if (flip_screen)
+ {
+ flipx ^= 1;
+ flipy ^= 1;
+ }
+
+ sy -= 16 * sizey;
+ sy = (sy & 0xff) - 32; // fix wraparound
+
+ for (y = 0;y <= sizey;y++)
+ {
+ for (x = 0;x <= sizex;x++)
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ sprite + gfx_offs[y ^ (sizey * flipy)][x ^ (sizex * flipx)],
+ color,
+ flipx,flipy,
+ sx + 16*x,sy + 16*y,
+ cliprect,TRANSPARENCY_COLOR,0xff);
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( skykid )
+{
+ if (flip_screen)
+ {
+ tilemap_set_scrollx(bg_tilemap, 0, 189 - (scroll_x ^ 1));
+ tilemap_set_scrolly(bg_tilemap, 0, 7 - scroll_y);
+ }
+ else
+ {
+ tilemap_set_scrollx(bg_tilemap, 0, scroll_x + 35);
+ tilemap_set_scrolly(bg_tilemap, 0, scroll_y + 25);
+ }
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ if ((priority & 0xf0) != 0x50)
+ draw_sprites(machine, bitmap,cliprect);
+
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+
+ if ((priority & 0xf0) == 0x50)
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/skyraid.c b/src/mame/video/skyraid.c
new file mode 100644
index 00000000000..22cda7c4570
--- /dev/null
+++ b/src/mame/video/skyraid.c
@@ -0,0 +1,159 @@
+/***************************************************************************
+
+Atari Sky Raider video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+
+int skyraid_scroll;
+
+UINT8* skyraid_alpha_num_ram;
+UINT8* skyraid_pos_ram;
+UINT8* skyraid_obj_ram;
+
+static mame_bitmap *helper;
+
+
+VIDEO_START( skyraid )
+{
+ helper = auto_bitmap_alloc(128, 240, machine->screen[0].format);
+}
+
+
+static void draw_text(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ const UINT8* p = skyraid_alpha_num_ram;
+
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ int x;
+ int y;
+
+ y = 136 + 16 * (i ^ 1);
+
+ for (x = 0; x < bitmap->width; x += 16)
+ {
+ drawgfx(bitmap, machine->gfx[0], *p++, 0, 0, 0,
+ x, y, cliprect, TRANSPARENCY_PEN, 0);
+ }
+ }
+}
+
+
+static void draw_terrain(running_machine *machine, mame_bitmap* bitmap, const rectangle *cliprect)
+{
+ const UINT8* p = memory_region(REGION_USER1);
+
+ int x;
+ int y;
+
+ for (y = 0; y < bitmap->height; y++)
+ {
+ int offset = (16 * skyraid_scroll + 16 * ((y + 1) / 2)) & 0x7FF;
+
+ x = 0;
+
+ while (x < bitmap->width)
+ {
+ UINT8 val = p[offset++];
+
+ int color = val / 32;
+ int count = val % 32;
+
+ rectangle r;
+
+ r.min_y = y;
+ r.min_x = x;
+ r.max_y = y + 1;
+ r.max_x = x + 31 - count;
+
+ fillbitmap(bitmap, machine->pens[color], &r);
+
+ x += 32 - count;
+ }
+ }
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ int code = skyraid_obj_ram[8 + 2 * i + 0] & 15;
+ int flag = skyraid_obj_ram[8 + 2 * i + 1] & 15;
+ int vert = skyraid_pos_ram[8 + 2 * i + 0];
+ int horz = skyraid_pos_ram[8 + 2 * i + 1];
+
+ vert -= 31;
+
+ if (flag & 1)
+ {
+ drawgfx(bitmap, machine->gfx[1],
+ code ^ 15, code >> 3, 0, 0,
+ horz / 2, vert, cliprect, TRANSPARENCY_PEN, 2);
+ }
+ }
+}
+
+
+static void draw_missiles(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ int i;
+
+ /* hardware is restricted to one sprite per scanline */
+
+ for (i = 0; i < 4; i++)
+ {
+ int code = skyraid_obj_ram[2 * i + 0] & 15;
+ int vert = skyraid_pos_ram[2 * i + 0];
+ int horz = skyraid_pos_ram[2 * i + 1];
+
+ vert -= 15;
+ horz -= 31;
+
+ drawgfx(bitmap, machine->gfx[2],
+ code ^ 15, 0, 0, 0,
+ horz / 2, vert, cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+
+static void draw_trapezoid(mame_bitmap* dst, mame_bitmap* src)
+{
+ const UINT8* p = memory_region(REGION_USER2);
+
+ int x;
+ int y;
+
+ for (y = 0; y < dst->height; y++)
+ {
+ UINT16* pSrc = BITMAP_ADDR16(src, y, 0);
+ UINT16* pDst = BITMAP_ADDR16(dst, y, 0);
+
+ int x1 = 0x000 + p[(y & ~1) + 0];
+ int x2 = 0x100 + p[(y & ~1) + 1];
+
+ for (x = x1; x < x2; x++)
+ {
+ pDst[x] = pSrc[128 * (x - x1) / (x2 - x1)];
+ }
+ }
+}
+
+
+VIDEO_UPDATE( skyraid )
+{
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ draw_terrain(machine, helper, cliprect);
+ draw_sprites(machine, helper, cliprect);
+ draw_missiles(machine, helper, cliprect);
+ draw_trapezoid(bitmap, helper);
+ draw_text(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/slapfght.c b/src/mame/video/slapfght.c
new file mode 100644
index 00000000000..777d0989020
--- /dev/null
+++ b/src/mame/video/slapfght.c
@@ -0,0 +1,254 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of early Toaplan hardware.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *slapfight_videoram;
+UINT8 *slapfight_colorram;
+size_t slapfight_videoram_size;
+UINT8 *slapfight_scrollx_lo,*slapfight_scrollx_hi,*slapfight_scrolly;
+static int flipscreen, slapfight_palette_bank = 0;
+
+static tilemap *pf1_tilemap,*fix_tilemap;
+
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_pf_tile_info ) /* For Performan only */
+{
+ int tile,color;
+
+ tile=videoram[tile_index] + ((colorram[tile_index] & 0x03) << 8);
+ color=(colorram[tile_index] >> 3) & 0x0f;
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_pf1_tile_info )
+{
+ int tile,color;
+
+ tile=videoram[tile_index] + ((colorram[tile_index] & 0x0f) << 8);
+ color=(colorram[tile_index] & 0xf0) >> 4;
+
+ SET_TILE_INFO(
+ 1,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_fix_tile_info )
+{
+ int tile,color;
+
+ tile=slapfight_videoram[tile_index] + ((slapfight_colorram[tile_index] & 0x03) << 8);
+ color=(slapfight_colorram[tile_index] & 0xfc) >> 2;
+
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( perfrman )
+{
+ pf1_tilemap = tilemap_create(get_pf_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_transparent_pen(pf1_tilemap,0);
+}
+
+VIDEO_START( slapfight )
+{
+ pf1_tilemap = tilemap_create(get_pf1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ fix_tilemap = tilemap_create(get_fix_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_transparent_pen(fix_tilemap,0);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( slapfight_videoram_w )
+{
+ videoram[offset]=data;
+ tilemap_mark_tile_dirty(pf1_tilemap,offset);
+}
+
+WRITE8_HANDLER( slapfight_colorram_w )
+{
+ colorram[offset]=data;
+ tilemap_mark_tile_dirty(pf1_tilemap,offset);
+}
+
+WRITE8_HANDLER( slapfight_fixram_w )
+{
+ slapfight_videoram[offset]=data;
+ tilemap_mark_tile_dirty(fix_tilemap,offset);
+}
+
+WRITE8_HANDLER( slapfight_fixcol_w )
+{
+ slapfight_colorram[offset]=data;
+ tilemap_mark_tile_dirty(fix_tilemap,offset);
+}
+
+WRITE8_HANDLER( slapfight_flipscreen_w )
+{
+ logerror("Writing %02x to flipscreen\n",offset);
+ if (offset==0) flipscreen=1; /* Port 0x2 is flipscreen */
+ else flipscreen=0; /* Port 0x3 is normal */
+}
+
+WRITE8_HANDLER( slapfight_palette_bank_w )
+{
+ slapfight_palette_bank = offset;
+}
+
+#ifdef MAME_DEBUG
+void slapfght_log_vram(void)
+{
+ if ( input_code_pressed_once(KEYCODE_B) )
+ {
+ int i;
+ for (i=0; i<0x800; i++)
+ {
+ logerror("Offset:%03x TileRAM:%02x AttribRAM:%02x SpriteRAM:%02x\n",i, videoram[i],colorram[i],spriteram[i]);
+ }
+ }
+}
+#endif
+
+/***************************************************************************
+
+ Render the Sprites
+
+***************************************************************************/
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority_to_display )
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int sx, sy;
+
+ if ((buffered_spriteram[offs+2] & 0x80) == priority_to_display)
+ {
+ if (flipscreen)
+ {
+ sx = 265 - buffered_spriteram[offs+1];
+ sy = 239 - buffered_spriteram[offs+3];
+ sy &= 0xff;
+ }
+ else
+ {
+ sx = buffered_spriteram[offs+1] + 3;
+ sy = buffered_spriteram[offs+3] - 1;
+ }
+ drawgfx(bitmap,machine->gfx[1],
+ buffered_spriteram[offs],
+ ((buffered_spriteram[offs+2] >> 1) & 3) |
+ ((buffered_spriteram[offs+2] << 2) & 4) | (slapfight_palette_bank << 3),
+ flipscreen, flipscreen,
+ sx, sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+
+VIDEO_UPDATE( perfrman )
+{
+ tilemap_set_flip( pf1_tilemap, flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ tilemap_set_scrolly( pf1_tilemap ,0 , 0 );
+ if (flipscreen) {
+ tilemap_set_scrollx( pf1_tilemap ,0 , 264 );
+ }
+ else {
+ tilemap_set_scrollx( pf1_tilemap ,0 , -16 );
+ }
+
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect,0x80);
+
+#ifdef MAME_DEBUG
+ slapfght_log_vram();
+#endif
+ return 0;
+}
+
+
+VIDEO_UPDATE( slapfight )
+{
+ int offs;
+
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ if (flipscreen) {
+ tilemap_set_scrollx( fix_tilemap,0,296);
+ tilemap_set_scrollx( pf1_tilemap,0,(*slapfight_scrollx_lo + 256 * *slapfight_scrollx_hi)+296 );
+ tilemap_set_scrolly( pf1_tilemap,0, (*slapfight_scrolly)+15 );
+ tilemap_set_scrolly( fix_tilemap,0, -1 ); /* Glitch in Tiger Heli otherwise */
+ }
+ else {
+ tilemap_set_scrollx( fix_tilemap,0,0);
+ tilemap_set_scrollx( pf1_tilemap,0,(*slapfight_scrollx_lo + 256 * *slapfight_scrollx_hi) );
+ tilemap_set_scrolly( pf1_tilemap,0, (*slapfight_scrolly)-1 );
+ tilemap_set_scrolly( fix_tilemap,0, -1 ); /* Glitch in Tiger Heli otherwise */
+ }
+
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+
+ /* Draw the sprites */
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ if (flipscreen)
+ drawgfx(bitmap,machine->gfx[2],
+ buffered_spriteram[offs] + ((buffered_spriteram[offs+2] & 0xc0) << 2),
+ (buffered_spriteram[offs+2] & 0x1e) >> 1,
+ 1,1,
+ 288-(buffered_spriteram[offs+1] + ((buffered_spriteram[offs+2] & 0x01) << 8)) +18,240-buffered_spriteram[offs+3],
+ cliprect,TRANSPARENCY_PEN,0);
+ else
+ drawgfx(bitmap,machine->gfx[2],
+ buffered_spriteram[offs] + ((buffered_spriteram[offs+2] & 0xc0) << 2),
+ (buffered_spriteram[offs+2] & 0x1e) >> 1,
+ 0,0,
+ (buffered_spriteram[offs+1] + ((buffered_spriteram[offs+2] & 0x01) << 8)) - 13,buffered_spriteram[offs+3],
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ tilemap_draw(bitmap,cliprect,fix_tilemap,0,0);
+
+#ifdef MAME_DEBUG
+ slapfght_log_vram();
+#endif
+ return 0;
+}
diff --git a/src/mame/video/slapshot.c b/src/mame/video/slapshot.c
new file mode 100644
index 00000000000..e6dbd0cff61
--- /dev/null
+++ b/src/mame/video/slapshot.c
@@ -0,0 +1,633 @@
+#include "driver.h"
+#include "video/taitoic.h"
+
+#define TC0480SCP_GFX_NUM 1
+#define TC0100SCN_GFX_NUM 1
+
+extern UINT8 TC0360PRI_regs[16];
+
+struct tempsprite
+{
+ int gfx;
+ int code,color;
+ int flipx,flipy;
+ int x,y;
+ int zoomx,zoomy;
+ int primask;
+};
+static struct tempsprite *spritelist;
+
+static INT32 sprites_disabled,sprites_active_area,sprites_master_scrollx,sprites_master_scrolly;
+static int sprites_flipscreen = 0;
+static UINT16 *spriteram_buffered,*spriteram_delayed;
+
+INT32 taito_sprite_type = 0;
+UINT16 *taito_sprite_ext;
+size_t taito_spriteext_size;
+static UINT16 spritebank[8];
+
+static INT32 taito_hide_pixels;
+
+
+
+/**********************************************************/
+
+static VIDEO_START( slapshot_core )
+{
+ int i;
+
+ spriteram_delayed = auto_malloc(spriteram_size);
+ spriteram_buffered = auto_malloc(spriteram_size);
+ spritelist = auto_malloc(0x400 * sizeof(*spritelist));
+
+ if (has_TC0480SCP()) /* it's a tc0480scp game */
+ TC0480SCP_vh_start(machine,TC0480SCP_GFX_NUM,taito_hide_pixels,30,9,-1,1,0,2,256);
+ else /* it's a tc0100scn game */
+ TC0100SCN_vh_start(machine,1,TC0100SCN_GFX_NUM,taito_hide_pixels,0,0,0,0,0,0);
+
+ TC0360PRI_vh_start(); /* Purely for save-state purposes */
+
+ for (i = 0; i < 8; i ++)
+ spritebank[i] = 0x400 * i;
+
+ sprites_disabled = 1;
+ sprites_active_area = 0;
+
+ state_save_register_global(taito_hide_pixels);
+ state_save_register_global(taito_sprite_type);
+ state_save_register_global_array(spritebank);
+ state_save_register_global(sprites_disabled);
+ state_save_register_global(sprites_active_area);
+ state_save_register_global_pointer(spriteram_delayed, spriteram_size/2);
+ state_save_register_global_pointer(spriteram_buffered, spriteram_size/2);
+}
+
+VIDEO_START( slapshot )
+{
+ taito_hide_pixels = 3;
+ taito_sprite_type = 2;
+ video_start_slapshot_core(machine);
+}
+
+
+/************************************************************
+ SPRITE DRAW ROUTINES
+************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int *primasks,int y_offset)
+{
+ /*
+ Sprite format:
+ 0000: ---xxxxxxxxxxxxx tile code (0x0000 - 0x1fff)
+ 0002: xxxxxxxx-------- sprite y-zoom level
+ --------xxxxxxxx sprite x-zoom level
+
+ 0x00 - non scaled = 100%
+ 0x80 - scaled to 50%
+ 0xc0 - scaled to 25%
+ 0xe0 - scaled to 12.5%
+ 0xff - scaled to zero pixels size (off)
+
+ [this zoom scale may not be 100% correct, see Gunfront flame screen]
+
+ 0004: ----xxxxxxxxxxxx x-coordinate (-0x800 to 0x07ff)
+ ---x------------ latch extra scroll
+ --x------------- latch master scroll
+ -x-------------- don't use extra scroll compensation
+ x--------------- absolute screen coordinates (ignore all sprite scrolls)
+ xxxx------------ the typical use of the above is therefore
+ 1010 = set master scroll
+ 0101 = set extra scroll
+ 0006: ----xxxxxxxxxxxx y-coordinate (-0x800 to 0x07ff)
+ x--------------- marks special control commands (used in conjunction with 00a)
+ If the special command flag is set:
+ ---------------x related to sprite ram bank
+ ---x------------ unknown (deadconx, maybe others)
+ --x------------- unknown, some games (growl, gunfront) set it to 1 when
+ screen is flipped
+ 0008: --------xxxxxxxx color (0x00 - 0xff)
+ -------x-------- flipx
+ ------x--------- flipy
+ -----x---------- if set, use latched color, else use & latch specified one
+ ----x----------- if set, next sprite entry is part of sequence
+ ---x------------ if clear, use latched y coordinate, else use current y
+ --x------------- if set, y += 16
+ -x-------------- if clear, use latched x coordinate, else use current x
+ x--------------- if set, x += 16
+ 000a: only valid when the special command bit in 006 is set
+ ---------------x related to sprite ram bank. I think this is the one causing
+ the bank switch, implementing it this way all games seem
+ to properly bank switch except for footchmp which uses the
+ bit in byte 006 instead.
+ ------------x--- unknown; some games toggle it before updating sprite ram.
+ ------xx-------- unknown (finalb)
+ -----x---------- unknown (mjnquest)
+ ---x------------ disable the following sprites until another marker with
+ this bit clear is found
+ --x------------- flip screen
+
+ 000b - 000f : unused
+
+ */
+ int x,y,off,extoffs;
+ int code,color,spritedata,spritecont,flipx,flipy;
+ int xcurrent,ycurrent,big_sprite=0;
+ int y_no=0, x_no=0, xlatch=0, ylatch=0, last_continuation_tile=0; /* for zooms */
+ UINT32 zoomword, zoomx, zoomy, zx=0, zy=0, zoomxlatch=0, zoomylatch=0; /* for zooms */
+ int scroll1x, scroll1y;
+ int scrollx=0, scrolly=0;
+ int curx,cury;
+ int x_offset;
+
+ /* pdrawgfx() needs us to draw sprites front to back, so we have to build a list
+ while processing sprite ram and then draw them all at the end */
+ struct tempsprite *sprite_ptr = spritelist;
+
+ /* must remember enable status from last frame because driftout fails to
+ reactivate them from a certain point onwards. */
+ int disabled = sprites_disabled;
+
+ /* must remember master scroll from previous frame because driftout
+ sometimes doesn't set it. */
+ int master_scrollx = sprites_master_scrollx;
+ int master_scrolly = sprites_master_scrolly;
+
+ /* must also remember the sprite bank from previous frame. */
+ int area = sprites_active_area;
+
+ scroll1x = 0;
+ scroll1y = 0;
+ x = y = 0;
+ xcurrent = ycurrent = 0;
+ color = 0;
+
+ x_offset = taito_hide_pixels; /* Get rid of 0-3 unwanted pixels on edge of screen. */
+ if (sprites_flipscreen) x_offset = -x_offset;
+
+ /* safety check to avoid getting stuck in bank 2 for games using only one bank */
+ if (area == 0x8000 &&
+ spriteram_buffered[(0x8000+6)/2] == 0 &&
+ spriteram_buffered[(0x8000+10)/2] == 0)
+ area = 0;
+
+
+ for (off = 0;off < 0x4000;off += 16)
+ {
+ /* sprites_active_area may change during processing */
+ int offs = off + area;
+
+ if (spriteram_buffered[(offs+6)/2] & 0x8000)
+ {
+ disabled = spriteram_buffered[(offs+10)/2] & 0x1000;
+ sprites_flipscreen = spriteram_buffered[(offs+10)/2] & 0x2000;
+ x_offset = taito_hide_pixels; /* Get rid of 0-3 unwanted pixels on edge of screen. */
+ if (sprites_flipscreen) x_offset = -x_offset;
+ area = 0x8000 * (spriteram_buffered[(offs+10)/2] & 0x0001);
+ continue;
+ }
+
+//popmessage("%04x",area);
+
+ /* check for extra scroll offset */
+ if ((spriteram_buffered[(offs+4)/2] & 0xf000) == 0xa000)
+ {
+ master_scrollx = spriteram_buffered[(offs+4)/2] & 0xfff;
+ if (master_scrollx >= 0x800) master_scrollx -= 0x1000; /* signed value */
+ master_scrolly = spriteram_buffered[(offs+6)/2] & 0xfff;
+ if (master_scrolly >= 0x800) master_scrolly -= 0x1000; /* signed value */
+ }
+
+ if ((spriteram_buffered[(offs+4)/2] & 0xf000) == 0x5000)
+ {
+ scroll1x = spriteram_buffered[(offs+4)/2] & 0xfff;
+ if (scroll1x >= 0x800) scroll1x -= 0x1000; /* signed value */
+
+ scroll1y = spriteram_buffered[(offs+6)/2] & 0xfff;
+ if (scroll1y >= 0x800) scroll1y -= 0x1000; /* signed value */
+ }
+
+ if (disabled)
+ continue;
+
+ spritedata = spriteram_buffered[(offs+8)/2];
+
+ spritecont = (spritedata & 0xff00) >> 8;
+
+ if ((spritecont & 0x08) != 0) /* sprite continuation flag set */
+ {
+ if (big_sprite == 0) /* are we starting a big sprite ? */
+ {
+ xlatch = spriteram_buffered[(offs+4)/2] & 0xfff;
+ ylatch = spriteram_buffered[(offs+6)/2] & 0xfff;
+ x_no = 0;
+ y_no = 0;
+ zoomword = spriteram_buffered[(offs+2)/2];
+ zoomylatch = (zoomword>>8) & 0xff;
+ zoomxlatch = (zoomword) & 0xff;
+ big_sprite = 1; /* we have started a new big sprite */
+ }
+ }
+ else if (big_sprite)
+ {
+ last_continuation_tile = 1; /* don't clear big_sprite until last tile done */
+ }
+
+
+ if ((spritecont & 0x04) == 0)
+ color = spritedata & 0xff;
+
+
+// DG: the bigsprite == 0 check fixes "tied-up" little sprites in Thunderfox
+// which (mostly?) have spritecont = 0x20 when they are not continuations
+// of anything.
+ if (big_sprite == 0 || (spritecont & 0xf0) == 0)
+ {
+ x = spriteram_buffered[(offs+4)/2];
+
+// DG: some absolute x values deduced here are 1 too high (scenes when you get
+// home run in Koshien, and may also relate to BG layer woods and stuff as you
+// journey in MjnQuest). You will see they are 1 pixel too far to the right.
+// Where is this extra pixel offset coming from??
+
+ if (x & 0x8000) /* absolute (koshien) */
+ {
+ scrollx = - x_offset - 0x60;
+ scrolly = 0;
+ }
+ else if (x & 0x4000) /* ignore extra scroll */
+ {
+ scrollx = master_scrollx - x_offset - 0x60;
+ scrolly = master_scrolly;
+ }
+ else /* all scrolls applied */
+ {
+ scrollx = scroll1x + master_scrollx - x_offset - 0x60;
+ scrolly = scroll1y + master_scrolly;
+ }
+ x &= 0xfff;
+ y = spriteram_buffered[(offs+6)/2] & 0xfff;
+
+ xcurrent = x;
+ ycurrent = y;
+ }
+ else
+ {
+ if ((spritecont & 0x10) == 0)
+ y = ycurrent;
+ else if ((spritecont & 0x20) != 0)
+ {
+ y += 16;
+ y_no++; /* keep track of y tile for zooms */
+ }
+ if ((spritecont & 0x40) == 0)
+ x = xcurrent;
+ else if ((spritecont & 0x80) != 0)
+ {
+ x += 16;
+ y_no=0;
+ x_no++; /* keep track of x tile for zooms */
+ }
+ }
+
+/* Black lines between flames in Gunfront attract before the zoom
+ finishes suggest these calculations are flawed? */
+
+ if (big_sprite)
+ {
+ zoomx = zoomxlatch;
+ zoomy = zoomylatch;
+ zx = 0x10; /* default, no zoom: 16 pixels across */
+ zy = 0x10; /* default, no zoom: 16 pixels vertical */
+
+ if (zoomx || zoomy)
+ {
+ /* "Zoom" zx&y is pixel size horizontally and vertically
+ of our sprite chunk. So it is difference in x and y
+ coords of our chunk and diagonally adjoining one. */
+
+ x = xlatch + x_no * (0x100 - zoomx) / 16;
+ y = ylatch + y_no * (0x100 - zoomy) / 16;
+ zx = xlatch + (x_no+1) * (0x100 - zoomx) / 16 - x;
+ zy = ylatch + (y_no+1) * (0x100 - zoomy) / 16 - y;
+ }
+ }
+ else
+ {
+ zoomword = spriteram_buffered[(offs+2)/2];
+ zoomy = (zoomword>>8) & 0xff;
+ zoomx = (zoomword) & 0xff;
+ zx = (0x100 - zoomx) / 16;
+ zy = (0x100 - zoomy) / 16;
+ }
+
+ if (last_continuation_tile)
+ {
+ big_sprite=0;
+ last_continuation_tile=0;
+ }
+
+ code = 0;
+ extoffs = offs;
+ if (extoffs >= 0x8000) extoffs -= 0x4000; /* spriteram[0x4000-7fff] has no corresponding extension area */
+
+ if (taito_sprite_type == 0)
+ {
+ int bank;
+
+ code = spriteram_buffered[(offs)/2] & 0x1fff;
+
+ bank = (code & 0x1c00) >> 10;
+ code = spritebank[bank] + (code & 0x3ff);
+ }
+
+ if (taito_sprite_type == 1) /* Yuyugogo */
+ {
+ int i;
+
+ code = spriteram_buffered[(offs)/2] & 0x3ff;
+ i = (taito_sprite_ext[(extoffs >> 4)] & 0x3f ) << 10;
+ code = (i | code);
+ }
+
+ if (taito_sprite_type == 2) /* Pulirula, Slapshot */
+ {
+ int i;
+
+ code = spriteram_buffered[(offs)/2] & 0xff;
+ i = (taito_sprite_ext[(extoffs >> 4)] & 0xff00 );
+ code = (i | code);
+ }
+
+ if (taito_sprite_type == 3) /* Dinorex and a few quizzes */
+ {
+ int i;
+
+ code = spriteram_buffered[(offs)/2] & 0xff;
+ i = (taito_sprite_ext[(extoffs >> 4)] & 0xff ) << 8;
+ code = (i | code);
+ }
+
+ if (code == 0) continue;
+
+ flipx = spritecont & 0x01;
+ flipy = spritecont & 0x02;
+
+ curx = (x + scrollx) & 0xfff;
+ if (curx >= 0x800) curx -= 0x1000; /* treat it as signed */
+
+ cury = (y + scrolly) & 0xfff;
+ if (cury >= 0x800) cury -= 0x1000; /* treat it as signed */
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 319 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ cury += y_offset;
+
+ {
+ sprite_ptr->code = code;
+ sprite_ptr->color = color;
+ if (machine->gfx[0]->color_granularity == 64) /* Final Blow, Slapshot are 6bpp */
+ sprite_ptr->color /= 4;
+ sprite_ptr->flipx = flipx;
+ sprite_ptr->flipy = flipy;
+ sprite_ptr->x = curx;
+ sprite_ptr->y = cury;
+ sprite_ptr->zoomx = zx << 12;
+ sprite_ptr->zoomy = zy << 12;
+
+ if (primasks)
+ {
+ sprite_ptr->primask = primasks[(color & 0xc0) >> 6];
+
+ sprite_ptr++;
+ }
+ else
+ {
+ drawgfxzoom(bitmap,machine->gfx[0],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,TRANSPARENCY_PEN,0,
+ sprite_ptr->zoomx,sprite_ptr->zoomy);
+ }
+ }
+ }
+
+
+ /* this happens only if primsks != NULL */
+ while (sprite_ptr != spritelist)
+ {
+ sprite_ptr--;
+
+ pdrawgfxzoom(bitmap,machine->gfx[0],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,TRANSPARENCY_PEN,0,
+ sprite_ptr->zoomx,sprite_ptr->zoomy,
+ sprite_ptr->primask);
+ }
+}
+
+static int prepare_sprites;
+
+static void taito_handle_sprite_buffering(void)
+{
+ if (prepare_sprites) /* no buffering */
+ {
+ memcpy(spriteram_buffered,spriteram16,spriteram_size);
+ prepare_sprites = 0;
+ }
+}
+
+static void taito_update_sprites_active_area(void)
+{
+ int off;
+
+
+ /* if the frame was skipped, we'll have to do the buffering now */
+ taito_handle_sprite_buffering();
+
+ /* safety check to avoid getting stuck in bank 2 for games using only one bank */
+ if (sprites_active_area == 0x8000 &&
+ spriteram_buffered[(0x8000+6)/2] == 0 &&
+ spriteram_buffered[(0x8000+10)/2] == 0)
+ sprites_active_area = 0;
+
+ for (off = 0;off < 0x4000;off += 16)
+ {
+ /* sprites_active_area may change during processing */
+ int offs = off + sprites_active_area;
+
+ if (spriteram_buffered[(offs+6)/2] & 0x8000)
+ {
+ sprites_disabled = spriteram_buffered[(offs+10)/2] & 0x1000;
+ sprites_active_area = 0x8000 * (spriteram_buffered[(offs+10)/2] & 0x0001);
+ continue;
+ }
+
+ /* check for extra scroll offset */
+ if ((spriteram_buffered[(offs+4)/2] & 0xf000) == 0xa000)
+ {
+ sprites_master_scrollx = spriteram_buffered[(offs+4)/2] & 0xfff;
+ if (sprites_master_scrollx >= 0x800) sprites_master_scrollx -= 0x1000; /* signed value */
+ sprites_master_scrolly = spriteram_buffered[(offs+6)/2] & 0xfff;
+ if (sprites_master_scrolly >= 0x800) sprites_master_scrolly -= 0x1000; /* signed value */
+ }
+ }
+}
+
+VIDEO_EOF( taito_no_buffer )
+{
+ taito_update_sprites_active_area();
+
+ prepare_sprites = 1;
+}
+
+
+/**************************************************************
+ SCREEN REFRESH
+
+Slapshot and Metalb use in the PRI chip
+---------------------------------------
+
++4 xxxx0000 BG1
+ 0000xxxx BG0
++6 xxxx0000 BG3
+ 0000xxxx BG2
+
+Slapshot mostly keeps all sprites above the bg layers.
+One exception is the "puck" in early attract which is
+a bg layer given priority over some sprites.
+********************************************************************/
+
+VIDEO_UPDATE( slapshot )
+{
+ UINT8 layer[5];
+ UINT8 tilepri[5];
+ UINT8 spritepri[4];
+ UINT16 priority;
+
+#ifdef MAME_DEBUG
+ static int dislayer[5]; /* Layer toggles to help get the layers correct */
+#endif
+
+#ifdef MAME_DEBUG
+ if (input_code_pressed_once (KEYCODE_Z))
+ {
+ dislayer[0] ^= 1;
+ popmessage("bg0: %01x",dislayer[0]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_X))
+ {
+ dislayer[1] ^= 1;
+ popmessage("bg1: %01x",dislayer[1]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_C))
+ {
+ dislayer[2] ^= 1;
+ popmessage("bg2: %01x",dislayer[2]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_V))
+ {
+ dislayer[3] ^= 1;
+ popmessage("bg3: %01x",dislayer[3]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_B))
+ {
+ dislayer[4] ^= 1;
+ popmessage("text: %01x",dislayer[4]);
+ }
+#endif
+
+ taito_handle_sprite_buffering();
+
+ TC0480SCP_tilemap_update(machine);
+
+ priority = TC0480SCP_get_bg_priority();
+
+ layer[0] = (priority &0xf000) >> 12; /* tells us which bg layer is bottom */
+ layer[1] = (priority &0x0f00) >> 8;
+ layer[2] = (priority &0x00f0) >> 4;
+ layer[3] = (priority &0x000f) >> 0; /* tells us which is top */
+ layer[4] = 4; /* text layer always over bg layers */
+
+ tilepri[0] = TC0360PRI_regs[4] & 0x0f; /* bg0 */
+ tilepri[1] = TC0360PRI_regs[4] >> 4; /* bg1 */
+ tilepri[2] = TC0360PRI_regs[5] & 0x0f; /* bg2 */
+ tilepri[3] = TC0360PRI_regs[5] >> 4; /* bg3 */
+
+/* we actually assume text layer is on top of everything anyway, but FWIW... */
+ tilepri[layer[4]] = TC0360PRI_regs[7] & 0x0f; /* fg (text layer) */
+
+ spritepri[0] = TC0360PRI_regs[6] & 0x0f;
+ spritepri[1] = TC0360PRI_regs[6] >> 4;
+ spritepri[2] = TC0360PRI_regs[7] & 0x0f;
+ spritepri[3] = TC0360PRI_regs[7] >> 4;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[0]]==0)
+#endif
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[0],0,1);
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[1]]==0)
+#endif
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[1],0,2);
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[2]]==0)
+#endif
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[2],0,4);
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[3]]==0)
+#endif
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[3],0,8);
+
+ {
+ int primasks[4] = {0,0,0,0};
+ int i;
+
+ for (i = 0;i < 4;i++)
+ {
+ if (spritepri[i] < tilepri[(layer[0])]) primasks[i] |= 0xaaaa;
+ if (spritepri[i] < tilepri[(layer[1])]) primasks[i] |= 0xcccc;
+ if (spritepri[i] < tilepri[(layer[2])]) primasks[i] |= 0xf0f0;
+ if (spritepri[i] < tilepri[(layer[3])]) primasks[i] |= 0xff00;
+ }
+
+ draw_sprites(machine,bitmap,cliprect,primasks,0);
+ }
+
+ /*
+ TODO: This isn't the correct way to handle the priority. At the moment of
+ writing, pdrawgfx() doesn't support 5 layers, so I have to cheat, assuming
+ that the FG layer is always on top of sprites.
+ */
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[4]]==0)
+#endif
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[4],0,0);
+ return 0;
+}
+
diff --git a/src/mame/video/snes.c b/src/mame/video/snes.c
new file mode 100644
index 00000000000..9a06ad5e59b
--- /dev/null
+++ b/src/mame/video/snes.c
@@ -0,0 +1,2208 @@
+/***************************************************************************
+
+ snes.c
+
+ Video file to handle emulation of the Nintendo Super NES.
+
+ Anthony Kruize
+ Based on the original code by Lee Hammerton (aka Savoury Snax)
+
+ Some notes on the snes video hardware:
+
+ Object Attribute Memory(OAM) is made up of 128 blocks of 32 bits, followed
+ by 128 blocks of 2 bits. The format for each block is:
+ -First Block----------------------------------------------------------------
+ | x pos | y pos |char no.| v flip | h flip |priority|palette |char no msb|
+ +--------+--------+--------+--------+--------+--------+--------+-----------+
+ | 8 bits | 8 bits | 8 bits | 1 bit | 1 bit | 2 bits | 3 bits | 1 bit |
+ -Second Block---------------------------------------------------------------
+ | size | x pos msb |
+ +-------+-----------+
+ | 1 bit | 1 bit |
+ ---------------------
+
+ Video RAM contains information for character data and screen maps.
+ Screen maps are made up of 32 x 32 blocks of 16 bits each.
+ The format for each block is:
+ ----------------------------------------------
+ | v flip | x flip |priority|palette |char no.|
+ +--------+--------+--------+--------+--------+
+ | 1 bit | 1 bit | 1 bit | 3 bits |10 bits |
+ ----------------------------------------------
+ Mode 7 is stored differently. Character data and screen map are interleaved.
+ There are two formats:
+ -Normal----------------- -EXTBG-----------------------------
+ | char data | char no. | | priority | char data | char no. |
+ +-----------+----------+ +----------+-----------+----------+
+ | 8 bits | 8 bits | | 1 bit | 7 bits | 8 bits |
+ ------------------------ -----------------------------------
+
+ The screen layers are drawn with the following priorities:
+ (highest to lowest)
+
+ Modes 0 and 1 Modes 2 to 7
+ -------------------------------------------------------
+ Mainscreens
+ (BG3:1 - BG3 priority) OBJ:3
+ OBJ:3 BG1:1
+ BG1:1 OBJ:2
+ BG2:1 BG2:1
+ OBJ:2 OBJ:1
+ BG1:0 BG1:0
+ BG2:0 OBJ:0
+ OBJ:1 BG2:0
+ (BG3:1 - BG3 not priority) Background Colour
+ BG4:1
+ OBJ:0
+ BG3:0
+ BG4:0
+ Background Colour
+ Subscreens
+ (BG3:1 - BG3 priority) OBJ:3
+ OBJ:3 BG1:1
+ BG1:1 OBJ:2
+ BG2:1 BG2:1
+ OBJ:2 OBJ:1
+ BG1:0 BG1:0
+ BG2:0 OBJ:0
+ OBJ:1 BG2:0
+ (BG3:1 - BG3 not priority)
+ BG4:1
+ OBJ:0
+ BG3:0
+ BG4:0
+
+***************************************************************************/
+
+#include "driver.h"
+#include "profiler.h"
+#include "includes/snes.h"
+
+#define MAINSCREEN 0
+#define SUBSCREEN 1
+#define SNES_BLEND_NONE 0
+#define SNES_BLEND_ADD 1
+#define SNES_BLEND_SUB 2
+#define SNES_CLIP_ALL 0
+#define SNES_CLIP_IN 1
+#define SNES_CLIP_OUT 2
+#define SNES_CLIP_ALL2 3
+
+#ifdef SNES_DBG_video
+struct DEBUGOPTS
+{
+ UINT8 input_count;
+ UINT8 bg_disabled[6];
+ UINT8 draw_subscreen;
+ UINT8 windows_disabled;
+ UINT8 transparency_disabled;
+};
+static struct DEBUGOPTS debug_options = {5, {0,0,0,0,0,0}, 0, 0, 0};
+/* red green blue purple yellow cyan grey white */
+static UINT16 dbg_mode_colours[8] = { 0x1f, 0x3e0, 0x7c00, 0x7c1f, 0x3ff, 0x7fe0, 0x4210, 0x7fff };
+static UINT8 snes_dbg_video(running_machine *machine, mame_bitmap *bitmap, UINT16 curline);
+#endif /* SNES_DBG_video */
+
+/* Forward declarations */
+static void snes_update_line_2(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 curline );
+static void snes_update_line_2_hi(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 curline );
+static void snes_update_line_4(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 curline );
+static void snes_update_line_4_hi(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 curline );
+static void snes_update_line_8(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 curline );
+static void snes_update_line_mode7(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 curline );
+
+/* Lookup tables */
+static const UINT8 table_bgd_pty[2][4][2] = { { {7,10}, {6,9}, {1,4}, {0,3} }, { {3,10}, {1,7}, {0,0}, {0,0} } };
+static const UINT8 table_obj_pty[4] = { 2, 5, 8, 11 };
+static const UINT16 table_obj_offset[8][8] =
+{
+ { (0*32), (0*32)+32, (0*32)+64, (0*32)+96, (0*32)+128, (0*32)+160, (0*32)+192, (0*32)+224 },
+ { (16*32), (16*32)+32, (16*32)+64, (16*32)+96, (16*32)+128, (16*32)+160, (16*32)+192, (16*32)+224 },
+ { (32*32), (32*32)+32, (32*32)+64, (32*32)+96, (32*32)+128, (32*32)+160, (32*32)+192, (32*32)+224 },
+ { (48*32), (48*32)+32, (48*32)+64, (48*32)+96, (48*32)+128, (48*32)+160, (48*32)+192, (48*32)+224 },
+ { (64*32), (64*32)+32, (64*32)+64, (64*32)+96, (64*32)+128, (64*32)+160, (64*32)+192, (64*32)+224 },
+ { (80*32), (80*32)+32, (80*32)+64, (80*32)+96, (80*32)+128, (80*32)+160, (80*32)+192, (80*32)+224 },
+ { (96*32), (96*32)+32, (96*32)+64, (96*32)+96, (96*32)+128, (96*32)+160, (96*32)+192, (96*32)+224 },
+ { (112*32), (112*32)+32, (112*32)+64, (112*32)+96, (112*32)+128, (112*32)+160, (112*32)+192, (112*32)+224 }
+};
+/* Scroll tables 32x32 64x32 32x64 64x64 */
+static const UINT16 table_hscroll[4][4] = { {0,0,0,0}, {0,0x800,0,0x800}, {0,0,0,0}, {0,0x800,0,0x800} };
+static const UINT16 table_vscroll[4][4] = { {0,0,0,0}, {0,0,0,0}, {0,0x800,0,0x800}, {0,0x1000,0,0x1000} };
+
+struct SCANLINE
+{
+ UINT16 buffer[(SNES_SCR_WIDTH * 2) + 16];
+ UINT8 zbuf[(SNES_SCR_WIDTH * 2) + 16];
+};
+struct SNES_MODE_CONFIG
+{
+ void (*drawLayer[5])(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 curline);
+ UINT8 count;
+};
+
+static struct SCANLINE scanlines[2];
+struct SNES_PPU_STRUCT snes_ppu;
+static struct SNES_MODE_CONFIG snes_modedefs[8] =
+{
+/*0*/ { {snes_update_line_2, snes_update_line_2, snes_update_line_2, snes_update_line_2}, 4 },
+/*1*/ { {snes_update_line_4, snes_update_line_4, snes_update_line_2, NULL}, 3 },
+/*2*/ { {snes_update_line_4, snes_update_line_4, NULL, NULL}, 2 }, /* Supports offset per tile */
+/*3*/ { {snes_update_line_8, snes_update_line_4, NULL, NULL}, 2 }, /* Supports direct colour */
+/*4*/ { {snes_update_line_8, snes_update_line_2, NULL, NULL}, 2 }, /* Supports offset per tile and direct colour */
+/*5*/ { {snes_update_line_4_hi, snes_update_line_2_hi, NULL, NULL}, 2 }, /* Supports hires */
+/*6*/ { {snes_update_line_4_hi, NULL, NULL, NULL}, 1 }, /* Supports offset per tile and hires */
+/*7*/ { {snes_update_line_mode7, NULL, NULL, NULL}, 1 } /* Supports direct colour */
+};
+
+/*****************************************
+ * snes_draw_blend()
+ *
+ * Routine for additive/subtractive blending
+ * between the main and sub screens.
+ *****************************************/
+INLINE void snes_draw_blend(running_machine *machine, UINT16 offset, UINT16 *colour, UINT8 mode, UINT8 clip )
+{
+#ifdef SNES_DBG_video
+ if( !debug_options.transparency_disabled )
+#endif /* SNES_DBG_video */
+ if( (clip == SNES_CLIP_ALL || clip == SNES_CLIP_ALL2) ||
+ (clip == SNES_CLIP_IN && snes_ppu.clipmasks[5][offset]) ||
+ (clip == SNES_CLIP_OUT && !snes_ppu.clipmasks[5][offset]) )
+ {
+ UINT16 r, g, b;
+ if( mode == SNES_BLEND_ADD )
+ {
+ if( snes_ram[CGWSEL] & 0x2 ) /* Subscreen*/
+ {
+ r = (*colour & 0x1f) + (scanlines[SUBSCREEN].buffer[offset] & 0x1f);
+ g = ((*colour & 0x3e0) >> 5) + ((scanlines[SUBSCREEN].buffer[offset] & 0x3e0) >> 5);
+ b = ((*colour & 0x7c00) >> 10) + ((scanlines[SUBSCREEN].buffer[offset] & 0x7c00) >> 10);
+ if( (snes_ram[CGADSUB] & 0x40) && (scanlines[SUBSCREEN].zbuf[offset]) ) /* FIXME: We shouldn't halve for the back colour */
+ {
+ r >>= 1;
+ g >>= 1;
+ b >>= 1;
+ }
+ }
+ else /* Fixed colour */
+ {
+ r = (*colour & 0x1f) + (machine->remapped_colortable[FIXED_COLOUR] & 0x1f);
+ g = ((*colour & 0x3e0) >> 5) + ((machine->remapped_colortable[FIXED_COLOUR] & 0x3e0) >> 5);
+ b = ((*colour & 0x7c00) >> 10) + ((machine->remapped_colortable[FIXED_COLOUR] & 0x7c00) >> 10);
+ if( snes_ram[CGADSUB] & 0x40 ) /* FIXME: We shouldn't halve for the back colour */
+ {
+ r >>= 1;
+ g >>= 1;
+ b >>= 1;
+ }
+ }
+ if( r > 0x1f ) r = 0x1f;
+ if( g > 0x1f ) g = 0x1f;
+ if( b > 0x1f ) b = 0x1f;
+ *colour = ((r & 0x1f) | ((g & 0x1f) << 5) | ((b & 0x1f) << 10));
+ }
+ else if( mode == SNES_BLEND_SUB )
+ {
+ if( snes_ram[CGWSEL] & 0x2 ) /* Subscreen */
+ {
+ r = (*colour & 0x1f) - (scanlines[SUBSCREEN].buffer[offset] & 0x1f);
+ g = ((*colour & 0x3e0) >> 5) - ((scanlines[SUBSCREEN].buffer[offset] & 0x3e0) >> 5);
+ b = ((*colour & 0x7c00) >> 10) - ((scanlines[SUBSCREEN].buffer[offset] & 0x7c00) >> 10);
+ if( r > 0x1f ) r = 0;
+ if( g > 0x1f ) g = 0;
+ if( b > 0x1f ) b = 0;
+ if( (snes_ram[CGADSUB] & 0x40) && (scanlines[SUBSCREEN].zbuf[offset]) ) /* FIXME: We shouldn't halve for the back colour */
+ {
+ r >>= 1;
+ g >>= 1;
+ b >>= 1;
+ }
+ }
+ else /* Fixed colour */
+ {
+ r = (*colour & 0x1f) - (machine->remapped_colortable[FIXED_COLOUR] & 0x1f);
+ g = ((*colour & 0x3e0) >> 5) - ((machine->remapped_colortable[FIXED_COLOUR] & 0x3e0) >> 5);
+ b = ((*colour & 0x7c00) >> 10) - ((machine->remapped_colortable[FIXED_COLOUR] & 0x7c00) >> 10);
+ if( r > 0x1f ) r = 0;
+ if( g > 0x1f ) g = 0;
+ if( b > 0x1f ) b = 0;
+ if( snes_ram[CGADSUB] & 0x40 ) /* FIXME: We shouldn't halve for the back colour */
+ {
+ r >>= 1;
+ g >>= 1;
+ b >>= 1;
+ }
+ }
+ *colour = ((r & 0x1f) | ((g & 0x1f) << 5) | ((b & 0x1f) << 10));
+ }
+ }
+}
+
+/*****************************************
+ * snes_draw_tile_2()
+ *
+ * Draw tiles with 2 bit planes(4 colors)
+ *****************************************/
+INLINE void snes_draw_tile_2(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 tileaddr, INT16 x, UINT8 priority, UINT8 flip, UINT16 pal )
+{
+ UINT8 mask, plane[2];
+ UINT16 c;
+ INT16 ii;
+
+ plane[0] = snes_vram[tileaddr];
+ plane[1] = snes_vram[tileaddr + 1];
+
+ if( flip )
+ mask = 0x1;
+ else
+ mask = 0x80;
+
+ for( ii = x; ii < (x + 8); ii++ )
+ {
+ register UINT8 colour;
+ if( flip )
+ {
+ colour = (plane[0] & mask ? 1 : 0) | (plane[1] & mask ? 2 : 0);
+ mask <<= 1;
+ }
+ else
+ {
+ colour = (plane[0] & mask ? 1 : 0) | (plane[1] & mask ? 2 : 0);
+ mask >>= 1;
+ }
+
+#ifdef SNES_DBG_video
+ if( !debug_options.windows_disabled )
+#endif /* SNES_DBG_video */
+ /* Clip to windows */
+ if( (screen == MAINSCREEN && (snes_ram[TMW] & (0x1 << layer))) || (screen == SUBSCREEN && (snes_ram[TSW] & (0x1 << layer))))
+ colour &= snes_ppu.clipmasks[layer][ii];
+
+ /* Only draw if we have a colour (0 == transparent) */
+ if( colour )
+ {
+ if( (scanlines[screen].zbuf[ii] <= priority) && (ii >= 0) )
+ {
+ c = machine->remapped_colortable[pal + colour];
+ if( screen == MAINSCREEN ) /* Only blend main screens */
+ snes_draw_blend(machine, ii, &c, snes_ppu.layer[layer].blend, (snes_ram[CGWSEL] & 0x30) >> 4 );
+ scanlines[screen].buffer[ii] = c;
+ scanlines[screen].zbuf[ii] = priority;
+ }
+ }
+ }
+}
+
+/*****************************************
+ * snes_draw_tile_2x2()
+ *
+ * Draw 2 tiles with 2 bit planes(4 colors)
+ *****************************************/
+INLINE void snes_draw_tile_2x2(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 tileaddr, INT16 x, UINT8 priority, UINT8 flip, UINT16 pal )
+{
+ if( flip )
+ {
+ snes_draw_tile_2(machine, screen, layer, tileaddr + 16, x, priority, flip, pal );
+ snes_draw_tile_2(machine, screen, layer, tileaddr, x + 8, priority, flip, pal );
+ }
+ else
+ {
+ snes_draw_tile_2(machine, screen, layer, tileaddr, x, priority, flip, pal );
+ snes_draw_tile_2(machine, screen, layer, tileaddr + 16, x + 8, priority, flip, pal );
+ }
+}
+
+/*****************************************
+ * snes_draw_tile_4()
+ *
+ * Draw tiles with 4 bit planes(16 colors)
+ *****************************************/
+INLINE void snes_draw_tile_4(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 tileaddr, INT16 x, UINT8 priority, UINT8 flip, UINT16 pal )
+{
+ UINT8 mask, plane[4];
+ UINT16 c;
+ INT16 ii;
+
+ plane[0] = snes_vram[tileaddr];
+ plane[1] = snes_vram[tileaddr + 1];
+ plane[2] = snes_vram[tileaddr + 16];
+ plane[3] = snes_vram[tileaddr + 17];
+
+ if( flip )
+ mask = 0x1;
+ else
+ mask = 0x80;
+
+ for( ii = x; ii < (x + 8); ii++ )
+ {
+ register UINT8 colour;
+ if( flip )
+ {
+ colour = (plane[0] & mask ? 1 : 0) | (plane[1] & mask ? 2 : 0) |
+ (plane[2] & mask ? 4 : 0) | (plane[3] & mask ? 8 : 0);
+ mask <<= 1;
+ }
+ else
+ {
+ colour = (plane[0] & mask ? 1 : 0) | (plane[1] & mask ? 2 : 0) |
+ (plane[2] & mask ? 4 : 0) | (plane[3] & mask ? 8 : 0);
+ mask >>= 1;
+ }
+
+#ifdef SNES_DBG_video
+ if( !debug_options.windows_disabled )
+#endif /* SNES_DBG_video */
+ /* Clip to windows */
+ if( (screen == MAINSCREEN && (snes_ram[TMW] & (0x1 << layer))) || (screen == SUBSCREEN && (snes_ram[TSW] & (0x1 << layer))))
+ colour &= snes_ppu.clipmasks[layer][ii];
+
+ /* Only draw if we have a colour (0 == transparent) */
+ if( colour )
+ {
+ if( (scanlines[screen].zbuf[ii] <= priority) && (ii >= 0) )
+ {
+ c = machine->remapped_colortable[pal + colour];
+ if( screen == MAINSCREEN ) /* Only blend main screens */
+ snes_draw_blend(machine, ii, &c, snes_ppu.layer[layer].blend, (snes_ram[CGWSEL] & 0x30) >> 4 );
+ scanlines[screen].buffer[ii] = c;
+ scanlines[screen].zbuf[ii] = priority;
+ }
+ }
+ }
+}
+
+/*****************************************
+ * snes_draw_tile_4x2()
+ *
+ * Draw 2 tiles with 4 bit planes(16 colors)
+ *****************************************/
+INLINE void snes_draw_tile_4x2(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 tileaddr, INT16 x, UINT8 priority, UINT8 flip, UINT16 pal )
+{
+ if( flip )
+ {
+ snes_draw_tile_4(machine, screen, layer, tileaddr + 32, x, priority, flip, pal );
+ snes_draw_tile_4(machine, screen, layer, tileaddr, x + 8, priority, flip, pal );
+ }
+ else
+ {
+ snes_draw_tile_4(machine, screen, layer, tileaddr, x, priority, flip, pal );
+ snes_draw_tile_4(machine, screen, layer, tileaddr + 32, x + 8, priority, flip, pal );
+ }
+}
+
+/*****************************************
+ * snes_draw_tile_8()
+ *
+ * Draw tiles with 8 bit planes(256 colors)
+ *****************************************/
+INLINE void snes_draw_tile_8(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 tileaddr, INT16 x, UINT8 priority, UINT8 flip )
+{
+ UINT8 mask, plane[8];
+ UINT16 c;
+ INT16 ii;
+
+ plane[0] = snes_vram[tileaddr];
+ plane[1] = snes_vram[tileaddr + 1];
+ plane[2] = snes_vram[tileaddr + 16];
+ plane[3] = snes_vram[tileaddr + 17];
+ plane[4] = snes_vram[tileaddr + 32];
+ plane[5] = snes_vram[tileaddr + 33];
+ plane[6] = snes_vram[tileaddr + 48];
+ plane[7] = snes_vram[tileaddr + 49];
+
+ if( flip )
+ mask = 0x1;
+ else
+ mask = 0x80;
+
+ for( ii = x; ii < (x + 8); ii++ )
+ {
+ register UINT8 colour;
+ if( flip )
+ {
+ colour = (plane[0] & mask ? 1 : 0) | (plane[1] & mask ? 2 : 0) |
+ (plane[2] & mask ? 4 : 0) | (plane[3] & mask ? 8 : 0) |
+ (plane[4] & mask ? 16 : 0) | (plane[5] & mask ? 32 : 0) |
+ (plane[6] & mask ? 64 : 0) | (plane[7] & mask ? 128 : 0);
+ mask <<= 1;
+ }
+ else
+ {
+ colour = (plane[0] & mask ? 1 : 0) | (plane[1] & mask ? 2 : 0) |
+ (plane[2] & mask ? 4 : 0) | (plane[3] & mask ? 8 : 0) |
+ (plane[4] & mask ? 16 : 0) | (plane[5] & mask ? 32 : 0) |
+ (plane[6] & mask ? 64 : 0) | (plane[7] & mask ? 128 : 0);
+ mask >>= 1;
+ }
+
+#ifdef SNES_DBG_video
+ if( !debug_options.windows_disabled )
+#endif /* SNES_DBG_video */
+ /* Clip to windows */
+ if( (screen == MAINSCREEN && (snes_ram[TMW] & (0x1 << layer))) || (screen == SUBSCREEN && (snes_ram[TSW] & (0x1 << layer))))
+ colour &= snes_ppu.clipmasks[layer][ii];
+
+ /* Only draw if we have a colour (0 == transparent) */
+ if( colour )
+ {
+ if( (scanlines[screen].zbuf[ii] <= priority) && (ii >= 0) )
+ {
+ c = machine->remapped_colortable[colour];
+ if( screen == MAINSCREEN ) /* Only blend main screens */
+ snes_draw_blend(machine, ii, &c, snes_ppu.layer[layer].blend, (snes_ram[CGWSEL] & 0x30) >> 4 );
+ scanlines[screen].buffer[ii] = c;
+ scanlines[screen].zbuf[ii] = priority;
+ }
+ }
+ }
+}
+
+/*****************************************
+ * snes_draw_tile_8x2()
+ *
+ * Draw 2 tiles with 8 bit planes(256 colors)
+ *****************************************/
+INLINE void snes_draw_tile_8x2(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 tileaddr, INT16 x, UINT8 priority, UINT8 flip )
+{
+ if( flip )
+ {
+ snes_draw_tile_8(machine, screen, layer, tileaddr + 64, x, priority, flip );
+ snes_draw_tile_8(machine, screen, layer, tileaddr, x + 8, priority, flip );
+ }
+ else
+ {
+ snes_draw_tile_8(machine, screen, layer, tileaddr, x, priority, flip );
+ snes_draw_tile_8(machine, screen, layer, tileaddr + 64, x + 8, priority, flip );
+ }
+}
+
+/*****************************************
+ * snes_draw_tile_object()
+ *
+ * Draw tiles with 4 bit planes(16 colors)
+ * The same as snes_draw_tile_4() except
+ * that it takes a blend parameter.
+ *****************************************/
+INLINE void snes_draw_tile_object(running_machine *machine, UINT8 screen, UINT16 tileaddr, INT16 x, UINT8 priority, UINT8 flip, UINT16 pal, UINT8 blend )
+{
+ UINT8 mask, plane[4];
+ UINT16 c;
+ INT16 ii;
+
+ plane[0] = snes_vram[tileaddr];
+ plane[1] = snes_vram[tileaddr + 1];
+ plane[2] = snes_vram[tileaddr + 16];
+ plane[3] = snes_vram[tileaddr + 17];
+
+ if( flip )
+ mask = 0x1;
+ else
+ mask = 0x80;
+
+ for( ii = x; ii < (x + 8); ii++ )
+ {
+ register UINT8 colour;
+ if( flip )
+ {
+ colour = (plane[0] & mask ? 1 : 0) | (plane[1] & mask ? 2 : 0) |
+ (plane[2] & mask ? 4 : 0) | (plane[3] & mask ? 8 : 0);
+ mask <<= 1;
+ }
+ else
+ {
+ colour = (plane[0] & mask ? 1 : 0) | (plane[1] & mask ? 2 : 0) |
+ (plane[2] & mask ? 4 : 0) | (plane[3] & mask ? 8 : 0);
+ mask >>= 1;
+ }
+
+#ifdef SNES_DBG_video
+ if( !debug_options.windows_disabled )
+#endif /* SNES_DBG_video */
+ /* Clip to windows */
+ if( (screen == MAINSCREEN && (snes_ram[TMW] & 0x10)) || (screen == SUBSCREEN && (snes_ram[TSW] & 0x10)))
+ colour &= snes_ppu.clipmasks[4][ii];
+
+ /* Only draw if we have a colour (0 == transparent) */
+ if( colour )
+ {
+ if( ii >= 0 )
+ {
+ c = machine->remapped_colortable[pal + colour];
+ if( blend && screen == MAINSCREEN ) /* Only blend main screens */
+ snes_draw_blend(machine, ii, &c, snes_ppu.layer[4].blend, (snes_ram[CGWSEL] & 0x30) >> 4 );
+
+ scanlines[screen].buffer[ii] = c;
+ scanlines[screen].zbuf[ii] = priority;
+ }
+ }
+ }
+}
+
+/*****************************************
+ * snes_draw_tile_object_w()
+ *
+ * Draw tiles with 4 bit planes(16 colors)
+ * The same as snes_draw_tile_4() except
+ * that it takes a blend parameter.
+ * Wide version.
+ *****************************************/
+INLINE void snes_draw_tile_object_w(running_machine *machine, UINT8 screen, UINT16 tileaddr, INT16 x, UINT8 priority, UINT8 flip, UINT16 pal, UINT8 blend )
+{
+ UINT8 mask, plane[4];
+ UINT16 c;
+ INT16 ii;
+
+ plane[0] = snes_vram[tileaddr];
+ plane[1] = snes_vram[tileaddr + 1];
+ plane[2] = snes_vram[tileaddr + 16];
+ plane[3] = snes_vram[tileaddr + 17];
+
+ if( flip )
+ mask = 0x1;
+ else
+ mask = 0x80;
+
+ x <<= 1;
+ for( ii = x; ii < (x + 16); ii += 2 )
+ {
+ register UINT8 colour;
+ if( flip )
+ {
+ colour = (plane[0] & mask ? 1 : 0) | (plane[1] & mask ? 2 : 0) |
+ (plane[2] & mask ? 4 : 0) | (plane[3] & mask ? 8 : 0);
+ mask <<= 1;
+ }
+ else
+ {
+ colour = (plane[0] & mask ? 1 : 0) | (plane[1] & mask ? 2 : 0) |
+ (plane[2] & mask ? 4 : 0) | (plane[3] & mask ? 8 : 0);
+ mask >>= 1;
+ }
+
+#ifdef SNES_DBG_video
+ if( !debug_options.windows_disabled )
+#endif /* SNES_DBG_video */
+ /* Clip to windows */
+ if( (screen == MAINSCREEN && (snes_ram[TMW] & 0x10)) || (screen == SUBSCREEN && (snes_ram[TSW] & 0x10)))
+ colour &= snes_ppu.clipmasks[4][ii];
+
+ /* Only draw if we have a colour (0 == transparent) */
+ if( colour )
+ {
+ if( ii >= 0 )
+ {
+ c = machine->remapped_colortable[pal + colour];
+ if( blend && screen == MAINSCREEN ) /* Only blend main screens */
+ snes_draw_blend(machine, ii, &c, snes_ppu.layer[4].blend, (snes_ram[CGWSEL] & 0x30) >> 4 );
+
+ scanlines[screen].buffer[ii] = c;
+ scanlines[screen].zbuf[ii] = priority;
+ scanlines[screen].buffer[ii + 1] = c;
+ scanlines[screen].zbuf[ii + 1] = priority;
+ }
+ }
+ }
+}
+
+/*********************************************
+ * snes_update_line_2()
+ *
+ * Update an entire line of 2 bit plane tiles.
+ *********************************************/
+static void snes_update_line_2(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 curline )
+{
+ UINT32 tmap, tile;
+ UINT16 ii, vflip, hflip, pal;
+ INT8 line, tile_line;
+ UINT8 priority;
+ /* scrolling */
+ UINT32 basevmap;
+ UINT16 vscroll, hscroll, vtilescroll;
+ UINT8 vshift, hshift, tile_size;
+ UINT8 bg3_pty = 0;
+
+#ifdef SNES_DBG_video
+ if( debug_options.bg_disabled[layer] )
+ return;
+#endif /* SNES_DBG_video */
+
+ /* set special priority bit */
+ if( snes_ppu.mode == 1 && snes_ram[BGMODE] & 0x8 )
+ bg3_pty = 1;
+
+ /* Handle Mosaic effects */
+ if( snes_ram[MOSAIC] & (1 << layer) )
+ curline -= (curline % ((snes_ram[MOSAIC] >> 4) + 1));
+
+ /* Find the size of the tiles (8x8 or 16x16) */
+ tile_size = snes_ppu.layer[layer].tile_size;
+ /* Find scroll info */
+ vscroll = snes_ppu.layer[layer].offset.tile_vert;
+ vshift = snes_ppu.layer[layer].offset.shift_vert;
+ hscroll = snes_ppu.layer[layer].offset.tile_horz;
+ hshift = snes_ppu.layer[layer].offset.shift_horz;
+
+ /* Find vertical scroll amount */
+ vtilescroll = vscroll + (curline >> (3 + tile_size));
+ /* figure out which line to draw */
+ line = (curline % (8 << tile_size)) + vshift;
+ if( line > ((8 << tile_size) - 1) ) /* scrolled into the next tile */
+ {
+ vtilescroll++; /* pretend we scrolled by 1 tile line */
+ line -= (8 << tile_size);
+ }
+ if( vtilescroll >= 128 )
+ vtilescroll -= 128;
+
+ /* Jump to base map address */
+ tmap = snes_ppu.layer[layer].map;
+ /* Offset vertically */
+ tmap += table_vscroll[snes_ppu.layer[layer].map_size][vtilescroll >> 5];
+ /* Scroll vertically */
+ tmap += (vtilescroll & 0x1f) << 6;
+ /* Remember this position */
+ basevmap = tmap;
+ /* Offset horizontally */
+ tmap += table_hscroll[snes_ppu.layer[layer].map_size][hscroll >> 5];
+ /* Scroll horizontally */
+ tmap += (hscroll & 0x1f) << 1;
+
+ for( ii = 0; ii < (66 >> tile_size); ii += 2 )
+ {
+ /* Have we scrolled into the next map? */
+ if( hscroll && ((ii >> 1) >= 32 - (hscroll & 0x1f)) )
+ {
+ tmap = basevmap + table_hscroll[snes_ppu.layer[layer].map_size][(hscroll >> 5) + 1];
+ tmap -= ii;
+ hscroll = 0; /* Make sure we don't do this again */
+ }
+ if (tmap > 0x10000) tmap %= 0x10000;
+ vflip = (snes_vram[tmap + ii + 1] & 0x80);
+ hflip = snes_vram[tmap + ii + 1] & 0x40;
+ priority = table_bgd_pty[snes_ppu.mode > 1][layer][(snes_vram[tmap + ii + 1] & 0x20) >> 5];
+ pal = (snes_vram[tmap + ii + 1] & 0x1c); /* 8 palettes of 4 colours */
+ tile = (snes_vram[tmap + ii + 1] & 0x3) << 8;
+ tile |= snes_vram[tmap + ii];
+
+ /* Mode 0 palettes are layer specific */
+ if( snes_ppu.mode == 0 )
+ {
+ pal += (layer << 5);
+ }
+
+ tile_line = line;
+ if( vflip )
+ {
+ if( tile_size )
+ {
+ if( line > 7 )
+ {
+ tile_line -= 8;
+ }
+ else
+ {
+ tile += 32;
+ }
+ }
+ tile_line = -tile_line + 7;
+ }
+ else
+ {
+ if( line > 7 )
+ {
+ tile += 32;
+ tile_line -= 8;
+ }
+ }
+ tile_line <<= 1;
+
+ /* Special case for bg3 */
+ if( layer == 2 && bg3_pty && (snes_vram[tmap + ii + 1] & 0x20) )
+ priority = table_obj_pty[3] + 1; /* We want to have the highest priority here */
+
+ if( tile_size )
+ {
+ snes_draw_tile_2x2(machine, screen, layer, snes_ppu.layer[layer].data + (tile << 4) + tile_line, ((ii >> 1) * (8 << tile_size)) - hshift, priority, hflip, pal );
+ }
+ else
+ {
+ snes_draw_tile_2(machine, screen, layer, snes_ppu.layer[layer].data + (tile << 4) + tile_line, ((ii >> 1) * (8 << tile_size)) - hshift, priority, hflip, pal );
+ }
+ }
+}
+
+/*********************************************
+ * snes_update_line_2_hi()
+ *
+ * Update an entire line of 2 bit plane tiles.
+ * This is the hires version.
+ *********************************************/
+static void snes_update_line_2_hi(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 curline )
+{
+ UINT32 tmap, tile;
+ UINT16 ii, vflip, hflip, pal;
+ INT8 line, tile_line;
+ UINT8 priority;
+ /* scrolling */
+ UINT32 basevmap;
+ UINT16 vscroll, hscroll, vtilescroll;
+ UINT8 vshift, hshift, tile_size;
+ UINT8 bg3_pty = 0;
+
+#ifdef SNES_DBG_video
+ if( debug_options.bg_disabled[layer] )
+ return;
+#endif /* SNES_DBG_video */
+
+ /* set special priority bit */
+ if( snes_ppu.mode == 1 && snes_ram[BGMODE] & 0x8 )
+ bg3_pty = 1;
+
+ /* Handle Mosaic effects */
+ if( snes_ram[MOSAIC] & (1 << layer) )
+ curline -= (curline % ((snes_ram[MOSAIC] >> 4) + 1));
+
+ /* Find the size of the tiles (8x8 or 16x16) */
+ tile_size = snes_ppu.layer[layer].tile_size;
+ /* Find scroll info */
+ vscroll = snes_ppu.layer[layer].offset.tile_vert;
+ vshift = snes_ppu.layer[layer].offset.shift_vert;
+ hscroll = snes_ppu.layer[layer].offset.tile_horz;
+ hshift = snes_ppu.layer[layer].offset.shift_horz;
+
+ /* Find vertical scroll amount */
+ vtilescroll = vscroll + (curline >> (3 + tile_size));
+ /* figure out which line to draw */
+ line = (curline % (8 << tile_size)) + vshift;
+ if( line > ((8 << tile_size) - 1) ) /* scrolled into the next tile */
+ {
+ vtilescroll++; /* pretend we scrolled by 1 tile line */
+ line -= (8 << tile_size);
+ }
+ if( vtilescroll >= 128 )
+ vtilescroll -= 128;
+
+ /* Jump to base map address */
+ tmap = snes_ppu.layer[layer].map;
+ /* Offset vertically */
+ tmap += table_vscroll[snes_ppu.layer[layer].map_size][vtilescroll >> 5];
+ /* Scroll vertically */
+ tmap += (vtilescroll & 0x1f) << 6;
+ /* Remember this position */
+ basevmap = tmap;
+ /* Offset horizontally */
+ tmap += table_hscroll[snes_ppu.layer[layer].map_size][hscroll >> 5];
+ /* Scroll horizontally */
+ tmap += (hscroll & 0x1f) << 1;
+
+ for( ii = 0; ii < (66 >> tile_size); ii += 2 )
+ {
+ /* Have we scrolled into the next map? */
+ if( hscroll && ((ii >> 1) >= 32 - (hscroll & 0x1f)) )
+ {
+ tmap = basevmap + table_hscroll[snes_ppu.layer[layer].map_size][(hscroll >> 5) + 1];
+ tmap -= ii;
+ hscroll = 0; /* Make sure we don't do this again */
+ }
+ if (tmap > 0x10000) tmap %= 0x10000;
+ vflip = (snes_vram[tmap + ii + 1] & 0x80);
+ hflip = snes_vram[tmap + ii + 1] & 0x40;
+ priority = table_bgd_pty[snes_ppu.mode > 1][layer][(snes_vram[tmap + ii + 1] & 0x20) >> 5];
+ pal = (snes_vram[tmap + ii + 1] & 0x1c); /* 8 palettes of 4 colours */
+ tile = (snes_vram[tmap + ii + 1] & 0x3) << 8;
+ tile |= snes_vram[tmap + ii];
+
+ /* Mode 0 palettes are layer specific */
+ if( snes_ppu.mode == 0 )
+ {
+ pal += (layer << 5);
+ }
+
+ tile_line = line;
+ if( vflip )
+ {
+ if( tile_size )
+ {
+ if( line > 7 )
+ {
+ tile_line -= 8;
+ }
+ else
+ {
+ tile += 32;
+ }
+ }
+ tile_line = -tile_line + 7;
+ }
+ else
+ {
+ if( line > 7 )
+ {
+ tile += 32;
+ tile_line -= 8;
+ }
+ }
+ tile_line <<= 1;
+
+ /* Special case for bg3 */
+ if( layer == 2 && bg3_pty && (snes_vram[tmap + ii + 1] & 0x20) )
+ priority = table_obj_pty[3] + 1; /* We want to have the highest priority here */
+
+ if( tile_size )
+ {
+ if( hflip )
+ {
+ snes_draw_tile_2x2(machine, screen, layer, snes_ppu.layer[layer].data + (tile << 4) + tile_line, ((ii >> 1) * (8 << (tile_size + 1))) - (hshift << 1) + 16, priority, hflip, pal );
+ snes_draw_tile_2x2(machine, screen, layer, snes_ppu.layer[layer].data + ((tile + 2) << 4) + tile_line, ((ii >> 1) * (8 << (tile_size + 1))) - (hshift << 1), priority, hflip, pal );
+ }
+ else
+ {
+ snes_draw_tile_2x2(machine, screen, layer, snes_ppu.layer[layer].data + (tile << 4) + tile_line, ((ii >> 1) * (8 << (tile_size + 1))) - (hshift << 1), priority, hflip, pal );
+ snes_draw_tile_2x2(machine, screen, layer, snes_ppu.layer[layer].data + ((tile + 2) << 4) + tile_line, ((ii >> 1) * (8 << (tile_size + 1))) - (hshift << 1) + 16, priority, hflip, pal );
+ }
+ }
+ else
+ {
+ snes_draw_tile_2x2(machine, screen, layer, snes_ppu.layer[layer].data + (tile << 4) + tile_line, ((ii >> 1) * (8 << (tile_size + 1))) - (hshift << 1), priority, hflip, pal );
+ }
+ }
+}
+
+/*********************************************
+ * snes_update_line_4()
+ *
+ * Update an entire line of 4 bit plane tiles.
+ *********************************************/
+static void snes_update_line_4(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 curline )
+{
+ UINT32 tmap, tile;
+ UINT16 ii, vflip, hflip, pal;
+ INT8 line, tile_line;
+ UINT8 priority;
+ /* scrolling */
+ UINT32 basevmap;
+ UINT16 vscroll, hscroll, vtilescroll;
+ UINT8 vshift, hshift, tile_size;
+
+#ifdef SNES_DBG_video
+ if( debug_options.bg_disabled[layer] )
+ return;
+#endif /* SNES_DBG_video */
+
+ /* Handle Mosaic effects */
+ if( snes_ram[MOSAIC] & (1 << layer) )
+ curline -= (curline % ((snes_ram[MOSAIC] >> 4) + 1));
+
+ /* Find the size of the tiles (8x8 or 16x16) */
+ tile_size = snes_ppu.layer[layer].tile_size;
+ /* Find scroll info */
+ vscroll = snes_ppu.layer[layer].offset.tile_vert;
+ vshift = snes_ppu.layer[layer].offset.shift_vert;
+ hscroll = snes_ppu.layer[layer].offset.tile_horz;
+ hshift = snes_ppu.layer[layer].offset.shift_horz;
+
+ /* Jump to base map address */
+ tmap = snes_ppu.layer[layer].map;
+
+ /* Find vertical scroll amount */
+ vtilescroll = vscroll + (curline >> (3 + tile_size));
+ /* figure out which line to draw */
+ line = (curline % (8 << tile_size)) + vshift;
+ if( line > ((8 << tile_size) - 1) ) /* scrolled into the next tile */
+ {
+ vtilescroll++; /* pretend we scrolled by 1 tile line */
+ line -= (8 << tile_size);
+ }
+ if( vtilescroll >= 128 )
+ vtilescroll -= 128;
+
+ /* Offset vertically */
+ tmap += table_vscroll[snes_ppu.layer[layer].map_size][vtilescroll >> 5];
+ /* Scroll vertically */
+ tmap += (vtilescroll & 0x1f) << 6;
+ /* Remember this position */
+ basevmap = tmap;
+ /* Offset horizontally */
+ tmap += table_hscroll[snes_ppu.layer[layer].map_size][hscroll >> 5];
+ /* Scroll horizontally */
+ tmap += (hscroll & 0x1f) << 1;
+
+ for( ii = 0; ii < (66 >> tile_size); ii += 2 )
+ {
+ /* Have we scrolled into the next map? */
+ if( hscroll && ((ii >> 1) >= 32 - (hscroll & 0x1f)) )
+ {
+ tmap = basevmap + table_hscroll[snes_ppu.layer[layer].map_size][(hscroll >> 5) + 1];
+ tmap -= ii;
+ hscroll = 0; /* Make sure we don't do this again */
+ }
+ if (tmap > 0x10000) tmap %= 0x10000;
+ vflip = snes_vram[tmap + ii + 1] & 0x80;
+ hflip = snes_vram[tmap + ii + 1] & 0x40;
+ priority = table_bgd_pty[snes_ppu.mode > 1][layer][(snes_vram[tmap + ii + 1] & 0x20) >> 5]; /* is this even right??? */
+ pal = (snes_vram[tmap + ii + 1] & 0x1c) << 2; /* 8 palettes of 16 colours */
+ tile = (snes_vram[tmap + ii + 1] & 0x3) << 8;
+ tile |= snes_vram[tmap + ii];
+
+ tile_line = line;
+ if( vflip )
+ {
+ if( tile_size )
+ {
+ if( line > 7 )
+ {
+ tile_line -= 8;
+ }
+ else
+ {
+ tile += 16;
+ }
+ }
+ tile_line = -tile_line + 7;
+ }
+ else
+ {
+ if( line > 7 )
+ {
+ tile += 16;
+ tile_line -= 8;
+ }
+ }
+ tile_line <<= 1;
+
+ if( tile_size )
+ {
+ snes_draw_tile_4x2(machine, screen, layer, snes_ppu.layer[layer].data + (tile << 5) + tile_line, ((ii >> 1) * (8 << tile_size)) - hshift, priority, hflip, pal );
+ }
+ else
+ {
+ snes_draw_tile_4(machine, screen, layer, snes_ppu.layer[layer].data + (tile << 5) + tile_line, ((ii >> 1) * (8 << tile_size)) - hshift, priority, hflip, pal );
+ }
+ }
+}
+
+/*********************************************
+ * snes_update_line_4_hi()
+ *
+ * Update an entire line of 4 bit plane tiles.
+ * This is the hires version
+ *********************************************/
+static void snes_update_line_4_hi(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 curline )
+{
+ UINT32 tmap, tile;
+ UINT16 ii, vflip, hflip, pal;
+ INT8 line, tile_line;
+ UINT8 priority;
+ /* scrolling */
+ UINT32 basevmap;
+ UINT16 vscroll, hscroll, vtilescroll;
+ UINT8 vshift, hshift, tile_size;
+
+#ifdef SNES_DBG_video
+ if( debug_options.bg_disabled[layer] )
+ return;
+#endif /* SNES_DBG_video */
+
+ /* Handle Mosaic effects */
+ if( snes_ram[MOSAIC] & (1 << layer) )
+ curline -= (curline % ((snes_ram[MOSAIC] >> 4) + 1));
+
+ /* Find the size of the tiles (8x8 or 16x16) */
+ tile_size = snes_ppu.layer[layer].tile_size;
+ /* Find scroll info */
+ vscroll = snes_ppu.layer[layer].offset.tile_vert;
+ vshift = snes_ppu.layer[layer].offset.shift_vert;
+ hscroll = snes_ppu.layer[layer].offset.tile_horz;
+ hshift = snes_ppu.layer[layer].offset.shift_horz;
+
+ /* Find vertical scroll amount */
+ vtilescroll = vscroll + (curline >> (3 + tile_size));
+ /* figure out which line to draw */
+ line = (curline % (8 << tile_size)) + vshift;
+ if( line > ((8 << tile_size) - 1) ) /* scrolled into the next tile */
+ {
+ vtilescroll++; /* pretend we scrolled by 1 tile line */
+ line -= (8 << tile_size);
+ }
+ if( vtilescroll >= 128 )
+ vtilescroll -= 128;
+
+ /* Jump to base map address */
+ tmap = snes_ppu.layer[layer].map;
+ /* Offset vertically */
+ tmap += table_vscroll[snes_ppu.layer[layer].map_size][vtilescroll >> 5];
+ /* Scroll vertically */
+ tmap += (vtilescroll & 0x1f) << 6;
+ /* Remember this position */
+ basevmap = tmap;
+ /* Offset horizontally */
+ tmap += table_hscroll[snes_ppu.layer[layer].map_size][hscroll >> 5];
+ /* Scroll horizontally */
+ tmap += (hscroll & 0x1f) << 1;
+
+ for( ii = 0; ii < (66 >> tile_size); ii += 2 )
+ {
+ /* Have we scrolled into the next map? */
+ if( hscroll && ((ii >> 1) >= 32 - (hscroll & 0x1f)) )
+ {
+ tmap = basevmap + table_hscroll[snes_ppu.layer[layer].map_size][(hscroll >> 5) + 1];
+ tmap -= ii;
+ hscroll = 0; /* Make sure we don't do this again */
+ }
+ if (tmap > 0x10000) tmap %= 0x10000;
+
+ vflip = snes_vram[tmap + ii + 1] & 0x80;
+ hflip = snes_vram[tmap + ii + 1] & 0x40;
+ priority = table_bgd_pty[snes_ppu.mode > 1][layer][(snes_vram[tmap + ii + 1] & 0x20) >> 5]; /* is this even right??? */
+ pal = (snes_vram[tmap + ii + 1] & 0x1c) << 2; /* 8 palettes of 16 colours */
+ tile = (snes_vram[tmap + ii + 1] & 0x3) << 8;
+ tile |= snes_vram[tmap + ii];
+
+ tile_line = line;
+ if( vflip )
+ {
+ if( tile_size )
+ {
+ if( line > 7 )
+ {
+ tile_line -= 8;
+ }
+ else
+ {
+ tile += 16;
+ }
+ }
+ tile_line = -tile_line + 7;
+ }
+ else
+ {
+ if( line > 7 )
+ {
+ tile += 16;
+ tile_line -= 8;
+ }
+ }
+ tile_line <<= 1;
+
+ /* Does hi-res support the tile-size option? */
+ if( tile_size )
+ {
+ if( hflip )
+ {
+ snes_draw_tile_4x2(machine, screen, layer, snes_ppu.layer[layer].data + (tile << 5) + tile_line, ((ii >> 1) * (8 << (tile_size + 1))) - (hshift << 1) + 16, priority, hflip, pal );
+ snes_draw_tile_4x2(machine, screen, layer, snes_ppu.layer[layer].data + ((tile + 2) << 5) + tile_line, ((ii >> 1) * (8 << (tile_size + 1))) - (hshift << 1), priority, hflip, pal );
+ }
+ else
+ {
+ snes_draw_tile_4x2(machine, screen, layer, snes_ppu.layer[layer].data + (tile << 5) + tile_line, ((ii >> 1) * (8 << (tile_size + 1))) - (hshift << 1), priority, hflip, pal );
+ snes_draw_tile_4x2(machine, screen, layer, snes_ppu.layer[layer].data + ((tile + 2) << 5) + tile_line, ((ii >> 1) * (8 << (tile_size + 1))) - (hshift << 1) + 16, priority, hflip, pal );
+ }
+ }
+ else
+ {
+ snes_draw_tile_4x2(machine, screen, layer, snes_ppu.layer[layer].data + (tile << 5) + tile_line, ((ii >> 1) * (8 << (tile_size + 1))) - (hshift << 1), priority, hflip, pal );
+ }
+ }
+}
+
+/*********************************************
+ * snes_update_line_8()
+ *
+ * Update an entire line of 8 bit plane tiles.
+ *********************************************/
+static void snes_update_line_8(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 curline )
+{
+ UINT32 tmap, tile;
+ UINT16 ii, vflip, hflip, pal;
+ INT8 line, tile_line;
+ UINT8 priority;
+ /* scrolling */
+ UINT32 basevmap;
+ UINT16 vscroll, hscroll, vtilescroll;
+ UINT8 vshift, hshift, tile_size;
+
+#ifdef SNES_DBG_video
+ if( debug_options.bg_disabled[layer] )
+ return;
+#endif /* SNES_DBG_video */
+
+ /* Handle Mosaic effects */
+ if( snes_ram[MOSAIC] & (1 << layer) )
+ curline -= (curline % ((snes_ram[MOSAIC] >> 4) + 1));
+
+ /* Find the size of the tiles (8x8 or 16x16) */
+ tile_size = snes_ppu.layer[layer].tile_size;
+ /* Find scroll info */
+ vscroll = snes_ppu.layer[layer].offset.tile_vert;
+ vshift = snes_ppu.layer[layer].offset.shift_vert;
+ hscroll = snes_ppu.layer[layer].offset.tile_horz;
+ hshift = snes_ppu.layer[layer].offset.shift_horz;
+
+ /* Find vertical scroll amount */
+ vtilescroll = vscroll + (curline >> (3 + tile_size));
+ /* figure out which line to draw */
+ line = (curline % (8 << tile_size)) + vshift;
+ if( line > ((8 << tile_size) - 1) ) /* scrolled into the next tile */
+ {
+ vtilescroll++; /* pretend we scrolled by 1 tile line */
+ line -= (8 << tile_size);
+ }
+ if( vtilescroll >= 128 )
+ vtilescroll -= 128;
+
+ /* Jump to base map address */
+ tmap = snes_ppu.layer[layer].map;
+ /* Offset vertically */
+ tmap += table_vscroll[snes_ppu.layer[layer].map_size][vtilescroll >> 5];
+ /* Scroll vertically */
+ tmap += (vtilescroll & 0x1f) << 6;
+ /* Remember this position */
+ basevmap = tmap;
+ /* Offset horizontally */
+ tmap += table_hscroll[snes_ppu.layer[layer].map_size][hscroll >> 5];
+ /* Scroll horizontally */
+ tmap += (hscroll & 0x1f) << 1;
+
+ for( ii = 0; ii < (66 >> tile_size); ii += 2 )
+ {
+ /* Have we scrolled into the next map? */
+ if( hscroll && ((ii >> 1) >= 32 - (hscroll & 0x1f)) )
+ {
+ tmap = basevmap + table_hscroll[snes_ppu.layer[layer].map_size][(hscroll >> 5) + 1];
+ tmap -= ii;
+ hscroll = 0; /* Make sure we don't do this again */
+ }
+ if (tmap > 0x10000) tmap %= 0x10000;
+ vflip = (snes_vram[tmap + ii + 1] & 0x80);
+ hflip = snes_vram[tmap + ii + 1] & 0x40;
+ priority = table_bgd_pty[snes_ppu.mode > 1][layer][(snes_vram[tmap + ii + 1] & 0x20) >> 5];
+ pal = (snes_vram[tmap + ii + 1] & 0x1c); /* what does this do for 8 bit screen? */
+ tile = (snes_vram[tmap + ii + 1] & 0x3) << 8;
+ tile |= snes_vram[tmap + ii];
+
+ tile_line = line;
+ if( vflip )
+ {
+ if( tile_size )
+ {
+ if( line > 7 )
+ {
+ tile_line -= 8;
+ }
+ else
+ {
+ tile += 8;
+ }
+ }
+ tile_line = -tile_line + 7;
+ }
+ else
+ {
+ if( line > 7 )
+ {
+ tile += 8;
+ tile_line -= 8;
+ }
+ }
+ tile_line <<= 1;
+
+ if( tile_size )
+ {
+ snes_draw_tile_8x2(machine, screen, layer, snes_ppu.layer[layer].data + (tile << 6) + tile_line, ((ii >> 1) * (8 << tile_size)) - hshift, priority, hflip );
+ }
+ else
+ {
+ snes_draw_tile_8(machine, screen, layer, snes_ppu.layer[layer].data + (tile << 6) + tile_line, ((ii >> 1) * (8 << tile_size)) - hshift, priority, hflip );
+ }
+ }
+}
+
+/*********************************************
+ * snes_update_line_mode7()
+ *
+ * Update an entire line of mode7 tiles.
+ *********************************************/
+static void snes_update_line_mode7(running_machine *machine, UINT8 screen, UINT8 layer, UINT16 curline )
+{
+ UINT32 tiled;
+ INT16 ma, mb, mc, md;
+ INT16 xc, yc, tx, ty, sx, sy, hs, vs, xpos, xdir;
+ UINT8 priority = 0;
+ register UINT8 colour = 0;
+
+#ifdef SNES_DBG_video
+ if( debug_options.bg_disabled[0] )
+ return;
+#endif /* SNES_DBG_video */
+
+ ma = snes_ppu.mode7.matrix_a;
+ mb = snes_ppu.mode7.matrix_b;
+ mc = snes_ppu.mode7.matrix_c;
+ md = snes_ppu.mode7.matrix_d;
+ xc = snes_ppu.mode7.origin_x;
+ yc = snes_ppu.mode7.origin_y;
+ hs = snes_ppu.layer[0].offset.horizontal;
+ vs = snes_ppu.layer[0].offset.vertical;
+
+ /* Sign extend */
+ xc <<= 3;
+ xc >>= 3;
+ yc <<= 3;
+ yc >>= 3;
+ hs <<= 3;
+ hs >>= 3;
+ vs <<= 3;
+ vs >>= 3;
+
+ /* Vertical flip */
+ if( snes_ram[M7SEL] & 0x2 )
+ sy = 255 - curline;
+ else
+ sy = curline;
+
+ /* Horizontal flip */
+ if( snes_ram[M7SEL] & 0x1 )
+ {
+ xpos = 255;
+ xdir = -1;
+ }
+ else
+ {
+ xpos = 0;
+ xdir = 1;
+ }
+
+ /* Let's do some mode7 drawing huh? */
+ for( sx = 0; sx < 256; sx++, xpos += xdir )
+ {
+ tx = (((ma * ((sx + hs) - xc)) + (mb * ((sy + vs) - yc))) >> 8) + xc;
+ ty = (((mc * ((sx + hs) - xc)) + (md * ((sy + vs) - yc))) >> 8) + yc;
+ switch( snes_ram[M7SEL] & 0xc0 )
+ {
+ case 0x00: /* Repeat if outside screen area */
+ tx &= 0x3ff;
+ ty &= 0x3ff;
+ tiled = snes_vram[((tx >> 3) * 2) + ((ty >> 3) * 128 * 2)] << 7;
+ colour = snes_vram[tiled + ((tx & 0x7) * 2) + ((ty & 0x7) * 16) + 1];
+ break;
+ case 0x80: /* Single colour backdrop screen if outside screen area */
+ if( (tx & 0x7fff) < 1024 && (ty & 0x7fff) < 1024 )
+ {
+ tiled = snes_vram[((tx >> 3) * 2) + ((ty >> 3) * 128 * 2)] << 7;
+ colour = snes_vram[tiled + ((tx & 0x7) * 2) + ((ty & 0x7) * 16) + 1];
+ }
+ else
+ {
+ colour = 0;
+ }
+ break;
+ case 0xC0: /* Character 0x00 repeat if outside screen area */
+ if( (tx & 0x7fff) < 1024 && (ty & 0x7fff) < 1024 )
+ {
+ tiled = snes_vram[(((tx & 0x3ff) >> 3) * 2) + (((ty & 0x3ff) >> 3) * 128 * 2)] << 7;
+ colour = snes_vram[tiled + ((tx & 0x7) * 2) + ((ty & 0x7) * 16) + 1];
+ }
+ else
+ {
+ colour = snes_vram[((sx & 0x7) * 2) + ((sy & 0x7) * 16) + 1];
+ }
+ break;
+ }
+
+ /* The last bit is for priority in EXTBG mode */
+ if( snes_ram[SETINI] & 0x40 )
+ {
+ priority = (colour & 0x80) >> 7;
+ colour &= 0x7f;
+ }
+
+ colour &= snes_ppu.clipmasks[0][xpos];
+
+ /* Draw pixel if appropriate */
+ if( scanlines[screen].zbuf[xpos] < table_bgd_pty[1][0][priority] && colour > 0 )
+ {
+ UINT16 clr;
+ /* Direct select */
+ if( snes_ram[CGWSEL] & 0x1 )
+ clr = ((colour & 0x7) << 2) | ((colour & 0x38) << 4) | ((colour & 0xc0) << 7);
+ else
+ clr = machine->remapped_colortable[colour];
+ /* Only blend main screens */
+ if( screen == MAINSCREEN )
+ snes_draw_blend(machine, xpos, &clr, snes_ppu.layer[0].blend, (snes_ram[CGWSEL] & 0x30) >> 4 ); /* FIXME: Need to support clip mode */
+
+ scanlines[screen].buffer[xpos] = clr;
+ scanlines[screen].zbuf[xpos] = table_bgd_pty[1][0][priority];
+ }
+ }
+}
+
+/*********************************************
+ * snes_update_objects()
+ *
+ * Update an entire line of sprites.
+ * FIXME: We need to support high priority bit
+ *********************************************/
+static void snes_update_objects(running_machine *machine, UINT8 screen, UINT16 curline )
+{
+ INT8 xs, ys;
+ UINT8 line, widemode = 0;
+ UINT16 oam_extra, extra;
+ INT16 oam;
+ UINT8 range_over = 0, time_over = 0;
+ UINT8 size, vflip, hflip, priority, pal, blend;
+ UINT16 tile;
+ INT16 i, x, y;
+ UINT8 *oamram = (UINT8 *)snes_oam;
+ UINT32 name_sel = 0;
+
+#ifdef SNES_DBG_video
+ if( debug_options.bg_disabled[4] )
+ return;
+#endif /* SNES_DBG_video */
+
+ if( snes_ppu.mode == 5 || snes_ppu.mode == 6 )
+ widemode = 1;
+
+ oam = 0x1ff;
+ oam_extra = oam + 0x20;
+ extra = 0;
+ for( i = 128; i > 0; i-- )
+ {
+ if( (i % 4) == 0 )
+ extra = oamram[oam_extra--];
+
+ vflip = (oamram[oam] & 0x80) >> 7;
+ hflip = (oamram[oam] & 0x40) >> 6;
+ priority = table_obj_pty[(oamram[oam] & 0x30) >> 4];
+ pal = 128 + ((oamram[oam] & 0xE) << 3);
+ tile = (oamram[oam--] & 0x1) << 8;
+ tile |= oamram[oam--];
+ y = oamram[oam--] + 1; /* We seem to need to add one here.... */
+ x = oamram[oam--];
+ size = (extra & 0x80) >> 7;
+ extra <<= 1;
+ x |= ((extra & 0x80) << 1);
+ extra <<= 1;
+
+ /* Adjust if past maximum position */
+ if( y >= snes_ppu.beam.last_visible_line )
+ y -= 256;
+ if( x > 255 )
+ x -= 512;
+
+ /* Draw sprite if it intersects the current line */
+ if( curline >= y && curline < (y + (snes_ppu.oam.size[size] << 3)) )
+ {
+ /* Only objects using palettes 4-7 can be transparent */
+ blend = (pal < 192) ? 0 : 1;
+
+ /* Only objects using tiles over 255 use name select */
+ name_sel = (tile < 256) ? 0 : snes_ppu.oam.name_select;
+
+ ys = (curline - y) >> 3;
+ line = (curline - y) % 8;
+ if( vflip )
+ {
+ ys = snes_ppu.oam.size[size] - ys - 1;
+ line = (-1 * line) + 7;
+ }
+ line <<= 1;
+ tile <<= 5;
+ if( hflip )
+ {
+ UINT8 count = 0;
+ for( xs = (snes_ppu.oam.size[size] - 1); xs >= 0; xs-- )
+ {
+ if( (x + (count << 3) < SNES_SCR_WIDTH + 8) )
+ {
+ if( widemode )
+ snes_draw_tile_object_w(machine, screen, snes_ppu.layer[4].data + name_sel + tile + table_obj_offset[ys][xs] + line, x + (count++ << 3), priority, hflip, pal, blend );
+ else
+ snes_draw_tile_object(machine, screen, snes_ppu.layer[4].data + name_sel + tile + table_obj_offset[ys][xs] + line, x + (count++ << 3), priority, hflip, pal, blend );
+ }
+ time_over++; /* Increase time_over. Should we stop drawing if exceeded 34 tiles? */
+ }
+ }
+ else
+ {
+ for( xs = 0; xs < snes_ppu.oam.size[size]; xs++ )
+ {
+ if( (x + (xs << 3) < SNES_SCR_WIDTH + 8) )
+ {
+ if( widemode )
+ snes_draw_tile_object_w(machine, screen, snes_ppu.layer[4].data + name_sel + tile + table_obj_offset[ys][xs] + line, x + (xs << 3), priority, hflip, pal, blend );
+ else
+ snes_draw_tile_object(machine, screen, snes_ppu.layer[4].data + name_sel + tile + table_obj_offset[ys][xs] + line, x + (xs << 3), priority, hflip, pal, blend );
+ }
+ time_over++; /* Increase time_over. Should we stop drawing if exceeded 34 tiles? */
+ }
+ }
+
+ /* Increase range_over.
+ * Stop drawing if exceeded 32 objects and
+ * enforcing that limit is enabled */
+ range_over++;
+ if( range_over == 32 && (readinputport( 16 ) & 0x10) )
+ {
+ /* Set the flag in STAT77 register */
+ snes_ram[STAT77] |= 0x40;
+ /* FIXME: This stops the SNESTest rom from drawing the object
+ * test properly. Maybe we shouldn't stop drawing? */
+ /* return; */
+ }
+ }
+ }
+
+ if( time_over >= 34 )
+ {
+ /* Set the flag in STAT77 register */
+ snes_ram[STAT77] |= 0x80;
+ }
+}
+
+/*********************************************
+ * snes_update_windowmasks()
+ *
+ * An example of how windows work:
+ * Win1: ...#####......
+ * Win2: ......#####...
+ * IN OUT
+ * OR: ...########... ###........###
+ * AND: ......##...... ######..######
+ * XOR: ...###..###... ###...##...###
+ * XNOR: ###...##...### ...###..###...
+ *********************************************/
+static void snes_update_windowmasks(void)
+{
+ UINT16 ii;
+ INT8 w1, w2;
+
+ snes_ppu.update_windows = 0; /* reset the flag */
+
+ for( ii = 0; ii < SNES_SCR_WIDTH; ii++ )
+ {
+ /* update bg 1 */
+ snes_ppu.clipmasks[0][ii] = 0xff;
+ w1 = w2 = -1;
+ if( snes_ram[W12SEL] & 0x2 )
+ {
+ if( (ii < snes_ram[WH0]) || (ii > snes_ram[WH1]) )
+ w1 = 0;
+ else
+ w1 = 1;
+ if( snes_ram[W12SEL] & 0x1 )
+ w1 = !w1;
+ }
+ if( snes_ram[W12SEL] & 0x8 )
+ {
+ if( (ii < snes_ram[WH2]) || (ii > snes_ram[WH3]) )
+ w2 = 0;
+ else
+ w2 = 1;
+ if( snes_ram[W12SEL] & 0x4 )
+ w2 = !w2;
+ }
+ if( w1 >= 0 && w2 >= 0 )
+ {
+ switch( snes_ram[WBGLOG] & 0x3 )
+ {
+ case 0x0: /* OR */
+ snes_ppu.clipmasks[0][ii] = w1 | w2 ? 0x00 : 0xff;
+ break;
+ case 0x1: /* AND */
+ snes_ppu.clipmasks[0][ii] = w1 & w2 ? 0x00 : 0xff;
+ break;
+ case 0x2: /* XOR */
+ snes_ppu.clipmasks[0][ii] = w1 ^ w2 ? 0x00 : 0xff;
+ break;
+ case 0x3: /* XNOR */
+ snes_ppu.clipmasks[0][ii] = !(w1 ^ w2) ? 0x00 : 0xff;
+ break;
+ }
+ }
+ else if( w1 >= 0 )
+ snes_ppu.clipmasks[0][ii] = w1 ? 0x00 : 0xff;
+ else if( w2 >= 0 )
+ snes_ppu.clipmasks[0][ii] = w2 ? 0x00 : 0xff;
+
+ /* update bg 2 */
+ snes_ppu.clipmasks[1][ii] = 0xff;
+ w1 = w2 = -1;
+ if( snes_ram[W12SEL] & 0x20 )
+ {
+ if( (ii < snes_ram[WH0]) || (ii > snes_ram[WH1]) )
+ w1 = 0;
+ else
+ w1 = 1;
+ if( snes_ram[W12SEL] & 0x10 )
+ w1 = !w1;
+ }
+ if( snes_ram[W12SEL] & 0x80 )
+ {
+ if( (ii < snes_ram[WH2]) || (ii > snes_ram[WH3]) )
+ w2 = 0;
+ else
+ w2 = 1;
+ if( snes_ram[W12SEL] & 0x40 )
+ w2 = !w2;
+ }
+ if( w1 >= 0 && w2 >= 0 )
+ {
+ switch( snes_ram[WBGLOG] & 0xc )
+ {
+ case 0x0: /* OR */
+ snes_ppu.clipmasks[1][ii] = w1 | w2 ? 0x00 : 0xff;
+ break;
+ case 0x4: /* AND */
+ snes_ppu.clipmasks[1][ii] = w1 & w2 ? 0x00 : 0xff;
+ break;
+ case 0x8: /* XOR */
+ snes_ppu.clipmasks[1][ii] = w1 ^ w2 ? 0x00 : 0xff;
+ break;
+ case 0xc: /* XNOR */
+ snes_ppu.clipmasks[1][ii] = !(w1 ^ w2) ? 0x00 : 0xff;
+ break;
+ }
+ }
+ else if( w1 >= 0 )
+ snes_ppu.clipmasks[1][ii] = w1 ? 0x00 : 0xff;
+ else if( w2 >= 0 )
+ snes_ppu.clipmasks[1][ii] = w2 ? 0x00 : 0xff;
+
+ /* update bg 3 */
+ snes_ppu.clipmasks[2][ii] = 0xff;
+ w1 = w2 = -1;
+ if( snes_ram[W34SEL] & 0x2 )
+ {
+ if( (ii < snes_ram[WH0]) || (ii > snes_ram[WH1]) )
+ w1 = 0;
+ else
+ w1 = 1;
+ if( snes_ram[W34SEL] & 0x1 )
+ w1 = !w1;
+ }
+ if( snes_ram[W34SEL] & 0x8 )
+ {
+ if( (ii < snes_ram[WH2]) || (ii > snes_ram[WH3]) )
+ w2 = 0;
+ else
+ w2 = 1;
+ if( snes_ram[W34SEL] & 0x4 )
+ w2 = !w2;
+ }
+ if( w1 >= 0 && w2 >= 0 )
+ {
+ switch( snes_ram[WBGLOG] & 0x30 )
+ {
+ case 0x0: /* OR */
+ snes_ppu.clipmasks[2][ii] = w1 | w2 ? 0x00 : 0xff;
+ break;
+ case 0x10: /* AND */
+ snes_ppu.clipmasks[2][ii] = w1 & w2 ? 0x00 : 0xff;
+ break;
+ case 0x20: /* XOR */
+ snes_ppu.clipmasks[2][ii] = w1 ^ w2 ? 0x00 : 0xff;
+ break;
+ case 0x30: /* XNOR */
+ snes_ppu.clipmasks[2][ii] = !(w1 ^ w2) ? 0x00 : 0xff;
+ break;
+ }
+ }
+ else if( w1 >= 0 )
+ snes_ppu.clipmasks[2][ii] = w1 ? 0x00 : 0xff;
+ else if( w2 >= 0 )
+ snes_ppu.clipmasks[2][ii] = w2 ? 0x00 : 0xff;
+
+ /* update bg 4 */
+ snes_ppu.clipmasks[3][ii] = 0xff;
+ w1 = w2 = -1;
+ if( snes_ram[W34SEL] & 0x20 )
+ {
+ if( (ii < snes_ram[WH0]) || (ii > snes_ram[WH1]) )
+ w1 = 0;
+ else
+ w1 = 1;
+ if( snes_ram[W34SEL] & 0x10 )
+ w1 = !w1;
+ }
+ if( snes_ram[W34SEL] & 0x80 )
+ {
+ if( (ii < snes_ram[WH2]) || (ii > snes_ram[WH3]) )
+ w2 = 0;
+ else
+ w2 = 1;
+ if( snes_ram[W34SEL] & 0x40 )
+ w2 = !w2;
+ }
+ if( w1 >= 0 && w2 >= 0 )
+ {
+ switch( snes_ram[WBGLOG] & 0xc0 )
+ {
+ case 0x0: /* OR */
+ snes_ppu.clipmasks[3][ii] = w1 | w2 ? 0x00 : 0xff;
+ break;
+ case 0x40: /* AND */
+ snes_ppu.clipmasks[3][ii] = w1 & w2 ? 0x00 : 0xff;
+ break;
+ case 0x80: /* XOR */
+ snes_ppu.clipmasks[3][ii] = w1 ^ w2 ? 0x00 : 0xff;
+ break;
+ case 0xc0: /* XNOR */
+ snes_ppu.clipmasks[3][ii] = !(w1 ^ w2) ? 0x00 : 0xff;
+ break;
+ }
+ }
+ else if( w1 >= 0 )
+ snes_ppu.clipmasks[3][ii] = w1 ? 0x00 : 0xff;
+ else if( w2 >= 0 )
+ snes_ppu.clipmasks[3][ii] = w2 ? 0x00 : 0xff;
+
+ /* update objects */
+ snes_ppu.clipmasks[4][ii] = 0xff;
+ w1 = w2 = -1;
+ if( snes_ram[WOBJSEL] & 0x2 )
+ {
+ if( (ii < snes_ram[WH0]) || (ii > snes_ram[WH1]) )
+ w1 = 0;
+ else
+ w1 = 1;
+ if( snes_ram[WOBJSEL] & 0x1 )
+ w1 = !w1;
+ }
+ if( snes_ram[WOBJSEL] & 0x8 )
+ {
+ if( (ii < snes_ram[WH2]) || (ii > snes_ram[WH3]) )
+ w2 = 0;
+ else
+ w2 = 1;
+ if( snes_ram[WOBJSEL] & 0x4 )
+ w2 = !w2;
+ }
+ if( w1 >= 0 && w2 >= 0 )
+ {
+ switch( snes_ram[WOBJLOG] & 0x3 )
+ {
+ case 0x0: /* OR */
+ snes_ppu.clipmasks[4][ii] = w1 | w2 ? 0x00 : 0xff;
+ break;
+ case 0x1: /* AND */
+ snes_ppu.clipmasks[4][ii] = w1 & w2 ? 0x00 : 0xff;
+ break;
+ case 0x2: /* XOR */
+ snes_ppu.clipmasks[4][ii] = w1 ^ w2 ? 0x00 : 0xff;
+ break;
+ case 0x3: /* XNOR */
+ snes_ppu.clipmasks[4][ii] = !(w1 ^ w2) ? 0x00 : 0xff;
+ break;
+ }
+ }
+ else if( w1 >= 0 )
+ snes_ppu.clipmasks[4][ii] = w1 ? 0x00 : 0xff;
+ else if( w2 >= 0 )
+ snes_ppu.clipmasks[4][ii] = w2 ? 0x00 : 0xff;
+
+ /* update colour window */
+ /* FIXME: Why is the colour window different to the other windows? *
+ * Have I overlooked something or done something wrong? */
+ snes_ppu.clipmasks[5][ii] = 0xff;
+ w1 = w2 = -1;
+ if( snes_ram[WOBJSEL] & 0x20 )
+ {
+ /* Default to mask area inside */
+ if( (ii < snes_ram[WH0]) || (ii > snes_ram[WH1]) )
+ w1 = 0;
+ else
+ w1 = 1;
+ /* If mask area is outside then swap */
+ if( snes_ram[WOBJSEL] & 0x10 )
+ w1 = !w1;
+ }
+ if( snes_ram[WOBJSEL] & 0x80 )
+ {
+ /* Default to mask area inside */
+ if( (ii < snes_ram[WH2]) || (ii > snes_ram[WH3]) )
+ w2 = 0;
+ else
+ w2 = 1;
+ /* If mask area is outside then swap */
+ if( snes_ram[WOBJSEL] & 0x40 )
+ w2 = !w2;
+ }
+ if( w1 >= 0 && w2 >= 0 )
+ {
+ switch( snes_ram[WOBJLOG] & 0xc )
+ {
+ case 0x0: /* OR */
+ snes_ppu.clipmasks[5][ii] = w1 | w2 ? 0xff : 0x00;
+/* snes_ppu.clipmasks[5][ii] = w1 | w2 ? 0x00 : 0xff;*/
+ break;
+ case 0x4: /* AND */
+ snes_ppu.clipmasks[5][ii] = w1 & w2 ? 0xff : 0x00;
+/* snes_ppu.clipmasks[5][ii] = w1 & w2 ? 0x00 : 0xff;*/
+ break;
+ case 0x8: /* XOR */
+ snes_ppu.clipmasks[5][ii] = w1 ^ w2 ? 0xff : 0x00;
+/* snes_ppu.clipmasks[5][ii] = w1 ^ w2 ? 0x00 : 0xff;*/
+ break;
+ case 0xc: /* XNOR */
+ snes_ppu.clipmasks[5][ii] = !(w1 ^ w2) ? 0xff : 0x00;
+/* snes_ppu.clipmasks[5][ii] = !(w1 ^ w2) ? 0x00 : 0xff;*/
+ break;
+ }
+ }
+ else if( w1 >= 0 )
+ snes_ppu.clipmasks[5][ii] = w1 ? 0xff : 0x00;
+/* snes_ppu.clipmasks[5][ii] = w1 ? 0x00 : 0xff;*/
+ else if( w2 >= 0 )
+ snes_ppu.clipmasks[5][ii] = w2 ? 0xff : 0x00;
+/* snes_ppu.clipmasks[5][ii] = w2 ? 0x00 : 0xff;*/
+ }
+}
+
+/*********************************************
+ * snes_update_palette()
+ *
+ * Update the palette with the latest changes.
+ *********************************************/
+static void snes_update_palette(running_machine *machine)
+{
+ UINT8 r, g, b, fade;
+ UINT16 ii;
+ UINT32 col;
+
+ /* Reset the flag */
+ snes_ppu.update_palette = 0;
+
+ /* Modify the palette to fade out the colours */
+ fade = (snes_ram[INIDISP] & 0xf) + 1;
+ for( ii = 0; ii <= 256; ii++ )
+ {
+ col = machine->pens[snes_cgram[ii] & 0x7fff];
+ r = ((col & 0x1f) * fade) >> 4;
+ g = (((col & 0x3e0) >> 5) * fade) >> 4;
+ b = (((col & 0x7c00) >> 10) * fade) >> 4;
+ /* palette hacks! */
+ ((pen_t *)machine->remapped_colortable)[ii] = ((r & 0x1f) | ((g & 0x1f) << 5) | ((b & 0x1f) << 10));
+ }
+}
+
+/*********************************************
+ * snes_update_offsets()
+ *
+ * Update the offsets with the latest changes.
+ *********************************************/
+static void snes_update_offsets(void)
+{
+ int ii;
+ for( ii = 0; ii < 4; ii++ )
+ {
+ snes_ppu.layer[ii].offset.tile_horz = (snes_ppu.layer[ii].offset.horizontal & 0x3ff) >> (3 + snes_ppu.layer[ii].tile_size);
+ snes_ppu.layer[ii].offset.shift_horz = snes_ppu.layer[ii].offset.horizontal & ((8 << snes_ppu.layer[ii].tile_size) - 1);
+ snes_ppu.layer[ii].offset.tile_vert = (snes_ppu.layer[ii].offset.vertical & 0x3ff) >> (3 + snes_ppu.layer[ii].tile_size);
+ snes_ppu.layer[ii].offset.shift_vert = snes_ppu.layer[ii].offset.vertical & ((8 << snes_ppu.layer[ii].tile_size) - 1);
+ }
+ snes_ppu.update_offsets = 0;
+}
+
+/*********************************************
+ * snes_refresh_scanline()
+ *
+ * Redraw the current line.
+ *********************************************/
+static void snes_refresh_scanline(running_machine *machine, mame_bitmap *bitmap, UINT16 curline )
+{
+ UINT16 ii;
+
+ profiler_mark(PROFILER_VIDEO);
+
+ if( snes_ram[INIDISP] & 0x80 ) /* screen is forced blank */
+ {
+ rectangle r = machine->screen[0].visarea;
+ r.min_y = r.max_y = curline;
+ fillbitmap(bitmap, machine->pens[0], &r);
+ }
+ else
+ {
+ /* Update clip window masks if necessary */
+ if( snes_ppu.update_windows )
+ snes_update_windowmasks();
+ /* Update the palette if necessary */
+ if( snes_ppu.update_palette )
+ snes_update_palette(machine);
+ /* Update the offsets if necessary */
+ if( snes_ppu.update_offsets )
+ snes_update_offsets();
+
+ /* Clear zbuffers */
+ memset( scanlines[MAINSCREEN].zbuf, 0, SNES_SCR_WIDTH * 2 );
+ memset( scanlines[SUBSCREEN].zbuf, 0, SNES_SCR_WIDTH * 2 );
+
+ /* Clear subscreen and draw back colour */
+ for( ii = 0; ii < SNES_SCR_WIDTH * 2; ii++ )
+ {
+ /* Not sure if this is correct behaviour, but a few games seem to
+ * require it. (SMW, Zelda etc) */
+ scanlines[SUBSCREEN].buffer[ii] = machine->remapped_colortable[FIXED_COLOUR];
+ /* Draw back colour */
+ scanlines[MAINSCREEN].buffer[ii] = machine->remapped_colortable[0];
+ }
+
+ /* Draw subscreen */
+ if( snes_ram[TS] & 0x10 )
+ snes_update_objects(machine, SUBSCREEN, curline );
+ for( ii = 0; ii < snes_modedefs[snes_ppu.mode].count; ii++ )
+ {
+ if( snes_ram[TS] & (0x1 << ii) )
+ snes_modedefs[snes_ppu.mode].drawLayer[ii](machine, SUBSCREEN, ii, curline );
+ }
+ /* Draw the back plane */
+#ifdef SNES_DBG_video
+ if( !debug_options.bg_disabled[5] )
+#endif /* SNES_DBG_video */
+ if( snes_ram[CGADSUB] & 0x20 )
+ {
+ for( ii = 0; ii < SNES_SCR_WIDTH; ii++ )
+ {
+ snes_draw_blend(machine, ii, &scanlines[MAINSCREEN].buffer[ii], (snes_ram[CGADSUB] & 0x80)?SNES_BLEND_SUB:SNES_BLEND_ADD, (snes_ram[CGWSEL] & 0x30) >> 4 );
+ }
+ }
+ /* Draw mainscreen */
+ if( snes_ram[TM] & 0x10 )
+ snes_update_objects(machine, MAINSCREEN, curline );
+ for( ii = 0; ii < snes_modedefs[snes_ppu.mode].count; ii++ )
+ {
+ if( snes_ram[TM] & (0x1 << ii) )
+ snes_modedefs[snes_ppu.mode].drawLayer[ii](machine, MAINSCREEN, ii, curline );
+ }
+
+#ifdef SNES_DBG_video
+ if( snes_dbg_video(machine, bitmap, curline ) )
+ {
+ profiler_mark(PROFILER_END);
+ return;
+ }
+
+ /* Toggle drawing of subscreen or mainscreen */
+ if( debug_options.draw_subscreen )
+ memcpy( (UINT16 *)bitmap->base + bitmap->rowpixels * curline, scanlines[SUBSCREEN].buffer, (SNES_SCR_WIDTH * 2) * sizeof(UINT16) );
+ else
+#endif /* SNES_DBG_video */
+
+ /* Phew! Draw the line to screen */
+ memcpy( (UINT16 *)bitmap->base + bitmap->rowpixels * curline, scanlines[MAINSCREEN].buffer, (SNES_SCR_WIDTH * 2) * sizeof(UINT16) );
+ }
+
+ profiler_mark(PROFILER_END);
+}
+
+VIDEO_UPDATE( snes )
+{
+ int y;
+
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ snes_refresh_scanline(machine, bitmap, y);
+ return 0;
+}
+
+
+/***** Debug Functions *****/
+
+#ifdef SNES_DBG_video
+
+static void snes_dbg_draw_maps(running_machine *machine, mame_bitmap *bitmap, UINT32 tmap, UINT8 bpl, UINT16 curline, UINT8 layer )
+{
+ UINT32 tile, addr = tmap;
+ UINT16 ii, vflip, hflip, pal;
+ INT8 line;
+ char str[50];
+
+ tmap += (curline >> 3) * 64;
+ for( ii = 0; ii < 64; ii += 2 )
+ {
+ vflip = (snes_vram[tmap + ii + 1] & 0x80);
+ hflip = snes_vram[tmap + ii + 1] & 0x40;
+ pal = (snes_vram[tmap + ii + 1] & 0x1c); /* 8 palettes of 4 colours */
+ tile = (snes_vram[tmap + ii + 1] & 0x3) << 8;
+ tile |= snes_vram[tmap + ii];
+ line = curline % 8;
+ if( vflip )
+ line = -line + 7;
+
+ if( tile != 0 )
+ {
+ switch( bpl )
+ {
+ case 1:
+ snes_draw_tile_2(machine, MAINSCREEN, layer, snes_ppu.layer[layer].data + (tile << 4) + ((curline % 8) * 2), (ii >> 1) * 8, 255, hflip, pal );
+ break;
+ case 2:
+ pal <<= 2;
+ snes_draw_tile_4(machine, MAINSCREEN, layer, snes_ppu.layer[layer].data + (tile << 5) + ((curline % 8) * 2), (ii >> 1) * 8, 255, hflip, pal );
+ break;
+ case 4:
+ snes_draw_tile_8(machine, MAINSCREEN, layer, snes_ppu.layer[layer].data + (tile << 6) + ((curline % 8) * 2), (ii >> 1) * 8, 255, hflip );
+ break;
+ }
+ }
+ }
+
+ sprintf( str, "%d : %8X ", layer, addr );
+ //ui_draw_text( str, 0, 227 );
+}
+
+static void snes_dbg_draw_all_tiles(running_machine *machine, mame_bitmap *bitmap, UINT32 tileaddr, UINT8 bpl, UINT16 pal )
+{
+ UINT16 ii, jj, kk;
+ UINT32 addr = tileaddr;
+ char str[50];
+
+ for( jj = 0; jj < 32; jj++ )
+ {
+ addr = tileaddr + (jj * bpl * 16 * 32);
+ for( kk = 0; kk < 8; kk++ )
+ {
+ /* Clear buffers */
+ memset( scanlines[MAINSCREEN].buffer, 0, SNES_SCR_WIDTH * 2 );
+ memset( scanlines[MAINSCREEN].zbuf, 0, SNES_SCR_WIDTH * 2 );
+ for( ii = 0; ii < 32; ii++ )
+ {
+ switch( bpl )
+ {
+ case 1:
+ snes_draw_tile_2(machine, MAINSCREEN, 0, addr, ii * 8, 255, 0, pal );
+ break;
+ case 2:
+ snes_draw_tile_4(machine, MAINSCREEN, 0, addr, ii * 8, 255, 0, pal );
+ break;
+ case 4:
+ snes_draw_tile_8(machine, MAINSCREEN, 0, addr, ii * 8, 255, 0 );
+ break;
+ }
+ addr += (bpl * 16);
+ }
+ draw_scanline16( bitmap, 0, jj * 8 + kk, SNES_SCR_WIDTH * 2, scanlines[MAINSCREEN].buffer, machine->pens, 200 );
+ addr -= (32 * (bpl * 16)) - 2;
+ }
+ }
+
+ sprintf( str, " %8X ", tileaddr );
+ //ui_draw_text( str, 0, 227 );
+}
+
+static UINT8 snes_dbg_video(running_machine *machine, mame_bitmap *bitmap, UINT16 curline )
+{
+ UINT16 ii;
+
+#define SNES_DBG_HORZ_POS 545
+
+ /* Check if the user has enabled or disabled stuff */
+ if( curline == 0 )
+ {
+ //UINT16 y = 1;
+ char t[100];
+ static char WINLOGIC[4] = { '|', '&', '^', '!' };
+
+ if( !debug_options.input_count-- )
+ {
+ UINT8 toggles = readinputport( 10 );
+ if( toggles & 0x1 )
+ debug_options.bg_disabled[0] = !debug_options.bg_disabled[0];
+ if( toggles & 0x2 )
+ debug_options.bg_disabled[1] = !debug_options.bg_disabled[1];
+ if( toggles & 0x4 )
+ debug_options.bg_disabled[2] = !debug_options.bg_disabled[2];
+ if( toggles & 0x8 )
+ debug_options.bg_disabled[3] = !debug_options.bg_disabled[3];
+ if( toggles & 0x10 )
+ debug_options.bg_disabled[4] = !debug_options.bg_disabled[4];
+ if( toggles & 0x20 )
+ debug_options.draw_subscreen = !debug_options.draw_subscreen;
+ if( toggles & 0x40 )
+ debug_options.bg_disabled[5] = !debug_options.bg_disabled[5];
+ if( toggles & 0x80 )
+ debug_options.windows_disabled = !debug_options.windows_disabled;
+ toggles = readinputport( 11 );
+ if( toggles & 0x4 )
+ debug_options.transparency_disabled = !debug_options.transparency_disabled;
+ debug_options.input_count = 5;
+ }
+ /* Display some debug info on the screen */
+ sprintf( t, "%s%s", debug_options.windows_disabled?" ":"W", debug_options.transparency_disabled?" ":"T" );
+ //ui_draw_text( t, SNES_DBG_HORZ_POS, y++ * 9 );
+ sprintf( t, "%s1 %s%s%s%s%s%c%s%s%d%s %d %4X %4X",
+ debug_options.bg_disabled[0]?" ":"*",
+ (snes_ram[TM] & 0x1)?"M":" ",
+ (snes_ram[TS] & 0x1)?"S":" ",
+ (snes_ram[CGADSUB] & 0x1)?"B":" ",
+ (snes_ram[TMW] & 0x1)?"m":" ",
+ (snes_ram[TSW] & 0x1)?"s":" ",
+ WINLOGIC[(snes_ram[WBGLOG] & 0x3)],
+ (snes_ram[W12SEL] & 0x2)?((snes_ram[W12SEL] & 0x1)?"o":"i"):" ",
+ (snes_ram[W12SEL] & 0x8)?((snes_ram[W12SEL] & 0x4)?"o":"i"):" ",
+ snes_ppu.layer[0].tile_size + 1,
+ (snes_ram[MOSAIC] & 0x1)?"m":" ",
+ snes_ram[BG1SC] & 0x3,
+ (snes_ram[BG1SC] & 0xfc) << 9,
+ snes_ppu.layer[0].data );
+ //ui_draw_text( t, SNES_DBG_HORZ_POS, y++ * 9 );
+ sprintf( t, "%s2 %s%s%s%s%s%c%s%s%d%s %d %4X %4X",
+ debug_options.bg_disabled[1]?" ":"*",
+ (snes_ram[TM] & 0x2)?"M":" ",
+ (snes_ram[TS] & 0x2)?"S":" ",
+ (snes_ram[CGADSUB] & 0x2)?"B":" ",
+ (snes_ram[TMW] & 0x2)?"m":" ",
+ (snes_ram[TSW] & 0x2)?"s":" ",
+ WINLOGIC[(snes_ram[WBGLOG] & 0xc) >> 2],
+ (snes_ram[W12SEL] & 0x20)?((snes_ram[W12SEL] & 0x10)?"o":"i"):" ",
+ (snes_ram[W12SEL] & 0x80)?((snes_ram[W12SEL] & 0x40)?"o":"i"):" ",
+ snes_ppu.layer[1].tile_size + 1,
+ (snes_ram[MOSAIC] & 0x2)?"m":" ",
+ snes_ram[BG2SC] & 0x3,
+ (snes_ram[BG2SC] & 0xfc) << 9,
+ snes_ppu.layer[1].data );
+ //ui_draw_text( t, SNES_DBG_HORZ_POS, y++ * 9 );
+ sprintf( t, "%s3 %s%s%s%s%s%c%s%s%d%s%s%d %4X %4X",
+ debug_options.bg_disabled[2]?" ":"*",
+ (snes_ram[TM] & 0x4)?"M":" ",
+ (snes_ram[TS] & 0x4)?"S":" ",
+ (snes_ram[CGADSUB] & 0x4)?"B":" ",
+ (snes_ram[TMW] & 0x4)?"m":" ",
+ (snes_ram[TSW] & 0x4)?"s":" ",
+ WINLOGIC[(snes_ram[WBGLOG] & 0x30)>>4],
+ (snes_ram[W34SEL] & 0x2)?((snes_ram[W34SEL] & 0x1)?"o":"i"):" ",
+ (snes_ram[W34SEL] & 0x8)?((snes_ram[W34SEL] & 0x4)?"o":"i"):" ",
+ snes_ppu.layer[2].tile_size + 1,
+ (snes_ram[MOSAIC] & 0x4)?"m":" ",
+ (snes_ram[BGMODE] & 0x8)?"P":" ",
+ snes_ram[BG3SC] & 0x3,
+ (snes_ram[BG3SC] & 0xfc) << 9,
+ snes_ppu.layer[2].data );
+ //ui_draw_text( t, SNES_DBG_HORZ_POS, y++ * 9 );
+ sprintf( t, "%s4 %s%s%s%s%s%c%s%s%d%s %d %4X %4X",
+ debug_options.bg_disabled[3]?" ":"*",
+ (snes_ram[TM] & 0x8)?"M":" ",
+ (snes_ram[TS] & 0x8)?"S":" ",
+ (snes_ram[CGADSUB] & 0x8)?"B":" ",
+ (snes_ram[TMW] & 0x8)?"m":" ",
+ (snes_ram[TSW] & 0x8)?"s":" ",
+ WINLOGIC[(snes_ram[WBGLOG] & 0xc0)>>6],
+ (snes_ram[W34SEL] & 0x20)?((snes_ram[W34SEL] & 0x10)?"o":"i"):" ",
+ (snes_ram[W34SEL] & 0x80)?((snes_ram[W34SEL] & 0x40)?"o":"i"):" ",
+ snes_ppu.layer[3].tile_size + 1,
+ (snes_ram[MOSAIC] & 0x8)?"m":" ",
+ snes_ram[BG4SC] & 0x3,
+ (snes_ram[BG4SC] & 0xfc) << 9,
+ snes_ppu.layer[3].data );
+ //ui_draw_text( t, SNES_DBG_HORZ_POS, y++ * 9 );
+ sprintf( t, "%sO %s%s%s%s%s%c%s%s%d%d %4X",
+ debug_options.bg_disabled[4]?" ":"*",
+ (snes_ram[TM] & 0x10)?"M":" ",
+ (snes_ram[TS] & 0x10)?"S":" ",
+ (snes_ram[CGADSUB] & 0x10)?"B":" ",
+ (snes_ram[TMW] & 0x10)?"m":" ",
+ (snes_ram[TSW] & 0x10)?"s":" ",
+ WINLOGIC[(snes_ram[WOBJLOG] & 0x3)],
+ (snes_ram[WOBJSEL] & 0x2)?((snes_ram[WOBJSEL] & 0x1)?"o":"i"):" ",
+ (snes_ram[WOBJSEL] & 0x8)?((snes_ram[WOBJSEL] & 0x4)?"o":"i"):" ",
+ snes_ppu.oam.size[0], snes_ppu.oam.size[1],
+ snes_ppu.layer[4].data );
+ //ui_draw_text( t, SNES_DBG_HORZ_POS, y++ * 9 );
+ sprintf( t, "%sB %s %c%s%s",
+ debug_options.bg_disabled[5]?" ":"*",
+ (snes_ram[CGADSUB] & 0x20)?"B":" ",
+ WINLOGIC[(snes_ram[WOBJLOG] & 0xc)>>2],
+ (snes_ram[WOBJSEL] & 0x20)?((snes_ram[WOBJSEL] & 0x10)?"o":"i"):" ",
+ (snes_ram[WOBJSEL] & 0x80)?((snes_ram[WOBJSEL] & 0x40)?"o":"i"):" " );
+ //ui_draw_text( t, SNES_DBG_HORZ_POS, y++ * 9 );
+ sprintf( t, "1) %3d %3d 2) %3d %3d", (snes_ppu.bgd_offset.horizontal[0] & 0x3ff) >> 3, (snes_ppu.bgd_offset.vertical[0] & 0x3ff) >> 3, (snes_ppu.bgd_offset.horizontal[1] & 0x3ff) >> 3, (snes_ppu.bgd_offset.vertical[1] & 0x3ff) >> 3 );
+ //ui_draw_text( t, SNES_DBG_HORZ_POS, y++ * 9 );
+ sprintf( t, "3) %3d %3d 4) %3d %3d", (snes_ppu.bgd_offset.horizontal[2] & 0x3ff) >> 3, (snes_ppu.bgd_offset.vertical[2] & 0x3ff) >> 3, (snes_ppu.bgd_offset.horizontal[3] & 0x3ff) >> 3, (snes_ppu.bgd_offset.vertical[3] & 0x3ff) >> 3 );
+ //ui_draw_text( t, SNES_DBG_HORZ_POS, y++ * 9 );
+ sprintf( t, "Flags: %s%s%s %s %2d", (snes_ram[CGWSEL] & 0x2)?"S":"F", (snes_ram[CGADSUB] & 0x80)?"-":"+", (snes_ram[CGADSUB] & 0x40)?" 50%":"100%",(snes_ram[CGWSEL] & 0x1)?"D":"P", (snes_ram[MOSAIC] & 0xf0) >> 4 );
+ //ui_draw_text( t, SNES_DBG_HORZ_POS, y++ * 9 );
+ sprintf( t, "SetINI: %s %s %s %s %s %s", (snes_ram[SETINI] & 0x1)?" I":"NI", (snes_ram[SETINI] & 0x2)?"P":"R", (snes_ram[SETINI] & 0x4)?"240":"225",(snes_ram[SETINI] & 0x8)?"512":"256",(snes_ram[SETINI] & 0x40)?"E":"N",(snes_ram[SETINI] & 0x80)?"ES":"NS" );
+ //ui_draw_text( t, SNES_DBG_HORZ_POS, y++ * 9 );
+ sprintf( t, "Mode7: A %5d B %5d", snes_ppu.mode7.matrix_a, snes_ppu.mode7.matrix_b );
+ //ui_draw_text( t, SNES_DBG_HORZ_POS, y++ * 9 );
+ sprintf( t, " %s%s%s C %5d D %5d", (snes_ram[M7SEL] & 0xc0)?((snes_ram[M7SEL] & 0x40)?"0":"C"):"R", (snes_ram[M7SEL] & 0x1)?"H":" ", (snes_ram[M7SEL] & 0x2)?"V":" ", snes_ppu.mode7.matrix_c, snes_ppu.mode7.matrix_d );
+ //ui_draw_text( t, SNES_DBG_HORZ_POS, y++ * 9 );
+ sprintf( t, " X %5d Y %5d", snes_ppu.mode7.origin_x, snes_ppu.mode7.origin_y );
+ //ui_draw_text( t, SNES_DBG_HORZ_POS, y++ * 9 );
+ }
+ /* Just for testing, draw as many tiles as possible */
+ {
+ UINT8 adjust = readinputport( 1 );
+ UINT8 dip = readinputport( 9 );
+ UINT8 inp = readinputport( 11 );
+ UINT8 dt = 1 << ((dip & 0x3) - 1);
+ UINT8 dm = 1 << (((dip & 0xc) >> 2) - 1);
+ if( dt )
+ {
+ static INT16 pal = 0;
+ static UINT32 addr = 0;
+ if( curline == 0 )
+ {
+ if( adjust & 0x1 ) addr += (dt * 16);
+ if( adjust & 0x2 ) addr -= (dt * 16);
+ if( adjust & 0x4 ) addr += (dt * 16 * 32);
+ if( adjust & 0x8 ) addr -= (dt * 16 * 32);
+ if( inp & 0x1 ) pal -= 1;
+ if( inp & 0x2 ) pal += 1;
+ if( pal < 0 ) pal = 0;
+ if( pal > 8 ) pal = 8;
+ for( ii = 0; ii < SNES_SCR_WIDTH; ii++ )
+ {
+ scanlines[MAINSCREEN].buffer[ii] = 0;
+ }
+ snes_dbg_draw_all_tiles(machine, bitmap, addr, dt, pal * 16 );
+ }
+ return 1;
+ }
+ if( dm )
+ {
+ static UINT32 tmaddr = 0;
+ static INT8 tmbg = 0;
+ if( curline == 0 )
+ {
+ if( adjust & 0x1 ) tmaddr += 2;
+ if( adjust & 0x2 ) tmaddr -= 2;
+ if( adjust & 0x4 ) tmaddr += 64;
+ if( adjust & 0x8 ) tmaddr -= 64;
+ if( inp & 0x1 ) tmbg -= 1;
+ if( inp & 0x2 ) tmbg += 1;
+ if( tmbg < 0 ) tmbg = 0;
+ if( tmbg > 3 ) tmbg = 3;
+ }
+ /* Clear zbuffer */
+ memset( scanlines[MAINSCREEN].zbuf, 0, SNES_SCR_WIDTH );
+ /* Draw back colour */
+ for( ii = 0; ii < SNES_SCR_WIDTH; ii++ )
+ scanlines[MAINSCREEN].buffer[ii] = machine->pens[0];
+ snes_dbg_draw_maps(machine, bitmap, tmaddr, dm, curline, tmbg );
+ draw_scanline16( bitmap, 0, curline, SNES_SCR_WIDTH, scanlines[MAINSCREEN].buffer, machine->pens, 200 );
+ return 1;
+ }
+ }
+
+ /* Draw some useful information about the back/fixed colours and current bg mode etc. */
+ *BITMAP_ADDR16(bitmap, curline, SNES_DBG_HORZ_POS - 26) = machine->pens[dbg_mode_colours[(snes_ram[CGWSEL] & 0xc0) >> 6]];
+ *BITMAP_ADDR16(bitmap, curline, SNES_DBG_HORZ_POS - 24) = machine->pens[dbg_mode_colours[(snes_ram[CGWSEL] & 0x30) >> 4]];
+ *BITMAP_ADDR16(bitmap, curline, SNES_DBG_HORZ_POS - 22) = machine->pens[dbg_mode_colours[snes_ram[BGMODE] & 0x7]];
+ *BITMAP_ADDR16(bitmap, curline, SNES_DBG_HORZ_POS - 12) = machine->pens[32767];
+ *BITMAP_ADDR16(bitmap, curline, SNES_DBG_HORZ_POS - 2 ) = machine->pens[32767];
+ for( ii = 0; ii < 5; ii++ )
+ {
+ *BITMAP_ADDR16(bitmap, curline, SNES_DBG_HORZ_POS - 19 + ii) = machine->remapped_colortable[0];
+ *BITMAP_ADDR16(bitmap, curline, SNES_DBG_HORZ_POS - 9 + ii) = machine->remapped_colortable[FIXED_COLOUR];
+ }
+ /* Draw window positions */
+ scanlines[MAINSCREEN].buffer[snes_ram[WH0]] = machine->pens[dbg_mode_colours[0]];
+ scanlines[MAINSCREEN].buffer[snes_ram[WH1]] = machine->pens[dbg_mode_colours[0]];
+ scanlines[MAINSCREEN].buffer[snes_ram[WH2]] = machine->pens[dbg_mode_colours[2]];
+ scanlines[MAINSCREEN].buffer[snes_ram[WH3]] = machine->pens[dbg_mode_colours[2]];
+
+ return 0;
+ }
+
+#endif /* SNES_DBG_video */
diff --git a/src/mame/video/snk.c b/src/mame/video/snk.c
new file mode 100644
index 00000000000..dcb909459a6
--- /dev/null
+++ b/src/mame/video/snk.c
@@ -0,0 +1,631 @@
+#include "driver.h"
+#include "snk.h"
+
+/*******************************************************************************
+ Shadow Handling Notes
+********************************************************************************
+ previously shadows were handled by toggling them on and off with a
+ shadows_visible flag.
+
+ Games Not Using Shadows?
+
+ those using gwar_vh_screenrefresh (gwar, bermudat, psychos, chopper1)
+ (0-15 , 15 is transparent)
+
+ Games Using Shadows?
+
+ those using tnk3_vh_screenrefresh (tnk3, athena, fitegolf) sgladiat is similar
+ (0-7 , 6 is shadow, 7 is transparent) * these are using aso colour prom convert *
+ those using tdfever_vh_screenrefresh (tdfever)
+ (0-15 , 14(13 for tdfeverj) is shadow, 15 is transparent)
+ those using ftsoccer_vh_screenrefresh (ftsoccer)
+ (0-15 , 14 is shadow/highlight, 15 is transparent)
+ those using ikari_vh_screenrefresh (ikari, victroad)
+ (0-7 , 6 is shadow, 7 is transparent)
+
+*******************************************************************************/
+
+
+int snk_blink_parity = 0;
+
+#define MAX_VRAM_SIZE (64*64*2) /* 0x2000 */
+
+
+
+
+PALETTE_INIT( snk_3bpp_shadow )
+{
+ int i;
+ palette_init_RRRR_GGGG_BBBB(machine, colortable, color_prom);
+
+ if(!(machine->drv->video_attributes & VIDEO_HAS_SHADOWS))
+ popmessage("driver should use VIDEO_HAS_SHADOWS");
+
+ /* prepare shadow draw table */
+ for(i = 0; i <= 5; i++) gfx_drawmode_table[i] = DRAWMODE_SOURCE;
+
+ gfx_drawmode_table[6] = DRAWMODE_SHADOW;
+ gfx_drawmode_table[7] = DRAWMODE_NONE;
+}
+
+PALETTE_INIT( snk_4bpp_shadow )
+{
+ int i;
+ palette_init_RRRR_GGGG_BBBB(machine, colortable, color_prom);
+
+ if(!(machine->drv->video_attributes & VIDEO_HAS_SHADOWS))
+ popmessage("driver should use VIDEO_HAS_SHADOWS");
+
+ /* prepare shadow draw table */
+ for(i = 0; i <= 13; i++) gfx_drawmode_table[i] = DRAWMODE_SOURCE;
+
+ gfx_drawmode_table[14] = DRAWMODE_SHADOW;
+ gfx_drawmode_table[15] = DRAWMODE_NONE;
+}
+
+VIDEO_START( snk )
+{
+ snk_blink_parity = 0;
+
+ dirtybuffer = auto_malloc( MAX_VRAM_SIZE );
+
+ tmpbitmap = auto_bitmap_alloc( 512, 512, machine->screen[0].format );
+
+ memset( dirtybuffer, 0xff, MAX_VRAM_SIZE );
+}
+
+/**************************************************************************************/
+
+static void tnk3_draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int scrollx, int scrolly,
+ int x_size, int y_size, int bg_type )
+{
+ const gfx_element *gfx = machine->gfx[1];
+
+ int tile_number, attributes, color, sx, sy;
+ int offs, x, y;
+
+ /* to be moved to memmap */
+ for(x=0; x<x_size; x++) for(y=0; y<y_size; y++)
+ {
+ offs = (x*y_size + y) << 1;
+ tile_number = videoram[offs];
+ attributes = videoram[offs+1];
+
+ if(tile_number != dirtybuffer[offs] || attributes != dirtybuffer[offs+1])
+ {
+ dirtybuffer[offs] = tile_number;
+ dirtybuffer[offs+1] = attributes;
+
+ if(bg_type == 0)
+ {
+ /* type tnk3 */
+ tile_number |= (attributes & 0x30) << 4;
+ color = (attributes & 0xf) ^ 8;
+ }
+ else
+ {
+ /* type ikari */
+ tile_number |= (attributes & 0x03) << 8;
+ color = attributes >> 4;
+ }
+
+ sx = x * 512 / x_size;
+ sy = y * 512 / y_size;
+
+ drawgfx(tmpbitmap,gfx,tile_number,color,0,0,sx,sy,0,TRANSPARENCY_NONE,0);
+ }
+ }
+ copyscrollbitmap(bitmap,tmpbitmap,1,&scrollx,1,&scrolly,cliprect,TRANSPARENCY_NONE,0);
+}
+
+void tnk3_draw_text(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int bank, UINT8 *source )
+{
+ const gfx_element *gfx = machine->gfx[0];
+
+ int tile_number, color, sx, sy;
+ int x, y;
+
+ for(x=0; x<32; x++) for(y=0; y<32; y++)
+ {
+ tile_number = source[(x<<5)+y];
+
+ if(tile_number == 0x20 || tile_number == 0xff) continue;
+
+ if(bank == -1) color = 8;
+ else
+ {
+ color = tile_number >> 5;
+ tile_number |= bank << 8;
+ }
+ sx = (x+2) << 3;
+ sy = (y+1) << 3;
+
+ drawgfx(bitmap,gfx,tile_number,color,0,0,sx,sy,cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+static void tnk3_draw_status_main(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int bank, UINT8 *source, int start )
+{
+ const gfx_element *gfx = machine->gfx[0];
+
+ int tile_number, color, sx, sy;
+ int x, y;
+
+ for(x = start; x < start+2; x++) for(y = 0; y < 32; y++)
+ {
+ tile_number = source[(x<<5)+y];
+
+ if(bank == -1) color = 8;
+ else
+ {
+ color = tile_number >> 5;
+ tile_number |= (bank << 8);
+ }
+ sx = ((x+34)&0x3f) << 3;
+ sy = (y+1) << 3;
+
+ drawgfx(bitmap,gfx,tile_number,color,0,0,sx,sy,cliprect,TRANSPARENCY_NONE,0);
+ }
+}
+
+void tnk3_draw_status(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int bank, UINT8 *source )
+{
+ tnk3_draw_status_main(machine,bitmap,cliprect,bank,source, 0);
+ tnk3_draw_status_main(machine,bitmap,cliprect,bank,source,30);
+}
+
+static void tnk3_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int xscroll, int yscroll )
+{
+ const gfx_element *gfx = machine->gfx[2];
+
+ int tile_number, attributes, color, sx, sy;
+ int offs;
+
+ for(offs = 0; offs < 50*4; offs+=4)
+ {
+ if(*(UINT32*)(spriteram+offs) == 0 || *(UINT32*)(spriteram+offs) == -1) continue;
+
+ tile_number = spriteram[offs+1];
+ attributes = spriteram[offs+3]; /* YBBX.CCCC */
+ if(attributes & 0x40) tile_number |= 256;
+ if(attributes & 0x20) tile_number |= 512;
+
+ color = attributes & 0xf;
+ sx = xscroll - spriteram[offs+2];
+ if(!(attributes & 0x80)) sx += 256;
+ sy = -yscroll + spriteram[offs];
+ if(attributes & 0x10) sy += 256;
+ sx &= 0x1ff;
+ sy &= 0x1ff;
+ if (sx > 512-16) sx -= 512;
+ if (sy > 512-16) sy -= 512;
+
+ drawgfx(bitmap,gfx,tile_number,color,0,0,sx,sy,cliprect,TRANSPARENCY_PEN_TABLE,7);
+ }
+}
+
+VIDEO_UPDATE( tnk3 )
+{
+ UINT8 *ram = snk_rambase - 0xd000;
+ int attributes = ram[0xc800];
+ /*
+ X-------
+ -X------ character bank (for text layer)
+ --X-----
+ ---X---- scrolly MSB (background)
+ ----X--- scrolly MSB (sprites)
+ -----X--
+ ------X- scrollx MSB (background)
+ -------X scrollx MSB (sprites)
+ */
+
+ /* to be moved to memmap */
+ spriteram = &ram[0xd000];
+
+ {
+ int bg_scrollx = -ram[0xcc00] + 15;
+ int bg_scrolly = -ram[0xcb00] + 8;
+ if(attributes & 0x02) bg_scrollx += 256;
+ if(attributes & 0x10) bg_scrolly += 256;
+ tnk3_draw_background( machine, bitmap, cliprect, bg_scrollx, bg_scrolly, 64, 64, 0 );
+ }
+
+ {
+ int sp_scrollx = ram[0xca00] + 29;
+ int sp_scrolly = ram[0xc900] + 9;
+ if(attributes & 0x01) sp_scrollx += 256;
+ if(attributes & 0x08) sp_scrolly += 256;
+ tnk3_draw_sprites( machine, bitmap, cliprect, sp_scrollx, sp_scrolly );
+ }
+
+ {
+ int bank = (attributes & 0x40) ? 1:0;
+
+ tnk3_draw_text( machine, bitmap, cliprect, bank, &ram[0xf800] );
+ tnk3_draw_status( machine, bitmap, cliprect, bank, &ram[0xfc00] );
+ }
+ return 0;
+}
+
+/************************************************************************************/
+
+VIDEO_START( sgladiat )
+{
+ dirtybuffer = auto_malloc( MAX_VRAM_SIZE );
+ tmpbitmap = auto_bitmap_alloc( 512, 256, machine->screen[0].format );
+ memset( dirtybuffer, 0xff, MAX_VRAM_SIZE );
+}
+
+static void sgladiat_draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int scrollx, int scrolly )
+{
+ const gfx_element *gfx = machine->gfx[1];
+
+ int tile_number, color, sx, sy;
+ int offs, x, y;
+
+ for(x = 0; x < 64; x++) for(y = 0; y < 32; y++)
+ {
+ offs = (x<<5)+y;
+ tile_number = videoram[offs];
+
+ if(tile_number != dirtybuffer[offs])
+ {
+ dirtybuffer[offs] = tile_number;
+
+ color = 0;
+ sx = x << 3;
+ sy = y << 3;
+
+ drawgfx(tmpbitmap,gfx,tile_number,color,0,0,sx,sy,0,TRANSPARENCY_NONE,0);
+ }
+ }
+ copyscrollbitmap(bitmap,tmpbitmap,1,&scrollx,1,&scrolly,cliprect,TRANSPARENCY_NONE,0);
+}
+
+VIDEO_UPDATE( sgladiat )
+{
+ UINT8 *pMem = snk_rambase - 0xd000;
+ int attributes, scrollx, scrolly;
+
+ attributes = pMem[0xd300];
+
+ scrollx = -pMem[0xd700] + ((attributes & 2) ? 256:0);
+ scrolly = -pMem[0xd600];
+ scrollx += 15;
+ scrolly += 8;
+ sgladiat_draw_background( machine, bitmap, cliprect, scrollx, scrolly );
+
+ scrollx = pMem[0xd500] + ((attributes & 1) ? 256:0);
+ scrolly = pMem[0xd400];
+ scrollx += 29;
+ scrolly += 9;
+ tnk3_draw_sprites( machine, bitmap, cliprect, scrollx, scrolly );
+
+ tnk3_draw_text( machine, bitmap, cliprect, 0, &pMem[0xf000] );
+ return 0;
+}
+
+/**************************************************************************************/
+
+static void ikari_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int start, int xscroll, int yscroll,
+ UINT8 *source, int mode )
+{
+ gfx_element *gfx = machine->gfx[mode];
+ int tile_number, attributes, color, sx, sy;
+ int which, finish;
+
+ finish = (start+25)*4;
+
+ for(which = start*4; which < finish; which+=4)
+ {
+ if(*(UINT32*)(source+which) == 0 || *(UINT32*)(source+which) == -1) continue;
+
+ tile_number = source[which+1];
+ attributes = source[which+3];
+ switch(mode)
+ {
+ case 2:
+ tile_number |= (attributes & 0x60) << 3;
+ break;
+ case 3:
+ if(attributes & 0x40) tile_number |= 256;
+ break;
+ }
+ color = attributes & 0xf;
+ sx = xscroll - source[which+2];
+ if(!(attributes & 0x80)) sx += 256;
+ sy = -yscroll + source[which];
+ if(attributes & 0x10) sy += 256;
+ sx = (sx - 16) & 0x1ff;
+ sy = (sy - 16) & 0x1ff;
+ if (sx > 512-16) sx -= 512;
+ if (sy > 512-16) sy -= 512;
+
+ drawgfx(bitmap,gfx,tile_number,color,0,0,sx,sy,cliprect,TRANSPARENCY_PEN_TABLE,7);
+ }
+}
+
+VIDEO_UPDATE( ikari )
+{
+ UINT8 *ram = snk_rambase - 0xd000;
+
+ {
+ int attributes = ram[0xc900];
+ int scrolly = 8-ram[0xc800] - ((attributes & 0x01) ? 256:0);
+ int scrollx = 13-ram[0xc880] - ((attributes & 0x02) ? 256:0);
+ tnk3_draw_background( machine, bitmap, cliprect, scrollx, scrolly, 32, 32, 1 );
+ }
+
+ {
+ int attributes = ram[0xcd00];
+
+ int sp16_scrolly = -7 + ram[0xca00] + ((attributes & 0x04) ? 256:0);
+ int sp16_scrollx = 44 + ram[0xca80] + ((attributes & 0x10) ? 256:0);
+
+ int sp32_scrolly = 9 + ram[0xcb00] + ((attributes & 0x08) ? 256:0);
+ int sp32_scrollx = 28 + ram[0xcb80] + ((attributes & 0x20) ? 256:0);
+
+ ikari_draw_sprites( machine, bitmap, cliprect, 0, sp16_scrollx, sp16_scrolly, &ram[0xe800], 2 );
+ ikari_draw_sprites( machine, bitmap, cliprect, 0, sp32_scrollx, sp32_scrolly, &ram[0xe000], 3 );
+ ikari_draw_sprites( machine, bitmap, cliprect, 25, sp16_scrollx, sp16_scrolly, &ram[0xe800], 2 );
+ }
+
+ tnk3_draw_text( machine, bitmap, cliprect, -1, &ram[0xf800] );
+ tnk3_draw_status( machine, bitmap, cliprect, -1, &ram[0xfc00] );
+ return 0;
+}
+
+/**************************************************************/
+
+static void tdfever_draw_bg(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int xscroll, int yscroll )
+{
+ const UINT8 *source = snk_rambase + 0x000;
+ const gfx_element *gfx = machine->gfx[1];
+
+ int tile_number, attributes, color, sx, sy;
+ int offs, x, y;
+
+ for(x = 0; x < 32; x++) for(y = 0; y < 32; y++)
+ {
+ offs = (x<<6)+(y<<1);
+ tile_number = source[offs];
+ attributes = source[offs+1];
+
+ if(tile_number != dirtybuffer[offs] || attributes != dirtybuffer[offs+1])
+ {
+ dirtybuffer[offs] = tile_number;
+ dirtybuffer[offs+1] = attributes;
+ tile_number |= (attributes & 0xf) << 8;
+
+ color = attributes >> 4;
+ sx = x << 4;
+ sy = y << 4;
+
+ // intercept overflown tile indices
+ if(tile_number >= gfx->total_elements)
+ plot_box(tmpbitmap, sx, sy, gfx->width, gfx->height, get_black_pen(machine));
+ else
+ drawgfx(tmpbitmap,gfx,tile_number,color,0,0,sx,sy,0,TRANSPARENCY_NONE,0);
+ }
+ }
+ copyscrollbitmap(bitmap,tmpbitmap,1,&xscroll,1,&yscroll,cliprect,TRANSPARENCY_NONE,0);
+}
+
+/*
+Sprite Format
+-------------
+byte0: y offset
+byte1: tile number
+byte2: x offset
+byte3: attributes
+
+ mode 0/1 attributes:
+
+ 76543210
+ ----xxxx (color)
+ ---x---- (y offset bit8)
+ -xx----- (bank number)
+ x------- (x offset bit8)
+
+ mode 2 attributes:
+
+ 76543210
+ -----xxx (color)
+ ---x---- (y offset bit8)
+ -xx-x--- (bank number)
+ x------- (x offset bit8)
+*/
+static void tdfever_draw_sp(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int xscroll, int yscroll, int mode )
+{
+ const UINT8 *source = snk_rambase + ((mode==2)?0x1800:0x1000);
+ const gfx_element *gfx = machine->gfx[(mode==1)?3:2];
+ int tile_number, attributes, sx, sy, color, pen_mode;
+ int which, finish, sp_size;
+
+ if(mode < 0 || mode > 2) return;
+
+ pen_mode = (snk_gamegroup & 1) ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN;
+
+ if(mode == 2)
+ {
+ finish = 64 * 4;
+ sp_size = 16;
+ }
+ else
+ {
+ finish = 32 * 4;
+ sp_size = 32;
+ }
+
+ for(which = 0; which < finish; which+=4)
+ {
+ if(*(UINT32*)(source+which) == 0 || *(UINT32*)(source+which) == -1) continue;
+
+ tile_number = source[which+1];
+ attributes = source[which+3];
+
+ sx = xscroll + source[which+2]; if(mode==0) sx = 256-sx;
+ sy = yscroll + source[which];
+ sx += attributes<<1 & 0x100;
+ sy += attributes<<4 & 0x100;
+ sx &= 0x1ff; if(sx > 512-sp_size) sx -= 512;
+ sy &= 0x1ff; if(sy > 512-sp_size) sy -= 512;
+
+ switch(mode)
+ {
+ case 2:
+ tile_number |= (attributes<<4 & 0x600) | (attributes<<5 & 0x100);
+ color = attributes & 0x07;
+ break;
+
+ default:
+ tile_number |= attributes<<3 & 0x300;
+ color = attributes & 0x0f;
+ if (snk_gamegroup == 7) // ftsoccer
+ palette_set_shadow_mode(machine, ((attributes & 0x6f) == 0x60) ? 1 : 0);
+ }
+
+ drawgfx(bitmap,gfx,tile_number,color,0,0,sx,sy,cliprect,pen_mode,15);
+ }
+}
+
+static void tdfever_draw_tx(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int attributes, int dx, int dy, int base )
+{
+ const UINT8 *source = snk_rambase - 0xd000 + base;
+ const gfx_element *gfx = machine->gfx[0];
+
+ int tile_high = (attributes & 0xf0) << 4;
+ int color = attributes & 0xf;
+ int tile_number, sx, sy;
+ int x, y;
+
+ for(x = 0; x < 64; x++) for(y = 0; y < 32; y++)
+ {
+ tile_number = source[(x<<5)+y];
+
+ if(tile_number == 0x20) continue;
+
+ sx = dx + x*8;
+ sy = dy + y*8;
+
+ drawgfx(bitmap,gfx,tile_high|tile_number,color,0,0,sx,sy,cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+/**************************************************************/
+
+VIDEO_UPDATE( tdfever )
+{
+ const UINT8 *ram = snk_rambase - 0xd000;
+ int i;
+
+ UINT8 bg_attributes = ram[0xc880];
+ UINT8 sp_attributes = ram[0xc900];
+ UINT8 tx_attributes = ram[0xc8c0];
+ int bg_scroll_x = -ram[0xc840] + ((bg_attributes & 0x02) ? 256:0);
+ int bg_scroll_y = -ram[0xc800] + ((bg_attributes & 0x01) ? 256:0);
+ int sp_scroll_x = -ram[0xc9c0] + ((sp_attributes & 0x40) ? 0:256);
+ int sp_scroll_y = -ram[0xc980] + ((sp_attributes & 0x80) ? 256:0);
+
+ if(snk_gamegroup == 3 || snk_gamegroup == 5) // tdfever, tdfeverj
+ {
+ bg_scroll_x += 143;
+ bg_scroll_y += -32;
+ sp_scroll_x += 135;
+ sp_scroll_y += -65;
+ }
+ else if(snk_gamegroup == 7) // ftsoccer
+ {
+ bg_scroll_x += 16;
+ bg_scroll_y += 0;
+ sp_scroll_x += 40;
+ sp_scroll_y += -31;
+ }
+ tdfever_draw_bg( machine, bitmap, cliprect, bg_scroll_x, bg_scroll_y );
+
+ if (snk_gamegroup == 5) // tdfeverj
+ {
+ gfx_drawmode_table[13] = DRAWMODE_SHADOW;
+ gfx_drawmode_table[14] = DRAWMODE_SOURCE;
+
+ for (i=0x10e; i<0x200; i+=0x10) palette_set_color(machine,i,MAKE_RGB(snk_blink_parity,snk_blink_parity,snk_blink_parity));
+ snk_blink_parity ^= 0x7f;
+ }
+ tdfever_draw_sp( machine, bitmap, cliprect, sp_scroll_x, sp_scroll_y, 0 );
+
+ tdfever_draw_tx( machine, bitmap, cliprect, tx_attributes, 0, 0, 0xf800 );
+ return 0;
+}
+
+VIDEO_UPDATE( gwar )
+{
+ const UINT8 *ram = snk_rambase - 0xd000;
+ int gwar_sp_baseaddr, gwar_tx_baseaddr;
+ UINT8 bg_attribute;
+
+ if(snk_gamegroup == 4) // gwara
+ {
+ gwar_sp_baseaddr = 0xf000;
+ gwar_tx_baseaddr = 0xc800;
+ }
+ else
+ {
+ gwar_sp_baseaddr = 0xc000;
+ gwar_tx_baseaddr = 0xf800;
+ }
+
+ bg_attribute = ram[gwar_sp_baseaddr+0x880];
+
+ {
+ int bg_scroll_y, bg_scroll_x;
+
+ bg_scroll_x = -ram[gwar_sp_baseaddr+0x840] + 16;
+ bg_scroll_y = -ram[gwar_sp_baseaddr+0x800];
+
+ bg_scroll_x += (bg_attribute & 2) ? 256:0;
+ bg_scroll_y += (bg_attribute & 1) ? 256:0;
+
+ tdfever_draw_bg( machine, bitmap, cliprect, bg_scroll_x, bg_scroll_y );
+ }
+
+ {
+ UINT8 sp_attribute = ram[gwar_sp_baseaddr+0xac0];
+ int sp16_x = -ram[gwar_sp_baseaddr+0x940] - 9;
+ int sp16_y = -ram[gwar_sp_baseaddr+0x900] - 15;
+ int sp32_x = -ram[gwar_sp_baseaddr+0x9c0] - 9;
+ int sp32_y = -ram[gwar_sp_baseaddr+0x980] - 31;
+
+ if(snk_gamegroup == 2) // gwar, gwarj, gwarb, choppera
+ {
+ sp16_y += (bg_attribute & 0x10) ? 256:0;
+ sp16_x += (bg_attribute & 0x40) ? 256:0;
+ sp32_y += (bg_attribute & 0x20) ? 256:0;
+ sp32_x += (bg_attribute & 0x80) ? 256:0;
+ }
+ else
+ {
+ UINT8 spp_attribute = ram[gwar_sp_baseaddr+0xa80];
+ sp16_x += (spp_attribute & 0x10) ? 256:0;
+ sp16_y += (spp_attribute & 0x04) ? 256:0;
+ sp32_x += (spp_attribute & 0x20) ? 256:0;
+ sp32_y += (spp_attribute & 0x08) ? 256:0;
+ }
+
+ if(sp_attribute & 0xf8) // improves priority
+ {
+ tdfever_draw_sp( machine, bitmap, cliprect, sp16_x, sp16_y, 2 );
+ tdfever_draw_sp( machine, bitmap, cliprect, sp32_x, sp32_y, 1 );
+ }
+ else
+ {
+ tdfever_draw_sp( machine, bitmap, cliprect, sp32_x, sp32_y, 1 );
+ tdfever_draw_sp( machine, bitmap, cliprect, sp16_x, sp16_y, 2 );
+ }
+ }
+
+ {
+ UINT8 text_attribute = ram[gwar_sp_baseaddr+0x8c0];
+ tdfever_draw_tx( machine, bitmap, cliprect, text_attribute, 0, 0, gwar_tx_baseaddr );
+ }
+ return 0;
+}
diff --git a/src/mame/video/snk68.c b/src/mame/video/snk68.c
new file mode 100644
index 00000000000..03dcf08a1c5
--- /dev/null
+++ b/src/mame/video/snk68.c
@@ -0,0 +1,299 @@
+/***************************************************************************
+
+ SNK 68000 video routines
+
+Notes:
+ Search & Rescue uses Y flip on sprites only.
+ Street Smart uses X flip on sprites only.
+
+ Seems to be controlled in same byte as flipscreen.
+
+ Emulation by Bryan McPhail, mish@tendril.co.uk
+
+***************************************************************************/
+
+#include "driver.h"
+
+static int sprite_flip, pow_charbase=0; //*
+static tilemap *fix_tilemap;
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_pow_tile_info )
+{
+ int tile=videoram16[2*tile_index]&0xff;
+ int color=videoram16[2*tile_index+1];
+
+ tile += pow_charbase; //AT: (powj36rc2gre)
+ color&=0xf;
+
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_sar_tile_info )
+{
+ int tile=videoram16[2*tile_index];
+ int color=tile >> 12;
+
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_ikari3_tile_info )
+{
+ int tile=videoram16[2*tile_index];
+ int color=tile >> 12;
+
+ /* Kludge - Tile 0x80ff is meant to be opaque black, but isn't. This fixes it */
+ if (tile==0x80ff) {
+ tile=0x2ca;
+ color=7;
+ } else
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( pow )
+{
+ fix_tilemap = tilemap_create(get_pow_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(fix_tilemap,0);
+}
+
+VIDEO_START( searchar )
+{
+ fix_tilemap = tilemap_create(get_sar_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(fix_tilemap,0);
+}
+
+VIDEO_START( ikari3 )
+{
+ fix_tilemap = tilemap_create(get_ikari3_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(fix_tilemap,0);
+}
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( pow_flipscreen16_w )
+{
+ if (ACCESSING_LSB)
+ {
+ flip_screen_set(data & 0x08);
+ sprite_flip=data&0x4;
+ pow_charbase = (data & 0x70) << 4;
+ }
+}
+
+WRITE16_HANDLER( pow_paletteram16_word_w )
+{
+ UINT16 newword;
+ int r,g,b;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ newword = paletteram16[offset];
+
+ r = ((newword >> 7) & 0x1e) | ((newword >> 14) & 0x01);
+ g = ((newword >> 3) & 0x1e) | ((newword >> 13) & 0x01) ;
+ b = ((newword << 1) & 0x1e) | ((newword >> 12) & 0x01) ;
+
+ palette_set_color_rgb(Machine,offset,pal5bit(r),pal5bit(g),pal5bit(b));
+}
+
+WRITE16_HANDLER( pow_video16_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty(fix_tilemap,offset>>1);
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int j,int pos)
+{
+ int offs,mx,my,color,tile,fx,fy,i;
+
+ for (offs = pos; offs < pos+0x800; offs += 0x80 )
+ {
+ mx=(spriteram16[(offs+4+(4*j))>>1]&0xff)<<4;
+ my=spriteram16[(offs+6+(4*j))>>1];
+ mx=mx+(my>>12);
+ mx=((mx+16)&0x1ff)-16;
+
+ mx=((mx+0x100)&0x1ff)-0x100;
+ my=((my+0x100)&0x1ff)-0x100;
+
+ my=0x200 - my;
+ my-=0x200;
+
+ if (flip_screen) {
+ mx=240-mx;
+ my=240-my;
+ }
+
+ for (i=0; i<0x80; i+=4) {
+ color=spriteram16[(offs+i+(0x1000*j)+0x1000)>>1]&0x7f;
+
+ if (color) {
+ tile=spriteram16[(offs+2+i+(0x1000*j)+0x1000)>>1];
+ fy=tile&0x8000;
+ fx=tile&0x4000;
+ tile&=0x3fff;
+
+ if (flip_screen) {
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ tile,
+ color,
+ fx,fy,
+ mx,my,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ if (flip_screen) {
+ my-=16;
+ if (my < -0x100) my+=0x200;
+ }
+ else {
+ my+=16;
+ if (my > 0x100) my-=0x200;
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( pow )
+{
+ fillbitmap(bitmap,machine->pens[2047],cliprect);
+
+ /* This appears to be correct priority */
+ draw_sprites(machine, bitmap,cliprect,1,0x000);
+ draw_sprites(machine, bitmap,cliprect,1,0x800);
+ draw_sprites(machine, bitmap,cliprect,2,0x000);
+ draw_sprites(machine, bitmap,cliprect,2,0x800);
+ draw_sprites(machine, bitmap,cliprect,0,0x000); //AT: (pow37b5yel)
+ draw_sprites(machine, bitmap,cliprect,0,0x800);
+
+ tilemap_draw(bitmap,cliprect,fix_tilemap,0,0);
+ return 0;
+}
+
+
+static void draw_sprites2(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int j, int z, int pos)
+{
+ int offs,mx,my,color,tile,fx,fy,i;
+
+ for (offs = pos; offs < pos+0x800 ; offs += 0x80 )
+ {
+ mx=spriteram16[(offs+j)>>1];
+ my=spriteram16[(offs+j+2)>>1];
+
+ mx=mx<<4;
+ mx=mx|((my>>12)&0xf);
+ my=my&0x1ff;
+
+ mx=(mx+0x100)&0x1ff;
+ my=(my+0x100)&0x1ff;
+ mx-=0x100;
+ my-=0x100;
+ my=0x200 - my;
+ my-=0x200;
+
+ if (flip_screen) {
+ mx=240-mx;
+ my=240-my;
+ }
+
+ for (i=0; i<0x80; i+=4) {
+ color=spriteram16[(offs+i+z)>>1]&0x7f;
+ if (color) {
+ tile=spriteram16[(offs+2+i+z)>>1];
+ if (sprite_flip) {
+ fx=0;
+ fy=tile&0x8000;
+ } else {
+ fy=0;
+ fx=tile&0x8000;
+ }
+
+ if (flip_screen) {
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ }
+
+ tile&=0x7fff;
+ if (tile>0x5fff) break;
+
+ drawgfx(bitmap,machine->gfx[1],
+ tile,
+ color,
+ fx,fy,
+ mx,my,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ if (flip_screen) {
+ my-=16;
+ if (my < -0x100) my+=0x200;
+ }
+ else {
+ my+=16;
+ if (my > 0x100) my-=0x200;
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( searchar )
+{
+ fillbitmap(bitmap,machine->pens[2047],cliprect);
+
+ /* This appears to be correct priority */
+ draw_sprites2(machine, bitmap,cliprect,8,0x2000,0x000);
+ draw_sprites2(machine, bitmap,cliprect,8,0x2000,0x800);
+ draw_sprites2(machine, bitmap,cliprect,12,0x3000,0x000);
+ draw_sprites2(machine, bitmap,cliprect,12,0x3000,0x800);
+ draw_sprites2(machine, bitmap,cliprect,4,0x1000,0x000);
+ draw_sprites2(machine, bitmap,cliprect,4,0x1000,0x800);
+
+ tilemap_draw(bitmap,cliprect,fix_tilemap,0,0);
+ return 0;
+}
+
diff --git a/src/mame/video/solomon.c b/src/mame/video/solomon.c
new file mode 100644
index 00000000000..23e24e2e57d
--- /dev/null
+++ b/src/mame/video/solomon.c
@@ -0,0 +1,107 @@
+#include "driver.h"
+
+UINT8 *solomon_videoram2;
+UINT8 *solomon_colorram2;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+WRITE8_HANDLER( solomon_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( solomon_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( solomon_videoram2_w )
+{
+ solomon_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( solomon_colorram2_w )
+{
+ solomon_colorram2[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( solomon_flipscreen_w )
+{
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = solomon_colorram2[tile_index];
+ int code = solomon_videoram2[tile_index] + 256 * (attr & 0x07);
+ int color = ((attr & 0x70) >> 4);
+ int flags = ((attr & 0x80) ? TILE_FLIPX : 0) | ((attr & 0x08) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(1, code, color, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + 256 * (attr & 0x07);
+ int color = (attr & 0x70) >> 4;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( solomon )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = spriteram_size - 4; offs >= 0; offs -= 4)
+ {
+ int code = spriteram[offs] + 16 * (spriteram[offs + 1] & 0x10);
+ int color = (spriteram[offs + 1] & 0x0e) >> 1;
+ int flipx = spriteram[offs + 1] & 0x40;
+ int flipy = spriteram[offs + 1] & 0x80;
+ int sx = spriteram[offs + 3];
+ int sy = 241 - spriteram[offs + 2];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 242 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[2],
+ code, color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( solomon )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/sonson.c b/src/mame/video/sonson.c
new file mode 100644
index 00000000000..d833ebd3336
--- /dev/null
+++ b/src/mame/video/sonson.c
@@ -0,0 +1,171 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Son Son has two 32x8 palette PROMs and two 256x4 lookup table PROMs (one
+ for characters, one for sprites).
+ The palette PROMs are connected to the RGB output this way:
+
+ I don't know the exact values of the resistors between the PROMs and the
+ RGB output. I assumed these values (the same as Commando)
+ bit 7 -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 2.2kohm resistor -- GREEN
+ -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 1 kohm resistor -- BLUE
+ bit 0 -- 2.2kohm resistor -- BLUE
+
+ bit 7 -- unused
+ -- unused
+ -- unused
+ -- unused
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ -- 1 kohm resistor -- RED
+ bit 0 -- 2.2kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( sonson )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ /* red component */
+ bit0 = (color_prom[i + machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[i + machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[i + machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[i + machine->drv->total_colors] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* green component */
+ bit0 = (color_prom[i] >> 4) & 0x01;
+ bit1 = (color_prom[i] >> 5) & 0x01;
+ bit2 = (color_prom[i] >> 6) & 0x01;
+ bit3 = (color_prom[i] >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* blue component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ bit3 = (color_prom[i] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* characters use colors 0-15 */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = *(color_prom++) & 0x0f;
+
+ /* sprites use colors 16-31 */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = (*(color_prom++) & 0x0f) + 0x10;
+}
+
+WRITE8_HANDLER( sonson_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( sonson_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( sonson_scroll_w )
+{
+ int row;
+
+ for (row = 5; row < 32; row++)
+ {
+ tilemap_set_scrollx(bg_tilemap, row, data);
+ }
+}
+
+WRITE8_HANDLER( sonson_flipscreen_w )
+{
+ if (flip_screen != (~data & 0x01))
+ {
+ flip_screen_set(~data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + 256 * (attr & 0x03);
+ int color = attr >> 2;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( sonson )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_scroll_rows(bg_tilemap, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = spriteram_size - 4; offs >= 0; offs -= 4)
+ {
+ int code = spriteram[offs + 2] + ((spriteram[offs + 1] & 0x20) << 3);
+ int color = spriteram[offs + 1] & 0x1f;
+ int flipx = ~spriteram[offs + 1] & 0x40;
+ int flipy = ~spriteram[offs + 1] & 0x80;
+ int sx = spriteram[offs + 3];
+ int sy = spriteram[offs + 0];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1],
+ code, color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( sonson )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/spacefb.c b/src/mame/video/spacefb.c
new file mode 100644
index 00000000000..f201664b7bb
--- /dev/null
+++ b/src/mame/video/spacefb.c
@@ -0,0 +1,471 @@
+/***************************************************************************
+
+ Space Firebird hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "spacefb.h"
+#include "video/resnet.h"
+
+
+UINT8 *spacefb_videoram;
+size_t spacefb_videoram_size;
+
+
+/* bitmap that marks whether a given pixel has a sprite/bullet there */
+static bitmap_t *object_present_map;
+
+static UINT8 flipscreen;
+static UINT8 gfx_bank;
+static UINT8 palette_bank;
+static UINT8 background_red;
+static UINT8 background_blue;
+static UINT8 disable_star_field;
+static UINT8 color_contrast_r;
+static UINT8 color_contrast_g;
+static UINT8 color_contrast_b;
+static UINT32 star_shift_reg;
+
+static double color_weights_r[3], color_weights_g[3], color_weights_b[3];
+
+
+
+/*************************************
+ *
+ * Port bit setters
+ *
+ *************************************/
+
+void spacefb_set_flip_screen(UINT8 data)
+{
+ flipscreen = data;
+
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+}
+
+
+void spacefb_set_gfx_bank(UINT8 data)
+{
+ gfx_bank = data;
+
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+}
+
+
+void spacefb_set_palette_bank(UINT8 data)
+{
+ palette_bank = data;
+
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+}
+
+
+void spacefb_set_background_red(UINT8 data)
+{
+ background_red = data;
+
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+}
+
+
+void spacefb_set_background_blue(UINT8 data)
+{
+ background_blue = data;
+
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+}
+
+
+void spacefb_set_disable_star_field(UINT8 data)
+{
+ disable_star_field = data;
+
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+}
+
+
+void spacefb_set_color_contrast_r(UINT8 data)
+{
+ color_contrast_r = data;
+
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+}
+
+
+void spacefb_set_color_contrast_g(UINT8 data)
+{
+ color_contrast_g = data;
+
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+}
+
+
+void spacefb_set_color_contrast_b(UINT8 data)
+{
+ color_contrast_b = data;
+
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ * The sprites use a 32 bytes palette PROM, connected to the RGB output this
+ * way:
+ *
+ * bit 7 -- 220 ohm resistor -- BLUE
+ * -- 470 ohm resistor -- BLUE
+ * -- 220 ohm resistor -- GREEN
+ * -- 470 ohm resistor -- GREEN
+ * -- 1 kohm resistor -- GREEN
+ * -- 220 ohm resistor -- RED
+ * -- 470 ohm resistor -- RED
+ * bit 0 -- 1 kohm resistor -- RED
+ *
+ *
+ * The schematics show that the bullet color is connected this way,
+ * but this is impossible
+ *
+ * 860 ohm resistor -- RED
+ * 68 ohm resistor -- GREEN
+ *
+ *
+ * The background color is connected this way:
+ *
+ * Ra -- 220 ohm resistor -- BLUE
+ * Rb -- 470 ohm resistor -- BLUE
+ * Ga -- 220 ohm resistor -- GREEN
+ * Gb -- 470 ohm resistor -- GREEN
+ * Ba -- 220 ohm resistor -- RED
+ * Bb -- 470 ohm resistor -- RED
+ *
+ *************************************/
+
+VIDEO_START( spacefb )
+{
+ /* compute the color gun weights */
+ static const int resistances_rg[] = { 1000, 470, 220 };
+ static const int resistances_b [] = { 470, 220 };
+
+ compute_resistor_weights(0, 0xff, -1.0,
+ 3, resistances_rg, color_weights_r, 470, 0,
+ 3, resistances_rg, color_weights_g, 470, 0,
+ 2, resistances_b, color_weights_b, 470, 0);
+
+ object_present_map = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED8);
+
+ /* this start value positions the stars to match the flyer screen shot,
+ but most likely, the actual star position is random as the hardware
+ uses whatever value is on the shift register on power-up */
+ star_shift_reg = 0x18f89;
+}
+
+
+
+/*************************************
+ *
+ * Star field generator
+ *
+ *************************************/
+
+#define NUM_STARFIELD_PENS (0x40)
+
+
+INLINE void shift_star_generator(void)
+{
+ star_shift_reg = ((star_shift_reg << 1) | (((~star_shift_reg >> 16) & 0x01) ^ ((star_shift_reg >> 4) & 0x01))) & 0x1ffff;
+}
+
+
+static void get_starfield_pens(pen_t *pens)
+{
+ /* generate the pens based on the various enable bits */
+ int i;
+
+ for (i = 0; i < NUM_STARFIELD_PENS; i++)
+ {
+ UINT8 gb = ((i >> 0) & 0x01) & color_contrast_g & !disable_star_field;
+ UINT8 ga = ((i >> 1) & 0x01) & !disable_star_field;
+ UINT8 bb = ((i >> 2) & 0x01) & color_contrast_b & !disable_star_field;
+ UINT8 ba = (((i >> 3) & 0x01) | background_blue) & !disable_star_field;
+ UINT8 ra = (((i >> 4) & 0x01) | background_red) & !disable_star_field;
+ UINT8 rb = ((i >> 5) & 0x01) & color_contrast_r & !disable_star_field;
+
+ UINT8 r = combine_3_weights(color_weights_r, 0, rb, ra);
+ UINT8 g = combine_3_weights(color_weights_g, 0, gb, ga);
+ UINT8 b = combine_2_weights(color_weights_b, bb, ba);
+
+ pens[i] = MAKE_RGB(r, g, b);
+ }
+
+}
+
+
+static void draw_starfield(running_machine *machine,
+ int scrnum,
+ mame_bitmap *bitmap,
+ const rectangle *cliprect)
+{
+ int y;
+ pen_t pens[NUM_STARFIELD_PENS];
+
+ get_starfield_pens(pens);
+
+ /* the shift register is always shifting -- do the portion in the top VBLANK */
+ if (cliprect->min_y == machine->screen[scrnum].visarea.min_y)
+ {
+ int i;
+
+ /* one cycle delay introduced by IC10 D flip-flop at the end of the VBLANK */
+ int clock_count = (SPACEFB_HBSTART - SPACEFB_HBEND) * SPACEFB_VBEND - 1;
+
+ for (i = 0; i < clock_count; i++)
+ shift_star_generator();
+ }
+
+ /* visible region of the screen */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ int x;
+
+ for (x = SPACEFB_HBEND; x < SPACEFB_HBSTART; x++)
+ {
+ if (!*BITMAP_ADDR8(object_present_map, y, x))
+ {
+ /* draw the star - the 4 possible values come from the effect of the two XOR gates */
+ if (((star_shift_reg & 0x1c0ff) == 0x0c0b7) ||
+ ((star_shift_reg & 0x1c0ff) == 0x0c0d7) ||
+ ((star_shift_reg & 0x1c0ff) == 0x0c0bb) ||
+ ((star_shift_reg & 0x1c0ff) == 0x0c0db))
+ *BITMAP_ADDR32(bitmap, y, x) = pens[(star_shift_reg >> 8) & 0x3f];
+ else
+ *BITMAP_ADDR32(bitmap, y, x) = pens[0];
+ }
+
+ shift_star_generator();
+ }
+ }
+
+ /* do the shifting in the bottom VBLANK */
+ if (cliprect->max_y == machine->screen[scrnum].visarea.max_y)
+ {
+ int i;
+ int clock_count = (SPACEFB_HBSTART - SPACEFB_HBEND) * (SPACEFB_VTOTAL - SPACEFB_VBSTART);
+
+ for (i = 0; i < clock_count; i++)
+ shift_star_generator();
+ }
+}
+
+
+
+/*************************************
+ *
+ * Sprite/Bullet hardware
+ *
+ * Sprites are opaque wrt. each other,
+ * but transparent wrt. to the
+ * star field.
+ *
+ *************************************/
+
+#define NUM_SPRITE_PENS (0x40)
+
+
+static void get_sprite_pens(pen_t *pens)
+{
+ static const double fade_weights[] = { 1.0, 1.5, 2.5, 4.0 };
+
+ int i;
+
+ for (i = 0; i < NUM_SPRITE_PENS; i++)
+ {
+ UINT8 data = memory_region(REGION_PROMS)[(palette_bank << 4) | (i & 0x0f)];
+
+ UINT8 r0 = (data >> 0) & 0x01;
+ UINT8 r1 = (data >> 1) & 0x01;
+ UINT8 r2 = (data >> 2) & 0x01;
+
+ UINT8 g0 = (data >> 3) & 0x01;
+ UINT8 g1 = (data >> 4) & 0x01;
+ UINT8 g2 = (data >> 5) & 0x01;
+
+ UINT8 b1 = (data >> 6) & 0x01;
+ UINT8 b2 = (data >> 7) & 0x01;
+
+ UINT8 r = combine_3_weights(color_weights_r, r0, r1, r2);
+ UINT8 g = combine_3_weights(color_weights_g, g0, g1, g2);
+ UINT8 b = combine_2_weights(color_weights_b, b1, b2);
+
+ if (i >> 4)
+ {
+ double fade_weight = fade_weights[i >> 4];
+
+ /* faded pens */
+ r = (r / fade_weight) + 0.5;
+ g = (g / fade_weight) + 0.5;
+ b = (b / fade_weight) + 0.5;
+ }
+
+ pens[i] = MAKE_RGB(r, g, b);
+ }
+}
+
+
+static void draw_bullet(offs_t offs, pen_t pen, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 sy;
+
+ UINT8 *gfx = memory_region(REGION_GFX2);
+
+ UINT8 code = spacefb_videoram[offs + 0x0200] & 0x3f;
+ UINT8 y = ~spacefb_videoram[offs + 0x0100] - 2;
+
+ for (sy = 0; sy < 4; sy++)
+ {
+ UINT8 sx, dy;
+
+ UINT8 data = gfx[(code << 2) | sy];
+ UINT8 x = spacefb_videoram[offs + 0x0000];
+
+ if (flipscreen)
+ dy = ~y;
+ else
+ dy = y;
+
+ if ((dy > cliprect->min_y) && (dy < cliprect->max_y))
+ {
+ for (sx = 0; sx < 4; sx++)
+ {
+ if (data & 0x01)
+ {
+ UINT16 dx;
+
+ if (flipscreen)
+ dx = (255 - x) * 2;
+ else
+ dx = x * 2;
+
+ *BITMAP_ADDR32(bitmap, dy, dx + 0) = pen;
+ *BITMAP_ADDR32(bitmap, dy, dx + 1) = pen;
+
+ *BITMAP_ADDR8(object_present_map, dy, dx + 0) = 1;
+ *BITMAP_ADDR8(object_present_map, dy, dx + 1) = 1;
+ }
+
+ x = x + 1;
+ data = data >> 1;
+ }
+ }
+
+ y = y + 1;
+ }
+}
+
+
+static void draw_sprite(offs_t offs, pen_t* pens, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 sy;
+
+ UINT8 *gfx = memory_region(REGION_GFX1);
+
+ UINT8 code = ~spacefb_videoram[offs + 0x0200];
+ UINT8 color_base = (~spacefb_videoram[offs + 0x0300] & 0x0f) << 2;
+ UINT8 y = ~spacefb_videoram[offs + 0x0100] - 2;
+
+ for (sy = 0; sy < 8; sy++)
+ {
+ UINT8 sx, dy;
+
+ UINT8 data1 = gfx[0x0000 | (code << 3) | (sy ^ 0x07)];
+ UINT8 data2 = gfx[0x0800 | (code << 3) | (sy ^ 0x07)];
+
+ UINT8 x = spacefb_videoram[offs + 0x0000] - 3;
+
+ if (flipscreen)
+ dy = ~y;
+ else
+ dy = y;
+
+ if ((dy > cliprect->min_y) && (dy < cliprect->max_y))
+ {
+ for (sx = 0; sx < 8; sx++)
+ {
+ UINT16 dx;
+ UINT8 data;
+ pen_t pen;
+
+ if (flipscreen)
+ dx = (255 - x) * 2;
+ else
+ dx = x * 2;
+
+ data = ((data1 << 1) & 0x02) | (data2 & 0x01);
+ pen = pens[color_base | data];
+
+ *BITMAP_ADDR32(bitmap, dy, dx + 0) = pen;
+ *BITMAP_ADDR32(bitmap, dy, dx + 1) = pen;
+
+ *BITMAP_ADDR8(object_present_map, dy, dx + 0) = (data != 0);
+ *BITMAP_ADDR8(object_present_map, dy, dx + 1) = (data != 0);
+
+ x = x + 1;
+ data1 = data1 >> 1;
+ data2 = data2 >> 1;
+ }
+ }
+
+ y = y + 1;
+ }
+}
+
+
+static void draw_objects(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ pen_t sprite_pens[NUM_SPRITE_PENS];
+
+ offs_t offs = gfx_bank ? 0x80 : 0x00;
+
+ /* since the way the schematics show the bullet color
+ connected is impossible, just use pure red for now */
+ pen_t bullet_pen = MAKE_RGB(0xff, 0x00, 0x00);
+
+ get_sprite_pens(sprite_pens);
+
+ while (1)
+ {
+ if (spacefb_videoram[offs + 0x0300] & 0x20)
+ draw_bullet(offs, bullet_pen, bitmap, cliprect);
+ else if (spacefb_videoram[offs + 0x0300] & 0x40)
+ draw_sprite(offs, sprite_pens, bitmap, cliprect);
+
+ /* next object */
+ offs = offs + 1;
+
+ /* end of bank? */
+ if ((offs & 0x7f) == 0) break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( spacefb )
+{
+ fillbitmap(object_present_map, 0, cliprect);
+
+ draw_objects(bitmap, cliprect);
+
+ draw_starfield(machine, screen, bitmap, cliprect);
+
+ return 0;
+}
diff --git a/src/mame/video/spbactn.c b/src/mame/video/spbactn.c
new file mode 100644
index 00000000000..a76406ff208
--- /dev/null
+++ b/src/mame/video/spbactn.c
@@ -0,0 +1,281 @@
+/* video/spbactn.c - see drivers/spbactn.c for more info */
+/* rather similar to galspnbl.c */
+
+#include "driver.h"
+
+extern UINT16 *spbactn_bgvideoram, *spbactn_fgvideoram, *spbactn_spvideoram;
+static mame_bitmap *tile_bitmap_bg, *tile_bitmap_fg;
+
+/* mix & blend the paletted 16-bit tile and sprite bitmaps into an RGB 32-bit bitmap */
+static void blendbitmaps(running_machine *machine,
+ mame_bitmap *dest,mame_bitmap *src1,mame_bitmap *src2,
+ int sx,int sy,const rectangle *clip)
+{
+ int ox;
+ int oy;
+ int ex;
+ int ey;
+
+ /* check bounds */
+ ox = sx;
+ oy = sy;
+
+ ex = sx + src1->width - 1;
+ if (sx < 0) sx = 0;
+ if (sx < clip->min_x) sx = clip->min_x;
+ if (ex >= dest->width) ex = dest->width - 1;
+ if (ex > clip->max_x) ex = clip->max_x;
+ if (sx > ex) return;
+
+ ey = sy + src1->height - 1;
+ if (sy < 0) sy = 0;
+ if (sy < clip->min_y) sy = clip->min_y;
+ if (ey >= dest->height) ey = dest->height - 1;
+ if (ey > clip->max_y) ey = clip->max_y;
+ if (sy > ey) return;
+
+ {
+ const pen_t *paldata = machine->pens;
+ UINT32 *end;
+
+ UINT16 *sd1 = src1->base; /* source data */
+ UINT16 *sd2 = src2->base;
+
+ int sw = ex-sx+1; /* source width */
+ int sh = ey-sy+1; /* source height */
+ int sm = src1->rowpixels; /* source modulo */
+
+ UINT32 *dd = BITMAP_ADDR32(dest, sy, sx); /* dest data */
+ int dm = dest->rowpixels; /* dest modulo */
+
+ sd1 += (sx-ox);
+ sd1 += sm * (sy-oy);
+ sd2 += (sx-ox);
+ sd2 += sm * (sy-oy);
+
+ sm -= sw;
+ dm -= sw;
+
+ while (sh)
+ {
+
+#define BLENDPIXEL(x) if (sd2[x]) { \
+ if (sd2[x] & 0x1000) { \
+ dd[x] = paldata[sd1[x] & 0x07ff] + paldata[sd2[x]]; \
+ } else { \
+ dd[x] = paldata[sd2[x]]; \
+ } \
+ } else { \
+ dd[x] = paldata[sd1[x]]; \
+ }
+
+ end = dd + sw;
+ while (dd <= end - 8)
+ {
+ BLENDPIXEL(0);
+ BLENDPIXEL(1);
+ BLENDPIXEL(2);
+ BLENDPIXEL(3);
+ BLENDPIXEL(4);
+ BLENDPIXEL(5);
+ BLENDPIXEL(6);
+ BLENDPIXEL(7);
+ dd += 8;
+ sd1 += 8;
+ sd2 += 8;
+ }
+ while (dd < end)
+ {
+ BLENDPIXEL(0);
+ dd++;
+ sd1++;
+ sd2++;
+ }
+ sd1 += sm;
+ sd2 += sm;
+ dd += dm;
+ sh--;
+
+#undef BLENDPIXEL
+
+ }
+ }
+}
+
+/* from gals pinball (which was in turn from ninja gaiden) */
+static int draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ static const UINT8 layout[8][8] =
+ {
+ { 0, 1, 4, 5,16,17,20,21},
+ { 2, 3, 6, 7,18,19,22,23},
+ { 8, 9,12,13,24,25,28,29},
+ {10,11,14,15,26,27,30,31},
+ {32,33,36,37,48,49,52,53},
+ {34,35,38,39,50,51,54,55},
+ {40,41,44,45,56,57,60,61},
+ {42,43,46,47,58,59,62,63}
+ };
+
+ int count = 0;
+
+ int offs;
+
+ for (offs = (0x1000 - 16) / 2; offs >= 0; offs -= 8)
+ {
+ int sx, sy, code, color, size, attr, flipx, flipy;
+ int col, row;
+
+ attr = spbactn_spvideoram[offs];
+ if ((attr & 0x0004) &&
+ ((attr & 0x0030) >> 4) == priority)
+ {
+ flipx = attr & 0x0001;
+ flipy = attr & 0x0002;
+
+ code = spbactn_spvideoram[offs + 1];
+
+ color = spbactn_spvideoram[offs + 2];
+ size = 1 << (color & 0x0003); /* 1,2,4,8 */
+ color = (color & 0x00f0) >> 4;
+
+ sx = spbactn_spvideoram[offs + 4];
+ sy = spbactn_spvideoram[offs + 3];
+
+ attr &= ~0x0040; /* !!! */
+
+ if (attr & 0x0040)
+ color |= 0x0180;
+ else
+ color |= 0x0080;
+
+
+ for (row = 0; row < size; row++)
+ {
+ for (col = 0; col < size; col++)
+ {
+ int x = sx + 8 * (flipx ? (size - 1 - col) : col);
+ int y = sy + 8 * (flipy ? (size - 1 - row) : row);
+
+ drawgfx(bitmap, machine->gfx[2],
+ code + layout[row][col],
+ color,
+ flipx, flipy,
+ x, y,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+ }
+
+ count++;
+ }
+ }
+
+ return count;
+}
+
+
+VIDEO_START( spbactn )
+{
+ /* allocate bitmaps */
+ tile_bitmap_bg = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+ tile_bitmap_fg = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+}
+
+VIDEO_UPDATE( spbactn )
+{
+ int offs, sx, sy;
+
+ fillbitmap(tile_bitmap_fg, 0, cliprect);
+
+ /* draw table bg gfx */
+ for (sx = sy = offs = 0; offs < 0x4000 / 2; offs++)
+ {
+ int attr, code, colour;
+
+ code = spbactn_bgvideoram[offs + 0x4000 / 2];
+ attr = spbactn_bgvideoram[offs + 0x0000 / 2];
+
+ colour = ((attr & 0x00f0) >> 4) | 0x80;
+
+ drawgfx(tile_bitmap_bg, machine->gfx[1],
+ code,
+ colour,
+ 0, 0,
+ 16 * sx, 8 * sy,
+ cliprect, TRANSPARENCY_NONE, 0);
+
+ sx++;
+ if (sx > 63)
+ {
+ sy++;
+ sx = 0;
+ }
+ }
+
+ if (draw_sprites(machine, tile_bitmap_bg, cliprect, 0))
+ {
+ /* kludge: draw table bg gfx again if priority 0 sprites are enabled */
+ for (sx = sy = offs = 0; offs < 0x4000 / 2; offs++)
+ {
+ int attr, code, colour;
+
+ code = spbactn_bgvideoram[offs + 0x4000 / 2];
+ attr = spbactn_bgvideoram[offs + 0x0000 / 2];
+
+ colour = ((attr & 0x00f0) >> 4) | 0x80;
+
+ drawgfx(tile_bitmap_bg, machine->gfx[1],
+ code,
+ colour,
+ 0, 0,
+ 16 * sx, 8 * sy,
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ sx++;
+ if (sx > 63)
+ {
+ sy++;
+ sx = 0;
+ }
+ }
+ }
+
+ draw_sprites(machine, tile_bitmap_bg, cliprect, 1);
+
+ /* draw table fg gfx */
+ for (sx = sy = offs = 0; offs < 0x4000 / 2; offs++)
+ {
+ int attr, code, colour;
+
+ code = spbactn_fgvideoram[offs + 0x4000 / 2];
+ attr = spbactn_fgvideoram[offs + 0x0000 / 2];
+
+ colour = ((attr & 0x00f0) >> 4);
+
+ /* blending */
+ if (attr & 0x0008)
+ colour += 0x00f0;
+ else
+ colour |= 0x0080;
+
+ drawgfx(tile_bitmap_fg, machine->gfx[0],
+ code,
+ colour,
+ 0, 0,
+ 16 * sx, 8 * sy,
+ cliprect,TRANSPARENCY_PEN, 0);
+
+ sx++;
+ if (sx > 63)
+ {
+ sy++;
+ sx = 0;
+ }
+ }
+ draw_sprites(machine, tile_bitmap_fg, cliprect, 2);
+ draw_sprites(machine, tile_bitmap_fg, cliprect, 3);
+
+ /* mix & blend the tilemaps and sprites into a 32-bit bitmap */
+ blendbitmaps(machine, bitmap, tile_bitmap_bg, tile_bitmap_fg, 0, 0, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/spcforce.c b/src/mame/video/spcforce.c
new file mode 100644
index 00000000000..3cfbbf6ecb5
--- /dev/null
+++ b/src/mame/video/spcforce.c
@@ -0,0 +1,55 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *spcforce_scrollram;
+
+
+WRITE8_HANDLER( spcforce_flip_screen_w )
+{
+ flip_screen_set(~data & 0x01);
+}
+
+
+VIDEO_UPDATE( spcforce )
+{
+ int offs;
+
+
+ /* draw the characters as sprites because they could be overlapping */
+
+ fillbitmap(bitmap,machine->pens[0],&machine->screen[0].visarea);
+
+
+ for (offs = 0; offs < videoram_size; offs++)
+ {
+ int code,sx,sy,col;
+
+
+ sy = 8 * (offs / 32) - (spcforce_scrollram[offs] & 0x0f);
+ sx = 8 * (offs % 32) + ((spcforce_scrollram[offs] >> 4) & 0x0f);
+
+ code = videoram[offs] + ((colorram[offs] & 0x01) << 8);
+ col = (~colorram[offs] >> 4) & 0x07;
+
+ if (flip_screen)
+ {
+ sx = 248 - sx;
+ sy = 248 - sy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ code, col,
+ flip_screen, flip_screen,
+ sx, sy,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/spdodgeb.c b/src/mame/video/spdodgeb.c
new file mode 100644
index 00000000000..d9a09160e35
--- /dev/null
+++ b/src/mame/video/spdodgeb.c
@@ -0,0 +1,221 @@
+#include "driver.h"
+#include "cpu/m6502/m6502.h"
+
+
+UINT8 *spdodgeb_videoram;
+
+static int tile_palbank;
+static int sprite_palbank;
+
+static tilemap *bg_tilemap;
+
+
+
+PALETTE_INIT( spdodgeb )
+{
+ int i;
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ /* red component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* green component */
+ bit0 = (color_prom[0] >> 4) & 0x01;
+ bit1 = (color_prom[0] >> 5) & 0x01;
+ bit2 = (color_prom[0] >> 6) & 0x01;
+ bit3 = (color_prom[0] >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* blue component */
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( background_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x20) << 5);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 code = spdodgeb_videoram[tile_index];
+ UINT8 attr = spdodgeb_videoram[tile_index + 0x800];
+ SET_TILE_INFO(
+ 0,
+ code + ((attr & 0x1f) << 8),
+ ((attr & 0xe0) >> 5) + 8 * tile_palbank,
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( spdodgeb )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,background_scan,TILEMAP_TYPE_PEN,8,8,64,32);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+static int lastscroll;
+
+INTERRUPT_GEN( spdodgeb_interrupt )
+{
+ int iloop = cpu_getiloops();
+ int scanline = (32-iloop) * 8;
+
+ if (iloop > 1 && iloop < 32)
+ {
+ cpunum_set_input_line(0, M6502_IRQ_LINE, HOLD_LINE);
+ video_screen_update_partial(0, scanline+7);
+ }
+ else if (!iloop)
+ {
+ cpunum_set_input_line(0, INPUT_LINE_NMI, PULSE_LINE);
+ video_screen_update_partial(0, 256);
+ }
+}
+
+WRITE8_HANDLER( spdodgeb_scrollx_lo_w )
+{
+ lastscroll = (lastscroll & 0x100) | data;
+}
+
+WRITE8_HANDLER( spdodgeb_ctrl_w )
+{
+ UINT8 *rom = memory_region(REGION_CPU1);
+
+ /* bit 0 = flip screen */
+ flip_screen_set(data & 0x01);
+
+ /* bit 1 = ROM bank switch */
+ memory_set_bankptr(1,rom + 0x10000 + 0x4000 * ((~data & 0x02) >> 1));
+
+ /* bit 2 = scroll high bit */
+ lastscroll = (lastscroll & 0x0ff) | ((data & 0x04) << 6);
+
+ /* bit 3 = to mcu?? */
+
+ /* bits 4-7 = palette bank select */
+ if (tile_palbank != ((data & 0x30) >> 4))
+ {
+ tile_palbank = ((data & 0x30) >> 4);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+ sprite_palbank = (data & 0xc0) >> 6;
+}
+
+WRITE8_HANDLER( spdodgeb_videoram_w )
+{
+ spdodgeb_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x7ff);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+#define DRAW_SPRITE( order, sx, sy ) drawgfx( bitmap, gfx, \
+ (which+order),color+ 8 * sprite_palbank,flipx,flipy,sx,sy, \
+ cliprect,TRANSPARENCY_PEN,0);
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ const gfx_element *gfx = machine->gfx[1];
+ UINT8 *src;
+ int i;
+
+ src = spriteram;
+
+/* 240-SY Z|F|CLR|WCH WHICH SX
+ xxxxxxxx x|x|xxx|xxx xxxxxxxx xxxxxxxx
+*/
+ for (i = 0;i < spriteram_size;i += 4)
+ {
+ int attr = src[i+1];
+ int which = src[i+2]+((attr & 0x07)<<8);
+ int sx = src[i+3];
+ int sy = 240 - src[i];
+ int size = (attr & 0x80) >> 7;
+ int color = (attr & 0x38) >> 3;
+ int flipx = ~attr & 0x40;
+ int flipy = 0;
+ int dy = -16;
+ int cy;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ dy = -dy;
+ }
+
+ if (sx < -8) sx += 256; else if (sx > 248) sx -= 256;
+
+ switch (size)
+ {
+ case 0: /* normal */
+ if (sy < -8) sy += 256; else if (sy > 248) sy -= 256;
+ DRAW_SPRITE(0,sx,sy);
+ break;
+
+ case 1: /* double y */
+ if (flip_screen) { if (sy > 240) sy -= 256; } else { if (sy < 0) sy += 256; }
+ cy = sy + dy;
+ which &= ~1;
+ DRAW_SPRITE(0,sx,cy);
+ DRAW_SPRITE(1,sx,sy);
+ break;
+ }
+ }
+}
+
+#undef DRAW_SPRITE
+
+
+VIDEO_UPDATE( spdodgeb )
+{
+
+ tilemap_set_scrollx(bg_tilemap,0,lastscroll+5);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/speedatk.c b/src/mame/video/speedatk.c
new file mode 100644
index 00000000000..2beb30cd352
--- /dev/null
+++ b/src/mame/video/speedatk.c
@@ -0,0 +1,109 @@
+/*****************************************************************************************
+
+ Speed Attack video hardware emulation
+
+*****************************************************************************************/
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+/*
+
+Color prom dump(only 0x00-0x10 range has valid data)
+0:---- ---- 0x00 Black
+1:---- -x-- 0x04
+2:---- -xxx 0x07
+3:x-x- -xxx 0xa7
+4:--x- x--- 0x28
+5:xxxx x--- 0xf8
+6:--xx xxxx 0x3f
+7:xxxx xxxx 0xff White
+8:x--- -x-- 0x84
+9:x-x- xx-x 0xad
+a:--x- -x-x 0x25
+b:-xxx xxx- 0x7e
+c:--x- xxxx 0x2f
+d:xx-- ---- 0xc0
+e:--xx -xx- 0x36
+f:xxx- x--- 0xe8
+
+*/
+
+PALETTE_INIT( speedatk )
+{
+ int i;
+
+ for (i = 0;i < 0x10;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ color_prom += 0x10;
+
+ /* Colortable entry */
+ for(i = 0; i < 0x100; i++)
+ colortable[i] = color_prom[i];
+}
+
+WRITE8_HANDLER( speedatk_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( speedatk_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( speedatk_flip_screen_w )
+{
+ flip_screen_set(data);
+}
+
+static TILE_GET_INFO( get_tile_info )
+{
+ int code, color, region;
+
+ code = videoram[tile_index] + ((colorram[tile_index] & 0xe0) << 3);
+ color = colorram[tile_index] & 0x0f;
+ region = (colorram[tile_index] & 0x10) >> 4;
+
+ color += 2;
+ if(region)
+ color += 0x10;
+ if (region == 1)
+ color &= 0x1f;
+
+ SET_TILE_INFO(region, code, color, 0);
+}
+
+VIDEO_START( speedatk )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,34,32);
+}
+
+VIDEO_UPDATE( speedatk )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/speedbal.c b/src/mame/video/speedbal.c
new file mode 100644
index 00000000000..3cdf81aa52d
--- /dev/null
+++ b/src/mame/video/speedbal.c
@@ -0,0 +1,135 @@
+ /****************************************************************************
+ * *
+ * video.c *
+ * *
+ * Functions to emulate the video hardware of the machine. *
+ * *
+ ****************************************************************************/
+
+#include "driver.h"
+
+UINT8 *speedbal_background_videoram;
+UINT8 *speedbal_foreground_videoram;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+static TILE_GET_INFO( get_tile_info_bg )
+{
+ int code = speedbal_background_videoram[tile_index*2] + ((speedbal_background_videoram[tile_index*2+1] & 0x30) << 4);
+ int color = speedbal_background_videoram[tile_index*2+1] & 0x0f;
+
+ SET_TILE_INFO(1, code, color, 0);
+ tileinfo->group = (color == 8);
+}
+
+static TILE_GET_INFO( get_tile_info_fg )
+{
+ int code = speedbal_foreground_videoram[tile_index*2] + ((speedbal_foreground_videoram[tile_index*2+1] & 0x30) << 4);
+ int color = speedbal_foreground_videoram[tile_index*2+1] & 0x0f;
+
+ SET_TILE_INFO(0, code, color, 0);
+ tileinfo->group = (color == 9);
+}
+
+/*************************************
+ * *
+ * Start-Stop *
+ * *
+ *************************************/
+
+VIDEO_START( speedbal )
+{
+ bg_tilemap = tilemap_create(get_tile_info_bg, tilemap_scan_cols_flip_x, TILEMAP_TYPE_PEN, 16, 16, 16, 16);
+ fg_tilemap = tilemap_create(get_tile_info_fg, tilemap_scan_cols_flip_x, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transmask(bg_tilemap,0,0xffff,0x0000); /* split type 0 is totally transparent in front half */
+ tilemap_set_transmask(bg_tilemap,1,0x00f7,0x0000); /* split type 1 has pen 0-2, 4-7 transparent in front half */
+
+ tilemap_set_transmask(fg_tilemap,0,0xffff,0x0001); /* split type 0 is totally transparent in front half and has pen 0 transparent in back half */
+ tilemap_set_transmask(fg_tilemap,1,0x0001,0x0001); /* split type 1 has pen 0 transparent in front and back half */
+}
+
+
+
+/*************************************
+ * *
+ * Foreground characters RAM *
+ * *
+ *************************************/
+
+WRITE8_HANDLER( speedbal_foreground_videoram_w )
+{
+ speedbal_foreground_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset>>1);
+}
+
+/*************************************
+ * *
+ * Background tiles RAM *
+ * *
+ *************************************/
+
+WRITE8_HANDLER( speedbal_background_videoram_w )
+{
+ speedbal_background_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset>>1);
+}
+
+
+/*************************************
+ * *
+ * Sprite drawing *
+ * *
+ *************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int x,y,code,color,offset,flipx,flipy;
+
+ /* Drawing sprites: 64 in total */
+
+ for (offset = 0;offset < spriteram_size;offset += 4)
+ {
+ if(!(spriteram[offset + 2] & 0x80))
+ continue;
+
+ x = 243 - spriteram[offset + 3];
+ y = 239 - spriteram[offset + 0];
+
+ code = BITSWAP8(spriteram[offset + 1],0,1,2,3,4,5,6,7) | ((spriteram[offset + 2] & 0x40) << 2);
+
+ color = spriteram[offset + 2] & 0x0f;
+
+ flipx = flipy = 0;
+
+ if(flip_screen)
+ {
+ x = 246 - x;
+ y = 238 - y;
+ flipx = flipy = 1;
+ }
+
+ drawgfx (bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx,flipy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+/*************************************
+ * *
+ * Refresh screen *
+ * *
+ *************************************/
+
+VIDEO_UPDATE( speedbal )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_LAYER1, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, TILEMAP_DRAW_LAYER1, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_LAYER0, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, TILEMAP_DRAW_LAYER0, 0);
+ return 0;
+}
diff --git a/src/mame/video/speedspn.c b/src/mame/video/speedspn.c
new file mode 100644
index 00000000000..ea6615153a0
--- /dev/null
+++ b/src/mame/video/speedspn.c
@@ -0,0 +1,113 @@
+/* Speed Spin video, see driver file for notes */
+
+#include "driver.h"
+
+UINT8 *speedspn_attram;
+
+static tilemap *speedspn_tilemap;
+static UINT8 speedspn_display_disable = 0;
+static int speedspn_bank_vidram = 0;
+static UINT8* speedspn_vidram;
+
+
+static TILE_GET_INFO( get_speedspn_tile_info )
+{
+ int code = speedspn_vidram[tile_index*2+1] | (speedspn_vidram[tile_index*2] << 8);
+ int attr = speedspn_attram[tile_index^0x400];
+
+ SET_TILE_INFO(0,code,attr & 0x3f,(attr & 0x80) ? TILE_FLIPX : 0);
+}
+
+VIDEO_START(speedspn)
+{
+ speedspn_vidram = auto_malloc(0x1000 * 2);
+ speedspn_tilemap = tilemap_create(get_speedspn_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 8, 8,64,32);
+}
+
+WRITE8_HANDLER( speedspn_vidram_w )
+{
+ speedspn_vidram[offset + speedspn_bank_vidram] = data;
+
+ if (speedspn_bank_vidram == 0)
+ tilemap_mark_tile_dirty(speedspn_tilemap,offset/2);
+}
+
+WRITE8_HANDLER( speedspn_attram_w )
+{
+ speedspn_attram[offset] = data;
+
+ tilemap_mark_tile_dirty(speedspn_tilemap,offset^0x400);
+}
+
+READ8_HANDLER( speedspn_vidram_r )
+{
+ return speedspn_vidram[offset + speedspn_bank_vidram];
+}
+
+WRITE8_HANDLER(speedspn_banked_vidram_change)
+{
+// logerror("VidRam Bank: %04x\n", data);
+ speedspn_bank_vidram = data & 1;
+ speedspn_bank_vidram *= 0x1000;
+}
+
+WRITE8_HANDLER(speedspn_global_display_w)
+{
+// logerror("Global display: %u\n", data);
+ speedspn_display_disable = data & 1;
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ const gfx_element *gfx = machine->gfx[1];
+ UINT8 *source = speedspn_vidram+ 0x1000;
+ UINT8 *finish = source + 0x1000;
+
+ while( source<finish )
+ {
+ int xpos = source[0];
+ int tileno = source[1];
+ int attr = source[2];
+ int ypos = source[3];
+ int color;
+
+ if (attr&0x10) xpos +=0x100;
+
+ xpos = 0x1f8-xpos;
+ tileno += ((attr & 0xe0) >> 5) * 0x100;
+ color = attr & 0x0f;
+
+ drawgfx(bitmap,gfx,
+ tileno,
+ color,
+ 0,0,
+ xpos,ypos,
+ cliprect,TRANSPARENCY_PEN,15);
+
+ source +=4;
+ }
+}
+
+
+VIDEO_UPDATE(speedspn)
+{
+ if (speedspn_display_disable)
+ {
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ return 0;
+ }
+
+#if 0
+ {
+ FILE* f;
+ f = fopen("vidram.bin","wb");
+ fwrite(speedspn_vidram, 1, 0x1000 * 2, f);
+ fclose(f);
+ }
+#endif
+ tilemap_set_scrollx(speedspn_tilemap,0, 0x100); // verify
+ tilemap_draw(bitmap,cliprect,speedspn_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/splash.c b/src/mame/video/splash.c
new file mode 100644
index 00000000000..12857441138
--- /dev/null
+++ b/src/mame/video/splash.c
@@ -0,0 +1,292 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *splash_vregs;
+UINT16 *splash_videoram;
+UINT16 *splash_spriteram;
+UINT16 *splash_pixelram;
+UINT16 *roldfrog_bitmap_mode;
+int splash_bitmap_type;
+int splash_sprite_attr2_shift;
+static tilemap *bg_tilemap[2];
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/*
+ Tile format
+ -----------
+
+ Tilemap 0: (64*32, 8x8 tiles)
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- xxxxxxxx | sprite code (low 8 bits)
+ 0 | ----xxxx -------- | sprite code (high 4 bits)
+ 0 | xxxx---- -------- | color
+
+ Tilemap 1: (32*32, 16x16 tiles)
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- -------x | flip y
+ 0 | -------- ------x- | flip x
+ 0 | -------- xxxxxx-- | sprite code (low 6 bits)
+ 0 | ----xxxx -------- | sprite code (high 4 bits)
+ 0 | xxxx---- -------- | color
+*/
+
+static TILE_GET_INFO( get_tile_info_splash_tilemap0 )
+{
+ int data = splash_videoram[tile_index];
+ int attr = data >> 8;
+ int code = data & 0xff;
+
+ SET_TILE_INFO(
+ 0,
+ code + ((0x20 + (attr & 0x0f)) << 8),
+ (attr & 0xf0) >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( get_tile_info_splash_tilemap1 )
+{
+ int data = splash_videoram[(0x1000/2) + tile_index];
+ int attr = data >> 8;
+ int code = data & 0xff;
+
+ SET_TILE_INFO(
+ 1,
+ (code >> 2) + ((0x30 + (attr & 0x0f)) << 6),
+ (attr & 0xf0) >> 4,
+ TILE_FLIPXY(code & 0x03));
+}
+
+/***************************************************************************
+
+ Memory Handlers
+
+***************************************************************************/
+
+READ16_HANDLER( splash_vram_r )
+{
+ return splash_videoram[offset];
+}
+
+WRITE16_HANDLER( splash_vram_w )
+{
+ COMBINE_DATA(&splash_videoram[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap[offset >> 11],((offset << 1) & 0x0fff) >> 1);
+}
+
+static void draw_bitmap(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int sx,sy,color,count,colxor,bitswap;
+ colxor = 0; /* splash and some bitmap modes in roldfrog */
+ bitswap = 0;
+
+ if (splash_bitmap_type==1) /* roldfrog */
+ {
+ if (roldfrog_bitmap_mode[0]==0x0000)
+ {
+ colxor = 0x7f;
+ }
+ else if (roldfrog_bitmap_mode[0]==0x0100)
+ {
+ bitswap = 1;
+ }
+ else if (roldfrog_bitmap_mode[0]==0x0200)
+ {
+ colxor = 0x55;
+ }
+ else if (roldfrog_bitmap_mode[0]==0x0300)
+ {
+ bitswap = 2;
+ colxor = 0x7f;
+ }
+ else if (roldfrog_bitmap_mode[0]==0x0400)
+ {
+ bitswap = 3;
+ }
+ else if (roldfrog_bitmap_mode[0]==0x0500)
+ {
+ bitswap = 4;
+ }
+ else if (roldfrog_bitmap_mode[0]==0x0600)
+ {
+ bitswap = 5;
+ colxor = 0x7f;
+ }
+ else if (roldfrog_bitmap_mode[0]==0x0700)
+ {
+ bitswap = 6;
+ colxor = 0x55;
+ }
+ }
+
+ count = 0;
+ for (sy=0;sy<256;sy++)
+ {
+ for (sx=0;sx<512;sx++)
+ {
+ color = splash_pixelram[count]&0xff;
+ count++;
+
+ switch( bitswap )
+ {
+ case 1:
+ color = BITSWAP8(color,7,0,1,2,3,4,5,6);
+ break;
+ case 2:
+ color = BITSWAP8(color,7,4,6,5,1,0,3,2);
+ break;
+ case 3:
+ color = BITSWAP8(color,7,3,2,1,0,6,5,4);
+ break;
+ case 4:
+ color = BITSWAP8(color,7,6,4,2,0,5,3,1);
+ break;
+ case 5:
+ color = BITSWAP8(color,7,0,6,5,4,3,2,1);
+ break;
+ case 6:
+ color = BITSWAP8(color,7,4,3,2,1,0,6,5);
+ break;
+ }
+
+ if (sy >= cliprect->min_y && sy <= cliprect->max_y && sx-9 >= cliprect->min_x && sx-9 <= cliprect->max_x)
+ *BITMAP_ADDR16(bitmap, sy, sx-9) = machine->pens[0x300+(color^colxor)];
+ }
+ }
+
+}
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( splash )
+{
+ bg_tilemap[0] = tilemap_create(get_tile_info_splash_tilemap0,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ bg_tilemap[1] = tilemap_create(get_tile_info_splash_tilemap1,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ tilemap_set_transparent_pen(bg_tilemap[0],0);
+ tilemap_set_transparent_pen(bg_tilemap[1],0);
+
+ tilemap_set_scrollx(bg_tilemap[0], 0, 4);
+}
+
+/***************************************************************************
+
+ Sprites
+
+***************************************************************************/
+
+/*
+ Sprite Format
+ -------------
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- xxxxxxxx | sprite number (low 8 bits)
+ 0 | xxxxxxxx -------- | unused
+ 1 | -------- xxxxxxxx | y position
+ 1 | xxxxxxxx -------- | unused
+ 2 | -------- xxxxxxxx | x position (low 8 bits)
+ 2 | xxxxxxxx -------- | unused
+ 3 | -------- ----xxxx | sprite number (high 4 bits)
+ 3 | -------- --xx---- | unknown
+ 3 | -------- -x------ | flip x
+ 3 | -------- x------- | flip y
+ 3 | xxxxxxxx -------- | unused
+ 400| -------- ----xxxx | sprite color
+ 400| -------- -xxx---- | unknown
+ 400| -------- x------- | x position (high bit)
+ 400| xxxxxxxx -------- | unused
+*/
+
+static void splash_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int i;
+ const gfx_element *gfx = machine->gfx[1];
+
+ for (i = 0; i < 0x400; i += 4){
+ int sx = splash_spriteram[i+2] & 0xff;
+ int sy = (240 - (splash_spriteram[i+1] & 0xff)) & 0xff;
+ int attr = splash_spriteram[i+3] & 0xff;
+ int attr2 = splash_spriteram[i+0x400] >> splash_sprite_attr2_shift;
+ int number = (splash_spriteram[i] & 0xff) + (attr & 0xf)*256;
+
+ if (attr2 & 0x80) sx += 256;
+
+ drawgfx(bitmap,gfx,number,
+ 0x10 + (attr2 & 0x0f),attr & 0x40,attr & 0x80,
+ sx-8,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+static void funystrp_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int i;
+ const gfx_element *gfx = machine->gfx[1];
+
+ for (i = 0; i < 0x400; i += 4){
+ int sx = splash_spriteram[i+2] & 0x1ff;
+ int sy = (240 - (splash_spriteram[i+1] & 0xff)) & 0xff;
+ int attr = splash_spriteram[i+3] & 0xff;
+ int attr2 = splash_spriteram[i+0x400] >> splash_sprite_attr2_shift;
+ int number = (splash_spriteram[i] & 0xff) + (attr & 0xf)*256;
+
+ drawgfx(bitmap,gfx,number,
+ (attr2 & 0x7f),attr & 0x40,attr & 0x80,
+ sx-8,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( splash )
+{
+ /* set scroll registers */
+ tilemap_set_scrolly(bg_tilemap[0], 0, splash_vregs[0]);
+ tilemap_set_scrolly(bg_tilemap[1], 0, splash_vregs[1]);
+
+ draw_bitmap(machine, bitmap,cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap[1],0,0);
+ splash_draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap[0],0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( funystrp )
+{
+ /* set scroll registers */
+ tilemap_set_scrolly(bg_tilemap[0], 0, splash_vregs[0]);
+ tilemap_set_scrolly(bg_tilemap[1], 0, splash_vregs[1]);
+
+ draw_bitmap(machine, bitmap,cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap[1],0,0);
+ /*Sprite chip is similar but not the same*/
+ funystrp_draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap[0],0,0);
+ return 0;
+}
diff --git a/src/mame/video/sprcros2.c b/src/mame/video/sprcros2.c
new file mode 100644
index 00000000000..60994007e25
--- /dev/null
+++ b/src/mame/video/sprcros2.c
@@ -0,0 +1,169 @@
+/*
+Super Cross II (JPN Ver.)
+(c)1986 GM Shoji
+*/
+
+#include "driver.h"
+
+static tilemap *sprcros2_bgtilemap, *sprcros2_fgtilemap;
+UINT8 *sprcros2_fgvideoram, *sprcros2_spriteram, *sprcros2_bgvideoram;
+size_t sprcros2_spriteram_size;
+extern UINT8 sprcros2_m_port7;
+
+PALETTE_INIT( sprcros2 )
+{
+ int i,bit0,bit1,bit2,r,g,b;
+
+ for (i = 0;i < machine->drv->total_colors; i++)
+ {
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x47 * bit1 + 0xb8 * bit2;
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ //cluts
+ for (i = 0;i < 0x100; i++)
+ {
+ colortable[i]=color_prom[i+0x20]+(color_prom[i+0x120]<<4); //bg
+ colortable[i+0x100]=color_prom[i+0x220]; //sprites
+ colortable[i+0x200]=color_prom[i+0x320]; //fg
+ }
+}
+
+WRITE8_HANDLER( sprcros2_fgvideoram_w )
+{
+ sprcros2_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(sprcros2_fgtilemap,offset&0x3ff);
+}
+
+WRITE8_HANDLER( sprcros2_bgvideoram_w )
+{
+ sprcros2_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(sprcros2_bgtilemap,offset&0x3ff);
+}
+
+WRITE8_HANDLER( sprcros2_bgscrollx_w )
+{
+ if(sprcros2_m_port7&0x02)
+ tilemap_set_scrollx(sprcros2_bgtilemap,0,0x100-data);
+ else
+ tilemap_set_scrollx(sprcros2_bgtilemap,0,data);
+}
+
+WRITE8_HANDLER( sprcros2_bgscrolly_w )
+{
+ tilemap_set_scrolly(sprcros2_bgtilemap,0,data);
+}
+
+static TILE_GET_INFO( get_sprcros2_bgtile_info )
+{
+ UINT32 tile_number = sprcros2_bgvideoram[tile_index];
+ UINT8 attr = sprcros2_bgvideoram[tile_index+0x400];
+
+ //attr
+ //76543210
+ //xxxx---- colour
+ //----x--- flipx
+ //-----xxx tile bank
+
+ tile_number += (attr&0x07)<<8;
+
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ (attr&0xf0)>>4,
+ (attr&0x08)?TILE_FLIPX:0);
+}
+
+static TILE_GET_INFO( get_sprcros2_fgtile_info )
+{
+ UINT32 tile_number = sprcros2_fgvideoram[tile_index];
+ UINT8 attr = sprcros2_fgvideoram[tile_index+0x400];
+
+ //attr
+ //76543210
+ //xxxxxx-- colour
+ //------xx tile bank
+
+ tile_number += (attr&0x03)<<8;
+
+ SET_TILE_INFO(
+ 2,
+ tile_number,
+ (attr&0xfc)>>2,
+ 0);
+}
+
+VIDEO_START( sprcros2 )
+{
+ sprcros2_bgtilemap = tilemap_create( get_sprcros2_bgtile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+ sprcros2_fgtilemap = tilemap_create( get_sprcros2_fgtile_info,tilemap_scan_rows,TILEMAP_TYPE_COLORTABLE,8,8,32,32 );
+
+ tilemap_set_transparent_pen(sprcros2_fgtilemap,0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs,sx,sy,flipx,flipy;
+
+ for (offs = sprcros2_spriteram_size-4; offs >= 0; offs -= 4)
+ {
+ if(sprcros2_spriteram[offs])
+ {
+
+ //offs
+ //76543210
+ //x------- unused
+ //-xxxxxxx sprite number
+ //offs+1
+ //76543210
+ //xx------ unused
+ //--xxx--- colour (6/7 unused and blank in prom)
+ //-----x-- unused
+ //------x- flipx
+ //-------x unused
+ //offs+2 y pos
+ //offs+3 x pos
+
+ sx = ((sprcros2_spriteram[offs+3]+0x10)%0x100)-0x10;
+ sy = 225-(((sprcros2_spriteram[offs+2]+0x10)%0x100)-0x10);
+ flipx = sprcros2_spriteram[offs+1]&0x02;
+ flipy = 0;
+
+ if (sprcros2_m_port7&0x02)
+ {
+ sx = 224-sx;
+ sy = 224-sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ sprcros2_spriteram[offs],
+ (sprcros2_spriteram[offs+1]&0x38)>>3,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_COLOR,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( sprcros2 )
+{
+ tilemap_draw( bitmap,cliprect,sprcros2_bgtilemap,0,0 );
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw( bitmap,cliprect,sprcros2_fgtilemap,0,0 );
+ return 0;
+}
diff --git a/src/mame/video/sprint2.c b/src/mame/video/sprint2.c
new file mode 100644
index 00000000000..beedff217f2
--- /dev/null
+++ b/src/mame/video/sprint2.c
@@ -0,0 +1,196 @@
+/***************************************************************************
+
+ Atari Sprint 2 video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/sprint2.h"
+
+UINT8* sprint2_video_ram;
+
+static tilemap* bg_tilemap;
+static mame_bitmap* helper;
+
+static int collision[2];
+
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 code = sprint2_video_ram[tile_index];
+
+ SET_TILE_INFO(0, code & 0x3f, code >> 7, 0);
+}
+
+
+VIDEO_START( sprint2 )
+{
+ helper = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ bg_tilemap = tilemap_create(get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 8, 32, 32);
+}
+
+
+READ8_HANDLER( sprint2_collision1_r )
+{
+ return collision[0];
+}
+READ8_HANDLER( sprint2_collision2_r )
+{
+ return collision[1];
+}
+
+
+WRITE8_HANDLER( sprint2_collision_reset1_w )
+{
+ collision[0] = 0;
+}
+WRITE8_HANDLER( sprint2_collision_reset2_w )
+{
+ collision[1] = 0;
+}
+
+
+WRITE8_HANDLER( sprint2_video_ram_w )
+{
+ sprint2_video_ram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+static UINT8 collision_check(rectangle* rect)
+{
+ UINT8 data = 0;
+
+ int x;
+ int y;
+
+ for (y = rect->min_y; y <= rect->max_y; y++)
+ {
+ for (x = rect->min_x; x <= rect->max_x; x++)
+ {
+ pen_t a = *BITMAP_ADDR16(helper, y, x);
+
+ if (a == 0)
+ {
+ data |= 0x40;
+ }
+ if (a == 3)
+ {
+ data |= 0x80;
+ }
+ }
+ }
+
+ return data;
+}
+
+
+static int get_sprite_code(int n)
+{
+ return sprint2_video_ram[0x398 + 2 * n + 1] >> 3;
+}
+static int get_sprite_x(int n)
+{
+ return 2 * (248 - sprint2_video_ram[0x390 + 1 * n]);
+}
+static int get_sprite_y(int n)
+{
+ return 1 * (248 - sprint2_video_ram[0x398 + 2 * n]);
+}
+
+
+VIDEO_UPDATE( sprint2 )
+{
+ int i;
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* draw the sprites */
+
+ for (i = 0; i < 4; i++)
+ {
+ drawgfx(bitmap, machine->gfx[1],
+ get_sprite_code(i),
+ i,
+ 0, 0,
+ get_sprite_x(i),
+ get_sprite_y(i),
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+ return 0;
+}
+
+
+VIDEO_EOF( sprint2 )
+{
+ int i;
+ int j;
+
+ /*
+ * Collisions are detected for both player cars:
+ *
+ * D7 => collision w/ white playfield
+ * D6 => collision w/ black playfield or another car
+ *
+ */
+
+ for (i = 0; i < 2; i++)
+ {
+ rectangle rect;
+
+ rect.min_x = get_sprite_x(i);
+ rect.min_y = get_sprite_y(i);
+ rect.max_x = get_sprite_x(i) + machine->gfx[1]->width - 1;
+ rect.max_y = get_sprite_y(i) + machine->gfx[1]->height - 1;
+
+ if (rect.min_x < machine->screen[0].visarea.min_x)
+ rect.min_x = machine->screen[0].visarea.min_x;
+ if (rect.min_y < machine->screen[0].visarea.min_y)
+ rect.min_y = machine->screen[0].visarea.min_y;
+ if (rect.max_x > machine->screen[0].visarea.max_x)
+ rect.max_x = machine->screen[0].visarea.max_x;
+ if (rect.max_y > machine->screen[0].visarea.max_y)
+ rect.max_y = machine->screen[0].visarea.max_y;
+
+ /* check for sprite-tilemap collisions */
+
+ tilemap_draw(helper, &rect, bg_tilemap, 0, 0);
+
+ drawgfx(helper, machine->gfx[1],
+ get_sprite_code(i),
+ 0,
+ 0, 0,
+ get_sprite_x(i),
+ get_sprite_y(i),
+ &rect, TRANSPARENCY_PEN, 1);
+
+ collision[i] |= collision_check(&rect);
+
+ /* check for sprite-sprite collisions */
+
+ for (j = 0; j < 4; j++)
+ {
+ if (j != i)
+ {
+ drawgfx(helper, machine->gfx[1],
+ get_sprite_code(j),
+ 1,
+ 0, 0,
+ get_sprite_x(j),
+ get_sprite_y(j),
+ &rect, TRANSPARENCY_PEN, 0);
+ }
+ }
+
+ drawgfx(helper, machine->gfx[1],
+ get_sprite_code(i),
+ 0,
+ 0, 0,
+ get_sprite_x(i),
+ get_sprite_y(i),
+ &rect, TRANSPARENCY_PEN, 1);
+
+ collision[i] |= collision_check(&rect);
+ }
+}
diff --git a/src/mame/video/sprint4.c b/src/mame/video/sprint4.c
new file mode 100644
index 00000000000..c11722da52b
--- /dev/null
+++ b/src/mame/video/sprint4.c
@@ -0,0 +1,163 @@
+/***************************************************************************
+
+Atari Sprint 4 video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "audio/sprint4.h"
+
+static tilemap* playfield;
+
+static mame_bitmap* helper;
+
+int sprint4_collision[4];
+
+
+PALETTE_INIT( sprint4 )
+{
+ palette_set_color(machine, 0, MAKE_RGB(0x00, 0x00, 0x00)); /* black */
+ palette_set_color(machine, 1, MAKE_RGB(0xfc, 0xdf, 0x80)); /* peach */
+ palette_set_color(machine, 2, MAKE_RGB(0xf0, 0x00, 0xf0)); /* violet */
+ palette_set_color(machine, 3, MAKE_RGB(0x00, 0xf0, 0x0f)); /* green */
+ palette_set_color(machine, 4, MAKE_RGB(0x30, 0x4f, 0xff)); /* blue */
+ palette_set_color(machine, 5, MAKE_RGB(0xff, 0xff, 0xff)); /* white */
+
+ colortable[0] = 0;
+ colortable[2] = 0;
+ colortable[4] = 0;
+ colortable[6] = 0;
+ colortable[8] = 0;
+
+ colortable[1] = 1;
+ colortable[3] = 2;
+ colortable[5] = 3;
+ colortable[7] = 4;
+ colortable[9] = 5;
+}
+
+
+static TILE_GET_INFO( sprint4_tile_info )
+{
+ UINT8 code = videoram[tile_index];
+
+ if ((code & 0x30) == 0x30)
+ {
+ SET_TILE_INFO(0, code & ~0x40, (code >> 6) ^ 3, 0);
+ }
+ else
+ {
+ SET_TILE_INFO(0, code, 4, 0);
+ }
+}
+
+
+VIDEO_START( sprint4 )
+{
+ helper = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ playfield = tilemap_create(sprint4_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+
+VIDEO_UPDATE( sprint4 )
+{
+ int i;
+
+ tilemap_draw(bitmap, cliprect, playfield, 0, 0);
+
+ for (i = 0; i < 4; i++)
+ {
+ int bank = 0;
+
+ UINT8 horz = videoram[0x390 + 2 * i + 0];
+ UINT8 attr = videoram[0x390 + 2 * i + 1];
+ UINT8 vert = videoram[0x398 + 2 * i + 0];
+ UINT8 code = videoram[0x398 + 2 * i + 1];
+
+ if (i & 1)
+ {
+ bank = 32;
+ }
+
+ drawgfx(bitmap, machine->gfx[1],
+ (code >> 3) | bank,
+ (attr & 0x80) ? 4 : i,
+ 0, 0,
+ horz - 15,
+ vert - 15,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+ return 0;
+}
+
+
+VIDEO_EOF( sprint4 )
+{
+ UINT16 BG = machine->remapped_colortable[machine->gfx[0]->color_base];
+
+ int i;
+
+ /* check for sprite-playfield collisions */
+
+ for (i = 0; i < 4; i++)
+ {
+ rectangle rect;
+
+ int x;
+ int y;
+
+ int bank = 0;
+
+ UINT8 horz = videoram[0x390 + 2 * i + 0];
+ UINT8 vert = videoram[0x398 + 2 * i + 0];
+ UINT8 code = videoram[0x398 + 2 * i + 1];
+
+ rect.min_x = horz - 15;
+ rect.min_y = vert - 15;
+ rect.max_x = horz - 15 + machine->gfx[1]->width - 1;
+ rect.max_y = vert - 15 + machine->gfx[1]->height - 1;
+
+ sect_rect(&rect, &machine->screen[0].visarea);
+
+ tilemap_draw(helper, &rect, playfield, 0, 0);
+
+ if (i & 1)
+ {
+ bank = 32;
+ }
+
+ drawgfx(helper, machine->gfx[1],
+ (code >> 3) | bank,
+ 4,
+ 0, 0,
+ horz - 15,
+ vert - 15,
+ &rect, TRANSPARENCY_PEN, 1);
+
+ for (y = rect.min_y; y <= rect.max_y; y++)
+ {
+ for (x = rect.min_x; x <= rect.max_x; x++)
+ {
+ if (*BITMAP_ADDR16(helper, y, x) != BG)
+ {
+ sprint4_collision[i] = 1;
+ }
+ }
+ }
+ }
+
+ /* update sound status */
+
+ discrete_sound_w(SPRINT4_MOTOR_DATA_1, videoram[0x391] & 15);
+ discrete_sound_w(SPRINT4_MOTOR_DATA_2, videoram[0x393] & 15);
+ discrete_sound_w(SPRINT4_MOTOR_DATA_3, videoram[0x395] & 15);
+ discrete_sound_w(SPRINT4_MOTOR_DATA_4, videoram[0x397] & 15);
+}
+
+
+WRITE8_HANDLER( sprint4_video_ram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(playfield, offset);
+}
diff --git a/src/mame/video/sprint8.c b/src/mame/video/sprint8.c
new file mode 100644
index 00000000000..a0035091cab
--- /dev/null
+++ b/src/mame/video/sprint8.c
@@ -0,0 +1,157 @@
+/***************************************************************************
+
+Atari Sprint 8 video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/sprint8.h"
+
+UINT8* sprint8_video_ram;
+UINT8* sprint8_pos_h_ram;
+UINT8* sprint8_pos_v_ram;
+UINT8* sprint8_pos_d_ram;
+
+static tilemap* tilemap1;
+static tilemap* tilemap2;
+
+static mame_bitmap* helper1;
+static mame_bitmap* helper2;
+
+
+static TILE_GET_INFO( get_tile_info1 )
+{
+ UINT8 code = sprint8_video_ram[tile_index];
+
+ int color = 0;
+
+ if ((code & 0x30) != 0x30) /* ? */
+ {
+ color = 17;
+ }
+ else
+ {
+ if ((tile_index + 1) & 0x010)
+ {
+ color |= 1;
+ }
+ if (code & 0x80)
+ {
+ color |= 2;
+ }
+ if (tile_index & 0x200)
+ {
+ color |= 4;
+ }
+ }
+
+ SET_TILE_INFO(code >> 7, code, color, (code & 0x40) ? (TILE_FLIPX | TILE_FLIPY) : 0);
+}
+
+
+static TILE_GET_INFO( get_tile_info2 )
+{
+ UINT8 code = sprint8_video_ram[tile_index];
+
+ int color = 0;
+
+ if ((code & 0x38) != 0x28)
+ {
+ color = 16;
+ }
+ else
+ {
+ color = 17;
+ }
+
+ SET_TILE_INFO(code >> 7, code, color, (code & 0x40) ? (TILE_FLIPX | TILE_FLIPY) : 0);
+}
+
+
+WRITE8_HANDLER( sprint8_video_ram_w )
+{
+ sprint8_video_ram[offset] = data;
+ tilemap_mark_tile_dirty(tilemap1, offset);
+ tilemap_mark_tile_dirty(tilemap2, offset);
+}
+
+
+VIDEO_START( sprint8 )
+{
+ helper1 = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ helper2 = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ tilemap1 = tilemap_create(get_tile_info1, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 8, 32, 32);
+ tilemap2 = tilemap_create(get_tile_info2, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 8, 32, 32);
+
+ tilemap_set_scrolly(tilemap1, 0, +24);
+ tilemap_set_scrolly(tilemap2, 0, +24);
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap* bitmap, const rectangle *cliprect)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ {
+ UINT8 code = sprint8_pos_d_ram[i];
+
+ int x = sprint8_pos_h_ram[i];
+ int y = sprint8_pos_v_ram[i];
+
+ if (code & 0x80)
+ {
+ x |= 0x100;
+ }
+
+ drawgfx(bitmap, machine->gfx[2],
+ code ^ 7,
+ i,
+ !(code & 0x10), !(code & 0x08),
+ 496 - x, y - 31,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+
+static TIMER_CALLBACK( sprint8_collision_callback )
+{
+ sprint8_set_collision(param);
+}
+
+
+VIDEO_UPDATE( sprint8 )
+{
+ tilemap_draw(bitmap, cliprect, tilemap1, 0, 0);
+
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
+
+
+VIDEO_EOF( sprint8 )
+{
+ int x;
+ int y;
+
+ tilemap_draw(helper2, &machine->screen[0].visarea, tilemap2, 0, 0);
+
+ fillbitmap(helper1, 16, &machine->screen[0].visarea);
+
+ draw_sprites(machine, helper1, &machine->screen[0].visarea);
+
+ for (y = machine->screen[0].visarea.min_y; y <= machine->screen[0].visarea.max_y; y++)
+ {
+ const UINT16* p1 = BITMAP_ADDR16(helper1, y, 0);
+ const UINT16* p2 = BITMAP_ADDR16(helper2, y, 0);
+
+ for (x = machine->screen[0].visarea.min_x; x <= machine->screen[0].visarea.max_x; x++)
+ {
+ if (p1[x] != 16 && p2[x] != 16)
+ {
+ timer_set(video_screen_get_time_until_pos(0, y + 24, x), p1[x], sprint8_collision_callback);
+ }
+ }
+ }
+}
diff --git a/src/mame/video/spy.c b/src/mame/video/spy.c
new file mode 100644
index 00000000000..58a7b84164a
--- /dev/null
+++ b/src/mame/video/spy.c
@@ -0,0 +1,84 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+int spy_video_enable;
+
+static int layer_colorbase[3],sprite_colorbase;
+
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ *flags = (*color & 0x20) ? TILE_FLIPX : 0;
+ *code |= ((*color & 0x03) << 8) | ((*color & 0x10) << 6) | ((*color & 0x0c) << 9)
+ | (bank << 13);
+ *color = layer_colorbase[layer] + ((*color & 0xc0) >> 6);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051960
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority_mask,int *shadow)
+{
+ /* bit 4 = priority over layer A (0 = have priority) */
+ /* bit 5 = priority over layer B (1 = have priority) */
+ *priority_mask = 0x00;
+ if ( *color & 0x10) *priority_mask |= 0xa;
+ if (~*color & 0x20) *priority_mask |= 0xc;
+
+ *color = sprite_colorbase + (*color & 0x0f);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( spy )
+{
+ layer_colorbase[0] = 48;
+ layer_colorbase[1] = 0;
+ layer_colorbase[2] = 16;
+ sprite_colorbase = 32;
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,NORMAL_PLANE_ORDER,sprite_callback);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( spy )
+{
+ K052109_tilemap_update();
+
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ if (!spy_video_enable)
+ {
+ fillbitmap(bitmap,machine->pens[16 * layer_colorbase[0]],cliprect);
+ return 0;
+ }
+
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],TILEMAP_DRAW_OPAQUE,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],0,2);
+ K051960_sprites_draw(bitmap,cliprect,-1,-1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],0,0);
+ return 0;
+}
diff --git a/src/mame/video/srmp2.c b/src/mame/video/srmp2.c
new file mode 100644
index 00000000000..30f25c970ec
--- /dev/null
+++ b/src/mame/video/srmp2.c
@@ -0,0 +1,462 @@
+/***************************************************************************
+
+Functions to emulate the video hardware of the machine.
+
+ Video hardware is very similar with "seta" hardware except color PROM.
+
+***************************************************************************/
+
+
+#include "driver.h"
+
+
+
+
+int srmp2_color_bank;
+int srmp3_gfx_bank;
+int mjyuugi_gfx_bank;
+
+
+PALETTE_INIT( srmp2 )
+{
+ int i;
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int col;
+
+ col = (color_prom[i] << 8) + color_prom[i + machine->drv->total_colors];
+
+ palette_set_color_rgb(machine,i,pal5bit(col >> 10),pal5bit(col >> 5),pal5bit(col >> 0));
+ }
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ colortable[i] = i ^ 0x0f;
+ }
+}
+
+
+PALETTE_INIT( srmp3 )
+{
+ int i;
+
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int col;
+
+ col = (color_prom[i] << 8) + color_prom[i + machine->drv->total_colors];
+ palette_set_color_rgb(machine,i,pal5bit(col >> 10),pal5bit(col >> 5),pal5bit(col >> 0));
+ }
+}
+
+
+static void srmp2_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+/*
+ Sprite RAM A: spriteram16_2
+ ==============
+ + 0x000 - 0x3ff
+ x--- ---- ---- ---- : Flip X
+ -x-- ---- ---- ---- : Flip Y
+ --xx xxxx xxxx xxxx : Tile number
+
+ + 0x400 - 0x7ff
+ xxxx x--- ---- ---- : Color
+ ---- ---x xxxx xxxx : X coords
+
+ Sprite RAM B: spriteram16
+ ==============
+ + 0x000 - 0x3ff
+ ---- ---- xxxx xxxx : Y coords
+
+ + 0x600
+ ---- ---- -x-- ---- : Flip screen
+*/
+
+ int offs;
+ int xoffs, yoffs;
+
+ int ctrl = spriteram16[ 0x600/2 ];
+ int ctrl2 = spriteram16[ 0x602/2 ];
+
+ int flip = ctrl & 0x40;
+
+ /* Sprites Banking and/or Sprites Buffering */
+ UINT16 *src = spriteram16_2 + ( ((ctrl2 ^ (~ctrl2<<1)) & 0x40) ? 0x2000/2 : 0 );
+
+ int max_y = machine -> screen[0].height;
+
+ xoffs = flip ? 0x10 : 0x10;
+ yoffs = flip ? 0x05 : 0x07;
+
+ for (offs = (0x400-2)/2; offs >= 0/2; offs -= 2/2)
+ {
+ int code = src[offs + 0x000/2];
+
+ int x = src[offs + 0x400/2];
+ int y = spriteram16[offs + 0x000/2] & 0xff;
+
+ int flipx = code & 0x8000;
+ int flipy = code & 0x4000;
+
+ int color = (x >> 11) & 0x1f;
+
+ if (flip)
+ {
+ y = max_y - y;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ code = code & 0x3fff;
+
+ if (srmp2_color_bank) color |= 0x20;
+
+ drawgfx(bitmap, machine->gfx[0],
+ code,
+ color,
+ flipx, flipy,
+ (x + xoffs) & 0x1ff,
+ max_y - ((y + yoffs) & 0x0ff),
+ cliprect, TRANSPARENCY_PEN, 15);
+ }
+}
+
+
+static void srmp3_draw_sprites_map(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs, col;
+ int xoffs, yoffs;
+
+ int ctrl = spriteram[ 0x600/2 ];
+ int ctrl2 = spriteram[ 0x602/2 ];
+
+ int flip = ctrl & 0x40;
+ int numcol = ctrl2 & 0x0f;
+
+ int upper = ( spriteram[ 0x604/2 ] & 0xFF ) +
+ ( spriteram[ 0x606/2 ] & 0xFF ) * 256;
+
+ int max_y = 0xf0;
+
+ xoffs = flip ? 0x10 : 0x10;
+ yoffs = flip ? -0x01 : -0x01;
+
+ /* Number of columns to draw - the value 1 seems special, meaning:
+ draw every column */
+ if (numcol == 1) numcol = 16;
+
+ /* The first column is the frontmost, see twineagl test mode */
+ for (col = numcol - 1; col >= 0; col--)
+ {
+ int x = spriteram[(col * 0x20 + 0x08 + 0x400)/2] & 0xff;
+ int y = spriteram[(col * 0x20 + 0x00 + 0x400)/2] & 0xff;
+
+ /* draw this column */
+ for (offs = 0; offs < 0x40/2; offs += 2/2)
+ {
+ int code = (((spriteram_3[((col)&0x0f) * 0x40/2 + offs + 0x800/2] & 0xff) << 8) + (spriteram_2[((col)&0xf) * 0x40/2 + offs + 0x800/2] & 0xff));
+
+ int color = ((spriteram_3[((col)&0x0f) * 0x40/2 + offs + 0xc00/2] & 0xf8) >> 3);
+
+ int flipx = code & 0x8000;
+ int flipy = code & 0x4000;
+
+ int sx = x + xoffs + (offs & 1) * 16;
+ int sy = -(y + yoffs) + (offs / 2) * 16 -
+ (machine->screen[0].height-(machine->screen[0].visarea.max_y + 1));
+
+ if (upper & (1 << col)) sx += 256;
+
+ if (flip)
+ {
+ sy = max_y - 14 - sy - 0x100;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ code = code & 0x1fff;
+
+#define DRAWTILE(_x_, _y_) \
+ drawgfx(bitmap, machine->gfx[0], \
+ code, \
+ color, \
+ flipx, flipy, \
+ _x_, _y_, \
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ DRAWTILE(sx - 0x000, sy + 0x000)
+ DRAWTILE(sx - 0x200, sy + 0x000)
+ DRAWTILE(sx - 0x000, sy + 0x100)
+ DRAWTILE(sx - 0x200, sy + 0x100)
+
+ }
+ /* next column */
+ }
+}
+
+
+static void srmp3_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+/*
+ Sprite RAM A: spriteram_2
+ ==============
+ + 0x000 - 0x1ff
+ xxxx xxxx : Tile number (low)
+
+ + 0x200 - 0x3ff
+ ---- ---- : Color
+ xxxx xxxx : X coords (low)
+
+
+ Sprite RAM B: spriteram_3
+ ==============
+ + 0x000 - 0x1ff
+ x--- ---- : Flip X ?
+ -x-- ---- : Flip Y ?
+ --x- ---- : Use GFX bank flag
+ ---x xxxx : Tile number (high)
+
+ + 0x200 - 0x3ff
+ xxxx x--- : Color
+ ---- ---x : X coords (high)
+
+
+ Sprite RAM C: spriteram
+ ==============
+ + 0x000 - 0x1ff
+ xxxx xxxx : Y coords (low)
+
+ + 0x300
+ -x-- ---- : Flip screen
+*/
+
+ int offs;
+ int xoffs, yoffs;
+
+ int max_y = machine -> screen[0].height;
+
+ int ctrl = spriteram[ 0x600/2 ];
+// int ctrl2 = spriteram[ 0x602/2 ];
+
+ int flip = ctrl & 0x40;
+
+ srmp3_draw_sprites_map(machine, bitmap, cliprect);
+
+ xoffs = flip ? 0x10 : 0x10;
+ yoffs = flip ? 0x06 : 0x06;
+
+ for (offs = 0x200 - 1; offs >= 0; offs--)
+ {
+ int code = (((spriteram_3[offs + 0x000] & 0xff) << 8) + (spriteram_2[offs + 0x000] & 0xff));
+ int gfxbank = (spriteram_3[offs + 0x000] & 0x20);
+
+ int color = ((spriteram_3[offs + 0x200] & 0xf8) >> 3);
+
+ int x = (((spriteram_3[offs + 0x200] & 0x01) << 8) + (spriteram_2[offs + 0x200] & 0xff));
+ int y = (spriteram[offs + 0x000] & 0xff);
+
+ int flipx = code & 0x8000;
+ int flipy = code & 0x4000;
+
+ code = (code & 0x1fff);
+ if (gfxbank) code += ((srmp3_gfx_bank + 1) * 0x2000);
+
+ if (flip)
+ {
+ y = max_y - y;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx, flipy,
+ (x + xoffs) & 0x1ff,
+ max_y - ((y + yoffs) & 0x0ff),
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+
+static void mjyuugi_draw_sprites_map(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs, col;
+ int xoffs, yoffs;
+
+ int total_color_codes = machine->drv->gfxdecodeinfo[0].total_color_codes;
+
+ int ctrl = spriteram16[ 0x600/2 ];
+ int ctrl2 = spriteram16[ 0x602/2 ];
+
+ int flip = ctrl & 0x40;
+ int numcol = ctrl2 & 0x000f;
+
+ /* Sprites Banking and/or Sprites Buffering */
+ UINT16 *src = spriteram16_2 + ( ((ctrl2 ^ (~ctrl2<<1)) & 0x40) ? 0x2000/2 : 0 );
+
+ int upper = ( spriteram16[ 0x604/2 ] & 0xFF ) +
+ ( spriteram16[ 0x606/2 ] & 0xFF ) * 256;
+
+ int max_y = 0xf0;
+
+ xoffs = flip ? 0x10 : 0x10;
+ yoffs = flip ? 0x09 : 0x07;
+
+ /* Number of columns to draw - the value 1 seems special, meaning:
+ draw every column */
+ if (numcol == 1) numcol = 16;
+
+ /* The first column is the frontmost, see twineagl test mode */
+ for (col = numcol - 1; col >= 0; col--)
+ {
+ int x = spriteram16[(col * 0x20 + 0x08 + 0x400)/2] & 0xff;
+ int y = spriteram16[(col * 0x20 + 0x00 + 0x400)/2] & 0xff;
+
+ /* draw this column */
+ for (offs = 0; offs < 0x40/2; offs += 2/2)
+ {
+ int code = src[((col)&0xf) * 0x40/2 + offs + 0x800/2];
+ int color = src[((col)&0xf) * 0x40/2 + offs + 0xc00/2];
+
+ int gfxbank = color & 0x0200;
+
+ int flipx = code & 0x8000;
+ int flipy = code & 0x4000;
+
+ int sx = x + xoffs + (offs & 1) * 16;
+ int sy = -(y + yoffs) + (offs / 2) * 16 -
+ (machine->screen[0].height-(machine->screen[0].visarea.max_y + 1));
+
+ if (upper & (1 << col)) sx += 256;
+
+ if (flip)
+ {
+ sy = max_y - 16 - sy - 0x100;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ color = ((color >> (16-5)) % total_color_codes);
+ code = (code & 0x3fff) + (gfxbank ? 0x4000 : 0);
+
+#define DRAWTILE(_x_, _y_) \
+ drawgfx(bitmap, machine->gfx[0], \
+ code, \
+ color, \
+ flipx, flipy, \
+ _x_, _y_, \
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ DRAWTILE(sx - 0x000, sy + 0x000)
+ DRAWTILE(sx - 0x200, sy + 0x000)
+ DRAWTILE(sx - 0x000, sy + 0x100)
+ DRAWTILE(sx - 0x200, sy + 0x100)
+
+ }
+ /* next column */
+ }
+}
+
+
+static void mjyuugi_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+/*
+ Sprite RAM A: spriteram16_2
+ ==============
+ + 0x000 - 0x3ff
+ x--- ---- ---- ---- : Flip X
+ -x-- ---- ---- ---- : Flip Y
+ --x- ---- ---- ---- : Use GFX bank flag
+ ---x xxxx xxxx xxxx : Tile number
+
+ + 0x400 - 0x7ff
+ xxxx x--- ---- ---- : Color
+ ---- ---x xxxx xxxx : X coords
+
+ Sprite RAM B: spriteram16
+ ==============
+ + 0x000 - 0x3ff
+ ---- ---- xxxx xxxx : Y coords
+
+ + 0x600
+ ---- ---- -x-- ---- : Flip screen
+*/
+
+ int offs;
+ int xoffs, yoffs;
+
+ int ctrl = spriteram16[ 0x600/2 ];
+ int ctrl2 = spriteram16[ 0x602/2 ];
+
+ int flip = ctrl & 0x40;
+
+ /* Sprites Banking and/or Sprites Buffering */
+ UINT16 *src = spriteram16_2 + ( ((ctrl2 ^ (~ctrl2<<1)) & 0x40) ? 0x2000/2 : 0 );
+
+ int max_y = machine -> screen[0].height;
+
+ mjyuugi_draw_sprites_map(machine, bitmap, cliprect);
+
+ xoffs = flip ? 0x10 : 0x10;
+ yoffs = flip ? 0x06 : 0x06;
+
+ for (offs = (0x400 - 6) / 2; offs >= 0 / 2; offs -= 2 / 2)
+ {
+ int code = src[offs + 0x000 / 2];
+ int gfxbank = code & 0x2000;
+
+ int color = ((src[offs + 0x400 / 2] >> 11) & 0x1f);
+
+ int x = (src[offs + 0x400 / 2] & 0x1ff);
+ int y = (spriteram16[offs + 0x000 / 2] & 0xff);
+
+ int flipx = code & 0x8000;
+ int flipy = code & 0x4000;
+
+ code = (code & 0x1fff);
+ if (gfxbank) code += ((mjyuugi_gfx_bank + 1) * 0x2000);
+
+ if (flip)
+ {
+ y = max_y - y
+ +(machine->screen[0].height-(machine->screen[0].visarea.max_y + 1));
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx, flipy,
+ (x + xoffs) & 0x1ff,
+ max_y - ((y + yoffs) & 0x0ff),
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+
+VIDEO_UPDATE( srmp2 )
+{
+ fillbitmap(bitmap, machine->pens[0x1f0], cliprect);
+ srmp2_draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
+
+
+VIDEO_UPDATE( srmp3 )
+{
+ fillbitmap(bitmap, machine->pens[0x1f0], cliprect);
+ srmp3_draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
+
+
+VIDEO_UPDATE( mjyuugi )
+{
+ fillbitmap(bitmap, machine->pens[0x1f0], cliprect);
+ mjyuugi_draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/srumbler.c b/src/mame/video/srumbler.c
new file mode 100644
index 00000000000..6720bc3f9fe
--- /dev/null
+++ b/src/mame/video/srumbler.c
@@ -0,0 +1,174 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *srumbler_backgroundram,*srumbler_foregroundram;
+static tilemap *bg_tilemap,*fg_tilemap;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 attr = srumbler_foregroundram[2*tile_index];
+ SET_TILE_INFO(
+ 0,
+ srumbler_foregroundram[2*tile_index + 1] + ((attr & 0x03) << 8),
+ (attr & 0x3c) >> 2,
+ (attr & 0x40) ? TILE_FORCE_LAYER0 : 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 attr = srumbler_backgroundram[2*tile_index];
+ SET_TILE_INFO(
+ 1,
+ srumbler_backgroundram[2*tile_index + 1] + ((attr & 0x07) << 8),
+ (attr & 0xe0) >> 5,
+ ((attr & 0x08) ? TILE_FLIPY : 0));
+ tileinfo->group = (attr & 0x10) >> 4;
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( srumbler )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,64,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 16,16,64,64);
+
+ tilemap_set_transparent_pen(fg_tilemap,3);
+
+ tilemap_set_transmask(bg_tilemap,0,0xffff,0x0000); /* split type 0 is totally transparent in front half */
+ tilemap_set_transmask(bg_tilemap,1,0x07ff,0xf800); /* split type 1 has pens 0-10 transparent in front half */
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( srumbler_foreground_w )
+{
+ srumbler_foregroundram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset/2);
+}
+
+WRITE8_HANDLER( srumbler_background_w )
+{
+ srumbler_backgroundram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+
+WRITE8_HANDLER( srumbler_4009_w )
+{
+ /* bit 0 flips screen */
+ flip_screen_set(data & 1);
+
+ /* bits 4-5 used during attract mode, unknown */
+
+ /* bits 6-7 coin counters */
+ coin_counter_w(0,data & 0x40);
+ coin_counter_w(1,data & 0x80);
+}
+
+
+WRITE8_HANDLER( srumbler_scroll_w )
+{
+ static int scroll[4];
+
+ scroll[offset] = data;
+
+ tilemap_set_scrollx(bg_tilemap,0,scroll[0] | (scroll[1] << 8));
+ tilemap_set_scrolly(bg_tilemap,0,scroll[2] | (scroll[3] << 8));
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ /* Draw the sprites. */
+ for (offs = spriteram_size-4; offs>=0;offs -= 4)
+ {
+ /* SPRITES
+ =====
+ Attribute
+ 0x80 Code MSB
+ 0x40 Code MSB
+ 0x20 Code MSB
+ 0x10 Colour
+ 0x08 Colour
+ 0x04 Colour
+ 0x02 y Flip
+ 0x01 X MSB
+ */
+
+
+ int code,colour,sx,sy,flipy;
+ int attr = buffered_spriteram[offs+1];
+ code = buffered_spriteram[offs];
+ code += ( (attr&0xe0) << 3 );
+ colour = (attr & 0x1c)>>2;
+ sy = buffered_spriteram[offs + 2];
+ sx = buffered_spriteram[offs + 3] + 0x100 * ( attr & 0x01);
+ flipy = attr & 0x02;
+
+ if (flip_screen)
+ {
+ sx = 496 - sx;
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ colour,
+ flip_screen,flipy,
+ sx, sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+
+VIDEO_UPDATE( srumbler )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_EOF( srumbler )
+{
+ buffer_spriteram_w(0,0);
+}
diff --git a/src/mame/video/sshangha.c b/src/mame/video/sshangha.c
new file mode 100644
index 00000000000..d5b14e07156
--- /dev/null
+++ b/src/mame/video/sshangha.c
@@ -0,0 +1,258 @@
+/***************************************************************************
+
+ Uses Data East custom chip 55 for backgrounds, with a special 8bpp mode
+ 2 times custom chips 52/71 for sprites.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *sshangha_pf2_data,*sshangha_pf1_data;
+UINT16 *sshangha_pf1_rowscroll,*sshangha_pf2_rowscroll;
+static UINT16 sshangha_control_0[8];
+static tilemap *pf1_8x8_tilemap,*pf1_16x16_tilemap,*pf2_tilemap;
+static int sshangha_pf1_bank,sshangha_pf2_bank,sshangha_video_control;
+
+/******************************************************************************/
+
+WRITE16_HANDLER( sshangha_palette_24bit_w )
+{
+ int r,g,b;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ if (offset&1) offset--;
+
+ b = (paletteram16[offset] >> 0) & 0xff;
+ g = (paletteram16[offset+1] >> 8) & 0xff;
+ r = (paletteram16[offset+1] >> 0) & 0xff;
+
+ palette_set_color(Machine,offset/2,MAKE_RGB(r,g,b));
+}
+
+static void sshangha_tilemap_draw(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const mame_bitmap *bitmap0 = tilemap_get_pixmap(pf1_16x16_tilemap);
+ const mame_bitmap *bitmap1 = tilemap_get_pixmap(pf2_tilemap);
+ int x,y,p;
+
+ for (y=0; y<240; y++) {
+ for (x=0; x<320; x++) {
+ p=*BITMAP_ADDR16(bitmap0, y, x)&0xf;
+ p|=(*BITMAP_ADDR16(bitmap1, y, x)&0xf)<<4;
+
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[p|0x300];
+ }
+ }
+}
+
+WRITE16_HANDLER (sshangha_video_w)
+{
+ /* 0x4: Special video mode, other bits unknown */
+ sshangha_video_control=data;
+// popmessage("%04x",data);
+}
+
+/******************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT16 *spritesrc, UINT16 pmask, UINT16 pval)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x800;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ sprite = spritesrc[offs+1] & 0x3fff;
+ if (!sprite) continue;
+
+ if ((spritesrc[offs+2]&pmask)!=pval)
+ continue;
+
+ y = spritesrc[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ x = spritesrc[offs+2];
+ colour = (x >>9) & 0x1f;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+
+ sprite &= ~multi;
+
+ if (flip_screen)
+ {
+ y=240-y;
+ x=304-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=-16;
+ }
+
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ mult=+16;
+
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ multi--;
+ }
+ }
+}
+
+/******************************************************************************/
+
+WRITE16_HANDLER( sshangha_pf2_data_w )
+{
+ COMBINE_DATA(&sshangha_pf2_data[offset]);
+ tilemap_mark_tile_dirty(pf2_tilemap,offset);
+}
+
+WRITE16_HANDLER( sshangha_pf1_data_w )
+{
+ COMBINE_DATA(&sshangha_pf1_data[offset]);
+ tilemap_mark_tile_dirty(pf1_8x8_tilemap,offset);
+ tilemap_mark_tile_dirty(pf1_16x16_tilemap,offset);
+}
+
+WRITE16_HANDLER( sshangha_control_0_w )
+{
+ COMBINE_DATA(&sshangha_control_0[offset]);
+}
+
+/******************************************************************************/
+
+#if 0
+static UINT32 sshangha_scan(UINT32 col,UINT32 row,UINT32 num_cols,UINT32 num_rows)
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x20) << 5);
+}
+#endif
+
+static TILE_GET_INFO( get_pf2_tile_info )
+{
+ UINT16 tile=sshangha_pf2_data[tile_index];
+ SET_TILE_INFO(1,(tile&0xfff)|sshangha_pf2_bank,(tile>>12)|32,0);
+}
+
+static TILE_GET_INFO( get_pf1_16x16_tile_info )
+{
+ UINT16 tile=sshangha_pf1_data[tile_index];
+ SET_TILE_INFO(1,(tile&0xfff)|sshangha_pf1_bank,tile>>12,0);
+}
+
+static TILE_GET_INFO( get_pf1_8x8_tile_info )
+{
+ UINT16 tile=sshangha_pf1_data[tile_index];
+ SET_TILE_INFO(0,(tile&0xfff)|sshangha_pf1_bank,tile>>12,0);
+}
+
+VIDEO_START( sshangha )
+{
+ pf1_8x8_tilemap = tilemap_create(get_pf1_8x8_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ pf1_16x16_tilemap = tilemap_create(get_pf1_16x16_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ pf2_tilemap = tilemap_create(get_pf2_tile_info,tilemap_scan_rows, TILEMAP_TYPE_PEN, 16,16,32,32);
+
+ tilemap_set_transparent_pen(pf1_8x8_tilemap,0);
+ tilemap_set_transparent_pen(pf1_16x16_tilemap,0);
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( sshangha )
+{
+ static int last_pf1_bank,last_pf2_bank;
+ int offs;
+
+ flip_screen=sshangha_control_0[0]&0x80;
+ tilemap_set_flip(ALL_TILEMAPS,flip_screen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ tilemap_set_enable( pf2_tilemap, sshangha_control_0[5]&0x8000);
+ tilemap_set_enable( pf1_8x8_tilemap, sshangha_control_0[5]&0x0080);
+ tilemap_set_enable( pf1_16x16_tilemap, sshangha_control_0[5]&0x0080);
+
+ sshangha_pf1_bank=((sshangha_control_0[7]>> 4)&0xf)*0x1000;
+ sshangha_pf2_bank=((sshangha_control_0[7]>>12)&0xf)*0x1000;
+
+ if (sshangha_pf1_bank!=last_pf1_bank) tilemap_mark_all_tiles_dirty(pf1_8x8_tilemap);
+ if (sshangha_pf1_bank!=last_pf1_bank) tilemap_mark_all_tiles_dirty(pf1_16x16_tilemap);
+ if (sshangha_pf2_bank!=last_pf2_bank) tilemap_mark_all_tiles_dirty(pf2_tilemap);
+ last_pf1_bank=sshangha_pf1_bank;
+ last_pf2_bank=sshangha_pf2_bank;
+
+ /* Rowscroll - todo, this might actually be col scroll, or both row & col combined. Check.. */
+ if (sshangha_control_0[6]&0x40) {
+ tilemap_set_scroll_rows(pf1_8x8_tilemap,256);
+ tilemap_set_scroll_rows(pf1_16x16_tilemap,256);
+ for (offs=0; offs<256; offs++) {
+ tilemap_set_scrollx( pf1_8x8_tilemap,0, sshangha_control_0[1] + sshangha_pf1_rowscroll[offs+0x200] );
+ tilemap_set_scrollx( pf1_16x16_tilemap,0, sshangha_control_0[1] + sshangha_pf1_rowscroll[offs+0x200] );
+ }
+ } else {
+ tilemap_set_scroll_rows(pf1_16x16_tilemap,1);
+ tilemap_set_scroll_rows(pf1_8x8_tilemap,1);
+ tilemap_set_scrollx( pf1_8x8_tilemap,0, sshangha_control_0[1] );
+ tilemap_set_scrollx( pf1_16x16_tilemap,0, sshangha_control_0[1] );
+ }
+
+ if (sshangha_control_0[6]&0x4000) {
+ tilemap_set_scroll_rows(pf2_tilemap,256);
+ for (offs=0; offs<256; offs++) {
+ tilemap_set_scrollx( pf2_tilemap,0, sshangha_control_0[3] - 3 + sshangha_pf2_rowscroll[offs+0x200] );
+ }
+ } else {
+ tilemap_set_scroll_rows(pf2_tilemap,1);
+ tilemap_set_scrollx( pf2_tilemap,0, sshangha_control_0[3] - 3 );
+ }
+
+ tilemap_set_scrolly( pf2_tilemap,0, sshangha_control_0[4] );
+ tilemap_set_scrolly( pf1_8x8_tilemap,0, sshangha_control_0[2] );
+ tilemap_set_scrolly( pf1_16x16_tilemap,0, sshangha_control_0[2] );
+
+ if ((sshangha_control_0[5]&0x8000)==0)
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ /* Super Shanghai has a mode where the two tilemaps are combined to
+ produce a 6bpp tilemap. We can't precompute this as any tiles can be
+ used in any tilemap, so we plot it on the fly */
+ if ((sshangha_video_control&4)==0) {
+ sshangha_tilemap_draw(machine, bitmap, cliprect);
+ draw_sprites(machine, bitmap, cliprect, spriteram16,0x4000,0x4000);
+ }
+ else {
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ draw_sprites(machine, bitmap, cliprect, spriteram16,0x4000,0x4000);
+
+ if (sshangha_control_0[6]&0x80)
+ tilemap_draw(bitmap,cliprect,pf1_8x8_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1_16x16_tilemap,0,0);
+ }
+
+ draw_sprites(machine, bitmap, cliprect, spriteram16_2,0x0000,0x0000);
+ draw_sprites(machine, bitmap, cliprect, spriteram16,0x4000,0x0000);
+ return 0;
+}
diff --git a/src/mame/video/sslam.c b/src/mame/video/sslam.c
new file mode 100644
index 00000000000..8bad894b988
--- /dev/null
+++ b/src/mame/video/sslam.c
@@ -0,0 +1,216 @@
+/* Super Slam - Video Hardware */
+
+#include "driver.h"
+
+static tilemap *sslam_bg_tilemap, *sslam_tx_tilemap, *sslam_md_tilemap;
+
+extern UINT16 *sslam_bg_tileram, *sslam_tx_tileram, *sslam_md_tileram;
+extern UINT16 *sslam_spriteram, *sslam_regs;
+
+static int sprites_x_offset;
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const gfx_element *gfx = machine->gfx[0];
+ UINT16 *source = sslam_spriteram;
+ UINT16 *finish = source + 0x1000/2;
+
+ source += 3; // strange
+
+ while( source<finish )
+ {
+ int xpos, ypos, number, flipx, colr, eightbyeight;
+
+ if (source[0] & 0x2000) break;
+
+ xpos = source[2] & 0x1ff;
+ ypos = source[0] & 0x01ff;
+ colr = (source[2] & 0xf000) >> 12;
+ eightbyeight = source[0] & 0x1000;
+ flipx = source[0] & 0x4000;
+ number = source[3];
+
+ xpos -=16; xpos -=7; xpos += sprites_x_offset;
+ ypos = 0xff - ypos;
+ ypos -=16; ypos -=7;
+
+ if(ypos < 0)
+ ypos += 256;
+
+ if(ypos >= 249)
+ ypos -= 256;
+
+ if (!eightbyeight)
+ {
+ if (flipx)
+ {
+ drawgfx(bitmap,gfx,number, colr,1,0,xpos+8,ypos, cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,gfx,number+1,colr,1,0,xpos+8,ypos+8,cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,gfx,number+2,colr,1,0,xpos, ypos, cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,gfx,number+3,colr,1,0,xpos, ypos+8,cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ drawgfx(bitmap,gfx,number, colr,0,0,xpos, ypos, cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,gfx,number+1,colr,0,0,xpos, ypos+8,cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,gfx,number+2,colr,0,0,xpos+8,ypos, cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,gfx,number+3,colr,0,0,xpos+8,ypos+8,cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ else
+ {
+ if (flipx)
+ {
+ drawgfx(bitmap,gfx,number ^ 2,colr,1,0,xpos,ypos,cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ drawgfx(bitmap,gfx,number,colr,0,0,xpos,ypos,cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+
+ source += 4;
+ }
+
+}
+
+
+/* Text Layer */
+
+static TILE_GET_INFO( get_sslam_tx_tile_info )
+{
+ int code = sslam_tx_tileram[tile_index] & 0x0fff;
+ int colr = sslam_tx_tileram[tile_index] & 0xf000;
+
+ SET_TILE_INFO(3,code+0xc000 ,colr >> 12,0);
+}
+
+WRITE16_HANDLER( sslam_tx_tileram_w )
+{
+ COMBINE_DATA(&sslam_tx_tileram[offset]);
+ tilemap_mark_tile_dirty(sslam_tx_tilemap,offset);
+}
+
+/* Middle Layer */
+
+static TILE_GET_INFO( get_sslam_md_tile_info )
+{
+ int code = sslam_md_tileram[tile_index] & 0x0fff;
+ int colr = sslam_md_tileram[tile_index] & 0xf000;
+
+ SET_TILE_INFO(2,code+0x2000 ,colr >> 12,0);
+}
+
+WRITE16_HANDLER( sslam_md_tileram_w )
+{
+ COMBINE_DATA(&sslam_md_tileram[offset]);
+ tilemap_mark_tile_dirty(sslam_md_tilemap,offset);
+}
+
+/* Background Layer */
+
+static TILE_GET_INFO( get_sslam_bg_tile_info )
+{
+ int code = sslam_bg_tileram[tile_index] & 0x1fff;
+ int colr = sslam_bg_tileram[tile_index] & 0xe000;
+
+ SET_TILE_INFO(1,code ,colr >> 13,0);
+}
+
+WRITE16_HANDLER( sslam_bg_tileram_w )
+{
+ COMBINE_DATA(&sslam_bg_tileram[offset]);
+ tilemap_mark_tile_dirty(sslam_bg_tilemap,offset);
+}
+
+static TILE_GET_INFO( get_powerbls_bg_tile_info )
+{
+ int code = sslam_bg_tileram[tile_index*2+1] & 0x0fff;
+ int colr = (sslam_bg_tileram[tile_index*2+1] & 0xf000) >> 12;
+ code |= (sslam_bg_tileram[tile_index*2] & 0x0f00) << 4;
+
+ //(sslam_bg_tileram[tile_index*2] & 0x0f00) == 0xf000 ???
+
+ SET_TILE_INFO(1,code,colr,0);
+}
+
+WRITE16_HANDLER( powerbls_bg_tileram_w )
+{
+ COMBINE_DATA(&sslam_bg_tileram[offset]);
+ tilemap_mark_tile_dirty(sslam_bg_tilemap,offset>>1);
+}
+
+VIDEO_START(sslam)
+{
+ sslam_bg_tilemap = tilemap_create(get_sslam_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ sslam_md_tilemap = tilemap_create(get_sslam_md_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ sslam_tx_tilemap = tilemap_create(get_sslam_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ tilemap_set_transparent_pen(sslam_md_tilemap,0);
+ tilemap_set_transparent_pen(sslam_tx_tilemap,0);
+
+ sprites_x_offset = 0;
+ state_save_register_global(sprites_x_offset);
+}
+
+VIDEO_START(powerbls)
+{
+ sslam_bg_tilemap = tilemap_create(get_powerbls_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ sprites_x_offset = -21;
+ state_save_register_global(sprites_x_offset);
+}
+
+VIDEO_UPDATE(sslam)
+{
+ if(!(sslam_regs[6] & 1))
+ {
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ return 0;
+ }
+
+ tilemap_set_scrollx(sslam_tx_tilemap,0, sslam_regs[0]+1); /* +0 looks better, but the real board has the left most pixel at the left edge shifted off screen */
+ tilemap_set_scrolly(sslam_tx_tilemap,0, (sslam_regs[1] & 0xff)+8);
+ tilemap_set_scrollx(sslam_md_tilemap,0, sslam_regs[2]+2);
+ tilemap_set_scrolly(sslam_md_tilemap,0, sslam_regs[3]+8);
+ tilemap_set_scrollx(sslam_bg_tilemap,0, sslam_regs[4]+4);
+ tilemap_set_scrolly(sslam_bg_tilemap,0, sslam_regs[5]+8);
+
+ tilemap_draw(bitmap,cliprect,sslam_bg_tilemap,0,0);
+
+ /* remove wraparound from the tilemap (used on title screen) */
+ if(sslam_regs[2]+2 > 0x8c8)
+ {
+ rectangle md_clip;
+ md_clip.min_x = cliprect->min_x;
+ md_clip.max_x = cliprect->max_x - (sslam_regs[2]+2 - 0x8c8);
+ md_clip.min_y = cliprect->min_y;
+ md_clip.max_y = cliprect->max_y;
+
+ tilemap_draw(bitmap,&md_clip,sslam_md_tilemap,0,0);
+ }
+ else
+ {
+ tilemap_draw(bitmap,cliprect,sslam_md_tilemap,0,0);
+ }
+
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,sslam_tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE(powerbls)
+{
+ if(!(sslam_regs[6] & 1))
+ {
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ return 0;
+ }
+
+ tilemap_set_scrollx(sslam_bg_tilemap,0, sslam_regs[0]+21);
+ tilemap_set_scrolly(sslam_bg_tilemap,0, sslam_regs[1]-240);
+
+ tilemap_draw(bitmap,cliprect,sslam_bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/ssozumo.c b/src/mame/video/ssozumo.c
new file mode 100644
index 00000000000..4d88ee57840
--- /dev/null
+++ b/src/mame/video/ssozumo.c
@@ -0,0 +1,181 @@
+/***************************************************************************
+
+Syusse Oozumou
+(c) 1984 Technos Japan (Licensed by Data East)
+
+Driver by Takahiro Nogi (nogi@kt.rim.or.jp) 1999/10/04
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *ssozumo_videoram2;
+UINT8 *ssozumo_colorram2;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+/**************************************************************************/
+
+PALETTE_INIT( ssozumo )
+{
+ int bit0, bit1, bit2, bit3, r, g, b;
+ int i;
+
+ for (i = 0 ; i < 64 ; i++)
+ {
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[0] >> 4) & 0x01;
+ bit1 = (color_prom[0] >> 5) & 0x01;
+ bit2 = (color_prom[0] >> 6) & 0x01;
+ bit3 = (color_prom[0] >> 7) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[64] >> 0) & 0x01;
+ bit1 = (color_prom[64] >> 1) & 0x01;
+ bit2 = (color_prom[64] >> 2) & 0x01;
+ bit3 = (color_prom[64] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( ssozumo_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( ssozumo_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( ssozumo_videoram2_w )
+{
+ ssozumo_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( ssozumo_colorram2_w )
+{
+ ssozumo_colorram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( ssozumo_paletteram_w )
+{
+ int bit0, bit1, bit2, bit3, val;
+ int r, g, b;
+ int offs2;
+
+ paletteram[offset] = data;
+ offs2 = offset & 0x0f;
+
+ val = paletteram[offs2];
+ bit0 = (val >> 0) & 0x01;
+ bit1 = (val >> 1) & 0x01;
+ bit2 = (val >> 2) & 0x01;
+ bit3 = (val >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ val = paletteram[offs2 | 0x10];
+ bit0 = (val >> 0) & 0x01;
+ bit1 = (val >> 1) & 0x01;
+ bit2 = (val >> 2) & 0x01;
+ bit3 = (val >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ val = paletteram[offs2 | 0x20];
+ bit0 = (val >> 0) & 0x01;
+ bit1 = (val >> 1) & 0x01;
+ bit2 = (val >> 2) & 0x01;
+ bit3 = (val >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(Machine, offs2 + 64, MAKE_RGB(r, g, b));
+}
+
+WRITE8_HANDLER( ssozumo_scroll_w )
+{
+ tilemap_set_scrolly(bg_tilemap, 0, data);
+}
+
+WRITE8_HANDLER( ssozumo_flipscreen_w )
+{
+ flip_screen_set(data & 0x80);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + ((colorram[tile_index] & 0x08) << 5);
+ int color = (colorram[tile_index] & 0x30) >> 4;
+ int flags = ((tile_index % 32) >= 16) ? TILE_FLIPY : 0;
+
+ SET_TILE_INFO(1, code, color, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = ssozumo_videoram2[tile_index] + 256 * (ssozumo_colorram2[tile_index] & 0x07);
+ int color = (ssozumo_colorram2[tile_index] & 0x30) >> 4;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( ssozumo )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols_flip_x,
+ TILEMAP_TYPE_PEN, 16, 16, 16, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols_flip_x,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0; offs < spriteram_size; offs += 4)
+ {
+ if (spriteram[offs] & 0x01)
+ {
+ int code = spriteram[offs + 1] + ((spriteram[offs] & 0xf0) << 4);
+ int color = (spriteram[offs] & 0x08) >> 3;
+ int flipx = spriteram[offs] & 0x04;
+ int flipy = spriteram[offs] & 0x02;
+ int sx = 239 - spriteram[offs + 3];
+ int sy = (240 - spriteram[offs + 2]) & 0xff;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[2],
+ code, color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+ }
+}
+
+VIDEO_UPDATE( ssozumo )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/sspeedr.c b/src/mame/video/sspeedr.c
new file mode 100644
index 00000000000..f4c566bb8cf
--- /dev/null
+++ b/src/mame/video/sspeedr.c
@@ -0,0 +1,274 @@
+/***************************************************************************
+
+Taito Super Speed Race video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+
+static int toggle;
+
+static unsigned driver_horz;
+static unsigned driver_vert;
+static unsigned driver_pic;
+
+static unsigned drones_horz;
+static unsigned drones_vert[3];
+static unsigned drones_mask;
+
+static unsigned track_horz;
+static unsigned track_vert[2];
+static unsigned track_ice;
+
+
+WRITE8_HANDLER( sspeedr_driver_horz_w )
+{
+ driver_horz = (driver_horz & 0x100) | data;
+}
+
+
+WRITE8_HANDLER( sspeedr_driver_horz_2_w )
+{
+ driver_horz = (driver_horz & 0xff) | ((data & 1) << 8);
+}
+
+
+WRITE8_HANDLER( sspeedr_driver_vert_w )
+{
+ driver_vert = data;
+}
+
+
+WRITE8_HANDLER( sspeedr_driver_pic_w )
+{
+ driver_pic = data & 0x1f;
+}
+
+
+WRITE8_HANDLER( sspeedr_drones_horz_w )
+{
+ drones_horz = (drones_horz & 0x100) | data;
+}
+
+
+WRITE8_HANDLER( sspeedr_drones_horz_2_w )
+{
+ drones_horz = (drones_horz & 0xff) | ((data & 1) << 8);
+}
+
+
+WRITE8_HANDLER( sspeedr_drones_mask_w )
+{
+ drones_mask = data & 0x3f;
+}
+
+
+WRITE8_HANDLER( sspeedr_drones_vert_w )
+{
+ drones_vert[offset] = data;
+}
+
+
+WRITE8_HANDLER( sspeedr_track_horz_w )
+{
+ track_horz = (track_horz & 0x100) | data;
+}
+
+
+WRITE8_HANDLER( sspeedr_track_horz_2_w )
+{
+ track_horz = (track_horz & 0xff) | ((data & 1) << 8);
+}
+
+
+WRITE8_HANDLER( sspeedr_track_vert_w )
+{
+ track_vert[offset] = data & 0x7f;
+}
+
+
+WRITE8_HANDLER( sspeedr_track_ice_w )
+{
+ track_ice = data & 0x07;
+}
+
+
+static void draw_track(mame_bitmap* bitmap)
+{
+ const UINT8* p = memory_region(REGION_GFX3);
+
+ int x;
+ int y;
+
+ for (x = 0; x < 376; x++)
+ {
+ unsigned counter_x = x + track_horz + 0x50;
+
+ int flag = 0;
+
+ if (track_ice & 2)
+ {
+ flag = 1;
+ }
+ else if (track_ice & 4)
+ {
+ if (track_ice & 1)
+ {
+ flag = (counter_x <= 0x1ff);
+ }
+ else
+ {
+ flag = (counter_x >= 0x200);
+ }
+ }
+
+ if (counter_x >= 0x200)
+ {
+ counter_x -= 0x1c8;
+ }
+
+ y = 0;
+
+ /* upper landscape */
+
+ for (; y < track_vert[0]; y++)
+ {
+ unsigned counter_y = y - track_vert[0];
+
+ int offset =
+ ((counter_y & 0x1f) << 3) |
+ ((counter_x & 0x1c) >> 2) |
+ ((counter_x & 0xe0) << 3);
+
+ if (counter_x & 2)
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = p[offset] / 16;
+ }
+ else
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = p[offset] % 16;
+ }
+ }
+
+ /* street */
+
+ for (; y < 128 + track_vert[1]; y++)
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = flag ? 15 : 0;
+ }
+
+ /* lower landscape */
+
+ for (; y < 248; y++)
+ {
+ unsigned counter_y = y - track_vert[1];
+
+ int offset =
+ ((counter_y & 0x1f) << 3) |
+ ((counter_x & 0x1c) >> 2) |
+ ((counter_x & 0xe0) << 3);
+
+ if (counter_x & 2)
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = p[offset] / 16;
+ }
+ else
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = p[offset] % 16;
+ }
+ }
+ }
+}
+
+
+static void draw_drones(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ static const UINT8 code[6] =
+ {
+ 0xf, 0x4, 0x3, 0x9, 0x7, 0xc
+ };
+
+ int i;
+
+ for (i = 0; i < 6; i++)
+ {
+ int x;
+ int y;
+
+ if ((drones_mask >> i) & 1)
+ {
+ continue;
+ }
+
+ x = (code[i] << 5) - drones_horz - 0x50;
+
+ if (x <= -32)
+ {
+ x += 0x1c8;
+ }
+
+ y = 0xf0 - drones_vert[i >> 1];
+
+ drawgfx(bitmap, machine->gfx[1],
+ code[i] ^ toggle,
+ 0,
+ 0, 0,
+ x,
+ y,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+}
+
+
+static void draw_driver(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ int x;
+ int y;
+
+ if (!(driver_pic & 0x10))
+ {
+ return;
+ }
+
+ x = 0x1e0 - driver_horz - 0x50;
+
+ if (x <= -32)
+ {
+ x += 0x1c8;
+ }
+
+ y = 0xf0 - driver_vert;
+
+ drawgfx(bitmap, machine->gfx[0],
+ driver_pic,
+ 0,
+ 0, 0,
+ x,
+ y,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+}
+
+
+VIDEO_START( sspeedr )
+{
+ toggle = 0;
+}
+
+
+VIDEO_UPDATE( sspeedr )
+{
+ draw_track(bitmap);
+
+ draw_drones(machine, bitmap, cliprect);
+
+ draw_driver(machine, bitmap, cliprect);
+ return 0;
+}
+
+
+VIDEO_EOF( sspeedr )
+{
+ toggle ^= 1;
+}
diff --git a/src/mame/video/ssrj.c b/src/mame/video/ssrj.c
new file mode 100644
index 00000000000..688490fbdd8
--- /dev/null
+++ b/src/mame/video/ssrj.c
@@ -0,0 +1,292 @@
+#include "driver.h"
+
+static tilemap *tilemap1,*tilemap2,*tilemap4;
+UINT8 *ssrj_vram1,*ssrj_vram2,*ssrj_vram3,*ssrj_vram4,*ssrj_scrollram;
+
+/* tilemap 1 */
+
+WRITE8_HANDLER(ssrj_vram1_w)
+{
+ ssrj_vram1[offset]=data;
+ tilemap_mark_tile_dirty(tilemap1,offset>>1);
+}
+
+READ8_HANDLER(ssrj_vram1_r)
+{
+ return ssrj_vram1[offset];
+}
+
+static TILE_GET_INFO( get_tile_info1 )
+{
+ int code;
+ code=ssrj_vram1[tile_index<<1]+(ssrj_vram1[(tile_index<<1)+1]<<8);
+ SET_TILE_INFO(
+ 0,
+ code&1023,
+ (code>>12)&0x3,
+ ((code & 0x8000) ? TILE_FLIPX:0) |( (code & 0x4000) ? TILE_FLIPY:0) );
+}
+
+/* tilemap 2 */
+
+WRITE8_HANDLER(ssrj_vram2_w)
+{
+ ssrj_vram2[offset]=data;
+ tilemap_mark_tile_dirty(tilemap2,offset>>1);
+}
+
+READ8_HANDLER(ssrj_vram2_r)
+{
+ return ssrj_vram2[offset];
+}
+
+static TILE_GET_INFO( get_tile_info2 )
+{
+ int code;
+ code=ssrj_vram2[tile_index<<1]+(ssrj_vram2[(tile_index<<1)+1]<<8);
+ SET_TILE_INFO(
+ 0,
+ code&1023,
+ ((code>>12)&0x3)+4,
+ ((code & 0x8000) ? TILE_FLIPX:0) |( (code & 0x4000) ? TILE_FLIPY:0) );
+}
+
+/* tilemap 4 */
+
+WRITE8_HANDLER(ssrj_vram4_w)
+{
+ ssrj_vram4[offset]=data;
+ tilemap_mark_tile_dirty(tilemap4,offset>>1);
+}
+
+READ8_HANDLER(ssrj_vram4_r)
+{
+ return ssrj_vram4[offset];
+}
+
+static TILE_GET_INFO( get_tile_info4 )
+{
+ int code;
+ code=ssrj_vram4[tile_index<<1]+(ssrj_vram4[(tile_index<<1)+1]<<8);
+ SET_TILE_INFO(
+ 0,
+ code&1023,
+ ((code>>12)&0x3)+12,
+ ((code & 0x8000) ? TILE_FLIPX:0) |( (code & 0x4000) ? TILE_FLIPY:0) );
+}
+
+
+
+static const int fakecols[4*4][8][3]=
+{
+
+{{0x00,0x00,0x00},
+ {42,87,140},
+ {0,0,0},
+ {33,75,160},
+ {0xff,0xff,0xff},
+ {37,56,81},
+ {0x1f,0x1f,0x2f},
+ {55,123,190}},
+
+{{0x00,0x00,0x00},
+ {0x00,99,41},
+ {0x00,0x00,0xff},
+ {0x00,0xff,0},
+ {255,255,255},
+ {0xff,0x00,0x00},
+ {0,45,105},
+ {0xff,0xff,0}},
+
+
+{{0x00,0x00,0x00},
+ {0x00,0x20,0x00},
+ {0x00,0x40,0x00},
+ {0x00,0x60,0x00},
+ {0x00,0x80,0x00},
+ {0x00,0xa0,0x00},
+ {0x00,0xc0,0x00},
+ {0x00,0xf0,0x00}},
+
+ {{0x00,0x00,0x00},
+ {0x20,0x00,0x20},
+ {0x40,0x00,0x40},
+ {0x60,0x00,0x60},
+ {0x80,0x00,0x80},
+ {0xa0,0x00,0xa0},
+ {0xc0,0x00,0xc0},
+ {0xf0,0x00,0xf0}},
+
+{{0x00,0x00,0x00},
+ {0xff,0x00,0x00},
+ {0x7f,0x00,0x00},
+ {0x00,0x00,0x00},
+ {0x00,0x00,0x00},
+ {0xaf,0x00,0x00},
+ {0xff,0xff,0xff},
+ {0xff,0x7f,0x7f}},
+
+{{0x00,0x00,0x00},
+ {0x20,0x20,0x20},
+ {0x40,0x40,0x40},
+ {0x60,0x60,0x60},
+ {0x80,0x80,0x80},
+ {0xa0,0xa0,0xa0},
+ {0xc0,0xc0,0xc0},
+ {0xf0,0xf0,0xf0}},
+
+{{0x00,0x00,0x00},
+ {0x20,0x20,0x20},
+ {0x40,0x40,0x40},
+ {0x60,0x60,0x60},
+ {0x80,0x80,0x80},
+ {0xa0,0xa0,0xa0},
+ {0xc0,0xc0,0xc0},
+ {0xf0,0xf0,0xf0}},
+
+{{0x00,0x00,0x00},
+ {0xff,0x00,0x00},
+ {0x00,0x00,0x9f},
+ {0x60,0x60,0x60},
+ {0x00,0x00,0x00},
+ {0xff,0xff,0x00},
+ {0x00,0xff,0x00},
+ {0xff,0xff,0xff}},
+
+{
+ {0x00,0x00,0x00},
+ {0x00,0x00,0xff},
+ {0x00,0x00,0x7f},
+ {0x00,0x00,0x00},
+ {0x00,0x00,0x00},
+ {0x00,0x00,0xaf},
+ {0xff,0xff,0xff},
+ {0x7f,0x7f,0xff}},
+
+{{0x00,0x00,0x00},
+ {0xff,0xff,0x00},
+ {0x7f,0x7f,0x00},
+ {0x00,0x00,0x00},
+ {0x00,0x00,0x00},
+ {0xaf,0xaf,0x00},
+ {0xff,0xff,0xff},
+ {0xff,0xff,0x7f}},
+
+{{0x00,0x00,0x00},
+ {0x00,0xff,0x00},
+ {0x00,0x7f,0x00},
+ {0x00,0x00,0x00},
+ {0x00,0x00,0x00},
+ {0x00,0xaf,0x00},
+ {0xff,0xff,0xff},
+ {0x7f,0xff,0x7f}},
+
+{{0x00,0x00,0x00},
+ {0x20,0x20,0x20},
+ {0x40,0x40,0x40},
+ {0x60,0x60,0x60},
+ {0x80,0x80,0x80},
+ {0xa0,0xa0,0xa0},
+ {0xc0,0xc0,0xc0},
+ {0xf0,0xf0,0xf0}},
+
+{{0x00,0x00,0x00},
+ {0x20,0x20,0x20},
+ {0x40,0x40,0x40},
+ {0x60,0x60,0x60},
+ {0x80,0x80,0x80},
+ {0xa0,0xa0,0xa0},
+ {0xc0,0xc0,0xc0},
+ {0xf0,0xf0,0xf0}},
+
+{{0x00,0x00,0x00},
+ {0x20,0x20,0x20},
+ {0x40,0x40,0x40},
+ {0x60,0x60,0x60},
+ {0x80,0x80,0x80},
+ {0xa0,0xa0,0xa0},
+ {0xc0,0xc0,0xc0},
+ {0xf0,0xf0,0xf0}},
+
+{{0x00,0x00,0x00},
+ {0x20,0x20,0x20},
+ {0x40,0x40,0x40},
+ {0x60,0x60,0x60},
+ {0x80,0x80,0x80},
+ {0xa0,0xa0,0xa0},
+ {0xc0,0xc0,0xc0},
+ {0xf0,0xf0,0xf0}},
+
+{
+ {0x00,0x00,0x00},
+ {0xff,0xaf,0xaf},
+ {0x00,0x00,0xff},
+ {0xff,0xff,0xff},
+ {0x00,0x00,0x00},
+ {0xff,0x50,0x50},
+ {0xff,0xff,0x00},
+ {0x00,0xff,0x00}
+}
+
+};
+
+VIDEO_START( ssrj )
+{
+ tilemap1 = tilemap_create( get_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+ tilemap2 = tilemap_create( get_tile_info2,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+ tilemap4 = tilemap_create( get_tile_info4,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32 );
+ tilemap_set_transparent_pen(tilemap2,0);
+ tilemap_set_transparent_pen(tilemap4,0);
+}
+
+
+static void draw_objects(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int i,j,k,x,y;
+
+ for(i=0;i<6;i++)
+ {
+ x=ssrj_scrollram[0x80+20*i];
+ y=ssrj_scrollram[0x80+20*i+2];
+ if(!ssrj_scrollram[0x80+20*i+3])
+ for(k=0;k<5;k++,y+=8)
+ for(j=0;j<0x20;j++)
+ {
+ int code;
+ code=ssrj_vram3[(i*5+k)*64+(31-j)*2]+256*ssrj_vram3[(i*5+k)*64+(31-j)*2+1];
+ drawgfx(bitmap,
+ machine->gfx[0],
+ code&1023,
+ ((code>>12)&0x3)+8,
+ code&0x8000,
+ code&0x4000,
+ (247-(x+(j<<3)))&0xff,
+ y,
+ cliprect,TRANSPARENCY_PEN,
+ 0);
+ }
+ }
+}
+
+
+PALETTE_INIT( ssrj )
+{
+ int i,j;
+ for(i=0;i<4*4;i++)
+ for(j=0;j<8;j++)
+ palette_set_color_rgb(machine,i*8+j,fakecols[i][j][0],fakecols[i][j][1],fakecols[i][j][2]);
+}
+
+VIDEO_UPDATE( ssrj )
+{
+ tilemap_set_scrolly(tilemap1 , 0, 0xff-ssrj_scrollram[2] );
+ tilemap_set_scrollx(tilemap1 , 0, ssrj_scrollram[0] );
+ tilemap_draw(bitmap,cliprect,tilemap1, 0,0);
+ draw_objects(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,tilemap2, 0,0);
+
+ if(ssrj_scrollram[0x101]==0xb)tilemap_draw(bitmap,cliprect,tilemap4, 0,0);/* hack to display 4th tilemap */
+ return 0;
+}
+
+
diff --git a/src/mame/video/ssv.c b/src/mame/video/ssv.c
new file mode 100644
index 00000000000..f50c87828c7
--- /dev/null
+++ b/src/mame/video/ssv.c
@@ -0,0 +1,1169 @@
+/***************************************************************************
+
+ -= Seta, Sammy, Visco (SSV) System =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+ This hardware only generates sprites. But they're of various types,
+ including some large "floating tilemap" ones.
+
+ Sprites RAM is 0x40000 bytes long. The first 0x2000 bytes hold a list
+ of sprites to display (the list can be made shorter using an end-of-list
+ marker).
+
+ Each entry in the list (8 bytes) is a multi-sprite (e.g it tells the
+ hardware to display up to 32 single-sprites).
+
+ The list looks like this:
+
+ Offset: Bits: Value:
+
+ 0.h f--- ---- ---- ---- Shadow
+ -edc ---- ---- ---- Each bit enables 2 bitplanes*
+ ---- ba-- ---- ---- X Size (1,2,4,8 tiles)
+ ---- --98 ---- ---- Y Size (1,2,4,8 tiles)
+ ---- ---- 765- ---- Index of a scroll to apply to the single-sprite(s)
+ ---- ---- ---4 3210 Number of single-sprites, minus 1
+
+ 2.h f--- ---- ---- ---- List end
+ -edc ba98 7654 3210 Offset of the single-sprite(s) data
+
+ 4.h fedc ba-- ---- ----
+ ---- --98 7654 3210 X displacement (ignored by tilemap sprites?)
+
+ 6.h fedc ba-- ---- ----
+ ---- --98 7654 3210 Y displacement (ignored by tilemap sprites?)
+
+
+* bit c, which enables/disables the 2 high order bitplanes (256 / 64 color tiles)
+ is the only one implemented. Needed by keithlcy (logo), drifto94 (wheels).
+
+ A single-sprite can be:
+
+ 1. a rectangle of tiles (only 1 tile code needs to be specified)
+ 2. a row of tiles of a tilemap in ram. The row is (always?) as wide
+ as the screen and 64 pixels tall.
+
+ Rectangle case(1):
+ Offset: Bits: Value:
+
+ 0.h Code (low bits)
+
+ 2.h f--- ---- ---- ---- Flip X
+ -e-- ---- ---- ---- Flip Y
+ --dc ba-- ---- ---- Code (high bits)
+ ---- --9- ---- ---- Code? Color?
+ ---- ---8 7654 3210 Color code (64 color steps)
+
+ 4.h f--- ---- ---- ---- Shadow
+ -edc ---- ---- ---- Each bit enables 2 bitplanes*
+ ---- ba-- ---- ---- X Size (1,2,4,8 tiles)
+ ---- --98 7654 3210 X
+
+ 6.h fedc ---- ---- ----
+ ---- ba-- ---- ---- Y Size (1,2,4 tiles) **
+ ---- --98 7654 3210 Y
+
+
+ Tilemap case(2):
+ Offset: Bits: Value:
+
+ 0.h fedc ba98 7654 3---
+ ---- ---- ---- -210 Scroll index (see below)
+
+ 2.h Always 0
+
+ 4.h fedc ba-- ---- ----
+ ---- --98 7654 3210 X?
+
+ 6.h fedc ---- ---- ----
+ ---- ba-- ---- ---- **
+ ---- --98 7654 3210 Y
+
+** ? both bits set means "Row Sprite" if the single-sprite type hasn't been
+ specified in the sprites list ?
+
+ There are 8 scroll values for the tilemap sprites, in the
+ 1c0000-1c003f area (each scroll value uses 8 bytes):
+
+ Offset: Bits: Value:
+
+ 0.h Scroll X
+
+ 2.h Scroll Y
+
+ 4.h Priority ? (0000, 0401, 0440, 057f, 05ff)
+
+ 6.h fed- ---- ---- ---- Tilemap width (games only use 1 -> $200, 2 -> $400)
+ ---c ---- ---- ---- ?
+ ---- b--- ---- ---- Shadow
+ ---- -a98 ---- ---- Each bit enables 2 bitplanes*
+ ---- ---- 7654 3210 ? some games leave it to 0, others
+ use e.g 28 for scroll 0, 29 for
+ scroll 1, 2a etc.
+
+ Where scroll x&y refer to a virtual $8000 x $200 tilemap (filling the
+ whole spriteram) made of 16x16 tiles. A tile uses 4 bytes:
+
+ Offset: Bits: Value:
+
+ 0.h Code (low bits)***
+
+ 2.h f--- ---- ---- ---- Flip X
+ -e-- ---- ---- ---- Flip Y
+ --dc ba-- ---- ---- Code (high bits)
+ ---- --9- ---- ---- Code? Color?
+ ---- ---8 7654 3210 Color code (64 color steps)
+
+ The tilemap is stored in ram by column.
+
+*** The tiles size is (always?) 16x16 so Code and Code+1 are used.
+
+
+ Note that there is a "background layer": a series of tilemap sprites
+ that fill up the screen and use scroll 0 as the source tilemap are
+ always displayed before the sprites in the sprites list.
+
+ Shadows:
+
+ The low bits of the pens from a "shadowing" tile (regardless of color code)
+ substitute the top bits of the color index (0-7fff) in the frame buffer.
+ The number of low bits from the "shadowing tile" is 4 or 2, depending on
+ bit 7 of 1c0076.
+
+Note: press Z to show some info on each sprite (debug builds only)
+
+***************************************************************************/
+
+#include "driver.h"
+#include "seta.h"
+#ifdef MAME_DEBUG
+#include "ui.h"
+#endif
+
+static int shadow_pen_mask, shadow_pen_shift;
+
+static void ssv_drawgfx( mame_bitmap *bitmap, const gfx_element *gfx,
+ UINT32 code,UINT32 color,int flipx,int flipy,int x0,int y0,
+ const rectangle *cliprect, int shadow )
+{
+ UINT8 *source, *addr, pen;
+ UINT16 *dest;
+ int sx, x1, dx;
+ int sy, y1, dy;
+
+ addr = (code % gfx->total_elements) * gfx->char_modulo + gfx->gfxdata;
+ color = gfx->color_granularity * (color % gfx->total_colors);
+
+ if ( flipx ) { x1 = x0-1; x0 += gfx->width-1; dx = -1; }
+ else { x1 = x0 + gfx->width; dx = 1; }
+
+ if ( flipy ) { y1 = y0-1; y0 += gfx->height-1; dy = -1; }
+ else { y1 = y0 + gfx->height; dy = 1; }
+
+#define SSV_DRAWGFX(SETPIXELCOLOR) \
+ for ( sy = y0; sy != y1; sy += dy ) \
+ { \
+ if ( sy >= cliprect->min_y && sy <= cliprect->max_y ) \
+ { \
+ source = addr; \
+ dest = BITMAP_ADDR16(bitmap, sy, 0); \
+ \
+ for ( sx = x0; sx != x1; sx += dx ) \
+ { \
+ pen = *source++; \
+ \
+ if ( pen && sx >= cliprect->min_x && sx <= cliprect->max_x ) \
+ SETPIXELCOLOR \
+ } \
+ } \
+ \
+ addr += gfx->line_modulo; \
+ }
+
+ if (shadow)
+ {
+ SSV_DRAWGFX( { dest[sx] = ((dest[sx] & shadow_pen_mask) | (pen << shadow_pen_shift)) & 0x7fff; } )
+ }
+ else
+ {
+ SSV_DRAWGFX( { dest[sx] = (color + pen) & 0x7fff; } )
+ }
+}
+
+
+VIDEO_START( ssv )
+{
+ machine->gfx[0]->color_granularity = 64; /* 256 colour sprites with palette selectable on 64 colour boundaries */
+}
+
+VIDEO_START( eaglshot )
+{
+ video_start_ssv(machine);
+
+ eaglshot_gfxram = (UINT16*)auto_malloc(16 * 0x40000);
+ eaglshot_dirty_tile = (char*)auto_malloc(16 * 0x40000 / (16*8));
+}
+
+static tilemap *gdfs_tmap;
+
+static TILE_GET_INFO( get_tile_info_0 )
+{
+ UINT16 tile = gdfs_tmapram[tile_index];
+ SET_TILE_INFO(3, tile, 0, TILE_FLIPXY( tile >> 14 ));
+}
+
+WRITE16_HANDLER( gdfs_tmapram_w )
+{
+ COMBINE_DATA(&gdfs_tmapram[offset]);
+ tilemap_mark_tile_dirty(gdfs_tmap, offset);
+}
+
+VIDEO_START( gdfs )
+{
+ video_start_ssv(machine);
+
+ machine->gfx[2]->color_granularity = 64; /* 256 colour sprites with palette selectable on 64 colour boundaries */
+
+ eaglshot_gfxram = (UINT16*)auto_malloc(4 * 0x100000);
+ eaglshot_dirty_tile = (char*)auto_malloc(4 * 0x100000 / (16*8));
+
+ gdfs_tmap = tilemap_create( get_tile_info_0, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 0x100,0x100 );
+
+ tilemap_set_transparent_pen(gdfs_tmap, 0);
+}
+
+/* Scroll values + CRT controller registers */
+UINT16 *ssv_scroll;
+
+int ssv_special; // game specific kludges
+
+int ssv_tile_code[16];
+
+int ssv_sprites_offsx, ssv_sprites_offsy;
+int ssv_tilemap_offsx, ssv_tilemap_offsy;
+
+UINT16 *eaglshot_gfxram, *gdfs_tmapram, *gdfs_tmapscroll;
+char eaglshot_dirty, *eaglshot_dirty_tile;
+
+/***************************************************************************
+
+ CRT controller, registers that are read
+ (vblank etc.?)
+
+ 1c0000 (wait for bit .. to become ..)
+
+ keithlcy: bit D, 0 -> 1
+
+ mslider: bit A, 0
+
+ hypreact:
+ meosism:
+ srmp7:
+ sxyreact:
+ ultrax: bit F, 0
+
+ twineag2:
+ hypreac2: bit C, 1 -> 0
+ bit F, 0
+
+ janjans1:
+ srmp4:
+ survarts: No checks
+
+ ryorioh:
+ drifto94: bit D, 0 -> 1
+ bit A, 0
+
+
+ CRT controller, registers that are written
+ (resolution, visible area, flipping etc. ?)
+
+
+
+ 1c0060-7f:
+
+ drifto94: 0000 0025 00cd 01c6 - 0001 0013 0101 0106
+ 0300 0711 0500 0000 - 0015 5940 0000 0000
+ 03ea 5558 (flip)
+
+ dynagear: 002b 002c 00d4 01c6 - 0001 0012 0102 0106
+ 02fd 0000 0500 0000 - 0015 5940 0000 0000
+ ???? ???? (flip)
+
+ eaglshot: 0021 002a 00ca 01c6 - 0001 0016 00f6 0106
+ 0301 0000 0500 d000 - 0015 5940 0000 0000
+ ???? ???? (flip)
+
+ gdfs: 002b 002c 00d5 01c6 - 0001 0012 0102 0106
+ 03ec 0711 0500 0000 - 00d5 5950 0000 0000
+ 03ec 1557 (flip)
+
+ hypreact: 0021 0022 00cb 01c6 - 0001 000e 00fe 0106
+ 0301 0000 0500 c000 - 0015 5140 0000 0000
+ 03f0 5558 (flip)
+
+ hypreac2: 0021 0022 00cb 01c6 - 0001 000e 00fe 0106
+ 0301 0000 05ff c000 - 0015 5140 0000 0000
+ 03ea 5558 (flip)
+
+ janjans1: 0021 0023 00cb 01c6 - 0001 000f 00fe 0106
+ 0300 0000 0500 c000 - 0015 5140 0000 0000
+ same! (flip)
+
+ keithlcy: 002b 0025 00cd 01c6 - 0001 0013 0101 0106
+ 0300 0711 0500 0000 - 0015 5940 0000 0000
+ 03ea 5558 (flip)
+
+ meosism: 002b 002c 00d5 01c6 - 0001 0012 00fe 0106
+ 0301 0000 0500 c000 - 0015 5140 0000 0000
+ (no flip)
+
+ mslider: 0021 0026 00d6 01c6 - 0001 000e 00fe 0106
+ 03f1 0711 5550 c080 - 0015 5940 0000 0000
+ 0301 0500 (flip)
+
+ ryorioh: 0021 0023*00cb 01c6 - 0001 000f 00fe 0106
+ 0300 0000 0500 c000 - 0015 5140 0000 0000
+ 03ed 5558 (flip) *0025
+
+ srmp4: 002b 002c 00d4 01c6 - 0001 0012 0102 0106
+ 0301 0711 0500 0000 - 0015 4940 0000 0000
+ ffe8 5557 (flip)
+
+ srmp7: 002b 002c 00d4 01c6 - 0001 000e 00fd 0106
+ 0000 0000 e500 0000 - 0015 7140 0000 0000
+ 02f2 b558 (flip)
+
+ stmblade: 0021 0026 00d6 01c6 - 0001 000e 00fe 0106
+ 03f1 0711 5550 c080 - 0015 5940 0000 0000 <- 711 becomes 0 during gameplay
+ 0301 0500 (flip)
+
+ survarts: 002b 002c 00d4 01c6 - 0001 0012 0102 0106
+ 0301 0000 0500 0000 - 0015 5140 0000 0000
+ 03e9 5558 (flip)
+
+ sxyreact: 0021 0022 00cb 01c6 - 0001 000e 00fe 0106
+ 0301 0000 0500 c000 - 0015 5140 0000 0000
+ 03ef 5558 (flip)
+
+ sxyreac2: 0021 0023 00cb 01c6 - 0001 000e 00fe 0106
+ 0301 0000 0500 c000 - 0015 5140 0000 0000
+ ???? ???? (flip)
+
+ twineag2: 002b 002c 00d4 01c6 - 0001 0012 0102 0106
+ ffec 0000 e500 4000 - 0315 7940 0000 0000
+ ???? ???? (flip)
+
+ ultrax: 002b 002c 00d4 01c6 - 0001 0012 0102 0106
+ ffec 0000 e500 4000 - 0315 7940 0000 0000
+ 02fe b558 (flip)
+
+ vasara & 0021 0024 00cc 01c6 - 0001 000e 00fe 0106
+ vasara2: 03f1 0000 6500 c000 - 0015 5140 0000 0000
+ 0301 3558 (flip)
+
+
+***************************************************************************/
+
+READ16_HANDLER( ssv_vblank_r )
+{
+ if (video_screen_get_vblank(0))
+ return 0x2000 | 0x1000;
+ else
+ return 0x0000;
+}
+
+WRITE16_HANDLER( ssv_scroll_w )
+{
+ COMBINE_DATA(ssv_scroll + offset);
+
+/* offsets 60-7f: CRT Controller */
+
+}
+
+WRITE16_HANDLER( paletteram16_xrgb_swap_word_w )
+{
+ int r, g, b;
+ UINT16 data0, data1;
+
+ COMBINE_DATA(paletteram16 + offset);
+
+ offset &= ~1;
+
+ data0 = paletteram16[offset + 1];
+ data1 = paletteram16[offset];
+
+ r = data0 & 0xff;
+ g = data1 >> 8;
+ b = data1 & 0xff;
+
+ palette_set_color(Machine, offset>>1, MAKE_RGB(r, g, b));
+}
+
+/***************************************************************************
+
+
+ Sprites Drawing
+
+[mslider]
+"Insert coins" 101f60: 0006 0825 00b0 000c
+ 104128: 1a3a 0000 63d4 0400 (16x16)
+
+Character tilemap 100080: 000f 0410 0000 0000
+ 102080: 0002 0000 6200 0c00
+ 0002 0000 6200 0c40
+ 0002 0000 6200 0c80
+ 0002 0000 6200 0cc0
+ 0002 0000 6200 0d00
+ ..
+ 0002 0000 6200 0fc0
+ 1c0010: 73f0 00f1 05ff 4600
+
+
+[hypreact]
+intro 100140: 6003 04ca 0000 0000 (tilemap sprite)
+ 102650: 0003 0000 0000 0c00
+ 0003 0000 0000 0c40
+ 0003 0000 0000 0c80
+ 0003 0000 0000 0cc0
+ 1c0018: 15f8 00e8 057f 2600
+
+game 100058: 6003 00db 0050 0040 (normal sprite)
+ 1006d8: 037c 001b 6400 0400
+
+tiles 100060: 6019 0120 0014 000a (sometimes 6619!)
+ 100900: 0a8c 0012 6400 0420 (32x16)
+ 0400 0012 6400 0800 (32x32)
+ ...
+
+[hypreac2]
+"warning" 100f60: 6106 3893 0068 00c8 (128x32)
+ 11c498: 00e0 00b2 6c00 0800
+ 0000 0000 0000 0000
+text below "warning" 100f70: 6016 389b 0048 00b0 ((16 or 8)x8)
+ 11c4d8: 0054 0007 6000 0000
+
+black regions 100af8: 6303 2d64 0000 03f8 (yoffs should be used)
+ 116b20: 0004 0000 0000 0fa0 <- move up and down
+ 0004 0000 0000 0fe0
+ 0004 0000 0000 0ce0
+ 0004 0000 0000 0d20
+ 1c0020: 6c00 00ef 057f 2600
+
+"credits" 1012f0: 6007 440e 00e0 0008 (16x8)
+ 122070: 0043 0006 6000 0000
+
+tiles 100ce8: 6111 3464 0008 0030 (16x32,empty tile frames)
+ 11a320: 0460 006b 6110 0800
+ 0460 006b 6100 0800
+ ..
+ 100d68: 6205 34de 0008 0030 (16x32, tiles on frames)
+ 11a6f0: 050c 0059 6000 0800
+ 04c0 005a 6010 0800
+ 04d4 005a 6020 0800
+ 0500 0059 6030 0800
+ ..
+ 100cf8: 6105 348a 0008 fff8 (16x16 x 2x3, big tiles below)
+ 11a450: 61d6 0059 6000 0420
+ 61f2 0059 6000 0410
+ 6212 0059 6000 0400
+ 61d8 0059 6010 0420
+ 61f4 0059 6010 0410
+ 6214 0059 6010 0400
+
+[keithlcy]
+high scores 101030: 717f 40c0 0010 0000
+ 120600: 0000 0000 00c0 0025 (16x16)
+ 0000 0000 00d0 0025
+ ..
+ 0000 0000 0000 ffff (ysize should be 16!)
+ 0000 0000 0010 ffff
+ ..
+
+K of "KEITH" 101180: 610e 4600 0020 0090
+ 123000: 4ef4 016a 0000 0040 (16x16)
+ 4ef6 016a 0010 0040
+ ..
+
+floating robot (demo) 101000: 713d 4000 03b0 0088
+ 120000: ..
+ 71f6 0020 0000 0030
+ 71f8 0020 0010 0030
+ ..
+
+cityscape 100030: 7304 1600 0000 007c (yoffs should not be used)
+ 10b000: 0001 0000 0200 0000
+ 0001 0000 0200 0040
+ 0001 0000 0200 0080
+ 0001 0000 0200 00c0
+ 1c0008: 0800 00f2 05ff 5729
+
+
+[meosism]
+shadows 100100: 701f 051b 0041 0020 (16x16 shadow)
+ 1028d8: 05aa 0030 f000 0470
+
+[srmp4]
+logo 100000: 6303 1680 0180 0078 (yoffs?)
+ 10b400: 0001 0000 0000 0060
+ 0001 0000 0000 0020
+ 0001 0000 0000 ffe0
+ 0001 0000 0000 ffa0
+ 1c0008: 0800 00ec 05ff 5629
+
+tiles 100088: 6103 25b7 0028 000a (16x16)
+ 112db8: f4aa 0009 03f8 0018
+ f4a8 0009 0008 0018
+ f4ba 0009 03f8 0008
+ f4bc 0009 0008 0008
+
+[survarts]
+tilemap 100030: 6303 2048 0000 0000
+ 110240: 0002 0000 0160 03fc
+ 0002 0000 0160 003c
+ 0002 0000 0160 007c
+ 0002 0000 0160 00bc
+ 1c0010: 0c2e 01f5 05ff 4628
+
+player 100030: 611f 1da0 0000 fffc
+ 10ed00: eb16 200f 005c fffa (16x16)
+
+"push start" 100130: 601d 1920 0048 0000
+ 10c900: 0441 0004 0000 004c (16x8)
+
+[drifto94]
+car shadow 100010: 8137 0640 0080 0030
+ 103200: ..
+ 544a 21e4 0030 0030 (16x16)
+
+writings on finish 100130: 6109 4840 004e 0058 "good work"
+ 124200: ee6e 0135 0024 0000 (16x16)
+ 100158: 611e 4860 0058 0020 "you have proved yOur"..
+ 124300: ee92 0137 0024 0014 (16x16)
+ ..
+ ee7e 0137 fff4 0000 (16x16!!) ; 'O'
+ ..
+
+[ultrax]
+sprite begin of lev1 100010: 6b60 4280 0016 00a0
+ 121400: 51a0 0042 6800 0c00 (64x64)
+
+[eaglshot]
+title logo 100040: 001b 2920 0048 00e0
+ 114900: 2130 0060 7018 0fd0 (16x64)
+
+play 100020: 0003 290c 0000 0000
+ 114860: 0003 0000 03f0 0ce0 (tilemap)
+
+sammy logo 100020: 0003 1000 0000 0000
+ 108000: 0001 0000 4380 0ce0 (tilemap)
+
+From the above some noteworthy cases are:
+
+ 101f60: 0006 0825 00b0 000c
+ 104128: 1a3a 0000 63d4 0400 consider y size
+
+ 101030: 717f 40c0 0010 0000
+ 120600: 0000 0000 0000 ffff ignore y size & depth
+
+ 100158: 611e 4860 0058 0020
+ 124300 ee7e 0137 fff4 0000 ignore x size & depth
+
+ 100f60: 6106 3893 0068 00c8
+ 11c498: 00e0 00b2 6c00 0800 consider x size & y size
+
+ 100100: 701f 051b 0041 0020
+ 1028d8: 05aa 0030 f000 0470 consider shadow (16x16 shadow)
+
+ 100010: 6b60 4280 0016 00a0
+ 121400: 51a0 0042 6800 0c00 (64x64)
+
+ 100140: 6003 04ca 0000 0000 tilemap
+ 102650: 0003 0000 0000 0c00
+
+ 100080: 000f 0410 0000 0000 tilemap
+ 102080: 0002 0000 6200 0c00
+
+**************************************************************************/
+
+/* Draw a tilemap sprite */
+
+static void draw_row(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int sx, int sy, int scroll)
+{
+ rectangle clip;
+ int attr, code, color, mode, size, page, shadow;
+ int x, x1, sx1, flipx, xnum, xstart, xend, xinc;
+ int y, y1, sy1, flipy, ynum, ystart, yend, yinc;
+ UINT16 *s3;
+
+ xnum = 0x20; // width in tiles (screen-wide)
+ ynum = 0x8; // height in tiles (always 64 pixels?)
+
+ scroll &= 0x7; // scroll register index
+
+ /* Sign extend the position */
+ sx = 0;
+ sy = (sy & 0x1ff) - (sy & 0x200);
+
+ /* Set up a clipping region for the tilemap slice .. */
+
+ clip.min_x = sx;
+ clip.max_x = sx + xnum * 0x10 - 1;
+ clip.min_y = sy;
+ clip.max_y = sy + ynum * 0x8 - 1;
+
+ /* .. and clip it against the visible screen */
+
+ if (clip.min_x > cliprect->max_x) return;
+ if (clip.min_y > cliprect->max_y) return;
+
+ if (clip.max_x < cliprect->min_x) return;
+ if (clip.max_y < cliprect->min_y) return;
+
+ if (clip.min_x < cliprect->min_x) clip.min_x = cliprect->min_x;
+ if (clip.max_x > cliprect->max_x) clip.max_x = cliprect->max_x;
+
+ if (clip.min_y < cliprect->min_y) clip.min_y = cliprect->min_y;
+ if (clip.max_y > cliprect->max_y) clip.max_y = cliprect->max_y;
+
+ /* Get the scroll data */
+
+ x = ssv_scroll[ scroll * 4 + 0 ]; // x scroll
+ y = ssv_scroll[ scroll * 4 + 1 ]; // y scroll
+ // ssv_scroll[ scroll * 4 + 2 ]; // Priority ?
+ mode = ssv_scroll[ scroll * 4 + 3 ]; // shadow, depth etc.
+
+ // Priority ?
+ if ( (ssv_scroll[ scroll * 4 + 2 ] < ssv_scroll[ 0 * 4 + 2 ]) )
+ return;
+
+ /* How is the background layer disabled ? */
+ if ((mode & 0x0700) == 0) return;
+
+ shadow = (mode & 0x0800);
+
+ /* Decide the actual size of the tilemap. $200 and $400 pixels
+ are the only values actually used AFAIK */
+ size = 1 << (8 + ((mode & 0xe000) >> 13));
+ page = (x & 0x7fff) / size;
+
+ /* Given a fixed scroll value, the portion of tilemap displayed changes
+ with the sprite postion */
+ x += sx;
+ y += sy;
+
+ /* Tweak the scroll values (game specific) */
+ x += ssv_tilemap_offsx;
+ y += ssv_tilemap_offsy;
+
+ /* Draw the rows */
+
+ x1 = x;
+ y1 = y;
+ sx1 = sx - (x & 0xf);
+ sy1 = sy - (y & 0xf);
+
+ for (sx=sx1,x=x1; sx <= clip.max_x; sx+=0x10,x+=0x10)
+ {
+ for (sy=sy1,y=y1; sy <= clip.max_y; sy+=0x10,y+=0x10)
+ {
+ int tx, ty, gfx;
+
+ s3 = &spriteram16[ page * (size * ((0x1000/0x200)/2)) +
+ ((x & ((size -1) & ~0xf)) << 2) +
+ ((y & ((0x200-1) & ~0xf)) >> 3) ];
+
+ code = s3[0]; // code high bits
+ attr = s3[1]; // code low bits + color
+
+ /* Code's high bits are scrambled */
+ code += ssv_tile_code[(attr & 0x3c00)>>10];
+ flipy = (attr & 0x4000);
+ flipx = (attr & 0x8000);
+ color = attr;
+
+ /* Select 256 or 64 color tiles */
+ gfx = ((mode & 0x0100) ? 0 : 1);
+
+ /* Force 16x16 tiles ? */
+ if (flipx) { xstart = 1-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = 1; xinc = +1; }
+
+ if (flipy) { ystart = 2-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = 2; yinc = +1; }
+
+ /* Draw a tile (16x16) */
+ for (tx = xstart; tx != xend; tx += xinc)
+ {
+ for (ty = ystart; ty != yend; ty += yinc)
+ {
+ ssv_drawgfx( bitmap, machine->gfx[gfx],
+ code++,
+ color,
+ flipx, flipy,
+ sx + tx * 16, sy + ty * 8,
+ &clip, shadow );
+ } /* ty */
+ } /* tx */
+
+ } /* sy */
+ } /* sx */
+
+}
+
+/* Draw the "background layer" using multiple tilemap sprites */
+
+static void draw_layer(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int nr)
+{
+ int sy;
+ for ( sy = 0; sy <= machine->screen[0].visarea.max_y; sy += 0x40 )
+ draw_row(machine, bitmap, cliprect, 0, sy, nr);
+}
+
+/* Draw sprites in the sprites list */
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /* Sprites list */
+
+ UINT16 *s1 = spriteram16;
+ UINT16 *end1 = spriteram16 + 0x02000/2;
+ UINT16 *end2 = spriteram16 + 0x40000/2;
+ UINT16 *s2;
+
+ for ( ; s1 < end1; s1+=4 )
+ {
+ int attr, code, color, num, sprite;
+ int sx, x, xoffs, flipx, xnum, xstart, xend, xinc;
+ int sy, y, yoffs, flipy, ynum, ystart, yend, yinc;
+ int mode,global_depth,global_xnum,global_ynum;
+
+ mode = s1[ 0 ];
+ sprite = s1[ 1 ];
+ xoffs = s1[ 2 ];
+ yoffs = s1[ 3 ];
+
+ /* Last sprite */
+ if (sprite & 0x8000) break;
+
+ /* Single-sprite address */
+ s2 = &spriteram16[ (sprite & 0x7fff) * 4 ];
+
+ /* Every single sprite is offset by x & yoffs, and additionally
+ by one of the 8 x & y offsets in the 1c0040-1c005f area */
+
+ xoffs += ssv_scroll[((mode & 0x00e0) >> 4) + 0x40/2];
+ yoffs += ssv_scroll[((mode & 0x00e0) >> 4) + 0x42/2];
+
+ /* Number of single-sprites (1-32) */
+ num = (mode & 0x001f) + 1;
+ global_ynum = (mode & 0x0300) << 2;
+ global_xnum = (mode & 0x0c00);
+ global_depth = (mode & 0xf000);
+
+ for( ; num > 0; num--,s2+=4 )
+ {
+ int depth, local_depth, local_xnum, local_ynum;
+
+ if (s2 >= end2) break;
+
+ sx = s2[ 2 ];
+ sy = s2[ 3 ];
+
+ local_depth = sx & 0xf000;
+ local_xnum = sx & 0x0c00;
+ local_ynum = sy & 0x0c00;
+
+ if (ssv_scroll[0x76/2] & 0x4000)
+ {
+ xnum = local_xnum;
+ ynum = local_ynum;
+ depth = local_depth;
+ }
+ else
+ {
+ xnum = global_xnum;
+ ynum = global_ynum;
+ depth = global_depth;
+ }
+
+ if ( s2[0] <= 7 && s2[1] == 0 && xnum == 0 && ynum == 0x0c00)
+ {
+ // Tilemap Sprite
+ int scroll;
+
+ scroll = s2[ 0 ]; // scroll index
+
+ switch( ssv_scroll[0x7a/2] )
+ {
+ case 0x4940: sy += 0x60; break; // srmp4
+ case 0x5940: sy -= 0x20; break; // drifto94, dynagear, eaglshot, keithlcy, mslider, stmblade
+ case 0x5950: sy += 0xdf; break; // gdfs
+ case 0x7940: sy -= 0x10; break; // ultrax, twineag2
+ }
+
+ draw_row(machine, bitmap, cliprect, sx, sy, scroll);
+ }
+ else
+ {
+ // "Normal" Sprite
+/*
+ hot spots:
+ "warning" in hypreac2 has mode & 0x0100 and is not 16x16
+ keithlcy high scores has mode & 0x0100 and y & 0x0c00 can be 0x0c00
+ drifto94 "you have proved yOur".. has mode & 0x0100 and x & 0x0c00 can be 0x0c00
+ ultrax (begin of lev1): 100010: 6b60 4280 0016 00a0
+ 121400: 51a0 0042 6800 0c00 needs to be a normal sprite
+*/
+
+ int shadow, gfx;
+ if (s2 >= end2) break;
+
+ code = s2[0]; // code high bits
+ attr = s2[1]; // code low bits + color
+
+ /* Code's high bits are scrambled */
+ code += ssv_tile_code[(attr & 0x3c00)>>10];
+ flipy = (attr & 0x4000);
+ flipx = (attr & 0x8000);
+ color = attr;
+
+ /* Select 256 or 64 color tiles */
+ gfx = (depth & 0x1000) ? 0 : 1;
+ shadow = (depth & 0x8000);
+
+ /* Single-sprite tile size */
+ xnum = 1 << (xnum >> 10); // 1, 2, 4 or 8 tiles
+ ynum = 1 << (ynum >> 10); // 1, 2, 4 tiles (8 means tilemap sprite?)
+
+ if (flipx) { xstart = xnum-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = xnum; xinc = +1; }
+
+ if (flipy) { ystart = ynum-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = ynum; yinc = +1; }
+
+ /* Apply global offsets */
+ sx += xoffs;
+ sy += yoffs;
+
+ /* Sign extend the position */
+ sx = (sx & 0x1ff) - (sx & 0x200);
+ sy = (sy & 0x1ff) - (sy & 0x200);
+
+ if (ssv_scroll[0x74/2] == 0x6500) // vasara
+ sy = 0xe8 - sy;
+
+ if (ssv_scroll[0x74/2] & 0x8000) // srmp7, twineag2, ultrax
+ {
+ if (ssv_scroll[0x76/2] & 0x4000) { // twineag2, ultrax
+ sx = ssv_sprites_offsx + sx - (xnum-1) * 8;
+ sy = ssv_sprites_offsy + sy - (ynum * 8) / 2;
+ } else { // srmp7
+ sx = ssv_sprites_offsx + sx;
+ sy = ssv_sprites_offsy + sy;
+ }
+ }
+ else if (ssv_scroll[0x76/2] & 0x1000) // eaglshot
+ {
+ sx = ssv_sprites_offsx + sx - (xnum-1) * 8;
+ sy = ssv_sprites_offsy - sy - (ynum * 8) / 2; // sy is the sprite center
+ }
+ else
+ {
+ sx = ssv_sprites_offsx + sx;
+ sy = ssv_sprites_offsy - sy - (ynum-1) * 8;
+ }
+
+ /* Draw the tiles */
+
+ for (x = xstart; x != xend; x += xinc)
+ {
+ for (y = ystart; y != yend; y += yinc)
+ {
+ ssv_drawgfx( bitmap, machine->gfx[gfx],
+ code++,
+ color,
+ flipx, flipy,
+ sx + x * 16, sy + y * 8,
+ cliprect, shadow );
+ }
+ }
+
+ #ifdef MAME_DEBUG
+ if (input_code_pressed(KEYCODE_Z)) /* Display some info on each sprite */
+ { char buf[10];
+ sprintf(buf, "%02X",/*(s2[2] & ~0x3ff)>>8*/mode>>8);
+ ui_draw_text(buf, sx, sy);
+ }
+ #endif
+
+ } /* sprite type */
+
+ } /* single-sprites */
+
+ } /* sprites list */
+}
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+VIDEO_UPDATE( eaglshot )
+{
+ int tile;
+
+ // Decode tiles from ram
+ if (eaglshot_dirty)
+ {
+ eaglshot_dirty = 0;
+
+ for (tile = 0; tile < (16 * 0x40000 / (16*8)); tile++)
+ {
+ if (eaglshot_dirty_tile[tile])
+ {
+ eaglshot_dirty_tile[tile] = 0;
+
+ decodechar(machine->gfx[0], tile, (UINT8 *)eaglshot_gfxram, machine->drv->gfxdecodeinfo[0].gfxlayout);
+ decodechar(machine->gfx[1], tile, (UINT8 *)eaglshot_gfxram, machine->drv->gfxdecodeinfo[1].gfxlayout);
+ }
+ }
+ }
+
+ video_update_ssv(machine, screen, bitmap, cliprect);
+ return 0;
+}
+
+/*
+ Sprites RAM is 0x80000 bytes long. The first 0x2000? bytes hold a list
+ of sprites to display (the list can be made shorter using an end-of-list
+ marker).
+
+ Each entry in the list (16 bytes) is a multi-sprite (e.g it tells the
+ hardware to display several single-sprites).
+
+ The list looks like this:
+
+ Offset: Bits: Value:
+
+ 0.h fedc ba-- ---- ----
+ ---- --98 7654 3210 X displacement
+
+ 2.h fedc ba-- ---- ----
+ ---- --98 7654 3210 Y displacement
+
+ 4.h f--- ---- ---- ---- List end
+ -edc ba98 7654 3210 Offset of the single-sprite(s) data
+
+ 0.h Number of single-sprites (how many bits?)
+
+ A single-sprite is:
+
+ Offset: Bits: Value:
+
+ 0.h Code
+
+ 2.h f--- ---- ---- ---- Flip X
+ -e-- ---- ---- ---- Flip Y
+ ---- -a-- ---- ---- 0 = 256 color steps, 1 = 64 color steps
+ ---- --98 7654 3210 Color code
+
+ 4.h fedc ba-- ---- ----
+ ---- --98 7654 3210 X displacement
+
+ 6.h fedc ba-- ---- ----
+ ---- --98 7654 3210 Y displacement
+
+ 8.h fedc ba98 ---- ---- Y Size
+ ---- ---- 7654 3210 X Size
+
+ A.h fedc ba98 ---- ----
+ ---- ---- 7654 ---- Priority
+ ---- ---- ---- 32-- Y Tiles (1,2,4,8)
+ ---- ---- ---- --10 X Tiles (1,2,4,8)
+
+ C.h Unused
+
+ E.h Unused
+
+*/
+static void gdfs_draw_zooming_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ /* Sprites list */
+
+ UINT16 *s1 = spriteram16_2;
+ UINT16 *end1 = spriteram16_2 + 0x02000/2;
+ UINT16 *s2;
+
+ priority <<= 4;
+
+ for ( ; s1 < end1; s1+=8/2 )
+ {
+ int attr, code, color, num, sprite, zoom, size;
+ int sx, x, xoffs, flipx, xnum, xstart, xend, xinc, xdim, xscale;
+ int sy, y, yoffs, flipy, ynum, ystart, yend, yinc, ydim, yscale;
+
+ xoffs = s1[ 0 ];
+ yoffs = s1[ 1 ];
+ sprite = s1[ 2 ];
+ num = s1[ 3 ] % 0x101;
+
+ /* Last sprite */
+ if (sprite & 0x8000) break;
+
+ /* Single-sprite address */
+ s2 = &spriteram16_2[ (sprite & 0x7fff) * 16/2 ];
+
+ for( ; num > 0; num--,s2+=16/2 )
+ {
+ code = s2[ 0 ];
+ attr = s2[ 1 ];
+ sx = s2[ 2 ];
+ sy = s2[ 3 ];
+ zoom = s2[ 4 ];
+ size = s2[ 5 ];
+
+ if (priority != (size & 0xf0))
+ break;
+
+ flipx = (attr & 0x8000);
+ flipy = (attr & 0x4000);
+ color = (attr & 0x0400) ? attr : attr * 4;
+
+ /* Single-sprite tile size */
+ xnum = 1 << ((size >> 0) & 3);
+ ynum = 1 << ((size >> 2) & 3);
+
+ xnum = (xnum + 1) / 2;
+
+ if (flipx) { xstart = xnum-1; xend = -1; xinc = -1; }
+ else { xstart = 0; xend = xnum; xinc = +1; }
+
+ if (flipy) { ystart = ynum-1; yend = -1; yinc = -1; }
+ else { ystart = 0; yend = ynum; yinc = +1; }
+
+ /* Apply global offsets */
+ sx += xoffs;
+ sy += yoffs;
+
+ /* Sign extend the position */
+ sx = (sx & 0x1ff) - (sx & 0x200);
+ sy = (sy & 0x1ff) - (sy & 0x200);
+
+ sy = -sy;
+
+ /* Use fixed point values (16.16), for accuracy */
+ sx <<= 16;
+ sy <<= 16;
+
+ xdim = ( ( ((zoom >> 0) & 0xff) + 1) << 16 ) / xnum;
+ ydim = ( ( ((zoom >> 8) & 0xff) + 1) << 16 ) / ynum;
+
+ xscale = xdim / 16;
+ yscale = ydim / 8;
+
+ /* Let's approximate to the nearest greater integer value
+ to avoid holes in between tiles */
+ if (xscale & 0xffff) xscale += (1<<16) / 16;
+ if (yscale & 0xffff) yscale += (1<<16) / 8;
+
+ /* Draw the tiles */
+
+ for (x = xstart; x != xend; x += xinc)
+ {
+ for (y = ystart; y != yend; y += yinc)
+ {
+ drawgfxzoom( bitmap, machine->gfx[2],
+ code++,
+ color,
+ flipx, flipy,
+ (sx + x * xdim) / 0x10000, (sy + y * ydim) / 0x10000,
+ cliprect, TRANSPARENCY_PEN, 0,
+ xscale, yscale
+ );
+ }
+ }
+
+ #ifdef MAME_DEBUG
+ if (input_code_pressed(KEYCODE_Z)) /* Display some info on each sprite */
+ {
+ char buf[10];
+ sprintf(buf, "%X",size);
+ ui_draw_text(buf, sx / 0x10000, sy / 0x10000);
+ }
+ #endif
+ } /* single-sprites */
+
+ } /* sprites list */
+}
+
+VIDEO_UPDATE( gdfs )
+{
+ int tile, pri;
+
+ video_update_ssv(machine, screen, bitmap, cliprect);
+
+ // Decode zooming sprites tiles from ram
+ if (eaglshot_dirty)
+ {
+ eaglshot_dirty = 0;
+
+ for (tile = 0; tile < (4 * 0x100000 / (16*8)); tile++)
+ {
+ if (eaglshot_dirty_tile[tile])
+ {
+ eaglshot_dirty_tile[tile] = 0;
+
+ decodechar(machine->gfx[2], tile, (UINT8 *)eaglshot_gfxram, machine->drv->gfxdecodeinfo[2].gfxlayout);
+ }
+ }
+ }
+
+ for (pri = 0; pri <= 0xf; pri++)
+ gdfs_draw_zooming_sprites(machine, bitmap, cliprect, pri);
+
+ tilemap_set_scrollx(gdfs_tmap,0,gdfs_tmapscroll[0x0c/2]);
+ tilemap_set_scrolly(gdfs_tmap,0,gdfs_tmapscroll[0x10/2]);
+ tilemap_draw(bitmap,cliprect, gdfs_tmap, 0, 0);
+
+ return 0;
+}
+
+static int enable_video;
+
+void ssv_enable_video(int enable)
+{
+ enable_video = enable;
+}
+
+VIDEO_UPDATE( ssv )
+{
+ if (ssv_scroll[0x76/2] & 0x0080)
+ {
+ // 4 bit shadows (mslider, stmblade)
+ shadow_pen_mask = 0x1fff;
+ shadow_pen_shift = 11;
+ }
+ else
+ {
+ // 2 bit shadows
+ shadow_pen_mask = 0x3fff;
+ shadow_pen_shift = 13;
+ }
+
+ /* The background color is the first one in the palette */
+ fillbitmap(bitmap,machine->pens[0], cliprect);
+
+ if (!enable_video) return 0;
+
+ draw_layer(machine, bitmap, cliprect, 0); // "background layer"
+
+ draw_sprites(machine, bitmap, cliprect); // sprites list
+ return 0;
+}
diff --git a/src/mame/video/st0016.c b/src/mame/video/st0016.c
new file mode 100644
index 00000000000..ec93155a2b1
--- /dev/null
+++ b/src/mame/video/st0016.c
@@ -0,0 +1,685 @@
+/************************************
+ Seta custom ST-0016 chip
+ driver by Tomasz Slanina
+************************************/
+
+#include "driver.h"
+#include "st0016.h"
+
+UINT8 *st0016_charram,*st0016_spriteram,*st0016_paletteram;
+
+UINT8 *macs_ram1,*macs_ram2;
+
+UINT32 st0016_game;
+
+static INT32 st0016_spr_bank,st0016_spr2_bank,st0016_pal_bank,st0016_char_bank;
+static int spr_dx,spr_dy;
+
+static UINT8 st0016_vregs[0xc0];
+static int st0016_ramgfx;
+
+//super eagle shot
+static mame_bitmap *speglsht_bitmap;
+extern UINT32 *speglsht_framebuffer;
+extern UINT32 speglsht_videoreg;
+
+static const gfx_layout charlayout =
+{
+ 8,8,
+ 0x10000,
+ 4,
+ { 0, 1, 2, 3 },
+ { 1*4, 0*4, 3*4, 2*4, 5*4, 4*4, 7*4, 6*4 },
+ { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 },
+ 8*8*4
+};
+
+WRITE8_HANDLER(st0016_sprite_bank_w)
+{
+/*
+ 76543210
+ xxxx - spriteram bank1
+ xxxx - spriteram bank2
+*/
+ st0016_spr_bank=data&ST0016_SPR_BANK_MASK;
+ st0016_spr2_bank=(data>>4)&ST0016_SPR_BANK_MASK;
+}
+
+WRITE8_HANDLER(st0016_palette_bank_w)
+{
+/*
+ 76543210
+ xx - palram bank
+ xxxxxx - unknown/unused
+*/
+ st0016_pal_bank=data&ST0016_PAL_BANK_MASK;
+}
+
+WRITE8_HANDLER(st0016_character_bank_w)
+{
+/*
+ fedcba9876543210
+ xxxxxxxxxxxxxxxx - character (bank )
+*/
+
+ if(offset&1)
+ st0016_char_bank=(st0016_char_bank&0xff)|(data<<8);
+ else
+ st0016_char_bank=(st0016_char_bank&0xff00)|data;
+
+ st0016_char_bank&=ST0016_CHAR_BANK_MASK;
+}
+
+
+READ8_HANDLER (st0016_sprite_ram_r)
+{
+ return st0016_spriteram[ST0016_SPR_BANK_SIZE*st0016_spr_bank+offset];
+}
+
+WRITE8_HANDLER (st0016_sprite_ram_w)
+{
+
+ st0016_spriteram[ST0016_SPR_BANK_SIZE*st0016_spr_bank+offset]=data;
+}
+
+READ8_HANDLER (st0016_sprite2_ram_r)
+{
+ return st0016_spriteram[ST0016_SPR_BANK_SIZE*st0016_spr2_bank+offset];
+}
+
+WRITE8_HANDLER (st0016_sprite2_ram_w)
+{
+ st0016_spriteram[ST0016_SPR_BANK_SIZE*st0016_spr2_bank+offset]=data;
+}
+
+READ8_HANDLER (st0016_palette_ram_r)
+{
+ return st0016_paletteram[ST0016_PAL_BANK_SIZE*st0016_pal_bank+offset];
+}
+
+WRITE8_HANDLER (st0016_palette_ram_w)
+{
+ int color=(ST0016_PAL_BANK_SIZE*st0016_pal_bank+offset)/2;
+ int val;
+ st0016_paletteram[ST0016_PAL_BANK_SIZE*st0016_pal_bank+offset]=data;
+ val=st0016_paletteram[color*2]+(st0016_paletteram[color*2+1]<<8);
+ if(!color)
+ palette_set_color_rgb(Machine,UNUSED_PEN,pal5bit(val >> 0),pal5bit(val >> 5),pal5bit(val >> 10)); /* same as color 0 - bg ? */
+ palette_set_color_rgb(Machine,color,pal5bit(val >> 0),pal5bit(val >> 5),pal5bit(val >> 10));
+}
+
+READ8_HANDLER(st0016_character_ram_r)
+{
+ return st0016_charram[ST0016_CHAR_BANK_SIZE*st0016_char_bank+offset];
+}
+
+WRITE8_HANDLER(st0016_character_ram_w)
+{
+ st0016_charram[ST0016_CHAR_BANK_SIZE*st0016_char_bank+offset]=data;
+ decodechar(Machine->gfx[st0016_ramgfx], st0016_char_bank,(UINT8 *) st0016_charram, &charlayout);
+}
+
+READ8_HANDLER(st0016_vregs_r)
+{
+/*
+ $0, $1 = max scanline(including vblank)/timer? ($3e7)
+
+ $8-$40 = bg tilemaps (8 bytes each) :
+ 0 - ? = usually 0/20/ba*
+ 1 - 0 = disabled , !zero = address of tilemap in spriteram /$1000 (for example: 3 -> tilemap at $3000 )
+ 2 - ? = usually ff/1f/af*
+ 3 - priority ? = 0 - under sprites , $ff - over sprites \
+ 4 - ? = $7f/$ff
+ 5 - ? = $29/$20 (29 when tilemap must be drawn over sprites . maybe this is real priority ?)
+ 6 - ? = 0
+ 7 - ? =$20/$10/$12*
+
+
+ $40-$60 = scroll registers , X.w, Y.w
+
+*/
+
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ return mame_rand(Machine);
+ }
+
+ return st0016_vregs[offset];
+}
+
+READ8_HANDLER(st0016_dma_r)
+{
+ /* bits 0 and 1 = 0 -> DMA transfer complete */
+ if(ISMACS)
+ return 0;
+ else
+ return 0;
+}
+
+
+WRITE8_HANDLER(st0016_vregs_w)
+{
+ /*
+
+ I/O ports:
+
+ $a0 \
+ $a1 - source address >> 1
+ $a2 /
+
+ $a3 \
+ $a4 - destination address >> 1 (inside character ram)
+ $a5 /
+
+ $a6 \
+ &a7 - (length inbytes - 1 ) >> 1
+
+ $a8 - 76543210
+ ??faaaaa
+
+ a - most sign. bits of length
+ f - DMA start latch
+
+ */
+
+ st0016_vregs[offset]=data;
+ if(offset==0xa8 && (data&0x20))
+ {
+ UINT32 srcadr=(st0016_vregs[0xa0]|(st0016_vregs[0xa1]<<8)|(st0016_vregs[0xa2]<<16))<<1;
+ UINT32 dstadr=(st0016_vregs[0xa3]|(st0016_vregs[0xa4]<<8)|(st0016_vregs[0xa5]<<16))<<1;
+ UINT32 length=((st0016_vregs[0xa6]|(st0016_vregs[0xa7]<<8)|((st0016_vregs[0xa8]&0x1f)<<16))+1)<<1;
+ while(length>0)
+ {
+ if( srcadr < (memory_region_length(REGION_CPU1)-0x10000) && (dstadr < ST0016_MAX_CHAR_BANK*ST0016_CHAR_BANK_SIZE))
+ {
+ st0016_char_bank=dstadr>>5;
+ st0016_character_ram_w(dstadr&0x1f,memory_region(REGION_CPU1)[0x10000+srcadr]);
+ srcadr++;
+ dstadr++;
+ length--;
+ }
+ else
+ {
+ /* samples ? sound dma ? */
+ // speaglsht: unknown DMA copy : src - 2B6740, dst - 4400, len - 1E400
+ logerror("unknown DMA copy : src - %X, dst - %X, len - %X, PC - %X\n",srcadr,dstadr,length,activecpu_get_previouspc());
+ break;
+ }
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /*
+ object ram :
+
+ each entry is 8 bytes:
+
+ 76543210 (bit)
+ 0 llllllll
+ 1 ---1SSSl
+ 2 oooooooo
+ 3 fooooooo
+ 4 xxxxxxxx
+ 5 ------xx
+ 6 yyyyyyyy
+ 7 ------yy
+
+ 1 - always(?) set
+ S - scroll index ? (ports $40-$60, X(word),Y(word) )
+ l - sublist length (8 byte entries -1)
+ o - sublist offset (*8 to get real offset)
+ f - end of list flag
+ x,y - sprite coords
+
+ sublist format (8 bytes/entry):
+
+ 76543210
+ 0 cccccccc
+ 1 cccccccc
+ 2 --kkkkkk
+ 3 QW------
+ 4 xxxxxxxx
+ 5 -B---XXx
+ 6 yyyyyyyy
+ 7 -----YYy
+
+ c - character code
+ k - palette
+ QW - flips
+ x,y - coords
+ XX,YY - size (1<<size)
+ B - merge pixel data with prevoius one (8bpp mode - neratte: seta logo and title screen)
+
+ */
+
+ int i,j,lx,ly,x,y,code,offset,length,sx,sy,color,flipx,flipy,scrollx,scrolly,plx,ply;
+
+
+ for(i=0;i<ST0016_SPR_BANK_SIZE*ST0016_MAX_SPR_BANK;i+=8)
+ {
+ x=st0016_spriteram[i+4]+((st0016_spriteram[i+5]&3)<<8);
+ y=st0016_spriteram[i+6]+((st0016_spriteram[i+7]&3)<<8);
+
+ scrollx=(st0016_vregs[(((st0016_spriteram[i+1]&0x0f)>>1)<<2)+0x40]+256*st0016_vregs[(((st0016_spriteram[i+1]&0x0f)>>1)<<2)+1+0x40])&0x3ff;
+ scrolly=(st0016_vregs[(((st0016_spriteram[i+1]&0x0f)>>1)<<2)+2+0x40]+256*st0016_vregs[(((st0016_spriteram[i+1]&0x0f)>>1)<<2)+3+0x40])&0x3ff;
+
+ if(!ISMACS)
+ {
+ if (x & 0x200) x-= 0x400; //sign
+ if (y & 0x200) y-= 0x400;
+
+ if (scrollx & 0x200) scrollx-= 0x400; //sign
+ if (scrolly & 0x200) scrolly-= 0x400;
+ }
+
+ if(ISMACS1)
+ {
+ if (x & 0x200) x-= 0x400; //sign
+ if (y & 0x200) y-= 0x2b0;//0x400;
+
+ if (scrollx & 0x200) scrollx-= 0x400; //sign
+ if (scrolly & 0x200) scrolly-= 0x400;
+ }
+
+ x+=scrollx;
+ y+=scrolly;
+
+ if(ISMACS)
+ {
+ y+=0x20;
+ }
+
+ if( st0016_spriteram[i+3]&0x80) /* end of list */
+ break;
+
+ offset=st0016_spriteram[i+2]+256*(st0016_spriteram[i+3]);
+ offset<<=3;
+
+ length=st0016_spriteram[i+0]+1+256*(st0016_spriteram[i+1]&1);
+
+ plx=(st0016_spriteram[i+5]>>2)&0x3;
+ ply=(st0016_spriteram[i+7]>>2)&0x3;
+
+ if(offset<ST0016_SPR_BANK_SIZE*ST0016_MAX_SPR_BANK)
+ {
+ for(j=0;j<length;j++)
+ {
+ code=st0016_spriteram[offset]+256*st0016_spriteram[offset+1];
+ sx=st0016_spriteram[offset+4]+((st0016_spriteram[offset+5]&1)<<8);
+ sy=st0016_spriteram[offset+6]+((st0016_spriteram[offset+7]&1)<<8);
+
+ if(ISMACS && !(ISMACS1))
+ {
+ if (sy & 0x100) sy-= 0x200; //yuka & yujan
+ }
+
+ if(ISMACS)
+ {
+ sy=0xe0-sy;
+ }
+
+ sx+=x;
+ sy+=y;
+ color=st0016_spriteram[offset+2]&0x3f;
+ lx=(st0016_spriteram[offset+5]>>2)&3;
+ ly=(st0016_spriteram[offset+7]>>2)&3;
+ /*
+ if(plx |ply) //parent
+ {
+ lx=plx;
+ ly=ply;
+ }
+ */
+
+ flipx=st0016_spriteram[offset+3]&0x80;
+ flipy=st0016_spriteram[offset+3]&0x40;
+
+ if(ISMACS)
+ sy-=(1<<ly)*8;
+
+ {
+ int x0,y0,i0=0;
+ for(x0=(flipx?((1<<lx)-1):0);x0!=(flipx?-1:(1<<lx));x0+=(flipx?-1:1))
+ for(y0=(flipy?((1<<ly)-1):0);y0!=(flipy?-1:(1<<ly));y0+=(flipy?-1:1))
+ {
+ /* custom draw */
+ UINT16 *destline;
+ int yloop,xloop;
+ int ypos, xpos;
+ int tileno;
+ const gfx_element *gfx = machine->gfx[0];
+ UINT8 *srcgfx;
+ int gfxoffs;
+ ypos = sy+y0*8+spr_dy;
+ xpos = sx+x0*8+spr_dx;
+ tileno = (code+i0++)&ST0016_CHAR_BANK_MASK ;
+
+ gfxoffs = 0;
+ srcgfx= gfx->gfxdata+(64*tileno);
+
+ for (yloop=0; yloop<8; yloop++)
+ {
+ UINT16 drawypos;
+
+ if (!flipy) {drawypos = ypos+yloop;} else {drawypos = (ypos+8-1)-yloop;}
+ destline = BITMAP_ADDR16(bitmap, drawypos, 0);
+
+ for (xloop=0; xloop<8; xloop++)
+ {
+ UINT16 drawxpos;
+ int pixdata;
+ pixdata = srcgfx[gfxoffs];
+
+ if (!flipx) { drawxpos = xpos+xloop; } else { drawxpos = (xpos+8-1)-xloop; }
+
+ if (drawxpos > cliprect->max_x)
+ drawxpos -= 512; // wrap around
+
+ if ((drawxpos >= cliprect->min_x) && (drawxpos <= cliprect->max_x) && (drawypos >= cliprect->min_y) && (drawypos <= cliprect->max_y) )
+ {
+ if(st0016_spriteram[offset+5]&0x40)
+ {
+ destline[drawxpos] =(destline[drawxpos] | pixdata<<4)&0x3ff;
+ }
+ else
+ {
+ if(ISMACS2)
+ {
+ if(pixdata )//|| destline[drawxpos]==UNUSED_PEN)
+ {
+ destline[drawxpos] = pixdata + (color*16);
+ }
+ }
+ else
+ {
+ if(pixdata || destline[drawxpos]==UNUSED_PEN)
+ {
+ destline[drawxpos] = pixdata + (color*16);
+ }
+ }
+ }
+ }
+
+ gfxoffs++;
+ }
+ }
+ }
+ }
+ offset+=8;
+ if(offset>=ST0016_SPR_BANK_SIZE*ST0016_MAX_SPR_BANK)
+ break;
+ }
+ }
+ }
+}
+
+static void st0016_postload(void)
+{
+ int i;
+ st0016_rom_bank_w(0,st0016_rom_bank);
+ for(i=0;i<ST0016_MAX_CHAR_BANK;i++)
+ decodechar(Machine->gfx[st0016_ramgfx], i,(UINT8 *) st0016_charram, &charlayout);
+}
+
+
+void st0016_save_init(void)
+{
+ state_save_register_global(st0016_spr_bank);
+ state_save_register_global(st0016_spr2_bank);
+ state_save_register_global(st0016_pal_bank);
+ state_save_register_global(st0016_char_bank);
+ state_save_register_global(st0016_rom_bank);
+ state_save_register_global_array(st0016_vregs);
+ state_save_register_global_pointer(st0016_charram, ST0016_MAX_CHAR_BANK*ST0016_CHAR_BANK_SIZE);
+ state_save_register_global_pointer(st0016_paletteram, ST0016_MAX_PAL_BANK*ST0016_PAL_BANK_SIZE);
+ state_save_register_global_pointer(st0016_spriteram, ST0016_MAX_SPR_BANK*ST0016_SPR_BANK_SIZE);
+ state_save_register_func_postload(st0016_postload);
+}
+
+
+VIDEO_START( st0016 )
+{
+ int gfx_index=0;
+ st0016_charram=auto_malloc(ST0016_MAX_CHAR_BANK*ST0016_CHAR_BANK_SIZE);
+ st0016_spriteram=auto_malloc(ST0016_MAX_SPR_BANK*ST0016_SPR_BANK_SIZE);
+ st0016_paletteram=auto_malloc(ST0016_MAX_PAL_BANK*ST0016_PAL_BANK_SIZE);
+
+ /* find first empty slot to decode gfx */
+ for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
+ if (machine->gfx[gfx_index] == 0)
+ break;
+
+ assert(gfx_index != MAX_GFX_ELEMENTS);
+
+ /* create the char set (gfx will then be updated dynamically from RAM) */
+ machine->gfx[gfx_index] = allocgfx(&charlayout);
+
+ /* set the color information */
+ machine->gfx[gfx_index]->color_base = 0;
+ machine->gfx[gfx_index]->total_colors = 0x40;
+ st0016_ramgfx = gfx_index;
+
+ spr_dx=0;
+ spr_dy=0;
+
+ switch(st0016_game&0x3f)
+ {
+ case 0: //renju kizoku
+ video_screen_set_visarea(0, 0, 40*8-1, 0, 30*8-1);
+ spr_dx=0;
+ spr_dy=0;
+ break;
+
+ case 1: //neratte chu!
+ video_screen_set_visarea(0, 8,41*8-1,0,30*8-1);
+ spr_dx=0;
+ spr_dy=8;
+ break;
+
+ case 3: //super eagle shot
+ speglsht_bitmap = auto_bitmap_alloc( 512, 5122, BITMAP_FORMAT_INDEXED16 );
+ break;
+
+ case 4: //mayjinsen 1&2
+ video_screen_set_visarea(0, 0,32*8-1,0,28*8-1);
+ break;
+
+ case 10:
+ video_screen_set_visarea(0, 0,383,0,255);
+ break;
+
+ case 11:
+ video_screen_set_visarea(0, 0,383,0,383);
+ break;
+
+ }
+
+ st0016_save_init();
+}
+
+
+static void draw_bgmap(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect, int priority)
+{
+ int j;
+ //for(j=0x40-8;j>=0;j-=8)
+ for(j=0;j<0x40;j+=8)
+ {
+ if(st0016_vregs[j+1] && ((priority && (st0016_vregs[j+3]==0xff))||((!priority)&&(st0016_vregs[j+3]!=0xff))))
+ {
+ int x,y,code,color,flipx,flipy;
+ int i=st0016_vregs[j+1]*0x1000;
+ for(x=0;x<32*2;x++)
+ for(y=0;y<8*4;y++)
+ {
+ code=st0016_spriteram[i]+256*st0016_spriteram[i+1];
+ color=st0016_spriteram[i+2]&0x3f;
+
+ flipx=st0016_spriteram[i+3]&0x80;
+ flipy=st0016_spriteram[i+3]&0x40;
+
+ if(priority)
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ x*8+spr_dx,y*8+spr_dy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ UINT16 *destline;
+ int yloop,xloop;
+ int ypos, xpos;
+ const gfx_element *gfx = machine->gfx[0];
+ UINT8 *srcgfx;
+ int gfxoffs;
+ ypos = y*8+spr_dy;//+((st0016_vregs[j+2]==0xaf)?0x50:0);//hack for mayjinsen title screen
+ xpos = x*8+spr_dx;
+ gfxoffs = 0;
+ srcgfx= gfx->gfxdata+(64*code);
+
+ for (yloop=0; yloop<8; yloop++)
+ {
+ UINT16 drawypos;
+
+ if (!flipy) {drawypos = ypos+yloop;} else {drawypos = (ypos+8-1)-yloop;}
+ destline = BITMAP_ADDR16(bitmap, drawypos, 0);
+
+ for (xloop=0; xloop<8; xloop++)
+ {
+ UINT16 drawxpos;
+ int pixdata;
+ pixdata = srcgfx[gfxoffs];
+
+ if (!flipx) { drawxpos = xpos+xloop; } else { drawxpos = (xpos+8-1)-xloop; }
+
+ if (drawxpos > cliprect->max_x)
+ drawxpos -= 512; // wrap around
+
+ if ((drawxpos >= cliprect->min_x) && (drawxpos <= cliprect->max_x) && (drawypos >= cliprect->min_y) && (drawypos <= cliprect->max_y) )
+ {
+
+ if(st0016_vregs[j+7]==0x12)
+ destline[drawxpos] = (destline[drawxpos] | (pixdata<<4))&0x3ff;
+ else
+ {
+
+ if(ISMACS2)
+ {
+ if(pixdata)// || destline[drawxpos]==UNUSED_PEN)
+ {
+ destline[drawxpos] = pixdata + (color*16);
+ }
+ }
+ else
+ {
+ if(pixdata || destline[drawxpos]==UNUSED_PEN)
+ {
+ destline[drawxpos] = pixdata + (color*16);
+ }
+ }
+
+ }
+ }
+
+ gfxoffs++;
+
+ }
+ }
+ }
+ i+=4;
+ }
+ }
+ }
+}
+
+
+#define PLOT_PIXEL_RGB(x,y,r,g,b) if(y>=0 && x>=0 && x<512 && y<512) \
+{ \
+ *BITMAP_ADDR32(bitmap, y, x) = (b) | ((g)<<8) | ((r)<<16); \
+}
+
+VIDEO_UPDATE( st0016 )
+{
+
+#ifdef MAME_DEBUG
+ if(input_code_pressed_once(KEYCODE_Z))
+ {
+ int h,j;
+ FILE *p=fopen("vram.bin","wb");
+ fwrite(st0016_spriteram,1,0x1000*ST0016_MAX_SPR_BANK,p);
+ fclose(p);
+
+ p=fopen("vram.txt","wt");
+ for(h=0;h<0xc0;h++)
+ fprintf(p,"VREG %.4x - %.4x\n",h,st0016_vregs[h]);
+ for(h=0;h<0x1000*ST0016_MAX_SPR_BANK;h+=8)
+ {
+ fprintf(p,"%.4x - %.4x - ",h,h>>3);
+ for(j=0;j<8;j++)
+ fprintf(p,"%.2x ",st0016_spriteram[h+j]);
+ fprintf(p,"\n");
+ }
+ fclose(p);
+ }
+#endif
+
+ if((st0016_game&0x3f)==3)
+ {
+ //super eagle shot
+ int x,y,dy;
+
+ fillbitmap(speglsht_bitmap,machine->pens[0],&machine->screen[0].visarea);
+ dy=(speglsht_videoreg&0x20)?(256*512):0; //visible frame
+
+ for(y=0;y<256;y++)
+ {
+ for(x=0;x<512;x++)
+ {
+ int tmp=dy+y*512+x;
+ PLOT_PIXEL_RGB(x-67,y-5,(speglsht_framebuffer[tmp]>>0)&0xff,(speglsht_framebuffer[tmp]>>8)&0xff,(speglsht_framebuffer[tmp]>>16)&0xff);
+ }
+ }
+
+ //draw st0016 gfx to temporary bitmap (indexed 16)
+ draw_bgmap(machine, speglsht_bitmap,cliprect,0);
+ draw_sprites(machine, speglsht_bitmap,cliprect);
+ draw_bgmap(machine, speglsht_bitmap,cliprect,1);
+
+ //copy temporary bitmap to rgb 32 bit bitmap
+ for(y=cliprect->min_y; y<cliprect->max_y;y++)
+ {
+ UINT16 *srcline = BITMAP_ADDR16(speglsht_bitmap, y, 0);
+ for(x=cliprect->min_x; x<cliprect->max_x;x++)
+ {
+ if(srcline[x])
+ {
+ rgb_t color=palette_get_color(machine, srcline[x]);
+ PLOT_PIXEL_RGB(x,y,RGB_RED(color),RGB_GREEN(color),RGB_BLUE(color));
+ }
+ }
+ }
+ }
+ else
+ {
+ if(ISMACS1)
+ {
+ if(!(readinputportbytag("SYS1")&1)) //fake coins - MACS2 system
+ {
+ macs_ram2[0]++;
+ }
+ }
+
+ fillbitmap(bitmap,machine->pens[UNUSED_PEN],&machine->screen[0].visarea);
+ draw_bgmap(machine, bitmap,cliprect,0);
+ draw_sprites(machine, bitmap,cliprect);
+ draw_bgmap(machine, bitmap,cliprect,1);
+ }
+ return 0;
+}
+
diff --git a/src/mame/video/stactics.c b/src/mame/video/stactics.c
new file mode 100644
index 00000000000..fc3f3bc62cd
--- /dev/null
+++ b/src/mame/video/stactics.c
@@ -0,0 +1,878 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+---
+
+The Video system used in Space Tactics is unusual.
+Here are my notes on how the video system works:
+
+There are 4, 4K pages of Video RAM. (B,D,E & F)
+
+The first 1K of each VRAM page contains the following:
+0 0 V V V V V H H H H H offset value for each 8x8 bitmap
+ (v-tile) (h-tile)
+
+The offset values are used to generate an access into the
+last 2K of the VRAM page:
+1 D D D D D D D D V V V here we find 8x8 character data
+ (offset) (line)
+
+In addition, in Page B, the upper nibble of the offset is
+also used to select the color palette for the tile.
+
+Page B, D, E, and F all work similarly, except that pages
+D, E, and F can be offset from Page B by a given
+number of scanlines, based on the contents of the offset
+RAM
+
+The offset RAM is addressed in this format:
+1 0 0 0 P P P V V V V V V V V V
+ (Page) (scanline)
+Page 4=D, 5=E, 6=F
+
+Page D, E, and F are drawn offset from the top of the screen,
+starting on the first scanline which contains a 1 in the
+appropriate memory location
+
+---
+
+The composited monitor image is seen in a mirror. It appears
+to move when the player moves the handle, due to motors which
+tilt the mirror up and down, and the monitor left and right.
+
+---
+
+As if this wasn't enough, there are also "3D" fire beams made
+of 120 green LED's which are on a mechanism in front of the mirror.
+Along with a single red "sight" LED. I am reading in the sequence
+ROMS and building up a character set to simulate the LEDS with
+conventional character graphics.
+
+Finally, there is a score display made of 7-segment LEDS, along
+with Credits, Barriers, and Rounds displays made of some other
+type of LED bar graphs. I'm displaying them the best I can on the
+bottom line of the screen
+
+***************************************************************************/
+
+#include "driver.h"
+
+/* These are defined in machine/stactics.c */
+extern int stactics_vert_pos;
+extern int stactics_horiz_pos;
+extern UINT8 *stactics_motor_on;
+
+/* These are needed by machine/stactics.c */
+int stactics_vblank_count;
+int stactics_shot_standby;
+int stactics_shot_arrive;
+
+/* These are needed by driver/stactics.c */
+UINT8 *stactics_scroll_ram;
+UINT8 *stactics_videoram_b;
+UINT8 *stactics_chardata_b;
+UINT8 *stactics_videoram_d;
+UINT8 *stactics_chardata_d;
+UINT8 *stactics_videoram_e;
+UINT8 *stactics_chardata_e;
+UINT8 *stactics_videoram_f;
+UINT8 *stactics_chardata_f;
+UINT8 *stactics_display_buffer;
+
+static UINT8 *dirty_videoram_b;
+static UINT8 *dirty_chardata_b;
+static UINT8 *dirty_videoram_d;
+static UINT8 *dirty_chardata_d;
+static UINT8 *dirty_videoram_e;
+static UINT8 *dirty_chardata_e;
+static UINT8 *dirty_videoram_f;
+static UINT8 *dirty_chardata_f;
+
+static int d_offset;
+static int e_offset;
+static int f_offset;
+
+static int palette_select;
+
+static mame_bitmap *tmpbitmap2;
+static mame_bitmap *bitmap_B;
+static mame_bitmap *bitmap_D;
+static mame_bitmap *bitmap_E;
+static mame_bitmap *bitmap_F;
+
+static UINT8 *beamdata;
+static int states_per_frame;
+
+#define DIRTY_CHARDATA_SIZE 0x100
+#define BEAMDATA_SIZE 0x800
+
+/* The first 16 came from the 7448 BCD to 7-segment decoder data sheet */
+/* The rest are made up */
+
+static UINT8 stactics_special_chars[32*8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Space */
+ 0x80, 0x80, 0x80, 0xf0, 0x80, 0x80, 0xf0, 0x00, /* extras... */
+ 0xf0, 0x80, 0x80, 0xf0, 0x00, 0x00, 0xf0, 0x00, /* extras... */
+ 0x90, 0x90, 0x90, 0xf0, 0x00, 0x00, 0x00, 0x00, /* extras... */
+ 0x00, 0x00, 0x00, 0xf0, 0x10, 0x10, 0xf0, 0x00, /* extras... */
+ 0x00, 0x00, 0x00, 0xf0, 0x80, 0x80, 0xf0, 0x00, /* extras... */
+ 0xf0, 0x90, 0x90, 0xf0, 0x10, 0x10, 0xf0, 0x00, /* 9 */
+ 0xf0, 0x90, 0x90, 0xf0, 0x90, 0x90, 0xf0, 0x00, /* 8 */
+ 0xf0, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, /* 7 */
+ 0xf0, 0x80, 0x80, 0xf0, 0x90, 0x90, 0xf0, 0x00, /* 6 */
+ 0xf0, 0x80, 0x80, 0xf0, 0x10, 0x10, 0xf0, 0x00, /* 5 */
+ 0x90, 0x90, 0x90, 0xf0, 0x10, 0x10, 0x10, 0x00, /* 4 */
+ 0xf0, 0x10, 0x10, 0xf0, 0x10, 0x10, 0xf0, 0x00, /* 3 */
+ 0xf0, 0x10, 0x10, 0xf0, 0x80, 0x80, 0xf0, 0x00, /* 2 */
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, /* 1 */
+ 0xf0, 0x90, 0x90, 0x90, 0x90, 0x90, 0xf0, 0x00, /* 0 */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Space */
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1 pip */
+ 0x60, 0x90, 0x80, 0x60, 0x10, 0x90, 0x60, 0x00, /* S for Score */
+ 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 pips */
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 3 pips */
+ 0x60, 0x90, 0x80, 0x80, 0x80, 0x90, 0x60, 0x00, /* C for Credits */
+ 0xe0, 0x90, 0x90, 0xe0, 0x90, 0x90, 0xe0, 0x00, /* B for Barriers */
+ 0xe0, 0x90, 0x90, 0xe0, 0xc0, 0xa0, 0x90, 0x00, /* R for Rounds */
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 4 pips */
+ 0x00, 0x60, 0x60, 0x00, 0x60, 0x60, 0x00, 0x00, /* Colon */
+ 0x40, 0xe0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, /* Sight */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Space (Unused) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Space (Unused) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Space (Unused) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Space (Unused) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* Space */
+};
+
+
+static int firebeam_state;
+static int old_firebeam_state;
+
+PALETTE_INIT( stactics )
+{
+ int i,j;
+
+ for (i=0;i<16;i++)
+ {
+ int bit0,bit1,bit2, bit3,r,g,b;
+
+ bit0 = i & 1;
+ bit1 = (i >> 1) & 1;
+ bit2 = (i >> 2) & 1;
+ bit3 = (i >> 3) & 1;
+
+ /* red component */
+ r = 0xff * bit0;
+
+ /* green component */
+ g = 0xff * bit1 - 0xcc * bit3;
+
+ /* blue component */
+ b = 0xff * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ /* The color prom in Space Tactics is used for both */
+ /* color codes, and priority layering of the 4 layers */
+
+ /* Since we are taking care of the layering by our */
+ /* drawing order, we don't need all of the color prom */
+ /* entries */
+
+ /* For each of 4 color schemes */
+ for(i=0;i<4;i++)
+ {
+ /* For page B - Alphanumerics and alien shots */
+ for(j=0;j<16;j++)
+ {
+ *(colortable++) = 0;
+ *(colortable++) = color_prom[i*0x100+0x01*0x10+j];
+ }
+ /* For page F - Close Aliens (these are all the same color) */
+ for(j=0;j<16;j++)
+ {
+ *(colortable++) = 0;
+ *(colortable++) = color_prom[i*0x100+0x02*0x10];
+ }
+ /* For page E - Medium Aliens (these are all the same color) */
+ for(j=0;j<16;j++)
+ {
+ *(colortable++) = 0;
+ *(colortable++) = color_prom[i*0x100+0x04*0x10+j];
+ }
+ /* For page D - Far Aliens (these are all the same color) */
+ for(j=0;j<16;j++)
+ {
+ *(colortable++) = 0;
+ *(colortable++) = color_prom[i*0x100+0x08*0x10+j];
+ }
+ }
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( stactics )
+{
+ int i,j;
+ const UINT8 *firebeam_data;
+ UINT8 firechar[256*8*9];
+
+ tmpbitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ tmpbitmap2 = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ bitmap_B = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ bitmap_D = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ bitmap_E = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ bitmap_F = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ /* Allocate dirty buffers */
+ dirty_videoram_b = auto_malloc(videoram_size);
+ dirty_videoram_d = auto_malloc(videoram_size);
+ dirty_videoram_e = auto_malloc(videoram_size);
+ dirty_videoram_f = auto_malloc(videoram_size);
+ dirty_chardata_b = auto_malloc(DIRTY_CHARDATA_SIZE);
+ dirty_chardata_d = auto_malloc(DIRTY_CHARDATA_SIZE);
+ dirty_chardata_e = auto_malloc(DIRTY_CHARDATA_SIZE);
+ dirty_chardata_f = auto_malloc(DIRTY_CHARDATA_SIZE);
+
+ memset(dirty_videoram_b,1,videoram_size);
+ memset(dirty_videoram_d,1,videoram_size);
+ memset(dirty_videoram_e,1,videoram_size);
+ memset(dirty_videoram_f,1,videoram_size);
+ memset(dirty_chardata_b,1,DIRTY_CHARDATA_SIZE);
+ memset(dirty_chardata_d,1,DIRTY_CHARDATA_SIZE);
+ memset(dirty_chardata_e,1,DIRTY_CHARDATA_SIZE);
+ memset(dirty_chardata_f,1,DIRTY_CHARDATA_SIZE);
+
+ d_offset = 0;
+ e_offset = 0;
+ f_offset = 0;
+
+ palette_select = 0;
+ stactics_vblank_count = 0;
+ stactics_shot_standby = 1;
+ stactics_shot_arrive = 0;
+ firebeam_state = 0;
+ old_firebeam_state = 0;
+
+ /* Create a fake character set for LED fire beam */
+
+ memset(firechar,0,sizeof(firechar));
+ for(i=0;i<256;i++)
+ {
+ for(j=0;j<8;j++)
+ {
+ if ((i>>j)&0x01)
+ {
+ firechar[i*9+(7-j)] |= (0x01<<(7-j));
+ firechar[i*9+(7-j)+1] |= (0x01<<(7-j));
+ }
+ }
+ }
+
+ for(i=0;i<256;i++)
+ {
+ decodechar(machine->gfx[4],
+ i,
+ firechar,
+ machine->drv->gfxdecodeinfo[4].gfxlayout);
+ }
+
+ /* Decode the Fire Beam ROM for later */
+ /* (I am basically just juggling the bytes */
+ /* and storing it again to make it easier) */
+
+ beamdata = auto_malloc(BEAMDATA_SIZE);
+
+ firebeam_data = memory_region(REGION_GFX1);
+
+ for(i=0;i<256;i++)
+ {
+ beamdata[i*8] = firebeam_data[i ];
+ beamdata[i*8+1] = firebeam_data[i + 1024 ];
+ beamdata[i*8+2] = firebeam_data[i + 256];
+ beamdata[i*8+3] = firebeam_data[i + 1024 + 256];
+ beamdata[i*8+4] = firebeam_data[i + 512 ];
+ beamdata[i*8+5] = firebeam_data[i + 1024 + 512 ];
+ beamdata[i*8+6] = firebeam_data[i + 512 + 256];
+ beamdata[i*8+7] = firebeam_data[i + 1024 + 512 + 256];
+ }
+
+ /* Build some characters for simulating the LED displays */
+
+ for(i=0;i<32;i++)
+ {
+ decodechar(machine->gfx[5],
+ i,
+ stactics_special_chars,
+ machine->drv->gfxdecodeinfo[5].gfxlayout);
+ }
+
+ stactics_vblank_count = 0;
+ stactics_vert_pos = 0;
+ stactics_horiz_pos = 0;
+ *stactics_motor_on = 0;
+}
+
+
+WRITE8_HANDLER( stactics_palette_w )
+{
+ int old_palette_select = palette_select;
+
+ switch (offset)
+ {
+ case 0:
+ palette_select = (palette_select & 0x02) | (data&0x01);
+ break;
+ case 1:
+ palette_select = (palette_select & 0x01) | ((data&0x01)<<1);
+ break;
+ default:
+ return;
+ }
+
+ if (old_palette_select != palette_select)
+ {
+ memset(dirty_videoram_b,1,videoram_size);
+ memset(dirty_videoram_d,1,videoram_size);
+ memset(dirty_videoram_e,1,videoram_size);
+ memset(dirty_videoram_f,1,videoram_size);
+ }
+ return;
+}
+
+
+WRITE8_HANDLER( stactics_scroll_ram_w )
+{
+ int temp;
+
+ if (stactics_scroll_ram[offset] != data)
+ {
+ stactics_scroll_ram[offset] = data;
+ temp = (offset&0x700)>>8;
+ switch(temp)
+ {
+ case 4: // Page D
+ {
+ if (data&0x01)
+ d_offset = offset&0xff;
+ break;
+ }
+ case 5: // Page E
+ {
+ if (data&0x01)
+ e_offset = offset&0xff;
+ break;
+ }
+ case 6: // Page F
+ {
+ if (data&0x01)
+ f_offset = offset&0xff;
+ break;
+ }
+ }
+ }
+}
+
+WRITE8_HANDLER( stactics_speed_latch_w )
+{
+ /* This writes to a shift register which is clocked by */
+ /* a 555 oscillator. This value determines the speed of */
+ /* the LED fire beams as follows: */
+
+ /* 555_freq / bits_in_SR * edges_in_SR / states_in_PR67 / frame_rate */
+ /* = num_led_states_per_frame */
+ /* 36439 / 8 * x / 32 / 60 ~= 19/8*x */
+
+ /* Here, we will count the number of rising edges in the shift register */
+
+ int i;
+ int num_rising_edges = 0;
+
+ for(i=0;i<8;i++)
+ {
+ if ( (((data>>i)&0x01) == 1) && (((data>>((i+1)%8))&0x01) == 0))
+ num_rising_edges++;
+ }
+
+ states_per_frame = num_rising_edges*19/8;
+}
+
+WRITE8_HANDLER( stactics_shot_trigger_w )
+{
+ stactics_shot_standby = 0;
+}
+
+WRITE8_HANDLER( stactics_shot_flag_clear_w )
+{
+ stactics_shot_arrive = 0;
+}
+
+WRITE8_HANDLER( stactics_videoram_b_w )
+{
+ if (stactics_videoram_b[offset] != data)
+ {
+ stactics_videoram_b[offset] = data;
+ dirty_videoram_b[offset] = 1;
+ }
+}
+
+WRITE8_HANDLER( stactics_chardata_b_w )
+{
+ if (stactics_chardata_b[offset] != data)
+ {
+ stactics_chardata_b[offset] = data;
+ dirty_chardata_b[offset>>3] = 1;
+ }
+}
+
+WRITE8_HANDLER( stactics_videoram_d_w )
+{
+ if (stactics_videoram_d[offset] != data)
+ {
+ stactics_videoram_d[offset] = data;
+ dirty_videoram_d[offset] = 1;
+ }
+}
+
+WRITE8_HANDLER( stactics_chardata_d_w )
+{
+ if (stactics_chardata_d[offset] != data)
+ {
+ stactics_chardata_d[offset] = data;
+ dirty_chardata_d[offset>>3] = 1;
+ }
+}
+
+WRITE8_HANDLER( stactics_videoram_e_w )
+{
+ if (stactics_videoram_e[offset] != data)
+ {
+ stactics_videoram_e[offset] = data;
+ dirty_videoram_e[offset] = 1;
+ }
+}
+
+WRITE8_HANDLER( stactics_chardata_e_w )
+{
+ if (stactics_chardata_e[offset] != data)
+ {
+ stactics_chardata_e[offset] = data;
+ dirty_chardata_e[offset>>3] = 1;
+ }
+}
+
+WRITE8_HANDLER( stactics_videoram_f_w )
+{
+ if (stactics_videoram_f[offset] != data)
+ {
+ stactics_videoram_f[offset] = data;
+ dirty_videoram_f[offset] = 1;
+ }
+}
+
+WRITE8_HANDLER( stactics_chardata_f_w )
+{
+ if (stactics_chardata_f[offset] != data)
+ {
+ stactics_chardata_f[offset] = data;
+ dirty_chardata_f[offset>>3] = 1;
+ }
+}
+
+/* Actual area for visible monitor stuff is only 30*8 lines */
+/* The rest is used for the score, etc. */
+
+static const rectangle visible_screen_area = {0*8, 32*8, 0*8, 30*8};
+
+VIDEO_UPDATE( stactics )
+{
+ int offs, sx, sy, i;
+ int char_number;
+ int color_code;
+ int pixel_x, pixel_y;
+
+ int palette_offset = palette_select * 64;
+
+ for(offs=0x400-1; offs>=0; offs--)
+ {
+ sx = offs%32;
+ sy = offs/32;
+
+ color_code = palette_offset + (stactics_videoram_b[offs]>>4);
+
+ /* Draw aliens in Page D */
+
+ char_number = stactics_videoram_d[offs];
+
+ if (dirty_chardata_d[char_number] == 1)
+ {
+ decodechar(machine->gfx[3],
+ char_number,
+ stactics_chardata_d,
+ machine->drv->gfxdecodeinfo[3].gfxlayout);
+ dirty_chardata_d[char_number] = 2;
+ dirty_videoram_d[offs] = 1;
+ }
+ else if (dirty_chardata_d[char_number] == 2)
+ {
+ dirty_videoram_d[offs] = 1;
+ }
+
+ if (dirty_videoram_d[offs])
+ {
+ drawgfx(bitmap_D,machine->gfx[3],
+ char_number,
+ color_code,
+ 0,0,
+ sx*8,sy*8,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ dirty_videoram_d[offs] = 0;
+ }
+
+ /* Draw aliens in Page E */
+
+ char_number = stactics_videoram_e[offs];
+
+ if (dirty_chardata_e[char_number] == 1)
+ {
+ decodechar(machine->gfx[2],
+ char_number,
+ stactics_chardata_e,
+ machine->drv->gfxdecodeinfo[2].gfxlayout);
+ dirty_chardata_e[char_number] = 2;
+ dirty_videoram_e[offs] = 1;
+ }
+ else if (dirty_chardata_e[char_number] == 2)
+ {
+ dirty_videoram_e[offs] = 1;
+ }
+
+ if (dirty_videoram_e[offs])
+ {
+ drawgfx(bitmap_E,machine->gfx[2],
+ char_number,
+ color_code,
+ 0,0,
+ sx*8,sy*8,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ dirty_videoram_e[offs] = 0;
+ }
+
+ /* Draw aliens in Page F */
+
+ char_number = stactics_videoram_f[offs];
+
+ if (dirty_chardata_f[char_number] == 1)
+ {
+ decodechar(machine->gfx[1],
+ char_number,
+ stactics_chardata_f,
+ machine->drv->gfxdecodeinfo[1].gfxlayout);
+ dirty_chardata_f[char_number] = 2;
+ dirty_videoram_f[offs] = 1;
+ }
+ else if (dirty_chardata_f[char_number] == 2)
+ {
+ dirty_videoram_f[offs] = 1;
+ }
+
+ if (dirty_videoram_f[offs])
+ {
+ drawgfx(bitmap_F,machine->gfx[1],
+ char_number,
+ color_code,
+ 0,0,
+ sx*8,sy*8,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ dirty_videoram_f[offs] = 0;
+ }
+
+ /* Draw the page B stuff */
+
+ char_number = stactics_videoram_b[offs];
+
+ if (dirty_chardata_b[char_number] == 1)
+ {
+ decodechar(machine->gfx[0],
+ char_number,
+ stactics_chardata_b,
+ machine->drv->gfxdecodeinfo[0].gfxlayout);
+ dirty_chardata_b[char_number] = 2;
+ dirty_videoram_b[offs] = 1;
+ }
+ else if (dirty_chardata_b[char_number] == 2)
+ {
+ dirty_videoram_b[offs] = 1;
+ }
+
+ if (dirty_videoram_b[offs])
+ {
+ drawgfx(bitmap_B,machine->gfx[0],
+ char_number,
+ color_code,
+ 0,0,
+ sx*8,sy*8,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ dirty_videoram_b[offs] = 0;
+ }
+
+ }
+
+ /* Now, composite the four layers together */
+
+ copyscrollbitmap(tmpbitmap2,bitmap_D,0,0,1,&d_offset,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ copyscrollbitmap(tmpbitmap2,bitmap_E,0,0,1,&e_offset,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+ copyscrollbitmap(tmpbitmap2,bitmap_F,0,0,1,&f_offset,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+ copybitmap(tmpbitmap2,bitmap_B,0,0,0,0,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+
+ /* Now flip X & simulate the monitor motion */
+ fillbitmap(bitmap, machine->pens[0], &machine->screen[0].visarea);
+ copybitmap(bitmap,tmpbitmap2,1,0,stactics_horiz_pos,stactics_vert_pos,
+ &visible_screen_area,TRANSPARENCY_NONE,0);
+
+ /* Finally, draw stuff that is on the console or on top of the monitor (LED's) */
+
+ /***** Draw Score Display *****/
+
+ pixel_x = 16;
+ pixel_y = 248;
+
+ /* Draw an S */
+ drawgfx(bitmap,machine->gfx[5],
+ 18,
+ 0,
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ pixel_x+=6;
+ /* Draw a colon */
+ drawgfx(bitmap,machine->gfx[5],
+ 25,
+ 0,
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ pixel_x+=6;
+ /* Draw the digits */
+ for(i=1;i<7;i++)
+ {
+ drawgfx(bitmap,machine->gfx[5],
+ stactics_display_buffer[i]&0x0f,
+ 16,
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ pixel_x+=6;
+ }
+
+ /***** Draw Credits Indicator *****/
+
+ pixel_x = 64+16;
+
+ /* Draw a C */
+ drawgfx(bitmap,machine->gfx[5],
+ 21,
+ 0,
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ pixel_x+=6;
+ /* Draw a colon */
+ drawgfx(bitmap,machine->gfx[5],
+ 25,
+ 0,
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ pixel_x+=6;
+ /* Draw the pips */
+ for(i=7;i<9;i++)
+ {
+ drawgfx(bitmap,machine->gfx[5],
+ 16 + (~stactics_display_buffer[i]&0x0f),
+ 16,
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ pixel_x+=2;
+ }
+
+ /***** Draw Rounds Indicator *****/
+
+ pixel_x = 128+16;
+
+ /* Draw an R */
+ drawgfx(bitmap,machine->gfx[5],
+ 22,
+ 0,
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ pixel_x+=6;
+ /* Draw a colon */
+ drawgfx(bitmap,machine->gfx[5],
+ 25,
+ 0,
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ pixel_x+=6;
+ /* Draw the pips */
+ for(i=9;i<12;i++)
+ {
+ drawgfx(bitmap,machine->gfx[5],
+ 16 + (~stactics_display_buffer[i]&0x0f),
+ 16,
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ pixel_x+=2;
+ }
+
+ /***** Draw Barriers Indicator *****/
+
+ pixel_x = 192+16;
+ /* Draw a B */
+ drawgfx(bitmap,machine->gfx[5],
+ 23,
+ 0,
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ pixel_x+=6;
+ /* Draw a colon */
+ drawgfx(bitmap,machine->gfx[5],
+ 25,
+ 0,
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ pixel_x+=6;
+ /* Draw the pips */
+ for(i=12;i<16;i++)
+ {
+ drawgfx(bitmap,machine->gfx[5],
+ 16 + (~stactics_display_buffer[i]&0x0f),
+ 16,
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ pixel_x+=2;
+ }
+
+ /* An LED fire beam! */
+ /* (There were 120 green LEDS mounted in the cabinet in the game, */
+ /* and one red one, for the sight) */
+
+ /* First, update the firebeam state */
+
+ old_firebeam_state = firebeam_state;
+ if (stactics_shot_standby == 0)
+ {
+ firebeam_state = (firebeam_state + states_per_frame)%512;
+ }
+
+ /* These are thresholds for the two shots from the LED fire ROM */
+ /* (Note: There are two more for sound triggers, */
+ /* whenever that gets implemented) */
+
+ if ((old_firebeam_state < 0x8b) & (firebeam_state >= 0x8b))
+ stactics_shot_arrive = 1;
+
+ if ((old_firebeam_state < 0xca) & (firebeam_state >= 0xca))
+ stactics_shot_arrive = 1;
+
+ if (firebeam_state > 255)
+ {
+ firebeam_state = 0;
+ stactics_shot_standby = 1;
+ }
+
+ /* Now, draw the beam */
+
+ pixel_x = 15;
+ pixel_y = 166;
+
+ for(i=0;i<8;i++)
+ {
+ if ((i%2)==1)
+ {
+ /* Draw 7 LEDS on each side */
+ drawgfx(bitmap,machine->gfx[4],
+ beamdata[firebeam_state*8+i]&0x7f,
+ 16*2, /* Make it green */
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+ drawgfx(bitmap,machine->gfx[4],
+ beamdata[firebeam_state*8+i]&0x7f,
+ 16*2, /* Make it green */
+ 1,0,
+ 255-pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+ pixel_x+=14;
+ pixel_y-=7;
+ }
+ else
+ {
+ /* Draw 8 LEDS on each side */
+ drawgfx(bitmap,machine->gfx[4],
+ beamdata[firebeam_state*8+i],
+ 16*2, /* Make it green */
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+ drawgfx(bitmap,machine->gfx[4],
+ beamdata[firebeam_state*8+i],
+ 16*2, /* Make it green */
+ 1,0,
+ 255-pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+ pixel_x+=16;
+ pixel_y-=8;
+ }
+
+ }
+
+ /* Red Sight LED */
+
+ pixel_x = 134;
+ pixel_y = 112;
+
+ if (*stactics_motor_on & 0x01)
+ {
+ drawgfx(bitmap,machine->gfx[5],
+ 26,
+ 16, /* red */
+ 0,0,
+ pixel_x,pixel_y,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+ }
+
+ /* Update vblank counter */
+ stactics_vblank_count++;
+
+ /* reset dirty flags */
+ for(i=0;i<0xff;i++)
+ {
+ dirty_chardata_b[i] &= 0x01;
+ dirty_chardata_d[i] &= 0x01;
+ dirty_chardata_e[i] &= 0x01;
+ dirty_chardata_f[i] &= 0x01;
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/stadhero.c b/src/mame/video/stadhero.c
new file mode 100644
index 00000000000..71f299c588d
--- /dev/null
+++ b/src/mame/video/stadhero.c
@@ -0,0 +1,169 @@
+/***************************************************************************
+
+ stadhero video emulation - Bryan McPhail, mish@tendril.co.uk
+
+*********************************************************************
+
+ MXC-06 chip to produce sprites, see dec0.c
+ BAC-06 chip for background?
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *stadhero_pf1_data,*stadhero_pf2_data;
+static tilemap *pf1_tilemap,*pf2_tilemap;
+static int flipscreen;
+
+static UINT16 stadhero_pf2_control_0[8];
+static UINT16 stadhero_pf2_control_1[8];
+
+/******************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int pri_mask,int pri_val)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ y = spriteram16[offs];
+ if ((y&0x8000) == 0) continue;
+
+ x = spriteram16[offs+2];
+ colour = x >> 12;
+ if ((colour & pri_mask) != pri_val) continue;
+
+ flash=x&0x800;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x1800) >> 11)) - 1; /* 1x, 2x, 4x, 8x height */
+ /* multi = 0 1 3 7 */
+
+ sprite = spriteram16[offs+1] & 0x0fff;
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 256) x -= 512;
+ if (y >= 256) y -= 512;
+ x = 240 - x;
+ y = 240 - y;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen) {
+ y=240-y;
+ x=240-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+ multi--;
+ }
+ }
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( stadhero )
+{
+ flipscreen=stadhero_pf2_control_0[0]&0x80;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ tilemap_set_scrollx( pf2_tilemap,0, stadhero_pf2_control_1[0] );
+ tilemap_set_scrolly( pf2_tilemap,0, stadhero_pf2_control_1[1] );
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect,0x00,0x00);
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ return 0;
+}
+
+/******************************************************************************/
+
+WRITE16_HANDLER( stadhero_pf1_data_w )
+{
+ COMBINE_DATA(&stadhero_pf1_data[offset]);
+ tilemap_mark_tile_dirty(pf1_tilemap,offset);
+}
+
+WRITE16_HANDLER( stadhero_pf2_data_w )
+{
+ COMBINE_DATA(&stadhero_pf2_data[offset]);
+ tilemap_mark_tile_dirty(pf2_tilemap,offset);
+}
+
+WRITE16_HANDLER( stadhero_pf2_control_0_w )
+{
+ COMBINE_DATA(&stadhero_pf2_control_0[offset]);
+}
+
+WRITE16_HANDLER( stadhero_pf2_control_1_w )
+{
+ COMBINE_DATA(&stadhero_pf2_control_1[offset]);
+}
+
+/******************************************************************************/
+
+static TILEMAP_MAPPER( stadhero_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0xf) + ((row & 0xf) << 4) + ((row & 0x30) << 4) + ((col & 0x30) << 6);
+}
+
+static TILE_GET_INFO( get_pf2_tile_info )
+{
+ int tile,color;
+
+ tile=stadhero_pf2_data[tile_index];
+ color=tile >> 12;
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 1,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_pf1_tile_info )
+{
+ int tile=stadhero_pf1_data[tile_index];
+ int color=tile >> 12;
+
+ tile=tile&0xfff;
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+VIDEO_START( stadhero )
+{
+ pf1_tilemap = tilemap_create(get_pf1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+ pf2_tilemap = tilemap_create(get_pf2_tile_info,stadhero_scan,TILEMAP_TYPE_PEN, 16,16,64,64);
+
+ tilemap_set_transparent_pen(pf1_tilemap,0);
+}
+
+/******************************************************************************/
diff --git a/src/mame/video/starcrus.c b/src/mame/video/starcrus.c
new file mode 100644
index 00000000000..8549e32c526
--- /dev/null
+++ b/src/mame/video/starcrus.c
@@ -0,0 +1,572 @@
+
+/* Ramtek - Star Cruiser */
+
+#include "driver.h"
+#include "sound/samples.h"
+
+static mame_bitmap *ship1_vid;
+static mame_bitmap *ship2_vid;
+static mame_bitmap *proj1_vid;
+static mame_bitmap *proj2_vid;
+
+static int s1_x = 0;
+static int s1_y = 0;
+static int s2_x = 0;
+static int s2_y = 0;
+static int p1_x = 0;
+static int p1_y = 0;
+static int p2_x = 0;
+static int p2_y = 0;
+
+static int p1_sprite = 0;
+static int p2_sprite = 0;
+static int s1_sprite = 0;
+static int s2_sprite = 0;
+
+static int engine1_on = 0;
+static int engine2_on = 0;
+static int explode1_on = 0;
+static int explode2_on = 0;
+static int launch1_on = 0;
+static int launch2_on = 0;
+
+/* The collision detection techniques use in this driver
+ are well explained in the comments in the sprint2 driver */
+
+static int collision_reg = 0x00;
+
+/* I hate to have sound in video, but the sprite and
+ audio bits are in the same bytes, and there are so few
+ samples... */
+
+int starcrus_engine_sound_playing = 0;
+int starcrus_explode_sound_playing = 0;
+int starcrus_launch1_sound_playing = 0;
+int starcrus_launch2_sound_playing = 0;
+
+WRITE8_HANDLER( starcrus_s1_x_w ) { s1_x = data^0xff; }
+WRITE8_HANDLER( starcrus_s1_y_w ) { s1_y = data^0xff; }
+WRITE8_HANDLER( starcrus_s2_x_w ) { s2_x = data^0xff; }
+WRITE8_HANDLER( starcrus_s2_y_w ) { s2_y = data^0xff; }
+WRITE8_HANDLER( starcrus_p1_x_w ) { p1_x = data^0xff; }
+WRITE8_HANDLER( starcrus_p1_y_w ) { p1_y = data^0xff; }
+WRITE8_HANDLER( starcrus_p2_x_w ) { p2_x = data^0xff; }
+WRITE8_HANDLER( starcrus_p2_y_w ) { p2_y = data^0xff; }
+
+VIDEO_START( starcrus )
+{
+ ship1_vid = auto_bitmap_alloc(16,16,machine->screen[0].format);
+ ship2_vid = auto_bitmap_alloc(16,16,machine->screen[0].format);
+
+ proj1_vid = auto_bitmap_alloc(16,16,machine->screen[0].format);
+ proj2_vid = auto_bitmap_alloc(16,16,machine->screen[0].format);
+}
+
+WRITE8_HANDLER( starcrus_ship_parm_1_w )
+{
+ s1_sprite = data&0x1f;
+ engine1_on = ((data&0x20)>>5)^0x01;
+
+ if (engine1_on || engine2_on)
+ {
+ if (starcrus_engine_sound_playing == 0)
+ {
+ starcrus_engine_sound_playing = 1;
+ sample_start(0,0,1); /* engine sample */
+
+ }
+ }
+ else
+ {
+ if (starcrus_engine_sound_playing == 1)
+ {
+ starcrus_engine_sound_playing = 0;
+ sample_stop(0);
+ }
+ }
+}
+
+WRITE8_HANDLER( starcrus_ship_parm_2_w )
+{
+ s2_sprite = data&0x1f;
+ set_led_status(2,~data & 0x80); /* game over lamp */
+ coin_counter_w(0, ((data&0x40)>>6)^0x01); /* coin counter */
+ engine2_on = ((data&0x20)>>5)^0x01;
+
+ if (engine1_on || engine2_on)
+ {
+ if (starcrus_engine_sound_playing == 0)
+ {
+ starcrus_engine_sound_playing = 1;
+ sample_start(0,0,1); /* engine sample */
+ }
+ }
+ else
+ {
+ if (starcrus_engine_sound_playing == 1)
+ {
+ starcrus_engine_sound_playing = 0;
+ sample_stop(0);
+ }
+ }
+
+}
+
+WRITE8_HANDLER( starcrus_proj_parm_1_w )
+{
+ p1_sprite = data&0x0f;
+ launch1_on = ((data&0x20)>>5)^0x01;
+ explode1_on = ((data&0x10)>>4)^0x01;
+
+ if (explode1_on || explode2_on)
+ {
+ if (starcrus_explode_sound_playing == 0)
+ {
+ starcrus_explode_sound_playing = 1;
+ sample_start(1,1,1); /* explosion initial sample */
+ }
+ }
+ else
+ {
+ if (starcrus_explode_sound_playing == 1)
+ {
+ starcrus_explode_sound_playing = 0;
+ sample_start(1,2,0); /* explosion ending sample */
+ }
+ }
+
+ if (launch1_on)
+ {
+ if (starcrus_launch1_sound_playing == 0)
+ {
+ starcrus_launch1_sound_playing = 1;
+ sample_start(2,3,0); /* launch sample */
+ }
+ }
+ else
+ {
+ starcrus_launch1_sound_playing = 0;
+ }
+}
+
+WRITE8_HANDLER( starcrus_proj_parm_2_w )
+{
+ p2_sprite = data&0x0f;
+ launch2_on = ((data&0x20)>>5)^0x01;
+ explode2_on = ((data&0x10)>>4)^0x01;
+
+ if (explode1_on || explode2_on)
+ {
+ if (starcrus_explode_sound_playing == 0)
+ {
+ starcrus_explode_sound_playing = 1;
+ sample_start(1,1,1); /* explosion initial sample */
+ }
+ }
+ else
+ {
+ if (starcrus_explode_sound_playing == 1)
+ {
+ starcrus_explode_sound_playing = 0;
+ sample_start(1,2,0); /* explosion ending sample */
+ }
+ }
+
+ if (launch2_on)
+ {
+ if (starcrus_launch2_sound_playing == 0)
+ {
+ starcrus_launch2_sound_playing = 1;
+ sample_start(3,3,0); /* launch sample */
+ }
+ }
+ else
+ {
+ starcrus_launch2_sound_playing = 0;
+ }
+}
+
+static int collision_check_s1s2(running_machine *machine)
+{
+ int org_x, org_y;
+ int sx, sy;
+ rectangle clip;
+
+ clip.min_x=0;
+ clip.max_x=15;
+ clip.min_y=0;
+ clip.max_y=15;
+
+ fillbitmap(ship1_vid,machine->pens[0],&clip);
+ fillbitmap(ship2_vid,machine->pens[0],&clip);
+
+ /* origin is with respect to ship1 */
+
+ org_x = s1_x;
+ org_y = s1_y;
+
+ /* Draw ship 1 */
+ drawgfx(ship1_vid,
+ machine->gfx[8+((s1_sprite&0x04)>>2)],
+ (s1_sprite&0x03)^0x03,
+ 0,
+ (s1_sprite&0x08)>>3,(s1_sprite&0x10)>>4,
+ s1_x-org_x,s1_y-org_y,
+ &clip,
+ TRANSPARENCY_NONE,
+ 0);
+
+ /* Draw ship 2 */
+ drawgfx(ship2_vid,
+ machine->gfx[10+((s2_sprite&0x04)>>2)],
+ (s2_sprite&0x03)^0x03,
+ 0,
+ (s2_sprite&0x08)>>3,(s2_sprite&0x10)>>4,
+ s2_x-org_x,s2_y-org_y,
+ &clip,
+ TRANSPARENCY_NONE,
+ 0);
+
+ /* Now check for collisions */
+ for (sy=0;sy<16;sy++)
+ {
+ for (sx=0;sx<16;sx++)
+ {
+ if (*BITMAP_ADDR16(ship1_vid, sy, sx)==machine->pens[1])
+ {
+ /* Condition 1 - ship 1 = ship 2 */
+ if (*BITMAP_ADDR16(ship2_vid, sy, sx)==machine->pens[1])
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int collision_check_p1p2(running_machine *machine)
+{
+ int org_x, org_y;
+ int sx, sy;
+ rectangle clip;
+
+ /* if both are scores, return */
+ if ( ((p1_sprite & 0x08) == 0) &&
+ ((p2_sprite & 0x08) == 0) )
+ {
+ return 0;
+ }
+
+ clip.min_x=0;
+ clip.max_x=15;
+ clip.min_y=0;
+ clip.max_y=15;
+
+ fillbitmap(proj1_vid,machine->pens[0],&clip);
+ fillbitmap(proj2_vid,machine->pens[0],&clip);
+
+ /* origin is with respect to proj1 */
+
+ org_x = p1_x;
+ org_y = p1_y;
+
+ if (p1_sprite & 0x08) /* if p1 is a projectile */
+ {
+ /* Draw score/projectile 1 */
+ drawgfx(proj1_vid,
+ machine->gfx[(p1_sprite&0x0c)>>2],
+ (p1_sprite&0x03)^0x03,
+ 0,
+ 0,0,
+ p1_x-org_x,p1_y-org_y,
+ &clip,
+ TRANSPARENCY_NONE,
+ 0);
+ }
+
+ if (p2_sprite & 0x08) /* if p2 is a projectile */
+ {
+ /* Draw score/projectile 2 */
+ drawgfx(proj2_vid,
+ machine->gfx[4+((p2_sprite&0x0c)>>2)],
+ (p2_sprite&0x03)^0x03,
+ 0,
+ 0,0,
+ p2_x-org_x,p2_y-org_y,
+ &clip,
+ TRANSPARENCY_NONE,
+ 0);
+ }
+
+ /* Now check for collisions */
+ for (sy=0;sy<16;sy++)
+ {
+ for (sx=0;sx<16;sx++)
+ {
+ if (*BITMAP_ADDR16(proj1_vid, sy, sx)==machine->pens[1])
+ {
+ /* Condition 1 - proj 1 = proj 2 */
+ if (*BITMAP_ADDR16(proj2_vid, sy, sx)==machine->pens[1])
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int collision_check_s1p1p2(running_machine *machine)
+{
+ int org_x, org_y;
+ int sx, sy;
+ rectangle clip;
+
+ /* if both are scores, return */
+ if ( ((p1_sprite & 0x08) == 0) &&
+ ((p2_sprite & 0x08) == 0) )
+ {
+ return 0;
+ }
+
+ clip.min_x=0;
+ clip.max_x=15;
+ clip.min_y=0;
+ clip.max_y=15;
+
+ fillbitmap(ship1_vid,machine->pens[0],&clip);
+ fillbitmap(proj1_vid,machine->pens[0],&clip);
+ fillbitmap(proj2_vid,machine->pens[0],&clip);
+
+ /* origin is with respect to ship1 */
+
+ org_x = s1_x;
+ org_y = s1_y;
+
+ /* Draw ship 1 */
+ drawgfx(ship1_vid,
+ machine->gfx[8+((s1_sprite&0x04)>>2)],
+ (s1_sprite&0x03)^0x03,
+ 0,
+ (s1_sprite&0x08)>>3,(s1_sprite&0x10)>>4,
+ s1_x-org_x,s1_y-org_y,
+ &clip,
+ TRANSPARENCY_NONE,
+ 0);
+
+ if (p1_sprite & 0x08) /* if p1 is a projectile */
+ {
+ /* Draw projectile 1 */
+ drawgfx(proj1_vid,
+ machine->gfx[(p1_sprite&0x0c)>>2],
+ (p1_sprite&0x03)^0x03,
+ 0,
+ 0,0,
+ p1_x-org_x,p1_y-org_y,
+ &clip,
+ TRANSPARENCY_NONE,
+ 0);
+ }
+
+ if (p2_sprite & 0x08) /* if p2 is a projectile */
+ {
+ /* Draw projectile 2 */
+ drawgfx(proj2_vid,
+ machine->gfx[4+((p2_sprite&0x0c)>>2)],
+ (p2_sprite&0x03)^0x03,
+ 0,
+ 0,0,
+ p2_x-org_x,p2_y-org_y,
+ &clip,
+ TRANSPARENCY_NONE,
+ 0);
+ }
+
+ /* Now check for collisions */
+ for (sy=0;sy<16;sy++)
+ {
+ for (sx=0;sx<16;sx++)
+ {
+ if (*BITMAP_ADDR16(ship1_vid, sy, sx)==machine->pens[1])
+ {
+ /* Condition 1 - ship 1 = proj 1 */
+ if (*BITMAP_ADDR16(proj1_vid, sy, sx)==machine->pens[1])
+ return 1;
+ /* Condition 2 - ship 1 = proj 2 */
+ if (*BITMAP_ADDR16(proj2_vid, sy, sx)==machine->pens[1])
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int collision_check_s2p1p2(running_machine *machine)
+{
+ int org_x, org_y;
+ int sx, sy;
+ rectangle clip;
+
+ /* if both are scores, return */
+ if ( ((p1_sprite & 0x08) == 0) &&
+ ((p2_sprite & 0x08) == 0) )
+ {
+ return 0;
+ }
+
+ clip.min_x=0;
+ clip.max_x=15;
+ clip.min_y=0;
+ clip.max_y=15;
+
+ fillbitmap(ship2_vid,machine->pens[0],&clip);
+ fillbitmap(proj1_vid,machine->pens[0],&clip);
+ fillbitmap(proj2_vid,machine->pens[0],&clip);
+
+ /* origin is with respect to ship2 */
+
+ org_x = s2_x;
+ org_y = s2_y;
+
+ /* Draw ship 2 */
+ drawgfx(ship2_vid,
+ machine->gfx[10+((s2_sprite&0x04)>>2)],
+ (s2_sprite&0x03)^0x03,
+ 0,
+ (s2_sprite&0x08)>>3,(s2_sprite&0x10)>>4,
+ s2_x-org_x,s2_y-org_y,
+ &clip,
+ TRANSPARENCY_NONE,
+ 0);
+
+ if (p1_sprite & 0x08) /* if p1 is a projectile */
+ {
+ /* Draw projectile 1 */
+ drawgfx(proj1_vid,
+ machine->gfx[(p1_sprite&0x0c)>>2],
+ (p1_sprite&0x03)^0x03,
+ 0,
+ 0,0,
+ p1_x-org_x,p1_y-org_y,
+ &clip,
+ TRANSPARENCY_NONE,
+ 0);
+ }
+
+ if (p2_sprite & 0x08) /* if p2 is a projectile */
+ {
+ /* Draw projectile 2 */
+ drawgfx(proj2_vid,
+ machine->gfx[4+((p2_sprite&0x0c)>>2)],
+ (p2_sprite&0x03)^0x03,
+ 0,
+ 0,0,
+ p2_x-org_x,p2_y-org_y,
+ &clip,
+ TRANSPARENCY_NONE,
+ 0);
+ }
+
+ /* Now check for collisions */
+ for (sy=0;sy<16;sy++)
+ {
+ for (sx=0;sx<16;sx++)
+ {
+ if (*BITMAP_ADDR16(ship2_vid, sy, sx)==machine->pens[1])
+ {
+ /* Condition 1 - ship 2 = proj 1 */
+ if (*BITMAP_ADDR16(proj1_vid, sy, sx)==machine->pens[1])
+ return 1;
+ /* Condition 2 - ship 2 = proj 2 */
+ if (*BITMAP_ADDR16(proj2_vid, sy, sx)==machine->pens[1])
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+VIDEO_UPDATE( starcrus )
+{
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ /* Draw ship 1 */
+ drawgfx(bitmap,
+ machine->gfx[8+((s1_sprite&0x04)>>2)],
+ (s1_sprite&0x03)^0x03,
+ 0,
+ (s1_sprite&0x08)>>3,(s1_sprite&0x10)>>4,
+ s1_x,s1_y,
+ cliprect,
+ TRANSPARENCY_PEN,
+ 0);
+
+ /* Draw ship 2 */
+ drawgfx(bitmap,
+ machine->gfx[10+((s2_sprite&0x04)>>2)],
+ (s2_sprite&0x03)^0x03,
+ 0,
+ (s2_sprite&0x08)>>3,(s2_sprite&0x10)>>4,
+ s2_x,s2_y,
+ cliprect,
+ TRANSPARENCY_PEN,
+ 0);
+
+ /* Draw score/projectile 1 */
+ drawgfx(bitmap,
+ machine->gfx[(p1_sprite&0x0c)>>2],
+ (p1_sprite&0x03)^0x03,
+ 0,
+ 0,0,
+ p1_x,p1_y,
+ cliprect,
+ TRANSPARENCY_PEN,
+ 0);
+
+ /* Draw score/projectile 2 */
+ drawgfx(bitmap,
+ machine->gfx[4+((p2_sprite&0x0c)>>2)],
+ (p2_sprite&0x03)^0x03,
+ 0,
+ 0,0,
+ p2_x,p2_y,
+ cliprect,
+ TRANSPARENCY_PEN,
+ 0);
+
+ /* Collision detection */
+ if (cliprect->max_y == machine->screen[screen].visarea.max_y)
+ {
+ collision_reg = 0x00;
+
+ /* Check for collisions between ship1 and ship2 */
+ if (collision_check_s1s2(machine))
+ {
+ collision_reg |= 0x08;
+ }
+ /* Check for collisions between ship1 and projectiles */
+ if (collision_check_s1p1p2(machine))
+ {
+ collision_reg |= 0x02;
+ }
+ /* Check for collisions between ship1 and projectiles */
+ if (collision_check_s2p1p2(machine))
+ {
+ collision_reg |= 0x01;
+ }
+ /* Check for collisions between ship1 and projectiles */
+ /* Note: I don't think this is used by the game */
+ if (collision_check_p1p2(machine))
+ {
+ collision_reg |= 0x04;
+ }
+ }
+
+ return 0;
+}
+
+READ8_HANDLER( starcrus_coll_det_r )
+{
+ return collision_reg ^ 0xff;
+}
diff --git a/src/mame/video/starfire.c b/src/mame/video/starfire.c
new file mode 100644
index 00000000000..4341a6ff0b8
--- /dev/null
+++ b/src/mame/video/starfire.c
@@ -0,0 +1,276 @@
+/***************************************************************************
+
+ Star Fire video system
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/starfire.h"
+
+/* local allocated storage */
+static UINT8 *scanline_dirty;
+
+static UINT8 starfire_vidctrl;
+static UINT8 starfire_vidctrl1;
+static UINT8 starfire_color;
+
+
+
+/*************************************
+ *
+ * Initialize the video system
+ *
+ *************************************/
+
+VIDEO_START( starfire )
+{
+ /* make a temporary bitmap */
+ tmpbitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ /* make a dirty array */
+ scanline_dirty = auto_malloc(STARFIRE_VTOTAL);
+
+ /* reset videoram */
+ memset(starfire_videoram, 0, 0x2000);
+ memset(starfire_colorram, 0, 0x2000);
+ memset(scanline_dirty, 1, 256);
+}
+
+
+
+/*************************************
+ *
+ * Video control writes
+ *
+ *************************************/
+
+WRITE8_HANDLER( starfire_vidctrl_w )
+{
+ starfire_vidctrl = data;
+}
+
+WRITE8_HANDLER( starfire_vidctrl1_w )
+{
+ starfire_vidctrl1 = data;
+}
+
+
+
+/*************************************
+ *
+ * Color RAM read/writes
+ *
+ *************************************/
+
+WRITE8_HANDLER( starfire_colorram_w )
+{
+ /* handle writes to the pseudo-color RAM */
+ if ((offset & 0xe0) == 0)
+ {
+ int palette_index = (offset & 0x1f) | ((offset & 0x200) >> 4);
+
+ /* set RAM regardless */
+ starfire_colorram[offset & ~0x100] = data;
+ starfire_colorram[offset | 0x100] = data;
+
+ /* don't modify the palette unless the TRANS bit is set */
+ starfire_color = data & 0x1f;
+ if (!(starfire_vidctrl1 & 0x40))
+ return;
+
+ palette_set_color_rgb(Machine, palette_index, pal3bit((data << 1) & 0x06) | ((offset >> 8) & 0x01), pal3bit(data >> 5), pal3bit(data >> 2));
+ }
+
+ /* handle writes to the rest of color RAM */
+ else
+ {
+ /* set RAM based on CDRM */
+ starfire_colorram[offset] = (starfire_vidctrl1 & 0x80) ? starfire_color : (data & 0x1f);
+ scanline_dirty[offset & 0xff] = 1;
+ starfire_color = data & 0x1f;
+ }
+}
+
+READ8_HANDLER( starfire_colorram_r )
+{
+ return starfire_colorram[offset];
+}
+
+
+
+/*************************************
+ *
+ * Video RAM read/writes
+ *
+ *************************************/
+
+WRITE8_HANDLER( starfire_videoram_w )
+{
+ int sh, lr, dm, ds, mask, d0, dalu;
+ int offset1 = offset & 0x1fff;
+ int offset2 = (offset + 0x100) & 0x1fff;
+
+ /* PROT */
+ if (!(offset & 0xe0) && !(starfire_vidctrl1 & 0x20))
+ return;
+
+ /* selector 6A */
+ if (offset & 0x2000)
+ {
+ sh = (starfire_vidctrl >> 1) & 0x07;
+ lr = starfire_vidctrl & 0x01;
+ }
+ else
+ {
+ sh = (starfire_vidctrl >> 5) & 0x07;
+ lr = (starfire_vidctrl >> 4) & 0x01;
+ }
+
+ /* mirror bits 5B/5C/5D/5E */
+ dm = data;
+ if (lr)
+ dm = ((dm & 0x01) << 7) | ((dm & 0x02) << 5) | ((dm & 0x04) << 3) | ((dm & 0x08) << 1) |
+ ((dm & 0x10) >> 1) | ((dm & 0x20) >> 3) | ((dm & 0x40) >> 5) | ((dm & 0x80) >> 7);
+
+ /* shifters 6D/6E */
+ ds = (dm << 8) >> sh;
+ mask = 0xff00 >> sh;
+
+ /* ROLL */
+ if ((offset & 0x1f00) == 0x1f00)
+ {
+ if (starfire_vidctrl1 & 0x10)
+ mask &= 0x00ff;
+ else
+ mask &= 0xff00;
+ }
+
+ /* ALU 8B/8D */
+ d0 = (starfire_videoram[offset1] << 8) | starfire_videoram[offset2];
+ dalu = d0 & ~mask;
+ d0 &= mask;
+ ds &= mask;
+ switch (~starfire_vidctrl1 & 15)
+ {
+ case 0: dalu |= ds ^ mask; break;
+ case 1: dalu |= (ds | d0) ^ mask; break;
+ case 2: dalu |= (ds ^ mask) & d0; break;
+ case 3: dalu |= 0; break;
+ case 4: dalu |= (ds & d0) ^ mask; break;
+ case 5: dalu |= d0 ^ mask; break;
+ case 6: dalu |= ds ^ d0; break;
+ case 7: dalu |= ds & (d0 ^ mask); break;
+ case 8: dalu |= (ds ^ mask) | d0; break;
+ case 9: dalu |= (ds ^ d0) ^ mask; break;
+ case 10: dalu |= d0; break;
+ case 11: dalu |= ds & d0; break;
+ case 12: dalu |= mask; break;
+ case 13: dalu |= ds | (d0 ^ mask); break;
+ case 14: dalu |= ds | d0; break;
+ case 15: dalu |= ds; break;
+ }
+
+ /* final output */
+ starfire_videoram[offset1] = dalu >> 8;
+ starfire_videoram[offset2] = dalu;
+ scanline_dirty[offset1 & 0xff] = 1;
+
+ /* color output */
+ if (!(offset & 0x2000) && !(starfire_vidctrl1 & 0x80))
+ {
+ if (mask & 0xff00)
+ starfire_colorram[offset1] = starfire_color;
+ if (mask & 0x00ff)
+ starfire_colorram[offset2] = starfire_color;
+ }
+}
+
+READ8_HANDLER( starfire_videoram_r )
+{
+ int sh, mask, d0;
+ int offset1 = offset & 0x1fff;
+ int offset2 = (offset + 0x100) & 0x1fff;
+
+ /* selector 6A */
+ if (offset & 0x2000)
+ sh = (starfire_vidctrl >> 1) & 0x07;
+ else
+ sh = (starfire_vidctrl >> 5) & 0x07;
+
+ /* shifters 6D/6E */
+ mask = 0xff00 >> sh;
+
+ /* ROLL */
+ if ((offset & 0x1f00) == 0x1f00)
+ {
+ if (starfire_vidctrl1 & 0x10)
+ mask &= 0x00ff;
+ else
+ mask &= 0xff00;
+ }
+
+ /* munge the results */
+ d0 = (starfire_videoram[offset1] & (mask >> 8)) | (starfire_videoram[offset2] & mask);
+ d0 = (d0 << sh) | (d0 >> (8 - sh));
+ return d0 & 0xff;
+}
+
+
+
+/*************************************
+ *
+ * Periodic screen refresh callback
+ *
+ *************************************/
+
+void starfire_video_update(int scanline, int count)
+{
+ UINT8 *pix = &starfire_videoram[scanline];
+ UINT8 *col = &starfire_colorram[scanline];
+ int x, y;
+
+ /* update any dirty scanlines in this range */
+ for (x = 0; x < 256; x += 8)
+ {
+ for (y = 0; y < count; y++)
+ if ((scanline + y) < STARFIRE_VTOTAL && scanline_dirty[scanline + y])
+ {
+ int data = pix[y];
+ int color = col[y];
+
+ *BITMAP_ADDR16(tmpbitmap, scanline + y, x + 0) = color | ((data >> 2) & 0x20);
+ *BITMAP_ADDR16(tmpbitmap, scanline + y, x + 1) = color | ((data >> 1) & 0x20);
+ *BITMAP_ADDR16(tmpbitmap, scanline + y, x + 2) = color | ((data >> 0) & 0x20);
+ *BITMAP_ADDR16(tmpbitmap, scanline + y, x + 3) = color | ((data << 1) & 0x20);
+ *BITMAP_ADDR16(tmpbitmap, scanline + y, x + 4) = color | ((data << 2) & 0x20);
+ *BITMAP_ADDR16(tmpbitmap, scanline + y, x + 5) = color | ((data << 3) & 0x20);
+ *BITMAP_ADDR16(tmpbitmap, scanline + y, x + 6) = color | ((data << 4) & 0x20);
+ *BITMAP_ADDR16(tmpbitmap, scanline + y, x + 7) = color | ((data << 5) & 0x20);
+ }
+
+ pix += 256;
+ col += 256;
+ }
+
+ /* mark them not dirty anymore */
+ for (y = 0; y < count; y++)
+ if ((scanline + y) < STARFIRE_VTOTAL)
+ scanline_dirty[scanline + y] = 0;
+}
+
+
+
+/*************************************
+ *
+ * Standard screen refresh callback
+ *
+ *************************************/
+
+VIDEO_UPDATE( starfire )
+{
+ /* copy the bitmap, remapping the colors */
+ copybitmap_remap(bitmap, tmpbitmap, 0, 0, 0, 0, &machine->screen[0].visarea, TRANSPARENCY_NONE, 0);
+ return 0;
+}
+
+
diff --git a/src/mame/video/starshp1.c b/src/mame/video/starshp1.c
new file mode 100644
index 00000000000..a7dfe164c62
--- /dev/null
+++ b/src/mame/video/starshp1.c
@@ -0,0 +1,432 @@
+/***************************************************************************
+
+Atari Starship 1 video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/starshp1.h"
+#include <math.h>
+
+UINT8* starshp1_playfield_ram;
+UINT8* starshp1_hpos_ram;
+UINT8* starshp1_vpos_ram;
+UINT8* starshp1_obj_ram;
+
+int starshp1_ship_explode;
+int starshp1_ship_picture;
+int starshp1_ship_hoffset;
+int starshp1_ship_voffset;
+int starshp1_ship_size;
+
+int starshp1_circle_kill;
+int starshp1_circle_mod;
+int starshp1_circle_hpos;
+int starshp1_circle_vpos;
+int starshp1_circle_size;
+
+int starshp1_starfield_kill;
+int starshp1_phasor;
+int starshp1_collision_latch;
+int starshp1_mux;
+
+static UINT16* LSFR;
+
+static mame_bitmap* helper;
+
+static tilemap* bg_tilemap;
+
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 code = starshp1_playfield_ram[tile_index];
+
+ SET_TILE_INFO(0, code & 0x3f, 0, 0);
+}
+
+
+VIDEO_START( starshp1 )
+{
+ UINT16 val = 0;
+
+ int i;
+
+ bg_tilemap = tilemap_create(get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 8, 32, 32);
+
+ tilemap_set_transparent_pen(bg_tilemap, 0);
+
+ tilemap_set_scrollx(bg_tilemap, 0, -8);
+
+ LSFR = auto_malloc(0x20000);
+
+ for (i = 0; i < 0x10000; i++)
+ {
+ int bit =
+ (val >> 0xF) ^
+ (val >> 0xC) ^
+ (val >> 0x7) ^
+ (val >> 0x1) ^ 1;
+
+ LSFR[i] = val;
+
+ val = (val << 1) | (bit & 1);
+ }
+
+ helper = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+}
+
+
+READ8_HANDLER( starshp1_rng_r )
+{
+ int x = video_screen_get_hpos(0);
+ int y = video_screen_get_vpos(0);
+
+ /* the LFSR is only running in the non-blank region
+ of the screen, so this is not quite right */
+ if (x > Machine->screen[0].width - 1)
+ x = Machine->screen[0].width - 1;
+ if (y > Machine->screen[0].height - 1)
+ y = Machine->screen[0].height - 1;
+
+ return LSFR[x + (UINT16) (512 * y)];
+}
+
+
+WRITE8_HANDLER( starshp1_ssadd_w )
+{
+ /*
+ * The range of sprite position values doesn't suffice to
+ * move the zoomed spaceship sprite over the top and left
+ * edges of the screen. These additional values are used
+ * to compensate for this. Technically, they cut off the
+ * first columns and rows of the spaceship sprite, but in
+ * practice they work like offsets in zoomed pixels.
+ */
+
+ starshp1_ship_voffset = ((offset & 0xf0) >> 4);
+ starshp1_ship_hoffset = ((offset & 0x0f) << 2) | (data & 3);
+}
+
+
+WRITE8_HANDLER( starshp1_sspic_w )
+{
+ /*
+ * Some mysterious game code at address $2CCE is causing
+ * erratic images in the target explosion sequence. The
+ * following condition is a hack to filter these images.
+ */
+
+ if (data != 0x87)
+ {
+ starshp1_ship_picture = data;
+ }
+}
+
+
+WRITE8_HANDLER( starshp1_playfield_w )
+{
+ if (starshp1_mux != 0)
+ {
+ offset ^= 0x1f;
+ starshp1_playfield_ram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+ }
+}
+
+
+static void draw_starfield(mame_bitmap* bitmap)
+{
+ /*
+ * The LSFR is reset once per frame at the position of
+ * sprite 15. This behavior is quite pointless and not
+ * really needed by the game. Not emulated.
+ */
+
+ int x;
+ int y;
+
+ for (y = 0; y < bitmap->height; y++)
+ {
+ const UINT16* p = LSFR + (UINT16) (512 * y);
+
+ UINT16* pLine = BITMAP_ADDR16(bitmap, y, 0);
+
+ for (x = 0; x < bitmap->width; x++)
+ {
+ if ((p[x] & 0x5b56) == 0x5b44)
+ {
+ pLine[x] = (p[x] & 0x0400) ? 5 : 2;
+ }
+ }
+ }
+}
+
+
+static int get_sprite_hpos(int i)
+{
+ return 2 * (starshp1_hpos_ram[i] ^ 0xff);
+}
+static int get_sprite_vpos(int i)
+{
+ return 1 * (starshp1_vpos_ram[i] - 0x07);
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ int i;
+
+ for (i = 0; i < 14; i++)
+ {
+ int code = (starshp1_obj_ram[i] & 0xf) ^ 0xf;
+
+ drawgfx(bitmap, machine->gfx[1],
+ code % 8,
+ code / 8,
+ 0, 0,
+ get_sprite_hpos(i),
+ get_sprite_vpos(i),
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+
+static void draw_spaceship(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ double scaler = -5 * log(1 - starshp1_ship_size / 256.0); /* ? */
+
+ unsigned xzoom = 2 * 0x10000 * scaler;
+ unsigned yzoom = 1 * 0x10000 * scaler;
+
+ int x = get_sprite_hpos(14);
+ int y = get_sprite_vpos(14);
+
+ if (x <= 0)
+ {
+ x -= (xzoom * starshp1_ship_hoffset) >> 16;
+ }
+ if (y <= 0)
+ {
+ y -= (yzoom * starshp1_ship_voffset) >> 16;
+ }
+
+ drawgfxzoom(bitmap, machine->gfx[2],
+ starshp1_ship_picture & 0x03,
+ starshp1_ship_explode,
+ starshp1_ship_picture & 0x80, 0,
+ x, y,
+ cliprect, TRANSPARENCY_PEN, 0,
+ xzoom, yzoom);
+}
+
+
+static void draw_phasor(mame_bitmap* bitmap)
+{
+ int i;
+
+ for (i = 128; i < 240; i++)
+ {
+ if (i >= get_sprite_vpos(13))
+ {
+ *BITMAP_ADDR16(bitmap, i, 2 * i + 0) = 7;
+ *BITMAP_ADDR16(bitmap, i, 2 * i + 1) = 7;
+ *BITMAP_ADDR16(bitmap, i, 2 * (255 - i) + 0) = 7;
+ *BITMAP_ADDR16(bitmap, i, 2 * (255 - i) + 1) = 7;
+ }
+ }
+}
+
+
+static int get_radius(void)
+{
+ return 6 * sqrt(starshp1_circle_size); /* size calibrated by hand */
+}
+static int get_circle_hpos(void)
+{
+ return 2 * (3 * starshp1_circle_hpos / 2 - 64);
+}
+static int get_circle_vpos(void)
+{
+ return 1 * (3 * starshp1_circle_vpos / 2 - 64);
+}
+
+
+static void draw_circle_line(mame_bitmap *bitmap, int x, int y, int l)
+{
+ if (y >= 0 && y <= bitmap->height - 1)
+ {
+ const UINT16* p = LSFR + (UINT16) (512 * y);
+
+ UINT16* pLine = BITMAP_ADDR16(bitmap, y, 0);
+
+ int h1 = x - 2 * l;
+ int h2 = x + 2 * l;
+
+ if (h1 < 0)
+ h1 = 0;
+ if (h2 > bitmap->width - 1)
+ h2 = bitmap->width - 1;
+
+ for (x = h1; x <= h2; x++)
+ {
+ if (starshp1_circle_mod)
+ {
+ if (p[x] & 1)
+ {
+ pLine[x] = 5;
+ }
+ }
+ else
+ {
+ pLine[x] = 7;
+ }
+ }
+ }
+}
+
+
+static void draw_circle(mame_bitmap* bitmap)
+{
+ int cx = get_circle_hpos();
+ int cy = get_circle_vpos();
+
+ int x = 0;
+ int y = get_radius();
+
+ /* Bresenham's circle algorithm */
+
+ int d = 3 - 2 * get_radius();
+
+ while (x <= y)
+ {
+ draw_circle_line(bitmap, cx, cy - x, y);
+ draw_circle_line(bitmap, cx, cy + x, y);
+ draw_circle_line(bitmap, cx, cy - y, x);
+ draw_circle_line(bitmap, cx, cy + y, x);
+
+ x++;
+
+ if (d < 0)
+ {
+ d += 4 * x + 6;
+ }
+ else
+ {
+ d += 4 * (x - y--) + 10;
+ }
+ }
+}
+
+
+static int spaceship_collision(mame_bitmap* bitmap, rectangle* rect)
+{
+ int x;
+ int y;
+
+ for (y = rect->min_y; y <= rect->max_y; y++)
+ {
+ const UINT16* pLine = BITMAP_ADDR16(helper, y, 0);
+
+ for (x = rect->min_x; x <= rect->max_x; x++)
+ {
+ if (pLine[x] != 0)
+ {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static int point_in_circle(int x, int y, int center_x, int center_y, int r)
+{
+ int dx = abs(x - center_x) / 2;
+ int dy = abs(y - center_y) / 1;
+
+ return dx * dx + dy * dy < r * r;
+}
+
+
+static int circle_collision(rectangle* rect)
+{
+ int center_x = get_circle_hpos();
+ int center_y = get_circle_vpos();
+
+ int r = get_radius();
+
+ return
+ point_in_circle(rect->min_x, rect->min_y, center_x, center_y, r) ||
+ point_in_circle(rect->min_x, rect->max_y, center_x, center_y, r) ||
+ point_in_circle(rect->max_x, rect->min_y, center_x, center_y, r) ||
+ point_in_circle(rect->max_x, rect->max_y, center_x, center_y, r);
+}
+
+
+VIDEO_UPDATE( starshp1 )
+{
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ if (starshp1_starfield_kill == 0)
+ draw_starfield(bitmap);
+
+ draw_sprites(machine, bitmap, cliprect);
+
+ if (starshp1_circle_kill == 0 && starshp1_circle_mod != 0)
+ draw_circle(bitmap);
+
+ if (starshp1_attract == 0)
+ draw_spaceship(machine, bitmap, cliprect);
+
+ if (starshp1_circle_kill == 0 && starshp1_circle_mod == 0)
+ draw_circle(bitmap);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ if (starshp1_phasor != 0)
+ draw_phasor(bitmap);
+ return 0;
+}
+
+
+VIDEO_EOF( starshp1 )
+{
+ rectangle rect;
+
+ rect.min_x = get_sprite_hpos(13);
+ rect.min_y = get_sprite_vpos(13);
+ rect.max_x = rect.min_x + machine->gfx[1]->width - 1;
+ rect.max_y = rect.min_y + machine->gfx[1]->height - 1;
+
+ if (rect.min_x < 0)
+ rect.min_x = 0;
+ if (rect.min_y < 0)
+ rect.min_y = 0;
+ if (rect.max_x > helper->width - 1)
+ rect.max_x = helper->width - 1;
+ if (rect.max_y > helper->height - 1)
+ rect.max_y = helper->height - 1;
+
+ fillbitmap(helper, machine->pens[0], &machine->screen[0].visarea);
+
+ if (starshp1_attract == 0)
+ draw_spaceship(machine, helper, &machine->screen[0].visarea);
+
+ if (circle_collision(&machine->screen[0].visarea))
+ {
+ starshp1_collision_latch |= 1;
+ }
+ if (circle_collision(&rect))
+ {
+ starshp1_collision_latch |= 2;
+ }
+ if (spaceship_collision(helper, &rect))
+ {
+ starshp1_collision_latch |= 4;
+ }
+ if (spaceship_collision(helper, &machine->screen[0].visarea))
+ {
+ starshp1_collision_latch |= 8;
+ }
+}
diff --git a/src/mame/video/stfight.c b/src/mame/video/stfight.c
new file mode 100644
index 00000000000..2a1ffcbc697
--- /dev/null
+++ b/src/mame/video/stfight.c
@@ -0,0 +1,300 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+// Real stuff
+UINT8 *stfight_text_char_ram;
+UINT8 *stfight_text_attr_ram;
+UINT8 *stfight_vh_latch_ram;
+UINT8 *stfight_sprite_ram;
+
+static tilemap *fg_tilemap,*bg_tilemap,*tx_tilemap;
+static int stfight_sprite_base = 0;
+
+/*
+ Graphics ROM Format
+ ===================
+
+ Each tile is 8x8 pixels
+ Each composite tile is 2x2 tiles, 16x16 pixels
+ Each screen is 32x32 composite tiles, 64x64 tiles, 256x256 pixels
+ Each layer is a 4-plane bitmap 8x16 screens, 2048x4096 pixels
+
+ There are 4x256=1024 composite tiles defined for each layer
+
+ Each layer is mapped using 2 bytes/composite tile
+ - one byte for the tile
+ - one byte for the tile bank, attribute
+ - b7,b5 tile bank (0-3)
+
+ Each pixel is 4 bits = 16 colours.
+
+ */
+
+PALETTE_INIT( stfight )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ /* unique color for transparency */
+ palette_set_color(machine,256,MAKE_RGB(0x04,0x04,0x04));
+
+ /* text uses colors 192-207 */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ {
+ if ((*color_prom & 0x0f) == 0x0f) COLOR(0,i) = 256; /* transparent */
+ else COLOR(0,i) = (*color_prom & 0x0f) + 0xc0;
+ color_prom++;
+ }
+ color_prom += 256 - TOTAL_COLORS(0); /* rest of the PROM is unused */
+
+ /* fg uses colors 64-127 */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ {
+ COLOR(1,i) = (color_prom[256] & 0x0f) + 16 * (color_prom[0] & 0x03) + 0x40;
+ color_prom++;
+ }
+ color_prom += 256;
+
+ /* bg uses colors 0-63 */
+ for (i = 0;i < TOTAL_COLORS(2);i++)
+ {
+ COLOR(2,i) = (color_prom[256] & 0x0f) + 16 * (color_prom[0] & 0x03) + 0x00;
+ color_prom++;
+ }
+ color_prom += 256;
+
+ /* sprites use colors 128-191 */
+ for (i = 0;i < TOTAL_COLORS(4);i++)
+ {
+ COLOR(4,i) = (color_prom[256] & 0x0f) + 16 * (color_prom[0] & 0x03) + 0x80;
+ color_prom++;
+ }
+ color_prom += 256;
+}
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( fg_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x0f) + ((row & 0x0f) << 4) + ((col & 0x70) << 4) + ((row & 0xf0) << 7);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 *fgMap = memory_region(REGION_GFX5);
+ int attr,tile_base;
+
+ attr = fgMap[0x8000+tile_index];
+ tile_base = ((attr & 0x80) << 2) | ((attr & 0x20) << 3);
+
+ SET_TILE_INFO(
+ 1,
+ tile_base + fgMap[tile_index],
+ attr & 0x07,
+ 0);
+}
+
+static TILEMAP_MAPPER( bg_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return ((col & 0x0e) >> 1) + ((row & 0x0f) << 3) + ((col & 0x70) << 3) +
+ ((row & 0x80) << 3) + ((row & 0x10) << 7) + ((col & 0x01) << 12) +
+ ((row & 0x60) << 8);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 *bgMap = memory_region(REGION_GFX6);
+ int attr,tile_bank,tile_base;
+
+ attr = bgMap[0x8000+tile_index];
+ tile_bank = (attr & 0x20) >> 5;
+ tile_base = (attr & 0x80) << 1;
+
+ SET_TILE_INFO(
+ 2+tile_bank,
+ tile_base + bgMap[tile_index],
+ attr & 0x07,
+ 0);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ UINT8 attr = stfight_text_attr_ram[tile_index];
+
+ SET_TILE_INFO(
+ 0,
+ stfight_text_char_ram[tile_index] + ((attr & 0x80) << 1),
+ attr & 0x0f,
+ TILE_FLIPYX((attr & 0x60) >> 5));
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( stfight )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,bg_scan,TILEMAP_TYPE_PEN, 16,16,128,256);
+ fg_tilemap = tilemap_create(get_fg_tile_info,fg_scan,TILEMAP_TYPE_PEN,16,16,128,256);
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,
+ TILEMAP_TYPE_COLORTABLE,8,8,32,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0x0F);
+ tilemap_set_transparent_pen(tx_tilemap,256);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( stfight_text_char_w )
+{
+ stfight_text_char_ram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+WRITE8_HANDLER( stfight_text_attr_w )
+{
+ stfight_text_attr_ram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+WRITE8_HANDLER( stfight_sprite_bank_w )
+{
+ stfight_sprite_base = ( ( data & 0x04 ) << 7 ) |
+ ( ( data & 0x01 ) << 8 );
+}
+
+WRITE8_HANDLER( stfight_vh_latch_w )
+{
+ int scroll;
+
+
+ stfight_vh_latch_ram[offset] = data;
+
+ switch( offset )
+ {
+ case 0x00:
+ case 0x01:
+ scroll = (stfight_vh_latch_ram[1] << 8) | stfight_vh_latch_ram[0];
+ tilemap_set_scrollx(fg_tilemap,0,scroll);
+ break;
+
+ case 0x02:
+ case 0x03:
+ scroll = (stfight_vh_latch_ram[3] << 8) | stfight_vh_latch_ram[2];
+ tilemap_set_scrolly(fg_tilemap,0,scroll);
+ break;
+
+ case 0x04:
+ case 0x05:
+ scroll = (stfight_vh_latch_ram[5] << 8) | stfight_vh_latch_ram[4];
+ tilemap_set_scrollx(bg_tilemap,0,scroll);
+ break;
+
+ case 0x06:
+ case 0x08:
+ scroll = (stfight_vh_latch_ram[8] << 8) | stfight_vh_latch_ram[6];
+ tilemap_set_scrolly(bg_tilemap,0,scroll);
+ break;
+
+ case 0x07:
+ tilemap_set_enable(tx_tilemap,data & 0x80);
+ /* 0x40 = sprites */
+ tilemap_set_enable(bg_tilemap,data & 0x20);
+ tilemap_set_enable(fg_tilemap,data & 0x10);
+ flip_screen_set(data & 0x01);
+ break;
+ }
+}
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs,sx,sy;
+
+ for (offs = 0;offs < 4096;offs += 32)
+ {
+ int code;
+ int attr = stfight_sprite_ram[offs+1];
+ int flipx = attr & 0x10;
+ int color = attr & 0x0f;
+ int pri = (attr & 0x20) >> 5;
+
+ sy = stfight_sprite_ram[offs+2];
+ sx = stfight_sprite_ram[offs+3];
+
+ // non-active sprites have zero y coordinate value
+ if( sy > 0 )
+ {
+ // sprites which wrap onto/off the screen have
+ // a sign extension bit in the sprite attribute
+ if( sx >= 0xf0 )
+ {
+ if (attr & 0x80)
+ sx -= 0x100;
+ }
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ }
+
+ code = stfight_sprite_base + stfight_sprite_ram[offs];
+
+ pdrawgfx(bitmap,machine->gfx[4],
+ code,
+ color,
+ flipx,flip_screen,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0x0f,
+ pri ? 0x02 : 0);
+ }
+ }
+}
+
+
+VIDEO_UPDATE( stfight )
+{
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ fillbitmap(bitmap,machine->pens[0],cliprect); /* in case bg_tilemap is disabled */
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,1);
+
+ /* Draw sprites (may be obscured by foreground layer) */
+ if (stfight_vh_latch_ram[0x07] & 0x40)
+ draw_sprites(machine, bitmap,cliprect);
+
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/stlforce.c b/src/mame/video/stlforce.c
new file mode 100644
index 00000000000..d51e915d9bd
--- /dev/null
+++ b/src/mame/video/stlforce.c
@@ -0,0 +1,196 @@
+/* video/stlforce.c - see main driver for other notes */
+
+#include "driver.h"
+
+static tilemap *stlforce_bg_tilemap, *stlforce_mlow_tilemap, *stlforce_mhigh_tilemap, *stlforce_tx_tilemap;
+
+extern UINT16 *stlforce_bg_videoram, *stlforce_mlow_videoram, *stlforce_mhigh_videoram, *stlforce_tx_videoram;
+extern UINT16 *stlforce_bg_scrollram, *stlforce_mlow_scrollram, *stlforce_mhigh_scrollram, *stlforce_vidattrram;
+
+extern UINT16 *stlforce_spriteram;
+
+int stlforce_sprxoffs;
+
+/* background, appears to be the bottom layer */
+
+static TILE_GET_INFO( get_stlforce_bg_tile_info )
+{
+ int tileno,colour;
+
+ tileno = stlforce_bg_videoram[tile_index] & 0x0fff;
+ colour = stlforce_bg_videoram[tile_index] & 0xe000;
+ colour = colour >> 13;
+ SET_TILE_INFO(0,tileno,colour,0);
+}
+
+WRITE16_HANDLER( stlforce_bg_videoram_w )
+{
+ stlforce_bg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(stlforce_bg_tilemap,offset);
+}
+
+/* middle layer, low */
+
+static TILE_GET_INFO( get_stlforce_mlow_tile_info )
+{
+ int tileno,colour;
+
+ tileno = stlforce_mlow_videoram[tile_index] & 0x0fff;
+ colour = stlforce_mlow_videoram[tile_index] & 0xe000;
+ colour = colour >> 13;
+ colour += 8;
+ tileno += 0x1000;
+
+ SET_TILE_INFO(0,tileno,colour,0);
+}
+
+WRITE16_HANDLER( stlforce_mlow_videoram_w )
+{
+ stlforce_mlow_videoram[offset] = data;
+ tilemap_mark_tile_dirty(stlforce_mlow_tilemap,offset);
+}
+
+/* middle layer, high */
+
+static TILE_GET_INFO( get_stlforce_mhigh_tile_info )
+{
+ int tileno,colour;
+
+ tileno = stlforce_mhigh_videoram[tile_index] & 0x0fff;
+ colour = stlforce_mhigh_videoram[tile_index] & 0xe000;
+ colour = colour >> 13;
+ colour += 16;
+ tileno += 0x2000;
+
+ SET_TILE_INFO(0,tileno,colour,0);
+}
+
+WRITE16_HANDLER( stlforce_mhigh_videoram_w )
+{
+ stlforce_mhigh_videoram[offset] = data;
+ tilemap_mark_tile_dirty(stlforce_mhigh_tilemap,offset);
+}
+
+/* text layer, appears to be the top layer */
+
+static TILE_GET_INFO( get_stlforce_tx_tile_info )
+{
+ int tileno,colour;
+
+ tileno = stlforce_tx_videoram[tile_index] & 0x0fff;
+ colour = stlforce_tx_videoram[tile_index] & 0xe000;
+ colour = colour >> 13;
+
+ tileno += 0xc000;
+
+ colour += 24;
+ SET_TILE_INFO(1,tileno,colour,0);
+}
+
+WRITE16_HANDLER( stlforce_tx_videoram_w )
+{
+ stlforce_tx_videoram[offset] = data;
+ tilemap_mark_tile_dirty(stlforce_tx_tilemap,offset);
+}
+
+/* sprites - quite a bit still needs doing .. */
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+
+ const UINT16 *source = stlforce_spriteram+0x0;
+ const UINT16 *finish = stlforce_spriteram+0x800;
+ const gfx_element *gfx = machine->gfx[2];
+ int ypos, xpos, attr, num;
+
+ while( source<finish )
+ {
+ if(source[0] & 0x0800)
+ {
+ ypos = source[0]& 0x01ff;
+ attr = source[1]& 0x000f;
+ xpos = source[3]& 0x03ff;
+ num = (source[2] & 0x1fff);
+
+ ypos = 512-ypos;
+
+ drawgfx( bitmap,
+ gfx,
+ num,
+ 64+attr,
+ 0,0,
+ xpos+stlforce_sprxoffs,ypos,
+ cliprect,
+ TRANSPARENCY_PEN,0 );
+ }
+
+ source += 0x4;
+ }
+}
+
+VIDEO_UPDATE( stlforce )
+{
+ int i;
+ if(stlforce_vidattrram[6] & 1)
+ {
+ for(i=0;i<256;i++)
+ tilemap_set_scrollx(stlforce_bg_tilemap, i, stlforce_bg_scrollram[i]+9); //+9 for twinbrat
+ }
+ else
+ {
+ for(i=0;i<256;i++)
+ tilemap_set_scrollx(stlforce_bg_tilemap, i, stlforce_bg_scrollram[0]+9); //+9 for twinbrat
+ }
+
+ if(stlforce_vidattrram[6] & 4)
+ {
+ for(i=0;i<256;i++)
+ tilemap_set_scrollx(stlforce_mlow_tilemap, i, stlforce_mlow_scrollram[i]+8);
+ }
+ else
+ {
+ for(i=0;i<256;i++)
+ tilemap_set_scrollx(stlforce_mlow_tilemap, i, stlforce_mlow_scrollram[0]+8);
+ }
+
+ if(stlforce_vidattrram[6] & 0x10)
+ {
+ for(i=0;i<256;i++)
+ tilemap_set_scrollx(stlforce_mhigh_tilemap, i, stlforce_mhigh_scrollram[i]+8);
+ }
+ else
+ {
+ for(i=0;i<256;i++)
+ tilemap_set_scrollx(stlforce_mhigh_tilemap, i, stlforce_mhigh_scrollram[0]+8);
+ }
+
+ tilemap_set_scrolly(stlforce_bg_tilemap, 0, stlforce_vidattrram[1]);
+ tilemap_set_scrolly(stlforce_mlow_tilemap, 0, stlforce_vidattrram[2]);
+ tilemap_set_scrolly(stlforce_mhigh_tilemap, 0, stlforce_vidattrram[3]);
+
+ tilemap_set_scrollx(stlforce_tx_tilemap, 0, stlforce_vidattrram[0]+8);
+ tilemap_set_scrolly(stlforce_tx_tilemap, 0, stlforce_vidattrram[4]);
+
+ tilemap_draw(bitmap,cliprect,stlforce_bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,stlforce_mlow_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,stlforce_mhigh_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,stlforce_tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_START( stlforce )
+{
+ stlforce_bg_tilemap = tilemap_create(get_stlforce_bg_tile_info, tilemap_scan_cols,TILEMAP_TYPE_PEN, 16,16,64,16);
+ stlforce_mlow_tilemap = tilemap_create(get_stlforce_mlow_tile_info, tilemap_scan_cols,TILEMAP_TYPE_PEN, 16,16,64,16);
+ stlforce_mhigh_tilemap = tilemap_create(get_stlforce_mhigh_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 16,16,64,16);
+ stlforce_tx_tilemap = tilemap_create(get_stlforce_tx_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+
+ tilemap_set_transparent_pen(stlforce_mlow_tilemap,0);
+ tilemap_set_transparent_pen(stlforce_mhigh_tilemap,0);
+ tilemap_set_transparent_pen(stlforce_tx_tilemap,0);
+
+ tilemap_set_scroll_rows(stlforce_bg_tilemap, 256);
+ tilemap_set_scroll_rows(stlforce_mlow_tilemap, 256);
+ tilemap_set_scroll_rows(stlforce_mhigh_tilemap, 256);
+}
diff --git a/src/mame/video/strnskil.c b/src/mame/video/strnskil.c
new file mode 100644
index 00000000000..e5d167596c9
--- /dev/null
+++ b/src/mame/video/strnskil.c
@@ -0,0 +1,148 @@
+/******************************************************************************
+
+Strength & Skill (c) 1984 Sun Electronics
+
+Video hardware driver by Uki
+
+ 19/Jun/2001 -
+
+******************************************************************************/
+
+#include "driver.h"
+
+static UINT8 strnskil_scrl_ctrl;
+static UINT8 strnskil_xscroll[2];
+
+static tilemap *bg_tilemap;
+
+PALETTE_INIT( strnskil )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int r = color_prom[0];
+ int g = color_prom[machine->drv->total_colors];
+ int b = color_prom[2*machine->drv->total_colors];
+
+ palette_set_color_rgb(machine,i,pal4bit(r),pal4bit(g),pal4bit(b));
+ color_prom++;
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* sprites lookup table */
+ for (i=0; i<512; i++)
+ *(colortable++) = *(color_prom++);
+
+ /* bg lookup table */
+ for (i=0; i<512; i++)
+ *(colortable++) = *(color_prom++);
+
+}
+
+WRITE8_HANDLER( strnskil_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+WRITE8_HANDLER( strnskil_scroll_x_w )
+{
+ strnskil_xscroll[offset] = data;
+}
+
+WRITE8_HANDLER( strnskil_scrl_ctrl_w )
+{
+ strnskil_scrl_ctrl = data >> 5;
+
+ if (flip_screen != (data & 0x08))
+ {
+ flip_screen_set(data & 0x08);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = videoram[tile_index * 2];
+ int code = videoram[(tile_index * 2) + 1] + ((attr & 0x60) << 3);
+ int color = (attr & 0x1f) | ((attr & 0x80) >> 2);
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( strnskil )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_scroll_rows(bg_tilemap, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0x60; offs < 0x100; offs += 4)
+ {
+ int code = spriteram[offs + 1];
+ int color = spriteram[offs + 2] & 0x3f;
+ int flipx = flip_screen_x;
+ int flipy = flip_screen_y;
+
+ int sx = spriteram[offs + 3];
+ int sy = spriteram[offs];
+ int px, py;
+
+ if (flip_screen)
+ {
+ px = 240 - sx + 0; /* +2 or +0 ? */
+ py = sy;
+ }
+ else
+ {
+ px = sx - 2;
+ py = 240 - sy;
+ }
+
+ sx = sx & 0xff;
+
+ if (sx > 248)
+ sx = sx - 256;
+
+ drawgfx(bitmap, machine->gfx[1],
+ code, color,
+ flipx, flipy,
+ px, py,
+ cliprect,
+ TRANSPARENCY_COLOR, 0);
+ }
+}
+
+VIDEO_UPDATE( strnskil )
+{
+ int row;
+
+ for (row = 0; row < 32; row++)
+ {
+ if (strnskil_scrl_ctrl != 0x07)
+ {
+ switch (memory_region(REGION_USER1)[strnskil_scrl_ctrl * 32 + row])
+ {
+ case 2:
+ tilemap_set_scrollx(bg_tilemap, row, -~strnskil_xscroll[1]);
+ break;
+ case 4:
+ tilemap_set_scrollx(bg_tilemap, row, -~strnskil_xscroll[0]);
+ break;
+ }
+ }
+ }
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/stvvdp1.c b/src/mame/video/stvvdp1.c
new file mode 100644
index 00000000000..9ac5b3b6c29
--- /dev/null
+++ b/src/mame/video/stvvdp1.c
@@ -0,0 +1,2147 @@
+/*
+
+STV - VDP1
+
+crude drawing code to support some of the basic vdp1 features
+based on what hanagumi columns needs
+-- to be expanded
+
+the vdp1 draws to the FRAMEBUFFER which is mapped in memory
+
+Framebuffer todo:
+- finish manual erase
+- add proper framebuffer erase
+- 8 bpp support - now we always draw as 16 bpp, but this is not a problem since
+ VDP2 interprets framebuffer as 8 bpp in these cases
+*/
+
+
+#include "driver.h"
+
+static int vdp1_sprite_log = 0;
+
+UINT32 *stv_vdp1_vram;
+static UINT32 *stv_vdp1_regs;
+UINT8* stv_vdp1_gfx_decode;
+
+extern UINT32 *stv_scu;
+extern int stv_vblank;
+
+static UINT16 *stv_framebuffer[2];
+static UINT16 **stv_framebuffer_draw_lines;
+UINT16 **stv_framebuffer_display_lines;
+static int stv_framebuffer_width;
+static int stv_framebuffer_height;
+int stv_framebuffer_mode;
+int stv_framebuffer_double_interlace;
+static int stv_vdp1_fbcr_accessed;
+static int stv_vdp1_current_display_framebuffer;
+static int stv_vdp1_current_draw_framebuffer;
+static int stv_vdp1_clear_framebuffer_on_next_frame;
+static rectangle stv_vdp1_system_cliprect;
+static rectangle stv_vdp1_user_cliprect;
+
+static int stvvdp1_local_x;
+static int stvvdp1_local_y;
+
+struct stv_vdp1_poly_scanline
+{
+ INT32 x[2];
+ INT32 b[2];
+ INT32 g[2];
+ INT32 r[2];
+ INT32 db;
+ INT32 dg;
+ INT32 dr;
+};
+
+struct stv_vdp1_poly_scanline_data
+{
+ INT32 sy, ey;
+ struct stv_vdp1_poly_scanline scanline[512];
+};
+
+static struct stv_vdp1_poly_scanline_data* stv_vdp1_shading_data;
+
+enum { FRAC_SHIFT = 16 };
+
+struct spoint {
+ INT32 x, y;
+ INT32 u, v;
+};
+
+struct shaded_point
+{
+ INT32 x,y;
+ INT32 r,g,b;
+};
+
+#define RGB_R(_color) (_color & 0x1f)
+#define RGB_G(_color) ((_color >> 5) & 0x1f)
+#define RGB_B(_color) ((_color >> 10) & 0x1f)
+
+#define SWAP_INT32(_a,_b) \
+ { \
+ INT32 t; \
+ t = _a; \
+ _a = _b; \
+ _b = t; \
+ }
+
+#define SWAP_INT32PTR(_p1, _p2) \
+ { \
+ INT32 *p; \
+ p = _p1; \
+ _p1 = _p2; \
+ _p2 = p; \
+ }
+
+/*TV Mode Selection Register */
+/*
+ xxxx xxxx xxxx ---- | UNUSED
+ ---- ---- ---- x--- | VBlank Erase/Write (VBE)
+ ---- ---- ---- -xxx | TV Mode (TVM)
+ TV-Mode:
+ This sets the Frame Buffer size,the rotation of the Frame Buffer & the bit width.
+ bit 2 HDTV disable(0)/enable(1)
+ bit 1 non-rotation/rotation(1)
+ bit 0 16(0)/8(1) bits per pixel
+ Size of the Frame Buffer:
+ 7 invalid
+ 6 invalid
+ 5 invalid
+ 4 512x256
+ 3 512x512
+ 2 512x256
+ 1 1024x256
+ 0 512x256
+*/
+#define STV_VDP1_TVMR ((stv_vdp1_regs[0x000/4] >> 16)&0x0000ffff)
+#define STV_VDP1_VBE ((STV_VDP1_TVMR & 0x0008) >> 3)
+#define STV_VDP1_TVM ((STV_VDP1_TVMR & 0x0007) >> 0)
+
+/*Frame Buffer Change Mode Register*/
+/*
+ xxxx xxxx xxx- ---- | UNUSED
+ ---- ---- ---x ---- | Even/Odd Coordinate Select Bit (EOS)
+ ---- ---- ---- x--- | Double Interlace Mode (DIE)
+ ---- ---- ---- -x-- | Double Interlace Draw Line (DIL)
+ ---- ---- ---- --x- | Frame Buffer Change Trigger (FCM)
+ ---- ---- ---- ---x | Frame Buffer Change Mode (FCT)
+*/
+#define STV_VDP1_FBCR ((stv_vdp1_regs[0x000/4] >> 0)&0x0000ffff)
+#define STV_VDP1_EOS ((STV_VDP1_FBCR & 0x0010) >> 4)
+#define STV_VDP1_DIE ((STV_VDP1_FBCR & 0x0008) >> 3)
+#define STV_VDP1_DIL ((STV_VDP1_FBCR & 0x0004) >> 2)
+#define STV_VDP1_FCM ((STV_VDP1_FBCR & 0x0002) >> 1)
+#define STV_VDP1_FCT ((STV_VDP1_FBCR & 0x0001) >> 0)
+
+/*Plot Trigger Register*/
+/*
+ xxxx xxxx xxxx xx-- | UNUSED
+ ---- ---- ---- --xx | Plot Trigger Mode (PTM)
+
+ Plot Trigger Mode:
+ 3 Invalid
+ 2 Automatic draw
+ 1 VDP1 draw by request
+ 0 VDP1 Idle (no access)
+*/
+#define STV_VDP1_PTMR ((stv_vdp1_regs[0x004/4] >> 16)&0x0000ffff)
+#define STV_VDP1_PTM ((STV_VDP1_PTMR & 0x0003) >> 0)
+#define SET_PTM_FROM_1_TO_0 if(STV_VDP1_PTM & 1) stv_vdp1_regs[0x004/4]^=0x00010000
+/*Erase/Write Upper-Left register*/
+/*
+ x--- ---- ---- ---- | UNUSED
+ -xxx xxx- ---- ---- | X1 register
+ ---- ---x xxxx xxxx | Y1 register
+
+*/
+#define STV_VDP1_EWLR ((stv_vdp1_regs[0x008/4] >> 16)&0x0000ffff)
+#define STV_VDP1_EWLR_X1 ((STV_VDP1_EWLR & 0x7e00) >> 9)
+#define STV_VDP1_EWLR_Y1 ((STV_VDP1_EWLR & 0x01ff) >> 0)
+/*Erase/Write Lower-Right register*/
+/*
+ xxxx xxx- ---- ---- | X3 register
+ ---- ---x xxxx xxxx | Y3 register
+
+*/
+#define STV_VDP1_EWRR ((stv_vdp1_regs[0x008/4] >> 0)&0x0000ffff)
+#define STV_VDP1_EWRR_X3 ((STV_VDP1_EWRR & 0xfe00) >> 9)
+#define STV_VDP1_EWRR_Y3 ((STV_VDP1_EWRR & 0x01ff) >> 0)
+/*Transfer End Status Register*/
+/*
+ xxxx xxxx xxxx xx-- | UNUSED
+ ---- ---- ---- --x- | CEF
+ ---- ---- ---- ---x | BEF
+
+*/
+#define STV_VDP1_EDSR ((stv_vdp1_regs[0x010/4] >> 16)&0x0000ffff)
+#define STV_VDP1_CEF (STV_VDP1_EDSR & 2)
+#define STV_VDP1_BEF (STV_VDP1_EDSR & 1)
+#define SET_CEF_FROM_1_TO_0 if(STV_VDP1_CEF) stv_vdp1_regs[0x010/4]^=0x00020000
+#define SET_CEF_FROM_0_TO_1 if(!(STV_VDP1_CEF)) stv_vdp1_regs[0x010/4]^=0x00020000
+/**/
+
+
+
+static void stv_vdp1_process_list(void);
+
+READ32_HANDLER( stv_vdp1_regs_r )
+{
+// static int x;
+
+// x ^= 0x00020000;
+
+ logerror ("cpu #%d (PC=%08X) VDP1: Read from Registers, Offset %04x\n",cpu_getactivecpu(), activecpu_get_pc(), offset);
+// if (offset == 0x04) return x;
+
+ return stv_vdp1_regs[offset];
+}
+
+static void stv_clear_framebuffer( int which_framebuffer )
+{
+ if ( vdp1_sprite_log ) logerror( "Clearing %d framebuffer\n", stv_vdp1_current_draw_framebuffer );
+ memset( stv_framebuffer[ which_framebuffer ], 0, 1024 * 256 * sizeof(UINT16) * 2 );
+}
+
+
+static void stv_prepare_framebuffers( void )
+{
+ int i,rowsize;
+
+ rowsize = stv_framebuffer_width;
+ if ( stv_vdp1_current_draw_framebuffer == 0 )
+ {
+ for ( i = 0; i < stv_framebuffer_height; i++ )
+ {
+ stv_framebuffer_draw_lines[i] = &stv_framebuffer[0][ i * rowsize ];
+ stv_framebuffer_display_lines[i] = &stv_framebuffer[1][ i * rowsize ];
+ }
+ for ( ; i < 512; i++ )
+ {
+ stv_framebuffer_draw_lines[i] = &stv_framebuffer[0][0];
+ stv_framebuffer_display_lines[i] = &stv_framebuffer[1][0];
+ }
+
+ }
+ else
+ {
+ for ( i = 0; i < stv_framebuffer_height; i++ )
+ {
+ stv_framebuffer_draw_lines[i] = &stv_framebuffer[1][ i * rowsize ];
+ stv_framebuffer_display_lines[i] = &stv_framebuffer[0][ i * rowsize ];
+ }
+ for ( ; i < 512; i++ )
+ {
+ stv_framebuffer_draw_lines[i] = &stv_framebuffer[1][0];
+ stv_framebuffer_display_lines[i] = &stv_framebuffer[0][0];
+ }
+
+ }
+
+ for ( ; i < 512; i++ )
+ {
+ stv_framebuffer_draw_lines[i] = &stv_framebuffer[0][0];
+ stv_framebuffer_display_lines[i] = &stv_framebuffer[1][0];
+ }
+
+}
+
+static void stv_vdp1_change_framebuffers( void )
+{
+ stv_vdp1_current_display_framebuffer ^= 1;
+ stv_vdp1_current_draw_framebuffer ^= 1;
+ if ( vdp1_sprite_log ) logerror( "Changing framebuffers: %d - draw, %d - display\n", stv_vdp1_current_draw_framebuffer, stv_vdp1_current_display_framebuffer );
+ stv_prepare_framebuffers();
+}
+
+static void stv_set_framebuffer_config( void )
+{
+ if ( stv_framebuffer_mode == STV_VDP1_TVM &&
+ stv_framebuffer_double_interlace == STV_VDP1_DIE ) return;
+
+ if ( vdp1_sprite_log ) logerror( "Setting framebuffer config\n" );
+ stv_framebuffer_mode = STV_VDP1_TVM;
+ stv_framebuffer_double_interlace = STV_VDP1_DIE;
+ switch( stv_framebuffer_mode )
+ {
+ case 0: stv_framebuffer_width = 512; stv_framebuffer_height = 256; break;
+ case 1: stv_framebuffer_width = 1024; stv_framebuffer_height = 256; break;
+ case 2: stv_framebuffer_width = 512; stv_framebuffer_height = 256; break;
+ case 3: stv_framebuffer_width = 512; stv_framebuffer_height = 512; break;
+ case 4: stv_framebuffer_width = 512; stv_framebuffer_height = 256; break;
+ default: logerror( "Invalid framebuffer config %x\n", STV_VDP1_TVM ); stv_framebuffer_width = 512; stv_framebuffer_height = 256; break;
+ }
+ if ( STV_VDP1_DIE ) stv_framebuffer_height *= 2; /* double interlace */
+
+ stv_vdp1_current_draw_framebuffer = 0;
+ stv_vdp1_current_display_framebuffer = 1;
+ stv_prepare_framebuffers();
+}
+
+WRITE32_HANDLER( stv_vdp1_regs_w )
+{
+ COMBINE_DATA(&stv_vdp1_regs[offset]);
+ if ( offset == 0 )
+ {
+ stv_set_framebuffer_config();
+ if ( ACCESSING_LSW32 )
+ {
+ if ( vdp1_sprite_log ) logerror( "VDP1: Access to register FBCR = %1X\n", STV_VDP1_FBCR );
+ stv_vdp1_fbcr_accessed = 1;
+ }
+ else
+ {
+ if ( vdp1_sprite_log ) logerror( "VDP1: Access to register TVMR = %1X\n", STV_VDP1_TVMR );
+ if ( STV_VDP1_VBE && stv_vblank )
+ {
+ stv_vdp1_clear_framebuffer_on_next_frame = 1;
+ }
+
+ /* needed by pblbeach, it doesn't clear local coordinates in its sprite list...*/
+ if ( !strcmp(Machine->gamedrv->name, "pblbeach") )
+ {
+ stvvdp1_local_x = stvvdp1_local_y = 0;
+ }
+ }
+ }
+ else if ( offset == 1 )
+ {
+ if ( ACCESSING_MSW32 )
+ {
+ if ( STV_VDP1_PTMR == 1 )
+ {
+ if ( vdp1_sprite_log ) logerror( "VDP1: Access to register PTMR = %1X\n", STV_VDP1_PTMR );
+ stv_vdp1_process_list( );
+
+ if(!(stv_scu[40] & 0x2000)) /*Sprite draw end irq*/
+ {
+ logerror( "Interrupt: Sprite draw end, Vector 0x4d, Level 0x02\n" );
+ cpunum_set_input_line_and_vector(0, 2, HOLD_LINE , 0x4d);
+ }
+ }
+ }
+ else if ( ACCESSING_LSW32 )
+ {
+ if ( vdp1_sprite_log ) logerror( "VDP1: Erase data set %08X\n", data );
+ }
+ }
+ else if ( offset == 2 )
+ {
+ if ( ACCESSING_MSW32 )
+ {
+ if ( vdp1_sprite_log ) logerror( "VDP1: Erase upper-left coord set: %08X\n", data );
+ }
+ else if ( ACCESSING_LSW32 )
+ {
+ if ( vdp1_sprite_log ) logerror( "VDP1: Erase lower-right coord set: %08X\n", data );
+ }
+ }
+
+}
+
+READ32_HANDLER ( stv_vdp1_vram_r )
+{
+ return stv_vdp1_vram[offset];
+}
+
+
+WRITE32_HANDLER ( stv_vdp1_vram_w )
+{
+ UINT8 *vdp1 = stv_vdp1_gfx_decode;
+
+ COMBINE_DATA (&stv_vdp1_vram[offset]);
+
+// if (((offset * 4) > 0xdf) && ((offset * 4) < 0x140))
+// {
+// logerror("cpu #%d (PC=%08X): VRAM dword write to %08X = %08X & %08X\n", cpu_getactivecpu(), activecpu_get_pc(), offset*4, data, mem_mask ^ 0xffffffff);
+// }
+
+ data = stv_vdp1_vram[offset];
+ /* put in gfx region for easy decoding */
+ vdp1[offset*4+0] = (data & 0xff000000) >> 24;
+ vdp1[offset*4+1] = (data & 0x00ff0000) >> 16;
+ vdp1[offset*4+2] = (data & 0x0000ff00) >> 8;
+ vdp1[offset*4+3] = (data & 0x000000ff) >> 0;
+}
+
+WRITE32_HANDLER ( stv_vdp1_framebuffer0_w )
+{
+ //popmessage ("STV VDP1 Framebuffer 0 WRITE offset %08x data %08x",offset, data);
+ if ( STV_VDP1_TVM & 0 )
+ {
+ /* 8-bit mode */
+ }
+ else
+ {
+ /* 16-bit mode */
+ if ( ACCESSING_MSW32 )
+ {
+ stv_framebuffer[stv_vdp1_current_draw_framebuffer][offset*2] = (data >> 16) & 0xffff;
+ }
+ if ( ACCESSING_LSW32 )
+ {
+ stv_framebuffer[stv_vdp1_current_draw_framebuffer][offset*2+1] = data & 0xffff;
+ }
+ }
+}
+
+READ32_HANDLER ( stv_vdp1_framebuffer0_r )
+{
+ UINT32 result = 0;
+ //popmessage ("STV VDP1 Framebuffer 0 READ offset %08x",offset);
+ if ( STV_VDP1_TVM & 0 )
+ {
+ /* 8-bit mode */
+ }
+ else
+ {
+ /* 16-bit mode */
+ if ( ACCESSING_MSW32 )
+ {
+ result |= (stv_framebuffer[stv_vdp1_current_draw_framebuffer][offset*2] << 16);
+ }
+ if ( ACCESSING_LSW32 )
+ {
+ result |= stv_framebuffer[stv_vdp1_current_draw_framebuffer][offset*2+1];
+ }
+
+ }
+
+ return result;
+}
+
+#ifdef UNUSED_FUNCTION
+WRITE32_HANDLER ( stv_vdp1_framebuffer1_w )
+{
+ //popmessage ("STV VDP1 Framebuffer 1 WRITE offset %08x data %08x",offset, data);
+}
+
+READ32_HANDLER ( stv_vdp1_framebuffer1_r )
+{
+ //popmessage ("STV VDP1 Framebuffer 1 READ offset %08x",offset);
+ return 0xffff;
+}
+#endif
+
+
+/*
+
+there is a command every 0x20 bytes
+the first word is the control word
+the rest are data used by it
+
+---
+00 CMDCTRL
+ e--- ---- ---- ---- | end bit (15)
+ -jjj ---- ---- ---- | jump select bits (12-14)
+ ---- zzzz ---- ---- | zoom point / hotspot (8-11)
+ ---- ---- 00-- ---- | UNUSED
+ ---- ---- --dd ---- | character read direction (4,5)
+ ---- ---- ---- cccc | command bits (0-3)
+
+02 CMDLINK
+ llll llll llll ll-- | link
+ ---- ---- ---- --00 | UNUSED
+
+04 CMDPMOD
+ m--- ---- ---- ---- | MON (looks at MSB and apply shadows etc.)
+ -00- ---- ---- ---- | UNUSED
+ ---h ---- ---- ---- | HSS (High Speed Shrink)
+ ---- p--- ---- ---- | PCLIP (Pre Clipping Disable)
+ ---- -c-- ---- ---- | CLIP (Clipping Mode Bit)
+ ---- --m- ---- ---- | CMOD (User Clipping Enable Bit)
+ ---- ---M ---- ---- | MESH (Mesh Enable Bit)
+ ---- ---- e--- ---- | ECD (End Code Disable)
+ ---- ---- -S-- ---- | SPD (Transparent Pixel Disable)
+ ---- ---- --cc c--- | Colour Mode
+ ---- ---- ---- -CCC | Colour Calculation bits
+
+06 CMDCOLR
+ mmmm mmmm mmmm mmmm | Colour Bank, Colour Lookup /8
+
+08 CMDSRCA (Character Address)
+ aaaa aaaa aaaa aa-- | Character Address
+ ---- ---- ---- --00 | UNUSED
+
+0a CMDSIZE (Character Size)
+ 00-- ---- ---- ---- | UNUSED
+ --xx xxxx ---- ---- | Character Size (X)
+ ---- ---- yyyy yyyy | Character Size (Y)
+
+0c CMDXA (used for normal sprite)
+ eeee ee-- ---- ---- | extension bits
+ ---- --xx xxxx xxxx | x position
+
+0e CMDYA (used for normal sprite)
+ eeee ee-- ---- ---- | extension bits
+ ---- --yy yyyy yyyy | y position
+
+10 CMDXB
+12 CMDYB
+14 CMDXC
+16 CMDYC
+18 CMDXD
+1a CMDYD
+1c CMDGRDA (Gouraud Shading Table)
+1e UNUSED
+---
+
+
+*/
+
+static struct stv_vdp2_sprite_list
+{
+
+ int CMDCTRL, CMDLINK, CMDPMOD, CMDCOLR, CMDSRCA, CMDSIZE, CMDGRDA;
+ int CMDXA, CMDYA;
+ int CMDXB, CMDYB;
+ int CMDXC, CMDYC;
+ int CMDXD, CMDYD;
+
+ int ispoly;
+
+} stv2_current_sprite;
+
+/* Gouraud shading */
+
+static struct _stv_gouraud_shading
+{
+ /* Gouraud shading table */
+ UINT16 GA;
+ UINT16 GB;
+ UINT16 GC;
+ UINT16 GD;
+} stv_gouraud_shading;
+
+static void stv_clear_gouraud_shading(void)
+{
+ memset( &stv_gouraud_shading, 0, sizeof( stv_gouraud_shading ) );
+}
+
+static UINT8 stv_read_gouraud_table(void)
+{
+ int gaddr;
+
+ if ( (stv2_current_sprite.CMDPMOD & 0x7) == 4 )
+ {
+ gaddr = stv2_current_sprite.CMDGRDA * 8;
+ stv_gouraud_shading.GA = (stv_vdp1_vram[gaddr/4] >> 16) & 0xffff;
+ stv_gouraud_shading.GB = (stv_vdp1_vram[gaddr/4] >> 0) & 0xffff;
+ stv_gouraud_shading.GC = (stv_vdp1_vram[gaddr/4 + 1] >> 16) & 0xffff;
+ stv_gouraud_shading.GD = (stv_vdp1_vram[gaddr/4 + 1] >> 0) & 0xffff;
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+INLINE INT32 _shading( INT32 color, INT32 correction )
+{
+ correction = (correction >> 16) & 0x1f;
+ color += (correction - 16);
+
+ if ( color < 0 ) color = 0;
+ if ( color > 0x1f ) color = 0x1f;
+
+ return color;
+};
+
+static UINT16 stv_vdp1_apply_gouraud_shading( int x, int y, UINT16 pix )
+{
+ INT32 r,g,b, msb;
+
+ msb = pix & 0x8000;
+
+#ifdef MAME_DEBUG
+ if ( (stv_vdp1_shading_data->scanline[y].x[0] >> 16) != x )
+ {
+ logerror( "ERROR in computing x coordinates (line %d, x = %x, %d, xc = %x, %d)\n", y, x, x, stv_vdp1_shading_data->scanline[y].x[0], stv_vdp1_shading_data->scanline[y].x[0] >> 16 );
+ };
+#endif
+
+ b = RGB_B(pix);
+ g = RGB_G(pix);
+ r = RGB_R(pix);
+
+ b = _shading( b, stv_vdp1_shading_data->scanline[y].b[0] );
+ g = _shading( g, stv_vdp1_shading_data->scanline[y].g[0] );
+ r = _shading( r, stv_vdp1_shading_data->scanline[y].r[0] );
+
+ stv_vdp1_shading_data->scanline[y].b[0] += stv_vdp1_shading_data->scanline[y].db;
+ stv_vdp1_shading_data->scanline[y].g[0] += stv_vdp1_shading_data->scanline[y].dg;
+ stv_vdp1_shading_data->scanline[y].r[0] += stv_vdp1_shading_data->scanline[y].dr;
+
+ stv_vdp1_shading_data->scanline[y].x[0] += 1 << FRAC_SHIFT;
+
+ return msb | b << 10 | g << 5 | r;
+}
+
+static void stv_vdp1_setup_shading_for_line(INT32 y, INT32 x1, INT32 x2,
+ INT32 r1, INT32 g1, INT32 b1,
+ INT32 r2, INT32 g2, INT32 b2)
+{
+ int xx1 = x1>>FRAC_SHIFT;
+ int xx2 = x2>>FRAC_SHIFT;
+
+
+ if ( xx1 > xx2 )
+ {
+ SWAP_INT32(xx1, xx2);
+ SWAP_INT32(r1, r2);
+ SWAP_INT32(g1, g2);
+ SWAP_INT32(b1, b2);
+ }
+
+ if ( (y >= 0) && (y < 512) )
+ {
+ INT32 dx;
+ INT32 gbd, ggd, grd;
+
+ dx = xx2 - xx1;
+
+ if ( dx == 0 )
+ {
+ gbd = ggd = grd = 0;
+ }
+ else
+ {
+ gbd = abs(b2 - b1) / dx;
+ if (b2 < b1) gbd = -gbd;
+ ggd = abs(g2 - g1) / dx;
+ if (g2 < g1) ggd = -ggd;
+ grd = abs(r2 - r1) / dx;
+ if (r2 < r1) grd = -grd;
+ }
+
+ stv_vdp1_shading_data->scanline[y].x[0] = x1;
+ stv_vdp1_shading_data->scanline[y].x[1] = x2;
+
+ stv_vdp1_shading_data->scanline[y].b[0] = b1;
+ stv_vdp1_shading_data->scanline[y].g[0] = g1;
+ stv_vdp1_shading_data->scanline[y].r[0] = r1;
+ stv_vdp1_shading_data->scanline[y].b[1] = b2;
+ stv_vdp1_shading_data->scanline[y].g[1] = g2;
+ stv_vdp1_shading_data->scanline[y].r[1] = r2;
+
+ stv_vdp1_shading_data->scanline[y].db = gbd;
+ stv_vdp1_shading_data->scanline[y].dg = ggd;
+ stv_vdp1_shading_data->scanline[y].dr = grd;
+
+ }
+}
+
+static void stv_vdp1_setup_shading_for_slope(
+ INT32 x1, INT32 x2, INT32 sl1, INT32 sl2, INT32 *nx1, INT32 *nx2,
+ INT32 r1, INT32 r2, INT32 slr1, INT32 slr2, INT32 *nr1, INT32 *nr2,
+ INT32 g1, INT32 g2, INT32 slg1, INT32 slg2, INT32 *ng1, INT32 *ng2,
+ INT32 b1, INT32 b2, INT32 slb1, INT32 slb2, INT32 *nb1, INT32 *nb2,
+ INT32 _y1, INT32 y2)
+{
+ if(x1 > x2 || (x1==x2 && sl1 > sl2)) {
+ SWAP_INT32(x1,x2);
+ SWAP_INT32(sl1,sl2);
+ SWAP_INT32PTR(nx1, nx2);
+ SWAP_INT32(r1,r2);
+ SWAP_INT32(slr1, slr2);
+ SWAP_INT32PTR(nr1, nr2);
+ SWAP_INT32(g1, g2);
+ SWAP_INT32(slg1, slg2);
+ SWAP_INT32PTR(ng1, ng2);
+ SWAP_INT32(b1, b2);
+ SWAP_INT32(slb1, slb2);
+ SWAP_INT32PTR(nb1, nb2);
+ }
+
+ while(_y1 < y2)
+ {
+ stv_vdp1_setup_shading_for_line(_y1, x1, x2, r1, g1, b1, r2, g2, b2);
+ x1 += sl1;
+ r1 += slr1;
+ g1 += slg1;
+ b1 += slb1;
+
+ x2 += sl2;
+ r2 += slr2;
+ g2 += slg2;
+ b2 += slb2;
+ _y1++;
+ }
+ *nx1 = x1;
+ *nr1 = r1;
+ *ng1 = g1;
+ *nb1 = b1;
+
+ *nx2 = x2;
+ *nr2 = r2;
+ *nb2 = b2;
+ *ng2 = g2;
+}
+
+static void stv_vdp1_setup_shading(const struct spoint* q, const rectangle *cliprect)
+{
+ INT32 x1, x2, delta, cury, limy;
+ INT32 r1, g1, b1, r2, g2, b2;
+ INT32 sl1, slg1, slb1, slr1;
+ INT32 sl2, slg2, slb2, slr2;
+ int pmin, pmax, i, ps1, ps2;
+ struct shaded_point p[8];
+ UINT16 gd[4];
+
+ if ( stv_read_gouraud_table() == 0 ) return;
+
+ gd[0] = stv_gouraud_shading.GA;
+ gd[1] = stv_gouraud_shading.GB;
+ gd[2] = stv_gouraud_shading.GC;
+ gd[3] = stv_gouraud_shading.GD;
+
+ for(i=0; i<4; i++) {
+ p[i].x = p[i+4].x = q[i].x << FRAC_SHIFT;
+ p[i].y = p[i+4].y = q[i].y;
+ p[i].r = p[i+4].r = RGB_R(gd[i]) << FRAC_SHIFT;
+ p[i].g = p[i+4].g = RGB_G(gd[i]) << FRAC_SHIFT;
+ p[i].b = p[i+4].b = RGB_B(gd[i]) << FRAC_SHIFT;
+ }
+
+ pmin = pmax = 0;
+ for(i=1; i<4; i++) {
+ if(p[i].y < p[pmin].y)
+ pmin = i;
+ if(p[i].y > p[pmax].y)
+ pmax = i;
+ }
+
+ cury = p[pmin].y;
+ limy = p[pmax].y;
+
+ stv_vdp1_shading_data->sy = cury;
+ stv_vdp1_shading_data->ey = limy;
+
+ if(cury == limy) {
+ x1 = x2 = p[0].x;
+ ps1 = ps2 = 0;
+ for(i=1; i<4; i++) {
+ if(p[i].x < x1) {
+ x1 = p[i].x;
+ ps1 = i;
+ }
+ if(p[i].x > x2) {
+ x2 = p[i].x;
+ ps2 = i;
+ }
+ }
+ stv_vdp1_setup_shading_for_line(cury, x1, x2, p[ps1].r, p[ps1].g, p[ps1].b, p[ps2].r, p[ps2].g, p[ps2].b);
+ goto finish;
+ }
+
+ ps1 = pmin+4;
+ ps2 = pmin;
+
+ goto startup;
+
+ for(;;) {
+ if(p[ps1-1].y == p[ps2+1].y) {
+ stv_vdp1_setup_shading_for_slope(
+ x1, x2, sl1, sl2, &x1, &x2,
+ r1, r2, slr1, slr2, &r1, &r2,
+ g1, g2, slg1, slg2, &g1, &g2,
+ b1, b2, slb1, slb2, &b1, &b2,
+ cury, p[ps1-1].y);
+ cury = p[ps1-1].y;
+ if(cury >= limy)
+ break;
+ ps1--;
+ ps2++;
+
+ startup:
+ while(p[ps1-1].y == cury)
+ ps1--;
+ while(p[ps2+1].y == cury)
+ ps2++;
+ x1 = p[ps1].x;
+ r1 = p[ps1].r;
+ g1 = p[ps1].g;
+ b1 = p[ps1].b;
+ x2 = p[ps2].x;
+ r2 = p[ps2].r;
+ g2 = p[ps2].g;
+ b2 = p[ps2].b;
+
+ delta = cury-p[ps1-1].y;
+ sl1 = (x1-p[ps1-1].x)/delta;
+ slr1 = (r1-p[ps1-1].r)/delta;
+ slg1 = (g1-p[ps1-1].g)/delta;
+ slb1 = (b1-p[ps1-1].b)/delta;
+
+ delta = cury-p[ps2+1].y;
+ sl2 = (x2-p[ps2+1].x)/delta;
+ slr2 = (r2-p[ps2+1].r)/delta;
+ slg2 = (g2-p[ps2+1].g)/delta;
+ slb2 = (b2-p[ps2+1].b)/delta;
+ } else if(p[ps1-1].y < p[ps2+1].y) {
+ stv_vdp1_setup_shading_for_slope(
+ x1, x2, sl1, sl2, &x1, &x2,
+ r1, r2, slr1, slr2, &r1, &r2,
+ g1, g2, slg1, slg2, &g1, &g2,
+ b1, b2, slb1, slb2, &b1, &b2,
+ cury, p[ps1-1].y);
+ cury = p[ps1-1].y;
+ if(cury >= limy)
+ break;
+ ps1--;
+ while(p[ps1-1].y == cury)
+ ps1--;
+ x1 = p[ps1].x;
+ r1 = p[ps1].r;
+ g1 = p[ps1].g;
+ b1 = p[ps1].b;
+
+ delta = cury-p[ps1-1].y;
+ sl1 = (x1-p[ps1-1].x)/delta;
+ slr1 = (r1-p[ps1-1].r)/delta;
+ slg1 = (g1-p[ps1-1].g)/delta;
+ slb1 = (b1-p[ps1-1].b)/delta;
+ } else {
+ stv_vdp1_setup_shading_for_slope(
+ x1, x2, sl1, sl2, &x1, &x2,
+ r1, r2, slr1, slr2, &r1, &r2,
+ g1, g2, slg1, slg2, &g1, &g2,
+ b1, b2, slb1, slb2, &b1, &b2,
+ cury, p[ps2+1].y);
+ cury = p[ps2+1].y;
+ if(cury >= limy)
+ break;
+ ps2++;
+ while(p[ps2+1].y == cury)
+ ps2++;
+ x2 = p[ps2].x;
+ r2 = p[ps2].r;
+ g2 = p[ps2].g;
+ b2 = p[ps2].b;
+
+ delta = cury-p[ps2+1].y;
+ sl2 = (x2-p[ps2+1].x)/delta;
+ slr2 = (r2-p[ps2+1].r)/delta;
+ slg2 = (g2-p[ps2+1].g)/delta;
+ slb2 = (b2-p[ps2+1].b)/delta;
+ }
+ }
+ if(cury == limy)
+ stv_vdp1_setup_shading_for_line(cury, x1, x2, r1, g1, b1, r2, g2, b2 );
+
+finish:
+
+ if ( stv_vdp1_shading_data->sy < 0 ) stv_vdp1_shading_data->sy = 0;
+ if ( stv_vdp1_shading_data->sy >= 512 ) return;
+ if ( stv_vdp1_shading_data->ey < 0 ) return;
+ if ( stv_vdp1_shading_data->ey >= 512 ) stv_vdp1_shading_data->ey = 511;
+
+ for ( cury = stv_vdp1_shading_data->sy; cury <= stv_vdp1_shading_data->ey; cury++ )
+ {
+ while( (stv_vdp1_shading_data->scanline[cury].x[0] >> 16) < cliprect->min_x )
+ {
+ stv_vdp1_shading_data->scanline[cury].x[0] += (1 << FRAC_SHIFT);
+ stv_vdp1_shading_data->scanline[cury].b[0] += stv_vdp1_shading_data->scanline[cury].db;
+ stv_vdp1_shading_data->scanline[cury].g[0] += stv_vdp1_shading_data->scanline[cury].dg;
+ stv_vdp1_shading_data->scanline[cury].r[0] += stv_vdp1_shading_data->scanline[cury].dr;
+ }
+ }
+
+}
+
+/* note that if we're drawing
+to the framebuffer we CAN'T frameskip the vdp1 drawing as the hardware can READ the framebuffer
+and if we skip the drawing the content could be incorrect when it reads it, although i have no idea
+why they would want to */
+
+extern UINT32* stv_vdp2_cram;
+
+static UINT8* gfxdata;
+static UINT16 sprite_colorbank;
+
+
+static void (*drawpixel)(int x, int y, int patterndata, int offsetcnt);
+
+static void drawpixel_poly(int x, int y, int patterndata, int offsetcnt)
+{
+ stv_framebuffer_draw_lines[y][x] = stv2_current_sprite.CMDCOLR;
+}
+
+static void drawpixel_8bpp_trans(int x, int y, int patterndata, int offsetcnt)
+{
+ UINT16 pix;
+
+ pix = gfxdata[patterndata+offsetcnt];
+ if ( pix & 0xff )
+ {
+ stv_framebuffer_draw_lines[y][x] = pix | sprite_colorbank;
+ }
+};
+
+static void drawpixel_4bpp_notrans(int x, int y, int patterndata, int offsetcnt)
+{
+ UINT16 pix;
+
+ pix = gfxdata[patterndata+offsetcnt/2];
+ pix = offsetcnt&1 ? (pix & 0x0f):((pix & 0xf0)>>4) ;
+ stv_framebuffer_draw_lines[y][x] = pix | sprite_colorbank;
+}
+
+static void drawpixel_4bpp_trans(int x, int y, int patterndata, int offsetcnt)
+{
+ UINT16 pix;
+
+ pix = gfxdata[patterndata+offsetcnt/2];
+ pix = offsetcnt&1 ? (pix & 0x0f):((pix & 0xf0)>>4) ;
+ if ( pix )
+ stv_framebuffer_draw_lines[y][x] = pix | sprite_colorbank;
+}
+
+static void drawpixel_generic(int x, int y, int patterndata, int offsetcnt)
+{
+ int pix,mode,transmask, spd = stv2_current_sprite.CMDPMOD & 0x40;
+ int mesh = stv2_current_sprite.CMDPMOD & 0x100;
+ int pix2;
+
+ if ( mesh && !((x ^ y) & 1) )
+ {
+ return;
+ }
+
+ if ( stv2_current_sprite.ispoly )
+ {
+ pix = stv2_current_sprite.CMDCOLR&0xffff;
+
+ transmask = 0xffff;
+ if ( pix & 0x8000 )
+ {
+ mode = 5;
+ }
+ else
+ {
+ mode = 1;
+ }
+ }
+ else
+ {
+ switch (stv2_current_sprite.CMDPMOD&0x0038)
+ {
+ case 0x0000: // mode 0 16 colour bank mode (4bits) (hanagumi blocks)
+ // most of the shienryu sprites use this mode
+ pix = gfxdata[patterndata+offsetcnt/2];
+ pix = offsetcnt&1 ? (pix & 0x0f):((pix & 0xf0)>>4) ;
+ pix = pix+((stv2_current_sprite.CMDCOLR&0xfff0));
+ mode = 0;
+ transmask = 0xf;
+ break;
+ case 0x0008: // mode 1 16 colour lookup table mode (4bits)
+ // shienryu explosisons (and some enemies) use this mode
+ pix2 = gfxdata[patterndata+offsetcnt/2];
+ pix2 = offsetcnt&1 ? (pix2 & 0x0f):((pix2 & 0xf0)>>4);
+ pix = pix2&1 ?
+ ((((stv_vdp1_vram[(((stv2_current_sprite.CMDCOLR&0xffff)*8)>>2)+((pix2&0xfffe)/2)])) & 0x0000ffff) >> 0):
+ ((((stv_vdp1_vram[(((stv2_current_sprite.CMDCOLR&0xffff)*8)>>2)+((pix2&0xfffe)/2)])) & 0xffff0000) >> 16);
+
+ mode = 5;
+ transmask = 0xffff;
+
+ if ( !spd )
+ {
+ if ( (pix2 & 0xf) == 0 )
+ {
+ return;
+ }
+ else
+ {
+ spd = 1;
+ }
+ }
+ break;
+ case 0x0010: // mode 2 64 colour bank mode (8bits) (character select portraits on hanagumi)
+ pix = gfxdata[patterndata+offsetcnt];
+ mode = 2;
+ pix = pix+(stv2_current_sprite.CMDCOLR&0xffc0);
+ transmask = 0x3f;
+ break;
+ case 0x0018: // mode 3 128 colour bank mode (8bits) (little characters on hanagumi use this mode)
+ pix = gfxdata[patterndata+offsetcnt];
+ pix = pix+(stv2_current_sprite.CMDCOLR&0xff80);
+ transmask = 0x7f;
+ mode = 3;
+ // pix = mame_rand(Machine);
+ break;
+ case 0x0020: // mode 4 256 colour bank mode (8bits) (hanagumi title)
+ pix = gfxdata[patterndata+offsetcnt];
+ pix = pix+(stv2_current_sprite.CMDCOLR&0xff00);
+ transmask = 0xff;
+ mode = 4;
+ break;
+ case 0x0028: // mode 5 32,768 colour RGB mode (16bits)
+ pix = gfxdata[patterndata+offsetcnt*2+1] | (gfxdata[patterndata+offsetcnt*2]<<8) ;
+ mode = 5;
+ transmask = 0xffff;
+ break;
+ default: // other settings illegal
+ pix = mame_rand(Machine);
+ mode = 0;
+ transmask = 0xff;
+ }
+
+
+ // preliminary end code disable support
+ if ( ((stv2_current_sprite.CMDPMOD & 0x80) == 0) &&
+ ((pix & transmask) == transmask) )
+ {
+ return;
+ }
+ }
+
+ /* MSBON */
+ pix |= stv2_current_sprite.CMDPMOD & 0x8000;
+ if ( mode != 5 )
+ {
+ if ( (pix & transmask) || spd )
+ {
+ stv_framebuffer_draw_lines[y][x] = pix;
+ }
+ }
+ else
+ {
+ if ( (pix & transmask) || spd )
+ {
+ switch( stv2_current_sprite.CMDPMOD & 0x7 )
+ {
+ case 0: /* replace */
+ stv_framebuffer_draw_lines[y][x] = pix;
+ break;
+ case 1: /* shadow */
+ if ( stv_framebuffer_draw_lines[y][x] & 0x8000 )
+ {
+ stv_framebuffer_draw_lines[y][x] = ((stv_framebuffer_draw_lines[y][x] & ~0x8421) >> 1) | 0x8000;
+ }
+ break;
+ case 2: /* half luminance */
+ stv_framebuffer_draw_lines[y][x] = ((pix & ~0x8421) >> 1) | 0x8000;
+ break;
+ case 3: /* half transparent */
+ if ( stv_framebuffer_draw_lines[y][x] & 0x8000 )
+ {
+ stv_framebuffer_draw_lines[y][x] = alpha_blend_r16( stv_framebuffer_draw_lines[y][x], pix, 0x80 ) | 0x8000;
+ }
+ else
+ {
+ stv_framebuffer_draw_lines[y][x] = pix;
+ }
+ break;
+ case 4: /* Gouraud shading */
+ stv_framebuffer_draw_lines[y][x] = stv_vdp1_apply_gouraud_shading( x, y, pix );
+ break;
+ default:
+ stv_framebuffer_draw_lines[y][x] = pix;
+ break;
+ }
+ }
+ }
+}
+
+
+static void stv_vdp1_set_drawpixel(void)
+{
+ int sprite_type = stv2_current_sprite.CMDCTRL & 0x000f;
+ int sprite_mode = stv2_current_sprite.CMDPMOD&0x0038;
+ int spd = stv2_current_sprite.CMDPMOD & 0x40;
+ int mesh = stv2_current_sprite.CMDPMOD & 0x100;
+ int ecd = stv2_current_sprite.CMDPMOD & 0x80;
+
+ gfxdata = stv_vdp1_gfx_decode;
+
+ if ( mesh || !ecd || ((stv2_current_sprite.CMDPMOD & 0x7) != 0) )
+ {
+ drawpixel = drawpixel_generic;
+ return;
+ }
+
+ if (sprite_type == 4 && ((stv2_current_sprite.CMDPMOD & 0x7) == 0))
+ {
+ drawpixel = drawpixel_poly;
+ }
+ else if ( (sprite_mode == 0x20) && !spd )
+ {
+ sprite_colorbank = (stv2_current_sprite.CMDCOLR&0xff00);
+ drawpixel = drawpixel_8bpp_trans;
+ }
+ else if ((sprite_mode == 0x00) && spd)
+ {
+ sprite_colorbank = (stv2_current_sprite.CMDCOLR&0xfff0);
+ drawpixel = drawpixel_4bpp_notrans;
+ }
+ else if (sprite_mode == 0x00 && !spd )
+ {
+ sprite_colorbank = (stv2_current_sprite.CMDCOLR&0xfff0);
+ drawpixel = drawpixel_4bpp_trans;
+ }
+ else
+ {
+ drawpixel = drawpixel_generic;
+ }
+}
+
+
+static void vdp1_fill_slope(const rectangle *cliprect, int patterndata, int xsize,
+ INT32 x1, INT32 x2, INT32 sl1, INT32 sl2, INT32 *nx1, INT32 *nx2,
+ INT32 u1, INT32 u2, INT32 slu1, INT32 slu2, INT32 *nu1, INT32 *nu2,
+ INT32 v1, INT32 v2, INT32 slv1, INT32 slv2, INT32 *nv1, INT32 *nv2,
+ INT32 _y1, INT32 y2)
+{
+ if(_y1 > cliprect->max_y)
+ return;
+
+ if(y2 <= cliprect->min_y) {
+ int delta = y2-_y1;
+ *nx1 = x1+delta*sl1;
+ *nu1 = u1+delta*slu1;
+ *nv1 = v1+delta*slv1;
+ *nx2 = x2+delta*sl2;
+ *nu2 = u2+delta*slu2;
+ *nv2 = v2+delta*slv2;
+ return;
+ }
+
+ if(y2 > cliprect->max_y)
+ y2 = cliprect->max_y+1;
+
+ if(_y1 < cliprect->min_y) {
+ int delta = cliprect->min_y - _y1;
+ x1 += delta*sl1;
+ u1 += delta*slu1;
+ v1 += delta*slv1;
+ x2 += delta*sl2;
+ u2 += delta*slu2;
+ v2 += delta*slv2;
+ _y1 = cliprect->min_y;
+ }
+
+ if(x1 > x2 || (x1==x2 && sl1 > sl2)) {
+ INT32 t, *tp;
+ t = x1;
+ x1 = x2;
+ x2 = t;
+ t = sl1;
+ sl1 = sl2;
+ sl2 = t;
+ tp = nx1;
+ nx1 = nx2;
+ nx2 = tp;
+
+ t = u1;
+ u1 = u2;
+ u2 = t;
+ t = slu1;
+ slu1 = slu2;
+ slu2 = t;
+ tp = nu1;
+ nu1 = nu2;
+ nu2 = tp;
+
+ t = v1;
+ v1 = v2;
+ v2 = t;
+ t = slv1;
+ slv1 = slv2;
+ slv2 = t;
+ tp = nv1;
+ nv1 = nv2;
+ nv2 = tp;
+ }
+
+ while(_y1 < y2) {
+ if(_y1 >= cliprect->min_y) {
+ INT32 slux = 0, slvx = 0;
+ int xx1 = x1>>FRAC_SHIFT;
+ int xx2 = x2>>FRAC_SHIFT;
+ INT32 u = u1;
+ INT32 v = v1;
+ if(xx1 != xx2) {
+ int delta = xx2-xx1;
+ slux = (u2-u1)/delta;
+ slvx = (v2-v1)/delta;
+ }
+ if(xx1 <= cliprect->max_x || xx2 >= cliprect->min_x) {
+ if(xx1 < cliprect->min_x) {
+ int delta = cliprect->min_x-xx1;
+ u += slux*delta;
+ v += slvx*delta;
+ xx1 = cliprect->min_x;
+ }
+ if(xx2 > cliprect->max_x)
+ xx2 = cliprect->max_x;
+
+ while(xx1 <= xx2) {
+ drawpixel(xx1,_y1,
+ patterndata,
+ (v>>FRAC_SHIFT)*xsize+(u>>FRAC_SHIFT));
+ xx1++;
+ u += slux;
+ v += slvx;
+ }
+ }
+ }
+
+ x1 += sl1;
+ u1 += slu1;
+ v1 += slv1;
+ x2 += sl2;
+ u2 += slu2;
+ v2 += slv2;
+ _y1++;
+ }
+ *nx1 = x1;
+ *nu1 = u1;
+ *nv1 = v1;
+ *nx2 = x2;
+ *nu2 = u2;
+ *nv2 = v2;
+}
+
+static void vdp1_fill_line(const rectangle *cliprect, int patterndata, int xsize, INT32 y,
+ INT32 x1, INT32 x2, INT32 u1, INT32 u2, INT32 v1, INT32 v2)
+{
+ int xx1 = x1>>FRAC_SHIFT;
+ int xx2 = x2>>FRAC_SHIFT;
+
+ if(y > cliprect->max_y || y < cliprect->min_y)
+ return;
+
+ if(xx1 <= cliprect->max_x || xx2 >= cliprect->min_x) {
+ INT32 slux = 0, slvx = 0;
+ INT32 u = u1;
+ INT32 v = v1;
+ if(xx1 != xx2) {
+ int delta = xx2-xx1;
+ slux = (u2-u1)/delta;
+ slvx = (v2-v1)/delta;
+ }
+ if(xx1 < cliprect->min_x) {
+ int delta = cliprect->min_x-xx1;
+ u += slux*delta;
+ v += slvx*delta;
+ xx1 = cliprect->min_x;
+ }
+ if(xx2 > cliprect->max_x)
+ xx2 = cliprect->max_x;
+
+ while(xx1 <= xx2) {
+ drawpixel(xx1,y,
+ patterndata,
+ (v>>FRAC_SHIFT)*xsize+(u>>FRAC_SHIFT));
+ xx1++;
+ u += slux;
+ v += slvx;
+ }
+ }
+}
+
+static void vdp1_fill_quad(const rectangle *cliprect, int patterndata, int xsize, const struct spoint *q)
+{
+ INT32 sl1, sl2, slu1, slu2, slv1, slv2, cury, limy, x1, x2, u1, u2, v1, v2, delta;
+ int pmin, pmax, i, ps1, ps2;
+ struct spoint p[8];
+
+ for(i=0; i<4; i++) {
+ p[i].x = p[i+4].x = q[i].x << FRAC_SHIFT;
+ p[i].y = p[i+4].y = q[i].y;
+ p[i].u = p[i+4].u = q[i].u << FRAC_SHIFT;
+ p[i].v = p[i+4].v = q[i].v << FRAC_SHIFT;
+ }
+
+ pmin = pmax = 0;
+ for(i=1; i<4; i++) {
+ if(p[i].y < p[pmin].y)
+ pmin = i;
+ if(p[i].y > p[pmax].y)
+ pmax = i;
+ }
+
+ cury = p[pmin].y;
+ limy = p[pmax].y;
+
+ if(cury == limy) {
+ x1 = x2 = p[0].x;
+ u1 = u2 = p[0].u;
+ v1 = v2 = p[0].v;
+ for(i=1; i<4; i++) {
+ if(p[i].x < x1) {
+ x1 = p[i].x;
+ u1 = p[i].u;
+ v1 = p[i].v;
+ }
+ if(p[i].x > x2) {
+ x2 = p[i].x;
+ u2 = p[i].u;
+ v2 = p[i].v;
+ }
+ }
+ vdp1_fill_line(cliprect, patterndata, xsize, cury, x1, x2, u1, u2, v1, v2);
+ return;
+ }
+
+ if(cury > cliprect->max_y)
+ return;
+ if(limy <= cliprect->min_y)
+ return;
+
+ if(limy > cliprect->max_y)
+ limy = cliprect->max_y;
+
+ ps1 = pmin+4;
+ ps2 = pmin;
+
+ goto startup;
+
+ for(;;) {
+ if(p[ps1-1].y == p[ps2+1].y) {
+ vdp1_fill_slope(cliprect, patterndata, xsize,
+ x1, x2, sl1, sl2, &x1, &x2,
+ u1, u2, slu1, slu2, &u1, &u2,
+ v1, v2, slv1, slv2, &v1, &v2,
+ cury, p[ps1-1].y);
+ cury = p[ps1-1].y;
+ if(cury >= limy)
+ break;
+ ps1--;
+ ps2++;
+
+ startup:
+ while(p[ps1-1].y == cury)
+ ps1--;
+ while(p[ps2+1].y == cury)
+ ps2++;
+ x1 = p[ps1].x;
+ u1 = p[ps1].u;
+ v1 = p[ps1].v;
+ x2 = p[ps2].x;
+ u2 = p[ps2].u;
+ v2 = p[ps2].v;
+
+ delta = cury-p[ps1-1].y;
+ sl1 = (x1-p[ps1-1].x)/delta;
+ slu1 = (u1-p[ps1-1].u)/delta;
+ slv1 = (v1-p[ps1-1].v)/delta;
+
+ delta = cury-p[ps2+1].y;
+ sl2 = (x2-p[ps2+1].x)/delta;
+ slu2 = (u2-p[ps2+1].u)/delta;
+ slv2 = (v2-p[ps2+1].v)/delta;
+ } else if(p[ps1-1].y < p[ps2+1].y) {
+ vdp1_fill_slope(cliprect, patterndata, xsize,
+ x1, x2, sl1, sl2, &x1, &x2,
+ u1, u2, slu1, slu2, &u1, &u2,
+ v1, v2, slv1, slv2, &v1, &v2,
+ cury, p[ps1-1].y);
+ cury = p[ps1-1].y;
+ if(cury >= limy)
+ break;
+ ps1--;
+ while(p[ps1-1].y == cury)
+ ps1--;
+ x1 = p[ps1].x;
+ u1 = p[ps1].u;
+ v1 = p[ps1].v;
+
+ delta = cury-p[ps1-1].y;
+ sl1 = (x1-p[ps1-1].x)/delta;
+ slu1 = (u1-p[ps1-1].u)/delta;
+ slv1 = (v1-p[ps1-1].v)/delta;
+ } else {
+ vdp1_fill_slope(cliprect, patterndata, xsize,
+ x1, x2, sl1, sl2, &x1, &x2,
+ u1, u2, slu1, slu2, &u1, &u2,
+ v1, v2, slv1, slv2, &v1, &v2,
+ cury, p[ps2+1].y);
+ cury = p[ps2+1].y;
+ if(cury >= limy)
+ break;
+ ps2++;
+ while(p[ps2+1].y == cury)
+ ps2++;
+ x2 = p[ps2].x;
+ u2 = p[ps2].u;
+ v2 = p[ps2].v;
+
+ delta = cury-p[ps2+1].y;
+ sl2 = (x2-p[ps2+1].x)/delta;
+ slu2 = (u2-p[ps2+1].u)/delta;
+ slv2 = (v2-p[ps2+1].v)/delta;
+ }
+ }
+ if(cury == limy)
+ vdp1_fill_line(cliprect, patterndata, xsize, cury, x1, x2, u1, u2, v1, v2);
+}
+
+static int x2s(int v)
+{
+ return (INT32)(INT16)v + stvvdp1_local_x;
+}
+
+static int y2s(int v)
+{
+ return (INT32)(INT16)v + stvvdp1_local_y;
+}
+
+static void stv_vdp1_draw_line( const rectangle *cliprect)
+{
+ struct spoint q[4];
+
+ q[0].x = x2s(stv2_current_sprite.CMDXA);
+ q[0].y = y2s(stv2_current_sprite.CMDYA);
+ q[1].x = x2s(stv2_current_sprite.CMDXB);
+ q[1].y = y2s(stv2_current_sprite.CMDYB);
+ q[2].x = x2s(stv2_current_sprite.CMDXA);
+ q[2].y = y2s(stv2_current_sprite.CMDYA);
+ q[3].x = x2s(stv2_current_sprite.CMDXB);
+ q[3].y = y2s(stv2_current_sprite.CMDYB);
+
+ q[0].u = q[3].u = q[1].u = q[2].u = 0;
+ q[0].v = q[1].v = q[2].v = q[3].v = 0;
+
+ vdp1_fill_quad(cliprect, 0, 1, q);
+}
+
+static void stv_vdp1_draw_poly_line( const rectangle *cliprect)
+{
+ struct spoint q[4];
+
+ q[0].x = x2s(stv2_current_sprite.CMDXA);
+ q[0].y = y2s(stv2_current_sprite.CMDYA);
+ q[1].x = x2s(stv2_current_sprite.CMDXB);
+ q[1].y = y2s(stv2_current_sprite.CMDYB);
+ q[2].x = x2s(stv2_current_sprite.CMDXA);
+ q[2].y = y2s(stv2_current_sprite.CMDYA);
+ q[3].x = x2s(stv2_current_sprite.CMDXB);
+ q[3].y = y2s(stv2_current_sprite.CMDYB);
+
+ q[0].u = q[3].u = q[1].u = q[2].u = 0;
+ q[0].v = q[1].v = q[2].v = q[3].v = 0;
+
+ vdp1_fill_quad(cliprect, 0, 1, q);
+
+ q[0].x = x2s(stv2_current_sprite.CMDXB);
+ q[0].y = y2s(stv2_current_sprite.CMDYB);
+ q[1].x = x2s(stv2_current_sprite.CMDXC);
+ q[1].y = y2s(stv2_current_sprite.CMDYC);
+ q[2].x = x2s(stv2_current_sprite.CMDXB);
+ q[2].y = y2s(stv2_current_sprite.CMDYB);
+ q[3].x = x2s(stv2_current_sprite.CMDXC);
+ q[3].y = y2s(stv2_current_sprite.CMDYC);
+
+ q[0].u = q[3].u = q[1].u = q[2].u = 0;
+ q[0].v = q[1].v = q[2].v = q[3].v = 0;
+
+ vdp1_fill_quad(cliprect, 0, 1, q);
+
+ q[0].x = x2s(stv2_current_sprite.CMDXC);
+ q[0].y = y2s(stv2_current_sprite.CMDYC);
+ q[1].x = x2s(stv2_current_sprite.CMDXD);
+ q[1].y = y2s(stv2_current_sprite.CMDYD);
+ q[2].x = x2s(stv2_current_sprite.CMDXC);
+ q[2].y = y2s(stv2_current_sprite.CMDYC);
+ q[3].x = x2s(stv2_current_sprite.CMDXD);
+ q[3].y = y2s(stv2_current_sprite.CMDYD);
+
+ q[0].u = q[3].u = q[1].u = q[2].u = 0;
+ q[0].v = q[1].v = q[2].v = q[3].v = 0;
+
+ vdp1_fill_quad(cliprect, 0, 1, q);
+
+ q[0].x = x2s(stv2_current_sprite.CMDXD);
+ q[0].y = y2s(stv2_current_sprite.CMDYD);
+ q[1].x = x2s(stv2_current_sprite.CMDXA);
+ q[1].y = y2s(stv2_current_sprite.CMDYA);
+ q[2].x = x2s(stv2_current_sprite.CMDXD);
+ q[2].y = y2s(stv2_current_sprite.CMDYD);
+ q[3].x = x2s(stv2_current_sprite.CMDXA);
+ q[3].y = y2s(stv2_current_sprite.CMDYA);
+
+ q[0].u = q[3].u = q[1].u = q[2].u = 0;
+ q[0].v = q[1].v = q[2].v = q[3].v = 0;
+
+ stv_vdp1_setup_shading(q, cliprect);
+ vdp1_fill_quad(cliprect, 0, 1, q);
+
+}
+
+static void stv_vpd1_draw_distorted_sprite(const rectangle *cliprect)
+{
+ struct spoint q[4];
+
+ int xsize, ysize;
+ int direction;
+ int patterndata;
+
+ direction = (stv2_current_sprite.CMDCTRL & 0x0030)>>4;
+
+ if ( stv2_current_sprite.ispoly )
+ {
+ xsize = ysize = 1;
+ patterndata = 0;
+ }
+ else
+ {
+ xsize = (stv2_current_sprite.CMDSIZE & 0x3f00) >> 8;
+ xsize = xsize * 8;
+ if (xsize == 0) return; /* setting prohibited */
+
+ ysize = (stv2_current_sprite.CMDSIZE & 0x00ff);
+ if (ysize == 0) return; /* setting prohibited */
+
+ patterndata = (stv2_current_sprite.CMDSRCA) & 0xffff;
+ patterndata = patterndata * 0x8;
+
+ }
+
+
+ q[0].x = x2s(stv2_current_sprite.CMDXA);
+ q[0].y = y2s(stv2_current_sprite.CMDYA);
+ q[1].x = x2s(stv2_current_sprite.CMDXB);
+ q[1].y = y2s(stv2_current_sprite.CMDYB);
+ q[2].x = x2s(stv2_current_sprite.CMDXC);
+ q[2].y = y2s(stv2_current_sprite.CMDYC);
+ q[3].x = x2s(stv2_current_sprite.CMDXD);
+ q[3].y = y2s(stv2_current_sprite.CMDYD);
+
+ if(direction & 1) { // xflip
+ q[0].u = q[3].u = xsize-1;
+ q[1].u = q[2].u = 0;
+ } else {
+ q[0].u = q[3].u = 0;
+ q[1].u = q[2].u = xsize-1;
+ }
+ if(direction & 2) { // yflip
+ q[0].v = q[1].v = ysize-1;
+ q[2].v = q[3].v = 0;
+ } else {
+ q[0].v = q[1].v = 0;
+ q[2].v = q[3].v = ysize-1;
+ }
+
+ stv_vdp1_setup_shading(q, cliprect);
+ vdp1_fill_quad(cliprect, patterndata, xsize, q);
+}
+
+static void stv_vpd1_draw_scaled_sprite(const rectangle *cliprect)
+{
+ struct spoint q[4];
+
+ int xsize, ysize;
+ int direction;
+ int patterndata;
+ int zoompoint;
+ int x,y;
+ int x2,y2;
+ int screen_width,screen_height,screen_height_negative = 0;
+
+ direction = (stv2_current_sprite.CMDCTRL & 0x0030)>>4;
+
+ xsize = (stv2_current_sprite.CMDSIZE & 0x3f00) >> 8;
+ xsize = xsize * 8;
+
+ ysize = (stv2_current_sprite.CMDSIZE & 0x00ff);
+
+ patterndata = (stv2_current_sprite.CMDSRCA) & 0xffff;
+ patterndata = patterndata * 0x8;
+
+ zoompoint = (stv2_current_sprite.CMDCTRL & 0x0f00)>>8;
+
+ x = stv2_current_sprite.CMDXA;
+ y = stv2_current_sprite.CMDYA;
+
+ screen_width = (INT16)stv2_current_sprite.CMDXB;
+ if ( (screen_width < 0) && zoompoint)
+ {
+ screen_width = -screen_width;
+ direction |= 1;
+ }
+
+ screen_height = (INT16)stv2_current_sprite.CMDYB;
+ if ( (screen_height < 0) && zoompoint )
+ {
+ screen_height_negative = 1;
+ screen_height = -screen_height;
+ direction |= 2;
+ }
+
+ x2 = stv2_current_sprite.CMDXC; // second co-ordinate set x
+ y2 = stv2_current_sprite.CMDYC; // second co-ordinate set y
+
+ switch (zoompoint)
+ {
+ case 0x0: // specified co-ordinates
+ break;
+ case 0x5: // up left
+ break;
+ case 0x6: // up center
+ x -= screen_width/2 ;
+ break;
+ case 0x7: // up right
+ x -= screen_width;
+ break;
+
+ case 0x9: // center left
+ y -= screen_height/2 ;
+ break;
+ case 0xa: // center center
+ y -= screen_height/2 ;
+ x -= screen_width/2 ;
+
+ break;
+
+ case 0xb: // center right
+ y -= screen_height/2 ;
+ x -= screen_width;
+ break;
+
+ case 0xd: // center left
+ y -= screen_height;
+ break;
+
+ case 0xe: // center center
+ y -= screen_height;
+ x -= screen_width/2 ;
+ break;
+
+ case 0xf: // center right
+ y -= screen_height;
+ x -= screen_width;
+ break;
+
+ default: // illegal
+ break;
+
+ }
+
+ /* 0----1
+ | |
+ | |
+ 3----2 */
+
+ if (zoompoint)
+ {
+ q[0].x = x2s(x);
+ q[0].y = y2s(y);
+ q[1].x = x2s(x)+screen_width;
+ q[1].y = y2s(y);
+ q[2].x = x2s(x)+screen_width;
+ q[2].y = y2s(y)+screen_height;
+ q[3].x = x2s(x);
+ q[3].y = y2s(y)+screen_height;
+
+ if ( screen_height_negative )
+ {
+ q[0].y += screen_height;
+ q[1].y += screen_height;
+ q[2].y += screen_height;
+ q[3].y += screen_height;
+ }
+ }
+ else
+ {
+ q[0].x = x2s(x);
+ q[0].y = y2s(y);
+ q[1].x = x2s(x2);
+ q[1].y = y2s(y);
+ q[2].x = x2s(x2);
+ q[2].y = y2s(y2);
+ q[3].x = x2s(x);
+ q[3].y = y2s(y2);
+ }
+
+
+ if(direction & 1) { // xflip
+ q[0].u = q[3].u = xsize-1;
+ q[1].u = q[2].u = 0;
+ } else {
+ q[0].u = q[3].u = 0;
+ q[1].u = q[2].u = xsize-1;
+ }
+ if(direction & 2) { // yflip
+ q[0].v = q[1].v = ysize-1;
+ q[2].v = q[3].v = 0;
+ } else {
+ q[0].v = q[1].v = 0;
+ q[2].v = q[3].v = ysize-1;
+ }
+
+ stv_vdp1_setup_shading(q, cliprect);
+ vdp1_fill_quad(cliprect, patterndata, xsize, q);
+}
+
+
+static void stv_vpd1_draw_normal_sprite(const rectangle *cliprect, int sprite_type)
+{
+ UINT16 *destline;
+
+ int y, ysize, drawypos;
+ int x, xsize, drawxpos;
+ int direction;
+ int patterndata;
+ UINT8 shading;
+ int su, u, dux, duy;
+ int maxdrawypos, maxdrawxpos;
+
+
+
+ shading = stv_read_gouraud_table();
+
+ x = x2s(stv2_current_sprite.CMDXA);
+ y = y2s(stv2_current_sprite.CMDYA);
+
+ direction = (stv2_current_sprite.CMDCTRL & 0x0030)>>4;
+
+ xsize = (stv2_current_sprite.CMDSIZE & 0x3f00) >> 8;
+ xsize = xsize * 8;
+
+ ysize = (stv2_current_sprite.CMDSIZE & 0x00ff);
+
+ patterndata = (stv2_current_sprite.CMDSRCA) & 0xffff;
+ patterndata = patterndata * 0x8;
+
+ if (vdp1_sprite_log) logerror ("Drawing Normal Sprite x %04x y %04x xsize %04x ysize %04x patterndata %06x\n",x,y,xsize,ysize,patterndata);
+
+ if ( x > cliprect->max_x ) return;
+ if ( y > cliprect->max_y ) return;
+
+ shading = stv_read_gouraud_table();
+ if ( shading )
+ {
+ struct spoint q[4];
+ q[0].x = x; q[0].y = y;
+ q[1].x = x + xsize; q[1].y = y;
+ q[2].x = x + xsize; q[2].y = y + ysize;
+ q[3].x = x; q[3].y = y + ysize;
+
+ stv_vdp1_setup_shading( q, cliprect );
+ }
+
+ u = 0;
+ dux = 1;
+ duy = xsize;
+ if ( direction & 0x1 ) //xflip
+ {
+ dux = -1;
+ u = xsize - 1;
+ }
+ if ( direction & 0x2 ) //yflip
+ {
+ duy = -xsize;
+ u += xsize*(ysize-1);
+ }
+ if ( y < cliprect->min_y ) //clip y
+ {
+ u += xsize*(cliprect->min_y - y);
+ ysize -= (cliprect->min_y - y);
+ y = cliprect->min_y;
+ }
+ if ( x < cliprect->min_x ) //clip x
+ {
+ u += dux*(cliprect->min_x - x);
+ xsize -= (cliprect->min_x - x);
+ x = cliprect->min_x;
+ }
+ maxdrawypos = MIN(y+ysize-1,cliprect->max_y);
+ maxdrawxpos = MIN(x+xsize-1,cliprect->max_x);
+ for (drawypos = y; drawypos <= maxdrawypos; drawypos++ )
+ {
+ destline = stv_framebuffer_draw_lines[drawypos];
+ su = u;
+ for (drawxpos = x; drawxpos <= maxdrawxpos; drawxpos++ )
+ {
+ drawpixel( drawxpos, drawypos, patterndata, u );
+ u += dux;
+ }
+ u = su + duy;
+ }
+}
+
+void stv_vdp1_process_list()
+{
+ int position;
+ int spritecount;
+ int vdp1_nest;
+ rectangle *cliprect;
+
+ spritecount = 0;
+ position = 0;
+
+ if (vdp1_sprite_log) logerror ("Sprite List Process START\n");
+
+ vdp1_nest = -1;
+
+ stv_clear_gouraud_shading();
+
+ /*Set CEF bit to 0*/
+ SET_CEF_FROM_1_TO_0;
+
+ while (spritecount<10000) // if its drawn this many sprites something is probably wrong or sega were crazy ;-)
+ {
+ int draw_this_sprite;
+
+ draw_this_sprite = 1;
+
+ // if (position >= ((0x80000/0x20)/4)) // safety check
+ // {
+ // if (vdp1_sprite_log) logerror ("Sprite List Position Too High!\n");
+ // position = 0;
+ // }
+
+ stv2_current_sprite.CMDCTRL = (stv_vdp1_vram[position * (0x20/4)+0] & 0xffff0000) >> 16;
+
+ if (stv2_current_sprite.CMDCTRL == 0x8000)
+ {
+ if (vdp1_sprite_log) logerror ("List Terminator (0x8000) Encountered, Sprite List Process END\n");
+ goto end; // end of list
+ }
+
+ stv2_current_sprite.CMDLINK = (stv_vdp1_vram[position * (0x20/4)+0] & 0x0000ffff) >> 0;
+ stv2_current_sprite.CMDPMOD = (stv_vdp1_vram[position * (0x20/4)+1] & 0xffff0000) >> 16;
+ stv2_current_sprite.CMDCOLR = (stv_vdp1_vram[position * (0x20/4)+1] & 0x0000ffff) >> 0;
+ stv2_current_sprite.CMDSRCA = (stv_vdp1_vram[position * (0x20/4)+2] & 0xffff0000) >> 16;
+ stv2_current_sprite.CMDSIZE = (stv_vdp1_vram[position * (0x20/4)+2] & 0x0000ffff) >> 0;
+ stv2_current_sprite.CMDXA = (stv_vdp1_vram[position * (0x20/4)+3] & 0xffff0000) >> 16;
+ stv2_current_sprite.CMDYA = (stv_vdp1_vram[position * (0x20/4)+3] & 0x0000ffff) >> 0;
+ stv2_current_sprite.CMDXB = (stv_vdp1_vram[position * (0x20/4)+4] & 0xffff0000) >> 16;
+ stv2_current_sprite.CMDYB = (stv_vdp1_vram[position * (0x20/4)+4] & 0x0000ffff) >> 0;
+ stv2_current_sprite.CMDXC = (stv_vdp1_vram[position * (0x20/4)+5] & 0xffff0000) >> 16;
+ stv2_current_sprite.CMDYC = (stv_vdp1_vram[position * (0x20/4)+5] & 0x0000ffff) >> 0;
+ stv2_current_sprite.CMDXD = (stv_vdp1_vram[position * (0x20/4)+6] & 0xffff0000) >> 16;
+ stv2_current_sprite.CMDYD = (stv_vdp1_vram[position * (0x20/4)+6] & 0x0000ffff) >> 0;
+ stv2_current_sprite.CMDGRDA = (stv_vdp1_vram[position * (0x20/4)+7] & 0xffff0000) >> 16;
+// stv2_current_sprite.UNUSED = (stv_vdp1_vram[position * (0x20/4)+7] & 0x0000ffff) >> 0;
+
+ /* proecess jump / skip commands, set position for next sprite */
+ switch (stv2_current_sprite.CMDCTRL & 0x7000)
+ {
+ case 0x0000: // jump next
+ if (vdp1_sprite_log) logerror ("Sprite List Process + Next (Normal)\n");
+ position++;
+ break;
+ case 0x1000: // jump assign
+ if (vdp1_sprite_log) logerror ("Sprite List Process + Jump Old %06x New %06x\n", position, (stv2_current_sprite.CMDLINK>>2));
+ position= (stv2_current_sprite.CMDLINK>>2);
+ break;
+ case 0x2000: // jump call
+ if (vdp1_nest == -1)
+ {
+ if (vdp1_sprite_log) logerror ("Sprite List Process + Call Old %06x New %06x\n",position, (stv2_current_sprite.CMDLINK>>2));
+ vdp1_nest = position+1;
+ position = (stv2_current_sprite.CMDLINK>>2);
+ }
+ else
+ {
+ if (vdp1_sprite_log) logerror ("Sprite List Nested Call, ignoring\n");
+ position++;
+ }
+ break;
+ case 0x3000:
+ if (vdp1_nest != -1)
+ {
+ if (vdp1_sprite_log) logerror ("Sprite List Process + Return\n");
+ position = vdp1_nest;
+ vdp1_nest = -1;
+ }
+ else
+ {
+ if (vdp1_sprite_log) logerror ("Attempted return from no subroutine, aborting\n");
+ position++;
+ goto end; // end of list
+ }
+ break;
+ case 0x4000:
+ draw_this_sprite = 0;
+ position++;
+ break;
+ case 0x5000:
+ if (vdp1_sprite_log) logerror ("Sprite List Skip + Jump Old %06x New %06x\n", position, (stv2_current_sprite.CMDLINK>>2));
+ draw_this_sprite = 0;
+ position= (stv2_current_sprite.CMDLINK>>2);
+
+ break;
+ case 0x6000:
+ draw_this_sprite = 0;
+ if (vdp1_nest == -1)
+ {
+ if (vdp1_sprite_log) logerror ("Sprite List Skip + Call To Subroutine Old %06x New %06x\n",position, (stv2_current_sprite.CMDLINK>>2));
+
+ vdp1_nest = position+1;
+ position = (stv2_current_sprite.CMDLINK>>2);
+ }
+ else
+ {
+ if (vdp1_sprite_log) logerror ("Sprite List Nested Call, ignoring\n");
+ position++;
+ }
+ break;
+ case 0x7000:
+ draw_this_sprite = 0;
+ if (vdp1_nest != -1)
+ {
+ if (vdp1_sprite_log) logerror ("Sprite List Skip + Return from Subroutine\n");
+
+ position = vdp1_nest;
+ vdp1_nest = -1;
+ }
+ else
+ {
+ if (vdp1_sprite_log) logerror ("Attempted return from no subroutine, aborting\n");
+ position++;
+ goto end; // end of list
+ }
+ break;
+ }
+
+ /* continue to draw this sprite only if the command wasn't to skip it */
+ if (draw_this_sprite ==1)
+ {
+ if ( stv2_current_sprite.CMDPMOD & 0x0400 )
+ {
+ cliprect = &stv_vdp1_user_cliprect;
+ }
+ else
+ {
+ cliprect = &stv_vdp1_system_cliprect;
+ }
+
+ stv_vdp1_set_drawpixel();
+
+ switch (stv2_current_sprite.CMDCTRL & 0x000f)
+ {
+ case 0x0000:
+ if (vdp1_sprite_log) logerror ("Sprite List Normal Sprite\n");
+ stv2_current_sprite.ispoly = 0;
+ stv_vpd1_draw_normal_sprite(cliprect, 0);
+ break;
+
+ case 0x0001:
+ if (vdp1_sprite_log) logerror ("Sprite List Scaled Sprite\n");
+ stv2_current_sprite.ispoly = 0;
+ stv_vpd1_draw_scaled_sprite(cliprect);
+ break;
+
+ case 0x0002:
+ if (vdp1_sprite_log) logerror ("Sprite List Distorted Sprite\n");
+ stv2_current_sprite.ispoly = 0;
+ stv_vpd1_draw_distorted_sprite(cliprect);
+ break;
+
+ case 0x0004:
+ if (vdp1_sprite_log) logerror ("Sprite List Polygon\n");
+ stv2_current_sprite.ispoly = 1;
+ stv_vpd1_draw_distorted_sprite(cliprect);
+ break;
+
+ case 0x0005:
+ if (vdp1_sprite_log) logerror ("Sprite List Polyline\n");
+ stv2_current_sprite.ispoly = 1;
+ stv_vdp1_draw_poly_line(cliprect);
+ break;
+
+ case 0x0006:
+ if (vdp1_sprite_log) logerror ("Sprite List Line\n");
+ stv2_current_sprite.ispoly = 1;
+ stv_vdp1_draw_line(cliprect);
+ break;
+
+ case 0x0008:
+ if (vdp1_sprite_log) logerror ("Sprite List Set Command for User Clipping (%d,%d),(%d,%d)\n", stv2_current_sprite.CMDXA, stv2_current_sprite.CMDYA, stv2_current_sprite.CMDXC, stv2_current_sprite.CMDYC);
+ stv_vdp1_user_cliprect.min_x = stv2_current_sprite.CMDXA;
+ stv_vdp1_user_cliprect.min_y = stv2_current_sprite.CMDYA;
+ stv_vdp1_user_cliprect.max_x = stv2_current_sprite.CMDXC;
+ stv_vdp1_user_cliprect.max_y = stv2_current_sprite.CMDYC;
+ break;
+
+ case 0x0009:
+ if (vdp1_sprite_log) logerror ("Sprite List Set Command for System Clipping (0,0),(%d,%d)\n", stv2_current_sprite.CMDXC, stv2_current_sprite.CMDYC);
+ stv_vdp1_system_cliprect.min_x = 0;
+ stv_vdp1_system_cliprect.min_y = 0;
+ stv_vdp1_system_cliprect.max_x = stv2_current_sprite.CMDXC;
+ stv_vdp1_system_cliprect.max_y = stv2_current_sprite.CMDYC;
+ break;
+
+ case 0x000a:
+ if (vdp1_sprite_log) logerror ("Sprite List Local Co-Ordinate Set\n");
+ stvvdp1_local_x = (INT16)stv2_current_sprite.CMDXA;
+ stvvdp1_local_y = (INT16)stv2_current_sprite.CMDYA;
+ break;
+
+ default:
+ if (vdp1_sprite_log) logerror ("Sprite List Illegal!\n");
+ break;
+
+
+ }
+
+
+ }
+
+ spritecount++;
+
+ }
+
+
+ end:
+ /*set CEF to 1*/
+ SET_CEF_FROM_0_TO_1;
+
+ /* not here! this is done every frame drawn even if the cpu isn't running eg in the debugger */
+// if(!(stv_scu[40] & 0x2000)) /*Sprite draw end irq*/
+// cpunum_set_input_line_and_vector(0, 2, HOLD_LINE , 0x4d);
+
+ if (vdp1_sprite_log) logerror ("End of list processing!\n");
+}
+
+void video_update_vdp1(running_machine *machine)
+{
+ int framebufer_changed = 0;
+
+// int enable;
+// if (input_code_pressed (KEYCODE_R)) vdp1_sprite_log = 1;
+// if (input_code_pressed (KEYCODE_T)) vdp1_sprite_log = 0;
+
+// if (input_code_pressed (KEYCODE_Y)) vdp1_sprite_log = 0;
+// {
+// FILE *fp;
+//
+// fp=fopen("vdp1_ram.dmp", "w+b");
+// if (fp)
+// {
+// fwrite(stv_vdp1, 0x00100000, 1, fp);
+// fclose(fp);
+// }
+// }
+ if (vdp1_sprite_log) logerror("video_update_vdp1 called\n");
+ if (vdp1_sprite_log) logerror( "FBCR = %0x, accessed = %d\n", STV_VDP1_FBCR, stv_vdp1_fbcr_accessed );
+
+ if ( stv_vdp1_clear_framebuffer_on_next_frame )
+ {
+ if ( ((STV_VDP1_FBCR & 0x3) == 3) &&
+ stv_vdp1_fbcr_accessed )
+ {
+ stv_clear_framebuffer(stv_vdp1_current_display_framebuffer);
+ stv_vdp1_clear_framebuffer_on_next_frame = 0;
+ }
+ }
+
+ switch( STV_VDP1_FBCR & 0x3 )
+ {
+ case 0: /* Automatic mode */
+ stv_vdp1_change_framebuffers();
+ stv_clear_framebuffer(stv_vdp1_current_draw_framebuffer);
+ framebufer_changed = 1;
+ break;
+ case 1: /* Setting prohibited */
+ break;
+ case 2: /* Manual mode - erase */
+ if ( stv_vdp1_fbcr_accessed )
+ {
+ stv_vdp1_clear_framebuffer_on_next_frame = 1;
+ }
+ break;
+ case 3: /* Manual mode - change */
+ if ( stv_vdp1_fbcr_accessed )
+ {
+ stv_vdp1_change_framebuffers();
+ if ( STV_VDP1_VBE )
+ {
+ stv_clear_framebuffer(stv_vdp1_current_draw_framebuffer);
+ }
+ framebufer_changed = 1;
+ }
+ break;
+ }
+ stv_vdp1_fbcr_accessed = 0;
+
+ if (vdp1_sprite_log) logerror( "PTM = %0x, TVM = %x\n", STV_VDP1_PTM, STV_VDP1_TVM );
+ switch(STV_VDP1_PTM & 3)
+ {
+ case 0:/*Idle Mode*/
+ break;
+ case 1:/*Draw by request*/
+ break;
+ case 2:/*Automatic Draw*/
+ if ( framebufer_changed )
+ stv_vdp1_process_list();
+ break;
+ case 3: /*<invalid>*/
+ logerror("Warning: Invalid PTM mode set for VDP1!\n");
+ break;
+ }
+ //popmessage("%04x %04x",STV_VDP1_EWRR_X3,STV_VDP1_EWRR_Y3);
+}
+
+static void stv_vdp1_state_save_postload(void)
+{
+ UINT8 *vdp1 = stv_vdp1_gfx_decode;
+ int offset;
+ UINT32 data;
+
+ stv_framebuffer_mode = -1;
+ stv_framebuffer_double_interlace = -1;
+
+ stv_set_framebuffer_config();
+
+ for (offset = 0; offset < 0x80000/4; offset++ )
+ {
+ data = stv_vdp1_vram[offset];
+ /* put in gfx region for easy decoding */
+ vdp1[offset*4+0] = (data & 0xff000000) >> 24;
+ vdp1[offset*4+1] = (data & 0x00ff0000) >> 16;
+ vdp1[offset*4+2] = (data & 0x0000ff00) >> 8;
+ vdp1[offset*4+3] = (data & 0x000000ff) >> 0;
+ }
+}
+
+int stv_vdp1_start ( void )
+{
+ stv_vdp1_regs = auto_malloc ( 0x040000 );
+ stv_vdp1_vram = auto_malloc ( 0x100000 );
+ stv_vdp1_gfx_decode = auto_malloc( 0x100000 );
+
+ stv_vdp1_shading_data = auto_malloc( sizeof(struct stv_vdp1_poly_scanline_data) );
+
+ memset(stv_vdp1_regs, 0, 0x040000);
+ memset(stv_vdp1_vram, 0, 0x100000);
+
+ stv_framebuffer[0] = auto_malloc( 1024 * 256 * sizeof(UINT16) * 2 ); /* *2 is for double interlace */
+ stv_framebuffer[1] = auto_malloc( 1024 * 256 * sizeof(UINT16) * 2 );
+
+ stv_framebuffer_display_lines = auto_malloc( 512 * sizeof(UINT16*) );
+ stv_framebuffer_draw_lines = auto_malloc( 512 * sizeof(UINT16*) );
+
+ stv_framebuffer_width = stv_framebuffer_height = 0;
+ stv_framebuffer_mode = -1;
+ stv_framebuffer_double_interlace = -1;
+ stv_vdp1_fbcr_accessed = 0;
+ stv_vdp1_current_display_framebuffer = 0;
+ stv_vdp1_current_draw_framebuffer = 1;
+ stv_clear_framebuffer(stv_vdp1_current_draw_framebuffer);
+ stv_vdp1_clear_framebuffer_on_next_frame = 0;
+
+ stv_vdp1_system_cliprect.min_x = stv_vdp1_system_cliprect.max_x = 0;
+ stv_vdp1_system_cliprect.min_y = stv_vdp1_system_cliprect.max_y = 0;
+ stv_vdp1_user_cliprect.min_x = stv_vdp1_user_cliprect.max_x = 0;
+ stv_vdp1_user_cliprect.min_y = stv_vdp1_user_cliprect.max_y = 0;
+
+ // save state
+ state_save_register_global_pointer(stv_vdp1_regs, 0x040000/4);
+ state_save_register_global_pointer(stv_vdp1_vram, 0x100000/4);
+ state_save_register_global(stv_vdp1_fbcr_accessed);
+ state_save_register_global(stv_vdp1_current_display_framebuffer);
+ state_save_register_global(stv_vdp1_current_draw_framebuffer);
+ state_save_register_global(stv_vdp1_clear_framebuffer_on_next_frame);
+ state_save_register_global(stvvdp1_local_x);
+ state_save_register_global(stvvdp1_local_y);
+ state_save_register_func_postload(stv_vdp1_state_save_postload);
+ return 0;
+}
diff --git a/src/mame/video/stvvdp2.c b/src/mame/video/stvvdp2.c
new file mode 100644
index 00000000000..2135ca2bd50
--- /dev/null
+++ b/src/mame/video/stvvdp2.c
@@ -0,0 +1,6291 @@
+/* Sega Saturn VDP2 */
+
+/*
+
+the dirty marking stuff and tile decoding will probably be removed in the end anyway as we'll need custom
+rendering code since mame's drawgfx / tilesytem don't offer everything st-v needs
+
+this system seems far too complex to use Mame's tilemap system
+
+4 'scroll' planes (scroll screens)
+
+the scroll planes have slightly different capabilities
+
+NBG0
+NBG1
+NBG2
+NBG3
+
+2 'rotate' planes
+
+RBG0
+RBG1
+
+-- other crap
+EXBG (external)
+
+------------------------------------------------------------------------------------------
+
+Notes of Interest:
+
+-the test mode / bios is drawn with layer NBG3
+
+-hanagumi Puts a 'RED' dragon logo in tileram (base 0x64000, 4bpp, 8x8 tiles) but
+its not displayed in gurus video.Update:It's actually not drawn because its
+priority value is 0.
+
+-scrolling is screen display wise,meaning that a scrolling value is masked with the
+screen resolution size values.
+
+-VDP1 priorities aren't taken into account yet,for now we fix the priority value to six...
+
+-AFAIK Suikoenbu & Winter Heat are the only ST-V games that use Mode 2 as the Color RAM
+format.
+
+-Bitmaps USES transparency pens,examples are:
+elandore's energy bars;
+mausuke's foreground(the one used on the playfield)(I guess that this is also
+alpha-blended);
+shanhigw's tile-based sprites;
+
+for now I've removed black pixels,it isn't 100% right so there MUST BE a better way
+for this...
+Update: some games uses transparent windows,others uses a transparency pen table like this:
+
+|------------------|---------------------|
+| Character count | Transparency code |
+|------------------|---------------------|
+| 16 colors |=0x0 (4 bits) |
+| 256 colors |=0x00 (8 bits) |
+| 2048 colors |=0x000 (11 bits) |
+| 32,768 colors |MSB=0 (bit 15) |
+| 16,770,000 colors|MSB=0 (bit 31) |
+|------------------|---------------------|
+
+In other words,the first three types uses the offset and not the color allocated...
+
+-Debug key list(only on a debug build):
+ \-T: NBG3 layer toggle
+ \-Y: NBG2 layer toggle
+ \-U: NBG1 layer toggle
+ \-I: NBG0 layer toggle
+ \-O: SPRITE toggle
+ \-K: RBG0 layer toggle
+ \-Z: Enables Window processing debug screen
+ \-C: Window 0 toggle
+ \-V: Window 1 toggle
+ \-W Decodes the graphics for F4 menu.
+ \-M Stores VDP1 ram contents from a file.
+ \-N Stores VDP1 ram contents into a file.
+*/
+
+#include "driver.h"
+#include "eminline.h"
+#include "profiler.h"
+
+UINT32* stv_vdp2_regs;
+UINT32* stv_vdp2_vram;
+/* this won't be used in the end .. */
+static UINT8* stv_vdp2_vram_dirty_8x8x4;
+static UINT8* stv_vdp2_vram_dirty_8x8x8;
+
+static UINT8* stv_vdp2_gfx_decode;
+extern UINT8* stv_vdp1_gfx_decode;
+
+static int stv_vdp2_render_rbg0;
+
+UINT32* stv_vdp2_cram;
+void video_update_vdp1(running_machine *machine);
+int stv_vdp1_start ( void );
+static void stv_vdp2_dynamic_res_change(void);
+static void refresh_palette_data(void);
+static int stv_vdp2_window_process(int x,int y);
+static int stv_vdp2_apply_window_on_layer(rectangle *cliprect);
+static void stv_vdp2_get_window0_coordinates(UINT16 *s_x, UINT16 *e_x, UINT16 *s_y, UINT16 *e_y);
+static void stv_vdp2_check_tilemap(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect);
+static mame_bitmap *stv_vdp2_roz_bitmap[2];
+
+enum
+{
+ STV_TRANSPARENCY_NONE = TRANSPARENCY_NONE,
+ STV_TRANSPARENCY_PEN = TRANSPARENCY_PEN,
+ STV_TRANSPARENCY_ALPHA = TRANSPARENCY_ALPHA,
+ STV_TRANSPARENCY_ADD_BLEND = TRANSPARENCY_MODES
+};
+
+#ifdef MAME_DEBUG
+#define LOG_VDP2 1
+#define LOG_ROZ 0
+#else
+#define LOG_VDP2 0
+#define LOG_ROZ 0
+#endif
+
+/*
+
+-------------------------------------------------|-----------------------------|------------------------------
+| Function | Normal Scroll Screen | Rotation Scroll Screen |
+| |-----------------------------|-----------------------------|------------------------------
+| | NBG0 | NBG1 | NBG2 | NBG3 | RBG0 | RBG1 |
+-------------------------------------------------|-----------------------------|------------------------------
+| Character Colour | 16 colours | 16 colours | 16 colours | 16 colours | 16 colours | 16 colours |
+| Count | 256 " " | 256 " " | 256 " " | 256 " " | 256 " " | 256 " " |
+| | 2048 " " | 2048 " " | | | 2048 " " | 2048 " " |
+| | 32768 " " | 32768 " " | | | 32768 " " | 32768 " " |
+| | 16770000 " " | | | | 16770000 " " | 16770000 " " |
+-------------------------------------------------|-----------------------------|------------------------------
+| Character Size | 1x1 Cells , 2x2 Cells |
+-------------------------------------------------|-----------------------------|------------------------------
+| Pattern Name | 1 word , 2 words |
+| Data Size | |
+-------------------------------------------------|-----------------------------|------------------------------
+| Plane Size | 1 H x 1 V 1 Pages ; 2 H x 1 V 1 Pages ; 2 H x 2 V Pages (I don't understand ... ) |
+-------------------------------------------------|-----------------------------|------------------------------
+| Plane Count | 4 | 16 |
+-------------------------------------------------|-----------------------------|------------------------------
+| Bitmap Possible | Yes | No | Yes | No |
+-------------------------------------------------|-----------------------------|------------------------------
+| Bitmap Size | 512 x 256 | N/A | 512x256 | N/A |
+| | 512 x 512 | | 512x512 | |
+| | 1024 x 256 | | | |
+| | 1024 x 512 | | | |
+-------------------------------------------------|-----------------------------|------------------------------
+| Scale | 0.25 x - 256 x | None | Any ? |
+-------------------------------------------------|-----------------------------|------------------------------
+| Rotation | No | Yes |
+-------------------------------------------------|-----------------------------|-----------------------------|
+| Linescroll | Yes | No |
+-------------------------------------------------|-----------------------------|------------------------------
+| Column Scroll | Yes | No |
+-------------------------------------------------|-----------------------------|------------------------------
+| Mosaic | Yes | Horizontal Only |
+-------------------------------------------------|-----------------------------|------------------------------
+
+*/
+
+/* 180000 - r/w - TVMD - TV Screen Mode
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | DISP | -- | -- | -- | -- | -- | -- | BDCLMD |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | LSMD1 | LSMD0 | VRESO1 | VRESO0 | -- | HRESO2 | HRESO1 | HRESO0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_TVMD ((stv_vdp2_regs[0x000/4] >> 16)&0x0000ffff)
+
+ #define STV_VDP2_DISP ((STV_VDP2_TVMD & 0x8000) >> 15)
+ #define STV_VDP2_BDCLMD ((STV_VDP2_TVMD & 0x0100) >> 8)
+ #define STV_VDP2_LSMD ((STV_VDP2_TVMD & 0x00c0) >> 6)
+ #define STV_VDP2_VRES ((STV_VDP2_TVMD & 0x0030) >> 4)
+ #define STV_VDP2_HRES ((STV_VDP2_TVMD & 0x0007) >> 0)
+
+/* 180002 - r/w - EXTEN - External Signal Enable Register
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | EXLTEN | EXSYEN |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | DASEL | EXBGEN |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 180004 - r/o - TVSTAT - Screen Status
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | EXLTFG | EXSYFG |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | VBLANK | HBLANK | ODD | EVEN |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 180006 - r/w - VRSIZE - VRAM Size
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | VRAMSZ | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | VER3 | VER2 | VER1 | VER0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_VRSIZE ((stv_vdp2_regs[0x004/4] >> 0)&0x0000ffff)
+
+ #define STV_VDP2_VRAMSZ ((STV_VDP2_VRSIZE & 0x8000) >> 15)
+
+/* 180008 - r/o - HCNT - H-Counter
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | HCT9 | HCT8 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | HCT7 | HCT6 | HCT5 | HCT4 | HCT3 | HCT2 | HCT1 | HCT0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_HCNT ((stv_vdp2_regs[0x008/4] >> 16)&0x000003ff)
+
+/* 18000A - r/o - VCNT - V-Counter
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | VCT9 | VCT8 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | VCT7 | VCT6 | VCT5 | VCT4 | VCT3 | VCT2 | VCT1 | VCT0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_VCNT ((stv_vdp2_regs[0x008/4] >> 0)&0x000003ff)
+
+/* 18000C - RESERVED
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 18000E - r/w - RAMCTL - RAM Control
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | CRKTE | -- | CRMD1 | CRMD0 | -- | -- | VRBMD | VRAMD |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | RDBSB11 | RDBSB10 | RDBSB01 | RDBSB00 | RDBSA11 | RDBSA10 | RDBSA01 | RDBSA00 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_RAMCTL ((stv_vdp2_regs[0x00c/4] >> 0)&0x0000ffff)
+
+ #define STV_VDP2_CRKTE ((STV_VDP2_RAMCTL & 0x8000) >> 15)
+ #define STV_VDP2_CRMD ((STV_VDP2_RAMCTL & 0x3000) >> 12)
+ #define STV_VDP2_RDBSB1 ((STV_VDP2_RAMCTL & 0x00c0) >> 6)
+ #define STV_VDP2_RDBSB0 ((STV_VDP2_RAMCTL & 0x0030) >> 4)
+ #define STV_VDP2_RDBSA1 ((STV_VDP2_RAMCTL & 0x000c) >> 2)
+ #define STV_VDP2_RDBSA0 ((STV_VDP2_RAMCTL & 0x0003) >> 0)
+
+
+/* 180010 - r/w - -CYCA0L - VRAM CYCLE PATTERN (BANK A0)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | VCP0A03 | VCP0A02 | VCP0A01 | VCP0A00 | VCP1A03 | VCP1A02 | VCP1A01 | VCP1A00 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | VCP2A03 | VCP2A02 | VCP2A01 | VCP2A00 | VCP3A03 | VCP3A02 | VCP3A01 | VCP3A00 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CYCA0L ((stv_vdp2_regs[0x010/4] >> 16)&0x0000ffff)
+
+/* 180012 - r/w - -CYCA0U - VRAM CYCLE PATTERN (BANK A0)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | VCP4A03 | VCP4A02 | VCP4A01 | VCP4A00 | VCP5A03 | VCP5A02 | VCP5A01 | VCP5A00 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | VCP6A03 | VCP6A02 | VCP6A01 | VCP6A00 | VCP7A03 | VCP7A02 | VCP7A01 | VCP7A00 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CYCA0U ((stv_vdp2_regs[0x10/4] >> 0)&0x0000ffff)
+
+/* 180014 - r/w - -CYCA1L - VRAM CYCLE PATTERN (BANK A1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | VCP0A13 | VCP0A12 | VCP0A11 | VCP0A10 | VCP1A13 | VCP1A12 | VCP1A11 | VCP1A10 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | VCP2A13 | VCP2A12 | VCP2A11 | VCP2A10 | VCP3A13 | VCP3A12 | VCP3A11 | VCP3A10 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CYCA1L ((stv_vdp2_regs[0x014/4] >> 16)&0x0000ffff)
+
+/* 180016 - r/w - -CYCA1U - VRAM CYCLE PATTERN (BANK A1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | VCP4A13 | VCP4A12 | VCP4A11 | VCP4A10 | VCP5A13 | VCP5A12 | VCP5A11 | VCP5A10 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | VCP6A13 | VCP6A12 | VCP6A11 | VCP6A10 | VCP7A13 | VCP7A12 | VCP7A11 | VCP7A10 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CYCA1U ((stv_vdp2_regs[0x14/4] >> 0)&0x0000ffff)
+
+/* 180018 - r/w - -CYCB0L - VRAM CYCLE PATTERN (BANK B0)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | VCP0B03 | VCP0B02 | VCP0B01 | VCP0B00 | VCP1B03 | VCP1B02 | VCP1B01 | VCP1B00 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | VCP2B03 | VCP2B02 | VCP2B01 | VCP2B00 | VCP3B03 | VCP3B02 | VCP3B01 | VCP3B00 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CYCA2L ((stv_vdp2_regs[0x018/4] >> 16)&0x0000ffff)
+
+/* 18001A - r/w - -CYCB0U - VRAM CYCLE PATTERN (BANK B0)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | VCP4B03 | VCP4B02 | VCP4B01 | VCP4B00 | VCP5B03 | VCP5B02 | VCP5B01 | VCP5B00 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | VCP6B03 | VCP6B02 | VCP6B01 | VCP6B00 | VCP7B03 | VCP7B02 | VCP7B01 | VCP7B00 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CYCA2U ((stv_vdp2_regs[0x18/4] >> 0)&0x0000ffff)
+
+/* 18001C - r/w - -CYCB1L - VRAM CYCLE PATTERN (BANK B1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | VCP0B13 | VCP0B12 | VCP0B11 | VCP0B10 | VCP1B13 | VCP1B12 | VCP1B11 | VCP1B10 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | VCP2B13 | VCP2B12 | VCP2B11 | VCP2B10 | VCP3B13 | VCP3B12 | VCP3B11 | VCP3B10 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CYCA3L ((stv_vdp2_regs[0x01c/4] >> 16)&0x0000ffff)
+
+/* 18001E - r/w - -CYCB1U - VRAM CYCLE PATTERN (BANK B1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | VCP4B13 | VCP4B12 | VCP4B11 | VCP4B10 | VCP5B13 | VCP5B12 | VCP5B11 | VCP5B10 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | VCP6B13 | VCP6B12 | VCP6B11 | VCP6B10 | VCP7B13 | VCP7B12 | VCP7B11 | VCP7B10 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CYCA3U ((stv_vdp2_regs[0x1c/4] >> 0)&0x0000ffff)
+
+/* 180020 - r/w - BGON - SCREEN DISPLAY ENABLE
+
+ this register allows each tilemap to be enabled or disabled and also which layers are solid
+
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | R0TPON | N3TPON | N2TPON | N1TPON | N0TPON |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | R1ON | R0ON | N3ON | N2ON | N1ON | N0ON |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_BGON ((stv_vdp2_regs[0x020/4] >> 16)&0x0000ffff)
+
+ // NxOn - Layer Enable Register
+ #define STV_VDP2_xxON ((STV_VDP2_BGON & 0x001f) >> 0) /* to see if anything is enabled */
+
+ #define STV_VDP2_N0ON ((STV_VDP2_BGON & 0x0001) >> 0) /* N0On = NBG0 Enable */
+ #define STV_VDP2_N1ON ((STV_VDP2_BGON & 0x0002) >> 1) /* N1On = NBG1 Enable */
+ #define STV_VDP2_N2ON ((STV_VDP2_BGON & 0x0004) >> 2) /* N2On = NBG2 Enable */
+ #define STV_VDP2_N3ON ((STV_VDP2_BGON & 0x0008) >> 3) /* N3On = NBG3 Enable */
+ #define STV_VDP2_R0ON ((STV_VDP2_BGON & 0x0010) >> 4) /* R0On = RBG0 Enable */
+ #define STV_VDP2_R1ON ((STV_VDP2_BGON & 0x0020) >> 5) /* R1On = RBG1 Enable */
+
+ // NxTPON - Transparency Pen Enable Registers
+ #define STV_VDP2_N0TPON ((STV_VDP2_BGON & 0x0100) >> 8) /* N0TPON = NBG0 Draw Transparent Pen (as solid) /or/ RBG1 Draw Transparent Pen */
+ #define STV_VDP2_N1TPON ((STV_VDP2_BGON & 0x0200) >> 9) /* N1TPON = NBG1 Draw Transparent Pen (as solid) /or/ EXBG Draw Transparent Pen */
+ #define STV_VDP2_N2TPON ((STV_VDP2_BGON & 0x0400) >> 10)/* N2TPON = NBG2 Draw Transparent Pen (as solid) */
+ #define STV_VDP2_N3TPON ((STV_VDP2_BGON & 0x0800) >> 11)/* N3TPON = NBG3 Draw Transparent Pen (as solid) */
+ #define STV_VDP2_R0TPON ((STV_VDP2_BGON & 0x1000) >> 12)/* R0TPON = RBG0 Draw Transparent Pen (as solid) */
+
+/*
+180022 - MZCTL - Mosaic Control
+bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MZCTL ((stv_vdp2_regs[0x020/4] >> 0)&0x0000ffff)
+
+ #define STV_VDP2_R0MZE ((STV_VDP2_MZCTL & 0x0010) >> 4)
+ #define STV_VDP2_N3MZE ((STV_VDP2_MZCTL & 0x0008) >> 3)
+ #define STV_VDP2_N2MZE ((STV_VDP2_MZCTL & 0x0004) >> 2)
+ #define STV_VDP2_N1MZE ((STV_VDP2_MZCTL & 0x0002) >> 1)
+ #define STV_VDP2_N0MZE ((STV_VDP2_MZCTL & 0x0001) >> 0)
+
+/*180024 - Special Function Code Select
+
+180026 - Special Function Code
+
+180028 - CHCTLA - Character Control (NBG0, NBG1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | N1CHCN1 | N1CHCN0 | N1BMSZ1 | N1BMSZ0 | N1BMEN | N1CHSZ |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | N0CHCN2 | N0CHCN1 | N0CHCN0 | N0BMSZ1 | N0BMSZ0 | N0BMEN | N0CHSZ |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CHCTLA ((stv_vdp2_regs[0x028/4] >> 16)&0x0000ffff)
+
+/* -------------------------- NBG0 Character Control Registers -------------------------- */
+
+/* N0CHCNx NBG0 (or RGB1) Colour Depth
+ 000 - 16 Colours
+ 001 - 256 Colours
+ 010 - 2048 Colours
+ 011 - 32768 Colours (RGB5)
+ 100 - 16770000 Colours (RGB8)
+ 101 - invalid
+ 110 - invalid
+ 111 - invalid */
+ #define STV_VDP2_N0CHCN ((STV_VDP2_CHCTLA & 0x0070) >> 4)
+
+/* N0BMSZx - NBG0 Bitmap Size *guessed*
+ 00 - 512 x 256
+ 01 - 512 x 512
+ 10 - 1024 x 256
+ 11 - 1024 x 512 */
+ #define STV_VDP2_N0BMSZ ((STV_VDP2_CHCTLA & 0x000c) >> 2)
+
+/* N0BMEN - NBG0 Bitmap Enable
+ 0 - use cell mode
+ 1 - use bitmap mode */
+ #define STV_VDP2_N0BMEN ((STV_VDP2_CHCTLA & 0x0002) >> 1)
+
+/* N0CHSZ - NBG0 Character (Tile) Size
+ 0 - 1 cell x 1 cell (8x8)
+ 1 - 2 cells x 2 cells (16x16) */
+ #define STV_VDP2_N0CHSZ ((STV_VDP2_CHCTLA & 0x0001) >> 0)
+
+/* -------------------------- NBG1 Character Control Registers -------------------------- */
+
+/* N1CHCNx - NBG1 (or EXB1) Colour Depth
+ 00 - 16 Colours
+ 01 - 256 Colours
+ 10 - 2048 Colours
+ 11 - 32768 Colours (RGB5) */
+ #define STV_VDP2_N1CHCN ((STV_VDP2_CHCTLA & 0x3000) >> 12)
+
+/* N1BMSZx - NBG1 Bitmap Size *guessed*
+ 00 - 512 x 256
+ 01 - 512 x 512
+ 10 - 1024 x 256
+ 11 - 1024 x 512 */
+ #define STV_VDP2_N1BMSZ ((STV_VDP2_CHCTLA & 0x0c00) >> 10)
+
+/* N1BMEN - NBG1 Bitmap Enable
+ 0 - use cell mode
+ 1 - use bitmap mode */
+ #define STV_VDP2_N1BMEN ((STV_VDP2_CHCTLA & 0x0200) >> 9)
+
+/* N1CHSZ - NBG1 Character (Tile) Size
+ 0 - 1 cell x 1 cell (8x8)
+ 1 - 2 cells x 2 cells (16x16) */
+ #define STV_VDP2_N1CHSZ ((STV_VDP2_CHCTLA & 0x0100) >> 8)
+
+/*
+18002A - CHCTLB - Character Control (NBG2, NBG1, RBG0)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | R0CHCN2 | R0CHCN1 | R0CHCN0 | -- | R0BMSZ | R0BMEN | R0CHSZ |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | N3CHCN | N3CHSZ | -- | -- | N2CHCN | N2CHSZ |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CHCTLB ((stv_vdp2_regs[0x028/4] >> 0)&0x0000ffff)
+
+/* -------------------------- RBG0 Character Control Registers -------------------------- */
+
+
+/* R0CHCNx RBG0 Colour Depth
+ 000 - 16 Colours
+ 001 - 256 Colours
+ 010 - 2048 Colours
+ 011 - 32768 Colours (RGB5)
+ 100 - 16770000 Colours (RGB8)
+ 101 - invalid
+ 110 - invalid
+ 111 - invalid */
+ #define STV_VDP2_R0CHCN ((STV_VDP2_CHCTLB & 0x7000) >> 12)
+
+/* R0BMSZx - RBG0 Bitmap Size *guessed*
+ 00 - 512 x 256
+ 01 - 512 x 512 */
+ #define STV_VDP2_R0BMSZ ((STV_VDP2_CHCTLB & 0x0400) >> 10)
+
+/* R0BMEN - RBG0 Bitmap Enable
+ 0 - use cell mode
+ 1 - use bitmap mode */
+ #define STV_VDP2_R0BMEN ((STV_VDP2_CHCTLB & 0x0200) >> 9)
+
+/* R0CHSZ - NBG0 Character (Tile) Size
+ 0 - 1 cell x 1 cell (8x8)
+ 1 - 2 cells x 2 cells (16x16) */
+ #define STV_VDP2_R0CHSZ ((STV_VDP2_CHCTLB & 0x0100) >> 8)
+
+ #define STV_VDP2_N3CHCN ((STV_VDP2_CHCTLB & 0x0020) >> 5)
+ #define STV_VDP2_N3CHSZ ((STV_VDP2_CHCTLB & 0x0010) >> 4)
+ #define STV_VDP2_N2CHCN ((STV_VDP2_CHCTLB & 0x0002) >> 1)
+ #define STV_VDP2_N2CHSZ ((STV_VDP2_CHCTLB & 0x0001) >> 0)
+
+
+/*
+18002C - BMPNA - Bitmap Palette Number (NBG0, NBG1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_BMPNA ((stv_vdp2_regs[0x02c/4] >> 16)&0x0000ffff)
+
+ #define STV_VDP2_N1BMP ((STV_VDP2_BMPNA & 0x0700) >> 8)
+ #define STV_VDP2_N0BMP ((STV_VDP2_BMPNA & 0x0007) >> 0)
+
+/* 18002E - Bitmap Palette Number (RBG0)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_BMPNB ((stv_vdp2_regs[0x02c/4] >> 16)&0x0000ffff)
+
+ #define STV_VDP2_R0BMP ((STV_VDP2_BMPNB & 0x0007) >> 0)
+
+/* 180030 - PNCN0 - Pattern Name Control (NBG0)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | N0PNB | N0CNSM | -- | -- | -- | -- | N0SPR | N0SCC |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | N0SPLT6 | N0SPLT5 | N0SPLT4 | N0SPCN4 | N0SPCN3 | N0SPCN2 | N0SPCN1 | N0SPCN0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_PNCN0 ((stv_vdp2_regs[0x030/4] >> 16)&0x0000ffff)
+
+/* Pattern Data Size
+ 0 = 2 bytes
+ 1 = 1 byte */
+ #define STV_VDP2_N0PNB ((STV_VDP2_PNCN0 & 0x8000) >> 15)
+
+/* Character Number Supplement (in 1 byte mode)
+ 0 = Character Number = 10bits + 2bits for flip
+ 1 = Character Number = 12 bits, no flip */
+ #define STV_VDP2_N0CNSM ((STV_VDP2_PNCN0 & 0x4000) >> 14)
+
+/* NBG0 Special Priority Register (in 1 byte mode) */
+ #define STV_VDP2_N0SPR ((STV_VDP2_PNCN0 & 0x0200) >> 9)
+
+/* NBG0 Special Colour Control Register (in 1 byte mode) */
+ #define STV_VDP2_N0SCC ((STV_VDP2_PNCN0 & 0x0100) >> 8)
+
+/* Supplementary Palette Bits (in 1 byte mode) */
+ #define STV_VDP2_N0SPLT ((STV_VDP2_PNCN0 & 0x00e0) >> 5)
+
+/* Supplementary Character Bits (in 1 byte mode) */
+ #define STV_VDP2_N0SPCN ((STV_VDP2_PNCN0 & 0x001f) >> 0)
+
+/* 180032 - Pattern Name Control (NBG1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_PNCN1 ((stv_vdp2_regs[0x030/4] >> 0)&0x0000ffff)
+
+/* Pattern Data Size
+ 0 = 2 bytes
+ 1 = 1 byte */
+ #define STV_VDP2_N1PNB ((STV_VDP2_PNCN1 & 0x8000) >> 15)
+
+/* Character Number Supplement (in 1 byte mode)
+ 0 = Character Number = 10bits + 2bits for flip
+ 1 = Character Number = 12 bits, no flip */
+ #define STV_VDP2_N1CNSM ((STV_VDP2_PNCN1 & 0x4000) >> 14)
+
+/* NBG0 Special Priority Register (in 1 byte mode) */
+ #define STV_VDP2_N1SPR ((STV_VDP2_PNCN1 & 0x0200) >> 9)
+
+/* NBG0 Special Colour Control Register (in 1 byte mode) */
+ #define STV_VDP2_N1SCC ((STV_VDP2_PNCN1 & 0x0100) >> 8)
+
+/* Supplementary Palette Bits (in 1 byte mode) */
+ #define STV_VDP2_N1SPLT ((STV_VDP2_PNCN1 & 0x00e0) >> 5)
+
+/* Supplementary Character Bits (in 1 byte mode) */
+ #define STV_VDP2_N1SPCN ((STV_VDP2_PNCN1 & 0x001f) >> 0)
+
+
+/* 180034 - Pattern Name Control (NBG2)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_PNCN2 ((stv_vdp2_regs[0x034/4] >> 16)&0x0000ffff)
+
+/* Pattern Data Size
+ 0 = 2 bytes
+ 1 = 1 byte */
+ #define STV_VDP2_N2PNB ((STV_VDP2_PNCN2 & 0x8000) >> 15)
+
+/* Character Number Supplement (in 1 byte mode)
+ 0 = Character Number = 10bits + 2bits for flip
+ 1 = Character Number = 12 bits, no flip */
+ #define STV_VDP2_N2CNSM ((STV_VDP2_PNCN2 & 0x4000) >> 14)
+
+/* NBG0 Special Priority Register (in 1 byte mode) */
+ #define STV_VDP2_N2SPR ((STV_VDP2_PNCN2 & 0x0200) >> 9)
+
+/* NBG0 Special Colour Control Register (in 1 byte mode) */
+ #define STV_VDP2_N2SCC ((STV_VDP2_PNCN2 & 0x0100) >> 8)
+
+/* Supplementary Palette Bits (in 1 byte mode) */
+ #define STV_VDP2_N2SPLT ((STV_VDP2_PNCN2 & 0x00e0) >> 5)
+
+/* Supplementary Character Bits (in 1 byte mode) */
+ #define STV_VDP2_N2SPCN ((STV_VDP2_PNCN2 & 0x001f) >> 0)
+
+
+/* 180036 - Pattern Name Control (NBG3)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | N3PNB | N3CNSM | -- | -- | -- | -- | N3SPR | N3SCC |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | N3SPLT6 | N3SPLT5 | N3SPLT4 | N3SPCN4 | N3SPCN3 | N3SPCN2 | N3SPCN1 | N3SPCN0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_PNCN3 ((stv_vdp2_regs[0x034/4] >> 0)&0x0000ffff)
+
+/* Pattern Data Size
+ 0 = 2 bytes
+ 1 = 1 byte */
+ #define STV_VDP2_N3PNB ((STV_VDP2_PNCN3 & 0x8000) >> 15)
+
+/* Character Number Supplement (in 1 byte mode)
+ 0 = Character Number = 10bits + 2bits for flip
+ 1 = Character Number = 12 bits, no flip */
+ #define STV_VDP2_N3CNSM ((STV_VDP2_PNCN3 & 0x4000) >> 14)
+
+/* NBG0 Special Priority Register (in 1 byte mode) */
+ #define STV_VDP2_N3SPR ((STV_VDP2_PNCN3 & 0x0200) >> 9)
+
+/* NBG0 Special Colour Control Register (in 1 byte mode) */
+ #define STV_VDP2_N3SCC ((STV_VDP2_PNCN3 & 0x0100) >> 8)
+
+/* Supplementary Palette Bits (in 1 byte mode) */
+ #define STV_VDP2_N3SPLT ((STV_VDP2_PNCN3 & 0x00e0) >> 5)
+
+/* Supplementary Character Bits (in 1 byte mode) */
+ #define STV_VDP2_N3SPCN ((STV_VDP2_PNCN3 & 0x001f) >> 0)
+
+
+/* 180038 - Pattern Name Control (RBG0)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_PNCR ((stv_vdp2_regs[0x038/4] >> 16)&0x0000ffff)
+
+/* Pattern Data Size
+ 0 = 2 bytes
+ 1 = 1 byte */
+ #define STV_VDP2_R0PNB ((STV_VDP2_PNCR & 0x8000) >> 15)
+
+/* Character Number Supplement (in 1 byte mode)
+ 0 = Character Number = 10bits + 2bits for flip
+ 1 = Character Number = 12 bits, no flip */
+ #define STV_VDP2_R0CNSM ((STV_VDP2_PNCR & 0x4000) >> 14)
+
+/* NBG0 Special Priority Register (in 1 byte mode) */
+ #define STV_VDP2_R0SPR ((STV_VDP2_PNCR & 0x0200) >> 9)
+
+/* NBG0 Special Colour Control Register (in 1 byte mode) */
+ #define STV_VDP2_R0SCC ((STV_VDP2_PNCR & 0x0100) >> 8)
+
+/* Supplementary Palette Bits (in 1 byte mode) */
+ #define STV_VDP2_R0SPLT ((STV_VDP2_PNCR & 0x00e0) >> 5)
+
+/* Supplementary Character Bits (in 1 byte mode) */
+ #define STV_VDP2_R0SPCN ((STV_VDP2_PNCR & 0x001f) >> 0)
+
+/* 18003A - PLSZ - Plane Size (incomplete)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | N3PLSZ1 | N3PLSZ0 | -- | -- | N1PLSZ1 | N1PLSZ0 | N0PLSZ1 | N0PLSZ0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_PLSZ ((stv_vdp2_regs[0x038/4] >> 0)&0x0000ffff)
+
+ /* NBG0 Plane Size
+ 00 1H Page x 1V Page
+ 01 2H Pages x 1V Page
+ 10 invalid
+ 11 2H Pages x 2V Pages */
+ #define STV_VDP2_RBOVR ((STV_VDP2_PLSZ & 0xc000) >> 14)
+ #define STV_VDP2_RAOVR ((STV_VDP2_PLSZ & 0x0c00) >> 10)
+ #define STV_VDP2_N0PLSZ ((STV_VDP2_PLSZ & 0x0003) >> 0)
+ #define STV_VDP2_N1PLSZ ((STV_VDP2_PLSZ & 0x000c) >> 2)
+ #define STV_VDP2_N2PLSZ ((STV_VDP2_PLSZ & 0x0030) >> 4)
+ #define STV_VDP2_N3PLSZ ((STV_VDP2_PLSZ & 0x00c0) >> 6)
+ #define STV_VDP2_RAPLSZ ((STV_VDP2_PLSZ & 0x0300) >> 8)
+ #define STV_VDP2_RBPLSZ ((STV_VDP2_PLSZ & 0x3000) >> 12)
+
+/* 18003C - MPOFN - Map Offset (NBG0, NBG1, NBG2, NBG3)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | N3MP8 | N3MP7 | N3MP6 | -- | N2MP8 | N2MP7 | N2MP6 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | N1MP8 | N1MP7 | N1MP6 | -- | N0MP8 | N0MP7 | N0MP6 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPOFN_ ((stv_vdp2_regs[0x03c/4] >> 16)&0x0000ffff)
+
+ /* Higher 3 bits of the map offset for each layer */
+ #define STV_VDP2_N0MP_ ((STV_VDP2_MPOFN_ & 0x0007) >> 0)
+ #define STV_VDP2_N1MP_ ((STV_VDP2_MPOFN_ & 0x0070) >> 4)
+ #define STV_VDP2_N2MP_ ((STV_VDP2_MPOFN_ & 0x0700) >> 8)
+ #define STV_VDP2_N3MP_ ((STV_VDP2_MPOFN_ & 0x7000) >> 12)
+
+
+
+
+/* 18003E - Map Offset (Rotation Parameter A,B)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPOFR_ ((stv_vdp2_regs[0x03c/4] >> 0)&0x0000ffff)
+
+ #define STV_VDP2_RAMP_ ((STV_VDP2_MPOFR_ & 0x0007) >> 0)
+ #define STV_VDP2_RBMP_ ((STV_VDP2_MPOFR_ & 0x0070) >> 4)
+
+/* 180040 - MPABN0 - Map (NBG0, Plane A,B)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | N0MPB5 | N0MPB4 | N0MPB3 | N0MPB2 | N0MPB1 | N0MPB0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | N0MPA5 | N0MPA4 | N0MPA3 | N0MPA2 | N0MPA1 | N0MPA0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPABN0 ((stv_vdp2_regs[0x040/4] >> 16)&0x0000ffff)
+
+ /* N0MPB5 = lower 6 bits of Map Address of Plane B of Tilemap NBG0 */
+ #define STV_VDP2_N0MPB ((STV_VDP2_MPABN0 & 0x3f00) >> 8)
+
+ /* N0MPA5 = lower 6 bits of Map Address of Plane A of Tilemap NBG0 */
+ #define STV_VDP2_N0MPA ((STV_VDP2_MPABN0 & 0x003f) >> 0)
+
+
+/* 180042 - MPCDN0 - (NBG0, Plane C,D)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | N0MPD5 | N0MPD4 | N0MPD3 | N0MPD2 | N0MPD1 | N0MPD0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | N0MPC5 | N0MPC4 | N0MPC3 | N0MPC2 | N0MPC1 | N0MPC0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPCDN0 ((stv_vdp2_regs[0x040/4] >> 0)&0x0000ffff)
+
+ /* N0MPB5 = lower 6 bits of Map Address of Plane D of Tilemap NBG0 */
+ #define STV_VDP2_N0MPD ((STV_VDP2_MPCDN0 & 0x3f00) >> 8)
+
+ /* N0MPA5 = lower 6 bits of Map Address of Plane C of Tilemap NBG0 */
+ #define STV_VDP2_N0MPC ((STV_VDP2_MPCDN0 & 0x003f) >> 0)
+
+
+/* 180044 - Map (NBG1, Plane A,B)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPABN1 ((stv_vdp2_regs[0x044/4] >> 16)&0x0000ffff)
+
+ /* N0MPB5 = lower 6 bits of Map Address of Plane B of Tilemap NBG1 */
+ #define STV_VDP2_N1MPB ((STV_VDP2_MPABN1 & 0x3f00) >> 8)
+
+ /* N0MPA5 = lower 6 bits of Map Address of Plane A of Tilemap NBG1 */
+ #define STV_VDP2_N1MPA ((STV_VDP2_MPABN1 & 0x003f) >> 0)
+
+/* 180046 - Map (NBG1, Plane C,D)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPCDN1 ((stv_vdp2_regs[0x044/4] >> 0)&0x0000ffff)
+
+ /* N0MPB5 = lower 6 bits of Map Address of Plane D of Tilemap NBG0 */
+ #define STV_VDP2_N1MPD ((STV_VDP2_MPCDN1 & 0x3f00) >> 8)
+
+ /* N0MPA5 = lower 6 bits of Map Address of Plane C of Tilemap NBG0 */
+ #define STV_VDP2_N1MPC ((STV_VDP2_MPCDN1 & 0x003f) >> 0)
+
+
+/* 180048 - Map (NBG2, Plane A,B)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPABN2 ((stv_vdp2_regs[0x048/4] >> 16)&0x0000ffff)
+
+ /* N0MPB5 = lower 6 bits of Map Address of Plane B of Tilemap NBG2 */
+ #define STV_VDP2_N2MPB ((STV_VDP2_MPABN2 & 0x3f00) >> 8)
+
+ /* N0MPA5 = lower 6 bits of Map Address of Plane A of Tilemap NBG2 */
+ #define STV_VDP2_N2MPA ((STV_VDP2_MPABN2 & 0x003f) >> 0)
+
+/* 18004a - Map (NBG2, Plane C,D)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPCDN2 ((stv_vdp2_regs[0x048/4] >> 0)&0x0000ffff)
+
+ /* N0MPB5 = lower 6 bits of Map Address of Plane D of Tilemap NBG2 */
+ #define STV_VDP2_N2MPD ((STV_VDP2_MPCDN2 & 0x3f00) >> 8)
+
+ /* N0MPA5 = lower 6 bits of Map Address of Plane C of Tilemap NBG2 */
+ #define STV_VDP2_N2MPC ((STV_VDP2_MPCDN2 & 0x003f) >> 0)
+
+/* 18004c - Map (NBG3, Plane A,B)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPABN3 ((stv_vdp2_regs[0x04c/4] >> 16)&0x0000ffff)
+
+ /* N0MPB5 = lower 6 bits of Map Address of Plane B of Tilemap NBG1 */
+ #define STV_VDP2_N3MPB ((STV_VDP2_MPABN3 & 0x3f00) >> 8)
+
+ /* N0MPA5 = lower 6 bits of Map Address of Plane A of Tilemap NBG1 */
+ #define STV_VDP2_N3MPA ((STV_VDP2_MPABN3 & 0x003f) >> 0)
+
+
+/* 18004e - Map (NBG3, Plane C,D)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPCDN3 ((stv_vdp2_regs[0x04c/4] >> 0)&0x0000ffff)
+
+ /* N0MPB5 = lower 6 bits of Map Address of Plane B of Tilemap NBG0 */
+ #define STV_VDP2_N3MPD ((STV_VDP2_MPCDN3 & 0x3f00) >> 8)
+
+ /* N0MPA5 = lower 6 bits of Map Address of Plane A of Tilemap NBG0 */
+ #define STV_VDP2_N3MPC ((STV_VDP2_MPCDN3 & 0x003f) >> 0)
+
+/* 180050 - Map (Rotation Parameter A, Plane A,B)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPABRA ((stv_vdp2_regs[0x050/4] >> 16)&0x0000ffff)
+
+ /* R0MPB5 = lower 6 bits of Map Address of Plane B of Tilemap RBG0 */
+ #define STV_VDP2_RAMPB ((STV_VDP2_MPABRA & 0x3f00) >> 8)
+
+ /* R0MPA5 = lower 6 bits of Map Address of Plane A of Tilemap RBG0 */
+ #define STV_VDP2_RAMPA ((STV_VDP2_MPABRA & 0x003f) >> 0)
+
+
+
+/* 180052 - Map (Rotation Parameter A, Plane C,D)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_MPCDRA ((stv_vdp2_regs[0x050/4] >> 0)&0x0000ffff)
+
+ /* R0MPB5 = lower 6 bits of Map Address of Plane D of Tilemap RBG0 */
+ #define STV_VDP2_RAMPD ((STV_VDP2_MPCDRA & 0x3f00) >> 8)
+
+ /* R0MPA5 = lower 6 bits of Map Address of Plane C of Tilemap RBG0 */
+ #define STV_VDP2_RAMPC ((STV_VDP2_MPCDRA & 0x003f) >> 0)
+
+/* 180054 - Map (Rotation Parameter A, Plane E,F)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_MPEFRA ((stv_vdp2_regs[0x054/4] >> 16)&0x0000ffff)
+
+ /* R0MPB5 = lower 6 bits of Map Address of Plane F of Tilemap RBG0 */
+ #define STV_VDP2_RAMPF ((STV_VDP2_MPEFRA & 0x3f00) >> 8)
+
+ /* R0MPA5 = lower 6 bits of Map Address of Plane E of Tilemap RBG0 */
+ #define STV_VDP2_RAMPE ((STV_VDP2_MPEFRA & 0x003f) >> 0)
+
+/* 180056 - Map (Rotation Parameter A, Plane G,H)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_MPGHRA ((stv_vdp2_regs[0x054/4] >> 0)&0x0000ffff)
+
+ /* R0MPB5 = lower 6 bits of Map Address of Plane H of Tilemap RBG0 */
+ #define STV_VDP2_RAMPH ((STV_VDP2_MPGHRA & 0x3f00) >> 8)
+
+ /* R0MPA5 = lower 6 bits of Map Address of Plane G of Tilemap RBG0 */
+ #define STV_VDP2_RAMPG ((STV_VDP2_MPGHRA & 0x003f) >> 0)
+
+/* 180058 - Map (Rotation Parameter A, Plane I,J)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_MPIJRA ((stv_vdp2_regs[0x058/4] >> 16)&0x0000ffff)
+
+ /* R0MPB5 = lower 6 bits of Map Address of Plane J of Tilemap RBG0 */
+ #define STV_VDP2_RAMPJ ((STV_VDP2_MPIJRA & 0x3f00) >> 8)
+
+ /* R0MPA5 = lower 6 bits of Map Address of Plane I of Tilemap RBG0 */
+ #define STV_VDP2_RAMPI ((STV_VDP2_MPIJRA & 0x003f) >> 0)
+
+/* 18005a - Map (Rotation Parameter A, Plane K,L)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_MPKLRA ((stv_vdp2_regs[0x058/4] >> 0)&0x0000ffff)
+
+ /* R0MPB5 = lower 6 bits of Map Address of Plane L of Tilemap RBG0 */
+ #define STV_VDP2_RAMPL ((STV_VDP2_MPKLRA & 0x3f00) >> 8)
+
+ /* R0MPA5 = lower 6 bits of Map Address of Plane K of Tilemap RBG0 */
+ #define STV_VDP2_RAMPK ((STV_VDP2_MPKLRA & 0x003f) >> 0)
+
+/* 18005c - Map (Rotation Parameter A, Plane M,N)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_MPMNRA ((stv_vdp2_regs[0x05c/4] >> 16)&0x0000ffff)
+
+ /* R0MPB5 = lower 6 bits of Map Address of Plane N of Tilemap RBG0 */
+ #define STV_VDP2_RAMPN ((STV_VDP2_MPMNRA & 0x3f00) >> 8)
+
+ /* R0MPA5 = lower 6 bits of Map Address of Plane M of Tilemap RBG0 */
+ #define STV_VDP2_RAMPM ((STV_VDP2_MPMNRA & 0x003f) >> 0)
+
+/* 18005e - Map (Rotation Parameter A, Plane O,P)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_MPOPRA ((stv_vdp2_regs[0x05c/4] >> 0)&0x0000ffff)
+
+ /* R0MPB5 = lower 6 bits of Map Address of Plane P of Tilemap RBG0 */
+ #define STV_VDP2_RAMPP ((STV_VDP2_MPOPRA & 0x3f00) >> 8)
+
+ /* R0MPA5 = lower 6 bits of Map Address of Plane O of Tilemap RBG0 */
+ #define STV_VDP2_RAMPO ((STV_VDP2_MPOPRA & 0x003f) >> 0)
+
+/* 180060 - Map (Rotation Parameter B, Plane A,B)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPABRB ((stv_vdp2_regs[0x060/4] >> 16)&0x0000ffff)
+
+ /* R0MPB5 = lower 6 bits of Map Address of Plane B of Tilemap RBG0 */
+ #define STV_VDP2_RBMPB ((STV_VDP2_MPABRB & 0x3f00) >> 8)
+
+ /* R0MPA5 = lower 6 bits of Map Address of Plane A of Tilemap RBG0 */
+ #define STV_VDP2_RBMPA ((STV_VDP2_MPABRB & 0x003f) >> 0)
+
+
+/* 180062 - Map (Rotation Parameter B, Plane C,D)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPCDRB ((stv_vdp2_regs[0x060/4] >> 0)&0x0000ffff)
+
+ /* R0MPD5 = lower 6 bits of Map Address of Plane D of Tilemap RBG0 */
+ #define STV_VDP2_RBMPD ((STV_VDP2_MPCDRB & 0x3f00) >> 8)
+
+ /* R0MPc5 = lower 6 bits of Map Address of Plane C of Tilemap RBG0 */
+ #define STV_VDP2_RBMPC ((STV_VDP2_MPCDRB & 0x003f) >> 0)
+
+/* 180064 - Map (Rotation Parameter B, Plane E,F)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPEFRB ((stv_vdp2_regs[0x064/4] >> 16)&0x0000ffff)
+
+ /* R0MPF5 = lower 6 bits of Map Address of Plane F of Tilemap RBG0 */
+ #define STV_VDP2_RBMPF ((STV_VDP2_MPEFRB & 0x3f00) >> 8)
+
+ /* R0MPE5 = lower 6 bits of Map Address of Plane E of Tilemap RBG0 */
+ #define STV_VDP2_RBMPE ((STV_VDP2_MPEFRB & 0x003f) >> 0)
+
+/* 180066 - Map (Rotation Parameter B, Plane G,H)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPGHRB ((stv_vdp2_regs[0x064/4] >> 0)&0x0000ffff)
+
+ /* R0MPH5 = lower 6 bits of Map Address of Plane H of Tilemap RBG0 */
+ #define STV_VDP2_RBMPH ((STV_VDP2_MPGHRB & 0x3f00) >> 8)
+
+ /* R0MPG5 = lower 6 bits of Map Address of Plane G of Tilemap RBG0 */
+ #define STV_VDP2_RBMPG ((STV_VDP2_MPGHRB & 0x003f) >> 0)
+
+/* 180068 - Map (Rotation Parameter B, Plane I,J)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPIJRB ((stv_vdp2_regs[0x068/4] >> 16)&0x0000ffff)
+
+ /* R0MPJ5 = lower 6 bits of Map Address of Plane J of Tilemap RBG0 */
+ #define STV_VDP2_RBMPJ ((STV_VDP2_MPIJRB & 0x3f00) >> 8)
+
+ /* R0MPI5 = lower 6 bits of Map Address of Plane E of Tilemap RBG0 */
+ #define STV_VDP2_RBMPI ((STV_VDP2_MPIJRB & 0x003f) >> 0)
+
+/* 18006a - Map (Rotation Parameter B, Plane K,L)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPKLRB ((stv_vdp2_regs[0x068/4] >> 0)&0x0000ffff)
+
+ /* R0MPL5 = lower 6 bits of Map Address of Plane L of Tilemap RBG0 */
+ #define STV_VDP2_RBMPL ((STV_VDP2_MPKLRB & 0x3f00) >> 8)
+
+ /* R0MPK5 = lower 6 bits of Map Address of Plane K of Tilemap RBG0 */
+ #define STV_VDP2_RBMPK ((STV_VDP2_MPKLRB & 0x003f) >> 0)
+
+/* 18006c - Map (Rotation Parameter B, Plane M,N)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPMNRB ((stv_vdp2_regs[0x06c/4] >> 16)&0x0000ffff)
+
+ /* R0MPN5 = lower 6 bits of Map Address of Plane N of Tilemap RBG0 */
+ #define STV_VDP2_RBMPN ((STV_VDP2_MPMNRB & 0x3f00) >> 8)
+
+ /* R0MPM5 = lower 6 bits of Map Address of Plane M of Tilemap RBG0 */
+ #define STV_VDP2_RBMPM ((STV_VDP2_MPMNRB & 0x003f) >> 0)
+
+/* 18006e - Map (Rotation Parameter B, Plane O,P)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_MPOPRB ((stv_vdp2_regs[0x06c/4] >> 0)&0x0000ffff)
+
+ /* R0MPP5 = lower 6 bits of Map Address of Plane P of Tilemap RBG0 */
+ #define STV_VDP2_RBMPP ((STV_VDP2_MPOPRB & 0x3f00) >> 8)
+
+ /* R0MPO5 = lower 6 bits of Map Address of Plane O of Tilemap RBG0 */
+ #define STV_VDP2_RBMPO ((STV_VDP2_MPOPRB & 0x003f) >> 0)
+
+/* 180070 - SCXIN0 - Screen Scroll (NBG0, Horizontal Integer Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_SCXIN0 ((stv_vdp2_regs[0x070/4] >> 16)&0x0000ffff)
+
+
+/* 180072 - Screen Scroll (NBG0, Horizontal Fractional Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 180074 - SCYIN0 - Screen Scroll (NBG0, Vertical Integer Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_SCYIN0 ((stv_vdp2_regs[0x074/4] >> 16)&0x0000ffff)
+
+
+/* 180076 - Screen Scroll (NBG0, Vertical Fractional Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 180078 - Coordinate Inc (NBG0, Horizontal Integer Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_ZMXIN0 ((stv_vdp2_regs[0x078/4] >> 16)&0x0000ffff)
+ #define STV_VDP2_ZMXN0 (stv_vdp2_regs[0x078/4] & 0x007ff00)
+
+ #define STV_VDP2_N0ZMXI ((STV_VDP2_ZMXIN0 & 0x0007) >> 0)
+
+/* 18007a - Coordinate Inc (NBG0, Horizontal Fractional Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_ZMXDN0 ((stv_vdp2_regs[0x078/4] >> 0)&0x0000ffff)
+
+ #define STV_VDP2_N0ZMXD ((STV_VDP2_ZMXDN0 >> 8)& 0xff)
+
+/* 18007c - Coordinate Inc (NBG0, Vertical Integer Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_ZMYIN0 ((stv_vdp2_regs[0x07c/4] >> 16)&0x0000ffff)
+ #define STV_VDP2_ZMYN0 (stv_vdp2_regs[0x07c/4] & 0x007ff00)
+
+ #define STV_VDP2_N0ZMYI ((STV_VDP2_ZMYIN0 & 0x0007) >> 0)
+
+/* 18007e - Coordinate Inc (NBG0, Vertical Fractional Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_ZMYDN0 ((stv_vdp2_regs[0x07c/4] >> 0)&0x0000ffff)
+
+ #define STV_VDP2_N0ZMYD ((STV_VDP2_ZMYDN0 >> 8)& 0xff)
+
+/* 180080 - SCXIN1 - Screen Scroll (NBG1, Horizontal Integer Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_SCXIN1 ((stv_vdp2_regs[0x080/4] >> 16)&0x0000ffff)
+
+/* 180082 - Screen Scroll (NBG1, Horizontal Fractional Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 180084 - SCYIN1 - Screen Scroll (NBG1, Vertical Integer Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_SCYIN1 ((stv_vdp2_regs[0x084/4] >> 16)&0x0000ffff)
+
+/* 180086 - Screen Scroll (NBG1, Vertical Fractional Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 180088 - Coordinate Inc (NBG1, Horizontal Integer Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_ZMXIN1 ((stv_vdp2_regs[0x088/4] >> 16)&0x0000ffff)
+ #define STV_VDP2_ZMXN1 (stv_vdp2_regs[0x088/4] & 0x007ff00)
+
+ #define STV_VDP2_N1ZMXI ((STV_VDP2_ZMXIN1 & 0x0007) >> 0)
+
+/* 18008a - Coordinate Inc (NBG1, Horizontal Fractional Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_ZMXDN1 ((stv_vdp2_regs[0x088/4] >> 0)&0x0000ffff)
+
+ #define STV_VDP2_N1ZMXD ((STV_VDP2_ZMXDN1 >> 8)& 0xff)
+
+/* 18008c - Coordinate Inc (NBG1, Vertical Integer Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_ZMYIN1 ((stv_vdp2_regs[0x08c/4] >> 16)&0x0000ffff)
+ #define STV_VDP2_ZMYN1 (stv_vdp2_regs[0x08c/4] & 0x007ff00)
+
+ #define STV_VDP2_N1ZMYI ((STV_VDP2_ZMYIN1 & 0x0007) >> 0)
+
+/* 18008e - Coordinate Inc (NBG1, Vertical Fractional Part)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_ZMYDN1 ((stv_vdp2_regs[0x08c/4] >> 0)&0x0000ffff)
+
+ #define STV_VDP2_N1ZMYD ((STV_VDP2_ZMYDN1 >> 8)& 0xff)
+
+/* 180090 - SCXN2 - Screen Scroll (NBG2, Horizontal)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_SCXN2 ((stv_vdp2_regs[0x090/4] >> 16)&0x0000ffff)
+
+/* 180092 - SCYN2 - Screen Scroll (NBG2, Vertical)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_SCYN2 ((stv_vdp2_regs[0x090/4] >> 0)&0x0000ffff)
+
+/* 180094 - SCXN3 - Screen Scroll (NBG3, Horizontal)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_SCXN3 ((stv_vdp2_regs[0x094/4] >> 16)&0x0000ffff)
+
+/* 180096 - SCYN3 - Screen Scroll (NBG3, Vertical)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_SCYN3 ((stv_vdp2_regs[0x094/4] >> 0)&0x0000ffff)
+
+/* 180098 - Reduction Enable
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 18009a - Line and Vertical Cell Scroll Control (NBG0, NBG1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_SCRCTL ((stv_vdp2_regs[0x098/4] >> 0)&0x0000ffff)
+
+ #define STV_VDP2_N1LSS ((STV_VDP2_SCRCTL & 0x3000) >> 12)
+ #define STV_VDP2_N1LZMX ((STV_VDP2_SCRCTL & 0x0800) >> 11)
+ #define STV_VDP2_N1LSCY ((STV_VDP2_SCRCTL & 0x0400) >> 10)
+ #define STV_VDP2_N1LSCX ((STV_VDP2_SCRCTL & 0x0200) >> 9)
+ #define STV_VDP2_N1VCSC ((STV_VDP2_SCRCTL & 0x0100) >> 8)
+ #define STV_VDP2_N0LSS ((STV_VDP2_SCRCTL & 0x0030) >> 4)
+ #define STV_VDP2_N0LZMX ((STV_VDP2_SCRCTL & 0x0008) >> 3)
+ #define STV_VDP2_N0LSCY ((STV_VDP2_SCRCTL & 0x0004) >> 2)
+ #define STV_VDP2_N0LSCX ((STV_VDP2_SCRCTL & 0x0002) >> 1)
+ #define STV_VDP2_N0VCSC ((STV_VDP2_SCRCTL & 0x0001) >> 0)
+
+/* 18009c - Vertical Cell Table Address (NBG0, NBG1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 18009e - Vertical Cell Table Address (NBG0, NBG1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 1800a0 - LSTA0U - Line Scroll Table Address (NBG0)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_LSTA0U ((stv_vdp2_regs[0x0a0/4] >> 16)&0x00000007)
+
+/* 1800a2 - LSTA0L - Line Scroll Table Address (NBG0)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_LSTA0L ((stv_vdp2_regs[0x0a0/4] >> 0)&0x0000fffe)
+
+/* 1800a4 - LSTA1U - Line Scroll Table Address (NBG1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_LSTA1U ((stv_vdp2_regs[0x0a4/4] >> 16)&0x00000007)
+
+/* 1800a6 - LSTA1L - Line Scroll Table Address (NBG1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_LSTA1L ((stv_vdp2_regs[0x0a4/4] >> 0)&0x0000fffe)
+
+/* 1800a8 - LCTAU - Line Colour Screen Table Address
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_LCTAU ((stv_vdp2_regs[0x0a8/4] >> 16) & 0xffff)
+ #define STV_VDP2_LCCLMD ((STV_VDP2_LCTAU & 0x8000) >> 15)
+
+/* 1800aa - LCTAL - Line Colour Screen Table Address
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_LCTAL ((stv_vdp2_regs[0x0a8/4] >> 0) & 0xffff)
+
+ #define STV_VDP2_LCTA (stv_vdp2_regs[0x0a8/4] & 0x0003ffff)
+
+/* 1800ac - Back Screen Table Address
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | BKCLMD | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | BKTA18 | BKTA17 | BKTA16 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 1800ae - Back Screen Table Address
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | BKTA15 | BKTA14 | BKTA13 | BKTA12 | BKTA11 | BKTA10 | BKTA9 | BKTA8 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | BKTA7 | BKTA7 | BKTA6 | BKTA5 | BKTA4 | BKTA3 | BKTA2 | BKTA0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_BKTA_UL (stv_vdp2_regs[0x0ac/4])
+
+ #define STV_VDP2_BKCLMD ((STV_VDP2_BKTA_UL & 0x80000000) >> 31)
+ #define STV_VDP2_BKTA ((STV_VDP2_BKTA_UL & 0x0003ffff) >> 0)
+ /*MSB of this register is used when the extra RAM cart is used,ignore it for now.*/
+ // #define STV_VDP2_BKTA ((STV_VDP2_BKTA_UL & 0x0007ffff) >> 0)
+
+/* 1800b0 - RPMD - Rotation Parameter Mode
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_RPMD ((stv_vdp2_regs[0x0b0/4] >> 16) & 0x00000003)
+
+/* 1800b2 - RPRCTL - Rotation Parameter Read Control
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | RBKASTRE | RBYSTRE | RBXSTRE |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | RAKASTRE | RAYSTRE | RBXSTRE |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_RPRCTL ((stv_vdp2_regs[0x0b0/4] >> 0)&0x0000ffff)
+ #define STV_VDP2_RBKASTRE ((STV_VDP2_RPRCTL & 0x0400) >> 10)
+ #define STV_VDP2_RBYSTRE ((STV_VDP2_RPRCTL & 0x0200) >> 9)
+ #define STV_VDP2_RBXSTRE ((STV_VDP2_RPRCTL & 0x0100) >> 8)
+ #define STV_VDP2_RAKASTRE ((STV_VDP2_RPRCTL & 0x0004) >> 2)
+ #define STV_VDP2_RAYSTRE ((STV_VDP2_RPRCTL & 0x0002) >> 1)
+ #define STV_VDP2_RAXSTRE ((STV_VDP2_RPRCTL & 0x0001) >> 0)
+
+/* 1800b4 - KTCTL - Coefficient Table Control
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | RBKLCE | RBKMD1 | RBKMD0 | RBKDBS | RBKTE |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | RAKLCE | RAKMD1 | RAKMD0 | RAKDBS | RAKTE |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_KTCTL ((stv_vdp2_regs[0x0b4/4] >> 16) & 0x0000ffff)
+ #define STV_VDP2_RBKLCE ((STV_VDP2_KTCTL & 0x1000) >> 12)
+ #define STV_VDP2_RBKMD ((STV_VDP2_KTCTL & 0x0c00) >> 10)
+ #define STV_VDP2_RBKDBS ((STV_VDP2_KTCTL & 0x0200) >> 9)
+ #define STV_VDP2_RBKTE ((STV_VDP2_KTCTL & 0x0100) >> 8)
+ #define STV_VDP2_RAKLCE ((STV_VDP2_KTCTL & 0x0010) >> 4)
+ #define STV_VDP2_RAKMD ((STV_VDP2_KTCTL & 0x000c) >> 2)
+ #define STV_VDP2_RAKDBS ((STV_VDP2_KTCTL & 0x0002) >> 1)
+ #define STV_VDP2_RAKTE ((STV_VDP2_KTCTL & 0x0001) >> 0)
+
+/* 1800b6 - KTAOF - Coefficient Table Address Offset (Rotation Parameter A,B)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | RBKTAOS2 | RBKTAOS1 | RBKTAOS0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | RAKTAOS2 | RAKTAOS1 | RAKTAOS0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_KTAOF ((stv_vdp2_regs[0x0b4/4] >> 0) & 0x0000ffff)
+ #define STV_VDP2_RBKTAOS ((STV_VDP2_KTAOF & 0x0700) >> 8)
+ #define STV_VDP2_RAKTAOS ((STV_VDP2_KTAOF & 0x0007) >> 0)
+
+/* 1800b8 - OVPNRA - Screen Over Pattern Name (Rotation Parameter A)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_OVPNRA ((stv_vdp2_regs[0x0b8/4] >> 16) & 0x0000ffff)
+
+/* 1800ba - Screen Over Pattern Name (Rotation Parameter B)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_OVPNRB ((stv_vdp2_regs[0x0b8/4] >> 0) & 0x0000ffff)
+
+/* 1800bc - RPTAU - Rotation Parameter Table Address (Rotation Parameter A,B)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | RPTA18 | RPTA17 | RPTA16 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_RPTAU ((stv_vdp2_regs[0x0bc/4] >> 16) & 0x00000007)
+
+/* 1800be - RPTAL - Rotation Parameter Table Address (Rotation Parameter A,B)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | RPTA15 | RPTA14 | RPTA13 | RPTA12 | RPTA11 | RPTA10 | RPTA9 | RPTA8 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | RPTA7 | RPTA6 | RPTA5 | RPTA4 | RPTA3 | RPTA2 | RPTA1 | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_RPTAL ((stv_vdp2_regs[0x0bc/4] >> 0) & 0x0000fffe)
+
+/* 1800c0 - Window Position (W0, Horizontal Start Point)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_WPSX0 ((stv_vdp2_regs[0x0c0/4] >> 16)&0x0000ffff)
+
+ #define STV_VDP2_W0SX ((STV_VDP2_WPSX0 & 0x03ff) >> 0)
+
+/* 1800c2 - Window Position (W0, Vertical Start Point)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_WPSY0 ((stv_vdp2_regs[0x0c0/4] >> 0)&0x0000ffff)
+
+ #define STV_VDP2_W0SY ((STV_VDP2_WPSY0 & 0x03ff) >> 0)
+
+/* 1800c4 - Window Position (W0, Horizontal End Point)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_WPEX0 ((stv_vdp2_regs[0x0c4/4] >> 16)&0x0000ffff)
+
+ #define STV_VDP2_W0EX ((STV_VDP2_WPEX0 & 0x03ff) >> 0)
+
+/* 1800c6 - Window Position (W0, Vertical End Point)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_WPEY0 ((stv_vdp2_regs[0x0c4/4] >> 0)&0x0000ffff)
+
+ #define STV_VDP2_W0EY ((STV_VDP2_WPEY0 & 0x03ff) >> 0)
+
+/* 1800c8 - Window Position (W1, Horizontal Start Point)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_WPSX1 ((stv_vdp2_regs[0x0c8/4] >> 16)&0x0000ffff)
+
+ #define STV_VDP2_W1SX ((STV_VDP2_WPSX1 & 0x03ff) >> 0)
+
+/* 1800ca - Window Position (W1, Vertical Start Point)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_WPSY1 ((stv_vdp2_regs[0x0c8/4] >> 0)&0x0000ffff)
+
+ #define STV_VDP2_W1SY ((STV_VDP2_WPSY1 & 0x03ff) >> 0)
+
+/* 1800cc - Window Position (W1, Horizontal End Point)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_WPEX1 ((stv_vdp2_regs[0x0cc/4] >> 16)&0x0000ffff)
+
+ #define STV_VDP2_W1EX ((STV_VDP2_WPEX1 & 0x03ff) >> 0)
+
+/* 1800ce - Window Position (W1, Vertical End Point)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_WPEY1 ((stv_vdp2_regs[0x0cc/4] >> 0)&0x0000ffff)
+
+ #define STV_VDP2_W1EY ((STV_VDP2_WPEY1 & 0x03ff) >> 0)
+
+/* 1800d0 - Window Control (NBG0, NBG1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_WCTLA ((stv_vdp2_regs[0x0d0/4] >> 16)&0x0000ffff)
+ #define STV_VDP2_N1LOG ((STV_VDP2_WCTLA & 0x8000) >> 15)
+ #define STV_VDP2_N1SWE ((STV_VDP2_WCTLA & 0x2000) >> 13)
+ #define STV_VDP2_N1SWA ((STV_VDP2_WCTLA & 0x1000) >> 12)
+ #define STV_VDP2_N1W1E ((STV_VDP2_WCTLA & 0x0800) >> 11)
+ #define STV_VDP2_N1W1A ((STV_VDP2_WCTLA & 0x0400) >> 10)
+ #define STV_VDP2_N1W0E ((STV_VDP2_WCTLA & 0x0200) >> 9)
+ #define STV_VDP2_N1W0A ((STV_VDP2_WCTLA & 0x0100) >> 8)
+ #define STV_VDP2_N0LOG ((STV_VDP2_WCTLA & 0x0080) >> 7)
+ #define STV_VDP2_N0SWE ((STV_VDP2_WCTLA & 0x0020) >> 5)
+ #define STV_VDP2_N0SWA ((STV_VDP2_WCTLA & 0x0010) >> 4)
+ #define STV_VDP2_N0W1E ((STV_VDP2_WCTLA & 0x0008) >> 3)
+ #define STV_VDP2_N0W1A ((STV_VDP2_WCTLA & 0x0004) >> 2)
+ #define STV_VDP2_N0W0E ((STV_VDP2_WCTLA & 0x0002) >> 1)
+ #define STV_VDP2_N0W0A ((STV_VDP2_WCTLA & 0x0001) >> 0)
+
+/* 1800d2 - Window Control (NBG2, NBG3)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_WCTLB ((stv_vdp2_regs[0x0d0/4] >> 0)&0x0000ffff)
+ #define STV_VDP2_N3LOG ((STV_VDP2_WCTLB & 0x8000) >> 15)
+ #define STV_VDP2_N3SWE ((STV_VDP2_WCTLB & 0x2000) >> 13)
+ #define STV_VDP2_N3SWA ((STV_VDP2_WCTLB & 0x1000) >> 12)
+ #define STV_VDP2_N3W1E ((STV_VDP2_WCTLB & 0x0800) >> 11)
+ #define STV_VDP2_N3W1A ((STV_VDP2_WCTLB & 0x0400) >> 10)
+ #define STV_VDP2_N3W0E ((STV_VDP2_WCTLB & 0x0200) >> 9)
+ #define STV_VDP2_N3W0A ((STV_VDP2_WCTLB & 0x0100) >> 8)
+ #define STV_VDP2_N2LOG ((STV_VDP2_WCTLB & 0x0080) >> 7)
+ #define STV_VDP2_N2SWE ((STV_VDP2_WCTLB & 0x0020) >> 5)
+ #define STV_VDP2_N2SWA ((STV_VDP2_WCTLB & 0x0010) >> 4)
+ #define STV_VDP2_N2W1E ((STV_VDP2_WCTLB & 0x0008) >> 3)
+ #define STV_VDP2_N2W1A ((STV_VDP2_WCTLB & 0x0004) >> 2)
+ #define STV_VDP2_N2W0E ((STV_VDP2_WCTLB & 0x0002) >> 1)
+ #define STV_VDP2_N2W0A ((STV_VDP2_WCTLB & 0x0001) >> 0)
+
+/* 1800d4 - Window Control (RBG0, Sprite)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_WCTLC ((stv_vdp2_regs[0x0d4/4] >> 16)&0x0000ffff)
+ #define STV_VDP2_SPLOG ((STV_VDP2_WCTLC & 0x8000) >> 15)
+ #define STV_VDP2_SPSWE ((STV_VDP2_WCTLC & 0x2000) >> 13)
+ #define STV_VDP2_SPSWA ((STV_VDP2_WCTLC & 0x1000) >> 12)
+ #define STV_VDP2_SPW1E ((STV_VDP2_WCTLC & 0x0800) >> 11)
+ #define STV_VDP2_SPW1A ((STV_VDP2_WCTLC & 0x0400) >> 10)
+ #define STV_VDP2_SPW0E ((STV_VDP2_WCTLC & 0x0200) >> 9)
+ #define STV_VDP2_SPW0A ((STV_VDP2_WCTLC & 0x0100) >> 8)
+ #define STV_VDP2_R0LOG ((STV_VDP2_WCTLC & 0x0080) >> 7)
+ #define STV_VDP2_R0SWE ((STV_VDP2_WCTLC & 0x0020) >> 5)
+ #define STV_VDP2_R0SWA ((STV_VDP2_WCTLC & 0x0010) >> 4)
+ #define STV_VDP2_R0W1E ((STV_VDP2_WCTLC & 0x0008) >> 3)
+ #define STV_VDP2_R0W1A ((STV_VDP2_WCTLC & 0x0004) >> 2)
+ #define STV_VDP2_R0W0E ((STV_VDP2_WCTLC & 0x0002) >> 1)
+ #define STV_VDP2_R0W0A ((STV_VDP2_WCTLC & 0x0001) >> 0)
+
+/* 1800d6 - Window Control (Parameter Window, Colour Calc. Window)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 1800d8 - Line Window Table Address (W0)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 1800da - Line Window Table Address (W0)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 1800dc - Line Window Table Address (W1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 1800de - Line Window Table Address (W1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 1800e0 - Sprite Control
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | SPCCCS1 | SPCCCS0 | -- | SPCCN2 | SPCCN1 | SPCCN0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | SPCLMD | SPWINEN | SPTYPE3 | SPTYPE2 | SPTYPE1 | SPTYPE0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_SPCTL ((stv_vdp2_regs[0xe0/4] >> 16)&0x0000ffff)
+ #define STV_VDP2_SPCCCS ((STV_VDP2_SPCTL & 0x3000) >> 12)
+ #define STV_VDP2_SPCCN ((STV_VDP2_SPCTL & 0x700) >> 8)
+ #define STV_VDP2_SPCLMD ((STV_VDP2_SPCTL & 0x20) >> 5)
+ #define STV_VDP2_SPWINEN ((STV_VDP2_SPCTL & 0x10) >> 4)
+ #define STV_VDP2_SPTYPE (STV_VDP2_SPCTL & 0xf)
+
+/* 1800e2 - Shadow Control
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_SDCTL ((stv_vdp2_regs[0x0e0/4] >> 0) & 0x0000ffff)
+
+/* 1800e4 - CRAOFA - Colour Ram Address Offset (NBG0 - NBG3)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | N0CAOS2 | N3CAOS1 | N3CAOS0 | -- | N2CAOS2 | N2CAOS1 | N2CAOS0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | N1CAOS2 | N1CAOS1 | N1CAOS0 | -- | N0CAOS2 | N0CAOS1 | N0CAOS0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CRAOFA ((stv_vdp2_regs[0x0e4/4] >> 16)&0x0000ffff)
+
+ /* NxCAOS = */
+ #define STV_VDP2_N0CAOS ((STV_VDP2_CRAOFA & 0x0007) >> 0)
+ #define STV_VDP2_N1CAOS ((STV_VDP2_CRAOFA & 0x0070) >> 4)
+ #define STV_VDP2_N2CAOS ((STV_VDP2_CRAOFA & 0x0700) >> 8)
+ #define STV_VDP2_N3CAOS ((STV_VDP2_CRAOFA & 0x7000) >> 12)
+
+
+/* 1800e6 - Colour Ram Address Offset (RBG0, SPRITE)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_CRAOFB ((stv_vdp2_regs[0x0e4/4] >> 0)&0x0000ffff)
+ #define STV_VDP2_R0CAOS ((STV_VDP2_CRAOFB & 0x0007) >> 0)
+ #define STV_VDP2_SPCAOS ((STV_VDP2_CRAOFB & 0x0070) >> 4)
+
+/* 1800e8 - LNCLEN - Line Colour Screen Enable
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | SPLCEN | R0LCEN | N3LCEN | N2LCEN | N1LCEN | N0LCEN |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_LNCLEN ((stv_vdp2_regs[0x0e8/4] >> 16)&0x0000ffff)
+ #define STV_VDP2_SPLCEN ((STV_VDP2_LNCLEN) & 0x0020) >> 5)
+ #define STV_VDP2_R0LCEN ((STV_VDP2_LNCLEN) & 0x0010) >> 4)
+ #define STV_VDP2_N3LCEN ((STV_VDP2_LNCLEN) & 0x0008) >> 3)
+ #define STV_VDP2_N2LCEN ((STV_VDP2_LNCLEN) & 0x0004) >> 2)
+ #define STV_VDP2_N1LCEN ((STV_VDP2_LNCLEN) & 0x0002) >> 1)
+ #define STV_VDP2_N0LCEN ((STV_VDP2_LNCLEN) & 0x0001) >> 0)
+
+/* 1800ea - Special Priority Mode
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 1800ec - Colour Calculation Control
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | BOKEN | BOKN2 | BOKN1 | BOKN0 | -- | EXCCEN | CCRTMD | CCMD |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | SPCCEN | LCCCEN | R0CCEN | N3CCEN | N2CCEN | N1CCEN | N0CCEN |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CCCR ((stv_vdp2_regs[0xec/4]>>16)&0x0000ffff)
+ #define STV_VDP2_CCMD ((STV_VDP2_CCCR & 0x100) >> 8)
+ #define STV_VDP2_SPCCEN ((STV_VDP2_CCCR & 0x40) >> 6)
+ #define STV_VDP2_LCCCEN ((STV_VDP2_CCCR & 0x20) >> 5)
+ #define STV_VDP2_R0CCEN ((STV_VDP2_CCCR & 0x10) >> 4)
+ #define STV_VDP2_N3CCEN ((STV_VDP2_CCCR & 0x8) >> 3)
+ #define STV_VDP2_N2CCEN ((STV_VDP2_CCCR & 0x4) >> 2)
+ #define STV_VDP2_N1CCEN ((STV_VDP2_CCCR & 0x2) >> 1)
+ #define STV_VDP2_N0CCEN ((STV_VDP2_CCCR & 0x1) >> 0)
+
+
+/* 1800ee - Special Colour Calculation Mode
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 1800f0 - Priority Number (Sprite 0,1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | S1PRIN2 | S1PRIN1 | S1PRIN0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | S0PRIN2 | S0PRIN1 | S0PRIN0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_PRISA ((stv_vdp2_regs[0xf0/4] >> 16) & 0x0000ffff)
+ #define STV_VDP2_S1PRIN ((STV_VDP2_PRISA & 0x0700) >> 8)
+ #define STV_VDP2_S0PRIN ((STV_VDP2_PRISA & 0x0007) >> 0)
+
+/* 1800f2 - Priority Number (Sprite 2,3)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | S3PRIN2 | S3PRIN1 | S3PRIN0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | S2PRIN2 | S2PRIN1 | S2PRIN0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_PRISB ((stv_vdp2_regs[0xf0/4] >> 0) & 0x0000ffff)
+ #define STV_VDP2_S3PRIN ((STV_VDP2_PRISB & 0x0700) >> 8)
+ #define STV_VDP2_S2PRIN ((STV_VDP2_PRISB & 0x0007) >> 0)
+
+/* 1800f4 - Priority Number (Sprite 4,5)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | S5PRIN2 | S5PRIN1 | S5PRIN0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | S4PRIN2 | S4PRIN1 | S4PRIN0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_PRISC ((stv_vdp2_regs[0xf4/4] >> 16) & 0x0000ffff)
+ #define STV_VDP2_S5PRIN ((STV_VDP2_PRISC & 0x0700) >> 8)
+ #define STV_VDP2_S4PRIN ((STV_VDP2_PRISC & 0x0007) >> 0)
+
+/* 1800f6 - Priority Number (Sprite 6,7)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | S7PRIN2 | S7PRIN1 | S7PRIN0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | S6PRIN2 | S6PRIN1 | S6PRIN0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_PRISD ((stv_vdp2_regs[0xf4/4] >> 0) & 0x0000ffff)
+ #define STV_VDP2_S7PRIN ((STV_VDP2_PRISD & 0x0700) >> 8)
+ #define STV_VDP2_S6PRIN ((STV_VDP2_PRISD & 0x0007) >> 0)
+
+
+/* 1800f8 - PRINA - Priority Number (NBG 0,1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_PRINA ((stv_vdp2_regs[0x0f8/4] >> 16)&0x0000ffff)
+
+ #define STV_VDP2_N1PRIN ((STV_VDP2_PRINA & 0x0700) >> 8)
+ #define STV_VDP2_N0PRIN ((STV_VDP2_PRINA & 0x0007) >> 0)
+
+/* 1800fa - PRINB - Priority Number (NBG 2,3)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_PRINB ((stv_vdp2_regs[0x0f8/4] >> 0)&0x0000ffff)
+
+ #define STV_VDP2_N3PRIN ((STV_VDP2_PRINB & 0x0700) >> 8)
+ #define STV_VDP2_N2PRIN ((STV_VDP2_PRINB & 0x0007) >> 0)
+
+/* 1800fc - Priority Number (RBG0)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_PRIR ((stv_vdp2_regs[0x0fc/4] >> 16)&0x0000ffff)
+
+ #define STV_VDP2_R0PRIN ((STV_VDP2_PRIR & 0x0007) >> 0)
+
+/* 1800fe - Reserved
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 180100 - Colour Calculation Ratio (Sprite 0,1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | S1CCRT4 | S1CCRT3 | S1CCRT2 | S1CCRT1 | S1CCRT0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | S0CCRT4 | S0CCRT3 | S0CCRT2 | S0CCRT1 | S0CCRT0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CCRSA ((stv_vdp2_regs[0x100/4] >> 16) & 0x0000ffff)
+ #define STV_VDP2_S1CCRT ((STV_VDP2_CCRSA & 0x1f00) >> 8)
+ #define STV_VDP2_S0CCRT ((STV_VDP2_CCRSA & 0x001f) >> 0)
+
+/* 180102 - Colour Calculation Ratio (Sprite 2,3)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | S3CCRT4 | S3CCRT3 | S3CCRT2 | S3CCRT1 | S3CCRT0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | S2CCRT4 | S2CCRT3 | S2CCRT2 | S2CCRT1 | S2CCRT0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CCRSB ((stv_vdp2_regs[0x100/4] >> 0) & 0x0000ffff)
+ #define STV_VDP2_S3CCRT ((STV_VDP2_CCRSB & 0x1f00) >> 8)
+ #define STV_VDP2_S2CCRT ((STV_VDP2_CCRSB & 0x001f) >> 0)
+
+/* 180104 - Colour Calculation Ratio (Sprite 4,5)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | S5CCRT4 | S5CCRT3 | S5CCRT2 | S5CCRT1 | S5CCRT0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | S4CCRT4 | S4CCRT3 | S4CCRT2 | S4CCRT1 | S4CCRT0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CCRSC ((stv_vdp2_regs[0x104/4 ]>> 16) & 0x0000ffff)
+ #define STV_VDP2_S5CCRT ((STV_VDP2_CCRSC & 0x1f00) >> 8)
+ #define STV_VDP2_S4CCRT ((STV_VDP2_CCRSC & 0x001f) >> 0)
+
+/* 180106 - Colour Calculation Ratio (Sprite 6,7)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | S7CCRT4 | S7CCRT3 | S7CCRT2 | S7CCRT1 | S7CCRT0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | S6CCRT4 | S6CCRT3 | S6CCRT2 | S6CCRT1 | S6CCRT0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CCRSD ((stv_vdp2_regs[0x104/4 ]>> 0) & 0x0000ffff)
+ #define STV_VDP2_S7CCRT ((STV_VDP2_CCRSD & 0x1f00) >> 8)
+ #define STV_VDP2_S6CCRT ((STV_VDP2_CCRSD & 0x001f) >> 0)
+
+/* 180108 - Colour Calculation Ratio (NBG 0,1)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | N1CCRT4 | N1CCRT3 | N1CCRT2 | N1CCRT1 | N1CCRT0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | N0CCRT4 | N0CCRT3 | N0CCRT2 | N0CCRT1 | N0CCRT0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CCRNA ((stv_vdp2_regs[0x108/4] >> 16)&0x0000ffff)
+ #define STV_VDP2_N1CCRT ((STV_VDP2_CCRNA & 0x1f00) >> 8)
+ #define STV_VDP2_N0CCRT (STV_VDP2_CCRNA & 0x1f)
+
+/* 18010a - Colour Calculation Ratio (NBG 2,3)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | N3CCRT4 | N3CCRT3 | N3CCRT2 | N3CCRT1 | N3CCRT0 |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | N2CCRT4 | N2CCRT3 | N2CCRT2 | N2CCRT1 | N2CCRT0 |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CCRNB ((stv_vdp2_regs[0x108/4] >> 0)&0x0000ffff)
+ #define STV_VDP2_N3CCRT ((STV_VDP2_CCRNB & 0x1f00) >> 8)
+ #define STV_VDP2_N2CCRT (STV_VDP2_CCRNB & 0x1f)
+
+/* 18010c - Colour Calculation Ratio (RBG 0)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CCRR ((stv_vdp2_regs[0x10c/4] >> 16)&0x0000ffff)
+ #define STV_VDP2_R0CCRT (STV_VDP2_CCRR & 0x1f)
+
+/* 18010e - Colour Calculation Ratio (Line Colour Screen, Back Colour Screen)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+/* 180110 - Colour Offset Enable
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CLOFEN ((stv_vdp2_regs[0x110/4] >> 16)&0x0000ffff)
+ #define STV_VDP2_N0COEN ((STV_VDP2_CLOFEN & 0x01) >> 0)
+ #define STV_VDP2_N1COEN ((STV_VDP2_CLOFEN & 0x02) >> 1)
+ #define STV_VDP2_N2COEN ((STV_VDP2_CLOFEN & 0x04) >> 2)
+ #define STV_VDP2_N3COEN ((STV_VDP2_CLOFEN & 0x08) >> 3)
+ #define STV_VDP2_R0COEN ((STV_VDP2_CLOFEN & 0x10) >> 4)
+ #define STV_VDP2_BKCOEN ((STV_VDP2_CLOFEN & 0x20) >> 5)
+ #define STV_VDP2_SPCOEN ((STV_VDP2_CLOFEN & 0x40) >> 6)
+
+/* 180112 - Colour Offset Select
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_CLOFSL ((stv_vdp2_regs[0x110/4] >> 0)&0x0000ffff)
+ #define STV_VDP2_N0COSL ((STV_VDP2_CLOFSL & 0x01) >> 0)
+ #define STV_VDP2_N1COSL ((STV_VDP2_CLOFSL & 0x02) >> 1)
+ #define STV_VDP2_N2COSL ((STV_VDP2_CLOFSL & 0x04) >> 2)
+ #define STV_VDP2_N3COSL ((STV_VDP2_CLOFSL & 0x08) >> 3)
+ #define STV_VDP2_R0COSL ((STV_VDP2_CLOFSL & 0x10) >> 4)
+ #define STV_VDP2_BKCOSL ((STV_VDP2_CLOFSL & 0x20) >> 5)
+ #define STV_VDP2_SPCOSL ((STV_VDP2_CLOFSL & 0x40) >> 6)
+
+/* 180114 - Colour Offset A (Red)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_COAR ((stv_vdp2_regs[0x114/4] >> 16)&0x0000ffff)
+
+/* 180116 - Colour Offset A (Green)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_COAG ((stv_vdp2_regs[0x114/4] >> 0)&0x0000ffff)
+
+/* 180118 - Colour Offset A (Blue)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+
+ #define STV_VDP2_COAB ((stv_vdp2_regs[0x118/4] >> 16)&0x0000ffff)
+
+/* 18011a - Colour Offset B (Red)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_COBR ((stv_vdp2_regs[0x118/4] >> 0)&0x0000ffff)
+
+/* 18011b - Colour Offset B (Green)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_COBG ((stv_vdp2_regs[0x11c/4] >> 16)&0x0000ffff)
+
+/* 18011c - Colour Offset B (Blue)
+ bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----|
+ | -- | -- | -- | -- | -- | -- | -- | -- |
+ \----------|----------|----------|----------|----------|----------|----------|---------*/
+ #define STV_VDP2_COBB ((stv_vdp2_regs[0x11c/4] >> 0)&0x0000ffff)
+
+/*For Debug purposes only*/
+static struct stv_vdp2_debugging
+{
+ UINT8 l_en; /*For Layer enable/disable*/
+ UINT8 win; /*Enters into Window effect debug menu*/
+ UINT32 error; /*bits for VDP2 error logging*/
+ UINT8 roz; /*Debug roz on screen*/
+} debug;
+
+/*
+Errors are currently mapped as follows:
+x--- ---- ---- ---- ---- ---- ---- ---- VRAM Size = 8 Mbit
+-x-- ---- ---- ---- ---- ---- ---- ---- CRKTE used
+---- ---- ---- ---- ---- ---- ---- --x- Mosaic Control
+---- ---- ---- ---- ---- ---- ---- ---x Window on tilemap
+*/
+#define VDP2_ERR(_bit_) (debug.error & _bit_)
+#define VDP2_CHK(_bit_) (debug.error^=_bit_)
+
+/* Not sure if to use this for the rotating tilemaps as well or just use different draw functions, might add too much bloat */
+static struct stv_vdp2_tilemap_capabilities
+{
+ UINT8 enabled;
+ UINT8 transparency;
+ UINT8 colour_calculation_enabled;
+ UINT8 colour_depth;
+ UINT8 tile_size;
+ UINT8 bitmap_enable;
+ UINT8 bitmap_size;
+ UINT8 bitmap_palette_number;
+ UINT8 bitmap_map;
+ UINT16 map_offset[16];
+ UINT8 map_count;
+
+ UINT8 pattern_data_size;
+ UINT8 character_number_supplement;
+ UINT8 special_priority_register;
+ UINT8 special_colour_control_register;
+ UINT8 supplementary_palette_bits;
+ UINT8 supplementary_character_bits;
+
+ INT16 scrollx;
+ INT16 scrolly;
+ UINT32 incx, incy;
+
+ UINT8 linescroll_enable;
+ UINT8 linescroll_interval;
+ UINT32 linescroll_table_address;
+ UINT8 vertical_linescroll_enable;
+ UINT8 linezoom_enable;
+
+ UINT8 plane_size;
+ UINT8 colour_ram_address_offset;
+ UINT8 fade_control;
+ UINT8 window_control;
+
+// UINT8 real_map_offset[16];
+
+ int layer_name; /* just to keep track */
+} stv2_current_tilemap;
+
+#define STV_VDP2_RBG_ROTATION_PARAMETER_A 1
+#define STV_VDP2_RBG_ROTATION_PARAMETER_B 2
+
+static struct rotation_table
+{
+ INT32 xst;
+ INT32 yst;
+ INT32 zst;
+ INT32 dxst;
+ INT32 dyst;
+ INT32 dx;
+ INT32 dy;
+ INT32 A;
+ INT32 B;
+ INT32 C;
+ INT32 D;
+ INT32 E;
+ INT32 F;
+ INT32 px;
+ INT32 py;
+ INT32 pz;
+ INT32 cx;
+ INT32 cy;
+ INT32 cz;
+ INT32 mx;
+ INT32 my;
+ INT32 kx;
+ INT32 ky;
+ UINT32 kast;
+ INT32 dkast;
+ INT32 dkax;
+
+} stv_current_rotation_parameter_table;
+
+static struct _stv_vdp2_layer_data_placement
+{
+ UINT32 map_offset_min;
+ UINT32 map_offset_max;
+ UINT32 tile_offset_min;
+ UINT32 tile_offset_max;
+} stv_vdp2_layer_data_placement;
+
+static struct _stv_rbg_cache_data
+{
+ UINT8 watch_vdp2_vram_writes;
+ UINT8 is_cache_dirty;
+
+ UINT32 map_offset_min[2];
+ UINT32 map_offset_max[2];
+ UINT32 tile_offset_min[2];
+ UINT32 tile_offset_max[2];
+
+ struct stv_vdp2_tilemap_capabilities layer_data[2];
+
+} stv_rbg_cache_data;
+
+#define mul_fixed32( a, b ) mul_32x32_shift( a, b, 16 )
+
+static void stv_vdp2_fill_rotation_parameter_table( UINT8 rot_parameter )
+{
+ UINT32 address;
+
+ address = (((STV_VDP2_RPTAU << 16) | STV_VDP2_RPTAL) << 1);
+ if ( rot_parameter == 1 )
+ {
+ address &= ~0x00000080;
+ }
+ else if ( rot_parameter == 2 )
+ {
+ address |= 0x00000080;
+ }
+
+ stv_current_rotation_parameter_table.xst = (stv_vdp2_vram[address/4] & 0x1fffffc0) | ((stv_vdp2_vram[address/4] & 0x10000000) ? 0xe0000000 : 0x00000000 );
+ stv_current_rotation_parameter_table.yst = (stv_vdp2_vram[address/4 + 1] & 0x1fffffc0) | ((stv_vdp2_vram[address/4 + 1] & 0x10000000) ? 0xe0000000 : 0x00000000 );
+ stv_current_rotation_parameter_table.zst = (stv_vdp2_vram[address/4 + 2] & 0x1fffffc0) | ((stv_vdp2_vram[address/4 + 2] & 0x10000000) ? 0xe0000000 : 0x00000000 );
+ stv_current_rotation_parameter_table.dxst = (stv_vdp2_vram[address/4 + 3] & 0x0007ffc0) | ((stv_vdp2_vram[address/4 + 3] & 0x00040000) ? 0xfff80000 : 0x00000000 );
+ stv_current_rotation_parameter_table.dyst = (stv_vdp2_vram[address/4 + 4] & 0x0007ffc0) | ((stv_vdp2_vram[address/4 + 4] & 0x00040000) ? 0xfff80000 : 0x00000000 );
+ stv_current_rotation_parameter_table.dx = (stv_vdp2_vram[address/4 + 5] & 0x0007ffc0) | ((stv_vdp2_vram[address/4 + 5] & 0x00040000) ? 0xfff80000 : 0x00000000 );
+ stv_current_rotation_parameter_table.dy = (stv_vdp2_vram[address/4 + 6] & 0x0007ffc0) | ((stv_vdp2_vram[address/4 + 6] & 0x00040000) ? 0xfff80000 : 0x00000000 );
+ stv_current_rotation_parameter_table.A = (stv_vdp2_vram[address/4 + 7] & 0x000fffc0) | ((stv_vdp2_vram[address/4 + 7] & 0x00080000) ? 0xfff00000 : 0x00000000 );
+ stv_current_rotation_parameter_table.B = (stv_vdp2_vram[address/4 + 8] & 0x000fffc0) | ((stv_vdp2_vram[address/4 + 8] & 0x00080000) ? 0xfff00000 : 0x00000000 );
+ stv_current_rotation_parameter_table.C = (stv_vdp2_vram[address/4 + 9] & 0x000fffc0) | ((stv_vdp2_vram[address/4 + 9] & 0x00080000) ? 0xfff00000 : 0x00000000 );
+ stv_current_rotation_parameter_table.D = (stv_vdp2_vram[address/4 + 10] & 0x000fffc0) | ((stv_vdp2_vram[address/4 + 10] & 0x00080000) ? 0xfff00000 : 0x00000000 );
+ stv_current_rotation_parameter_table.E = (stv_vdp2_vram[address/4 + 11] & 0x000fffc0) | ((stv_vdp2_vram[address/4 + 11] & 0x00080000) ? 0xfff00000 : 0x00000000 );
+ stv_current_rotation_parameter_table.F = (stv_vdp2_vram[address/4 + 12] & 0x000fffc0) | ((stv_vdp2_vram[address/4 + 12] & 0x00080000) ? 0xfff00000 : 0x00000000 );
+ stv_current_rotation_parameter_table.px = (stv_vdp2_vram[address/4 + 13] & 0x3fff0000) | ((stv_vdp2_vram[address/4 + 13] & 0x30000000) ? 0xc0000000 : 0x00000000 );
+ stv_current_rotation_parameter_table.py = (stv_vdp2_vram[address/4 + 13] & 0x00003fff) << 16;
+ if ( stv_current_rotation_parameter_table.py & 0x20000000 ) stv_current_rotation_parameter_table.py |= 0xc0000000;
+ stv_current_rotation_parameter_table.pz = (stv_vdp2_vram[address/4 + 14] & 0x3fff0000) | ((stv_vdp2_vram[address/4 + 14] & 0x20000000) ? 0xc0000000 : 0x00000000 );
+ stv_current_rotation_parameter_table.cx = (stv_vdp2_vram[address/4 + 15] & 0x3fff0000) | ((stv_vdp2_vram[address/4 + 15] & 0x20000000) ? 0xc0000000 : 0x00000000 );
+ stv_current_rotation_parameter_table.cy = (stv_vdp2_vram[address/4 + 15] & 0x00003fff) << 16;
+ if ( stv_current_rotation_parameter_table.cy & 0x20000000 ) stv_current_rotation_parameter_table.cy |= 0xc0000000;
+ stv_current_rotation_parameter_table.cz = (stv_vdp2_vram[address/4 + 16] & 0x3fff0000) | ((stv_vdp2_vram[address/4 + 16] & 0x20000000) ? 0xc0000000 : 0x00000000 );
+ stv_current_rotation_parameter_table.mx = (stv_vdp2_vram[address/4 + 17] & 0x3fffffc0) | ((stv_vdp2_vram[address/4 + 17] & 0x20000000) ? 0xc0000000 : 0x00000000 );
+ stv_current_rotation_parameter_table.my = (stv_vdp2_vram[address/4 + 18] & 0x3fffffc0) | ((stv_vdp2_vram[address/4 + 18] & 0x20000000) ? 0xc0000000 : 0x00000000 );
+ stv_current_rotation_parameter_table.kx = (stv_vdp2_vram[address/4 + 19] & 0x00ffffff) | ((stv_vdp2_vram[address/4 + 19] & 0x00800000) ? 0xff000000 : 0x00000000 );
+ stv_current_rotation_parameter_table.ky = (stv_vdp2_vram[address/4 + 20] & 0x00ffffff) | ((stv_vdp2_vram[address/4 + 20] & 0x00800000) ? 0xff000000 : 0x00000000 );
+ stv_current_rotation_parameter_table.kast = (stv_vdp2_vram[address/4 + 21] & 0xffffffc0);
+ stv_current_rotation_parameter_table.dkast= (stv_vdp2_vram[address/4 + 22] & 0x03ffffc0) | ((stv_vdp2_vram[address/4 + 22] & 0x02000000) ? 0xfc000000 : 0x00000000 );
+ stv_current_rotation_parameter_table.dkax = (stv_vdp2_vram[address/4 + 23] & 0x03ffffc0) | ((stv_vdp2_vram[address/4 + 23] & 0x02000000) ? 0xfc000000 : 0x00000000 );
+
+#define RP stv_current_rotation_parameter_table
+
+ if(LOG_ROZ == 1) logerror( "Rotation parameter table (%d)\n", rot_parameter );
+ if(LOG_ROZ == 1) logerror( "xst = %x, yst = %x, zst = %x\n", RP.xst, RP.yst, RP.zst );
+ if(LOG_ROZ == 1) logerror( "dxst = %x, dyst = %x\n", RP.dxst, RP.dyst );
+ if(LOG_ROZ == 1) logerror( "dx = %x, dy = %x\n", RP.dx, RP.dy );
+ if(LOG_ROZ == 1) logerror( "A = %x, B = %x, C = %x, D = %x, E = %x, F = %x\n", RP.A, RP.B, RP.C, RP.D, RP.E, RP.F );
+ if(LOG_ROZ == 1) logerror( "px = %x, py = %x, pz = %x\n", RP.px, RP.py, RP.pz );
+ if(LOG_ROZ == 1) logerror( "cx = %x, cy = %x, cz = %x\n", RP.cx, RP.cy, RP.cz );
+ if(LOG_ROZ == 1) logerror( "mx = %x, my = %x\n", RP.mx, RP.my );
+ if(LOG_ROZ == 1) logerror( "kx = %x, ky = %x\n", RP.kx, RP.ky );
+ if(LOG_ROZ == 1) logerror( "kast = %x, dkast = %x, dkax = %x\n", RP.kast, RP.dkast, RP.dkax );
+
+ /*Attempt to show on screen the rotation table*/
+ if(LOG_ROZ == 2)
+ {
+ if(input_code_pressed_once(JOYCODE_Y_UP_SWITCH))
+ debug.roz++;
+
+ if(input_code_pressed_once(JOYCODE_Y_DOWN_SWITCH))
+ debug.roz--;
+
+ if(debug.roz > 10)
+ debug.roz = 10;
+
+ switch(debug.roz)
+ {
+ case 0: popmessage( "Rotation parameter Table (%d)", rot_parameter ); break;
+ case 1: popmessage( "xst = %x, yst = %x, zst = %x", RP.xst, RP.yst, RP.zst ); break;
+ case 2: popmessage( "dxst = %x, dyst = %x", RP.dxst, RP.dyst ); break;
+ case 3: popmessage( "dx = %x, dy = %x", RP.dx, RP.dy ); break;
+ case 4: popmessage( "A = %x, B = %x, C = %x, D = %x, E = %x, F = %x", RP.A, RP.B, RP.C, RP.D, RP.E, RP.F ); break;
+ case 5: popmessage( "px = %x, py = %x, pz = %x", RP.px, RP.py, RP.pz ); break;
+ case 6: popmessage( "cx = %x, cy = %x, cz = %x", RP.cx, RP.cy, RP.cz ); break;
+ case 7: popmessage( "mx = %x, my = %x", RP.mx, RP.my ); break;
+ case 8: popmessage( "kx = %x, ky = %x", RP.kx, RP.ky ); break;
+ case 9: popmessage( "kast = %x, dkast = %x, dkax = %x", RP.kast, RP.dkast, RP.dkax ); break;
+ case 10: break;
+ }
+ }
+}
+
+/* check if RGB layer has rotation applied */
+static UINT8 stv_vdp2_is_rotation_applied(void)
+{
+#define _FIXED_1 (0x00010000)
+#define _FIXED_0 (0x00000000)
+
+ if ( RP.A == _FIXED_1 &&
+ RP.B == _FIXED_0 &&
+ RP.C == _FIXED_0 &&
+ RP.D == _FIXED_0 &&
+ RP.E == _FIXED_1 &&
+ RP.F == _FIXED_0 &&
+ RP.dxst == _FIXED_0 &&
+ RP.dyst == _FIXED_1 &&
+ RP.dx == _FIXED_1 &&
+ RP.dy == _FIXED_0 )
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+static UINT8 stv_vdp2_are_map_registers_equal(void)
+{
+ int i;
+
+ for ( i = 1; i < stv2_current_tilemap.map_count; i++ )
+ {
+ if ( stv2_current_tilemap.map_offset[i] != stv2_current_tilemap.map_offset[0] )
+ {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void stv_vdp2_check_fade_control_for_layer(void)
+{
+ if ( stv2_current_tilemap.fade_control & 1 )
+ {
+ if ( stv2_current_tilemap.fade_control & 2 )
+ {
+ if ((STV_VDP2_COBR & 0x1ff) == 0 &&
+ (STV_VDP2_COBG & 0x1ff) == 0 &&
+ (STV_VDP2_COBB & 0x1ff) == 0 )
+ {
+ stv2_current_tilemap.fade_control = 0;
+ }
+ }
+ else
+ {
+ if ((STV_VDP2_COAR & 0x1ff) == 0 &&
+ (STV_VDP2_COAG & 0x1ff) == 0 &&
+ (STV_VDP2_COAB & 0x1ff) == 0 )
+ {
+ stv2_current_tilemap.fade_control = 0;
+ }
+ }
+ }
+}
+
+#define STV_VDP2_CP_NBG0_PNMDR 0x0
+#define STV_VDP2_CP_NBG1_PNMDR 0x1
+#define STV_VDP2_CP_NBG2_PNMDR 0x2
+#define STV_VDP2_CP_NBG3_PNMDR 0x3
+#define STV_VDP2_CP_NBG0_CPDR 0x4
+#define STV_VDP2_CP_NBG1_CPDR 0x5
+#define STV_VDP2_CP_NBG2_CPDR 0x6
+#define STV_VDP2_CP_NBG3_CPDR 0x7
+
+static UINT8 stv_vdp2_check_vram_cycle_pattern_registers(
+ UINT8 access_command_pnmdr,
+ UINT8 access_command_cpdr,
+ UINT8 bitmap_enable )
+{
+ int i;
+ UINT8 access_command_ok = 0;
+ UINT16 cp_regs[8];
+ cp_regs[0] = STV_VDP2_CYCA0L;
+ cp_regs[1] = STV_VDP2_CYCA0U;
+ cp_regs[2] = STV_VDP2_CYCA1L;
+ cp_regs[3] = STV_VDP2_CYCA1U;
+ cp_regs[4] = STV_VDP2_CYCA2L;
+ cp_regs[5] = STV_VDP2_CYCA2U;
+ cp_regs[6] = STV_VDP2_CYCA3L;
+ cp_regs[7] = STV_VDP2_CYCA3U;
+
+ if ( bitmap_enable ) access_command_ok = 1;
+
+ for ( i = 0; i < 8; i++ )
+ {
+ if ( ((cp_regs[i] >> 12) & 0xf) == access_command_pnmdr )
+ {
+ access_command_ok |= 1;
+ }
+ if ( ((cp_regs[i] >> 12) & 0xf) == access_command_cpdr )
+ {
+ access_command_ok |= 2;
+ }
+ if ( ((cp_regs[i] >> 8) & 0xf) == access_command_pnmdr )
+ {
+ access_command_ok |= 1;
+ }
+ if ( ((cp_regs[i] >> 8) & 0xf) == access_command_cpdr )
+ {
+ access_command_ok |= 2;
+ }
+ if ( ((cp_regs[i] >> 4) & 0xf) == access_command_pnmdr )
+ {
+ access_command_ok |= 1;
+ }
+ if ( ((cp_regs[i] >> 4) & 0xf) == access_command_cpdr )
+ {
+ access_command_ok |= 2;
+ }
+ if ( ((cp_regs[i] >> 0) & 0xf) == access_command_pnmdr )
+ {
+ access_command_ok |= 1;
+ }
+ if ( ((cp_regs[i] >> 0) & 0xf) == access_command_cpdr )
+ {
+ access_command_ok |= 2;
+ }
+ }
+ return access_command_ok == 3 ? 1 : 0;
+}
+
+INLINE UINT16 stv_add_blend(UINT16 a, UINT16 b)
+{
+ UINT16 _r = (a & 0x7c00) + (b & 0x7c00);
+ UINT16 _g = (a & 0x03e0) + (b & 0x03e0);
+ UINT16 _b = (a & 0x001f) + (b & 0x001f);
+
+ if ( _r > 0x7c00 ) _r = 0x7c00;
+ if ( _g > 0x03e0 ) _g = 0x03e0;
+ if ( _b > 0x001f ) _b = 0x001f;
+
+ return _r | _g | _b;
+
+}
+
+static void stv_vdp2_drawgfxzoom( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ UINT32 code,UINT32 color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,int scalex, int scaley,
+ int sprite_screen_width, int sprite_screen_height)
+{
+ rectangle myclip;
+
+ if (!scalex || !scaley) return;
+
+ if (gfx->pen_usage && (transparency == TRANSPARENCY_PEN || transparency == TRANSPARENCY_PENS))
+ {
+ int transmask = 0;
+
+ if (transparency == TRANSPARENCY_PEN)
+ {
+ transmask = 1 << (transparent_color & 0xff);
+ }
+ else /* transparency == TRANSPARENCY_PENS */
+ {
+ transmask = transparent_color;
+ }
+
+ if ((gfx->pen_usage[code] & ~transmask) == 0)
+ /* character is totally transparent, no need to draw */
+ return;
+ else if ((gfx->pen_usage[code] & transmask) == 0)
+ /* character is totally opaque, can disable transparency */
+ transparency = TRANSPARENCY_NONE;
+ }
+
+ /*
+ scalex and scaley are 16.16 fixed point numbers
+ 1<<15 : shrink to 50%
+ 1<<16 : uniform scale
+ 1<<17 : double to 200%
+ */
+
+
+ /* KW 991012 -- Added code to force clip to bitmap boundary */
+ if(clip)
+ {
+ myclip.min_x = clip->min_x;
+ myclip.max_x = clip->max_x;
+ myclip.min_y = clip->min_y;
+ myclip.max_y = clip->max_y;
+
+ if (myclip.min_x < 0) myclip.min_x = 0;
+ if (myclip.max_x >= dest_bmp->width) myclip.max_x = dest_bmp->width-1;
+ if (myclip.min_y < 0) myclip.min_y = 0;
+ if (myclip.max_y >= dest_bmp->height) myclip.max_y = dest_bmp->height-1;
+
+ clip=&myclip;
+ }
+
+ if( gfx )
+ {
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+ UINT8 *source_base = gfx->gfxdata + (code % gfx->total_elements) * gfx->char_modulo;
+
+ //int sprite_screen_height = (scaley*gfx->height+0x8000)>>16;
+ //int sprite_screen_width = (scalex*gfx->width+0x8000)>>16;
+
+ if (sprite_screen_width && sprite_screen_height)
+ {
+ /* compute sprite increment per screen pixel */
+ //int dx = (gfx->width<<16)/sprite_screen_width;
+ //int dy = (gfx->height<<16)/sprite_screen_height;
+ int dx = stv2_current_tilemap.incx;
+ int dy = stv2_current_tilemap.incy;
+
+ int ex = sx+sprite_screen_width;
+ int ey = sy+sprite_screen_height;
+
+ int x_index_base;
+ int y_index;
+
+ if( flipx )
+ {
+ x_index_base = (sprite_screen_width-1)*dx;
+ dx = -dx;
+ }
+ else
+ {
+ x_index_base = 0;
+ }
+
+ if( flipy )
+ {
+ y_index = (sprite_screen_height-1)*dy;
+ dy = -dy;
+ }
+ else
+ {
+ y_index = 0;
+ }
+
+ if( clip )
+ {
+ if( sx < clip->min_x)
+ { /* clip left */
+ int pixels = clip->min_x-sx;
+ sx += pixels;
+ x_index_base += pixels*dx;
+ }
+ if( sy < clip->min_y )
+ { /* clip top */
+ int pixels = clip->min_y-sy;
+ sy += pixels;
+ y_index += pixels*dy;
+ }
+ /* NS 980211 - fixed incorrect clipping */
+ if( ex > clip->max_x+1 )
+ { /* clip right */
+ int pixels = ex-clip->max_x-1;
+ ex -= pixels;
+ }
+ if( ey > clip->max_y+1 )
+ { /* clip bottom */
+ int pixels = ey-clip->max_y-1;
+ ey -= pixels;
+ }
+ }
+
+ if( ex>sx )
+ { /* skip if inner loop doesn't draw anything */
+ int y;
+
+ /* case 0: TRANSPARENCY_NONE */
+ if (transparency == TRANSPARENCY_NONE)
+ {
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT16 *dest = BITMAP_ADDR16(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ dest[x] = pal[(source[x_index>>17] >> ((x_index & 0x10000) >> 14)) & 0x0f];
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT16 *dest = BITMAP_ADDR16(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ dest[x] = pal[source[x_index>>16]];
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 1: TRANSPARENCY_PEN */
+ if (transparency == TRANSPARENCY_PEN)
+ {
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT16 *dest = BITMAP_ADDR16(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = (source[x_index>>17] >> ((x_index & 0x10000) >> 14)) & 0x0f;
+ if( c != transparent_color ) dest[x] = pal[c];
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT16 *dest = BITMAP_ADDR16(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if( c != transparent_color ) dest[x] = pal[c];
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ /* case 6: TRANSPARENCY_ALPHA */
+ if (transparency == TRANSPARENCY_ALPHA)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT16 *dest = BITMAP_ADDR16(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if( c != transparent_color ) dest[x] = alpha_blend16(dest[x], pal[c]);
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+
+ /* case : STV_TRANSPARENCY_ADD_BLEND */
+ if (transparency == STV_TRANSPARENCY_ADD_BLEND )
+ {
+ if (gfx->flags & GFX_ELEMENT_PACKED)
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT16 *dest = BITMAP_ADDR16(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = (source[x_index>>17] >> ((x_index & 0x10000) >> 14)) & 0x0f;
+ if( c != transparent_color ) dest[x] = stv_add_blend(dest[x],pal[c]);
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ else
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT16 *dest = BITMAP_ADDR16(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if( c != transparent_color ) dest[x] = stv_add_blend(dest[x],pal[c]);
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+}
+
+static void stv_vdp2_compute_color_offset_RGB555( int *r, int *g, int *b, int cor )
+{
+ *r <<= 3;
+ *g <<= 3;
+ *b <<= 3;
+ if ( cor == 0 )
+ {
+ *r = (STV_VDP2_COAR & 0x100) ? (*r - (0x100 - (STV_VDP2_COAR & 0xff))) : ((STV_VDP2_COAR & 0xff) + *r);
+ *g = (STV_VDP2_COAG & 0x100) ? (*g - (0x100 - (STV_VDP2_COAG & 0xff))) : ((STV_VDP2_COAG & 0xff) + *g);
+ *b = (STV_VDP2_COAB & 0x100) ? (*b - (0x100 - (STV_VDP2_COAB & 0xff))) : ((STV_VDP2_COAB & 0xff) + *b);
+ }
+ else
+ {
+ *r = (STV_VDP2_COBR & 0x100) ? (*r - (0xff - (STV_VDP2_COBR & 0xff))) : ((STV_VDP2_COBR & 0xff) + *r);
+ *g = (STV_VDP2_COBG & 0x100) ? (*g - (0xff - (STV_VDP2_COBG & 0xff))) : ((STV_VDP2_COBG & 0xff) + *g);
+ *b = (STV_VDP2_COBB & 0x100) ? (*b - (0xff - (STV_VDP2_COBB & 0xff))) : ((STV_VDP2_COBB & 0xff) + *b);
+ }
+ if(*r < 0) { *r = 0; }
+ if(*r > 0xff) { *r = 0xff; }
+ if(*g < 0) { *g = 0; }
+ if(*g > 0xff) { *g = 0xff; }
+ if(*b < 0) { *b = 0; }
+ if(*b > 0xff) { *b = 0xff; }
+ *r >>= 3;
+ *g >>= 3;
+ *b >>= 3;
+
+}
+
+static void stv_vdp2_compute_color_offset_RGB555_UINT16(UINT16 *rgb, int cor)
+{
+ int _r = (*rgb & 0x7c00) >> (10-3);
+ int _g = (*rgb & 0x03e0) >> (5-3);
+ int _b = (*rgb & 0x001f) << 3;
+ if ( cor == 0 )
+ {
+ _r = (STV_VDP2_COAR & 0x100) ? (_r - (0x100 - (STV_VDP2_COAR & 0xff))) : ((STV_VDP2_COAR & 0xff) + _r);
+ _g = (STV_VDP2_COAG & 0x100) ? (_g - (0x100 - (STV_VDP2_COAG & 0xff))) : ((STV_VDP2_COAG & 0xff) + _g);
+ _b = (STV_VDP2_COAB & 0x100) ? (_b - (0x100 - (STV_VDP2_COAB & 0xff))) : ((STV_VDP2_COAB & 0xff) + _b);
+ }
+ else
+ {
+ _r = (STV_VDP2_COBR & 0x100) ? (_r - (0xff - (STV_VDP2_COBR & 0xff))) : ((STV_VDP2_COBR & 0xff) + _r);
+ _g = (STV_VDP2_COBG & 0x100) ? (_g - (0xff - (STV_VDP2_COBG & 0xff))) : ((STV_VDP2_COBG & 0xff) + _g);
+ _b = (STV_VDP2_COBB & 0x100) ? (_b - (0xff - (STV_VDP2_COBB & 0xff))) : ((STV_VDP2_COBB & 0xff) + _b);
+ }
+ if(_r < 0) { _r = 0; }
+ if(_r > 0xff) { _r = 0xff; }
+ if(_g < 0) { _g = 0; }
+ if(_g > 0xff) { _g = 0xff; }
+ if(_b < 0) { _b = 0; }
+ if(_b > 0xff) { _b = 0xff; }
+ _r >>= 3;
+ _g >>= 3;
+ _b >>= 3;
+
+ *rgb = (_r << 10) | (_g << 5) | _b;
+}
+
+static void stv_vdp2_drawgfx_rgb555( mame_bitmap *dest_bmp, UINT32 code, int flipx, int flipy,
+ int sx, int sy, const rectangle *clip, int transparency)
+{
+ rectangle myclip;
+ UINT8* gfxdata;
+ int t_pen;
+ int sprite_screen_width, sprite_screen_height;
+
+ gfxdata = stv_vdp2_gfx_decode + code * 0x20;
+ sprite_screen_width = sprite_screen_height = 8;
+
+ /* KW 991012 -- Added code to force clip to bitmap boundary */
+ if(clip)
+ {
+ myclip.min_x = clip->min_x;
+ myclip.max_x = clip->max_x;
+ myclip.min_y = clip->min_y;
+ myclip.max_y = clip->max_y;
+
+ if (myclip.min_x < 0) myclip.min_x = 0;
+ if (myclip.max_x >= dest_bmp->width) myclip.max_x = dest_bmp->width-1;
+ if (myclip.min_y < 0) myclip.min_y = 0;
+ if (myclip.max_y >= dest_bmp->height) myclip.max_y = dest_bmp->height-1;
+
+ clip=&myclip;
+ }
+ {
+ int dx = stv2_current_tilemap.incx;
+ int dy = stv2_current_tilemap.incy;
+
+ int ex = sx+sprite_screen_width;
+ int ey = sy+sprite_screen_height;
+
+ int x_index_base;
+ int y_index;
+
+ if( flipx )
+ {
+ x_index_base = (sprite_screen_width-1)*dx;
+ dx = -dx;
+ }
+ else
+ {
+ x_index_base = 0;
+ }
+
+ if( flipy )
+ {
+ y_index = (sprite_screen_height-1)*dy;
+ dy = -dy;
+ }
+ else
+ {
+ y_index = 0;
+ }
+
+ if( clip )
+ {
+ if( sx < clip->min_x)
+ { /* clip left */
+ int pixels = clip->min_x-sx;
+ sx += pixels;
+ x_index_base += pixels*dx;
+ }
+ if( sy < clip->min_y )
+ { /* clip top */
+ int pixels = clip->min_y-sy;
+ sy += pixels;
+ y_index += pixels*dy;
+ }
+ /* NS 980211 - fixed incorrect clipping */
+ if( ex > clip->max_x+1 )
+ { /* clip right */
+ int pixels = ex-clip->max_x-1;
+ ex -= pixels;
+ }
+ if( ey > clip->max_y+1 )
+ { /* clip bottom */
+ int pixels = ey-clip->max_y-1;
+ ey -= pixels;
+ }
+ }
+
+ if( ex>sx )
+ { /* skip if inner loop doesn't draw anything */
+ int y;
+
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = gfxdata + (y_index>>16)*16;
+ UINT16 *dest = BITMAP_ADDR16(dest_bmp, y, 0);
+ UINT16 data;
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int r,g,b;
+
+ data = (source[(x_index>>16)*2] << 8) | source[(x_index>>16)*2+1];
+ t_pen = (data & 0x8000) || ( transparency == TRANSPARENCY_NONE );
+ if (t_pen)
+ {
+ b = (data & 0x7c00) >> 10;
+ g = (data & 0x03e0) >> 5;
+ r = (data & 0x001f);
+ if(stv2_current_tilemap.fade_control & 1)
+ stv_vdp2_compute_color_offset_RGB555(&r,&g,&b,stv2_current_tilemap.fade_control & 2);
+
+ if ( transparency == TRANSPARENCY_ALPHA )
+ dest[x] = alpha_blend16( dest[x], b | g << 5 | r << 10 );
+ else
+ dest[x] = b | g << 5 | r << 10;
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+
+ }
+
+ }
+
+}
+
+static void stv_vdp2_draw_basic_bitmap(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+// if(LOG_VDP2) logerror ("bitmap enable %02x size %08x depth %08x\n", stv2_current_tilemap.layer_name, stv2_current_tilemap.bitmap_size, stv2_current_tilemap.colour_depth);
+// popmessage ("bitmap enable %02x size %08x depth %08x number %02x", stv2_current_tilemap.layer_name, stv2_current_tilemap.bitmap_size, stv2_current_tilemap.colour_depth,stv2_current_tilemap.bitmap_palette_number);
+ //popmessage("%04x",STV_VDP2_SCRCTL);
+
+ int xsize = 0, xsizemask = 0;
+ int ysize = 0, ysizemask = 0;
+ int xlinesize = 0, xpixelsize = 0;
+ int xcnt,ycnt;
+ UINT8* gfxdata = stv_vdp2_gfx_decode;
+ static UINT16 *destline;
+ UINT16 pal_color_offset = 0;
+ UINT8* gfxdatalow, *gfxdatahigh;
+
+ /*Window effect 1=no draw*/
+ int tw;
+
+ /*Transparency code 1=opaque,0=transparent*/
+ int t_pen;
+ if (!stv2_current_tilemap.enabled) return;
+
+ /* size for n0 / n1 */
+ switch (stv2_current_tilemap.bitmap_size)
+ {
+ case 0: xsize=512; ysize=256; break;
+ case 1: xsize=512; ysize=512; break;
+ case 2: xsize=1024; ysize=256; break;
+ case 3: xsize=1024; ysize=512; break;
+ }
+ xsizemask = xsize - 1;
+ ysizemask = ysize - 1;
+
+ switch( stv2_current_tilemap.colour_depth )
+ {
+ case 0: xlinesize = xsize / 2; xpixelsize = 0; break;
+ case 1: xlinesize = xsize; xpixelsize = 1; break;
+ case 2: case 3: xlinesize = xsize * 2; xpixelsize = 2; break;
+ case 4: xlinesize = xsize * 4; xpixelsize = 4; break;
+ }
+
+ if(stv2_current_tilemap.colour_depth == 0)
+ stv2_current_tilemap.scrollx /= 2;
+ if(stv2_current_tilemap.colour_depth == 2 || stv2_current_tilemap.colour_depth == 3)
+ stv2_current_tilemap.scrollx*=2;
+ if(stv2_current_tilemap.colour_depth == 4)
+ stv2_current_tilemap.scrollx*=4;
+
+ gfxdatalow = gfxdata + stv2_current_tilemap.bitmap_map * 0x20000;
+ gfxdata+=(
+ (stv2_current_tilemap.scrollx & (xlinesize-1)) +
+ ((stv2_current_tilemap.scrolly & (ysize-1)) * (xlinesize)) +
+ (stv2_current_tilemap.bitmap_map * 0x20000)
+ );
+ gfxdatahigh = gfxdatalow + xlinesize*ysize;
+
+// popmessage("%04x %04x",stv2_current_tilemap.scrollx,stv2_current_tilemap.scrolly);
+
+ /*Enable fading bit*/
+ if(stv2_current_tilemap.fade_control & 1)
+ {
+ /*Select fading bit*/
+ pal_color_offset += ((stv2_current_tilemap.fade_control & 2) ? (2*2048) : (2048));
+ }
+
+ stv2_current_tilemap.bitmap_palette_number+=stv2_current_tilemap.colour_ram_address_offset;
+ stv2_current_tilemap.bitmap_palette_number&=7;//safety check
+
+ switch(stv2_current_tilemap.colour_depth)
+ {
+ /*Palette Format*/
+ case 0:
+ for (ycnt = 0; ycnt <ysize;ycnt++)
+ {
+ for (xcnt = 0; xcnt <xsize;xcnt+=2)
+ {
+ tw = stv_vdp2_window_process(xcnt+1,ycnt);
+ if(tw == 0)
+ {
+ t_pen = (((gfxdata[0] & 0x0f) >> 0) != 0) ? (1) : (0);
+ if(stv2_current_tilemap.transparency == TRANSPARENCY_NONE) t_pen = 1;
+ if(t_pen)
+ {
+ if ( stv2_current_tilemap.colour_calculation_enabled == 0 )
+ *BITMAP_ADDR16(bitmap, ycnt, xcnt+1) = machine->pens[((gfxdata[0] & 0x0f) >> 0) | (stv2_current_tilemap.bitmap_palette_number * 0x100) | pal_color_offset];
+ else
+ *BITMAP_ADDR16(bitmap, ycnt, xcnt+1) = alpha_blend16(*BITMAP_ADDR16(bitmap, ycnt, xcnt+1), machine->pens[((gfxdata[0] & 0x0f) >> 0) | (stv2_current_tilemap.bitmap_palette_number * 0x100) | pal_color_offset]);
+ }
+ }
+ tw = stv_vdp2_window_process(xcnt,ycnt);
+ if(tw == 0)
+ {
+ t_pen = (((gfxdata[0] & 0xf0) >> 4) != 0) ? (1) : (0);
+ if(stv2_current_tilemap.transparency == TRANSPARENCY_NONE) t_pen = 1;
+ if(t_pen)
+ {
+ if ( stv2_current_tilemap.colour_calculation_enabled == 0 )
+ *BITMAP_ADDR16(bitmap, ycnt, xcnt) = machine->pens[((gfxdata[0] & 0xf0) >> 4) | (stv2_current_tilemap.bitmap_palette_number * 0x100) | pal_color_offset];
+ else
+ *BITMAP_ADDR16(bitmap, ycnt, xcnt) = alpha_blend16(*BITMAP_ADDR16(bitmap, ycnt, xcnt), machine->pens[((gfxdata[0] & 0x0f) >> 0) | (stv2_current_tilemap.bitmap_palette_number * 0x100) | pal_color_offset]);
+ }
+ }
+ gfxdata++;
+ if ( gfxdata >= gfxdatahigh ) gfxdata = gfxdatalow;
+ }
+ }
+ break;
+ case 1:
+ if ( stv2_current_tilemap.incx == 0x10000 && stv2_current_tilemap.incy == 0x10000 )
+ {
+ int gfx_wraparound = -1;
+
+ gfxdata += xlinesize*cliprect->min_y;
+
+ for (ycnt = cliprect->min_y; ycnt <= cliprect->max_y; ycnt++)
+ {
+ for (xcnt = cliprect->min_x; xcnt <= cliprect->max_x; xcnt++)
+ {
+ int xs = xcnt & xsizemask;
+
+ tw = stv_vdp2_window_process(xcnt,ycnt);
+ if(tw == 0)
+ {
+ t_pen = ((gfxdata[xs] & 0xff) != 0) ? (1) : (0);
+ if(stv2_current_tilemap.transparency == TRANSPARENCY_NONE) t_pen = 1;
+ if(t_pen)
+ *BITMAP_ADDR16(bitmap, ycnt, xcnt) = machine->pens[(gfxdata[xs] & 0xff) | (stv2_current_tilemap.bitmap_palette_number * 0x100) | pal_color_offset];
+ }
+ if ( (gfxdata + xs) >= gfxdatahigh )
+ {
+ gfx_wraparound = (ycnt << 16) | xcnt;
+ gfxdata = gfxdatalow - xs;
+ }
+ }
+ if ( (gfxdata + xlinesize) < gfxdatahigh )
+ {
+ gfxdata += xlinesize;
+ }
+ else
+ {
+ gfxdata = gfxdatalow + ((gfxdata + xlinesize) - gfxdatahigh);
+ }
+ }
+
+ }
+ else
+ {
+ int xx, xs, yy=0;
+ for (ycnt = cliprect->min_y; ycnt <= cliprect->max_y; yy+=stv2_current_tilemap.incy, ycnt++ )
+ {
+ gfxdata += xlinesize*(yy>>16);
+ yy &= 0xffff;
+
+ destline = BITMAP_ADDR16(bitmap, ycnt, 0);
+ xx = 0;
+ for (xcnt = cliprect->min_x; xcnt <= cliprect->max_x; xx+=stv2_current_tilemap.incx, xcnt++)
+ {
+ xs = xx >> 16;
+ tw = stv_vdp2_window_process(xcnt,ycnt);
+ if(tw == 0)
+ {
+ t_pen = ((gfxdata[xs] & 0xff) != 0) ? 1 : 0;
+ if(stv2_current_tilemap.transparency == TRANSPARENCY_NONE) t_pen = 1;
+ if(t_pen)
+ *BITMAP_ADDR16(bitmap, ycnt, xcnt) = machine->pens[(gfxdata[xs] & 0xff) | (stv2_current_tilemap.bitmap_palette_number * 0x100) | pal_color_offset];
+ }
+
+ if ( (gfxdata + xs) >= gfxdatahigh ) gfxdata = gfxdatalow;
+
+ }
+ }
+ }
+ break;
+ case 2:
+ for (ycnt = 0; ycnt <ysize;ycnt++)
+ {
+ for (xcnt = 0; xcnt <xsize;xcnt++)
+ {
+ tw = stv_vdp2_window_process(xcnt,ycnt);
+ if(tw == 0)
+ {
+ t_pen = ((((gfxdata[0] & 0x07) * 0x100) | (gfxdata[1] & 0xff)) != 0) ? (1) : (0);
+ if(stv2_current_tilemap.transparency == TRANSPARENCY_NONE) t_pen = 1;
+ if(t_pen)
+ *BITMAP_ADDR16(bitmap, ycnt, xcnt) = machine->pens[((gfxdata[0] & 0x07) * 0x100) | (gfxdata[1] & 0xff) | pal_color_offset];
+ }
+
+ gfxdata+=2;
+ if ( gfxdata >= gfxdatahigh ) gfxdata = gfxdatalow;
+ }
+ }
+ break;
+ /*RGB format*/
+ /*
+ M L
+ S S
+ B B
+ --------BBBBBGGGGGRRRRR
+ */
+ case 3:
+ if ( stv2_current_tilemap.incx == 0x10000 && stv2_current_tilemap.incy == 0x10000 )
+ {
+ /* adjust for cliprect */
+ gfxdata += xlinesize*cliprect->min_y;
+
+ for (ycnt = cliprect->min_y; ycnt <= cliprect->max_y; ycnt++)
+ {
+ destline = BITMAP_ADDR16(bitmap, ycnt, 0);
+
+ for (xcnt = cliprect->min_x; xcnt <= cliprect->max_x; xcnt++)
+ {
+ int r,g,b;
+ int xs = xcnt & xsizemask;
+
+ t_pen = ((gfxdata[2*xs] & 0x80) >> 7) || (stv2_current_tilemap.transparency == TRANSPARENCY_NONE);
+ if (!t_pen) continue;
+ b = ((gfxdata[2*xs] & 0x7c) >> 2);
+ g = ((gfxdata[2*xs] & 0x03) << 3) | ((gfxdata[2*xs+1] & 0xe0) >> 5);
+ r = ((gfxdata[2*xs+1] & 0x1f));
+ if(stv2_current_tilemap.fade_control & 1)
+ stv_vdp2_compute_color_offset_RGB555(&r,&g,&b,stv2_current_tilemap.fade_control & 2);
+ tw = stv_vdp2_window_process(xcnt,ycnt);
+ if(tw == 0)
+ {
+ if ( stv2_current_tilemap.colour_calculation_enabled == 0 )
+ destline[xcnt] = b | g << 5 | r << 10;
+ else
+ destline[xcnt] = alpha_blend16( destline[xcnt], b | g << 5 | r << 10 );
+ }
+
+ if ( (gfxdata + 2*xs) >= gfxdatahigh ) gfxdata = gfxdatalow;
+ }
+
+ gfxdata += xlinesize;
+ if ( gfxdata >= gfxdatahigh ) gfxdata = gfxdatalow + (gfxdata - gfxdatahigh);
+ }
+
+ }
+ else
+ {
+ int xx, xs, yy=0;
+ for (ycnt = cliprect->min_y; ycnt <= cliprect->max_y; yy+=stv2_current_tilemap.incy, ycnt++ )
+ {
+ gfxdata += xlinesize*(yy>>16);
+ yy &= 0xffff;
+
+ destline = BITMAP_ADDR16(bitmap, ycnt, 0);
+ xx = 0;
+ for (xcnt = cliprect->min_x; xcnt <= cliprect->max_x; xx+=stv2_current_tilemap.incx, xcnt++)
+ {
+ int r,g,b;
+
+ xs = xx >> 16;
+ t_pen = ((gfxdata[2*xs] & 0x80) >> 7);
+ if(stv2_current_tilemap.transparency == TRANSPARENCY_NONE) t_pen = 1;
+ b = ((gfxdata[2*xs] & 0x7c) >> 2);
+ g = ((gfxdata[2*xs] & 0x03) << 3) | ((gfxdata[2*xs+1] & 0xe0) >> 5);
+ r = ((gfxdata[2*xs+1] & 0x1f));
+ if(stv2_current_tilemap.fade_control & 1)
+ stv_vdp2_compute_color_offset_RGB555(&r,&g,&b,stv2_current_tilemap.fade_control & 2);
+ tw = stv_vdp2_window_process(xcnt,ycnt);
+ if(tw == 0)
+ {
+ if(t_pen)
+ {
+ if ( stv2_current_tilemap.colour_calculation_enabled == 1 )
+ destline[xcnt] = alpha_blend16( destline[xcnt], b | g << 5 | r << 10 );
+ else
+ destline[xcnt] = b | g << 5 | r << 10;
+ }
+ }
+
+ if ( (gfxdata + 2*xs) >= gfxdatahigh ) gfxdata = gfxdatalow;
+ }
+ gfxdata += xlinesize;
+ if ( gfxdata >= gfxdatahigh ) gfxdata = gfxdatalow + (gfxdata - gfxdatahigh);
+ }
+ }
+ break;
+ /*
+ M L
+ S S
+ B B
+ --------BBBBBBBBGGGGGGGGRRRRRRRR
+ */
+ case 4:
+ //popmessage("BITMAP type 4 enabled");
+ for (ycnt = 0; ycnt <ysize;ycnt++)
+ {
+ destline = BITMAP_ADDR16(bitmap, ycnt, 0);
+
+ for (xcnt = 0; xcnt <xsize;xcnt++)
+ {
+ int r,g,b;
+
+ t_pen = ((gfxdata[0] & 0x80) >> 7);
+ if(stv2_current_tilemap.transparency == TRANSPARENCY_NONE) t_pen = 1;
+
+ /*TODO: 8bpp*/
+ b = (gfxdata[1] & 0xf8) >> 3;
+ g = (gfxdata[2] & 0xf8) >> 3;
+ r = (gfxdata[3] & 0xf8) >> 3;
+
+ tw = stv_vdp2_window_process(xcnt,ycnt);
+ if(tw == 0)
+ {
+ if(t_pen)
+ destline[xcnt] = b | g << 5 | r << 10;
+ }
+ gfxdata+=4;
+ /*This is not used for this type,see shanhigw Sunsoft logo*/
+ //if ( gfxdata >= gfxdatahigh ) gfxdata = gfxdatalow;
+ }
+ }
+ break;
+ }
+}
+
+ /*---------------------------------------------------------------------------
+ | Plane Size | Pattern Name Data Size | Character Size | Map Bits / Address |
+ ----------------------------------------------------------------------------|
+ | | | 1 H x 1 V | bits 6-0 * 0x02000 |
+ | | 1 word |-------------------------------------|
+ | | | 2 H x 2 V | bits 8-0 * 0x00800 |
+ | 1 H x 1 V ---------------------------------------------------------------|
+ | | | 1 H x 1 V | bits 5-0 * 0x04000 |
+ | | 2 words |-------------------------------------|
+ | | | 2 H x 2 V | bits 7-0 * 0x01000 |
+ -----------------------------------------------------------------------------
+ | | | 1 H x 1 V | bits 6-1 * 0x04000 |
+ | | 1 word |-------------------------------------|
+ | | | 2 H x 2 V | bits 8-1 * 0x01000 |
+ | 2 H x 1 V ---------------------------------------------------------------|
+ | | | 1 H x 1 V | bits 5-1 * 0x08000 |
+ | | 2 words |-------------------------------------|
+ | | | 2 H x 2 V | bits 7-1 * 0x02000 |
+ -----------------------------------------------------------------------------
+ | | | 1 H x 1 V | bits 6-2 * 0x08000 |
+ | | 1 word |-------------------------------------|
+ | | | 2 H x 2 V | bits 8-2 * 0x02000 |
+ | 2 H x 2 V ---------------------------------------------------------------|
+ | | | 1 H x 1 V | bits 5-2 * 0x10000 |
+ | | 2 words |-------------------------------------|
+ | | | 2 H x 2 V | bits 7-2 * 0x04000 |
+ --the-highest-bit-is-ignored-if-vram-is-only-4mbits------------------------*/
+
+
+/*
+4.2 Sega's Cell / Character Pattern / Page / Plane / Map system, aka a rather annoying thing that makes optimizations hard
+ (this is only for the normal tilemaps at the moment, i haven't even thought about the ROZ ones)
+
+Tiles:
+
+Cells are 8x8 gfx stored in video ram, they can be of various colour depths
+
+Character Patterns can be 8x8 or 16x16 (1 hcell x 1 vcell or 2 hcell x 2 vcell)
+ (a 16x16 character pattern is 4 8x8 cells put together)
+
+A page is made up of 64x64 cells, thats 64x64 character patterns in 8x8 mode or 32x32 character patterns in 16x16 mode.
+ 64 * 8 = 512 (0x200)
+ 32 * 16 = 512 (0x200)
+A page is _always_ 512 (0x200) pixels in each direction
+
+in 1 word mode a 32*16 x 32*16 page is 0x0800 bytes
+in 1 word mode a 64*8 x 64*8 page is 0x2000 bytes
+in 2 word mode a 32*16 x 32*16 page is 0x1000 bytes
+in 2 word mode a 64*8 x 64*8 page is 0x4000 bytes
+
+either 1, 2 or 4 pages make each plane depending on the plane size register (per tilemap)
+ therefore each plane is either
+ 64 * 8 * 1 x 64 * 8 * 1 (512 x 512)
+ 64 * 8 * 2 x 64 * 8 * 1 (1024 x 512)
+ 64 * 8 * 2 x 64 * 8 * 2 (1024 x 1024)
+
+ 32 * 16 * 1 x 32 * 16 * 1 (512 x 512)
+ 32 * 16 * 2 x 32 * 16 * 1 (1024 x 512)
+ 32 * 16 * 2 x 32 * 16 * 2 (1024 x 1024)
+
+map is always enabled?
+ map is a 2x2 arrangement of planes, all 4 of the planes can be the same.
+
+*/
+
+static void stv_vdp2_get_map_page( int x, int y, int *_map, int *_page )
+{
+ int page = 0;
+ int map = 0;
+
+ if ( stv2_current_tilemap.map_count == 4 )
+ {
+ if ( stv2_current_tilemap.tile_size == 0 )
+ {
+ if ( stv2_current_tilemap.plane_size & 1 )
+ {
+ page = ((x >> 6) & 1);
+ map = (x >> 7) & 1;
+ }
+ else
+ {
+ map = (x >> 6) & 1;
+ }
+
+ if ( stv2_current_tilemap.plane_size & 2 )
+ {
+ page |= ((y >> (6-1)) & 2);
+ map |= ((y >> (7-1)) & 2);
+ }
+ else
+ {
+ map |= ((y >> (6-1)) & 2);
+ }
+ }
+ else
+ {
+ if ( stv2_current_tilemap.plane_size & 1 )
+ {
+ page = ((x >> 5) & 1);
+ map = (x >> 6) & 1;
+ }
+ else
+ {
+ map = (x >> 5) & 1;
+ }
+
+ if ( stv2_current_tilemap.plane_size & 2 )
+ {
+ page |= ((y >> (5 - 1)) & 2);
+ map |= ((y >> (6-1)) & 2);
+ }
+ else
+ {
+ map |= ((y >> (5-1)) & 2);
+ }
+ }
+ }
+ else //16
+ {
+ if ( stv2_current_tilemap.tile_size == 0 )
+ {
+ if ( stv2_current_tilemap.plane_size & 1 )
+ {
+ page = ((x >> 6) & 1);
+ map = (x >> 7) & 3;
+ }
+ else
+ {
+ map = (x >> 6) & 3;
+ }
+
+ if ( stv2_current_tilemap.plane_size & 2 )
+ {
+ page |= ((y >> (6-1)) & 2);
+ map |= ((y >> (7-2)) & 12);
+ }
+ else
+ {
+ map |= ((y >> (6-2)) & 12);
+ }
+ }
+ else
+ {
+ if ( stv2_current_tilemap.plane_size & 1 )
+ {
+ page = ((x >> 5) & 1);
+ map = (x >> 6) & 3;
+ }
+ else
+ {
+ map = (x >> 5) & 3;
+ }
+
+ if ( stv2_current_tilemap.plane_size & 2 )
+ {
+ page |= ((y >> (5 - 1)) & 2);
+ map |= ((y >> (6-2)) & 12);
+ }
+ else
+ {
+ map |= ((y >> (5-2)) & 12);
+ }
+ }
+ }
+ *_page = page;
+ *_map = map;
+}
+
+static void stv_vdp2_draw_basic_tilemap(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /* hopefully this is easier to follow than it is efficient .. */
+
+ /* I call character patterns tiles .. even if they represent up to 4 tiles */
+
+ /* Page variables */
+ int pgtiles_x, pgpixels_x;
+ int pgtiles_y, pgpixels_y;
+ int pgsize_bytes, pgsize_dwords;
+
+ /* Plane Variables */
+ int pltiles_x, plpixels_x;
+ int pltiles_y, plpixels_y;
+ int plsize_bytes, plsize_dwords;
+
+ /* Map Variables */
+ int mptiles_x, mppixels_x;
+ int mptiles_y, mppixels_y;
+ int mpsize_bytes, mpsize_dwords;
+
+ /* work Variables */
+ int i, x, y;
+ int base[16];
+
+ int scalex,scaley;
+ int tilesizex, tilesizey;
+ int drawypos, drawxpos;
+
+ int tilecodemin = 0x10000000, tilecodemax = 0;
+
+ if ( stv2_current_tilemap.incx == 0 || stv2_current_tilemap.incy == 0 ) return;
+
+ if ( stv2_current_tilemap.colour_calculation_enabled == 1 )
+ {
+ if ( STV_VDP2_CCMD )
+ {
+ stv2_current_tilemap.transparency = STV_TRANSPARENCY_ADD_BLEND;
+ }
+ else
+ {
+ stv2_current_tilemap.transparency = TRANSPARENCY_ALPHA;
+ }
+ }
+
+ scalex = (INT32)((INT64)S64(0x100000000) / (INT64)stv2_current_tilemap.incx);
+ scaley = (INT32)((INT64)S64(0x100000000) / (INT64)stv2_current_tilemap.incy);
+ tilesizex = scalex * 8;
+ tilesizey = scaley * 8;
+ drawypos = drawxpos = 0;
+
+ /* Calculate the Number of tiles for x / y directions of each page (actually these will be the same */
+ /* (2-stv2_current_tilemap.tile_size) << 5) */
+ pgtiles_x = ((2-stv2_current_tilemap.tile_size) << 5); // 64 (8x8 mode) or 32 (16x16 mode)
+ pgtiles_y = ((2-stv2_current_tilemap.tile_size) << 5); // 64 (8x8 mode) or 32 (16x16 mode)
+
+ /* Calculate the Page Size in BYTES */
+ /* 64 * 64 * (1 * 2) = 0x2000 bytes
+ 32 * 32 * (1 * 2) = 0x0800 bytes
+ 64 * 64 * (2 * 2) = 0x4000 bytes
+ 32 * 32 * (2 * 2) = 0x1000 bytes */
+
+ pgsize_bytes = (pgtiles_x * pgtiles_y) * ((2-stv2_current_tilemap.pattern_data_size)*2);
+
+ /*---------------------------------------------------------------------------
+ | Plane Size | Pattern Name Data Size | Character Size | Map Bits / Address |
+ ----------------------------------------------------------------------------|
+ | | | 1 H x 1 V | bits 6-0 * 0x02000 |
+ | | 1 word |-------------------------------------|
+ | | | 2 H x 2 V | bits 8-0 * 0x00800 |
+ | 1 H x 1 V ---------------------------------------------------------------|
+ | | | 1 H x 1 V | bits 5-0 * 0x04000 |
+ | | 2 words |-------------------------------------|
+ | | | 2 H x 2 V | bits 7-0 * 0x01000 |
+ ---------------------------------------------------------------------------*/
+
+
+ /* Page Dimensions are always 0x200 pixes (512x512) */
+ pgpixels_x = 0x200;
+ pgpixels_y = 0x200;
+
+ /* Work out the Plane Size in tiles and Plane Dimensions (pixels) */
+ switch (stv2_current_tilemap.plane_size & 3)
+ {
+ case 0: // 1 page * 1 page
+ pltiles_x = pgtiles_x;
+ plpixels_x = pgpixels_x;
+ pltiles_y = pgtiles_y;
+ plpixels_y = pgpixels_y;
+ break;
+
+ case 1: // 2 pages * 1 page
+ pltiles_x = pgtiles_x * 2;
+ plpixels_x = pgpixels_x * 2;
+ pltiles_y = pgtiles_y;
+ plpixels_y = pgpixels_y;
+ break;
+
+ case 3: // 2 pages * 2 pages
+ pltiles_x = pgtiles_x * 2;
+ plpixels_x = pgpixels_x * 2;
+ pltiles_y = pgtiles_y * 2;
+ plpixels_y = pgpixels_y * 2;
+ break;
+
+ default:
+ // illegal
+ pltiles_x = pgtiles_x;
+ plpixels_x = pgpixels_x;
+ pltiles_y = pgtiles_y * 2;
+ plpixels_y = pgpixels_y * 2;
+ break;
+ }
+
+ /* Plane Size in BYTES */
+ /* still the same as before
+ (64 * 1) * (64 * 1) * (1 * 2) = 0x02000 bytes
+ (32 * 1) * (32 * 1) * (1 * 2) = 0x00800 bytes
+ (64 * 1) * (64 * 1) * (2 * 2) = 0x04000 bytes
+ (32 * 1) * (32 * 1) * (2 * 2) = 0x01000 bytes
+ changed
+ (64 * 2) * (64 * 1) * (1 * 2) = 0x04000 bytes
+ (32 * 2) * (32 * 1) * (1 * 2) = 0x01000 bytes
+ (64 * 2) * (64 * 1) * (2 * 2) = 0x08000 bytes
+ (32 * 2) * (32 * 1) * (2 * 2) = 0x02000 bytes
+ changed
+ (64 * 2) * (64 * 1) * (1 * 2) = 0x08000 bytes
+ (32 * 2) * (32 * 1) * (1 * 2) = 0x02000 bytes
+ (64 * 2) * (64 * 1) * (2 * 2) = 0x10000 bytes
+ (32 * 2) * (32 * 1) * (2 * 2) = 0x04000 bytes
+ */
+
+ plsize_bytes = (pltiles_x * pltiles_y) * ((2-stv2_current_tilemap.pattern_data_size)*2);
+
+ /*---------------------------------------------------------------------------
+ | Plane Size | Pattern Name Data Size | Character Size | Map Bits / Address |
+ -----------------------------------------------------------------------------
+ | 1 H x 1 V see above, nothing has changed |
+ -----------------------------------------------------------------------------
+ | | | 1 H x 1 V | bits 6-1 * 0x04000 |
+ | | 1 word |-------------------------------------|
+ | | | 2 H x 2 V | bits 8-1 * 0x01000 |
+ | 2 H x 1 V ---------------------------------------------------------------|
+ | | | 1 H x 1 V | bits 5-1 * 0x08000 |
+ | | 2 words |-------------------------------------|
+ | | | 2 H x 2 V | bits 7-1 * 0x02000 |
+ -----------------------------------------------------------------------------
+ | | | 1 H x 1 V | bits 6-2 * 0x08000 |
+ | | 1 word |-------------------------------------|
+ | | | 2 H x 2 V | bits 8-2 * 0x02000 |
+ | 2 H x 2 V ---------------------------------------------------------------|
+ | | | 1 H x 1 V | bits 5-2 * 0x10000 |
+ | | 2 words |-------------------------------------|
+ | | | 2 H x 2 V | bits 7-2 * 0x04000 |
+ --the-highest-bit-is-ignored-if-vram-is-only-4mbits------------------------*/
+
+
+ /* Work out the Map Sizes in tiles, Map Dimensions */
+ /* maps are always enabled? */
+ if ( stv2_current_tilemap.map_count == 4 )
+ {
+ mptiles_x = pltiles_x * 2;
+ mptiles_y = pltiles_y * 2;
+ mppixels_x = plpixels_x * 2;
+ mppixels_y = plpixels_y * 2;
+ }
+ else
+ {
+ mptiles_x = pltiles_x * 4;
+ mptiles_y = pltiles_y * 4;
+ mppixels_x = plpixels_x * 4;
+ mppixels_y = plpixels_y * 4;
+ }
+
+ /* Map Size in BYTES */
+ mpsize_bytes = (mptiles_x * mptiles_y) * ((2-stv2_current_tilemap.pattern_data_size)*2);
+
+
+ /*-----------------------------------------------------------------------------------------------------------
+ | | | 1 H x 1 V | bits 6-1 (upper mask 0x07f) (0x1ff >> 2) * 0x04000 |
+ | | 1 word |---------------------------------------------------------------------|
+ | | | 2 H x 2 V | bits 8-1 (upper mask 0x1ff) (0x1ff >> 0) * 0x01000 |
+ | 2 H x 1 V -----------------------------------------------------------------------------------------------|
+ | | | 1 H x 1 V | bits 5-1 (upper mask 0x03f) (0x1ff >> 3) * 0x08000 |
+ | | 2 words |---------------------------------------------------------------------|
+ | | | 2 H x 2 V | bits 7-1 (upper mask 0x0ff) (0x1ff >> 1) * 0x02000 |
+ -------------------------------------------------------------------------------------------------------------
+ lower mask = ~stv2_current_tilemap.plane_size
+ -----------------------------------------------------------------------------------------------------------*/
+
+ /* Precalculate bases from MAP registers */
+ for (i = 0; i < stv2_current_tilemap.map_count; i++)
+ {
+ static const int shifttable[4] = {0,1,2,2};
+
+ int uppermask, uppermaskshift;
+
+ uppermaskshift = (1-stv2_current_tilemap.pattern_data_size) | ((1-stv2_current_tilemap.tile_size)<<1);
+ uppermask = 0x1ff >> uppermaskshift;
+
+ base[i] = ((stv2_current_tilemap.map_offset[i] & uppermask) >> shifttable[stv2_current_tilemap.plane_size]) * plsize_bytes;
+
+ base[i] &= 0x7ffff; /* shienryu needs this for the text layer, is there a problem elsewhere or is it just right without the ram cart */
+
+ base[i] = base[i] / 4; // convert bytes to DWORDS
+ }
+
+ /* other bits */
+ //stv2_current_tilemap.trans_enabled = stv2_current_tilemap.trans_enabled ? TRANSPARENCY_NONE : TRANSPARENCY_PEN;
+ stv2_current_tilemap.scrollx &= mppixels_x-1;
+ stv2_current_tilemap.scrolly &= mppixels_y-1;
+
+ pgsize_dwords = pgsize_bytes /4;
+ plsize_dwords = plsize_bytes /4;
+ mpsize_dwords = mpsize_bytes /4;
+
+// if (stv2_current_tilemap.layer_name==3) popmessage ("well this is a bit %08x", stv2_current_tilemap.map_offset[0]);
+// if (stv2_current_tilemap.layer_name==3) popmessage ("well this is a bit %08x %08x %08x %08x", stv2_current_tilemap.plane_size, pgtiles_x, pltiles_x, mptiles_x);
+
+ if (!stv2_current_tilemap.enabled) return; // stop right now if its disabled ...
+
+ /* most things we need (or don't need) to work out are now worked out */
+
+ for (y = 0; y<mptiles_y; y++) {
+ int ypageoffs;
+ int page, map, newbase, offs, data;
+ int tilecode, flipyx, pal, gfx = 0;
+
+ map = 0 ; page = 0 ;
+ if ( y == 0 )
+ {
+ int drawyposinc = tilesizey*(stv2_current_tilemap.tile_size ? 2 : 1);
+ drawypos = -(stv2_current_tilemap.scrolly*scaley);
+ while( ((drawypos + drawyposinc) >> 16) < cliprect->min_y )
+ {
+ drawypos += drawyposinc;
+ y++;
+ }
+ mptiles_y += y;
+ }
+ else
+ {
+ drawypos += tilesizey*(stv2_current_tilemap.tile_size ? 2 : 1);
+ }
+ if ((drawypos >> 16) > cliprect->max_y) break;
+
+ ypageoffs = y & (pgtiles_y-1);
+
+ for (x = 0; x<mptiles_x; x++) {
+ int xpageoffs;
+
+ if ( x == 0 )
+ {
+ int drawxposinc = tilesizex*(stv2_current_tilemap.tile_size ? 2 : 1);
+ drawxpos = -(stv2_current_tilemap.scrollx*scalex);
+ while( ((drawxpos + drawxposinc) >> 16) < cliprect->min_x )
+ {
+ drawxpos += drawxposinc;
+ x++;
+ }
+ mptiles_x += x;
+ }
+ else
+ {
+ drawxpos+=tilesizex*(stv2_current_tilemap.tile_size ? 2 : 1);
+ }
+ if ( (drawxpos >> 16) > cliprect->max_x ) break;
+
+ xpageoffs = x & (pgtiles_x-1);
+
+ stv_vdp2_get_map_page(x,y,&map,&page);
+
+ newbase = base[map] + page * pgsize_dwords;
+ offs = (ypageoffs * pgtiles_x) + xpageoffs;
+
+/* GET THE TILE INFO ... */
+ /* 1 word per tile mode with supplement bits */
+ if (stv2_current_tilemap.pattern_data_size ==1)
+ {
+
+ data = stv_vdp2_vram[newbase + offs/2];
+ data = (offs&1) ? (data & 0x0000ffff) : ((data & 0xffff0000) >> 16);
+
+ /* Supplement Mode 12 bits, no flip */
+ if (stv2_current_tilemap.character_number_supplement == 1)
+ {
+/* no flip */ flipyx = 0;
+/* 8x8 */ if (stv2_current_tilemap.tile_size==0) tilecode = (data & 0x0fff) + ( (stv2_current_tilemap.supplementary_character_bits&0x1c) << 10);
+/* 16x16 */ else tilecode = ((data & 0x0fff) << 2) + (stv2_current_tilemap.supplementary_character_bits&0x03) + ((stv2_current_tilemap.supplementary_character_bits&0x10) << 10);
+ }
+ /* Supplement Mode 10 bits, with flip */
+ else
+ {
+/* flip bits */ flipyx = (data & 0x0c00) >> 10;
+/* 8x8 */ if (stv2_current_tilemap.tile_size==0) tilecode = (data & 0x03ff) + ( (stv2_current_tilemap.supplementary_character_bits) << 10);
+/* 16x16 */ else tilecode = ((data & 0x03ff) <<2) + (stv2_current_tilemap.supplementary_character_bits&0x03) + ((stv2_current_tilemap.supplementary_character_bits&0x1c) << 10);
+ }
+
+/*>16cols*/ if (stv2_current_tilemap.colour_depth != 0) pal = ((data & 0x7000)>>8);
+/*16 cols*/ else pal = ((data & 0xf000)>>12) +( (stv2_current_tilemap.supplementary_palette_bits) << 4);
+
+ }
+ /* 2 words per tile, no supplement bits */
+ else
+ {
+
+ data = stv_vdp2_vram[newbase + offs];
+ tilecode = (data & 0x00007fff);
+ pal = (data & 0x007f0000)>>16;
+ // specialc = (data & 0x10000000)>>28;
+ flipyx = (data & 0xc0000000)>>30;
+ }
+/* WE'VE GOT THE TILE INFO ... */
+
+ if ( tilecode < tilecodemin ) tilecodemin = tilecode;
+ if ( tilecode > tilecodemax ) tilecodemax = tilecode;
+
+/* DECODE ANY TILES WE NEED TO DECODE */
+
+ pal += stv2_current_tilemap.colour_ram_address_offset<< 4; // bios uses this ..
+
+ /*Enable fading bit*/
+ if(stv2_current_tilemap.fade_control & 1)
+ {
+ /*Select fading bit*/
+ pal += ((stv2_current_tilemap.fade_control & 2) ? (0x100) : (0x80));
+ }
+
+ if (stv2_current_tilemap.colour_depth == 1)
+ {
+ UINT8 gfx_mem_offset = (tilecode & 0x1) ? 0x20 : 0x0;
+
+ tilecode = tilecode >> 1;
+ gfx = 2;
+ pal = pal >>4;
+
+ /* do a bit of tile decoding */
+ tilecode &=0x3fff;
+ if (stv2_current_tilemap.tile_size==1)
+ { /* we're treating 16x16 tiles as 4 8x8's atm */
+ if (stv_vdp2_vram_dirty_8x8x8[tilecode] == 1) { stv_vdp2_vram_dirty_8x8x8[tilecode] = 0; decodechar(machine->gfx[2], tilecode, stv_vdp2_gfx_decode + gfx_mem_offset, machine->drv->gfxdecodeinfo[2].gfxlayout); };
+ if (stv_vdp2_vram_dirty_8x8x8[tilecode+1] == 1) { stv_vdp2_vram_dirty_8x8x8[tilecode+1] = 0; decodechar(machine->gfx[2], tilecode+1, stv_vdp2_gfx_decode + gfx_mem_offset, machine->drv->gfxdecodeinfo[2].gfxlayout); };
+ if (stv_vdp2_vram_dirty_8x8x8[tilecode+2] == 1) { stv_vdp2_vram_dirty_8x8x8[tilecode+2] = 0; decodechar(machine->gfx[2], tilecode+2, stv_vdp2_gfx_decode + gfx_mem_offset, machine->drv->gfxdecodeinfo[2].gfxlayout); };
+ if (stv_vdp2_vram_dirty_8x8x8[tilecode+3] == 1) { stv_vdp2_vram_dirty_8x8x8[tilecode+3] = 0; decodechar(machine->gfx[2], tilecode+3, stv_vdp2_gfx_decode + gfx_mem_offset, machine->drv->gfxdecodeinfo[2].gfxlayout); };
+ }
+ else
+ {
+ if (stv_vdp2_vram_dirty_8x8x8[tilecode] == 1) { stv_vdp2_vram_dirty_8x8x8[tilecode] = 0; decodechar(machine->gfx[2], tilecode, stv_vdp2_gfx_decode + gfx_mem_offset, machine->drv->gfxdecodeinfo[2].gfxlayout); };
+ }
+
+ }
+ else if (stv2_current_tilemap.colour_depth == 0)
+ {
+ gfx = 0;
+
+ /* do a bit of tile decoding */
+ tilecode &=0x7fff;
+ if (stv2_current_tilemap.tile_size==1)
+ { /* we're treating 16x16 tiles as 4 8x8's atm */
+ if (stv_vdp2_vram_dirty_8x8x4[tilecode] == 1) { stv_vdp2_vram_dirty_8x8x4[tilecode] = 0; decodechar(machine->gfx[0], tilecode, stv_vdp2_gfx_decode, machine->drv->gfxdecodeinfo[0].gfxlayout); };
+ if (stv_vdp2_vram_dirty_8x8x4[tilecode+1] == 1) { stv_vdp2_vram_dirty_8x8x4[tilecode+1] = 0; decodechar(machine->gfx[0], tilecode+1, stv_vdp2_gfx_decode, machine->drv->gfxdecodeinfo[0].gfxlayout); };
+ if (stv_vdp2_vram_dirty_8x8x4[tilecode+2] == 1) { stv_vdp2_vram_dirty_8x8x4[tilecode+2] = 0; decodechar(machine->gfx[0], tilecode+2, stv_vdp2_gfx_decode, machine->drv->gfxdecodeinfo[0].gfxlayout); };
+ if (stv_vdp2_vram_dirty_8x8x4[tilecode+3] == 1) { stv_vdp2_vram_dirty_8x8x4[tilecode+3] = 0; decodechar(machine->gfx[0], tilecode+3, stv_vdp2_gfx_decode, machine->drv->gfxdecodeinfo[0].gfxlayout); };
+ }
+ else
+ {
+ if (stv_vdp2_vram_dirty_8x8x4[tilecode] == 1) { stv_vdp2_vram_dirty_8x8x4[tilecode] = 0; decodechar(machine->gfx[0], tilecode, stv_vdp2_gfx_decode, machine->drv->gfxdecodeinfo[0].gfxlayout); };
+ }
+ }
+/* TILES ARE NOW DECODED */
+
+/* DRAW! */
+ if(stv2_current_tilemap.incx != 0x10000 ||
+ stv2_current_tilemap.incy != 0x10000 ||
+ stv2_current_tilemap.transparency == STV_TRANSPARENCY_ADD_BLEND )
+ {
+#define SCR_TILESIZE_X (((drawxpos + tilesizex) >> 16) - (drawxpos >> 16))
+#define SCR_TILESIZE_X1(startx) (((drawxpos + (startx) + tilesizex) >> 16) - ((drawxpos + (startx))>>16))
+#define SCR_TILESIZE_Y (((drawypos + tilesizey) >> 16) - (drawypos >> 16))
+#define SCR_TILESIZE_Y1(starty) (((drawypos + (starty) + tilesizey) >> 16) - ((drawypos + (starty))>>16))
+ if (stv2_current_tilemap.tile_size==1)
+ {
+ /* normal */
+ stv_vdp2_drawgfxzoom(bitmap,machine->gfx[gfx],tilecode+0+(flipyx&1)+(flipyx&2),pal,flipyx&1,flipyx&2,drawxpos >> 16, drawypos >> 16,cliprect,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X, SCR_TILESIZE_Y);
+ stv_vdp2_drawgfxzoom(bitmap,machine->gfx[gfx],tilecode+1-(flipyx&1)+(flipyx&2),pal,flipyx&1,flipyx&2,(drawxpos+tilesizex) >> 16,drawypos >> 16,cliprect,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X1(tilesizex), SCR_TILESIZE_Y);
+ stv_vdp2_drawgfxzoom(bitmap,machine->gfx[gfx],tilecode+2+(flipyx&1)-(flipyx&2),pal,flipyx&1,flipyx&2,drawxpos >> 16,(drawypos+tilesizey) >> 16,cliprect,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X, SCR_TILESIZE_Y1(tilesizey));
+ stv_vdp2_drawgfxzoom(bitmap,machine->gfx[gfx],tilecode+3-(flipyx&1)-(flipyx&2),pal,flipyx&1,flipyx&2,(drawxpos+tilesizex)>> 16,(drawypos+tilesizey) >> 16,cliprect,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X1(tilesizex), SCR_TILESIZE_Y1(tilesizey));
+
+ }
+ else
+ {
+ stv_vdp2_drawgfxzoom(bitmap,machine->gfx[gfx],tilecode,pal,flipyx&1,flipyx&2, drawxpos >> 16, drawypos >> 16,cliprect,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X,SCR_TILESIZE_Y);
+ }
+ }
+ else
+ {
+ int olddrawxpos, olddrawypos;
+ olddrawxpos = drawxpos; drawxpos >>= 16;
+ olddrawypos = drawypos; drawypos >>= 16;
+ if (stv2_current_tilemap.tile_size==1)
+ {
+ if ( stv2_current_tilemap.colour_depth == 3 )
+ {
+ /* normal */
+ stv_vdp2_drawgfx_rgb555(bitmap,tilecode+(0+(flipyx&1)+(flipyx&2))*4,flipyx&1,flipyx&2,drawxpos, drawypos,cliprect,stv2_current_tilemap.transparency);
+ stv_vdp2_drawgfx_rgb555(bitmap,tilecode+(1-(flipyx&1)+(flipyx&2))*4,flipyx&1,flipyx&2,drawxpos+8,drawypos,cliprect,stv2_current_tilemap.transparency);
+ stv_vdp2_drawgfx_rgb555(bitmap,tilecode+(2+(flipyx&1)-(flipyx&2))*4,flipyx&1,flipyx&2,drawxpos,drawypos+8,cliprect,stv2_current_tilemap.transparency);
+ stv_vdp2_drawgfx_rgb555(bitmap,tilecode+(3-(flipyx&1)-(flipyx&2))*4,flipyx&1,flipyx&2,drawxpos+8,drawypos+8,cliprect,stv2_current_tilemap.transparency);
+
+ }
+ else
+ {
+ /* normal */
+ drawgfx(bitmap,machine->gfx[gfx],tilecode+0+(flipyx&1)+(flipyx&2),pal,flipyx&1,flipyx&2,drawxpos, drawypos,cliprect,stv2_current_tilemap.transparency,0);
+ drawgfx(bitmap,machine->gfx[gfx],tilecode+1-(flipyx&1)+(flipyx&2),pal,flipyx&1,flipyx&2,drawxpos+8,drawypos,cliprect,stv2_current_tilemap.transparency,0);
+ drawgfx(bitmap,machine->gfx[gfx],tilecode+2+(flipyx&1)-(flipyx&2),pal,flipyx&1,flipyx&2,drawxpos,drawypos+8,cliprect,stv2_current_tilemap.transparency,0);
+ drawgfx(bitmap,machine->gfx[gfx],tilecode+3-(flipyx&1)-(flipyx&2),pal,flipyx&1,flipyx&2,drawxpos+8,drawypos+8,cliprect,stv2_current_tilemap.transparency,0);
+
+ }
+ }
+ else
+ {
+ if ( stv2_current_tilemap.colour_depth == 3 )
+ {
+ stv_vdp2_drawgfx_rgb555(bitmap,tilecode,flipyx&1,flipyx&2,drawxpos,drawypos,cliprect,stv2_current_tilemap.transparency);
+ }
+ else
+ {
+ drawgfx(bitmap,machine->gfx[gfx],tilecode,pal,flipyx&1,flipyx&2, drawxpos, drawypos,cliprect,stv2_current_tilemap.transparency,0);
+ }
+ }
+ drawxpos = olddrawxpos;
+ drawypos = olddrawypos;
+ }
+/* DRAWN?! */
+
+ }
+ }
+ if ( stv2_current_tilemap.layer_name & 0x80 )
+ {
+ static const int shifttable[4] = {0,1,2,2};
+ int uppermask, uppermaskshift;
+ int mapsize;
+ uppermaskshift = (1-stv2_current_tilemap.pattern_data_size) | ((1-stv2_current_tilemap.tile_size)<<1);
+ uppermask = 0x1ff >> uppermaskshift;
+
+ if ( LOG_VDP2 )
+ {
+ logerror( "Layer RBG%d, size %d x %d\n", stv2_current_tilemap.layer_name & 0x7f, cliprect->max_x + 1, cliprect->max_y + 1 );
+ logerror( "Tiles: min %08X, max %08X\n", tilecodemin, tilecodemax );
+ logerror( "MAP size in dwords %08X\n", mpsize_dwords );
+ for (i = 0; i < stv2_current_tilemap.map_count; i++)
+ {
+ logerror( "Map register %d: base %08X\n", stv2_current_tilemap.map_offset[i], base[i] );
+ }
+ }
+
+ // store map information
+ stv_vdp2_layer_data_placement.map_offset_min = 0x7fffffff;
+ stv_vdp2_layer_data_placement.map_offset_max = 0x00000000;
+ for (i = 0; i < stv2_current_tilemap.map_count; i++)
+ {
+ if ( base[i] < stv_vdp2_layer_data_placement.map_offset_min )
+ stv_vdp2_layer_data_placement.map_offset_min = base[i];
+ if ( base[i] > stv_vdp2_layer_data_placement.map_offset_max )
+ stv_vdp2_layer_data_placement.map_offset_max = base[i];
+ }
+
+
+ mapsize = ((1 & uppermask) >> shifttable[stv2_current_tilemap.plane_size]) * plsize_bytes -
+ ((0 & uppermask) >> shifttable[stv2_current_tilemap.plane_size]) * plsize_bytes;
+ mapsize /= 4;
+
+ stv_vdp2_layer_data_placement.map_offset_max += mapsize;
+
+ stv_vdp2_layer_data_placement.tile_offset_min = tilecodemin * 0x20 / 4;
+ stv_vdp2_layer_data_placement.tile_offset_max = (tilecodemax + 1) * 0x20 / 4;
+ }
+
+}
+
+#define STV_VDP2_READ_VERTICAL_LINESCROLL( _val, _address ) \
+ { \
+ _val = stv_vdp2_vram[ _address ]; \
+ _val &= 0x07ffff00; \
+ if ( _val & 0x04000000 ) _val |= 0xf8000000; \
+ }
+
+
+static void stv_vdp2_check_tilemap_with_linescroll(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ rectangle mycliprect;
+ int cur_line = cliprect->min_y;
+ int address;
+ int active_functions = 0;
+ INT32 scroll_values[3], prev_scroll_values[3];
+ int i;
+ int scroll_values_equal;
+ int lines;
+ INT16 scrollx, scrolly;
+ INT32 incx;
+ int linescroll_enable, vertical_linescroll_enable, linezoom_enable;
+ int vertical_linescroll_index = -1;
+
+ // read original scroll values
+ scrollx = stv2_current_tilemap.scrollx;
+ scrolly = stv2_current_tilemap.scrolly;
+ incx = stv2_current_tilemap.incx;
+
+ // prepare linescroll flags
+ linescroll_enable = stv2_current_tilemap.linescroll_enable;
+ stv2_current_tilemap.linescroll_enable = 0;
+ vertical_linescroll_enable = stv2_current_tilemap.vertical_linescroll_enable;
+ stv2_current_tilemap.vertical_linescroll_enable = 0;
+ linezoom_enable = stv2_current_tilemap.linezoom_enable;
+ stv2_current_tilemap.linezoom_enable = 0;
+
+ // prepare working clipping rectangle
+ memcpy( &mycliprect, cliprect, sizeof(rectangle) );
+
+ // calculate the number of active functions
+ if ( linescroll_enable ) active_functions++;
+ if ( vertical_linescroll_enable )
+ {
+ vertical_linescroll_index = active_functions;
+ active_functions++;
+ }
+ if ( linezoom_enable ) active_functions++;
+
+ // address of data table
+ address = stv2_current_tilemap.linescroll_table_address + active_functions*4*cliprect->min_y;
+
+ // get the first scroll values
+ for ( i = 0; i < active_functions; i++ )
+ {
+ if ( i == vertical_linescroll_index )
+ {
+ STV_VDP2_READ_VERTICAL_LINESCROLL( prev_scroll_values[i], (address / 4) + i );
+ prev_scroll_values[i] -= (cur_line * stv2_current_tilemap.incy);
+ }
+ else
+ {
+ prev_scroll_values[i] = stv_vdp2_vram[ (address / 4) + i ];
+ }
+ }
+
+ while( cur_line <= cliprect->max_y )
+ {
+ lines = 0;
+ do
+ {
+ // update address
+ address += active_functions*4;
+
+ // update lines count
+ lines += stv2_current_tilemap.linescroll_interval;
+
+ // get scroll values
+ for ( i = 0; i < active_functions; i++ )
+ {
+ if ( i == vertical_linescroll_index )
+ {
+ STV_VDP2_READ_VERTICAL_LINESCROLL( scroll_values[i], (address/4) + i );
+ scroll_values[i] -= (cur_line + lines) * stv2_current_tilemap.incy;
+ }
+ else
+ {
+ scroll_values[i] = stv_vdp2_vram[ (address / 4) + i ];
+ }
+ }
+
+ // compare scroll values
+ scroll_values_equal = 1;
+ for ( i = 0; i < active_functions; i++ )
+ {
+ scroll_values_equal &= (scroll_values[i] == prev_scroll_values[i]);
+ }
+ } while( scroll_values_equal && ((cur_line + lines) <= cliprect->max_y) );
+
+ // determined how many lines can be drawn
+ // prepare clipping rectangle
+ mycliprect.min_y = cur_line;
+ mycliprect.max_y = cur_line + lines - 1;
+
+ // prepare scroll values
+ i = 0;
+ // linescroll
+ if ( linescroll_enable )
+ {
+ prev_scroll_values[i] &= 0x07ffff00;
+ if ( prev_scroll_values[i] & 0x04000000 ) prev_scroll_values[i] |= 0xf8000000;
+ stv2_current_tilemap.scrollx = scrollx + (prev_scroll_values[i] >> 16);
+ i++;
+ }
+ // vertical line scroll
+ if ( vertical_linescroll_enable )
+ {
+ stv2_current_tilemap.scrolly = scrolly + (prev_scroll_values[i] >> 16);
+ i++;
+ }
+
+ // linezooom
+ if ( linezoom_enable )
+ {
+ prev_scroll_values[i] &= 0x0007ff00;
+ if ( prev_scroll_values[i] & 0x00040000 ) prev_scroll_values[i] |= 0xfff80000;
+ stv2_current_tilemap.incx = prev_scroll_values[i];
+ i++;
+ }
+
+ if ( LOG_VDP2 ) logerror( "Linescroll: y < %d, %d >, scrollx = %d, scrolly = %d, incx = %f\n", mycliprect.min_y, mycliprect.max_y, stv2_current_tilemap.scrollx, stv2_current_tilemap.scrolly, (float)stv2_current_tilemap.incx/65536.0 );
+ // render current tilemap portion
+ stv_vdp2_check_tilemap(machine, bitmap, &mycliprect );
+
+ // update parameters for next iteration
+ memcpy( prev_scroll_values, scroll_values, sizeof(scroll_values));
+ cur_line += lines;
+ }
+}
+
+static void stv_vdp2_check_tilemap(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /* the idea is here we check the tilemap capabilities / whats enabled and call an appropriate tilemap drawing routine, or
+ at the very list throw up a few errors if the tilemaps want to do something we don't support yet */
+
+ int window_applied = 0;
+ rectangle mycliprect;
+ mycliprect.min_x = cliprect->min_x;
+ mycliprect.max_x = cliprect->max_x;
+ mycliprect.min_y = cliprect->min_y;
+ mycliprect.max_y = cliprect->max_y;
+
+ if ( stv2_current_tilemap.linescroll_enable ||
+ stv2_current_tilemap.vertical_linescroll_enable ||
+ stv2_current_tilemap.linezoom_enable )
+ {
+ stv_vdp2_check_tilemap_with_linescroll(machine, bitmap, cliprect);
+ return;
+ }
+
+ window_applied = stv_vdp2_apply_window_on_layer(&mycliprect);
+
+ if (stv2_current_tilemap.bitmap_enable) // this layer is a bitmap
+ {
+ if ( window_applied )
+ stv2_current_tilemap.window_control = 0;
+ stv_vdp2_draw_basic_bitmap(machine, bitmap, &mycliprect);
+ }
+ else
+ {
+ stv_vdp2_draw_basic_tilemap(machine, bitmap, &mycliprect);
+
+ if((stv2_current_tilemap.window_control & 6) != 0 && VDP2_ERR(1))
+ {
+ VDP2_CHK(1);
+ mame_printf_debug("Window control enabled on a tilemap plane = %02x\n",stv2_current_tilemap.window_control);
+ }
+ }
+
+ if((STV_VDP2_MZCTL & 0x1f) != 0 && VDP2_ERR(2))
+ {
+ VDP2_CHK(2);
+ mame_printf_debug("Mosaic control enabled = %04x\n",STV_VDP2_MZCTL);
+ }
+}
+
+static void stv_vdp2_copy_roz_bitmap(mame_bitmap *bitmap,
+ mame_bitmap *roz_bitmap,
+ const rectangle *cliprect,
+ int iRP,
+ int planesizex,
+ int planesizey,
+ int planerenderedsizex,
+ int planerenderedsizey)
+{
+ INT32 xsp, ysp, xp, yp, dx, dy, x, y, xs, ys, dxs, dys;
+ INT32 vcnt, hcnt;
+ INT32 kx, ky;
+ INT8 use_coeff_table, coeff_table_mode, coeff_table_size, coeff_table_shift;
+ INT8 screen_over_process;
+ UINT8 vcnt_shift, hcnt_shift;
+ UINT8 coeff_msb;
+ UINT32 *coeff_table_base, coeff_table_offset;
+ INT32 coeff_table_val;
+ UINT32 address;
+ UINT16 *line;
+ UINT16 pix;
+ UINT32 coeff_line_color_screen_data;
+ INT32 clipxmask = 0, clipymask = 0;
+
+
+ if((STV_VDP2_LSMD & 3) == 3)
+ {
+ vcnt_shift = 1;
+ }
+ else
+ {
+ vcnt_shift = 0;
+ }
+
+ switch( STV_VDP2_HRES & 7 )
+ {
+ case 2: /*640*/
+ case 3: /*704*/
+ case 6:
+ case 7:
+ hcnt_shift = 1;
+ break;
+ default:
+ hcnt_shift = 0;
+ break;
+ }
+
+ planesizex--;
+ planesizey--;
+ planerenderedsizex--;
+ planerenderedsizey--;
+
+ kx = RP.kx;
+ ky = RP.ky;
+
+ use_coeff_table = coeff_table_mode = coeff_table_size = coeff_table_shift = 0;
+ coeff_table_offset = 0;
+ coeff_table_val = 0;
+ coeff_table_base = NULL;
+
+ if ( LOG_ROZ == 1 ) logerror( "Rendering RBG with parameter %s\n", iRP == 1 ? "A" : "B" );
+ if ( LOG_ROZ == 1 ) logerror( "RPMD (parameter mode) = %x\n", STV_VDP2_RPMD );
+ if ( LOG_ROZ == 1 ) logerror( "RPRCTL (parameter read control) = %04x\n", STV_VDP2_RPRCTL );
+ if ( LOG_ROZ == 1 ) logerror( "KTCTL (coefficient table control) = %04x\n", STV_VDP2_KTCTL );
+ if ( LOG_ROZ == 1 ) logerror( "KTAOF (coefficient table address offset) = %04x\n", STV_VDP2_KTAOF );
+ if ( LOG_ROZ == 1 ) logerror( "RAOVR (screen-over process) = %x\n", STV_VDP2_RAOVR );
+ if ( iRP == 1 )
+ {
+ use_coeff_table = STV_VDP2_RAKTE;
+ if ( use_coeff_table == 1 )
+ {
+ coeff_table_mode = STV_VDP2_RAKMD;
+ coeff_table_size = STV_VDP2_RAKDBS;
+ coeff_table_offset = STV_VDP2_RAKTAOS;
+ }
+ screen_over_process = STV_VDP2_RAOVR;
+ }
+ else
+ {
+ use_coeff_table = STV_VDP2_RBKTE;
+ if ( use_coeff_table == 1 )
+ {
+ coeff_table_mode = STV_VDP2_RBKMD;
+ coeff_table_size = STV_VDP2_RBKDBS;
+ coeff_table_offset = STV_VDP2_RBKTAOS;
+ }
+ screen_over_process = STV_VDP2_RBOVR;
+ }
+ if ( use_coeff_table )
+ {
+ if ( STV_VDP2_CRKTE == 0 )
+ {
+ coeff_table_base = stv_vdp2_vram;
+ }
+ else
+ {
+ coeff_table_base = stv_vdp2_cram;
+ }
+ if ( coeff_table_size == 0 )
+ {
+ coeff_table_offset = (coeff_table_offset & 0x0003) * 0x40000;
+ coeff_table_shift = 2;
+ }
+ else
+ {
+ coeff_table_offset = (coeff_table_offset & 0x0007) * 0x20000;
+ coeff_table_shift = 1;
+ }
+ }
+
+ if ( stv2_current_tilemap.colour_calculation_enabled == 1 )
+ {
+ if ( STV_VDP2_CCMD )
+ {
+ stv2_current_tilemap.transparency = STV_TRANSPARENCY_ADD_BLEND;
+ }
+ else
+ {
+ stv2_current_tilemap.transparency = TRANSPARENCY_ALPHA;
+ }
+ }
+
+ /* clipping */
+ switch( screen_over_process )
+ {
+ case 0:
+ /* repeated */
+ clipxmask = clipymask = 0;
+ break;
+ case 1:
+ /* screen over pattern, not supported */
+ clipxmask = clipymask = 0;
+ break;
+ case 2:
+ /* outside display area, scroll screen is transparent */
+ clipxmask = ~planesizex;
+ clipymask = ~planesizey;
+ break;
+ case 3:
+ /* display area is 512x512, outside is transparent */
+ clipxmask = ~511;
+ clipymask = ~511;
+ break;
+ }
+
+ //dx = (RP.A * RP.dx) + (RP.B * RP.dy);
+ //dy = (RP.D * RP.dx) + (RP.E * RP.dy);
+ dx = mul_fixed32( RP.A, RP.dx ) + mul_fixed32( RP.B, RP.dy );
+ dy = mul_fixed32( RP.D, RP.dx ) + mul_fixed32( RP.E, RP.dy );
+
+ //xp = RP.A * ( RP.px - RP.cx ) + RP.B * ( RP.py - RP.cy ) + RP.C * ( RP.pz - RP.cz ) + RP.cx + RP.mx;
+ //yp = RP.D * ( RP.px - RP.cx ) + RP.E * ( RP.py - RP.cy ) + RP.F * ( RP.pz - RP.cz ) + RP.cy + RP.my;
+ xp = mul_fixed32( RP.A, RP.px - RP.cx ) + mul_fixed32( RP.B, RP.py - RP.cy ) + mul_fixed32( RP.C, RP.pz - RP.cz ) + RP.cx + RP.mx;
+ yp = mul_fixed32( RP.D, RP.px - RP.cx ) + mul_fixed32( RP.E, RP.py - RP.cy ) + mul_fixed32( RP.F, RP.pz - RP.cz ) + RP.cy + RP.my;
+
+ for (vcnt = cliprect->min_y; vcnt <= cliprect->max_y; vcnt++ )
+ {
+ /*xsp = RP.A * ( ( RP.xst + RP.dxst * (vcnt << 16) ) - RP.px ) +
+ RP.B * ( ( RP.yst + RP.dyst * (vcnt << 16) ) - RP.py ) +
+ RP.C * ( RP.zst - RP.pz);
+ ysp = RP.D * ( ( RP.xst + RP.dxst * (vcnt << 16) ) - RP.px ) +
+ RP.E * ( ( RP.yst + RP.dyst * (vcnt << 16) ) - RP.py ) +
+ RP.F * ( RP.zst - RP.pz );*/
+ xsp = mul_fixed32( RP.A, RP.xst + mul_fixed32( RP.dxst, vcnt << (16 - vcnt_shift)) - RP.px ) +
+ mul_fixed32( RP.B, RP.yst + mul_fixed32( RP.dyst, vcnt << (16 - vcnt_shift)) - RP.py ) +
+ mul_fixed32( RP.C, RP.zst - RP.pz );
+ ysp = mul_fixed32( RP.D, RP.xst + mul_fixed32( RP.dxst, vcnt << (16 - vcnt_shift)) - RP.px ) +
+ mul_fixed32( RP.E, RP.yst + mul_fixed32( RP.dyst, vcnt << (16 - vcnt_shift)) - RP.py ) +
+ mul_fixed32( RP.F, RP.zst - RP.pz );
+ //xp = RP.A * ( RP.px - RP.cx ) + RP.B * ( RP.py - RP.cy ) + RP.C * ( RP.pz - RP.cz ) + RP.cx + RP.mx;
+ //yp = RP.D * ( RP.px - RP.cx ) + RP.E * ( RP.py - RP.cy ) + RP.F * ( RP.pz - RP.cz ) + RP.cy + RP.my;
+ //dx = (RP.A * RP.dx) + (RP.B * RP.dy);
+ //dy = (RP.D * RP.dx) + (RP.E * RP.dy);
+
+ line = BITMAP_ADDR16(bitmap, vcnt, 0);
+
+ if ( !use_coeff_table || RP.dkax == 0 )
+ {
+ if ( use_coeff_table )
+ {
+ switch( coeff_table_size )
+ {
+ case 0:
+ address = coeff_table_offset + ((RP.kast + RP.dkast*(vcnt>>vcnt_shift)) >> 16) * 4;
+ coeff_table_val = coeff_table_base[ address / 4 ];
+ coeff_line_color_screen_data = (coeff_table_val & 0x7f000000) >> 24;
+ coeff_msb = (coeff_table_val & 0x80000000) > 0;
+ if ( coeff_table_val & 0x00800000 )
+ {
+ coeff_table_val |= 0xff000000;
+ }
+ else
+ {
+ coeff_table_val &= 0x007fffff;
+ }
+ break;
+ case 1:
+ address = coeff_table_offset + ((RP.kast + RP.dkast*(vcnt>>vcnt_shift)) >> 16) * 2;
+ coeff_table_val = coeff_table_base[ address / 4 ];
+ if ( (address & 2) == 0 )
+ {
+ coeff_table_val >>= 16;
+ }
+ coeff_table_val &= 0xffff;
+ coeff_line_color_screen_data = 0;
+ coeff_msb = (coeff_table_val & 0x8000) > 0;
+ if ( coeff_table_val & 0x4000 )
+ {
+ coeff_table_val |= 0xffff8000;
+ }
+ else
+ {
+ coeff_table_val &= 0x3fff;
+ }
+ coeff_table_val <<= 6; /* to form 16.16 fixed point val */
+ break;
+ default:
+ coeff_msb = 1;
+ break;
+ }
+ if ( coeff_msb ) continue;
+
+ switch( coeff_table_mode )
+ {
+ case 0:
+ kx = ky = coeff_table_val;
+ break;
+ case 1:
+ kx = coeff_table_val;
+ break;
+ case 2:
+ ky = coeff_table_val;
+ break;
+ case 3:
+ xp = coeff_table_val;
+ break;
+ }
+ }
+
+ //x = RP.kx * ( xsp + dx * (hcnt << 16)) + xp;
+ //y = RP.ky * ( ysp + dy * (hcnt << 16)) + yp;
+ xs = mul_fixed32( kx, xsp ) + xp;
+ ys = mul_fixed32( ky, ysp ) + yp;
+ dxs = mul_fixed32( kx, mul_fixed32( dx, 1 << (16-hcnt_shift)));
+ dys = mul_fixed32( ky, mul_fixed32( dy, 1 << (16-hcnt_shift)));
+
+ for (hcnt = cliprect->min_x; hcnt <= cliprect->max_x; xs+=dxs, ys+=dys, hcnt++ )
+ {
+ x = xs >> 16;
+ y = ys >> 16;
+
+ if ( x & clipxmask || y & clipymask ) continue;
+ pix = *BITMAP_ADDR16(roz_bitmap, y & planerenderedsizey, x & planerenderedsizex);
+ if(stv2_current_tilemap.fade_control & 1)
+ stv_vdp2_compute_color_offset_RGB555_UINT16(&pix,stv2_current_tilemap.fade_control & 2);
+ switch( stv2_current_tilemap.transparency )
+ {
+ case TRANSPARENCY_PEN:
+ if ( pix != 0x0000 ) line[hcnt] = pix;
+ break;
+ case TRANSPARENCY_NONE:
+ line[hcnt] = pix;
+ break;
+ case TRANSPARENCY_ALPHA:
+ if ( pix != 0x000 ) line[hcnt] = alpha_blend16( line[hcnt], pix );
+ break;
+ case STV_TRANSPARENCY_ADD_BLEND:
+ if ( pix != 0x0000 ) line[hcnt] = stv_add_blend( line[hcnt], pix );
+ break;
+ }
+
+ }
+ }
+ else
+ {
+ for (hcnt = cliprect->min_x; hcnt <= cliprect->max_x; hcnt++ )
+ {
+ switch( coeff_table_size )
+ {
+ case 0:
+ address = coeff_table_offset + ((RP.kast + RP.dkast*(vcnt>>vcnt_shift) + RP.dkax*hcnt) >> 16) * 4;
+ coeff_table_val = coeff_table_base[ address / 4 ];
+ coeff_line_color_screen_data = (coeff_table_val & 0x7f000000) >> 24;
+ coeff_msb = (coeff_table_val & 0x80000000) > 0;
+ if ( coeff_table_val & 0x00800000 )
+ {
+ coeff_table_val |= 0xff000000;
+ }
+ else
+ {
+ coeff_table_val &= 0x007fffff;
+ }
+ break;
+ case 1:
+ address = coeff_table_offset + ((RP.kast + RP.dkast*(vcnt>>vcnt_shift) + RP.dkax*hcnt) >> 16) * 2;
+ coeff_table_val = coeff_table_base[ address / 4 ];
+ if ( (address & 2) == 0 )
+ {
+ coeff_table_val >>= 16;
+ }
+ coeff_table_val &= 0xffff;
+ coeff_line_color_screen_data = 0;
+ coeff_msb = (coeff_table_val & 0x8000) > 0;
+ if ( coeff_table_val & 0x4000 )
+ {
+ coeff_table_val |= 0xffff8000;
+ }
+ else
+ {
+ coeff_table_val &= 0x3fff;
+ }
+ coeff_table_val <<= 6; /* to form 16.16 fixed point val */
+ break;
+ default:
+ coeff_msb = 1;
+ break;
+ }
+ if ( coeff_msb ) continue;
+ switch( coeff_table_mode )
+ {
+ case 0:
+ kx = ky = coeff_table_val;
+ break;
+ case 1:
+ kx = coeff_table_val;
+ break;
+ case 2:
+ ky = coeff_table_val;
+ break;
+ case 3:
+ xp = coeff_table_val;
+ break;
+ }
+
+ //x = RP.kx * ( xsp + dx * (hcnt << 16)) + xp;
+ //y = RP.ky * ( ysp + dy * (hcnt << 16)) + yp;
+ x = mul_fixed32( kx, xsp + mul_fixed32( dx, (hcnt>>hcnt_shift) << 16 ) ) + xp;
+ y = mul_fixed32( ky, ysp + mul_fixed32( dy, (hcnt>>hcnt_shift) << 16 ) ) + yp;
+
+ x >>= 16;
+ y >>= 16;
+
+ if ( x & clipxmask || y & clipymask ) continue;
+
+ pix = *BITMAP_ADDR16(roz_bitmap, y & planerenderedsizey, x & planerenderedsizex);
+ if(stv2_current_tilemap.fade_control & 1)
+ stv_vdp2_compute_color_offset_RGB555_UINT16(&pix,stv2_current_tilemap.fade_control & 2);
+ switch( stv2_current_tilemap.transparency )
+ {
+ case TRANSPARENCY_PEN:
+ if ( pix != 0x0000 ) line[hcnt] = pix;
+ break;
+ case TRANSPARENCY_NONE:
+ line[hcnt] = pix;
+ break;
+ case TRANSPARENCY_ALPHA:
+ if ( pix != 0x000 ) line[hcnt] = alpha_blend16( line[hcnt], pix );
+ break;
+ case STV_TRANSPARENCY_ADD_BLEND:
+ if ( pix != 0x0000 ) line[hcnt] = stv_add_blend( line[hcnt], pix );
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void stv_vdp2_draw_NBG0(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /*
+ Colours : 16, 256, 2048, 32768, 16770000
+ Char Size : 1x1 cells, 2x2 cells
+ Pattern Data Size : 1 word, 2 words
+ Plane Layouts : 1 x 1, 2 x 1, 2 x 2
+ Planes : 4
+ Bitmap : Possible
+ Bitmap Sizes : 512 x 256, 512 x 512, 1024 x 256, 1024 x 512
+ Scale : 0.25 x - 256 x
+ Rotation : No
+ Linescroll : Yes
+ Column Scroll : Yes
+ Mosaic : Yes
+ */
+ stv2_current_tilemap.enabled = STV_VDP2_N0ON;
+
+// if (!stv2_current_tilemap.enabled) return; // stop right now if its disabled ...
+
+ //stv2_current_tilemap.trans_enabled = STV_VDP2_N0TPON;
+ if ( STV_VDP2_N0CCEN )
+ {
+ stv2_current_tilemap.colour_calculation_enabled = 1;
+ alpha_set_level( ((UINT16)(0x1f-STV_VDP2_N0CCRT)*0xff)/0x1f);
+ }
+ else
+ {
+ stv2_current_tilemap.colour_calculation_enabled = 0;
+ }
+ if ( STV_VDP2_N0TPON == 0 )
+ {
+ stv2_current_tilemap.transparency = TRANSPARENCY_PEN;
+ }
+ else
+ {
+ stv2_current_tilemap.transparency = TRANSPARENCY_NONE;
+ }
+ stv2_current_tilemap.colour_depth = STV_VDP2_N0CHCN;
+ stv2_current_tilemap.tile_size = STV_VDP2_N0CHSZ;
+ stv2_current_tilemap.bitmap_enable = STV_VDP2_N0BMEN;
+ stv2_current_tilemap.bitmap_size = STV_VDP2_N0BMSZ;
+ stv2_current_tilemap.bitmap_palette_number = STV_VDP2_N0BMP;
+ stv2_current_tilemap.bitmap_map = STV_VDP2_N0MP_;
+ stv2_current_tilemap.map_offset[0] = STV_VDP2_N0MPA | (STV_VDP2_N0MP_ << 6);
+ stv2_current_tilemap.map_offset[1] = STV_VDP2_N0MPB | (STV_VDP2_N0MP_ << 6);
+ stv2_current_tilemap.map_offset[2] = STV_VDP2_N0MPC | (STV_VDP2_N0MP_ << 6);
+ stv2_current_tilemap.map_offset[3] = STV_VDP2_N0MPD | (STV_VDP2_N0MP_ << 6);
+ stv2_current_tilemap.map_count = 4;
+
+ stv2_current_tilemap.pattern_data_size = STV_VDP2_N0PNB;
+ stv2_current_tilemap.character_number_supplement = STV_VDP2_N0CNSM;
+ stv2_current_tilemap.special_priority_register = STV_VDP2_N0SPR;
+ stv2_current_tilemap.special_colour_control_register = STV_VDP2_PNCN0;
+ stv2_current_tilemap.supplementary_palette_bits = STV_VDP2_N0SPLT;
+ stv2_current_tilemap.supplementary_character_bits = STV_VDP2_N0SPCN;
+
+ stv2_current_tilemap.scrollx = STV_VDP2_SCXIN0;
+ stv2_current_tilemap.scrolly = STV_VDP2_SCYIN0;
+ stv2_current_tilemap.incx = STV_VDP2_ZMXN0;
+ stv2_current_tilemap.incy = STV_VDP2_ZMYN0;
+
+ stv2_current_tilemap.linescroll_enable = STV_VDP2_N0LSCX;
+ stv2_current_tilemap.linescroll_interval = 1 << (STV_VDP2_N0LSS);
+ stv2_current_tilemap.linescroll_table_address = ((STV_VDP2_LSTA0U << 16) | STV_VDP2_LSTA0L) * 2;
+ stv2_current_tilemap.vertical_linescroll_enable = STV_VDP2_N0LSCY;
+ stv2_current_tilemap.linezoom_enable = STV_VDP2_N0LZMX;
+
+ stv2_current_tilemap.plane_size = STV_VDP2_N0PLSZ;
+ stv2_current_tilemap.colour_ram_address_offset = STV_VDP2_N0CAOS;
+ stv2_current_tilemap.fade_control = (STV_VDP2_N0COEN * 1) | (STV_VDP2_N0COSL * 2);
+ stv_vdp2_check_fade_control_for_layer();
+ stv2_current_tilemap.window_control = (STV_VDP2_N0LOG * 0x01) |
+ (STV_VDP2_N0W0E * 0x02) |
+ (STV_VDP2_N0W1E * 0x04) |
+ (STV_VDP2_N0SWE * 0x08) |
+ (STV_VDP2_N0W0A * 0x10) |
+ (STV_VDP2_N0W1A * 0x20) |
+ (STV_VDP2_N0SWA * 0x40);
+
+ stv2_current_tilemap.layer_name=0;
+
+ if ( stv2_current_tilemap.enabled )
+ {
+ stv2_current_tilemap.enabled = stv_vdp2_check_vram_cycle_pattern_registers( STV_VDP2_CP_NBG0_PNMDR, STV_VDP2_CP_NBG0_CPDR, stv2_current_tilemap.bitmap_enable );
+ }
+
+ stv_vdp2_check_tilemap(machine, bitmap, cliprect);
+}
+
+static void stv_vdp2_draw_NBG1(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /*
+ Colours : 16, 256, 2048, 32768
+ Char Size : 1x1 cells, 2x2 cells
+ Pattern Data Size : 1 word, 2 words
+ Plane Layouts : 1 x 1, 2 x 1, 2 x 2
+ Planes : 4
+ Bitmap : Possible
+ Bitmap Sizes : 512 x 256, 512 x 512, 1024 x 256, 1024 x 512
+ Scale : 0.25 x - 256 x
+ Rotation : No
+ Linescroll : Yes
+ Column Scroll : Yes
+ Mosaic : Yes
+ */
+ stv2_current_tilemap.enabled = STV_VDP2_N1ON;
+
+// if (!stv2_current_tilemap.enabled) return; // stop right now if its disabled ...
+
+ //stv2_current_tilemap.trans_enabled = STV_VDP2_N1TPON;
+ if ( STV_VDP2_N1CCEN )
+ {
+ stv2_current_tilemap.colour_calculation_enabled = 1;
+ alpha_set_level( ((UINT16)(0x1f-STV_VDP2_N1CCRT)*0xff)/0x1f);
+ }
+ else
+ {
+ stv2_current_tilemap.colour_calculation_enabled = 0;
+ }
+ if ( STV_VDP2_N1TPON == 0 )
+ {
+ stv2_current_tilemap.transparency = TRANSPARENCY_PEN;
+ }
+ else
+ {
+ stv2_current_tilemap.transparency = TRANSPARENCY_NONE;
+ }
+ stv2_current_tilemap.colour_depth = STV_VDP2_N1CHCN;
+ stv2_current_tilemap.tile_size = STV_VDP2_N1CHSZ;
+ stv2_current_tilemap.bitmap_enable = STV_VDP2_N1BMEN;
+ stv2_current_tilemap.bitmap_size = STV_VDP2_N1BMSZ;
+ stv2_current_tilemap.bitmap_palette_number = STV_VDP2_N1BMP;
+ stv2_current_tilemap.bitmap_map = STV_VDP2_N1MP_;
+ stv2_current_tilemap.map_offset[0] = STV_VDP2_N1MPA | (STV_VDP2_N1MP_ << 6);
+ stv2_current_tilemap.map_offset[1] = STV_VDP2_N1MPB | (STV_VDP2_N1MP_ << 6);
+ stv2_current_tilemap.map_offset[2] = STV_VDP2_N1MPC | (STV_VDP2_N1MP_ << 6);
+ stv2_current_tilemap.map_offset[3] = STV_VDP2_N1MPD | (STV_VDP2_N1MP_ << 6);
+ stv2_current_tilemap.map_count = 4;
+
+ stv2_current_tilemap.pattern_data_size = STV_VDP2_N1PNB;
+ stv2_current_tilemap.character_number_supplement = STV_VDP2_N1CNSM;
+ stv2_current_tilemap.special_priority_register = STV_VDP2_N1SPR;
+ stv2_current_tilemap.special_colour_control_register = STV_VDP2_PNCN1;
+ stv2_current_tilemap.supplementary_palette_bits = STV_VDP2_N1SPLT;
+ stv2_current_tilemap.supplementary_character_bits = STV_VDP2_N1SPCN;
+
+ stv2_current_tilemap.scrollx = STV_VDP2_SCXIN1;
+ stv2_current_tilemap.scrolly = STV_VDP2_SCYIN1;
+ stv2_current_tilemap.incx = STV_VDP2_ZMXN1;
+ stv2_current_tilemap.incy = STV_VDP2_ZMYN1;
+
+ stv2_current_tilemap.linescroll_enable = STV_VDP2_N1LSCX;
+ stv2_current_tilemap.linescroll_interval = 1 << (STV_VDP2_N1LSS);
+ stv2_current_tilemap.linescroll_table_address = ((STV_VDP2_LSTA1U << 16) | STV_VDP2_LSTA1L) * 2;
+ stv2_current_tilemap.vertical_linescroll_enable = STV_VDP2_N1LSCY;
+ stv2_current_tilemap.linezoom_enable = STV_VDP2_N1LZMX;
+
+ stv2_current_tilemap.plane_size = STV_VDP2_N1PLSZ;
+ stv2_current_tilemap.colour_ram_address_offset = STV_VDP2_N1CAOS;
+ stv2_current_tilemap.fade_control = (STV_VDP2_N1COEN * 1) | (STV_VDP2_N1COSL * 2);
+ stv_vdp2_check_fade_control_for_layer();
+ stv2_current_tilemap.window_control = (STV_VDP2_N1LOG * 0x01) |
+ (STV_VDP2_N1W0E * 0x02) |
+ (STV_VDP2_N1W1E * 0x04) |
+ (STV_VDP2_N1SWE * 0x08) |
+ (STV_VDP2_N1W0A * 0x10) |
+ (STV_VDP2_N1W1A * 0x20) |
+ (STV_VDP2_N1SWA * 0x40);
+
+ stv2_current_tilemap.layer_name=1;
+
+ if ( stv2_current_tilemap.enabled )
+ {
+ stv2_current_tilemap.enabled = stv_vdp2_check_vram_cycle_pattern_registers( STV_VDP2_CP_NBG1_PNMDR, STV_VDP2_CP_NBG1_CPDR, stv2_current_tilemap.bitmap_enable );
+ }
+
+ stv_vdp2_check_tilemap(machine, bitmap, cliprect);
+}
+
+static void stv_vdp2_draw_NBG2(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /*
+ NBG2 is the first of the 2 more basic tilemaps, it has exactly the same capabilities as NBG3
+
+ Colours : 16, 256
+ Char Size : 1x1 cells, 2x2 cells
+ Pattern Data Size : 1 word, 2 words
+ Plane Layouts : 1 x 1, 2 x 1, 2 x 2
+ Planes : 4
+ Bitmap : No
+ Bitmap Sizes : N/A
+ Scale : No
+ Rotation : No
+ Linescroll : No
+ Column Scroll : No
+ Mosaic : Yes
+ */
+
+ stv2_current_tilemap.enabled = STV_VDP2_N2ON;
+
+ /* these modes for N0 disable this layer */
+ if (STV_VDP2_N0CHCN == 0x03) stv2_current_tilemap.enabled = 0;
+ if (STV_VDP2_N0CHCN == 0x04) stv2_current_tilemap.enabled = 0;
+
+// if (!stv2_current_tilemap.enabled) return; // stop right now if its disabled ...
+
+ //stv2_current_tilemap.trans_enabled = STV_VDP2_N2TPON;
+ if ( STV_VDP2_N2CCEN )
+ {
+ stv2_current_tilemap.colour_calculation_enabled = 1;
+ alpha_set_level( ((UINT16)(0x1f-STV_VDP2_N2CCRT)*0xff)/0x1f);
+ }
+ else
+ {
+ stv2_current_tilemap.colour_calculation_enabled = 0;
+ }
+ if ( STV_VDP2_N2TPON == 0 )
+ {
+ stv2_current_tilemap.transparency = TRANSPARENCY_PEN;
+ }
+ else
+ {
+ stv2_current_tilemap.transparency = TRANSPARENCY_NONE;
+ }
+ stv2_current_tilemap.colour_depth = STV_VDP2_N2CHCN;
+ stv2_current_tilemap.tile_size = STV_VDP2_N2CHSZ;
+ /* this layer can't be a bitmap,so ignore these registers*/
+ stv2_current_tilemap.bitmap_enable = 0;
+ stv2_current_tilemap.bitmap_size = 0;
+ stv2_current_tilemap.bitmap_palette_number = 0;
+ stv2_current_tilemap.bitmap_map = 0;
+ stv2_current_tilemap.map_offset[0] = STV_VDP2_N2MPA | (STV_VDP2_N2MP_ << 6);
+ stv2_current_tilemap.map_offset[1] = STV_VDP2_N2MPB | (STV_VDP2_N2MP_ << 6);
+ stv2_current_tilemap.map_offset[2] = STV_VDP2_N2MPC | (STV_VDP2_N2MP_ << 6);
+ stv2_current_tilemap.map_offset[3] = STV_VDP2_N2MPD | (STV_VDP2_N2MP_ << 6);
+ stv2_current_tilemap.map_count = 4;
+
+ stv2_current_tilemap.pattern_data_size = STV_VDP2_N2PNB;
+ stv2_current_tilemap.character_number_supplement = STV_VDP2_N2CNSM;
+ stv2_current_tilemap.special_priority_register = STV_VDP2_N2SPR;
+ stv2_current_tilemap.special_colour_control_register = STV_VDP2_PNCN2;
+ stv2_current_tilemap.supplementary_palette_bits = STV_VDP2_N2SPLT;
+ stv2_current_tilemap.supplementary_character_bits = STV_VDP2_N2SPCN;
+
+ stv2_current_tilemap.scrollx = STV_VDP2_SCXN2;
+ stv2_current_tilemap.scrolly = STV_VDP2_SCYN2;
+ /*This layer can't be scaled*/
+ stv2_current_tilemap.incx = 0x10000;
+ stv2_current_tilemap.incy = 0x10000;
+
+ stv2_current_tilemap.linescroll_enable = 0;
+ stv2_current_tilemap.linescroll_interval = 0;
+ stv2_current_tilemap.linescroll_table_address = 0;
+ stv2_current_tilemap.vertical_linescroll_enable = 0;
+ stv2_current_tilemap.linezoom_enable = 0;
+
+ stv2_current_tilemap.colour_ram_address_offset = STV_VDP2_N2CAOS;
+ stv2_current_tilemap.fade_control = (STV_VDP2_N2COEN * 1) | (STV_VDP2_N2COSL * 2);
+ stv_vdp2_check_fade_control_for_layer();
+ stv2_current_tilemap.window_control = (STV_VDP2_N2LOG * 0x01) |
+ (STV_VDP2_N2W0E * 0x02) |
+ (STV_VDP2_N2W1E * 0x04) |
+ (STV_VDP2_N2SWE * 0x08) |
+ (STV_VDP2_N2W0A * 0x10) |
+ (STV_VDP2_N2W1A * 0x20) |
+ (STV_VDP2_N2SWA * 0x40);
+
+ stv2_current_tilemap.layer_name=2;
+
+ stv2_current_tilemap.plane_size = STV_VDP2_N2PLSZ;
+
+ if ( stv2_current_tilemap.enabled )
+ {
+ stv2_current_tilemap.enabled = stv_vdp2_check_vram_cycle_pattern_registers( STV_VDP2_CP_NBG2_PNMDR, STV_VDP2_CP_NBG2_CPDR, stv2_current_tilemap.bitmap_enable );
+ }
+
+ stv_vdp2_check_tilemap(machine, bitmap, cliprect);
+}
+
+static void stv_vdp2_draw_NBG3(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /*
+ NBG3 is the second of the 2 more basic tilemaps, it has exactly the same capabilities as NBG2
+
+ Colours : 16, 256
+ Char Size : 1x1 cells, 2x2 cells
+ Pattern Data Size : 1 word, 2 words
+ Plane Layouts : 1 x 1, 2 x 1, 2 x 2
+ Planes : 4
+ Bitmap : No
+ Bitmap Sizes : N/A
+ Scale : No
+ Rotation : No
+ Linescroll : No
+ Column Scroll : No
+ Mosaic : Yes
+ */
+
+ stv2_current_tilemap.enabled = STV_VDP2_N3ON;
+
+// if (!stv2_current_tilemap.enabled) return; // stop right now if its disabled ...
+
+ /* these modes for N1 disable this layer */
+ if (STV_VDP2_N1CHCN == 0x03) stv2_current_tilemap.enabled = 0;
+ if (STV_VDP2_N1CHCN == 0x04) stv2_current_tilemap.enabled = 0;
+
+ //stv2_current_tilemap.trans_enabled = STV_VDP2_N3TPON;
+ if ( STV_VDP2_N3CCEN )
+ {
+ stv2_current_tilemap.colour_calculation_enabled = 1;
+ alpha_set_level( ((UINT16)(0x1f-STV_VDP2_N3CCRT)*0xff)/0x1f);
+ }
+ else
+ {
+ stv2_current_tilemap.colour_calculation_enabled = 0;
+ }
+ if ( STV_VDP2_N3TPON == 0 )
+ {
+ stv2_current_tilemap.transparency = TRANSPARENCY_PEN;
+ }
+ else
+ {
+ stv2_current_tilemap.transparency = TRANSPARENCY_NONE;
+ }
+ stv2_current_tilemap.colour_depth = STV_VDP2_N3CHCN;
+ stv2_current_tilemap.tile_size = STV_VDP2_N3CHSZ;
+ /* this layer can't be a bitmap,so ignore these registers*/
+ stv2_current_tilemap.bitmap_enable = 0;
+ stv2_current_tilemap.bitmap_size = 0;
+ stv2_current_tilemap.bitmap_palette_number = 0;
+ stv2_current_tilemap.bitmap_map = 0;
+ stv2_current_tilemap.map_offset[0] = STV_VDP2_N3MPA | (STV_VDP2_N3MP_ << 6);
+ stv2_current_tilemap.map_offset[1] = STV_VDP2_N3MPB | (STV_VDP2_N3MP_ << 6);
+ stv2_current_tilemap.map_offset[2] = STV_VDP2_N3MPC | (STV_VDP2_N3MP_ << 6);
+ stv2_current_tilemap.map_offset[3] = STV_VDP2_N3MPD | (STV_VDP2_N3MP_ << 6);
+ stv2_current_tilemap.map_count = 4;
+
+ stv2_current_tilemap.pattern_data_size = STV_VDP2_N3PNB;
+ stv2_current_tilemap.character_number_supplement = STV_VDP2_N3CNSM;
+ stv2_current_tilemap.special_priority_register = STV_VDP2_N3SPR;
+ stv2_current_tilemap.special_colour_control_register = STV_VDP2_N3SCC;
+ stv2_current_tilemap.supplementary_palette_bits = STV_VDP2_N3SPLT;
+ stv2_current_tilemap.supplementary_character_bits = STV_VDP2_N3SPCN;
+
+ stv2_current_tilemap.scrollx = STV_VDP2_SCXN3;
+ stv2_current_tilemap.scrolly = STV_VDP2_SCYN3;
+ /*This layer can't be scaled*/
+ stv2_current_tilemap.incx = 0x10000;
+ stv2_current_tilemap.incy = 0x10000;
+
+ stv2_current_tilemap.linescroll_enable = 0;
+ stv2_current_tilemap.linescroll_interval = 0;
+ stv2_current_tilemap.linescroll_table_address = 0;
+ stv2_current_tilemap.vertical_linescroll_enable = 0;
+ stv2_current_tilemap.linezoom_enable = 0;
+
+ stv2_current_tilemap.colour_ram_address_offset = STV_VDP2_N3CAOS;
+ stv2_current_tilemap.fade_control = (STV_VDP2_N3COEN * 1) | (STV_VDP2_N3COSL * 2);
+ stv_vdp2_check_fade_control_for_layer();
+ stv2_current_tilemap.window_control = (STV_VDP2_N3LOG * 0x01) |
+ (STV_VDP2_N3W0E * 0x02) |
+ (STV_VDP2_N3W1E * 0x04) |
+ (STV_VDP2_N3SWE * 0x08) |
+ (STV_VDP2_N3W0A * 0x10) |
+ (STV_VDP2_N3W1A * 0x20) |
+ (STV_VDP2_N3SWA * 0x40);
+
+ stv2_current_tilemap.layer_name=3;
+
+ stv2_current_tilemap.plane_size = STV_VDP2_N3PLSZ;
+
+ if ( stv2_current_tilemap.enabled )
+ {
+ stv2_current_tilemap.enabled = stv_vdp2_check_vram_cycle_pattern_registers( STV_VDP2_CP_NBG3_PNMDR, STV_VDP2_CP_NBG3_CPDR, stv2_current_tilemap.bitmap_enable );
+ }
+
+ stv_vdp2_check_tilemap(machine, bitmap, cliprect);
+}
+
+
+static void stv_vdp2_draw_rotation_screen(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int iRP)
+{
+ rectangle roz_clip_rect, mycliprect;
+ int planesizex = 0, planesizey = 0, planerenderedsizex, planerenderedsizey;
+ UINT8 colour_calculation_enabled;
+ UINT8 window_control;
+ UINT8 fade_control;
+
+ if ( iRP == 1)
+ {
+ stv2_current_tilemap.bitmap_map = STV_VDP2_RAMP_;
+ stv2_current_tilemap.map_offset[0] = STV_VDP2_RAMPA | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[1] = STV_VDP2_RAMPB | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[2] = STV_VDP2_RAMPC | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[3] = STV_VDP2_RAMPD | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[4] = STV_VDP2_RAMPE | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[5] = STV_VDP2_RAMPF | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[6] = STV_VDP2_RAMPG | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[7] = STV_VDP2_RAMPH | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[8] = STV_VDP2_RAMPI | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[9] = STV_VDP2_RAMPJ | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[10] = STV_VDP2_RAMPK | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[11] = STV_VDP2_RAMPL | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[12] = STV_VDP2_RAMPM | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[13] = STV_VDP2_RAMPN | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[14] = STV_VDP2_RAMPO | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_offset[15] = STV_VDP2_RAMPP | (STV_VDP2_RAMP_ << 6);
+ stv2_current_tilemap.map_count = 16;
+ }
+ else
+ {
+ stv2_current_tilemap.bitmap_map = STV_VDP2_RBMP_;
+ stv2_current_tilemap.map_offset[0] = STV_VDP2_RBMPA | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[1] = STV_VDP2_RBMPB | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[2] = STV_VDP2_RBMPC | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[3] = STV_VDP2_RBMPD | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[4] = STV_VDP2_RBMPE | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[5] = STV_VDP2_RBMPF | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[6] = STV_VDP2_RBMPG | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[7] = STV_VDP2_RBMPH | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[8] = STV_VDP2_RBMPI | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[9] = STV_VDP2_RBMPJ | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[10] = STV_VDP2_RBMPK | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[11] = STV_VDP2_RBMPL | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[12] = STV_VDP2_RBMPM | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[13] = STV_VDP2_RBMPN | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[14] = STV_VDP2_RBMPO | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_offset[15] = STV_VDP2_RBMPP | (STV_VDP2_RBMP_ << 6);
+ stv2_current_tilemap.map_count = 16;
+ }
+
+ stv_vdp2_fill_rotation_parameter_table(iRP);
+
+ if ( iRP == 1 )
+ {
+ stv2_current_tilemap.plane_size = STV_VDP2_RAPLSZ;
+ }
+ else
+ {
+ stv2_current_tilemap.plane_size = STV_VDP2_RBPLSZ;
+ }
+
+ if (stv2_current_tilemap.bitmap_enable)
+ {
+ switch (stv2_current_tilemap.bitmap_size)
+ {
+ case 0: planesizex=512; planesizey=256; break;
+ case 1: planesizex=512; planesizey=512; break;
+ case 2: planesizex=1024; planesizey=256; break;
+ case 3: planesizex=1024; planesizey=512; break;
+ }
+ }
+ else
+ {
+ switch( stv2_current_tilemap.plane_size )
+ {
+ case 0:
+ planesizex = planesizey = 2048;
+ break;
+ case 1:
+ planesizex = 4096;
+ planesizey = 2048;
+ break;
+ case 2:
+ planesizex = 0;
+ planesizey = 0;
+ break;
+ case 3:
+ planesizex = planesizey = 4096;
+ break;
+ }
+ }
+
+
+ if ( stv_vdp2_is_rotation_applied() == 0 )
+ {
+ stv2_current_tilemap.scrollx = stv_current_rotation_parameter_table.mx >> 16;
+ stv2_current_tilemap.scrolly = stv_current_rotation_parameter_table.my >> 16;
+
+ stv_vdp2_check_tilemap(machine, bitmap,cliprect);
+ }
+ else
+ {
+ if ( stv_vdp2_roz_bitmap[iRP-1] == NULL )
+ {
+ stv_vdp2_roz_bitmap[iRP-1] = auto_bitmap_alloc( 4096, 4096, machine->screen[0].format );
+ }
+
+ roz_clip_rect.min_x = roz_clip_rect.min_y = 0;
+ if ( (iRP == 1 && STV_VDP2_RAOVR == 3) ||
+ (iRP == 2 && STV_VDP2_RBOVR == 3) )
+ {
+ roz_clip_rect.max_x = roz_clip_rect.max_y = 511;
+ planerenderedsizex = planerenderedsizey = 512;
+ }
+ else if (stv_vdp2_are_map_registers_equal() &&
+ !stv2_current_tilemap.bitmap_enable)
+ {
+ roz_clip_rect.max_x = (planesizex / 4) - 1;
+ roz_clip_rect.max_y = (planesizey / 4) - 1;
+ planerenderedsizex = planesizex / 4;
+ planerenderedsizey = planesizey / 4;
+ }
+ else
+ {
+ roz_clip_rect.max_x = planesizex - 1;
+ roz_clip_rect.max_y = planesizey - 1;
+ planerenderedsizex = planesizex;
+ planerenderedsizey = planesizey;
+ }
+
+
+ colour_calculation_enabled = stv2_current_tilemap.colour_calculation_enabled;
+ stv2_current_tilemap.colour_calculation_enabled = 0;
+ window_control = stv2_current_tilemap.window_control;
+ stv2_current_tilemap.window_control = 0;
+ fade_control = stv2_current_tilemap.fade_control;
+ stv2_current_tilemap.fade_control = 0;
+ profiler_mark(PROFILER_USER1);
+ if ( LOG_VDP2 ) logerror( "Checking for cached RBG bitmap, cache_dirty = %d, memcmp() = %d\n", stv_rbg_cache_data.is_cache_dirty, memcmp(&stv_rbg_cache_data.layer_data[iRP-1],&stv2_current_tilemap,sizeof(stv2_current_tilemap)));
+ if ( (stv_rbg_cache_data.is_cache_dirty & iRP) ||
+ memcmp(&stv_rbg_cache_data.layer_data[iRP-1],&stv2_current_tilemap,sizeof(stv2_current_tilemap)) != 0 )
+ {
+ fillbitmap( stv_vdp2_roz_bitmap[iRP-1], get_black_pen(machine), &roz_clip_rect );
+ stv_vdp2_check_tilemap(machine, stv_vdp2_roz_bitmap[iRP-1], &roz_clip_rect);
+ // prepare cache data
+ stv_rbg_cache_data.watch_vdp2_vram_writes |= iRP;
+ stv_rbg_cache_data.is_cache_dirty &= ~iRP;
+ memcpy(&stv_rbg_cache_data.layer_data[iRP-1], &stv2_current_tilemap, sizeof(stv2_current_tilemap));
+ stv_rbg_cache_data.map_offset_min[iRP-1] = stv_vdp2_layer_data_placement.map_offset_min;
+ stv_rbg_cache_data.map_offset_max[iRP-1] = stv_vdp2_layer_data_placement.map_offset_max;
+ stv_rbg_cache_data.tile_offset_min[iRP-1] = stv_vdp2_layer_data_placement.tile_offset_min;
+ stv_rbg_cache_data.tile_offset_max[iRP-1] = stv_vdp2_layer_data_placement.tile_offset_max;
+ if ( LOG_VDP2 ) logerror( "Cache watch: map = %06X - %06X, tile = %06X - %06X\n", stv_rbg_cache_data.map_offset_min[iRP-1],
+ stv_rbg_cache_data.map_offset_max[iRP-1], stv_rbg_cache_data.tile_offset_min[iRP-1], stv_rbg_cache_data.tile_offset_max[iRP-1] );
+ }
+
+ profiler_mark(PROFILER_END);
+
+ stv2_current_tilemap.colour_calculation_enabled = colour_calculation_enabled;
+ if ( colour_calculation_enabled )
+ {
+ stv2_current_tilemap.transparency = TRANSPARENCY_ALPHA;
+ }
+
+ mycliprect.min_x = cliprect->min_x;
+ mycliprect.max_x = cliprect->max_x;
+ mycliprect.min_y = cliprect->min_y;
+ mycliprect.max_y = cliprect->max_y;
+
+ if ( window_control )
+ {
+ stv2_current_tilemap.window_control = window_control;
+ stv_vdp2_apply_window_on_layer(&mycliprect);
+ }
+
+ stv2_current_tilemap.fade_control = fade_control;
+
+ profiler_mark(PROFILER_USER2);
+ stv_vdp2_copy_roz_bitmap(bitmap, stv_vdp2_roz_bitmap[iRP-1], &mycliprect, iRP, planesizex, planesizey, planerenderedsizex, planerenderedsizey );
+ profiler_mark(PROFILER_END);
+ }
+
+}
+
+static void stv_vdp2_draw_RBG0(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /*
+ Colours : 16, 256, 2048, 32768, 16770000
+ Char Size : 1x1 cells, 2x2 cells
+ Pattern Data Size : 1 word, 2 words
+ Plane Layouts : 1 x 1, 2 x 1, 2 x 2
+ Planes : 4
+ Bitmap : Possible
+ Bitmap Sizes : 512 x 256, 512 x 512, 1024 x 256, 1024 x 512
+ Scale : 0.25 x - 256 x
+ Rotation : Yes
+ Linescroll : Yes
+ Column Scroll : Yes
+ Mosaic : Yes
+ */
+
+ stv2_current_tilemap.enabled = STV_VDP2_R0ON;
+
+// if (!stv2_current_tilemap.enabled) return; // stop right now if its disabled ...
+
+ //stv2_current_tilemap.trans_enabled = STV_VDP2_R0TPON;
+ if ( STV_VDP2_R0CCEN )
+ {
+ stv2_current_tilemap.colour_calculation_enabled = 1;
+ alpha_set_level( ((UINT16)(0x1f-STV_VDP2_R0CCRT)*0xff)/0x1f);
+ }
+ else
+ {
+ stv2_current_tilemap.colour_calculation_enabled = 0;
+ }
+ if ( STV_VDP2_R0TPON == 0 )
+ {
+ stv2_current_tilemap.transparency = TRANSPARENCY_PEN;
+ }
+ else
+ {
+ stv2_current_tilemap.transparency = TRANSPARENCY_NONE;
+ }
+ stv2_current_tilemap.colour_depth = STV_VDP2_R0CHCN;
+ stv2_current_tilemap.tile_size = STV_VDP2_R0CHSZ;
+ stv2_current_tilemap.bitmap_enable = STV_VDP2_R0BMEN;
+ stv2_current_tilemap.bitmap_size = STV_VDP2_R0BMSZ;
+ stv2_current_tilemap.bitmap_palette_number = STV_VDP2_R0BMP;
+
+ stv2_current_tilemap.pattern_data_size = STV_VDP2_R0PNB;
+ stv2_current_tilemap.character_number_supplement = STV_VDP2_R0CNSM;
+ stv2_current_tilemap.special_priority_register = STV_VDP2_R0SPR;
+ stv2_current_tilemap.special_colour_control_register = STV_VDP2_R0SCC;
+ stv2_current_tilemap.supplementary_palette_bits = STV_VDP2_R0SPLT;
+ stv2_current_tilemap.supplementary_character_bits = STV_VDP2_R0SPCN;
+
+ stv2_current_tilemap.colour_ram_address_offset = STV_VDP2_R0CAOS;
+ stv2_current_tilemap.fade_control = (STV_VDP2_R0COEN * 1) | (STV_VDP2_R0COSL * 2);
+ stv_vdp2_check_fade_control_for_layer();
+ stv2_current_tilemap.window_control = (STV_VDP2_R0LOG * 0x01) |
+ (STV_VDP2_R0W0E * 0x02) |
+ (STV_VDP2_R0W1E * 0x04) |
+ (STV_VDP2_R0SWE * 0x08) |
+ (STV_VDP2_R0W0A * 0x10) |
+ (STV_VDP2_R0W1A * 0x20) |
+ (STV_VDP2_R0SWA * 0x40);
+
+ stv2_current_tilemap.scrollx = 0;
+ stv2_current_tilemap.scrolly = 0;
+ stv2_current_tilemap.incx = 0x10000;
+ stv2_current_tilemap.incy = 0x10000;
+
+ stv2_current_tilemap.linescroll_enable = 0;
+ stv2_current_tilemap.linescroll_interval = 0;
+ stv2_current_tilemap.linescroll_table_address = 0;
+ stv2_current_tilemap.vertical_linescroll_enable = 0;
+ stv2_current_tilemap.linezoom_enable = 0;
+
+ /*Use 0x80 as a normal/rotate switch*/
+ stv2_current_tilemap.layer_name=0x80;
+
+ if ( !stv_vdp2_render_rbg0 ) return;
+ if ( !stv2_current_tilemap.enabled ) return;
+
+ switch(STV_VDP2_RPMD)
+ {
+ case 0://Rotation Parameter A
+ stv_vdp2_draw_rotation_screen(machine, bitmap, cliprect, 1 );
+ break;
+ case 1://Rotation Parameter B
+ //case 2:
+ stv_vdp2_draw_rotation_screen(machine, bitmap, cliprect, 2 );
+ break;
+ case 2://Rotation Parameter A & B CKTE
+ stv_vdp2_draw_rotation_screen(machine, bitmap, cliprect, 2 );
+ stv_vdp2_draw_rotation_screen(machine, bitmap, cliprect, 1 );
+ break;
+ case 3://Rotation Parameter A & B Window (wrong)
+ stv_vdp2_draw_rotation_screen(machine, bitmap, cliprect, 1 );
+ break;
+ }
+
+}
+
+static void stv_vdp2_draw_back(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int xcnt,ycnt;
+ UINT8* gfxdata = stv_vdp2_gfx_decode;
+ static UINT16 *destline;
+ int r,b,g;
+ UINT16 data;
+
+ if(!(STV_VDP2_BDCLMD & 1))
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ else
+ {
+ #ifdef MAME_DEBUG
+ //popmessage("Back screen enabled %08x",STV_VDP2_BKTA);
+ #endif
+ gfxdata+=((STV_VDP2_BKTA)<<1);
+
+ b = ((gfxdata[0] & 0x7c) >> 2);
+ g = ((gfxdata[0] & 0x03) << 3) | ((gfxdata[1] & 0xe0) >> 5);
+ r = ((gfxdata[1] & 0x1f));
+ data = b | g << 5 | r << 10;
+
+ for (ycnt = cliprect->min_y; ycnt <= cliprect->max_y;ycnt++)
+ {
+ destline = BITMAP_ADDR16(bitmap, ycnt, 0);
+
+ for (xcnt = cliprect->min_x; xcnt <=cliprect->max_x;xcnt++)
+ {
+ destline[xcnt] = data;
+ }
+ if(STV_VDP2_BKCLMD)
+ {
+ gfxdata+=2;
+ b = ((gfxdata[0] & 0x7c) >> 2);
+ g = ((gfxdata[0] & 0x03) << 3) | ((gfxdata[1] & 0xe0) >> 5);
+ r = ((gfxdata[1] & 0x1f));
+ data = b | g << 5 | r << 10;
+ }
+ }
+ }
+}
+
+
+WRITE32_HANDLER ( stv_vdp2_vram_w )
+{
+ UINT8 *stv_vdp2_vram_decode = stv_vdp2_gfx_decode;
+
+ COMBINE_DATA(&stv_vdp2_vram[offset]);
+
+ data = stv_vdp2_vram[offset];
+ /* put in gfx region for easy decoding */
+ stv_vdp2_vram_decode[offset*4+0] = (data & 0xff000000) >> 24;
+ stv_vdp2_vram_decode[offset*4+1] = (data & 0x00ff0000) >> 16;
+ stv_vdp2_vram_decode[offset*4+2] = (data & 0x0000ff00) >> 8;
+ stv_vdp2_vram_decode[offset*4+3] = (data & 0x000000ff) >> 0;
+
+ stv_vdp2_vram_dirty_8x8x4[offset/8] = 1;
+ stv_vdp2_vram_dirty_8x8x8[offset/16] = 1;
+
+ if ( stv_rbg_cache_data.watch_vdp2_vram_writes )
+ {
+ if ( stv_rbg_cache_data.watch_vdp2_vram_writes & STV_VDP2_RBG_ROTATION_PARAMETER_A )
+ {
+ if ( (offset >= stv_rbg_cache_data.map_offset_min[0] &&
+ offset < stv_rbg_cache_data.map_offset_max[0]) ||
+ (offset >= stv_rbg_cache_data.tile_offset_min[0] &&
+ offset < stv_rbg_cache_data.tile_offset_max[0]) )
+ {
+ if ( LOG_VDP2 ) logerror( "RBG Cache: dirtying for RP = 1, write at offset = %06X\n", offset );
+ stv_rbg_cache_data.is_cache_dirty |= STV_VDP2_RBG_ROTATION_PARAMETER_A;
+ stv_rbg_cache_data.watch_vdp2_vram_writes &= ~STV_VDP2_RBG_ROTATION_PARAMETER_A;
+ }
+ }
+ if ( stv_rbg_cache_data.watch_vdp2_vram_writes & STV_VDP2_RBG_ROTATION_PARAMETER_B )
+ {
+ if ( (offset >= stv_rbg_cache_data.map_offset_min[1] &&
+ offset < stv_rbg_cache_data.map_offset_max[1]) ||
+ (offset >= stv_rbg_cache_data.tile_offset_min[1] &&
+ offset < stv_rbg_cache_data.tile_offset_max[1]) )
+ {
+ if ( LOG_VDP2 ) logerror( "RBG Cache: dirtying for RP = 2, write at offset = %06X\n", offset );
+ stv_rbg_cache_data.is_cache_dirty |= STV_VDP2_RBG_ROTATION_PARAMETER_B;
+ stv_rbg_cache_data.watch_vdp2_vram_writes &= ~STV_VDP2_RBG_ROTATION_PARAMETER_B;
+ }
+ }
+
+ }
+
+}
+
+READ32_HANDLER ( stv_vdp2_vram_r )
+{
+ return stv_vdp2_vram[offset];
+}
+
+WRITE32_HANDLER ( stv_vdp2_cram_w )
+{
+ int r,g,b;
+ COMBINE_DATA(&stv_vdp2_cram[offset]);
+
+// popmessage("%01x",STV_VDP2_CRMD);
+
+ switch( STV_VDP2_CRMD )
+ {
+ /*Mode 2/3*/
+ case 2:
+ case 3:
+ {
+ b = ((stv_vdp2_cram[offset] & 0x00ff0000) >> 16);
+ g = ((stv_vdp2_cram[offset] & 0x0000ff00) >> 8);
+ r = ((stv_vdp2_cram[offset] & 0x000000ff) >> 0);
+ palette_set_color(Machine,offset,MAKE_RGB(r,g,b));
+ }
+ break;
+ /*Mode 0*/
+ case 0:
+ {
+ offset &= 0x3ff;
+
+ b = ((stv_vdp2_cram[offset] & 0x00007c00) >> 10);
+ g = ((stv_vdp2_cram[offset] & 0x000003e0) >> 5);
+ r = ((stv_vdp2_cram[offset] & 0x0000001f) >> 0);
+ palette_set_color_rgb(Machine,(offset*2)+1,pal5bit(r),pal5bit(g),pal5bit(b));
+ b = ((stv_vdp2_cram[offset] & 0x7c000000) >> 26);
+ g = ((stv_vdp2_cram[offset] & 0x03e00000) >> 21);
+ r = ((stv_vdp2_cram[offset] & 0x001f0000) >> 16);
+ palette_set_color_rgb(Machine,offset*2,pal5bit(r),pal5bit(g),pal5bit(b));
+ }
+ break;
+ /*Mode 1*/
+ case 1:
+ {
+ offset &= 0x7ff;
+
+ b = ((stv_vdp2_cram[offset] & 0x00007c00) >> 10);
+ g = ((stv_vdp2_cram[offset] & 0x000003e0) >> 5);
+ r = ((stv_vdp2_cram[offset] & 0x0000001f) >> 0);
+ palette_set_color_rgb(Machine,(offset*2)+1,pal5bit(r),pal5bit(g),pal5bit(b));
+ b = ((stv_vdp2_cram[offset] & 0x7c000000) >> 26);
+ g = ((stv_vdp2_cram[offset] & 0x03e00000) >> 21);
+ r = ((stv_vdp2_cram[offset] & 0x001f0000) >> 16);
+ palette_set_color_rgb(Machine,offset*2,pal5bit(r),pal5bit(g),pal5bit(b));
+ }
+ break;
+ }
+}
+
+static void refresh_palette_data()
+{
+ int r,g,b;
+ int c_i;
+
+ for(c_i=0;c_i<0x800;c_i++)
+ {
+ switch( STV_VDP2_CRMD )
+ {
+ /*Mode 2/3*/
+ case 2:
+ case 3:
+ {
+ b = ((stv_vdp2_cram[c_i] & 0x00ff0000) >> 16);
+ g = ((stv_vdp2_cram[c_i] & 0x0000ff00) >> 8);
+ r = ((stv_vdp2_cram[c_i] & 0x000000ff) >> 0);
+ palette_set_color(Machine,c_i,MAKE_RGB(r,g,b));
+ }
+ break;
+ /*Mode 0*/
+ case 0:
+ {
+ //c_i &= 0x3ff;
+
+ b = ((stv_vdp2_cram[c_i] & 0x00007c00) >> 10);
+ g = ((stv_vdp2_cram[c_i] & 0x000003e0) >> 5);
+ r = ((stv_vdp2_cram[c_i] & 0x0000001f) >> 0);
+ palette_set_color_rgb(Machine,(c_i*2)+1,pal5bit(r),pal5bit(g),pal5bit(b));
+ b = ((stv_vdp2_cram[c_i] & 0x7c000000) >> 26);
+ g = ((stv_vdp2_cram[c_i] & 0x03e00000) >> 21);
+ r = ((stv_vdp2_cram[c_i] & 0x001f0000) >> 16);
+ palette_set_color_rgb(Machine,c_i*2,pal5bit(r),pal5bit(g),pal5bit(b));
+ }
+ break;
+ /*Mode 1*/
+ case 1:
+ {
+ //c_i &= 0x7ff;
+
+ b = ((stv_vdp2_cram[c_i] & 0x00007c00) >> 10);
+ g = ((stv_vdp2_cram[c_i] & 0x000003e0) >> 5);
+ r = ((stv_vdp2_cram[c_i] & 0x0000001f) >> 0);
+ palette_set_color_rgb(Machine,(c_i*2)+1,pal5bit(r),pal5bit(g),pal5bit(b));
+ b = ((stv_vdp2_cram[c_i] & 0x7c000000) >> 26);
+ g = ((stv_vdp2_cram[c_i] & 0x03e00000) >> 21);
+ r = ((stv_vdp2_cram[c_i] & 0x001f0000) >> 16);
+ palette_set_color_rgb(Machine,c_i*2,pal5bit(r),pal5bit(g),pal5bit(b));
+ }
+ break;
+ }
+ }
+}
+
+READ32_HANDLER ( stv_vdp2_cram_r )
+{
+ return stv_vdp2_cram[offset];
+}
+
+WRITE32_HANDLER ( stv_vdp2_regs_w )
+{
+ static UINT8 old_crmd;
+ COMBINE_DATA(&stv_vdp2_regs[offset]);
+
+ if(old_crmd != STV_VDP2_CRMD)
+ {
+ old_crmd = STV_VDP2_CRMD;
+ refresh_palette_data();
+ }
+}
+
+extern int stv_vblank,stv_hblank;
+READ32_HANDLER ( stv_vdp2_regs_r )
+{
+// if (offset!=1) if(LOG_VDP2) logerror ("VDP2: Read from Registers, Offset %04x\n",offset);
+
+ switch(offset)
+ {
+ case 0x4/4:
+ /*Screen Status Register*/
+ /*VBLANK HBLANK ODD PAL */
+ stv_vdp2_regs[offset] = (stv_vblank<<19) | (stv_hblank<<18) | (1 << 17) | (0 << 16);
+ break;
+ case 0x8/4:
+ /*H/V Counter Register*/
+ /*H-Counter V-Counter */
+ stv_vdp2_regs[offset] = (((Machine->screen[0].visarea.max_x - 1)<<16)&0x3ff0000)|(((Machine->screen[0].visarea.max_y - 1)<<0)& ((STV_VDP2_LSMD == 3) ? 0x7ff : 0x3ff));
+ if(LOG_VDP2) logerror("CPU #%d PC(%08x) = VDP2: H/V counter read : %08x\n",cpu_getactivecpu(),activecpu_get_pc(),stv_vdp2_regs[offset]);
+ stv_vdp2_regs[offset] = 0;
+ break;
+ }
+ return stv_vdp2_regs[offset];
+}
+
+static void stv_vdp2_state_save_postload(void)
+{
+ UINT8 *stv_vdp2_vram_decode = stv_vdp2_gfx_decode;
+ int offset;
+ UINT32 data;
+
+ for ( offset = 0; offset < 0x100000/4; offset++ )
+ {
+ data = stv_vdp2_vram[offset];
+ /* put in gfx region for easy decoding */
+ stv_vdp2_vram_decode[offset*4+0] = (data & 0xff000000) >> 24;
+ stv_vdp2_vram_decode[offset*4+1] = (data & 0x00ff0000) >> 16;
+ stv_vdp2_vram_decode[offset*4+2] = (data & 0x0000ff00) >> 8;
+ stv_vdp2_vram_decode[offset*4+3] = (data & 0x000000ff) >> 0;
+
+ stv_vdp2_vram_dirty_8x8x4[offset/8] = 1;
+ stv_vdp2_vram_dirty_8x8x8[offset/16] = 1;
+ }
+
+ memset( &stv_rbg_cache_data, 0, sizeof(stv_rbg_cache_data));
+ stv_rbg_cache_data.is_cache_dirty = 3;
+ memset( &stv_vdp2_layer_data_placement, 0, sizeof(stv_vdp2_layer_data_placement));
+
+ refresh_palette_data();
+}
+
+static int stv_vdp2_start (running_machine *machine)
+{
+ stv_vdp2_regs = auto_malloc ( 0x040000 );
+ stv_vdp2_vram = auto_malloc ( 0x100000 ); // actually we only need half of it since we don't emulate extra 4mbit ram cart.
+ stv_vdp2_cram = auto_malloc ( 0x080000 );
+ stv_vdp2_gfx_decode = auto_malloc ( 0x100000 );
+ stv_vdp2_vram_dirty_8x8x4 = auto_malloc ( 0x100000 );
+ stv_vdp2_vram_dirty_8x8x8 = auto_malloc ( 0x100000 );
+
+ memset(stv_vdp2_regs, 0, 0x040000);
+ memset(stv_vdp2_vram, 0, 0x100000);
+ memset(stv_vdp2_cram, 0, 0x080000);
+
+ stv_vdp2_render_rbg0 = 1;
+// machine->gfx[0]->color_granularity=4;
+// machine->gfx[1]->color_granularity=4;
+
+ memset( &stv_rbg_cache_data, 0, sizeof(stv_rbg_cache_data));
+ stv_rbg_cache_data.is_cache_dirty = 3;
+ memset( &stv_vdp2_layer_data_placement, 0, sizeof(stv_vdp2_layer_data_placement));
+
+ state_save_register_global_pointer(stv_vdp2_regs, 0x040000/4);
+ state_save_register_global_pointer(stv_vdp2_vram, 0x100000/4);
+ state_save_register_global_pointer(stv_vdp2_cram, 0x080000/4);
+ state_save_register_func_postload(stv_vdp2_state_save_postload);
+
+ return 0;
+}
+
+/* maybe we should move this to video/stv.c */
+VIDEO_START( stv_vdp2 )
+{
+ stv_vdp2_roz_bitmap[0] = stv_vdp2_roz_bitmap[1] = NULL;
+ stv_vdp2_start(machine);
+ stv_vdp1_start();
+ debug.l_en = 0xff;
+ debug.error = 0xffffffff;
+ debug.roz = 0;
+}
+
+static void stv_vdp2_dynamic_res_change()
+{
+ static UINT16 horz,vert;
+
+ switch( STV_VDP2_VRES & 3 )
+ {
+ case 0: vert = 224; break;
+ case 1: vert = 240; break;
+ case 2: vert = 256; break;
+ case 3:
+ if(LOG_VDP2) logerror("WARNING: V Res setting (3) not allowed!\n");
+ vert = 256;
+ break;
+ }
+
+ /*Double-density interlace mode,doubles the vertical res*/
+ if((STV_VDP2_LSMD & 3) == 3) { vert*=2; }
+
+ switch( STV_VDP2_HRES & 7 )
+ {
+ case 0: horz = 320; break;
+ case 1: horz = 352; break;
+ case 2: horz = 640; break;
+ case 3: horz = 704; break;
+ /*Exclusive modes,they sets the Vertical Resolution without considering the
+ VRES register.*/
+ case 4: horz = 320; vert = 480; break;
+ case 5: horz = 352; vert = 480; break;
+ case 6: horz = 640; vert = 480; break;
+ case 7: horz = 704; vert = 480; break;
+ }
+
+ video_screen_set_visarea(0, 0*8, horz-1,0*8, vert-1);
+ //if(LOG_VDP2) popmessage("%04d %04d",horz-1,vert-1);
+}
+
+/*This is for calculating the rgb brightness*/
+/*TODO: Optimize this...*/
+static void stv_vdp2_fade_effects(running_machine *machine)
+{
+ /*
+ Note:We have to use temporary storages because palette_get_color must use
+ variables setted with unsigned int8
+ */
+ INT16 t_r,t_g,t_b;
+ UINT8 r,g,b;
+ rgb_t color;
+ int i;
+ //popmessage("%04x %04x",STV_VDP2_CLOFEN,STV_VDP2_CLOFSL);
+ for(i=0;i<2048;i++)
+ {
+ /*Fade A*/
+ color = palette_get_color(machine, i);
+ t_r = (STV_VDP2_COAR & 0x100) ? (RGB_RED(color) - (0x100 - (STV_VDP2_COAR & 0xff))) : ((STV_VDP2_COAR & 0xff) + RGB_RED(color));
+ t_g = (STV_VDP2_COAG & 0x100) ? (RGB_GREEN(color) - (0x100 - (STV_VDP2_COAG & 0xff))) : ((STV_VDP2_COAG & 0xff) + RGB_GREEN(color));
+ t_b = (STV_VDP2_COAB & 0x100) ? (RGB_BLUE(color) - (0x100 - (STV_VDP2_COAB & 0xff))) : ((STV_VDP2_COAB & 0xff) + RGB_BLUE(color));
+ if(t_r < 0) { t_r = 0; }
+ if(t_r > 0xff) { t_r = 0xff; }
+ if(t_g < 0) { t_g = 0; }
+ if(t_g > 0xff) { t_g = 0xff; }
+ if(t_b < 0) { t_b = 0; }
+ if(t_b > 0xff) { t_b = 0xff; }
+ r = t_r;
+ g = t_g;
+ b = t_b;
+ palette_set_color(machine,i+(2048*1),MAKE_RGB(r,g,b));
+
+ /*Fade B*/
+ color = palette_get_color(machine, i);
+ t_r = (STV_VDP2_COBR & 0x100) ? (RGB_RED(color) - (0xff - (STV_VDP2_COBR & 0xff))) : ((STV_VDP2_COBR & 0xff) + RGB_RED(color));
+ t_g = (STV_VDP2_COBG & 0x100) ? (RGB_GREEN(color) - (0xff - (STV_VDP2_COBG & 0xff))) : ((STV_VDP2_COBG & 0xff) + RGB_GREEN(color));
+ t_b = (STV_VDP2_COBB & 0x100) ? (RGB_BLUE(color) - (0xff - (STV_VDP2_COBB & 0xff))) : ((STV_VDP2_COBB & 0xff) + RGB_BLUE(color));
+ if(t_r < 0) { t_r = 0; }
+ if(t_r > 0xff) { t_r = 0xff; }
+ if(t_g < 0) { t_g = 0; }
+ if(t_g > 0xff) { t_g = 0xff; }
+ if(t_b < 0) { t_b = 0; }
+ if(t_b > 0xff) { t_b = 0xff; }
+ r = t_r;
+ g = t_g;
+ b = t_b;
+ palette_set_color(machine,i+(2048*2),MAKE_RGB(r,g,b));
+ }
+ //popmessage("%04x %04x %04x %04x %04x %04x",STV_VDP2_COAR,STV_VDP2_COAG,STV_VDP2_COAB,STV_VDP2_COBR,STV_VDP2_COBG,STV_VDP2_COBB);
+}
+
+/******************************************************************************************
+
+ST-V VDP2 window effect function version 0.03
+
+How it works: returns 0 if the requested pixel is drawnable,1 if it isn't.
+For tilemap and sprite layer, clipping rectangle is changed.
+
+Done:
+-Basic support(w0 or w1),bitmaps only.
+-W0 (outside) for tilemaps and sprite layer.
+
+Not Done:
+-Windows on cells.Requires that the tilemap are converted to bitmap AFAIK...
+-w0 & w1 at the same time.
+-Window logic.
+-Line window.
+-Color Calculation.
+-Rotation parameter Window.
+
+Window Registers are hooked up like this ATM:
+ x--- ---- UNUSED
+ -x-- ---- Sprite Window Area
+ --x- ---- Window 1 Area
+ ---x ---- Window 0 Area
+ (0 = Inside,1 = Outside)
+ ---- x--- Sprite Window Enable
+ ---- -x-- Window 1 Enable
+ ---- --x- Window 0 Enable
+ (0 = Disabled,1 = Enabled)
+ ---- ---x Window Logic
+ (0 = OR,1 = AND)
+******************************************************************************************/
+
+static void stv_vdp2_get_window0_coordinates(UINT16 *s_x, UINT16 *e_x, UINT16 *s_y, UINT16 *e_y)
+{
+ /*W0*/
+ switch(STV_VDP2_LSMD & 3)
+ {
+ case 0:
+ case 1:
+ case 2:
+ *s_y = ((STV_VDP2_W0SY & 0x3ff) >> 0);
+ *e_y = ((STV_VDP2_W0EY & 0x3ff) >> 0);
+ break;
+ case 3:
+ *s_y = ((STV_VDP2_W0SY & 0x7ff) >> 0);
+ *e_y = ((STV_VDP2_W0EY & 0x7ff) >> 0);
+ break;
+ }
+ switch(STV_VDP2_HRES & 6)
+ {
+ /*Normal*/
+ case 0:
+ *s_x = ((STV_VDP2_W0SX & 0x3fe) >> 1);
+ *e_x = ((STV_VDP2_W0EX & 0x3fe) >> 1);
+ break;
+ /*Hi-Res*/
+ case 2:
+ *s_x = ((STV_VDP2_W0SX & 0x3ff) >> 0);
+ *e_x = ((STV_VDP2_W0EX & 0x3ff) >> 0);
+ break;
+ /*Exclusive Normal*/
+ case 4:
+ *s_x = ((STV_VDP2_W0SX & 0x1ff) >> 0);
+ *e_x = ((STV_VDP2_W0EX & 0x1ff) >> 0);
+ *s_y = ((STV_VDP2_W0SY & 0x3ff) >> 0);
+ *e_y = ((STV_VDP2_W0EY & 0x3ff) >> 0);
+ break;
+ /*Exclusive Hi-Res*/
+ case 6:
+ *s_x = ((STV_VDP2_W0SX & 0x1ff) << 1);
+ *e_x = ((STV_VDP2_W0EX & 0x1ff) << 1);
+ *s_y = ((STV_VDP2_W0SY & 0x3ff) >> 0);
+ *e_y = ((STV_VDP2_W0EY & 0x3ff) >> 0);
+ break;
+ }
+}
+
+static void stv_vdp2_get_window1_coordinates(UINT16 *s_x, UINT16 *e_x, UINT16 *s_y, UINT16 *e_y)
+{
+ /*W1*/
+ switch(STV_VDP2_LSMD & 3)
+ {
+ case 0:
+ case 1:
+ case 2:
+ *s_y = ((STV_VDP2_W1SY & 0x3ff) >> 0);
+ *e_y = ((STV_VDP2_W1EY & 0x3ff) >> 0);
+ break;
+ case 3:
+ *s_y = ((STV_VDP2_W1SY & 0x3ff) >> 0);
+ *e_y = ((STV_VDP2_W1EY & 0x3ff) >> 0);
+ break;
+ }
+ switch(STV_VDP2_HRES & 6)
+ {
+ /*Normal*/
+ case 0:
+ *s_x = ((STV_VDP2_W1SX & 0x3fe) >> 1);
+ *e_x = ((STV_VDP2_W1EX & 0x3fe) >> 1);
+ break;
+ /*Hi-Res*/
+ case 2:
+ *s_x = ((STV_VDP2_W1SX & 0x3ff) >> 0);
+ *e_x = ((STV_VDP2_W1EX & 0x3ff) >> 0);
+ break;
+ /*Exclusive Normal*/
+ case 4:
+ *s_x = ((STV_VDP2_W1SX & 0x1ff) >> 0);
+ *e_x = ((STV_VDP2_W1EX & 0x1ff) >> 0);
+ *s_y = ((STV_VDP2_W1SY & 0x3ff) >> 0);
+ *e_y = ((STV_VDP2_W1EY & 0x3ff) >> 0);
+ break;
+ /*Exclusive Hi-Res*/
+ case 6:
+ *s_x = ((STV_VDP2_W1SX & 0x1ff) << 1);
+ *e_x = ((STV_VDP2_W1EX & 0x1ff) << 1);
+ *s_y = ((STV_VDP2_W1SY & 0x3ff) >> 0);
+ *e_y = ((STV_VDP2_W1EY & 0x3ff) >> 0);
+ break;
+ }
+
+}
+
+static int stv_vdp2_window_process(int x,int y)
+{
+ UINT16 s_x=0,e_x=0,s_y=0,e_y=0;
+
+ if ((stv2_current_tilemap.window_control & 6) == 0)
+ return 0;
+
+ stv_vdp2_get_window0_coordinates(&s_x, &e_x, &s_y, &e_y);
+
+ if(stv2_current_tilemap.window_control & 2)
+ {
+ /*Outside Area*/
+ if(stv2_current_tilemap.window_control & 0x10)
+ {
+ if(y < s_y || y > e_y)
+ return 1;
+ else
+ {
+ if(x < s_x || x > e_x)
+ return 1;
+ //else
+ // return 0;
+ }
+ }
+ /*Inside Area*/
+ else
+ {
+ if(y > s_y && y < e_y)
+ {
+ if(x > s_x && x < e_x)
+ return 1;
+ }
+ //else
+ // return 0;
+ }
+ }
+
+ stv_vdp2_get_window1_coordinates(&s_x, &e_x, &s_y, &e_y);
+
+ if(stv2_current_tilemap.window_control & 4)
+ {
+ /*Outside Area*/
+ if(stv2_current_tilemap.window_control & 0x20)
+ {
+ if(y < s_y || y > e_y)
+ return 1;
+ else
+ {
+ if(x < s_x || x > e_x)
+ return 1;
+ //else
+ // return 0;
+ }
+ }
+ /*Inside Area*/
+ else
+ {
+ if(y > s_y && y < e_y)
+ {
+ if(x > s_x && x < e_x)
+ return 1;
+ }
+ //else
+ // return 0;
+ }
+ }
+ return 0;
+// return 1;
+}
+
+static int stv_vdp2_apply_window_on_layer(rectangle *cliprect)
+{
+ UINT16 s_x=0,e_x=0,s_y=0,e_y=0;
+
+ if ( stv2_current_tilemap.window_control == 0x12 )
+ {
+ /* w0, transparent outside supported */
+ stv_vdp2_get_window0_coordinates(&s_x, &e_x, &s_y, &e_y);
+
+ if ( s_x > cliprect->min_x ) cliprect->min_x = s_x;
+ if ( e_x < cliprect->max_x ) cliprect->max_x = e_x;
+ if ( s_y > cliprect->min_y ) cliprect->min_y = s_y;
+ if ( e_y < cliprect->max_y ) cliprect->max_y = e_y;
+
+ return 1;
+ }
+ else if ( stv2_current_tilemap.window_control == 0x24 )
+ {
+ /* w1, transparent outside supported */
+ stv_vdp2_get_window1_coordinates(&s_x, &e_x, &s_y, &e_y);
+
+ if ( s_x > cliprect->min_x ) cliprect->min_x = s_x;
+ if ( e_x < cliprect->max_x ) cliprect->max_x = e_x;
+ if ( s_y > cliprect->min_y ) cliprect->min_y = s_y;
+ if ( e_y < cliprect->max_y ) cliprect->max_y = e_y;
+
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/* VDP1 Framebuffer handling */
+extern UINT16 **stv_framebuffer_display_lines;
+extern int stv_framebuffer_width;
+extern int stv_framebuffer_height;
+extern int stv_framebuffer_double_interlace;
+extern int stv_framebuffer_mode;
+
+static int stv_sprite_priorities_used[8];
+static int stv_sprite_priorities_usage_valid;
+static UINT8 stv_sprite_priorities_in_fb_line[512][8];
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8 pri)
+{
+ int x,y,r,g,b;
+ int i;
+ UINT16 pix;
+ UINT16 *framebuffer_line;
+ UINT16 *bitmap_line, *bitmap_line2 = NULL;
+ UINT8 interlace_framebuffer;
+ UINT8 double_x;
+ static const UINT16 sprite_colormask_table[] = { 0x07ff, 0x07ff, 0x07ff, 0x07ff, 0x03ff, 0x07ff, 0x03ff, 0x01ff,
+ 0x007f, 0x003f, 0x003f, 0x003f, 0x0ff, 0x0ff, 0x0ff, 0x0ff };
+ static const UINT16 priority_shift_table[] = { 14, 13, 14, 13, 13, 12, 12, 12, 7, 7, 6, 0, 7, 7, 6, 0 };
+ static const UINT16 priority_mask_table[] = { 3, 7, 1, 3, 3, 7, 7, 7, 1, 1, 3, 0, 1, 1, 3, 0 };
+ static const UINT16 ccrr_shift_table[] = { 11, 11, 11, 11, 10, 11, 10, 9, 0, 6, 0, 6, 0, 6, 0, 6 };
+ static const UINT16 ccrr_mask_table[] = { 7, 3, 7, 3, 7, 1, 3, 7, 0, 1, 0, 3, 0, 1, 0, 3 };
+ UINT16 alpha_enabled;
+
+ int sprite_type;
+ int sprite_colormask;
+ int color_offset_pal;
+ UINT16 sprite_priority_shift, sprite_priority_mask, sprite_ccrr_shift, sprite_ccrr_mask;
+ UINT8 priority;
+ UINT8 ccr = 0;
+ UINT8 sprite_priorities[8];
+ UINT8 sprite_ccr[8];
+ int sprite_color_mode = STV_VDP2_SPCLMD;
+ rectangle mycliprect;
+
+ if ( (stv_sprite_priorities_usage_valid == 1) && (stv_sprite_priorities_used[pri] == 0) )
+ return;
+
+ sprite_priorities[0] = STV_VDP2_S0PRIN;
+ sprite_priorities[1] = STV_VDP2_S1PRIN;
+ sprite_priorities[2] = STV_VDP2_S2PRIN;
+ sprite_priorities[3] = STV_VDP2_S3PRIN;
+ sprite_priorities[4] = STV_VDP2_S4PRIN;
+ sprite_priorities[5] = STV_VDP2_S5PRIN;
+ sprite_priorities[6] = STV_VDP2_S6PRIN;
+ sprite_priorities[7] = STV_VDP2_S7PRIN;
+
+ sprite_ccr[0] = STV_VDP2_S0CCRT;
+ sprite_ccr[1] = STV_VDP2_S1CCRT;
+ sprite_ccr[2] = STV_VDP2_S2CCRT;
+ sprite_ccr[3] = STV_VDP2_S3CCRT;
+ sprite_ccr[4] = STV_VDP2_S4CCRT;
+ sprite_ccr[5] = STV_VDP2_S5CCRT;
+ sprite_ccr[6] = STV_VDP2_S6CCRT;
+ sprite_ccr[7] = STV_VDP2_S7CCRT;
+
+ sprite_type = STV_VDP2_SPTYPE;
+ sprite_colormask = sprite_colormask_table[sprite_type];
+ sprite_priority_shift = priority_shift_table[sprite_type];
+ sprite_priority_mask = priority_mask_table[sprite_type];
+ sprite_ccrr_shift = ccrr_shift_table[sprite_type];
+ sprite_ccrr_mask = ccrr_mask_table[sprite_type];
+
+ for ( i = 0; i < (sprite_priority_mask+1); i++ ) if ( sprite_priorities[i] == pri ) break;
+ if ( i == (sprite_priority_mask+1) ) return;
+
+ /* color offset (RGB brightness) */
+ color_offset_pal = 0;
+ if ( STV_VDP2_SPCOEN )
+ {
+ if ( STV_VDP2_SPCOSL == 0 )
+ { color_offset_pal = 2048; }
+ else
+ { color_offset_pal = 2048*2; }
+ }
+
+ /* color calculation (alpha blending)*/
+ if ( STV_VDP2_SPCCEN )
+ {
+ alpha_enabled = 0;
+ switch( STV_VDP2_SPCCCS )
+ {
+ case 0x0: if ( pri <= STV_VDP2_SPCCN ) alpha_enabled = 1; break;
+ case 0x1: if ( pri == STV_VDP2_SPCCN ) alpha_enabled = 1; break;
+ case 0x2: if ( pri >= STV_VDP2_SPCCN ) alpha_enabled = 1; break;
+ case 0x3: /* MSBON */ break;
+ }
+ }
+ else
+ {
+ alpha_enabled = 0;
+ }
+
+ /* framebuffer interlace */
+ if ( (STV_VDP2_LSMD == 2 || STV_VDP2_LSMD == 3) && stv_framebuffer_double_interlace == 0 )
+ interlace_framebuffer = 1;
+ else
+ interlace_framebuffer = 0;
+
+ /*Guess:Some games needs that the horizontal sprite size to be doubled
+ (TODO: understand the proper settings,it might not work like this)*/
+ if(STV_VDP2_LSMD == 3 && /*((STV_VDP2_HRES & 3) != 3) &&*/ (!(stv_framebuffer_mode & 1)))
+ double_x = 1;
+ else
+ double_x = 0;
+
+ /* window control */
+ stv2_current_tilemap.window_control = (STV_VDP2_SPLOG * 0x01) |
+ (STV_VDP2_SPW0E * 0x02) |
+ (STV_VDP2_SPW1E * 0x04) |
+ (STV_VDP2_SPSWE * 0x08) |
+ (STV_VDP2_SPW0A * 0x10) |
+ (STV_VDP2_SPW1A * 0x20) |
+ (STV_VDP2_SPSWA * 0x40);
+ mycliprect.min_x = cliprect->min_x;
+ mycliprect.max_x = cliprect->max_x;
+ mycliprect.min_y = cliprect->min_y;
+ mycliprect.max_y = cliprect->max_y;
+ stv_vdp2_apply_window_on_layer(&mycliprect);
+
+ if (interlace_framebuffer == 0 && double_x == 0 )
+ {
+ if ( alpha_enabled == 0 )
+ {
+ for ( y = mycliprect.min_y; y <= mycliprect.max_y; y++ )
+ {
+ if ( stv_sprite_priorities_usage_valid )
+ if (stv_sprite_priorities_in_fb_line[y][pri] == 0)
+ continue;
+
+ framebuffer_line = stv_framebuffer_display_lines[y];
+ bitmap_line = BITMAP_ADDR16(bitmap, y, 0);
+
+ for ( x = mycliprect.min_x; x <= mycliprect.max_x; x++ )
+ {
+ pix = framebuffer_line[x];
+ if ( (pix & 0x8000) && sprite_color_mode)
+ {
+ if ( sprite_priorities[0] != pri )
+ {
+ stv_sprite_priorities_used[sprite_priorities[0]] = 1;
+ stv_sprite_priorities_in_fb_line[y][sprite_priorities[0]] = 1;
+ continue;
+ };
+ b = (pix & 0x7c00) >> 10;
+ g = (pix & 0x03e0) >> 5;
+ r = (pix & 0x1f);
+ if ( color_offset_pal )
+ {
+ stv_vdp2_compute_color_offset_RGB555( &r, &g, &b, STV_VDP2_SPCOSL );
+ }
+ bitmap_line[x] = b | g << 5 | r << 10;
+ }
+ else
+ {
+ priority = sprite_priorities[(pix >> sprite_priority_shift) & sprite_priority_mask];
+ if ( priority != pri )
+ {
+ stv_sprite_priorities_used[priority] = 1;
+ stv_sprite_priorities_in_fb_line[y][priority] = 1;
+ continue;
+ };
+
+ pix &= sprite_colormask;
+ if ( pix == (sprite_colormask - 1) )
+ {
+ /*shadow - in reality, we should check from what layer pixel beneath comes...*/
+ if ( STV_VDP2_SDCTL & 0x3f )
+ {
+ bitmap_line[x] = (bitmap_line[x] & ~0x421) >> 1;
+ }
+ /* note that when shadows are disabled, "shadow" palette entries are not drawn */
+ }
+ else if ( pix )
+ {
+ pix += (STV_VDP2_SPCAOS << 8);
+ pix &= 0x7ff;
+ pix += color_offset_pal;
+ bitmap_line[x] = machine->pens[ pix ];
+ }
+ }
+ }
+ }
+ }
+ else //alpha_enabled == 1
+ {
+ for ( y = mycliprect.min_y; y <= mycliprect.max_y; y++ )
+ {
+ if ( stv_sprite_priorities_usage_valid )
+ if (stv_sprite_priorities_in_fb_line[y][pri] == 0)
+ continue;
+
+ framebuffer_line = stv_framebuffer_display_lines[y];
+ bitmap_line = BITMAP_ADDR16(bitmap, y, 0);
+
+ for ( x = mycliprect.min_x; x <= mycliprect.max_x; x++ )
+ {
+ pix = framebuffer_line[x];
+ if ( (pix & 0x8000) && sprite_color_mode)
+ {
+ if ( sprite_priorities[0] != pri )
+ {
+ stv_sprite_priorities_used[sprite_priorities[0]] = 1;
+ stv_sprite_priorities_in_fb_line[y][sprite_priorities[0]] = 1;
+ continue;
+ };
+
+ b = (pix & 0x7c00) >> 10;
+ g = (pix & 0x03e0) >> 5;
+ r = (pix & 0x1f);
+ if ( color_offset_pal )
+ {
+ stv_vdp2_compute_color_offset_RGB555( &r, &g, &b, STV_VDP2_SPCOSL );
+ }
+ ccr = sprite_ccr[0];
+ if ( STV_VDP2_CCMD )
+ {
+ bitmap_line[x] = stv_add_blend( bitmap_line[x], b | g << 5 | r << 10 );
+ }
+ else
+ {
+ bitmap_line[x] = alpha_blend_r16( bitmap_line[x], b | g << 5 | r << 10, ((UINT16)(0x1f-ccr)*0xff)/0x1f);
+ }
+ }
+ else
+ {
+ priority = sprite_priorities[(pix >> sprite_priority_shift) & sprite_priority_mask];
+ if ( priority != pri )
+ {
+ stv_sprite_priorities_used[priority] = 1;
+ stv_sprite_priorities_in_fb_line[y][priority] = 1;
+ continue;
+ };
+
+ ccr = sprite_ccr[ (pix >> sprite_ccrr_shift) & sprite_ccrr_mask ];
+
+ pix &= sprite_colormask;
+ if ( pix == (sprite_colormask - 1) )
+ {
+ /*shadow - in reality, we should check from what layer pixel beneath comes...*/
+ if ( STV_VDP2_SDCTL & 0x3f )
+ {
+ bitmap_line[x] = (bitmap_line[x] & ~0x421) >> 1;
+ }
+ /* note that when shadows are disabled, "shadow" palette entries are not drawn */
+ } else if ( pix )
+ {
+ pix += (STV_VDP2_SPCAOS << 8);
+ pix &= 0x7ff;
+ pix += color_offset_pal;
+ if ( ccr > 0 )
+ {
+ if ( STV_VDP2_CCMD )
+ {
+ bitmap_line[x] = stv_add_blend( bitmap_line[x], machine->pens[pix] );
+ }
+ else
+ {
+ bitmap_line[x] = alpha_blend_r16( bitmap_line[x], machine->pens[pix], ((UINT16)(0x1f-ccr)*0xff)/0x1f );
+ }
+ }
+ else
+ bitmap_line[x] = machine->pens[pix];
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for ( y = mycliprect.min_y; y <= mycliprect.max_y; y++ )
+ {
+ if ( stv_sprite_priorities_usage_valid )
+ if (stv_sprite_priorities_in_fb_line[y][pri] == 0)
+ continue;
+
+ framebuffer_line = stv_framebuffer_display_lines[y];
+ if ( interlace_framebuffer == 0 )
+ {
+ bitmap_line = BITMAP_ADDR16(bitmap, y, 0);
+ }
+ else
+ {
+ bitmap_line = BITMAP_ADDR16(bitmap, 2*y, 0);
+ bitmap_line2 = BITMAP_ADDR16(bitmap, 2*y + 1, 0);
+ }
+
+ for ( x = mycliprect.min_x; double_x ? x <= ((mycliprect.max_x)/2) : (x <= mycliprect.max_x); x++ )
+ {
+ pix = framebuffer_line[x];
+ if ( (pix & 0x8000) && sprite_color_mode)
+ {
+ if ( sprite_priorities[0] != pri )
+ {
+ stv_sprite_priorities_used[sprite_priorities[0]] = 1;
+ stv_sprite_priorities_in_fb_line[y][sprite_priorities[0]] = 1;
+ continue;
+ };
+ b = (pix & 0x7c00) >> 10;
+ g = (pix & 0x03e0) >> 5;
+ r = (pix & 0x1f);
+ if ( color_offset_pal )
+ {
+ stv_vdp2_compute_color_offset_RGB555( &r, &g, &b, STV_VDP2_SPCOSL );
+ }
+ if ( alpha_enabled == 0 )
+ {
+ if(double_x)
+ {
+ bitmap_line[x*2] = b | g << 5 | r << 10;
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x*2] = b | g << 5 | r << 10;
+ bitmap_line[x*2+1] = b | g << 5 | r << 10;
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x*2+1] = b | g << 5 | r << 10;
+ }
+ else
+ {
+ bitmap_line[x] = b | g << 5 | r << 10;
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x] = b | g << 5 | r << 10;
+ }
+ }
+ else // alpha_blend == 1
+ {
+ ccr = sprite_ccr[0];
+
+ if ( STV_VDP2_CCMD )
+ {
+ if(double_x)
+ {
+ bitmap_line[x*2] = stv_add_blend( bitmap_line[x*2], b | g << 5 | r << 10 );
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x*2] = stv_add_blend( bitmap_line2[x*2], b | g << 5 | r << 10 );
+ bitmap_line[x*2+1] = stv_add_blend( bitmap_line[x*2+1], b | g << 5 | r << 10 );
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x*2+1] = stv_add_blend( bitmap_line2[x*2+1], b | g << 5 | r << 10 );
+ }
+ else
+ {
+ bitmap_line[x] = stv_add_blend( bitmap_line[x], b | g << 5 | r << 10 );
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x] = stv_add_blend( bitmap_line2[x], b | g << 5 | r << 10 );
+ }
+ }
+ else
+ {
+ if(double_x)
+ {
+ bitmap_line[x*2] = alpha_blend_r16( bitmap_line[x*2], b | g << 5 | r << 10, ((UINT16)(0x1f-ccr)*0xff)/0x1f );
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x*2] = alpha_blend_r16( bitmap_line2[x*2], b | g << 5 | r << 10, ((UINT16)(0x1f-ccr)*0xff)/0x1f );
+ bitmap_line[x*2+1] = alpha_blend_r16( bitmap_line[x*2+1], b | g << 5 | r << 10, ((UINT16)(0x1f-ccr)*0xff)/0x1f );
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x*2+1] = alpha_blend_r16( bitmap_line2[x*2+1], b | g << 5 | r << 10, ((UINT16)(0x1f-ccr)*0xff)/0x1f);
+ }
+ else
+ {
+ bitmap_line[x] = alpha_blend_r16( bitmap_line[x], b | g << 5 | r << 10, ((UINT16)(0x1f-ccr)*0xff)/0x1f);
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x] = alpha_blend_r16( bitmap_line2[x], b | g << 5 | r << 10, ((UINT16)(0x1f-ccr)*0xff)/0x1f);
+ }
+ }
+ }
+ }
+ else
+ {
+ priority = sprite_priorities[(pix >> sprite_priority_shift) & sprite_priority_mask];
+ if ( priority != pri )
+ {
+ stv_sprite_priorities_used[priority] = 1;
+ stv_sprite_priorities_in_fb_line[y][priority] = 1;
+ continue;
+ };
+
+ if ( alpha_enabled )
+ ccr = sprite_ccr[ (pix >> sprite_ccrr_shift) & sprite_ccrr_mask ];
+
+ pix &= sprite_colormask;
+ if ( pix == (sprite_colormask - 1) )
+ {
+ /*shadow - in reality, we should check from what layer pixel beneath comes...*/
+ if ( STV_VDP2_SDCTL & 0x3f )
+ {
+ bitmap_line[x] = (bitmap_line[x] & ~0x421) >> 1;
+ }
+ /* note that when shadows are disabled, "shadow" palette entries are not drawn */
+ } else if ( pix )
+ {
+ pix += (STV_VDP2_SPCAOS << 8);
+ pix &= 0x7ff;
+ pix += color_offset_pal;
+ if ( alpha_enabled == 0 )
+ {
+ if(double_x)
+ {
+ bitmap_line[x*2] = machine->pens[ pix ];
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x*2] = machine->pens[ pix ];
+ bitmap_line[x*2+1] = machine->pens[ pix ];
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x*2+1] = machine->pens[ pix ];
+ }
+ else
+ {
+ bitmap_line[x] = machine->pens[ pix ];
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x] = machine->pens[ pix ];
+ }
+ }
+ else // alpha_blend == 1
+ {
+ if ( STV_VDP2_CCMD )
+ {
+ if(double_x)
+ {
+ bitmap_line[x*2] = stv_add_blend( bitmap_line[x*2], machine->pens[pix] );
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x*2] = stv_add_blend( bitmap_line2[x], machine->pens[pix] );
+ bitmap_line[x*2+1] = stv_add_blend( bitmap_line[x*2+1], machine->pens[pix] );
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x*2+1] = stv_add_blend( bitmap_line2[x], machine->pens[pix] );
+ }
+ else
+ {
+ bitmap_line[x] = stv_add_blend( bitmap_line[x], machine->pens[pix] );
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x] = stv_add_blend( bitmap_line2[x], machine->pens[pix] );
+ }
+ }
+ else
+ {
+ if(double_x)
+ {
+ bitmap_line[x*2] = alpha_blend_r16( bitmap_line[x*2], machine->pens[pix], ((UINT16)(0x1f-ccr)*0xff)/0x1f );
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x*2] = alpha_blend_r16( bitmap_line2[x], machine->pens[pix], ((UINT16)(0x1f-ccr)*0xff)/0x1f );
+ bitmap_line[x*2+1] = alpha_blend_r16( bitmap_line[x*2+1], machine->pens[pix], ((UINT16)(0x1f-ccr)*0xff)/0x1f );
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x*2+1] = alpha_blend_r16( bitmap_line2[x], machine->pens[pix], ((UINT16)(0x1f-ccr)*0xff)/0x1f );
+ }
+ else
+ {
+ bitmap_line[x] = alpha_blend_r16( bitmap_line[x], machine->pens[pix], ((UINT16)(0x1f-ccr)*0xff)/0x1f );
+ if ( interlace_framebuffer == 1 ) bitmap_line2[x] = alpha_blend_r16( bitmap_line2[x], machine->pens[pix], ((UINT16)(0x1f-ccr)*0xff)/0x1f );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ stv_sprite_priorities_usage_valid = 1;
+}
+
+extern UINT32 *stv_vdp1_vram;
+
+VIDEO_UPDATE( stv_vdp2 )
+{
+ static UINT8 pri;
+
+ stv_vdp2_dynamic_res_change();
+
+ video_update_vdp1(machine);
+
+ stv_vdp2_fade_effects(machine);
+
+ stv_vdp2_draw_back(machine, bitmap,cliprect);
+
+ #ifdef MAME_DEBUG
+ if(input_code_pressed_once(KEYCODE_T))
+ {
+ debug.l_en^=1;
+ popmessage("NBG3 %sabled",debug.l_en & 1 ? "en" : "dis");
+ }
+ if(input_code_pressed_once(KEYCODE_Y))
+ {
+ debug.l_en^=2;
+ popmessage("NBG2 %sabled",debug.l_en & 2 ? "en" : "dis");
+ }
+ if(input_code_pressed_once(KEYCODE_U))
+ {
+ debug.l_en^=4;
+ popmessage("NBG1 %sabled",debug.l_en & 4 ? "en" : "dis");
+ }
+ if(input_code_pressed_once(KEYCODE_I))
+ {
+ debug.l_en^=8;
+ popmessage("NBG0 %sabled",debug.l_en & 8 ? "en" : "dis");
+ }
+ if(input_code_pressed_once(KEYCODE_K))
+ {
+ debug.l_en^=0x10;
+ popmessage("RBG0 %sabled",debug.l_en & 0x10 ? "en" : "dis");
+ }
+ if(input_code_pressed_once(KEYCODE_O))
+ {
+ debug.l_en^=0x20;
+ popmessage("SPRITE %sabled",debug.l_en & 0x20 ? "en" : "dis");
+ }
+ #endif
+
+ if(STV_VDP2_DISP != 0)
+ {
+ stv_sprite_priorities_usage_valid = 0;
+ memset(stv_sprite_priorities_used, 0, sizeof(stv_sprite_priorities_used));
+ memset(stv_sprite_priorities_in_fb_line, 0, sizeof(stv_sprite_priorities_in_fb_line));
+
+ /*If a plane has a priority value of zero it isn't shown at all.*/
+ for(pri=1;pri<8;pri++)
+ {
+ if (debug.l_en & 1) {if(pri==STV_VDP2_N3PRIN) stv_vdp2_draw_NBG3(machine, bitmap,cliprect);}
+ if (debug.l_en & 2) {if(pri==STV_VDP2_N2PRIN) stv_vdp2_draw_NBG2(machine, bitmap,cliprect);}
+ if (debug.l_en & 4) {if(pri==STV_VDP2_N1PRIN) stv_vdp2_draw_NBG1(machine, bitmap,cliprect);}
+ if (debug.l_en & 8) {if(pri==STV_VDP2_N0PRIN) stv_vdp2_draw_NBG0(machine, bitmap,cliprect);}
+ if (debug.l_en & 0x10) {if(pri==STV_VDP2_R0PRIN) stv_vdp2_draw_RBG0(machine, bitmap,cliprect);}
+ if (debug.l_en & 0x20) {draw_sprites(machine,bitmap,cliprect,pri);}
+ }
+ }
+
+#ifdef MAME_DEBUG
+ if(STV_VDP2_VRAMSZ && VDP2_ERR(0x80000000))
+ {
+ VDP2_CHK(0x80000000);
+ mame_printf_debug("Warning: VRAM Size = 8 MBit!\n");
+ }
+ if(STV_VDP2_CRKTE && VDP2_ERR(0x40000000))
+ {
+ VDP2_CHK(0x40000000);
+ mame_printf_debug("Warning: Color RAM Coefficient Table Ctrl used\n");
+ }
+
+ /*popmessage("N0 %02x %04x %02x %04x N1 %02x %04x %02x %04x"
+ ,STV_VDP2_N0ZMXI,STV_VDP2_N0ZMXD
+ ,STV_VDP2_N0ZMYI,STV_VDP2_N0ZMYD
+ ,STV_VDP2_N1ZMXI,STV_VDP2_N1ZMXD
+ ,STV_VDP2_N1ZMYI,STV_VDP2_N1ZMYD);*/
+
+ if ( input_code_pressed_once(KEYCODE_W) )
+ {
+ int tilecode;
+
+ for (tilecode = 0;tilecode<0x8000;tilecode++)
+ {
+ decodechar(machine->gfx[0], tilecode, stv_vdp2_gfx_decode, machine->drv->gfxdecodeinfo[0].gfxlayout);
+ }
+
+ for (tilecode = 0;tilecode<0x2000;tilecode++)
+ {
+ decodechar(machine->gfx[1], tilecode, stv_vdp2_gfx_decode, machine->drv->gfxdecodeinfo[1].gfxlayout);
+ }
+
+ for (tilecode = 0;tilecode<0x4000;tilecode++)
+ {
+ decodechar(machine->gfx[2], tilecode, stv_vdp2_gfx_decode, machine->drv->gfxdecodeinfo[2].gfxlayout);
+ }
+
+ for (tilecode = 0;tilecode<0x1000;tilecode++)
+ {
+ decodechar(machine->gfx[3], tilecode, stv_vdp2_gfx_decode, machine->drv->gfxdecodeinfo[3].gfxlayout);
+ }
+
+ /* vdp 1 ... doesn't have to be tile based */
+
+ for (tilecode = 0;tilecode<0x8000;tilecode++)
+ {
+ decodechar(machine->gfx[4], tilecode, stv_vdp1_gfx_decode, machine->drv->gfxdecodeinfo[4].gfxlayout);
+ }
+ for (tilecode = 0;tilecode<0x2000;tilecode++)
+ {
+ decodechar(machine->gfx[5], tilecode, stv_vdp1_gfx_decode, machine->drv->gfxdecodeinfo[5].gfxlayout);
+ }
+ for (tilecode = 0;tilecode<0x4000;tilecode++)
+ {
+ decodechar(machine->gfx[6], tilecode, stv_vdp1_gfx_decode, machine->drv->gfxdecodeinfo[6].gfxlayout);
+ }
+ for (tilecode = 0;tilecode<0x1000;tilecode++)
+ {
+ decodechar(machine->gfx[7], tilecode, stv_vdp1_gfx_decode, machine->drv->gfxdecodeinfo[7].gfxlayout);
+ }
+ }
+
+ if ( input_code_pressed_once(KEYCODE_N) )
+ {
+ FILE *fp;
+
+ fp=fopen("mamevdp1", "w+b");
+ if (fp)
+ {
+ fwrite(stv_vdp1_vram, 0x80000, 1, fp);
+ fclose(fp);
+ }
+ }
+
+ if ( input_code_pressed_once(KEYCODE_M) )
+ {
+ FILE *fp;
+
+ fp=fopen("vdp1_vram.bin", "r+b");
+ if (fp)
+ {
+ fread(stv_vdp1_vram, 0x80000, 1, fp);
+ fclose(fp);
+ }
+ }
+
+#endif
+
+
+
+ return 0;
+}
+
+/* below is some old code we might use .. */
+
+#if 0
+
+static void stv_dump_ram()
+{
+ FILE *fp;
+
+ fp=fopen("workraml.dmp", "w+b");
+ if (fp)
+ {
+ fwrite(stv_workram_l, 0x00100000, 1, fp);
+ fclose(fp);
+ }
+ fp=fopen("workramh.dmp", "w+b");
+ if (fp)
+ {
+ fwrite(stv_workram_h, 0x00100000, 1, fp);
+ fclose(fp);
+ }
+ fp=fopen("scu.dmp", "w+b");
+ if (fp)
+ {
+ fwrite(stv_scu, 0xd0, 1, fp);
+ fclose(fp);
+ }
+ fp=fopen("stv_a0_vram.dmp", "w+b");
+ if (fp)
+ {
+ fwrite(stv_a0_vram, 0x00020000, 1, fp);
+ fclose(fp);
+ }
+ fp=fopen("stv_a1_vram.dmp", "w+b");
+ if (fp)
+ {
+ fwrite(stv_a1_vram, 0x00020000, 1, fp);
+ fclose(fp);
+ }
+ fp=fopen("stv_b0_vram.dmp", "w+b");
+ if (fp)
+ {
+ fwrite(stv_b0_vram, 0x00020000, 1, fp);
+ fclose(fp);
+ }
+ fp=fopen("stv_b1_vram.dmp", "w+b");
+ if (fp)
+ {
+ fwrite(stv_b1_vram, 0x00020000, 1, fp);
+ fclose(fp);
+ }
+ fp=fopen("cram.dmp", "w+b");
+ if (fp)
+ {
+ fwrite(stv_cram, 0x00080000, 1, fp);
+ fclose(fp);
+ }
+ fp=fopen("68k.dmp", "w+b");
+ if (fp)
+ {
+ fwrite(memory_region(REGION_CPU3), 0x100000, 1, fp);
+ fclose(fp);
+ }
+}
+
+
+#endif
diff --git a/src/mame/video/subs.c b/src/mame/video/subs.c
new file mode 100644
index 00000000000..fd36fc86f80
--- /dev/null
+++ b/src/mame/video/subs.c
@@ -0,0 +1,163 @@
+/***************************************************************************
+
+ Atari Subs hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "subs.h"
+#include "sound/discrete.h"
+
+WRITE8_HANDLER( subs_invert1_w )
+{
+ if ((offset & 0x01) == 1)
+ {
+ palette_set_color(Machine, 0, MAKE_RGB(0x00, 0x00, 0x00));
+ palette_set_color(Machine, 1, MAKE_RGB(0xFF, 0xFF, 0xFF));
+ }
+ else
+ {
+ palette_set_color(Machine, 1, MAKE_RGB(0x00, 0x00, 0x00));
+ palette_set_color(Machine, 0, MAKE_RGB(0xFF, 0xFF, 0xFF));
+ }
+}
+
+WRITE8_HANDLER( subs_invert2_w )
+{
+ if ((offset & 0x01) == 1)
+ {
+ palette_set_color(Machine, 2, MAKE_RGB(0x00, 0x00, 0x00));
+ palette_set_color(Machine, 3, MAKE_RGB(0xFF, 0xFF, 0xFF));
+ }
+ else
+ {
+ palette_set_color(Machine, 3, MAKE_RGB(0x00, 0x00, 0x00));
+ palette_set_color(Machine, 2, MAKE_RGB(0xFF, 0xFF, 0xFF));
+ }
+}
+
+
+VIDEO_UPDATE( subs )
+{
+ int offs;
+
+ /* for every character in the Video RAM, check if it has been modified */
+ /* since last time and update it accordingly. */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int charcode;
+ int sx,sy;
+ int left_enable,right_enable;
+ int left_sonar_window,right_sonar_window;
+
+ left_sonar_window = 0;
+ right_sonar_window = 0;
+
+ charcode = videoram[offs];
+
+ /* Which monitor is this for? */
+ right_enable = charcode & 0x40;
+ left_enable = charcode & 0x80;
+
+ sx = 8 * (offs % 32);
+ sy = 8 * (offs / 32);
+
+ /* Special hardware logic for sonar windows */
+ if ((sy >= (128+64)) && (sx < 32))
+ left_sonar_window = 1;
+ else if ((sy >= (128+64)) && (sx >= (128+64+32)))
+ right_sonar_window = 1;
+ else
+ charcode = charcode & 0x3F;
+
+ /* Draw the left screen */
+ if (screen==0)
+ {
+ if ((left_enable || left_sonar_window) && (!right_sonar_window))
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ charcode, 1,
+ 0,0,sx,sy,
+ cliprect,TRANSPARENCY_NONE,0);
+ }
+ else
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ 0, 1,
+ 0,0,sx,sy,
+ cliprect,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ /* Draw the right screen */
+ if (screen==1)
+ {
+ if ((right_enable || right_sonar_window) && (!left_sonar_window))
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ charcode, 0,
+ 0,0,sx,sy,
+ cliprect,TRANSPARENCY_NONE,0);
+ }
+ else
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ 0, 0,
+ 0,0,sx,sy,
+ cliprect,TRANSPARENCY_NONE,0);
+ }
+ }
+ }
+
+ /* draw the motion objects */
+ for (offs = 0; offs < 4; offs++)
+ {
+ int sx,sy;
+ int charcode;
+ int prom_set;
+ int sub_enable;
+
+ sx = spriteram[0x00 + (offs * 2)] - 16;
+ sy = spriteram[0x08 + (offs * 2)] - 16;
+ charcode = spriteram[0x09 + (offs * 2)];
+ if (offs < 2)
+ sub_enable = spriteram[0x01 + (offs * 2)] & 0x80;
+ else
+ sub_enable = 1;
+
+ prom_set = charcode & 0x01;
+ charcode = (charcode >> 3) & 0x1F;
+
+ /* Left screen - special check for drawing right screen's sub */
+ if (screen==0)
+ {
+ if ((offs!=0) || (sub_enable))
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ charcode + 32 * prom_set,
+ 0,
+ 0,0,sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+
+
+ /* Right screen - special check for drawing left screen's sub */
+ if (screen==1)
+ {
+ if ((offs!=1) || (sub_enable))
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ charcode + 32 * prom_set,
+ 0,
+ 0,0,sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+
+ /* Update sound */
+ discrete_sound_w(SUBS_LAUNCH_DATA, spriteram[5] & 0x0f); // Launch data
+ discrete_sound_w(SUBS_CRASH_DATA, spriteram[5] >> 4); // Crash/explode data
+ return 0;
+}
diff --git a/src/mame/video/suna16.c b/src/mame/video/suna16.c
new file mode 100644
index 00000000000..ec7ab020e27
--- /dev/null
+++ b/src/mame/video/suna16.c
@@ -0,0 +1,245 @@
+/***************************************************************************
+
+ -= SunA 16 Bit Games =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+ These games have only sprites, of a peculiar type:
+
+ there is a region of memory where 32 pages of 32x32 tile codes can
+ be written like a tilemap made of 32 pages of 256x256 pixels. Each
+ tile uses 2 words.
+
+ Sprites are rectangular regions of *tiles* fetched from there and
+ sent to the screen. Each sprite uses 4 words, held where the last
+ page of tiles would be.
+
+
+ [ Sprites Format ]
+
+
+ Offset: Bits: Value:
+
+ 0.w fedc ---- ---- ---- Source Page (Low Bits)
+ ---- ba98 ---- ---- Source Column (Bit 8 = Sprite Flip X)
+ ---- ---- 7654 3210 Screen Y Position
+
+ 2.w fedc ---- ---- ---- Tile Bank
+ ---- ba-- ---- ----
+ ---- --9- ---- ---- Source Page (High Bit)
+ ---- ---8 7654 3210 Screen X Position
+
+ $10000.w fedc ba98 ---- ----
+ ---- ---- 76-- ---- Sprite Size:
+ 00 -> 16 x 16 (2x2 tiles)
+ 01 -> 32 x 32 (4x4 tiles)
+ 10 -> 16 x 256 (2x32 tiles)
+ 11 -> 32 x 256 (4x32 tiles)
+ ---- ---- --54 ---- ? (Bit 4 used by uballoon)
+ ---- ---- ---- 3210 Source Row
+
+ $10002.w -
+
+
+ [ Sprite's Tiles Format ]
+
+
+ Offset: Bits: Value:
+
+ 0.w f--- ---- ---- ---- Flip Y
+ -e-- ---- ---- ---- Flip X
+ --dc ba98 7654 3210 Code
+
+ $10000.w fedc ba98 7654 ----
+ ---- ---- ---- 3210 Color
+
+
+***************************************************************************/
+
+#include "driver.h"
+
+static int color_bank;
+
+WRITE16_HANDLER( suna16_flipscreen_w )
+{
+ if (ACCESSING_LSB)
+ {
+ flip_screen_set( data & 1 );
+ color_bank = ( data & 4 ) >> 2;
+ }
+ if (data & ~(1|4)) logerror("CPU#0 PC %06X - Flip screen unknown bits: %04X\n", activecpu_get_pc(), data);
+}
+
+WRITE16_HANDLER( bestbest_flipscreen_w )
+{
+ if (ACCESSING_LSB)
+ {
+ flip_screen_set( data & 0x10 );
+// color_bank = ( data & 0x07 );
+ }
+ if (data & ~(0x10)) logerror("CPU#0 PC %06X - Flip screen unknown bits: %04X\n", activecpu_get_pc(), data);
+}
+
+
+/***************************************************************************
+
+
+ Banked Palette RAM. Format is xBBBBBGGGGRRRRR
+
+
+***************************************************************************/
+
+VIDEO_START( suna16 )
+{
+ paletteram16 = auto_malloc( machine->drv->total_colors * sizeof(UINT16) );
+}
+
+READ16_HANDLER( suna16_paletteram16_r )
+{
+ return paletteram16[offset + color_bank * 256];
+}
+
+WRITE16_HANDLER( suna16_paletteram16_w )
+{
+ offset += color_bank * 256;
+ data = COMBINE_DATA(&paletteram16[offset]);
+ palette_set_color_rgb( Machine, offset, pal5bit(data >> 0),pal5bit(data >> 5),pal5bit(data >> 10));
+}
+
+
+/***************************************************************************
+
+
+ Sprites Drawing
+
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT16 *sprites, int gfx)
+{
+ int offs;
+
+ int max_x = machine->screen[0].width - 8;
+ int max_y = machine->screen[0].height - 8;
+
+ for ( offs = 0xfc00/2; offs < 0x10000/2 ; offs += 4/2 )
+ {
+ int srcpg, srcx,srcy, dimx,dimy;
+ int tile_x, tile_xinc, tile_xstart;
+ int tile_y, tile_yinc;
+ int dx, dy;
+ int flipx, y0;
+
+ int y = sprites[ offs + 0 + 0x00000 / 2 ];
+ int x = sprites[ offs + 1 + 0x00000 / 2 ];
+ int dim = sprites[ offs + 0 + 0x10000 / 2 ];
+
+ int bank = (x >> 12) & 0xf;
+
+ srcpg = ((y & 0xf000) >> 12) + ((x & 0x0200) >> 5); // src page
+ srcx = ((y >> 8) & 0xf) * 2; // src col
+ srcy = ((dim >> 0) & 0xf) * 2; // src row
+
+ switch ( (dim >> 4) & 0xc )
+ {
+ case 0x0: dimx = 2; dimy = 2; y0 = 0x100; break;
+ case 0x4: dimx = 4; dimy = 4; y0 = 0x100; break;
+ case 0x8: dimx = 2; dimy = 32; y0 = 0x130; break;
+ default:
+ case 0xc: dimx = 4; dimy = 32; y0 = 0x120; break;
+ }
+
+ if (dimx==4) { flipx = srcx & 2; srcx &= ~2; }
+ else { flipx = 0; }
+
+ x = (x & 0xff) - (x & 0x100);
+ y = (y0 - (y & 0xff) - dimy*8 ) & 0xff;
+
+ if (flipx) { tile_xstart = dimx-1; tile_xinc = -1; }
+ else { tile_xstart = 0; tile_xinc = +1; }
+
+ tile_y = 0; tile_yinc = +1;
+
+ for (dy = 0; dy < dimy * 8; dy += 8)
+ {
+ tile_x = tile_xstart;
+
+ for (dx = 0; dx < dimx * 8; dx += 8)
+ {
+ int addr = (srcpg * 0x20 * 0x20) +
+ ((srcx + tile_x) & 0x1f) * 0x20 +
+ ((srcy + tile_y) & 0x1f);
+
+ int tile = sprites[ addr + 0x00000 / 2 ];
+ int attr = sprites[ addr + 0x10000 / 2 ];
+
+ int sx = x + dx;
+ int sy = (y + dy) & 0xff;
+
+ int tile_flipx = tile & 0x4000;
+ int tile_flipy = tile & 0x8000;
+
+ if (flipx) tile_flipx = !tile_flipx;
+
+ if (flip_screen)
+ {
+ sx = max_x - sx;
+ sy = max_y - sy;
+ tile_flipx = !tile_flipx;
+ tile_flipy = !tile_flipy;
+ }
+
+ drawgfx( bitmap, machine->gfx[gfx],
+ (tile & 0x3fff) + bank*0x4000,
+ attr + (color_bank << 4),
+ tile_flipx, tile_flipy,
+ sx, sy,
+ cliprect,TRANSPARENCY_PEN,15 );
+
+ tile_x += tile_xinc;
+ }
+
+ tile_y += tile_yinc;
+ }
+
+ }
+
+}
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+VIDEO_UPDATE( suna16 )
+{
+ /* Suna Quiz indicates the background is the last pen */
+ fillbitmap(bitmap,machine->pens[0xff],cliprect);
+ draw_sprites(machine, bitmap, cliprect, spriteram16, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( bestbest )
+{
+ int layers_ctrl = -1;
+
+#ifdef MAME_DEBUG
+if (input_code_pressed(KEYCODE_Z))
+{ int msk = 0;
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+ if (msk != 0) layers_ctrl &= msk;
+}
+#endif
+
+ /* Suna Quiz indicates the background is the last pen */
+ fillbitmap(bitmap,machine->pens[0xff],cliprect);
+ if (layers_ctrl & 1) draw_sprites(machine, bitmap, cliprect, spriteram16, 0);
+ if (layers_ctrl & 2) draw_sprites(machine, bitmap, cliprect, spriteram16_2, 1);
+ return 0;
+}
diff --git a/src/mame/video/suna8.c b/src/mame/video/suna8.c
new file mode 100644
index 00000000000..b118f6d69b9
--- /dev/null
+++ b/src/mame/video/suna8.c
@@ -0,0 +1,449 @@
+/***************************************************************************
+
+ -= SunA 8 Bit Games =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+ These games have only sprites, of a peculiar type:
+
+ there is a region of memory where 4 pages of 32x32 tile codes can
+ be written like a tilemap made of 4 pages of 256x256 pixels. Each
+ tile uses 2 bytes. Later games may use more pages through RAM
+ banking.
+
+ Sprites are rectangular regions of *tiles* fetched from there and
+ sent to the screen. Each sprite uses 4 bytes, held within the last
+ page of tiles.
+
+ * Note: later games use a more complex format than the following,
+ which is yet to be completely understood.
+
+ [ Sprites Format ]
+
+
+ Offset: Bits: Value:
+
+ 0.b Y (Bottom up)
+
+ 1.b 7--- ---- Sprite Size (1 = 2x32 tiles; 0 = 2x2)
+
+ 2x2 Sprites:
+ -65- ---- Tiles Row (height = 8 tiles)
+ ---4 ---- Page
+
+ 2x32 Sprites:
+ -6-- ---- Ignore X (Multisprite)
+ --54 ---- Page
+
+ ---- 3210 Tiles Column (width = 2 tiles)
+
+ 2.b X
+
+ 3.b 7--- ----
+ -6-- ---- X (Sign Bit)
+ --54 3---
+ ---- -210 Tiles Bank
+
+
+ [ Sprite's Tiles Format ]
+
+
+ Offset: Bits: Value:
+
+ 0.b Code (Low Bits)
+
+ 1.b 7--- ---- Flip Y
+ -6-- ---- Flip X
+ --54 32-- Color
+ ---- --10 Code (High Bits)
+
+
+
+ Set TILEMAPS to 1 to debug.
+ Press Z (you see the "tilemaps" in RAM) or
+ Press X (you see the "tilemaps" in ROM) then
+
+ - use Q&W to cycle through the pages.
+ - Use E&R to cycle through the tiles banks.
+ - Use A&S to cycle through the ROM banks (only with X pressed, of course).
+
+***************************************************************************/
+
+#include "driver.h"
+
+#define TILEMAPS 0
+
+static int suna8_text_dim; /* specifies format of text layer */
+
+UINT8 suna8_rombank, suna8_spritebank, suna8_palettebank;
+UINT8 suna8_unknown;
+
+/* Functions defined in video: */
+
+WRITE8_HANDLER( suna8_spriteram_w ); // for debug
+WRITE8_HANDLER( suna8_banked_spriteram_w ); // for debug
+
+VIDEO_START( suna8 );
+VIDEO_UPDATE( suna8 );
+
+
+/***************************************************************************
+ For Debug: there's no tilemap, just sprites.
+***************************************************************************/
+#if TILEMAPS
+static tilemap *bg_tilemap;
+static int tiles, rombank, page;
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 code, attr;
+ if (input_code_pressed(KEYCODE_X))
+ { UINT8 *rom = memory_region(REGION_CPU1) + 0x10000 + 0x4000*rombank;
+ code = rom[ 2 * tile_index + 0 ];
+ attr = rom[ 2 * tile_index + 1 ]; }
+ else
+ { code = spriteram[ 2 * tile_index + 0 ];
+ attr = spriteram[ 2 * tile_index + 1 ]; }
+ SET_TILE_INFO(
+ 0,
+ ( (attr & 0x03) << 8 ) + code + tiles*0x400,
+ (attr >> 2) & 0xf,
+ TILE_FLIPYX( (attr >> 6) & 3 ));
+}
+#endif
+
+
+READ8_HANDLER( suna8_banked_paletteram_r )
+{
+ offset += suna8_palettebank * 0x200;
+ return paletteram[offset];
+}
+
+READ8_HANDLER( suna8_banked_spriteram_r )
+{
+ offset += suna8_spritebank * 0x2000;
+ return spriteram[offset];
+}
+
+WRITE8_HANDLER( suna8_spriteram_w )
+{
+ spriteram[offset] = data;
+#if TILEMAPS
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+#endif
+}
+
+WRITE8_HANDLER( suna8_banked_spriteram_w )
+{
+ offset += suna8_spritebank * 0x2000;
+ spriteram[offset] = data;
+#if TILEMAPS
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+#endif
+}
+
+/*
+ Banked Palette RAM. The data is scrambled
+*/
+WRITE8_HANDLER( brickzn_banked_paletteram_w )
+{
+ int r,g,b;
+ UINT16 rgb;
+ offset += suna8_palettebank * 0x200;
+ paletteram[offset] = data;
+ rgb = (paletteram[offset&~1] << 8) + paletteram[offset|1];
+ r = (((rgb & (1<<0xc))?1:0)<<0) |
+ (((rgb & (1<<0xb))?1:0)<<1) |
+ (((rgb & (1<<0xe))?1:0)<<2) |
+ (((rgb & (1<<0xf))?1:0)<<3);
+ g = (((rgb & (1<<0x8))?1:0)<<0) |
+ (((rgb & (1<<0x9))?1:0)<<1) |
+ (((rgb & (1<<0xa))?1:0)<<2) |
+ (((rgb & (1<<0xd))?1:0)<<3);
+ b = (((rgb & (1<<0x4))?1:0)<<0) |
+ (((rgb & (1<<0x3))?1:0)<<1) |
+ (((rgb & (1<<0x6))?1:0)<<2) |
+ (((rgb & (1<<0x7))?1:0)<<3);
+
+ palette_set_color_rgb(Machine,offset/2,pal4bit(r),pal4bit(g),pal4bit(b));
+}
+
+
+
+static void suna8_vh_start_common(int dim)
+{
+ suna8_text_dim = dim;
+ if (!(suna8_text_dim > 0))
+ {
+ paletteram = auto_malloc(0x200 * 2);
+ spriteram = auto_malloc(0x2000 * 2);
+ suna8_spritebank = 0;
+ suna8_palettebank = 0;
+ }
+
+#if TILEMAPS
+ bg_tilemap = tilemap_create( get_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN,
+ 8,8,0x20*((suna8_text_dim > 0)?4:8),0x20);
+
+ tilemap_set_transparent_pen(bg_tilemap,15);
+#endif
+}
+
+VIDEO_START( suna8_textdim0 ) { suna8_vh_start_common(0); }
+VIDEO_START( suna8_textdim8 ) { suna8_vh_start_common(8); }
+VIDEO_START( suna8_textdim12 ) { suna8_vh_start_common(12); }
+
+/***************************************************************************
+
+
+ Sprites Drawing
+
+
+***************************************************************************/
+
+static void draw_normal_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int i;
+ int mx = 0; // multisprite x counter
+
+ int max_x = machine->screen[0].width - 8;
+ int max_y = machine->screen[0].height - 8;
+
+ for (i = 0x1d00; i < 0x2000; i += 4)
+ {
+ int srcpg, srcx,srcy, dimx,dimy, tx, ty;
+ int gfxbank, colorbank = 0, flipx,flipy, multisprite;
+
+ int y = spriteram[i + 0];
+ int code = spriteram[i + 1];
+ int x = spriteram[i + 2];
+ int bank = spriteram[i + 3];
+
+ if (suna8_text_dim > 0)
+ {
+ /* Older, simpler hardware */
+ flipx = 0;
+ flipy = 0;
+ gfxbank = bank & 0x3f;
+ switch( code & 0x80 )
+ {
+ case 0x80:
+ dimx = 2; dimy = 32;
+ srcx = (code & 0xf) * 2; srcy = 0;
+ srcpg = (code >> 4) & 3;
+ break;
+ case 0x00:
+ default:
+ dimx = 2; dimy = 2;
+ srcx = (code & 0xf) * 2; srcy = ((code >> 5) & 0x3) * 8 + 6;
+ srcpg = (code >> 4) & 1;
+ break;
+ }
+ multisprite = ((code & 0x80) && (code & 0x40));
+ }
+ else
+ {
+ /* Newer, more complex hardware (not finished yet!) */
+ switch( code & 0xc0 )
+ {
+ case 0xc0:
+ dimx = 4; dimy = 32;
+ srcx = (code & 0xe) * 2; srcy = 0;
+ flipx = (code & 0x1);
+ flipy = 0;
+ gfxbank = bank & 0x1f;
+ srcpg = (code >> 4) & 3;
+ break;
+ case 0x80:
+ dimx = 2; dimy = 32;
+ srcx = (code & 0xf) * 2; srcy = 0;
+ flipx = 0;
+ flipy = 0;
+ gfxbank = bank & 0x1f;
+ srcpg = (code >> 4) & 3;
+ break;
+// hardhea2: fire code=52/54 bank=a4; player code=02/04/06 bank=08; arrow:code=16 bank=27
+ case 0x40:
+ dimx = 4; dimy = 4;
+ srcx = (code & 0xe) * 2;
+ flipx = code & 0x01;
+ flipy = bank & 0x10;
+ srcy = (((bank & 0x80)>>4) + (bank & 0x04) + ((~bank >> 4)&2)) * 2;
+ srcpg = (code >> 4) & 7;
+ gfxbank = (bank & 0x3) + (srcpg & 4); // brickzn: 06,a6,a2,b2->6. starfigh: 01->01,4->0
+ colorbank = (bank & 8) >> 3;
+ break;
+ case 0x00:
+ default:
+ dimx = 2; dimy = 2;
+ srcx = (code & 0xf) * 2;
+ flipx = 0;
+ flipy = 0;
+ gfxbank = bank & 0x03;
+ srcy = (((bank & 0x80)>>4) + (bank & 0x04) + ((~bank >> 4)&3)) * 2;
+ srcpg = (code >> 4) & 3;
+ break;
+ }
+ multisprite = ((code & 0x80) && (bank & 0x80));
+ }
+
+ x = x - ((bank & 0x40) ? 0x100 : 0);
+ y = (0x100 - y - dimy*8 ) & 0xff;
+
+ /* Multi Sprite */
+ if ( multisprite ) { mx += dimx*8; x = mx; }
+ else mx = x;
+
+ gfxbank *= 0x400;
+
+ for (ty = 0; ty < dimy; ty ++)
+ {
+ for (tx = 0; tx < dimx; tx ++)
+ {
+ int addr = (srcpg * 0x20 * 0x20) +
+ ((srcx + (flipx?dimx-tx-1:tx)) & 0x1f) * 0x20 +
+ ((srcy + (flipy?dimy-ty-1:ty)) & 0x1f);
+
+ int tile = spriteram[addr*2 + 0];
+ int attr = spriteram[addr*2 + 1];
+
+ int tile_flipx = attr & 0x40;
+ int tile_flipy = attr & 0x80;
+
+ int sx = x + tx * 8;
+ int sy = (y + ty * 8) & 0xff;
+
+ if (flipx) tile_flipx = !tile_flipx;
+ if (flipy) tile_flipy = !tile_flipy;
+
+ if (flip_screen)
+ { sx = max_x - sx; tile_flipx = !tile_flipx;
+ sy = max_y - sy; tile_flipy = !tile_flipy; }
+
+ drawgfx( bitmap,machine->gfx[0],
+ tile + (attr & 0x3)*0x100 + gfxbank,
+ ((attr >> 2) & 0xf) | colorbank, // hardhea2 player2
+ tile_flipx, tile_flipy,
+ sx, sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+
+ }
+}
+
+static void draw_text_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int i;
+
+ int max_x = machine->screen[0].width - 8;
+ int max_y = machine->screen[0].height - 8;
+
+ /* Earlier games only */
+ if (!(suna8_text_dim > 0)) return;
+
+ for (i = 0x1900; i < 0x19ff; i += 4)
+ {
+ int srcpg, srcx,srcy, dimx,dimy, tx, ty;
+
+ int y = spriteram[i + 0];
+ int code = spriteram[i + 1];
+ int x = spriteram[i + 2];
+ int bank = spriteram[i + 3];
+
+ if (~code & 0x80) continue;
+
+ dimx = 2; dimy = suna8_text_dim;
+ srcx = (code & 0xf) * 2; srcy = (y & 0xf0) / 8;
+ srcpg = (code >> 4) & 3;
+
+ x = x - ((bank & 0x40) ? 0x100 : 0);
+ y = 0;
+
+ bank = (bank & 0x3f) * 0x400;
+
+ for (ty = 0; ty < dimy; ty ++)
+ {
+ for (tx = 0; tx < dimx; tx ++)
+ {
+ int real_ty = (ty < (dimy/2)) ? ty : (ty + 0x20 - dimy);
+
+ int addr = (srcpg * 0x20 * 0x20) +
+ ((srcx + tx) & 0x1f) * 0x20 +
+ ((srcy + real_ty) & 0x1f);
+
+ int tile = spriteram[addr*2 + 0];
+ int attr = spriteram[addr*2 + 1];
+
+ int flipx = attr & 0x40;
+ int flipy = attr & 0x80;
+
+ int sx = x + tx * 8;
+ int sy = (y + real_ty * 8) & 0xff;
+
+ if (flip_screen)
+ { sx = max_x - sx; flipx = !flipx;
+ sy = max_y - sy; flipy = !flipy; }
+
+ drawgfx( bitmap,machine->gfx[0],
+ tile + (attr & 0x3)*0x100 + bank,
+ (attr >> 2) & 0xf,
+ flipx, flipy,
+ sx, sy,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+
+ }
+}
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+VIDEO_UPDATE( suna8 )
+{
+ /* see hardhead, hardhea2 test mode (press button 2 for both players) */
+ fillbitmap(bitmap,machine->pens[0xff],cliprect);
+
+#ifdef MAME_DEBUG
+#if TILEMAPS
+ if (input_code_pressed(KEYCODE_Z) || input_code_pressed(KEYCODE_X))
+ {
+ int max_tiles = memory_region_length(REGION_GFX1) / (0x400 * 0x20);
+
+ if (input_code_pressed_once(KEYCODE_Q)) { page--; tilemap_mark_all_tiles_dirty(ALL_TILEMAPS); }
+ if (input_code_pressed_once(KEYCODE_W)) { page++; tilemap_mark_all_tiles_dirty(ALL_TILEMAPS); }
+ if (input_code_pressed_once(KEYCODE_E)) { tiles--; tilemap_mark_all_tiles_dirty(ALL_TILEMAPS); }
+ if (input_code_pressed_once(KEYCODE_R)) { tiles++; tilemap_mark_all_tiles_dirty(ALL_TILEMAPS); }
+ if (input_code_pressed_once(KEYCODE_A)) { rombank--; tilemap_mark_all_tiles_dirty(ALL_TILEMAPS); }
+ if (input_code_pressed_once(KEYCODE_S)) { rombank++; tilemap_mark_all_tiles_dirty(ALL_TILEMAPS); }
+
+ rombank &= 0xf;
+ page &= (suna8_text_dim > 0)?3:7;
+ tiles %= max_tiles;
+ if (tiles < 0) tiles += max_tiles;
+
+ tilemap_set_scrollx( bg_tilemap, 0, 0x100 * page);
+ tilemap_set_scrolly( bg_tilemap, 0, 0);
+ tilemap_draw(bitmap,cliprect, bg_tilemap, 0, 0);
+#if 1
+ popmessage("%02X %02X %02X %02X - p%2X g%02X r%02X",
+ suna8_rombank, suna8_palettebank, suna8_spritebank, suna8_unknown,
+ page,tiles,rombank );
+#endif
+ }
+ else
+#endif
+#endif
+ {
+ draw_normal_sprites(machine ,bitmap,cliprect);
+ draw_text_sprites(machine, bitmap,cliprect);
+ }
+ return 0;
+}
diff --git a/src/mame/video/supbtime.c b/src/mame/video/supbtime.c
new file mode 100644
index 00000000000..96a1192584f
--- /dev/null
+++ b/src/mame/video/supbtime.c
@@ -0,0 +1,103 @@
+/***************************************************************************
+
+ Super Burger Time Video emulation - Bryan McPhail, mish@tendril.co.uk
+
+*********************************************************************
+
+Uses Data East custom chip 55 for backgrounds, custom chip 52 for sprites.
+
+See Dark Seal & Caveman Ninja drivers for info on these chips.
+
+End sequence uses rowscroll '98 c0' on pf1 (jmp to 1d61a on supbtimj)
+
+***************************************************************************/
+
+#include "driver.h"
+#include "deco16ic.h"
+
+/******************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ sprite = spriteram16[offs+1] & 0x3fff;
+ if (!sprite) continue;
+
+ y = spriteram16[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ x = spriteram16[offs+2];
+ colour = (x >>9) & 0x1f;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+ y = 240 - y;
+ x = 304 - x;
+
+ if (x>320) continue;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen)
+ {
+ y=240-y;
+ x=304-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ multi--;
+ }
+ }
+}
+
+/******************************************************************************/
+
+VIDEO_START(supbtime)
+{
+ deco16_1_video_init();
+}
+
+VIDEO_UPDATE(supbtime)
+{
+ flip_screen_set( deco16_pf12_control[0]&0x80 );
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+
+ fillbitmap(bitmap,machine->pens[768],cliprect);
+
+ deco16_tilemap_2_draw(bitmap,cliprect,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+ return 0;
+}
+
diff --git a/src/mame/video/superchs.c b/src/mame/video/superchs.c
new file mode 100644
index 00000000000..a7bcb2685b4
--- /dev/null
+++ b/src/mame/video/superchs.c
@@ -0,0 +1,251 @@
+#include "driver.h"
+#include "video/taitoic.h"
+
+#define TC0480SCP_GFX_NUM 1
+
+struct tempsprite
+{
+ int gfx;
+ int code,color;
+ int flipx,flipy;
+ int x,y;
+ int zoomx,zoomy;
+ int primask;
+};
+static struct tempsprite *spritelist;
+
+VIDEO_START( superchs )
+{
+ spritelist = auto_malloc(0x4000 * sizeof(*spritelist));
+
+ TC0480SCP_vh_start(machine,TC0480SCP_GFX_NUM,0,0x20,0x08,-1,0,0,0,0);
+}
+
+/************************************************************
+ SPRITE DRAW ROUTINES
+
+We draw a series of small tiles ("chunks") together to
+create each big sprite. The spritemap rom provides the lookup
+table for this. The game hardware looks up 16x16 sprite chunks
+from the spritemap rom, creating a 64x64 sprite like this:
+
+ 0 1 2 3
+ 4 5 6 7
+ 8 9 10 11
+ 12 13 14 15
+
+(where the number is the word offset into the spritemap rom).
+It can also create 32x32 sprites.
+
+NB: unused portions of the spritemap rom contain hex FF's.
+It is a useful coding check to warn in the log if these
+are being accessed. [They can be inadvertently while
+spriteram is being tested, take no notice of that.]
+
+Heavy use is made of sprite zooming.
+
+ ***
+
+ Sprite table layout (4 long words per entry)
+
+ ------------------------------------------
+ 0 | ........ x....... ........ ........ | Flip X
+ 0 | ........ .xxxxxxx ........ ........ | ZoomX
+ 0 | ........ ........ .xxxxxxx xxxxxxxx | Sprite Tile
+ | |
+ 2 | ........ ....xx.. ........ ........ | Sprite/tile priority [*]
+ 2 | ........ ......xx xxxxxx.. ........ | Palette bank
+ 2 | ........ ........ ......xx xxxxxxxx | X position
+ | |
+ 3 | ........ .....x.. ........ ........ | Sprite size (0=32x32, 1=64x64)
+ 3 | ........ ......x. ........ ........ | Flip Y
+ 3 | ........ .......x xxxxxx.. ........ | ZoomY
+ 3 | ........ ........ ......xx xxxxxxxx | Y position
+ ------------------------------------------
+
+ [* 00=over BG1; 01=BG2; 10=BG3; 11=over text]
+
+********************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,const int *primasks,int x_offs,int y_offs)
+{
+ UINT16 *spritemap = (UINT16 *)memory_region(REGION_USER1);
+ int offs, data, tilenum, color, flipx, flipy;
+ int x, y, priority, dblsize, curx, cury;
+ int sprites_flipscreen = 0;
+ int zoomx, zoomy, zx, zy;
+ int sprite_chunk,map_offset,code,j,k,px,py;
+ int dimension,total_chunks,bad_chunks;
+
+ /* pdrawgfx() needs us to draw sprites front to back, so we have to build a list
+ while processing sprite ram and then draw them all at the end */
+ struct tempsprite *sprite_ptr = spritelist;
+
+ for (offs = (spriteram_size/4-4);offs >= 0;offs -= 4)
+ {
+ data = spriteram32[offs+0];
+ flipx = (data & 0x00800000) >> 23;
+ zoomx = (data & 0x007f0000) >> 16;
+ tilenum = (data & 0x00007fff);
+
+ data = spriteram32[offs+2];
+ priority = (data & 0x000c0000) >> 18;
+ color = (data & 0x0003fc00) >> 10;
+ x = (data & 0x000003ff);
+
+ data = spriteram32[offs+3];
+ dblsize = (data & 0x00040000) >> 18;
+ flipy = (data & 0x00020000) >> 17;
+ zoomy = (data & 0x0001fc00) >> 10;
+ y = (data & 0x000003ff);
+
+ color |= 0x100;
+
+ if (!tilenum) continue;
+
+ flipy = !flipy;
+ zoomx += 1;
+ zoomy += 1;
+
+ y += y_offs;
+
+ /* treat coords as signed */
+ if (x>0x340) x -= 0x400;
+ if (y>0x340) y -= 0x400;
+
+ x -= x_offs;
+
+ bad_chunks = 0;
+ dimension = ((dblsize*2) + 2); // 2 or 4
+ total_chunks = ((dblsize*3) + 1) << 2; // 4 or 16
+ map_offset = tilenum << 2;
+
+ {
+ for (sprite_chunk=0;sprite_chunk<total_chunks;sprite_chunk++)
+ {
+ j = sprite_chunk / dimension; /* rows */
+ k = sprite_chunk % dimension; /* chunks per row */
+
+ px = k;
+ py = j;
+ /* pick tiles back to front for x and y flips */
+ if (flipx) px = dimension-1-k;
+ if (flipy) py = dimension-1-j;
+
+ code = spritemap[map_offset + px + (py<<(dblsize+1))];
+
+ if (code==0xffff)
+ {
+ bad_chunks += 1;
+ continue;
+ }
+
+ curx = x + ((k*zoomx)/dimension);
+ cury = y + ((j*zoomy)/dimension);
+
+ zx= x + (((k+1)*zoomx)/dimension) - curx;
+ zy= y + (((j+1)*zoomy)/dimension) - cury;
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 320 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ sprite_ptr->gfx = 0;
+ sprite_ptr->code = code;
+ sprite_ptr->color = color;
+ sprite_ptr->flipx = !flipx;
+ sprite_ptr->flipy = flipy;
+ sprite_ptr->x = curx;
+ sprite_ptr->y = cury;
+ sprite_ptr->zoomx = zx << 12;
+ sprite_ptr->zoomy = zy << 12;
+
+ if (primasks)
+ {
+ sprite_ptr->primask = primasks[priority];
+
+ sprite_ptr++;
+ }
+ else
+ {
+ drawgfxzoom(bitmap,machine->gfx[sprite_ptr->gfx],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,TRANSPARENCY_PEN,0,
+ sprite_ptr->zoomx,sprite_ptr->zoomy);
+ }
+ }
+ }
+
+ if (bad_chunks)
+logerror("Sprite number %04x had %02x invalid chunks\n",tilenum,bad_chunks);
+ }
+
+ /* this happens only if primsks != NULL */
+ while (sprite_ptr != spritelist)
+ {
+ sprite_ptr--;
+
+ pdrawgfxzoom(bitmap,machine->gfx[sprite_ptr->gfx],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,TRANSPARENCY_PEN,0,
+ sprite_ptr->zoomx,sprite_ptr->zoomy,
+ sprite_ptr->primask);
+ }
+}
+
+
+/**************************************************************
+ SCREEN REFRESH
+**************************************************************/
+
+VIDEO_UPDATE( superchs )
+{
+ UINT8 layer[5];
+ UINT16 priority;
+ static const int primasks[4] = {0xfffc, 0xfff0, 0xff00, 0x0};
+
+ TC0480SCP_tilemap_update(machine);
+
+ priority = TC0480SCP_get_bg_priority();
+ layer[0] = (priority &0xf000) >> 12; /* tells us which bg layer is bottom */
+ layer[1] = (priority &0x0f00) >> 8;
+ layer[2] = (priority &0x00f0) >> 4;
+ layer[3] = (priority &0x000f) >> 0; /* tells us which is top */
+ layer[4] = 4; /* text layer always over bg layers */
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* We have to assume 2nd to bottom layer is always underneath
+ sprites as pdrawgfx cannot yet cope with more than 4 layers */
+
+#ifdef MAME_DEBUG
+ if (!input_code_pressed (KEYCODE_Z)) TC0480SCP_tilemap_draw(bitmap,cliprect,layer[0],TILEMAP_DRAW_OPAQUE,0);
+ if (!input_code_pressed (KEYCODE_X)) TC0480SCP_tilemap_draw(bitmap,cliprect,layer[1],0,1);
+ if (!input_code_pressed (KEYCODE_C)) TC0480SCP_tilemap_draw(bitmap,cliprect,layer[2],0,2);
+ if (!input_code_pressed (KEYCODE_V)) TC0480SCP_tilemap_draw(bitmap,cliprect,layer[3],0,4);
+ if (!input_code_pressed (KEYCODE_B)) TC0480SCP_tilemap_draw(bitmap,cliprect,layer[4],0,8);
+ if (!input_code_pressed (KEYCODE_N)) draw_sprites(machine,bitmap,cliprect,primasks,48,-116);
+#else
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[0],TILEMAP_DRAW_OPAQUE,0);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[1],0,1);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[2],0,2);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[3],0,4);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[4],0,8); /* text layer */
+ draw_sprites(machine, bitmap,cliprect,primasks,48,-116);
+#endif
+ return 0;
+}
diff --git a/src/mame/video/superqix.c b/src/mame/video/superqix.c
new file mode 100644
index 00000000000..b63d9149b6f
--- /dev/null
+++ b/src/mame/video/superqix.c
@@ -0,0 +1,260 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *superqix_videoram;
+UINT8 *superqix_bitmapram,*superqix_bitmapram2;
+int pbillian_show_power;
+
+static int gfxbank;
+static mame_bitmap *fg_bitmap[2];
+static int show_bitmap;
+static tilemap *bg_tilemap;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( pb_get_bg_tile_info )
+{
+ int attr = superqix_videoram[tile_index + 0x400];
+ int code = superqix_videoram[tile_index] + 256 * (attr & 0x7);
+ int color = (attr & 0xf0) >> 4;
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static TILE_GET_INFO( sqix_get_bg_tile_info )
+{
+ int attr = superqix_videoram[tile_index + 0x400];
+ int bank = (attr & 0x04) ? 0 : 1;
+ int code = superqix_videoram[tile_index] + 256 * (attr & 0x03);
+ int color = (attr & 0xf0) >> 4;
+
+ if (bank) code += 1024 * gfxbank;
+
+ SET_TILE_INFO(bank, code, color, 0);
+ tileinfo->group = (attr & 0x08) >> 3;
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( pbillian )
+{
+ bg_tilemap = tilemap_create(pb_get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8,32,32);
+}
+
+VIDEO_START( superqix )
+{
+ fg_bitmap[0] = auto_bitmap_alloc(256, 256, machine->screen[0].format);
+ fg_bitmap[1] = auto_bitmap_alloc(256, 256, machine->screen[0].format);
+ bg_tilemap = tilemap_create(sqix_get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transmask(bg_tilemap,0,0xffff,0x0000); /* split type 0 is totally transparent in front half */
+ tilemap_set_transmask(bg_tilemap,1,0x0001,0xfffe); /* split type 1 has pen 0 transparent in front half */
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( superqix_videoram_w )
+{
+ superqix_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset & 0x3ff);
+}
+
+WRITE8_HANDLER( superqix_bitmapram_w )
+{
+ if (superqix_bitmapram[offset] != data)
+ {
+ int x = 2 * (offset % 128);
+ int y = offset / 128 + 16;
+
+ superqix_bitmapram[offset] = data;
+
+ *BITMAP_ADDR16(fg_bitmap[0], y, x + 0) = Machine->pens[data >> 4];
+ *BITMAP_ADDR16(fg_bitmap[0], y, x + 1) = Machine->pens[data & 0x0f];
+ }
+}
+
+WRITE8_HANDLER( superqix_bitmapram2_w )
+{
+ if (data != superqix_bitmapram2[offset])
+ {
+ int x = 2 * (offset % 128);
+ int y = offset / 128 + 16;
+
+ superqix_bitmapram2[offset] = data;
+
+ *BITMAP_ADDR16(fg_bitmap[1], y, x + 0) = Machine->pens[data >> 4];
+ *BITMAP_ADDR16(fg_bitmap[1], y, x + 1) = Machine->pens[data & 0x0f];
+ }
+}
+
+WRITE8_HANDLER( pbillian_0410_w )
+{
+ int bankaddress;
+ UINT8 *rom = memory_region(REGION_CPU1);
+
+ /*
+ -------0 ? [not used]
+ ------1- coin counter 1
+ -----2-- coin counter 2
+ ----3--- rom 2 HI (reserved for ROM banking , not used)
+ ---4---- nmi enable/disable
+ --5----- flip screen
+ */
+
+ coin_counter_w(0,data & 0x02);
+ coin_counter_w(1,data & 0x04);
+
+ bankaddress = 0x10000 + ((data & 0x08) >> 3) * 0x4000;
+ memory_set_bankptr(1,&rom[bankaddress]);
+
+ interrupt_enable_w(0,data & 0x10);
+ flip_screen_set(data & 0x20);
+}
+
+WRITE8_HANDLER( superqix_0410_w )
+{
+ int bankaddress;
+ UINT8 *rom = memory_region(REGION_CPU1);
+
+ /* bits 0-1 select the tile bank */
+ if (gfxbank != (data & 0x03))
+ {
+ gfxbank = data & 0x03;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ /* bit 2 selects which of the two bitmaps to display (for 2 players game) */
+ show_bitmap = (data & 0x04) >> 2;
+
+ /* bit 3 enables NMI */
+ interrupt_enable_w(offset,data & 0x08);
+
+ /* bits 4-5 control ROM bank */
+ bankaddress = 0x10000 + ((data & 0x30) >> 4) * 0x4000;
+ memory_set_bankptr(1,&rom[bankaddress]);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void pbillian_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = 0; offs < spriteram_size; offs += 4)
+ {
+ int attr = spriteram[offs + 3];
+ int code = ((spriteram[offs] & 0xfc) >> 2) + 64 * (attr & 0x0f);
+ int color = (attr & 0xf0) >> 4;
+ int sx = spriteram[offs + 1] + 256 * (spriteram[offs] & 0x01);
+ int sy = spriteram[offs + 2];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flip_screen, flip_screen,
+ sx, sy,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+static void superqix_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0; offs < spriteram_size; offs += 4)
+ {
+ int attr = spriteram[offs + 3];
+ int code = spriteram[offs] + 256 * (attr & 0x01);
+ int color = (attr & 0xf0) >> 4;
+ int flipx = attr & 0x04;
+ int flipy = attr & 0x08;
+ int sx = spriteram[offs + 1];
+ int sy = spriteram[offs + 2];
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( pbillian )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ pbillian_draw_sprites(machine, bitmap,cliprect);
+
+ if (pbillian_show_power)
+ {
+ static int last_power[2];
+ int curr_power;
+
+ curr_power = ((readinputport(4)&0x3f)*100)/0x3f;
+ if (last_power[0] != curr_power)
+ {
+ popmessage ("Power %d%%", curr_power);
+ last_power[0] = curr_power;
+ }
+
+ curr_power = ((readinputport(6)&0x3f)*100)/0x3f;
+ if (last_power[1] != curr_power)
+ {
+ popmessage ("Power %d%%", curr_power);
+ last_power[1] = curr_power;
+ }
+ }
+ return 0;
+}
+
+VIDEO_UPDATE( superqix )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_LAYER1, 0);
+ copybitmap(bitmap,fg_bitmap[show_bitmap],flip_screen,flip_screen,0,0,cliprect,TRANSPARENCY_PEN,0);
+ superqix_draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_LAYER0, 0);
+ return 0;
+}
diff --git a/src/mame/video/suprloco.c b/src/mame/video/suprloco.c
new file mode 100644
index 00000000000..35ecaf56b00
--- /dev/null
+++ b/src/mame/video/suprloco.c
@@ -0,0 +1,277 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *suprloco_videoram;
+
+static tilemap *bg_tilemap;
+static int control;
+
+#define SPR_Y_TOP 0
+#define SPR_Y_BOTTOM 1
+#define SPR_X 2
+#define SPR_COL 3
+#define SPR_SKIP_LO 4
+#define SPR_SKIP_HI 5
+#define SPR_GFXOFS_LO 6
+#define SPR_GFXOFS_HI 7
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ I'm not sure about the resistor values, I'm using the Galaxian ones.
+
+***************************************************************************/
+PALETTE_INIT( suprloco )
+{
+ int i;
+
+
+ for (i = 0;i < 512;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ /* hack: generate a second bank of sprite palette with red changed to purple */
+ if (i >= 256)
+ {
+ if ((i & 0x0f) == 0x09)
+ palette_set_color(machine,i+256,MAKE_RGB(r,g,0xff));
+ else
+ palette_set_color(machine,i+256,MAKE_RGB(r,g,b));
+ }
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 attr = suprloco_videoram[2*tile_index+1];
+ SET_TILE_INFO(
+ 0,
+ suprloco_videoram[2*tile_index] | ((attr & 0x03) << 8),
+ (attr & 0x1c) >> 2,
+ 0);
+ tileinfo->category = (attr & 0x20) >> 5;
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( suprloco )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_scroll_rows(bg_tilemap,32);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( suprloco_videoram_w )
+{
+ suprloco_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+static int suprloco_scrollram[32];
+
+WRITE8_HANDLER( suprloco_scrollram_w )
+{
+ int adj = flip_screen ? -8 : 8;
+
+ suprloco_scrollram[offset] = data;
+ tilemap_set_scrollx(bg_tilemap,offset, data - adj);
+}
+
+READ8_HANDLER( suprloco_scrollram_r )
+{
+ return suprloco_scrollram[offset];
+}
+
+WRITE8_HANDLER( suprloco_control_w )
+{
+ /* There is probably a palette select in here */
+
+ /* Bit 0 - coin counter A */
+ /* Bit 1 - coin counter B (only used if coinage differs from A) */
+ /* Bit 2-3 - probably unused */
+ /* Bit 4 - ??? */
+ /* Bit 5 - pulsated when loco turns "super" */
+ /* Bit 6 - probably unused */
+ /* Bit 7 - flip screen */
+
+ if ((control & 0x10) != (data & 0x10))
+ {
+ /*logerror("Bit 4 = %d\n", (data >> 4) & 1); */
+ }
+
+ coin_counter_w(0, data & 0x01);
+ coin_counter_w(1, data & 0x02);
+
+ flip_screen_set(data & 0x80);
+ tilemap_set_scrolly(bg_tilemap,0,flip_screen ? -32 : 0);
+
+ control = data;
+}
+
+
+READ8_HANDLER( suprloco_control_r )
+{
+ return control;
+}
+
+
+
+INLINE void draw_pixel(mame_bitmap *bitmap,const rectangle *cliprect,int x,int y,int color)
+{
+ if (flip_screen)
+ {
+ x = bitmap->width - x - 1;
+ y = bitmap->height - y - 1;
+ }
+
+ if (x < cliprect->min_x ||
+ x > cliprect->max_x ||
+ y < cliprect->min_y ||
+ y > cliprect->max_y)
+ return;
+
+ *BITMAP_ADDR16(bitmap, y, x) = color;
+}
+
+
+static void draw_sprite(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int spr_number)
+{
+ int sx,sy,col,row,height,src,adjy,dy;
+ UINT8 *spr_reg;
+ const pen_t *spr_palette;
+ short skip; /* bytes to skip before drawing each row (can be negative) */
+
+
+ spr_reg = spriteram + 0x10 * spr_number;
+
+ src = spr_reg[SPR_GFXOFS_LO] + (spr_reg[SPR_GFXOFS_HI] << 8);
+ skip = spr_reg[SPR_SKIP_LO] + (spr_reg[SPR_SKIP_HI] << 8);
+
+ height = spr_reg[SPR_Y_BOTTOM] - spr_reg[SPR_Y_TOP];
+ spr_palette = machine->remapped_colortable + 0x100 + 0x10 * (spr_reg[SPR_COL]&0x03) + ((control & 0x20)?0x100:0);
+ sx = spr_reg[SPR_X];
+ sy = spr_reg[SPR_Y_TOP] + 1;
+
+ if (!flip_screen)
+ {
+ adjy = sy;
+ dy = 1;
+ }
+ else
+ {
+ adjy = sy + height + 30; /* some of the sprites are still off by a pixel */
+ dy = -1;
+ }
+
+ for (row = 0;row < height;row++,adjy+=dy)
+ {
+ int color1,color2,flipx;
+ UINT8 data;
+ UINT8 *gfx;
+
+ src += skip;
+
+ col = 0;
+
+ /* get pointer to packed sprite data */
+ gfx = &(memory_region(REGION_GFX2)[src & 0x7fff]);
+ flipx = src & 0x8000; /* flip x */
+
+ while (1)
+ {
+ if (flipx) /* flip x */
+ {
+ data = *gfx--;
+ color1 = data & 0x0f;
+ color2 = data >> 4;
+ }
+ else
+ {
+ data = *gfx++;
+ color1 = data >> 4;
+ color2 = data & 0x0f;
+ }
+
+ if (color1 == 15) break;
+ if (color1)
+ draw_pixel(bitmap,cliprect,sx+col, adjy,spr_palette[color1]);
+
+ if (color2 == 15) break;
+ if (color2)
+ draw_pixel(bitmap,cliprect,sx+col+1,adjy,spr_palette[color2]);
+
+ col += 2;
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int spr_number;
+ UINT8 *spr_reg;
+
+
+ for (spr_number = 0;spr_number < (spriteram_size >> 4);spr_number++)
+ {
+ spr_reg = spriteram + 0x10 * spr_number;
+ if (spr_reg[SPR_X] != 0xff)
+ draw_sprite(machine, bitmap, cliprect, spr_number);
+ }
+}
+
+VIDEO_UPDATE( suprloco )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,1,0);
+ return 0;
+}
diff --git a/src/mame/video/suprnova.c b/src/mame/video/suprnova.c
new file mode 100644
index 00000000000..c854ee32e6f
--- /dev/null
+++ b/src/mame/video/suprnova.c
@@ -0,0 +1,973 @@
+/* Super Kaneko Nova System video */
+
+/*
+TODO:
+Implement double buffering for sprites?
+We have to tell games which buffer to draw to? irrelevant to emulation
+
+Remove all debug keys
+*/
+
+/*
+Done:
+Add global sprite flip
+Tilemap flip flags were reversed
+*/
+
+#include "driver.h"
+
+#define SUPRNOVA_DECODE_BUFFER_SIZE 0x2000
+
+extern UINT32 *skns_tilemapA_ram, *skns_tilemapB_ram, *skns_v3slc_ram;
+extern UINT32 *skns_palette_ram, *skns_v3t_ram, *skns_main_ram, *skns_cache_ram;
+extern UINT32 *skns_pal_regs, *skns_v3_regs, *skns_spc_regs;
+extern UINT32 skns_v3t_dirty[0x4000]; // allocate this elsewhere?
+extern UINT32 skns_v3t_4bppdirty[0x8000]; // allocate this elsewhere?
+extern int skns_v3t_somedirty,skns_v3t_4bpp_somedirty;
+
+static UINT8 decodebuffer[SUPRNOVA_DECODE_BUFFER_SIZE];
+static int old_depthA=0, depthA=0;
+static int old_depthB=0, depthB=0;
+
+static int sprite_kludge_x=0, sprite_kludge_y=0;
+static int use_spc_bright, use_v3_bright;
+static UINT8 bright_spc_b=0x00, bright_spc_g=0x00, bright_spc_r=0x00;
+static UINT8 bright_v3_b=0x00, bright_v3_g=0x00, bright_v3_r=0x00;
+
+
+// This ignores the alpha values atm.
+static int spc_changed=0, v3_changed=0, palette_updated=0;
+
+WRITE32_HANDLER ( skns_pal_regs_w )
+{
+ COMBINE_DATA(&skns_pal_regs[offset]);
+ palette_updated =1;
+
+ switch ( offset )
+ {
+ case (0x00/4): // RWRA0
+ if( use_spc_bright != (data&1) ) {
+ use_spc_bright = data&1;
+ spc_changed = 1;
+ }
+ break;
+ case (0x04/4): // RWRA1
+ if( bright_spc_g != (data&0xff) ) {
+ bright_spc_g = data&0xff;
+ spc_changed = 1;
+ }
+ break;
+ case (0x08/4): // RWRA2
+ if( bright_spc_r != (data&0xff) ) {
+ bright_spc_r = data&0xff;
+ spc_changed = 1;
+ }
+ break;
+ case (0x0C/4): // RWRA3
+ if( bright_spc_b != (data&0xff) ) {
+ bright_spc_b = data&0xff;
+ spc_changed = 1;
+ }
+ break;
+
+ case (0x10/4): // RWRB0
+ if( use_v3_bright != (data&1) ) {
+ use_v3_bright = data&1;
+ v3_changed = 1;
+ }
+ break;
+ case (0x14/4): // RWRB1
+ if( bright_v3_g != (data&0xff) ) {
+ bright_v3_g = data&0xff;
+ v3_changed = 1;
+ }
+ break;
+ case (0x18/4): // RWRB2
+ if( bright_v3_r != (data&0xff) ) {
+ bright_v3_r = data&0xff;
+ v3_changed = 1;
+ }
+ break;
+ case (0x1C/4): // RWRB3
+ if( bright_v3_b != (data&0xff) ) {
+ bright_v3_b = data&0xff;
+ v3_changed = 1;
+ }
+ break;
+ }
+}
+
+
+WRITE32_HANDLER ( skns_palette_ram_w )
+{
+ int r,g,b;
+ int brightness_r, brightness_g, brightness_b, alpha;
+ int use_bright;
+
+ COMBINE_DATA(&skns_palette_ram[offset]);
+
+ b = ((skns_palette_ram[offset] >> 0 ) & 0x1f);
+ g = ((skns_palette_ram[offset] >> 5 ) & 0x1f);
+ r = ((skns_palette_ram[offset] >> 10 ) & 0x1f);
+
+ alpha = ((skns_palette_ram[offset] >> 15 ) & 0x1);
+
+ if(offset<(0x40*256)) { // 1st half is for Sprites
+ use_bright = use_spc_bright;
+ brightness_b = bright_spc_b;
+ brightness_g = bright_spc_g;
+ brightness_r = bright_spc_r;
+ } else { // V3 bg's
+ use_bright = use_v3_bright;
+ brightness_b = bright_v3_b;
+ brightness_g = bright_v3_g;
+ brightness_r = bright_v3_r;
+ }
+
+ if(use_bright) {
+ if(brightness_b) b = ((b<<3) * (brightness_b+1))>>8;
+ else b = 0;
+ if(brightness_g) g = ((g<<3) * (brightness_g+1))>>8;
+ else g = 0;
+ if(brightness_r) r = ((r<<3) * (brightness_r+1))>>8;
+ else r = 0;
+ } else {
+ b <<= 3;
+ g <<= 3;
+ r <<= 3;
+ }
+
+ palette_set_color(Machine,offset,MAKE_RGB(r,g,b));
+}
+
+
+static void palette_set_rgb_brightness (running_machine *machine, int offset, UINT8 brightness_r, UINT8 brightness_g, UINT8 brightness_b)
+{
+ int use_bright, r, g, b, alpha;
+
+ b = ((skns_palette_ram[offset] >> 0 ) & 0x1f);
+ g = ((skns_palette_ram[offset] >> 5 ) & 0x1f);
+ r = ((skns_palette_ram[offset] >> 10 ) & 0x1f);
+
+ alpha = ((skns_palette_ram[offset] >> 15 ) & 0x1);
+
+ if(offset<(0x40*256)) { // 1st half is for Sprites
+ use_bright = use_spc_bright;
+ } else { // V3 bg's
+ use_bright = use_v3_bright;
+ }
+
+ if(use_bright) {
+ if(brightness_b) b = ((b<<3) * (brightness_b+1))>>8;
+ else b = 0;
+ if(brightness_g) g = ((g<<3) * (brightness_g+1))>>8;
+ else g = 0;
+ if(brightness_r) r = ((r<<3) * (brightness_r+1))>>8;
+ else r = 0;
+ } else {
+ b <<= 3;
+ g <<= 3;
+ r <<= 3;
+ }
+
+ palette_set_color(machine,offset,MAKE_RGB(r,g,b));
+}
+
+
+static void palette_update(running_machine *machine)
+{
+ int i;
+
+ if (palette_updated)
+ {
+ if(spc_changed)
+ for(i=0; i<=((0x40*256)-1); i++)
+ palette_set_rgb_brightness (machine, i, bright_spc_r, bright_spc_g, bright_spc_b);
+
+ if(v3_changed)
+ for(i=(0x40*256); i<=((0x80*256)-1); i++)
+ palette_set_rgb_brightness (machine, i, bright_v3_r, bright_v3_g, bright_v3_b);
+ palette_updated =0;
+ }
+}
+
+
+static int skns_rle_decode ( int romoffset, int size )
+{
+ UINT8 *src = memory_region (REGION_GFX1);
+ size_t srcsize = memory_region_length (REGION_GFX1);
+ UINT8 *dst = decodebuffer;
+ int decodeoffset = 0;
+
+ while(size>0) {
+ UINT8 code = src[(romoffset++)%srcsize];
+ size -= (code & 0x7f) + 1;
+ if(code & 0x80) {
+ code &= 0x7f;
+ do {
+ dst[(decodeoffset++)%SUPRNOVA_DECODE_BUFFER_SIZE] = src[(romoffset++)%srcsize];
+ code--;
+ } while(code != 0xff);
+ } else {
+ UINT8 val = src[(romoffset++)%srcsize];
+ do {
+ dst[(decodeoffset++)%SUPRNOVA_DECODE_BUFFER_SIZE] = val;
+ code--;
+ } while(code != 0xff);
+ }
+ }
+ return &src[romoffset%srcsize]-memory_region (REGION_GFX1);
+}
+
+void skns_sprite_kludge(int x, int y)
+{
+ sprite_kludge_x = x;
+ sprite_kludge_y = y;
+}
+
+/* Zooming blitter, zoom is by way of both source and destination offsets */
+/* We are working in .6 fixed point if you hadn't guessed */
+
+#define z_decls(step) \
+ UINT16 zxs = 0x40-(zx>>10); \
+ UINT16 zxd = 0x40-((zx>>2) & 0x3f); \
+ UINT16 zys = 0x40-(zy>>10); \
+ UINT16 zyd = 0x40-((zy>>2) & 0x3f); \
+ int xs, ys, xd, yd, old, old2; \
+ int step_spr = step; \
+ int bxs = 0, bys = 0; \
+ rectangle clip; \
+ clip.min_x = cliprect->min_x<<6; \
+ clip.max_x = (cliprect->max_x+1)<<6; \
+ clip.min_y = cliprect->min_y<<6; \
+ clip.max_y = (cliprect->max_y+1)<<6; \
+ sx <<= 6; \
+ sy <<= 6; \
+ x <<= 6; \
+ y <<= 6;
+
+#define z_clamp_x_min() \
+ if(x < clip.min_x) { \
+ do { \
+ bxs += zxs; \
+ x += zxd; \
+ } while(x < clip.min_x); \
+ }
+
+#define z_clamp_x_max() \
+ if(x > clip.max_x) { \
+ do { \
+ bxs += zxs; \
+ x -= zxd; \
+ } while(x > clip.max_x); \
+ }
+
+#define z_clamp_y_min() \
+ if(y < clip.min_y) { \
+ do { \
+ bys += zys; \
+ y += zyd; \
+ } while(y < clip.min_y); \
+ src += (bys>>6)*step_spr; \
+ }
+
+#define z_clamp_y_max() \
+ if(y > clip.max_y) { \
+ do { \
+ bys += zys; \
+ y -= zyd; \
+ } while(y > clip.max_y); \
+ src += (bys>>6)*step_spr; \
+ }
+
+#define z_loop_x() \
+ xs = bxs; \
+ xd = x; \
+ while(xs < sx && xd <= clip.max_x)
+
+#define z_loop_x_flip() \
+ xs = bxs; \
+ xd = x; \
+ while(xs < sx && xd >= clip.min_x)
+
+#define z_loop_y() \
+ ys = bys; \
+ yd = y; \
+ while(ys < sy && yd <= clip.max_y)
+
+#define z_loop_y_flip() \
+ ys = bys; \
+ yd = y; \
+ while(ys < sy && yd >= clip.min_y)
+
+#define z_draw_pixel() \
+ UINT8 val = src[xs >> 6]; \
+ if(val) \
+ *BITMAP_ADDR16(bitmap, yd>>6, xd>>6) = val + colour;
+
+#define z_x_dst(op) \
+ old = xd; \
+ do { \
+ xs += zxs; \
+ xd op zxd; \
+ } while(!((xd^old) & ~0x3f));
+
+#define z_y_dst(op) \
+ old = yd; \
+ old2 = ys; \
+ do { \
+ ys += zys; \
+ yd op zyd; \
+ } while(!((yd^old) & ~0x3f)); \
+ while((ys^old2) & ~0x3f) { \
+ src += step_spr; \
+ old2 += 0x40; \
+ }
+
+static void blit_nf_z(mame_bitmap *bitmap, const rectangle *cliprect, const UINT8 *src, int x, int y, int sx, int sy, UINT16 zx, UINT16 zy, int colour)
+{
+ z_decls(sx);
+ z_clamp_x_min();
+ z_clamp_y_min();
+ z_loop_y() {
+ z_loop_x() {
+ z_draw_pixel();
+ z_x_dst(+=);
+ }
+ z_y_dst(+=);
+ }
+}
+
+static void blit_fy_z(mame_bitmap *bitmap, const rectangle *cliprect, const UINT8 *src, int x, int y, int sx, int sy, UINT16 zx, UINT16 zy, int colour)
+{
+ z_decls(sx);
+ z_clamp_x_min();
+ z_clamp_y_max();
+ z_loop_y_flip() {
+ z_loop_x() {
+ z_draw_pixel();
+ z_x_dst(+=);
+ }
+ z_y_dst(-=);
+ }
+}
+
+static void blit_fx_z(mame_bitmap *bitmap, const rectangle *cliprect, const UINT8 *src, int x, int y, int sx, int sy, UINT16 zx, UINT16 zy, int colour)
+{
+ z_decls(sx);
+ z_clamp_x_max();
+ z_clamp_y_min();
+ z_loop_y() {
+ z_loop_x_flip() {
+ z_draw_pixel();
+ z_x_dst(-=);
+ }
+ z_y_dst(+=);
+ }
+}
+
+static void blit_fxy_z(mame_bitmap *bitmap, const rectangle *cliprect, const UINT8 *src, int x, int y, int sx, int sy, UINT16 zx, UINT16 zy, int colour)
+{
+ z_decls(sx);
+ z_clamp_x_max();
+ z_clamp_y_max();
+ z_loop_y_flip() {
+ z_loop_x_flip() {
+ z_draw_pixel();
+ z_x_dst(-=);
+ }
+ z_y_dst(-=);
+ }
+}
+
+static void (*blit_z[4])(mame_bitmap *bitmap, const rectangle *cliprect, const UINT8 *src, int x, int y, int sx, int sy, UINT16 zx, UINT16 zy, int colour) = {
+ blit_nf_z,
+ blit_fy_z,
+ blit_fx_z,
+ blit_fxy_z,
+};
+
+void skns_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ /*- SPR RAM Format -**
+
+ 16 bytes per sprite
+
+0x00 --ss --SS z--- ---- jjjg g-ff ppcc cccc
+
+ s = y size
+ S = x size
+ j = joint
+ g = group sprite is part of (if groups are enabled)
+ f = flip
+ p = priority
+ c = palette
+
+0x04 ---- -aaa aaaa aaaa aaaa aaaa aaaa aaaa
+
+ a = ROM address of sprite data
+
+0x08 ZZZZ ZZ-- zzzz zz-- xxxx xxxx xx-- ----
+
+ Z = horizontal zoom table
+ z = horizontal zoom subtable
+ x = x position
+
+0x0C ZZZZ ZZ-- zzzz zz-- yyyy yyyy yy-- ----
+
+ Z = vertical zoom table
+ z = vertical zoom subtable
+ x = y position
+
+ **- End of Comments -*/
+
+ /* sprite ram start / end is not really fixed registers change it */
+
+ UINT32 *source = buffered_spriteram32;
+ UINT32 *finish = source + spriteram_size/4;
+
+ int group_x_offset[4];
+ int group_y_offset[4];
+ int group_enable;
+ int group_number;
+ int sprite_flip;
+ int sprite_x_scroll;
+ int sprite_y_scroll;
+ int disabled = skns_spc_regs[0x04/4] & 0x08; // RWR1
+ int xsize,ysize, size, xpos=0,ypos=0, pri=0, romoffset, colour=0, xflip,yflip, joint;
+ int sx,sy;
+ int endromoffs=0;
+ UINT16 zoomx, zoomy;
+
+
+ if (!disabled){
+
+ group_enable = (skns_spc_regs[0x00/4] & 0x0040) >> 6; // RWR0
+
+ /* Sengekis uses global flip */
+ sprite_flip = (skns_spc_regs[0x04/4] & 0x03); // RWR1
+
+ sprite_y_scroll = ((skns_spc_regs[0x08/4] & 0x7fc0) >> 6); // RWR2
+ sprite_x_scroll = ((skns_spc_regs[0x10/4] & 0x7fc0) >> 6); // RWR4
+ if (sprite_y_scroll&0x100) sprite_y_scroll -= 0x200; // Signed
+ if (sprite_x_scroll&0x100) sprite_x_scroll -= 0x200; // Signed
+
+ group_x_offset[0] = (skns_spc_regs[0x18/4] & 0xffc0) >> 6; // RWR6
+ group_y_offset[0] = (skns_spc_regs[0x1c/4] & 0xffc0) >> 6; // RWR7
+ if (group_x_offset[0]&0x200) group_x_offset[0] -= 0x400; // Signed
+ if (group_y_offset[0]&0x200) group_y_offset[0] -= 0x400; // Signed
+
+ group_x_offset[1] = (skns_spc_regs[0x20/4] & 0xffc0) >> 6; // RWR8
+ group_y_offset[1] = (skns_spc_regs[0x24/4] & 0xffc0) >> 6; // RWR9
+ if (group_x_offset[1]&0x200) group_x_offset[1] -= 0x400; // Signed
+ if (group_y_offset[1]&0x200) group_y_offset[1] -= 0x400; // Signed
+
+ group_x_offset[2] = (skns_spc_regs[0x28/4] & 0xffc0) >> 6; // RWR10
+ group_y_offset[2] = (skns_spc_regs[0x2c/4] & 0xffc0) >> 6; // RWR11
+ if (group_x_offset[2]&0x200) group_x_offset[2] -= 0x400; // Signed
+ if (group_y_offset[2]&0x200) group_y_offset[2] -= 0x400; // Signed
+
+ group_x_offset[3] = (skns_spc_regs[0x30/4] & 0xffc0) >> 6; // RWR12
+ group_y_offset[3] = (skns_spc_regs[0x34/4] & 0xffc0) >> 6; // RWR13
+ if (group_x_offset[3]&0x200) group_x_offset[3] -= 0x400; // Signed
+ if (group_y_offset[3]&0x200) group_y_offset[3] -= 0x400; // Signed
+
+ // popmessage ("x %08x y %08x x2 %08x y2 %08x",sprite_x_scroll, sprite_y_scroll,group_x_offset[1], group_y_offset[1]);
+ // popmessage("%d %d %d %d A:%d B:%d", sprite_kludge_x, sprite_kludge_y, sprite_x_scroll, sprite_y_scroll, (skns_pal_regs[0x00/4] & 0x7000) >> 12, (skns_pal_regs[0x10/4] & 0x7000) >> 12);
+ // if (keyboard_pressed(KEYCODE_Q)) sprite_kludge_x++;
+ // if (keyboard_pressed(KEYCODE_W)) sprite_kludge_x--;
+ // if (keyboard_pressed(KEYCODE_E)) sprite_kludge_y++;
+ // if (keyboard_pressed(KEYCODE_D)) sprite_kludge_y--;
+
+ // Tilemap Pri/enables
+ // popmessage("A: %x %x B: %x %x", skns_v3_regs[0x10/4]>>3, skns_v3_regs[0x10/4]&7, skns_v3_regs[0x34/4]>>3, skns_v3_regs[0x34/4]&7);
+
+ /* Seems that sprites are consistently off by a fixed no. of pixels in different games
+ (Patterns emerge through Manufacturer/Date/Orientation) */
+ sprite_x_scroll += sprite_kludge_x;
+ sprite_y_scroll += sprite_kludge_y;
+
+
+ while( source<finish )
+ {
+ xflip = (source[0] & 0x00000200) >> 9;
+ yflip = (source[0] & 0x00000100) >> 8;
+
+ ysize = (source[0] & 0x30000000) >> 28;
+ xsize = (source[0] & 0x03000000) >> 24;
+ xsize ++;
+ ysize ++;
+
+ xsize *= 16;
+ ysize *= 16;
+
+ size = xsize * ysize;
+
+ joint = (source[0] & 0x0000e000) >> 13;
+
+ if (!(joint & 1))
+ {
+ xpos = (source[2] & 0x0000ffc0) >> 6;
+ ypos = (source[3] & 0x0000ffc0) >> 6;
+
+ xpos += sprite_x_scroll; // Global offset
+ ypos += sprite_y_scroll;
+
+ if (group_enable)
+ {
+ group_number = (source[0] & 0x00001800) >> 11;
+
+ /* the group positioning doesn't seem to be working as i'd expect,
+ if I apply the x position the cursor on galpani4 ends up moving
+ from the correct position to too far right, also the y offset
+ seems to cause the position to be off by one in galpans2 even if
+ it fixes the position in galpani4?
+
+ even if I take into account the global sprite scroll registers
+ it isn't right
+
+ global offset kludged using game specific offset -pjp */
+
+ xpos += group_x_offset[group_number];
+ ypos += group_y_offset[group_number];
+ }
+ }
+ else
+ {
+ xpos += (source[2] & 0x0000ffc0) >> 6;
+ ypos += (source[3] & 0x0000ffc0) >> 6;
+ }
+
+ if (xpos > 0x1ff) xpos -= 0x400;
+ if (ypos > 0x1ff) ypos -= 0x400;
+
+ /* Local sprite offset (for taking flip into account and drawing offset) */
+ sx = xpos;
+ sy = ypos;
+
+ /* Global Sprite Flip (sengekis) */
+ if (sprite_flip&2)
+ {
+ xflip ^= 1;
+ sx = machine->screen[0].visarea.max_x+1 - sx;
+ }
+ if (sprite_flip&1)
+ {
+ yflip ^= 1;
+ sy = machine->screen[0].visarea.max_y+1 - sy;
+ }
+
+ /* Palette linking */
+ if (!(joint & 2))
+ {
+ colour = (source[0] & 0x0000003f) >> 0;
+ }
+
+ /* Priority and Tile linking */
+ if (!(joint & 4))
+ {
+ romoffset = (source[1] & 0x07ffffff) >> 0;
+ pri = (source[0] & 0x000000c0) >> 6;
+ } else {
+ romoffset = endromoffs;
+ }
+
+ zoomx = source[2] >> 16;
+ zoomy = source[3] >> 16;
+
+ romoffset &= memory_region_length (REGION_GFX1)-1;
+
+ endromoffs = skns_rle_decode ( romoffset, size );
+
+ // PriTest
+// if(!( (keyboard_pressed(KEYCODE_Q)&&(pri==0)) || (keyboard_pressed(KEYCODE_W)&&(pri==1)) || (keyboard_pressed(KEYCODE_E)&&(pri==2)) || (keyboard_pressed(KEYCODE_D)&&(pri==3)) ))
+// if( !(keyboard_pressed(KEYCODE_Q) && ((source[0] & 0x00800000)>>24)) )
+ {
+ int NewColour = colour*256;
+
+ if(zoomx || zoomy)
+ {
+ blit_z[ (xflip<<1) | yflip ](bitmap, cliprect, decodebuffer, sx, sy, xsize, ysize, zoomx, zoomy, NewColour);
+ }
+ else
+ {
+ if (!xflip && !yflip) {
+ int xx,yy;
+
+ for (xx = 0; xx<xsize; xx++)
+ {
+ if ((sx+xx < (cliprect->max_x+1)) && (sx+xx >= cliprect->min_x))
+ {
+ for (yy = 0; yy<ysize; yy++)
+ {
+ if ((sy+yy < (cliprect->max_y+1)) && (sy+yy >= cliprect->min_y))
+ {
+ int pix;
+ pix = decodebuffer[xsize*yy+xx];
+ if (pix)
+ *BITMAP_ADDR16(bitmap, sy+yy, sx+xx) = pix+ NewColour; // change later
+ }
+ }
+ }
+ }
+ } else if (!xflip && yflip) {
+ int xx,yy;
+ sy -= ysize;
+
+ for (xx = 0; xx<xsize; xx++)
+ {
+ if ((sx+xx < (cliprect->max_x+1)) && (sx+xx >= cliprect->min_x))
+ {
+ for (yy = 0; yy<ysize; yy++)
+ {
+ if ((sy+(ysize-1-yy) < (cliprect->max_y+1)) && (sy+(ysize-1-yy) >= cliprect->min_y))
+ {
+ int pix;
+ pix = decodebuffer[xsize*yy+xx];
+ if (pix)
+ *BITMAP_ADDR16(bitmap, sy+(ysize-1-yy), sx+xx) = pix+ NewColour; // change later
+ }
+ }
+ }
+ }
+ } else if (xflip && !yflip) {
+ int xx,yy;
+ sx -= xsize;
+
+ for (xx = 0; xx<xsize; xx++)
+ {
+ if ( (sx+(xsize-1-xx) < (cliprect->max_x+1)) && (sx+(xsize-1-xx) >= cliprect->min_x))
+ {
+ for (yy = 0; yy<ysize; yy++)
+ {
+ if ((sy+yy < (cliprect->max_y+1)) && (sy+yy >= cliprect->min_y))
+ {
+ int pix;
+ pix = decodebuffer[xsize*yy+xx];
+ if (pix)
+ *BITMAP_ADDR16(bitmap, sy+yy, sx+(xsize-1-xx)) = pix+ NewColour; // change later
+ }
+ }
+ }
+ }
+ } else if (xflip && yflip) {
+ int xx,yy;
+ sx -= xsize;
+ sy -= ysize;
+
+ for (xx = 0; xx<xsize; xx++)
+ {
+ if ((sx+(xsize-1-xx) < (cliprect->max_x+1)) && (sx+(xsize-1-xx) >= cliprect->min_x))
+ {
+ for (yy = 0; yy<ysize; yy++)
+ {
+ if ((sy+(ysize-1-yy) < (cliprect->max_y+1)) && (sy+(ysize-1-yy) >= cliprect->min_y))
+ {
+ int pix;
+ pix = decodebuffer[xsize*yy+xx];
+ if (pix)
+ *BITMAP_ADDR16(bitmap, sy+(ysize-1-yy), sx+(xsize-1-xx)) = pix+ NewColour; // change later
+ }
+ }
+ }
+ }
+ }
+ }
+ }//End PriTest
+
+ source+=4;
+ }
+ }
+}
+
+static tilemap *skns_tilemap_A;
+static tilemap *skns_tilemap_B;
+
+static TILE_GET_INFO( get_tilemap_A_tile_info )
+{
+ int code = ((skns_tilemapA_ram[tile_index] & 0x001fffff) >> 0 );
+ int colr = ((skns_tilemapA_ram[tile_index] & 0x3f000000) >> 24 );
+// int pri = ((skns_tilemapA_ram[tile_index] & 0x00e00000) >> 21 );
+ int depth = (skns_v3_regs[0x0c/4] & 0x0001) << 1;
+ int flags = 0;
+
+ if(skns_tilemapA_ram[tile_index] & 0x80000000) flags |= TILE_FLIPX;
+ if(skns_tilemapA_ram[tile_index] & 0x40000000) flags |= TILE_FLIPY;
+
+ SET_TILE_INFO(
+ 0+depth,
+ code,
+ 0x40+colr,
+ flags);
+// tileinfo->category = pri;
+}
+
+WRITE32_HANDLER ( skns_tilemapA_w )
+{
+ COMBINE_DATA(&skns_tilemapA_ram[offset]);
+ tilemap_mark_tile_dirty(skns_tilemap_A,offset);
+}
+
+static TILE_GET_INFO( get_tilemap_B_tile_info )
+{
+ int code = ((skns_tilemapB_ram[tile_index] & 0x001fffff) >> 0 );
+ int colr = ((skns_tilemapB_ram[tile_index] & 0x3f000000) >> 24 );
+// int pri = ((skns_tilemapA_ram[tile_index] & 0x00e00000) >> 21 );
+ int depth = (skns_v3_regs[0x0c/4] & 0x0100) >> 7;
+ int flags = 0;
+
+ if(skns_tilemapB_ram[tile_index] & 0x80000000) flags |= TILE_FLIPX;
+ if(skns_tilemapB_ram[tile_index] & 0x40000000) flags |= TILE_FLIPY;
+
+ SET_TILE_INFO(
+ 1+depth,
+ code,
+ 0x40+colr,
+ flags);
+// tileinfo->category = pri;
+}
+
+WRITE32_HANDLER ( skns_tilemapB_w )
+{
+ COMBINE_DATA(&skns_tilemapB_ram[offset]);
+ tilemap_mark_tile_dirty(skns_tilemap_B,offset);
+}
+
+WRITE32_HANDLER ( skns_v3_regs_w )
+{
+ COMBINE_DATA(&skns_v3_regs[offset]);
+
+ /* if the depth changes we need to dirty the tilemap */
+ if (offset == 0x0c/4)
+ {
+ old_depthA = depthA;
+ old_depthB = depthB;
+
+ depthA = (skns_v3_regs[0x0c/4] & 0x0001) << 1;
+ depthB = (skns_v3_regs[0x0c/4] & 0x0100) >> 7;
+
+ if (old_depthA != depthA) tilemap_mark_all_tiles_dirty (skns_tilemap_A);
+ if (old_depthB != depthB) tilemap_mark_all_tiles_dirty (skns_tilemap_B);
+
+ }
+}
+
+
+VIDEO_START(skns)
+{
+ skns_tilemap_A = tilemap_create(get_tilemap_A_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64, 64);
+ tilemap_set_transparent_pen(skns_tilemap_A,0);
+
+ skns_tilemap_B = tilemap_create(get_tilemap_B_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64, 64);
+ tilemap_set_transparent_pen(skns_tilemap_B,0);
+
+ machine->gfx[2]->color_granularity=256;
+ machine->gfx[3]->color_granularity=256;
+}
+
+static void supernova_draw_a( mame_bitmap *bitmap, const rectangle *cliprect, int tran )
+{
+ int enable_a = (skns_v3_regs[0x10/4] >> 0) & 0x0001;
+ UINT32 startx,starty;
+ int incxx,incxy,incyx,incyy;
+
+ if (enable_a)
+ {
+ startx = skns_v3_regs[0x1c/4];
+ incyy = skns_v3_regs[0x30/4]; // was xx, changed for sarukani
+ incyx = skns_v3_regs[0x2c/4];
+ starty = skns_v3_regs[0x20/4];
+ incxy = skns_v3_regs[0x28/4];
+ incxx = skns_v3_regs[0x24/4]; // was yy, changed for sarukani
+
+ if( (incxx == 1<<8) && !incxy & !incyx && (incyy == 1<<8) ) // No Roz, only scroll.
+ {
+ int columnscroll_a = (skns_v3_regs[0x0c/4] >> 1) & 0x0001;
+ int offs;
+
+ startx >>= 8; // Lose Floating point
+ starty >>= 8;
+
+ if(columnscroll_a) {
+ tilemap_set_scroll_rows(skns_tilemap_A,1);
+ tilemap_set_scroll_cols(skns_tilemap_A,0x400);
+
+ tilemap_set_scrollx( skns_tilemap_A, 0, startx );
+ for(offs=0; offs<(0x1000/4); offs++)
+ tilemap_set_scrolly( skns_tilemap_A, offs, starty - (skns_v3slc_ram[offs]&0x3ff) );
+ }
+ else
+ {
+ tilemap_set_scroll_rows(skns_tilemap_A,0x400);
+ tilemap_set_scroll_cols(skns_tilemap_A,1);
+
+ tilemap_set_scrolly( skns_tilemap_A, 0, starty );
+ for(offs=0; offs<(0x1000/4); offs++)
+ tilemap_set_scrollx( skns_tilemap_A, offs, startx - (skns_v3slc_ram[offs]&0x3ff) );
+ }
+ tilemap_draw(bitmap,cliprect,skns_tilemap_A,tran ? 0 : TILEMAP_DRAW_OPAQUE,0);
+ }
+ else
+ {
+ tilemap_draw_roz(bitmap,cliprect,skns_tilemap_A,startx << 8,starty << 8,
+ incxx << 8,incxy << 8,incyx << 8,incyy << 8,
+ 1, /* wraparound */
+ tran ? 0 : TILEMAP_DRAW_OPAQUE,0);
+ }
+ }
+}
+
+static void supernova_draw_b( mame_bitmap *bitmap, const rectangle *cliprect, int tran )
+{
+ int enable_b = (skns_v3_regs[0x34/4] >> 0) & 0x0001;
+ UINT32 startx,starty;
+ int incxx,incxy,incyx,incyy;
+
+ if (enable_b)
+ {
+ startx = skns_v3_regs[0x40/4];
+ incyy = skns_v3_regs[0x54/4];
+ incyx = skns_v3_regs[0x50/4];
+ starty = skns_v3_regs[0x44/4];
+ incxy = skns_v3_regs[0x4c/4];
+ incxx = skns_v3_regs[0x48/4];
+
+ if( (incxx == 1<<8) && !incxy & !incyx && (incyy == 1<<8) ) // No Roz, only scroll.
+ {
+ int columnscroll_b = (skns_v3_regs[0x0c/4] >> 9) & 0x0001;
+ int offs;
+
+ startx >>= 8;
+ starty >>= 8;
+
+ if(columnscroll_b) {
+ tilemap_set_scroll_rows(skns_tilemap_B,1);
+ tilemap_set_scroll_cols(skns_tilemap_B,0x400);
+
+ tilemap_set_scrollx( skns_tilemap_B, 0, startx );
+ for(offs=0; offs<(0x1000/4); offs++)
+ tilemap_set_scrolly( skns_tilemap_B, offs, starty - (skns_v3slc_ram[offs+(0x1000/4)]&0x3ff) );
+ }
+ else
+ {
+ tilemap_set_scroll_rows(skns_tilemap_B,0x400);
+ tilemap_set_scroll_cols(skns_tilemap_B,1);
+
+ tilemap_set_scrolly( skns_tilemap_B, 0, starty );
+ for(offs=0; offs<(0x1000/4); offs++)
+ tilemap_set_scrollx( skns_tilemap_B, offs, startx - (skns_v3slc_ram[offs+(0x1000/4)]&0x3ff) );
+ }
+ tilemap_draw(bitmap,cliprect,skns_tilemap_B,tran ? 0 : TILEMAP_DRAW_OPAQUE,0);
+ }
+ else
+ {
+ tilemap_draw_roz(bitmap,cliprect,skns_tilemap_B,startx << 8,starty << 8,
+ incxx << 8,incxy << 8,incyx << 8,incyy << 8,
+ 1, /* wraparound */
+ tran ? 0 : TILEMAP_DRAW_OPAQUE,0);
+ }
+ }
+}
+
+VIDEO_UPDATE(skns)
+{
+ int i, offset;
+
+ UINT8 *btiles;
+
+
+ palette_update(machine);
+
+ btiles = memory_region (REGION_GFX3);
+
+// if (!(skns_v3_regs[0x0c/4] & 0x0100)); // if tilemap b is in 8bpp mode
+ {
+ if (skns_v3t_somedirty)
+ {
+ skns_v3t_somedirty = 0;
+
+ /* check if & where that tile is used in the tilemap */
+ for (offset=0;offset<0x4000/4;offset++)
+ {
+ int code = ((skns_tilemapB_ram[offset] & 0x001fffff) >> 0 );
+ if (skns_v3t_dirty[code&0x3ff])
+ tilemap_mark_tile_dirty(skns_tilemap_B,offset);
+ }
+
+ for (i = 0; i < 0x0400; i++)
+ {
+ if (skns_v3t_dirty[i] == 1)
+ {
+ decodechar(machine->gfx[1], i, (UINT8*)btiles, machine->drv->gfxdecodeinfo[0].gfxlayout);
+
+ skns_v3t_dirty[i] = 0;
+ }
+ }
+ }
+ }
+
+// if (skns_v3_regs[0x0c/4] & 0x0100); // if tilemap b is in 4bpp mode
+ {
+ if (skns_v3t_4bpp_somedirty)
+ {
+ skns_v3t_4bpp_somedirty = 0;
+
+ /* check if & where that tile is used in the tilemap */
+ for (offset=0;offset<0x4000/4;offset++)
+ {
+ int code = ((skns_tilemapB_ram[offset] & 0x001fffff) >> 0 );
+ if (skns_v3t_4bppdirty[code&0x7ff])
+ tilemap_mark_tile_dirty(skns_tilemap_B,offset);
+ }
+
+ for (i = 0; i < 0x0800; i++)
+ {
+ if (skns_v3t_4bppdirty[i] == 1)
+ {
+ decodechar(machine->gfx[3], i, (UINT8*)btiles, machine->drv->gfxdecodeinfo[3].gfxlayout);
+
+ skns_v3t_4bppdirty[i] = 0;
+ }
+ }
+ }
+ }
+
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ {
+ int supernova_pri_a;
+ int supernova_pri_b;
+ int tran = 0;
+
+ supernova_pri_a = skns_v3_regs[0x10/4] & 0x0002;
+ supernova_pri_b = skns_v3_regs[0x34/4] & 0x0002;
+
+
+ /* needed until we have the per tile priorities sorted out */
+ if (!strcmp(machine->gamedrv->name,"vblokbrk") ||
+ !strcmp(machine->gamedrv->name,"sarukani") ||
+ !strcmp(machine->gamedrv->name,"sengekis") ||
+ !strcmp(machine->gamedrv->name,"sengekij"))
+ {
+ supernova_pri_b = 0;
+ supernova_pri_a = 1;
+ }
+
+
+ if (!supernova_pri_a) { supernova_draw_a(bitmap,cliprect,tran); tran = 1;}
+ if (!supernova_pri_b) { supernova_draw_b(bitmap,cliprect,tran); tran = 1;}
+ if (supernova_pri_a) { supernova_draw_a(bitmap,cliprect,tran); tran = 1;}
+ if (supernova_pri_b) { supernova_draw_b(bitmap,cliprect,tran); tran = 1;}
+
+
+ }
+
+
+ skns_draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
+
+VIDEO_EOF(skns)
+{
+ buffer_spriteram32_w(0,0,0);
+}
diff --git a/src/mame/video/suprridr.c b/src/mame/video/suprridr.c
new file mode 100644
index 00000000000..98fbac87624
--- /dev/null
+++ b/src/mame/video/suprridr.c
@@ -0,0 +1,212 @@
+/***************************************************************************
+
+ Venture Line Super Rider driver
+
+***************************************************************************/
+
+#include "driver.h"
+#include "suprridr.h"
+
+
+UINT8 *suprridr_bgram;
+UINT8 *suprridr_fgram;
+
+static tilemap *fg_tilemap;
+static tilemap *bg_tilemap;
+static tilemap *bg_tilemap_noscroll;
+static UINT8 flipx, flipy;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 code = suprridr_bgram[tile_index];
+ SET_TILE_INFO(0, code, 0, 0);
+}
+
+
+static TILE_GET_INFO( get_tile_info2 )
+{
+ UINT8 code = suprridr_fgram[tile_index];
+ SET_TILE_INFO(1, code, 0, 0);
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( suprridr )
+{
+ fg_tilemap = tilemap_create(get_tile_info2, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+ bg_tilemap = tilemap_create(get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+ bg_tilemap_noscroll = tilemap_create(get_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+
+
+/*************************************
+ *
+ * Color PROM decoding
+ *
+ *************************************/
+
+PALETTE_INIT( suprridr )
+{
+ int i;
+
+ for (i = 0; i < 96; i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (*color_prom >> 6) & 0x01;
+ bit1 = (*color_prom >> 7) & 0x01;
+ b = 0x4f * bit0 + 0xa8 * bit1;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Screen flip/scroll registers
+ *
+ *************************************/
+
+WRITE8_HANDLER( suprridr_flipx_w )
+{
+ flipx = data & 1;
+ tilemap_set_flip(ALL_TILEMAPS, (flipx ? TILEMAP_FLIPX : 0) | (flipy ? TILEMAP_FLIPY : 0));
+}
+
+
+WRITE8_HANDLER( suprridr_flipy_w )
+{
+ flipy = data & 1;
+ tilemap_set_flip(ALL_TILEMAPS, (flipx ? TILEMAP_FLIPX : 0) | (flipy ? TILEMAP_FLIPY : 0));
+}
+
+
+WRITE8_HANDLER( suprridr_fgdisable_w )
+{
+ tilemap_set_enable(fg_tilemap, ~data & 1);
+}
+
+
+WRITE8_HANDLER( suprridr_fgscrolly_w )
+{
+ tilemap_set_scrolly(fg_tilemap, 0, data);
+}
+
+
+WRITE8_HANDLER( suprridr_bgscrolly_w )
+{
+ tilemap_set_scrolly(bg_tilemap, 0, data);
+}
+
+
+
+/*************************************
+ *
+ * Video RAM writes
+ *
+ *************************************/
+
+WRITE8_HANDLER( suprridr_bgram_w )
+{
+ suprridr_bgram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+ tilemap_mark_tile_dirty(bg_tilemap_noscroll, offset);
+}
+
+
+WRITE8_HANDLER( suprridr_fgram_w )
+{
+ suprridr_fgram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+
+
+/*************************************
+ *
+ * Video refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( suprridr )
+{
+ rectangle subclip;
+ int i;
+
+ /* render left 4 columns with no scroll */
+ subclip = machine->screen[0].visarea;
+ subclip.max_x = subclip.min_x + (flipx ? 1*8 : 4*8) - 1;
+ sect_rect(&subclip, cliprect);
+ tilemap_draw(bitmap, &subclip, bg_tilemap_noscroll, 0, 0);
+
+ /* render right 1 column with no scroll */
+ subclip = machine->screen[0].visarea;
+ subclip.min_x = subclip.max_x - (flipx ? 4*8 : 1*8) + 1;
+ sect_rect(&subclip, cliprect);
+ tilemap_draw(bitmap, &subclip, bg_tilemap_noscroll, 0, 0);
+
+ /* render the middle columns normally */
+ subclip = machine->screen[0].visarea;
+ subclip.min_x += flipx ? 1*8 : 4*8;
+ subclip.max_x -= flipx ? 4*8 : 1*8;
+ sect_rect(&subclip, cliprect);
+ tilemap_draw(bitmap, &subclip, bg_tilemap, 0, 0);
+
+ /* render the top layer */
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+
+ /* draw the sprites */
+ for (i = 0; i < 48; i++)
+ {
+ int code = (spriteram[i*4+1] & 0x3f) | ((spriteram[i*4+2] >> 1) & 0x40);
+ int color = spriteram[i*4+2] & 0x7f;
+ int fx = spriteram[i*4+1] & 0x40;
+ int fy = spriteram[i*4+1] & 0x80;
+ int x = spriteram[i*4+3];
+ int y = 240 - spriteram[i*4+0];
+
+ if (flipx)
+ {
+ fx = !fx;
+ x = 240 - x;
+ }
+ if (flipy)
+ {
+ fy = !fy;
+ y = 240 - y;
+ }
+ drawgfx(bitmap, machine->gfx[2], code, color, fx, fy, x, y, cliprect, TRANSPARENCY_PEN, 0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/suprslam.c b/src/mame/video/suprslam.c
new file mode 100644
index 00000000000..453e082ae5b
--- /dev/null
+++ b/src/mame/video/suprslam.c
@@ -0,0 +1,174 @@
+/* Super Slams - video, see notes in driver file */
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+UINT16 *suprslam_screen_videoram, *suprslam_bg_videoram,*suprslam_sp_videoram, *suprslam_spriteram;
+static UINT16 screen_bank, bg_bank;
+static tilemap *suprslam_screen_tilemap, *suprslam_bg_tilemap;
+
+/* todo, fix zooming correctly, its _not_ like aerofgt */
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ /* SPRITE INFO
+
+ Video System hardware, like aerofgt etc.
+
+ the sprites use 2 areas of ram, one containing a spritelist + sprite attributes, the other
+ contains the sprite tile #'s to use
+
+ sprite attribute info (4 words per sprite)
+
+ | ZZZZ hhhy yyyy yyyy | zzzz wwwx xxxx xxxx | -fpp pppp ---- ---- | -ooo oooo oooo oooo |
+
+ x = x position
+ y = y position
+ w = width
+ h = height
+ zZ = y zoom / x zoom
+ f = xflip
+ p = palette / colour
+ o = offset to tile data in other ram area
+
+ */
+
+
+ const gfx_element *gfx = machine->gfx[1];
+ UINT16 *source = suprslam_spriteram;
+ UINT16 *source2 = suprslam_spriteram;
+ UINT16 *finish = source + 0x2000/2;
+
+ while( source<finish )
+ {
+ UINT32 sprnum = source[0] & 0x03ff;
+ if (source[0] == 0x4000) break;
+
+ sprnum *= 4;
+
+ source++;
+ /* DRAW START */
+ {
+ int ypos = source2[sprnum+0] & 0x1ff;
+ int high = (source2[sprnum+0] & 0x0e00) >> 9;
+ int yzoom = (source2[sprnum+0] & 0xf000) >> 12;
+
+ int xpos = source2[sprnum+1] & 0x1ff;
+ int wide = (source2[sprnum+1] & 0x0e00) >> 9;
+ int xzoom = (source2[sprnum+1] & 0xf000) >> 12;
+
+ int col = (source2[sprnum+2] & 0x3f00) >> 8;
+ int flipx = (source2[sprnum+2] & 0x4000) >> 14;
+// int flipy = (source2[sprnum+2] & 0x8000) >> 15;
+
+ int word_offset = source2[sprnum+3] & 0x7fff;
+ int xcnt, ycnt;
+
+ int loopno = 0;
+
+ xzoom = 32 - xzoom;
+ yzoom = 32 - yzoom;
+
+ if (ypos > 0xff) ypos -=0x200;
+
+ for (ycnt = 0; ycnt < high+1; ycnt ++) {
+ if (!flipx) {
+ for (xcnt = 0; xcnt < wide+1; xcnt ++) {
+ int tileno = suprslam_sp_videoram[word_offset+loopno];
+ drawgfxzoom(bitmap, gfx, tileno, col, 0, 0,xpos + xcnt * xzoom/2, ypos + ycnt * yzoom/2, cliprect, TRANSPARENCY_PEN, 15,xzoom << 11, yzoom << 11);
+ drawgfxzoom(bitmap, gfx, tileno, col, 0, 0,-0x200+xpos + xcnt * xzoom/2, ypos + ycnt * yzoom/2, cliprect, TRANSPARENCY_PEN, 15,xzoom << 11, yzoom << 11);
+ loopno ++;
+ }
+ } else {
+ for (xcnt = wide; xcnt >= 0; xcnt --) {
+ int tileno = suprslam_sp_videoram[word_offset+loopno];
+ drawgfxzoom(bitmap, gfx, tileno, col, 1, 0,xpos + xcnt * xzoom/2, ypos + ycnt * yzoom/2, cliprect, TRANSPARENCY_PEN, 15,xzoom << 11, yzoom << 11);
+ drawgfxzoom(bitmap, gfx, tileno, col, 1, 0,-0x200+xpos + xcnt * xzoom/2, ypos + ycnt * yzoom/2, cliprect, TRANSPARENCY_PEN, 15,xzoom << 11, yzoom << 11);
+ loopno ++;
+ }
+ }
+ }
+ }
+ }
+}
+
+/* FG 'SCREEN' LAYER */
+
+WRITE16_HANDLER( suprslam_screen_videoram_w )
+{
+ suprslam_screen_videoram[offset] = data;
+ tilemap_mark_tile_dirty(suprslam_screen_tilemap,offset);
+}
+
+
+static TILE_GET_INFO( get_suprslam_tile_info )
+{
+ int tileno, colour;
+
+ tileno = suprslam_screen_videoram[tile_index] & 0x0fff;
+ colour = suprslam_screen_videoram[tile_index] & 0xf000;
+
+ tileno += screen_bank;
+ colour = colour >> 12;
+
+ SET_TILE_INFO(0,tileno,colour,0);
+}
+
+
+/* BG LAYER */
+WRITE16_HANDLER( suprslam_bg_videoram_w )
+{
+ suprslam_bg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(suprslam_bg_tilemap,offset);
+}
+
+
+static TILE_GET_INFO( get_suprslam_bg_tile_info )
+{
+ int tileno, colour;
+
+ tileno = suprslam_bg_videoram[tile_index] & 0x0fff;
+ colour = suprslam_bg_videoram[tile_index] & 0xf000;
+
+ tileno += bg_bank;
+ colour = colour >> 12;
+
+ SET_TILE_INFO(2,tileno,colour,0);
+}
+
+
+VIDEO_START( suprslam )
+{
+ suprslam_bg_tilemap = tilemap_create(get_suprslam_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,64,64);
+ suprslam_screen_tilemap = tilemap_create(get_suprslam_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+
+ K053936_wraparound_enable(0, 1);
+ K053936_set_offset(0, -45, -21);
+
+ tilemap_set_transparent_pen(suprslam_screen_tilemap,15);
+}
+
+VIDEO_UPDATE( suprslam )
+{
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ K053936_0_zoom_draw(bitmap,cliprect,suprslam_bg_tilemap,0,0);
+
+ draw_sprites(machine, bitmap, cliprect);
+
+ tilemap_draw(bitmap,cliprect,suprslam_screen_tilemap,0,0);
+ return 0;
+}
+
+WRITE16_HANDLER (suprslam_bank_w)
+{
+ UINT16 old_screen_bank, old_bg_bank;
+ old_screen_bank = screen_bank;
+ old_bg_bank = bg_bank;
+
+ screen_bank = data & 0xf000;
+ bg_bank = (data & 0x0f00) << 4;
+
+ if (screen_bank != old_screen_bank) tilemap_mark_all_tiles_dirty (suprslam_screen_tilemap);
+ if (bg_bank != old_bg_bank) tilemap_mark_all_tiles_dirty (suprslam_bg_tilemap);
+}
diff --git a/src/mame/video/surpratk.c b/src/mame/video/surpratk.c
new file mode 100644
index 00000000000..d625f659dc5
--- /dev/null
+++ b/src/mame/video/surpratk.c
@@ -0,0 +1,99 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+static int layer_colorbase[3],sprite_colorbase,bg_colorbase;
+static int layerpri[3];
+
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ *flags = (*color & 0x80) ? TILE_FLIPX : 0;
+ *code |= ((*color & 0x03) << 8) | ((*color & 0x10) << 6) | ((*color & 0x0c) << 9) | (bank << 13);
+ *color = layer_colorbase[layer] + ((*color & 0x60) >> 5);
+}
+
+/***************************************************************************
+
+ Callbacks for the K053245
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority_mask)
+{
+ int pri = 0x20 | ((*color & 0x60) >> 2);
+ if (pri <= layerpri[2]) *priority_mask = 0;
+ else if (pri > layerpri[2] && pri <= layerpri[1]) *priority_mask = 0xf0;
+ else if (pri > layerpri[1] && pri <= layerpri[0]) *priority_mask = 0xf0|0xcc;
+ else *priority_mask = 0xf0|0xcc|0xaa;
+
+ *color = sprite_colorbase + (*color & 0x1f);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( surpratk )
+{
+ K053251_vh_start();
+
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tile_callback);
+ K053245_vh_start(machine,0,REGION_GFX2,NORMAL_PLANE_ORDER,sprite_callback);
+}
+
+/* useful function to sort the three tile layers by priority order */
+static void sortlayers(int *layer,int *pri)
+{
+#define SWAP(a,b) \
+ if (pri[a] < pri[b]) \
+ { \
+ int t; \
+ t = pri[a]; pri[a] = pri[b]; pri[b] = t; \
+ t = layer[a]; layer[a] = layer[b]; layer[b] = t; \
+ }
+
+ SWAP(0,1)
+ SWAP(0,2)
+ SWAP(1,2)
+}
+
+VIDEO_UPDATE( surpratk )
+{
+ int layer[3];
+
+
+ bg_colorbase = K053251_get_palette_index(K053251_CI0);
+ sprite_colorbase = K053251_get_palette_index(K053251_CI1);
+ layer_colorbase[0] = K053251_get_palette_index(K053251_CI2);
+ layer_colorbase[1] = K053251_get_palette_index(K053251_CI4);
+ layer_colorbase[2] = K053251_get_palette_index(K053251_CI3);
+
+ K052109_tilemap_update();
+
+ layer[0] = 0;
+ layerpri[0] = K053251_get_priority(K053251_CI2);
+ layer[1] = 1;
+ layerpri[1] = K053251_get_priority(K053251_CI4);
+ layer[2] = 2;
+ layerpri[2] = K053251_get_priority(K053251_CI3);
+
+ sortlayers(layer,layerpri);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[16 * bg_colorbase],cliprect);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[0]],0,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[1]],0,2);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[2]],0,4);
+
+ K053245_sprites_draw(0,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/sys16spr.c b/src/mame/video/sys16spr.c
new file mode 100644
index 00000000000..fc9c640df4a
--- /dev/null
+++ b/src/mame/video/sys16spr.c
@@ -0,0 +1,188 @@
+/* sys16spr.c
+**
+** This module maps spriteram for various Sega System16/System18 games to
+** a shared abstraction represented by the sys16_sprite_attributes
+** structure.
+**
+** Each function takes a pointer to a sprite attribute structure to fill
+** out. This function is initialized to zero automatically prior to the
+** function call.
+**
+** The next parameter, source points to the spriteram
+** associated with a particular sprite.
+**
+** The final parameter bJustGetColor is set when this function is called while
+** marking colors. During this pass, only the palette field needs to be
+** populated.
+**
+** This function must return 1 if the sprite was flagged as the last sprite,
+** or 0 if the sprite was not flagged as the last sprite.
+**
+** We should probably unpack sprites into an array once, rather than processing
+** sprites one at a time, once when marking colors and once when rendering them.
+** Note that we need to draw sprites from front to back to achieve proper sprite-tilemap
+** orthogonality, so would make it easier to know how many sprites there are (and
+** thus which is the 'last sprite' with which we need to start.
+*/
+
+/*
+Changes:
+03/12/04 Charles MacDonald
+- Fixed end of list and sprite hide flag processing in sys16_sprite_shinobi, hwchamp output test works properly.
+- Fixed size of zoom fields, fixes sprite alignment issues in hwchamp
+*/
+
+#include "driver.h"
+#include "system16.h"
+
+int sys16_sprite_shinobi( struct sys16_sprite_attributes *sprite, const UINT16 *source, int bJustGetColor ){
+/* standard sprite hardware (Shinobi, Altered Beast, Golden Axe
+ 0 YYYYYYYY YYYYYYYY top, bottom (screen coordinates)
+ 1 -------X XXXXXXXX left (screen coordinate)
+ 2 EH------F WWWWWWWW end list flag, hide sprite flag, flipx, signed pitch
+ 3 TTTTTTTT TTTTTTTT word offset for start of sprite data; each word is 16 bits (4 pixels)
+ 4 ----BBBB PPCCCCCC attributes: bank, priority, color
+ 5 ------YY YYYXXXXX zoomy, zoomx
+ 6 -------- --------
+ 7 -------- --------
+*/
+ UINT16 ypos = source[0];
+ UINT16 width = source[2];
+ int top = ypos&0xff;
+ int bottom = ypos>>8;
+ if(width & 0x8000) return 1; // End of list bit set
+ if(width & 0x4000) return 0; // Hide this sprite bit set
+ if(top >= bottom || top >= 0xe0) return 0; // Invalid height or off-screen
+ if(bottom >= 0xe0) bottom = 0xe0; // Clip bottom of sprite
+
+ {
+ UINT16 attributes = source[4];
+
+ UINT16 zoomx = source[5] & 0x1F;
+ UINT16 zoomy = (source[5] >> 5) & 0x1F;
+
+ // Rest of rendering code expects zoom to be 10 bits
+ zoomx <<= 5;
+ zoomy <<= 5;
+
+ // Having zoomy set to zoomx when zoomy is zero heavily distorts the multi-sprite opponents in hwchamp
+ //if( zoomy==0 || source[6]==0xffff ) zoomy = zoomx; /* if zoomy is 0, use zoomx instead */
+
+ sprite->x = source[1] + sys16_sprxoffset;
+ sprite->y = top;
+ sprite->priority = (attributes>>6)&0x3;
+ sprite->color = 1024/16 + (attributes&0x3f);
+ sprite->screen_height = bottom-top;
+ sprite->flags = SYS16_SPR_VISIBLE;
+ if( width&0x100 ) sprite->flags |= SYS16_SPR_FLIPX;
+ if ((attributes&0x3f)==0x3f) sprite->flags|= SYS16_SPR_SHADOW;
+ sprite->zoomx = zoomx;
+ sprite->zoomy = zoomy;
+ sprite->pitch = source[2]&0xff;
+ sprite->gfx = ( source[3] + (sys16_obj_bank[(attributes>>8)&0xf]<<16) ) << 1; //*
+ }
+ return 0;
+}
+
+int sys16_sprite_passshot( struct sys16_sprite_attributes *sprite, const UINT16 *source, int bJustGetColor ){
+/* Passing shot 4p needs: passshot_y=-0x23; passshot_width=1;
+ 0 -------X XXXXXXXX left (screen coordinate)
+ 1 YYYYYYYY YYYYYYYY bottom, top (screen coordinates)
+ 2 XTTTTTTT TTTTTTTT (pen data, flipx, flipy)
+ 3 -------- FWWWWWWW pitch: flipy, logical width
+ 4 ------ZZ ZZZZZZZZ zoom
+ 5 PPCCCCCC BBBB---- attributes: priority, color, bank
+ 6 -------- --------
+ 7 -------- --------
+*/
+ int passshot_y=0;
+ int passshot_width=0;
+ UINT16 attributes = source[5];
+ UINT16 ypos = source[1];
+ int bottom = (ypos>>8)+passshot_y;
+ int top = (ypos&0xff)+passshot_y;
+ if( bottom>top && ypos!=0xffff ){
+ int bank = (attributes>>4)&0xf;
+ UINT16 number = source[2];
+ UINT16 width = source[3];
+ int zoom = source[4]&0x3ff;
+ int xpos = source[0] + sys16_sprxoffset;
+ sprite->screen_height = bottom - top;
+ sprite->priority = attributes>>14;
+ sprite->color = 1024/16+ ((attributes>>8)&0x3f);
+ /* hack */
+ if( passshot_width) { /* 4 player bootleg version */
+ width = -width;
+ number -= width*(bottom-top-1)-1;
+ }
+ sprite->flags = SYS16_SPR_VISIBLE;
+ if( number & 0x8000 ) sprite->flags |= SYS16_SPR_FLIPX;
+ if (((attributes>>8)&0x3f)==0x3f) // shadow sprite
+ sprite->flags|= SYS16_SPR_SHADOW;
+ sprite->pitch = width&0xff;
+ if( sprite->flags&SYS16_SPR_FLIPX ){
+ bank = (bank-1) & 0xf; /* ? */
+ }
+ sprite->gfx = ((number-(short)width)*4 + (sys16_obj_bank[bank] << 17))/2; //*
+ sprite->x = xpos;
+ sprite->y = top+2; //*
+ sprite->zoomx = sprite->zoomy = zoom;
+ }
+ return 0;
+}
+
+
+int sys16_sprite_quartet2( struct sys16_sprite_attributes *sprite, const UINT16 *source, int bJustGetColor ){
+/* Quartet2, Alexkidd, Bodyslam, mjleague, shinobibl
+ 0 YYYYYYYY YYYYYYYY bottom, top
+ 1 -------X XXXXXXXX xpos
+ 2 -------- WWWWWWWW pitch
+ 3 FTTTTTTT TTTTTTTT flipx, gfx
+ 4 --CCCCCC BBBBPPPP color, bank, priority
+ 5 -------- --------
+ 6 -------- --------
+ 7 -------- --------
+*/
+ UINT16 ypos = source[0];
+ int top = ypos&0xff;
+ int bottom = ypos>>8;
+ if( bottom == 0xff ) return 1;
+ if(bottom !=0 && bottom > top){
+ UINT16 spr_pri=(source[4])&0xf; /* ?? */
+ UINT16 bank=(source[4]>>4) &0xf;
+ UINT16 pal=(source[4]>>8)&0x3f;
+ UINT16 tsource[4];
+ UINT16 width;
+ int gfx;
+
+ if (spr_pri) { /* MASH - ?? */
+ tsource[2]=source[2];
+ tsource[3]=source[3];
+ if((tsource[3] & 0x7f80) == 0x7f80){
+ bank=(bank-1)&0xf;
+ tsource[3]^=0x8000;
+ }
+ tsource[2] &= 0x00ff;
+ if (tsource[3]&0x8000){ // reverse
+ tsource[2] |= 0x0100;
+ tsource[3] &= 0x7fff;
+ }
+ gfx = tsource[3]*4;
+ width = tsource[2];
+ //top++;
+ //bottom++;
+ sprite->x = source[1] + sys16_sprxoffset;
+ if(sprite->x > 0x140) sprite->x-=0x200;
+ sprite->y = top;
+ sprite->priority = spr_pri;
+ sprite->color = 1024/16 + pal;
+ sprite->screen_height = bottom-top;
+ sprite->pitch = width&0xff;
+ sprite->flags = SYS16_SPR_VISIBLE;
+ if( width&0x100 ) sprite->flags |= SYS16_SPR_FLIPX;
+ if( pal==0x3f ) sprite->flags|= SYS16_SPR_SHADOW; // shadow sprite
+ sprite->gfx = ((gfx &0x3ffff) + (sys16_obj_bank[bank] << 17))/2;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/system1.c b/src/mame/video/system1.c
new file mode 100644
index 00000000000..6618071ae64
--- /dev/null
+++ b/src/mame/video/system1.c
@@ -0,0 +1,904 @@
+/*************************************************************************
+
+ System1 / System 2. By Jarek Parchanski & Mirko Buffoni.
+
+ Many thanks to Roberto Ventura, for precious information about
+ System 1 hardware.
+
+*************************************************************************/
+
+#include "driver.h"
+#include "system1.h"
+
+UINT8 *system1_scroll_y;
+UINT8 *system1_scroll_x;
+UINT8 *system1_videoram;
+UINT8 *system1_backgroundram;
+UINT8 *system1_sprites_collisionram;
+UINT8 *system1_background_collisionram;
+UINT8 *system1_scrollx_ram;
+size_t system1_videoram_size;
+size_t system1_backgroundram_size;
+
+static UINT8 *sprite_onscreen_map;
+static int background_scrollx=0,background_scrolly=0;
+static UINT8 *bg_dirtybuffer;
+
+static int scrollx_row[32];
+static mame_bitmap *tmp_bitmap;
+
+//static int system1_pixel_mode = 0
+static UINT8 system1_background_memory,system1_video_mode=0;
+
+static const UINT8 *system1_color_prom;
+
+static UINT8 *wbml_paged_videoram;
+static UINT8 wbml_videoram_bank=0,wbml_videoram_bank_latch=0;
+
+static int blockgal_kludgeoffset;
+static int system1_sprite_xoffset = 0;
+
+/***************************************************************************
+
+ There are two kind of color handling: in the System 1 games, values in the
+ palette RAM are directly mapped to colors with the usual BBGGGRRR format;
+ in the System 2 ones (Choplifter, WBML, etc.), the value in the palette RAM
+ is a lookup offset for three palette PROMs in RRRRGGGGBBBB format.
+
+ It's hard to tell for sure because they use resistor packs, but here's
+ what I think the values are from measurment with a volt meter:
+
+ Blue: .250K ohms
+ Blue: .495K ohms
+ Green:.250K ohms
+ Green:.495K ohms
+ Green:.995K ohms
+ Red: .495K ohms
+ Red: .250K ohms
+ Red: .995K ohms
+
+ accurate to +/- .003K ohms.
+
+***************************************************************************/
+PALETTE_INIT( system1 )
+{
+ system1_color_prom = color_prom;
+}
+
+WRITE8_HANDLER( system1_paletteram_w )
+{
+ int val,r,g,b;
+
+
+ paletteram[offset] = data;
+
+ if (system1_color_prom)
+ {
+ int bit0,bit1,bit2,bit3;
+
+ val = system1_color_prom[data+0*256];
+ bit0 = (val >> 0) & 0x01;
+ bit1 = (val >> 1) & 0x01;
+ bit2 = (val >> 2) & 0x01;
+ bit3 = (val >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ val = system1_color_prom[data+1*256];
+ bit0 = (val >> 0) & 0x01;
+ bit1 = (val >> 1) & 0x01;
+ bit2 = (val >> 2) & 0x01;
+ bit3 = (val >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ val = system1_color_prom[data+2*256];
+ bit0 = (val >> 0) & 0x01;
+ bit1 = (val >> 1) & 0x01;
+ bit2 = (val >> 2) & 0x01;
+ bit3 = (val >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ }
+ else
+ {
+ r = pal3bit(data >> 0);
+ g = pal3bit(data >> 3);
+ b = pal2bit(data >> 6);
+ }
+
+ palette_set_color(Machine,offset,MAKE_RGB(r,g,b));
+}
+
+static void system1_postload(void)
+{
+ memset(sprite_onscreen_map, 255, 256*256);
+ memset(bg_dirtybuffer, 1, 1024);
+}
+
+VIDEO_START( system1 )
+{
+ sprite_onscreen_map = auto_malloc(256*256);
+ memset(sprite_onscreen_map,255,256*256);
+
+ bg_dirtybuffer = auto_malloc(1024);
+ memset(bg_dirtybuffer,1,1024);
+
+ tmp_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ state_save_register_func_postload(system1_postload);
+ state_save_register_global(system1_background_memory);
+ state_save_register_global(system1_video_mode);
+
+ system1_sprite_xoffset = 1;
+}
+
+VIDEO_START( wbml )
+{
+ sprite_onscreen_map = auto_malloc(256*256);
+ memset(sprite_onscreen_map,255,256*256);
+
+ bg_dirtybuffer = auto_malloc(1024);
+ memset(bg_dirtybuffer,1,1024);
+ wbml_paged_videoram = auto_malloc(0x4000); /* Allocate 16k for background banked ram */
+ memset(wbml_paged_videoram,0,0x4000);
+
+ tmp_bitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ system1_sprite_xoffset = 1+7*2;
+
+ state_save_register_func_postload(system1_postload);
+ state_save_register_global(system1_background_memory);
+ state_save_register_global(system1_video_mode);
+
+ state_save_register_global_pointer(wbml_paged_videoram, 0x4000);
+ state_save_register_global(wbml_videoram_bank);
+ state_save_register_global(wbml_videoram_bank_latch);
+}
+
+WRITE8_HANDLER( system1_videomode_w )
+{
+if (data & 0x6e) logerror("videomode = %02x\n",data);
+
+ /* bit 0 is coin counter */
+ coin_counter_w(0, data & 1);
+
+ /* bit 4 is screen blank */
+ system1_video_mode = data;
+
+ /* bit 7 is flip screen */
+ flip_screen_set(data & 0x80);
+}
+
+READ8_HANDLER( system1_videomode_r )
+{
+ return system1_video_mode;
+}
+
+void system1_define_background_memory(int mode)
+{
+ system1_background_memory = mode;
+}
+
+
+INLINE int get_sprite_bottom_y(int spr_number)
+{
+ return spriteram[0x10 * spr_number + SPR_Y_BOTTOM];
+}
+
+INLINE void draw_pixel(mame_bitmap *bitmap,
+ int x,int y,int x_flipped,int y_flipped,
+ int spr_number,int color)
+{
+ int xr,yr;
+ int sprite_onscreen;
+
+
+ if (x < 0 || x >= Machine->screen[0].width ||
+ y < 0 || y >= Machine->screen[0].height)
+ return;
+
+ if (sprite_onscreen_map[256*y+x] != 255)
+ {
+ sprite_onscreen = sprite_onscreen_map[256*y+x];
+ system1_sprites_collisionram[sprite_onscreen + 32 * spr_number] = 0xff;
+ }
+
+ sprite_onscreen_map[256*y+x] = spr_number;
+
+ if (x_flipped >= Machine->screen[0].visarea.min_x ||
+ x_flipped <= Machine->screen[0].visarea.max_x ||
+ y_flipped >= Machine->screen[0].visarea.min_y ||
+ y_flipped <= Machine->screen[0].visarea.max_y)
+ {
+ *BITMAP_ADDR16(bitmap, y_flipped, x_flipped) = color;
+ }
+
+ xr = ((x - background_scrollx) & 0xff) / 8;
+ yr = ((y - background_scrolly) & 0xff) / 8;
+
+ /* TODO: bits 5 and 6 of backgroundram are also used (e.g. Pitfall2, Mr. Viking) */
+ /* what's the difference? Bit 7 is used in Choplifter/WBML for extra char bank */
+ /* selection, but it is also set in Pitfall2 */
+
+ if (system1_background_memory == system1_BACKGROUND_MEMORY_SINGLE)
+ {
+ if (system1_backgroundram[2 * (32 * yr + xr) + 1] & 0x10)
+ system1_background_collisionram[0x20 + spr_number] = 0xff;
+ }
+ else
+ {
+ /* TODO: I should handle the paged background memory here. */
+ /* maybe collision detection is not used by the paged games */
+ /* (wbml and tokisens), though tokisens doesn't play very well */
+ /* (you can't seem to fit in gaps where you should fit) */
+ }
+
+ /* TODO: collision should probably be checked with the foreground as well */
+ /* (TeddyBoy Blues, head of the tiger in girl bonus round) */
+}
+
+WRITE8_HANDLER( system1_background_collisionram_w )
+{
+ /* to do the RAM check, Mister Viking writes 0xff and immediately */
+ /* reads it back, expecting bit 0 to be NOT set. */
+ system1_background_collisionram[offset] = 0x7e;
+}
+
+WRITE8_HANDLER( system1_sprites_collisionram_w )
+{
+ /* to do the RAM check, Mister Viking write 0xff and immediately */
+ /* reads it back, expecting bit 0 to be NOT set. */
+ /* Up'n Down expects to find 0x7e at f800 before doing the whole */
+ /* collision test */
+ system1_sprites_collisionram[offset] = 0x7e;
+}
+
+static void draw_sprite(mame_bitmap *bitmap,int spr_number)
+{
+ int sy,row,height,src,bank;
+ UINT8 *sprite_base;
+ const pen_t *sprite_palette;
+ INT16 skip; /* bytes to skip before drawing each row (can be negative) */
+ UINT8 *gfx;
+
+
+ sprite_base = spriteram + 0x10 * spr_number;
+
+ src = sprite_base[SPR_GFXOFS_LO] + (sprite_base[SPR_GFXOFS_HI] << 8);
+ bank = 0x8000 * (((sprite_base[SPR_X_HI] & 0x80) >> 7) + ((sprite_base[SPR_X_HI] & 0x40) >> 5));
+ bank &= (memory_region_length(REGION_GFX2)-1); /* limit to the range of available ROMs */
+ skip = sprite_base[SPR_SKIP_LO] + (sprite_base[SPR_SKIP_HI] << 8);
+
+ height = sprite_base[SPR_Y_BOTTOM] - sprite_base[SPR_Y_TOP];
+ sprite_palette = Machine->remapped_colortable + 0x10 * spr_number;
+
+ sy = sprite_base[SPR_Y_TOP] + 1;
+
+ /* graphics region #2 contains the packed sprite data */
+ gfx = &memory_region(REGION_GFX2)[bank];
+
+ for (row = 0;row < height;row++)
+ {
+ int x,x_flipped;
+ int y,y_flipped;
+ int src2;
+
+ src = src2 = src + skip;
+
+ x = sprite_base[SPR_X_LO] + ((sprite_base[SPR_X_HI] & 0x01) << 8) + system1_sprite_xoffset;
+ x_flipped = x;
+ y = y_flipped = sy+row;
+
+ if (flip_screen)
+ {
+ y_flipped = 258 - sy - height + row;
+ x_flipped = (252*2) - x;
+ }
+
+ x /= 2; /* the hardware has sub-pixel placement, it seems */
+ x_flipped /= 2;
+
+ while (1)
+ {
+ int color1,color2,data;
+
+ data = gfx[src2 & 0x7fff];
+
+ if (src & 0x8000)
+ {
+ src2--;
+
+ color1 = data & 0x0f;
+ color2 = data >> 4;
+ }
+ else
+ {
+ src2++;
+
+ color1 = data >> 4;
+ color2 = data & 0x0f;
+ }
+
+ if (color1 == 15) break;
+ if (color1)
+ draw_pixel(bitmap,x,y,x_flipped,y_flipped,spr_number,sprite_palette[color1]);
+ x++;
+ x_flipped += flip_screen ? -1 : 1;
+
+ if (color2 == 15) break;
+ if (color2)
+ draw_pixel(bitmap,x,y,x_flipped,y_flipped,spr_number,sprite_palette[color2]);
+ x++;
+ x_flipped += flip_screen ? -1 : 1;
+ }
+ }
+}
+
+
+static void draw_sprites(mame_bitmap *bitmap)
+{
+ int spr_number,sprite_bottom_y,sprite_top_y;
+ UINT8 *sprite_base;
+
+
+ memset(sprite_onscreen_map,255,256*256);
+
+ for (spr_number = 0;spr_number < 32;spr_number++)
+ {
+ sprite_base = spriteram + 0x10 * spr_number;
+ sprite_top_y = sprite_base[SPR_Y_TOP];
+ sprite_bottom_y = sprite_base[SPR_Y_BOTTOM];
+ if (sprite_bottom_y && (sprite_bottom_y-sprite_top_y > 0))
+ draw_sprite(bitmap,spr_number);
+ }
+}
+
+
+
+WRITE8_HANDLER( system1_backgroundram_w )
+{
+ system1_backgroundram[offset] = data;
+ bg_dirtybuffer[offset>>1] = 1;
+}
+
+
+static int system1_draw_fg(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int sx,sy,offs;
+ int drawn = 0;
+
+
+ priority <<= 3;
+
+ for (offs = 0;offs < system1_videoram_size;offs += 2)
+ {
+ if ((system1_videoram[offs+1] & 0x08) == priority)
+ {
+ int code,color;
+
+
+ code = (system1_videoram[offs] | (system1_videoram[offs+1] << 8));
+ code = ((code >> 4) & 0x800) | (code & 0x7ff); /* Heavy Metal only */
+ color = ((code >> 5) & 0x3f);
+ sx = (offs/2) % 32;
+ sy = (offs/2) / 32;
+
+ if (flip_screen)
+ {
+ sx = 31 - sx;
+ sy = 31 - sy;
+ }
+
+ code %= machine->gfx[0]->total_elements;
+ if (machine->gfx[0]->pen_usage[code] & ~1)
+ {
+ drawn = 1;
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flip_screen,flip_screen,
+ 8*sx + blockgal_kludgeoffset,8*sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+
+ return drawn;
+}
+
+static void system1_draw_bg(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int sx,sy,offs;
+ int background_scrollx_flip, background_scrolly_flip;
+
+
+ background_scrollx = ((system1_scroll_x[0] >> 1) + ((system1_scroll_x[1] & 1) << 7) + 14 + 2*blockgal_kludgeoffset) & 0xff;
+ background_scrolly = (-*system1_scroll_y) & 0xff;
+
+ background_scrollx_flip = (275 - background_scrollx) & 0xff;
+ background_scrolly_flip = (256 - background_scrolly) & 0xff;
+
+ if (priority == -1)
+ {
+ /* optimized far background */
+
+ /* for every character in the background video RAM, check if it has
+ * been modified since last time and update it accordingly.
+ */
+
+ for (offs = 0;offs < system1_backgroundram_size;offs += 2)
+ {
+ if (bg_dirtybuffer[offs / 2])
+ {
+ int code,color;
+
+
+ bg_dirtybuffer[offs / 2] = 0;
+
+ code = (system1_backgroundram[offs] | (system1_backgroundram[offs+1] << 8));
+ code = ((code >> 4) & 0x800) | (code & 0x7ff); /* Heavy Metal only */
+ color = ((code >> 5) & 0x3f) + 0x40;
+ sx = (offs/2) % 32;
+ sy = (offs/2) / 32;
+
+ if (flip_screen)
+ {
+ sx = 31 - sx;
+ sy = 31 - sy;
+ }
+
+ drawgfx(tmp_bitmap,machine->gfx[0],
+ code,
+ color,
+ flip_screen,flip_screen,
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ /* copy the temporary bitmap to the screen */
+ if (flip_screen)
+ copyscrollbitmap(bitmap,tmp_bitmap,1,&background_scrollx_flip,1,&background_scrolly_flip,cliprect,TRANSPARENCY_NONE,0);
+ else
+ copyscrollbitmap(bitmap,tmp_bitmap,1,&background_scrollx,1,&background_scrolly,cliprect,TRANSPARENCY_NONE,0);
+ }
+ else
+ {
+ priority <<= 3;
+
+ for (offs = 0;offs < system1_backgroundram_size;offs += 2)
+ {
+ if ((system1_backgroundram[offs+1] & 0x08) == priority)
+ {
+ int code,color;
+
+
+ code = (system1_backgroundram[offs] | (system1_backgroundram[offs+1] << 8));
+ code = ((code >> 4) & 0x800) | (code & 0x7ff); /* Heavy Metal only */
+ color = ((code >> 5) & 0x3f) + 0x40;
+ sx = (offs/2) % 32;
+ sy = (offs/2) / 32;
+
+ if (flip_screen)
+ {
+ sx = 8*(31-sx) + background_scrollx_flip;
+ sy = 8*(31-sy) + background_scrolly_flip;
+ }
+ else
+ {
+ sx = 8*sx + background_scrollx;
+ sy = 8*sy + background_scrolly;
+ }
+
+ /* draw it 4 times because of possible wrap around */
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flip_screen,flip_screen,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flip_screen,flip_screen,
+ sx-256,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flip_screen,flip_screen,
+ sx,sy-256,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flip_screen,flip_screen,
+ sx-256,sy-256,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( system1 )
+{
+ int drawn;
+
+
+ system1_draw_bg(machine, bitmap, cliprect, -1);
+ drawn = system1_draw_fg(machine, bitmap, cliprect, 0);
+ /* redraw low priority bg tiles if necessary */
+ if (drawn) system1_draw_bg(machine, bitmap, cliprect, 0);
+ draw_sprites(bitmap);
+ system1_draw_bg(machine, bitmap, cliprect, 1);
+ system1_draw_fg(machine, bitmap, cliprect, 1);
+
+ /* even if screen is off, sprites must still be drawn to update the collision table */
+ if (system1_video_mode & 0x10) /* screen off */
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+WRITE8_HANDLER( choplifter_scroll_x_w )
+{
+ system1_scrollx_ram[offset] = data;
+
+ scrollx_row[offset/2] = (system1_scrollx_ram[offset & ~1] >> 1) + ((system1_scrollx_ram[offset | 1] & 1) << 7);
+}
+
+static void chplft_draw_bg(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ int sx,sy,offs;
+ int choplifter_scroll_x_on = (system1_scrollx_ram[0] == 0xe5 && system1_scrollx_ram[1] == 0xff) ? 0 : 1;
+
+
+ if (priority == -1)
+ {
+ /* optimized far background */
+
+ /* for every character in the background video RAM, check if it has
+ * been modified since last time and update it accordingly.
+ */
+
+ for (offs = 0;offs < system1_backgroundram_size;offs += 2)
+ {
+ if (bg_dirtybuffer[offs / 2])
+ {
+ int code,color;
+
+
+ bg_dirtybuffer[offs / 2] = 0;
+
+ code = (system1_backgroundram[offs] | (system1_backgroundram[offs+1] << 8));
+ code = ((code >> 4) & 0x800) | (code & 0x7ff); /* Heavy Metal only */
+ color = ((code >> 5) & 0x3f) + 0x40;
+ sx = (offs/2) % 32;
+ sy = (offs/2) / 32;
+
+ if (flip_screen)
+ {
+ sx = 31 - sx;
+ sy = 31 - sy;
+ }
+
+ drawgfx(tmp_bitmap,machine->gfx[0],
+ code,
+ color,
+ flip_screen,flip_screen,
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ /* copy the temporary bitmap to the screen */
+ if (choplifter_scroll_x_on)
+ {
+ if (flip_screen)
+ {
+ int scrollx_row_flip[32],i;
+
+ for (i = 0; i < 32; i++)
+ scrollx_row_flip[31-i] = (256-scrollx_row[i]) & 0xff;
+
+ copyscrollbitmap(bitmap,tmp_bitmap,32,scrollx_row_flip,0,0,cliprect,TRANSPARENCY_NONE,0);
+ }
+ else
+ copyscrollbitmap(bitmap,tmp_bitmap,32,scrollx_row,0,0,cliprect,TRANSPARENCY_NONE,0);
+ }
+ else
+ copybitmap(bitmap,tmp_bitmap,0,0,0,0,cliprect,TRANSPARENCY_NONE,0);
+ }
+ else
+ {
+ priority <<= 3;
+
+ for (offs = 0;offs < system1_backgroundram_size;offs += 2)
+ {
+ if ((system1_backgroundram[offs+1] & 0x08) == priority)
+ {
+ int code,color;
+
+
+ code = (system1_backgroundram[offs] | (system1_backgroundram[offs+1] << 8));
+ code = ((code >> 4) & 0x800) | (code & 0x7ff); /* Heavy Metal only */
+ color = ((code >> 5) & 0x3f) + 0x40;
+ sx = (offs/2) % 32;
+ sy = (offs/2) / 32;
+
+ if (flip_screen)
+ {
+ sx = 8*(31-sx);
+
+ if (choplifter_scroll_x_on)
+ sx = (sx - scrollx_row[sy]) & 0xff;
+
+ sy = 31 - sy;
+ }
+ else
+ {
+ sx = 8*sx;
+
+ if (choplifter_scroll_x_on)
+ sx = (sx + scrollx_row[sy]) & 0xff;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flip_screen,flip_screen,
+ sx,8*sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( choplifter )
+{
+ int drawn;
+
+
+ chplft_draw_bg(machine, bitmap, cliprect, -1);
+ drawn = system1_draw_fg(machine, bitmap, cliprect, 0);
+ /* redraw low priority bg tiles if necessary */
+ if (drawn) chplft_draw_bg(machine, bitmap, cliprect, 0);
+ draw_sprites(bitmap);
+ chplft_draw_bg(machine, bitmap, cliprect, 1);
+ system1_draw_fg(machine, bitmap, cliprect, 1);
+
+ /* even if screen is off, sprites must still be drawn to update the collision table */
+ if (system1_video_mode & 0x10) /* screen off */
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+
+#ifdef MAME_DEBUG
+ if (input_code_pressed(KEYCODE_SPACE)) // goto next level
+ {
+ memory_region(REGION_CPU1)[0xC085]=33;
+ }
+#endif
+ return 0;
+}
+
+
+
+READ8_HANDLER( wbml_videoram_bank_latch_r )
+{
+ return wbml_videoram_bank_latch;
+}
+
+WRITE8_HANDLER( wbml_videoram_bank_latch_w )
+{
+ wbml_videoram_bank_latch = data;
+ wbml_videoram_bank = (data >> 1) & 0x03; /* Select 4 banks of 4k, bit 2,1 */
+}
+
+READ8_HANDLER( wbml_paged_videoram_r )
+{
+ return wbml_paged_videoram[0x1000*wbml_videoram_bank + offset];
+}
+
+WRITE8_HANDLER( wbml_paged_videoram_w )
+{
+ wbml_paged_videoram[0x1000*wbml_videoram_bank + offset] = data;
+}
+
+static void wbml_draw_bg(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int trasp)
+{
+ int page;
+
+ int xscroll = (wbml_paged_videoram[0x7c0] >> 1) + ((wbml_paged_videoram[0x7c1] & 1) << 7) - 256 + 5;
+ int yscroll = -wbml_paged_videoram[0x7ba];
+
+ for (page=0; page < 4; page++)
+ {
+ const UINT8 *source = wbml_paged_videoram + (wbml_paged_videoram[0x0740 + page*2] & 0x07)*0x800;
+ int startx = (page&1)*256+xscroll;
+ int starty = (page>>1)*256+yscroll;
+ int row,col;
+
+
+ for( row=0; row<32*8; row+=8 )
+ {
+ for( col=0; col<32*8; col+=8 )
+ {
+ int code,priority;
+ int x = (startx+col) & 0x1ff;
+ int y = (starty+row) & 0x1ff;
+ if (x > 256) x -= 512;
+ if (y > 224) y -= 512;
+
+ if (flip_screen)
+ {
+ x = 248 - x;
+ y = 248 - y;
+ }
+
+ code = source[0] + (source[1] << 8);
+ priority = code & 0x800;
+ code = ((code >> 4) & 0x800) | (code & 0x7ff);
+
+ if (!trasp)
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ ((code >> 5) & 0x3f) + 64,
+ flip_screen,flip_screen,
+ x,y,
+ cliprect, TRANSPARENCY_NONE, 0);
+ else if (priority)
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ ((code >> 5) & 0x3f) + 64,
+ flip_screen,flip_screen,
+ x,y,
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ source+=2;
+ }
+ }
+ } /* next page */
+}
+
+static void wbml_draw_fg(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+
+ for (offs = 0;offs < 0x700;offs += 2)
+ {
+ int sx,sy,code;
+
+
+ sx = (offs/2) % 32;
+ sy = (offs/2) / 32;
+ code = wbml_paged_videoram[offs] | (wbml_paged_videoram[offs+1] << 8);
+ code = ((code >> 4) & 0x800) | (code & 0x7ff);
+
+ if (flip_screen)
+ {
+ sx = 31 - sx;
+ sy = 31 - sy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ (code >> 5) & 0x3f,
+ flip_screen,flip_screen,
+ 8*sx,8*sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+VIDEO_UPDATE( wbml )
+{
+ wbml_draw_bg(machine, bitmap, cliprect, 0);
+ draw_sprites(bitmap);
+ wbml_draw_bg(machine, bitmap, cliprect, 1);
+ wbml_draw_fg(machine, bitmap, cliprect);
+
+ /* even if screen is off, sprites must still be drawn to update the collision table */
+ if (system1_video_mode & 0x10) /* screen off */
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ return 0;
+}
+
+/* same as wbml but with rows scroll */
+static void ufosensi_draw_bg(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int trasp)
+{
+ int page;
+
+ int yscroll = -wbml_paged_videoram[0x7ba];
+
+ for (page=0; page < 4; page++)
+ {
+ const UINT8 *source = wbml_paged_videoram + (wbml_paged_videoram[0x0740 + page*2] & 0x07)*0x800;
+ int starty = (page>>1)*256+yscroll;
+ int row,col;
+
+
+ for( row=0; row<32*8; row+=8 )
+ {
+ for( col=0; col<32*8; col+=8 )
+ {
+ int code,priority;
+ int xscroll = (wbml_paged_videoram[0x7c0 + row/4] >> 1) + ((wbml_paged_videoram[0x7c1 + row/4] & 1) << 7) - 256 + 5;
+ int startx = (page&1)*256+xscroll;
+ int x = (startx+col) & 0x1ff;
+ int y = (starty+row) & 0x1ff;
+ if (x > 256) x -= 512;
+ if (y > 224) y -= 512;
+
+ if (flip_screen)
+ {
+ x = 248 - x;
+ y = 248 - y;
+ }
+
+ code = source[0] + (source[1] << 8);
+ priority = code & 0x800;
+ code = ((code >> 4) & 0x800) | (code & 0x7ff);
+
+ if (!trasp)
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ ((code >> 5) & 0x3f) + 64,
+ flip_screen,flip_screen,
+ x,y,
+ cliprect, TRANSPARENCY_NONE, 0);
+ else if (priority)
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ ((code >> 5) & 0x3f) + 64,
+ flip_screen,flip_screen,
+ x,y,
+ cliprect, TRANSPARENCY_PEN, 0);
+
+ source+=2;
+ }
+ }
+ } /* next page */
+}
+
+VIDEO_UPDATE( ufosensi )
+{
+ ufosensi_draw_bg(machine, bitmap, cliprect, 0);
+ draw_sprites(bitmap);
+ ufosensi_draw_bg(machine, bitmap, cliprect, 1);
+ wbml_draw_fg(machine, bitmap, cliprect);
+
+ /* even if screen is off, sprites must still be drawn to update the collision table */
+ if (system1_video_mode & 0x10) /* screen off */
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( blockgal )
+{
+ int drawn;
+
+
+ blockgal_kludgeoffset = -8;
+
+ system1_draw_bg(machine, bitmap, cliprect, -1);
+ drawn = system1_draw_fg(machine, bitmap, cliprect, 0);
+ /* redraw low priority bg tiles if necessary */
+ if (drawn) system1_draw_bg(machine, bitmap, cliprect, 0);
+ draw_sprites(bitmap);
+ system1_draw_bg(machine, bitmap, cliprect, 1);
+ system1_draw_fg(machine, bitmap, cliprect, 1);
+
+ /* even if screen is off, sprites must still be drawn to update the collision table */
+ if (system1_video_mode & 0x10) /* screen off */
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ blockgal_kludgeoffset = 0;
+ return 0;
+}
diff --git a/src/mame/video/system1.h b/src/mame/video/system1.h
new file mode 100644
index 00000000000..47b64aba067
--- /dev/null
+++ b/src/mame/video/system1.h
@@ -0,0 +1,50 @@
+#ifndef _system1_H_
+#define _system1_H_
+
+#define SPR_Y_TOP 0
+#define SPR_Y_BOTTOM 1
+#define SPR_X_LO 2
+#define SPR_X_HI 3
+#define SPR_SKIP_LO 4
+#define SPR_SKIP_HI 5
+#define SPR_GFXOFS_LO 6
+#define SPR_GFXOFS_HI 7
+
+#define system1_BACKGROUND_MEMORY_SINGLE 0
+#define system1_BACKGROUND_MEMORY_BANKED 1
+
+extern UINT8 *system1_scroll_y;
+extern UINT8 *system1_scroll_x;
+extern UINT8 *system1_videoram;
+extern UINT8 *system1_backgroundram;
+extern UINT8 *system1_sprites_collisionram;
+extern UINT8 *system1_background_collisionram;
+extern UINT8 *system1_scrollx_ram;
+extern size_t system1_videoram_size;
+extern size_t system1_backgroundram_size;
+
+
+VIDEO_START( system1 );
+VIDEO_START( wbml );
+void system1_define_background_memory(int Mode);
+
+READ8_HANDLER( wbml_videoram_bank_latch_r );
+WRITE8_HANDLER( wbml_videoram_bank_latch_w );
+READ8_HANDLER( wbml_paged_videoram_r );
+WRITE8_HANDLER( wbml_paged_videoram_w );
+WRITE8_HANDLER( system1_background_collisionram_w );
+WRITE8_HANDLER( system1_sprites_collisionram_w );
+WRITE8_HANDLER( system1_paletteram_w );
+WRITE8_HANDLER( system1_backgroundram_w );
+VIDEO_UPDATE( system1 );
+PALETTE_INIT( system1 );
+WRITE8_HANDLER( system1_videomode_w );
+READ8_HANDLER( system1_videomode_r );
+
+WRITE8_HANDLER( choplifter_scroll_x_w );
+VIDEO_UPDATE( choplifter );
+VIDEO_UPDATE( wbml );
+VIDEO_UPDATE( ufosensi );
+VIDEO_UPDATE( blockgal );
+
+#endif
diff --git a/src/mame/video/system16.c b/src/mame/video/system16.c
new file mode 100644
index 00000000000..b377da745cc
--- /dev/null
+++ b/src/mame/video/system16.c
@@ -0,0 +1,1147 @@
+/***************************************************************************
+
+Sega System 16 Video Hardware
+
+Known issues:
+- better abstraction of tilemap hardware is needed; a lot of this mess could and should
+ be consolidated further
+- many games have ROM patches - why? let's emulate protection when possible
+- several games fail their RAM self-test because of hacks in the drivers
+- many registers are suspiciously plucked from working RAM
+- several games have nvram according to the self test, but we aren't yet saving it
+- many games suffer from sys16_refreshenable register not being mapped
+- road-rendering routines need to be cleaned up or at least better described
+- logical sprite height computation isn't quite right - garbage pixels are drawn
+- sprite drawing is unoptimized
+- end-of-sprite marker support will fix some glitches
+- shadow and partial shadow sprite support
+- to achieve sprite-tilemap orthogonality we must draw sprites from front to back;
+ this will also allow us to avoid processing the same shadowed pixel twice.
+
+The System16 video hardware consists of:
+
+- Road Layer (present only for certain games)
+
+- Two scrolling tilemap layers
+
+- Two alternate scrolling tilemap layers, normally invisible.
+
+- A fixed tilemap layer, normally used for score, lives display
+
+Each scrolling layer (foreground, background) is an arrangement
+of 4 pages selected from 16 available pages, laid out as follows:
+
+ Page0 Page1
+ Page2 Page3
+
+Each page is an arrangement of 8x8 tiles, 64 tiles wide, and 32 tiles high.
+
+Layers normally scroll as a whole, with xscroll and yscroll.
+
+However, layers can also be configured with screenwise rowscroll, if the most significant
+bit of xscroll is set. When a layer is in this mode, the splittable is used.
+
+When rowscroll is in effect, the most significant bit of rowscroll selects between the
+default layer and an alternate layer associated with it.
+
+The foreground layer's tiles may be flagged as high-priority; this is used to mask
+sprites, i.e. the grass in Altered Beast.
+
+The background layer's tiles may also be flagged as high-priority. In this case,
+it's really a transparency_pen effect rather. Aurail uses this.
+
+Most games map Video Registers in textram as follows:
+
+type0:
+most games
+
+type1:
+alexkidd,fantzone,shinobl,hangon
+mjleague
+
+others:
+ shangon, shdancbl,
+ dduxbl,eswat,
+ passsht,passht4b
+ quartet,quartet2,
+ tetris,tturfbl,wb3bl
+
+sys16_textram:
+type1 type0 function
+---------------------------------------
+0x74f 0x740 sys16_fg_page
+0x74e 0x741 sys16_bg_page
+ 0x742 sys16_fg2_page
+ 0x743 sys16_bg2_page
+
+0x792 0x748 sys16_fg_scrolly
+0x793 0x749 sys16_bg_scrolly
+ 0x74a sys16_fg2_scrolly
+ 0x74b sys16_bg2_scrolly
+
+0x7fc 0x74c sys16_fg_scrollx
+0x7fd 0x74d sys16_bg_scrollx
+ 0x74e sys16_fg2_scrollx
+ 0x74f sys16_bg2_scrollx
+
+ 0x7c0..0x7df sys18_splittab_fg_x
+ 0x7e0..0x7ff sys18_splittab_bg_x
+
+***************************************************************************/
+#include "driver.h"
+#include "system16.h"
+#include "video/resnet.h"
+
+/* video/segac2.c */
+extern void update_system18_vdp( mame_bitmap *bitmap, const rectangle *cliprect );
+extern void start_system18_vdp(void);
+extern READ16_HANDLER( segac2_vdp_r );
+extern WRITE16_HANDLER( segac2_vdp_w );
+static UINT16 sys18_ddcrew_bankregs[0x20];
+
+
+
+
+/* callback to poll video registers */
+void (* sys16_update_proc)( void );
+
+UINT16 *sys16_tileram;
+UINT16 *sys16_textram;
+UINT16 *sys16_spriteram;
+
+static int num_sprites;
+
+#define MAXCOLOURS 0x2000 /* 8192 */
+
+int sys16_sh_shadowpal;
+int sys16_MaxShadowColors;
+
+/* video driver constants (potentially different for each game) */
+int sys16_gr_bitmap_width;
+int (*sys16_spritesystem)( struct sys16_sprite_attributes *sprite, const UINT16 *source, int bJustGetColor );
+int *sys16_obj_bank;
+int sys16_sprxoffset;
+int sys16_bgxoffset;
+int sys16_fgxoffset;
+int sys16_textlayer_lo_min;
+int sys16_textlayer_lo_max;
+int sys16_textlayer_hi_min;
+int sys16_textlayer_hi_max;
+int sys16_bg1_trans; // alien syn + sys18
+int sys16_bg_priority_mode;
+int sys16_fg_priority_mode;
+int sys16_bg_priority_value;
+int sys16_fg_priority_value;
+static int sys16_18_mode;
+int sys16_tilebank_switch;
+int sys16_rowscroll_scroll;
+int shinobl_kludge;
+
+/* video registers */
+int sys16_tile_bank1;
+int sys16_tile_bank0;
+int sys16_refreshenable;
+
+int sys16_bg_scrollx, sys16_bg_scrolly;
+int sys16_bg2_scrollx, sys16_bg2_scrolly;
+int sys16_fg_scrollx, sys16_fg_scrolly;
+int sys16_fg2_scrollx, sys16_fg2_scrolly;
+
+int sys16_bg_page[4];
+int sys16_bg2_page[4];
+int sys16_fg_page[4];
+int sys16_fg2_page[4];
+
+int sys18_bg2_active;
+int sys18_fg2_active;
+UINT16 *sys18_splittab_bg_x;
+UINT16 *sys18_splittab_bg_y;
+UINT16 *sys18_splittab_fg_x;
+UINT16 *sys18_splittab_fg_y;
+
+UINT16 *sys16_gr_ver;
+UINT16 *sys16_gr_hor;
+UINT16 *sys16_gr_pal;
+UINT16 *sys16_gr_flip;
+int sys16_gr_palette;
+int sys16_gr_palette_default;
+UINT8 sys16_gr_colorflip[2][4];
+UINT16 *sys16_gr_second_road;
+
+static tilemap *background, *foreground, *text_layer;
+static tilemap *background2, *foreground2;
+static int old_bg_page[4],old_fg_page[4], old_tile_bank1, old_tile_bank0;
+static int old_bg2_page[4],old_fg2_page[4];
+
+/***************************************************************************/
+
+READ16_HANDLER( sys16_textram_r ){
+ return sys16_textram[offset];
+}
+
+READ16_HANDLER( sys16_tileram_r ){
+ return sys16_tileram[offset];
+}
+
+/***************************************************************************/
+
+/*
+ We mark the priority buffer as follows:
+ text (0xf)
+ fg (hi) (0x7)
+ fg (lo) (0x3)
+ bg (hi) (0x1)
+ bg (lo) (0x0)
+
+ Each sprite has 4 levels of priority, specifying where they are placed between bg(lo) and text.
+*/
+
+static void draw_sprite(running_machine *machine,
+ mame_bitmap *bitmap,
+ const rectangle *cliprect,
+ const UINT8 *addr, int pitch,
+ const pen_t *paldata,
+ int x0, int y0, int screen_width, int screen_height,
+ int width, int height,
+ int flipx, int flipy,
+ int priority,
+ int shadow,
+ int shadow_pen, int eos )
+{
+ const pen_t *shadow_base = machine->remapped_colortable + machine->gfx[0]->color_base + (machine->drv->total_colors/2);
+ const UINT8 *source;
+ int full_shadow=shadow&SYS16_SPR_SHADOW;
+ int partial_shadow=shadow&SYS16_SPR_PARTIAL_SHADOW;
+ int shadow_mask=(machine->drv->total_colors/2)-1;
+ int sx, x, xcount;
+ int sy, y, ycount = 0;
+ int dx,dy;
+ UINT16 *dest;
+ UINT8 *pri;
+ unsigned pen, data;
+
+ priority = 1<<priority;
+
+ if( flipy ){
+ dy = -1;
+ y0 += screen_height-1;
+ }
+ else {
+ dy = 1;
+ }
+
+ if( flipx ){
+ dx = -1;
+ x0 += screen_width-1;
+ }
+ else {
+ dx = 1;
+ }
+
+ if (!eos)
+ {
+ sy = y0;
+ for( y=height; y; y-- ){
+ ycount += screen_height;
+ while( ycount>=height ){
+ if( sy>=cliprect->min_y && sy<=cliprect->max_y ){
+ source = addr;
+ dest = BITMAP_ADDR16(bitmap, sy, 0);
+ pri = BITMAP_ADDR8(priority_bitmap, sy, 0);
+ sx = x0;
+ xcount = 0;
+ for( x=width; x; x-=2 ){
+ data = (unsigned)*source++; /* next 2 pixels */
+ pen = data>>4;
+ xcount += screen_width;
+ while( xcount>=width )
+ {
+ if( pen && pen!=0xf && sx>=cliprect->min_x && sx<=cliprect->max_x ){
+ if(!(pri[sx]&priority)){
+ if (full_shadow)
+ dest[sx] = shadow_base[dest[sx]&shadow_mask];
+ else if (partial_shadow && pen==shadow_pen)
+ dest[sx] = shadow_base[dest[sx]&shadow_mask];
+ else
+ dest[sx] = paldata[pen];
+ }
+ }
+ xcount -= width;
+ sx+=dx;
+ }
+ pen = data&0xf;
+ xcount += screen_width;
+ while( xcount>=width )
+ {
+ if( pen && pen!=0xf && sx>=cliprect->min_x && sx<=cliprect->max_x ){
+ if(!(pri[sx]&priority)){
+ if (full_shadow)
+ dest[sx] = shadow_base[dest[sx]&shadow_mask];
+ else if (partial_shadow && pen==shadow_pen)
+ dest[sx] = shadow_base[dest[sx]&shadow_mask];
+ else
+ dest[sx] = paldata[pen];
+ }
+ }
+ xcount -= width;
+ sx+=dx;
+ }
+ }
+ }
+ ycount -= height;
+ sy+=dy;
+ }
+ addr += pitch;
+ }
+ }
+ else
+ {
+ sy = y0;
+ for( y=height; y; y-- ){
+ ycount += screen_height;
+ while( ycount>=height ){
+ if( sy>=cliprect->min_y && sy<=cliprect->max_y ){
+ source = addr;
+ dest = BITMAP_ADDR16(bitmap, sy, 0);
+ pri = BITMAP_ADDR8(priority_bitmap, sy, 0);
+ sx = x0;
+ xcount = 0;
+ for( x=width; x; x-=2 ){
+ data = (unsigned)*source++; /* next 2 pixels */
+ pen = data>>4;
+ if (pen==0xf) break;
+ xcount += screen_width;
+ while( xcount>=width )
+ {
+ if( pen && pen!=0xf && sx>=cliprect->min_x && sx<=cliprect->max_x )
+ if(!(pri[sx]&priority)) dest[sx] = paldata[pen];
+ xcount -= width;
+ sx+=dx;
+ }
+ pen = data&0xf;
+ xcount += screen_width;
+ while( xcount>=width )
+ {
+ if( pen && pen!=0xf && sx>=cliprect->min_x && sx<=cliprect->max_x )
+ if(!(pri[sx]&priority)) dest[sx] = paldata[pen];
+ xcount -= width;
+ sx+=dx;
+ }
+ }
+ }
+ ycount -= height;
+ sy+=dy;
+ }
+ addr += pitch;
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int b3d ) //*
+{
+ const pen_t *base_pal = machine->remapped_colortable + machine->gfx[0]->color_base;
+ const UINT8 *base_gfx = memory_region(REGION_GFX2);
+ const int gfx_rom_size = memory_region_length(REGION_GFX2);
+ const UINT16 *source = sys16_spriteram;
+ struct sys16_sprite_attributes sprite;
+ int xpos, ypos, screen_width, width, logical_height, pitch, flipy, flipx;
+ int i, mod_h, mod_x, eos;
+ unsigned gfx;
+
+ memset(&sprite, 0x00, sizeof(sprite));
+
+ for(i=0; i<num_sprites; i++)
+ {
+ sprite.flags = 0;
+ if (sys16_spritesystem(&sprite, source, 0)) return; /* end-of-spritelist */
+ source += 8;
+
+ if( sprite.flags & SYS16_SPR_VISIBLE )
+ {
+ xpos = sprite.x;
+ flipx = sprite.flags & SYS16_SPR_FLIPX;
+ ypos = sprite.y;
+ pitch = sprite.pitch;
+ flipy = pitch & 0x80;
+ width = pitch & 0x7f;
+ if (pitch & 0x80) width = 0x80 - width;
+ pitch = width << 1;
+ width <<= 2;
+ eos = 0;
+
+ if( b3d ) // outrun/aburner
+ {
+ if (b3d == 2) eos = 1;
+ if (xpos < 0 && flipx) continue;
+ if (ypos >= 240) ypos -= 256;
+ sprite.screen_height++;
+ logical_height = (sprite.screen_height<<4)*sprite.zoomy/0x2000;
+ screen_width = width*0x200/sprite.zoomx;
+
+ if (flipx && flipy) { mod_h = -logical_height; mod_x = 4; }
+ else if (flipx) { mod_h = -1; xpos++; mod_x = 4; }
+ else if (flipy) { mod_h = -logical_height; mod_x = 0; }
+ else { mod_h = 0; mod_x = 0; }
+
+ if( sprite.flags & SYS16_SPR_DRAW_TO_TOP )
+ {
+ ypos -= sprite.screen_height;
+ flipy = !flipy;
+ }
+
+ if( sprite.flags & SYS16_SPR_DRAW_TO_LEFT )
+ {
+ xpos -= screen_width;
+ flipx = !flipx;
+ }
+ }
+ else
+ {
+ if (!width) { width = 512; eos = 1; } // used by fantasy zone for laser
+ screen_width = width;
+ logical_height = sprite.screen_height;
+
+ if (sprite.zoomy) logical_height = logical_height*(0x400 + sprite.zoomy)/0x400 - 1;
+ if (sprite.zoomx) screen_width = screen_width*(0x800 - sprite.zoomx)/0x800 + 2;
+
+// fix, 5-bit zoom field
+// if (sprite.zoomy) logical_height = logical_height*(0x20 + sprite.zoomy)/0x20 - 1;
+// if (sprite.zoomx) screen_width = screen_width*(0x40 - sprite.zoomx)/0x40 + 2;
+
+ if (flipx && flipy) { mod_h = -logical_height-1; mod_x = 2; }
+ else if (flipx) { mod_h = 0; mod_x = 2; }
+ else if (flipy) { mod_h = -logical_height; mod_x = 0; }
+ else { mod_h = 1; mod_x = 0; }
+ }
+
+ gfx = sprite.gfx + pitch * mod_h + mod_x;
+ if (gfx >= gfx_rom_size) gfx %= gfx_rom_size;
+
+ gfx &= 0x1fffff; // temp kludge to stop line of fire crashing
+
+ draw_sprite(machine,
+ bitmap,cliprect,
+ base_gfx + gfx, pitch,
+ base_pal + (sprite.color<<4),
+ xpos, ypos, screen_width, sprite.screen_height,
+ width, logical_height,
+ flipx, flipy,
+ sprite.priority,
+ sprite.flags,
+ sprite.shadow_pen, eos);
+ }
+ }
+}
+
+/***************************************************************************/
+
+static TILEMAP_MAPPER( sys16_bg_map )
+{
+ int page = 0;
+ if( row<32 ){ /* top */
+ if( col<64 ) page = 0; else page = 1;
+ }
+ else { /* bottom */
+ if( col<64 ) page = 2; else page = 3;
+ }
+ row = row%32;
+ col = col%64;
+ return page*64*32+row*64+col;
+}
+
+static TILEMAP_MAPPER( sys16_text_map )
+{
+ return row*64+col+(64-40);
+}
+
+/***************************************************************************/
+
+/*
+ Color generation details
+
+ Each color is made up of 5 bits, connected through one or more resistors like so:
+
+ Bit 0 = 1 x 3.9K ohm
+ Bit 1 = 1 x 2.0K ohm
+ Bit 2 = 1 x 1.0K ohm
+ Bit 3 = 2 x 1.0K ohm
+ Bit 4 = 4 x 1.0K ohm
+
+ Another data bit is connected by a tristate buffer to the color output through a 470 ohm resistor.
+ The buffer allows the resistor to have no effect (tristate), halve brightness (pull-down) or double brightness (pull-up).
+ The data bit source is a PPI pin in some of the earlier hardware (Hang-On, Pre-System 16) or bit 15 of each
+ color RAM entry (Space Harrier, System 16B and most later boards).
+*/
+
+static const int resistances_normal[6] = {3900, 2000, 1000, 1000/2, 1000/4, 0};
+static const int resistances_sh[6] = {3900, 2000, 1000, 1000/2, 1000/4, 470};
+static double weights[2][3][6];
+
+WRITE16_HANDLER( sys16_paletteram_w )
+{
+ UINT16 oldword = paletteram16[offset];
+ UINT16 newword;
+ COMBINE_DATA( &paletteram16[offset] );
+ newword = paletteram16[offset];
+
+ if( oldword!=newword )
+ {
+ /* we can do this, because we initialize palette RAM to all black in vh_start */
+ /* byte 0 byte 1 */
+ /* sBGR BBBB GGGG RRRR */
+ /* x000 4321 4321 4321 */
+
+ int r, g, b, rs, gs, bs, rh, gh, bh;
+ int r0 = (newword >> 12) & 1;
+ int r1 = (newword >> 0) & 1;
+ int r2 = (newword >> 1) & 1;
+ int r3 = (newword >> 2) & 1;
+ int r4 = (newword >> 3) & 1;
+ int g0 = (newword >> 13) & 1;
+ int g1 = (newword >> 4) & 1;
+ int g2 = (newword >> 5) & 1;
+ int g3 = (newword >> 6) & 1;
+ int g4 = (newword >> 7) & 1;
+ int b0 = (newword >> 14) & 1;
+ int b1 = (newword >> 8) & 1;
+ int b2 = (newword >> 9) & 1;
+ int b3 = (newword >> 10) & 1;
+ int b4 = (newword >> 11) & 1;
+
+ /* Normal colors */
+ r = combine_6_weights(weights[0][0], r0, r1, r2, r3, r4, 0);
+ g = combine_6_weights(weights[0][1], g0, g1, g2, g3, g4, 0);
+ b = combine_6_weights(weights[0][2], b0, b1, b2, b3, b4, 0);
+
+ /* Shadow colors */
+ rs = combine_6_weights(weights[1][0], r0, r1, r2, r3, r4, 0);
+ gs = combine_6_weights(weights[1][1], g0, g1, g2, g3, g4, 0);
+ bs = combine_6_weights(weights[1][2], b0, b1, b2, b3, b4, 0);
+
+ /* Highlight colors */
+ rh = combine_6_weights(weights[1][0], r0, r1, r2, r3, r4, 1);
+ gh = combine_6_weights(weights[1][1], g0, g1, g2, g3, g4, 1);
+ bh = combine_6_weights(weights[1][2], b0, b1, b2, b3, b4, 1);
+
+ palette_set_color( Machine, offset, MAKE_RGB(r, g, b) );
+
+ palette_set_color( Machine, offset+Machine->drv->total_colors/2,MAKE_RGB(rs,gs,bs));
+ }
+}
+
+
+static void update_page( void ){
+ int all_dirty = 0;
+ int i,offset;
+ if( old_tile_bank1 != sys16_tile_bank1 ){
+ all_dirty = 1;
+ old_tile_bank1 = sys16_tile_bank1;
+ }
+ if( old_tile_bank0 != sys16_tile_bank0 ){
+ all_dirty = 1;
+ old_tile_bank0 = sys16_tile_bank0;
+ tilemap_mark_all_tiles_dirty( text_layer );
+ }
+ if( all_dirty ){
+ tilemap_mark_all_tiles_dirty( background );
+ tilemap_mark_all_tiles_dirty( foreground );
+ if( sys16_18_mode ){
+ tilemap_mark_all_tiles_dirty( background2 );
+ tilemap_mark_all_tiles_dirty( foreground2 );
+ }
+ }
+ else {
+ for(i=0;i<4;i++){
+ int page0 = 64*32*i;
+ if( old_bg_page[i]!=sys16_bg_page[i] ){
+ old_bg_page[i] = sys16_bg_page[i];
+ for( offset = page0; offset<page0+64*32; offset++ ){
+ tilemap_mark_tile_dirty( background, offset );
+ }
+ }
+ if( old_fg_page[i]!=sys16_fg_page[i] ){
+ old_fg_page[i] = sys16_fg_page[i];
+ for( offset = page0; offset<page0+64*32; offset++ ){
+ tilemap_mark_tile_dirty( foreground, offset );
+ }
+ }
+ if( sys16_18_mode ){
+ if( old_bg2_page[i]!=sys16_bg2_page[i] ){
+ old_bg2_page[i] = sys16_bg2_page[i];
+ for( offset = page0; offset<page0+64*32; offset++ ){
+ tilemap_mark_tile_dirty( background2, offset );
+ }
+ }
+ if( old_fg2_page[i]!=sys16_fg2_page[i] ){
+ old_fg2_page[i] = sys16_fg2_page[i];
+ for( offset = page0; offset<page0+64*32; offset++ ){
+ tilemap_mark_tile_dirty( foreground2, offset );
+ }
+ }
+ }
+ }
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info ){
+ const UINT16 *source = 64*32*sys16_bg_page[tile_index/(64*32)] + sys16_tileram;
+ int data = source[tile_index%(64*32)];
+ int tile_number = (data&0xfff) + 0x1000*((data&sys16_tilebank_switch)?sys16_tile_bank1:sys16_tile_bank0);
+
+ if (!shinobl_kludge)
+ {
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ (data>>6)&0x7f,
+ 0);
+ }
+ else
+ {
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ (data>>5)&0x7f,
+ 0);
+ }
+
+ switch(sys16_bg_priority_mode) {
+ case 1: // Alien Syndrome
+ tileinfo->category = (data&0x8000)?1:0;
+ break;
+ case 2: // Body Slam / wrestwar
+ tileinfo->category = ((data&0xff00) >= sys16_bg_priority_value)?1:0;
+ break;
+ case 3: // sys18 games
+ if( data&0x8000 ){
+ tileinfo->category = 2;
+ }
+ else {
+ tileinfo->category = ((data&0xff00) >= sys16_bg_priority_value)?1:0;
+ }
+ break;
+ }
+}
+
+static TILE_GET_INFO( get_fg_tile_info ){
+ const UINT16 *source = 64*32*sys16_fg_page[tile_index/(64*32)] + sys16_tileram;
+ int data = source[tile_index%(64*32)];
+ int tile_number = (data&0xfff) + 0x1000*((data&sys16_tilebank_switch)?sys16_tile_bank1:sys16_tile_bank0);
+
+ if (!shinobl_kludge)
+ {
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ (data>>6)&0x7f,
+ 0);
+ }
+ else
+ {
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ (data>>5)&0x7f,
+ 0);
+ }
+
+ switch(sys16_fg_priority_mode){
+ case 1: // alien syndrome
+ tileinfo->category = (data&0x8000)?1:0;
+ break;
+
+ case 3:
+ tileinfo->category = ((data&0xff00) >= sys16_fg_priority_value)?1:0;
+ break;
+
+ default:
+ if( sys16_fg_priority_mode>=0 ){
+ tileinfo->category = (data&0x8000)?1:0;
+ }
+ break;
+ }
+}
+
+static TILE_GET_INFO( get_bg2_tile_info ){
+ const UINT16 *source = 64*32*sys16_bg2_page[tile_index/(64*32)] + sys16_tileram;
+ int data = source[tile_index%(64*32)];
+ int tile_number = (data&0xfff) + 0x1000*((data&0x1000)?sys16_tile_bank1:sys16_tile_bank0);
+
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ (data>>6)&0x7f,
+ 0);
+
+ tileinfo->category = 0;
+}
+
+static TILE_GET_INFO( get_fg2_tile_info ){
+ const UINT16 *source = 64*32*sys16_fg2_page[tile_index/(64*32)] + sys16_tileram;
+ int data = source[tile_index%(64*32)];
+ int tile_number = (data&0xfff) + 0x1000*((data&0x1000)?sys16_tile_bank1:sys16_tile_bank0);
+
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ (data>>6)&0x7f,
+ 0);
+
+ if((data&0xff00) >= sys16_fg_priority_value) tileinfo->category = 1;
+ else tileinfo->category = 0;
+}
+
+WRITE16_HANDLER( sys16_tileram_w ){
+ UINT16 oldword = sys16_tileram[offset];
+ COMBINE_DATA( &sys16_tileram[offset] );
+ if( oldword != sys16_tileram[offset] ){
+ int page = offset/(64*32);
+ offset = offset%(64*32);
+
+ if( sys16_bg_page[0]==page ) tilemap_mark_tile_dirty( background, offset+64*32*0 );
+ if( sys16_bg_page[1]==page ) tilemap_mark_tile_dirty( background, offset+64*32*1 );
+ if( sys16_bg_page[2]==page ) tilemap_mark_tile_dirty( background, offset+64*32*2 );
+ if( sys16_bg_page[3]==page ) tilemap_mark_tile_dirty( background, offset+64*32*3 );
+
+ if( sys16_fg_page[0]==page ) tilemap_mark_tile_dirty( foreground, offset+64*32*0 );
+ if( sys16_fg_page[1]==page ) tilemap_mark_tile_dirty( foreground, offset+64*32*1 );
+ if( sys16_fg_page[2]==page ) tilemap_mark_tile_dirty( foreground, offset+64*32*2 );
+ if( sys16_fg_page[3]==page ) tilemap_mark_tile_dirty( foreground, offset+64*32*3 );
+
+ if( sys16_18_mode ){
+ if( sys16_bg2_page[0]==page ) tilemap_mark_tile_dirty( background2, offset+64*32*0 );
+ if( sys16_bg2_page[1]==page ) tilemap_mark_tile_dirty( background2, offset+64*32*1 );
+ if( sys16_bg2_page[2]==page ) tilemap_mark_tile_dirty( background2, offset+64*32*2 );
+ if( sys16_bg2_page[3]==page ) tilemap_mark_tile_dirty( background2, offset+64*32*3 );
+
+ if( sys16_fg2_page[0]==page ) tilemap_mark_tile_dirty( foreground2, offset+64*32*0 );
+ if( sys16_fg2_page[1]==page ) tilemap_mark_tile_dirty( foreground2, offset+64*32*1 );
+ if( sys16_fg2_page[2]==page ) tilemap_mark_tile_dirty( foreground2, offset+64*32*2 );
+ if( sys16_fg2_page[3]==page ) tilemap_mark_tile_dirty( foreground2, offset+64*32*3 );
+ }
+ }
+}
+
+/***************************************************************************/
+
+static TILE_GET_INFO( get_text_tile_info ){
+ const UINT16 *source = sys16_textram;
+ int tile_number = source[tile_index];
+ int pri = tile_number >> 8;
+
+ if (!shinobl_kludge)
+ {
+ SET_TILE_INFO(
+ 0,
+ (tile_number&0x1ff) + sys16_tile_bank0 * 0x1000,
+ (tile_number>>9)%8,
+ 0);
+ }
+ else
+ {
+ SET_TILE_INFO(
+ 0,
+ (tile_number&0xff) + sys16_tile_bank0 * 0x1000,
+ (tile_number>>8)%8,
+ 0);
+ }
+
+ if(pri>=sys16_textlayer_lo_min && pri<=sys16_textlayer_lo_max)
+ tileinfo->category = 1;
+ if(pri>=sys16_textlayer_hi_min && pri<=sys16_textlayer_hi_max)
+ tileinfo->category = 0;
+}
+
+WRITE16_HANDLER( sys16_textram_w ){
+ COMBINE_DATA( &sys16_textram[offset] );
+ tilemap_mark_tile_dirty( text_layer, offset );
+}
+
+/***************************************************************************/
+
+VIDEO_START( system16 ){
+ static int bank_default[16] = {
+ 0x0,0x1,0x2,0x3,
+ 0x4,0x5,0x6,0x7,
+ 0x8,0x9,0xa,0xb,
+ 0xc,0xd,0xe,0xf
+ };
+ if (!sys16_obj_bank)
+ sys16_obj_bank = bank_default;
+
+ /* Normal colors */
+ compute_resistor_weights(0, 255, -1.0,
+ 6, resistances_normal, weights[0][0], 0, 0,
+ 6, resistances_normal, weights[0][1], 0, 0,
+ 6, resistances_normal, weights[0][2], 0, 0
+ );
+
+ /* Shadow/Highlight colors */
+ compute_resistor_weights(0, 255, -1.0,
+ 6, resistances_sh, weights[1][0], 0, 0,
+ 6, resistances_sh, weights[1][1], 0, 0,
+ 6, resistances_sh, weights[1][2], 0, 0
+ );
+
+ if( !sys16_bg1_trans )
+ background = tilemap_create(
+ get_bg_tile_info,
+ sys16_bg_map,
+ TILEMAP_TYPE_PEN,
+ 8,8,
+ 64*2,32*2 );
+ else
+ background = tilemap_create(
+ get_bg_tile_info,
+ sys16_bg_map,
+ TILEMAP_TYPE_PEN,
+ 8,8,
+ 64*2,32*2 );
+
+ foreground = tilemap_create(
+ get_fg_tile_info,
+ sys16_bg_map,
+ TILEMAP_TYPE_PEN,
+ 8,8,
+ 64*2,32*2 );
+
+ text_layer = tilemap_create(
+ get_text_tile_info,
+ sys16_text_map,
+ TILEMAP_TYPE_PEN,
+ 8,8,
+ 40,28 );
+
+ num_sprites = 128*2; /* only 128 for most games; aburner uses 256 */
+
+ if(!strcmp(machine->gamedrv->name, "hangon"))
+ num_sprites = 128;
+
+ {
+ /* initialize all entries to black - needed for Golden Axe*/
+ int i;
+ for( i=0; i<machine->drv->total_colors; i++ ){
+ palette_set_color( machine, i, MAKE_RGB(0,0,0) );
+ }
+
+ if(sys16_bg1_trans) tilemap_set_transparent_pen( background, 0 );
+ tilemap_set_transparent_pen( foreground, 0 );
+ tilemap_set_transparent_pen( text_layer, 0 );
+
+ sys16_tile_bank0 = 0;
+ sys16_tile_bank1 = 1;
+
+ sys16_fg_scrollx = 0;
+ sys16_fg_scrolly = 0;
+
+ sys16_bg_scrollx = 0;
+ sys16_bg_scrolly = 0;
+
+ sys16_refreshenable = 1;
+
+ /* common defaults */
+ sys16_spritesystem = sys16_sprite_shinobi;
+ if (!sys16_sprxoffset)
+ sys16_sprxoffset = -0xb8;
+ sys16_bgxoffset = 0;
+ sys16_bg_priority_mode=0;
+ sys16_fg_priority_mode=0;
+ sys16_tilebank_switch=0x1000;
+
+ // Defaults for sys16 games
+ sys16_textlayer_lo_min=0;
+ sys16_textlayer_lo_max=0x7f;
+ sys16_textlayer_hi_min=0x80;
+ sys16_textlayer_hi_max=0xff;
+
+ sys16_18_mode=0;
+ }
+}
+
+VIDEO_START( system18old ){
+ int i;
+
+ sys16_bg1_trans=1;
+
+ start_system18_vdp();
+
+ /* clear these registers to -1 so that writes of 0 get picked up */
+ for (i=0;i<0x20;i++)
+ {
+ sys18_ddcrew_bankregs[i]=-1;
+ }
+
+ background2 = tilemap_create(
+ get_bg2_tile_info,
+ sys16_bg_map,
+ TILEMAP_TYPE_PEN,
+ 8,8,
+ 64*2,32*2 );
+
+ foreground2 = tilemap_create(
+ get_fg2_tile_info,
+ sys16_bg_map,
+ TILEMAP_TYPE_PEN,
+ 8,8,
+ 64*2,32*2 );
+
+ video_start_system16(machine);
+
+ tilemap_set_transparent_pen( foreground2, 0 );
+
+ if(sys18_splittab_fg_x){
+ tilemap_set_scroll_rows( foreground , 64 );
+ tilemap_set_scroll_rows( foreground2 , 64 );
+ }
+ if(sys18_splittab_bg_x){
+ tilemap_set_scroll_rows( background , 64 );
+ tilemap_set_scroll_rows( background2 , 64 );
+ }
+
+ sys16_textlayer_lo_min=0;
+ sys16_textlayer_lo_max=0x1f;
+ sys16_textlayer_hi_min=0x20;
+ sys16_textlayer_hi_max=0xff;
+
+ sys16_18_mode=1;
+ sys16_bg_priority_mode=3;
+ sys16_fg_priority_mode=3;
+ sys16_bg_priority_value=0x1800;
+ sys16_fg_priority_value=0x2000;
+}
+
+/***************************************************************************/
+
+static void sys16_vh_refresh_helper( void ){
+ if( sys18_splittab_bg_x ){
+ if( (sys16_bg_scrollx&0xff00) != sys16_rowscroll_scroll ){
+ tilemap_set_scroll_rows( background , 1 );
+ tilemap_set_scrollx( background, 0, -320-sys16_bg_scrollx+sys16_bgxoffset );
+ }
+ else {
+ int offset, scroll,i;
+
+ tilemap_set_scroll_rows( background , 64 );
+ offset = 32+((sys16_bg_scrolly&0x1f8) >> 3);
+
+ for( i=0; i<29; i++ ){
+ scroll = sys18_splittab_bg_x[i];
+ tilemap_set_scrollx( background , (i+offset)&0x3f, -320-(scroll&0x3ff)+sys16_bgxoffset );
+ }
+ }
+ }
+ else {
+ tilemap_set_scrollx( background, 0, -320-sys16_bg_scrollx+sys16_bgxoffset );
+ }
+
+ if( sys18_splittab_bg_y ){
+ if( (sys16_bg_scrolly&0xff00) != sys16_rowscroll_scroll ){
+ tilemap_set_scroll_cols( background , 1 );
+ tilemap_set_scrolly( background, 0, -256+sys16_bg_scrolly );
+ }
+ else {
+ int offset, scroll,i;
+
+ tilemap_set_scroll_cols( background , 128 );
+ offset = 127-((sys16_bg_scrollx&0x3f8) >> 3)-40+2;
+
+ for( i=0;i<41;i++ ){
+ scroll = sys18_splittab_bg_y[(i+24)>>1];
+ tilemap_set_scrolly( background , (i+offset)&0x7f, -256+(scroll&0x3ff) );
+ }
+ }
+ }
+ else {
+ tilemap_set_scrolly( background, 0, -256+sys16_bg_scrolly );
+ }
+
+ if( sys18_splittab_fg_x ){
+ if( (sys16_fg_scrollx&0xff00) != sys16_rowscroll_scroll ){
+ tilemap_set_scroll_rows( foreground , 1 );
+ tilemap_set_scrollx( foreground, 0, -320-sys16_fg_scrollx+sys16_fgxoffset );
+ }
+ else {
+ int offset, scroll,i;
+
+ tilemap_set_scroll_rows( foreground , 64 );
+ offset = 32+((sys16_fg_scrolly&0x1f8) >> 3);
+
+ for(i=0;i<29;i++){
+ scroll = sys18_splittab_fg_x[i];
+ tilemap_set_scrollx( foreground , (i+offset)&0x3f, -320-(scroll&0x3ff)+sys16_fgxoffset );
+ }
+ }
+ }
+ else {
+ tilemap_set_scrollx( foreground, 0, -320-sys16_fg_scrollx+sys16_fgxoffset );
+ }
+
+ if( sys18_splittab_fg_y ){
+ if( (sys16_fg_scrolly&0xff00) != sys16_rowscroll_scroll ){
+ tilemap_set_scroll_cols( foreground , 1 );
+ tilemap_set_scrolly( foreground, 0, -256+sys16_fg_scrolly );
+ }
+ else {
+ int offset, scroll,i;
+
+ tilemap_set_scroll_cols( foreground , 128 );
+ offset = 127-((sys16_fg_scrollx&0x3f8) >> 3)-40+2;
+
+ for( i=0; i<41; i++ ){
+ scroll = sys18_splittab_fg_y[(i+24)>>1];
+ tilemap_set_scrolly( foreground , (i+offset)&0x7f, -256+(scroll&0x3ff) );
+ }
+ }
+ }
+ else {
+ tilemap_set_scrolly( foreground, 0, -256+sys16_fg_scrolly );
+ }
+}
+
+static void sys18_vh_screenrefresh_helper( void ){
+ int i;
+ if( sys18_splittab_bg_x ){ // screenwise rowscroll?
+ int offset,offset2, scroll,scroll2,orig_scroll;
+
+ offset = 32+((sys16_bg_scrolly&0x1f8) >> 3); // 0x00..0x3f
+ offset2 = 32+((sys16_bg2_scrolly&0x1f8) >> 3); // 0x00..0x3f
+
+ for( i=0;i<29;i++ ){
+ orig_scroll = scroll2 = scroll = sys18_splittab_bg_x[i];
+ if((sys16_bg_scrollx &0xff00) != 0x8000) scroll = sys16_bg_scrollx;
+ if((sys16_bg2_scrollx &0xff00) != 0x8000) scroll2 = sys16_bg2_scrollx;
+
+ if(orig_scroll&0x8000){ // background2
+ tilemap_set_scrollx( background , (i+offset)&0x3f, TILE_LINE_DISABLED );
+ tilemap_set_scrollx( background2, (i+offset2)&0x3f, -320-(scroll2&0x3ff)+sys16_bgxoffset );
+ }
+ else{ // background
+ tilemap_set_scrollx( background , (i+offset)&0x3f, -320-(scroll&0x3ff)+sys16_bgxoffset );
+ tilemap_set_scrollx( background2, (i+offset2)&0x3f, TILE_LINE_DISABLED );
+ }
+ }
+ }
+ else {
+ tilemap_set_scrollx( background , 0, -320-(sys16_bg_scrollx&0x3ff)+sys16_bgxoffset );
+ tilemap_set_scrollx( background2, 0, -320-(sys16_bg2_scrollx&0x3ff)+sys16_bgxoffset );
+ }
+
+ tilemap_set_scrolly( background , 0, -256+sys16_bg_scrolly );
+ tilemap_set_scrolly( background2, 0, -256+sys16_bg2_scrolly );
+
+ if( sys18_splittab_fg_x ){
+ int offset,offset2, scroll,scroll2,orig_scroll;
+
+ offset = 32+((sys16_fg_scrolly&0x1f8) >> 3);
+ offset2 = 32+((sys16_fg2_scrolly&0x1f8) >> 3);
+
+ for( i=0;i<29;i++ ){
+ orig_scroll = scroll2 = scroll = sys18_splittab_fg_x[i];
+ if( (sys16_fg_scrollx &0xff00) != 0x8000 ) scroll = sys16_fg_scrollx;
+
+ if( (sys16_fg2_scrollx &0xff00) != 0x8000 ) scroll2 = sys16_fg2_scrollx;
+
+ if( orig_scroll&0x8000 ){
+ tilemap_set_scrollx( foreground , (i+offset)&0x3f, TILE_LINE_DISABLED );
+ tilemap_set_scrollx( foreground2, (i+offset2)&0x3f, -320-(scroll2&0x3ff)+sys16_fgxoffset );
+ }
+ else {
+ tilemap_set_scrollx( foreground , (i+offset)&0x3f, -320-(scroll&0x3ff)+sys16_fgxoffset );
+ tilemap_set_scrollx( foreground2 , (i+offset2)&0x3f, TILE_LINE_DISABLED );
+ }
+ }
+ }
+ else {
+ tilemap_set_scrollx( foreground , 0, -320-(sys16_fg_scrollx&0x3ff)+sys16_fgxoffset );
+ tilemap_set_scrollx( foreground2, 0, -320-(sys16_fg2_scrollx&0x3ff)+sys16_fgxoffset );
+ }
+
+
+ tilemap_set_scrolly( foreground , 0, -256+sys16_fg_scrolly );
+ tilemap_set_scrolly( foreground2, 0, -256+sys16_fg2_scrolly );
+
+ tilemap_set_enable( background2, sys18_bg2_active );
+ tilemap_set_enable( foreground2, sys18_fg2_active );
+}
+
+VIDEO_UPDATE( system16 ){
+ if (!sys16_refreshenable)
+ {
+ fillbitmap(bitmap, 0, cliprect);
+ return 0;
+ }
+
+ if( sys16_update_proc ) sys16_update_proc();
+ update_page();
+ sys16_vh_refresh_helper(); /* set scroll registers */
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw( bitmap,cliprect, background, TILEMAP_DRAW_OPAQUE, 0x00 );
+ if(sys16_bg_priority_mode) tilemap_draw( bitmap,cliprect, background, TILEMAP_DRAW_OPAQUE | 1, 0x00 );
+// sprite_draw(sprite_list,3); // needed for Aurail
+ if( sys16_bg_priority_mode==2 ) tilemap_draw( bitmap,cliprect, background, 1, 0x01 );// body slam (& wrestwar??)
+// sprite_draw(sprite_list,2);
+ else if( sys16_bg_priority_mode==1 ) tilemap_draw( bitmap,cliprect, background, 1, 0x03 );// alien syndrome / aurail
+ tilemap_draw( bitmap,cliprect, foreground, 0, 0x03 );
+// sprite_draw(sprite_list,1);
+ tilemap_draw( bitmap,cliprect, foreground, 1, 0x07 );
+ if( sys16_textlayer_lo_max!=0 ) tilemap_draw( bitmap,cliprect, text_layer, 1, 7 );// needed for Body Slam
+// sprite_draw(sprite_list,0);
+ tilemap_draw( bitmap,cliprect, text_layer, 0, 0xf );
+
+ draw_sprites(machine, bitmap,cliprect,0 );
+ return 0;
+}
+
+
+VIDEO_UPDATE( system18old ){
+ if (!sys16_refreshenable)
+ {
+ /* should it REALLY not clear the bitmap? ddcrew vdp gfx look ugly if i don't do it like this */
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+ return 0;
+ }
+
+ if( sys16_update_proc ) sys16_update_proc();
+ update_page();
+ sys18_vh_screenrefresh_helper(); /* set scroll registers */
+
+ fillbitmap(priority_bitmap,0,NULL);
+ if(sys18_bg2_active)
+ tilemap_draw( bitmap,cliprect, background2, 0, 0 );
+ else
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ tilemap_draw( bitmap,cliprect, background, TILEMAP_DRAW_OPAQUE, 0 );
+ tilemap_draw( bitmap,cliprect, background, TILEMAP_DRAW_OPAQUE | 1, 0 ); //??
+ tilemap_draw( bitmap,cliprect, background, TILEMAP_DRAW_OPAQUE | 2, 0 ); //??
+
+ if (!strcmp(machine->gamedrv->name,"astorm")) update_system18_vdp(bitmap,cliprect); // kludge: render vdp here for astorm
+ /* ASTORM also draws some sprites with the vdp, needs to be higher priority..*/
+
+// sprite_draw(sprite_list,3);
+ tilemap_draw( bitmap,cliprect, background, 1, 0x1 );
+// sprite_draw(sprite_list,2);
+ tilemap_draw( bitmap,cliprect, background, 2, 0x3 );
+
+
+ if(sys18_fg2_active) tilemap_draw( bitmap,cliprect, foreground2, 0, 0x3 );
+ tilemap_draw( bitmap,cliprect, foreground, 0, 0x3 );
+// sprite_draw(sprite_list,1);
+ if(sys18_fg2_active) tilemap_draw( bitmap,cliprect, foreground2, 1, 0x7 );
+ tilemap_draw( bitmap,cliprect, foreground, 1, 0x7 );
+
+ if (!strcmp(machine->gamedrv->name,"ddcrew")) update_system18_vdp(bitmap,cliprect); // kludge: render vdp here for ddcrew
+
+ tilemap_draw( bitmap,cliprect, text_layer, 1, 0x7 );
+// sprite_draw(sprite_list,0);
+ tilemap_draw( bitmap,cliprect, text_layer, 0, 0xf );
+
+ if (!strcmp(machine->gamedrv->name,"cltchitr")) update_system18_vdp(bitmap,cliprect); // kludge: render vdp here for clthitr, draws the ball in game!
+ if (!strcmp(machine->gamedrv->name,"cltchtrj")) update_system18_vdp(bitmap,cliprect); // kludge: render vdp here for clthitr, draws the ball in game!
+// if (!strcmp(machine->gamedrv->name,"astorm")) update_system18_vdp(bitmap,cliprect); // kludge: render vdp here for astorm
+
+ draw_sprites(machine, bitmap,cliprect, 0 );
+ return 0;
+}
diff --git a/src/mame/video/system24.c b/src/mame/video/system24.c
new file mode 100644
index 00000000000..8d12d8c1153
--- /dev/null
+++ b/src/mame/video/system24.c
@@ -0,0 +1,54 @@
+#include "driver.h"
+#include "video/segaic24.h"
+#include "includes/system24.h"
+
+VIDEO_START(system24)
+{
+ sys24_tile_vh_start(machine, 0xfff);
+ sys24_sprite_vh_start();
+ sys24_mixer_vh_start();
+}
+
+static int layer_cmp(const void *pl1, const void *pl2)
+{
+ static const int default_pri[12] = { 0, 1, 2, 3, 4, 5, 6, 7, -4, -3, -2, -1 };
+ int l1 = *(int *)pl1;
+ int l2 = *(int *)pl2;
+ int p1 = sys24_mixer_get_reg(l1) & 7;
+ int p2 = sys24_mixer_get_reg(l2) & 7;
+ if(p1 != p2)
+ return p1 - p2;
+ return default_pri[l2] - default_pri[l1];
+}
+
+VIDEO_UPDATE(system24)
+{
+ int i, level;
+ int order[12], spri[4];
+
+ if(sys24_mixer_get_reg(13) & 1) {
+ fillbitmap(bitmap, get_black_pen(machine), 0);
+ return 0;
+ }
+
+ sys24_tile_update(machine);
+
+ fillbitmap(priority_bitmap, 0, 0);
+ fillbitmap(bitmap, machine->pens[0], &machine->screen[0].visarea);
+
+ for(i=0; i<12; i++)
+ order[i] = i;
+ qsort(order, 12, sizeof(int), layer_cmp);
+
+ level = 0;
+ for(i=0; i<12; i++)
+ if(order[i] < 8)
+ sys24_tile_draw(machine, bitmap, cliprect, order[i], level, 0);
+ else {
+ spri[order[i]-8] = level;
+ level++;
+ }
+
+ sys24_sprite_draw(bitmap, cliprect, spri);
+ return 0;
+}
diff --git a/src/mame/video/tagteam.c b/src/mame/video/tagteam.c
new file mode 100644
index 00000000000..c0a011bcf6b
--- /dev/null
+++ b/src/mame/video/tagteam.c
@@ -0,0 +1,187 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static int palettebank;
+
+static tilemap *bg_tilemap;
+
+PALETTE_INIT( tagteam )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( tagteam_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( tagteam_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+READ8_HANDLER( tagteam_mirrorvideoram_r )
+{
+ int x,y;
+
+ /* swap x and y coordinates */
+ x = offset / 32;
+ y = offset % 32;
+ offset = 32 * y + x;
+
+ return videoram_r(offset);
+}
+
+READ8_HANDLER( tagteam_mirrorcolorram_r )
+{
+ int x,y;
+
+ /* swap x and y coordinates */
+ x = offset / 32;
+ y = offset % 32;
+ offset = 32 * y + x;
+
+ return colorram_r(offset);
+}
+
+WRITE8_HANDLER( tagteam_mirrorvideoram_w )
+{
+ int x,y;
+
+ /* swap x and y coordinates */
+ x = offset / 32;
+ y = offset % 32;
+ offset = 32 * y + x;
+
+ tagteam_videoram_w(offset,data);
+}
+
+WRITE8_HANDLER( tagteam_mirrorcolorram_w )
+{
+ int x,y;
+
+ /* swap x and y coordinates */
+ x = offset / 32;
+ y = offset % 32;
+ offset = 32 * y + x;
+
+ tagteam_colorram_w(offset,data);
+}
+
+WRITE8_HANDLER( tagteam_control_w )
+{
+logerror("%04x: control = %02x\n",activecpu_get_pc(),data);
+
+ /* bit 7 is the palette bank */
+ palettebank = (data & 0x80) >> 7;
+}
+
+WRITE8_HANDLER( tagteam_flipscreen_w )
+{
+ if (flip_screen != (data &0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index] + 256 * colorram[tile_index];
+ int color = palettebank * 2; // GUESS
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( tagteam )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows_flip_x,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0; offs < 0x20; offs += 4)
+ {
+ int spritebank = (videoram[offs] & 0x30) << 4;
+ int code = videoram[offs + 1] + 256 * spritebank;
+ int color = 1 + 2 * palettebank; // GUESS
+ int flipx = videoram[offs] & 0x04;
+ int flipy = videoram[offs] & 0x02;
+ int sx = 240 - videoram[offs + 3];
+ int sy = 240 - videoram[offs + 2];
+
+ if (!(videoram[offs] & 0x01)) continue;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1],
+ code, color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+
+ /* Wrap around */
+
+ code = videoram[offs + 0x20] + 256 * spritebank;
+ color = palettebank;
+ sy += (flip_screen ? -256 : 256);
+
+ drawgfx(bitmap, machine->gfx[1],
+ code, color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( tagteam )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/tail2nos.c b/src/mame/video/tail2nos.c
new file mode 100644
index 00000000000..261659890de
--- /dev/null
+++ b/src/mame/video/tail2nos.c
@@ -0,0 +1,214 @@
+#include "driver.h"
+#include "konamiic.h"
+
+
+UINT16 *tail2nos_bgvideoram;
+
+
+static tilemap *bg_tilemap;
+
+static int charbank,charpalette,video_enable;
+static UINT16 *zoomdata;
+static int dirtygfx;
+static UINT8 *dirtychar;
+
+#define TOTAL_CHARS 0x400
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT16 code = tail2nos_bgvideoram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ (code & 0x1fff) + (charbank << 13),
+ ((code & 0xe000) >> 13) + charpalette * 16,
+ 0);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051316
+
+***************************************************************************/
+
+static void zoom_callback(int *code,int *color,int *flags)
+{
+ *code |= ((*color & 0x03) << 8);
+ *color = 32 + ((*color & 0x38) >> 3);
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( tail2nos )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ K051316_vh_start_0(machine,REGION_GFX3,4,TRUE,0,zoom_callback);
+
+ dirtychar = auto_malloc(TOTAL_CHARS);
+ memset(dirtychar,1,TOTAL_CHARS);
+
+ tilemap_set_transparent_pen(bg_tilemap,15);
+
+ K051316_wraparound_enable(0,1);
+ K051316_set_offset(0,-89,-14);
+ zoomdata = (UINT16 *)memory_region(REGION_GFX3);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( tail2nos_bgvideoram_w )
+{
+ COMBINE_DATA(&tail2nos_bgvideoram[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+READ16_HANDLER( tail2nos_zoomdata_r )
+{
+ return zoomdata[offset];
+}
+
+WRITE16_HANDLER( tail2nos_zoomdata_w )
+{
+ int oldword = zoomdata[offset];
+ COMBINE_DATA(&zoomdata[offset]);
+ if (oldword != zoomdata[offset])
+ {
+ dirtygfx = 1;
+ dirtychar[offset / 64] = 1;
+ }
+}
+
+WRITE16_HANDLER( tail2nos_gfxbank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ int bank;
+
+ /* bits 0 and 2 select char bank */
+ if (data & 0x04) bank = 2;
+ else if (data & 0x01) bank = 1;
+ else bank = 0;
+
+ if (charbank != bank)
+ {
+ charbank = bank;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ /* bit 5 seems to select palette bank (used on startup) */
+ if (data & 0x20) bank = 7;
+ else bank = 3;
+
+ if (charpalette != bank)
+ {
+ charpalette = bank;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ /* bit 4 seems to be video enable */
+ video_enable = data & 0x10;
+ }
+}
+
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+
+ for (offs = 0;offs < spriteram_size/2;offs += 4)
+ {
+ int sx,sy,flipx,flipy,code,color;
+
+ sx = spriteram16[offs + 1];
+ if (sx >= 0x8000) sx -= 0x10000;
+ sy = 0x10000 - spriteram16[offs + 0];
+ if (sy >= 0x8000) sy -= 0x10000;
+ code = spriteram16[offs + 2] & 0x07ff;
+ color = (spriteram16[offs + 2] & 0xe000) >> 13;
+ flipx = spriteram16[offs + 2] & 0x1000;
+ flipy = spriteram16[offs + 2] & 0x0800;
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ 40 + color,
+ flipx,flipy,
+ sx+3,sy+1, /* placement relative to zoom layer verified on the real thing */
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+}
+
+VIDEO_UPDATE( tail2nos )
+{
+ static const gfx_layout tilelayout =
+ {
+ 16,16,
+ TOTAL_CHARS,
+ 4,
+ { 0, 1, 2, 3 },
+#ifdef LSB_FIRST
+ { 2*4, 3*4, 0*4, 1*4, 6*4, 7*4, 4*4, 5*4,
+ 10*4, 11*4, 8*4, 9*4, 14*4, 15*4, 12*4, 13*4 },
+#else
+ { 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4,
+ 8*4, 9*4, 10*4, 11*4, 12*4, 13*4, 14*4, 15*4 },
+#endif
+ { 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64,
+ 8*64, 9*64, 10*64, 11*64, 12*64, 13*64, 14*64, 15*64 },
+ 128*8
+ };
+
+
+ if (dirtygfx)
+ {
+ int i;
+
+ dirtygfx = 0;
+
+ for (i = 0;i < TOTAL_CHARS;i++)
+ {
+ if (dirtychar[i])
+ {
+ dirtychar[i] = 0;
+ decodechar(machine->gfx[2],i,(UINT8 *)zoomdata,&tilelayout);
+ }
+ }
+
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+
+ if (video_enable)
+ {
+ K051316_zoom_draw_0(bitmap,cliprect,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ }
+ else
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ return 0;
+}
diff --git a/src/mame/video/taito_b.c b/src/mame/video/taito_b.c
new file mode 100644
index 00000000000..d29bf4a6c8b
--- /dev/null
+++ b/src/mame/video/taito_b.c
@@ -0,0 +1,635 @@
+#include "driver.h"
+#include "profiler.h"
+
+UINT16 *taitob_scroll;
+UINT16 *TC0180VCU_ram;
+UINT16 *taitob_spriteram;
+UINT16 *taitob_pixelram;
+
+static tilemap *bg_tilemap, *fg_tilemap, *tx_tilemap;
+static UINT16 bg_rambank[2],fg_rambank[2],tx_rambank;
+
+/* framebuffer is a raw bitmap, remapped as a last step */
+static mame_bitmap *framebuffer[2],*pixel_bitmap;
+
+static UINT16 pixel_scroll[2];
+
+static UINT8 framebuffer_page;
+
+static int b_bg_color_base = 0;
+static int b_fg_color_base = 0;
+static int b_sp_color_base = 0;
+static int b_tx_color_base = 0;
+
+
+static UINT8 video_control = 0;
+static UINT16 TC0180VCU_ctrl[0x10] = {0};
+
+/* TC0180VCU control registers:
+* offset:
+* 0 - -----xxx bg ram page 0 (tile codes)
+* -xxx---- bg ram page 1 (attributes)
+* 1 - -----xxx fg ram page 0 (tile codes)
+* -xxx---- fg ram page 1 (attributes)
+* 2 - xxxxxxxx number of independent foreground scrolling blocks (see below)
+* 3 - xxxxxxxx number of independent background scrolling blocks
+* 4 - --xxxxxx text tile bank 0
+* 5 - --xxxxxx text tile bank 1
+* 6 - ----xxxx text ram page
+* 7 - xxxxxxxx video control: pixelram page and enable, screen flip, sprite to foreground priority (see below)
+* 8 to f - unused (always zero)
+*
+******************************************************************************************
+*
+* offset 6 - text video page register:
+* This location controls which page of video text ram to view
+* hitice:
+* 0x08 (00001000) - show game text: credits XX, player1 score
+* 0x09 (00001001) - show FBI logo
+* rambo3:
+* 0x08 (00001000) - show game text
+* 0x09 (00001001) - show taito logo
+* 0x0a (00001010) - used in pair with 0x09 to smooth screen transitions (attract mode)
+*
+* Is bit 3 (0x08) video text enable/disable ?
+*
+******************************************************************************************
+*
+* offset 7 - video control register:
+* bit 0 (0x01) 1 = don't erase sprite frame buffer "after the beam"
+* bit 3 (0x08) sprite to foreground priority
+* 1 = bg, fg, obj, tx
+* 0 = bg, obj1, fg, obj0, tx (obj0/obj1 selected by bit 0 of color code)
+* bit 4 (0x10) screen flip (active HI) (this one is for sure)
+* bit 5 (0x20) could be global video enable switch (Hit the Ice clears this
+* bit, clears videoram portions and sets this bit)
+* bit 6 (0x40) frame buffer page to show when bit 7 is set
+* bit 7 (0x80) don't flip frame buffer every vblank, use the page selected by bit 6
+*
+*/
+
+static void taitob_video_control (UINT8 data)
+{
+#if 0
+ if (data != video_control)
+ popmessage("video control = %02x",data);
+#endif
+
+ video_control = data;
+
+ if (video_control & 0x80)
+ framebuffer_page = (~video_control & 0x40) >> 6;
+
+ tilemap_set_flip(ALL_TILEMAPS, (video_control & 0x10) ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0 );
+}
+
+
+READ16_HANDLER( taitob_v_control_r )
+{
+ return (TC0180VCU_ctrl[offset]);
+}
+
+WRITE16_HANDLER( taitob_v_control_w )
+{
+ UINT16 oldword = TC0180VCU_ctrl[offset];
+
+ COMBINE_DATA (&TC0180VCU_ctrl[offset]);
+
+ if (ACCESSING_MSB)
+ {
+ switch(offset)
+ {
+ case 0:
+ if (oldword != TC0180VCU_ctrl[offset])
+ {
+ tilemap_mark_all_tiles_dirty(fg_tilemap);
+ fg_rambank[0] = (((TC0180VCU_ctrl[offset]>>8)&0x0f)<<12);
+ fg_rambank[1] = (((TC0180VCU_ctrl[offset]>>12)&0x0f)<<12);
+ }
+ break;
+ case 1:
+ if (oldword != TC0180VCU_ctrl[offset])
+ {
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ bg_rambank[0] = (((TC0180VCU_ctrl[offset]>>8)&0x0f)<<12);
+ bg_rambank[1] = (((TC0180VCU_ctrl[offset]>>12)&0x0f)<<12);
+ }
+ break;
+ case 4:
+ case 5:
+ if (oldword != TC0180VCU_ctrl[offset])
+ tilemap_mark_all_tiles_dirty(tx_tilemap);
+ break;
+ case 6:
+ if (oldword != TC0180VCU_ctrl[offset])
+ {
+ tilemap_mark_all_tiles_dirty(tx_tilemap);
+ tx_rambank = (((TC0180VCU_ctrl[offset]>>8)&0x0f)<<11);
+ }
+ break;
+ case 7:
+ taitob_video_control( (TC0180VCU_ctrl[offset]>>8) & 0xff );
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+WRITE16_HANDLER( hitice_pixelram_w )
+{
+ int sy = offset >> 9;
+ int sx = offset & 0x1ff;
+
+ COMBINE_DATA(&taitob_pixelram[offset]);
+
+ if (ACCESSING_LSB)
+ {
+ /* bit 15 of pixel_scroll[0] is probably flip screen */
+
+ *BITMAP_ADDR16(pixel_bitmap, sy, 2*sx+0) = Machine->pens[b_fg_color_base * 16 + (data & 0xff)];
+ *BITMAP_ADDR16(pixel_bitmap, sy, 2*sx+1) = Machine->pens[b_fg_color_base * 16 + (data & 0xff)];
+ }
+}
+
+WRITE16_HANDLER( hitice_pixel_scroll_w )
+{
+ COMBINE_DATA(&pixel_scroll[offset]);
+}
+
+static void hitice_clear_pixel_bitmap(void)
+{
+ int i;
+
+ for (i = 0;i < 0x40000;i++)
+ hitice_pixelram_w(i,0,0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int tile = TC0180VCU_ram[tile_index + bg_rambank[0]];
+ int color = TC0180VCU_ram[tile_index + bg_rambank[1]];
+
+ SET_TILE_INFO(
+ 1,
+ tile,
+ b_bg_color_base + (color&0x3f),
+ TILE_FLIPYX((color & 0x00c0)>>6));
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int tile = TC0180VCU_ram[tile_index + fg_rambank[0]];
+ int color = TC0180VCU_ram[tile_index + fg_rambank[1]];
+
+ SET_TILE_INFO(
+ 1,
+ tile,
+ b_fg_color_base + (color&0x3f),
+ TILE_FLIPYX((color & 0x00c0)>>6));
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int tile = TC0180VCU_ram[tile_index + tx_rambank];
+
+ SET_TILE_INFO(
+ 0,
+ (tile & 0x07ff) | ((TC0180VCU_ctrl[4 + ((tile & 0x800) >> 11)]>>8) << 11),
+ b_tx_color_base + ((tile >> 12) & 0x0f),
+ 0);
+}
+
+
+static VIDEO_START( taitob_core )
+{
+ framebuffer[0] = auto_bitmap_alloc(512,256,machine->screen[0].format);
+ framebuffer[1] = auto_bitmap_alloc(512,256,machine->screen[0].format);
+ pixel_bitmap = NULL; /* only hitice needs this */
+
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,64,64);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_transparent_pen(tx_tilemap,0);
+
+ tilemap_set_scrolldx(bg_tilemap,0,24*8);
+ tilemap_set_scrolldx(fg_tilemap,0,24*8);
+ tilemap_set_scrolldx(tx_tilemap,0,24*8);
+
+
+ state_save_register_global_array(bg_rambank);
+ state_save_register_global_array(fg_rambank);
+ state_save_register_global(tx_rambank);
+
+ state_save_register_global_array(pixel_scroll);
+ state_save_register_global(framebuffer_page);
+
+ state_save_register_global(video_control);
+ state_save_register_global_array(TC0180VCU_ctrl);
+
+ state_save_register_global_bitmap(framebuffer[0]);
+ state_save_register_global_bitmap(framebuffer[1]);
+}
+
+VIDEO_START( taitob_color_order0 )
+{
+ /*graphics are shared, only that they use different palette*/
+ /*this is the basic layout used in: Nastar, Ashura Blaster, Hit the Ice, Rambo3, Tetris*/
+
+ /*Note that in both this and color order 1
+ * pixel_color_base/color_granularity is equal to sprites color base.
+ * Pure coincidence ?*/
+
+ b_bg_color_base = 0xc0; /*background*/
+ b_fg_color_base = 0x80; /*foreground*/
+ b_sp_color_base = 0x40*16; /*sprites */
+ b_tx_color_base = 0x00; /*text */
+
+ video_start_taitob_core(machine);
+}
+
+VIDEO_START( taitob_color_order1 )
+{
+ /*and this is the reversed layout used in: Crime City, Puzzle Bobble*/
+ b_bg_color_base = 0x00;
+ b_fg_color_base = 0x40;
+ b_sp_color_base = 0x80*16;
+ b_tx_color_base = 0xc0;
+
+ video_start_taitob_core(machine);
+}
+
+VIDEO_START( taitob_color_order2 )
+{
+ /*this is used in: rambo3a, masterw, silentd, selfeena, ryujin */
+ b_bg_color_base = 0x30;
+ b_fg_color_base = 0x20;
+ b_sp_color_base = 0x10*16;
+ b_tx_color_base = 0x00;
+
+ video_start_taitob_core(machine);
+}
+
+
+VIDEO_START( hitice )
+{
+ video_start_taitob_color_order0(machine);
+
+ pixel_bitmap = auto_bitmap_alloc(1024,512,machine->screen[0].format);
+
+ state_save_register_global_bitmap(pixel_bitmap);
+}
+
+VIDEO_RESET( hitice )
+{
+ /* kludge: clear the bitmap on startup */
+ hitice_clear_pixel_bitmap();
+}
+
+
+READ16_HANDLER( TC0180VCU_word_r )
+{
+ return TC0180VCU_ram[offset];
+}
+
+WRITE16_HANDLER( TC0180VCU_word_w )
+{
+ COMBINE_DATA(&TC0180VCU_ram[offset]);
+
+ if ((offset & 0x7000) == fg_rambank[0] || (offset & 0x7000) == fg_rambank[1])
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x0fff);
+ if ((offset & 0x7000) == bg_rambank[0] || (offset & 0x7000) == bg_rambank[1])
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x0fff);
+ if ((offset & 0x7800) == tx_rambank)
+ tilemap_mark_tile_dirty(tx_tilemap,offset & 0x7ff);
+}
+
+READ16_HANDLER( TC0180VCU_framebuffer_word_r )
+{
+ int sy = offset >> 8;
+ int sx = 2*(offset & 0xff);
+
+ return (*BITMAP_ADDR16(framebuffer[sy >> 8], sy & 0xff, sx + 0) << 8) |
+ *BITMAP_ADDR16(framebuffer[sy >> 8], sy & 0xff, sx + 1);
+}
+
+WRITE16_HANDLER( TC0180VCU_framebuffer_word_w )
+{
+ int sy = offset >> 8;
+ int sx = 2*(offset & 0xff);
+
+ if (ACCESSING_MSB)
+ *BITMAP_ADDR16(framebuffer[sy >> 8], sy & 0xff, sx + 0) = data >> 8;
+ if (ACCESSING_LSB)
+ *BITMAP_ADDR16(framebuffer[sy >> 8], sy & 0xff, sx + 1) = data & 0xff;
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+/* Sprite format: (16 bytes per sprite)
+ offs: bits:
+ 0000: 0xxxxxxxxxxxxxxx: tile code - 0x0000 to 0x7fff in qzshowby
+ 0002: 0000000000xxxxxx: color (0x00 - 0x3f)
+ x000000000000000: flipy
+ 0x00000000000000: flipx
+ 00????????000000: unused ?
+ 0004: xxxxxx0000000000: doesn't matter - some games (eg nastar) fill this with sign bit, some (eg ashura) do not
+ 000000xxxxxxxxxx: x-coordinate 10 bits signed (all zero for sprites forming up a big sprite, except for the first one)
+ 0006: xxxxxx0000000000: doesn't matter - same as x
+ 000000xxxxxxxxxx: y-coordinate 10 bits signed (same as x)
+ 0008: xxxxxxxx00000000: sprite x-zoom level
+ 00000000xxxxxxxx: sprite y-zoom level
+ 0x00 - non scaled = 100%
+ 0x80 - scaled to 50%
+ 0xc0 - scaled to 25%
+ 0xe0 - scaled to 12.5%
+ 0xff - scaled to zero pixels size (off)
+ Sprite zoom is used in Ashura Blaster just in the beginning
+ where you can see a big choplifter and a japanese title.
+ This japanese title is a scaled sprite.
+ It is used in Crime City also at the end of the third level (in the garage)
+ where there are four columns on the sides of the screen
+ Heaviest usage is in Rambo 3 - almost every sprite in game is scaled
+ 000a: xxxxxxxx00000000: x-sprites number (big sprite) decremented by one
+ 00000000xxxxxxxx: y-sprites number (big sprite) decremented by one
+ 000c - 000f: unused
+*/
+
+ int x,y,xlatch=0,ylatch=0,x_no=0,y_no=0,x_num=0,y_num=0,big_sprite=0;
+ int offs,code,color,flipx,flipy;
+ UINT32 data, zoomx, zoomy, zx, zy, zoomxlatch=0, zoomylatch=0;
+
+ for (offs = (0x1980-16)/2; offs >=0; offs -= 8)
+ {
+ code = taitob_spriteram[offs];
+
+ color = taitob_spriteram[offs+1];
+ flipx = color & 0x4000;
+ flipy = color & 0x8000;
+#if 0
+/*check the unknown bits*/
+ if (color & 0x3fc0){
+ logerror("sprite color (taitob)=%4x ofs=%4x\n",color,offs);
+ color = rand()&0x3f;
+ }
+#endif
+ color = (color & 0x3f) * 16;
+
+ x = taitob_spriteram[offs+2] & 0x3ff;
+ y = taitob_spriteram[offs+3] & 0x3ff;
+ if (x >= 0x200) x -= 0x400;
+ if (y >= 0x200) y -= 0x400;
+
+ data = taitob_spriteram[offs+5];
+ if (data)
+ {
+ if (!big_sprite)
+ {
+ x_num = (data>>8) & 0xff;
+ y_num = (data) & 0xff;
+ x_no = 0;
+ y_no = 0;
+ xlatch = x;
+ ylatch = y;
+ data = taitob_spriteram[offs+4];
+ zoomxlatch = (data>>8) & 0xff;
+ zoomylatch = (data) & 0xff;
+ big_sprite = 1;
+ }
+ }
+
+ data = taitob_spriteram[offs+4];
+ zoomx = (data>>8) & 0xff;
+ zoomy = (data) & 0xff;
+ zx = (0x100 - zoomx) / 16;
+ zy = (0x100 - zoomy) / 16;
+
+ if (big_sprite)
+ {
+ zoomx = zoomxlatch;
+ zoomy = zoomylatch;
+
+ x = xlatch + x_no * (0x100 - zoomx) / 16;
+ y = ylatch + y_no * (0x100 - zoomy) / 16;
+ zx = xlatch + (x_no+1) * (0x100 - zoomx) / 16 - x;
+ zy = ylatch + (y_no+1) * (0x100 - zoomy) / 16 - y;
+ y_no++;
+ if (y_no>y_num)
+ {
+ y_no = 0;
+ x_no++;
+ if (x_no>x_num)
+ big_sprite = 0;
+ }
+ }
+
+ if ( zoomx || zoomy )
+ {
+ drawgfxzoom (bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ x,y,
+ cliprect,
+ TRANSPARENCY_PEN_RAW,0,(zx << 16) / 16,(zy << 16) / 16);
+ }
+ else
+ {
+ drawgfx (bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ x,y,
+ cliprect,
+ TRANSPARENCY_PEN_RAW,0);
+ }
+ }
+}
+
+
+static void TC0180VCU_tilemap_draw(mame_bitmap *bitmap,const rectangle *cliprect,tilemap *tmap,int plane)
+{
+/*plane = 0 fg tilemap*/
+/*plane = 1 bg tilemap*/
+ rectangle my_clip;
+ int i;
+ int scrollx, scrolly;
+ int lines_per_block; /* number of lines scrolled by the same amount (per one scroll value) */
+ int number_of_blocks; /* number of such blocks per _screen_ (256 lines) */
+
+ lines_per_block = 256 - (TC0180VCU_ctrl[2 + plane] >> 8);
+ number_of_blocks = 256 / lines_per_block;
+
+
+ my_clip.min_x = cliprect->min_x;
+ my_clip.max_x = cliprect->max_x;
+
+ for (i = 0;i < number_of_blocks;i++)
+ {
+ scrollx = taitob_scroll[ plane*0x200 + i*2*lines_per_block ];
+ scrolly = taitob_scroll[ plane*0x200 + i*2*lines_per_block+1 ];
+
+ my_clip.min_y = i*lines_per_block;
+ my_clip.max_y = (i+1)*lines_per_block -1;
+ if (video_control&0x10) /*flip screen*/
+ {
+ my_clip.min_y = bitmap->height - 1 - (i+1)*lines_per_block -1;
+ my_clip.max_y = bitmap->height - 1 - i*lines_per_block;
+ }
+ sect_rect(&my_clip, cliprect);
+
+ if (my_clip.min_y <= my_clip.max_y)
+ {
+ tilemap_set_scrollx(tmap,0,-scrollx);
+ tilemap_set_scrolly(tmap,0,-scrolly);
+ tilemap_draw(bitmap,&my_clip,tmap,0,0);
+ }
+ }
+}
+
+
+static void draw_framebuffer(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int priority)
+{
+ rectangle myclip = *cliprect;
+ int x,y;
+
+profiler_mark(PROFILER_USER1);
+
+ priority <<= 4;
+
+
+ if (video_control & 0x08)
+ {
+ if (priority) return;
+
+ if (video_control & 0x10) /*flip screen*/
+ {
+ /*popmessage("1. X[%3i;%3i] Y[%3i;%3i]", myclip.min_x, myclip.max_x, myclip.min_y, myclip.max_y);*/
+ for (y = myclip.min_y;y <= myclip.max_y;y++)
+ {
+ UINT16 *src = BITMAP_ADDR16(framebuffer[framebuffer_page], y, myclip.min_x);
+ UINT16 *dst;
+
+ dst = BITMAP_ADDR16(bitmap, bitmap->height-1-y, myclip.max_x);
+
+ for (x = myclip.min_x;x <= myclip.max_x;x++)
+ {
+ UINT16 c = *src++;
+
+ if (c != 0)
+ *dst = machine->pens[b_sp_color_base + c];
+
+ dst--;
+ }
+ }
+ }
+ else
+ {
+ for (y = myclip.min_y;y <= myclip.max_y;y++)
+ {
+ UINT16 *src = BITMAP_ADDR16(framebuffer[framebuffer_page], y, myclip.min_x);
+ UINT16 *dst = BITMAP_ADDR16(bitmap, y, myclip.min_x);
+
+ for (x = myclip.min_x;x <= myclip.max_x;x++)
+ {
+ UINT16 c = *src++;
+
+ if (c != 0)
+ *dst = machine->pens[b_sp_color_base + c];
+
+ dst++;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (video_control & 0x10) /*flip screen*/
+ {
+ /*popmessage("3. X[%3i;%3i] Y[%3i;%3i]", myclip.min_x, myclip.max_x, myclip.min_y, myclip.max_y);*/
+ for (y = myclip.min_y;y <= myclip.max_y;y++)
+ {
+ UINT16 *src = BITMAP_ADDR16(framebuffer[framebuffer_page], y, myclip.min_x);
+ UINT16 *dst;
+
+ dst = BITMAP_ADDR16(bitmap, bitmap->height-1-y, myclip.max_x);
+
+ for (x = myclip.min_x;x <= myclip.max_x;x++)
+ {
+ UINT16 c = *src++;
+
+ if (c != 0 && (c & 0x10) == priority)
+ *dst = machine->pens[b_sp_color_base + c];
+
+ dst--;
+ }
+ }
+ }
+ else
+ {
+ for (y = myclip.min_y;y <= myclip.max_y;y++)
+ {
+ UINT16 *src = BITMAP_ADDR16(framebuffer[framebuffer_page], y, myclip.min_x);
+ UINT16 *dst = BITMAP_ADDR16(bitmap, y, myclip.min_x);
+
+ for (x = myclip.min_x;x <= myclip.max_x;x++)
+ {
+ UINT16 c = *src++;
+
+ if (c != 0 && (c & 0x10) == priority)
+ *dst = machine->pens[b_sp_color_base + c];
+
+ dst++;
+ }
+ }
+ }
+ }
+profiler_mark(PROFILER_END);
+}
+
+VIDEO_UPDATE( taitob )
+{
+ if ((video_control & 0x20) == 0)
+ {
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ return 0;
+ }
+
+ /* Draw playfields */
+ TC0180VCU_tilemap_draw(bitmap,cliprect,bg_tilemap,1);
+
+ draw_framebuffer(machine, bitmap,cliprect,1);
+
+ TC0180VCU_tilemap_draw(bitmap,cliprect,fg_tilemap,0);
+
+ if (pixel_bitmap) /* hitice only */
+ {
+ int scrollx = -2*pixel_scroll[0]; //+320;
+ int scrolly = -pixel_scroll[1]; //+240;
+ /* bit 15 of pixel_scroll[0] is probably flip screen */
+
+ copyscrollbitmap(bitmap,pixel_bitmap,1,&scrollx,1,&scrolly,cliprect,TRANSPARENCY_COLOR,b_fg_color_base * 16);
+ }
+
+ draw_framebuffer(machine, bitmap,cliprect,0);
+
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+
+
+VIDEO_EOF( taitob )
+{
+ if (~video_control & 0x01)
+ fillbitmap(framebuffer[framebuffer_page],0,&machine->screen[0].visarea);
+
+ if (~video_control & 0x80)
+ framebuffer_page ^= 1;
+
+ draw_sprites(machine, framebuffer[framebuffer_page],&machine->screen[0].visarea);
+}
+
diff --git a/src/mame/video/taito_f2.c b/src/mame/video/taito_f2.c
new file mode 100644
index 00000000000..324d6989e15
--- /dev/null
+++ b/src/mame/video/taito_f2.c
@@ -0,0 +1,1442 @@
+#include "driver.h"
+#include "video/taitoic.h"
+#include "includes/taito_f2.h"
+
+#define TC0100SCN_GFX_NUM 1
+#define TC0480SCP_GFX_NUM 1
+#define TC0280GRD_GFX_NUM 2
+#define TC0430GRW_GFX_NUM 2
+
+extern UINT8 TC0360PRI_regs[16];
+
+struct tempsprite
+{
+ int code,color;
+ int flipx,flipy;
+ int x,y;
+ int zoomx,zoomy;
+ int primask;
+};
+static struct tempsprite *spritelist;
+
+static UINT16 *spriteram_buffered,*spriteram_delayed;
+
+
+/************************************************************
+ SPRITE BANKING
+
+ Four sprite banking methods are used for games with more
+ than $2000 sprite tiles, because the sprite ram only has
+ 13 bits available for tile numbers.
+
+ 0 = standard (only a limited selection of sprites are
+ available for display at a given time)
+ 1 = use sprite extension area lo bytes for hi 6 bits
+ 2 = use sprite extension area hi bytes
+ 3 = use sprite extension area lo bytes as hi bytes
+ (sprite extension areas mean all sprite
+ tiles are always accessible)
+************************************************************/
+
+int f2_sprite_type = 0;
+UINT16 *f2_sprite_extension;
+size_t f2_spriteext_size;
+
+static UINT16 spritebank[8];
+//static UINT16 spritebank_eof[8];
+static UINT16 spritebank_buffered[8];
+static UINT16 koshien_spritebank;
+
+static INT32 sprites_disabled,sprites_active_area,sprites_master_scrollx,sprites_master_scrolly;
+/* remember flip status over frames because driftout can fail to set it */
+static INT32 sprites_flipscreen = 0;
+
+
+/* On the left hand screen edge (assuming horiz screen, no
+ screenflip: in screenflip it is the right hand edge etc.)
+ there may be 0-3 unwanted pixels in both tilemaps *and*
+ sprites. To erase this we use f2_hide_pixels (0 to +3). */
+
+static INT32 f2_hide_pixels;
+static INT32 f2_flip_hide_pixels; /* Different in some games */
+
+static INT32 f2_pivot_xdisp = 0; /* Needed in games with a pivot layer */
+static INT32 f2_pivot_ydisp = 0;
+
+static INT32 f2_tilemap_xoffs = 0; /* Needed in TC0480SCP games */
+static INT32 f2_tilemap_yoffs = 0;
+static INT32 f2_text_xoffs = 0;
+
+int f2_tilemap_col_base = 0;
+
+static INT32 f2_game = 0;
+static INT32 FOOTCHMP = 1;
+
+static UINT8 f2_tilepri[6]; // todo - move into taitoic.c
+static UINT8 f2_spritepri[6]; // todo - move into taitoic.c
+static UINT8 f2_spriteblendmode; // todo - move into taitoic.c
+
+/***********************************************************************************/
+
+static void taitof2_core_vh_start (running_machine *machine, int sprite_type,int hide,int flip_hide,int x_offs,int y_offs,
+ int flip_xoffs,int flip_yoffs,int flip_text_x_offs,int flip_text_yoffs)
+{
+ int i,chips;
+ f2_sprite_type = sprite_type;
+ f2_hide_pixels = hide;
+ f2_flip_hide_pixels = flip_hide;
+
+ spriteram_delayed = auto_malloc(spriteram_size);
+ spriteram_buffered = auto_malloc(spriteram_size);
+ spritelist = auto_malloc(0x400 * sizeof(*spritelist));
+
+ chips = number_of_TC0100SCN();
+
+ assert_always(chips >= 0, "erroneous TC0100SCN configuratiom");
+
+ if (has_TC0480SCP()) /* it's a tc0480scp game */
+ {
+ TC0480SCP_vh_start(machine,TC0480SCP_GFX_NUM,f2_hide_pixels,f2_tilemap_xoffs,
+ f2_tilemap_yoffs,f2_text_xoffs,0,-1,0,f2_tilemap_col_base);
+ }
+ else /* it's a tc0100scn game */
+ {
+ TC0100SCN_vh_start(machine,chips,TC0100SCN_GFX_NUM,f2_hide_pixels,0,
+ flip_xoffs,flip_yoffs,flip_text_x_offs,flip_text_yoffs,TC0100SCN_SINGLE_VDU);
+ }
+
+ if (has_TC0110PCR())
+ TC0110PCR_vh_start();
+
+ if (has_TC0280GRD())
+ TC0280GRD_vh_start(TC0280GRD_GFX_NUM);
+
+ if (has_TC0430GRW())
+ TC0430GRW_vh_start(TC0430GRW_GFX_NUM);
+
+ if (has_TC0360PRI())
+ TC0360PRI_vh_start(); /* Purely for save-state purposes */
+
+ for (i = 0; i < 8; i ++)
+ {
+ spritebank_buffered[i] = 0x400 * i;
+ spritebank[i] = spritebank_buffered[i];
+ }
+
+ sprites_disabled = 1;
+ sprites_active_area = 0;
+
+ f2_game = 0; /* means NOT footchmp */
+
+ state_save_register_global(f2_hide_pixels);
+ state_save_register_global(f2_sprite_type);
+ state_save_register_global_array(spritebank);
+ state_save_register_global(koshien_spritebank);
+ state_save_register_global(sprites_disabled);
+ state_save_register_global(sprites_active_area);
+ state_save_register_global_pointer(spriteram_delayed, spriteram_size/2);
+ state_save_register_global_pointer(spriteram_buffered, spriteram_size/2);
+}
+
+
+/**************************************************************************************/
+/* ( spritetype, hide, hideflip, xoffs, yoffs, flipx, flipy, textflipx, textflipy) */
+/**************************************************************************************/
+
+VIDEO_START( taitof2_default )
+{
+ taitof2_core_vh_start(machine, 0,0,0,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_megab ) /* Megab, Liquidk */
+{
+ taitof2_core_vh_start(machine, 0,3,3,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_quiz ) /* Quiz Crayons, Quiz Jinsei */
+{
+ taitof2_core_vh_start(machine, 3,3,3,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_finalb )
+{
+ taitof2_core_vh_start(machine, 0,1,1,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_ssi )
+{
+ taitof2_core_vh_start(machine, 0,3,3,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_growl )
+{
+ taitof2_core_vh_start(machine, 0,3,3,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_ninjak )
+{
+ taitof2_core_vh_start(machine, 0,0,0,0,0,0,0,1,2);
+}
+
+VIDEO_START( taitof2_qzchikyu )
+{
+ taitof2_core_vh_start(machine, 0,0,4,0,0,-4,0,-11,0);
+}
+
+VIDEO_START( taitof2_solfigtr )
+{
+ taitof2_core_vh_start(machine, 0,3,-3,0,0,6,0,6,0);
+}
+
+VIDEO_START( taitof2_koshien )
+{
+ taitof2_core_vh_start(machine, 0,1,-1,0,0,2,0,0,0);
+}
+
+VIDEO_START( taitof2_gunfront )
+{
+ taitof2_core_vh_start(machine, 0,3,3,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_thundfox )
+{
+ taitof2_core_vh_start(machine, 0,3,-3,0,0,5,0,4,1);
+}
+
+VIDEO_START( taitof2_mjnquest )
+{
+ taitof2_core_vh_start(machine, 0,0,0,0,0,0,0,0,0);
+ TC0100SCN_set_bg_tilemask(0x7fff);
+}
+
+VIDEO_START( taitof2_footchmp )
+{
+ f2_tilemap_xoffs = 0x1d;
+ f2_tilemap_yoffs = 0x08;
+ f2_text_xoffs = -1;
+ f2_tilemap_col_base = 0;
+ taitof2_core_vh_start(machine, 0,3,3,0,0,0,0,0,0);
+
+ f2_game = FOOTCHMP;
+}
+
+VIDEO_START( taitof2_hthero )
+{
+ f2_tilemap_xoffs = 0x33;
+ f2_tilemap_yoffs = - 0x04;
+ f2_text_xoffs = -1;
+ f2_tilemap_col_base = 0;
+ taitof2_core_vh_start(machine, 0,3,3,0,0,0,0,0,0);
+
+ f2_game = FOOTCHMP;
+}
+
+VIDEO_START( taitof2_deadconx )
+{
+ f2_tilemap_xoffs = 0x1e;
+ f2_tilemap_yoffs = 0x08;
+ f2_text_xoffs = -1;
+ f2_tilemap_col_base = 0;
+ taitof2_core_vh_start(machine, 0,3,3,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_deadconj )
+{
+ f2_tilemap_xoffs = 0x34;
+ f2_tilemap_yoffs = - 0x05;
+ f2_text_xoffs = -1;
+ f2_tilemap_col_base = 0;
+ taitof2_core_vh_start(machine, 0,3,3,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_metalb )
+{
+ f2_tilemap_xoffs = 0x32;
+ f2_tilemap_yoffs = - 0x04;
+ f2_text_xoffs = 1; /* not the usual -1 */
+ f2_tilemap_col_base = 256; /* separate palette area for tilemaps */
+ taitof2_core_vh_start(machine, 0,3,3,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_yuyugogo )
+{
+ taitof2_core_vh_start(machine, 1,3,3,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_yesnoj )
+{
+ taitof2_core_vh_start(machine, 0,3,3,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_dinorex )
+{
+ taitof2_core_vh_start(machine, 3,3,3,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_dondokod ) /* dondokod, cameltry */
+{
+ f2_pivot_xdisp = -16;
+ f2_pivot_ydisp = 0;
+ taitof2_core_vh_start(machine, 0,3,3,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_pulirula )
+{
+ f2_pivot_xdisp = -10; /* alignment seems correct (see level 2, falling */
+ f2_pivot_ydisp = 16; /* block of ice after armour man) */
+ taitof2_core_vh_start(machine, 2,3,3,0,0,0,0,0,0);
+}
+
+VIDEO_START( taitof2_driftout )
+{
+ f2_pivot_xdisp = -16;
+ f2_pivot_ydisp = 16;
+ taitof2_core_vh_start(machine, 0,3,3,0,0,0,0,0,0);
+}
+
+
+/********************************************************
+ SPRITE READ AND WRITE HANDLERS
+
+The spritebank buffering is currently not needed.
+
+If we wanted to buffer sprites by an extra frame, it
+might be for Footchmp. That seems to be the only game
+altering spritebanks of sprites while they're on screen.
+********************************************************/
+
+WRITE16_HANDLER( taitof2_sprite_extension_w )
+{
+ /* areas above 0x1000 cleared in some games, but not used */
+
+ if (offset < 0x800)
+ {
+ COMBINE_DATA(&f2_sprite_extension[offset]);
+ }
+}
+
+
+WRITE16_HANDLER( taitof2_spritebank_w )
+{
+ int i=0;
+ int j=0;
+
+ if (offset < 2) return; /* irrelevant zero writes */
+
+ if (offset < 4) /* special bank pairs */
+ {
+ j = (offset & 1) << 1; /* either set pair 0&1 or 2&3 */
+ i = data << 11;
+ spritebank_buffered[j] = i;
+ spritebank_buffered[j+1] = (i + 0x400);
+
+//logerror("bank %d, set to: %04x\n", j, i);
+//logerror("bank %d, paired so: %04x\n", j + 1, i + 0x400);
+
+ }
+ else /* last 4 are individual banks */
+ {
+ i = data << 10;
+ spritebank_buffered[offset] = i;
+
+//logerror("bank %d, new value: %04x\n", offset, i);
+ }
+
+}
+
+READ16_HANDLER( koshien_spritebank_r )
+{
+ return koshien_spritebank;
+}
+
+WRITE16_HANDLER( koshien_spritebank_w )
+{
+ koshien_spritebank = data;
+
+ spritebank_buffered[0]=0x0000; /* never changes */
+ spritebank_buffered[1]=0x0400;
+
+ spritebank_buffered[2] = ((data & 0x00f) + 1) * 0x800;
+ spritebank_buffered[4] = (((data & 0x0f0) >> 4) + 1) * 0x800;
+ spritebank_buffered[6] = (((data & 0xf00) >> 8) + 1) * 0x800;
+ spritebank_buffered[3] = spritebank_buffered[2] + 0x400;
+ spritebank_buffered[5] = spritebank_buffered[4] + 0x400;
+ spritebank_buffered[7] = spritebank_buffered[6] + 0x400;
+}
+
+static void taito_f2_tc360_spritemixdraw( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ UINT32 code,UINT32 color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int scalex, int scaley)
+{
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+ UINT8 *source_base = gfx->gfxdata + (code % gfx->total_elements) * gfx->char_modulo;
+
+ int sprite_screen_height = (scaley*gfx->height+0x8000)>>16;
+ int sprite_screen_width = (scalex*gfx->width+0x8000)>>16;
+
+ if (!scalex || !scaley) return;
+
+ if (sprite_screen_width && sprite_screen_height)
+ {
+ /* compute sprite increment per screen pixel */
+ int dx = (gfx->width<<16)/sprite_screen_width;
+ int dy = (gfx->height<<16)/sprite_screen_height;
+
+ int ex = sx+sprite_screen_width;
+ int ey = sy+sprite_screen_height;
+
+ int x_index_base;
+ int y_index;
+
+ if( flipx )
+ {
+ x_index_base = (sprite_screen_width-1)*dx;
+ dx = -dx;
+ }
+ else
+ {
+ x_index_base = 0;
+ }
+
+ if( flipy )
+ {
+ y_index = (sprite_screen_height-1)*dy;
+ dy = -dy;
+ }
+ else
+ {
+ y_index = 0;
+ }
+
+ if( clip )
+ {
+ if( sx < clip->min_x)
+ { /* clip left */
+ int pixels = clip->min_x-sx;
+ sx += pixels;
+ x_index_base += pixels*dx;
+ }
+ if( sy < clip->min_y )
+ { /* clip top */
+ int pixels = clip->min_y-sy;
+ sy += pixels;
+ y_index += pixels*dy;
+ }
+ /* NS 980211 - fixed incorrect clipping */
+ if( ex > clip->max_x+1 )
+ { /* clip right */
+ int pixels = ex-clip->max_x-1;
+ ex -= pixels;
+ }
+ if( ey > clip->max_y+1 )
+ { /* clip bottom */
+ int pixels = ey-clip->max_y-1;
+ ey -= pixels;
+ }
+ }
+
+ if( ex>sx )
+ {
+ /* skip if inner loop doesn't draw anything */
+ int y;
+
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT16 *dest = BITMAP_ADDR16(dest_bmp, y, 0);
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if( c && (pri[x]&0x80)==0 )
+ {
+ UINT8 tilemap_priority=0, sprite_priority=0;
+
+ // Get tilemap priority (0 - 0xf) for this destination pixel
+ if (pri[x]&0x10) tilemap_priority=f2_tilepri[4];
+ else if (pri[x]&0x8) tilemap_priority=f2_tilepri[3];
+ else if (pri[x]&0x4) tilemap_priority=f2_tilepri[2];
+ else if (pri[x]&0x2) tilemap_priority=f2_tilepri[1];
+ else if (pri[x]&0x1) tilemap_priority=f2_tilepri[0];
+
+ // Get sprite priority (0 - 0xf) for this source pixel
+ if ((color&0xc0)==0xc0)
+ sprite_priority=f2_spritepri[3];
+ else if ((color&0xc0)==0x80)
+ sprite_priority=f2_spritepri[2];
+ else if ((color&0xc0)==0x40)
+ sprite_priority=f2_spritepri[1];
+ else if ((color&0xc0)==0x00)
+ sprite_priority=f2_spritepri[0];
+
+ // Blend mode 1 - Sprite under tilemap, use sprite palette with tilemap data
+ if ((f2_spriteblendmode&0xc0)==0xc0 && sprite_priority==(tilemap_priority-1))
+ {
+ dest[x]=(pal[c]&0xfff0)|(dest[x]&0xf);
+ }
+ // Blend mode 1 - Sprite over tilemap, use sprite data with tilemap palette
+ else if ((f2_spriteblendmode&0xc0)==0xc0 && sprite_priority==(tilemap_priority+1))
+ {
+ if (dest[x]&0xf)
+ dest[x]=(dest[x]&0xfff0)|(pal[c]&0xf);
+ else
+ dest[x]=pal[c];
+ }
+ // Blend mode 2 - Sprite under tilemap, use sprite data with tilemap palette
+ else if ((f2_spriteblendmode&0xc0)==0x80 && sprite_priority==(tilemap_priority-1))
+ {
+ dest[x]=(dest[x]&0xffef);
+ }
+ // Blend mode 2 - Sprite over tilemap, alternate sprite palette, confirmed in Pulirula level 2
+ else if ((f2_spriteblendmode&0xc0)==0x80 && sprite_priority==(tilemap_priority+1))
+ {
+ dest[x]=(pal[c]&0xffef); // Pulirula level 2, Liquid Kids attract mode
+ }
+ // No blending
+ else
+ {
+ if (sprite_priority>tilemap_priority) // Ninja Kids confirms tilemap takes priority in equal value case
+ dest[x]=pal[c];
+ }
+ pri[x] |= 0x80;
+ }
+
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int *primasks,int uses_tc360_mixer)
+{
+ /*
+ Sprite format:
+ 0000: ---xxxxxxxxxxxxx tile code (0x0000 - 0x1fff)
+ 0002: xxxxxxxx-------- sprite y-zoom level
+ --------xxxxxxxx sprite x-zoom level
+
+ 0x00 - non scaled = 100%
+ 0x80 - scaled to 50%
+ 0xc0 - scaled to 25%
+ 0xe0 - scaled to 12.5%
+ 0xff - scaled to zero pixels size (off)
+
+ [this zoom scale may not be 100% correct, see Gunfront flame screen]
+
+ 0004: ----xxxxxxxxxxxx x-coordinate (-0x800 to 0x07ff)
+ ---x------------ latch extra scroll
+ --x------------- latch master scroll
+ -x-------------- don't use extra scroll compensation
+ x--------------- absolute screen coordinates (ignore all sprite scrolls)
+ xxxx------------ the typical use of the above is therefore
+ 1010 = set master scroll
+ 0101 = set extra scroll
+ 0006: ----xxxxxxxxxxxx y-coordinate (-0x800 to 0x07ff)
+ x--------------- marks special control commands (used in conjunction with 00a)
+ If the special command flag is set:
+ ---------------x related to sprite ram bank
+ ---x------------ unknown (deadconx, maybe others)
+ --x------------- unknown, some games (growl, gunfront) set it to 1 when
+ screen is flipped
+ 0008: --------xxxxxxxx color (0x00 - 0xff)
+ -------x-------- flipx
+ ------x--------- flipy
+ -----x---------- if set, use latched color, else use & latch specified one
+ ----x----------- if set, next sprite entry is part of sequence
+ ---x------------ if clear, use latched y coordinate, else use current y
+ --x------------- if set, y += 16
+ -x-------------- if clear, use latched x coordinate, else use current x
+ x--------------- if set, x += 16
+ 000a: only valid when the special command bit in 006 is set
+ ---------------x related to sprite ram bank. I think this is the one causing
+ the bank switch, implementing it this way all games seem
+ to properly bank switch except for footchmp which uses the
+ bit in byte 006 instead.
+ ------------x--- unknown; some games toggle it before updating sprite ram.
+ ------xx-------- unknown (finalb)
+ -----x---------- unknown (mjnquest)
+ ---x------------ disable the following sprites until another marker with
+ this bit clear is found
+ --x------------- flip screen
+
+ 000b - 000f : unused
+
+ DG comment: the sprite zoom code grafted on from Jarek's TaitoB
+ may mean I have pointlessly duplicated x,y latches in the zoom &
+ non zoom parts.
+
+ */
+ int i,x,y,off,extoffs;
+ int code,color,spritedata,spritecont,flipx,flipy;
+ int xcurrent,ycurrent,big_sprite=0;
+ int y_no=0, x_no=0, xlatch=0, ylatch=0, last_continuation_tile=0; /* for zooms */
+ UINT32 zoomword, zoomx, zoomy, zx=0, zy=0, zoomxlatch=0, zoomylatch=0; /* for zooms */
+ int scroll1x, scroll1y;
+ int scrollx=0, scrolly=0;
+ int curx,cury;
+ int f2_x_offset;
+
+ /* pdrawgfx() needs us to draw sprites front to back, so we have to build a list
+ while processing sprite ram and then draw them all at the end */
+ struct tempsprite *sprite_ptr = spritelist;
+
+ /* must remember enable status from last frame because driftout fails to
+ reactivate them from a certain point onwards. */
+ int disabled = sprites_disabled;
+
+ /* must remember master scroll from previous frame because driftout
+ sometimes doesn't set it. */
+ int master_scrollx = sprites_master_scrollx;
+ int master_scrolly = sprites_master_scrolly;
+
+ /* must also remember the sprite bank from previous frame. */
+ int area = sprites_active_area;
+
+ scroll1x = 0;
+ scroll1y = 0;
+ x = y = 0;
+ xcurrent = ycurrent = 0;
+ color = 0;
+
+ f2_x_offset = f2_hide_pixels; /* Get rid of 0-3 unwanted pixels on edge of screen. */
+ if (sprites_flipscreen) f2_x_offset = -f2_flip_hide_pixels; // was -f2_x_offset
+
+ /* safety check to avoid getting stuck in bank 2 for games using only one bank */
+ if (area == 0x8000 &&
+ spriteram_buffered[(0x8000+6)/2] == 0 &&
+ spriteram_buffered[(0x8000+10)/2] == 0)
+ area = 0;
+
+
+ for (off = 0;off < 0x4000;off += 16)
+ {
+ /* sprites_active_area may change during processing */
+ int offs = off + area;
+
+ if (spriteram_buffered[(offs+6)/2] & 0x8000)
+ {
+ disabled = spriteram_buffered[(offs+10)/2] & 0x1000;
+ sprites_flipscreen = spriteram_buffered[(offs+10)/2] & 0x2000;
+
+ /* Get rid of 0-3 unwanted pixels on edge of screen. */
+ f2_x_offset = f2_hide_pixels;
+ if (sprites_flipscreen) f2_x_offset = -f2_flip_hide_pixels; // was -f2_x_offset
+
+ if (f2_game == FOOTCHMP)
+ area = 0x8000 * (spriteram_buffered[(offs+6)/2] & 0x0001);
+ else
+ area = 0x8000 * (spriteram_buffered[(offs+10)/2] & 0x0001);
+ continue;
+ }
+
+//popmessage("%04x",area);
+
+ /* check for extra scroll offset */
+ if ((spriteram_buffered[(offs+4)/2] & 0xf000) == 0xa000)
+ {
+ master_scrollx = spriteram_buffered[(offs+4)/2] & 0xfff;
+ if (master_scrollx >= 0x800) master_scrollx -= 0x1000; /* signed value */
+ master_scrolly = spriteram_buffered[(offs+6)/2] & 0xfff;
+ if (master_scrolly >= 0x800) master_scrolly -= 0x1000; /* signed value */
+ }
+
+ if ((spriteram_buffered[(offs+4)/2] & 0xf000) == 0x5000)
+ {
+ scroll1x = spriteram_buffered[(offs+4)/2] & 0xfff;
+ if (scroll1x >= 0x800) scroll1x -= 0x1000; /* signed value */
+
+ scroll1y = spriteram_buffered[(offs+6)/2] & 0xfff;
+ if (scroll1y >= 0x800) scroll1y -= 0x1000; /* signed value */
+ }
+
+ if (disabled)
+ continue;
+
+ spritedata = spriteram_buffered[(offs+8)/2];
+
+ spritecont = (spritedata & 0xff00) >> 8;
+
+ if ((spritecont & 0x08) != 0) /* sprite continuation flag set */
+ {
+ if (big_sprite == 0) /* are we starting a big sprite ? */
+ {
+ xlatch = spriteram_buffered[(offs+4)/2] & 0xfff;
+ ylatch = spriteram_buffered[(offs+6)/2] & 0xfff;
+ x_no = 0;
+ y_no = 0;
+ zoomword = spriteram_buffered[(offs+2)/2];
+ zoomylatch = (zoomword>>8) & 0xff;
+ zoomxlatch = (zoomword) & 0xff;
+ big_sprite = 1; /* we have started a new big sprite */
+ }
+ }
+ else if (big_sprite)
+ {
+ last_continuation_tile = 1; /* don't clear big_sprite until last tile done */
+ }
+
+
+ if ((spritecont & 0x04) == 0)
+ color = spritedata & 0xff;
+
+
+// The bigsprite == 0 check fixes "tied-up" little sprites in Thunderfox
+// which (mostly?) have spritecont = 0x20 when they are not continuations
+// of anything.
+ if (big_sprite == 0 || (spritecont & 0xf0) == 0)
+ {
+ x = spriteram_buffered[(offs+4)/2];
+
+// Some absolute x values deduced here are 1 too high (scenes when you get
+// home run in Koshien, and may also relate to BG layer woods and stuff as you
+// journey in MjnQuest). You will see they are 1 pixel too far to the right.
+// Where is this extra pixel offset coming from??
+
+ if (x & 0x8000) /* absolute (koshien) */
+ {
+ scrollx = - f2_x_offset - 0x60;
+ scrolly = 0;
+ }
+ else if (x & 0x4000) /* ignore extra scroll */
+ {
+ scrollx = master_scrollx - f2_x_offset - 0x60;
+ scrolly = master_scrolly;
+ }
+ else /* all scrolls applied */
+ {
+ scrollx = scroll1x + master_scrollx - f2_x_offset - 0x60;
+ scrolly = scroll1y + master_scrolly;
+ }
+ x &= 0xfff;
+ y = spriteram_buffered[(offs+6)/2] & 0xfff;
+
+ xcurrent = x;
+ ycurrent = y;
+ }
+ else
+ {
+ if ((spritecont & 0x10) == 0)
+ y = ycurrent;
+ else if ((spritecont & 0x20) != 0)
+ {
+ y += 16;
+ y_no++; /* keep track of y tile for zooms */
+ }
+ if ((spritecont & 0x40) == 0)
+ x = xcurrent;
+ else if ((spritecont & 0x80) != 0)
+ {
+ x += 16;
+ y_no=0;
+ x_no++; /* keep track of x tile for zooms */
+ }
+ }
+
+ if (big_sprite)
+ {
+ zoomx = zoomxlatch;
+ zoomy = zoomylatch;
+ zx = 0x10; /* default, no zoom: 16 pixels across */
+ zy = 0x10; /* default, no zoom: 16 pixels vertical */
+
+ if (zoomx || zoomy)
+ {
+ /* "Zoom" zx&y is pixel size horizontally and vertically
+ of our sprite chunk. So it is difference in x and y
+ coords of our chunk and diagonally adjoining one. */
+
+// These calcs caused black lines between flames in Gunfront attract...
+// x = xlatch + x_no * (0x100 - zoomx) / 16;
+// y = ylatch + y_no * (0x100 - zoomy) / 16;
+// zx = xlatch + (x_no+1) * (0x100 - zoomx) / 16 - x;
+// zy = ylatch + (y_no+1) * (0x100 - zoomy) / 16 - y;
+
+ x = xlatch + (x_no * (0x100 - zoomx)+12) / 16; //ks
+ y = ylatch + (y_no * (0x100 - zoomy)+12) / 16; //ks
+ zx = xlatch + ((x_no+1) * (0x100 - zoomx)+12) / 16 - x; //ks
+ zy = ylatch + ((y_no+1) * (0x100 - zoomy)+12) / 16 - y; //ks
+ }
+ }
+ else
+ {
+ zoomword = spriteram_buffered[(offs+2)/2];
+ zoomy = (zoomword>>8) & 0xff;
+ zoomx = (zoomword) & 0xff;
+ zx = (0x100 - zoomx) / 16;
+ zy = (0x100 - zoomy) / 16;
+ }
+
+ if (last_continuation_tile)
+ {
+ big_sprite=0;
+ last_continuation_tile=0;
+ }
+
+ code = 0;
+ extoffs = offs;
+ /* spriteram[0x4000-7fff] has no corresponding extension area */
+ if (extoffs >= 0x8000) extoffs -= 0x4000;
+
+ if (f2_sprite_type == 0)
+ {
+ code = spriteram_buffered[(offs)/2] & 0x1fff;
+ i = (code & 0x1c00) >> 10;
+ code = spritebank[i] + (code & 0x3ff);
+ }
+
+ if (f2_sprite_type == 1) /* Yuyugogo */
+ {
+ code = spriteram_buffered[(offs)/2] & 0x3ff;
+ i = (f2_sprite_extension[(extoffs >> 4)] & 0x3f ) << 10;
+ code = (i | code);
+ }
+
+ if (f2_sprite_type == 2) /* Pulirula */
+ {
+ code = spriteram_buffered[(offs)/2] & 0xff;
+ i = (f2_sprite_extension[(extoffs >> 4)] & 0xff00 );
+ code = (i | code);
+ }
+
+ if (f2_sprite_type == 3) /* Dinorex and a few quizzes */
+ {
+ code = spriteram_buffered[(offs)/2] & 0xff;
+ i = (f2_sprite_extension[(extoffs >> 4)] & 0xff ) << 8;
+ code = (i | code);
+ }
+
+ if (code == 0) continue;
+
+ flipx = spritecont & 0x01;
+ flipy = spritecont & 0x02;
+
+ curx = (x + scrollx) & 0xfff;
+ if (curx >= 0x800) curx -= 0x1000; /* treat it as signed */
+
+ cury = (y + scrolly) & 0xfff;
+ if (cury >= 0x800) cury -= 0x1000; /* treat it as signed */
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 320 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ {
+ sprite_ptr->code = code;
+ sprite_ptr->color = color;
+ if (machine->gfx[0]->color_granularity == 64) /* Final Blow is 6-bit deep */
+ sprite_ptr->color /= 4;
+ sprite_ptr->flipx = flipx;
+ sprite_ptr->flipy = flipy;
+ sprite_ptr->x = curx;
+ sprite_ptr->y = cury;
+ sprite_ptr->zoomx = zx << 12;
+ sprite_ptr->zoomy = zy << 12;
+
+ if (primasks || uses_tc360_mixer)
+ {
+ if (primasks)
+ sprite_ptr->primask = primasks[(color & 0xc0) >> 6];
+
+ sprite_ptr++;
+ }
+ else
+ {
+ drawgfxzoom(bitmap,machine->gfx[0],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,TRANSPARENCY_PEN,0,
+ sprite_ptr->zoomx,sprite_ptr->zoomy);
+ }
+ }
+ }
+
+
+ /* this happens only if primsks != NULL */
+ while (sprite_ptr != spritelist)
+ {
+ sprite_ptr--;
+
+ if (!uses_tc360_mixer)
+ pdrawgfxzoom(bitmap,machine->gfx[0],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,TRANSPARENCY_PEN,0,
+ sprite_ptr->zoomx,sprite_ptr->zoomy,
+ sprite_ptr->primask);
+ else
+ taito_f2_tc360_spritemixdraw(bitmap,machine->gfx[0],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,
+ sprite_ptr->zoomx,sprite_ptr->zoomy);
+ }
+}
+
+static int prepare_sprites;
+
+static void update_spritebanks(void)
+{
+ int i;
+#if 1
+ for (i = 0; i < 8; i ++)
+ {
+ spritebank[i] = spritebank_buffered[i];
+ }
+#else
+ /* this makes footchmp blobbing worse! */
+ for (i = 0; i < 8; i ++)
+ {
+ spritebank[i] = spritebank_eof[i];
+ spritebank_eof[i] = spritebank_buffered[i];
+ }
+#endif
+}
+
+static void taitof2_handle_sprite_buffering(void)
+{
+ if (prepare_sprites) /* no buffering */
+ {
+ memcpy(spriteram_buffered,spriteram16,spriteram_size);
+ prepare_sprites = 0;
+ }
+}
+
+static void taitof2_update_sprites_active_area(void)
+{
+ int off;
+
+ update_spritebanks();
+
+ /* if the frame was skipped, we'll have to do the buffering now */
+ taitof2_handle_sprite_buffering();
+
+ /* safety check to avoid getting stuck in bank 2 for games using only one bank */
+ if (sprites_active_area == 0x8000 &&
+ spriteram_buffered[(0x8000+6)/2] == 0 &&
+ spriteram_buffered[(0x8000+10)/2] == 0)
+ sprites_active_area = 0;
+
+ for (off = 0;off < 0x4000;off += 16)
+ {
+ /* sprites_active_area may change during processing */
+ int offs = off + sprites_active_area;
+
+ if (spriteram_buffered[(offs+6)/2] & 0x8000)
+ {
+ sprites_disabled = spriteram_buffered[(offs+10)/2] & 0x1000;
+ if (f2_game == FOOTCHMP)
+ sprites_active_area = 0x8000 * (spriteram_buffered[(offs+6)/2] & 0x0001);
+ else
+ sprites_active_area = 0x8000 * (spriteram_buffered[(offs+10)/2] & 0x0001);
+ continue;
+ }
+
+ /* check for extra scroll offset */
+ if ((spriteram_buffered[(offs+4)/2] & 0xf000) == 0xa000)
+ {
+ sprites_master_scrollx = spriteram_buffered[(offs+4)/2] & 0xfff;
+ if (sprites_master_scrollx >= 0x800)
+ sprites_master_scrollx -= 0x1000; /* signed value */
+
+ sprites_master_scrolly = spriteram_buffered[(offs+6)/2] & 0xfff;
+ if (sprites_master_scrolly >= 0x800)
+ sprites_master_scrolly -= 0x1000; /* signed value */
+ }
+ }
+}
+
+VIDEO_EOF( taitof2_no_buffer )
+{
+ taitof2_update_sprites_active_area();
+
+ prepare_sprites = 1;
+}
+
+VIDEO_EOF( taitof2_full_buffer_delayed )
+{
+ int i;
+
+ taitof2_update_sprites_active_area();
+
+ prepare_sprites = 0;
+ memcpy(spriteram_buffered,spriteram_delayed,spriteram_size);
+ for (i = 0;i < spriteram_size/2;i++)
+ spriteram_buffered[i] = spriteram16[i];
+ memcpy(spriteram_delayed,spriteram16,spriteram_size);
+}
+
+VIDEO_EOF( taitof2_partial_buffer_delayed )
+{
+ int i;
+
+ taitof2_update_sprites_active_area();
+
+ prepare_sprites = 0;
+ memcpy(spriteram_buffered,spriteram_delayed,spriteram_size);
+ for (i = 0;i < spriteram_size/2;i += 4)
+ spriteram_buffered[i] = spriteram16[i];
+ memcpy(spriteram_delayed,spriteram16,spriteram_size);
+}
+
+VIDEO_EOF( taitof2_partial_buffer_delayed_thundfox )
+{
+ int i;
+
+ taitof2_update_sprites_active_area();
+
+ prepare_sprites = 0;
+ memcpy(spriteram_buffered,spriteram_delayed,spriteram_size);
+ for (i = 0;i < spriteram_size/2;i += 8)
+ {
+ spriteram_buffered[i] = spriteram16[i];
+ spriteram_buffered[i+1] = spriteram16[i+1];
+ spriteram_buffered[i+4] = spriteram16[i+4];
+ }
+ memcpy(spriteram_delayed,spriteram16,spriteram_size);
+}
+
+VIDEO_EOF( taitof2_partial_buffer_delayed_qzchikyu )
+{
+ /* spriteram[2] and [3] are 1 frame behind...
+ probably thundfox_eof_callback would work fine */
+
+ int i;
+
+ taitof2_update_sprites_active_area();
+
+ prepare_sprites = 0;
+ memcpy(spriteram_buffered,spriteram_delayed,spriteram_size);
+ for (i = 0;i < spriteram_size/2;i += 8)
+ {
+ spriteram_buffered[i] = spriteram16[i];
+ spriteram_buffered[i+1] = spriteram16[i+1];
+ spriteram_buffered[i+4] = spriteram16[i+4];
+ spriteram_buffered[i+5] = spriteram16[i+5]; // not needed?
+ spriteram_buffered[i+6] = spriteram16[i+6]; // not needed?
+ spriteram_buffered[i+7] = spriteram16[i+7]; // not needed?
+ }
+ memcpy(spriteram_delayed,spriteram16,spriteram_size);
+}
+
+
+/* SSI */
+VIDEO_UPDATE( ssi )
+{
+ taitof2_handle_sprite_buffering();
+
+ /* SSI only uses sprites, the tilemap registers are not even initialized.
+ (they are in Majestic 12, but the tilemaps are not used anyway) */
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ draw_sprites(machine, bitmap,cliprect,NULL, 0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( yesnoj )
+{
+ taitof2_handle_sprite_buffering();
+
+ TC0100SCN_tilemap_update(machine);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect); /* wrong color? */
+ draw_sprites(machine, bitmap,cliprect,NULL, 0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,TC0100SCN_bottomlayer(0),0,0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,TC0100SCN_bottomlayer(0)^1,0,0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,2,0,0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( taitof2 )
+{
+ taitof2_handle_sprite_buffering();
+
+ TC0100SCN_tilemap_update(machine);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect); /* wrong color? */
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,TC0100SCN_bottomlayer(0),0,0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,TC0100SCN_bottomlayer(0)^1,0,0);
+ draw_sprites(machine, bitmap,cliprect,NULL, 0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,2,0,0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( taitof2_pri )
+{
+ int layer[3];
+
+ taitof2_handle_sprite_buffering();
+
+ TC0100SCN_tilemap_update(machine);
+
+ layer[0] = TC0100SCN_bottomlayer(0);
+ layer[1] = layer[0]^1;
+ layer[2] = 2;
+ f2_tilepri[layer[0]] = TC0360PRI_regs[5] & 0x0f;
+ f2_tilepri[layer[1]] = TC0360PRI_regs[5] >> 4;
+ f2_tilepri[layer[2]] = TC0360PRI_regs[4] >> 4;
+
+ f2_spritepri[0] = TC0360PRI_regs[6] & 0x0f;
+ f2_spritepri[1] = TC0360PRI_regs[6] >> 4;
+ f2_spritepri[2] = TC0360PRI_regs[7] & 0x0f;
+ f2_spritepri[3] = TC0360PRI_regs[7] >> 4;
+
+ f2_spriteblendmode = TC0360PRI_regs[0]&0xc0;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect); /* wrong color? */
+
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0],0,1);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[1],0,2);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[2],0,4);
+
+ draw_sprites(machine, bitmap,cliprect,NULL,1);
+ return 0;
+}
+
+
+
+static void draw_roz_layer(mame_bitmap *bitmap,const rectangle *cliprect,UINT32 priority)
+{
+ if (has_TC0280GRD())
+ TC0280GRD_zoom_draw(bitmap,cliprect,f2_pivot_xdisp,f2_pivot_ydisp,priority);
+
+ if (has_TC0430GRW())
+ TC0430GRW_zoom_draw(bitmap,cliprect,f2_pivot_xdisp,f2_pivot_ydisp,priority);
+}
+
+VIDEO_UPDATE( taitof2_pri_roz )
+{
+ int tilepri[3];
+ int rozpri;
+ int layer[3];
+ int drawn;
+ int i,j;
+ int roz_base_color = (TC0360PRI_regs[1] & 0x3f) << 2;
+
+ taitof2_handle_sprite_buffering();
+
+ if (has_TC0280GRD())
+ TC0280GRD_tilemap_update(roz_base_color);
+
+ if (has_TC0430GRW())
+ TC0430GRW_tilemap_update(roz_base_color);
+
+ TC0100SCN_tilemap_update(machine);
+
+ rozpri = (TC0360PRI_regs[1] & 0xc0) >> 6;
+ rozpri = (TC0360PRI_regs[8 + rozpri/2] >> 4*(rozpri & 1)) & 0x0f;
+
+ layer[0] = TC0100SCN_bottomlayer(0);
+ layer[1] = layer[0]^1;
+ layer[2] = 2;
+
+ tilepri[layer[0]] = TC0360PRI_regs[5] & 0x0f;
+ tilepri[layer[1]] = TC0360PRI_regs[5] >> 4;
+ tilepri[layer[2]] = TC0360PRI_regs[4] >> 4;
+
+ f2_spritepri[0] = TC0360PRI_regs[6] & 0x0f;
+ f2_spritepri[1] = TC0360PRI_regs[6] >> 4;
+ f2_spritepri[2] = TC0360PRI_regs[7] & 0x0f;
+ f2_spritepri[3] = TC0360PRI_regs[7] >> 4;
+
+ f2_spriteblendmode = TC0360PRI_regs[0]&0xc0;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect); /* wrong color? */
+
+ drawn=0;
+ for (i=0; i<16; i++)
+ {
+ if (rozpri==i)
+ {
+ draw_roz_layer(bitmap,cliprect,1 << drawn);
+ f2_tilepri[drawn]=i;
+ drawn++;
+ }
+
+ for (j=0; j<3; j++)
+ {
+ if (tilepri[layer[j]]==i)
+ {
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[j],0,1<<drawn);
+ f2_tilepri[drawn]=i;
+ drawn++;
+ }
+ }
+ }
+
+ draw_sprites(machine, bitmap,cliprect,NULL,1);
+ return 0;
+}
+
+
+
+/* Thunderfox */
+VIDEO_UPDATE( thundfox )
+{
+ int tilepri[2][3];
+ int spritepri[4];
+ int layer[2][3];
+ int drawn[2];
+
+
+ taitof2_handle_sprite_buffering();
+
+ TC0100SCN_tilemap_update(machine);
+
+ layer[0][0] = TC0100SCN_bottomlayer(0);
+ layer[0][1] = layer[0][0]^1;
+ layer[0][2] = 2;
+ tilepri[0][layer[0][0]] = TC0360PRI_regs[5] & 0x0f;
+ tilepri[0][layer[0][1]] = TC0360PRI_regs[5] >> 4;
+ tilepri[0][layer[0][2]] = TC0360PRI_regs[4] >> 4;
+
+ layer[1][0] = TC0100SCN_bottomlayer(1);
+ layer[1][1] = layer[1][0]^1;
+ layer[1][2] = 2;
+ tilepri[1][layer[1][0]] = TC0360PRI_regs[9] & 0x0f;
+ tilepri[1][layer[1][1]] = TC0360PRI_regs[9] >> 4;
+ tilepri[1][layer[1][2]] = TC0360PRI_regs[8] >> 4;
+
+ spritepri[0] = TC0360PRI_regs[6] & 0x0f;
+ spritepri[1] = TC0360PRI_regs[6] >> 4;
+ spritepri[2] = TC0360PRI_regs[7] & 0x0f;
+ spritepri[3] = TC0360PRI_regs[7] >> 4;
+
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect); /* wrong color? */
+
+
+ /*
+ TODO: This isn't the correct way to handle the priority. At the moment of
+ writing, pdrawgfx() doesn't support 6 layers, so I have to cheat, assuming
+ that the two FG layers are always on top of sprites.
+ */
+
+ drawn[0] = drawn[1] = 0;
+ while (drawn[0] < 2 && drawn[1] < 2)
+ {
+ int pick;
+
+ if (tilepri[0][drawn[0]] < tilepri[1][drawn[1]])
+ pick = 0;
+ else pick = 1;
+
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,pick,layer[pick][drawn[pick]],0,1<<(drawn[pick]+2*pick));
+ drawn[pick]++;
+ }
+ while (drawn[0] < 2)
+ {
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0][drawn[0]],0,1<<drawn[0]);
+ drawn[0]++;
+ }
+ while (drawn[1] < 2)
+ {
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,1,layer[1][drawn[1]],0,1<<(drawn[1]+2));
+ drawn[1]++;
+ }
+
+ {
+ int primasks[4] = {0,0,0,0};
+ int i;
+
+ for (i = 0;i < 4;i++)
+ {
+ if (spritepri[i] < tilepri[0][0]) primasks[i] |= 0xaaaa;
+ if (spritepri[i] < tilepri[0][1]) primasks[i] |= 0xcccc;
+ if (spritepri[i] < tilepri[1][0]) primasks[i] |= 0xf0f0;
+ if (spritepri[i] < tilepri[1][1]) primasks[i] |= 0xff00;
+ }
+
+ draw_sprites(machine, bitmap,cliprect,primasks,0);
+ }
+
+
+ /*
+ TODO: This isn't the correct way to handle the priority. At the moment of
+ writing, pdrawgfx() doesn't support 6 layers, so I have to cheat, assuming
+ that the two FG layers are always on top of sprites.
+ */
+
+ if (tilepri[0][2] < tilepri[1][2])
+ {
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0][2],0,0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,1,layer[1][2],0,0);
+ }
+ else
+ {
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,1,layer[1][2],0,0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0][2],0,0);
+ }
+ return 0;
+}
+
+
+
+/*********************************************************************
+
+Deadconx and Footchmp use in the PRI chip
+-----------------------------------------
+
++4 xxxx0000 BG0
+ 0000xxxx BG3
++6 xxxx0000 BG2
+ 0000xxxx BG1
+
+Deadconx = 0x7db9 (bg0-3) 0x8eca (sprites)
+So it has bg0 [back] / s / bg1 / s / bg2 / s / bg3 / s
+
+Footchmp = 0x8db9 (bg0-3) 0xe5ac (sprites)
+So it has s / bg0 [grass] / bg1 [crowd] / s / bg2 [goal] / s / bg3 [messages] / s [scan dots]
+
+Metalb uses in the PRI chip
+---------------------------
+
++4 xxxx0000 BG1
+ 0000xxxx BG0
++6 xxxx0000 BG3
+ 0000xxxx BG2
+
+and it changes these (and the sprite pri settings) a lot.
+
+********************************************************************/
+
+VIDEO_UPDATE( metalb )
+{
+ UINT8 layer[5], invlayer[4];
+ UINT16 priority;
+
+ taitof2_handle_sprite_buffering();
+
+ TC0480SCP_tilemap_update(machine);
+
+ priority = TC0480SCP_get_bg_priority();
+
+ layer[0] = (priority &0xf000) >> 12; /* tells us which bg layer is bottom */
+ layer[1] = (priority &0x0f00) >> 8;
+ layer[2] = (priority &0x00f0) >> 4;
+ layer[3] = (priority &0x000f) >> 0; /* tells us which is top */
+ layer[4] = 4; /* text layer always over bg layers */
+
+ invlayer[layer[0]]=0;
+ invlayer[layer[1]]=1;
+ invlayer[layer[2]]=2;
+ invlayer[layer[3]]=3;
+
+ f2_tilepri[invlayer[0]] = TC0360PRI_regs[4] & 0x0f; /* bg0 */
+ f2_tilepri[invlayer[1]] = TC0360PRI_regs[4] >> 4; /* bg1 */
+ f2_tilepri[invlayer[2]] = TC0360PRI_regs[5] & 0x0f; /* bg2 */
+ f2_tilepri[invlayer[3]] = TC0360PRI_regs[5] >> 4; /* bg3 */
+ f2_tilepri[4] = TC0360PRI_regs[9] & 0x0f; /* fg (text layer) */
+
+ f2_spritepri[0] = TC0360PRI_regs[6] & 0x0f;
+ f2_spritepri[1] = TC0360PRI_regs[6] >> 4;
+ f2_spritepri[2] = TC0360PRI_regs[7] & 0x0f;
+ f2_spritepri[3] = TC0360PRI_regs[7] >> 4;
+
+ f2_spriteblendmode = TC0360PRI_regs[0]&0xc0;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[0],0,1);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[1],0,2);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[2],0,4);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[3],0,8);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[4],0,16);
+
+ draw_sprites(machine, bitmap,cliprect,NULL,1);
+ return 0;
+}
+
+
+/* Deadconx, Footchmp */
+VIDEO_UPDATE( deadconx )
+{
+ UINT8 layer[5];
+ UINT8 tilepri[5];
+ UINT8 spritepri[4];
+ UINT16 priority;
+
+ taitof2_handle_sprite_buffering();
+
+ TC0480SCP_tilemap_update(machine);
+
+ priority = TC0480SCP_get_bg_priority();
+
+ layer[0] = (priority &0xf000) >> 12; /* tells us which bg layer is bottom */
+ layer[1] = (priority &0x0f00) >> 8;
+ layer[2] = (priority &0x00f0) >> 4;
+ layer[3] = (priority &0x000f) >> 0; /* tells us which is top */
+ layer[4] = 4; /* text layer always over bg layers */
+
+ tilepri[0] = TC0360PRI_regs[4] >> 4; /* bg0 */
+ tilepri[1] = TC0360PRI_regs[5] & 0x0f; /* bg1 */
+ tilepri[2] = TC0360PRI_regs[5] >> 4; /* bg2 */
+ tilepri[3] = TC0360PRI_regs[4] & 0x0f; /* bg3 */
+
+/* we actually assume text layer is on top of everything anyway, but FWIW... */
+ tilepri[layer[4]] = TC0360PRI_regs[7] >> 4; /* fg (text layer) */
+
+ spritepri[0] = TC0360PRI_regs[6] & 0x0f;
+ spritepri[1] = TC0360PRI_regs[6] >> 4;
+ spritepri[2] = TC0360PRI_regs[7] & 0x0f;
+ spritepri[3] = TC0360PRI_regs[7] >> 4;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[0],0,1);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[1],0,2);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[2],0,4);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[3],0,8);
+
+ {
+ int primasks[4] = {0,0,0,0};
+ int i;
+
+ for (i = 0;i < 4;i++)
+ {
+ if (spritepri[i] < tilepri[(layer[0])]) primasks[i] |= 0xaaaa;
+ if (spritepri[i] < tilepri[(layer[1])]) primasks[i] |= 0xcccc;
+ if (spritepri[i] < tilepri[(layer[2])]) primasks[i] |= 0xf0f0;
+ if (spritepri[i] < tilepri[(layer[3])]) primasks[i] |= 0xff00;
+ }
+
+ draw_sprites(machine, bitmap,cliprect,primasks,0);
+ }
+
+ /*
+ TODO: This isn't the correct way to handle the priority. At the moment of
+ writing, pdrawgfx() doesn't support 5 layers, so I have to cheat, assuming
+ that the FG layer is always on top of sprites.
+ */
+
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[4],0,0);
+ return 0;
+}
diff --git a/src/mame/video/taito_f3.c b/src/mame/video/taito_f3.c
new file mode 100644
index 00000000000..b82411d3b9b
--- /dev/null
+++ b/src/mame/video/taito_f3.c
@@ -0,0 +1,3321 @@
+/***************************************************************************
+
+ Taito F3 Video emulation - Bryan McPhail, mish@tendril.co.uk
+
+****************************************************************************
+
+Brief overview:
+
+ 4 scrolling layers (512x512 or 1024x512) of 4/5/6 bpp tiles.
+ 1 scrolling text layer (512x512, characters generated in vram), 4bpp chars.
+ 1 scrolling pixel layer (512x256 pixels generated in pivot ram), 4bpp pixels.
+ 2 sprite banks (for double buffering of sprites)
+ Sprites can be 4, 5 or 6 bpp
+ Sprite scaling.
+ Rowscroll on all playfields
+ Line by line zoom on all playfields
+ Column scroll on all playfields
+ Line by line sprite and playfield priority mixing
+
+Notes:
+ All special effects are controlled by an area in 'line ram'. Typically
+ there are 256 values, one for each line of the screen (including clipped
+ lines at the top of the screen). For example, at 0x8000 in lineram,
+ there are 4 sets of 256 values (one for each playfield) and each value
+ is the scale control for that line in the destination bitmap (screen).
+ Therefore each line can have a different zoom value for special effects.
+
+ This also applies to playfield priority, rowscroll, column scroll, sprite
+ priority and VRAM/pivot layers.
+
+ However - at the start of line ram there are also sets of 256 values
+ controlling each effect - effects can be selectively applied to individual
+ playfields or only certain lines out of the 256 can be active - in which
+ case the last allowed value can be latched (typically used so a game can
+ use one zoom or row value over the whole playfield).
+
+ The programmers of some of these games made strange use of flipscreen -
+ some games have all their graphics flipped in ROM, and use the flipscreen
+ bit to display them correctly!.
+
+ Most games display 232 scanlines, but some use lineram effects to clip
+ themselves to 224 or less.
+
+****************************************************************************
+
+Line ram memory map:
+
+ Here 'playfield 1' refers to the first playfield in memory, etc
+
+ 0x0000: Column line control ram (256 lines)
+ 100x: Where bit 0 of x enables effect on playfield 1
+ Where bit 1 of x enables effect on playfield 2
+ Where bit 2 of x enables effect on playfield 3
+ Where bit 3 of x enables effect on playfield 4
+ 0x0200: Line control ram for 0x5000 section.
+ 0x0400: Line control ram for 0x6000 section.
+ 180x: Where bit 0 of x latches sprite alpha value
+ Where bit 1 of x latches tilemap alpha value
+ 0x0600: Sprite control ram
+ 1c0x: Where x enables sprite control word for that line
+ 0x0800: Zoom line control ram (256 lines)
+ 200x: Where bit 0 of x enables effect on playfield 1
+ Where bit 1 of x enables effect on playfield 2
+ Where bit 2 of x enables effect on playfield 3
+ Where bit 3 of x enables effect on playfield 4
+ 0x0a00: Assumed unused.
+ 0x0c00: Rowscroll line control ram (256 lines)
+ 280x: Where bit 0 of x enables effect on playfield 1
+ Where bit 1 of x enables effect on playfield 2
+ Where bit 2 of x enables effect on playfield 3
+ Where bit 3 of x enables effect on playfield 4
+ 0x0e00: Priority line control ram (256 lines)
+ 2c0x: Where bit 0 of x enables effect on playfield 1
+ Where bit 1 of x enables effect on playfield 2
+ Where bit 2 of x enables effect on playfield 3
+ Where bit 3 of x enables effect on playfield 4
+
+ 0x4000: Column scroll & clipping info
+
+ 0x5000: Clip plane 0 (low bits)
+ 0x5200: Clip plane 1 (low bits)
+ 0x5400: Unused?
+ 0x5600: Unused?
+
+ 0x6000: Sync register
+ 0x6004: Sprite alpha control
+ 0xff00: VRAM/Pixel layer control
+ 0xa000 enables pixel layer for this line (Disables VRAM layer)
+ 0x2000 enables garbage pixels for this line (maybe another pixel bank?) [unemulated]
+ 0x0800 seems to set the vram layer to be opaque [unemulated]
+ Effect of other bits is unknown.
+ 0x00c0: Alpha mode for sprites with pri value 0x00
+ 0x0030: Alpha mode for sprites with pri value 0x00
+ 0x000c: Alpha mode for sprites with pri value 0x00
+ 0x0003: Alpha mode for sprites with pri value 0x00
+ 0x6200: Alpha blending control
+
+ 0x6400 - controls X zoom of tile - each tile collapses to 16 single colour lines
+ xxx1 - affects bottom playfield
+ xxx2 -
+ xxx4 -
+ xxx8 - affects top playfield
+ xxfx - x zoom - 0 = 1st pixel 16 times
+ 1 = 1st pixel 8, then 2nd 8
+ 8 = 2 per pixel
+
+ (these effects only known to be used on spcinvdj title screen and riding fight - not emulated)
+
+ 1xxx = interpret palette ram for this playfield line as 15 bit and bilinear filter framebuffer(??)
+ 3xxx = interpret palette ram for this playfield line as 15 bit
+ 7xxx = interpret palette ram for this playfield line as 24 bit palette
+ 8xxx = interpret palette ram for this playfield line as 21 bit palette
+
+ (effect not emulated)
+
+ 0x6600: Background - background palette entry (under all tilemaps) (takes part in alpha blending)
+
+ (effect not emulated)
+
+ 0x7000: Pivot/vram layer enable
+ 0x7200: Cram layer priority
+ 0x7400: Sprite clipping
+ 0x7600: Sprite priority values
+ 0xf000: Relative priority for sprites with pri value 0xc0
+ 0x0f00: Relative priority for sprites with pri value 0x80
+ 0x00f0: Relative priority for sprites with pri value 0x40
+ 0x000f: Relative priority for sprites with pri value 0x00
+
+ 0x8000: Playfield 1 scale (1 word per line, 256 lines, 0x80 = default no scale)
+ 0x8200: Playfield 2/4 scale
+ 0x8400: Playfield 3 scale
+ 0x8600: Playfield 2/4 scale
+ 0x00ff = Y scale (0x80 = no scale, > 0x80 is zoom in, < 0x80 is zoom out [0xc0 is half height of 0x80])
+ 0xff00 = X scale (0 = no scale, > 0 = zoom in, [0x8000 would be double length])
+
+ Playfield 2 & 4 registers seem to be interleaved, playfield 2 Y zoom is stored where you would
+ expect playfield 4 y zoom to be and vice versa.
+
+ 0x9000: Palette add (can affect opacity) [ not emulated ]
+
+ 0xa000: Playfield 1 rowscroll (1 word per line, 256 lines)
+ 0xa200: Playfield 2 rowscroll
+ 0xa400: Playfield 3 rowscroll
+ 0xa600: Playfield 4 rowscroll
+
+ 0xb000: Playfield 1 priority (1 word per line, 256 lines)
+ 0xb200: Playfield 2 priority
+ 0xb400: Playfield 3 priority
+ 0xb600: Playfield 4 priority
+ 0xf000 = Blend mode, 0x3000 = Normal, 0x7000 = Alpha A, 0xb000 = Alpha B, others disable line
+ 0x0800 = Clip line (totally disable line)
+ 0x0400 = Assumed unused
+ 0x0200 = If set enable clip plane 1
+ 0x0100 = If set enable clip plane 0
+ 0x00c0 = Assumed unused
+ 0x0020 = Enable clip inverse mode for plane 1
+ 0x0010 = Enable clip inverse mode for plane 0
+ 0x000f = Layer priority
+
+ 0xc000 - 0xffff: Unused.
+
+ When sprite priority==playfield priority sprite takes precedence (Bubble Symph title)
+
+****************************************************************************
+
+ F3 sprite format:
+
+ Word 0: 0xffff Tile number (LSB)
+ Word 1: 0xff00 X zoom
+ 0x00ff Y zoom
+ Word 2: 0x03ff X position
+ Word 3: 0x03ff Y position
+ Word 4: 0xf000 Sprite block controls
+ 0x0800 Sprite block start
+ 0x0400 Use same colour on this sprite as block start
+ 0x0200 Y flip
+ 0x0100 X flip
+ 0x00ff Colour
+ Word 5: 0xffff Tile number (MSB), probably only low bits used
+ Word 6: 0x8000 If set, jump to sprite location in low bits
+ 0x03ff Location to jump to.
+ Word 7: 0xffff Unused? Always zero?
+
+****************************************************************************
+
+ Playfield control information (0x660000-1f):
+
+ Word 0- 3: X scroll values for the 4 playfields.
+ Word 4- 7: Y scroll values for the 4 playfields.
+ Word 8-11: Unused. Always zero.
+ Word 12: Pixel + VRAM playfields X scroll
+ Word 13: Pixel + VRAM playfields Y scroll
+ Word 14: Unused. Always zero.
+ Word 15: If set to 0x80, then 1024x512 playfields are used, else 512x512
+
+ top bits unused - writing to low 4 bits is desync or blank tilemap
+
+Playfield tile info:
+ 0xc000 0000 - X/Y Flip
+ 0x3000 ffff - Tile index
+ 0x0dff 0000 - Colour (top 2 bits use not clear, always set)
+ 0x0200 0000 - Alpha blend mode
+
+***************************************************************************/
+
+#include "driver.h"
+#include "taito_f3.h"
+#include "ui.h"
+
+#define VERBOSE 0
+#define DARIUSG_KLUDGE
+//#define DEBUG_F3 1
+
+static tilemap *pf1_tilemap,*pf2_tilemap,*pf3_tilemap,*pf4_tilemap;
+static tilemap *pixel_layer,*vram_layer;
+static UINT32 *spriteram32_buffered;
+static int vram_dirty[256];
+static int pivot_changed,vram_changed;
+static UINT32 f3_control_0[8];
+static UINT32 f3_control_1[8];
+static int flipscreen;
+
+static UINT8 *pivot_dirty;
+
+static UINT32 *f3_pf_data_1,*f3_pf_data_2,*f3_pf_data_3,*f3_pf_data_4;
+
+UINT32 *f3_vram,*f3_line_ram;
+UINT32 *f3_pf_data,*f3_pivot_ram;
+
+static int f3_skip_this_frame;
+
+/* Game specific data, some of this can be
+removed when the software values are figured out */
+struct F3config
+{
+ int name;
+ int extend;
+ int sprite_lag;
+};
+
+static const struct F3config *f3_game_config;
+
+static const struct F3config f3_config_table[] =
+{
+ /* Name Extend Sprite Lag */
+ { RINGRAGE, 0, 2 },
+ { ARABIANM, 0, 2 },
+ { RIDINGF, 1, 1 },
+ { GSEEKER, 0, 1 },
+ { TRSTAR, 1, 0 },
+ { GUNLOCK, 1, 2 },
+ { TWINQIX, 1, 1 },
+ { SCFINALS, 0, 1 },
+ { LIGHTBR, 1, 2 },
+ { KAISERKN, 0, 2 },
+ { DARIUSG, 0, 2 },
+ { BUBSYMPH, 1, 1 },
+ { SPCINVDX, 1, 1 },
+ { QTHEATER, 1, 1 },
+ { HTHERO95, 0, 1 },
+ { SPCINV95, 0, 1 },
+ { EACTION2, 1, 2 },
+ { QUIZHUHU, 1, 1 },
+ { PBOBBLE2, 0, 1 },
+ { GEKIRIDO, 0, 1 },
+ { KTIGER2, 0, 0 },
+ { BUBBLEM, 1, 1 },
+ { CLEOPATR, 0, 1 },
+ { PBOBBLE3, 0, 1 },
+ { ARKRETRN, 1, 1 },
+ { KIRAMEKI, 0, 1 },
+ { PUCHICAR, 1, 1 },
+ { PBOBBLE4, 0, 1 },
+ { POPNPOP, 1, 1 },
+ { LANDMAKR, 1, 1 },
+ { RECALH, 1, 1 },
+ { COMMANDW, 1, 1 },
+ {0}
+};
+
+
+struct tempsprite
+{
+ int code,color;
+ int flipx,flipy;
+ int x,y;
+ int zoomx,zoomy;
+ int pri;
+};
+static struct tempsprite *spritelist;
+static const struct tempsprite *sprite_end;
+
+static void get_sprite_info(running_machine *machine, const UINT32 *spriteram32_ptr);
+static int sprite_lag=1;
+static UINT8 sprite_pri_usage=0;
+
+struct f3_playfield_line_inf
+{
+ int alpha_mode[256];
+ int pri[256];
+
+ /* use for draw_scanlines */
+ UINT16 *src[256],*src_s[256],*src_e[256];
+ UINT8 *tsrc[256],*tsrc_s[256];
+ int x_count[256];
+ UINT32 x_zoom[256];
+ UINT32 clip0[256];
+ UINT32 clip1[256];
+};
+
+struct f3_spritealpha_line_inf
+{
+ UINT16 alpha_level[256];
+ UINT16 spri[256];
+ UINT16 sprite_alpha[256];
+ UINT32 sprite_clip0[256];
+ UINT32 sprite_clip1[256];
+ INT16 clip0_l[256];
+ INT16 clip0_r[256];
+ INT16 clip1_l[256];
+ INT16 clip1_r[256];
+};
+
+/*
+alpha_mode
+---- --xx 0:disable 1:nomal 2:alpha 7000 3:alpha b000
+---1 ---- alpha level a
+--1- ---- alpha level b
+1-------- opaque line
+*/
+
+static struct f3_playfield_line_inf *pf_line_inf;
+static struct f3_spritealpha_line_inf *sa_line_inf;
+
+
+static mame_bitmap *pri_alp_bitmap;
+/*
+pri_alp_bitmap
+---- ---1 sprite priority 0
+---- --1- sprite priority 1
+---- -1-- sprite priority 2
+---- 1--- sprite priority 3
+---1 ---- alpha level a 7000
+--1- ---- alpha level b 7000
+-1-- ---- alpha level a b000
+1--- ---- alpha level b b000
+1111 1111 opaque pixel
+*/
+static int f3_alpha_level_2as=127;
+static int f3_alpha_level_2ad=127;
+static int f3_alpha_level_3as=127;
+static int f3_alpha_level_3ad=127;
+static int f3_alpha_level_2bs=127;
+static int f3_alpha_level_2bd=127;
+static int f3_alpha_level_3bs=127;
+static int f3_alpha_level_3bd=127;
+
+static void init_alpha_blend_func(void);
+
+static int width_mask=0x1ff;
+static int twidth_mask=0x1f,twidth_mask_bit=5;
+static UINT8 *tile_opaque_sp;
+static UINT8 *tile_opaque_pf;
+
+
+/******************************************************************************/
+
+static void print_debug_info(mame_bitmap *bitmap)
+{
+ int l[16];
+ char buf[64*16];
+ char *bufptr = buf;
+
+ bufptr += sprintf(bufptr,"%04X %04X %04X %04X\n",f3_control_0[0]>>22,(f3_control_0[0]&0xffff)>>6,f3_control_0[1]>>22,(f3_control_0[1]&0xffff)>>6);
+ bufptr += sprintf(bufptr,"%04X %04X %04X %04X\n",f3_control_0[2]>>23,(f3_control_0[2]&0xffff)>>7,f3_control_0[3]>>23,(f3_control_0[3]&0xffff)>>7);
+ bufptr += sprintf(bufptr,"%04X %04X %04X %04X\n",f3_control_1[0]>>16,f3_control_1[0]&0xffff,f3_control_1[1]>>16,f3_control_1[1]&0xffff);
+ bufptr += sprintf(bufptr,"%04X %04X %04X %04X\n",f3_control_1[2]>>16,f3_control_1[2]&0xffff,f3_control_1[3]>>16,f3_control_1[3]&0xffff);
+
+ bufptr += sprintf(bufptr,"%04X %04X %04X %04X %04X %04X %04X %04X\n",spriteram32_buffered[0]>>16,spriteram32_buffered[0]&0xffff,spriteram32_buffered[1]>>16,spriteram32_buffered[1]&0xffff,spriteram32_buffered[2]>>16,spriteram32_buffered[2]&0xffff,spriteram32_buffered[3]>>16,spriteram32_buffered[3]&0xffff);
+ bufptr += sprintf(bufptr,"%04X %04X %04X %04X %04X %04X %04X %04X\n",spriteram32_buffered[4]>>16,spriteram32_buffered[4]&0xffff,spriteram32_buffered[5]>>16,spriteram32_buffered[5]&0xffff,spriteram32_buffered[6]>>16,spriteram32_buffered[6]&0xffff,spriteram32_buffered[7]>>16,spriteram32_buffered[7]&0xffff);
+ bufptr += sprintf(bufptr,"%04X %04X %04X %04X %04X %04X %04X %04X\n",spriteram32_buffered[8]>>16,spriteram32_buffered[8]&0xffff,spriteram32_buffered[9]>>16,spriteram32_buffered[9]&0xffff,spriteram32_buffered[10]>>16,spriteram32_buffered[10]&0xffff,spriteram32_buffered[11]>>16,spriteram32_buffered[11]&0xffff);
+
+ l[0]=f3_line_ram[0x0040]&0xffff;
+ l[1]=f3_line_ram[0x00c0]&0xffff;
+ l[2]=f3_line_ram[0x0140]&0xffff;
+ l[3]=f3_line_ram[0x01c0]&0xffff;
+ bufptr += sprintf(bufptr,"Ctr1: %04x %04x %04x %04x\n",l[0],l[1],l[2],l[3]);
+
+ l[0]=f3_line_ram[0x0240]&0xffff;
+ l[1]=f3_line_ram[0x02c0]&0xffff;
+ l[2]=f3_line_ram[0x0340]&0xffff;
+ l[3]=f3_line_ram[0x03c0]&0xffff;
+ bufptr += sprintf(bufptr,"Ctr2: %04x %04x %04x %04x\n",l[0],l[1],l[2],l[3]);
+
+ l[0]=f3_line_ram[0x2c60]&0xffff;
+ l[1]=f3_line_ram[0x2ce0]&0xffff;
+ l[2]=f3_line_ram[0x2d60]&0xffff;
+ l[3]=f3_line_ram[0x2de0]&0xffff;
+ bufptr += sprintf(bufptr,"Pri : %04x %04x %04x %04x\n",l[0],l[1],l[2],l[3]);
+
+ l[0]=f3_line_ram[0x2060]&0xffff;
+ l[1]=f3_line_ram[0x20e0]&0xffff;
+ l[2]=f3_line_ram[0x2160]&0xffff;
+ l[3]=f3_line_ram[0x21e0]&0xffff;
+ bufptr += sprintf(bufptr,"Zoom: %04x %04x %04x %04x\n",l[0],l[1],l[2],l[3]);
+
+ l[0]=f3_line_ram[0x2860]&0xffff;
+ l[1]=f3_line_ram[0x28e0]&0xffff;
+ l[2]=f3_line_ram[0x2960]&0xffff;
+ l[3]=f3_line_ram[0x29e0]&0xffff;
+ bufptr += sprintf(bufptr,"Line: %04x %04x %04x %04x\n",l[0],l[1],l[2],l[3]);
+
+ l[0]=f3_line_ram[0x1c60]&0xffff;
+ l[1]=f3_line_ram[0x1ce0]&0xffff;
+ l[2]=f3_line_ram[0x1d60]&0xffff;
+ l[3]=f3_line_ram[0x1de0]&0xffff;
+ bufptr += sprintf(bufptr,"Sprt: %04x %04x %04x %04x\n",l[0],l[1],l[2],l[3]);
+
+ l[0]=f3_line_ram[0x1860]&0xffff;
+ l[1]=f3_line_ram[0x18e0]&0xffff;
+ l[2]=f3_line_ram[0x1960]&0xffff;
+ l[3]=f3_line_ram[0x19e0]&0xffff;
+ bufptr += sprintf(bufptr,"Pivt: %04x %04x %04x %04x\n",l[0],l[1],l[2],l[3]);
+
+ l[0]=f3_line_ram[0x1060]&0xffff;
+ l[1]=f3_line_ram[0x10e0]&0xffff;
+ l[2]=f3_line_ram[0x1160]&0xffff;
+ l[3]=f3_line_ram[0x11e0]&0xffff;
+ bufptr += sprintf(bufptr,"Colm: %04x %04x %04x %04x\n",l[0],l[1],l[2],l[3]);
+
+ l[0]=f3_line_ram[0x1460]&0xffff;
+ l[1]=f3_line_ram[0x14e0]&0xffff;
+ l[2]=f3_line_ram[0x1560]&0xffff;
+ l[3]=f3_line_ram[0x15e0]&0xffff;
+ bufptr += sprintf(bufptr,"5000: %04x %04x %04x %04x\n",l[0],l[1],l[2],l[3]);
+
+ ui_draw_text(buf, 60, 40);
+}
+
+/******************************************************************************/
+
+INLINE void get_tile_info(running_machine *machine, tile_data *tileinfo, int tile_index, UINT32 *gfx_base)
+{
+ UINT32 tile=gfx_base[tile_index];
+ UINT8 abtype=(tile>>(16+9))&0x1f;
+
+ SET_TILE_INFO(
+ 1,
+ tile&0xffff,
+ (tile>>16)&0x1ff,
+ TILE_FLIPYX( tile >> 30 ));
+ tileinfo->category = abtype&1; /* alpha blending type */
+}
+
+static TILE_GET_INFO( get_tile_info1 )
+{
+ get_tile_info(machine,tileinfo,tile_index,f3_pf_data_1);
+}
+
+static TILE_GET_INFO( get_tile_info2 )
+{
+ get_tile_info(machine,tileinfo,tile_index,f3_pf_data_2);
+}
+
+static TILE_GET_INFO( get_tile_info3 )
+{
+ get_tile_info(machine,tileinfo,tile_index,f3_pf_data_3);
+}
+
+static TILE_GET_INFO( get_tile_info4 )
+{
+ get_tile_info(machine,tileinfo,tile_index,f3_pf_data_4);
+}
+
+static TILE_GET_INFO( get_tile_info_vram )
+{
+ int vram_tile;
+ int flags=0;
+
+ if (tile_index&1)
+ vram_tile = (videoram32[tile_index>>1]&0xffff);
+ else
+ vram_tile = (videoram32[tile_index>>1]>>16);
+
+ if (vram_tile&0x0100) flags|=TILE_FLIPX;
+ if (vram_tile&0x8000) flags|=TILE_FLIPY;
+
+ SET_TILE_INFO(
+ 0,
+ vram_tile&0xff,
+ (vram_tile>>9)&0x3f,
+ flags);
+}
+
+static TILE_GET_INFO( get_tile_info_pixel )
+{
+ int vram_tile,col_off;
+ int flags=0;
+ int y_offs=(f3_control_1[2]&0x1ff);
+ if (flipscreen) y_offs+=0x100;
+
+ /* Colour is shared with VRAM layer */
+ if ((((tile_index%32)*8 + y_offs)&0x1ff)>0xff)
+ col_off=0x800+((tile_index%32)*0x40)+((tile_index&0xfe0)>>5);
+ else
+ col_off=((tile_index%32)*0x40)+((tile_index&0xfe0)>>5);
+
+ if (col_off&1)
+ vram_tile = (videoram32[col_off>>1]&0xffff);
+ else
+ vram_tile = (videoram32[col_off>>1]>>16);
+
+ if (vram_tile&0x0100) flags|=TILE_FLIPX;
+ if (vram_tile&0x8000) flags|=TILE_FLIPY;
+
+ SET_TILE_INFO(
+ 3,
+ tile_index,
+ (vram_tile>>9)&0x3f,
+ flags);
+}
+
+/******************************************************************************/
+
+VIDEO_EOF( f3 )
+{
+ if (sprite_lag==2)
+ {
+ if (video_skip_this_frame() == 0)
+ {
+ get_sprite_info(machine, spriteram32_buffered);
+ }
+ memcpy(spriteram32_buffered,spriteram32,spriteram_size);
+ }
+ else if (sprite_lag==1)
+ {
+ if (video_skip_this_frame() == 0)
+ {
+ get_sprite_info(machine, spriteram32);
+ }
+ }
+}
+
+VIDEO_START( f3 )
+{
+ const struct F3config *pCFG=&f3_config_table[0];
+ int tile;
+
+ spritelist=0;
+ spriteram32_buffered=0;
+ pivot_dirty=0;
+ pf_line_inf=0;
+ pri_alp_bitmap=0;
+ tile_opaque_sp=0;
+ tile_opaque_pf=0;
+
+ /* Setup individual game */
+ do {
+ if (pCFG->name==f3_game)
+ {
+ break;
+ }
+ pCFG++;
+ } while(pCFG->name);
+
+ f3_game_config=pCFG;
+
+ if (f3_game_config->extend) {
+ pf1_tilemap = tilemap_create(get_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf2_tilemap = tilemap_create(get_tile_info2,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf3_tilemap = tilemap_create(get_tile_info3,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf4_tilemap = tilemap_create(get_tile_info4,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+
+ f3_pf_data_1=f3_pf_data+0x0000;
+ f3_pf_data_2=f3_pf_data+0x0800;
+ f3_pf_data_3=f3_pf_data+0x1000;
+ f3_pf_data_4=f3_pf_data+0x1800;
+
+ width_mask=0x3ff;
+ twidth_mask=0x3f;
+ twidth_mask_bit=6;
+
+ } else {
+ pf1_tilemap = tilemap_create(get_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ pf2_tilemap = tilemap_create(get_tile_info2,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ pf3_tilemap = tilemap_create(get_tile_info3,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ pf4_tilemap = tilemap_create(get_tile_info4,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ f3_pf_data_1=f3_pf_data+0x0000;
+ f3_pf_data_2=f3_pf_data+0x0400;
+ f3_pf_data_3=f3_pf_data+0x0800;
+ f3_pf_data_4=f3_pf_data+0x0c00;
+
+ width_mask=0x1ff;
+ twidth_mask=0x1f;
+ twidth_mask_bit=5;
+ }
+
+ spriteram32_buffered = (UINT32 *)auto_malloc(0x10000);
+ spritelist = auto_malloc(0x400 * sizeof(*spritelist));
+ sprite_end = spritelist;
+ vram_layer = tilemap_create(get_tile_info_vram,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ pixel_layer = tilemap_create(get_tile_info_pixel,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,64,32);
+ pivot_dirty = (UINT8 *)auto_malloc(2048);
+ pf_line_inf = auto_malloc(5 * sizeof(struct f3_playfield_line_inf));
+ sa_line_inf = auto_malloc(1 * sizeof(struct f3_spritealpha_line_inf));
+ pri_alp_bitmap = auto_bitmap_alloc( machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED8 );
+ tile_opaque_sp = (UINT8 *)auto_malloc(machine->gfx[2]->total_elements);
+ tile_opaque_pf = (UINT8 *)auto_malloc(machine->gfx[1]->total_elements);
+
+ tilemap_set_transparent_pen(pf1_tilemap,0);
+ tilemap_set_transparent_pen(pf2_tilemap,0);
+ tilemap_set_transparent_pen(pf3_tilemap,0);
+ tilemap_set_transparent_pen(pf4_tilemap,0);
+ tilemap_set_transparent_pen(vram_layer,0);
+ tilemap_set_transparent_pen(pixel_layer,0);
+
+ /* Palettes have 4 bpp indexes despite up to 6 bpp data */
+ machine->gfx[1]->color_granularity=16;
+ machine->gfx[2]->color_granularity=16;
+
+ flipscreen = 0;
+ memset(spriteram32_buffered,0,spriteram_size);
+ memset(spriteram32,0,spriteram_size);
+
+ state_save_register_global_array(f3_control_0);
+ state_save_register_global_array(f3_control_1);
+
+ for (tile = 0;tile < 256;tile++)
+ vram_dirty[tile]=1;
+ for (tile = 0;tile < 2048;tile++)
+ pivot_dirty[tile]=1;
+
+ f3_skip_this_frame=0;
+
+ sprite_lag=f3_game_config->sprite_lag;
+
+ init_alpha_blend_func();
+
+ {
+ const gfx_element *sprite_gfx = machine->gfx[2];
+ int c;
+
+ for (c = 0;c < sprite_gfx->total_elements;c++)
+ {
+ int x,y;
+ int chk_trans_or_opa=0;
+ UINT8 *dp = sprite_gfx->gfxdata + c * sprite_gfx->char_modulo;
+ for (y = 0;y < sprite_gfx->height;y++)
+ {
+ for (x = 0;x < sprite_gfx->width;x++)
+ {
+ if(!dp[x]) chk_trans_or_opa|=2;
+ else chk_trans_or_opa|=1;
+ }
+ dp += sprite_gfx->line_modulo;
+ }
+ if(chk_trans_or_opa==1) tile_opaque_sp[c]=1;
+ else tile_opaque_sp[c]=0;
+ }
+ }
+
+
+ {
+ const gfx_element *pf_gfx = machine->gfx[1];
+ int c;
+
+ for (c = 0;c < pf_gfx->total_elements;c++)
+ {
+ int x,y;
+ int chk_trans_or_opa=0;
+ UINT8 *dp = pf_gfx->gfxdata + c * pf_gfx->char_modulo;
+ for (y = 0;y < pf_gfx->height;y++)
+ {
+ for (x = 0;x < pf_gfx->width;x++)
+ {
+ if(!dp[x]) chk_trans_or_opa|=2;
+ else chk_trans_or_opa|=1;
+ }
+ dp += pf_gfx->line_modulo;
+ }
+ tile_opaque_pf[c]=chk_trans_or_opa;
+ }
+ }
+}
+
+/******************************************************************************/
+
+WRITE32_HANDLER( f3_pf_data_w )
+{
+ COMBINE_DATA(&f3_pf_data[offset]);
+
+ if (f3_game_config->extend) {
+ if (offset<0x800) tilemap_mark_tile_dirty(pf1_tilemap,offset-0x0000);
+ else if (offset<0x1000) tilemap_mark_tile_dirty(pf2_tilemap,offset-0x0800);
+ else if (offset<0x1800) tilemap_mark_tile_dirty(pf3_tilemap,offset-0x1000);
+ else if (offset<0x2000) tilemap_mark_tile_dirty(pf4_tilemap,offset-0x1800);
+ } else {
+ if (offset<0x400) tilemap_mark_tile_dirty(pf1_tilemap,offset-0x0000);
+ else if (offset<0x800) tilemap_mark_tile_dirty(pf2_tilemap,offset-0x0400);
+ else if (offset<0xc00) tilemap_mark_tile_dirty(pf3_tilemap,offset-0x0800);
+ else if (offset<0x1000) tilemap_mark_tile_dirty(pf4_tilemap,offset-0xc00);
+ }
+}
+
+WRITE32_HANDLER( f3_control_0_w )
+{
+ COMBINE_DATA(&f3_control_0[offset]);
+}
+
+WRITE32_HANDLER( f3_control_1_w )
+{
+ COMBINE_DATA(&f3_control_1[offset]);
+}
+
+WRITE32_HANDLER( f3_videoram_w )
+{
+ int tile,col_off;
+ COMBINE_DATA(&videoram32[offset]);
+
+ tilemap_mark_tile_dirty(vram_layer,offset<<1);
+ tilemap_mark_tile_dirty(vram_layer,(offset<<1)+1);
+
+ if (offset>0x3ff) offset-=0x400;
+
+ tile=offset<<1;
+ col_off=((tile&0x3f)*32)+((tile&0xfc0)>>6);
+
+ tilemap_mark_tile_dirty(pixel_layer,col_off);
+ tilemap_mark_tile_dirty(pixel_layer,col_off+32);
+}
+
+WRITE32_HANDLER( f3_vram_w )
+{
+ COMBINE_DATA(&f3_vram[offset]);
+ vram_dirty[offset/8]=1;
+ vram_changed=1;
+}
+
+WRITE32_HANDLER( f3_pivot_w )
+{
+ COMBINE_DATA(&f3_pivot_ram[offset]);
+ pivot_dirty[offset/8]=1;
+ pivot_changed=1;
+}
+
+WRITE32_HANDLER( f3_lineram_w )
+{
+ /* DariusGX has an interesting bug at the start of Round D - the clearing of lineram
+ (0xa000->0x0xa7ff) overflows into priority RAM (0xb000) and creates garbage priority
+ values. I'm not sure what the real machine would do with these values, and this
+ emulation certainly doesn't like it, so I've chosen to catch the bug here, and prevent
+ the trashing of priority ram. If anyone has information on what the real machine does,
+ please let me know! */
+ if (f3_game==DARIUSG) {
+ if (f3_skip_this_frame)
+ return;
+ if (offset==0xb000/4 && data==0x003f0000) {
+ f3_skip_this_frame=1;
+ return;
+ }
+ }
+
+ COMBINE_DATA(&f3_line_ram[offset]);
+}
+
+WRITE32_HANDLER( f3_palette_24bit_w )
+{
+ int r,g,b;
+
+ COMBINE_DATA(&paletteram32[offset]);
+
+ /* 12 bit palette games - there has to be a palette select bit somewhere */
+ if (f3_game==SPCINVDX || f3_game==RIDINGF || f3_game==ARABIANM || f3_game==RINGRAGE) {
+ b = 15 * ((paletteram32[offset] >> 4) & 0xf);
+ g = 15 * ((paletteram32[offset] >> 8) & 0xf);
+ r = 15 * ((paletteram32[offset] >> 12) & 0xf);
+ }
+
+ /* This is weird - why are only the sprites and VRAM palettes 21 bit? */
+ else if (f3_game==CLEOPATR) {
+ if (offset<0x100 || offset>0x1000) {
+ r = ((paletteram32[offset] >>16) & 0x7f)<<1;
+ g = ((paletteram32[offset] >> 8) & 0x7f)<<1;
+ b = ((paletteram32[offset] >> 0) & 0x7f)<<1;
+ } else {
+ r = (paletteram32[offset] >>16) & 0xff;
+ g = (paletteram32[offset] >> 8) & 0xff;
+ b = (paletteram32[offset] >> 0) & 0xff;
+ }
+ }
+
+ /* Another weird couple - perhaps this is alpha blending related? */
+ else if (f3_game==TWINQIX || f3_game==RECALH) {
+ if (offset>0x1c00) {
+ r = ((paletteram32[offset] >>16) & 0x7f)<<1;
+ g = ((paletteram32[offset] >> 8) & 0x7f)<<1;
+ b = ((paletteram32[offset] >> 0) & 0x7f)<<1;
+ } else {
+ r = (paletteram32[offset] >>16) & 0xff;
+ g = (paletteram32[offset] >> 8) & 0xff;
+ b = (paletteram32[offset] >> 0) & 0xff;
+ }
+ }
+
+ /* All other games - standard 24 bit palette */
+ else {
+ r = (paletteram32[offset] >>16) & 0xff;
+ g = (paletteram32[offset] >> 8) & 0xff;
+ b = (paletteram32[offset] >> 0) & 0xff;
+ }
+
+ palette_set_color(Machine,offset,MAKE_RGB(r,g,b));
+}
+
+/******************************************************************************/
+
+static UINT8 add_sat[256][256];
+
+static int alpha_s_1_1;
+static int alpha_s_1_2;
+static int alpha_s_1_4;
+static int alpha_s_1_5;
+static int alpha_s_1_6;
+static int alpha_s_1_8;
+static int alpha_s_1_9;
+static int alpha_s_1_a;
+
+static int alpha_s_2a_0;
+static int alpha_s_2a_4;
+static int alpha_s_2a_8;
+
+static int alpha_s_2b_0;
+static int alpha_s_2b_4;
+static int alpha_s_2b_8;
+
+static int alpha_s_3a_0;
+static int alpha_s_3a_1;
+static int alpha_s_3a_2;
+
+static int alpha_s_3b_0;
+static int alpha_s_3b_1;
+static int alpha_s_3b_2;
+
+static UINT32 dval;
+static UINT8 pval;
+static UINT8 tval;
+static UINT8 pdest_2a = 0x10;
+static UINT8 pdest_2b = 0x20;
+static int tr_2a = 0;
+static int tr_2b = 1;
+static UINT8 pdest_3a = 0x40;
+static UINT8 pdest_3b = 0x80;
+static int tr_3a = 0;
+static int tr_3b = 1;
+
+static int (*dpix_n[8][16])(UINT32 s_pix);
+static int (**dpix_lp[5])(UINT32 s_pix);
+static int (**dpix_sp[9])(UINT32 s_pix);
+
+/*============================================================================*/
+
+#define SET_ALPHA_LEVEL(d,s) \
+{ \
+ int level = s; \
+ if(level == 0) level = -1; \
+ d = level+1; \
+}
+
+INLINE void f3_alpha_set_level(void)
+{
+// SET_ALPHA_LEVEL(alpha_s_1_1, f3_alpha_level_2ad)
+ SET_ALPHA_LEVEL(alpha_s_1_1, 255-f3_alpha_level_2as)
+// SET_ALPHA_LEVEL(alpha_s_1_2, f3_alpha_level_2bd)
+ SET_ALPHA_LEVEL(alpha_s_1_2, 255-f3_alpha_level_2bs)
+ SET_ALPHA_LEVEL(alpha_s_1_4, f3_alpha_level_3ad)
+// SET_ALPHA_LEVEL(alpha_s_1_5, f3_alpha_level_3ad*f3_alpha_level_2ad/255)
+ SET_ALPHA_LEVEL(alpha_s_1_5, f3_alpha_level_3ad*(255-f3_alpha_level_2as)/255)
+// SET_ALPHA_LEVEL(alpha_s_1_6, f3_alpha_level_3ad*f3_alpha_level_2bd/255)
+ SET_ALPHA_LEVEL(alpha_s_1_6, f3_alpha_level_3ad*(255-f3_alpha_level_2bs)/255)
+ SET_ALPHA_LEVEL(alpha_s_1_8, f3_alpha_level_3bd)
+// SET_ALPHA_LEVEL(alpha_s_1_9, f3_alpha_level_3bd*f3_alpha_level_2ad/255)
+ SET_ALPHA_LEVEL(alpha_s_1_9, f3_alpha_level_3bd*(255-f3_alpha_level_2as)/255)
+// SET_ALPHA_LEVEL(alpha_s_1_a, f3_alpha_level_3bd*f3_alpha_level_2bd/255)
+ SET_ALPHA_LEVEL(alpha_s_1_a, f3_alpha_level_3bd*(255-f3_alpha_level_2bs)/255)
+
+ SET_ALPHA_LEVEL(alpha_s_2a_0, f3_alpha_level_2as)
+ SET_ALPHA_LEVEL(alpha_s_2a_4, f3_alpha_level_2as*f3_alpha_level_3ad/255)
+ SET_ALPHA_LEVEL(alpha_s_2a_8, f3_alpha_level_2as*f3_alpha_level_3bd/255)
+
+ SET_ALPHA_LEVEL(alpha_s_2b_0, f3_alpha_level_2bs)
+ SET_ALPHA_LEVEL(alpha_s_2b_4, f3_alpha_level_2bs*f3_alpha_level_3ad/255)
+ SET_ALPHA_LEVEL(alpha_s_2b_8, f3_alpha_level_2bs*f3_alpha_level_3bd/255)
+
+ SET_ALPHA_LEVEL(alpha_s_3a_0, f3_alpha_level_3as)
+ SET_ALPHA_LEVEL(alpha_s_3a_1, f3_alpha_level_3as*f3_alpha_level_2ad/255)
+ SET_ALPHA_LEVEL(alpha_s_3a_2, f3_alpha_level_3as*f3_alpha_level_2bd/255)
+
+ SET_ALPHA_LEVEL(alpha_s_3b_0, f3_alpha_level_3bs)
+ SET_ALPHA_LEVEL(alpha_s_3b_1, f3_alpha_level_3bs*f3_alpha_level_2ad/255)
+ SET_ALPHA_LEVEL(alpha_s_3b_2, f3_alpha_level_3bs*f3_alpha_level_2bd/255)
+}
+#undef SET_ALPHA_LEVEL
+
+/*============================================================================*/
+
+#ifdef LSB_FIRST
+#define COLOR1 0
+#define COLOR2 1
+#define COLOR3 2
+#else
+#define COLOR1 3
+#define COLOR2 2
+#define COLOR3 1
+#endif
+
+
+
+INLINE void f3_alpha_blend32_s( int alphas, UINT32 s )
+{
+ UINT8 *sc = (UINT8 *)&s;
+ UINT8 *dc = (UINT8 *)&dval;
+ dc[COLOR1] = (alphas * sc[COLOR1]) >> 8;
+ dc[COLOR2] = (alphas * sc[COLOR2]) >> 8;
+ dc[COLOR3] = (alphas * sc[COLOR3]) >> 8;
+}
+
+INLINE void f3_alpha_blend32_d( int alphas, UINT32 s )
+{
+ UINT8 *sc = (UINT8 *)&s;
+ UINT8 *dc = (UINT8 *)&dval;
+ dc[COLOR1] = add_sat[dc[COLOR1]][(alphas * sc[COLOR1]) >> 8];
+ dc[COLOR2] = add_sat[dc[COLOR2]][(alphas * sc[COLOR2]) >> 8];
+ dc[COLOR3] = add_sat[dc[COLOR3]][(alphas * sc[COLOR3]) >> 8];
+}
+
+/*============================================================================*/
+
+INLINE void f3_alpha_blend_1_1( UINT32 s ){f3_alpha_blend32_d(alpha_s_1_1,s);}
+INLINE void f3_alpha_blend_1_2( UINT32 s ){f3_alpha_blend32_d(alpha_s_1_2,s);}
+INLINE void f3_alpha_blend_1_4( UINT32 s ){f3_alpha_blend32_d(alpha_s_1_4,s);}
+INLINE void f3_alpha_blend_1_5( UINT32 s ){f3_alpha_blend32_d(alpha_s_1_5,s);}
+INLINE void f3_alpha_blend_1_6( UINT32 s ){f3_alpha_blend32_d(alpha_s_1_6,s);}
+INLINE void f3_alpha_blend_1_8( UINT32 s ){f3_alpha_blend32_d(alpha_s_1_8,s);}
+INLINE void f3_alpha_blend_1_9( UINT32 s ){f3_alpha_blend32_d(alpha_s_1_9,s);}
+INLINE void f3_alpha_blend_1_a( UINT32 s ){f3_alpha_blend32_d(alpha_s_1_a,s);}
+
+INLINE void f3_alpha_blend_2a_0( UINT32 s ){f3_alpha_blend32_s(alpha_s_2a_0,s);}
+INLINE void f3_alpha_blend_2a_4( UINT32 s ){f3_alpha_blend32_d(alpha_s_2a_4,s);}
+INLINE void f3_alpha_blend_2a_8( UINT32 s ){f3_alpha_blend32_d(alpha_s_2a_8,s);}
+
+INLINE void f3_alpha_blend_2b_0( UINT32 s ){f3_alpha_blend32_s(alpha_s_2b_0,s);}
+INLINE void f3_alpha_blend_2b_4( UINT32 s ){f3_alpha_blend32_d(alpha_s_2b_4,s);}
+INLINE void f3_alpha_blend_2b_8( UINT32 s ){f3_alpha_blend32_d(alpha_s_2b_8,s);}
+
+INLINE void f3_alpha_blend_3a_0( UINT32 s ){f3_alpha_blend32_s(alpha_s_3a_0,s);}
+INLINE void f3_alpha_blend_3a_1( UINT32 s ){f3_alpha_blend32_d(alpha_s_3a_1,s);}
+INLINE void f3_alpha_blend_3a_2( UINT32 s ){f3_alpha_blend32_d(alpha_s_3a_2,s);}
+
+INLINE void f3_alpha_blend_3b_0( UINT32 s ){f3_alpha_blend32_s(alpha_s_3b_0,s);}
+INLINE void f3_alpha_blend_3b_1( UINT32 s ){f3_alpha_blend32_d(alpha_s_3b_1,s);}
+INLINE void f3_alpha_blend_3b_2( UINT32 s ){f3_alpha_blend32_d(alpha_s_3b_2,s);}
+
+/*============================================================================*/
+
+static int dpix_1_noalpha(UINT32 s_pix) {dval = s_pix; return 1;}
+static int dpix_ret1(UINT32 s_pix) {return 1;}
+static int dpix_ret0(UINT32 s_pix) {return 0;}
+static int dpix_1_1(UINT32 s_pix) {if(s_pix) f3_alpha_blend_1_1(s_pix); return 1;}
+static int dpix_1_2(UINT32 s_pix) {if(s_pix) f3_alpha_blend_1_2(s_pix); return 1;}
+static int dpix_1_4(UINT32 s_pix) {if(s_pix) f3_alpha_blend_1_4(s_pix); return 1;}
+static int dpix_1_5(UINT32 s_pix) {if(s_pix) f3_alpha_blend_1_5(s_pix); return 1;}
+static int dpix_1_6(UINT32 s_pix) {if(s_pix) f3_alpha_blend_1_6(s_pix); return 1;}
+static int dpix_1_8(UINT32 s_pix) {if(s_pix) f3_alpha_blend_1_8(s_pix); return 1;}
+static int dpix_1_9(UINT32 s_pix) {if(s_pix) f3_alpha_blend_1_9(s_pix); return 1;}
+static int dpix_1_a(UINT32 s_pix) {if(s_pix) f3_alpha_blend_1_a(s_pix); return 1;}
+
+static int dpix_2a_0(UINT32 s_pix)
+{
+ if(s_pix) f3_alpha_blend_2a_0(s_pix);
+ else dval = 0;
+ if(pdest_2a) {pval |= pdest_2a;return 0;}
+ return 1;
+}
+static int dpix_2a_4(UINT32 s_pix)
+{
+ if(s_pix) f3_alpha_blend_2a_4(s_pix);
+ if(pdest_2a) {pval |= pdest_2a;return 0;}
+ return 1;
+}
+static int dpix_2a_8(UINT32 s_pix)
+{
+ if(s_pix) f3_alpha_blend_2a_8(s_pix);
+ if(pdest_2a) {pval |= pdest_2a;return 0;}
+ return 1;
+}
+
+static int dpix_3a_0(UINT32 s_pix)
+{
+ if(s_pix) f3_alpha_blend_3a_0(s_pix);
+ else dval = 0;
+ if(pdest_3a) {pval |= pdest_3a;return 0;}
+ return 1;
+}
+static int dpix_3a_1(UINT32 s_pix)
+{
+ if(s_pix) f3_alpha_blend_3a_1(s_pix);
+ if(pdest_3a) {pval |= pdest_3a;return 0;}
+ return 1;
+}
+static int dpix_3a_2(UINT32 s_pix)
+{
+ if(s_pix) f3_alpha_blend_3a_2(s_pix);
+ if(pdest_3a) {pval |= pdest_3a;return 0;}
+ return 1;
+}
+
+static int dpix_2b_0(UINT32 s_pix)
+{
+ if(s_pix) f3_alpha_blend_2b_0(s_pix);
+ else dval = 0;
+ if(pdest_2b) {pval |= pdest_2b;return 0;}
+ return 1;
+}
+static int dpix_2b_4(UINT32 s_pix)
+{
+ if(s_pix) f3_alpha_blend_2b_4(s_pix);
+ if(pdest_2b) {pval |= pdest_2b;return 0;}
+ return 1;
+}
+static int dpix_2b_8(UINT32 s_pix)
+{
+ if(s_pix) f3_alpha_blend_2b_8(s_pix);
+ if(pdest_2b) {pval |= pdest_2b;return 0;}
+ return 1;
+}
+
+static int dpix_3b_0(UINT32 s_pix)
+{
+ if(s_pix) f3_alpha_blend_3b_0(s_pix);
+ else dval = 0;
+ if(pdest_3b) {pval |= pdest_3b;return 0;}
+ return 1;
+}
+static int dpix_3b_1(UINT32 s_pix)
+{
+ if(s_pix) f3_alpha_blend_3b_1(s_pix);
+ if(pdest_3b) {pval |= pdest_3b;return 0;}
+ return 1;
+}
+static int dpix_3b_2(UINT32 s_pix)
+{
+ if(s_pix) f3_alpha_blend_3b_2(s_pix);
+ if(pdest_3b) {pval |= pdest_3b;return 0;}
+ return 1;
+}
+
+static int dpix_2_0(UINT32 s_pix)
+{
+ UINT8 tr2=tval&1;
+ if(s_pix)
+ {
+ if(tr2==tr_2b) {f3_alpha_blend_2b_0(s_pix);if(pdest_2b) pval |= pdest_2b;else return 1;}
+ else if(tr2==tr_2a) {f3_alpha_blend_2a_0(s_pix);if(pdest_2a) pval |= pdest_2a;else return 1;}
+ }
+ else
+ {
+ if(tr2==tr_2b) {dval = 0;if(pdest_2b) pval |= pdest_2b;else return 1;}
+ else if(tr2==tr_2a) {dval = 0;if(pdest_2a) pval |= pdest_2a;else return 1;}
+ }
+ return 0;
+}
+static int dpix_2_4(UINT32 s_pix)
+{
+ UINT8 tr2=tval&1;
+ if(s_pix)
+ {
+ if(tr2==tr_2b) {f3_alpha_blend_2b_4(s_pix);if(pdest_2b) pval |= pdest_2b;else return 1;}
+ else if(tr2==tr_2a) {f3_alpha_blend_2a_4(s_pix);if(pdest_2a) pval |= pdest_2a;else return 1;}
+ }
+ else
+ {
+ if(tr2==tr_2b) {if(pdest_2b) pval |= pdest_2b;else return 1;}
+ else if(tr2==tr_2a) {if(pdest_2a) pval |= pdest_2a;else return 1;}
+ }
+ return 0;
+}
+static int dpix_2_8(UINT32 s_pix)
+{
+ UINT8 tr2=tval&1;
+ if(s_pix)
+ {
+ if(tr2==tr_2b) {f3_alpha_blend_2b_8(s_pix);if(pdest_2b) pval |= pdest_2b;else return 1;}
+ else if(tr2==tr_2a) {f3_alpha_blend_2a_8(s_pix);if(pdest_2a) pval |= pdest_2a;else return 1;}
+ }
+ else
+ {
+ if(tr2==tr_2b) {if(pdest_2b) pval |= pdest_2b;else return 1;}
+ else if(tr2==tr_2a) {if(pdest_2a) pval |= pdest_2a;else return 1;}
+ }
+ return 0;
+}
+
+static int dpix_3_0(UINT32 s_pix)
+{
+ UINT8 tr2=tval&1;
+ if(s_pix)
+ {
+ if(tr2==tr_3b) {f3_alpha_blend_3b_0(s_pix);if(pdest_3b) pval |= pdest_3b;else return 1;}
+ else if(tr2==tr_3a) {f3_alpha_blend_3a_0(s_pix);if(pdest_3a) pval |= pdest_3a;else return 1;}
+ }
+ else
+ {
+ if(tr2==tr_3b) {dval = 0;if(pdest_3b) pval |= pdest_3b;else return 1;}
+ else if(tr2==tr_3a) {dval = 0;if(pdest_3a) pval |= pdest_3a;else return 1;}
+ }
+ return 0;
+}
+static int dpix_3_1(UINT32 s_pix)
+{
+ UINT8 tr2=tval&1;
+ if(s_pix)
+ {
+ if(tr2==tr_3b) {f3_alpha_blend_3b_1(s_pix);if(pdest_3b) pval |= pdest_3b;else return 1;}
+ else if(tr2==tr_3a) {f3_alpha_blend_3a_1(s_pix);if(pdest_3a) pval |= pdest_3a;else return 1;}
+ }
+ else
+ {
+ if(tr2==tr_3b) {if(pdest_3b) pval |= pdest_3b;else return 1;}
+ else if(tr2==tr_3a) {if(pdest_3a) pval |= pdest_3a;else return 1;}
+ }
+ return 0;
+}
+static int dpix_3_2(UINT32 s_pix)
+{
+ UINT8 tr2=tval&1;
+ if(s_pix)
+ {
+ if(tr2==tr_3b) {f3_alpha_blend_3b_2(s_pix);if(pdest_3b) pval |= pdest_3b;else return 1;}
+ else if(tr2==tr_3a) {f3_alpha_blend_3a_2(s_pix);if(pdest_3a) pval |= pdest_3a;else return 1;}
+ }
+ else
+ {
+ if(tr2==tr_3b) {if(pdest_3b) pval |= pdest_3b;else return 1;}
+ else if(tr2==tr_3a) {if(pdest_3a) pval |= pdest_3a;else return 1;}
+ }
+ return 0;
+}
+
+INLINE void dpix_1_sprite(UINT32 s_pix)
+{
+ if(s_pix)
+ {
+ UINT8 p1 = pval&0xf0;
+ if (p1==0x10) f3_alpha_blend_1_1(s_pix);
+ else if(p1==0x20) f3_alpha_blend_1_2(s_pix);
+ else if(p1==0x40) f3_alpha_blend_1_4(s_pix);
+ else if(p1==0x50) f3_alpha_blend_1_5(s_pix);
+ else if(p1==0x60) f3_alpha_blend_1_6(s_pix);
+ else if(p1==0x80) f3_alpha_blend_1_8(s_pix);
+ else if(p1==0x90) f3_alpha_blend_1_9(s_pix);
+ else if(p1==0xa0) f3_alpha_blend_1_a(s_pix);
+ }
+}
+
+INLINE void dpix_bg(UINT32 bgcolor)
+{
+ UINT8 p1 = pval&0xf0;
+ if(!p1) dval = bgcolor;
+ else if(p1==0x10) f3_alpha_blend_1_1(bgcolor);
+ else if(p1==0x20) f3_alpha_blend_1_2(bgcolor);
+ else if(p1==0x40) f3_alpha_blend_1_4(bgcolor);
+ else if(p1==0x50) f3_alpha_blend_1_5(bgcolor);
+ else if(p1==0x60) f3_alpha_blend_1_6(bgcolor);
+ else if(p1==0x80) f3_alpha_blend_1_8(bgcolor);
+ else if(p1==0x90) f3_alpha_blend_1_9(bgcolor);
+ else if(p1==0xa0) f3_alpha_blend_1_a(bgcolor);
+}
+
+/******************************************************************************/
+
+static void init_alpha_blend_func(void)
+{
+ int i,j;
+
+ dpix_n[0][0x0]=dpix_1_noalpha;
+ dpix_n[0][0x1]=dpix_1_noalpha;
+ dpix_n[0][0x2]=dpix_1_noalpha;
+ dpix_n[0][0x3]=dpix_1_noalpha;
+ dpix_n[0][0x4]=dpix_1_noalpha;
+ dpix_n[0][0x5]=dpix_1_noalpha;
+ dpix_n[0][0x6]=dpix_1_noalpha;
+ dpix_n[0][0x7]=dpix_1_noalpha;
+ dpix_n[0][0x8]=dpix_1_noalpha;
+ dpix_n[0][0x9]=dpix_1_noalpha;
+ dpix_n[0][0xa]=dpix_1_noalpha;
+ dpix_n[0][0xb]=dpix_1_noalpha;
+ dpix_n[0][0xc]=dpix_1_noalpha;
+ dpix_n[0][0xd]=dpix_1_noalpha;
+ dpix_n[0][0xe]=dpix_1_noalpha;
+ dpix_n[0][0xf]=dpix_1_noalpha;
+
+ dpix_n[1][0x0]=dpix_1_noalpha;
+ dpix_n[1][0x1]=dpix_1_1;
+ dpix_n[1][0x2]=dpix_1_2;
+ dpix_n[1][0x3]=dpix_ret1;
+ dpix_n[1][0x4]=dpix_1_4;
+ dpix_n[1][0x5]=dpix_1_5;
+ dpix_n[1][0x6]=dpix_1_6;
+ dpix_n[1][0x7]=dpix_ret1;
+ dpix_n[1][0x8]=dpix_1_8;
+ dpix_n[1][0x9]=dpix_1_9;
+ dpix_n[1][0xa]=dpix_1_a;
+ dpix_n[1][0xb]=dpix_ret1;
+ dpix_n[1][0xc]=dpix_ret1;
+ dpix_n[1][0xd]=dpix_ret1;
+ dpix_n[1][0xe]=dpix_ret1;
+ dpix_n[1][0xf]=dpix_ret1;
+
+ dpix_n[2][0x0]=dpix_2a_0;
+ dpix_n[2][0x1]=dpix_ret0;
+ dpix_n[2][0x2]=dpix_ret0;
+ dpix_n[2][0x3]=dpix_ret0;
+ dpix_n[2][0x4]=dpix_2a_4;
+ dpix_n[2][0x5]=dpix_ret0;
+ dpix_n[2][0x6]=dpix_ret0;
+ dpix_n[2][0x7]=dpix_ret0;
+ dpix_n[2][0x8]=dpix_2a_8;
+ dpix_n[2][0x9]=dpix_ret0;
+ dpix_n[2][0xa]=dpix_ret0;
+ dpix_n[2][0xb]=dpix_ret0;
+ dpix_n[2][0xc]=dpix_ret0;
+ dpix_n[2][0xd]=dpix_ret0;
+ dpix_n[2][0xe]=dpix_ret0;
+ dpix_n[2][0xf]=dpix_ret0;
+
+ dpix_n[3][0x0]=dpix_3a_0;
+ dpix_n[3][0x1]=dpix_3a_1;
+ dpix_n[3][0x2]=dpix_3a_2;
+ dpix_n[3][0x3]=dpix_ret0;
+ dpix_n[3][0x4]=dpix_ret0;
+ dpix_n[3][0x5]=dpix_ret0;
+ dpix_n[3][0x6]=dpix_ret0;
+ dpix_n[3][0x7]=dpix_ret0;
+ dpix_n[3][0x8]=dpix_ret0;
+ dpix_n[3][0x9]=dpix_ret0;
+ dpix_n[3][0xa]=dpix_ret0;
+ dpix_n[3][0xb]=dpix_ret0;
+ dpix_n[3][0xc]=dpix_ret0;
+ dpix_n[3][0xd]=dpix_ret0;
+ dpix_n[3][0xe]=dpix_ret0;
+ dpix_n[3][0xf]=dpix_ret0;
+
+ dpix_n[4][0x0]=dpix_2b_0;
+ dpix_n[4][0x1]=dpix_ret0;
+ dpix_n[4][0x2]=dpix_ret0;
+ dpix_n[4][0x3]=dpix_ret0;
+ dpix_n[4][0x4]=dpix_2b_4;
+ dpix_n[4][0x5]=dpix_ret0;
+ dpix_n[4][0x6]=dpix_ret0;
+ dpix_n[4][0x7]=dpix_ret0;
+ dpix_n[4][0x8]=dpix_2b_8;
+ dpix_n[4][0x9]=dpix_ret0;
+ dpix_n[4][0xa]=dpix_ret0;
+ dpix_n[4][0xb]=dpix_ret0;
+ dpix_n[4][0xc]=dpix_ret0;
+ dpix_n[4][0xd]=dpix_ret0;
+ dpix_n[4][0xe]=dpix_ret0;
+ dpix_n[4][0xf]=dpix_ret0;
+
+ dpix_n[5][0x0]=dpix_3b_0;
+ dpix_n[5][0x1]=dpix_3b_1;
+ dpix_n[5][0x2]=dpix_3b_2;
+ dpix_n[5][0x3]=dpix_ret0;
+ dpix_n[5][0x4]=dpix_ret0;
+ dpix_n[5][0x5]=dpix_ret0;
+ dpix_n[5][0x6]=dpix_ret0;
+ dpix_n[5][0x7]=dpix_ret0;
+ dpix_n[5][0x8]=dpix_ret0;
+ dpix_n[5][0x9]=dpix_ret0;
+ dpix_n[5][0xa]=dpix_ret0;
+ dpix_n[5][0xb]=dpix_ret0;
+ dpix_n[5][0xc]=dpix_ret0;
+ dpix_n[5][0xd]=dpix_ret0;
+ dpix_n[5][0xe]=dpix_ret0;
+ dpix_n[5][0xf]=dpix_ret0;
+
+ dpix_n[6][0x0]=dpix_2_0;
+ dpix_n[6][0x1]=dpix_ret0;
+ dpix_n[6][0x2]=dpix_ret0;
+ dpix_n[6][0x3]=dpix_ret0;
+ dpix_n[6][0x4]=dpix_2_4;
+ dpix_n[6][0x5]=dpix_ret0;
+ dpix_n[6][0x6]=dpix_ret0;
+ dpix_n[6][0x7]=dpix_ret0;
+ dpix_n[6][0x8]=dpix_2_8;
+ dpix_n[6][0x9]=dpix_ret0;
+ dpix_n[6][0xa]=dpix_ret0;
+ dpix_n[6][0xb]=dpix_ret0;
+ dpix_n[6][0xc]=dpix_ret0;
+ dpix_n[6][0xd]=dpix_ret0;
+ dpix_n[6][0xe]=dpix_ret0;
+ dpix_n[6][0xf]=dpix_ret0;
+
+ dpix_n[7][0x0]=dpix_3_0;
+ dpix_n[7][0x1]=dpix_3_1;
+ dpix_n[7][0x2]=dpix_3_2;
+ dpix_n[7][0x3]=dpix_ret0;
+ dpix_n[7][0x4]=dpix_ret0;
+ dpix_n[7][0x5]=dpix_ret0;
+ dpix_n[7][0x6]=dpix_ret0;
+ dpix_n[7][0x7]=dpix_ret0;
+ dpix_n[7][0x8]=dpix_ret0;
+ dpix_n[7][0x9]=dpix_ret0;
+ dpix_n[7][0xa]=dpix_ret0;
+ dpix_n[7][0xb]=dpix_ret0;
+ dpix_n[7][0xc]=dpix_ret0;
+ dpix_n[7][0xd]=dpix_ret0;
+ dpix_n[7][0xe]=dpix_ret0;
+ dpix_n[7][0xf]=dpix_ret0;
+
+ for(i=0;i<256;i++)
+ for(j=0;j<256;j++)
+ add_sat[i][j] = (i + j < 256) ? i + j : 255;
+}
+
+/******************************************************************************/
+
+#define GET_PIXMAP_POINTER(pf_num) \
+{ \
+ const struct f3_playfield_line_inf *line_tmp=line_t[pf_num]; \
+ src##pf_num=line_tmp->src[y]; \
+ src_s##pf_num=line_tmp->src_s[y]; \
+ src_e##pf_num=line_tmp->src_e[y]; \
+ tsrc##pf_num=line_tmp->tsrc[y]; \
+ tsrc_s##pf_num=line_tmp->tsrc_s[y]; \
+ x_count##pf_num=line_tmp->x_count[y]; \
+ x_zoom##pf_num=line_tmp->x_zoom[y]; \
+ clip_al##pf_num=line_tmp->clip0[y]&0xffff; \
+ clip_ar##pf_num=line_tmp->clip0[y]>>16; \
+ clip_bl##pf_num=line_tmp->clip1[y]&0xffff; \
+ clip_br##pf_num=line_tmp->clip1[y]>>16; \
+}
+
+#define CULC_PIXMAP_POINTER(pf_num) \
+{ \
+ x_count##pf_num += x_zoom##pf_num; \
+ if(x_count##pf_num>>16) \
+ { \
+ x_count##pf_num &= 0xffff; \
+ src##pf_num++; \
+ tsrc##pf_num++; \
+ if(src##pf_num==src_e##pf_num) {src##pf_num=src_s##pf_num; tsrc##pf_num=tsrc_s##pf_num;} \
+ } \
+}
+
+/*============================================================================*/
+
+INLINE void draw_scanlines(running_machine *machine,
+ mame_bitmap *bitmap,int xsize,INT16 *draw_line_num,
+ const struct f3_playfield_line_inf **line_t,
+ const int *sprite,
+ UINT32 orient,
+ int skip_layer_num)
+{
+ const pen_t *clut = &machine->remapped_colortable[0];
+ UINT32 bgcolor=clut[0];
+ int length;
+
+ const int x=46;
+
+ UINT32 sprite_noalp_0=sprite[0]&0x100;
+ UINT32 sprite_noalp_1=sprite[1]&0x100;
+ UINT32 sprite_noalp_2=sprite[2]&0x100;
+ UINT32 sprite_noalp_3=sprite[3]&0x100;
+ UINT32 sprite_noalp_4=sprite[4]&0x100;
+ UINT32 sprite_noalp_5=sprite[5]&0x100;
+
+ static UINT16 *src0=0,*src_s0=0,*src_e0=0,clip_al0=0,clip_ar0=0,clip_bl0=0,clip_br0=0;
+ static UINT8 *tsrc0=0,*tsrc_s0=0;
+ static UINT32 x_count0=0,x_zoom0=0;
+
+ static UINT16 *src1=0,*src_s1=0,*src_e1=0,clip_al1=0,clip_ar1=0,clip_bl1=0,clip_br1=0;
+ static UINT8 *tsrc1=0,*tsrc_s1=0;
+ static UINT32 x_count1=0,x_zoom1=0;
+
+ static UINT16 *src2=0,*src_s2=0,*src_e2=0,clip_al2=0,clip_ar2=0,clip_bl2=0,clip_br2=0;
+ static UINT8 *tsrc2=0,*tsrc_s2=0;
+ static UINT32 x_count2=0,x_zoom2=0;
+
+ static UINT16 *src3=0,*src_s3=0,*src_e3=0,clip_al3=0,clip_ar3=0,clip_bl3=0,clip_br3=0;
+ static UINT8 *tsrc3=0,*tsrc_s3=0;
+ static UINT32 x_count3=0,x_zoom3=0;
+
+ static UINT16 *src4=0,*src_s4=0,*src_e4=0,clip_al4=0,clip_ar4=0,clip_bl4=0,clip_br4=0;
+ static UINT8 *tsrc4=0,*tsrc_s4=0;
+ static UINT32 x_count4=0,x_zoom4=0;
+
+ UINT16 clip_als=0, clip_ars=0, clip_bls=0, clip_brs=0;
+
+ UINT8 *dstp0,*dstp;
+
+ int yadv = bitmap->rowpixels;
+ int i=0,y=draw_line_num[0];
+ int ty = y;
+
+ if (orient & ORIENTATION_FLIP_Y)
+ {
+ ty = bitmap->height - 1 - ty;
+ yadv = -yadv;
+ }
+
+ dstp0 = BITMAP_ADDR8(pri_alp_bitmap, ty, x);
+
+ pdest_2a = f3_alpha_level_2ad ? 0x10 : 0;
+ pdest_2b = f3_alpha_level_2bd ? 0x20 : 0;
+ tr_2a =(f3_alpha_level_2as==0 && f3_alpha_level_2ad==255) ? -1 : 0;
+ tr_2b =(f3_alpha_level_2bs==0 && f3_alpha_level_2bd==255) ? -1 : 1;
+ pdest_3a = f3_alpha_level_3ad ? 0x40 : 0;
+ pdest_3b = f3_alpha_level_3bd ? 0x80 : 0;
+ tr_3a =(f3_alpha_level_3as==0 && f3_alpha_level_3ad==255) ? -1 : 0;
+ tr_3b =(f3_alpha_level_3bs==0 && f3_alpha_level_3bd==255) ? -1 : 1;
+
+ {
+ UINT32 *dsti0,*dsti;
+ dsti0 = BITMAP_ADDR32(bitmap, ty, x);
+ while(1)
+ {
+ int cx=0;
+
+ clip_als=sa_line_inf->sprite_clip0[y]&0xffff;
+ clip_ars=sa_line_inf->sprite_clip0[y]>>16;
+ clip_bls=sa_line_inf->sprite_clip1[y]&0xffff;
+ clip_brs=sa_line_inf->sprite_clip1[y]>>16;
+
+ length=xsize;
+ dsti = dsti0;
+ dstp = dstp0;
+
+ switch(skip_layer_num)
+ {
+ case 0: GET_PIXMAP_POINTER(0)
+ case 1: GET_PIXMAP_POINTER(1)
+ case 2: GET_PIXMAP_POINTER(2)
+ case 3: GET_PIXMAP_POINTER(3)
+ case 4: GET_PIXMAP_POINTER(4)
+ }
+
+ while (1)
+ {
+ pval=*dstp;
+ if (pval!=0xff)
+ {
+ UINT8 sprite_pri;
+ switch(skip_layer_num)
+ {
+ case 0: if(cx>=clip_als && cx<clip_ars && !(cx>=clip_bls && cx<clip_brs) && (sprite_pri=sprite[0]&pval))
+ {
+ if(sprite_noalp_0) break;
+ if(!dpix_sp[sprite_pri]) break;
+ if(dpix_sp[sprite_pri][pval>>4](*dsti)) {*dsti=dval;break;}
+ }
+ if (cx>=clip_al0 && cx<clip_ar0 && !(cx>=clip_bl0 && cx<clip_br0)) {tval=*tsrc0;if(tval&0xf0) if(dpix_lp[0][pval>>4](clut[*src0])) {*dsti=dval;break;}}
+ case 1: if(cx>=clip_als && cx<clip_ars && !(cx>=clip_bls && cx<clip_brs) && (sprite_pri=sprite[1]&pval))
+ {
+ if(sprite_noalp_1) break;
+ if(!dpix_sp[sprite_pri])
+ {
+ if(!(pval&0xf0)) break;
+ else {dpix_1_sprite(*dsti);*dsti=dval;break;}
+ }
+ if(dpix_sp[sprite_pri][pval>>4](*dsti)) {*dsti=dval;break;}
+ }
+ if (cx>=clip_al1 && cx<clip_ar1 && !(cx>=clip_bl1 && cx<clip_br1)) {tval=*tsrc1;if(tval&0xf0) if(dpix_lp[1][pval>>4](clut[*src1])) {*dsti=dval;break;}}
+ case 2: if(cx>=clip_als && cx<clip_ars && !(cx>=clip_bls && cx<clip_brs) && (sprite_pri=sprite[2]&pval))
+ {
+ if(sprite_noalp_2) break;
+ if(!dpix_sp[sprite_pri])
+ {
+ if(!(pval&0xf0)) break;
+ else {dpix_1_sprite(*dsti);*dsti=dval;break;}
+ }
+ if(dpix_sp[sprite_pri][pval>>4](*dsti)) {*dsti=dval;break;}
+ }
+ if (cx>=clip_al2 && cx<clip_ar2 && !(cx>=clip_bl2 && cx<clip_br2)) {tval=*tsrc2;if(tval&0xf0) if(dpix_lp[2][pval>>4](clut[*src2])) {*dsti=dval;break;}}
+ case 3: if(cx>=clip_als && cx<clip_ars && !(cx>=clip_bls && cx<clip_brs) && (sprite_pri=sprite[3]&pval))
+ {
+ if(sprite_noalp_3) break;
+ if(!dpix_sp[sprite_pri])
+ {
+ if(!(pval&0xf0)) break;
+ else {dpix_1_sprite(*dsti);*dsti=dval;break;}
+ }
+ if(dpix_sp[sprite_pri][pval>>4](*dsti)) {*dsti=dval;break;}
+ }
+ if (cx>=clip_al3 && cx<clip_ar3 && !(cx>=clip_bl3 && cx<clip_br3)) {tval=*tsrc3;if(tval&0xf0) if(dpix_lp[3][pval>>4](clut[*src3])) {*dsti=dval;break;}}
+
+ case 4: if(cx>=clip_als && cx<clip_ars && !(cx>=clip_bls && cx<clip_brs) && (sprite_pri=sprite[4]&pval))
+ {
+ if(sprite_noalp_4) break;
+ if(!dpix_sp[sprite_pri])
+ {
+ if(!(pval&0xf0)) break;
+ else {dpix_1_sprite(*dsti);*dsti=dval;break;}
+ }
+ if(dpix_sp[sprite_pri][pval>>4](*dsti)) {*dsti=dval;break;}
+ }
+ if (cx>=clip_al4 && cx<clip_ar4 && !(cx>=clip_bl4 && cx<clip_br4)) {
+ tval=*tsrc4;
+ if(tval&0xf0)
+ {
+ if(dpix_lp[4][pval>>4](clut[*src4]))
+ {
+ *dsti=dval;
+ break;
+ }
+ }
+ }
+
+
+ case 5: if(cx>=clip_als && cx<clip_ars && !(cx>=clip_bls && cx<clip_brs) && (sprite_pri=sprite[5]&pval))
+ {
+ if(sprite_noalp_5) break;
+ if(!dpix_sp[sprite_pri])
+ {
+ if(!(pval&0xf0)) break;
+ else {dpix_1_sprite(*dsti);*dsti=dval;break;}
+ }
+ if(dpix_sp[sprite_pri][pval>>4](*dsti)) {*dsti=dval;break;}
+ }
+ if(!bgcolor) {if(!(pval&0xf0)) {*dsti=0;break;}}
+ else dpix_bg(bgcolor);
+ *dsti=dval;
+ }
+ }
+
+ if(!(--length)) break;
+ dsti++;
+ dstp++;
+ cx++;
+
+ switch(skip_layer_num)
+ {
+ case 0: CULC_PIXMAP_POINTER(0)
+ case 1: CULC_PIXMAP_POINTER(1)
+ case 2: CULC_PIXMAP_POINTER(2)
+ case 3: CULC_PIXMAP_POINTER(3)
+ case 4: CULC_PIXMAP_POINTER(4)
+ }
+ }
+
+ i++;
+ if(draw_line_num[i]<0) break;
+ if(draw_line_num[i]==y+1)
+ {
+ dsti0 += yadv;
+ dstp0 += yadv;
+ y++;
+ continue;
+ }
+ else
+ {
+ int dy=(draw_line_num[i]-y)*yadv;
+ dsti0 += dy;
+ dstp0 += dy;
+ y=draw_line_num[i];
+ }
+ }
+ }
+}
+#undef GET_PIXMAP_POINTER
+#undef CULC_PIXMAP_POINTER
+
+/******************************************************************************/
+
+static void visible_tile_check(running_machine *machine,
+ struct f3_playfield_line_inf *line_t,
+ int line,
+ UINT32 x_index_fx,UINT32 y_index,
+ UINT32 *f3_pf_data_n)
+{
+ UINT32 *pf_base;
+ int i,trans_all,tile_index,tile_num;
+ int alpha_type,alpha_mode;
+ int opaque_all;
+ int total_elements;
+
+ if(!(alpha_mode=line_t->alpha_mode[line])) return;
+
+ total_elements=machine->gfx[1]->total_elements;
+
+ tile_index=x_index_fx>>16;
+ tile_num=(((line_t->x_zoom[line]*320+(x_index_fx & 0xffff)+0xffff)>>16)+(tile_index%16)+15)/16;
+ tile_index/=16;
+
+ if (flipscreen)
+ {
+ pf_base=f3_pf_data_n+((31-(y_index/16))<<twidth_mask_bit);
+ tile_index=(twidth_mask-tile_index)-tile_num+1;
+ }
+ else pf_base=f3_pf_data_n+((y_index/16)<<twidth_mask_bit);
+
+
+ trans_all=1;
+ opaque_all=1;
+ alpha_type=0;
+ for(i=0;i<tile_num;i++)
+ {
+ UINT32 tile=pf_base[(tile_index)&twidth_mask];
+ if(tile&0xffff)
+ {
+ trans_all=0;
+ if(opaque_all)
+ {
+ if(tile_opaque_pf[(tile&0xffff)%total_elements]!=1) opaque_all=0;
+ }
+
+ if(alpha_mode==1)
+ {
+ if(!opaque_all) return;
+ }
+ else
+ {
+ if(alpha_type!=3)
+ {
+ if((tile>>(16+9))&1) alpha_type|=2;
+ else alpha_type|=1;
+ }
+ else if(!opaque_all) break;
+ }
+ }
+ else if(opaque_all) opaque_all=0;
+
+ tile_index++;
+ }
+
+ if(trans_all) {line_t->alpha_mode[line]=0;return;}
+
+ if(alpha_mode>1)
+ {
+ line_t->alpha_mode[line]|=alpha_type<<4;
+ }
+
+ if(opaque_all)
+ line_t->alpha_mode[line]|=0x80;
+}
+
+/******************************************************************************/
+
+static void calculate_clip(int y, UINT16 pri, UINT32* clip0, UINT32* clip1, int* line_enable)
+{
+ const struct f3_spritealpha_line_inf *sa_line_t=&sa_line_inf[0];
+
+ switch (pri)
+ {
+ case 0x0100: /* Clip plane 1 enable */
+ {
+ if (sa_line_t->clip0_l[y] > sa_line_t->clip0_r[y])
+ *line_enable=0;
+ else
+ *clip0=(sa_line_t->clip0_l[y]) | (sa_line_t->clip0_r[y]<<16);
+ *clip1=0;
+ }
+ break;
+ case 0x0110: /* Clip plane 1 enable, inverted */
+ {
+ *clip1=(sa_line_t->clip0_l[y]) | (sa_line_t->clip0_r[y]<<16);
+ *clip0=0x7fff0000;
+ }
+ break;
+ case 0x0200: /* Clip plane 2 enable */
+ {
+ if (sa_line_t->clip1_l[y] > sa_line_t->clip1_r[y])
+ *line_enable=0;
+ else
+ *clip0=(sa_line_t->clip1_l[y]) | (sa_line_t->clip1_r[y]<<16);
+ *clip1=0;
+ }
+ break;
+ case 0x0220: /* Clip plane 2 enable, inverted */
+ {
+ *clip1=(sa_line_t->clip1_l[y]) | (sa_line_t->clip1_r[y]<<16);
+ *clip0=0x7fff0000;
+ }
+ break;
+ case 0x0300: /* Clip plane 1 & 2 enable */
+ {
+ int clipl=0,clipr=0;
+
+ if (sa_line_t->clip1_l[y] > sa_line_t->clip0_l[y])
+ clipl=sa_line_t->clip1_l[y];
+ else
+ clipl=sa_line_t->clip0_l[y];
+
+ if (sa_line_t->clip1_r[y] < sa_line_t->clip0_r[y])
+ clipr=sa_line_t->clip1_r[y];
+ else
+ clipr=sa_line_t->clip0_r[y];
+
+ if (clipl > clipr)
+ *line_enable=0;
+ else
+ *clip0=(clipl) | (clipr<<16);
+ *clip1=0;
+ }
+ break;
+ case 0x0310: /* Clip plane 1 & 2 enable, plane 1 inverted */
+ {
+ if (sa_line_t->clip1_l[y] > sa_line_t->clip1_r[y])
+ line_enable=0;
+ else
+ *clip0=(sa_line_t->clip1_l[y]) | (sa_line_t->clip1_r[y]<<16);
+
+ *clip1=(sa_line_t->clip0_l[y]) | (sa_line_t->clip0_r[y]<<16);
+ }
+ break;
+ case 0x0320: /* Clip plane 1 & 2 enable, plane 2 inverted */
+ {
+ if (sa_line_t->clip0_l[y] > sa_line_t->clip0_r[y])
+ line_enable=0;
+ else
+ *clip0=(sa_line_t->clip0_l[y]) | (sa_line_t->clip0_r[y]<<16);
+
+ *clip1=(sa_line_t->clip1_l[y]) | (sa_line_t->clip1_r[y]<<16);
+ }
+ break;
+ case 0x0330: /* Clip plane 1 & 2 enable, both inverted */
+ {
+ int clipl=0,clipr=0;
+
+ if (sa_line_t->clip1_l[y] < sa_line_t->clip0_l[y])
+ clipl=sa_line_t->clip1_l[y];
+ else
+ clipl=sa_line_t->clip0_l[y];
+
+ if (sa_line_t->clip1_r[y] > sa_line_t->clip0_r[y])
+ clipr=sa_line_t->clip1_r[y];
+ else
+ clipr=sa_line_t->clip0_r[y];
+
+ if (clipl > clipr)
+ *line_enable=0;
+ else
+ *clip1=(clipl) | (clipr<<16);
+ *clip0=0x7fff0000;
+ }
+ break;
+ default:
+ // popmessage("Illegal clip mode");
+ break;
+ }
+}
+
+static void get_spritealphaclip_info(void)
+{
+ struct f3_spritealpha_line_inf *line_t=&sa_line_inf[0];
+
+ int y,y_end,y_inc;
+
+ int spri_base,clip_base_low,clip_base_high,inc;
+
+ UINT16 spri=0;
+ UINT16 sprite_clip=0;
+ UINT16 clip0_low=0, clip0_high=0, clip1_low=0;
+ int alpha_level=0;
+ UINT16 sprite_alpha=0;
+
+ if (flipscreen)
+ {
+ spri_base=0x77fe;
+ clip_base_low=0x51fe;
+ clip_base_high=0x45fe;
+ inc=-2;
+ y=255;
+ y_end=-1;
+ y_inc=-1;
+
+ }
+ else
+ {
+ spri_base=0x7600;
+ clip_base_low=0x5000;
+ clip_base_high=0x4400;
+ inc=2;
+ y=0;
+ y_end=256;
+ y_inc=1;
+ }
+
+ while(y!=y_end)
+ {
+ /* The zoom, column and row values can latch according to control ram */
+ if (y&1)
+ {
+ if (f3_line_ram[0x080+(y>>1)]&1)
+ clip0_low=(f3_line_ram[clip_base_low/4]>> 0)&0xffff;
+ if (f3_line_ram[0x000+(y>>1)]&4)
+ clip0_high=(f3_line_ram[clip_base_high/4]>> 0)&0xffff;
+ if (f3_line_ram[0x080+(y>>1)]&2)
+ clip1_low=(f3_line_ram[(clip_base_low+0x200)/4]>> 0)&0xffff;
+
+ if (f3_line_ram[(0x0600/4)+(y>>1)]&0x8)
+ spri=f3_line_ram[spri_base/4]&0xffff;
+ if (f3_line_ram[(0x0600/4)+(y>>1)]&0x4)
+ sprite_clip=f3_line_ram[(spri_base-0x200)/4]&0xffff;
+ if (f3_line_ram[(0x0400/4)+(y>>1)]&0x1)
+ sprite_alpha=f3_line_ram[(spri_base-0x1600)/4]&0xffff;
+ if (f3_line_ram[(0x0400/4)+(y>>1)]&0x2)
+ alpha_level=f3_line_ram[(spri_base-0x1400)/4]&0xffff;
+ }
+ else
+ {
+ if (f3_line_ram[0x080+(y>>1)]&0x10000)
+ clip0_low=(f3_line_ram[clip_base_low/4]>>16)&0xffff;
+ if (f3_line_ram[0x000+(y>>1)]&0x40000)
+ clip0_high=(f3_line_ram[clip_base_high/4]>>16)&0xffff;
+ if (f3_line_ram[0x080+(y>>1)]&0x20000)
+ clip1_low=(f3_line_ram[(clip_base_low+0x200)/4]>>16)&0xffff;
+
+ if (f3_line_ram[(0x0600/4)+(y>>1)]&0x80000)
+ spri=f3_line_ram[spri_base/4]>>16;
+ if (f3_line_ram[(0x0600/4)+(y>>1)]&0x40000)
+ sprite_clip=f3_line_ram[(spri_base-0x200)/4]>>16;
+ if (f3_line_ram[(0x0400/4)+(y>>1)]&0x10000)
+ sprite_alpha=f3_line_ram[(spri_base-0x1600)/4]>>16;
+ if (f3_line_ram[(0x0400/4)+(y>>1)]&0x20000)
+ alpha_level=f3_line_ram[(spri_base-0x1400)/4]>>16;
+ }
+
+ line_t->alpha_level[y]=alpha_level;
+ line_t->spri[y]=spri;
+ line_t->sprite_alpha[y]=sprite_alpha;
+ line_t->clip0_l[y]=((clip0_low&0xff)|((clip0_high&0x1000)>>4)) - 47;
+ line_t->clip0_r[y]=(((clip0_low&0xff00)>>8)|((clip0_high&0x2000)>>5)) - 47;
+ line_t->clip1_l[y]=((clip1_low&0xff)|((clip0_high&0x4000)>>6)) - 47;
+ line_t->clip1_r[y]=(((clip1_low&0xff00)>>8)|((clip0_high&0x8000)>>7)) - 47;
+ if (line_t->clip0_l[y]<0) line_t->clip0_l[y]=0;
+ if (line_t->clip0_r[y]<0) line_t->clip0_r[y]=0;
+ if (line_t->clip1_l[y]<0) line_t->clip1_l[y]=0;
+ if (line_t->clip1_r[y]<0) line_t->clip1_r[y]=0;
+
+ /* Evaluate sprite clipping */
+ if (sprite_clip&0x080)
+ {
+ line_t->sprite_clip0[y]=0x7fff7fff;
+ line_t->sprite_clip1[y]=0;
+ }
+ else if (sprite_clip&0x33)
+ {
+ int line_enable=1;
+ calculate_clip(y, ((sprite_clip&0x33)<<4), &line_t->sprite_clip0[y], &line_t->sprite_clip1[y], &line_enable);
+ if (line_enable==0)
+ line_t->sprite_clip0[y]=0x7fff7fff;
+ }
+ else
+ {
+ line_t->sprite_clip0[y]=0x7fff0000;
+ line_t->sprite_clip1[y]=0;
+ }
+
+ spri_base+=inc;
+ clip_base_low+=inc;
+ clip_base_high+=inc;
+ y +=y_inc;
+ }
+}
+
+/* sx and sy are 16.16 fixed point numbers */
+static void get_line_ram_info(running_machine *machine, tilemap *tmap, int sx, int sy, int pos, UINT32 *f3_pf_data_n)
+{
+ struct f3_playfield_line_inf *line_t=&pf_line_inf[pos];
+ const mame_bitmap *srcbitmap;
+ const mame_bitmap *flagsbitmap;
+
+ int y,y_start,y_end,y_inc;
+ int line_base,zoom_base,col_base,pri_base,inc;
+
+ int line_enable;
+ int colscroll=0,x_offset=0,line_zoom=0;
+ UINT32 _y_zoom[256];
+ UINT16 pri=0;
+ int bit_select0=0x10000<<pos;
+ int bit_select1=1<<pos;
+
+ int _colscroll[256];
+ UINT32 _x_offset[256];
+ int y_index_fx;
+
+ sx+=((46<<16));
+
+ if (flipscreen)
+ {
+ line_base=0xa1fe + (pos*0x200);
+ zoom_base=0x81fe;// + (pos*0x200);
+ col_base =0x41fe + (pos*0x200);
+ pri_base =0xb1fe + (pos*0x200);
+ inc=-2;
+ y_start=255;
+ y_end=-1;
+ y_inc=-1;
+
+ if (f3_game_config->extend) sx=-sx+((188-512)<<16); else sx=-sx+(188<<16); /* Adjust for flipped scroll position */
+ y_index_fx=-sy-(256<<16); /* Adjust for flipped scroll position */
+ }
+ else
+ {
+ line_base=0xa000 + (pos*0x200);
+ zoom_base=0x8000;// + (pos*0x200);
+ col_base =0x4000 + (pos*0x200);
+ pri_base =0xb000 + (pos*0x200);
+ inc=2;
+ y_start=0;
+ y_end=256;
+ y_inc=1;
+
+ y_index_fx=sy;
+ }
+
+ y=y_start;
+ while(y!=y_end)
+ {
+ /* The zoom, column and row values can latch according to control ram */
+ if (y&1)
+ {
+ if (f3_line_ram[0x300+(y>>1)]&bit_select1)
+ x_offset=(f3_line_ram[line_base/4]&0xffff)<<10;
+ if (f3_line_ram[0x380+(y>>1)]&bit_select1)
+ pri=f3_line_ram[pri_base/4]&0xffff;
+
+ // Zoom for playfields 1 & 3 is interleaved, as is the latch select
+ switch (pos)
+ {
+ case 0:
+ if (f3_line_ram[0x200+(y>>1)]&bit_select1)
+ line_zoom=f3_line_ram[(zoom_base+0x000)/4]&0xffff;
+ break;
+ case 1:
+ if (f3_line_ram[0x200+(y>>1)]&0x2)
+ line_zoom=((f3_line_ram[(zoom_base+0x200)/4]&0xffff)&0xff00) | (line_zoom&0x00ff);
+ if (f3_line_ram[0x200+(y>>1)]&0x8)
+ line_zoom=((f3_line_ram[(zoom_base+0x600)/4]&0xffff)&0x00ff) | (line_zoom&0xff00);
+ break;
+ case 2:
+ if (f3_line_ram[0x200+(y>>1)]&bit_select1)
+ line_zoom=f3_line_ram[(zoom_base+0x400)/4]&0xffff;
+ break;
+ case 3:
+ if (f3_line_ram[0x200+(y>>1)]&0x8)
+ line_zoom=((f3_line_ram[(zoom_base+0x600)/4]&0xffff)&0xff00) | (line_zoom&0x00ff);
+ if (f3_line_ram[0x200+(y>>1)]&0x2)
+ line_zoom=((f3_line_ram[(zoom_base+0x200)/4]&0xffff)&0x00ff) | (line_zoom&0xff00);
+ break;
+ default:
+ break;
+ }
+
+ // Column scroll only affects playfields 2 & 3
+ if (pos>=2 && f3_line_ram[0x000+(y>>1)]&bit_select1)
+ colscroll=(f3_line_ram[col_base/4]>> 0)&0x3ff;
+ }
+ else
+ {
+ if (f3_line_ram[0x300+(y>>1)]&bit_select0)
+ x_offset=(f3_line_ram[line_base/4]&0xffff0000)>>6;
+
+ if (f3_line_ram[0x380+(y>>1)]&bit_select0)
+ pri=(f3_line_ram[pri_base/4]>>16)&0xffff;
+
+ // Zoom for playfields 1 & 3 is interleaved, as is the latch select
+ switch (pos)
+ {
+ case 0:
+ if (f3_line_ram[0x200+(y>>1)]&bit_select0)
+ line_zoom=f3_line_ram[(zoom_base+0x000)/4]>>16;
+ break;
+ case 1:
+ if (f3_line_ram[0x200+(y>>1)]&0x20000)
+ line_zoom=((f3_line_ram[(zoom_base+0x200)/4]>>16)&0xff00) | (line_zoom&0x00ff);
+ if (f3_line_ram[0x200+(y>>1)]&0x80000)
+ line_zoom=((f3_line_ram[(zoom_base+0x600)/4]>>16)&0x00ff) | (line_zoom&0xff00);
+ break;
+ case 2:
+ if (f3_line_ram[0x200+(y>>1)]&bit_select0)
+ line_zoom=f3_line_ram[(zoom_base+0x400)/4]>>16;
+ break;
+ case 3:
+ if (f3_line_ram[0x200+(y>>1)]&0x80000)
+ line_zoom=((f3_line_ram[(zoom_base+0x600)/4]>>16)&0xff00) | (line_zoom&0x00ff);
+ if (f3_line_ram[0x200+(y>>1)]&0x20000)
+ line_zoom=((f3_line_ram[(zoom_base+0x200)/4]>>16)&0x00ff) | (line_zoom&0xff00);
+ break;
+ default:
+ break;
+ }
+
+ // Column scroll only affects playfields 2 & 3
+ if (pos>=2 && f3_line_ram[0x000+(y>>1)]&bit_select0)
+ colscroll=(f3_line_ram[col_base/4]>>16)&0x3ff;
+ }
+
+ if (!pri || (!flipscreen && y<24) || (flipscreen && y>231) ||
+ (pri&0xc000)==0xc000 || !(pri&0x2000)/**/)
+ line_enable=0;
+ else if(pri&0x4000) //alpha1
+ line_enable=2;
+ else if(pri&0x8000) //alpha2
+ line_enable=3;
+ else
+ line_enable=1;
+
+ _colscroll[y]=colscroll;
+ _x_offset[y]=(x_offset&0xffff0000) - (x_offset&0x0000ffff);
+ _y_zoom[y] = (line_zoom&0xff) << 9;
+
+ /* The football games use values in the range 0x200-0x3ff where the crowd should be drawn - !?
+
+ Until this is understood we disable those lines (which would usually wrap and show the grass
+ area.
+ */
+ if (colscroll&0x200)
+ pri|=0x0800;
+
+ /* Evaluate clipping */
+ if (pri&0x0800)
+ line_enable=0;
+ else if (pri&0x0330)
+ {
+ //fast path todo - remove line enable
+ calculate_clip(y, pri&0x0330, &line_t->clip0[y], &line_t->clip1[y], &line_enable);
+ }
+ else
+ {
+ /* No clipping */
+ line_t->clip0[y]=0x7fff0000;
+ line_t->clip1[y]=0;
+ }
+
+ line_t->x_zoom[y]=0x10000 - (line_zoom&0xff00);
+ line_t->alpha_mode[y]=line_enable;
+ line_t->pri[y]=pri;
+
+ zoom_base+=inc;
+ line_base+=inc;
+ col_base +=inc;
+ pri_base +=inc;
+ y +=y_inc;
+ }
+
+ /* set pixmap pointer */
+ srcbitmap = tilemap_get_pixmap(tmap);
+ flagsbitmap = tilemap_get_flagsmap(tmap);
+
+ y=y_start;
+ while(y!=y_end)
+ {
+ UINT32 x_index_fx;
+ UINT32 y_index;
+
+ if(line_t->alpha_mode[y]!=0)
+ {
+ UINT16 *src_s;
+ UINT8 *tsrc_s;
+
+ x_index_fx = (sx+_x_offset[y]-(10*0x10000)+(10*line_t->x_zoom[y]))&((width_mask<<16)|0xffff);
+ y_index = ((y_index_fx>>16)+_colscroll[y])&0x1ff;
+
+ /* check tile status */
+ visible_tile_check(machine, line_t,y,x_index_fx,y_index,f3_pf_data_n);
+
+ /* If clipping enabled for this line have to disable 'all opaque' optimisation */
+ if (line_t->clip0[y]!=0x7fff0000 || line_t->clip1[y]!=0)
+ line_t->alpha_mode[y]&=~0x80;
+
+ /* set pixmap index */
+ line_t->x_count[y]=x_index_fx & 0xffff; // Fractional part
+ line_t->src_s[y]=src_s=BITMAP_ADDR16(srcbitmap, y_index, 0);
+ line_t->src_e[y]=&src_s[width_mask+1];
+ line_t->src[y]=&src_s[x_index_fx>>16];
+
+ line_t->tsrc_s[y]=tsrc_s=BITMAP_ADDR8(flagsbitmap, y_index, 0);
+ line_t->tsrc[y]=&tsrc_s[x_index_fx>>16];
+ }
+
+ y_index_fx += _y_zoom[y];
+ y +=y_inc;
+ }
+}
+
+static void get_vram_info(tilemap *vram_tilemap, tilemap *pixel_tilemap, int sx, int sy)
+{
+ const struct f3_spritealpha_line_inf *sprite_alpha_line_t=&sa_line_inf[0];
+ struct f3_playfield_line_inf *line_t=&pf_line_inf[4];
+ const mame_bitmap *srcbitmap_pixel, *srcbitmap_vram;
+ const mame_bitmap *flagsbitmap_pixel, *flagsbitmap_vram;
+
+ int y,y_start,y_end,y_inc;
+ int pri_base,inc;
+
+ int line_enable;
+
+ UINT16 pri=0;
+
+ const int vram_width_mask=0x1ff;
+
+ if (flipscreen)
+ {
+ pri_base =0x73fe;
+ inc=-2;
+ y_start=255;
+ y_end=-1;
+ y_inc=-1;
+ }
+ else
+ {
+ pri_base =0x7200;
+ inc=2;
+ y_start=0;
+ y_end=256;
+ y_inc=1;
+
+ }
+
+ y=y_start;
+ while(y!=y_end)
+ {
+ /* The zoom, column and row values can latch according to control ram */
+ if (y&1)
+ {
+ if (f3_line_ram[(0x0600/4)+(y>>1)]&0x2)
+ pri=(f3_line_ram[pri_base/4]&0xffff);
+ }
+ else
+ {
+ if (f3_line_ram[(0x0600/4)+(y>>1)]&0x20000)
+ pri=(f3_line_ram[pri_base/4]&0xffff0000)>>16;
+ }
+
+ if (!pri || (!flipscreen && y<24) || (flipscreen && y>231) ||
+ (pri&0xc000)==0xc000 || !(pri&0x2000)/**/)
+ line_enable=0;
+ else if(pri&0x4000) //alpha1
+ line_enable=2;
+ else if(pri&0x8000) //alpha2
+ line_enable=3;
+ else
+ line_enable=1;
+
+ line_t->pri[y]=pri;
+
+ /* Evaluate clipping */
+ if (pri&0x0800)
+ line_enable=0;
+ else if (pri&0x0330)
+ {
+ //fast path todo - remove line enable
+ calculate_clip(y, pri&0x0330, &line_t->clip0[y], &line_t->clip1[y], &line_enable);
+ }
+ else
+ {
+ /* No clipping */
+ line_t->clip0[y]=0x7fff0000;
+ line_t->clip1[y]=0;
+ }
+
+ line_t->x_zoom[y]=0x10000;
+ line_t->alpha_mode[y]=line_enable;
+ if (line_t->alpha_mode[y]>1)
+ line_t->alpha_mode[y]|=0x10;
+
+ pri_base +=inc;
+ y +=y_inc;
+ }
+
+ sx&=0x1ff;
+
+ /* set pixmap pointer */
+ srcbitmap_pixel = tilemap_get_pixmap(pixel_tilemap);
+ flagsbitmap_pixel = tilemap_get_flagsmap(pixel_tilemap);
+ srcbitmap_vram = tilemap_get_pixmap(vram_tilemap);
+ flagsbitmap_vram = tilemap_get_flagsmap(vram_tilemap);
+
+ y=y_start;
+ while(y!=y_end)
+ {
+ if(line_t->alpha_mode[y]!=0)
+ {
+ UINT16 *src_s;
+ UINT8 *tsrc_s;
+
+ // These bits in control ram indicate whether the line is taken from
+ // the VRAM tilemap layer or pixel layer.
+ const int usePixelLayer=((sprite_alpha_line_t->sprite_alpha[y]&0xa000)==0xa000);
+
+ /* set pixmap index */
+ line_t->x_count[y]=0xffff;
+ if (usePixelLayer)
+ line_t->src_s[y]=src_s=BITMAP_ADDR16(srcbitmap_pixel, sy&0xff, 0);
+ else
+ line_t->src_s[y]=src_s=BITMAP_ADDR16(srcbitmap_vram, sy&0x1ff, 0);
+ line_t->src_e[y]=&src_s[vram_width_mask+1];
+ line_t->src[y]=&src_s[sx];
+
+ if (usePixelLayer)
+ line_t->tsrc_s[y]=tsrc_s=BITMAP_ADDR8(flagsbitmap_pixel, sy&0xff, 0);
+ else
+ line_t->tsrc_s[y]=tsrc_s=BITMAP_ADDR8(flagsbitmap_vram, sy&0x1ff, 0);
+ line_t->tsrc[y]=&tsrc_s[sx];
+ }
+
+ sy++;
+ y += y_inc;
+ }
+}
+
+/******************************************************************************/
+
+static void scanline_draw(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int i,j,y,ys,ye;
+ int y_start,y_end,y_start_next,y_end_next;
+ UINT8 draw_line[256];
+ INT16 draw_line_num[256];
+
+ UINT32 rot=0;
+
+ if (flipscreen)
+ {
+ rot=ORIENTATION_FLIP_Y;
+ ys=0;
+ ye=232;
+ }
+ else
+ {
+ ys=24;
+ ye=256;
+ }
+
+ y_start=ys;
+ y_end=ye;
+ memset(draw_line,0,256);
+
+ while(1)
+ {
+ static int alpha_level_last=-1;
+ int pos;
+ int pri[5],alpha_mode[5],alpha_mode_flag[5],alpha_level;
+ UINT16 sprite_alpha;
+ UINT8 sprite_alpha_check;
+ UINT8 sprite_alpha_all_2a;
+ int spri;
+ int alpha;
+ int layer_tmp[5];
+
+ int count_skip_layer=0;
+ int sprite[6]={0,0,0,0,0,0};
+ const struct f3_playfield_line_inf *line_t[5];
+
+
+ /* find same status of scanlines */
+ pri[0]=pf_line_inf[0].pri[y_start];
+ pri[1]=pf_line_inf[1].pri[y_start];
+ pri[2]=pf_line_inf[2].pri[y_start];
+ pri[3]=pf_line_inf[3].pri[y_start];
+ pri[4]=pf_line_inf[4].pri[y_start];
+ alpha_mode[0]=pf_line_inf[0].alpha_mode[y_start];
+ alpha_mode[1]=pf_line_inf[1].alpha_mode[y_start];
+ alpha_mode[2]=pf_line_inf[2].alpha_mode[y_start];
+ alpha_mode[3]=pf_line_inf[3].alpha_mode[y_start];
+ alpha_mode[4]=pf_line_inf[4].alpha_mode[y_start];
+ alpha_level=sa_line_inf[0].alpha_level[y_start];
+ spri=sa_line_inf[0].spri[y_start];
+ sprite_alpha=sa_line_inf[0].sprite_alpha[y_start];
+
+ draw_line[y_start]=1;
+ draw_line_num[i=0]=y_start;
+ y_start_next=-1;
+ y_end_next=-1;
+ for(y=y_start+1;y<y_end;y++)
+ {
+ if(!draw_line[y])
+ {
+ if(pri[0]!=pf_line_inf[0].pri[y]) y_end_next=y+1;
+ else if(pri[1]!=pf_line_inf[1].pri[y]) y_end_next=y+1;
+ else if(pri[2]!=pf_line_inf[2].pri[y]) y_end_next=y+1;
+ else if(pri[3]!=pf_line_inf[3].pri[y]) y_end_next=y+1;
+ else if(pri[4]!=pf_line_inf[4].pri[y]) y_end_next=y+1;
+ else if(alpha_mode[0]!=pf_line_inf[0].alpha_mode[y]) y_end_next=y+1;
+ else if(alpha_mode[1]!=pf_line_inf[1].alpha_mode[y]) y_end_next=y+1;
+ else if(alpha_mode[2]!=pf_line_inf[2].alpha_mode[y]) y_end_next=y+1;
+ else if(alpha_mode[3]!=pf_line_inf[3].alpha_mode[y]) y_end_next=y+1;
+ else if(alpha_mode[4]!=pf_line_inf[4].alpha_mode[y]) y_end_next=y+1;
+ else if(alpha_level!=sa_line_inf[0].alpha_level[y]) y_end_next=y+1;
+ else if(spri!=sa_line_inf[0].spri[y]) y_end_next=y+1;
+ else if(sprite_alpha!=sa_line_inf[0].sprite_alpha[y]) y_end_next=y+1;
+ else
+ {
+ draw_line[y]=1;
+ draw_line_num[++i]=y;
+ continue;
+ }
+
+ if(y_start_next<0) y_start_next=y;
+ }
+ }
+ y_end=y_end_next;
+ y_start=y_start_next;
+ draw_line_num[++i]=-1;
+
+ /* alpha blend */
+ alpha_mode_flag[0]=alpha_mode[0]&~3;
+ alpha_mode_flag[1]=alpha_mode[1]&~3;
+ alpha_mode_flag[2]=alpha_mode[2]&~3;
+ alpha_mode_flag[3]=alpha_mode[3]&~3;
+ alpha_mode_flag[4]=alpha_mode[4]&~3;
+ alpha_mode[0]&=3;
+ alpha_mode[1]&=3;
+ alpha_mode[2]&=3;
+ alpha_mode[3]&=3;
+ alpha_mode[4]&=3;
+ if( alpha_mode[0]>1 ||
+ alpha_mode[1]>1 ||
+ alpha_mode[2]>1 ||
+ alpha_mode[3]>1 ||
+ alpha_mode[4]>1 ||
+ (sprite_alpha&0xff) != 0xff )
+ {
+ /* set alpha level */
+ if(alpha_level!=alpha_level_last)
+ {
+ int al_s,al_d;
+ int a=alpha_level;
+ int b=(a>>8)&0xf;
+ int c=(a>>4)&0xf;
+ int d=(a>>0)&0xf;
+ a>>=12;
+
+ /* b000 7000 */
+ al_s = ( (15-d)*256) / 8;
+ al_d = ( (15-b)*256) / 8;
+ if(al_s>255) al_s = 255;
+ if(al_d>255) al_d = 255;
+ f3_alpha_level_3as = al_s;
+ f3_alpha_level_3ad = al_d;
+ f3_alpha_level_2as = al_d;
+ f3_alpha_level_2ad = al_s;
+
+ al_s = ( (15-c)*256) / 8;
+ al_d = ( (15-a)*256) / 8;
+ if(al_s>255) al_s = 255;
+ if(al_d>255) al_d = 255;
+ f3_alpha_level_3bs = al_s;
+ f3_alpha_level_3bd = al_d;
+ f3_alpha_level_2bs = al_d;
+ f3_alpha_level_2bd = al_s;
+
+ f3_alpha_set_level();
+ alpha_level_last=alpha_level;
+ }
+
+ /* set sprite alpha mode */
+ sprite_alpha_check=0;
+ sprite_alpha_all_2a=1;
+ dpix_sp[1]=0;
+ dpix_sp[2]=0;
+ dpix_sp[4]=0;
+ dpix_sp[8]=0;
+ for(i=0;i<4;i++) /* i = sprite priority offset */
+ {
+ UINT8 sprite_alpha_mode=(sprite_alpha>>(i*2))&3;
+ UINT8 sftbit=1<<i;
+ if(sprite_pri_usage&sftbit)
+ {
+ if(sprite_alpha_mode==1)
+ {
+ if(f3_alpha_level_2as==0 && f3_alpha_level_2ad==255)
+ sprite_pri_usage&=~sftbit; // Disable sprite priority block
+ else
+ {
+ dpix_sp[sftbit]=dpix_n[2];
+ sprite_alpha_check|=sftbit;
+ }
+ }
+ else if(sprite_alpha_mode==2)
+ {
+ if(sprite_alpha&0xff00)
+ {
+ if(f3_alpha_level_3as==0 && f3_alpha_level_3ad==255) sprite_pri_usage&=~sftbit;
+ else
+ {
+ dpix_sp[sftbit]=dpix_n[3];
+ sprite_alpha_check|=sftbit;
+ sprite_alpha_all_2a=0;
+ }
+ }
+ else
+ {
+ if(f3_alpha_level_3bs==0 && f3_alpha_level_3bd==255) sprite_pri_usage&=~sftbit;
+ else
+ {
+ dpix_sp[sftbit]=dpix_n[5];
+ sprite_alpha_check|=sftbit;
+ sprite_alpha_all_2a=0;
+ }
+ }
+ }
+ }
+ }
+
+
+ /* check alpha level */
+ for(i=0;i<5;i++) /* i = playfield num (pos) */
+ {
+ int alpha_type = (alpha_mode_flag[i]>>4)&3;
+
+ if(alpha_mode[i]==2)
+ {
+ if(alpha_type==1)
+ {
+ if (f3_alpha_level_2as==0 && f3_alpha_level_2ad==255) alpha_mode[i]=0;
+ else if(f3_alpha_level_2as==255 && f3_alpha_level_2ad==0 ) alpha_mode[i]=1;
+ }
+ else if(alpha_type==2)
+ {
+ if (f3_alpha_level_2bs==0 && f3_alpha_level_2bd==255) alpha_mode[i]=0;
+ else if(f3_alpha_level_2as==255 && f3_alpha_level_2ad==0 &&
+ f3_alpha_level_2bs==255 && f3_alpha_level_2bd==0 ) alpha_mode[i]=1;
+ }
+ else if(alpha_type==3)
+ {
+ if (f3_alpha_level_2as==0 && f3_alpha_level_2ad==255 &&
+ f3_alpha_level_2bs==0 && f3_alpha_level_2bd==255) alpha_mode[i]=0;
+ else if(f3_alpha_level_2as==255 && f3_alpha_level_2ad==0 &&
+ f3_alpha_level_2bs==255 && f3_alpha_level_2bd==0 ) alpha_mode[i]=1;
+ }
+ }
+ else if(alpha_mode[i]==3)
+ {
+ if(alpha_type==1)
+ {
+ if (f3_alpha_level_3as==0 && f3_alpha_level_3ad==255) alpha_mode[i]=0;
+ else if(f3_alpha_level_3as==255 && f3_alpha_level_3ad==0 ) alpha_mode[i]=1;
+ }
+ else if(alpha_type==2)
+ {
+ if (f3_alpha_level_3bs==0 && f3_alpha_level_3bd==255) alpha_mode[i]=0;
+ else if(f3_alpha_level_3as==255 && f3_alpha_level_3ad==0 &&
+ f3_alpha_level_3bs==255 && f3_alpha_level_3bd==0 ) alpha_mode[i]=1;
+ }
+ else if(alpha_type==3)
+ {
+ if (f3_alpha_level_3as==0 && f3_alpha_level_3ad==255 &&
+ f3_alpha_level_3bs==0 && f3_alpha_level_3bd==255) alpha_mode[i]=0;
+ else if(f3_alpha_level_3as==255 && f3_alpha_level_3ad==0 &&
+ f3_alpha_level_3bs==255 && f3_alpha_level_3bd==0 ) alpha_mode[i]=1;
+ }
+ }
+ }
+
+ if ( (alpha_mode[0]==1 || alpha_mode[0]==2 || !alpha_mode[0]) &&
+ (alpha_mode[1]==1 || alpha_mode[1]==2 || !alpha_mode[1]) &&
+ (alpha_mode[2]==1 || alpha_mode[2]==2 || !alpha_mode[2]) &&
+ (alpha_mode[3]==1 || alpha_mode[3]==2 || !alpha_mode[3]) &&
+ (alpha_mode[4]==1 || alpha_mode[4]==2 || !alpha_mode[4]) &&
+ sprite_alpha_all_2a )
+ {
+ int alpha_type = (alpha_mode_flag[0] | alpha_mode_flag[1] | alpha_mode_flag[2] | alpha_mode_flag[3])&0x30;
+ if( (alpha_type==0x10 && f3_alpha_level_2as==255) ||
+ (alpha_type==0x20 && f3_alpha_level_2as==255 && f3_alpha_level_2bs==255) ||
+ (alpha_type==0x30 && f3_alpha_level_2as==255 && f3_alpha_level_2bs==255) )
+ {
+ if(alpha_mode[0]>1) alpha_mode[0]=1;
+ if(alpha_mode[1]>1) alpha_mode[1]=1;
+ if(alpha_mode[2]>1) alpha_mode[2]=1;
+ if(alpha_mode[3]>1) alpha_mode[3]=1;
+ if(alpha_mode[4]>1) alpha_mode[4]=1;
+ sprite_alpha_check=0;
+ dpix_sp[1]=0;
+ dpix_sp[2]=0;
+ dpix_sp[4]=0;
+ dpix_sp[8]=0;
+ }
+ }
+ }
+ else
+ {
+ sprite_alpha_check=0;
+ dpix_sp[1]=0;
+ dpix_sp[2]=0;
+ dpix_sp[4]=0;
+ dpix_sp[8]=0;
+ }
+
+
+
+ /* set scanline priority */
+ {
+ int pri_max_opa=-1;
+ for(i=0;i<5;i++) /* i = playfield num (pos) */
+ {
+ int p0=pri[i];
+ int pri_sl1=p0&0x0f;
+
+ layer_tmp[i]=i + (pri_sl1<<3);
+
+ if(!alpha_mode[i])
+ {
+ layer_tmp[i]|=0x80;
+ count_skip_layer++;
+ }
+ else if(alpha_mode[i]==1 && (alpha_mode_flag[i]&0x80))
+ {
+ if(layer_tmp[i]>pri_max_opa) pri_max_opa=layer_tmp[i];
+ }
+ }
+
+ if(pri_max_opa!=-1)
+ {
+ if(pri_max_opa>layer_tmp[0]) {layer_tmp[0]|=0x80;count_skip_layer++;}
+ if(pri_max_opa>layer_tmp[1]) {layer_tmp[1]|=0x80;count_skip_layer++;}
+ if(pri_max_opa>layer_tmp[2]) {layer_tmp[2]|=0x80;count_skip_layer++;}
+ if(pri_max_opa>layer_tmp[3]) {layer_tmp[3]|=0x80;count_skip_layer++;}
+ if(pri_max_opa>layer_tmp[4]) {layer_tmp[4]|=0x80;count_skip_layer++;}
+ }
+ }
+
+
+ /* sort layer_tmp */
+ for(i=0;i<4;i++)
+ {
+ for(j=i+1;j<5;j++)
+ {
+ if(layer_tmp[i]<layer_tmp[j])
+ {
+ int temp = layer_tmp[i];
+ layer_tmp[i] = layer_tmp[j];
+ layer_tmp[j] = temp;
+ }
+ }
+ }
+
+
+ /* check sprite & layer priority */
+ {
+ int l0,l1,l2,l3,l4;
+ int pri_sp[5];
+
+ l0=layer_tmp[0]>>3;
+ l1=layer_tmp[1]>>3;
+ l2=layer_tmp[2]>>3;
+ l3=layer_tmp[3]>>3;
+ l4=layer_tmp[4]>>3;
+
+ pri_sp[0]=spri&0xf;
+ pri_sp[1]=(spri>>4)&0xf;
+ pri_sp[2]=(spri>>8)&0xf;
+ pri_sp[3]=spri>>12;
+
+ for(i=0;i<4;i++) /* i = sprite priority offset */
+ {
+ int sp,sflg=1<<i;
+ if(!(sprite_pri_usage & sflg)) continue;
+ sp=pri_sp[i];
+
+ /*
+ sprite priority==playfield priority
+ BUBSYMPH (title) ---> sprite
+ DARIUSG (ZONE V' BOSS) ---> playfield
+ */
+
+ if (f3_game == BUBSYMPH ) sp++; //BUBSYMPH (title)
+
+ if( sp>l0) sprite[0]|=sflg;
+ else if(sp<=l0 && sp>l1) sprite[1]|=sflg;
+ else if(sp<=l1 && sp>l2) sprite[2]|=sflg;
+ else if(sp<=l2 && sp>l3) sprite[3]|=sflg;
+ else if(sp<=l3 && sp>l4) sprite[4]|=sflg;
+ else if(sp<=l4 ) sprite[5]|=sflg;
+ }
+ }
+
+
+ /* draw scanlines */
+ alpha=0;
+ for(i=count_skip_layer;i<5;i++)
+ {
+ pos=layer_tmp[i]&7;
+ line_t[i]=&pf_line_inf[pos];
+
+ if(sprite[i]&sprite_alpha_check) alpha=1;
+ else if(!alpha) sprite[i]|=0x100;
+
+ if(alpha_mode[pos]>1)
+ {
+ int alpha_type=(((alpha_mode_flag[pos]>>4)&3)-1)*2;
+ dpix_lp[i]=dpix_n[alpha_mode[pos]+alpha_type];
+ alpha=1;
+ }
+ else
+ {
+ if(alpha) dpix_lp[i]=dpix_n[1];
+ else dpix_lp[i]=dpix_n[0];
+ }
+ }
+ if(sprite[5]&sprite_alpha_check) alpha=1;
+ else if(!alpha) sprite[5]|=0x100;
+
+ draw_scanlines(machine, bitmap,320,draw_line_num,line_t,sprite,rot,count_skip_layer);
+ if(y_start<0) break;
+ }
+}
+
+/******************************************************************************/
+
+#define PSET_T \
+ c = *source; \
+ if(c) \
+ { \
+ p=*pri; \
+ if(!p || p==0xff) \
+ { \
+ *dest = pal[c]; \
+ *pri = pri_dst; \
+ } \
+ }
+
+#define PSET_O \
+ p=*pri; \
+ if(!p || p==0xff) \
+ { \
+ *dest = pal[*source]; \
+ *pri = pri_dst; \
+ }
+
+#define NEXT_P \
+ source += dx; \
+ dest++; \
+ pri++;
+
+INLINE void f3_drawgfx( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ UINT32 code,
+ UINT32 color,
+ int flipx,int flipy,
+ int sx,int sy,
+ const rectangle *clip,
+ UINT8 pri_dst)
+{
+ rectangle myclip;
+
+ pri_dst=1<<pri_dst;
+
+ /* KW 991012 -- Added code to force clip to bitmap boundary */
+ if(clip)
+ {
+ myclip.min_x = clip->min_x;
+ myclip.max_x = clip->max_x;
+ myclip.min_y = clip->min_y;
+ myclip.max_y = clip->max_y;
+
+ if (myclip.min_x < 0) myclip.min_x = 0;
+ if (myclip.max_x >= dest_bmp->width) myclip.max_x = dest_bmp->width-1;
+ if (myclip.min_y < 0) myclip.min_y = 0;
+ if (myclip.max_y >= dest_bmp->height) myclip.max_y = dest_bmp->height-1;
+
+ clip=&myclip;
+ }
+
+
+ if( gfx )
+ {
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+ int source_base = (code % gfx->total_elements) * 16;
+
+ {
+ /* compute sprite increment per screen pixel */
+ int dx = 1;
+ int dy = 1;
+
+ int ex = sx+16;
+ int ey = sy+16;
+
+ int x_index_base;
+ int y_index;
+
+ if( flipx )
+ {
+ x_index_base = 15;
+ dx = -1;
+ }
+ else
+ {
+ x_index_base = 0;
+ }
+
+ if( flipy )
+ {
+ y_index = 15;
+ dy = -1;
+ }
+ else
+ {
+ y_index = 0;
+ }
+
+ if( clip )
+ {
+ if( sx < clip->min_x)
+ { /* clip left */
+ int pixels = clip->min_x-sx;
+ sx += pixels;
+ x_index_base += pixels*dx;
+ }
+ if( sy < clip->min_y )
+ { /* clip top */
+ int pixels = clip->min_y-sy;
+ sy += pixels;
+ y_index += pixels*dy;
+ }
+ /* NS 980211 - fixed incorrect clipping */
+ if( ex > clip->max_x+1 )
+ { /* clip right */
+ int pixels = ex-clip->max_x-1;
+ ex -= pixels;
+ }
+ if( ey > clip->max_y+1 )
+ { /* clip bottom */
+ int pixels = ey-clip->max_y-1;
+ ey -= pixels;
+ }
+ }
+
+ if( ex>sx && ey>sy)
+ { /* skip if inner loop doesn't draw anything */
+// if (dest_bmp->bpp == 32)
+ {
+ int y=ey-sy;
+ int x=(ex-sx-1)|(tile_opaque_sp[code % gfx->total_elements]<<4);
+ UINT8 *source0 = gfx->gfxdata + (source_base+y_index) * 16 + x_index_base;
+ UINT32 *dest0 = BITMAP_ADDR32(dest_bmp, sy, sx);
+ UINT8 *pri0 = BITMAP_ADDR8(pri_alp_bitmap, sy, sx);
+ int yadv = dest_bmp->rowpixels;
+ dy=dy*16;
+ while(1)
+ {
+ UINT8 *source = source0;
+ UINT32 *dest = dest0;
+ UINT8 *pri = pri0;
+
+ switch(x)
+ {
+ int c;
+ UINT8 p;
+ case 31: PSET_O NEXT_P
+ case 30: PSET_O NEXT_P
+ case 29: PSET_O NEXT_P
+ case 28: PSET_O NEXT_P
+ case 27: PSET_O NEXT_P
+ case 26: PSET_O NEXT_P
+ case 25: PSET_O NEXT_P
+ case 24: PSET_O NEXT_P
+ case 23: PSET_O NEXT_P
+ case 22: PSET_O NEXT_P
+ case 21: PSET_O NEXT_P
+ case 20: PSET_O NEXT_P
+ case 19: PSET_O NEXT_P
+ case 18: PSET_O NEXT_P
+ case 17: PSET_O NEXT_P
+ case 16: PSET_O break;
+
+ case 15: PSET_T NEXT_P
+ case 14: PSET_T NEXT_P
+ case 13: PSET_T NEXT_P
+ case 12: PSET_T NEXT_P
+ case 11: PSET_T NEXT_P
+ case 10: PSET_T NEXT_P
+ case 9: PSET_T NEXT_P
+ case 8: PSET_T NEXT_P
+ case 7: PSET_T NEXT_P
+ case 6: PSET_T NEXT_P
+ case 5: PSET_T NEXT_P
+ case 4: PSET_T NEXT_P
+ case 3: PSET_T NEXT_P
+ case 2: PSET_T NEXT_P
+ case 1: PSET_T NEXT_P
+ case 0: PSET_T
+ }
+
+ if(!(--y)) break;
+ source0 += dy;
+ dest0+=yadv;
+ pri0+=yadv;
+ }
+ }
+ }
+ }
+ }
+}
+#undef PSET_T
+#undef PSET_O
+#undef NEXT_P
+
+
+INLINE void f3_drawgfxzoom(mame_bitmap *dest_bmp,const gfx_element *gfx,
+ UINT32 code,
+ UINT32 color,
+ int flipx,int flipy,
+ int sx,int sy,
+ const rectangle *clip,
+ int scalex, int scaley,
+ UINT8 pri_dst)
+{
+ rectangle myclip;
+
+ pri_dst=1<<pri_dst;
+
+ /* KW 991012 -- Added code to force clip to bitmap boundary */
+ if(clip)
+ {
+ myclip.min_x = clip->min_x;
+ myclip.max_x = clip->max_x;
+ myclip.min_y = clip->min_y;
+ myclip.max_y = clip->max_y;
+
+ if (myclip.min_x < 0) myclip.min_x = 0;
+ if (myclip.max_x >= dest_bmp->width) myclip.max_x = dest_bmp->width-1;
+ if (myclip.min_y < 0) myclip.min_y = 0;
+ if (myclip.max_y >= dest_bmp->height) myclip.max_y = dest_bmp->height-1;
+
+ clip=&myclip;
+ }
+
+
+ if( gfx )
+ {
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+ int source_base = (code % gfx->total_elements) * 16;
+
+ {
+ /* compute sprite increment per screen pixel */
+ int dx = (16<<16)/scalex;
+ int dy = (16<<16)/scaley;
+
+ int ex = sx+scalex;
+ int ey = sy+scaley;
+
+ int x_index_base;
+ int y_index;
+
+ if( flipx )
+ {
+ x_index_base = (scalex-1)*dx;
+ dx = -dx;
+ }
+ else
+ {
+ x_index_base = 0;
+ }
+
+ if( flipy )
+ {
+ y_index = (scaley-1)*dy;
+ dy = -dy;
+ }
+ else
+ {
+ y_index = 0;
+ }
+
+ if( clip )
+ {
+ if( sx < clip->min_x)
+ { /* clip left */
+ int pixels = clip->min_x-sx;
+ sx += pixels;
+ x_index_base += pixels*dx;
+ }
+ if( sy < clip->min_y )
+ { /* clip top */
+ int pixels = clip->min_y-sy;
+ sy += pixels;
+ y_index += pixels*dy;
+ }
+ /* NS 980211 - fixed incorrect clipping */
+ if( ex > clip->max_x+1 )
+ { /* clip right */
+ int pixels = ex-clip->max_x-1;
+ ex -= pixels;
+ }
+ if( ey > clip->max_y+1 )
+ { /* clip bottom */
+ int pixels = ey-clip->max_y-1;
+ ey -= pixels;
+ }
+ }
+
+ if( ex>sx )
+ { /* skip if inner loop doesn't draw anything */
+// if (dest_bmp->bpp == 32)
+ {
+ int y;
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = gfx->gfxdata + (source_base+(y_index>>16)) * 16;
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+ UINT8 *pri = BITMAP_ADDR8(pri_alp_bitmap, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if(c)
+ {
+ UINT8 p=pri[x];
+ if (p == 0 || p == 0xff)
+ {
+ dest[x] = pal[c];
+ pri[x] = pri_dst;
+ }
+ }
+ x_index += dx;
+ }
+ y_index += dy;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+#define CALC_ZOOM(p) { \
+ p##_addition = 0x100 - block_zoom_##p + p##_addition_left; \
+ p##_addition_left = p##_addition & 0xf; \
+ p##_addition = p##_addition >> 4; \
+ /*zoom##p = p##_addition << 12;*/ \
+}
+
+static void get_sprite_info(running_machine *machine, const UINT32 *spriteram32_ptr)
+{
+ const int min_x=machine->screen[0].visarea.min_x,max_x=machine->screen[0].visarea.max_x;
+ const int min_y=machine->screen[0].visarea.min_y,max_y=machine->screen[0].visarea.max_y;
+ int offs,spritecont,flipx,flipy,old_x,old_y,color,x,y;
+ int sprite,global_x=0,global_y=0,subglobal_x=0,subglobal_y=0;
+ int block_x=0, block_y=0;
+ int last_color=0,last_x=0,last_y=0,block_zoom_x=0,block_zoom_y=0;
+ int this_x,this_y;
+ int y_addition=16, x_addition=16;
+ int multi=0;
+ int sprite_top;
+
+ int x_addition_left = 8, y_addition_left = 8;
+
+ struct tempsprite *sprite_ptr = spritelist;
+
+ int total_sprites=0;
+
+ color=0;
+ flipx=flipy=0;
+ old_y=old_x=0;
+ y=x=0;
+
+ sprite_top=0x1000;
+ for (offs = 0; offs < sprite_top && (total_sprites < 0x400); offs += 4)
+ {
+ const int current_offs=offs; /* Offs can change during loop, current_offs cannot */
+
+ /* Check if the sprite list jump command bit is set */
+ if ((spriteram32_ptr[current_offs+3]>>16) & 0x8000) {
+ UINT32 jump = (spriteram32_ptr[current_offs+3]>>16)&0x3ff;
+
+ UINT32 new_offs=((offs&0x2000)|((jump<<4)/4));
+ if (new_offs==offs)
+ break;
+ offs=new_offs - 4;
+ }
+
+ /* Check if special command bit is set */
+ if (spriteram32_ptr[current_offs+1] & 0x8000) {
+ UINT32 cntrl=(spriteram32_ptr[current_offs+2])&0xffff;
+ flipscreen=cntrl&0x2000;
+
+ /* cntrl&0x1000 = disabled? (From F2 driver, doesn't seem used anywhere)
+ cntrl&0x0010 = ???
+ cntrl&0x0020 = ???
+ */
+
+ /* Sprite bank select */
+ if (cntrl&1) {
+ offs=offs|0x2000;
+ sprite_top=sprite_top|0x2000;
+ }
+ }
+
+ /* Set global sprite scroll */
+ if (((spriteram32_ptr[current_offs+1]>>16) & 0xf000) == 0xa000) {
+ global_x = (spriteram32_ptr[current_offs+1]>>16) & 0xfff;
+ if (global_x >= 0x800) global_x -= 0x1000;
+ global_y = spriteram32_ptr[current_offs+1] & 0xfff;
+ if (global_y >= 0x800) global_y -= 0x1000;
+ }
+
+ /* And sub-global sprite scroll */
+ if (((spriteram32_ptr[current_offs+1]>>16) & 0xf000) == 0x5000) {
+ subglobal_x = (spriteram32_ptr[current_offs+1]>>16) & 0xfff;
+ if (subglobal_x >= 0x800) subglobal_x -= 0x1000;
+ subglobal_y = spriteram32_ptr[current_offs+1] & 0xfff;
+ if (subglobal_y >= 0x800) subglobal_y -= 0x1000;
+ }
+
+ if (((spriteram32_ptr[current_offs+1]>>16) & 0xf000) == 0xb000) {
+ subglobal_x = (spriteram32_ptr[current_offs+1]>>16) & 0xfff;
+ if (subglobal_x >= 0x800) subglobal_x -= 0x1000;
+ subglobal_y = spriteram32_ptr[current_offs+1] & 0xfff;
+ if (subglobal_y >= 0x800) subglobal_y -= 0x1000;
+ global_y=subglobal_y;
+ global_x=subglobal_x;
+ }
+
+ /* A real sprite to process! */
+ sprite = (spriteram32_ptr[current_offs]>>16) | ((spriteram32_ptr[current_offs+2]&1)<<16);
+ spritecont = spriteram32_ptr[current_offs+2]>>24;
+
+/* These games either don't set the XY control bits properly (68020 bug?), or
+ have some different mode from the others */
+#ifdef DARIUSG_KLUDGE
+ if (f3_game==DARIUSG || f3_game==GEKIRIDO || f3_game==CLEOPATR || f3_game==RECALH)
+ multi=spritecont&0xf0;
+#endif
+
+ /* Check if this sprite is part of a continued block */
+ if (multi) {
+ /* Bit 0x4 is 'use previous colour' for this block part */
+ if (spritecont&0x4) color=last_color;
+ else color=(spriteram32_ptr[current_offs+2]>>16)&0xff;
+
+#ifdef DARIUSG_KLUDGE
+ if (f3_game==DARIUSG || f3_game==GEKIRIDO || f3_game==CLEOPATR || f3_game==RECALH) {
+ /* Adjust X Position */
+ if ((spritecont & 0x40) == 0) {
+ if (spritecont & 0x4) {
+ x = block_x;
+ } else {
+ this_x = spriteram32_ptr[current_offs+1]>>16;
+ if (this_x&0x800) this_x= 0 - (0x800 - (this_x&0x7ff)); else this_x&=0x7ff;
+
+ if ((spriteram32_ptr[current_offs+1]>>16)&0x8000) {
+ this_x+=0;
+ } else if ((spriteram32_ptr[current_offs+1]>>16)&0x4000) {
+ /* Ignore subglobal (but apply global) */
+ this_x+=global_x;
+ } else { /* Apply both scroll offsets */
+ this_x+=global_x+subglobal_x;
+ }
+
+ x = block_x = this_x;
+ }
+ x_addition_left = 8;
+ CALC_ZOOM(x)
+ }
+ else if ((spritecont & 0x80) != 0) {
+ x = last_x+x_addition;
+ CALC_ZOOM(x)
+ }
+
+ /* Adjust Y Position */
+ if ((spritecont & 0x10) == 0) {
+ if (spritecont & 0x4) {
+ y = block_y;
+ } else {
+ this_y = spriteram32_ptr[current_offs+1]&0xffff;
+ if (this_y&0x800) this_y= 0 - (0x800 - (this_y&0x7ff)); else this_y&=0x7ff;
+
+ if ((spriteram32_ptr[current_offs+1]>>16)&0x8000) {
+ this_y+=0;
+ } else if ((spriteram32_ptr[current_offs+1]>>16)&0x4000) {
+ /* Ignore subglobal (but apply global) */
+ this_y+=global_y;
+ } else { /* Apply both scroll offsets */
+ this_y+=global_y+subglobal_y;
+ }
+
+ y = block_y = this_y;
+ }
+ y_addition_left = 8;
+ CALC_ZOOM(y)
+ }
+ else if ((spritecont & 0x20) != 0) {
+ y = last_y+y_addition;
+ CALC_ZOOM(y)
+ }
+ } else
+#endif
+ {
+ /* Adjust X Position */
+ if ((spritecont & 0x40) == 0) {
+ x = block_x;
+ x_addition_left = 8;
+ CALC_ZOOM(x)
+ }
+ else if ((spritecont & 0x80) != 0) {
+ x = last_x+x_addition;
+ CALC_ZOOM(x)
+ }
+ /* Adjust Y Position */
+ if ((spritecont & 0x10) == 0) {
+ y = block_y;
+ y_addition_left = 8;
+ CALC_ZOOM(y)
+ }
+ else if ((spritecont & 0x20) != 0) {
+ y = last_y+y_addition;
+ CALC_ZOOM(y)
+ }
+ /* Both zero = reread block latch? */
+ }
+ }
+ /* Else this sprite is the possible start of a block */
+ else {
+ color = (spriteram32_ptr[current_offs+2]>>16)&0xff;
+ last_color=color;
+
+ /* Sprite positioning */
+ this_y = spriteram32_ptr[current_offs+1]&0xffff;
+ this_x = spriteram32_ptr[current_offs+1]>>16;
+ if (this_y&0x800) this_y= 0 - (0x800 - (this_y&0x7ff)); else this_y&=0x7ff;
+ if (this_x&0x800) this_x= 0 - (0x800 - (this_x&0x7ff)); else this_x&=0x7ff;
+
+ /* Ignore both scroll offsets for this block */
+ if ((spriteram32_ptr[current_offs+1]>>16)&0x8000) {
+ this_x+=0;
+ this_y+=0;
+ } else if ((spriteram32_ptr[current_offs+1]>>16)&0x4000) {
+ /* Ignore subglobal (but apply global) */
+ this_x+=global_x;
+ this_y+=global_y;
+ } else { /* Apply both scroll offsets */
+ this_x+=global_x+subglobal_x;
+ this_y+=global_y+subglobal_y;
+ }
+
+ block_y = y = this_y;
+ block_x = x = this_x;
+
+ block_zoom_x=spriteram32_ptr[current_offs];
+ block_zoom_y=(block_zoom_x>>8)&0xff;
+ block_zoom_x&=0xff;
+
+ x_addition_left = 8;
+ CALC_ZOOM(x)
+
+ y_addition_left = 8;
+ CALC_ZOOM(y)
+ }
+
+ /* These features are common to sprite and block parts */
+ flipx = spritecont&0x1;
+ flipy = spritecont&0x2;
+ multi = spritecont&0x8;
+ last_x=x;
+ last_y=y;
+
+ if (!sprite) continue;
+ if (!x_addition || !y_addition) continue;
+
+ if (flipscreen)
+ {
+ int tx,ty;
+
+ tx = 512-x_addition-x;
+ ty = 256-y_addition-y;
+
+ if (tx+x_addition<=min_x || tx>max_x || ty+y_addition<=min_y || ty>max_y) continue;
+ sprite_ptr->x = tx;
+ sprite_ptr->y = ty;
+ sprite_ptr->flipx = !flipx;
+ sprite_ptr->flipy = !flipy;
+ }
+ else
+ {
+ if (x+x_addition<=min_x || x>max_x || y+y_addition<=min_y || y>max_y) continue;
+ sprite_ptr->x = x;
+ sprite_ptr->y = y;
+ sprite_ptr->flipx = flipx;
+ sprite_ptr->flipy = flipy;
+ }
+
+
+ sprite_ptr->code = sprite;
+ sprite_ptr->color = color;
+ sprite_ptr->zoomx = x_addition;
+ sprite_ptr->zoomy = y_addition;
+ sprite_ptr->pri = (color & 0xc0) >> 6;
+ sprite_ptr++;
+ total_sprites++;
+ }
+ sprite_end = sprite_ptr;
+}
+#undef CALC_ZOOM
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const struct tempsprite *sprite_ptr;
+ const gfx_element *sprite_gfx = machine->gfx[2];
+
+ sprite_ptr = sprite_end;
+ sprite_pri_usage=0;
+ while (sprite_ptr != spritelist)
+ {
+ int pri;
+ sprite_ptr--;
+
+ pri=sprite_ptr->pri;
+ sprite_pri_usage|=1<<pri;
+
+ if(sprite_ptr->zoomx==16 && sprite_ptr->zoomy==16)
+ f3_drawgfx(bitmap,sprite_gfx,
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,
+ pri);
+ else
+ f3_drawgfxzoom(bitmap,sprite_gfx,
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,
+ sprite_ptr->zoomx,sprite_ptr->zoomy,
+ pri);
+ }
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( f3 )
+{
+ UINT32 sy_fix[5],sx_fix[5];
+ int tile;
+
+ f3_skip_this_frame=0;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ /* Dynamically decode VRAM chars if dirty */
+ if (vram_changed)
+ for (tile = 0;tile < 256;tile++)
+ if (vram_dirty[tile]) {
+ decodechar(machine->gfx[0],tile,(UINT8 *)f3_vram,machine->drv->gfxdecodeinfo[0].gfxlayout);
+ tilemap_mark_all_tiles_dirty(vram_layer); // TODO
+ //tilemap_mark_tile_dirty(vram_layer,tile);
+ vram_dirty[tile]=0;
+ }
+
+ /* Decode chars & mark tilemap dirty */
+ if (pivot_changed)
+ for (tile = 0;tile < 2048;tile++)
+ if (pivot_dirty[tile]) {
+ decodechar(machine->gfx[3],tile,(UINT8 *)f3_pivot_ram,machine->drv->gfxdecodeinfo[3].gfxlayout);
+ tilemap_mark_tile_dirty(pixel_layer,tile);
+ pivot_dirty[tile]=0;
+ }
+ pivot_changed=vram_changed=0;
+
+ /* Setup scroll */
+ sy_fix[0]=((f3_control_0[2]&0xffff0000)>> 7) + (1<<16);
+ sy_fix[1]=((f3_control_0[2]&0x0000ffff)<< 9) + (1<<16);
+ sy_fix[2]=((f3_control_0[3]&0xffff0000)>> 7) + (1<<16);
+ sy_fix[3]=((f3_control_0[3]&0x0000ffff)<< 9) + (1<<16);
+ sx_fix[0]=((f3_control_0[0]&0xffc00000)>> 6) - (6<<16);
+ sx_fix[1]=((f3_control_0[0]&0x0000ffc0)<<10) - (10<<16);
+ sx_fix[2]=((f3_control_0[1]&0xffc00000)>> 6) - (14<<16);
+ sx_fix[3]=((f3_control_0[1]&0x0000ffc0)<<10) - (18<<16);
+ sx_fix[4]=-(f3_control_1[2]>>16)+41;
+ sy_fix[4]=-(f3_control_1[2]&0x1ff);
+
+ sx_fix[0]-=((f3_control_0[0]&0x003f0000)>> 6)+0x0400-0x10000;
+ sx_fix[1]-=((f3_control_0[0]&0x0000003f)<<10)+0x0400-0x10000;
+ sx_fix[2]-=((f3_control_0[1]&0x003f0000)>> 6)+0x0400-0x10000;
+ sx_fix[3]-=((f3_control_0[1]&0x0000003f)<<10)+0x0400-0x10000;
+
+ if (flipscreen)
+ {
+ sy_fix[0]= 0x3000000-sy_fix[0];
+ sy_fix[1]= 0x3000000-sy_fix[1];
+ sy_fix[2]= 0x3000000-sy_fix[2];
+ sy_fix[3]= 0x3000000-sy_fix[3];
+ sx_fix[0]=-0x1a00000-sx_fix[0];
+ sx_fix[1]=-0x1a00000-sx_fix[1];
+ sx_fix[2]=-0x1a00000-sx_fix[2];
+ sx_fix[3]=-0x1a00000-sx_fix[3];
+ sx_fix[4]=-sx_fix[4] + 75;
+ sy_fix[4]=-sy_fix[4];
+ }
+
+ fillbitmap(pri_alp_bitmap,0,cliprect);
+
+ /* sprites */
+ if (sprite_lag==0)
+ get_sprite_info(machine, spriteram32);
+
+ /* Update sprite buffer */
+ draw_sprites(machine, bitmap,cliprect);
+
+ /* Parse sprite, alpha & clipping parts of lineram */
+ get_spritealphaclip_info();
+
+ /* Parse playfield effects */
+ get_line_ram_info(machine, pf1_tilemap,sx_fix[0],sy_fix[0],0,f3_pf_data_1);
+ get_line_ram_info(machine, pf2_tilemap,sx_fix[1],sy_fix[1],1,f3_pf_data_2);
+ get_line_ram_info(machine, pf3_tilemap,sx_fix[2],sy_fix[2],2,f3_pf_data_3);
+ get_line_ram_info(machine, pf4_tilemap,sx_fix[3],sy_fix[3],3,f3_pf_data_4);
+ get_vram_info(vram_layer,pixel_layer,sx_fix[4],sy_fix[4]);
+
+ /* Draw final framebuffer */
+ scanline_draw(machine, bitmap,cliprect);
+
+ if (VERBOSE)
+ print_debug_info(bitmap);
+ return 0;
+}
diff --git a/src/mame/video/taito_h.c b/src/mame/video/taito_h.c
new file mode 100644
index 00000000000..deeff0a74a7
--- /dev/null
+++ b/src/mame/video/taito_h.c
@@ -0,0 +1,502 @@
+/***************************************************************************
+
+Functions to emulate the video hardware of the machine.
+
+TODO
+====
+
+Harmonise draw_sprites code and offload it into taitoic.c, leaving this
+as short as possible (TC0080VCO has sprites as well as tilemaps in its
+address space).
+
+Maybe wait until the Taito Air system is done - also uses TC0080VCO.
+
+Why does syvalion draw_sprites ignore the zoomy value
+(using zoomx instead) ???
+
+
+Sprite ram notes
+----------------
+
+BG / chain RAM
+-----------------------------------------
+[0] +0 +1
+ -xxx xxxx xxxx xxxx = tile number
+
+[1] +0 +1
+ ---- ---- x--- ---- = flip Y
+ ---- ---- -x-- ---- = flip X
+ ---- ---- --xx xxxx = color
+
+
+sprite RAM
+--------------------------------------------------------------
+ +0 +1 +2 +3
+ ---x ---- ---- ---- ---- ---- ---- ---- = unknown
+ ---- xx-- ---- ---- ---- ---- ---- ---- = chain y size
+ ---- --xx xxxx xxxx ---- ---- ---- ---- = sprite x coords
+ ---- ---- ---- ---- ---- --xx xxxx xxxx = sprite y coords
+
+ +4 +5 +6 +7
+ --xx xxxx ---- ---- ---- ---- ---- ---- = zoom x
+ ---- ---- --xx xxxx ---- ---- ---- ---- = zoom y
+ ---- ---- ---- ---- ---x xxxx xxxx xxxx = tile information offset
+
+
+***************************************************************************/
+
+#include "driver.h"
+#include "taitoic.h"
+
+
+extern UINT16 *TC0080VCO_chain_ram_0;
+extern UINT16 *TC0080VCO_chain_ram_1;
+extern UINT16 *TC0080VCO_spriteram;
+extern UINT16 *TC0080VCO_scroll_ram;
+extern int TC0080VCO_flipscreen;
+
+/* Needed in the sprite palette color marking */
+extern int TC0080VCO_has_tx;
+
+/* These are hand-tuned values */
+static int zoomy_conv_table[] =
+{
+/* +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f */
+ 0x00,0x01,0x01,0x02,0x02,0x03,0x04,0x05, 0x06,0x06,0x07,0x08,0x09,0x0a,0x0a,0x0b, /* 0x00 */
+ 0x0b,0x0c,0x0c,0x0d,0x0e,0x0e,0x0f,0x10, 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x16,
+ 0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e, 0x1f,0x20,0x21,0x22,0x24,0x25,0x26,0x27,
+ 0x28,0x2a,0x2b,0x2c,0x2e,0x30,0x31,0x32, 0x34,0x36,0x37,0x38,0x3a,0x3c,0x3e,0x3f,
+
+ 0x40,0x41,0x42,0x42,0x43,0x43,0x44,0x44, 0x45,0x45,0x46,0x46,0x47,0x47,0x48,0x49, /* 0x40 */
+ 0x4a,0x4a,0x4b,0x4b,0x4c,0x4d,0x4e,0x4f, 0x4f,0x50,0x51,0x51,0x52,0x53,0x54,0x55,
+ 0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d, 0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x66,
+ 0x67,0x68,0x6a,0x6b,0x6c,0x6e,0x6f,0x71, 0x72,0x74,0x76,0x78,0x80,0x7b,0x7d,0x7f
+};
+
+
+
+/***************************************************************************
+ Initialize and destroy video hardware emulation
+***************************************************************************/
+
+VIDEO_START( syvalion )
+{
+ TC0080VCO_vh_start(machine,0,1,1,1,-2);
+}
+
+VIDEO_START( recordbr )
+{
+ TC0080VCO_vh_start(machine,0,0,1,1,-2);
+}
+
+VIDEO_START( dleague )
+{
+ TC0080VCO_vh_start(machine,0,0,1,1,-2);
+}
+
+
+/***************************************************************************
+ Screen refresh
+***************************************************************************/
+
+static void syvalion_draw_sprites(mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ /* Y chain size is 16/32?/64/64? pixels. X chain size
+ is always 64 pixels. */
+
+ static const int size[] = { 1, 2, 4, 4 };
+ int x0, y0, x, y, dx, ex, zx;
+ int ysize;
+ int j, k;
+ int offs; /* sprite RAM offset */
+ int tile_offs; /* sprite chain offset */
+ int zoomx; /* zoomx value */
+
+ for (offs = 0x03f8 / 2 ; offs >= 0 ; offs -= 0x008 / 2)
+ {
+ x0 = TC0080VCO_spriteram[offs + 1] & 0x3ff;
+ y0 = TC0080VCO_spriteram[offs + 0] & 0x3ff;
+ zoomx = (TC0080VCO_spriteram[offs + 2] & 0x7f00) >> 8;
+ tile_offs = (TC0080VCO_spriteram[offs + 3] & 0x1fff) << 2;
+ ysize = size[ ( TC0080VCO_spriteram[ offs ] & 0x0c00 ) >> 10 ];
+
+ if (tile_offs)
+ {
+ /* The increasing ratio of expansion is different whether zoom value */
+ /* is less or more than 63. */
+ if (zoomx < 63)
+ {
+ dx = 8 + (zoomx + 2) / 8;
+ ex = (zoomx + 2) % 8;
+ zx = ((dx << 1) + ex) << 11;
+ }
+ else
+ {
+ dx = 16 + (zoomx - 63) / 4;
+ ex = (zoomx - 63) % 4;
+ zx = (dx + ex) << 12;
+ }
+
+ if (x0 >= 0x200) x0 -= 0x400;
+ if (y0 >= 0x200) y0 -= 0x400;
+
+ if (TC0080VCO_flipscreen)
+ {
+ x0 = 497 - x0;
+ y0 = 498 - y0;
+ dx = -dx;
+ }
+ else
+ {
+ x0 += 1;
+ y0 += 2;
+ }
+
+ y = y0;
+ for ( j = 0 ; j < ysize ; j ++ )
+ {
+ x = x0;
+ for (k = 0 ; k < 4 ; k ++ )
+ {
+ if (tile_offs >= 0x1000)
+ {
+ int tile, color, flipx, flipy;
+
+ tile = TC0080VCO_chain_ram_0[tile_offs] & 0x7fff;
+ color = TC0080VCO_chain_ram_1[tile_offs] & 0x001f;
+ flipx = TC0080VCO_chain_ram_1[tile_offs] & 0x0040;
+ flipy = TC0080VCO_chain_ram_1[tile_offs] & 0x0080;
+
+ if (TC0080VCO_flipscreen)
+ {
+ flipx ^= 0x0040;
+ flipy ^= 0x0080;
+ }
+
+ drawgfxzoom( bitmap, Machine -> gfx[0],
+ tile,
+ color,
+ flipx, flipy,
+ x, y,
+ cliprect,
+ TRANSPARENCY_PEN, 0,
+ zx, zx
+ );
+ }
+ tile_offs ++;
+ x += dx;
+ }
+ y += dx;
+ }
+ }
+ }
+}
+
+static void recordbr_draw_sprites(mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ /* Y chain size is 16/32?/64/64? pixels. X chain size
+ is always 64 pixels. */
+
+ static const int size[] = { 1, 2, 4, 4 };
+ int x0, y0, x, y, dx, dy, ex, ey, zx, zy;
+ int ysize;
+ int j, k;
+ int offs; /* sprite RAM offset */
+ int tile_offs; /* sprite chain offset */
+ int zoomx, zoomy; /* zoom value */
+
+ for (offs = 0x03f8 / 2 ; offs >= 0 ; offs -= 0x008 / 2)
+ {
+ if (offs < 0x01b0 && priority == 0) continue;
+ if (offs >= 0x01b0 && priority == 1) continue;
+
+ x0 = TC0080VCO_spriteram[offs + 1] & 0x3ff;
+ y0 = TC0080VCO_spriteram[offs + 0] & 0x3ff;
+ zoomx = (TC0080VCO_spriteram[offs + 2] & 0x7f00) >> 8;
+ zoomy = (TC0080VCO_spriteram[offs + 2] & 0x007f);
+ tile_offs = (TC0080VCO_spriteram[offs + 3] & 0x1fff) << 2;
+ ysize = size[ ( TC0080VCO_spriteram[ offs ] & 0x0c00 ) >> 10 ];
+
+ if (tile_offs)
+ {
+ /* Convert zoomy value to real value as zoomx */
+ zoomy = zoomy_conv_table[zoomy];
+
+ if (zoomx < 63)
+ {
+ dx = 8 + (zoomx + 2) / 8;
+ ex = (zoomx + 2) % 8;
+ zx = ((dx << 1) + ex) << 11;
+ }
+ else
+ {
+ dx = 16 + (zoomx - 63) / 4;
+ ex = (zoomx - 63) % 4;
+ zx = (dx + ex) << 12;
+ }
+
+ if (zoomy < 63)
+ {
+ dy = 8 + (zoomy + 2) / 8;
+ ey = (zoomy + 2) % 8;
+ zy = ((dy << 1) + ey) << 11;
+ }
+ else
+ {
+ dy = 16 + (zoomy - 63) / 4;
+ ey = (zoomy - 63) % 4;
+ zy = (dy + ey) << 12;
+ }
+
+ if (x0 >= 0x200) x0 -= 0x400;
+ if (y0 >= 0x200) y0 -= 0x400;
+
+ if (TC0080VCO_flipscreen)
+ {
+ x0 = 497 - x0;
+ y0 = 498 - y0;
+ dx = -dx;
+ dy = -dy;
+ }
+ else
+ {
+ x0 += 1;
+ y0 += 2;
+ }
+
+ y = y0;
+ for (j = 0 ; j < ysize ; j ++)
+ {
+ x = x0;
+ for (k = 0 ; k < 4 ; k ++)
+ {
+ if (tile_offs >= 0x1000)
+ {
+ int tile, color, flipx, flipy;
+
+ tile = TC0080VCO_chain_ram_0[tile_offs] & 0x7fff;
+ color = TC0080VCO_chain_ram_1[tile_offs] & 0x001f;
+ flipx = TC0080VCO_chain_ram_1[tile_offs] & 0x0040;
+ flipy = TC0080VCO_chain_ram_1[tile_offs] & 0x0080;
+
+ if (TC0080VCO_flipscreen)
+ {
+ flipx ^= 0x0040;
+ flipy ^= 0x0080;
+ }
+
+ drawgfxzoom( bitmap, Machine -> gfx[0],
+ tile,
+ color,
+ flipx, flipy,
+ x, y,
+ cliprect,
+ TRANSPARENCY_PEN, 0,
+ zx, zy
+ );
+ }
+ tile_offs ++;
+ x += dx;
+ }
+ y += dy;
+ }
+ }
+ }
+}
+
+static void dleague_draw_sprites(mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ /* Y chain size is 16/32?/64/64? pixels. X chain size
+ is always 64 pixels. */
+
+ static const int size[] = { 1, 2, 4, 4 };
+ int x0, y0, x, y, dx, ex, zx;
+ int ysize;
+ int j, k;
+ int offs; /* sprite RAM offset */
+ int tile_offs; /* sprite chain offset */
+ int zoomx; /* zoomx value */
+ int pribit;
+
+ for (offs = 0x03f8 / 2 ; offs >= 0 ; offs -= 0x008 / 2)
+ {
+ x0 = TC0080VCO_spriteram[offs + 1] & 0x3ff;
+ y0 = TC0080VCO_spriteram[offs + 0] & 0x3ff;
+ zoomx = (TC0080VCO_spriteram[offs + 2] & 0x7f00) >> 8;
+ tile_offs = (TC0080VCO_spriteram[offs + 3] & 0x1fff) << 2;
+ pribit = (TC0080VCO_spriteram[offs + 0] & 0x1000) >> 12;
+ ysize = size[ ( TC0080VCO_spriteram[ offs ] & 0x0c00 ) >> 10 ];
+
+ if (tile_offs)
+ {
+ /* The increasing ratio of expansion is different whether zoom value */
+ /* is less or more than 63. */
+ if (zoomx < 63)
+ {
+ dx = 8 + (zoomx + 2) / 8;
+ ex = (zoomx + 2) % 8;
+ zx = ((dx << 1) + ex) << 11;
+ pribit = 0;
+ }
+ else
+ {
+ dx = 16 + (zoomx - 63) / 4;
+ ex = (zoomx - 63) % 4;
+ zx = (dx + ex) << 12;
+ }
+
+ if (TC0080VCO_scroll_ram[0x0002] & 0x8000)
+ pribit = 1;
+
+ if (x0 >= 0x200) x0 -= 0x400;
+ if (y0 >= 0x200) y0 -= 0x400;
+
+ if (TC0080VCO_flipscreen)
+ {
+ x0 = 497 - x0;
+ y0 = 498 - y0;
+ dx = -dx;
+ }
+ else
+ {
+ x0 += 1;
+ y0 += 2;
+ }
+
+ if ( priority == pribit )
+ {
+ y = y0;
+ for ( j = 0 ; j < ysize ; j ++ )
+ {
+ x = x0;
+ for (k = 0 ; k < 4 ; k ++ )
+ {
+ if (tile_offs >= 0x1000) /* or pitcher gets blanked */
+ {
+ int tile, color, flipx, flipy;
+
+ tile = TC0080VCO_chain_ram_0[tile_offs] & 0x7fff;
+ color = TC0080VCO_chain_ram_1[tile_offs] & 0x001f;
+ flipx = TC0080VCO_chain_ram_1[tile_offs] & 0x0040;
+ flipy = TC0080VCO_chain_ram_1[tile_offs] & 0x0080;
+
+ if (TC0080VCO_flipscreen)
+ {
+ flipx ^= 0x0040;
+ flipy ^= 0x0080;
+ }
+
+ drawgfxzoom( bitmap, Machine -> gfx[0],
+ tile,
+ color,
+ flipx, flipy,
+ x, y,
+ cliprect,
+ TRANSPARENCY_PEN, 0,
+ zx, zx
+ );
+ }
+ tile_offs ++;
+ x += dx;
+ }
+ y += dx;
+ }
+ }
+ }
+ }
+}
+
+
+
+#ifdef MAME_DEBUG
+
+static void taitoh_log_vram(void)
+{
+ // null function: the necessary pointers are now internal to taitoic.c
+ // Recreate it there if wanted (add prototype to taitoic.h)
+}
+
+#endif
+
+
+/**************************************************************************/
+
+VIDEO_UPDATE( syvalion )
+{
+ TC0080VCO_tilemap_update(machine);
+
+#ifdef MAME_DEBUG
+ taitoh_log_vram();
+#endif
+
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,0,TILEMAP_DRAW_OPAQUE,0);
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,1,0,0);
+ syvalion_draw_sprites (bitmap,cliprect);
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,2,0,0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( recordbr )
+{
+ TC0080VCO_tilemap_update(machine);
+
+#ifdef MAME_DEBUG
+ taitoh_log_vram();
+#endif
+
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+#ifdef MAME_DEBUG
+ if ( !input_code_pressed(KEYCODE_A) )
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,0,TILEMAP_DRAW_OPAQUE,0);
+ if ( !input_code_pressed(KEYCODE_S) )
+ recordbr_draw_sprites(bitmap,cliprect,0);
+ if ( !input_code_pressed(KEYCODE_D) )
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,1,0,0);
+ if ( !input_code_pressed(KEYCODE_F) )
+ recordbr_draw_sprites(bitmap,cliprect,1);
+#else
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,0,TILEMAP_DRAW_OPAQUE,0);
+ recordbr_draw_sprites (bitmap,cliprect,0);
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,1,0,0);
+ recordbr_draw_sprites (bitmap,cliprect,1);
+#endif
+
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,2,0,0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( dleague )
+{
+ TC0080VCO_tilemap_update(machine);
+
+#ifdef MAME_DEBUG
+ taitoh_log_vram();
+#endif
+
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+#ifdef MAME_DEBUG
+ if ( !input_code_pressed(KEYCODE_A) )
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,0,TILEMAP_DRAW_OPAQUE,0);
+ if ( !input_code_pressed(KEYCODE_S) )
+ dleague_draw_sprites(bitmap,cliprect,0);
+ if ( !input_code_pressed(KEYCODE_D) )
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,1,0,0);
+ if ( !input_code_pressed(KEYCODE_F) )
+ dleague_draw_sprites(bitmap,cliprect,1);
+#else
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,0,TILEMAP_DRAW_OPAQUE,0);
+ dleague_draw_sprites (bitmap,cliprect,0);
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,1,0,0);
+ dleague_draw_sprites (bitmap,cliprect,1);
+#endif
+
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,2,0,0);
+ return 0;
+}
+
diff --git a/src/mame/video/taito_l.c b/src/mame/video/taito_l.c
new file mode 100644
index 00000000000..cd2c0378b9d
--- /dev/null
+++ b/src/mame/video/taito_l.c
@@ -0,0 +1,352 @@
+#include "driver.h"
+
+
+extern UINT8 *taitol_rambanks;
+
+static tilemap *bg18_tilemap;
+static tilemap *bg19_tilemap;
+static tilemap *ch1a_tilemap;
+
+static int cur_ctrl = 0;
+static int horshoes_gfxbank = 0;
+static int bankc[4];
+static int flipscreen;
+#define SPRITERAM_SIZE 0x400
+static UINT8 buff_spriteram[SPRITERAM_SIZE];
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg18_tile_info )
+{
+ int attr = taitol_rambanks[2*tile_index+0x4000+1];
+ int code = taitol_rambanks[2*tile_index+0x4000]
+ | ((attr & 0x03) << 8)
+ | ((bankc[(attr & 0xc) >> 2]) << 10)
+ | (horshoes_gfxbank << 12);
+
+ SET_TILE_INFO(
+ 0,
+ code,
+ (attr & 0xf0) >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg19_tile_info )
+{
+ int attr = taitol_rambanks[2*tile_index+0x5000+1];
+ int code = taitol_rambanks[2*tile_index+0x5000]
+ | ((attr & 0x03) << 8)
+ | ((bankc[(attr & 0xc) >> 2]) << 10)
+ | (horshoes_gfxbank << 12);
+
+ SET_TILE_INFO(
+ 0,
+ code,
+ (attr & 0xf0) >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( get_ch1a_tile_info )
+{
+ int attr = taitol_rambanks[2*tile_index+0x6000+1];
+ int code = taitol_rambanks[2*tile_index+0x6000]|((attr&0x01)<<8)|((attr&0x04)<<7);
+
+ SET_TILE_INFO(
+ 2,
+ code,
+ (attr & 0xf0) >> 4,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( taitol )
+{
+ int i;
+
+ bg18_tilemap = tilemap_create(get_bg18_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ bg19_tilemap = tilemap_create(get_bg19_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,32);
+ ch1a_tilemap = tilemap_create(get_ch1a_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ bankc[0] = bankc[1] = bankc[2] = bankc[3] = 0;
+ horshoes_gfxbank = 0;
+ cur_ctrl = 0;
+
+ tilemap_set_transparent_pen(bg18_tilemap,0);
+ tilemap_set_transparent_pen(ch1a_tilemap,0);
+
+ for (i=0;i<256;i++)
+ palette_set_color(machine, i, MAKE_RGB(0, 0, 0));
+
+ tilemap_set_scrolldx(ch1a_tilemap,-8,-8);
+ tilemap_set_scrolldx(bg18_tilemap,28,-11);
+ tilemap_set_scrolldx(bg19_tilemap,38,-21);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( horshoes_bankg_w )
+{
+ if (horshoes_gfxbank != data)
+ {
+ horshoes_gfxbank = data;
+
+ tilemap_mark_all_tiles_dirty(bg18_tilemap);
+ tilemap_mark_all_tiles_dirty(bg19_tilemap);
+ }
+}
+
+WRITE8_HANDLER( taitol_bankc_w )
+{
+ if (bankc[offset] != data)
+ {
+ bankc[offset] = data;
+// logerror("Bankc %d, %02x (%04x)\n", offset, data, activecpu_get_pc());
+
+ tilemap_mark_all_tiles_dirty(bg18_tilemap);
+ tilemap_mark_all_tiles_dirty(bg19_tilemap);
+ }
+}
+
+READ8_HANDLER( taitol_bankc_r )
+{
+ return bankc[offset];
+}
+
+
+WRITE8_HANDLER( taitol_control_w )
+{
+// logerror("Control Write %02x (%04x)\n", data, activecpu_get_pc());
+
+ cur_ctrl = data;
+//popmessage("%02x",data);
+
+ /* bit 0 unknown */
+
+ /* bit 1 unknown */
+
+ /* bit 3 controls sprite/tile priority - handled in vh_screenrefresh() */
+
+ /* bit 4 flip screen */
+ flipscreen = data & 0x10;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+
+ /* bit 5 display enable - handled in vh_screenrefresh() */
+}
+
+READ8_HANDLER( taitol_control_r )
+{
+// logerror("Control Read %02x (%04x)\n", cur_ctrl, activecpu_get_pc());
+ return cur_ctrl;
+}
+
+void taitol_chardef14_m(int offset)
+{
+ decodechar(Machine->gfx[2], offset/32, taitol_rambanks,
+ Machine->drv->gfxdecodeinfo[2].gfxlayout);
+ tilemap_mark_all_tiles_dirty(ch1a_tilemap);
+}
+
+void taitol_chardef15_m(int offset)
+{
+ decodechar(Machine->gfx[2], offset/32+128, taitol_rambanks,
+ Machine->drv->gfxdecodeinfo[2].gfxlayout);
+ tilemap_mark_all_tiles_dirty(ch1a_tilemap);
+}
+
+void taitol_chardef16_m(int offset)
+{
+ decodechar(Machine->gfx[2], offset/32+256, taitol_rambanks,
+ Machine->drv->gfxdecodeinfo[2].gfxlayout);
+ tilemap_mark_all_tiles_dirty(ch1a_tilemap);
+}
+
+void taitol_chardef17_m(int offset)
+{
+ decodechar(Machine->gfx[2], offset/32+384, taitol_rambanks,
+ Machine->drv->gfxdecodeinfo[2].gfxlayout);
+ tilemap_mark_all_tiles_dirty(ch1a_tilemap);
+}
+
+void taitol_chardef1c_m(int offset)
+{
+ decodechar(Machine->gfx[2], offset/32+512, taitol_rambanks + 0x4000,
+ Machine->drv->gfxdecodeinfo[2].gfxlayout);
+ tilemap_mark_all_tiles_dirty(ch1a_tilemap);
+}
+
+void taitol_chardef1d_m(int offset)
+{
+ decodechar(Machine->gfx[2], offset/32+640, taitol_rambanks + 0x4000,
+ Machine->drv->gfxdecodeinfo[2].gfxlayout);
+ tilemap_mark_all_tiles_dirty(ch1a_tilemap);
+}
+
+void taitol_chardef1e_m(int offset)
+{
+ decodechar(Machine->gfx[2], offset/32+768, taitol_rambanks + 0x4000,
+ Machine->drv->gfxdecodeinfo[2].gfxlayout);
+ tilemap_mark_all_tiles_dirty(ch1a_tilemap);
+}
+
+void taitol_chardef1f_m(int offset)
+{
+ decodechar(Machine->gfx[2], offset/32+896, taitol_rambanks + 0x4000,
+ Machine->drv->gfxdecodeinfo[2].gfxlayout);
+ tilemap_mark_all_tiles_dirty(ch1a_tilemap);
+}
+
+void taitol_bg18_m(int offset)
+{
+ tilemap_mark_tile_dirty(bg18_tilemap,offset/2);
+}
+
+void taitol_bg19_m(int offset)
+{
+ tilemap_mark_tile_dirty(bg19_tilemap,offset/2);
+}
+
+void taitol_char1a_m(int offset)
+{
+ tilemap_mark_tile_dirty(ch1a_tilemap,offset/2);
+}
+
+void taitol_obj1b_m(int offset)
+{
+#if 0
+ if (offset>=0x3f0 && offset<=0x3ff)
+ {
+ /* scroll, handled in vh-screenrefresh */
+ }
+#endif
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+/*
+ Sprite format:
+ 00: xxxxxxxx tile number (low)
+ 01: xxxxxxxx tile number (high)
+ 02: ----xxxx color
+ ----x--- priority
+ 03: -------x flip x
+ ------x- flip y
+ 04: xxxxxxxx x position (low)
+ 05: -------x x position (high)
+ 06: xxxxxxxx y position
+ 07: xxxxxxxx unknown / ignored? Seems just garbage in many cases, e.g
+ plgirs2 bullets and raimais big bosses.
+*/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+
+ /* at spriteram + 0x3f0 and 03f8 are the tilemap control registers;
+ spriteram + 0x3e8 seems to be unused
+ */
+ for (offs = 0;offs < SPRITERAM_SIZE-3*8;offs += 8)
+ {
+ int code,color,sx,sy,flipx,flipy;
+
+ color = buff_spriteram[offs + 2] & 0x0f;
+ code = buff_spriteram[offs] | (buff_spriteram[offs + 1] << 8);
+
+ code |= (horshoes_gfxbank & 0x03) << 10;
+
+ sx = buff_spriteram[offs + 4] | ((buff_spriteram[offs + 5] & 1) << 8);
+ sy = buff_spriteram[offs + 6];
+ if (sx >= 320) sx -= 512;
+ flipx = buff_spriteram[offs + 3] & 0x01;
+ flipy = buff_spriteram[offs + 3] & 0x02;
+
+ if (flipscreen)
+ {
+ sx = 304 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ pdrawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0,
+ (color & 0x08) ? 0xaa : 0x00);
+ }
+}
+
+
+VIDEO_UPDATE( taitol )
+{
+ int dx,dy;
+
+
+ dx = taitol_rambanks[0x73f4]|(taitol_rambanks[0x73f5]<<8);
+ if (flipscreen)
+ dx = ((dx & 0xfffc) | ((dx - 3) & 0x0003)) ^ 0xf;
+ dy = taitol_rambanks[0x73f6];
+ tilemap_set_scrollx(bg18_tilemap,0,-dx);
+ tilemap_set_scrolly(bg18_tilemap,0,-dy);
+
+ dx = taitol_rambanks[0x73fc]|(taitol_rambanks[0x73fd]<<8);
+ if (flipscreen)
+ dx = ((dx & 0xfffc) | ((dx - 3) & 0x0003)) ^ 0xf;
+ dy = taitol_rambanks[0x73fe];
+ tilemap_set_scrollx(bg19_tilemap,0,-dx);
+ tilemap_set_scrolly(bg19_tilemap,0,-dy);
+
+
+ if (cur_ctrl & 0x20) /* display enable */
+ {
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg19_tilemap,0,0);
+
+ if (cur_ctrl & 0x08) /* sprites always over BG1 */
+ tilemap_draw(bitmap,cliprect,bg18_tilemap,0,0);
+ else /* split priority */
+ tilemap_draw(bitmap,cliprect,bg18_tilemap,0,1);
+ draw_sprites(machine, bitmap,cliprect);
+
+ tilemap_draw(bitmap,cliprect,ch1a_tilemap,0,0);
+ }
+ else
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ return 0;
+}
+
+
+
+VIDEO_EOF( taitol )
+{
+ UINT8 *spriteram = taitol_rambanks + 0x7000;
+
+ memcpy(buff_spriteram,spriteram,SPRITERAM_SIZE);
+}
diff --git a/src/mame/video/taito_z.c b/src/mame/video/taito_z.c
new file mode 100644
index 00000000000..b61677d9425
--- /dev/null
+++ b/src/mame/video/taito_z.c
@@ -0,0 +1,1032 @@
+#include "driver.h"
+#include "video/taitoic.h"
+
+#define TC0100SCN_GFX_NUM 1
+#define TC0480SCP_GFX_NUM 1
+
+static int sci_spriteframe;
+extern UINT16 *taitoz_sharedram;
+
+static int road_palbank;
+
+
+/**********************************************************/
+
+static void taitoz_core_vh_start(running_machine *machine, int x_offs)
+{
+ if (has_TC0480SCP()) /* it's Dblaxle, a tc0480scp game */
+ TC0480SCP_vh_start(machine,TC0480SCP_GFX_NUM,x_offs,0x21,0x08,4,0,0,0,0);
+ else /* it's a tc0100scn game */
+ TC0100SCN_vh_start(machine,1,TC0100SCN_GFX_NUM,x_offs,0,0,0,0,0,0);
+
+ if (has_TC0150ROD())
+ TC0150ROD_vh_start();
+
+ if (has_TC0110PCR())
+ TC0110PCR_vh_start();
+}
+
+VIDEO_START( taitoz )
+{
+ taitoz_core_vh_start(machine, 0);
+}
+
+VIDEO_START( spacegun )
+{
+ taitoz_core_vh_start(machine, 4);
+}
+
+/********************************************************
+ SPRITE READ AND WRITE HANDLERS
+********************************************************/
+
+
+READ16_HANDLER( sci_spriteframe_r )
+{
+ return (sci_spriteframe << 8);
+}
+
+WRITE16_HANDLER( sci_spriteframe_w )
+{
+ sci_spriteframe = (data >> 8) &0xff;
+}
+
+
+/************************************************************
+ SPRITE DRAW ROUTINES
+
+These draw a series of small tiles ("chunks") together to
+create each big sprite. The spritemap rom provides the lookup
+table for this. E.g. Spacegun looks up 16x8 sprite chunks
+from the spritemap rom, creating this 64x64 sprite (numbers
+are the word offset into the spritemap rom):
+
+ 0 1 2 3
+ 4 5 6 7
+ 8 9 10 11
+ 12 13 14 15
+ 16 17 18 19
+ 20 21 22 23
+ 24 25 26 27
+ 28 29 30 31
+
+Chasehq/Nightstr are the only games to build from 16x16
+tiles. They are also more complicated to draw, as they have
+3 different aggregation formats [32/64/128 x 128]
+whereas the other games stick to one, typically 64x64.
+
+All the games make heavy use of sprite zooming.
+
+I'm 99% sure there are probably just two levels of sprite
+priority - under and over the road - but this isn't certain.
+
+ ***
+
+[The routines for the 16x8 tile games seem to have large
+common elements that could be extracted as subroutines.]
+
+NB: unused portions of the spritemap rom contain hex FF's.
+It is a useful coding check to warn in the log if these
+are being accessed. [They can be inadvertently while
+spriteram is being tested, take no notice of that.]
+
+BUT: Nightstr uses code 0x3ff as a mask sprite. This
+references 0x1ff00-ff in spritemap rom, which is an 0xff fill.
+This must be accessing sprite chunk 0x3fff: in other words the
+top bits are thrown away and so accessing chunk 0xfe45 would
+display chunk 0x3e45 etc.
+
+
+ Aquajack/Spacegun (modified table from Raine; size of bit
+ masks verified in Spacegun code)
+
+ Byte | Bit(s) | Description
+ -----+76543210+-------------------------------------
+ 0 |xxxxxxx.| ZoomY (0 min, 63 max - msb unused as sprites are 64x64)
+ 0 |.......x| Y position (High)
+ 1 |xxxxxxxx| Y position (Low)
+ 2 |x.......| Priority (0=sprites high)
+ 2 |.x......| Flip X
+ 2 |..?????.| unknown/unused ?
+ 2 |.......x| X position (High)
+ 3 |xxxxxxxx| X position (Low)
+ 4 |xxxxxxxx| Palette bank
+ 5 |?.......| unknown/unused ?
+ 5 |.xxxxxxx| ZoomX (0 min, 63 max - msb unused as sprites are 64x64)
+ 6 |x.......| Flip Y ?
+ 6 |.??.....| unknown/unused ?
+ 6 |...xxxxx| Sprite Tile high (msb unused - half of spritemap rom empty)
+ 7 |xxxxxxxx| Sprite Tile low
+
+ Continental circus (modified Raine table): note similar format.
+ The zoom msb is actually used, as sprites are 128x128.
+
+ ---+-------------------+--------------
+ 0 | xxxxxxx. ........ | ZoomY
+ 0 | .......x xxxxxxxx | Y position
+ // unsure about Flip Y
+ 2 | .....xxx xxxxxxxx | Sprite Tile
+ 4 | x....... ........ | Priority (0=sprites high)
+ 4 | .x...... ........ | Flip X
+ 4 | .......x xxxxxxxx | X position
+ 6 | xxxxxxxx ........ | Palette bank
+ 6 | ........ .xxxxxxx | ZoomX
+ ---+-------------------+--------------
+
+ Bshark/Chasehq/Nightstr/SCI (modified Raine table): similar format.
+ The zoom msb is only used for 128x128 sprites.
+
+ -----+--------+------------------------
+ Byte | Bit(s) | Description
+ -----+76543210+------------------------
+ 0 |xxxxxxx.| ZoomY
+ 0 |.......x| Y position (High)
+ 1 |xxxxxxxx| Y position (Low)
+ 2 |x.......| Priority (0=sprites high)
+ 2 |.xxxxxxx| Palette bank (High)
+ 3 |x.......| Palette bank (Low)
+ 3 |.xxxxxxx| ZoomX
+ 4 |x.......| Flip Y
+ 4 |.x......| Flip X
+ 4 |.......x| X position (High)
+ 5 |xxxxxxxx| X position (Low)
+ 6 |...xxxxx| Sprite Tile (High)
+ 7 |xxxxxxxx| Sprite Tile (Low)
+ -----+--------+------------------------
+
+ [Raine Chasehq sprite plotting is peculiar. It determines
+ the type of big sprite by reference to the zoomx and y.
+ Therefore it says that the big sprite number is 0-0x7ff
+ across ALL three sizes and you can't distinguish them by
+ tilenum. FWIW I seem to be ok just using zoomx.]
+
+TODO: Contcirc, Aquajack, Spacegun need flip y bit to be
+confirmed
+
+********************************************************/
+
+
+static void contcirc_draw_sprites_16x8(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int y_offs)
+{
+ UINT16 *spritemap = (UINT16 *)memory_region(REGION_USER1);
+ int offs, data, tilenum, color, flipx, flipy;
+ int x, y, priority, curx, cury;
+ int sprites_flipscreen = 0;
+ int zoomx, zoomy, zx, zy;
+ int sprite_chunk,map_offset,code,j,k,px,py;
+ int bad_chunks;
+ static const int primasks[2] = {0xf0,0xfc};
+
+ for (offs = 0;offs < spriteram_size/2;offs += 4)
+ {
+ data = spriteram16[offs+0];
+ zoomy = (data & 0xfe00) >> 9;
+ y = data & 0x1ff;
+
+ data = spriteram16[offs+1];
+ tilenum = data & 0x7ff; /* $80000 spritemap rom maps up to $7ff 128x128 sprites */
+
+ data = spriteram16[offs+2];
+ priority = (data & 0x8000) >> 15;
+ flipx = (data & 0x4000) >> 14;
+ flipy = (data & 0x2000) >> 13; // ???
+ x = data & 0x1ff; // correct mask?
+
+ data = spriteram16[offs+3];
+ color = (data & 0xff00) >> 8;
+ zoomx = (data & 0x7f);
+
+ if (!tilenum) continue;
+
+ map_offset = tilenum << 7;
+
+ zoomx += 1;
+ zoomy += 1;
+
+ y += y_offs;
+ y += (128-zoomy);
+
+ /* treat coords as signed */
+ if (x>0x140) x -= 0x200;
+ if (y>0x140) y -= 0x200;
+
+ bad_chunks = 0;
+
+ for (sprite_chunk=0;sprite_chunk<128;sprite_chunk++)
+ {
+ k = sprite_chunk % 8; /* 8 sprite chunks per row */
+ j = sprite_chunk / 8; /* 16 rows */
+
+ px = flipx ? (7-k) : k; /* pick tiles back to front for x and y flips */
+ py = flipy ? (15-j) : j;
+
+ code = spritemap[map_offset + px + (py<<3)];
+
+ if (code == 0xffff) bad_chunks++;
+
+ curx = x + ((k*zoomx)/8);
+ cury = y + ((j*zoomy)/16);
+
+ zx = x + (((k+1)*zoomx)/8) - curx;
+ zy = y + (((j+1)*zoomy)/16) - cury;
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 320 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ pdrawgfxzoom(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ curx,cury,
+ cliprect,TRANSPARENCY_PEN,0,
+ zx<<12,zy<<13,primasks[priority]);
+ }
+
+ if (bad_chunks)
+logerror("Sprite number %04x had %02x invalid chunks\n",tilenum,bad_chunks);
+ }
+}
+
+
+
+static void chasehq_draw_sprites_16x16(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int y_offs)
+{
+ UINT16 *spritemap = (UINT16 *)memory_region(REGION_USER1);
+ int offs, data, tilenum, color, flipx, flipy;
+ int x, y, priority, curx, cury;
+ int sprites_flipscreen = 0;
+ int zoomx, zoomy, zx, zy;
+ int sprite_chunk,map_offset,code,j,k,px,py;
+ int bad_chunks;
+ static const int primasks[2] = {0xf0,0xfc};
+
+ for (offs = spriteram_size/2-4;offs >=0;offs -= 4)
+ {
+ data = spriteram16[offs+0];
+ zoomy = (data & 0xfe00) >> 9;
+ y = data & 0x1ff;
+
+ data = spriteram16[offs+1];
+ priority = (data & 0x8000) >> 15;
+ color = (data & 0x7f80) >> 7;
+ zoomx = (data & 0x7f);
+
+ data = spriteram16[offs+2];
+ flipy = (data & 0x8000) >> 15;
+ flipx = (data & 0x4000) >> 14;
+ x = data & 0x1ff;
+
+ data = spriteram16[offs+3];
+ /* higher bits are sometimes used... e.g. sign over flashing enemy car...! */
+ tilenum = data & 0x7ff;
+
+ if (!tilenum) continue;
+
+ zoomx += 1;
+ zoomy += 1;
+
+ y += y_offs;
+ y += (128-zoomy);
+
+ /* treat coords as signed */
+ if (x>0x140) x -= 0x200;
+ if (y>0x140) y -= 0x200;
+
+ bad_chunks = 0;
+
+ if ((zoomx-1) & 0x40) /* 128x128 sprites, $0-$3ffff in spritemap rom, OBJA */
+ {
+ map_offset = tilenum << 6;
+
+ for (sprite_chunk=0;sprite_chunk<64;sprite_chunk++)
+ {
+ j = sprite_chunk / 8; /* 8 rows */
+ k = sprite_chunk % 8; /* 8 sprite chunks per row */
+
+ px = flipx ? (7-k) : k; /* pick tiles back to front for x and y flips */
+ py = flipy ? (7-j) : j;
+
+ code = spritemap[map_offset + px + (py<<3)];
+
+ if (code == 0xffff) bad_chunks++;
+
+ curx = x + ((k*zoomx)/8);
+ cury = y + ((j*zoomy)/8);
+
+ zx = x + (((k+1)*zoomx)/8) - curx;
+ zy = y + (((j+1)*zoomy)/8) - cury;
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 320 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ pdrawgfxzoom(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ curx,cury,
+ cliprect,TRANSPARENCY_PEN,0,
+ zx<<12,zy<<12,
+ primasks[priority]);
+ }
+ }
+ else if ((zoomx-1) & 0x20) /* 64x128 sprites, $40000-$5ffff in spritemap rom, OBJB */
+ {
+ map_offset = (tilenum << 5) + 0x20000;
+
+ for (sprite_chunk=0;sprite_chunk<32;sprite_chunk++)
+ {
+ j = sprite_chunk / 4; /* 8 rows */
+ k = sprite_chunk % 4; /* 4 sprite chunks per row */
+
+ px = flipx ? (3-k) : k; /* pick tiles back to front for x and y flips */
+ py = flipy ? (7-j) : j;
+
+ code = spritemap[map_offset + px + (py<<2)];
+
+ if (code == 0xffff) bad_chunks++;
+
+ curx = x + ((k*zoomx)/4);
+ cury = y + ((j*zoomy)/8);
+
+ zx = x + (((k+1)*zoomx)/4) - curx;
+ zy = y + (((j+1)*zoomy)/8) - cury;
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 320 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ pdrawgfxzoom(bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx,flipy,
+ curx,cury,
+ cliprect,TRANSPARENCY_PEN,0,
+ zx<<12,zy<<12,
+ primasks[priority]);
+ }
+ }
+ else if (!((zoomx-1) & 0x60)) /* 32x128 sprites, $60000-$7ffff in spritemap rom, OBJB */
+ {
+ map_offset = (tilenum << 4) + 0x30000;
+
+ for (sprite_chunk=0;sprite_chunk<16;sprite_chunk++)
+ {
+ j = sprite_chunk / 2; /* 8 rows */
+ k = sprite_chunk % 2; /* 2 sprite chunks per row */
+
+ px = flipx ? (1-k) : k; /* pick tiles back to front for x and y flips */
+ py = flipy ? (7-j) : j;
+
+ code = spritemap[map_offset + px + (py<<1)];
+
+ if (code == 0xffff) bad_chunks ++;
+
+ curx = x + ((k*zoomx)/2);
+ cury = y + ((j*zoomy)/8);
+
+ zx = x + (((k+1)*zoomx)/2) - curx;
+ zy = y + (((j+1)*zoomy)/8) - cury;
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 320 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ pdrawgfxzoom(bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx,flipy,
+ curx,cury,
+ cliprect,TRANSPARENCY_PEN,0,
+ zx<<12,zy<<12,
+ primasks[priority]);
+ }
+ }
+
+ if (bad_chunks)
+logerror("Sprite number %04x had %02x invalid chunks\n",tilenum,bad_chunks);
+ }
+}
+
+
+
+static void bshark_draw_sprites_16x8(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int y_offs)
+{
+ UINT16 *spritemap = (UINT16 *)memory_region(REGION_USER1);
+ int offs, data, tilenum, color, flipx, flipy;
+ int x, y, priority, curx, cury;
+ int sprites_flipscreen = 0;
+ int zoomx, zoomy, zx, zy;
+ int sprite_chunk,map_offset,code,j,k,px,py;
+ int bad_chunks;
+ static const int primasks[2] = {0xf0,0xfc};
+
+ for (offs = spriteram_size/2-4;offs >= 0;offs -= 4)
+ {
+ data = spriteram16[offs+0];
+ zoomy = (data & 0x7e00) >> 9;
+ y = data & 0x1ff;
+
+ data = spriteram16[offs+1];
+ priority = (data & 0x8000) >> 15;
+ color = (data & 0x7f80) >> 7;
+ zoomx = (data & 0x3f);
+
+ data = spriteram16[offs+2];
+ flipy = (data & 0x8000) >> 15;
+ flipx = (data & 0x4000) >> 14;
+ x = data & 0x1ff;
+
+ data = spriteram16[offs+3];
+ tilenum = data & 0x1fff; /* $80000 spritemap rom maps up to $2000 64x64 sprites */
+
+ if (!tilenum) continue;
+
+ map_offset = tilenum << 5;
+
+ zoomx += 1;
+ zoomy += 1;
+
+ y += y_offs;
+ y += (64-zoomy);
+
+ /* treat coords as signed */
+ if (x>0x140) x -= 0x200;
+ if (y>0x140) y -= 0x200;
+
+ bad_chunks = 0;
+
+ for (sprite_chunk=0;sprite_chunk<32;sprite_chunk++)
+ {
+ k = sprite_chunk % 4; /* 4 sprite chunks per row */
+ j = sprite_chunk / 4; /* 8 rows */
+
+ px = flipx ? (3-k) : k; /* pick tiles back to front for x and y flips */
+ py = flipy ? (7-j) : j;
+
+ code = spritemap[map_offset + px + (py<<2)];
+
+ if (code == 0xffff) bad_chunks++;
+
+ curx = x + ((k*zoomx)/4);
+ cury = y + ((j*zoomy)/8);
+
+ zx = x + (((k+1)*zoomx)/4) - curx;
+ zy = y + (((j+1)*zoomy)/8) - cury;
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 320 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ pdrawgfxzoom(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ curx,cury,
+ cliprect,TRANSPARENCY_PEN,0,
+ zx<<12,zy<<13,
+ primasks[priority]);
+ }
+
+ if (bad_chunks)
+logerror("Sprite number %04x had %02x invalid chunks\n",tilenum,bad_chunks);
+ }
+}
+
+
+
+static void sci_draw_sprites_16x8(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int y_offs)
+{
+ UINT16 *spritemap = (UINT16 *)memory_region(REGION_USER1);
+ int offs, start_offs, data, tilenum, color, flipx, flipy;
+ int x, y, priority, curx, cury;
+ int sprites_flipscreen = 0;
+ int zoomx, zoomy, zx, zy;
+ int sprite_chunk,map_offset,code,j,k,px,py;
+ int bad_chunks;
+ static const int primasks[2] = {0xf0,0xfc};
+
+ /* SCI alternates between two areas of its spriteram */
+
+ // This gave back to front frames causing bad flicker... but
+ // reversing it now only gives us sprite updates on alternate
+ // frames. So we probably have to partly buffer spriteram?
+
+ start_offs = (sci_spriteframe &1) * 0x800;
+ start_offs = 0x800 - start_offs;
+
+ for (offs = (start_offs + 0x800 - 4);offs >= start_offs;offs -= 4)
+ {
+ data = spriteram16[offs+0];
+ zoomy = (data & 0x7e00) >> 9;
+ y = data & 0x1ff;
+
+ data = spriteram16[offs+1];
+ priority = (data & 0x8000) >> 15;
+ color = (data & 0x7f80) >> 7;
+ zoomx = (data & 0x3f);
+
+ data = spriteram16[offs+2];
+ flipy = (data & 0x8000) >> 15;
+ flipx = (data & 0x4000) >> 14;
+ x = data & 0x1ff;
+
+ data = spriteram16[offs+3];
+ tilenum = data & 0x1fff; /* $80000 spritemap rom maps up to $2000 64x64 sprites */
+
+ if (!tilenum) continue;
+
+ map_offset = tilenum << 5;
+
+ zoomx += 1;
+ zoomy += 1;
+
+ y += y_offs;
+ y += (64-zoomy);
+
+ /* treat coords as signed */
+ if (x>0x140) x -= 0x200;
+ if (y>0x140) y -= 0x200;
+
+ bad_chunks = 0;
+
+ for (sprite_chunk=0;sprite_chunk<32;sprite_chunk++)
+ {
+ j = sprite_chunk / 4; /* 8 rows */
+ k = sprite_chunk % 4; /* 4 sprite chunks per row */
+
+ px = flipx ? (3-k) : k; /* pick tiles back to front for x and y flips */
+ py = flipy ? (7-j) : j;
+
+ code = spritemap[map_offset + px + (py<<2)];
+
+ if (code == 0xffff) bad_chunks++;
+
+ curx = x + ((k*zoomx)/4);
+ cury = y + ((j*zoomy)/8);
+
+ zx = x + (((k+1)*zoomx)/4) - curx;
+ zy = y + (((j+1)*zoomy)/8) - cury;
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 320 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ pdrawgfxzoom(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ curx,cury,
+ cliprect,TRANSPARENCY_PEN,0,
+ zx<<12,zy<<13,
+ primasks[priority]);
+ }
+
+ if (bad_chunks)
+logerror("Sprite number %04x had %02x invalid chunks\n",tilenum,bad_chunks);
+ }
+}
+
+
+
+static void aquajack_draw_sprites_16x8(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int y_offs)
+{
+ UINT16 *spritemap = (UINT16 *)memory_region(REGION_USER1);
+ int offs, data, tilenum, color, flipx, flipy;
+ int x, y, priority, curx, cury;
+ int sprites_flipscreen = 0;
+ int zoomx, zoomy, zx, zy;
+ int sprite_chunk,map_offset,code,j,k,px,py;
+ int bad_chunks;
+ static const int primasks[2] = {0xf0,0xfc};
+
+ for (offs = 0;offs < spriteram_size/2;offs += 4)
+ {
+ data = spriteram16[offs+0];
+ zoomy = (data & 0x7e00) >> 9;
+ y = data & 0x1ff;
+
+ data = spriteram16[offs+1];
+ priority = (data & 0x8000) >> 15;
+ flipx = (data & 0x4000) >> 14;
+ x = data & 0x1ff; // correct mask?
+
+ data = spriteram16[offs+2];
+ color = (data & 0xff00) >> 8;
+ zoomx = (data & 0x3f);
+
+ data = spriteram16[offs+3];
+ flipy = (data & 0x8000) >> 15; // ???
+ tilenum = data & 0x1fff; /* $80000 spritemap rom maps up to $2000 64x64 sprites */
+
+ if (!tilenum) continue;
+
+ map_offset = tilenum << 5;
+
+ zoomx += 1;
+ zoomy += 1;
+
+ y += y_offs;
+
+ /* treat coords as signed */
+ if (x>0x140) x -= 0x200;
+ if (y>0x140) y -= 0x200;
+
+ bad_chunks = 0;
+
+ for (sprite_chunk=0;sprite_chunk<32;sprite_chunk++)
+ {
+ k = sprite_chunk % 4; /* 4 sprite chunks per row */
+ j = sprite_chunk / 4; /* 8 rows */
+
+ px = flipx ? (3-k) : k; /* pick tiles back to front for x and y flips */
+ py = flipy ? (7-j) : j;
+
+ code = spritemap[map_offset + px + (py<<2)];
+
+ if (code == 0xffff) bad_chunks++;
+
+ curx = x + ((k*zoomx)/4);
+ cury = y + ((j*zoomy)/8);
+
+ zx = x + (((k+1)*zoomx)/4) - curx;
+ zy = y + (((j+1)*zoomy)/8) - cury;
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 320 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ pdrawgfxzoom(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ curx,cury,
+ cliprect,TRANSPARENCY_PEN,0,
+ zx<<12,zy<<13,
+ primasks[priority]);
+ }
+
+ if (bad_chunks)
+logerror("Sprite number %04x had %02x invalid chunks\n",tilenum,bad_chunks);
+ }
+}
+
+
+
+static void spacegun_draw_sprites_16x8(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int y_offs)
+{
+ UINT16 *spritemap = (UINT16 *)memory_region(REGION_USER1);
+ int offs, data, tilenum, color, flipx, flipy;
+ int x, y, priority, curx, cury;
+ int sprites_flipscreen = 0;
+ int zoomx, zoomy, zx, zy;
+ int sprite_chunk,map_offset,code,j,k,px,py;
+ int bad_chunks;
+ static const int primasks[2] = {0xf0,0xfc};
+
+ for (offs = 0; offs < spriteram_size/2-4;offs += 4)
+ {
+ data = spriteram16[offs+0];
+ zoomy = (data & 0xfe00) >> 9;
+ y = data & 0x1ff;
+
+ data = spriteram16[offs+1];
+ priority = (data & 0x8000) >> 15;
+ flipx = (data & 0x4000) >> 14;
+ x = data & 0x1ff; // correct mask?
+
+ data = spriteram16[offs+2];
+ color = (data & 0xff00) >> 8;
+ zoomx = (data & 0x7f);
+
+ data = spriteram16[offs+3];
+ flipy = (data & 0x8000) >> 15; // ???
+ tilenum = data & 0x1fff; /* $80000 spritemap rom maps up to $2000 64x64 sprites */
+
+ if (!tilenum) continue;
+
+ map_offset = tilenum << 5;
+
+ zoomx += 1;
+ zoomy += 1;
+
+ y += y_offs;
+
+ /* treat coords as signed */
+ if (x>0x140) x -= 0x200;
+ if (y>0x140) y -= 0x200;
+
+ bad_chunks = 0;
+
+ for (sprite_chunk=0;sprite_chunk<32;sprite_chunk++)
+ {
+ k = sprite_chunk % 4; /* 4 sprite chunks per row */
+ j = sprite_chunk / 4; /* 8 rows */
+
+ px = flipx ? (3-k) : k; /* pick tiles back to front for x and y flips */
+ py = flipy ? (7-j) : j;
+
+ code = spritemap[map_offset + px + (py<<2)];
+
+ if (code == 0xffff) bad_chunks++;
+
+ curx = x + ((k*zoomx)/4);
+ cury = y + ((j*zoomy)/8);
+
+ zx = x + (((k+1)*zoomx)/4) - curx;
+ zy = y + (((j+1)*zoomy)/8) - cury;
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 320 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ pdrawgfxzoom(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ curx,cury,
+ cliprect,TRANSPARENCY_PEN,0,
+ zx<<12,zy<<13,
+ primasks[priority]);
+ }
+
+ if (bad_chunks)
+logerror("Sprite number %04x had %02x invalid chunks\n",tilenum,bad_chunks);
+ }
+}
+
+
+/**************************************************************
+ SCREEN REFRESH
+**************************************************************/
+
+WRITE16_HANDLER( contcirc_out_w )
+{
+ if (ACCESSING_LSB)
+ {
+ /* bit 0 = reset sub CPU */
+ cpunum_set_input_line(1, INPUT_LINE_RESET, (data & 1) ? CLEAR_LINE : ASSERT_LINE);
+
+ /* bits 1-3 n.c. */
+
+ /* 3d glasses control */
+ /* bit 4 = SCPSW */
+ /* bit 5 = SCP */
+
+ /* bits 6 and 7 select the road palette bank */
+ road_palbank = (data & 0xc0) >> 6;
+ }
+}
+
+
+VIDEO_UPDATE( contcirc )
+{
+ UINT8 layer[3];
+
+ TC0100SCN_tilemap_update(machine);
+
+ layer[0] = TC0100SCN_bottomlayer(0);
+ layer[1] = layer[0]^1;
+ layer[2] = 2;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0],0,0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[1],0,1);
+ TC0150ROD_draw(bitmap,cliprect,-3,road_palbank << 6,1,0,1,2); // -6
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[2],0,4);
+
+ contcirc_draw_sprites_16x8(machine, bitmap,cliprect,5); // 7
+ return 0;
+}
+
+
+/* Nightstr and ChaseHQ */
+
+VIDEO_UPDATE( chasehq )
+{
+ UINT8 layer[3];
+
+ TC0100SCN_tilemap_update(machine);
+
+ layer[0] = TC0100SCN_bottomlayer(0);
+ layer[1] = layer[0]^1;
+ layer[2] = 2;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* Ensure screen blanked even when bottom layer not drawn due to disable bit */
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0],TILEMAP_DRAW_OPAQUE,0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[1],0,1);
+ TC0150ROD_draw(bitmap,cliprect,-1,0xc0,0,0,1,2);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[2],0,4);
+
+ chasehq_draw_sprites_16x16(machine, bitmap,cliprect,7);
+ return 0;
+}
+
+
+VIDEO_UPDATE( bshark )
+{
+ UINT8 layer[3];
+
+ TC0100SCN_tilemap_update(machine);
+
+ layer[0] = TC0100SCN_bottomlayer(0);
+ layer[1] = layer[0]^1;
+ layer[2] = 2;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* Ensure screen blanked even when bottom layer not drawn due to disable bit */
+ fillbitmap(bitmap, machine->pens[0],cliprect);
+
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0],TILEMAP_DRAW_OPAQUE,0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[1],0,1);
+ TC0150ROD_draw(bitmap,cliprect,-1,0xc0,0,1,1,2);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[2],0,4);
+
+ bshark_draw_sprites_16x8(machine, bitmap,cliprect,8);
+ return 0;
+}
+
+
+VIDEO_UPDATE( sci )
+{
+ UINT8 layer[3];
+
+ TC0100SCN_tilemap_update(machine);
+
+ layer[0] = TC0100SCN_bottomlayer(0);
+ layer[1] = layer[0]^1;
+ layer[2] = 2;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* Ensure screen blanked even when bottom layer not drawn due to disable bit */
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0],TILEMAP_DRAW_OPAQUE,0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[1],0,1);
+ TC0150ROD_draw(bitmap,cliprect,-1,0xc0,0,0,1,2);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[2],0,4);
+
+ sci_draw_sprites_16x8(machine, bitmap,cliprect,6);
+ return 0;
+}
+
+
+VIDEO_UPDATE( aquajack )
+{
+ UINT8 layer[3];
+
+ TC0100SCN_tilemap_update(machine);
+
+ layer[0] = TC0100SCN_bottomlayer(0);
+ layer[1] = layer[0]^1;
+ layer[2] = 2;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* Ensure screen blanked even when bottom layer not drawn due to disable bit */
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0],TILEMAP_DRAW_OPAQUE,0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[1],0,1);
+ TC0150ROD_draw(bitmap,cliprect,-1,0,2,1,1,2);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[2],0,4);
+
+ aquajack_draw_sprites_16x8(machine, bitmap,cliprect,3);
+ return 0;
+}
+
+
+VIDEO_UPDATE( spacegun )
+{
+ UINT8 layer[3];
+
+ TC0100SCN_tilemap_update(machine);
+
+ layer[0] = TC0100SCN_bottomlayer(0);
+ layer[1] = layer[0]^1;
+ layer[2] = 2;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* Ensure screen blanked even when bottom layer not drawn due to disable bit */
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0],TILEMAP_DRAW_OPAQUE,1);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[1],0,2);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[2],0,4);
+
+ spacegun_draw_sprites_16x8(machine, bitmap,cliprect,4);
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( dblaxle )
+{
+ UINT8 layer[5];
+ UINT16 priority;
+
+ TC0480SCP_tilemap_update(machine);
+
+ priority = TC0480SCP_get_bg_priority();
+
+ layer[0] = (priority &0xf000) >> 12; /* tells us which bg layer is bottom */
+ layer[1] = (priority &0x0f00) >> 8;
+ layer[2] = (priority &0x00f0) >> 4;
+ layer[3] = (priority &0x000f) >> 0; /* tells us which is top */
+ layer[4] = 4; /* text layer always over bg layers */
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* Ensure screen blanked - this shouldn't be necessary! */
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[0],TILEMAP_DRAW_OPAQUE,0);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[1],0,0);
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[2],0,1);
+
+ TC0150ROD_draw(bitmap,cliprect,-1,0xc0,0,0,1,2);
+ bshark_draw_sprites_16x8(machine, bitmap,cliprect,7);
+
+ /* This layer used for the big numeric displays */
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[3],0,4);
+
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[4],0,0); /* Text layer */
+ return 0;
+}
+
+
diff --git a/src/mame/video/taitoair.c b/src/mame/video/taitoair.c
new file mode 100644
index 00000000000..effed5f0d8c
--- /dev/null
+++ b/src/mame/video/taitoair.c
@@ -0,0 +1,420 @@
+/***************************************************************************
+
+Functions to emulate the video hardware of the machine.
+
+TODO
+====
+
+Harmonise draw_sprites code and offload it into taitoic.c, leaving this
+as short as possible (TC0080VCO has sprites as well as tilemaps in its
+address space).
+
+Maybe wait until the Taito Air system is done - also uses TC0080VCO.
+
+Why does syvalion draw_sprites ignore the zoomy value
+(using zoomx instead) ???
+
+
+Sprite ram notes
+----------------
+
+BG / chain RAM
+-----------------------------------------
+[0] +0 +1
+ -xxx xxxx xxxx xxxx = tile number
+
+[1] +0 +1
+ ---- ---- x--- ---- = flip Y
+ ---- ---- -x-- ---- = flip X
+ ---- ---- --xx xxxx = color
+
+
+sprite RAM
+--------------------------------------------------------------
+ +0 +1 +2 +3
+ ---x ---- ---- ---- ---- ---- ---- ---- = unknown
+ ---- xx-- ---- ---- ---- ---- ---- ---- = chain y size
+ ---- --xx xxxx xxxx ---- ---- ---- ---- = sprite x coords
+ ---- ---- ---- ---- ---- --xx xxxx xxxx = sprite y coords
+
+ +4 +5 +6 +7
+ --xx xxxx ---- ---- ---- ---- ---- ---- = zoom x
+ ---- ---- --xx xxxx ---- ---- ---- ---- = zoom y
+ ---- ---- ---- ---- ---x xxxx xxxx xxxx = tile information offset
+
+
+***************************************************************************/
+
+#include "driver.h"
+#include "taitoic.h"
+
+
+extern UINT16 *TC0080VCO_chain_ram_0;
+extern UINT16 *TC0080VCO_chain_ram_1;
+extern UINT16 *TC0080VCO_spriteram;
+extern UINT16 *TC0080VCO_scroll_ram;
+extern int TC0080VCO_flipscreen;
+
+/* Needed in the sprite palette color marking */
+extern int TC0080VCO_has_tx;
+
+/* These are hand-tuned values */
+static int zoomy_conv_table[] =
+{
+/* +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f */
+ 0x00,0x01,0x01,0x02,0x02,0x03,0x04,0x05, 0x06,0x06,0x07,0x08,0x09,0x0a,0x0a,0x0b, /* 0x00 */
+ 0x0b,0x0c,0x0c,0x0d,0x0e,0x0e,0x0f,0x10, 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x16,
+ 0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e, 0x1f,0x20,0x21,0x22,0x24,0x25,0x26,0x27,
+ 0x28,0x2a,0x2b,0x2c,0x2e,0x30,0x31,0x32, 0x34,0x36,0x37,0x38,0x3a,0x3c,0x3e,0x3f,
+
+ 0x40,0x41,0x42,0x42,0x43,0x43,0x44,0x44, 0x45,0x45,0x46,0x46,0x47,0x47,0x48,0x49, /* 0x40 */
+ 0x4a,0x4a,0x4b,0x4b,0x4c,0x4d,0x4e,0x4f, 0x4f,0x50,0x51,0x51,0x52,0x53,0x54,0x55,
+ 0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d, 0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x66,
+ 0x67,0x68,0x6a,0x6b,0x6c,0x6e,0x6f,0x71, 0x72,0x74,0x76,0x78,0x80,0x7b,0x7d,0x7f
+};
+
+
+
+/***************************************************************************
+ Initialize and destroy video hardware emulation
+***************************************************************************/
+
+VIDEO_START( taitoair )
+{
+ TC0080VCO_vh_start(machine,0,0,1,1,-2);
+}
+
+
+/***************************************************************************
+ Screen refresh
+***************************************************************************/
+
+static void draw_sprites(mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+ /* Y chain size is 16/32?/64/64? pixels. X chain size
+ is always 64 pixels. */
+
+ static const int size[] = { 1, 2, 4, 4 };
+ int x0, y0, x, y, dx, dy, ex, ey, zx, zy;
+ int ysize;
+ int j, k;
+ int offs; /* sprite RAM offset */
+ int tile_offs; /* sprite chain offset */
+ int zoomx, zoomy; /* zoom value */
+
+ for (offs = 0x03f8 / 2 ; offs >= 0 ; offs -= 0x008 / 2)
+ {
+ if (offs < 0x01b0 && priority == 0) continue;
+ if (offs >= 0x01b0 && priority == 1) continue;
+
+ x0 = TC0080VCO_spriteram[offs + 1] & 0x3ff;
+ y0 = TC0080VCO_spriteram[offs + 0] & 0x3ff;
+ zoomx = (TC0080VCO_spriteram[offs + 2] & 0x7f00) >> 8;
+ zoomy = (TC0080VCO_spriteram[offs + 2] & 0x007f);
+ tile_offs = (TC0080VCO_spriteram[offs + 3] & 0x1fff) << 2;
+ ysize = size[ ( TC0080VCO_spriteram[ offs ] & 0x0c00 ) >> 10 ];
+
+ if (tile_offs)
+ {
+ /* Convert zoomy value to real value as zoomx */
+ zoomy = zoomy_conv_table[zoomy];
+
+ if (zoomx < 63)
+ {
+ dx = 8 + (zoomx + 2) / 8;
+ ex = (zoomx + 2) % 8;
+ zx = ((dx << 1) + ex) << 11;
+ }
+ else
+ {
+ dx = 16 + (zoomx - 63) / 4;
+ ex = (zoomx - 63) % 4;
+ zx = (dx + ex) << 12;
+ }
+
+ if (zoomy < 63)
+ {
+ dy = 8 + (zoomy + 2) / 8;
+ ey = (zoomy + 2) % 8;
+ zy = ((dy << 1) + ey) << 11;
+ }
+ else
+ {
+ dy = 16 + (zoomy - 63) / 4;
+ ey = (zoomy - 63) % 4;
+ zy = (dy + ey) << 12;
+ }
+
+ if (x0 >= 0x200) x0 -= 0x400;
+ if (y0 >= 0x200) y0 -= 0x400;
+
+ if (TC0080VCO_flipscreen)
+ {
+ x0 = 497 - x0;
+ y0 = 498 - y0;
+ dx = -dx;
+ dy = -dy;
+ }
+ else
+ {
+ x0 += 1;
+ y0 += 2;
+ }
+
+ y = y0;
+ for (j = 0 ; j < ysize ; j ++)
+ {
+ x = x0;
+ for (k = 0 ; k < 4 ; k ++)
+ {
+ if (tile_offs >= 0x1000)
+ {
+ int tile, color, flipx, flipy;
+
+ tile = TC0080VCO_chain_ram_0[tile_offs] & 0x7fff;
+ color = TC0080VCO_chain_ram_1[tile_offs] & 0x001f;
+ flipx = TC0080VCO_chain_ram_1[tile_offs] & 0x0040;
+ flipy = TC0080VCO_chain_ram_1[tile_offs] & 0x0080;
+
+ if (TC0080VCO_flipscreen)
+ {
+ flipx ^= 0x0040;
+ flipy ^= 0x0080;
+ }
+
+ drawgfxzoom( bitmap, Machine -> gfx[0],
+ tile,
+ color,
+ flipx, flipy,
+ x, y,
+ cliprect,
+ TRANSPARENCY_PEN, 0,
+ zx, zy
+ );
+ }
+ tile_offs ++;
+ x += dx;
+ }
+ y += dy;
+ }
+ }
+ }
+}
+
+extern UINT16 *taitoair_line_ram;
+
+enum { FRAC_SHIFT = 16, POLY_MAX_PT = 16 };
+
+static struct {
+ int x1, y1, x2, y2;
+} view;
+
+struct spoint {
+ INT32 x, y;
+};
+
+struct poly {
+ struct spoint p[POLY_MAX_PT];
+ int pcount;
+ int col;
+};
+
+static void fill_slope(mame_bitmap *bitmap, int color, INT32 x1, INT32 x2, INT32 sl1, INT32 sl2, INT32 y1, INT32 y2, INT32 *nx1, INT32 *nx2)
+{
+ if(y1 > view.y2)
+ return;
+
+ if(y2 <= view.y1) {
+ int delta = y2-y1;
+ *nx1 = x1+delta*sl1;
+ *nx2 = x2+delta*sl2;
+ return;
+ }
+
+ if(y1 < -1000000 || y1 > 1000000)
+ return;
+
+ if(y2 > view.y2)
+ y2 = view.y2+1;
+
+ if(y1 < view.y1) {
+ int delta = view.y1 - y1;
+ x1 += delta*sl1;
+ x2 += delta*sl2;
+ y1 = view.y1;
+ }
+
+ if(x1 > x2 || (x1==x2 && sl1 > sl2)) {
+ INT32 t, *tp;
+ t = x1;
+ x1 = x2;
+ x2 = t;
+ t = sl1;
+ sl1 = sl2;
+ sl2 = t;
+ tp = nx1;
+ nx1 = nx2;
+ nx2 = tp;
+ }
+
+ while(y1 < y2) {
+ if(y1 >= view.y1) {
+ int xx1 = x1>>FRAC_SHIFT;
+ int xx2 = x2>>FRAC_SHIFT;
+ if(xx1 <= view.x2 || xx2 >= view.x1) {
+ if(xx1 < view.x1)
+ xx1 = view.x1;
+ if(xx2 > view.x2)
+ xx2 = view.x2;
+
+ while(xx1 <= xx2) {
+ *BITMAP_ADDR16(bitmap, y1, xx1) = color;
+ xx1++;
+ }
+ }
+ }
+
+ x1 += sl1;
+ x2 += sl2;
+ y1++;
+ }
+ *nx1 = x1;
+ *nx2 = x2;
+}
+
+static void fill_poly(mame_bitmap *bitmap, const struct poly *q)
+{
+ INT32 sl1, sl2, cury, limy, x1, x2;
+ int pmin, pmax, i, ps1, ps2;
+ struct spoint p[POLY_MAX_PT*2];
+ int color = q->col;
+ int pcount = q->pcount;
+
+ for(i=0; i<pcount; i++) {
+ p[i].x = p[i+pcount].x = q->p[i].x << FRAC_SHIFT;
+ p[i].y = p[i+pcount].y = q->p[i].y;
+ }
+
+ pmin = pmax = 0;
+ for(i=1; i<pcount; i++) {
+ if(p[i].y < p[pmin].y)
+ pmin = i;
+ if(p[i].y > p[pmax].y)
+ pmax = i;
+ }
+
+ cury = p[pmin].y;
+ limy = p[pmax].y;
+
+ if(cury == limy)
+ return;
+
+ if(cury > view.y2)
+ return;
+ if(limy <= view.y1)
+ return;
+
+ if(limy > view.y2)
+ limy = view.y2;
+
+ ps1 = pmin+pcount;
+ ps2 = pmin;
+
+ goto startup;
+
+ for(;;) {
+ if(p[ps1-1].y == p[ps2+1].y) {
+ fill_slope(bitmap, color, x1, x2, sl1, sl2, cury, p[ps1-1].y, &x1, &x2);
+ cury = p[ps1-1].y;
+ if(cury >= limy)
+ break;
+ ps1--;
+ ps2++;
+
+ startup:
+ while(p[ps1-1].y == cury)
+ ps1--;
+ while(p[ps2+1].y == cury)
+ ps2++;
+ x1 = p[ps1].x;
+ x2 = p[ps2].x;
+ sl1 = (x1-p[ps1-1].x)/(cury-p[ps1-1].y);
+ sl2 = (x2-p[ps2+1].x)/(cury-p[ps2+1].y);
+ } else if(p[ps1-1].y < p[ps2+1].y) {
+ fill_slope(bitmap, color, x1, x2, sl1, sl2, cury, p[ps1-1].y, &x1, &x2);
+ cury = p[ps1-1].y;
+ if(cury >= limy)
+ break;
+ ps1--;
+ while(p[ps1-1].y == cury)
+ ps1--;
+ x1 = p[ps1].x;
+ sl1 = (x1-p[ps1-1].x)/(cury-p[ps1-1].y);
+ } else {
+ fill_slope(bitmap, color, x1, x2, sl1, sl2, cury, p[ps2+1].y, &x1, &x2);
+ cury = p[ps2+1].y;
+ if(cury >= limy)
+ break;
+ ps2++;
+ while(p[ps2+1].y == cury)
+ ps2++;
+ x2 = p[ps2].x;
+ sl2 = (x2-p[ps2+1].x)/(cury-p[ps2+1].y);
+ }
+ }
+}
+
+VIDEO_UPDATE( taitoair )
+{
+ TC0080VCO_tilemap_update(machine);
+
+ fillbitmap(bitmap, machine->pens[0x41], cliprect);
+
+#ifdef MAME_DEBUG
+ if ( !input_code_pressed(KEYCODE_A) )
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,0,0,0);
+ if ( !input_code_pressed(KEYCODE_S) )
+ draw_sprites(bitmap,cliprect,0);
+ if ( !input_code_pressed(KEYCODE_D) )
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,1,0,0);
+ if ( !input_code_pressed(KEYCODE_F) )
+ draw_sprites(bitmap,cliprect,1);
+#else
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,0,0,0);
+ draw_sprites (bitmap,cliprect,0);
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,1,0,0);
+ draw_sprites (bitmap,cliprect,1);
+#endif
+
+ TC0080VCO_tilemap_draw(machine,bitmap,cliprect,2,0,0);
+
+ if(taitoair_line_ram[0x3fff]) {
+ int adr = 0x3fff;
+ struct poly q;
+ view.x1 = cliprect->min_x;
+ view.y1 = cliprect->min_y;
+ view.x2 = cliprect->max_x;
+ view.y2 = cliprect->max_y;
+
+ while(adr>=0 && taitoair_line_ram[adr] && taitoair_line_ram[adr] != 0x4000) {
+ int pcount;
+ if(!(taitoair_line_ram[adr] & 0x8000) || adr<10) {
+ logerror("quad: unknown value %04x at %04x\n", taitoair_line_ram[adr], adr);
+ break;
+ }
+ q.col = (taitoair_line_ram[adr] & 0x7fff) + 0x300;
+ adr--;
+ pcount = 0;
+ while(pcount < POLY_MAX_PT && adr>=1 && !(taitoair_line_ram[adr] & 0xc000)) {
+ q.p[pcount].y = taitoair_line_ram[adr]+3*16;
+ q.p[pcount].x = taitoair_line_ram[adr-1];
+ pcount++;
+ adr -= 2;
+ }
+ adr--;
+ q.pcount = pcount;
+ fill_poly(bitmap, &q);
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/taitoic.c b/src/mame/video/taitoic.c
new file mode 100644
index 00000000000..031ba13a321
--- /dev/null
+++ b/src/mame/video/taitoic.c
@@ -0,0 +1,5263 @@
+/*******************************************************************************
+
+Taito Custom ICs
+================
+
+Thanks to Suzuki2go for his videos of Metal Black which made better
+emulation of TC0480SCP row and column effects possible.
+
+TODO
+----
+
+Tidy ups of new transparency-related code in TC0080VCO and TC0480SCP.
+Merge bryan_draw_scanline with its F3 equivalent?
+
+TC0080VCO seems bugged, various sigsevs after games have been reset.
+
+sizeof() s in the TC0110PCR section are probably unnecessary?
+
+ ---
+
+PC080SN
+-------
+Tilemap generator. Two tilemaps, with gfx data fetched from ROM.
+Darius uses 3xPC080SN and has double width tilemaps. (NB: it
+has not been verified that Topspeed uses this chip. Possibly
+it had a variant with added rowscroll capability.)
+
+Standard memory layout (two 64x64 tilemaps with 8x8 tiles)
+
+0000-3fff BG
+4000-41ff BG rowscroll (only verified to exist on Topspeed)
+4200-7fff unknown/unused?
+8000-bfff FG (FG/BG layer order fixed per game; Topspeed has BG on top)
+c000-c1ff FG rowscroll (only verified to exist on Topspeed)
+c200-ffff unknown/unused?
+
+Double width memory layout (two 128x64 tilemaps with 8x8 tiles)
+
+0000-7fff BG
+8000-ffff FG
+(Tile layout is different; tiles and colors are separated:
+0x0000-3fff color / flip words
+0x4000-7fff tile number words)
+
+Control registers
+
++0x20000 (on from tilemaps)
+000-001 BG scroll Y
+002-003 FG scroll Y
+
++0x40000
+000-001 BG scroll X
+002-003 FG scroll X
+
++0x50000 control word (written infrequently, only 2 bits used)
+ ---------------x flip screen
+ ----------x----- 0x20 poked here in Topspeed init, followed
+ by zero (Darius does the same).
+
+
+
+PC090OJ
+-------
+
+ Information from Raine (todo: reformat)
+
+ OBJECT RAM
+ ----------
+
+ - 8 bytes/sprite
+ - 256 sprites (0x800 bytes)
+ - First sprite has *highest* priority
+
+ -----+--------+-------------------------
+ Byte | Bit(s) | Use
+ -----+76543210+-------------------------
+ 0 |.x......| Flip Y Axis
+ 0 |x.......| Flip X Axis
+ 1 |....xxxx| Colour Bank
+ 2 |.......x| Sprite Y
+ 3 |xxxxxxxx| Sprite Y
+ 4 |...xxxxx| Sprite Tile
+ 5 |xxxxxxxx| Sprite Tile
+ 6 |.......x| Sprite X
+ 7 |xxxxxxxx| Sprite X
+ -----+--------+-------------------------
+
+ SPRITE CONTROL
+ --------------
+
+ - Maze of Flott [603D MASK] 201C 200B 200F
+ - Earth Joker 001C
+ - Cadash 0011 0013 0010 0000
+
+ -----+--------+-------------------------
+ Byte | Bit(s) | Use
+ -----+76543210+-------------------------
+ 0 |.......x| ?
+ 0 |......x.| Write Acknowledge?
+ 0 |..xxxx..| Colour Bank Offset
+ 0 |xx......| Unused
+ 1 |...xxxxx| Unused
+ 1 |..x.....| BG1:Sprite Priority
+ 1 |.x......| Priority?
+ 1 |x.......| Unused
+ -----+--------+-------------------------
+
+ OLD SPRITE CONTROL (RASTAN TYPE)
+ --------------------------------
+
+ -----+--------+-------------------------
+ Byte | Bit(s) | Use
+ -----+76543210+-------------------------
+ 1 |.......x| BG1:Sprite Priority?
+ 1 |......x.| Write Acknowledge?
+ 1 |xxx.....| Colour Bank Offset
+ -----+--------+-------------------------
+
+
+
+TC0080VCO
+---------
+Combined tilemap and motion object generator. The front tilemap
+fetches 3bpp gfx data from ram and only has 8 colors available.
+The other tilemaps use ROMs as usual. The same gfx set is used
+for both tilemaps and motion objects.
+
+There are two 64x64 tilemaps with 16x16 tiles; the optional
+front tilemap is 64x64 with 8x8 tiles.
+
+00000-00fff gfx data for FG0 (lo 2 bits per pixel)
+01000-01fff FG0 (64x64) (two tilenums per word, no color bits)
+02000-0bfff chain ram (sprite tile mapping/colors)
+0c000-0dfff BG0 tile numbers (64x64)
+0e000-0ffff BG1 tile numbers (64x64)
+10000-10fff gfx data for FG0 (hi bit per pixel: Ainferno proves not 4bpp)
+11000-11fff unknown / unused ?
+12000-1bfff chain ram (sprite tile mapping/colors)
+1c000-1dfff BG0 color / flip bits (64x64)
+1e000-1ffff BG1 color / flip bits (64x64)
+20000-203ff BG0 rowscroll (see Dleague title screen *)
+20400-207ff spriteram
+20800-2080f control registers
+
+[*only used in Dleague AFAIK. Note 0x200 words is not enough for a
+64x16 => 0x400 pixel high tilemap. So probably it wraps around and
+each rowscroll word affects 2 separate lines. Tacky, but wouldn't be
+noticeable unless y zoom more than halved the apparent pixel height
+meaning you could see more than half of the total tilemap...]
+
+[There is an oddity with this chip: FG0 areas can be addressed
+as chain ram, since the offsets used in spriteram are from the
+start of the TC0080VCO address space - not the start of chain ram.
+In practice only Dleague seems to do this, for c.10 frames as the
+pitcher bowls, and I think it's a coding error. Log it and see.]
+
+[Ainferno and Syvalion are only games using FG0 layer.]
+
+Control registers
+
+000-001 ----xx---------- screen invert
+ ------xx-------- unknown (always set)
+ ---------------- any others ???
+
+002-003 BG0 scroll X (0x3ff is the tilemap span)
+004-005 BG1 scroll X
+006-007 BG0 scroll Y (0x3ff is the tilemap span)
+008-009 BG1 scroll Y
+00a-00b unknown (Syvalion - FG0 scroll? - and Recordbr)
+00c-00d BG0 zoom (hi byte=X, lo byte=Y *)
+00e-00f BG1 zoom (hi byte=X, lo byte=Y *)
+
+[* X zoom normal=0x3f Y zoom normal=0x7f]
+
+All we know is that as y zoom gets bigger the magnification grows:
+this seems to be the only zoom feature actually used in the games.
+
+
+TC0100SCN
+---------
+Tilemap generator. The front tilemap fetches gfx data from RAM,
+the others use ROMs as usual.
+
+Standard memory layout (three 64x64 tilemaps with 8x8 tiles)
+
+0000-3fff BG0
+4000-5fff FG0
+6000-6fff gfx data for FG0
+7000-7fff unused (probably)
+8000-bfff BG1
+c000-c3ff BG0 rowscroll (second half unused*)
+c400-c7ff BG1 rowscroll (second half unused*)
+c800-dfff unused (probably)
+e000-e0ff BG0 colscroll [see info below]
+e100-ffff unused (probably)
+
+Double width tilemaps memory layout (two 128x64 tilemaps, one 128x32 tilemap)
+
+00000-07fff BG0 (128x64)
+08000-0ffff BG1 (128x64)
+10000-103ff BG0 rowscroll (second half unused*)
+10400-107ff BG1 rowscroll (second half unused*)
+10800-108ff BG0 colscroll [evidenced by Warriorb inits from $1634]
+10900-10fff unused (probably)
+11000-11fff gfx data for FG0
+12000-13fff FG0 (128x32)
+
+* Perhaps Taito wanted potential for double height tilemaps on the
+ TC0100SCN. The inits state the whole area is "linescroll".
+
+Control registers
+
+000-001 BG0 scroll X
+002-003 BG1 scroll X
+004-005 FG0 scroll X
+006-007 BG0 scroll Y
+008-009 BG1 scroll Y
+00a-00b FG0 scroll Y
+00c-00d ---------------x BG0 disable
+ --------------x- BG1 disable
+ -------------x-- FG0 disable
+ ------------x--- change priority order from BG0-BG1-FG0 to BG1-BG0-FG0
+ -----------x---- double width tilemaps + different memory map
+ (cameltru and all the multi-screen games)
+ ----------x----- unknown (set in most of the TaitoZ games and Cadash)
+00e-00f ---------------x flip screen
+ ----------x----- this TC0100SCN is subsidiary [= not the main one]
+ (Multi-screen games only. Could it mean: "write
+ through what is written into main TC0100SCN" ?)
+ --x------------- unknown (thunderfox)
+
+
+Colscroll [standard layout]
+=========
+
+The e000-ff area is not divided into two halves, it appears to refer only
+to bg1 - the top most layer unless bg0/1 are flipped.
+
+128 words are available in 0xe0?? area. Every word scrolls 8
+pixels.
+
+Growl
+-----
+This uses column scroll in the boat scene [that's just after you have
+disposed of the fat men in fezzes] and in the underground lava cavern
+scene.
+
+Boat scene: code from $2eb58 appears to be doing see-saw motion for
+water layer under boat. $e08c is highest word written, it oscillates
+between fffa and 0005. Going back towards $e000 a middle point is reached
+which sticks at zero. By $e000 written values oscillate again.
+
+A total of 80 words are being written to [some below 0xe000, I think those
+won't do anything, sloppy coding...]
+
+Cavern scene: code from $3178a moves a sequence of 0s, 1s and 0x1ffs
+along. These words equate to 0, +1, -1 so will gently ripple bg 0
+up and down adding to the shimmering heat effect.
+
+Ninja Kids
+----------
+This uses column scroll in the fat flame boss scene [that's the end of
+round 2] and in the last round in the final confrontation with Satan scene.
+
+Fat flame boss: code at $8eee moves a sequence of 1s and 0s along. This
+is similar to the heat shimmer in Growl cavern scene.
+
+Final boss: code at $a024 moves a sine wave of values 0-4 along. When
+you are close to getting him the range of values expands to 0-10.
+
+Gunfront
+--------
+In demo mode when the boss appears with the clouds, a sequence of 40 words
+forming sine wave between 0xffd0 and ffe0 is moved along. Bg0 has been
+given priority over bg1 so it's the foreground (clouds) affected.
+
+The 40 words will affect 40 8-pixel columns [rows, as this game is
+rotated] i.e. what is visible on screen at any point.
+
+Galmedes
+--------
+Towards end of first round in empty starfield area, about three big ship
+sprites cross the screen (scrolling down with the starfield). 16 starfield
+columns [rows, as the game is rotated] scroll across with the ship.
+$84fc0 and neighbouring routines poke col scroll area.
+
+
+
+TC0150ROD
+---------
+Road generator. Two roads allow for forking. Gfx data fetched from ROM.
+Refer to notes below.
+
+
+
+TC0280GRD
+TC0430GRW
+---------
+These generate a zooming/rotating tilemap. The TC0280GRD has to be used in
+pairs, while the TC0430GRW is a newer, single-chip solution.
+Regardless of the hardware differences, the two are functionally identical
+except for incxx and incxy, which need to be multiplied by 2 in the TC0280GRD
+to bring them to the same scale of the other parameters (maybe the chip has
+half-pixel resolution?).
+
+control registers:
+000-003 start x
+004-005 incxx
+006-007 incyx
+008-00b start y
+00c-00d incxy
+00e-00f incyy
+
+
+
+TC0360PRI
+---------
+Priority manager
+A higher priority value means higher priority. 0 could mean disable but
+I'm not sure. If two inputs have the same priority value, I think the first
+one has priority, but I'm not sure of that either.
+It seems the chip accepts three inputs from three different sources, and
+each one of them can declare to have four different priority levels.
+
+000 Top two bits indicate special blend mode (see taito_f2.c). Other bits unused?
+001 in games with a roz layer, this is the roz palette bank (bottom 6 bits
+ affect roz color, top 2 bits affect priority)
+002 unknown
+003 unknown
+
+004 ----xxxx \ priority level 0 (usually FG1 if present)
+ xxxx---- | Input priority level 1 (usually FG0)
+005 ----xxxx | #1 priority level 2 (usually BG0)
+ xxxx---- / priority level 3 (usually BG1)
+
+006 ----xxxx \ priority level 0 (usually sprites with top color bits 00)
+ xxxx---- | Input priority level 1 (usually sprites with top color bits 01)
+007 ----xxxx | #2 priority level 2 (usually sprites with top color bits 10)
+ xxxx---- / priority level 3 (usually sprites with top color bits 11)
+
+008 ----xxxx \ priority level 0 (e.g. roz layer if top bits of register 001 are 00)
+ xxxx---- | Input priority level 1 (e.g. roz layer if top bits of register 001 are 01)
+009 ----xxxx | #3 priority level 2 (e.g. roz layer if top bits of register 001 are 10)
+ xxxx---- / priority level 3 (e.g. roz layer if top bits of register 001 are 11)
+
+00a unused
+00b unused
+00c unused
+00d unused
+00e unused
+00f unused
+
+
+
+TC0480SCP
+---------
+Tilemap generator, has four zoomable tilemaps with 16x16 tiles.
+It also has a front tilemap with 8x8 tiles which fetches gfx data
+from RAM.
+
+BG2 and 3 are "special" layers which have row zoom and source
+columnscroll. The selectable layer priority order is a function
+of the need to have the "special" layers in particular priority
+positions.
+
+Standard memory layout (four 32x32 bg tilemaps, one 64x64 fg tilemap)
+
+0000-0fff BG0
+1000-1fff BG1
+2000-2fff BG2
+3000-3fff BG3
+4000-43ff BG0 rowscroll
+4400-47ff BG1 rowscroll
+4800-4bff BG2 rowscroll
+4c00-4fff BG3 rowscroll
+5000-53ff BG0 rowscroll low order bytes (see info below)
+5400-57ff BG1 rowscroll low order bytes
+5800-5bff BG2 rowscroll low order bytes
+5c00-5fff BG3 rowscroll low order bytes
+6000-63ff BG2 row zoom
+6400-67ff BG3 row zoom
+6800-6bff BG2 source colscroll
+6c00-6fff BG3 source colscroll
+7000-bfff unknown/unused?
+c000-dfff FG0
+e000-ffff gfx data for FG0 (4bpp)
+
+Double width tilemaps memory layout (four 64x32 bg tilemaps, one 64x64 fg tilemap)
+
+0000-1fff BG0
+2000-3fff BG1
+4000-5fff BG2
+6000-7fff BG3
+8000-83ff BG0 rowscroll
+8400-87ff BG1 rowscroll
+8800-8bff BG2 rowscroll
+8c00-8fff BG3 rowscroll
+9000-93ff BG0 rowscroll low order bytes (used for accuracy with row zoom or layer zoom)
+9400-97ff BG1 rowscroll low order bytes [*]
+9800-9bff BG2 rowscroll low order bytes
+9c00-9fff BG3 rowscroll low order bytes
+a000-a3ff BG2 row zoom [+]
+a400-a7ff BG3 row zoom
+a800-abff BG2 source colscroll
+ac00-afff BG3 source colscroll
+b000-bfff unknown (Slapshot and Superchs poke in TBA OVER error message in FG0 format)
+c000-dfff FG0
+e000-ffff gfx data for FG0 (4bpp)
+
+[* Gunbustr suggests that high bytes are irrelevant: it leaves them
+all zeroed. Superchs is the only game which uses high bytes that
+aren't the low byte of the main rowscroll (Footchmp/Undrfire have
+this verified in the code).]
+
+[+ Usual row zoom values are 0 - 0x7f. Gunbustr also uses 0x80-d0
+approx. Undrfire keeps to the 0-0x7f range but oddly also uses
+the high byte with a mask of 0x3f. Meaning of this high byte is
+unknown.]
+
+Bg layers tile word layout
+
++0x00 %yx..bbbb cccccccc b=control bits(?) c=color .=unused(?)
++0x02 tilenum
+[y=yflip x=xflip b=unknown seen in Metalb]
+
+Control registers
+
+000-001 BG0 x scroll (layer priority order is definable)
+002-003 BG1 x scroll
+004-005 BG2 x scroll
+006-007 BG3 x scroll
+008-009 BG0 y scroll
+00a-00b BG1 y scroll
+00c-00d BG2 y scroll
+00e-00f BG3 y scroll
+010-011 BG0 zoom (high byte = X zoom, low byte = Y zoom,
+012-013 BG1 zoom compression is allowed on Y axis only)
+014-015 BG2 zoom
+016-017 BG3 zoom
+018-019 Text layer x scroll
+01a-01b Text layer y scroll
+01c-01d Unused (not written)
+01e-01f Layer Control register
+ x------- Double width tilemaps (4 bg tilemaps become 64x32, and the
+ memory layout changes). Slapshot changes this on the fly.
+ -x------ Flip screen
+ --x----- unknown
+
+ Set in Metalb init by whether a byte in prg ROM $7fffe is zero.
+ Subsequently Metalb changes it for some screen layer layouts.
+ Footchmp clears it, Hthero sets it [then both leave it alone].
+ Deadconx code at $10e2 is interesting, with possible values of:
+ 0x0, 0x20, 0x40, 0x60 poked in (via ram buffer) to control reg,
+ dependent on byte in prg ROM $7fffd and whether screen is flipped.
+
+ ---xxx-- BG layer priority order
+
+ ...000.. 0 1 2 3
+ ...001.. 1 2 3 0 (no evidence of this)
+ ...010.. 2 3 0 1 (no evidence of this)
+ ...011.. 3 0 1 2
+ ...100.. 3 2 1 0
+ ...101.. 2 1 0 3 [Gunbustr attract and Metalb (c) screen]
+ ...110.. 1 0 3 2 (no evidence of this)
+ ...111.. 0 3 2 1
+
+ ------x- BG3 row zoom enable
+ -------x BG2 row zoom enable
+
+020-021 BG0 dx (provides extra precision to x-scroll, only changed with xscroll)
+022-023 BG1 dx
+024-025 BG2 dx
+026-027 BG3 dx
+028-029 BG0 dy (provides extra precision to y-scroll, only changed with yscroll)
+02a-02b BG1 dy
+02c-02d BG2 dy
+02e-02f BG3 dy
+
+[see code at $1b4a in Slapshot and $xxxxx in Undrfire for evidence of row areas]
+
+
+TC0110PCR
+---------
+Interface to palette RAM, and simple tilemap/sprite priority handler. The
+priority order seems to be fixed.
+The data bus is 16 bits wide.
+
+000 W selects palette RAM address
+002 RW read/write palette RAM
+004 W unknown, often written to
+
+
+TC0220IOC
+---------
+A simple I/O interface with integrated watchdog.
+It has four address inputs, which would suggest 16 bytes of addressing space,
+but only the first 8 seem to be used.
+
+000 R IN00-07 (DSA)
+000 W watchdog reset
+001 R IN08-15 (DSB)
+002 R IN16-23 (1P)
+002 W unknown. Usually written on startup: initialize?
+003 R IN24-31 (2P)
+004 RW coin counters and lockout
+005 W unknown
+006 W unknown
+007 R INB0-7 (coin)
+
+
+TC0510NIO
+---------
+Newer version of the I/O chip
+
+000 R DSWA
+000 W watchdog reset
+001 R DSWB
+001 W unknown (ssi)
+002 R 1P
+003 R 2P
+003 W unknown (yuyugogo, qzquest and qzchikyu use it a lot)
+004 RW coin counters and lockout
+005 W unknown
+006 W unknown (koshien and pulirula use it a lot)
+007 R coin
+
+
+TC0640FIO
+---------
+Newer version of the I/O chip ?
+
+
+***************************************************************************/
+
+#include "driver.h"
+#include "taitoic.h"
+
+#define TOPSPEED_ROAD_COLORS
+
+
+/* These scanline drawing routines lifted from Taito F3: optimise / merge ? */
+
+INLINE void taitoic_drawscanline(
+ mame_bitmap *bitmap,int x,int y,
+ const UINT16 *src,int transparent,UINT32 orient,int pri, const rectangle *cliprect)
+{
+ UINT16 *dsti = BITMAP_ADDR16(bitmap, y, x);
+ UINT8 *dstp = BITMAP_ADDR8(priority_bitmap, y, x);
+ int length=cliprect->max_x - cliprect->min_x + 1;
+
+ src+=cliprect->min_x;
+ dsti+=cliprect->min_x;
+ dstp+=cliprect->min_x;
+ if (transparent) {
+ while (length--) {
+ UINT32 spixel = *src++;
+ if (spixel<0x7fff) {
+ *dsti = spixel;
+ *dstp = pri;
+ }
+ dsti++;
+ dstp++;
+ }
+ } else { /* Not transparent case */
+ while (length--) {
+ *dsti++ = *src++;
+ *dstp++ = pri;
+ }
+ }
+}
+
+
+
+
+/***************************************************************************/
+
+/* Note: various assumptions are made in these routines, typically that
+ only CPU#0 is of interest. If in doubt, check the routine. */
+
+static int has_write_handler(int cpunum, write16_handler handler)
+{
+ const address_map *map;
+ for (map = memory_get_map(cpunum, ADDRESS_SPACE_PROGRAM); map && !IS_AMENTRY_END(map); map++)
+ if (map->write.handler16 == handler)
+ return 1;
+
+ return 0;
+}
+
+int number_of_TC0100SCN(void)
+{
+ int has_chip[3] = {0,0,0};
+
+ /* scan the memory handlers and see how many TC0100SCN are used */
+ if (has_write_handler(0, TC0100SCN_word_0_w) ||
+ has_write_handler(0, TC0100SCN_dual_screen_w) ||
+ has_write_handler(0, TC0100SCN_triple_screen_w))
+ has_chip[0] = 1;
+
+ if (has_write_handler(0, TC0100SCN_word_1_w))
+ has_chip[1] = 1;
+
+ if (has_write_handler(0, TC0100SCN_word_2_w))
+ has_chip[2] = 1;
+
+ /* Catch illegal configurations */
+ /* TODO: we should give an appropriate warning */
+
+ if (!has_chip[0] && (has_chip[1] || has_chip[2]))
+ return -1;
+
+ if (!has_chip[1] && has_chip[2])
+ return -1;
+
+ return (has_chip[0] + has_chip[1] + has_chip[2]);
+}
+
+
+int has_TC0110PCR(void)
+{
+ return has_write_handler(0, TC0110PCR_word_w) ||
+ has_write_handler(0, TC0110PCR_step1_word_w) ||
+ has_write_handler(0, TC0110PCR_step1_rbswap_word_w) ||
+ has_write_handler(0, TC0110PCR_step1_4bpg_word_w);
+}
+
+int has_second_TC0110PCR(void)
+{
+ return has_write_handler(0, TC0110PCR_step1_word_1_w);
+}
+
+int has_third_TC0110PCR(void)
+{
+ return has_write_handler(0, TC0110PCR_step1_word_2_w);
+}
+
+
+int has_TC0150ROD(void)
+{
+ return has_write_handler(0, TC0150ROD_word_w) ||
+ has_write_handler(1, TC0150ROD_word_w) ||
+ has_write_handler(2, TC0150ROD_word_w);
+}
+
+
+int has_TC0280GRD(void)
+{
+ return has_write_handler(0, TC0280GRD_word_w);
+}
+
+
+int has_TC0360PRI(void)
+{
+ return has_write_handler(0, TC0360PRI_halfword_w) ||
+ has_write_handler(0, TC0360PRI_halfword_swap_w);
+}
+
+
+int has_TC0430GRW(void)
+{
+ return has_write_handler(0, TC0430GRW_word_w);
+}
+
+
+int has_TC0480SCP(void)
+{
+ return has_write_handler(0, TC0480SCP_word_w);
+}
+
+
+
+/***************************************************************************/
+
+
+
+#define PC080SN_RAM_SIZE 0x10000
+#define PC080SN_MAX_CHIPS 2
+static int PC080SN_chips;
+
+static UINT16 PC080SN_ctrl[PC080SN_MAX_CHIPS][8];
+
+static UINT16 *PC080SN_ram[PC080SN_MAX_CHIPS],
+ *PC080SN_bg_ram[PC080SN_MAX_CHIPS][2],
+ *PC080SN_bgscroll_ram[PC080SN_MAX_CHIPS][2];
+
+static int PC080SN_bgscrollx[PC080SN_MAX_CHIPS][2],PC080SN_bgscrolly[PC080SN_MAX_CHIPS][2];
+static int PC080SN_xoffs,PC080SN_yoffs;
+
+static tilemap *PC080SN_tilemap[PC080SN_MAX_CHIPS][2];
+static int PC080SN_bg_gfx[PC080SN_MAX_CHIPS];
+static int PC080SN_yinvert,PC080SN_dblwidth;
+
+INLINE void common_get_PC080SN_bg_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,UINT16 *ram,int gfxnum)
+{
+ UINT16 code,attr;
+
+ if (!PC080SN_dblwidth)
+ {
+ code = (ram[2*tile_index + 1] & 0x3fff);
+ attr = ram[2*tile_index];
+ }
+ else
+ {
+ code = (ram[tile_index + 0x2000] & 0x3fff);
+ attr = ram[tile_index];
+ }
+
+ SET_TILE_INFO(
+ gfxnum,
+ code,
+ (attr & 0x1ff),
+ TILE_FLIPYX((attr & 0xc000) >> 14));
+}
+
+INLINE void common_get_PC080SN_fg_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,UINT16 *ram,int gfxnum)
+{
+ UINT16 code,attr;
+
+ if (!PC080SN_dblwidth)
+ {
+ code = (ram[2*tile_index + 1] & 0x3fff);
+ attr = ram[2*tile_index];
+ }
+ else
+ {
+ code = (ram[tile_index + 0x2000] & 0x3fff);
+ attr = ram[tile_index];
+ }
+
+ SET_TILE_INFO(
+ gfxnum,
+ code,
+ (attr & 0x1ff),
+ TILE_FLIPYX((attr & 0xc000) >> 14));
+}
+
+static TILE_GET_INFO( PC080SN_get_bg_tile_info_0 )
+{
+ common_get_PC080SN_bg_tile_info(machine,tileinfo,tile_index,PC080SN_bg_ram[0][0],PC080SN_bg_gfx[0]);
+}
+
+static TILE_GET_INFO( PC080SN_get_fg_tile_info_0 )
+{
+ common_get_PC080SN_fg_tile_info(machine,tileinfo,tile_index,PC080SN_bg_ram[0][1],PC080SN_bg_gfx[0]);
+}
+
+static TILE_GET_INFO( PC080SN_get_bg_tile_info_1 )
+{
+ common_get_PC080SN_bg_tile_info(machine,tileinfo,tile_index,PC080SN_bg_ram[1][0],PC080SN_bg_gfx[1]);
+}
+
+static TILE_GET_INFO( PC080SN_get_fg_tile_info_1 )
+{
+ common_get_PC080SN_fg_tile_info(machine,tileinfo,tile_index,PC080SN_bg_ram[1][1],PC080SN_bg_gfx[1]);
+}
+
+static tile_get_info_callback PC080SN_get_tile_info[PC080SN_MAX_CHIPS][2] =
+{
+ { PC080SN_get_bg_tile_info_0, PC080SN_get_fg_tile_info_0 },
+ { PC080SN_get_bg_tile_info_1, PC080SN_get_fg_tile_info_1 }
+};
+
+static void PC080SN_restore_scroll(int chip)
+{
+ int flip;
+
+ PC080SN_bgscrollx[chip][0] = -PC080SN_ctrl[chip][0];
+ PC080SN_bgscrollx[chip][1] = -PC080SN_ctrl[chip][1];
+ PC080SN_bgscrolly[chip][0] = -PC080SN_ctrl[chip][2];
+ PC080SN_bgscrolly[chip][1] = -PC080SN_ctrl[chip][3];
+
+ flip = (PC080SN_ctrl[chip][4] & 0x01) ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0;
+ tilemap_set_flip(PC080SN_tilemap[chip][0],flip);
+ tilemap_set_flip(PC080SN_tilemap[chip][1],flip);
+}
+
+
+/* opaque parameter is no longer supported and will be removed */
+
+void PC080SN_vh_start(int chips,int gfxnum,int x_offset,int y_offset,int y_invert,
+ int opaque,int dblwidth)
+{
+ int i;
+
+ assert(chips <= PC080SN_MAX_CHIPS);
+ PC080SN_chips = chips;
+
+ PC080SN_yinvert = y_invert;
+ PC080SN_dblwidth = dblwidth;
+ PC080SN_xoffs = x_offset;
+ PC080SN_yoffs = y_offset;
+
+ for (i = 0;i < chips;i++)
+ {
+ int xd,yd;
+
+ if (!PC080SN_dblwidth) /* standard tilemaps */
+ {
+ PC080SN_tilemap[i][0] = tilemap_create(PC080SN_get_tile_info[i][0],tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ PC080SN_tilemap[i][1] = tilemap_create(PC080SN_get_tile_info[i][1],tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ }
+ else /* double width tilemaps */
+ {
+ PC080SN_tilemap[i][0] = tilemap_create(PC080SN_get_tile_info[i][0],tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,128,64);
+ PC080SN_tilemap[i][1] = tilemap_create(PC080SN_get_tile_info[i][1],tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,128,64);
+ }
+
+ PC080SN_ram[i] = auto_malloc(PC080SN_RAM_SIZE);
+
+ PC080SN_bg_ram[i][0] = PC080SN_ram[i] + 0x0000 /2;
+ PC080SN_bg_ram[i][1] = PC080SN_ram[i] + 0x8000 /2;
+ PC080SN_bgscroll_ram[i][0] = PC080SN_ram[i] + 0x4000 /2;
+ PC080SN_bgscroll_ram[i][1] = PC080SN_ram[i] + 0xc000 /2;
+ memset(PC080SN_ram[i],0,PC080SN_RAM_SIZE);
+
+ state_save_register_item_pointer("PC080SN", i, PC080SN_ram[i], PC080SN_RAM_SIZE/2);
+ state_save_register_item_array("PC080SN", i, PC080SN_ctrl[i]);
+ state_save_register_func_postload_int(PC080SN_restore_scroll, i);
+
+ /* use the given gfx set for bg tiles */
+ PC080SN_bg_gfx[i] = gfxnum;
+
+ tilemap_set_transparent_pen(PC080SN_tilemap[i][0],0);
+ tilemap_set_transparent_pen(PC080SN_tilemap[i][1],0);
+
+ /* I'm setting optional chip #2 with the same offsets (Topspeed) */
+ xd = (i == 0) ? -x_offset : -x_offset;
+ yd = (i == 0) ? y_offset : y_offset;
+
+ tilemap_set_scrolldx(PC080SN_tilemap[i][0],-16 + xd,-16 - xd);
+ tilemap_set_scrolldy(PC080SN_tilemap[i][0],yd,-yd);
+ tilemap_set_scrolldx(PC080SN_tilemap[i][1],-16 + xd,-16 - xd);
+ tilemap_set_scrolldy(PC080SN_tilemap[i][1],yd,-yd);
+
+ if (!PC080SN_dblwidth)
+ {
+ tilemap_set_scroll_rows(PC080SN_tilemap[i][0],512);
+ tilemap_set_scroll_rows(PC080SN_tilemap[i][1],512);
+ }
+ }
+}
+
+READ16_HANDLER( PC080SN_word_0_r )
+{
+ return PC080SN_ram[0][offset];
+}
+
+READ16_HANDLER( PC080SN_word_1_r )
+{
+ return PC080SN_ram[1][offset];
+}
+
+static void PC080SN_word_w(int chip,offs_t offset,UINT16 data,UINT32 mem_mask)
+{
+ COMBINE_DATA(&PC080SN_ram[chip][offset]);
+ if (!PC080SN_dblwidth)
+ {
+ if (offset < 0x2000)
+ tilemap_mark_tile_dirty(PC080SN_tilemap[chip][0],offset / 2);
+ else if (offset >= 0x4000 && offset < 0x6000)
+ tilemap_mark_tile_dirty(PC080SN_tilemap[chip][1],(offset & 0x1fff) / 2);
+ }
+ else
+ {
+ if (offset < 0x4000)
+ tilemap_mark_tile_dirty(PC080SN_tilemap[chip][0],(offset & 0x1fff));
+ else if (offset >= 0x4000 && offset < 0x8000)
+ tilemap_mark_tile_dirty(PC080SN_tilemap[chip][1],(offset & 0x1fff));
+ }
+}
+
+WRITE16_HANDLER( PC080SN_word_0_w )
+{
+ PC080SN_word_w(0,offset,data,mem_mask);
+}
+
+WRITE16_HANDLER( PC080SN_word_1_w )
+{
+ PC080SN_word_w(1,offset,data,mem_mask);
+}
+
+static void PC080SN_xscroll_word_w(int chip,offs_t offset,UINT16 data,UINT32 mem_mask)
+{
+ COMBINE_DATA(&PC080SN_ctrl[chip][offset]);
+
+ data = PC080SN_ctrl[chip][offset];
+
+ switch (offset)
+ {
+ case 0x00:
+ PC080SN_bgscrollx[chip][0] = -data;
+ break;
+
+ case 0x01:
+ PC080SN_bgscrollx[chip][1] = -data;
+ break;
+ }
+}
+
+static void PC080SN_yscroll_word_w(int chip,offs_t offset,UINT16 data,UINT32 mem_mask)
+{
+ COMBINE_DATA(&PC080SN_ctrl[chip][offset+2]);
+
+ data = PC080SN_ctrl[chip][offset+2];
+ if (PC080SN_yinvert)
+ data = -data;
+
+ switch (offset)
+ {
+ case 0x00:
+ PC080SN_bgscrolly[chip][0] = -data;
+ break;
+
+ case 0x01:
+ PC080SN_bgscrolly[chip][1] = -data;
+ break;
+ }
+}
+
+static void PC080SN_ctrl_word_w(int chip,offs_t offset,UINT16 data,UINT32 mem_mask)
+{
+ COMBINE_DATA(&PC080SN_ctrl[chip][offset+4]);
+
+ data = PC080SN_ctrl[chip][offset+4];
+
+ switch (offset)
+ {
+ case 0x00:
+ {
+ int flip = (data & 0x01) ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0;
+
+ tilemap_set_flip(PC080SN_tilemap[chip][0],flip);
+ tilemap_set_flip(PC080SN_tilemap[chip][1],flip);
+ break;
+ }
+ }
+#if 0
+ popmessage("PC080SN ctrl = %4x",data);
+#endif
+}
+
+WRITE16_HANDLER( PC080SN_xscroll_word_0_w )
+{
+ PC080SN_xscroll_word_w(0,offset,data,mem_mask);
+}
+
+WRITE16_HANDLER( PC080SN_xscroll_word_1_w )
+{
+ PC080SN_xscroll_word_w(1,offset,data,mem_mask);
+}
+
+WRITE16_HANDLER( PC080SN_yscroll_word_0_w )
+{
+ PC080SN_yscroll_word_w(0,offset,data,mem_mask);
+}
+
+WRITE16_HANDLER( PC080SN_yscroll_word_1_w )
+{
+ PC080SN_yscroll_word_w(1,offset,data,mem_mask);
+}
+
+WRITE16_HANDLER( PC080SN_ctrl_word_0_w )
+{
+ PC080SN_ctrl_word_w(0,offset,data,mem_mask);
+}
+
+WRITE16_HANDLER( PC080SN_ctrl_word_1_w )
+{
+ PC080SN_ctrl_word_w(1,offset,data,mem_mask);
+}
+
+/* This routine is needed as an override by Jumping, which
+ doesn't set proper scroll values for foreground tilemap */
+
+void PC080SN_set_scroll(int chip,int tilemap_num,int scrollx,int scrolly)
+{
+ tilemap_set_scrollx(PC080SN_tilemap[chip][tilemap_num],0,scrollx);
+ tilemap_set_scrolly(PC080SN_tilemap[chip][tilemap_num],0,scrolly);
+}
+
+/* This routine is needed as an override by Jumping */
+
+void PC080SN_set_trans_pen(int chip,int tilemap_num,int pen)
+{
+ tilemap_set_transparent_pen(PC080SN_tilemap[chip][tilemap_num],pen);
+}
+
+
+void PC080SN_tilemap_update(void)
+{
+ int chip,j;
+
+ for (chip = 0;chip < PC080SN_chips;chip++)
+ {
+ tilemap_set_scrolly(PC080SN_tilemap[chip][0],0,PC080SN_bgscrolly[chip][0]);
+ tilemap_set_scrolly(PC080SN_tilemap[chip][1],0,PC080SN_bgscrolly[chip][1]);
+
+ if (!PC080SN_dblwidth)
+ {
+ for (j = 0;j < 256;j++)
+ tilemap_set_scrollx(PC080SN_tilemap[chip][0],
+ (j + PC080SN_bgscrolly[chip][0]) & 0x1ff,
+ PC080SN_bgscrollx[chip][0] - PC080SN_bgscroll_ram[chip][0][j]);
+ for (j = 0;j < 256;j++)
+ tilemap_set_scrollx(PC080SN_tilemap[chip][1],
+ (j + PC080SN_bgscrolly[chip][1]) & 0x1ff,
+ PC080SN_bgscrollx[chip][1] - PC080SN_bgscroll_ram[chip][1][j]);
+ }
+ else
+ {
+ tilemap_set_scrollx(PC080SN_tilemap[chip][0],0,PC080SN_bgscrollx[chip][0]);
+ tilemap_set_scrollx(PC080SN_tilemap[chip][1],0,PC080SN_bgscrollx[chip][1]);
+ }
+ }
+}
+
+
+static UINT16 topspeed_get_road_pixel_color(UINT16 pixel,UINT16 color)
+{
+ UINT16 road_body_color,off_road_color,pixel_type;
+
+ /* Color changes based on screenshots from game flyer */
+ pixel_type = (pixel % 0x10);
+ road_body_color = (pixel &0x7ff0) + 4;
+ off_road_color = road_body_color + 1;
+
+ if ((color &0xffe0) == 0xffe0)
+ {
+ pixel += 10; /* Tunnel colors */
+ road_body_color += 10;
+ off_road_color += 10;
+ }
+ else
+ {
+ /* Unsure which way round these bits go */
+ if (color &0x10) road_body_color += 5;
+ if (color &0x02) off_road_color += 5;
+ }
+
+ switch (pixel_type)
+ {
+ case 0x01: /* Center lines */
+ {
+ if (color &0x08) pixel = road_body_color;
+ break;
+ }
+ case 0x02: /* Road edge (inner) */
+ {
+ if (color &0x08) pixel = road_body_color;
+ break;
+ }
+ case 0x03: /* Road edge (outer) */
+ {
+ if (color &0x04) pixel = road_body_color;
+ break;
+ }
+ case 0x04: /* Road body */
+ {
+ pixel = road_body_color;
+ break;
+ }
+ case 0x05: /* Off road */
+ pixel = off_road_color;
+ default:
+ {}
+ }
+ return pixel;
+}
+
+
+static void topspeed_custom_draw(mame_bitmap *bitmap,const rectangle *cliprect,int chip,int layer,int flags,
+ UINT32 priority,UINT16 *color_ctrl_ram)
+{
+ UINT16 *dst16,*src16;
+ UINT8 *tsrc;
+ UINT16 scanline[1024]; /* won't be called by a wide-screen game, but just in case... */
+
+ mame_bitmap *srcbitmap = tilemap_get_pixmap(PC080SN_tilemap[chip][layer]);
+ mame_bitmap *flagsbitmap = tilemap_get_flagsmap(PC080SN_tilemap[chip][layer]);
+
+ UINT16 a,color;
+ int sx,x_index;
+ int i,y,y_index,src_y_index,row_index;
+
+ int flip = 0;
+ int machine_flip = 0; /* for ROT 180 ? */
+
+ int min_x = cliprect->min_x;
+ int max_x = cliprect->max_x;
+ int min_y = cliprect->min_y;
+ int max_y = cliprect->max_y;
+ int screen_width = max_x - min_x + 1;
+ int width_mask = 0x1ff; /* underlying tilemap */
+
+ if (!flip)
+ {
+ sx = PC080SN_bgscrollx[chip][layer] + 16 - PC080SN_xoffs;
+ y_index = PC080SN_bgscrolly[chip][layer] + min_y - PC080SN_yoffs;
+ }
+ else // never used
+ {
+ sx = 0;
+ y_index = 0;
+ }
+
+ if (!machine_flip) y = min_y; else y = max_y;
+
+ do
+ {
+ src_y_index = y_index &0x1ff; /* tilemaps are 512 px up/down */
+ row_index = (src_y_index - PC080SN_bgscrolly[chip][layer]) &0x1ff;
+ color = color_ctrl_ram[(row_index + PC080SN_yoffs - 2) &0xff];
+
+ x_index = sx - (PC080SN_bgscroll_ram[chip][layer][row_index]);
+
+ src16 = BITMAP_ADDR16(srcbitmap, src_y_index, 0);
+ tsrc = BITMAP_ADDR8(flagsbitmap, src_y_index, 0);
+ dst16 = scanline;
+
+ if (flags & TILEMAP_DRAW_OPAQUE)
+ {
+ for (i=0; i<screen_width; i++)
+ {
+ a = src16[x_index & width_mask];
+#ifdef TOPSPEED_ROAD_COLORS
+ a = topspeed_get_road_pixel_color(a,color);
+#endif
+ *dst16++ = a;
+ x_index++;
+ }
+ }
+ else
+ {
+ for (i=0; i<screen_width; i++)
+ {
+ if (tsrc[x_index & width_mask])
+ {
+ a = src16[x_index & width_mask];
+#ifdef TOPSPEED_ROAD_COLORS
+ a = topspeed_get_road_pixel_color(a,color);
+#endif
+ *dst16++ = a;
+ }
+ else
+ *dst16++ = 0x8000;
+ x_index++;
+ }
+ }
+
+ if (flags & TILEMAP_DRAW_OPAQUE)
+ taitoic_drawscanline(bitmap,0,y,scanline,0,ROT0,priority,cliprect);
+ else
+ taitoic_drawscanline(bitmap,0,y,scanline,1,ROT0,priority,cliprect);
+
+ y_index++;
+ if (!machine_flip) y++; else y--;
+ }
+ while ( (!machine_flip && y <= max_y) || (machine_flip && y >= min_y) );
+}
+
+
+void PC080SN_tilemap_draw(mame_bitmap *bitmap,const rectangle *cliprect,int chip,int layer,int flags,UINT32 priority)
+{
+ tilemap_draw(bitmap,cliprect,PC080SN_tilemap[chip][layer],flags,priority);
+}
+
+void PC080SN_tilemap_draw_offset(mame_bitmap *bitmap,const rectangle *cliprect,int chip,int layer,int flags,UINT32 priority,int xoffs,int yoffs)
+{
+ int basedx = -16 - PC080SN_xoffs;
+ int basedxflip = -16 + PC080SN_xoffs;
+ int basedy = PC080SN_yoffs;
+ int basedyflip = -PC080SN_yoffs;
+
+ tilemap_set_scrolldx(PC080SN_tilemap[chip][layer], basedx + xoffs, basedxflip + xoffs);
+ tilemap_set_scrolldy(PC080SN_tilemap[chip][layer], basedy + yoffs, basedyflip + yoffs);
+ tilemap_draw(bitmap,cliprect,PC080SN_tilemap[chip][layer],flags,priority);
+ tilemap_set_scrolldx(PC080SN_tilemap[chip][layer], basedx, basedxflip);
+ tilemap_set_scrolldy(PC080SN_tilemap[chip][layer], basedy, basedyflip);
+}
+
+void PC080SN_tilemap_draw_special(mame_bitmap *bitmap,const rectangle *cliprect,int chip,int layer,int flags,UINT32 priority,UINT16 *ram)
+{
+ topspeed_custom_draw(bitmap,cliprect,chip,layer,flags,priority,ram);
+}
+
+
+
+
+
+/***************************************************************************/
+
+
+#define PC090OJ_RAM_SIZE 0x4000
+#define PC090OJ_ACTIVE_RAM_SIZE 0x800
+
+/* NB: PC090OJ_ctrl is the internal register controlling flipping
+
+ PC090OJ_sprite_ctrl is a representation of the hardware OUTSIDE the PC090OJ
+ which impacts on sprite plotting, and which varies between games. It
+ includes color banking and (optionally) priority. It allows each game to
+ control these aspects of the sprites in different ways, while keeping the
+ routines here modular.
+
+*/
+
+static UINT16 PC090OJ_ctrl,PC090OJ_buffer,PC090OJ_gfxnum;
+UINT16 PC090OJ_sprite_ctrl;
+
+static UINT16 *PC090OJ_ram,*PC090OJ_ram_buffered;
+
+static int PC090OJ_xoffs,PC090OJ_yoffs;
+
+
+
+void PC090OJ_vh_start(int gfxnum,int x_offset,int y_offset,int use_buffer)
+{
+ /* use the given gfx set */
+ PC090OJ_gfxnum = gfxnum;
+
+ PC090OJ_xoffs = x_offset;
+ PC090OJ_yoffs = y_offset;
+
+ PC090OJ_buffer = use_buffer;
+
+ PC090OJ_ram = auto_malloc(PC090OJ_RAM_SIZE);
+ PC090OJ_ram_buffered = auto_malloc(PC090OJ_RAM_SIZE);
+
+ memset(PC090OJ_ram,0,PC090OJ_RAM_SIZE);
+ memset(PC090OJ_ram_buffered,0,PC090OJ_RAM_SIZE);
+
+ state_save_register_global_pointer(PC090OJ_ram, PC090OJ_RAM_SIZE/2);
+ state_save_register_global_pointer(PC090OJ_ram_buffered, PC090OJ_RAM_SIZE/2);
+ state_save_register_global(PC090OJ_ctrl);
+
+// state_save_register_func_postload(PC090OJ_restore);
+}
+
+READ16_HANDLER( PC090OJ_word_0_r ) // in case we find a game using 2...
+{
+ return PC090OJ_ram[offset];
+}
+
+static void PC090OJ_word_w(offs_t offset,UINT16 data,UINT32 mem_mask)
+{
+ COMBINE_DATA(&PC090OJ_ram[offset]);
+
+ /* If we're not buffering sprite ram, write it straight through... */
+ if (!PC090OJ_buffer)
+ PC090OJ_ram_buffered[offset] = PC090OJ_ram[offset];
+
+ if (offset == 0xdff)
+ {
+ /* Bit 0 is flip control, others seem unused */
+ PC090OJ_ctrl = data;
+
+#if 0
+ popmessage("PC090OJ ctrl = %4x",data);
+#endif
+ }
+}
+
+WRITE16_HANDLER( PC090OJ_word_0_w ) // in case we find a game using 2...
+{
+ PC090OJ_word_w(offset,data,mem_mask);
+}
+
+void PC090OJ_eof_callback(void)
+{
+ if (PC090OJ_buffer)
+ {
+ int i;
+ for (i=0;i<PC090OJ_ACTIVE_RAM_SIZE/2;i++)
+ PC090OJ_ram_buffered[i] = PC090OJ_ram[i];
+ }
+}
+
+
+void PC090OJ_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect,int pri_type)
+{
+ int offs,priority=0;
+ int sprite_colbank = (PC090OJ_sprite_ctrl & 0xf) << 4; /* top nibble */
+
+ switch (pri_type)
+ {
+ case 0x00:
+ priority = 0; /* sprites over top bg layer */
+ break;
+
+ case 0x01:
+ priority = 1; /* sprites under top bg layer */
+ break;
+
+ case 0x02:
+ priority = PC090OJ_sprite_ctrl >> 15; /* variable sprite/tile priority */
+ }
+
+
+ for (offs = 0;offs < PC090OJ_ACTIVE_RAM_SIZE/2;offs += 4)
+ {
+ int flipx, flipy;
+ int x, y;
+ int data,code,color;
+
+ data = PC090OJ_ram_buffered[offs+0];
+ flipy = (data & 0x8000) >> 15;
+ flipx = (data & 0x4000) >> 14;
+ color = (data & 0x000f) | sprite_colbank;
+
+ code = PC090OJ_ram_buffered[offs+2] & 0x1fff;
+ x = PC090OJ_ram_buffered[offs+3] & 0x1ff; /* mask verified with Rainbowe board */
+ y = PC090OJ_ram_buffered[offs+1] & 0x1ff; /* mask verified with Rainbowe board */
+
+ /* treat coords as signed */
+ if (x>0x140) x -= 0x200;
+ if (y>0x140) y -= 0x200;
+
+ if (!(PC090OJ_ctrl & 1)) /* sprites flipscreen */
+ {
+ x = 320 - x - 16;
+ y = 256 - y - 16;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ x += PC090OJ_xoffs;
+ y += PC090OJ_yoffs;
+
+ pdrawgfx(bitmap,machine->gfx[PC090OJ_gfxnum],
+ code,
+ color,
+ flipx,flipy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,0,
+ priority ? 0xfc : 0xf0);
+ }
+}
+
+
+
+
+/******************************************************************************/
+
+
+#define TC0080VCO_RAM_SIZE 0x21000
+#define TC0080VCO_CHAR_RAM_SIZE 0x2000
+#define TC0080VCO_TOTAL_CHARS 256
+
+static UINT16 *TC0080VCO_ram,
+ *TC0080VCO_bg0_ram_0, *TC0080VCO_bg0_ram_1,
+ *TC0080VCO_bg1_ram_0, *TC0080VCO_bg1_ram_1,
+ *TC0080VCO_tx_ram_0, *TC0080VCO_tx_ram_1,
+ *TC0080VCO_char_ram, *TC0080VCO_bgscroll_ram;
+
+/* This sprite related stuff still needs to be accessed in
+ video/taito_h */
+UINT16 *TC0080VCO_chain_ram_0, *TC0080VCO_chain_ram_1,
+ *TC0080VCO_spriteram, *TC0080VCO_scroll_ram;
+
+static UINT16 TC0080VCO_bg0_scrollx,TC0080VCO_bg0_scrolly,
+ TC0080VCO_bg1_scrollx,TC0080VCO_bg1_scrolly;
+
+static tilemap *TC0080VCO_tilemap[3];
+
+static UINT8 *TC0080VCO_char_dirty;
+static int TC0080VCO_chars_dirty;
+static int TC0080VCO_bg_gfx,TC0080VCO_tx_gfx;
+static int TC0080VCO_bg_xoffs,TC0080VCO_bg_yoffs;
+static int TC0080VCO_bg_flip_yoffs;
+
+INT32 TC0080VCO_flipscreen = 0,TC0080VCO_has_tx;
+
+
+#if 0
+static int TC0080VCO_zoomy_conv_table[] =
+{
+/* These are hand-tuned values... */
+/* +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f */
+ 0x00,0x01,0x01,0x02,0x02,0x03,0x04,0x05, 0x06,0x06,0x07,0x08,0x09,0x0a,0x0a,0x0b, /* 0x00 */
+ 0x0b,0x0c,0x0c,0x0d,0x0e,0x0e,0x0f,0x10, 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x16,
+ 0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e, 0x1f,0x20,0x21,0x22,0x24,0x25,0x26,0x27,
+ 0x28,0x2a,0x2b,0x2c,0x2e,0x30,0x31,0x32, 0x34,0x36,0x37,0x38,0x3a,0x3c,0x3e,0x3f,
+
+ 0x40,0x41,0x42,0x42,0x43,0x43,0x44,0x44, 0x45,0x45,0x46,0x46,0x47,0x47,0x48,0x49, /* 0x40 */
+ 0x4a,0x4a,0x4b,0x4b,0x4c,0x4d,0x4e,0x4f, 0x4f,0x50,0x51,0x51,0x52,0x53,0x54,0x55,
+ 0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d, 0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x66,
+ 0x67,0x68,0x6a,0x6b,0x6c,0x6e,0x6f,0x71, 0x72,0x74,0x76,0x78,0x80,0x7b,0x7d,0x7f
+};
+#endif
+
+
+static TILE_GET_INFO( TC0080VCO_get_bg0_tile_info_0 )
+{
+ int color, tile;
+
+ color = TC0080VCO_bg0_ram_1[ tile_index ] & 0x001f;
+ tile = TC0080VCO_bg0_ram_0[ tile_index ] & 0x7fff;
+
+ tileinfo->category = 0;
+
+ SET_TILE_INFO(
+ TC0080VCO_bg_gfx,
+ tile,
+ color,
+ TILE_FLIPYX((TC0080VCO_bg0_ram_1[tile_index] & 0x00c0) >> 6));
+}
+
+static TILE_GET_INFO( TC0080VCO_get_bg1_tile_info_0 )
+{
+ int color, tile;
+
+ color = TC0080VCO_bg1_ram_1[ tile_index ] & 0x001f;
+ tile = TC0080VCO_bg1_ram_0[ tile_index ] & 0x7fff;
+
+ tileinfo->category = 0;
+
+ SET_TILE_INFO(
+ TC0080VCO_bg_gfx,
+ tile,
+ color,
+ TILE_FLIPYX((TC0080VCO_bg1_ram_1[tile_index] & 0x00c0) >> 6));
+}
+
+static TILE_GET_INFO( TC0080VCO_get_tx_tile_info )
+{
+ int tile;
+
+ if (!TC0080VCO_flipscreen)
+ {
+ if ( (tile_index & 1) )
+ tile = (TC0080VCO_tx_ram_0[tile_index >> 1] & 0x00ff);
+ else
+ tile = (TC0080VCO_tx_ram_0[tile_index >> 1] & 0xff00) >> 8;
+ tileinfo->category = 0;
+ }
+ else
+ {
+ if ( (tile_index & 1) )
+ tile = (TC0080VCO_tx_ram_0[tile_index >> 1] & 0xff00) >> 8;
+ else
+ tile = (TC0080VCO_tx_ram_0[tile_index >> 1] & 0x00ff);
+ tileinfo->category = 0;
+ }
+
+ SET_TILE_INFO(
+ TC0080VCO_tx_gfx,
+ tile,
+ 0x40,
+ 0); /* 0x20<<1 as 3bpp */
+}
+
+
+/* Is this endian-correct ??? */
+
+static const gfx_layout TC0080VCO_charlayout =
+{
+ 8, 8, /* 8x8 pixels */
+ 256, /* 256 chars */
+
+// can't be 4bpp as it becomes opaque in Ainferno...
+// 4, /* 4 bits per pixel */
+//#ifdef LSB_FIRST
+// { 0x10000*8 + 8, 0x10000*8, 8, 0 },
+//#else
+// { 0x10000*8, 0x10000*8 + 8, 0, 8 },
+//#endif
+
+ 3, /* 3 bits per pixel */
+#ifdef LSB_FIRST
+ { 0x10000*8, 8, 0 },
+#else
+ { 0x10000*8 + 8, 0, 8 },
+#endif
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ { 16*0, 16*1, 16*2, 16*3, 16*4, 16*5, 16*6, 16*7 },
+ 16*8
+};
+
+
+static void TC0080VCO_set_layer_ptrs(void)
+{
+ TC0080VCO_char_ram = TC0080VCO_ram + 0x00000/2; /* continues at +0x10000 */
+ TC0080VCO_tx_ram_0 = TC0080VCO_ram + 0x01000/2;
+ TC0080VCO_chain_ram_0 = TC0080VCO_ram + 0x00000/2; /* only used from +0x2000 */
+
+ TC0080VCO_bg0_ram_0 = TC0080VCO_ram + 0x0c000/2;
+ TC0080VCO_bg1_ram_0 = TC0080VCO_ram + 0x0e000/2;
+
+ TC0080VCO_tx_ram_1 = TC0080VCO_ram + 0x11000/2;
+ TC0080VCO_chain_ram_1 = TC0080VCO_ram + 0x10000/2; /* only used from +0x12000 */
+
+ TC0080VCO_bg0_ram_1 = TC0080VCO_ram + 0x1c000/2;
+ TC0080VCO_bg1_ram_1 = TC0080VCO_ram + 0x1e000/2;
+ TC0080VCO_bgscroll_ram = TC0080VCO_ram + 0x20000/2;
+ TC0080VCO_spriteram = TC0080VCO_ram + 0x20400/2;
+ TC0080VCO_scroll_ram = TC0080VCO_ram + 0x20800/2;
+}
+
+static void TC0080VCO_dirty_chars(void)
+{
+ memset(TC0080VCO_char_dirty,1,TC0080VCO_TOTAL_CHARS);
+ TC0080VCO_chars_dirty = 1;
+}
+
+static void TC0080VCO_dirty_tilemaps(void)
+{
+ tilemap_mark_all_tiles_dirty(TC0080VCO_tilemap[0]);
+ tilemap_mark_all_tiles_dirty(TC0080VCO_tilemap[1]);
+ tilemap_mark_all_tiles_dirty(TC0080VCO_tilemap[2]);
+}
+
+static void TC0080VCO_restore_scroll(void)
+{
+ TC0080VCO_flipscreen = TC0080VCO_scroll_ram[0] & 0x0c00;
+
+ tilemap_set_flip( TC0080VCO_tilemap[0], TC0080VCO_flipscreen ? TILEMAP_FLIPX | TILEMAP_FLIPY : 0 );
+ tilemap_set_flip( TC0080VCO_tilemap[1], TC0080VCO_flipscreen ? TILEMAP_FLIPX | TILEMAP_FLIPY : 0 );
+ tilemap_set_flip( TC0080VCO_tilemap[2], TC0080VCO_flipscreen ? TILEMAP_FLIPX | TILEMAP_FLIPY : 0 );
+
+ TC0080VCO_bg0_scrollx = TC0080VCO_scroll_ram[1] &0x03ff;
+ TC0080VCO_bg1_scrollx = TC0080VCO_scroll_ram[2] &0x03ff;
+ TC0080VCO_bg0_scrolly = TC0080VCO_scroll_ram[3] &0x03ff;
+ TC0080VCO_bg1_scrolly = TC0080VCO_scroll_ram[4] &0x03ff;
+}
+
+
+void TC0080VCO_vh_start(running_machine *machine, int gfxnum,int has_fg0,int bg_xoffs,int bg_yoffs,int bg_flip_yoffs)
+{
+ int gfx_index=0;
+
+ TC0080VCO_bg_xoffs = bg_xoffs; /* usually 1 */
+ TC0080VCO_bg_yoffs = bg_yoffs; /* usually 1 */
+ TC0080VCO_bg_flip_yoffs = bg_flip_yoffs; /* usually -2 */
+ TC0080VCO_has_tx = has_fg0; /* for debugging only */
+
+ TC0080VCO_tilemap[0] = tilemap_create(TC0080VCO_get_bg0_tile_info_0,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ TC0080VCO_tilemap[1] = tilemap_create(TC0080VCO_get_bg1_tile_info_0,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ TC0080VCO_ram = auto_malloc(TC0080VCO_RAM_SIZE);
+
+ memset( TC0080VCO_ram,0,TC0080VCO_RAM_SIZE );
+ TC0080VCO_set_layer_ptrs();
+
+ /* use the given gfx set for bg tiles*/
+ TC0080VCO_bg_gfx = gfxnum;
+
+ tilemap_set_transparent_pen( TC0080VCO_tilemap[0],0 );
+ tilemap_set_transparent_pen( TC0080VCO_tilemap[1],0 );
+
+ tilemap_set_scrolldx(TC0080VCO_tilemap[0],TC0080VCO_bg_xoffs,512);
+ tilemap_set_scrolldx(TC0080VCO_tilemap[1],TC0080VCO_bg_xoffs,512);
+ tilemap_set_scrolldy(TC0080VCO_tilemap[0],TC0080VCO_bg_yoffs,TC0080VCO_bg_flip_yoffs);
+ tilemap_set_scrolldy(TC0080VCO_tilemap[1],TC0080VCO_bg_yoffs,TC0080VCO_bg_flip_yoffs);
+
+ state_save_register_global_pointer(TC0080VCO_ram, TC0080VCO_RAM_SIZE/2);
+ state_save_register_global(TC0080VCO_has_tx);
+ state_save_register_func_postload(TC0080VCO_set_layer_ptrs);
+
+ /* Perform extra initialisations for text layer */
+ {
+ TC0080VCO_tilemap[2] = tilemap_create(TC0080VCO_get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ TC0080VCO_char_dirty = auto_malloc(TC0080VCO_TOTAL_CHARS);
+
+ TC0080VCO_dirty_chars();
+ state_save_register_func_postload(TC0080VCO_dirty_chars);
+
+ /* find first empty slot to decode gfx */
+ for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
+ if (machine->gfx[gfx_index] == 0)
+ break;
+ assert(gfx_index != MAX_GFX_ELEMENTS);
+
+ /* create the char set (gfx will then be updated dynamically from RAM) */
+ machine->gfx[gfx_index] = allocgfx(&TC0080VCO_charlayout);
+
+ /* set the color information */
+ machine->gfx[gfx_index]->total_colors = 64; // is this correct ?
+ TC0080VCO_tx_gfx = gfx_index;
+
+ tilemap_set_scrolldx(TC0080VCO_tilemap[2],0,0);
+ tilemap_set_scrolldy(TC0080VCO_tilemap[2],48,-448);
+
+ tilemap_set_transparent_pen( TC0080VCO_tilemap[2],0 );
+ }
+
+ state_save_register_func_postload(TC0080VCO_dirty_tilemaps); // unnecessary ?
+ state_save_register_func_postload(TC0080VCO_restore_scroll);
+
+ /* bg0 tilemap scrollable per pixel row */
+ tilemap_set_scroll_rows(TC0080VCO_tilemap[0],512);
+}
+
+
+static WRITE16_HANDLER( TC0080VCO_scrollram_w )
+{
+ switch ( offset )
+ {
+ case 0x00: /* screen invert control */
+ TC0080VCO_restore_scroll();
+ break;
+
+ case 0x01: /* BG0 scroll X */
+ TC0080VCO_bg0_scrollx = data &0x03ff;
+ break;
+
+ case 0x02: /* BG1 scroll X */
+ TC0080VCO_bg1_scrollx = data &0x03ff;
+ break;
+
+ case 0x03: /* BG0 scroll Y */
+ TC0080VCO_bg0_scrolly = data &0x03ff;
+ break;
+
+ case 0x04: /* BG1 scroll Y */
+ TC0080VCO_bg1_scrolly = data &0x03ff;
+ break;
+
+ default:
+ break;
+ }
+}
+
+READ16_HANDLER( TC0080VCO_word_r )
+{
+ return TC0080VCO_ram[offset];
+}
+
+WRITE16_HANDLER( TC0080VCO_word_w )
+{
+ COMBINE_DATA(&TC0080VCO_ram[offset]);
+
+ /* A lot of TC0080VCO writes require no action... */
+
+ if (offset < 0x1000/2)
+ {
+ TC0080VCO_char_dirty[offset / 8] = 1;
+ TC0080VCO_chars_dirty = 1;
+#if 0
+ if (!TC0080VCO_has_tx)
+ {
+ if (TC0080VCO_ram[offset])
+ popmessage("Write non-zero to TC0080VCO char ram\nPlease report to MAMEDEV");
+ }
+#endif
+ }
+ else if (offset < 0x2000/2) /* fg0 (text layer) */
+ {
+ tilemap_mark_tile_dirty( TC0080VCO_tilemap[2],(offset &0x07ff) * 2 );
+ tilemap_mark_tile_dirty( TC0080VCO_tilemap[2],(offset &0x07ff) * 2 + 1 );
+#if 0
+ if (!TC0080VCO_has_tx)
+ {
+ if (TC0080VCO_ram[offset])
+ popmessage("Write non-zero to TC0080VCO fg0\nPlease report to MAMEDEV");
+ }
+#endif
+ }
+ else if (offset < 0xc000/2) /* chain ram */
+ {}
+ else if (offset < 0xe000/2) /* bg0 (0) */
+ tilemap_mark_tile_dirty(TC0080VCO_tilemap[0],(offset & 0xfff));
+
+ else if (offset < 0x10000/2) /* bg1 (0) */
+ tilemap_mark_tile_dirty(TC0080VCO_tilemap[1],(offset & 0xfff));
+
+ else if (offset < 0x11000/2)
+ {
+ TC0080VCO_char_dirty[(offset - 0x10000/2) / 8] = 1;
+ TC0080VCO_chars_dirty = 1;
+#if 0
+ if (!TC0080VCO_has_tx)
+ {
+ if (TC0080VCO_ram[offset])
+ popmessage("Write non-zero to TC0080VCO char-hi ram\nPlease report to MAMEDEV");
+ }
+#endif
+ }
+ else if (offset < 0x12000/2) /* unknown/unused */
+ {
+#if 1
+ if (TC0080VCO_ram[offset])
+ popmessage("Write non-zero to mystery TC0080VCO area\nPlease report to MAMEDEV");
+#endif
+ }
+ else if (offset < 0x1c000/2) /* chain ram */
+ {}
+ else if (offset < 0x1e000/2) /* bg0 (1) */
+ tilemap_mark_tile_dirty(TC0080VCO_tilemap[0],(offset & 0xfff));
+
+ else if (offset < 0x20000/2) /* bg1 (1) */
+ tilemap_mark_tile_dirty(TC0080VCO_tilemap[1],(offset & 0xfff));
+
+ else if (offset < 0x20400/2) /* bg0 rowscroll */
+ {}
+ else if (offset < 0x20800/2) /* sprite ram */
+ {}
+ else if (offset < 0x20fff/2)
+ TC0080VCO_scrollram_w(offset-(0x20800/2),TC0080VCO_ram[offset],mem_mask);
+}
+
+
+void TC0080VCO_tilemap_update(running_machine *machine)
+{
+ int j;
+
+ if (!TC0080VCO_flipscreen)
+ {
+ for (j = 0;j < 0x400;j++)
+ tilemap_set_scrollx(TC0080VCO_tilemap[0],(j+0) & 0x3ff,
+ -TC0080VCO_bg0_scrollx - TC0080VCO_bgscroll_ram[j &0x1ff]);
+ }
+ else
+ {
+ for (j = 0;j < 0x400;j++)
+ tilemap_set_scrollx(TC0080VCO_tilemap[0],(j+0) & 0x3ff,
+ -TC0080VCO_bg0_scrollx + TC0080VCO_bgscroll_ram[j &0x1ff]);
+ }
+
+ tilemap_set_scrolly(TC0080VCO_tilemap[0],0, TC0080VCO_bg0_scrolly);
+ tilemap_set_scrollx(TC0080VCO_tilemap[1],0,-TC0080VCO_bg1_scrollx);
+ tilemap_set_scrolly(TC0080VCO_tilemap[1],0, TC0080VCO_bg1_scrolly);
+ tilemap_set_scrollx(TC0080VCO_tilemap[2],0,0); /* no scroll (maybe) */
+ tilemap_set_scrolly(TC0080VCO_tilemap[2],0,0);
+
+ /* Decode any characters that have changed */
+
+ if (TC0080VCO_chars_dirty)
+ {
+ int tile_index;
+
+ for (tile_index = 0;tile_index < 64*64;tile_index++)
+ {
+ int attr = TC0080VCO_tx_ram_0[tile_index >> 1];
+
+ /* should this be reversed in flipscreen ?? */
+ if (tile_index & 1) /* each word has 2 chars */
+ {
+ attr = (attr &0xff);
+ }
+ else
+ {
+ attr = (attr &0xff00) >> 8;
+ }
+
+ if (TC0080VCO_char_dirty[attr])
+ tilemap_mark_tile_dirty(TC0080VCO_tilemap[2],tile_index);
+ }
+
+ for (j = 0;j < TC0080VCO_TOTAL_CHARS;j++)
+ {
+ if (TC0080VCO_char_dirty[j])
+ decodechar(machine->gfx[TC0080VCO_tx_gfx],j,
+ (UINT8 *)TC0080VCO_char_ram,&TC0080VCO_charlayout);
+ TC0080VCO_char_dirty[j] = 0;
+ }
+ TC0080VCO_chars_dirty = 0;
+ }
+}
+
+
+/* NB: orientation_flipx code in following routine has not been tested */
+
+static void TC0080VCO_bg0_tilemap_draw(mame_bitmap *bitmap,const rectangle *cliprect,int flags,UINT32 priority)
+{
+ UINT16 zoom = TC0080VCO_scroll_ram[6];
+ int zx, zy;
+
+ zx = (zoom & 0xff00) >> 8;
+ zy = zoom & 0x00ff;
+
+ if (zx == 0x3f && zy == 0x7f) /* normal size */
+ {
+ tilemap_draw(bitmap,cliprect,TC0080VCO_tilemap[0],flags,priority);
+ }
+ else /* zoom + rowscroll = custom draw routine */
+ {
+ UINT16 *dst16,*src16;
+ UINT8 *tsrc;
+ UINT16 scanline[512];
+ mame_bitmap *srcbitmap = tilemap_get_pixmap(TC0080VCO_tilemap[0]);
+ mame_bitmap *flagsbitmap = tilemap_get_flagsmap(TC0080VCO_tilemap[0]);
+
+ int sx,zoomx,zoomy;
+ int dx,ex,dy,ey;
+ int i,y,y_index,src_y_index,row_index;
+ int x_index,x_step;
+
+ int flip = TC0080VCO_flipscreen;
+ int machine_flip = 0; /* for ROT 180 ? */
+
+ int min_x = cliprect->min_x;
+ int max_x = cliprect->max_x;
+ int min_y = cliprect->min_y;
+ int max_y = cliprect->max_y;
+ int screen_width = max_x - min_x + 1;
+ int width_mask=0x3ff; /* underlying tilemap */
+
+
+#if 0
+{
+ char buf[100];
+ sprintf(buf,"xmin= %04x xmax= %04x ymin= %04x ymax= %04x",min_x,max_x,min_y,max_y);
+ popmessage(buf);
+}
+#endif
+
+ if (zx < 63)
+ {
+ /* no evidence for these calcs? */
+ dx = 16 - (zx + 2) / 8;
+ ex = (zx + 2) % 8;
+ zoomx = ((dx << 3) - ex) << 10;
+ }
+ else
+ {
+ /* 256 is speculative, haven't found a game using zoomx yet */
+ zoomx = 0x10000 - ((zx - 0x3f) * 256);
+ }
+
+ if (zy < 127)
+ {
+ /* no evidence for these calcs? */
+ dy = 16 - (zy + 2) / 16;
+ ey = (zy + 2) % 16;
+ zoomy = ((dy << 4) - ey) << 9;
+ }
+ else
+ {
+ /* confirmed with real board */
+ zoomy = 0x10000 - ((zy - 0x7f) * 512);
+ }
+
+ if (!flip)
+ {
+ sx = (-TC0080VCO_scroll_ram[1] - 1) << 16;
+ y_index = (( TC0080VCO_scroll_ram[3] - 1) << 16) + min_y * zoomy;
+ }
+ else
+ {
+ /* adjustment for zx is entirely speculative */
+ sx = (( 0x200 + TC0080VCO_scroll_ram[1]) << 16)
+ - (max_x + min_x) * (zoomx-0x10000);
+
+ /* 0x130 correct for Dleague. Syvalion correct with 0x1f0.
+ min_y is 0x20 and 0x30; max_y is 0x10f and 0x1bf;
+ max_y + min_y seems a good bet... */
+
+ y_index = ((-TC0080VCO_scroll_ram[3] - 2) << 16)
+ + min_y * zoomy - (max_y + min_y) * (zoomy-0x10000);
+ }
+
+ if (!machine_flip) y = min_y; else y = max_y;
+
+ do
+ {
+ src_y_index = (y_index>>16) &0x3ff; /* tilemaps are 1024 px up/down */
+
+ /* row areas are the same in flipscreen, so we must read in reverse */
+ row_index = (src_y_index &0x1ff);
+ if (flip) row_index = 0x1ff - row_index;
+
+ x_index = sx - ((TC0080VCO_bgscroll_ram[row_index] << 16));
+
+ src16 = BITMAP_ADDR16(srcbitmap, src_y_index, 0);
+ tsrc = BITMAP_ADDR8(flagsbitmap, src_y_index, 0);
+ dst16 = scanline;
+
+ x_step = zoomx;
+
+/*** NEW ***/
+ if (flags & TILEMAP_DRAW_OPAQUE)
+ {
+ for (i=0; i<screen_width; i++)
+ {
+ *dst16++ = src16[(x_index >> 16) &width_mask];
+ x_index += x_step;
+ }
+ }
+ else
+ {
+ for (i=0; i<screen_width; i++)
+ {
+ if (tsrc[(x_index >> 16) &width_mask])
+ *dst16++ = src16[(x_index >> 16) &width_mask];
+ else
+ *dst16++ = 0x8000;
+ x_index += x_step;
+ }
+ }
+/***********/
+
+// while (x_index<x_max)
+// {
+// *dst16++ = src16[(x_index >> 16) &width_mask];
+// x_index += x_step;
+// }
+//
+// pdraw_scanline16(bitmap,0,y,screen_width,
+// scanline,0,0,rot,priority);
+
+/*** NEW ***/
+ if (flags & TILEMAP_DRAW_OPAQUE)
+ taitoic_drawscanline(bitmap,0,y,scanline,0,ROT0,priority,cliprect);
+ else
+ taitoic_drawscanline(bitmap,0,y,scanline,1,ROT0,priority,cliprect);
+/***********/
+
+ y_index += zoomy;
+ if (!machine_flip) y++; else y--;
+ }
+ while ( (!machine_flip && y <= max_y) || (machine_flip && y >= min_y) );
+
+ }
+}
+
+
+static void TC0080VCO_bg1_tilemap_draw(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int flags,UINT32 priority)
+{
+ UINT8 layer=1;
+ UINT16 zoom = TC0080VCO_scroll_ram[6+layer];
+ int min_x = cliprect->min_x;
+ int max_x = cliprect->max_x;
+ int min_y = cliprect->min_y;
+ int max_y = cliprect->max_y;
+ int zoomx, zoomy;
+
+ zoomx = (zoom & 0xff00) >> 8;
+ zoomy = zoom & 0x00ff;
+
+ if (zoomx == 0x3f && zoomy == 0x7f) /* normal size */
+ {
+ tilemap_draw(bitmap,cliprect,TC0080VCO_tilemap[layer],flags,priority);
+ }
+ else /* zoomed */
+ {
+ int zx, zy, dx, dy, ex, ey;
+ int sx,sy;
+
+ /* shouldn't we set no_clip before doing this (see TC0480SCP) ? */
+ mame_bitmap *srcbitmap = tilemap_get_pixmap(TC0080VCO_tilemap[layer]);
+
+ if (zoomx < 63)
+ {
+ /* no evidence for these calcs? */
+ dx = 16 - (zoomx + 2) / 8;
+ ex = (zoomx + 2) % 8;
+ zx = ((dx << 3) - ex) << 10;
+ }
+ else
+ {
+ /* 256 is speculative, haven't found a game using zoomx yet */
+ zx = 0x10000 - ((zoomx - 0x3f) * 256);
+ }
+
+ if (zoomy < 127)
+ {
+ /* no evidence for these calcs? */
+ dy = 16 - (zoomy + 2) / 16;
+ ey = (zoomy + 2) % 16;
+ zy = ((dy << 4) - ey) << 9;
+ }
+ else
+ {
+ /* confirmed with real board */
+ zy = 0x10000 - ((zoomy - 0x7f) * 512);
+ }
+
+ if (!TC0080VCO_flipscreen)
+ {
+ sx = (-TC0080VCO_scroll_ram[layer+1] - 1) << 16;
+ sy = ( TC0080VCO_scroll_ram[layer+3] - 1) << 16;
+ }
+ else
+ {
+ /* adjustment for zx is entirely speculative */
+ sx = (( 0x200 + TC0080VCO_scroll_ram[layer+1]) << 16)
+ - (max_x + min_x) * (zx-0x10000);
+
+ sy = (( 0x3fe - TC0080VCO_scroll_ram[layer+3]) << 16)
+ - (max_y + min_y) * (zy-0x10000);
+ }
+
+ copyrozbitmap(bitmap,srcbitmap,
+ sx, sy,
+ zx, 0, 0, zy,
+ 0, /* why no wraparound ?? */
+ &machine->screen[0].visarea,
+ TRANSPARENCY_COLOR, 0, priority);
+ }
+}
+
+
+void TC0080VCO_tilemap_draw(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int layer,int flags,UINT32 priority)
+{
+ int disable = 0x00; /* possibly layer disable bits do exist ?? */
+
+#if 0
+ popmessage("layer disable = %x",disable);
+#endif
+
+ switch (layer)
+ {
+ case 0:
+ if (disable & 0x01) return;
+ TC0080VCO_bg0_tilemap_draw(bitmap,cliprect,flags,priority);
+ break;
+ case 1:
+ if (disable & 0x02) return;
+ TC0080VCO_bg1_tilemap_draw(machine, bitmap,cliprect,flags,priority);
+ break;
+ case 2:
+ if (disable & 0x04) return;
+ tilemap_draw(bitmap,cliprect,TC0080VCO_tilemap[2],flags,priority);
+ break;
+ }
+}
+
+
+
+/***************************************************************************/
+
+
+#define TC0100SCN_RAM_SIZE 0x14000 /* enough for double-width tilemaps */
+#define TC0100SCN_TOTAL_CHARS 256
+#define TC0100SCN_MAX_CHIPS 3
+static int TC0100SCN_chips;
+static rectangle myclip;
+
+const int TC0100SCN_SINGLE_VDU = 1024;
+
+static UINT16 TC0100SCN_ctrl[TC0100SCN_MAX_CHIPS][8];
+
+static UINT16 *TC0100SCN_ram[TC0100SCN_MAX_CHIPS],
+ *TC0100SCN_bg_ram[TC0100SCN_MAX_CHIPS],
+ *TC0100SCN_fg_ram[TC0100SCN_MAX_CHIPS],
+ *TC0100SCN_tx_ram[TC0100SCN_MAX_CHIPS],
+ *TC0100SCN_char_ram[TC0100SCN_MAX_CHIPS],
+ *TC0100SCN_bgscroll_ram[TC0100SCN_MAX_CHIPS],
+ *TC0100SCN_fgscroll_ram[TC0100SCN_MAX_CHIPS],
+ *TC0100SCN_colscroll_ram[TC0100SCN_MAX_CHIPS];
+
+static int TC0100SCN_bgscrollx[TC0100SCN_MAX_CHIPS],TC0100SCN_bgscrolly[TC0100SCN_MAX_CHIPS],
+ TC0100SCN_fgscrollx[TC0100SCN_MAX_CHIPS],TC0100SCN_fgscrolly[TC0100SCN_MAX_CHIPS];
+
+/* We keep two tilemaps for each of the 3 actual tilemaps: one at standard width, one double */
+static tilemap *TC0100SCN_tilemap[TC0100SCN_MAX_CHIPS][3][2];
+static rectangle TC0100SCN_cliprect[TC0100SCN_MAX_CHIPS];
+
+static char *TC0100SCN_char_dirty[TC0100SCN_MAX_CHIPS];
+static int TC0100SCN_chars_dirty[TC0100SCN_MAX_CHIPS];
+static int TC0100SCN_bg_gfx[TC0100SCN_MAX_CHIPS],TC0100SCN_tx_gfx[TC0100SCN_MAX_CHIPS];
+static int TC0100SCN_bg_col_mult,TC0100SCN_bg_tilemask,TC0100SCN_tx_col_mult;
+static INT32 TC0100SCN_gfxbank,TC0100SCN_chip_colbank[3],TC0100SCN_colbank[3];
+static int TC0100SCN_dblwidth[TC0100SCN_MAX_CHIPS];
+
+
+INLINE void common_get_bg0_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,UINT16 *ram,int gfxnum,int colbank,int dblwidth)
+{
+ int code,attr;
+
+ if (!dblwidth)
+ {
+ /* Mahjong Quest (F2 system) inexplicably has a banking feature */
+ code = (ram[2*tile_index + 1] & TC0100SCN_bg_tilemask) + (TC0100SCN_gfxbank << 15);
+ attr = ram[2*tile_index];
+ }
+ else
+ {
+ code = ram[2*tile_index + 1] & TC0100SCN_bg_tilemask;
+ attr = ram[2*tile_index];
+ }
+ SET_TILE_INFO(
+ gfxnum,
+ code,
+ (((attr * TC0100SCN_bg_col_mult) + TC0100SCN_colbank[0]) & 0xff) + colbank,
+ TILE_FLIPYX((attr & 0xc000) >> 14));
+}
+
+INLINE void common_get_bg1_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,UINT16 *ram,int gfxnum,int colbank,int dblwidth)
+{
+ int code,attr;
+
+ if (!dblwidth)
+ {
+ /* Mahjong Quest (F2 system) inexplicably has a banking feature */
+ code = (ram[2*tile_index + 1] & TC0100SCN_bg_tilemask) + (TC0100SCN_gfxbank << 15);
+ attr = ram[2*tile_index];
+ }
+ else
+ {
+ code = ram[2*tile_index + 1] & TC0100SCN_bg_tilemask;
+ attr = ram[2*tile_index];
+ }
+ SET_TILE_INFO(
+ gfxnum,
+ code,
+ (((attr * TC0100SCN_bg_col_mult) + TC0100SCN_colbank[1]) & 0xff) + colbank,
+ TILE_FLIPYX((attr & 0xc000) >> 14));
+}
+
+INLINE void common_get_tx_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,UINT16 *ram,int gfxnum,int colbank,int dblwidth)
+{
+ int attr = ram[tile_index];
+
+ SET_TILE_INFO(
+ gfxnum,
+ attr & 0xff,
+ ((((attr >> 6) &0xfc) * TC0100SCN_tx_col_mult + (TC0100SCN_colbank[2] << 2)) &0x3ff) + colbank*4,
+ TILE_FLIPYX((attr & 0xc000) >> 14));
+}
+
+static TILE_GET_INFO( TC0100SCN_get_bg_tile_info_0 )
+{
+ common_get_bg0_tile_info(machine,tileinfo,tile_index,TC0100SCN_bg_ram[0],TC0100SCN_bg_gfx[0],
+ TC0100SCN_chip_colbank[0],TC0100SCN_dblwidth[0]);
+}
+
+static TILE_GET_INFO( TC0100SCN_get_fg_tile_info_0 )
+{
+ common_get_bg1_tile_info(machine,tileinfo,tile_index,TC0100SCN_fg_ram[0],TC0100SCN_bg_gfx[0],
+ TC0100SCN_chip_colbank[0],TC0100SCN_dblwidth[0]);
+}
+
+static TILE_GET_INFO( TC0100SCN_get_tx_tile_info_0 )
+{
+ common_get_tx_tile_info(machine,tileinfo,tile_index,TC0100SCN_tx_ram[0],TC0100SCN_tx_gfx[0],
+ TC0100SCN_chip_colbank[0],TC0100SCN_dblwidth[0]);
+}
+
+static TILE_GET_INFO( TC0100SCN_get_bg_tile_info_1 )
+{
+ common_get_bg0_tile_info(machine,tileinfo,tile_index,TC0100SCN_bg_ram[1],TC0100SCN_bg_gfx[1],
+ TC0100SCN_chip_colbank[1],TC0100SCN_dblwidth[1]);
+}
+
+static TILE_GET_INFO( TC0100SCN_get_fg_tile_info_1 )
+{
+ common_get_bg1_tile_info(machine,tileinfo,tile_index,TC0100SCN_fg_ram[1],TC0100SCN_bg_gfx[1],
+ TC0100SCN_chip_colbank[1],TC0100SCN_dblwidth[1]);
+}
+
+static TILE_GET_INFO( TC0100SCN_get_tx_tile_info_1 )
+{
+ common_get_tx_tile_info(machine,tileinfo,tile_index,TC0100SCN_tx_ram[1],TC0100SCN_tx_gfx[1],
+ TC0100SCN_chip_colbank[1],TC0100SCN_dblwidth[1]);
+}
+
+static TILE_GET_INFO( TC0100SCN_get_bg_tile_info_2 )
+{
+ common_get_bg0_tile_info(machine,tileinfo,tile_index,TC0100SCN_bg_ram[2],TC0100SCN_bg_gfx[2],
+ TC0100SCN_chip_colbank[2],TC0100SCN_dblwidth[2]);
+}
+
+static TILE_GET_INFO( TC0100SCN_get_fg_tile_info_2 )
+{
+ common_get_bg1_tile_info(machine,tileinfo,tile_index,TC0100SCN_fg_ram[2],TC0100SCN_bg_gfx[2],
+ TC0100SCN_chip_colbank[2],TC0100SCN_dblwidth[2]);
+}
+
+static TILE_GET_INFO( TC0100SCN_get_tx_tile_info_2 )
+{
+ common_get_tx_tile_info(machine,tileinfo,tile_index,TC0100SCN_tx_ram[2],TC0100SCN_tx_gfx[2],
+ TC0100SCN_chip_colbank[2],TC0100SCN_dblwidth[2]);
+}
+
+/* This array changes with TC0100SCN_MAX_CHIPS */
+
+static tile_get_info_callback TC0100SCN_get_tile_info[TC0100SCN_MAX_CHIPS][3] =
+{
+ { TC0100SCN_get_bg_tile_info_0, TC0100SCN_get_fg_tile_info_0, TC0100SCN_get_tx_tile_info_0 },
+ { TC0100SCN_get_bg_tile_info_1, TC0100SCN_get_fg_tile_info_1, TC0100SCN_get_tx_tile_info_1 },
+ { TC0100SCN_get_bg_tile_info_2, TC0100SCN_get_fg_tile_info_2, TC0100SCN_get_tx_tile_info_2 }
+};
+
+
+static const gfx_layout TC0100SCN_charlayout =
+{
+ 8,8, /* 8*8 characters */
+ 256, /* 256 characters */
+ 2, /* 2 bits per pixel */
+#ifdef LSB_FIRST
+ { 8, 0 },
+#else
+ { 0, 8 },
+#endif
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ { 0*16, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16 },
+ 16*8 /* every sprite takes 16 consecutive bytes */
+};
+
+
+void TC0100SCN_set_chip_colbanks(int chip0,int chip1,int chip2)
+{
+ TC0100SCN_chip_colbank[0] = chip0; /* palette area for chip 0 */
+ TC0100SCN_chip_colbank[1] = chip1;
+ TC0100SCN_chip_colbank[2] = chip2;
+}
+
+void TC0100SCN_set_colbanks(int bg0,int bg1,int fg)
+{
+ TC0100SCN_colbank[0] = bg0;
+ TC0100SCN_colbank[1] = bg1;
+ TC0100SCN_colbank[2] = fg; /* text */
+}
+
+void TC0100SCN_set_bg_tilemask(int mask)
+{
+ TC0100SCN_bg_tilemask = mask;
+}
+
+WRITE16_HANDLER( TC0100SCN_gfxbank_w ) /* Mjnquest banks its 2 sets of scr tiles */
+{
+ TC0100SCN_gfxbank = (data & 0x1);
+}
+
+static void TC0100SCN_set_layer_ptrs(int i)
+{
+ if (!TC0100SCN_dblwidth[i])
+ {
+ TC0100SCN_bg_ram[i] = TC0100SCN_ram[i] + 0x0;
+ TC0100SCN_tx_ram[i] = TC0100SCN_ram[i] + 0x4000 /2;
+ TC0100SCN_char_ram[i] = TC0100SCN_ram[i] + 0x6000 /2;
+ TC0100SCN_fg_ram[i] = TC0100SCN_ram[i] + 0x8000 /2;
+ TC0100SCN_bgscroll_ram[i] = TC0100SCN_ram[i] + 0xc000 /2;
+ TC0100SCN_fgscroll_ram[i] = TC0100SCN_ram[i] + 0xc400 /2;
+ TC0100SCN_colscroll_ram[i] = TC0100SCN_ram[i] + 0xe000 /2;
+ }
+ else
+ {
+ TC0100SCN_bg_ram[i] = TC0100SCN_ram[i] + 0x0;
+ TC0100SCN_fg_ram[i] = TC0100SCN_ram[i] + 0x08000 /2;
+ TC0100SCN_bgscroll_ram[i] = TC0100SCN_ram[i] + 0x10000 /2;
+ TC0100SCN_fgscroll_ram[i] = TC0100SCN_ram[i] + 0x10400 /2;
+ TC0100SCN_colscroll_ram[i] = TC0100SCN_ram[i] + 0x10800 /2;
+ TC0100SCN_char_ram[i] = TC0100SCN_ram[i] + 0x11000 /2;
+ TC0100SCN_tx_ram[i] = TC0100SCN_ram[i] + 0x12000 /2;
+ }
+}
+
+/* As we can't pass function calls with params in set...func_postload() calls
+ in the vh_start, this slightly obnoxious method is used */
+
+static void TC0100SCN_dirty_tilemaps(int chip)
+{
+ tilemap_mark_all_tiles_dirty(TC0100SCN_tilemap[chip][0][TC0100SCN_dblwidth[chip]]);
+ tilemap_mark_all_tiles_dirty(TC0100SCN_tilemap[chip][1][TC0100SCN_dblwidth[chip]]);
+ tilemap_mark_all_tiles_dirty(TC0100SCN_tilemap[chip][2][TC0100SCN_dblwidth[chip]]);
+}
+
+static void TC0100SCN_dirty_chars(int chip)
+{
+ memset(TC0100SCN_char_dirty[chip],1,TC0100SCN_TOTAL_CHARS);
+ TC0100SCN_chars_dirty[chip] = 1;
+}
+
+static void TC0100SCN_restore_scroll(int chip)
+{
+ int flip;
+
+ TC0100SCN_bgscrollx[chip] = -TC0100SCN_ctrl[chip][0];
+ TC0100SCN_fgscrollx[chip] = -TC0100SCN_ctrl[chip][1];
+ tilemap_set_scrollx(TC0100SCN_tilemap[chip][2][0],0,-TC0100SCN_ctrl[chip][2]);
+ tilemap_set_scrollx(TC0100SCN_tilemap[chip][2][1],0,-TC0100SCN_ctrl[chip][2]);
+
+ TC0100SCN_bgscrolly[chip] = -TC0100SCN_ctrl[chip][3];
+ TC0100SCN_fgscrolly[chip] = -TC0100SCN_ctrl[chip][4];
+ tilemap_set_scrolly(TC0100SCN_tilemap[chip][2][0],0,-TC0100SCN_ctrl[chip][5]);
+ tilemap_set_scrolly(TC0100SCN_tilemap[chip][2][1],0,-TC0100SCN_ctrl[chip][5]);
+
+ flip = (TC0100SCN_ctrl[chip][7] & 0x01) ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0;
+ tilemap_set_flip(TC0100SCN_tilemap[chip][0][0],flip);
+ tilemap_set_flip(TC0100SCN_tilemap[chip][1][0],flip);
+ tilemap_set_flip(TC0100SCN_tilemap[chip][2][0],flip);
+ tilemap_set_flip(TC0100SCN_tilemap[chip][0][1],flip);
+ tilemap_set_flip(TC0100SCN_tilemap[chip][1][1],flip);
+ tilemap_set_flip(TC0100SCN_tilemap[chip][2][1],flip);
+}
+
+
+void TC0100SCN_vh_start(running_machine *machine, int chips,int gfxnum,int x_offset,int y_offset,int flip_xoffs,
+ int flip_yoffs,int flip_text_xoffs,int flip_text_yoffs,int multiscrn_xoffs)
+{
+ int gfx_index,gfxset_offs,i;
+
+ assert(chips <= TC0100SCN_MAX_CHIPS);
+
+ TC0100SCN_chips = chips;
+
+ for (i = 0;i < chips;i++)
+ {
+ int xd,yd;
+ TC0100SCN_dblwidth[i]=0;
+
+ /* Single width versions */
+ TC0100SCN_tilemap[i][0][0] = tilemap_create(TC0100SCN_get_tile_info[i][0],tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ TC0100SCN_tilemap[i][1][0] = tilemap_create(TC0100SCN_get_tile_info[i][1],tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ TC0100SCN_tilemap[i][2][0] = tilemap_create(TC0100SCN_get_tile_info[i][2],tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ /* Double width versions */
+ TC0100SCN_tilemap[i][0][1] = tilemap_create(TC0100SCN_get_tile_info[i][0],tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,128,64);
+ TC0100SCN_tilemap[i][1][1] = tilemap_create(TC0100SCN_get_tile_info[i][1],tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,128,64);
+ TC0100SCN_tilemap[i][2][1] = tilemap_create(TC0100SCN_get_tile_info[i][2],tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,128,32);
+
+ /* Set up clipping for multi-TC0100SCN games. We assume
+ this code won't ever affect single screen games:
+ Thundfox is the only one of those with two chips, and
+ we're safe as it uses single width tilemaps. */
+
+ myclip = machine->screen[(machine->drv->screen[i].tag == NULL) ? 0 : i].visarea;
+
+ TC0100SCN_cliprect[i] = myclip;
+
+ TC0100SCN_ram[i] = auto_malloc(TC0100SCN_RAM_SIZE);
+ TC0100SCN_char_dirty[i] = auto_malloc(TC0100SCN_TOTAL_CHARS);
+
+ TC0100SCN_set_layer_ptrs(i);
+ TC0100SCN_dirty_chars(i);
+ memset(TC0100SCN_ram[i],0,TC0100SCN_RAM_SIZE);
+
+ {
+ state_save_register_item_pointer("TC0100SCN", i, TC0100SCN_ram[i], TC0100SCN_RAM_SIZE/2);
+ state_save_register_item_array("TC0100SCN", i, TC0100SCN_ctrl[i]);
+ state_save_register_item("TC0100SCN", i, TC0100SCN_dblwidth[i]);
+ }
+
+ state_save_register_func_postload_int(TC0100SCN_set_layer_ptrs, i);
+ state_save_register_func_postload_int(TC0100SCN_dirty_chars, i);
+ state_save_register_func_postload_int(TC0100SCN_dirty_tilemaps, i); // unnecessary ?
+ state_save_register_func_postload_int(TC0100SCN_restore_scroll, i);
+
+ /* find first empty slot to decode gfx */
+ for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
+ if (machine->gfx[gfx_index] == 0)
+ break;
+ assert(gfx_index != MAX_GFX_ELEMENTS);
+
+ /* create the char set (gfx will then be updated dynamically from RAM) */
+ machine->gfx[gfx_index] = allocgfx(&TC0100SCN_charlayout);
+
+ /* set the color information */
+ machine->gfx[gfx_index]->total_colors = 64;
+
+ TC0100SCN_tx_gfx[i] = gfx_index;
+
+ /* use the given gfx set for bg tiles; 2nd/3rd chips will
+ use the same gfx set */
+ gfxset_offs = i;
+ if (i > 1)
+ gfxset_offs = 1;
+ TC0100SCN_bg_gfx[i] = gfxnum + gfxset_offs;
+
+ tilemap_set_transparent_pen(TC0100SCN_tilemap[i][0][0],0);
+ tilemap_set_transparent_pen(TC0100SCN_tilemap[i][1][0],0);
+ tilemap_set_transparent_pen(TC0100SCN_tilemap[i][2][0],0);
+
+ tilemap_set_transparent_pen(TC0100SCN_tilemap[i][0][1],0);
+ tilemap_set_transparent_pen(TC0100SCN_tilemap[i][1][1],0);
+ tilemap_set_transparent_pen(TC0100SCN_tilemap[i][2][1],0);
+
+ /* Standard width tilemaps. I'm setting the optional chip #2
+ 7 bits higher and 2 pixels to the left than chip #1 because
+ that's how thundfox wants it. */
+
+ xd = (i == 0) ? (-x_offset) : (-x_offset-2);
+ yd = (i == 0) ? (8-y_offset) : (1-y_offset);
+
+ tilemap_set_scrolldx(TC0100SCN_tilemap[i][0][0], xd-16, -flip_xoffs -xd-16);
+ tilemap_set_scrolldy(TC0100SCN_tilemap[i][0][0], yd, -flip_yoffs -yd);
+ tilemap_set_scrolldx(TC0100SCN_tilemap[i][1][0], xd-16, -flip_xoffs -xd-16);
+ tilemap_set_scrolldy(TC0100SCN_tilemap[i][1][0], yd, -flip_yoffs -yd);
+ tilemap_set_scrolldx(TC0100SCN_tilemap[i][2][0], xd-16, -flip_text_xoffs -xd-16-7);
+ tilemap_set_scrolldy(TC0100SCN_tilemap[i][2][0], yd, -flip_text_yoffs -yd);
+
+ /* Double width tilemaps. We must correct offsets for
+ extra chips, as MAME sees offsets from LHS of whole
+ display not from the edges of individual screens.
+ NB flipscreen tilemap offsets are based on Cameltry */
+
+ xd = -x_offset;
+ yd = 8-y_offset;
+
+#if 0
+ if (chips==2) /* Dual screen */
+ {
+ if (i==1) xd += (320-multiscrn_xoffs);
+ }
+ if (chips==3) /* Triple screen */
+ {
+ if (i==1) xd += (286-multiscrn_xoffs);
+ if (i==2) xd += (572-multiscrn_xoffs*2);
+ }
+#endif
+ tilemap_set_scrolldx(TC0100SCN_tilemap[i][0][1], xd-16, -flip_xoffs -xd-16);
+ tilemap_set_scrolldy(TC0100SCN_tilemap[i][0][1], yd, -flip_yoffs -yd);
+ tilemap_set_scrolldx(TC0100SCN_tilemap[i][1][1], xd-16, -flip_xoffs -xd-16);
+ tilemap_set_scrolldy(TC0100SCN_tilemap[i][1][1], yd, -flip_yoffs -yd);
+ tilemap_set_scrolldx(TC0100SCN_tilemap[i][2][1], xd-16, -flip_text_xoffs -xd-16-7);
+ tilemap_set_scrolldy(TC0100SCN_tilemap[i][2][1], yd, -flip_text_yoffs -yd);
+
+ tilemap_set_scroll_rows(TC0100SCN_tilemap[i][0][0],512);
+ tilemap_set_scroll_rows(TC0100SCN_tilemap[i][1][0],512);
+ tilemap_set_scroll_rows(TC0100SCN_tilemap[i][0][1],512);
+ tilemap_set_scroll_rows(TC0100SCN_tilemap[i][1][1],512);
+
+ /* Default is for all used chips to access the same palette area */
+ TC0100SCN_chip_colbank[i]=0;
+ }
+
+ TC0100SCN_gfxbank= 0; /* Mjnquest uniquely banks tiles */
+ state_save_register_global(TC0100SCN_gfxbank);
+
+ TC0100SCN_bg_tilemask = 0xffff; /* Mjnquest has 0x7fff tilemask */
+
+ TC0100SCN_bg_col_mult = 1; /* multiplier for when bg gfx != 4bpp */
+ TC0100SCN_tx_col_mult = 1; /* multiplier needed when bg gfx is 6bpp */
+
+ if (machine->gfx[gfxnum]->color_granularity == 2) /* Yuyugogo, Yesnoj */
+ TC0100SCN_bg_col_mult = 8;
+
+ if (machine->gfx[gfxnum]->color_granularity == 0x40) /* Undrfire */
+ TC0100SCN_tx_col_mult = 4;
+
+//logerror("TC0100SCN bg gfx granularity %04x: multiplier %04x\n",
+//machine->gfx[gfxnum]->color_granularity,TC0100SCN_tx_col_mult);
+
+ TC0100SCN_set_colbanks(0,0,0); /* standard values, only Wgp changes them */
+}
+
+
+READ16_HANDLER( TC0100SCN_word_0_r )
+{
+ return TC0100SCN_ram[0][offset];
+}
+
+READ16_HANDLER( TC0100SCN_word_1_r )
+{
+ return TC0100SCN_ram[1][offset];
+}
+
+READ16_HANDLER( TC0100SCN_word_2_r )
+{
+ return TC0100SCN_ram[2][offset];
+}
+
+static void TC0100SCN_word_w(int chip,offs_t offset,UINT16 data,UINT32 mem_mask)
+{
+ COMBINE_DATA(&TC0100SCN_ram[chip][offset]);
+ if (!TC0100SCN_dblwidth[chip])
+ {
+ if (offset < 0x2000)
+ tilemap_mark_tile_dirty(TC0100SCN_tilemap[chip][0][0],offset / 2);
+ else if (offset < 0x3000)
+ tilemap_mark_tile_dirty(TC0100SCN_tilemap[chip][2][0],(offset & 0x0fff));
+ else if (offset < 0x3800)
+ {
+ TC0100SCN_char_dirty[chip][(offset - 0x3000) / 8] = 1;
+ TC0100SCN_chars_dirty[chip] = 1;
+ }
+ else if (offset >= 0x4000 && offset < 0x6000)
+ tilemap_mark_tile_dirty(TC0100SCN_tilemap[chip][1][0],(offset & 0x1fff) / 2);
+ }
+ else /* Double-width tilemaps have a different memory map */
+ {
+ if (offset < 0x4000)
+ tilemap_mark_tile_dirty(TC0100SCN_tilemap[chip][0][1],offset / 2);
+ else if (offset >= 0x4000 && offset < 0x8000)
+ tilemap_mark_tile_dirty(TC0100SCN_tilemap[chip][1][1],(offset & 0x3fff) / 2);
+ else if (offset >= 0x8800 && offset < 0x9000)
+ {
+ TC0100SCN_char_dirty[chip][(offset - 0x8800) / 8] = 1;
+ TC0100SCN_chars_dirty[chip] = 1;
+ }
+ else if (offset >= 0x9000)
+ tilemap_mark_tile_dirty(TC0100SCN_tilemap[chip][2][1],(offset & 0x0fff));
+ }
+}
+
+WRITE16_HANDLER( TC0100SCN_word_0_w )
+{
+ TC0100SCN_word_w(0,offset,data,mem_mask);
+}
+
+WRITE16_HANDLER( TC0100SCN_word_1_w )
+{
+ TC0100SCN_word_w(1,offset,data,mem_mask);
+}
+
+WRITE16_HANDLER( TC0100SCN_word_2_w )
+{
+ TC0100SCN_word_w(2,offset,data,mem_mask);
+}
+
+WRITE16_HANDLER( TC0100SCN_dual_screen_w )
+{
+ TC0100SCN_word_0_w(offset,data,mem_mask);
+ TC0100SCN_word_1_w(offset,data,mem_mask);
+}
+
+WRITE16_HANDLER( TC0100SCN_triple_screen_w )
+{
+ TC0100SCN_word_0_w(offset,data,mem_mask);
+ TC0100SCN_word_1_w(offset,data,mem_mask);
+ TC0100SCN_word_2_w(offset,data,mem_mask);
+}
+
+
+READ16_HANDLER( TC0100SCN_ctrl_word_0_r )
+{
+ return TC0100SCN_ctrl[0][offset];
+}
+
+READ16_HANDLER( TC0100SCN_ctrl_word_1_r )
+{
+ return TC0100SCN_ctrl[1][offset];
+}
+
+READ16_HANDLER( TC0100SCN_ctrl_word_2_r )
+{
+ return TC0100SCN_ctrl[2][offset];
+}
+
+
+static void TC0100SCN_ctrl_word_w(int chip,offs_t offset,UINT16 data,UINT32 mem_mask)
+{
+ COMBINE_DATA(&TC0100SCN_ctrl[chip][offset]);
+
+ data = TC0100SCN_ctrl[chip][offset];
+
+ switch (offset)
+ {
+ case 0x00:
+ TC0100SCN_bgscrollx[chip] = -data;
+ break;
+
+ case 0x01:
+ TC0100SCN_fgscrollx[chip] = -data;
+ break;
+
+ case 0x02:
+ tilemap_set_scrollx(TC0100SCN_tilemap[chip][2][0],0,-data);
+ tilemap_set_scrollx(TC0100SCN_tilemap[chip][2][1],0,-data);
+ break;
+
+ case 0x03:
+ TC0100SCN_bgscrolly[chip] = -data;
+ break;
+
+ case 0x04:
+ TC0100SCN_fgscrolly[chip] = -data;
+ break;
+
+ case 0x05:
+ tilemap_set_scrolly(TC0100SCN_tilemap[chip][2][0],0,-data);
+ tilemap_set_scrolly(TC0100SCN_tilemap[chip][2][1],0,-data);
+ break;
+
+ case 0x06:
+ {
+ int old_width = TC0100SCN_dblwidth[chip];
+ TC0100SCN_dblwidth[chip] = (data &0x10) >> 4;
+
+ if (TC0100SCN_dblwidth[chip] != old_width) /* tilemap width is changing */
+ {
+ /* Reinitialise layer pointers */
+ TC0100SCN_set_layer_ptrs(chip);
+
+ /* and ensure full redraw of the tilemaps */
+ TC0100SCN_dirty_tilemaps(chip);
+ }
+
+ break;
+ }
+
+ case 0x07:
+ {
+ int flip = (data & 0x01) ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0;
+
+ tilemap_set_flip(TC0100SCN_tilemap[chip][0][0],flip);
+ tilemap_set_flip(TC0100SCN_tilemap[chip][1][0],flip);
+ tilemap_set_flip(TC0100SCN_tilemap[chip][2][0],flip);
+ tilemap_set_flip(TC0100SCN_tilemap[chip][0][1],flip);
+ tilemap_set_flip(TC0100SCN_tilemap[chip][1][1],flip);
+ tilemap_set_flip(TC0100SCN_tilemap[chip][2][1],flip);
+
+ break;
+ }
+ }
+}
+
+WRITE16_HANDLER( TC0100SCN_ctrl_word_0_w )
+{
+ TC0100SCN_ctrl_word_w(0,offset,data,mem_mask);
+}
+
+WRITE16_HANDLER( TC0100SCN_ctrl_word_1_w )
+{
+ TC0100SCN_ctrl_word_w(1,offset,data,mem_mask);
+}
+
+WRITE16_HANDLER( TC0100SCN_ctrl_word_2_w )
+{
+ TC0100SCN_ctrl_word_w(2,offset,data,mem_mask);
+}
+
+
+READ32_HANDLER( TC0100SCN_ctrl_long_r )
+{
+ return (TC0100SCN_ctrl_word_0_r(offset*2,0)<<16)|TC0100SCN_ctrl_word_0_r(offset*2+1,0);
+}
+
+WRITE32_HANDLER( TC0100SCN_ctrl_long_w )
+{
+ if (ACCESSING_MSW32) TC0100SCN_ctrl_word_w(0,offset*2,data>>16,mem_mask>>16);
+ if (ACCESSING_LSW32) TC0100SCN_ctrl_word_w(0,(offset*2)+1,data&0xffff,mem_mask&0xffff);
+}
+
+READ32_HANDLER( TC0100SCN_long_r )
+{
+ return (TC0100SCN_word_0_r(offset*2,0)<<16)|TC0100SCN_word_0_r(offset*2+1,0);
+}
+
+WRITE32_HANDLER( TC0100SCN_long_w )
+{
+ if (((mem_mask & 0xff000000) == 0) || ((mem_mask & 0x00ff0000) == 0))
+ {
+ int oldword = TC0100SCN_word_0_r(offset*2,0);
+ int newword = data>>16;
+ if ((mem_mask & 0x00ff0000) != 0)
+ newword |= (oldword &0x00ff);
+ if ((mem_mask & 0xff000000) != 0)
+ newword |= (oldword &0xff00);
+ TC0100SCN_word_0_w(offset*2,newword,0);
+ }
+ if (((mem_mask & 0x0000ff00) == 0) || ((mem_mask & 0x000000ff) == 0))
+ {
+ int oldword = TC0100SCN_word_0_r((offset*2)+1,0);
+ int newword = data&0xffff;
+ if ((mem_mask & 0x000000ff) != 0)
+ newword |= (oldword &0x00ff);
+ if ((mem_mask & 0x0000ff00) != 0)
+ newword |= (oldword &0xff00);
+ TC0100SCN_word_0_w((offset*2)+1,newword,0);
+ }
+}
+
+
+void TC0100SCN_tilemap_update(running_machine *machine)
+{
+ int chip,j;
+
+ for (chip = 0;chip < TC0100SCN_chips;chip++)
+ {
+ tilemap_set_scrolly(TC0100SCN_tilemap[chip][0][TC0100SCN_dblwidth[chip]],0,TC0100SCN_bgscrolly[chip]);
+ tilemap_set_scrolly(TC0100SCN_tilemap[chip][1][TC0100SCN_dblwidth[chip]],0,TC0100SCN_fgscrolly[chip]);
+
+ for (j = 0;j < 256;j++)
+ tilemap_set_scrollx(TC0100SCN_tilemap[chip][0][TC0100SCN_dblwidth[chip]],
+ (j + TC0100SCN_bgscrolly[chip]) & 0x1ff,
+ TC0100SCN_bgscrollx[chip] - TC0100SCN_bgscroll_ram[chip][j]);
+ for (j = 0;j < 256;j++)
+ tilemap_set_scrollx(TC0100SCN_tilemap[chip][1][TC0100SCN_dblwidth[chip]],
+ (j + TC0100SCN_fgscrolly[chip]) & 0x1ff,
+ TC0100SCN_fgscrollx[chip] - TC0100SCN_fgscroll_ram[chip][j]);
+
+ /* Decode any characters that have changed */
+ if (TC0100SCN_chars_dirty[chip])
+ {
+ int tile_index;
+
+
+ for (tile_index = 0;tile_index < 64*64;tile_index++)
+ {
+ int attr = TC0100SCN_tx_ram[chip][tile_index];
+ if (TC0100SCN_char_dirty[chip][attr & 0xff])
+ tilemap_mark_tile_dirty(TC0100SCN_tilemap[chip][2][TC0100SCN_dblwidth[chip]],tile_index);
+ }
+
+ for (j = 0;j < TC0100SCN_TOTAL_CHARS;j++)
+ {
+ if (TC0100SCN_char_dirty[chip][j])
+ decodechar(machine->gfx[TC0100SCN_tx_gfx[chip]],j,
+ (UINT8 *)TC0100SCN_char_ram[chip],&TC0100SCN_charlayout);
+ TC0100SCN_char_dirty[chip][j] = 0;
+ }
+ TC0100SCN_chars_dirty[chip] = 0;
+ }
+ }
+}
+
+static void TC0100SCN_tilemap_draw_fg(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect, int chip, tilemap* tmap ,int flags, UINT32 priority)
+{
+ const mame_bitmap *src_bitmap = tilemap_get_pixmap(tmap);
+ int width_mask, height_mask, x, y, p;
+ int column_offset, src_x=0, src_y=0;
+ int scrollx_delta = - tilemap_get_scrolldx( tmap );
+ int scrolly_delta = - tilemap_get_scrolldy( tmap );
+
+ width_mask=src_bitmap->width - 1;
+ height_mask=src_bitmap->height - 1;
+
+ src_y=(TC0100SCN_fgscrolly[chip] + scrolly_delta)&height_mask;
+ if (TC0100SCN_ctrl[chip][0x7]&1) // Flipscreen
+ src_y=(256-src_y)&height_mask;
+
+ //We use cliprect->max_y and cliprect->max_x to support games which use more than 1 screen
+
+ // Row offsets are 'screen space' 0-255 regardless of Y scroll
+ for (y=0; y<=cliprect->max_y; y++) {
+ src_x=(TC0100SCN_fgscrollx[chip] - TC0100SCN_fgscroll_ram[chip][(y + scrolly_delta)&0x1ff] + scrollx_delta + cliprect->min_x)&width_mask;
+ if (TC0100SCN_ctrl[chip][0x7]&1) // Flipscreen
+ src_x=(256 - 64 - src_x)&width_mask;
+
+ // Col offsets are 'tilemap' space 0-511, and apply to blocks of 8 pixels at once
+ for (x=0; x<=(cliprect->max_x - cliprect->min_x); x++) {
+ column_offset=TC0100SCN_colscroll_ram[chip][(src_x&0x3ff) / 8];
+ p=*BITMAP_ADDR16(src_bitmap, (src_y - column_offset)&height_mask, src_x);
+
+ if ((p&0xf)!=0 || (flags & TILEMAP_DRAW_OPAQUE))
+ {
+ *BITMAP_ADDR16(bitmap, y, x + cliprect->min_x) = machine->pens[p];
+ if (priority_bitmap)
+ {
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+ pri[x + cliprect->min_x]|=priority;
+ }
+ }
+ src_x=(src_x+1)&width_mask;
+ }
+ src_y=(src_y+1)&height_mask;
+ }
+}
+
+int TC0100SCN_tilemap_draw(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int chip,int layer,int flags,UINT32 priority)
+{
+ int disable = TC0100SCN_ctrl[chip][6] & 0xf7;
+ rectangle clip = *cliprect;
+ sect_rect(&clip, &TC0100SCN_cliprect[chip]);
+
+#if 0
+if (disable != 0 && disable != 3 && disable != 7)
+ popmessage("layer disable = %x",disable);
+#endif
+
+ switch (layer)
+ {
+ case 0:
+ if (disable & 0x01) return 1;
+ tilemap_draw(bitmap,&clip,TC0100SCN_tilemap[chip][0][TC0100SCN_dblwidth[chip]],flags,priority);
+ break;
+ case 1:
+ if (disable & 0x02) return 1;
+ TC0100SCN_tilemap_draw_fg(machine,bitmap,&clip,chip,TC0100SCN_tilemap[chip][1][TC0100SCN_dblwidth[chip]],flags,priority);
+ break;
+ case 2:
+ if (disable & 0x04) return 1;
+ tilemap_draw(bitmap,&clip,TC0100SCN_tilemap[chip][2][TC0100SCN_dblwidth[chip]],flags,priority);
+ break;
+ }
+ return 0;
+}
+
+int TC0100SCN_bottomlayer(int chip)
+{
+ return (TC0100SCN_ctrl[chip][6] & 0x8) >> 3;
+}
+
+
+/***************************************************************************/
+
+#define TC0280GRD_RAM_SIZE 0x2000
+static UINT16 TC0280GRD_ctrl[8];
+static UINT16 *TC0280GRD_ram;
+static tilemap *TC0280GRD_tilemap;
+static int TC0280GRD_gfxnum,TC0280GRD_base_color;
+
+
+static TILE_GET_INFO( TC0280GRD_get_tile_info )
+{
+ int attr = TC0280GRD_ram[tile_index];
+ SET_TILE_INFO(
+ TC0280GRD_gfxnum,
+ attr & 0x3fff,
+ ((attr & 0xc000) >> 14) + TC0280GRD_base_color,
+ 0);
+}
+
+
+void TC0280GRD_vh_start(int gfxnum)
+{
+ TC0280GRD_ram = auto_malloc(TC0280GRD_RAM_SIZE);
+ TC0280GRD_tilemap = tilemap_create(TC0280GRD_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ state_save_register_global_pointer(TC0280GRD_ram, TC0280GRD_RAM_SIZE/2);
+ state_save_register_global_array(TC0280GRD_ctrl);
+
+ tilemap_set_transparent_pen(TC0280GRD_tilemap,0);
+
+ TC0280GRD_gfxnum = gfxnum;
+}
+
+void TC0430GRW_vh_start(int gfxnum)
+{
+ TC0280GRD_vh_start(gfxnum);
+}
+
+READ16_HANDLER( TC0280GRD_word_r )
+{
+ return TC0280GRD_ram[offset];
+}
+
+READ16_HANDLER( TC0430GRW_word_r )
+{
+ return TC0280GRD_word_r(offset,mem_mask);
+}
+
+WRITE16_HANDLER( TC0280GRD_word_w )
+{
+ COMBINE_DATA(&TC0280GRD_ram[offset]);
+ tilemap_mark_tile_dirty(TC0280GRD_tilemap,offset);
+}
+
+WRITE16_HANDLER( TC0430GRW_word_w )
+{
+ TC0280GRD_word_w(offset,data,mem_mask);
+}
+
+WRITE16_HANDLER( TC0280GRD_ctrl_word_w )
+{
+ COMBINE_DATA(&TC0280GRD_ctrl[offset]);
+}
+
+WRITE16_HANDLER( TC0430GRW_ctrl_word_w )
+{
+ TC0280GRD_ctrl_word_w(offset,data,mem_mask);
+}
+
+void TC0280GRD_tilemap_update(int base_color)
+{
+ if (TC0280GRD_base_color != base_color)
+ {
+ TC0280GRD_base_color = base_color;
+ tilemap_mark_all_tiles_dirty(TC0280GRD_tilemap);
+ }
+}
+
+void TC0430GRW_tilemap_update(int base_color)
+{
+ TC0280GRD_tilemap_update(base_color);
+}
+
+static void zoom_draw(mame_bitmap *bitmap,const rectangle *cliprect,int xoffset,int yoffset,UINT32 priority,int xmultiply)
+{
+ UINT32 startx,starty;
+ int incxx,incxy,incyx,incyy;
+
+ /* 24-bit signed */
+ startx = ((TC0280GRD_ctrl[0] & 0xff) << 16) + TC0280GRD_ctrl[1];
+ if (startx & 0x800000) startx -= 0x1000000;
+ incxx = (INT16)TC0280GRD_ctrl[2];
+ incxx *= xmultiply;
+ incyx = (INT16)TC0280GRD_ctrl[3];
+ /* 24-bit signed */
+ starty = ((TC0280GRD_ctrl[4] & 0xff) << 16) + TC0280GRD_ctrl[5];
+ if (starty & 0x800000) starty -= 0x1000000;
+ incxy = (INT16)TC0280GRD_ctrl[6];
+ incxy *= xmultiply;
+ incyy = (INT16)TC0280GRD_ctrl[7];
+
+ startx -= xoffset * incxx + yoffset * incyx;
+ starty -= xoffset * incxy + yoffset * incyy;
+
+ tilemap_draw_roz(bitmap,cliprect,TC0280GRD_tilemap,startx << 4,starty << 4,
+ incxx << 4,incxy << 4,incyx << 4,incyy << 4,
+ 1, /* copy with wraparound */
+ 0,priority);
+}
+
+void TC0280GRD_zoom_draw(mame_bitmap *bitmap,const rectangle *cliprect,int xoffset,int yoffset,UINT32 priority)
+{
+ zoom_draw(bitmap,cliprect,xoffset,yoffset,priority,2);
+}
+
+void TC0430GRW_zoom_draw(mame_bitmap *bitmap,const rectangle *cliprect,int xoffset,int yoffset,UINT32 priority)
+{
+ zoom_draw(bitmap,cliprect,xoffset,yoffset,priority,1);
+}
+
+
+/***************************************************************************/
+
+UINT8 TC0360PRI_regs[16];
+
+void TC0360PRI_vh_start(void)
+{
+ state_save_register_global_array(TC0360PRI_regs);
+}
+
+WRITE8_HANDLER( TC0360PRI_w )
+{
+ TC0360PRI_regs[offset] = data;
+
+if (offset >= 0x0a)
+ popmessage("write %02x to unused TC0360PRI reg %x",data,offset);
+#if 0
+#define regs TC0360PRI_regs
+ popmessage("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+ regs[0x00],regs[0x01],regs[0x02],regs[0x03],
+ regs[0x04],regs[0x05],regs[0x06],regs[0x07],
+ regs[0x08],regs[0x09]);
+#endif
+}
+
+WRITE16_HANDLER( TC0360PRI_halfword_w )
+{
+ if (ACCESSING_LSB)
+ {
+ TC0360PRI_w(offset,data & 0xff);
+#if 0
+if (data & 0xff00)
+{ logerror("CPU #0 PC %06x: warning - write %02x to MSB of TC0360PRI address %02x\n",activecpu_get_pc(),data,offset); }
+ else
+{ logerror("CPU #0 PC %06x: warning - write %02x to MSB of TC0360PRI address %02x\n",activecpu_get_pc(),data,offset); }
+#endif
+ }
+}
+
+WRITE16_HANDLER( TC0360PRI_halfword_swap_w )
+{
+ if (ACCESSING_MSB)
+ {
+ TC0360PRI_w(offset,(data >> 8) & 0xff);
+#if 0
+if (data & 0xff)
+{ logerror("CPU #0 PC %06x: warning - write %02x to LSB of TC0360PRI address %02x\n",activecpu_get_pc(),data,offset); }
+ else
+{ logerror("CPU #0 PC %06x: warning - write %02x to LSB of TC0360PRI address %02x\n",activecpu_get_pc(),data,offset); }
+#endif
+ }
+}
+
+
+/***************************************************************************/
+
+
+#define TC0480SCP_RAM_SIZE 0x10000
+#define TC0480SCP_TOTAL_CHARS 256
+static UINT16 TC0480SCP_ctrl[0x18];
+static UINT16 *TC0480SCP_ram,
+ *TC0480SCP_bg_ram[4],
+ *TC0480SCP_tx_ram,
+ *TC0480SCP_char_ram,
+ *TC0480SCP_bgscroll_ram[4],
+ *TC0480SCP_rowzoom_ram[4],
+ *TC0480SCP_bgcolumn_ram[4];
+static int TC0480SCP_bgscrollx[4];
+static int TC0480SCP_bgscrolly[4];
+int TC0480SCP_pri_reg;
+
+/* We keep two tilemaps for each of the 5 actual tilemaps: one at standard width, one double */
+static tilemap *TC0480SCP_tilemap[5][2];
+static char *TC0480SCP_char_dirty;
+static int TC0480SCP_chars_dirty;
+static int TC0480SCP_bg_gfx,TC0480SCP_tx_gfx;
+static INT32 TC0480SCP_tile_colbase,TC0480SCP_dblwidth;
+static int TC0480SCP_x_offs,TC0480SCP_y_offs;
+static int TC0480SCP_text_xoffs,TC0480SCP_text_yoffs;
+static int TC0480SCP_flip_xoffs,TC0480SCP_flip_yoffs;
+
+
+INLINE void common_get_tc0480bg_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,UINT16 *ram,int gfxnum)
+{
+ int code = ram[2*tile_index + 1] & 0x7fff;
+ int attr = ram[2*tile_index];
+ SET_TILE_INFO(
+ gfxnum,
+ code,
+ (attr & 0xff) + TC0480SCP_tile_colbase,
+ TILE_FLIPYX((attr & 0xc000) >> 14));
+}
+
+INLINE void common_get_tc0480tx_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,UINT16 *ram,int gfxnum)
+{
+ int attr = ram[tile_index];
+ SET_TILE_INFO(
+ gfxnum,
+ attr & 0xff,
+ ((attr & 0x3f00) >> 8) + TC0480SCP_tile_colbase,
+ TILE_FLIPYX((attr & 0xc000) >> 14));
+}
+
+static TILE_GET_INFO( TC0480SCP_get_bg0_tile_info )
+{
+ common_get_tc0480bg_tile_info(machine,tileinfo,tile_index,TC0480SCP_bg_ram[0],TC0480SCP_bg_gfx);
+}
+
+static TILE_GET_INFO( TC0480SCP_get_bg1_tile_info )
+{
+ common_get_tc0480bg_tile_info(machine,tileinfo,tile_index,TC0480SCP_bg_ram[1],TC0480SCP_bg_gfx);
+}
+
+static TILE_GET_INFO( TC0480SCP_get_bg2_tile_info )
+{
+ common_get_tc0480bg_tile_info(machine,tileinfo,tile_index,TC0480SCP_bg_ram[2],TC0480SCP_bg_gfx);
+}
+
+static TILE_GET_INFO( TC0480SCP_get_bg3_tile_info )
+{
+ common_get_tc0480bg_tile_info(machine,tileinfo,tile_index,TC0480SCP_bg_ram[3],TC0480SCP_bg_gfx);
+}
+
+static TILE_GET_INFO( TC0480SCP_get_tx_tile_info )
+{
+ common_get_tc0480tx_tile_info(machine,tileinfo,tile_index,TC0480SCP_tx_ram,TC0480SCP_tx_gfx);
+}
+
+static tile_get_info_callback tc480_get_tile_info[5] =
+{
+ TC0480SCP_get_bg0_tile_info, TC0480SCP_get_bg1_tile_info,
+ TC0480SCP_get_bg2_tile_info, TC0480SCP_get_bg3_tile_info,
+ TC0480SCP_get_tx_tile_info
+};
+
+
+static const gfx_layout TC0480SCP_charlayout =
+{
+ 8,8, /* 8*8 characters */
+ 256, /* 256 characters */
+ 4, /* 4 bits per pixel */
+ { 0, 1, 2, 3 },
+#ifdef LSB_FIRST
+ { 1*4, 0*4, 3*4, 2*4, 5*4, 4*4, 7*4, 6*4 },
+#else
+ { 3*4, 2*4, 1*4, 0*4, 7*4, 6*4, 5*4, 4*4 },
+#endif
+ { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 },
+ 32*8 /* every sprite takes 32 consecutive bytes */
+};
+
+static void TC0480SCP_set_layer_ptrs(void)
+{
+ if (!TC0480SCP_dblwidth)
+ {
+ TC0480SCP_bg_ram[0] = TC0480SCP_ram + 0x0000; //0000
+ TC0480SCP_bg_ram[1] = TC0480SCP_ram + 0x0800; //1000
+ TC0480SCP_bg_ram[2] = TC0480SCP_ram + 0x1000; //2000
+ TC0480SCP_bg_ram[3] = TC0480SCP_ram + 0x1800; //3000
+ TC0480SCP_bgscroll_ram[0] = TC0480SCP_ram + 0x2000; //4000
+ TC0480SCP_bgscroll_ram[1] = TC0480SCP_ram + 0x2200; //4400
+ TC0480SCP_bgscroll_ram[2] = TC0480SCP_ram + 0x2400; //4800
+ TC0480SCP_bgscroll_ram[3] = TC0480SCP_ram + 0x2600; //4c00
+ TC0480SCP_rowzoom_ram[2] = TC0480SCP_ram + 0x3000; //6000
+ TC0480SCP_rowzoom_ram[3] = TC0480SCP_ram + 0x3200; //6400
+ TC0480SCP_bgcolumn_ram[2] = TC0480SCP_ram + 0x3400; //6800
+ TC0480SCP_bgcolumn_ram[3] = TC0480SCP_ram + 0x3600; //6c00
+ TC0480SCP_tx_ram = TC0480SCP_ram + 0x6000; //c000
+ TC0480SCP_char_ram = TC0480SCP_ram + 0x7000; //e000
+ }
+ else
+ {
+ TC0480SCP_bg_ram[0] = TC0480SCP_ram + 0x0000; //0000
+ TC0480SCP_bg_ram[1] = TC0480SCP_ram + 0x1000; //2000
+ TC0480SCP_bg_ram[2] = TC0480SCP_ram + 0x2000; //4000
+ TC0480SCP_bg_ram[3] = TC0480SCP_ram + 0x3000; //6000
+ TC0480SCP_bgscroll_ram[0] = TC0480SCP_ram + 0x4000; //8000
+ TC0480SCP_bgscroll_ram[1] = TC0480SCP_ram + 0x4200; //8400
+ TC0480SCP_bgscroll_ram[2] = TC0480SCP_ram + 0x4400; //8800
+ TC0480SCP_bgscroll_ram[3] = TC0480SCP_ram + 0x4600; //8c00
+ TC0480SCP_rowzoom_ram[2] = TC0480SCP_ram + 0x5000; //a000
+ TC0480SCP_rowzoom_ram[3] = TC0480SCP_ram + 0x5200; //a400
+ TC0480SCP_bgcolumn_ram[2] = TC0480SCP_ram + 0x5400; //a800
+ TC0480SCP_bgcolumn_ram[3] = TC0480SCP_ram + 0x5600; //ac00
+ TC0480SCP_tx_ram = TC0480SCP_ram + 0x6000; //c000
+ TC0480SCP_char_ram = TC0480SCP_ram + 0x7000; //e000
+ }
+}
+
+static void TC0480SCP_dirty_tilemaps(void)
+{
+ tilemap_mark_all_tiles_dirty(TC0480SCP_tilemap[0][TC0480SCP_dblwidth]);
+ tilemap_mark_all_tiles_dirty(TC0480SCP_tilemap[1][TC0480SCP_dblwidth]);
+ tilemap_mark_all_tiles_dirty(TC0480SCP_tilemap[2][TC0480SCP_dblwidth]);
+ tilemap_mark_all_tiles_dirty(TC0480SCP_tilemap[3][TC0480SCP_dblwidth]);
+ tilemap_mark_all_tiles_dirty(TC0480SCP_tilemap[4][TC0480SCP_dblwidth]);
+}
+
+static void TC0480SCP_dirty_chars(void)
+{
+ memset(TC0480SCP_char_dirty,1,TC0480SCP_TOTAL_CHARS);
+ TC0480SCP_chars_dirty = 1;
+}
+
+static void TC0480SCP_restore_scroll(void)
+{
+ int reg;
+ int flip = TC0480SCP_ctrl[0xf] & 0x40;
+
+ tilemap_set_flip(TC0480SCP_tilemap[0][0],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[1][0],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[2][0],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[3][0],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[4][0],flip);
+
+ tilemap_set_flip(TC0480SCP_tilemap[0][1],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[1][1],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[2][1],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[3][1],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[4][1],flip);
+
+ reg = TC0480SCP_ctrl[0];
+ if (!flip) reg = -reg;
+ TC0480SCP_bgscrollx[0] = reg;
+
+ reg = TC0480SCP_ctrl[1] + 4;
+ if (!flip) reg = -reg;
+ TC0480SCP_bgscrollx[1] = reg;
+
+ reg = TC0480SCP_ctrl[2] + 8;
+ if (!flip) reg = -reg;
+ TC0480SCP_bgscrollx[2] = reg;
+
+ reg = TC0480SCP_ctrl[3] + 12;
+ if (!flip) reg = -reg;
+ TC0480SCP_bgscrollx[3] = reg;
+
+ reg = TC0480SCP_ctrl[4];
+ if (!flip) reg = -reg;
+ TC0480SCP_bgscrolly[0] = reg;
+
+ reg = TC0480SCP_ctrl[5];
+ if (!flip) reg = -reg;
+ TC0480SCP_bgscrolly[1] = reg;
+
+ reg = TC0480SCP_ctrl[6];
+ if (!flip) reg = -reg;
+ TC0480SCP_bgscrolly[2] = reg;
+
+ reg = TC0480SCP_ctrl[7];
+ if (!flip) reg = -reg;
+ TC0480SCP_bgscrolly[3] = reg;
+
+ reg = TC0480SCP_ctrl[0x0c];
+ if (!flip) reg -= TC0480SCP_text_xoffs;
+ if (flip) reg += TC0480SCP_text_xoffs;
+ tilemap_set_scrollx(TC0480SCP_tilemap[4][0], 0, -reg);
+ tilemap_set_scrollx(TC0480SCP_tilemap[4][1], 0, -reg);
+
+ reg = TC0480SCP_ctrl[0x0d];
+ if (!flip) reg -= TC0480SCP_text_yoffs;
+ if (flip) reg += TC0480SCP_text_yoffs;
+ tilemap_set_scrolly(TC0480SCP_tilemap[4][0], 0, -reg);
+ tilemap_set_scrolly(TC0480SCP_tilemap[4][1], 0, -reg);
+}
+
+
+void TC0480SCP_vh_start(running_machine *machine, int gfxnum,int pixels,int x_offset,int y_offset,int text_xoffs,
+ int text_yoffs,int flip_xoffs,int flip_yoffs,int col_base)
+{
+ int gfx_index;
+
+ int i,xd,yd;
+ TC0480SCP_tile_colbase = col_base;
+ TC0480SCP_text_xoffs = text_xoffs;
+ TC0480SCP_text_yoffs = text_yoffs;
+ TC0480SCP_flip_xoffs = flip_xoffs; /* for most games (-1,0) */
+ TC0480SCP_flip_yoffs = flip_yoffs;
+ TC0480SCP_dblwidth=0;
+
+ /* Single width versions */
+ TC0480SCP_tilemap[0][0] = tilemap_create(tc480_get_tile_info[0],tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ TC0480SCP_tilemap[1][0] = tilemap_create(tc480_get_tile_info[1],tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ TC0480SCP_tilemap[2][0] = tilemap_create(tc480_get_tile_info[2],tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ TC0480SCP_tilemap[3][0] = tilemap_create(tc480_get_tile_info[3],tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ TC0480SCP_tilemap[4][0] = tilemap_create(tc480_get_tile_info[4],tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ /* Double width versions */
+ TC0480SCP_tilemap[0][1] = tilemap_create(tc480_get_tile_info[0],tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ TC0480SCP_tilemap[1][1] = tilemap_create(tc480_get_tile_info[1],tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ TC0480SCP_tilemap[2][1] = tilemap_create(tc480_get_tile_info[2],tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ TC0480SCP_tilemap[3][1] = tilemap_create(tc480_get_tile_info[3],tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ TC0480SCP_tilemap[4][1] = tilemap_create(tc480_get_tile_info[4],tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ TC0480SCP_ram = auto_malloc(TC0480SCP_RAM_SIZE);
+ TC0480SCP_char_dirty = auto_malloc(TC0480SCP_TOTAL_CHARS);
+
+ TC0480SCP_set_layer_ptrs();
+ TC0480SCP_dirty_chars();
+ memset(TC0480SCP_ram,0,TC0480SCP_RAM_SIZE);
+
+ state_save_register_global_pointer(TC0480SCP_ram, TC0480SCP_RAM_SIZE/2);
+ state_save_register_global_array(TC0480SCP_ctrl);
+ state_save_register_global(TC0480SCP_dblwidth);
+ state_save_register_func_postload(TC0480SCP_set_layer_ptrs);
+ state_save_register_func_postload(TC0480SCP_dirty_chars);
+ state_save_register_func_postload(TC0480SCP_dirty_tilemaps); // unnecessary ?
+ state_save_register_func_postload(TC0480SCP_restore_scroll);
+
+ /* find first empty slot to decode gfx */
+ for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
+ if (machine->gfx[gfx_index] == 0)
+ break;
+ assert(gfx_index != MAX_GFX_ELEMENTS);
+
+ /* create the char set (gfx will then be updated dynamically from RAM) */
+ machine->gfx[gfx_index] = allocgfx(&TC0480SCP_charlayout);
+
+ /* set the color information */
+ machine->gfx[gfx_index]->total_colors = 64;
+
+ TC0480SCP_tx_gfx = gfx_index;
+
+ /* use the given gfx set for bg tiles */
+ TC0480SCP_bg_gfx = gfxnum;
+
+ for (i=0;i<2;i++)
+ {
+ tilemap_set_transparent_pen(TC0480SCP_tilemap[0][i],0);
+ tilemap_set_transparent_pen(TC0480SCP_tilemap[1][i],0);
+ tilemap_set_transparent_pen(TC0480SCP_tilemap[2][i],0);
+ tilemap_set_transparent_pen(TC0480SCP_tilemap[3][i],0);
+ tilemap_set_transparent_pen(TC0480SCP_tilemap[4][i],0);
+ }
+
+ TC0480SCP_x_offs = x_offset + pixels;
+ TC0480SCP_y_offs = y_offset;
+
+ xd = -TC0480SCP_x_offs;
+ yd = TC0480SCP_y_offs;
+
+ /* Metalb and Deadconx have minor screenflip issues: blue planet
+ is off on x axis by 1 and in Deadconx the dark blue screen
+ between stages also seems off by 1 pixel. */
+
+ /* It's not possible to get the text scrolldx calculations
+ harmonised with the other layers: xd-2, 315-xd is the
+ next valid pair:- the numbers diverge from xd, 319-xd */
+
+ /* Single width offsets */
+ tilemap_set_scrolldx(TC0480SCP_tilemap[0][0], xd, 320-xd +TC0480SCP_flip_xoffs );
+ tilemap_set_scrolldy(TC0480SCP_tilemap[0][0], yd, 256-yd +TC0480SCP_flip_yoffs );
+ tilemap_set_scrolldx(TC0480SCP_tilemap[1][0], xd, 320-xd +TC0480SCP_flip_xoffs );
+ tilemap_set_scrolldy(TC0480SCP_tilemap[1][0], yd, 256-yd +TC0480SCP_flip_yoffs );
+ tilemap_set_scrolldx(TC0480SCP_tilemap[2][0], xd, 320-xd +TC0480SCP_flip_xoffs );
+ tilemap_set_scrolldy(TC0480SCP_tilemap[2][0], yd, 256-yd +TC0480SCP_flip_yoffs );
+ tilemap_set_scrolldx(TC0480SCP_tilemap[3][0], xd, 320-xd +TC0480SCP_flip_xoffs );
+ tilemap_set_scrolldy(TC0480SCP_tilemap[3][0], yd, 256-yd +TC0480SCP_flip_yoffs );
+ tilemap_set_scrolldx(TC0480SCP_tilemap[4][0], xd-3, 316-xd); /* text layer */
+ tilemap_set_scrolldy(TC0480SCP_tilemap[4][0], yd, 256-yd); /* text layer */
+
+ /* Double width offsets */
+ tilemap_set_scrolldx(TC0480SCP_tilemap[0][1], xd, 320-xd +TC0480SCP_flip_xoffs );
+ tilemap_set_scrolldy(TC0480SCP_tilemap[0][1], yd, 256-yd +TC0480SCP_flip_yoffs );
+ tilemap_set_scrolldx(TC0480SCP_tilemap[1][1], xd, 320-xd +TC0480SCP_flip_xoffs );
+ tilemap_set_scrolldy(TC0480SCP_tilemap[1][1], yd, 256-yd +TC0480SCP_flip_yoffs );
+ tilemap_set_scrolldx(TC0480SCP_tilemap[2][1], xd, 320-xd +TC0480SCP_flip_xoffs );
+ tilemap_set_scrolldy(TC0480SCP_tilemap[2][1], yd, 256-yd +TC0480SCP_flip_yoffs );
+ tilemap_set_scrolldx(TC0480SCP_tilemap[3][1], xd, 320-xd +TC0480SCP_flip_xoffs );
+ tilemap_set_scrolldy(TC0480SCP_tilemap[3][1], yd, 256-yd +TC0480SCP_flip_yoffs );
+ tilemap_set_scrolldx(TC0480SCP_tilemap[4][1], xd-3, 317-xd); /* text layer */
+ tilemap_set_scrolldy(TC0480SCP_tilemap[4][1], yd, 256-yd); /* text layer */
+
+ for (i=0;i<2;i++)
+ {
+ /* Both sets of bg tilemaps scrollable per pixel row */
+ tilemap_set_scroll_rows(TC0480SCP_tilemap[0][i],512);
+ tilemap_set_scroll_rows(TC0480SCP_tilemap[1][i],512);
+ tilemap_set_scroll_rows(TC0480SCP_tilemap[2][i],512);
+ tilemap_set_scroll_rows(TC0480SCP_tilemap[3][i],512);
+ }
+}
+
+READ32_HANDLER( TC0480SCP_ctrl_long_r )
+{
+ return (TC0480SCP_ctrl_word_r(offset*2,0)<<16)|TC0480SCP_ctrl_word_r(offset*2+1,0);
+}
+
+/* TODO: byte access ? */
+
+WRITE32_HANDLER( TC0480SCP_ctrl_long_w )
+{
+ if (ACCESSING_MSW32) TC0480SCP_ctrl_word_w(offset*2,data>>16,mem_mask>>16);
+ if (ACCESSING_LSW32) TC0480SCP_ctrl_word_w((offset*2)+1,data&0xffff,mem_mask&0xffff);
+}
+
+READ32_HANDLER( TC0480SCP_long_r )
+{
+ return (TC0480SCP_word_r(offset*2,0)<<16)|TC0480SCP_word_r(offset*2+1,0);
+}
+
+WRITE32_HANDLER( TC0480SCP_long_w )
+{
+ if (((mem_mask & 0xff000000) == 0) || ((mem_mask & 0x00ff0000) == 0))
+ {
+ int oldword = TC0480SCP_word_r(offset*2,0);
+ int newword = data>>16;
+ if ((mem_mask & 0x00ff0000) != 0)
+ newword |= (oldword &0x00ff);
+ if ((mem_mask & 0xff000000) != 0)
+ newword |= (oldword &0xff00);
+ TC0480SCP_word_w(offset*2,newword,0);
+ }
+ if (((mem_mask & 0x0000ff00) == 0) || ((mem_mask & 0x000000ff) == 0))
+ {
+ int oldword = TC0480SCP_word_r((offset*2)+1,0);
+ int newword = data&0xffff;
+ if ((mem_mask & 0x000000ff) != 0)
+ newword |= (oldword &0x00ff);
+ if ((mem_mask & 0x0000ff00) != 0)
+ newword |= (oldword &0xff00);
+ TC0480SCP_word_w((offset*2)+1,newword,0);
+ }
+}
+
+READ16_HANDLER( TC0480SCP_word_r )
+{
+ return TC0480SCP_ram[offset];
+}
+
+static void TC0480SCP_word_write(offs_t offset,UINT16 data,UINT32 mem_mask)
+{
+ COMBINE_DATA(&TC0480SCP_ram[offset]);
+
+ if (!TC0480SCP_dblwidth)
+ {
+ if (offset < 0x2000)
+ {
+ tilemap_mark_tile_dirty(TC0480SCP_tilemap[(offset /
+ 0x800)][TC0480SCP_dblwidth],((offset % 0x800) / 2));
+ }
+ else if (offset < 0x6000)
+ { /* do nothing */
+ }
+ else if (offset < 0x7000)
+ {
+ tilemap_mark_tile_dirty(TC0480SCP_tilemap[4][TC0480SCP_dblwidth],
+ (offset - 0x6000));
+ }
+ else if (offset <= 0x7fff)
+ {
+ TC0480SCP_char_dirty[(offset - 0x7000) / 16] = 1;
+ TC0480SCP_chars_dirty = 1;
+ }
+ }
+ else
+ {
+ if (offset < 0x4000)
+ {
+ tilemap_mark_tile_dirty(TC0480SCP_tilemap[(offset /
+ 0x1000)][TC0480SCP_dblwidth],((offset % 0x1000) / 2));
+ }
+ else if (offset < 0x6000)
+ { /* do nothing */
+ }
+ else if (offset < 0x7000)
+ {
+ tilemap_mark_tile_dirty(TC0480SCP_tilemap[4][TC0480SCP_dblwidth],
+ (offset - 0x6000));
+ }
+ else if (offset <= 0x7fff)
+ {
+ TC0480SCP_char_dirty[(offset - 0x7000) / 16] = 1;
+ TC0480SCP_chars_dirty = 1;
+ }
+ }
+}
+
+WRITE16_HANDLER( TC0480SCP_word_w )
+{
+ TC0480SCP_word_write(offset,data,mem_mask);
+}
+
+READ16_HANDLER( TC0480SCP_ctrl_word_r )
+{
+ return TC0480SCP_ctrl[offset];
+}
+
+static void TC0480SCP_ctrl_word_write(offs_t offset,UINT16 data,UINT32 mem_mask)
+{
+ int flip = TC0480SCP_pri_reg & 0x40;
+
+ COMBINE_DATA(&TC0480SCP_ctrl[offset]);
+ data = TC0480SCP_ctrl[offset];
+
+ switch( offset )
+ {
+ /* The x offsets of the four bg layers are staggered by intervals of 4 pixels */
+
+ case 0x00: /* bg0 x */
+ if (!flip) data = -data;
+ TC0480SCP_bgscrollx[0] = data;
+ break;
+
+ case 0x01: /* bg1 x */
+ data += 4;
+ if (!flip) data = -data;
+ TC0480SCP_bgscrollx[1] = data;
+ break;
+
+ case 0x02: /* bg2 x */
+ data += 8;
+ if (!flip) data = -data;
+ TC0480SCP_bgscrollx[2] = data;
+ break;
+
+ case 0x03: /* bg3 x */
+ data += 12;
+ if (!flip) data = -data;
+ TC0480SCP_bgscrollx[3] = data;
+ break;
+
+ case 0x04: /* bg0 y */
+ if (flip) data = -data;
+ TC0480SCP_bgscrolly[0] = data;
+ break;
+
+ case 0x05: /* bg1 y */
+ if (flip) data = -data;
+ TC0480SCP_bgscrolly[1] = data;
+ break;
+
+ case 0x06: /* bg2 y */
+ if (flip) data = -data;
+ TC0480SCP_bgscrolly[2] = data;
+ break;
+
+ case 0x07: /* bg3 y */
+ if (flip) data = -data;
+ TC0480SCP_bgscrolly[3] = data;
+ break;
+
+ case 0x08: /* bg0 zoom */
+ case 0x09: /* bg1 zoom */
+ case 0x0a: /* bg2 zoom */
+ case 0x0b: /* bg3 zoom */
+ break;
+
+ case 0x0c: /* fg (text) x */
+
+ /* Text layer can be offset from bg0 (e.g. Metalb) */
+ if (!flip) data -= TC0480SCP_text_xoffs;
+ if (flip) data += TC0480SCP_text_xoffs;
+
+ tilemap_set_scrollx(TC0480SCP_tilemap[4][0], 0, -data);
+ tilemap_set_scrollx(TC0480SCP_tilemap[4][1], 0, -data);
+ break;
+
+ case 0x0d: /* fg (text) y */
+
+ /* Text layer can be offset from bg0 (e.g. Slapshot) */
+ if (!flip) data -= TC0480SCP_text_yoffs;
+ if (flip) data += TC0480SCP_text_yoffs;
+
+ tilemap_set_scrolly(TC0480SCP_tilemap[4][0], 0, -data);
+ tilemap_set_scrolly(TC0480SCP_tilemap[4][1], 0, -data);
+ break;
+
+ /* offset 0x0e unused */
+
+ case 0x0f: /* control register */
+ {
+ int old_width = (TC0480SCP_pri_reg &0x80) >> 7;
+ flip = (data & 0x40) ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0;
+ TC0480SCP_pri_reg = data;
+
+ tilemap_set_flip(TC0480SCP_tilemap[0][0],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[1][0],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[2][0],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[3][0],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[4][0],flip);
+
+ tilemap_set_flip(TC0480SCP_tilemap[0][1],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[1][1],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[2][1],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[3][1],flip);
+ tilemap_set_flip(TC0480SCP_tilemap[4][1],flip);
+
+ TC0480SCP_dblwidth = (TC0480SCP_pri_reg &0x80) >> 7;
+
+ if (TC0480SCP_dblwidth != old_width) /* tilemap width is changing */
+ {
+ /* Reinitialise layer pointers */
+ TC0480SCP_set_layer_ptrs();
+
+ /* and ensure full redraw of tilemaps */
+ TC0480SCP_dirty_tilemaps();
+ }
+
+ break;
+ }
+
+ /* Rest are layer specific delta x and y, used while scrolling that layer */
+ }
+}
+
+
+
+WRITE16_HANDLER( TC0480SCP_ctrl_word_w )
+{
+ TC0480SCP_ctrl_word_write(offset,data,mem_mask);
+}
+
+void TC0480SCP_tilemap_update(running_machine *machine)
+{
+ int layer, zoom, i, j;
+ int flip = TC0480SCP_pri_reg & 0x40;
+
+ for (layer = 0; layer < 4; layer++)
+ {
+ tilemap_set_scrolly(TC0480SCP_tilemap[layer][TC0480SCP_dblwidth],0,TC0480SCP_bgscrolly[layer]);
+ zoom = 0x10000 + 0x7f - TC0480SCP_ctrl[0x08 + layer];
+
+ if (zoom != 0x10000) /* can't use scroll rows when zooming */
+ {
+ tilemap_set_scrollx(TC0480SCP_tilemap[layer][TC0480SCP_dblwidth],
+ 0, TC0480SCP_bgscrollx[layer]);
+ }
+ else
+ {
+ for (j = 0;j < 512;j++)
+ {
+ i = TC0480SCP_bgscroll_ram[layer][j];
+
+ if (!flip)
+ tilemap_set_scrollx(TC0480SCP_tilemap[layer][TC0480SCP_dblwidth],
+ j & 0x1ff,
+ TC0480SCP_bgscrollx[layer] - i);
+ if (flip)
+ tilemap_set_scrollx(TC0480SCP_tilemap[layer][TC0480SCP_dblwidth],
+ j & 0x1ff,
+ TC0480SCP_bgscrollx[layer] + i);
+ }
+ }
+ }
+
+ /* Decode any characters that have changed */
+ if (TC0480SCP_chars_dirty)
+ {
+ int tile_index;
+
+ for (tile_index = 0;tile_index < 64*64;tile_index++)
+ {
+ int attr = TC0480SCP_tx_ram[tile_index];
+ if (TC0480SCP_char_dirty[attr & 0xff])
+ tilemap_mark_tile_dirty(TC0480SCP_tilemap[4][TC0480SCP_dblwidth],tile_index);
+ }
+
+ for (j = 0;j < TC0480SCP_TOTAL_CHARS;j++)
+ {
+ if (TC0480SCP_char_dirty[j])
+ decodechar(machine->gfx[TC0480SCP_tx_gfx],j,
+ (UINT8 *)TC0480SCP_char_ram,&TC0480SCP_charlayout);
+ TC0480SCP_char_dirty[j] = 0;
+ }
+ TC0480SCP_chars_dirty = 0;
+ }
+}
+
+
+/*********************************************************************
+ BG0,1 LAYER DRAW
+
+TODO
+----
+
+Broken for any rotation except ROT0. ROT180 support could probably
+be added without too much difficulty: machine_flip is there as a
+place-holder for this purpose.
+
+Wouldn't work if y needs to be > 255 (i.e. if some game uses a
+bigger than usual vertical visible area). Refer to TC0080VCO
+custom draw routine for an example of dealing with this.
+
+
+Historical Issues
+-----------------
+
+1) bg layers got too far left and down, the greater the magnification.
+ Largely fixed by adding offsets (to sx&y) which get bigger as we
+ zoom in (why we have *zoomx and *zoomy in the calculations).
+
+2) Hthero and Footchmp bg layers behaved differently when zoomed.
+ Fixed by bringing tc0480scp_x&y_offs into calculations.
+
+3) Metalb "TAITO" text in attract too far to the right. Fixed by
+ bringing (layer*4) into offset calculations. But might be possible
+ to avoid this by stepping the scroll deltas for the four layers -
+ currently they are the same, and we have to kludge the offsets in
+ TC0480SCP_ctrl_word_write.
+
+4) Zoom movement was jagged: improved by bringing in scroll delta
+ values... but the results are noticably imperfect.
+
+**********************************************************************/
+
+static void TC0480SCP_bg01_draw(mame_bitmap *bitmap,const rectangle *cliprect,int layer,int flags,UINT32 priority)
+{
+ /* X-axis zoom offers expansion only: 0 = no zoom, 0xff = max
+ Y-axis zoom offers expansion/compression: 0x7f = no zoom, 0xff = max
+ (0x1a in Footchmp hiscore = shrunk) */
+
+ int zoomx = 0x10000 - (TC0480SCP_ctrl[0x08 + layer] &0xff00);
+ int zoomy = 0x10000 - (((TC0480SCP_ctrl[0x08 + layer] &0xff) - 0x7f) * 512);
+
+ if ((zoomx == 0x10000) && (zoomy == 0x10000)) /* no zoom, simple */
+ {
+ /* Prevent bad things */
+ tilemap_draw(bitmap,cliprect,TC0480SCP_tilemap[layer][TC0480SCP_dblwidth],flags,priority);
+ }
+ else /* zoom */
+ {
+ UINT16 *dst16,*src16;
+ UINT8 *tsrc;
+ UINT16 scanline[512];
+ UINT32 sx;
+ mame_bitmap *srcbitmap = tilemap_get_pixmap(TC0480SCP_tilemap[layer][TC0480SCP_dblwidth]);
+ mame_bitmap *flagsbitmap = tilemap_get_flagsmap
+ (TC0480SCP_tilemap[layer][TC0480SCP_dblwidth]);
+ int flip = TC0480SCP_pri_reg & 0x40;
+ int i,y,y_index,src_y_index,row_index;
+ int x_index,x_step;
+ int machine_flip = 0; /* for ROT 180 ? */
+
+ UINT16 screen_width = 512; //cliprect->max_x - cliprect->min_x + 1;
+ UINT16 min_y = cliprect->min_y;
+ UINT16 max_y = cliprect->max_y;
+
+ int width_mask=0x1ff;
+ if (TC0480SCP_dblwidth) width_mask=0x3ff;
+
+
+ if (!flip)
+ {
+ sx = ((TC0480SCP_bgscrollx[layer] + 15 + layer*4) << 16)
+ + ((255-(TC0480SCP_ctrl[0x10 + layer] & 0xff)) << 8);
+ sx += (TC0480SCP_x_offs - 15 - layer*4) * zoomx;
+
+ y_index = (TC0480SCP_bgscrolly[layer] << 16)
+ + ((TC0480SCP_ctrl[0x14 + layer] & 0xff) << 8);
+ y_index -= (TC0480SCP_y_offs - min_y) * zoomy;
+ }
+ else /* TC0480SCP tiles flipscreen */
+ {
+ sx = ((-TC0480SCP_bgscrollx[layer] + 15 + layer*4 + TC0480SCP_flip_xoffs ) << 16)
+ + ((255-(TC0480SCP_ctrl[0x10 + layer] & 0xff)) << 8);
+ sx += (TC0480SCP_x_offs - 15 - layer*4) * zoomx;
+
+ y_index = ((-TC0480SCP_bgscrolly[layer] + TC0480SCP_flip_yoffs) << 16)
+ + ((TC0480SCP_ctrl[0x14 + layer] & 0xff) << 8);
+ y_index -= (TC0480SCP_y_offs - min_y) * zoomy;
+ }
+
+
+ if (!machine_flip) y=min_y; else y=max_y;
+
+ do
+ {
+ src_y_index = (y_index>>16) &0x1ff;
+
+ /* row areas are the same in flipscreen, so we must read in reverse */
+ row_index = src_y_index;
+ if (flip) row_index = 0x1ff - row_index;
+
+ x_index = sx - ((TC0480SCP_bgscroll_ram[layer][row_index] << 16))
+ - ((TC0480SCP_bgscroll_ram[layer][row_index+0x800] << 8) &0xffff);
+
+ src16 = BITMAP_ADDR16(srcbitmap, src_y_index, 0);
+ tsrc = BITMAP_ADDR8(flagsbitmap, src_y_index, 0);
+ dst16 = scanline;
+
+ x_step = zoomx;
+
+ if (flags & TILEMAP_DRAW_OPAQUE)
+ {
+ for (i=0; i<screen_width; i++)
+ {
+ *dst16++ = src16[(x_index >> 16) &width_mask];
+ x_index += x_step;
+ }
+ }
+ else
+ {
+ for (i=0; i<screen_width; i++)
+ {
+ if (tsrc[(x_index >> 16) &width_mask])
+ *dst16++ = src16[(x_index >> 16) &width_mask];
+ else
+ *dst16++ = 0x8000;
+ x_index += x_step;
+ }
+ }
+
+ if (flags & TILEMAP_DRAW_OPAQUE)
+ taitoic_drawscanline(bitmap,0,y,scanline,0,ROT0,priority,cliprect);
+ else
+ taitoic_drawscanline(bitmap,0,y,scanline,1,ROT0,priority,cliprect);
+
+ y_index += zoomy;
+ if (!machine_flip) y++; else y--;
+ }
+ while ( (!machine_flip && y<=max_y) || (machine_flip && y>=min_y) );
+
+ }
+}
+
+
+/****************************************************************
+ BG2,3 LAYER DRAW
+
+TODO
+----
+
+Broken for any rotation except ROT0. ROT180 support could probably
+be added without too much difficulty: machine_flip is there as a
+place-holder for this purpose.
+
+Wouldn't work if y needs to be > 255 (i.e. if some game uses a
+bigger than usual vertical visible area). Refer to TC0080VCO
+custom draw routine for an example of dealing with this.
+
+Low order words for overall layer zoom are not really understood.
+In Metalbj initial text screen zoom you can see they ARE words
+(not separate bytes); however, I just use the low byte to smooth
+the zooming sequences. This is noticeably imperfect on the Y axis.
+
+Verify behaviour of Taito logo (Gunbustr) against real machine
+to perfect the row zoom emulation.
+
+What do high bytes of row zoom do - if anything - in UndrFire?
+There is still jaggedness to the road in this game and Superchs.
+
+
+Historical Issues
+-----------------
+
+Sometimes BG2/3 were misaligned by 1 pixel horizontally: this
+was due to low order byte of 0 causing different (sx >> 16) than
+when it was 1-255. To prevent this we use (255-byte) so
+(sx >> 16) no longer depends on the low order byte.
+
+In flipscreen we have to bring in extra offsets, since various
+games don't have exactly (320-,256-) tilemap scroll deltas in
+flipscreen.
+
+****************************************************************/
+
+static void TC0480SCP_bg23_draw(mame_bitmap *bitmap,const rectangle *cliprect,int layer,int flags,UINT32 priority)
+{
+ mame_bitmap *srcbitmap = tilemap_get_pixmap(TC0480SCP_tilemap[layer][TC0480SCP_dblwidth]);
+ mame_bitmap *flagsbitmap = tilemap_get_flagsmap
+ (TC0480SCP_tilemap[layer][TC0480SCP_dblwidth]);
+
+ UINT16 *dst16,*src16;
+ UINT8 *tsrc;
+ int i,y,y_index,src_y_index,row_index,row_zoom;
+ int sx,x_index,x_step;
+ UINT32 zoomx,zoomy;
+ UINT16 scanline[512];
+ int flipscreen = TC0480SCP_pri_reg & 0x40;
+ int machine_flip = 0; /* for ROT 180 ? */
+
+ UINT16 screen_width = 512; //cliprect->max_x - cliprect->min_x + 1;
+ UINT16 min_y = cliprect->min_y;
+ UINT16 max_y = cliprect->max_y;
+
+ int width_mask=0x1ff;
+ if (TC0480SCP_dblwidth) width_mask=0x3ff;
+
+ /* X-axis zoom offers expansion only: 0 = no zoom, 0xff = max
+ Y-axis zoom offers expansion/compression: 0x7f = no zoom, 0xff = max
+ (0x1a in Footchmp hiscore = shrunk) */
+
+ zoomx = 0x10000 - (TC0480SCP_ctrl[0x08 + layer] &0xff00);
+ zoomy = 0x10000 - (((TC0480SCP_ctrl[0x08 + layer] &0xff) - 0x7f) * 512);
+
+ if (!flipscreen)
+ {
+ sx = ((TC0480SCP_bgscrollx[layer] + 15 + layer*4) << 16)
+ + ((255-(TC0480SCP_ctrl[0x10 + layer] & 0xff)) << 8);
+ sx += (TC0480SCP_x_offs - 15 - layer*4) * zoomx;
+
+ y_index = (TC0480SCP_bgscrolly[layer] << 16)
+ + ((TC0480SCP_ctrl[0x14 + layer] & 0xff) << 8);
+ y_index -= (TC0480SCP_y_offs - min_y) * zoomy;
+ }
+ else /* TC0480SCP tiles flipscreen */
+ {
+ sx = ((-TC0480SCP_bgscrollx[layer] + 15 + layer*4 + TC0480SCP_flip_xoffs ) << 16)
+ + ((255-(TC0480SCP_ctrl[0x10 + layer] & 0xff)) << 8);
+ sx += (TC0480SCP_x_offs - 15 - layer*4) * zoomx;
+
+ y_index = ((-TC0480SCP_bgscrolly[layer] + TC0480SCP_flip_yoffs) << 16)
+ + ((TC0480SCP_ctrl[0x14 + layer] & 0xff) << 8);
+ y_index -= (TC0480SCP_y_offs - min_y) * zoomy;
+ }
+
+
+ if (!machine_flip) y=min_y; else y=max_y;
+
+ do
+ {
+ if (!flipscreen)
+ src_y_index = ((y_index>>16) + TC0480SCP_bgcolumn_ram[layer][(y -
+ TC0480SCP_y_offs) &0x1ff]) &0x1ff;
+ else /* colscroll area is back to front in flipscreen */
+ src_y_index = ((y_index>>16) + TC0480SCP_bgcolumn_ram[layer][0x1ff -
+ ((y - TC0480SCP_y_offs) &0x1ff)]) &0x1ff;
+
+ /* row areas are the same in flipscreen, so we must read in reverse */
+ row_index = src_y_index;
+ if (flipscreen) row_index = 0x1ff - row_index;
+
+ if (TC0480SCP_pri_reg & (layer-1)) /* bit0 enables for BG2, bit1 for BG3 */
+ row_zoom = TC0480SCP_rowzoom_ram[layer][row_index];
+ else
+ row_zoom = 0;
+
+ x_index = sx - ((TC0480SCP_bgscroll_ram[layer][row_index] << 16))
+ - ((TC0480SCP_bgscroll_ram[layer][row_index+0x800] << 8) &0xffff);
+
+ /* flawed calc ?? */
+ x_index -= (TC0480SCP_x_offs - 0x1f + layer*4) * ((row_zoom &0xff) << 8);
+
+/* We used to kludge 270 multiply factor, before adjusting x_index instead */
+
+ x_step = zoomx;
+ if (row_zoom) /* need to reduce x_step */
+ {
+ if (!(row_zoom &0xff00))
+ x_step -= ((row_zoom * 256) &0xffff);
+ else /* Undrfire uses the hi byte, why? */
+ x_step -= (((row_zoom &0xff) * 256) &0xffff);
+ }
+
+ src16 = BITMAP_ADDR16(srcbitmap, src_y_index, 0);
+ tsrc = BITMAP_ADDR8(flagsbitmap, src_y_index, 0);
+ dst16 = scanline;
+
+ if (flags & TILEMAP_DRAW_OPAQUE)
+ {
+ for (i=0; i<screen_width; i++)
+ {
+ *dst16++ = src16[(x_index >> 16) &width_mask];
+ x_index += x_step;
+ }
+ }
+ else
+ {
+ for (i=0; i<screen_width; i++)
+ {
+ if (tsrc[(x_index >> 16) &width_mask])
+ *dst16++ = src16[(x_index >> 16) &width_mask];
+ else
+ *dst16++ = 0x8000;
+ x_index += x_step;
+ }
+ }
+
+ if (flags & TILEMAP_DRAW_OPAQUE)
+ taitoic_drawscanline(bitmap,0,y,scanline,0,ROT0,priority,cliprect);
+ else
+ taitoic_drawscanline(bitmap,0,y,scanline,1,ROT0,priority,cliprect);
+
+ y_index += zoomy;
+ if (!machine_flip) y++; else y--;
+ }
+ while ( (!machine_flip && y<=max_y) || (machine_flip && y>=min_y) );
+
+}
+
+
+
+void TC0480SCP_tilemap_draw(mame_bitmap *bitmap,const rectangle *cliprect,int layer,int flags,UINT32 priority)
+{
+ /* no layer disable bits */
+
+ switch (layer)
+ {
+ case 0:
+ TC0480SCP_bg01_draw(bitmap,cliprect,0,flags,priority);
+ break;
+ case 1:
+ TC0480SCP_bg01_draw(bitmap,cliprect,1,flags,priority);
+ break;
+ case 2:
+ TC0480SCP_bg23_draw(bitmap,cliprect,2,flags,priority);
+ break;
+ case 3:
+ TC0480SCP_bg23_draw(bitmap,cliprect,3,flags,priority);
+ break;
+ case 4:
+ tilemap_draw(bitmap,cliprect,TC0480SCP_tilemap[4][TC0480SCP_dblwidth],flags,priority);
+ break;
+ }
+}
+
+/* For evidence table of TC0480SCP bg layer priorities, refer to mame55 source */
+
+static UINT16 TC0480SCP_bg_pri_lookup[8] =
+{
+ 0x0123,
+ 0x1230,
+ 0x2301,
+ 0x3012,
+ 0x3210,
+ 0x2103,
+ 0x1032,
+ 0x0321
+};
+
+int TC0480SCP_get_bg_priority(void)
+{
+ return TC0480SCP_bg_pri_lookup[(TC0480SCP_pri_reg &0x1c) >> 2];
+}
+
+
+/****************************************************************
+ TC0150ROD
+****************************************************************/
+
+static UINT16 *TC0150ROD_ram;
+#define TC0150ROD_RAM_SIZE 0x2000
+
+READ16_HANDLER( TC0150ROD_word_r )
+{
+ return TC0150ROD_ram[offset];
+}
+
+WRITE16_HANDLER( TC0150ROD_word_w )
+{
+ COMBINE_DATA(&TC0150ROD_ram[offset]);
+}
+
+void TC0150ROD_vh_start(void)
+{
+ TC0150ROD_ram = auto_malloc(TC0150ROD_RAM_SIZE);
+
+ state_save_register_global_pointer(TC0150ROD_ram, TC0150ROD_RAM_SIZE/2);
+}
+
+
+/******************************************************************************
+
+ Memory map for TC0150ROD
+ ------------------------
+
+ 0000-07ff Road A, bank 0 [all are 256 lines]
+ 0800-0fff Road A, bank 1
+ 1000-17ff Road B, bank 0
+ 1800-1fff Road B, bank 1
+
+ 1ffe-1fff Control word
+ ........ xxxxxxxx Screen line where priority changes
+ ......xx ........ Road A RAM page
+ ....xx.. ........ Road B RAM page
+ 0000.... ........ Not used?
+
+
+
+ Road ram line layout (thanks to Raine for original table)
+ --------------------
+
+ -----+-----------------+----------------------------------------
+ Word | Bit(s) | Info
+ -----+-----------------+----------------------------------------
+ 0 |x....... ........| Draw background behind left road edge
+ 0 |.x...... ........| Left road edge from road A has priority over road B ?? (+)
+ 0 |..x..... ........| Left road edge from road A has priority over road B ?? (*)
+ 0 |...xx... ........| Left edge/background palette entry offset
+ 0 |......xx xxxxxxxx| Left edge [pixels from road center] (@)
+ | |
+ 1 |x....... ........| Draw background behind right road edge
+ 1 |.x...... ........| Right road edge from road A has priority over road B ??
+ 1 |..x..... ........| Right road edge from road A has priority over road B ?? (*)
+ 1 |...xx... ........| Right edge/background palette entry offset
+ 1 |......xx xxxxxxxx| Right edge [pixels from road center] (@)
+ | |
+ 2 |x....... ........| Draw background behind road body
+ 2 |.x...... ........| Road line body from Road A has higher priority than Road B ??
+ 2 |..x..... ........| Road line body from Road A has higher priority than Road B ??
+ 2 |...xx... ........| Body/background palette entry offset
+ 2 |.....xxx xxxxxxxx| X Offset [offset is inverted] (^)
+ | |
+ 3 |xxxx.... ........| Color Bank (selects group of 4 palette entries used for line)
+ 3 |....xxxx xxxxxxxx| Road Gfx Tile number (top 2 bits not used by any game)
+ -----+-----------------+-----------------------------------------
+
+ @ size of bitmask suggested by Nightstr stage C when boss appears
+ ^ bitmask confirmed in ChaseHQ code
+
+ * see Nightstr "stage choice tunnel"
+ + see Contcirc track at race start
+
+ These priority bits have a different meaning in road B ram. They appear to mean
+ that the relevant part of road B slips under road A. I.e. in road A they raise
+ priority, in road B they lower it.
+
+ We need a screenshot of Nightstr "stage choice tunnel" showing exactly what effect
+ happens at top and bottom of screen while tunnel bifurcates.
+
+
+Priority Levels - used by this code to represent the way the TC0150ROD appears to work
+---------------
+
+To speed up the code, three bits in the existing pixel-color map are used to store
+priority information:
+
+x....... ........ = transparency
+.xxx.... ........ = pixel priority
+....xxxx xxxxxxxx = pixel pen
+
+There's a problem if any TaitoZ games using twice the palette space turn
+up that also use TC0150ROD. This seems unlikely.
+
+Pixel priority levels
+---------------------
+0 = bottom (used for off-edge i.e. background)
+1,2,3,4 = ascending priority levels
+
+
+Priority bits refer to: (edge a, body a, edge b, body b)
+
+Standard: bits=(0,0,0,0)
+ edge a, body a, edge b, body b
+ 1 2 3 4
+
+Contcirc: bits=(0,1,0,0) (body a up by 2)
+ edge a, edge b, body b, body a
+ 1 3 4 4
+
+Nightstr bottom half: bits=(0,1,1,0) (Contcirc PLUS edge b down by 2)
+ edge b, edge a, body b, body a
+ 1 1 4 4
+
+Nightstr top half: bits=(1,0,0,1) (edge b down by 1, body a up by 1)
+ edge a, edge b, body a, body b
+ 1 2 3 4
+
+When numbers are the same, A goes on top...
+
+These may need revising once Nightstr / Contcirc screenshots showing road
+intersections are obtained.
+
+
+
+Road info
+---------
+
+Road gfx is 2bpp, each word holds 8 pixels in this format:
+xxxxxxxx ........ lo 8 bits
+........ xxxxxxxx hi 8 bits
+
+The line gfx is back to front: this is why we call 'left' 'right' and vice versa in
+this code: when the pixels are poked in they are done in reverse order, restoring
+the orientation.
+
+Each road gfx tile is 0x200 long in the rom. This comprises TWO road lines each
+of 1024x1 pixels.
+
+The first is the "edge" graphic. The second is the road body graphic. This means
+separate sets of colors can be used for road edge and road body, giving greater
+color variety.
+
+The edge graphic is stored with the edges touching each other. So we must pull LHS
+and RHS out separately to draw them.
+
+Gfx lines: generally 0-0x1ff are the standard group (higher tile number indexes
+wider lines). However this is just the way the games are: NOT a function of the
+TC0150ROD.
+
+Proof of background palette entry offset is in Contcirc in the tunnel on
+Monaco level, the flyer screenshot shows different background colors on left
+and right.
+
+To investigate the weird road A/B priority system look at Nightstr and also
+Contcirc. Contcirc: the "pit entry lane" in road B looks completely wrong if it is
+allowed on top of road A body.
+
+Aquajack road requires correct bank selection, or it goes crazy.
+
+Should pen0 in Road A body be transparent? It seems necessary for Bshark round 6
+and it makes Aquajack roads look much better. However, in Nightstr stage C
+this results in a black band in the middle of the water. Also, it leaves
+transparent areas in Dblaxle road which look obviously wrong. For time being a
+parameter has been added to select which games use the transparency.
+
+TODO
+----
+
+Contcirc: is road really meant to be so ugly when going uphill?
+
+ChaseHQ: take right fork on level 1, at either edge of road you can see black
+edge. Not obvious what is going wrong here. What color is it meant to be?
+
+Nightstr: is the choice tunnel split correct? Need verification from machine.
+
+Dblaxle: some stray background lines at top of road on occasional frames.
+
+Sprite/road Y positions sometimes don't match. Maybe we need to use a zoom
+lookup table from rom for the TaitoZ sprites.
+
+
+******************************************************************************/
+
+void TC0150ROD_draw(mame_bitmap *bitmap,const rectangle *cliprect,int y_offs,int palette_offs,int type,int road_trans,UINT32 low_priority,UINT32 high_priority)
+{
+#ifdef MAME_DEBUG
+ static int dislayer[6]; /* Road Layer toggles to help get road correct */
+#endif
+
+ int x_offs = 0xa7; /* Increasing this shifts road to right */
+ UINT16 scanline[512];
+ UINT16 roada_line[512],roadb_line[512];
+ UINT16 *dst16;
+ UINT16 *roada,*roadb;
+ UINT16 *roadgfx = (UINT16 *)memory_region(REGION_GFX3);
+
+ UINT16 pixel,color,gfx_word;
+ UINT16 roada_clipl,roada_clipr,roada_bodyctrl;
+ UINT16 roadb_clipl,roadb_clipr,roadb_bodyctrl;
+ UINT16 pri,pixpri;
+ UINT8 priorities[6];
+ int x_index,roadram_index,roadram2_index,i;
+ int xoffset,paloffs,palloffs,palroffs;
+ int road_gfx_tilenum,colbank,road_center;
+ int road_ctrl = TC0150ROD_ram[0xfff];
+ int left_edge,right_edge,begin,end,right_over,left_over;
+ int line_needs_drawing,draw_top_road_line,background_only;
+
+ int min_x = cliprect->min_x;
+ int max_x = cliprect->max_x;
+ int min_y = cliprect->min_y;
+ int max_y = cliprect->max_y;
+ int screen_width = max_x - min_x + 1;
+
+ int y = min_y;
+
+ int twin_road = 0;
+
+ int road_A_address = y_offs * 4 + ((road_ctrl & 0x0300) << 2); /* Index into roadram for road A */
+ int road_B_address = y_offs * 4 + ((road_ctrl & 0x0c00) << 0); /* Index into roadram for road B */
+
+ int priority_switch_line = (road_ctrl & 0x00ff) - y_offs;
+
+#ifdef MAME_DEBUG
+ if (input_code_pressed_once (KEYCODE_X))
+ {
+ dislayer[0] ^= 1;
+ popmessage("RoadA body: %01x",dislayer[0]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_C))
+ {
+ dislayer[1] ^= 1;
+ popmessage("RoadA l-edge: %01x",dislayer[1]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_V))
+ {
+ dislayer[2] ^= 1;
+ popmessage("RoadA r-edge: %01x",dislayer[2]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_B))
+ {
+ dislayer[3] ^= 1;
+ popmessage("RoadB body: %01x",dislayer[3]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_N))
+ {
+ dislayer[4] ^= 1;
+ popmessage("RoadB l-edge: %01x",dislayer[4]);
+ }
+ if (input_code_pressed_once (KEYCODE_M))
+ {
+ dislayer[5] ^= 1;
+ popmessage("RoadB r-edge: %01x",dislayer[5]);
+ }
+#endif
+
+#if 0
+ if (1)
+ {
+ char buf3[80];
+ sprintf(buf3,"road control: %04x",road_ctrl);
+ popmessage(buf3);
+ }
+#endif
+
+ do
+ {
+ line_needs_drawing = 0;
+
+ roadram_index = road_A_address + y * 4; /* in case there is some switching mechanism (unlikely) */
+ roadram2_index = road_B_address + y * 4;
+
+ roada = roada_line;
+ roadb = roadb_line;
+
+ for (i=0;i<screen_width;i++) /* Default transparency fill */
+ {
+ *roada++ = 0x8000;
+ *roadb++ = 0x8000;
+ }
+
+ /* l-edge a, r-edge a, body a, l-edge b, r-edge-b, body b */
+ priorities[0] = 1;
+ priorities[1] = 1;
+ priorities[2] = 2;
+ priorities[3] = 3;
+ priorities[4] = 3;
+ priorities[5] = 4;
+
+ roada_clipr = TC0150ROD_ram[roadram_index];
+ roada_clipl = TC0150ROD_ram[roadram_index+1];
+ roada_bodyctrl = TC0150ROD_ram[roadram_index+2];
+ roadb_clipr = TC0150ROD_ram[roadram2_index];
+ roadb_clipl = TC0150ROD_ram[roadram2_index+1];
+ roadb_bodyctrl = TC0150ROD_ram[roadram2_index+2];
+
+ /* Not very logical, but seems to work */
+ if (roada_bodyctrl & 0x2000) priorities[2] += 2;
+ if (roadb_bodyctrl & 0x2000) priorities[2] += 1;
+ if (roada_clipl & 0x2000) priorities[3] -= 1;
+ if (roadb_clipl & 0x2000) priorities[3] -= 2;
+ if (roada_clipr & 0x2000) priorities[4] -= 1;
+ if (roadb_clipr & 0x2000) priorities[4] -= 2;
+
+ if (priorities[4] == 0) priorities[4]++; /* Fixes Aquajack LH edge dropping below background */
+
+ if ((roada_bodyctrl &0x8000) || (roadb_bodyctrl &0x8000))
+ twin_road ++;
+
+ /********************************************************/
+ /* ROAD A */
+ /********************************************************/
+
+ palroffs =(roada_clipr &0x1000) >> 11;
+ palloffs =(roada_clipl &0x1000) >> 11;
+ xoffset = roada_bodyctrl &0x7ff;
+ paloffs =(roada_bodyctrl &0x1800) >> 11;
+ colbank =(TC0150ROD_ram[roadram_index+3] &0xf000) >> 10;
+ road_gfx_tilenum = TC0150ROD_ram[roadram_index+3] &0x3ff;
+ right_over = 0;
+ left_over = 0;
+
+ road_center = 0x5ff - ((-xoffset + x_offs) &0x7ff);
+ left_edge = road_center - (roada_clipl &0x3ff); /* start pixel for left edge */
+ right_edge = road_center + 1 + (roada_clipr &0x3ff); /* start pixel for right edge */
+
+ if ((roada_clipl) || (roada_clipr)) line_needs_drawing = 1;
+
+ /* Main road line is drawn from 'begin' to 'end'-1 */
+
+ begin = left_edge + 1;
+ if (begin < 0)
+ {
+ begin = 0; /* can't begin off edge of screen */
+ }
+
+ end = right_edge;
+ if (end > screen_width)
+ {
+ end = screen_width; /* can't end off edge of screen */
+ }
+
+ /* We need to offset start pixel we draw for road edge when edge of
+ road is partially or wholly offscreen on the opposite side
+ e.g. Contcirc attract */
+
+ if (right_edge < 0)
+ {
+ right_over = -right_edge;
+ right_edge = 0;
+ }
+ if (left_edge >= screen_width)
+ {
+ left_over = left_edge - screen_width + 1;
+ left_edge = screen_width - 1;
+ }
+
+ /* If road is way off to right we only need to plot background */
+ background_only = (road_center > (screen_width - 2 + 1024/2)) ? 1 : 0;
+
+
+ /********* Draw main part of road *********/
+
+ color = ((palette_offs + colbank + paloffs) << 4) + ((type) ? (1) : (4));
+ pri = priorities[2] << 12;
+
+#ifdef MAME_DEBUG
+ if (!dislayer[0])
+#endif
+ {
+ /* Is this calculation imperfect ? (0xa0 = screen width/2) */
+ x_index = (-xoffset + x_offs + begin) &0x7ff;
+
+ roada = roada_line + screen_width - 1 - begin;
+
+ if ((line_needs_drawing) && (begin < end))
+ {
+ for (i=begin; i<end; i++)
+ {
+ if (road_gfx_tilenum) /* fixes Nightstr round C */
+ {
+ gfx_word = roadgfx[(road_gfx_tilenum << 8) + (x_index >> 3)];
+ pixel = ((gfx_word >> (7-(x_index % 8) + 8)) &0x1) * 2 + ((gfx_word >> (7-(x_index % 8))) &0x1);
+
+ if ((pixel) || !(road_trans))
+ {
+ if (type) pixel = (pixel-1)&3;
+ *roada-- = (color + pixel) | pri;
+ }
+ else *roada-- = 0xf000; /* priority transparency, fixes Bshark round 6 + Aquajack */
+ }
+ else roada--;
+
+ x_index++;
+ x_index &= 0x7ff;
+ }
+ }
+ }
+
+
+ /********* Draw 'left' road edge *********/
+
+ color = ((palette_offs + colbank + palloffs) << 4) + ((type) ? (1) : (4));
+ pri = priorities[0] << 12;
+
+#ifdef MAME_DEBUG
+ if (!dislayer[2])
+#endif
+ {
+ if (background_only) /* The "road edge" line is entirely off screen so can't be drawn */
+ {
+ if (roada_clipl &0x8000) /* but we may need to fill in the background color */
+ {
+ roada = roada_line;
+ for (i=0;i<screen_width;i++)
+ {
+ *roada++ = (color + (type ? (3) : (0)));
+ }
+ }
+ }
+ else
+ {
+ if ((left_edge >= 0) && (left_edge < screen_width))
+ {
+ x_index = (1024/2 - 1 - left_over) &0x7ff;
+
+ roada = roada_line + screen_width - 1 - left_edge;
+
+ if (line_needs_drawing)
+ {
+ for (i=left_edge; i>=0; i--)
+ {
+ gfx_word = roadgfx[(road_gfx_tilenum << 8) + (x_index >> 3)];
+ pixel = ((gfx_word >> (7-(x_index % 8) + 8)) &0x1) * 2 + ((gfx_word >> (7-(x_index % 8))) &0x1);
+
+ pixpri = (pixel==0) ? (0) : (pri); /* off edge has low priority */
+
+ if ((pixel==0) && !(roada_clipl &0x8000))
+ {
+ roada++;
+ }
+ else
+ {
+ if (type) pixel = (pixel-1)&3;
+ *roada++ = (color + pixel) | pixpri;
+ }
+
+ x_index--;
+ x_index &= 0x7ff;
+ }
+ }
+ }
+ }
+ }
+
+
+ /********* Draw 'right' road edge *********/
+
+ color = ((palette_offs + colbank + palroffs) << 4) + ((type) ? (1) : (4));
+ pri = priorities[1] << 12;
+
+#ifdef MAME_DEBUG
+ if (!dislayer[1])
+#endif
+ {
+ if ((right_edge < screen_width) && (right_edge >= 0))
+ {
+ x_index = (1024/2 + right_over) &0x7ff;
+
+ roada = roada_line + screen_width - 1 - right_edge;
+
+ if (line_needs_drawing)
+ {
+ for (i=right_edge; i<screen_width; i++)
+ {
+ gfx_word = roadgfx[(road_gfx_tilenum << 8) + (x_index >> 3)];
+ pixel = ((gfx_word >> (7-(x_index % 8) + 8)) &0x1) * 2 + ((gfx_word >> (7-(x_index % 8))) &0x1);
+
+ pixpri = (pixel==0) ? (0) : (pri); /* off edge has low priority */
+
+ if ((pixel==0) && !(roada_clipr &0x8000))
+ {
+ roada--;
+ }
+ else
+ {
+ if (type) pixel = (pixel-1)&3;
+ *roada-- = (color + pixel) | pixpri;
+ }
+
+ x_index++;
+ x_index &= 0x7ff;
+ }
+ }
+ }
+ }
+
+
+ /********************************************************/
+ /* ROAD B */
+ /********************************************************/
+
+ palroffs = (roadb_clipr &0x1000) >> 11;
+ palloffs = (roadb_clipl &0x1000) >> 11;
+ xoffset = roadb_bodyctrl &0x7ff;
+ paloffs = (roadb_bodyctrl &0x1800) >> 11;
+ colbank = (TC0150ROD_ram[roadram2_index+3] &0xf000) >> 10;
+ road_gfx_tilenum = TC0150ROD_ram[roadram2_index+3] &0x3ff;
+ right_over = 0;
+ left_over = 0;
+
+ road_center = 0x5ff - ((-xoffset + x_offs) &0x7ff);
+
+// ChaseHQ glitches on right when road rejoins:
+// de7, de8 causes problems => 5e7/e8
+// 5ff - (a7 - 5e7)
+// 5ff - 2c0 = 33f / 340 which is not quite > screenwidth + 1024/2: so we subtract 2 more, fixed
+
+
+// ChaseHQ glitches on right when road rejoins:
+// 0a6 and lower => 0x5ff 5fe etc.
+// 35c => 575 right road edge wraps back onto other side of screen
+// 5ff-54a thru 5ff-331
+// b6 thru 2ce
+// 2a6 thru 0 thru 5a7 ??
+
+ left_edge = road_center - (roadb_clipl &0x3ff); /* start pixel for left edge */
+ right_edge = road_center + 1 + (roadb_clipr &0x3ff); /* start pixel for right edge */
+
+ if (((roadb_clipl) || (roadb_clipr)) && ((road_ctrl &0x800) || (type==2)))
+ {
+ draw_top_road_line = 1;
+ line_needs_drawing = 1;
+ }
+ else draw_top_road_line = 0;
+
+ /* Main road line is drawn from 'begin' to 'end'-1 */
+
+ begin = left_edge + 1;
+ if (begin < 0)
+ {
+ begin = 0; /* can't begin off edge of screen */
+ }
+
+ end = right_edge;
+ if (end > screen_width)
+ {
+ end = screen_width; /* can't end off edge of screen */
+ }
+
+ /* We need to offset start pixel we draw for road edge when edge of
+ road is partially or wholly offscreen on the opposite side
+ e.g. Contcirc attract */
+
+ if (right_edge < 0)
+ {
+ right_over = -right_edge;
+ right_edge = 0;
+ }
+ if (left_edge >= screen_width)
+ {
+ left_over = left_edge - screen_width + 1;
+ left_edge = screen_width - 1;
+ }
+
+ /* If road is way off to right we only need to plot background */
+ background_only = (road_center > (screen_width - 2 + 1024/2)) ? 1 : 0;
+
+
+ /********* Draw main part of road *********/
+
+ color = ((palette_offs + colbank + paloffs) << 4) + ((type) ? (1) : (4));
+ pri = priorities[5] << 12;
+
+#ifdef MAME_DEBUG
+ if (!dislayer[3])
+#endif
+ {
+ /* Is this calculation imperfect ? (0xa0 = screen width/2) */
+ x_index = (-xoffset + x_offs + begin) &0x7ff;
+
+ if (x_index > 0x3ff) /* Second half of gfx contains the road body line */
+ {
+ roadb = roadb_line + screen_width - 1 - begin;
+
+ if (draw_top_road_line && road_gfx_tilenum && (begin < end))
+ {
+ for (i=begin; i<end; i++)
+ {
+ gfx_word = roadgfx[(road_gfx_tilenum << 8) + (x_index >> 3)];
+ pixel = ((gfx_word >> (7-(x_index % 8) + 8)) &0x1) * 2 + ((gfx_word >> (7-(x_index % 8))) &0x1);
+
+ if ((pixel) || !(road_trans))
+ {
+ if (type) pixel = (pixel-1)&3;
+ *roadb-- = (color + pixel) | pri;
+ }
+ else *roadb-- = 0xf000; /* high priority transparency, fixes Aquajack */
+
+ x_index++;
+ x_index &= 0x7ff;
+ }
+ }
+ }
+ }
+
+
+ /********* Draw 'left' road edge *********/
+
+ color = ((palette_offs + colbank + palloffs) << 4) + ((type) ? (1) : (4));
+ pri = priorities[3] << 12;
+
+#ifdef MAME_DEBUG
+ if (!dislayer[5])
+#endif
+ {
+ if (background_only) /* The "road edge" line is entirely off screen so can't be drawn */
+ {
+ if ((roadb_clipl &0x8000) && draw_top_road_line) /* but we may need to fill in the background color */
+ {
+ roadb = roadb_line;
+ for (i=0;i<screen_width;i++)
+ {
+ *roadb++ = (color + (type ? (3) : (0)));
+ }
+ }
+ }
+ else
+ {
+ if ((left_edge >= 0) && (left_edge < screen_width))
+ {
+ x_index = (1024/2 - 1 - left_over) &0x7ff;
+
+ roadb = roadb_line + screen_width - 1 - left_edge;
+
+ if (draw_top_road_line) // rename to draw_roadb_line !?
+ {
+ for (i=left_edge; i>=0; i--)
+ {
+ gfx_word = roadgfx[(road_gfx_tilenum << 8) + (x_index >> 3)];
+ pixel = ((gfx_word >> (7-(x_index % 8) + 8)) &0x1) * 2 + ((gfx_word >> (7-(x_index % 8))) &0x1);
+
+ pixpri = (pixel==0) ? (0) : (pri); /* off edge has low priority */
+
+ if ((pixel==0) && !(roadb_clipl &0x8000)) /* test for background disabled */
+ {
+ roadb++;
+ }
+ else
+ {
+ if (type) pixel = (pixel-1)&3;
+ *roadb++ = (color + pixel) | pixpri;
+ }
+
+ x_index--;
+ if (x_index < 0) break;
+ }
+ }
+ }
+ }
+ }
+
+
+ /********* Draw 'right' road edge *********/
+
+ color = ((palette_offs + colbank + palroffs) << 4) + ((type) ? (1) : (4));
+ pri = priorities[4] << 12;
+
+#ifdef MAME_DEBUG
+ if (!dislayer[4])
+#endif
+ {
+ if ((right_edge < screen_width) && (right_edge >= 0))
+ {
+ x_index = (1024/2 + right_over) &0x7ff;
+
+ roadb = roadb_line + screen_width - 1 - right_edge;
+
+ if (draw_top_road_line)
+ {
+ for (i=right_edge; i<screen_width; i++)
+ {
+ gfx_word = roadgfx[(road_gfx_tilenum << 8) + (x_index >> 3)];
+ pixel = ((gfx_word >> (7-(x_index % 8) + 8)) &0x1) * 2 + ((gfx_word >> (7-(x_index % 8))) &0x1);
+
+ pixpri = (pixel==0) ? (0) : (pri); /* off edge has low priority */
+
+ if ((pixel==0) && !(roadb_clipr &0x8000)) /* test for background disabled */
+ {
+ roadb--;
+ }
+ else
+ {
+ if (type) pixel = (pixel-1)&3;
+ *roadb-- = (color + pixel) | pixpri;
+ }
+
+ x_index++;
+ if (x_index > 0x3ff) break;
+ }
+ }
+ }
+ }
+
+
+ /******** Combine the two lines according to pixel priorities ********/
+
+ if (line_needs_drawing)
+ {
+ dst16 = scanline;
+
+ for (i=0;i<screen_width;i++)
+ {
+ if (roada_line[i] == 0x8000) /* road A pixel transparent */
+ {
+ *dst16++ = roadb_line[i] & 0x8fff;
+ }
+ else if (roadb_line[i] == 0x8000) /* road B pixel transparent */
+ {
+ *dst16++ = roada_line[i] & 0x8fff;
+ }
+ else /* two competing pixels, which has highest priority... */
+ {
+ if ((roadb_line[i] & 0x7000) > (roada_line[i] & 0x7000))
+ {
+ *dst16++ = roadb_line[i] & 0x8fff;
+ }
+ else
+ {
+ *dst16++ = roada_line[i] & 0x8fff;
+ }
+ }
+ }
+
+ if (y > priority_switch_line)
+ taitoic_drawscanline(bitmap,0,y,scanline,1,ROT0,high_priority,cliprect);
+ else
+ taitoic_drawscanline(bitmap,0,y,scanline,1,ROT0,low_priority,cliprect);
+ }
+
+ y++;
+ }
+ while (y <= max_y);
+
+#if 0
+ if (twin_road) // I don't know what this means, actually...
+ {
+ char buf2[80];
+ sprintf(buf2,"Road twinned for %04x lines",twin_road);
+ popmessage(buf2);
+ }
+#endif
+}
+
+/***************************************************************************/
+
+
+static int TC0110PCR_type = 0;
+static int TC0110PCR_addr[3];
+static UINT16 *TC0110PCR_ram[3];
+#define TC0110PCR_RAM_SIZE 0x2000
+
+
+static void TC0110PCR_restore_colors(int chip)
+{
+ int i,color,r=0,g=0,b=0;
+
+ for (i=0; i<(256*16); i++)
+ {
+ color = TC0110PCR_ram[chip][i];
+
+ switch (TC0110PCR_type)
+ {
+
+ case 0x00:
+ {
+ r = pal5bit(color >> 0);
+ g = pal5bit(color >> 5);
+ b = pal5bit(color >> 10);
+ break;
+ }
+
+ case 0x01:
+ {
+ b = pal5bit(color >> 0);
+ g = pal5bit(color >> 5);
+ r = pal5bit(color >> 10);
+ break;
+ }
+
+ case 0x02:
+ {
+ r = pal4bit(color >> 0);
+ g = pal4bit(color >> 4);
+ b = pal4bit(color >> 8);
+ break;
+ }
+ }
+
+ palette_set_color(Machine, i + (chip << 12),MAKE_RGB(r,g,b));
+ }
+}
+
+
+void TC0110PCR_vh_start(void)
+{
+ TC0110PCR_ram[0] = auto_malloc(TC0110PCR_RAM_SIZE * sizeof(*TC0110PCR_ram[0]));
+
+ state_save_register_global_pointer(TC0110PCR_ram[0], TC0110PCR_RAM_SIZE);
+ state_save_register_func_postload_int(TC0110PCR_restore_colors, 0);
+
+ TC0110PCR_type = 0; /* default, xBBBBBGGGGGRRRRR */
+}
+
+void TC0110PCR_1_vh_start(void)
+{
+ TC0110PCR_ram[1] = auto_malloc(TC0110PCR_RAM_SIZE * sizeof(*TC0110PCR_ram[1]));
+
+ state_save_register_global_pointer(TC0110PCR_ram[1], TC0110PCR_RAM_SIZE);
+ state_save_register_func_postload_int(TC0110PCR_restore_colors, 1);
+}
+
+void TC0110PCR_2_vh_start(void)
+{
+ TC0110PCR_ram[2] = auto_malloc(TC0110PCR_RAM_SIZE * sizeof(*TC0110PCR_ram[2]));
+
+ state_save_register_global_pointer(TC0110PCR_ram[2], TC0110PCR_RAM_SIZE);
+ state_save_register_func_postload_int(TC0110PCR_restore_colors, 2);
+}
+
+READ16_HANDLER( TC0110PCR_word_r )
+{
+ switch (offset)
+ {
+ case 1:
+ return TC0110PCR_ram[0][(TC0110PCR_addr[0])];
+
+ default:
+logerror("PC %06x: warning - read TC0110PCR address %02x\n",activecpu_get_pc(),offset);
+ return 0xff;
+ }
+}
+
+READ16_HANDLER( TC0110PCR_word_1_r )
+{
+ switch (offset)
+ {
+ case 1:
+ return TC0110PCR_ram[1][(TC0110PCR_addr[1])];
+
+ default:
+logerror("PC %06x: warning - read second TC0110PCR address %02x\n",activecpu_get_pc(),offset);
+ return 0xff;
+ }
+}
+
+READ16_HANDLER( TC0110PCR_word_2_r )
+{
+ switch (offset)
+ {
+ case 1:
+ return TC0110PCR_ram[2][(TC0110PCR_addr[2])];
+
+ default:
+logerror("PC %06x: warning - read third TC0110PCR address %02x\n",activecpu_get_pc(),offset);
+ return 0xff;
+ }
+}
+
+WRITE16_HANDLER( TC0110PCR_word_w )
+{
+ switch (offset)
+ {
+ case 0:
+ /* In test mode game writes to odd register number so (data>>1) */
+ TC0110PCR_addr[0] = (data >> 1) & 0xfff;
+ if (data>0x1fff) logerror ("Write to palette index > 0x1fff\n");
+ break;
+
+ case 1:
+ {
+ TC0110PCR_ram[0][(TC0110PCR_addr[0])] = data & 0xffff;
+ palette_set_color_rgb(Machine,TC0110PCR_addr[0],pal5bit(data >> 0),pal5bit(data >> 5),pal5bit(data >> 10));
+ break;
+ }
+
+ default:
+logerror("PC %06x: warning - write %04x to TC0110PCR address %02x\n",activecpu_get_pc(),data,offset);
+ break;
+ }
+}
+
+WRITE16_HANDLER( TC0110PCR_step1_word_w )
+{
+ switch (offset)
+ {
+ case 0:
+ TC0110PCR_addr[0] = data & 0xfff;
+ if (data>0xfff) logerror ("Write to palette index > 0xfff\n");
+ break;
+
+ case 1:
+ {
+ TC0110PCR_ram[0][(TC0110PCR_addr[0])] = data & 0xffff;
+ palette_set_color_rgb(Machine,TC0110PCR_addr[0],pal5bit(data >> 0),pal5bit(data >> 5),pal5bit(data >> 10));
+ break;
+ }
+
+ default:
+logerror("PC %06x: warning - write %04x to TC0110PCR address %02x\n",activecpu_get_pc(),data,offset);
+ break;
+ }
+}
+
+WRITE16_HANDLER( TC0110PCR_step1_word_1_w )
+{
+ switch (offset)
+ {
+ case 0:
+ TC0110PCR_addr[1] = data & 0xfff;
+ if (data>0xfff) logerror ("Write to second TC0110PCR palette index > 0xfff\n");
+ break;
+
+ case 1:
+ {
+ TC0110PCR_ram[1][(TC0110PCR_addr[1])] = data & 0xffff;
+ /* change a color in the second color area (4096-8191) */
+ palette_set_color_rgb(Machine,TC0110PCR_addr[1] + 4096,pal5bit(data >> 0),pal5bit(data >> 5),pal5bit(data >> 10));
+ break;
+ }
+
+ default:
+logerror("PC %06x: warning - write %04x to second TC0110PCR offset %02x\n",activecpu_get_pc(),data,offset);
+ break;
+ }
+}
+
+WRITE16_HANDLER( TC0110PCR_step1_word_2_w )
+{
+ switch (offset)
+ {
+ case 0:
+ TC0110PCR_addr[2] = data & 0xfff;
+ if (data>0xfff) logerror ("Write to third TC0110PCR palette index > 0xfff\n");
+ break;
+
+ case 1:
+ {
+ TC0110PCR_ram[2][(TC0110PCR_addr[2])] = data & 0xffff;
+ /* change a color in the second color area (8192-12288) */
+ palette_set_color_rgb(Machine,TC0110PCR_addr[2] + 8192,pal5bit(data >> 0),pal5bit(data >> 5),pal5bit(data >> 10));
+ break;
+ }
+
+ default:
+logerror("PC %06x: warning - write %04x to third TC0110PCR offset %02x\n",activecpu_get_pc(),data,offset);
+ break;
+ }
+}
+
+WRITE16_HANDLER( TC0110PCR_step1_rbswap_word_w )
+{
+ TC0110PCR_type = 1; /* xRRRRRGGGGGBBBBB */
+
+ switch (offset)
+ {
+ case 0:
+ TC0110PCR_addr[0] = data & 0xfff;
+ if (data>0xfff) logerror ("Write to palette index > 0xfff\n");
+ break;
+
+ case 1:
+ {
+ TC0110PCR_ram[0][(TC0110PCR_addr[0])] = data & 0xffff;
+ palette_set_color_rgb(Machine,TC0110PCR_addr[0],pal5bit(data >> 10),pal5bit(data >> 5),pal5bit(data >> 0));
+ break;
+ }
+
+ default:
+logerror("PC %06x: warning - write %04x to TC0110PCR offset %02x\n",activecpu_get_pc(),data,offset);
+ break;
+ }
+}
+
+WRITE16_HANDLER( TC0110PCR_step1_4bpg_word_w )
+{
+ TC0110PCR_type = 2; /* xxxxBBBBGGGGRRRR */
+
+ switch (offset)
+ {
+ case 0:
+ TC0110PCR_addr[0] = data & 0xfff;
+ if (data>0xfff) logerror ("Write to palette index > 0xfff\n");
+ break;
+
+ case 1:
+ {
+ TC0110PCR_ram[0][(TC0110PCR_addr[0])] = data & 0xffff;
+ palette_set_color_rgb(Machine,TC0110PCR_addr[0],pal4bit(data >> 0),pal4bit(data >> 4),pal4bit(data >> 8));
+ break;
+ }
+
+ default:
+logerror("PC %06x: warning - write %04x to TC0110PCR address %02x\n",activecpu_get_pc(),data,offset);
+ break;
+ }
+}
+
+/***************************************************************************/
+
+
+static UINT8 TC0220IOC_regs[8];
+static UINT8 TC0220IOC_port;
+
+READ8_HANDLER( TC0220IOC_r )
+{
+ switch (offset)
+ {
+ case 0x00: /* IN00-07 (DSA) */
+ return input_port_0_r(0);
+
+ case 0x01: /* IN08-15 (DSB) */
+ return input_port_1_r(0);
+
+ case 0x02: /* IN16-23 (1P) */
+ return input_port_2_r(0);
+
+ case 0x03: /* IN24-31 (2P) */
+ return input_port_3_r(0);
+
+ case 0x04: /* coin counters and lockout */
+ return TC0220IOC_regs[4];
+
+ case 0x07: /* INB0-7 (coin) */
+ return input_port_4_r(0);
+
+ default:
+logerror("PC %06x: warning - read TC0220IOC address %02x\n",activecpu_get_pc(),offset);
+ return 0xff;
+ }
+}
+
+WRITE8_HANDLER( TC0220IOC_w )
+{
+ TC0220IOC_regs[offset] = data;
+
+ switch (offset)
+ {
+ case 0x00:
+ watchdog_reset_w(offset,data);
+ break;
+
+ case 0x04: /* coin counters and lockout, hi nibble irrelevant */
+ coin_lockout_w(0,~data & 0x01);
+ coin_lockout_w(1,~data & 0x02);
+ coin_counter_w(0,data & 0x04);
+ coin_counter_w(1,data & 0x08);
+
+//if (data &0xf0)
+//logerror("PC %06x: warning - write %02x to TC0220IOC address %02x\n",activecpu_get_pc(),data,offset);
+
+ break;
+
+ default:
+logerror("PC %06x: warning - write %02x to TC0220IOC address %02x\n",activecpu_get_pc(),data,offset);
+ break;
+ }
+}
+
+READ8_HANDLER( TC0220IOC_port_r )
+{
+ return TC0220IOC_port;
+}
+
+WRITE8_HANDLER( TC0220IOC_port_w )
+{
+ TC0220IOC_port = data;
+}
+
+READ8_HANDLER( TC0220IOC_portreg_r )
+{
+ return TC0220IOC_r(TC0220IOC_port);
+}
+
+WRITE8_HANDLER( TC0220IOC_portreg_w )
+{
+ TC0220IOC_w(TC0220IOC_port, data);
+}
+
+READ16_HANDLER( TC0220IOC_halfword_port_r )
+{
+ return TC0220IOC_port_r( offset );
+}
+
+WRITE16_HANDLER( TC0220IOC_halfword_port_w )
+{
+ if (ACCESSING_LSB)
+ TC0220IOC_port_w( offset, data & 0xff );
+}
+
+READ16_HANDLER( TC0220IOC_halfword_portreg_r )
+{
+ return TC0220IOC_portreg_r( offset );
+}
+
+WRITE16_HANDLER( TC0220IOC_halfword_portreg_w )
+{
+ if (ACCESSING_LSB)
+ TC0220IOC_portreg_w( offset, data & 0xff );
+}
+
+READ16_HANDLER( TC0220IOC_halfword_byteswap_port_r )
+{
+ return TC0220IOC_port_r( offset ) << 8;
+}
+
+WRITE16_HANDLER( TC0220IOC_halfword_byteswap_port_w )
+{
+ if (ACCESSING_MSB)
+ TC0220IOC_port_w( offset, (data>>8) & 0xff );
+}
+
+READ16_HANDLER( TC0220IOC_halfword_byteswap_portreg_r )
+{
+ return TC0220IOC_portreg_r( offset )<<8;
+}
+
+WRITE16_HANDLER( TC0220IOC_halfword_byteswap_portreg_w )
+{
+ if (ACCESSING_MSB)
+ TC0220IOC_portreg_w( offset, (data>>8) & 0xff );
+}
+
+READ16_HANDLER( TC0220IOC_halfword_r )
+{
+ return TC0220IOC_r(offset);
+}
+
+WRITE16_HANDLER( TC0220IOC_halfword_w )
+{
+ if (ACCESSING_LSB)
+ TC0220IOC_w(offset,data & 0xff);
+ else
+ {
+ /* qtorimon writes here the coin counters - bug? */
+ TC0220IOC_w(offset,(data >> 8) & 0xff);
+
+ if (offset) /* ainferno writes watchdog in msb */
+logerror("CPU #0 PC %06x: warning - write to MSB of TC0220IOC address %02x\n",activecpu_get_pc(),offset);
+ }
+}
+
+READ16_HANDLER( TC0220IOC_halfword_byteswap_r )
+{
+ return TC0220IOC_halfword_r(offset,mem_mask) << 8;
+}
+
+WRITE16_HANDLER( TC0220IOC_halfword_byteswap_w )
+{
+ if (ACCESSING_MSB)
+ TC0220IOC_w(offset,(data >> 8) & 0xff);
+ else
+ {
+ TC0220IOC_w(offset,data & 0xff);
+
+logerror("CPU #0 PC %06x: warning - write to LSB of TC0220IOC address %02x\n",activecpu_get_pc(),offset);
+ }
+}
+
+
+/***************************************************************************/
+
+
+static UINT8 TC0510NIO_regs[8];
+
+READ8_HANDLER( TC0510NIO_r )
+{
+ switch (offset)
+ {
+ case 0x00: /* DSA */
+ return input_port_0_r(0);
+
+ case 0x01: /* DSB */
+ return input_port_1_r(0);
+
+ case 0x02: /* 1P */
+ return input_port_2_r(0);
+
+ case 0x03: /* 2P */
+ return input_port_3_r(0);
+
+ case 0x04: /* coin counters and lockout */
+ return TC0510NIO_regs[4];
+
+ case 0x07: /* coin */
+ return input_port_4_r(0);
+
+ default:
+logerror("PC %06x: warning - read TC0510NIO address %02x\n",activecpu_get_pc(),offset);
+ return 0xff;
+ }
+}
+
+WRITE8_HANDLER( TC0510NIO_w )
+{
+ TC0510NIO_regs[offset] = data;
+
+ switch (offset)
+ {
+ case 0x00:
+ watchdog_reset_w(offset,data);
+ break;
+
+ case 0x04: /* coin counters and lockout */
+ coin_lockout_w(0,~data & 0x01);
+ coin_lockout_w(1,~data & 0x02);
+ coin_counter_w(0,data & 0x04);
+ coin_counter_w(1,data & 0x08);
+ break;
+
+ default:
+logerror("PC %06x: warning - write %02x to TC0510NIO address %02x\n",activecpu_get_pc(),data,offset);
+ break;
+ }
+}
+
+READ16_HANDLER( TC0510NIO_halfword_r )
+{
+ return TC0510NIO_r(offset);
+}
+
+WRITE16_HANDLER( TC0510NIO_halfword_w )
+{
+ if (ACCESSING_LSB)
+ TC0510NIO_w(offset,data & 0xff);
+ else
+ {
+ /* driftout writes the coin counters here - bug? */
+logerror("CPU #0 PC %06x: warning - write to MSB of TC0510NIO address %02x\n",activecpu_get_pc(),offset);
+ TC0510NIO_w(offset,(data >> 8) & 0xff);
+ }
+}
+
+READ16_HANDLER( TC0510NIO_halfword_wordswap_r )
+{
+ return TC0510NIO_halfword_r(offset ^ 1,mem_mask);
+}
+
+WRITE16_HANDLER( TC0510NIO_halfword_wordswap_w )
+{
+ TC0510NIO_halfword_w(offset ^ 1,data,mem_mask);
+}
+
+
+/***************************************************************************/
+
+static UINT8 TC0640FIO_regs[8];
+
+READ8_HANDLER( TC0640FIO_r )
+{
+ switch (offset)
+ {
+ case 0x00: /* DSA */
+ return input_port_0_r(0);
+
+ case 0x01: /* DSB */
+ return input_port_1_r(0);
+
+ case 0x02: /* 1P */
+ return input_port_2_r(0);
+
+ case 0x03: /* 2P */
+ return input_port_3_r(0);
+
+ case 0x04: /* coin counters and lockout */
+ return TC0640FIO_regs[4];
+
+ case 0x07: /* coin */
+ return input_port_4_r(0);
+
+ default:
+logerror("PC %06x: warning - read TC0640FIO address %02x\n",activecpu_get_pc(),offset);
+ return 0xff;
+ }
+}
+
+WRITE8_HANDLER( TC0640FIO_w )
+{
+ TC0640FIO_regs[offset] = data;
+
+ switch (offset)
+ {
+ case 0x00:
+ watchdog_reset_w(offset,data);
+ break;
+
+ case 0x04: /* coin counters and lockout */
+ coin_lockout_w(0,~data & 0x01);
+ coin_lockout_w(1,~data & 0x02);
+ coin_counter_w(0,data & 0x04);
+ coin_counter_w(1,data & 0x08);
+ break;
+
+ default:
+logerror("PC %06x: warning - write %02x to TC0640FIO address %02x\n",activecpu_get_pc(),data,offset);
+ break;
+ }
+}
+
+READ16_HANDLER( TC0640FIO_halfword_r )
+{
+ return TC0640FIO_r(offset);
+}
+
+WRITE16_HANDLER( TC0640FIO_halfword_w )
+{
+ if (ACCESSING_LSB)
+ TC0640FIO_w(offset,data & 0xff);
+ else
+ {
+ TC0640FIO_w(offset,(data >> 8) & 0xff);
+logerror("CPU #0 PC %06x: warning - write to MSB of TC0640FIO address %02x\n",activecpu_get_pc(),offset);
+ }
+}
+
+READ16_HANDLER( TC0640FIO_halfword_byteswap_r )
+{
+ return TC0640FIO_halfword_r(offset,mem_mask) << 8;
+}
+
+WRITE16_HANDLER( TC0640FIO_halfword_byteswap_w )
+{
+ if (ACCESSING_MSB)
+ TC0640FIO_w(offset,(data >> 8) & 0xff);
+ else
+ {
+ TC0640FIO_w(offset,data & 0xff);
+logerror("CPU #0 PC %06x: warning - write to LSB of TC0640FIO address %02x\n",activecpu_get_pc(),offset);
+ }
+}
+
+
diff --git a/src/mame/video/taitoic.h b/src/mame/video/taitoic.h
new file mode 100644
index 00000000000..e2c37310135
--- /dev/null
+++ b/src/mame/video/taitoic.h
@@ -0,0 +1,234 @@
+/***************************************************************************
+ Taito Custom Chips
+***************************************************************************/
+
+extern const int TC0100SCN_SINGLE_VDU; /* value set in taitoic.c */
+
+int number_of_TC0100SCN(void);
+int has_TC0110PCR(void);
+int has_second_TC0110PCR(void);
+int has_third_TC0110PCR(void);
+int has_TC0150ROD(void);
+int has_TC0280GRD(void);
+int has_TC0360PRI(void);
+int has_TC0430GRW(void);
+int has_TC0480SCP(void);
+
+
+/***************************************************************************/
+
+void PC080SN_vh_start(int chips,int gfxnum,int x_offset,int y_offset,int y_invert,int opaque,int dblwidth);
+READ16_HANDLER ( PC080SN_word_0_r );
+WRITE16_HANDLER( PC080SN_word_0_w );
+WRITE16_HANDLER( PC080SN_xscroll_word_0_w );
+WRITE16_HANDLER( PC080SN_yscroll_word_0_w );
+WRITE16_HANDLER( PC080SN_ctrl_word_0_w );
+READ16_HANDLER ( PC080SN_word_1_r );
+WRITE16_HANDLER( PC080SN_word_1_w );
+WRITE16_HANDLER( PC080SN_xscroll_word_1_w );
+WRITE16_HANDLER( PC080SN_yscroll_word_1_w );
+WRITE16_HANDLER( PC080SN_ctrl_word_1_w );
+void PC080SN_set_scroll(int chip,int tilemap_num,int scrollx,int scrolly);
+void PC080SN_set_trans_pen(int chip,int tilemap_num,int pen);
+void PC080SN_tilemap_update(void);
+void PC080SN_tilemap_draw(mame_bitmap *bitmap,const rectangle *cliprect,int chip,int layer,int flags,UINT32 priority);
+void PC080SN_tilemap_draw_offset(mame_bitmap *bitmap,const rectangle *cliprect,int chip,int layer,int flags,UINT32 priority,int xoffs,int yoffs);
+
+/* For Topspeed */
+void PC080SN_tilemap_draw_special(mame_bitmap *bitmap,const rectangle *cliprect,int chip,int layer,int flags,UINT32 priority,UINT16 *ram);
+
+
+/***************************************************************************/
+
+void PC090OJ_vh_start(int gfxnum,int x_offset,int y_offset,int use_buffer);
+
+READ16_HANDLER( PC090OJ_word_0_r );
+WRITE16_HANDLER( PC090OJ_word_0_w );
+
+void PC090OJ_eof_callback(void);
+void PC090OJ_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect,int pri_type);
+
+extern UINT16 PC090OJ_sprite_ctrl;
+
+
+/***************************************************************************/
+
+void TC0080VCO_vh_start(running_machine *machine, int gfxnum,int has_fg0,int bg_xoffs,int bg_yoffs,int bg_flip_yoffs);
+
+READ16_HANDLER ( TC0080VCO_word_r );
+WRITE16_HANDLER( TC0080VCO_word_w );
+
+void TC0080VCO_tilemap_update(running_machine *machine);
+void TC0080VCO_tilemap_draw(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int layer,int flags,UINT32 priority);
+
+
+/***************************************************************************/
+
+/* When writing a driver pass zero for all the offsets initially then
+ tweak them later. Most TC0100SCN games have y_offset=0 */
+
+void TC0100SCN_vh_start(running_machine *machine, int chips,int gfxnum,int x_offset,int y_offset,int flip_xoffs,
+ int flip_yoffs,int flip_text_xoffs,int flip_text_yoffs,int multiscrn_xoffs);
+
+/* Function to set separate color banks for the three tilemapped layers.
+ To change from the default (0,0,0) use after calling TC0100SCN_vh_start */
+void TC0100SCN_set_colbanks(int bg0,int bg1,int fg);
+
+/* Function to set separate color banks for each TC0100SCN.
+ To change from the default (0,0,0) use after calling TC0100SCN_vh_start */
+void TC0100SCN_set_chip_colbanks(int chip0,int chip1,int chip2);
+
+/* Function to set bg tilemask < 0xffff */
+void TC0100SCN_set_bg_tilemask(int mask);
+
+/* Function to for Mjnquest to select gfx bank */
+WRITE16_HANDLER( TC0100SCN_gfxbank_w );
+
+READ16_HANDLER ( TC0100SCN_word_0_r );
+WRITE16_HANDLER( TC0100SCN_word_0_w );
+READ16_HANDLER ( TC0100SCN_ctrl_word_0_r );
+WRITE16_HANDLER( TC0100SCN_ctrl_word_0_w );
+READ16_HANDLER ( TC0100SCN_word_1_r );
+WRITE16_HANDLER( TC0100SCN_word_1_w );
+READ16_HANDLER ( TC0100SCN_ctrl_word_1_r );
+WRITE16_HANDLER( TC0100SCN_ctrl_word_1_w );
+READ16_HANDLER ( TC0100SCN_word_2_r );
+WRITE16_HANDLER( TC0100SCN_word_2_w );
+READ16_HANDLER ( TC0100SCN_ctrl_word_2_r );
+WRITE16_HANDLER( TC0100SCN_ctrl_word_2_w );
+
+/* Functions for use with 68020 (Under Fire) */
+READ32_HANDLER ( TC0100SCN_long_r );
+WRITE32_HANDLER( TC0100SCN_long_w );
+READ32_HANDLER ( TC0100SCN_ctrl_long_r );
+WRITE32_HANDLER( TC0100SCN_ctrl_long_w );
+
+/* Functions to write multiple TC0100SCNs with the same data */
+WRITE16_HANDLER( TC0100SCN_dual_screen_w );
+WRITE16_HANDLER( TC0100SCN_triple_screen_w );
+
+void TC0100SCN_tilemap_update(running_machine *machine);
+int TC0100SCN_tilemap_draw(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int chip,int layer,int flags,UINT32 priority);
+
+/* returns 0 or 1 depending on the lowest priority tilemap set in the internal
+ register. Use this function to draw tilemaps in the correct order. */
+int TC0100SCN_bottomlayer(int chip);
+
+
+/***************************************************************************/
+
+void TC0280GRD_vh_start(int gfxnum);
+READ16_HANDLER ( TC0280GRD_word_r );
+WRITE16_HANDLER( TC0280GRD_word_w );
+WRITE16_HANDLER( TC0280GRD_ctrl_word_w );
+void TC0280GRD_tilemap_update(int base_color);
+void TC0280GRD_zoom_draw(mame_bitmap *bitmap,const rectangle *cliprect,int xoffset,int yoffset,UINT32 priority);
+
+void TC0430GRW_vh_start(int gfxnum);
+READ16_HANDLER ( TC0430GRW_word_r );
+WRITE16_HANDLER( TC0430GRW_word_w );
+WRITE16_HANDLER( TC0430GRW_ctrl_word_w );
+void TC0430GRW_tilemap_update(int base_color);
+void TC0430GRW_zoom_draw(mame_bitmap *bitmap,const rectangle *cliprect,int xoffset,int yoffset,UINT32 priority);
+
+
+/***************************************************************************/
+
+/* When writing a driver, pass zero for the text and flip offsets initially:
+ then tweak them once you have the 4 bg layer positions correct. Col_base
+ may be needed when tilemaps use a palette area from sprites. */
+
+void TC0480SCP_vh_start(running_machine *machine, int gfxnum,int pixels,int x_offset,int y_offset,int text_xoffs,int text_yoffs,int flip_xoffs,int flip_yoffs,int col_base);
+READ16_HANDLER ( TC0480SCP_word_r );
+WRITE16_HANDLER( TC0480SCP_word_w );
+READ16_HANDLER ( TC0480SCP_ctrl_word_r );
+WRITE16_HANDLER( TC0480SCP_ctrl_word_w );
+
+/* Functions for use with 68020 (Super-Z system) */
+READ32_HANDLER ( TC0480SCP_long_r );
+WRITE32_HANDLER( TC0480SCP_long_w );
+READ32_HANDLER ( TC0480SCP_ctrl_long_r );
+WRITE32_HANDLER( TC0480SCP_ctrl_long_w );
+
+void TC0480SCP_tilemap_update(running_machine *machine);
+void TC0480SCP_tilemap_draw(mame_bitmap *bitmap,const rectangle *cliprect,int layer,int flags,UINT32 priority);
+
+/* Returns the priority order of the bg tilemaps set in the internal
+ register. The order in which the four layers should be drawn is
+ returned in the lowest four nibbles (msn = bottom layer; lsn = top) */
+int TC0480SCP_get_bg_priority(void);
+
+/* Undrfire needs to read this for a sprite/tile priority hack */
+extern int TC0480SCP_pri_reg;
+
+
+/***************************************************************************/
+
+READ16_HANDLER( TC0150ROD_word_r );
+WRITE16_HANDLER( TC0150ROD_word_w );
+void TC0150ROD_vh_start(void);
+void TC0150ROD_draw(mame_bitmap *bitmap,const rectangle *cliprect,int y_offs,int palette_offs,int type,int road_trans,UINT32 low_priority,UINT32 high_priority);
+
+
+/***************************************************************************/
+
+void TC0110PCR_vh_start(void);
+void TC0110PCR_1_vh_start(void); /* 2nd chip */
+void TC0110PCR_2_vh_start(void); /* 3rd chip */
+READ16_HANDLER ( TC0110PCR_word_r );
+READ16_HANDLER ( TC0110PCR_word_1_r ); /* 2nd chip */
+READ16_HANDLER ( TC0110PCR_word_2_r ); /* 3rd chip */
+WRITE16_HANDLER( TC0110PCR_word_w ); /* color index goes up in step of 2 */
+WRITE16_HANDLER( TC0110PCR_step1_word_w ); /* color index goes up in step of 1 */
+WRITE16_HANDLER( TC0110PCR_step1_word_1_w ); /* 2nd chip */
+WRITE16_HANDLER( TC0110PCR_step1_word_2_w ); /* 3rd chip */
+WRITE16_HANDLER( TC0110PCR_step1_rbswap_word_w ); /* swaps red and blue components */
+WRITE16_HANDLER( TC0110PCR_step1_4bpg_word_w ); /* only 4 bits per color gun */
+
+void TC0360PRI_vh_start(void); /* must be called to ensure regs saved in state.c */
+WRITE8_HANDLER( TC0360PRI_w );
+WRITE16_HANDLER( TC0360PRI_halfword_w );
+WRITE16_HANDLER( TC0360PRI_halfword_swap_w );
+
+
+/***************************************************************************/
+
+/* I/O chips, all extremely similar. The TC0220IOC was sometimes addressed
+ through a port, typically on earlier games. */
+
+READ8_HANDLER ( TC0220IOC_r );
+WRITE8_HANDLER( TC0220IOC_w );
+READ8_HANDLER ( TC0220IOC_port_r );
+WRITE8_HANDLER( TC0220IOC_port_w );
+READ8_HANDLER ( TC0220IOC_portreg_r );
+WRITE8_HANDLER( TC0220IOC_portreg_w );
+
+READ16_HANDLER ( TC0220IOC_halfword_port_r );
+WRITE16_HANDLER( TC0220IOC_halfword_port_w );
+READ16_HANDLER ( TC0220IOC_halfword_portreg_r );
+WRITE16_HANDLER( TC0220IOC_halfword_portreg_w );
+READ16_HANDLER ( TC0220IOC_halfword_byteswap_port_r );
+WRITE16_HANDLER( TC0220IOC_halfword_byteswap_port_w );
+READ16_HANDLER ( TC0220IOC_halfword_byteswap_portreg_r );
+WRITE16_HANDLER( TC0220IOC_halfword_byteswap_portreg_w );
+READ16_HANDLER ( TC0220IOC_halfword_r );
+WRITE16_HANDLER( TC0220IOC_halfword_w );
+READ16_HANDLER ( TC0220IOC_halfword_byteswap_r );
+WRITE16_HANDLER( TC0220IOC_halfword_byteswap_w );
+
+READ8_HANDLER ( TC0510NIO_r );
+WRITE8_HANDLER( TC0510NIO_w );
+
+READ16_HANDLER ( TC0510NIO_halfword_r );
+WRITE16_HANDLER( TC0510NIO_halfword_w );
+READ16_HANDLER ( TC0510NIO_halfword_wordswap_r );
+WRITE16_HANDLER( TC0510NIO_halfword_wordswap_w );
+
+READ8_HANDLER ( TC0640FIO_r );
+WRITE8_HANDLER( TC0640FIO_w );
+
+READ16_HANDLER ( TC0640FIO_halfword_r );
+WRITE16_HANDLER( TC0640FIO_halfword_w );
+READ16_HANDLER ( TC0640FIO_halfword_byteswap_r );
+WRITE16_HANDLER( TC0640FIO_halfword_byteswap_w );
+
diff --git a/src/mame/video/taitojc.c b/src/mame/video/taitojc.c
new file mode 100644
index 00000000000..5a3808fa2d2
--- /dev/null
+++ b/src/mame/video/taitojc.c
@@ -0,0 +1,644 @@
+#include "driver.h"
+#include "video/poly.h"
+
+UINT8 *taitojc_texture;
+static mame_bitmap *framebuffer;
+static mame_bitmap *zbuffer;
+
+extern UINT32 *taitojc_vram;
+extern UINT32 *taitojc_objlist;
+
+//static int debug_tex_pal = 0;
+
+typedef struct _poly_extra_data poly_extra_data;
+struct _poly_extra_data
+{
+ int tex_base_x;
+ int tex_base_y;
+ int tex_wrap_x;
+ int tex_wrap_y;
+};
+
+
+static int taitojc_gfx_index;
+
+static UINT8 *taitojc_dirty_map;
+static UINT32 *taitojc_char_ram;
+static UINT32 *taitojc_tile_ram;
+static int taitojc_char_dirty = 1;
+static tilemap *taitojc_tilemap;
+
+static poly_manager *poly;
+
+#define TAITOJC_NUM_TILES 0x80
+
+static const gfx_layout taitojc_char_layout =
+{
+ 16,16,
+ TAITOJC_NUM_TILES,
+ 4,
+ { 0,1,2,3 },
+ { 24,28,16,20,8,12,0,4, 56,60,48,52,40,44,32,36 },
+ { 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64,8*64,9*64,10*64,11*64,12*64,13*64,14*64,15*64 },
+ 16*64
+};
+
+static TILE_GET_INFO( taitojc_tile_info )
+{
+ UINT32 val = taitojc_tile_ram[tile_index];
+ int color = (val >> 22) & 0xff;
+ int tile = (val >> 2) & 0x7f;
+ SET_TILE_INFO(taitojc_gfx_index, tile, color, 0);
+}
+
+static void taitojc_tile_update(running_machine *machine)
+{
+ int i;
+ if (taitojc_char_dirty)
+ {
+ for (i=0; i < TAITOJC_NUM_TILES; i++)
+ {
+ if (taitojc_dirty_map[i])
+ {
+ taitojc_dirty_map[i] = 0;
+ decodechar(Machine->gfx[taitojc_gfx_index], i, (UINT8 *)taitojc_char_ram, &taitojc_char_layout);
+ }
+ }
+ tilemap_mark_all_tiles_dirty(taitojc_tilemap);
+ taitojc_char_dirty = 0;
+ }
+}
+
+READ32_HANDLER(taitojc_tile_r)
+{
+ return taitojc_tile_ram[offset];
+}
+
+READ32_HANDLER(taitojc_char_r)
+{
+ return taitojc_char_ram[offset];
+}
+
+WRITE32_HANDLER(taitojc_tile_w)
+{
+ COMBINE_DATA(taitojc_tile_ram + offset);
+ tilemap_mark_tile_dirty(taitojc_tilemap, offset);
+}
+
+WRITE32_HANDLER(taitojc_char_w)
+{
+ COMBINE_DATA(taitojc_char_ram + offset);
+ taitojc_dirty_map[offset/32] = 1;
+ taitojc_char_dirty = 1;
+}
+
+// Object data format:
+//
+// 0x00: xxxxxx-- -------- -------- -------- Height
+// 0x00: ------xx xxxxxxxx -------- -------- Y
+// 0x00: -------- -------- xxxxxx-- -------- Width
+// 0x00: -------- -------- ------xx xxxxxxxx X
+// 0x01: ---xxxxx xx------ -------- -------- Palette
+// 0x01: -------- --x----- -------- -------- Priority (0 = below 3D, 1 = above 3D)
+// 0x01: -------- -------- -xxxxxxx xxxxxxxx VRAM data address
+
+static void draw_object(mame_bitmap *bitmap, const rectangle *cliprect, UINT32 w1, UINT32 w2)
+{
+ int x, y, width, height, palette;
+ int i, j;
+ int x1, x2, y1, y2;
+ int ix, iy;
+ UINT32 address;
+ UINT8 *v;
+
+ address = (w2 & 0x7fff) * 0x20;
+ if (w2 & 0x4000)
+ address |= 0x40000;
+
+ x = ((w1 >> 0) & 0x3ff);
+ if (x & 0x200)
+ x |= ~0x1ff; // sign-extend
+
+ y = ((w1 >> 16) & 0x3ff);
+ if (y & 0x200)
+ y |= ~0x1ff; // sign-extend
+
+ width = ((w1 >> 10) & 0x3f) * 16;
+ height = ((w1 >> 26) & 0x3f) * 16;
+ palette = ((w2 >> 22) & 0x7f) << 8;
+
+ v = (UINT8*)&taitojc_vram[address/4];
+
+ if (address >= 0xf8000 || width == 0 || height == 0)
+ return;
+
+ x1 = x;
+ x2 = x + width;
+ y1 = y;
+ y2 = y + height;
+
+ // trivial rejection
+ if (x1 > cliprect->max_x || x2 < cliprect->min_x || y1 > cliprect->max_y || y2 < cliprect->min_y)
+ {
+ return;
+ }
+
+// mame_printf_debug("draw_object: %08X %08X, X: %d, Y: %d, W: %d, H: %d\n", w1, w2, x, y, width, height);
+
+ ix = 0;
+ iy = 0;
+
+ // clip
+ if (x1 < cliprect->min_x)
+ {
+ ix = abs(cliprect->min_x - x1);
+ x1 = cliprect->min_x;
+ }
+ if (x2 > cliprect->max_x)
+ {
+ x2 = cliprect->max_x;
+ }
+ if (y1 < cliprect->min_y)
+ {
+ iy = abs(cliprect->min_y - y1);
+ y1 = cliprect->min_y;
+ }
+ if (y2 > cliprect->max_y)
+ {
+ y2 = cliprect->max_y;
+ }
+
+ for (j=y1; j < y2; j++)
+ {
+ UINT16 *d = BITMAP_ADDR16(bitmap, j, 0);
+ int index = (iy * width) + ix;
+
+ for (i=x1; i < x2; i++)
+ {
+ UINT8 pen = v[BYTE4_XOR_BE(index)];
+ if (pen != 0)
+ {
+ d[i] = palette + pen;
+ }
+ index++;
+ }
+
+ iy++;
+ }
+}
+
+static void taitojc_exit(running_machine *machine)
+{
+ poly_free(poly);
+}
+
+VIDEO_START( taitojc )
+{
+ poly = poly_alloc(4000, sizeof(poly_extra_data), POLYFLAG_ALLOW_QUADS);
+ add_exit_callback(machine, taitojc_exit);
+
+ /* find first empty slot to decode gfx */
+ for (taitojc_gfx_index = 0; taitojc_gfx_index < MAX_GFX_ELEMENTS; taitojc_gfx_index++)
+ if (machine->gfx[taitojc_gfx_index] == 0)
+ break;
+
+ assert(taitojc_gfx_index != MAX_GFX_ELEMENTS);
+
+ taitojc_tilemap = tilemap_create(taitojc_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 64, 64);
+ taitojc_dirty_map = auto_malloc(TAITOJC_NUM_TILES);
+
+ tilemap_set_transparent_pen(taitojc_tilemap, 0);
+
+ taitojc_char_ram = auto_malloc(0x4000);
+ taitojc_tile_ram = auto_malloc(0x4000);
+
+ memset(taitojc_char_ram, 0, 0x4000);
+ memset(taitojc_tile_ram, 0, 0x4000);
+
+ /* create the char set (gfx will then be updated dynamically from RAM) */
+ machine->gfx[taitojc_gfx_index] = allocgfx(&taitojc_char_layout);
+
+ /* set the color information */
+ if (machine->drv->color_table_len)
+ machine->gfx[taitojc_gfx_index]->total_colors = machine->drv->color_table_len / 16;
+ else
+ machine->gfx[taitojc_gfx_index]->total_colors = machine->drv->total_colors / 16;
+
+ taitojc_texture = auto_malloc(0x400000);
+
+ framebuffer = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ zbuffer = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+}
+
+//static int tick = 0;
+VIDEO_UPDATE( taitojc )
+{
+ int i;
+
+ /*
+ tick++;
+ if( tick >= 5 ) {
+ tick = 0;
+
+ if( input_code_pressed(KEYCODE_O) )
+ debug_tex_pal++;
+
+ if( input_code_pressed(KEYCODE_I) )
+ debug_tex_pal--;
+
+ debug_tex_pal &= 0x7f;
+ }
+ */
+
+ fillbitmap(bitmap, 0, cliprect);
+
+ for (i=(0xc00/4)-2; i >= 0; i-=2)
+ {
+ UINT32 w1 = taitojc_objlist[i + 0];
+ UINT32 w2 = taitojc_objlist[i + 1];
+
+ if ((w2 & 0x200000) == 0)
+ {
+ draw_object(bitmap, cliprect, w1, w2);
+ }
+ }
+
+ copybitmap(bitmap, framebuffer, 0, 0, 0, 0, cliprect, TRANSPARENCY_PEN, 0);
+
+ for (i=(0xc00/4)-2; i >= 0; i-=2)
+ {
+ UINT32 w1 = taitojc_objlist[i + 0];
+ UINT32 w2 = taitojc_objlist[i + 1];
+
+ if ((w2 & 0x200000) != 0)
+ {
+ draw_object(bitmap, cliprect, w1, w2);
+ }
+ }
+
+ taitojc_tile_update(machine);
+ tilemap_draw(bitmap, cliprect, taitojc_tilemap, 0,0);
+
+ /*
+ if (debug_tex_pal > 0)
+ {
+ int j;
+ for (j=cliprect->min_y; j <= cliprect->max_y; j++)
+ {
+ UINT16 *d = BITMAP_ADDR16(bitmap, j, 0);
+ int index = 2048 * j;
+
+ for (i=cliprect->min_x; i <= cliprect->max_x; i++)
+ {
+ UINT8 t = taitojc_texture[index+i];
+ UINT32 color;
+
+ //color = 0xff000000 | (t << 16) | (t << 8) | (t);
+ color = (debug_tex_pal << 8) | t;
+
+ d[i] = color;
+ }
+ }
+
+ {
+ char string[200];
+ sprintf(string, "Texture palette %d", debug_tex_pal);
+ popmessage("%s", string);
+ }
+ }
+ */
+
+ return 0;
+}
+
+
+
+
+static void render_solid_scan(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ mame_bitmap *destmap = dest;
+ float z = extent->param[0].start;
+ int color = extent->param[1].start;
+ float dz = extent->param[0].dpdx;
+ UINT16 *fb = BITMAP_ADDR16(destmap, scanline, 0);
+ UINT16 *zb = BITMAP_ADDR16(zbuffer, scanline, 0);
+ int x;
+
+ for (x = extent->startx; x < extent->stopx; x++)
+ {
+ int iz = (int)z & 0xffff;
+
+ if (iz <= zb[x])
+ {
+ fb[x] = color;
+ zb[x] = iz;
+ }
+
+ z += dz;
+ }
+}
+
+static void render_shade_scan(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ mame_bitmap *destmap = dest;
+ float z = extent->param[0].start;
+ float color = extent->param[1].start;
+ float dz = extent->param[0].dpdx;
+ float dcolor = extent->param[1].dpdx;
+ UINT16 *fb = BITMAP_ADDR16(destmap, scanline, 0);
+ UINT16 *zb = BITMAP_ADDR16(zbuffer, scanline, 0);
+ int x;
+
+ for (x = extent->startx; x < extent->stopx; x++)
+ {
+ int ic = (int)color & 0xffff;
+ int iz = (int)z & 0xffff;
+
+ if (iz <= zb[x])
+ {
+ fb[x] = ic;
+ zb[x] = iz;
+ }
+
+ color += dcolor;
+ z += dz;
+ }
+}
+
+static void render_texture_scan(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = extradata;
+ mame_bitmap *destmap = dest;
+ float z = extent->param[0].start;
+ float u = extent->param[1].start;
+ float v = extent->param[2].start;
+ float color = extent->param[3].start;
+ float dz = extent->param[0].dpdx;
+ float du = extent->param[1].dpdx;
+ float dv = extent->param[2].dpdx;
+ float dcolor = extent->param[3].dpdx;
+ UINT16 *fb = BITMAP_ADDR16(destmap, scanline, 0);
+ UINT16 *zb = BITMAP_ADDR16(zbuffer, scanline, 0);
+ int tex_wrap_x = extra->tex_wrap_x;
+ int tex_wrap_y = extra->tex_wrap_y;
+ int tex_base_x = extra->tex_base_x;
+ int tex_base_y = extra->tex_base_y;
+ int x;
+
+ for (x = extent->startx; x < extent->stopx; x++)
+ {
+ int iu, iv;
+ UINT8 texel;
+ int palette = ((int)color & 0x7f) << 8;
+ int iz = (int)z & 0xffff;
+
+ if (!tex_wrap_x)
+ {
+ iu = ((int)u >> 4) & 0x7ff;
+ }
+ else
+ {
+ iu = (tex_base_x + (((int)u >> 4) & 0x3f)) & 0x7ff;
+ }
+
+ if (!tex_wrap_y)
+ {
+ iv = ((int)v >> 4) & 0x7ff;
+ }
+ else
+ {
+ iv = (tex_base_y + (((int)v >> 4) & 0x3f)) & 0x7ff;
+ }
+
+ texel = taitojc_texture[(iv * 2048) + iu];
+
+ if (iz <= zb[x] && texel != 0)
+ {
+ fb[x] = palette | texel;
+ zb[x] = iz;
+ }
+
+ u += du;
+ v += dv;
+ color += dcolor;
+ z += dz;
+ }
+}
+
+void taitojc_render_polygons(UINT16 *polygon_fifo, int length)
+{
+ poly_vertex vert[4];
+ int i;
+ int ptr;
+
+ ptr = 0;
+ while (ptr < length)
+ {
+ UINT16 cmd = polygon_fifo[ptr++];
+
+ switch (cmd & 0x7)
+ {
+ case 0x03: // Textured Triangle
+ {
+ // 0x00: Command ID (0x0003)
+ // 0x01: Texture base
+ // 0x02: Vertex 1 Palette
+ // 0x03: Vertex 1 V
+ // 0x04: Vertex 1 U
+ // 0x05: Vertex 1 Y
+ // 0x06: Vertex 1 X
+ // 0x07: Vertex 1 Z
+ // 0x08: Vertex 2 Palette
+ // 0x09: Vertex 2 V
+ // 0x0a: Vertex 2 U
+ // 0x0b: Vertex 2 Y
+ // 0x0c: Vertex 2 X
+ // 0x0d: Vertex 2 Z
+ // 0x0e: Vertex 3 Palette
+ // 0x0f: Vertex 3 V
+ // 0x10: Vertex 3 U
+ // 0x11: Vertex 3 Y
+ // 0x12: Vertex 3 X
+ // 0x13: Vertex 3 Z
+
+ poly_extra_data *extra = poly_get_extra_data(poly);
+ UINT16 texbase;
+
+ /*
+ printf("CMD3: ");
+ for (i=0; i < 0x13; i++)
+ {
+ printf("%04X ", polygon_fifo[ptr+i]);
+ }
+ printf("\n");
+ */
+
+ texbase = polygon_fifo[ptr++];
+
+ extra->tex_base_x = ((texbase >> 0) & 0xff) << 4;
+ extra->tex_base_y = ((texbase >> 8) & 0xff) << 4;
+
+ extra->tex_wrap_x = (cmd & 0xc0) ? 1 : 0;
+ extra->tex_wrap_y = (cmd & 0x30) ? 1 : 0;
+
+ for (i=0; i < 3; i++)
+ {
+ vert[i].p[3] = polygon_fifo[ptr++]; // palette
+ vert[i].p[2] = (UINT16)(polygon_fifo[ptr++]);
+ vert[i].p[1] = (UINT16)(polygon_fifo[ptr++]);
+ vert[i].y = (INT16)(polygon_fifo[ptr++]);
+ vert[i].x = (INT16)(polygon_fifo[ptr++]);
+ vert[i].p[0] = (UINT16)(polygon_fifo[ptr++]);
+ }
+
+ if (vert[0].p[0] < 0x8000 && vert[1].p[0] < 0x8000 && vert[2].p[0] < 0x8000)
+ {
+ poly_render_triangle(poly, framebuffer, &Machine->screen[0].visarea, render_texture_scan, 4, &vert[0], &vert[1], &vert[2]);
+ }
+ break;
+ }
+ case 0x04: // Gouraud shaded Quad
+ {
+ // 0x00: Command ID (0x0004)
+ // 0x01: Vertex 0 color
+ // 0x02: Vertex 0 Y
+ // 0x03: Vertex 0 X
+ // 0x04: Vertex 0 Z
+ // 0x05: Vertex 1 color
+ // 0x06: Vertex 1 Y
+ // 0x07: Vertex 1 X
+ // 0x08: Vertex 1 Z
+ // 0x09: Vertex 2 color
+ // 0x0a: Vertex 2 Y
+ // 0x0b: Vertex 2 X
+ // 0x0c: Vertex 2 Z
+ // 0x0d: Vertex 3 color
+ // 0x0e: Vertex 3 Y
+ // 0x0f: Vertex 3 X
+ // 0x10: Vertex 3 Z
+
+ /*
+ printf("CMD4: ");
+ for (i=0; i < 0x10; i++)
+ {
+ printf("%04X ", polygon_fifo[ptr+i]);
+ }
+ printf("\n");
+ */
+
+ for (i=0; i < 4; i++)
+ {
+ vert[i].p[1] = polygon_fifo[ptr++];
+ vert[i].y = (INT16)(polygon_fifo[ptr++]);
+ vert[i].x = (INT16)(polygon_fifo[ptr++]);
+ vert[i].p[0] = (UINT16)(polygon_fifo[ptr++]);
+ }
+
+ if (vert[0].p[0] < 0x8000 && vert[1].p[0] < 0x8000 && vert[2].p[0] < 0x8000 && vert[3].p[0] < 0x8000)
+ {
+ if (vert[0].p[1] == vert[1].p[1] &&
+ vert[1].p[1] == vert[2].p[1] &&
+ vert[2].p[1] == vert[3].p[1])
+ {
+ // optimization: all colours the same -> render solid
+ poly_render_quad(poly, framebuffer, &Machine->screen[0].visarea, render_solid_scan, 2, &vert[0], &vert[1], &vert[2], &vert[3]);
+ }
+ else
+ {
+ poly_render_quad(poly, framebuffer, &Machine->screen[0].visarea, render_shade_scan, 2, &vert[0], &vert[1], &vert[2], &vert[3]);
+ }
+ }
+ break;
+ }
+ case 0x06: // Textured Quad
+ {
+ // 0x00: Command ID (0x0006)
+ // 0x01: Texture base
+ // 0x02: Vertex 1 Palette
+ // 0x03: Vertex 1 V
+ // 0x04: Vertex 1 U
+ // 0x05: Vertex 1 Y
+ // 0x06: Vertex 1 X
+ // 0x07: Vertex 1 Z
+ // 0x08: Vertex 2 Palette
+ // 0x09: Vertex 2 V
+ // 0x0a: Vertex 2 U
+ // 0x0b: Vertex 2 Y
+ // 0x0c: Vertex 2 X
+ // 0x0d: Vertex 2 Z
+ // 0x0e: Vertex 3 Palette
+ // 0x0f: Vertex 3 V
+ // 0x10: Vertex 3 U
+ // 0x11: Vertex 3 Y
+ // 0x12: Vertex 3 X
+ // 0x13: Vertex 3 Z
+ // 0x14: Vertex 4 Palette
+ // 0x15: Vertex 4 V
+ // 0x16: Vertex 4 U
+ // 0x17: Vertex 4 Y
+ // 0x18: Vertex 4 X
+ // 0x19: Vertex 4 Z
+
+ poly_extra_data *extra = poly_get_extra_data(poly);
+ UINT16 texbase;
+
+ /*
+ printf("CMD6: ");
+ for (i=0; i < 0x19; i++)
+ {
+ printf("%04X ", polygon_fifo[ptr+i]);
+ }
+ printf("\n");
+ */
+
+ texbase = polygon_fifo[ptr++];
+
+ extra->tex_base_x = ((texbase >> 0) & 0xff) << 4;
+ extra->tex_base_y = ((texbase >> 8) & 0xff) << 4;
+
+ extra->tex_wrap_x = (cmd & 0xc0) ? 1 : 0;
+ extra->tex_wrap_y = (cmd & 0x30) ? 1 : 0;
+
+ for (i=0; i < 4; i++)
+ {
+ vert[i].p[3] = polygon_fifo[ptr++]; // palette
+ vert[i].p[2] = (UINT16)(polygon_fifo[ptr++]);
+ vert[i].p[1] = (UINT16)(polygon_fifo[ptr++]);
+ vert[i].y = (INT16)(polygon_fifo[ptr++]);
+ vert[i].x = (INT16)(polygon_fifo[ptr++]);
+ vert[i].p[0] = (UINT16)(polygon_fifo[ptr++]);
+ }
+
+ if (vert[0].p[0] < 0x8000 && vert[1].p[0] < 0x8000 && vert[2].p[0] < 0x8000 && vert[3].p[0] < 0x8000)
+ {
+ poly_render_quad(poly, framebuffer, &Machine->screen[0].visarea, render_texture_scan, 4, &vert[0], &vert[1], &vert[2], &vert[3]);
+ }
+ break;
+ }
+ case 0x00:
+ {
+ ptr += 6;
+ break;
+ }
+ default:
+ {
+ //printf("render_polygons: unknown command %04X\n", cmd);
+ }
+ }
+ };
+ poly_wait(poly, "Finished render");
+}
+
+void taitojc_clear_frame(void)
+{
+ rectangle cliprect;
+
+ cliprect.min_x = 0;
+ cliprect.min_y = 0;
+ cliprect.max_x = Machine->screen[0].width-1;
+ cliprect.max_y = Machine->screen[0].height-1;
+
+ fillbitmap(framebuffer, 0, &cliprect);
+ fillbitmap(zbuffer, 0xffff, &cliprect);
+}
diff --git a/src/mame/video/taitosj.c b/src/mame/video/taitosj.c
new file mode 100644
index 00000000000..1677595bb60
--- /dev/null
+++ b/src/mame/video/taitosj.c
@@ -0,0 +1,934 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+#ifndef MIN
+#define MIN(x,y) (x)<(y)?(x):(y)
+#endif
+
+
+UINT8 *taitosj_videoram2,*taitosj_videoram3;
+UINT8 *taitosj_characterram;
+UINT8 *taitosj_scroll;
+UINT8 *taitosj_colscrolly;
+UINT8 *taitosj_gfxpointer;
+UINT8 *taitosj_colorbank,*taitosj_video_priority;
+UINT8 *kikstart_scrollram;
+static UINT8 *taitosj_spritebank;
+static UINT8 taitosj_collision_reg[4];
+static UINT8 *dirtybuffer2,*dirtybuffer3;
+static mame_bitmap *taitosj_tmpbitmap[3];
+static mame_bitmap *sprite_sprite_collbitmap1,*sprite_sprite_collbitmap2;
+static mame_bitmap *sprite_plane_collbitmap1;
+static mame_bitmap *sprite_plane_collbitmap2[3];
+static UINT8 dirtycharacter1[256],dirtycharacter2[256];
+static UINT8 dirtysprite1[64],dirtysprite2[64];
+static UINT8 taitosj_video_enable;
+static UINT8 flipscreen[2];
+static rectangle spritearea[32]; /*areas on bitmap (sprite locations)*/
+static UINT8 spriteon[32]; /* 1 if sprite is active */
+
+static int playfield_enable_mask[3] = { 0x10, 0x20, 0x40 };
+
+
+/***************************************************************************
+
+ I call the three planes with the conventional names "front", "middle" and
+ "back", because that's their default order, but they can be arranged,
+ together with the sprites, in any order. The priority is selected by
+ register 0xd300, which works as follow:
+
+ bits 0-3 go to A4-A7 of a 256x4 PROM
+ bit 4 selects D0/D1 or D2/D3 of the PROM
+ bit 5-7 n.c.
+ A0-A3 of the PROM is fed with a mask of the inactive planes
+ (i.e. all-zero) in the order sprites-front-middle-back
+ the 2-bit code which comes out from the PROM selects the plane
+ to display.
+
+ Here is a dump of one of these PROMs; on the right is the resulting order
+ (s = sprites f = front m = middle b = back). Note that, in theory, the
+ PROM could encode some really funky priority schemes which couldn't be
+ reconducted to the simple layer order given here. Luckily, none of the
+ games seem to do that. Actually, all of them seem to use the same PROM,
+ with the exception of Wild Western.
+
+ d300 pri d300 pri
+ 00: 08 09 08 0A 00 05 00 0F 08 09 08 0A 00 05 00 0F | 00 sfmb 10 msfb
+ 10: 08 09 08 0B 00 0D 00 0F 08 09 08 0A 00 05 00 0F | 01 sfbm 11 msbf
+ 20: 08 0A 08 0A 04 05 00 0F 08 0A 08 0A 04 05 00 0F | 02 smfb 12 mfsb
+ 30: 08 0A 08 0A 04 07 0C 0F 08 0A 08 0A 04 05 00 0F | 03 smbf 13 mfbs
+ 40: 08 0B 08 0B 0C 0F 0C 0F 08 09 08 0A 00 05 00 0F | 04 sbfm 14 mbsf
+ 50: 08 0B 08 0B 0C 0F 0C 0F 08 0A 08 0A 04 05 00 0F | 05 sbmf 15 mbfs
+ 60: 0D 0D 0C 0E 0D 0D 0C 0F 01 05 00 0A 01 05 00 0F | 06 fsmb 16 bsfm
+ 70: 0D 0D 0C 0F 0D 0D 0C 0F 01 09 00 0A 01 05 00 0F | 07 fsbm 17 bsmf
+ 80: 0D 0D 0E 0E 0D 0D 0C 0F 05 05 02 0A 05 05 00 0F | 08 fmsb 18 bfsm
+ 90: 0D 0D 0E 0E 0D 0D 0F 0F 05 05 0A 0A 05 05 00 0F | 09 fmbs 19 bfms
+ A0: 0D 0D 0F 0F 0D 0D 0F 0F 09 09 08 0A 01 05 00 0F | 0A fbsm 1A bmsf
+ B0: 0D 0D 0F 0F 0D 0D 0F 0F 09 09 0A 0A 05 05 00 0F | 0B fbms 1B bmfs
+ C0: 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F | 0C - 1C -
+ D0: 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F | 0D - 1D -
+ E0: 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F | 0E - 1E -
+ F0: 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F | 0F - 1F -
+
+***************************************************************************/
+
+static int draworder[32][4];
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ The Taito games don't have a color PROM. They use RAM to dynamically
+ create the palette. The resolution is 9 bit (3 bits per gun).
+
+ The RAM is connected to the RGB output this way:
+
+ bit 0 -- inverter -- 220 ohm resistor -- RED
+ bit 7 -- inverter -- 470 ohm resistor -- RED
+ -- inverter -- 1 kohm resistor -- RED
+ -- inverter -- 220 ohm resistor -- GREEN
+ -- inverter -- 470 ohm resistor -- GREEN
+ -- inverter -- 1 kohm resistor -- GREEN
+ -- inverter -- 220 ohm resistor -- BLUE
+ -- inverter -- 470 ohm resistor -- BLUE
+ bit 0 -- inverter -- 1 kohm resistor -- BLUE
+
+***************************************************************************/
+
+PALETTE_INIT( taitosj )
+{
+ int i;
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ /* all gfx elements use the same palette */
+ for (i = 0;i < 64;i++)
+ {
+ COLOR(0,i) = i;
+ /* we create both a "normal" lookup table and one where pen 0 is */
+ /* always mapped to color 0. This is needed for transparency. */
+ if (i % 8 == 0) COLOR(0,i + 64) = 0;
+ else COLOR(0,i + 64) = i;
+ }
+
+
+ /* do a simple conversion of the PROM into layer priority order. Note that */
+ /* this is a simplification, which assumes the PROM encodes a sensible priority */
+ /* scheme. */
+ color_prom = memory_region(REGION_PROMS);
+ for (i = 0;i < 32;i++)
+ {
+ int j,mask;
+
+ mask = 0; /* start with all four layers active, so we'll get the highest */
+ /* priority one in the first loop */
+
+ for (j = 3;j >= 0;j--)
+ {
+ int data;
+
+ data = color_prom[0x10 * (i & 0x0f) + mask];
+ if (i & 0x10) data >>= 2;
+ data &= 0x03;
+ mask |= (1 << data); /* in next loop, we'll see which of the remaining */
+ /* layers has top priority when this one is transparent */
+ draworder[i][j] = data;
+ }
+ }
+}
+
+
+
+WRITE8_HANDLER( taitosj_paletteram_w )
+{
+ int bit0,bit1,bit2;
+ int r,g,b,val;
+
+
+ paletteram[offset] = data;
+
+ /* red component */
+ val = paletteram[offset | 1];
+ bit0 = (~val >> 6) & 0x01;
+ bit1 = (~val >> 7) & 0x01;
+ val = paletteram[offset & ~1];
+ bit2 = (~val >> 0) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* green component */
+ val = paletteram[offset | 1];
+ bit0 = (~val >> 3) & 0x01;
+ bit1 = (~val >> 4) & 0x01;
+ bit2 = (~val >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* blue component */
+ val = paletteram[offset | 1];
+ bit0 = (~val >> 0) & 0x01;
+ bit1 = (~val >> 1) & 0x01;
+ bit2 = (~val >> 2) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(Machine,offset / 2,MAKE_RGB(r,g,b));
+}
+
+static void taitosj_postload(void)
+{
+ memset(dirtybuffer, 1, videoram_size);
+ memset(dirtybuffer2, 1, videoram_size);
+ memset(dirtybuffer3, 1, videoram_size);
+ memset(dirtycharacter1, 1, sizeof(dirtycharacter1));
+ memset(dirtycharacter2, 1, sizeof(dirtycharacter2));
+ memset(dirtysprite1, 1, sizeof(dirtysprite1));
+ memset(dirtysprite2, 1, sizeof(dirtysprite2));
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+VIDEO_START( taitosj )
+{
+ int i;
+
+
+ taitosj_tmpbitmap[0] = taitosj_tmpbitmap[1] = taitosj_tmpbitmap[2] = 0;
+ sprite_sprite_collbitmap2 = sprite_sprite_collbitmap1 = 0;
+ sprite_plane_collbitmap1 = 0;
+ sprite_plane_collbitmap2[0] = sprite_plane_collbitmap2[1] = sprite_plane_collbitmap2[2] = 0;
+ dirtybuffer3 = dirtybuffer2 = 0;
+
+
+ video_start_generic(machine);
+
+ dirtybuffer2 = auto_malloc(videoram_size);
+ memset(dirtybuffer2,1,videoram_size);
+
+ dirtybuffer3 = auto_malloc(videoram_size);
+ memset(dirtybuffer3,1,videoram_size);
+
+ sprite_plane_collbitmap1 = auto_bitmap_alloc(16,16,machine->screen[0].format);
+
+ for (i = 0; i < 3; i++)
+ {
+ taitosj_tmpbitmap[i] = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+
+ sprite_plane_collbitmap2[i] = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ }
+
+ sprite_sprite_collbitmap1 = auto_bitmap_alloc(32,32,machine->screen[0].format);
+ sprite_sprite_collbitmap2 = auto_bitmap_alloc(32,32,machine->screen[0].format);
+
+ flipscreen[0] = flipscreen[1] = 0;
+
+ taitosj_spritebank = spriteram;
+
+ memset(dirtycharacter1, 1, sizeof(dirtycharacter1));
+ memset(dirtycharacter2, 1, sizeof(dirtycharacter2));
+ memset(dirtysprite1, 1, sizeof(dirtysprite1));
+ memset(dirtysprite2, 1, sizeof(dirtysprite2));
+
+ state_save_register_func_postload(taitosj_postload);
+ state_save_register_global_array(taitosj_collision_reg);
+ state_save_register_global(taitosj_video_enable);
+ state_save_register_global_array(flipscreen);
+}
+
+
+
+READ8_HANDLER( taitosj_gfxrom_r )
+{
+ int offs;
+
+
+ offs = taitosj_gfxpointer[0]+taitosj_gfxpointer[1]*256;
+
+ taitosj_gfxpointer[0]++;
+ if (taitosj_gfxpointer[0] == 0) taitosj_gfxpointer[1]++;
+
+ if (offs < 0x8000)
+ return memory_region(REGION_GFX1)[offs];
+ else return 0;
+}
+
+
+WRITE8_HANDLER( taitosj_videoram2_w )
+{
+ if (taitosj_videoram2[offset] != data)
+ {
+ dirtybuffer2[offset] = 1;
+
+ taitosj_videoram2[offset] = data;
+ }
+}
+
+
+
+WRITE8_HANDLER( taitosj_videoram3_w )
+{
+ if (taitosj_videoram3[offset] != data)
+ {
+ dirtybuffer3[offset] = 1;
+
+ taitosj_videoram3[offset] = data;
+ }
+}
+
+
+
+WRITE8_HANDLER( taitosj_colorbank_w )
+{
+ if (taitosj_colorbank[offset] != data)
+ {
+logerror("colorbank %d = %02x\n",offset,data);
+ memset(dirtybuffer,1,videoram_size);
+ memset(dirtybuffer2,1,videoram_size);
+ memset(dirtybuffer3,1,videoram_size);
+
+ taitosj_colorbank[offset] = data;
+ }
+}
+
+
+
+WRITE8_HANDLER( taitosj_videoenable_w )
+{
+ if (taitosj_video_enable != data)
+ {
+logerror("videoenable = %02x\n",data);
+
+ if ((taitosj_video_enable & 3) != (data & 3))
+ {
+ flipscreen[0] = data & 1;
+ flipscreen[1] = data & 2;
+
+ memset(dirtybuffer,1,videoram_size);
+ memset(dirtybuffer2,1,videoram_size);
+ memset(dirtybuffer3,1,videoram_size);
+ }
+
+ //OBJEX sprite bank select
+ if( data & 4 )
+ taitosj_spritebank = spriteram_2;
+ else
+ taitosj_spritebank = spriteram;
+
+ if ((taitosj_video_enable & 4) != (data & 4))
+ logerror( "sprite bank[%d]\n", (data & 4) >> 2 );
+
+ taitosj_video_enable = data;
+ }
+}
+
+
+
+WRITE8_HANDLER( taitosj_characterram_w )
+{
+ if (taitosj_characterram[offset] != data)
+ {
+ if (offset < 0x1800)
+ {
+ dirtycharacter1[(offset / 8) & 0xff] = 1;
+ dirtysprite1[(offset / 32) & 0x3f] = 1;
+ }
+ else
+ {
+ dirtycharacter2[(offset / 8) & 0xff] = 1;
+ dirtysprite2[(offset / 32) & 0x3f] = 1;
+ }
+
+ taitosj_characterram[offset] = data;
+ }
+}
+
+WRITE8_HANDLER( junglhbr_characterram_w )
+{
+ taitosj_characterram_w(offset, data ^ 0xfc);
+}
+
+/***************************************************************************
+
+ As if the hardware weren't complicated enough, it also has built-in
+ collision detection.
+
+***************************************************************************/
+READ8_HANDLER( taitosj_collision_reg_r )
+{
+ return taitosj_collision_reg[offset];
+}
+
+WRITE8_HANDLER( taitosj_collision_reg_clear_w )
+{
+ taitosj_collision_reg[0] = 0;
+ taitosj_collision_reg[1] = 0;
+ taitosj_collision_reg[2] = 0;
+ taitosj_collision_reg[3] = 0;
+}
+
+INLINE int get_sprite_xy(UINT8 num, UINT8* sx, UINT8* sy)
+{
+ int offs = num * 4;
+
+
+ *sx = taitosj_spritebank[offs] - 1;
+ *sy = 240 - taitosj_spritebank[offs + 1];
+ return (*sy < 240);
+}
+
+
+static int check_sprite_sprite_bitpattern(running_machine *machine,
+ int sx1, int sy1, int num1,
+ int sx2, int sy2, int num2)
+{
+ int x,y,minx,miny,maxx = 16,maxy = 16;
+ int offs1 = num1 * 4;
+ int offs2 = num2 * 4;
+
+ /* normalize coordinates to (0,0) and compute overlap */
+ if (sx1 < sx2)
+ {
+ sx2 -= sx1;
+ sx1 = 0;
+ minx = sx2;
+ }
+ else
+ {
+ sx1 -= sx2;
+ sx2 = 0;
+ minx = sx1;
+ }
+
+ if (sy1 < sy2)
+ {
+ sy2 -= sy1;
+ sy1 = 0;
+ miny = sy2;
+ }
+ else
+ {
+ sy1 -= sy2;
+ sy2 = 0;
+ miny = sy1;
+ }
+
+ /* draw the sprites into seperate bitmaps and check overlapping region */
+ drawgfx(sprite_sprite_collbitmap1,machine->gfx[(taitosj_spritebank[offs1 + 3] & 0x40) ? 3 : 1],
+ taitosj_spritebank[offs1 + 3] & 0x3f,
+ 0,
+ taitosj_spritebank[offs1 + 2] & 1, taitosj_spritebank[offs1 + 2] & 2,
+ sx1,sy1,
+ 0,TRANSPARENCY_NONE,0);
+
+ drawgfx(sprite_sprite_collbitmap2,machine->gfx[(taitosj_spritebank[offs2 + 3] & 0x40) ? 3 : 1],
+ taitosj_spritebank[offs2 + 3] & 0x3f,
+ 0,
+ taitosj_spritebank[offs2 + 2] & 1, taitosj_spritebank[offs2 + 2] & 2,
+ sx2,sy2,
+ 0,TRANSPARENCY_NONE,0);
+
+ for (y = miny;y < maxy;y++)
+ {
+ for(x = minx;x < maxx;x++)
+ {
+ if ((*BITMAP_ADDR16(sprite_sprite_collbitmap1, y, x) != machine->pens[0]) &&
+ (*BITMAP_ADDR16(sprite_sprite_collbitmap2, y, x) != machine->pens[0]))
+ {
+ return 1; /* collided */
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static void check_sprite_sprite_collision(running_machine *machine)
+{
+ UINT8 i,j,sx1,sx2,sy1,sy2;
+
+
+ if (taitosj_video_enable & 0x80) // check OBJOFF
+ {
+ /* chech each pair of sprites */
+ for (i = 0x00; i < 0x20; i++)
+ {
+ if ((i >= 0x10) && (i <= 0x17)) continue; /* no sprites here */
+
+ if (get_sprite_xy(i, &sx1, &sy1))
+ {
+ for (j = i+1; j < 0x20; j++)
+ {
+ if ((j >= 0x10) && (j <= 0x17)) continue; /* no sprites here */
+
+ if (get_sprite_xy(j, &sx2, &sy2))
+ {
+ /* rule out any pairs that cannot be touching */
+ if ((abs((INT8)sx1 - (INT8)sx2) < 16) &&
+ (abs((INT8)sy1 - (INT8)sy2) < 16))
+ {
+ if (check_sprite_sprite_bitpattern(machine, sx1, sy1, i, sx2, sy2, j))
+ {
+ /* mark sprite as collided */
+ /* note that only the sprite with the higher number is marked */
+ /* as collided. This is how the hardware works and required */
+ /* by Pirate Pete to be able to finish the last round. */
+ int reg;
+
+ /* Here I am mimicking what I do in the sprite drawing code. */
+ /* The last sprite has to be moved at the start of the list. */
+ if (j == 0x1f)
+ {
+ reg = i >> 3;
+ if (reg == 3) reg = 2;
+
+ taitosj_collision_reg[reg] |= (1 << (i & 0x07));
+ }
+ else
+ {
+ reg = j >> 3;
+ if (reg == 3) reg = 2;
+
+ taitosj_collision_reg[reg] |= (1 << (j & 0x07));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+static void calculate_sprite_areas(running_machine *machine)
+{
+ UINT8 sx,sy;
+ int i,minx,miny,maxx,maxy;
+
+ for (i = 0x00; i < 0x20; i++)
+ {
+ if ((i >= 0x10) && (i <= 0x17)) continue; /* no sprites here */
+
+ if (get_sprite_xy(i, &sx, &sy))
+ {
+ if (flipscreen[0])
+ sx = 238 - sx;
+ if (flipscreen[1])
+ sy = 242 - sy;
+
+ minx = sx;
+ miny = sy;
+
+ maxx = minx+15;
+ maxy = miny+15;
+
+ /* check for bitmap bounds to avoid illegal memory access */
+ if (minx < 0) minx = 0;
+ if (miny < 0) miny = 0;
+ if (maxx >= machine->screen[0].width - 1)
+ maxx = machine->screen[0].width - 1;
+ if (maxy >= machine->screen[0].height - 1)
+ maxy = machine->screen[0].height - 1;
+
+ spritearea[i].min_x = minx;
+ spritearea[i].max_x = maxx;
+ spritearea[i].min_y = miny;
+ spritearea[i].max_y = maxy;
+ spriteon[i] = 1;
+ }
+ else /* sprite is off */
+ {
+ spriteon[i] = 0;
+ }
+ }
+}
+
+static int check_sprite_plane_bitpattern(running_machine *machine, int num)
+{
+ int x,y,flipx,flipy,minx,miny,maxx,maxy;
+ int offs = num * 4;
+ int result = 0; /* no collisions */
+
+ int check_playfield1 = taitosj_video_enable & playfield_enable_mask[0];
+ int check_playfield2 = taitosj_video_enable & playfield_enable_mask[1];
+ int check_playfield3 = taitosj_video_enable & playfield_enable_mask[2];
+
+ minx = spritearea[num].min_x;
+ miny = spritearea[num].min_y;
+ maxx = spritearea[num].max_x + 1;
+ maxy = spritearea[num].max_y + 1;
+
+
+ flipx = taitosj_spritebank[offs + 2] & 1;
+ flipy = taitosj_spritebank[offs + 2] & 2;
+
+ if (flipscreen[0])
+ flipx = !flipx;
+ if (flipscreen[1])
+ flipy = !flipy;
+
+ /* draw sprite into a bitmap and check if playfields collide */
+ drawgfx(sprite_plane_collbitmap1, machine->gfx[(taitosj_spritebank[offs + 3] & 0x40) ? 3 : 1],
+ taitosj_spritebank[offs + 3] & 0x3f,
+ 0,
+ flipx, flipy,
+ 0,0,
+ 0,TRANSPARENCY_NONE,0);
+
+ for (y = miny;y < maxy;y++)
+ {
+ for (x = minx;x < maxx;x++)
+ {
+ if (*BITMAP_ADDR16(sprite_plane_collbitmap1, y-miny, x-minx) != machine->pens[0]) /* is there anything to check for ? */
+ {
+ if (check_playfield1 && (*BITMAP_ADDR16(sprite_plane_collbitmap2[0], y, x) != machine->pens[0]))
+ {
+ result |= 1; /* collided */
+ if (result == 7) goto done;
+ check_playfield1 = 0;
+ }
+ if (check_playfield2 && (*BITMAP_ADDR16(sprite_plane_collbitmap2[1], y, x) != machine->pens[0]))
+ {
+ result |= 2; /* collided */
+ if (result == 7) goto done;
+ check_playfield2 = 0;
+
+ }
+ if (check_playfield3 && (*BITMAP_ADDR16(sprite_plane_collbitmap2[2], y, x) != machine->pens[0]))
+ {
+ result |= 4; /* collided */
+ if (result == 7) goto done;
+ check_playfield3 = 0;
+ }
+ }
+ }
+ }
+
+done:
+ return result;
+}
+
+static void check_sprite_plane_collision(running_machine *machine)
+{
+ UINT8 i;
+
+
+ if (taitosj_video_enable & 0x80) // check OBJOFF
+ {
+ /* check each sprite */
+ for (i = 0x00; i < 0x20; i++)
+ {
+ if ((i >= 0x10) && (i <= 0x17)) continue; /* no sprites here */
+
+ if (spriteon[i])
+ {
+ taitosj_collision_reg[3] |= check_sprite_plane_bitpattern(machine, i);
+ }
+ }
+ }
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap)
+{
+ /* sprite visibility area is missing 4 pixels from the sides, surely to reduce
+ wraparound side effects. This was verified on a real Elevator Action.
+ Note that the clipping is asymmetrical. This matches the real thing.
+ I'm not sure of what should happen when the screen is flipped, though.
+ */
+ static rectangle spritevisiblearea =
+ {
+ 0*8+3, 32*8-1-1,
+ 2*8, 30*8-1
+ };
+ static rectangle spritevisibleareaflip =
+ {
+ 0*8+1, 32*8-3-1,
+ 2*8, 30*8-1
+ };
+
+ if (taitosj_video_enable & 0x80) // check OBJOFF
+ {
+ int sprite;
+
+
+ /* drawing order is a bit strange. The last sprite has to be moved at the start of the list. */
+ for (sprite = 0x1f;sprite >= 0;sprite--)
+ {
+ UINT8 sx,sy,flipx,flipy;
+ int offs = ((sprite - 1) & 0x1f) * 4; // move last sprite at the head of the list
+
+
+ if ((offs >= 0x40) && (offs <= 0x5f)) continue; /* no sprites here */
+
+
+ if (get_sprite_xy(offs / 4, &sx, &sy))
+ {
+ flipx = taitosj_spritebank[offs + 2] & 1;
+ flipy = taitosj_spritebank[offs + 2] & 2;
+ if (flipscreen[0])
+ {
+ sx = 238 - sx;
+ flipx = !flipx;
+ }
+ if (flipscreen[1])
+ {
+ sy = 242 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[(taitosj_spritebank[offs + 3] & 0x40) ? 3 : 1],
+ taitosj_spritebank[offs + 3] & 0x3f,
+ 2 * ((taitosj_colorbank[1] >> 4) & 0x03) + ((taitosj_spritebank[offs + 2] >> 2) & 1),
+ flipx,flipy,
+ sx,sy,
+ flipscreen[0] ? &spritevisibleareaflip : &spritevisiblearea,TRANSPARENCY_PEN,0);
+
+ /* draw with wrap around. The horizontal games (eg. sfposeid) need this */
+ drawgfx(bitmap,machine->gfx[(taitosj_spritebank[offs + 3] & 0x40) ? 3 : 1],
+ taitosj_spritebank[offs + 3] & 0x3f,
+ 2 * ((taitosj_colorbank[1] >> 4) & 0x03) + ((taitosj_spritebank[offs + 2] >> 2) & 1),
+ flipx,flipy,
+ sx - 0x100,sy,
+ flipscreen[0] ? &spritevisibleareaflip : &spritevisiblearea,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+}
+
+
+static void draw_playfield(running_machine *machine, int n, mame_bitmap *bitmap)
+{
+ static int fudge1[3] = { 3, 1, -1 };
+ static int fudge2[3] = { 8, 10, 12 };
+
+ if (taitosj_video_enable & playfield_enable_mask[n])
+ {
+ int i,scrollx,scrolly[32];
+
+
+ scrollx = taitosj_scroll[2*n];
+ if (flipscreen[0])
+ scrollx = (scrollx & 0xf8) + ((scrollx + fudge1[n]) & 7) + fudge2[n];
+ else
+ scrollx = -(scrollx & 0xf8) + ((scrollx + fudge1[n]) & 7) + fudge2[n];
+
+ if (flipscreen[1])
+ {
+ for (i = 0;i < 32;i++)
+ scrolly[31-i] = taitosj_colscrolly[32*n+i] + taitosj_scroll[2*n+1];
+ }
+ else
+ {
+ for (i = 0;i < 32;i++)
+ scrolly[i] = -taitosj_colscrolly[32*n+i] - taitosj_scroll[2*n+1];
+ }
+
+ copyscrollbitmap(bitmap,taitosj_tmpbitmap[n],1,&scrollx,32,scrolly,&machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+
+ /* store parts covered with sprites for sprites/playfields collision detection */
+ for (i=0x00; i<0x20; i++)
+ {
+ if ((i >= 0x10) && (i <= 0x17)) continue; /* no sprites here */
+ if (spriteon[i])
+ copyscrollbitmap( sprite_plane_collbitmap2[n],taitosj_tmpbitmap[n],1,&scrollx,32,scrolly,&spritearea[i],TRANSPARENCY_NONE,0);
+ }
+ }
+}
+
+static void kikstart_draw_playfield(running_machine *machine, int n, mame_bitmap *bitmap)
+{
+ if (taitosj_video_enable & playfield_enable_mask[n])
+ {
+ int i,scrolly,scrollx[32*8];
+
+ for (i = 1;i < 32*8;i++)// 1-255 !
+ {
+ if(flipscreen[1])
+ {
+ switch(n)
+ {
+ case 0: scrollx[32*8-i] = 0 ;break;
+ case 1: scrollx[32*8-i] = kikstart_scrollram[i]+((taitosj_scroll[2*n]+0xa)&0xff);break;
+ case 2: scrollx[32*8-i] = kikstart_scrollram[0x100+i]+((taitosj_scroll[2*n]+0xc)&0xff);break;
+ }
+ }
+ else
+ {
+ switch(n)
+ {
+ case 0: scrollx[i] = 0 ;break;
+ case 1: scrollx[i] = 0xff-kikstart_scrollram[i-1]-((taitosj_scroll[2*n]-0x10)&0xff);break;
+ case 2: scrollx[i] = 0xff-kikstart_scrollram[0x100+i-1]-((taitosj_scroll[2*n]-0x12)&0xff);break;
+ }
+ }
+ }
+ scrolly=taitosj_scroll[2*n+1];//always 0 ?
+ copyscrollbitmap(bitmap,taitosj_tmpbitmap[n],32*8,scrollx,1,&scrolly,&machine->screen[0].visarea,TRANSPARENCY_COLOR,0);
+ /* store parts covered with sprites for sprites/playfields collision detection */
+ for (i=0x00; i<0x20; i++)
+ {
+ if ((i >= 0x10) && (i <= 0x17)) continue; /* no sprites here */
+ if (spriteon[i])
+ copyscrollbitmap( sprite_plane_collbitmap2[n],taitosj_tmpbitmap[n],32*8,scrollx,1,&scrolly,&spritearea[i],TRANSPARENCY_NONE,0);
+ }
+ }
+}
+
+
+static void draw_plane(running_machine *machine, int n, mame_bitmap *bitmap)
+{
+ switch (n)
+ {
+ case 0:
+ draw_sprites(machine, bitmap);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ if(!strcmp(machine->gamedrv->name,"kikstart"))
+ kikstart_draw_playfield(machine, n - 1, bitmap);
+ else
+ draw_playfield(machine, n - 1, bitmap);
+ break;
+ }
+}
+
+
+VIDEO_UPDATE( taitosj )
+{
+ int offs,i,alldirty = 0;
+
+
+ /* decode modified characters */
+ for (offs = 0;offs < 256;offs++)
+ {
+ if (dirtycharacter1[offs] == 1)
+ {
+ decodechar(machine->gfx[0],offs,taitosj_characterram,machine->drv->gfxdecodeinfo[0].gfxlayout);
+ dirtycharacter1[offs] = 0;
+ alldirty = 1;
+ }
+ if (dirtycharacter2[offs] == 1)
+ {
+ decodechar(machine->gfx[2],offs,taitosj_characterram + 0x1800,machine->drv->gfxdecodeinfo[2].gfxlayout);
+ dirtycharacter2[offs] = 0;
+ alldirty = 1;
+ }
+ }
+
+ /* if characters changed, redraw everything */
+ if (alldirty)
+ {
+ memset(dirtybuffer, 1,videoram_size);
+ memset(dirtybuffer2,1,videoram_size);
+ memset(dirtybuffer3,1,videoram_size);
+ }
+
+ /* decode modified sprites */
+ for (offs = 0;offs < 64;offs++)
+ {
+ if (dirtysprite1[offs] == 1)
+ {
+ decodechar(machine->gfx[1],offs,taitosj_characterram,machine->drv->gfxdecodeinfo[1].gfxlayout);
+ dirtysprite1[offs] = 0;
+ }
+ if (dirtysprite2[offs] == 1)
+ {
+ decodechar(machine->gfx[3],offs,taitosj_characterram + 0x1800,machine->drv->gfxdecodeinfo[3].gfxlayout);
+ dirtysprite2[offs] = 0;
+ }
+ }
+
+
+ /* for every character in the Video RAM, check if it has been modified */
+ /* since last time and update it accordingly. */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ if (dirtybuffer[offs])
+ {
+ int sx,sy;
+
+
+ dirtybuffer[offs] = 0;
+
+ sx = offs % 32;
+ sy = offs / 32;
+ if (flipscreen[0]) sx = 31 - sx;
+ if (flipscreen[1]) sy = 31 - sy;
+
+ drawgfx(taitosj_tmpbitmap[0],machine->gfx[taitosj_colorbank[0] & 0x08 ? 2 : 0],
+ videoram[offs],
+ (taitosj_colorbank[0] & 0x07) + 8, /* use transparent pen 0 */
+ flipscreen[0],flipscreen[1],
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+
+ if (dirtybuffer2[offs])
+ {
+ int sx,sy;
+
+
+ dirtybuffer2[offs] = 0;
+
+ sx = offs % 32;
+ sy = offs / 32;
+ if (flipscreen[0]) sx = 31 - sx;
+ if (flipscreen[1]) sy = 31 - sy;
+
+ drawgfx(taitosj_tmpbitmap[1],machine->gfx[taitosj_colorbank[0] & 0x80 ? 2 : 0],
+ taitosj_videoram2[offs],
+ ((taitosj_colorbank[0] >> 4) & 0x07) + 8, /* use transparent pen 0 */
+ flipscreen[0],flipscreen[1],
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+
+ if (dirtybuffer3[offs])
+ {
+ int sx,sy;
+
+
+ dirtybuffer3[offs] = 0;
+
+ sx = offs % 32;
+ sy = offs / 32;
+ if (flipscreen[0]) sx = 31 - sx;
+ if (flipscreen[1]) sy = 31 - sy;
+
+ drawgfx(taitosj_tmpbitmap[2],machine->gfx[taitosj_colorbank[1] & 0x08 ? 2 : 0],
+ taitosj_videoram3[offs],
+ (taitosj_colorbank[1] & 0x07) + 8, /* use transparent pen 0 */
+ flipscreen[0],flipscreen[1],
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+
+ /*called here because draw_playfield() uses its output (spritearea[32]) */
+ calculate_sprite_areas(machine);
+
+ /* first of all, fill the screen with the background color */
+ fillbitmap(bitmap,machine->pens[8 * (taitosj_colorbank[1] & 0x07)], cliprect);
+
+ for (i = 0;i < 4;i++)
+ draw_plane(machine, draworder[*taitosj_video_priority & 0x1f][i],bitmap);
+
+ check_sprite_sprite_collision(machine);
+
+ /*check_sprite_plane_collision() uses drawn bitmaps, so it must me called _AFTER_ drawplane() */
+ check_sprite_plane_collision(machine);
+
+ /*check_plane_plane_collision();*/ /*not implemented !!!*/
+ return 0;
+}
diff --git a/src/mame/video/tank8.c b/src/mame/video/tank8.c
new file mode 100644
index 00000000000..97d4e2a40aa
--- /dev/null
+++ b/src/mame/video/tank8.c
@@ -0,0 +1,275 @@
+/***************************************************************************
+
+Atari Tank 8 video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/tank8.h"
+
+
+UINT8* tank8_video_ram;
+UINT8* tank8_pos_h_ram;
+UINT8* tank8_pos_v_ram;
+UINT8* tank8_pos_d_ram;
+
+static tilemap* tilemap1;
+static tilemap* tilemap2;
+
+static mame_bitmap* helper1;
+static mame_bitmap* helper2;
+static mame_bitmap* helper3;
+
+
+
+WRITE8_HANDLER( tank8_video_ram_w )
+{
+ tank8_video_ram[offset] = data;
+ tilemap_mark_tile_dirty(tilemap1, offset);
+ tilemap_mark_tile_dirty(tilemap2, offset);
+}
+
+
+
+static TILE_GET_INFO( tank8_get_tile_info1 )
+{
+ UINT8 code = tank8_video_ram[tile_index];
+
+ int color = 0;
+
+ if ((code & 0x38) == 0x28)
+ {
+ color = 9; /* walls & mines */
+ }
+ else
+ {
+ if (tile_index & 0x010)
+ {
+ color |= 1;
+ }
+ if (code & 0x80)
+ {
+ color |= 2;
+ }
+ if (tile_index & 0x200)
+ {
+ color |= 4;
+ }
+ }
+
+ SET_TILE_INFO(code >> 7, code, color, (code & 0x40) ? (TILE_FLIPX | TILE_FLIPY) : 0);
+}
+
+
+static TILE_GET_INFO( tank8_get_tile_info2 )
+{
+ UINT8 code = tank8_video_ram[tile_index];
+
+ int color = 8;
+
+ if ((code & 0x38) == 0x28)
+ {
+ if ((code & 7) != 3)
+ {
+ color = 1; /* walls */
+ }
+ else
+ {
+ color = 2; /* mines */
+ }
+ }
+
+ SET_TILE_INFO(code >> 7, code, color, (code & 0x40) ? (TILE_FLIPX | TILE_FLIPY) : 0);
+}
+
+
+VIDEO_START( tank8 )
+{
+ helper1 = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ helper2 = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+ helper3 = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ tilemap1 = tilemap_create(tank8_get_tile_info1, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+ tilemap2 = tilemap_create(tank8_get_tile_info2, tilemap_scan_rows, TILEMAP_TYPE_PEN, 16, 16, 32, 32);
+
+ /* VBLANK starts on scanline #256 and ends on scanline #24 */
+
+ tilemap_set_scrolly(tilemap1, 0, 2 * 24);
+ tilemap_set_scrolly(tilemap2, 0, 2 * 24);
+}
+
+
+static int get_x_pos(int n)
+{
+ return 498 - tank8_pos_h_ram[n] - 2 * (tank8_pos_d_ram[n] & 128); /* ? */
+}
+
+
+static int get_y_pos(int n)
+{
+ return 2 * tank8_pos_v_ram[n] - 62;
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ {
+ UINT8 code = ~tank8_pos_d_ram[i];
+
+ int x = get_x_pos(i);
+ int y = get_y_pos(i);
+
+ drawgfx(bitmap, machine->gfx[(code & 0x04) ? 2 : 3],
+ code & 0x03,
+ i,
+ code & 0x10,
+ code & 0x08,
+ x,
+ y,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+
+static void draw_bullets(mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ {
+ rectangle rect;
+
+ int x = get_x_pos(8 + i);
+ int y = get_y_pos(8 + i);
+
+ x -= 4; /* ? */
+
+ rect.min_x = x;
+ rect.min_y = y;
+ rect.max_x = rect.min_x + 3;
+ rect.max_y = rect.min_y + 4;
+
+ if (rect.min_x < cliprect->min_x)
+ rect.min_x = cliprect->min_x;
+ if (rect.min_y < cliprect->min_y)
+ rect.min_y = cliprect->min_y;
+ if (rect.max_x > cliprect->max_x)
+ rect.max_x = cliprect->max_x;
+ if (rect.max_y > cliprect->max_y)
+ rect.max_y = cliprect->max_y;
+
+ fillbitmap(bitmap, i, &rect);
+ }
+}
+
+
+static TIMER_CALLBACK( tank8_collision_callback )
+{
+ tank8_set_collision(param);
+}
+
+
+VIDEO_UPDATE( tank8 )
+{
+ tilemap_draw(bitmap, cliprect, tilemap1, 0, 0);
+
+ draw_sprites(machine, bitmap, cliprect);
+ draw_bullets(bitmap, cliprect);
+ return 0;
+}
+
+
+VIDEO_EOF( tank8 )
+{
+ const rectangle* clip = &machine->screen[0].visarea;
+
+ int x;
+ int y;
+
+ tilemap_draw(helper1, clip, tilemap2, 0, 0);
+
+ fillbitmap(helper2, 8, clip);
+ fillbitmap(helper3, 8, clip);
+
+ draw_sprites(machine, helper2, clip);
+ draw_bullets(helper3, clip);
+
+ for (y = clip->min_y; y <= clip->max_y; y++)
+ {
+ int state = 0;
+
+ const UINT16* p1 = BITMAP_ADDR16(helper1, y, 0);
+ const UINT16* p2 = BITMAP_ADDR16(helper2, y, 0);
+ const UINT16* p3 = BITMAP_ADDR16(helper3, y, 0);
+
+ if (y % 2 != cpu_getcurrentframe() % 2)
+ {
+ continue; /* video display is interlaced */
+ }
+
+ for (x = clip->min_x; x <= clip->max_x; x++)
+ {
+ UINT8 index;
+
+ if (p1[x] == 8)
+ {
+ state = 0; continue; /* neither wall nor mine */
+ }
+ if (p2[x] == 8 && p3[x] == 8)
+ {
+ state = 0; continue; /* neither tank nor bullet */
+ }
+ if (p3[x] != 8 && p1[x] == 2)
+ {
+ state = 0; continue; /* bullets cannot hit mines */
+ }
+
+ if (state)
+ {
+ continue;
+ }
+
+ if (p3[x] != 8)
+ {
+ index = p3[x] | 0x18;
+
+ if (1)
+ {
+ index |= 0x20;
+ }
+ if (0)
+ {
+ index |= 0x40;
+ }
+ if (1)
+ {
+ index |= 0x80;
+ }
+ }
+ else
+ {
+ index = p2[x] | 0x10;
+
+ if (p1[x] == 1)
+ {
+ index |= 0x20;
+ }
+ if (y - get_y_pos(p2[x]) >= 8)
+ {
+ index |= 0x40; /* collision on bottom side */
+ }
+ if (x - get_x_pos(p2[x]) >= 8)
+ {
+ index |= 0x80; /* collision on right side */
+ }
+ }
+
+ timer_set(video_screen_get_time_until_pos(0, y, x), index, tank8_collision_callback);
+
+ state = 1;
+ }
+ }
+}
diff --git a/src/mame/video/tankbatt.c b/src/mame/video/tankbatt.c
new file mode 100644
index 00000000000..89cab70b26d
--- /dev/null
+++ b/src/mame/video/tankbatt.c
@@ -0,0 +1,110 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *tankbatt_bulletsram;
+size_t tankbatt_bulletsram_size;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+***************************************************************************/
+PALETTE_INIT( tankbatt )
+{
+ int i;
+
+ #define RES_1 0xc0 /* this is a guess */
+ #define RES_2 0x3f /* this is a guess */
+
+ /* Stick black in there */
+ palette_set_color(machine,0,MAKE_RGB(0,0,0));
+
+ /* ? Skip the first byte ? */
+ color_prom++;
+
+ for (i = 1;i < machine->drv->total_colors;i++)
+ {
+ int bit0, bit1, bit2, bit3, r, g, b;
+
+ bit0 = (*color_prom >> 0) & 0x01; /* intensity */
+ bit1 = (*color_prom >> 1) & 0x01; /* red */
+ bit2 = (*color_prom >> 2) & 0x01; /* green */
+ bit3 = (*color_prom >> 3) & 0x01; /* blue */
+
+ /* red component */
+ r = RES_1 * bit1;
+ if (bit1) r += RES_2 * bit0;
+
+ /* green component */
+ g = RES_1 * bit2;
+ if (bit2) g += RES_2 * bit0;
+
+ /* blue component */
+ b = RES_1 * bit3;
+ if (bit3) b += RES_2 * bit0;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom += 4;
+ }
+
+ for (i = 0;i < 128;i++)
+ {
+ colortable[i++] = 0;
+ colortable[i] = (i/2) + 1;
+ }
+}
+
+WRITE8_HANDLER( tankbatt_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index];
+ int color = videoram[tile_index] >> 2;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( tankbatt )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_bullets(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < tankbatt_bulletsram_size;offs += 2)
+ {
+ int color = 63; /* cyan, same color as the tanks */
+ int x = tankbatt_bulletsram[offs + 1];
+ int y = 255 - tankbatt_bulletsram[offs] - 2;
+
+ drawgfx(bitmap,machine->gfx[1],
+ 0, /* this is just a square, generated by the hardware */
+ color,
+ 0,0,
+ x,y,
+ cliprect,TRANSPARENCY_NONE,0);
+ }
+}
+
+VIDEO_UPDATE( tankbatt )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_bullets(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/tankbust.c b/src/mame/video/tankbust.c
new file mode 100644
index 00000000000..76889bfedaf
--- /dev/null
+++ b/src/mame/video/tankbust.c
@@ -0,0 +1,253 @@
+/*
+* Video Driver for Tank Busters
+*/
+
+#include "driver.h"
+
+/*
+* variables
+*/
+
+static tilemap *bg_tilemap;
+static tilemap *txt_tilemap;
+UINT8 * tankbust_txtram;
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/* background tilemap :
+
+0xc000-0xc7ff: xxxx xxxx tile code: 8 lsb bits
+
+0xc800-0xcfff: .... .xxx tile code: 3 msb bits
+ .... x... tile priority ON TOP of sprites (roofs and part of the rails)
+ .xxx .... tile color code
+ x... .... ?? set on *all* roofs (a different bg/sprite priority ?)
+
+note:
+ - seems that the only way to get color test right is to swap bit 1 and bit 0 of color code
+
+*/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index];
+ int attr = colorram[tile_index];
+
+ int color = ((attr>>4) & 0x07);
+
+ code |= (attr&0x07) * 256;
+
+
+#if 0
+ if (attr&0x08) //priority bg/sprites (1 = this bg tile on top of sprites)
+ {
+ color = ((int)rand()) & 0x0f;
+ }
+ if (attr&0x80) //al the roofs of all buildings have this bit set. What's this ???
+ {
+ color = ((int)rand()) & 0x0f;
+ }
+#endif
+
+ /* priority bg/sprites (1 = this bg tile on top of sprites) */
+ tileinfo->category = (attr & 0x08) >> 3;
+
+ SET_TILE_INFO( 1,
+ code,
+ (color&4) | ((color&2)>>1) | ((color&1)<<1),
+ 0);
+}
+
+static TILE_GET_INFO( get_txt_tile_info )
+{
+ int code = tankbust_txtram[tile_index];
+ int color = ((code>>6) & 0x03);
+
+ SET_TILE_INFO( 2,
+ code & 0x3f,
+ ((color&2)>>1) | ((color&1)<<1),
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( tankbust )
+{
+ /* not scrollable */
+ txt_tilemap = tilemap_create(get_txt_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ /* scrollable */
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+
+ tilemap_set_transparent_pen(txt_tilemap, 0);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( tankbust_background_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+READ8_HANDLER( tankbust_background_videoram_r )
+{
+ return videoram[offset];
+}
+
+WRITE8_HANDLER( tankbust_background_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+READ8_HANDLER( tankbust_background_colorram_r )
+{
+ return colorram[offset];
+}
+
+WRITE8_HANDLER( tankbust_txtram_w )
+{
+ tankbust_txtram[offset] = data;
+ tilemap_mark_tile_dirty(txt_tilemap, offset);
+}
+READ8_HANDLER( tankbust_txtram_r )
+{
+ return tankbust_txtram[offset];
+}
+
+
+static UINT8 xscroll[2];
+
+WRITE8_HANDLER( tankbust_xscroll_w )
+{
+ if( xscroll[offset] != data )
+ {
+ int x;
+
+ xscroll[offset] = data;
+
+ x = xscroll[0] + 256 * (xscroll[1]&1);
+ if (x>=0x100) x-=0x200;
+ tilemap_set_scrollx(bg_tilemap, 0, x );
+ }
+//popmessage("x=%02x %02x", xscroll[0], xscroll[1]);
+}
+
+static UINT8 yscroll[2];
+
+WRITE8_HANDLER( tankbust_yscroll_w )
+{
+ if( yscroll[offset] != data )
+ {
+ int y;
+
+ yscroll[offset] = data;
+ y = yscroll[0];
+ if (y>=0x80) y-=0x100;
+ tilemap_set_scrolly(bg_tilemap, 0, y );
+ }
+//popmessage("y=%02x %02x", yscroll[0], yscroll[1]);
+}
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+/*
+spriteram format (4 bytes per sprite):
+
+ offset 0 x....... flip X
+ offset 0 .x...... flip Y
+ offset 0 ..xxxxxx gfx code (6 bits)
+
+ offset 1 xxxxxxxx y position
+
+ offset 2 ??????.. not used ?
+ offset 2 ......?. used but unknown ??? (color code ? or x ?)
+ offset 2 .......x x position (1 MSB bit)
+
+ offset 3 xxxxxxxx x position (8 LSB bits)
+*/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0; offs < spriteram_size; offs += 4)
+ {
+ int code,color,sx,sy,flipx,flipy;
+
+ code = spriteram[offs+0] & 0x3f;
+ flipy = spriteram[offs+0] & 0x40;
+ flipx = spriteram[offs+0] & 0x80;
+
+ sy = (240- spriteram[offs+1]) - 14;
+ sx = (spriteram[offs+2] & 0x01) * 256 + spriteram[offs+3] - 7;
+
+ color = 0;
+
+ //0x02 - dont know (most of the time this bit is set in tank sprite and others but not all and not always)
+ //0x04 - not used
+ //0x08 - not used
+ //0x10 - not used
+ //0x20 - not used
+ //0x40 - not used
+ //0x80 - not used
+#if 0
+ if ((spriteram[offs+2] & 0x02))
+ {
+ code = ((int)rand()) & 63;
+ }
+#endif
+
+ if ((spriteram[offs+1]!=4)) //otherwise - ghost sprites
+ {
+
+ drawgfx(bitmap,machine->gfx[0],
+ code, color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+
+VIDEO_UPDATE( tankbust )
+{
+#if 0
+ int i;
+
+ for (i=0; i<0x800; i++)
+ {
+ int tile_attrib = colorram[i];
+
+ if ( (tile_attrib&8) || (tile_attrib&0x80) )
+ {
+ tilemap_mark_tile_dirty(bg_tilemap, i);
+ }
+ }
+#endif
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 1, 0);
+
+ tilemap_draw(bitmap, cliprect, txt_tilemap, 0,0);
+ return 0;
+}
diff --git a/src/mame/video/taotaido.c b/src/mame/video/taotaido.c
new file mode 100644
index 00000000000..fc495467e7e
--- /dev/null
+++ b/src/mame/video/taotaido.c
@@ -0,0 +1,241 @@
+/* Tao Taido Video Hardware */
+
+/*
+
+its similar to other video system games
+
+zooming might be wrong (only used on title logo?)
+
+*/
+
+#include "driver.h"
+
+static UINT16 taotaido_sprite_character_bank_select[8];
+static UINT16 taotaido_video_bank_select[8];
+static tilemap *bg_tilemap;
+
+extern UINT16 *taotaido_spriteram;
+extern UINT16 *taotaido_spriteram2;
+extern UINT16 *taotaido_scrollram;
+extern UINT16 *taotaido_bgram;
+
+static UINT16 *taotaido_spriteram_old, *taotaido_spriteram_older;
+static UINT16 *taotaido_spriteram2_old, *taotaido_spriteram2_older;
+
+/* sprite tile codes 0x4000 - 0x7fff get remapped according to the content of these registers */
+WRITE16_HANDLER( taotaido_sprite_character_bank_select_w )
+{
+ if(ACCESSING_MSB)
+ taotaido_sprite_character_bank_select[offset*2] = data >> 8;
+ if(ACCESSING_LSB)
+ taotaido_sprite_character_bank_select[offset*2+1] = data &0xff;
+}
+
+/* sprites are like the other video system / psikyo games, we can merge this with aerofgt and plenty of other
+ things eventually */
+
+static void draw_sprite(running_machine *machine, UINT16 spriteno, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ /*- SPR RAM Format -**
+
+ 4 words per sprite
+
+ zzzz sssp pppp pppp (y zoom, y size, y position)
+ zzzz sssp pppp pppp (x zoom, x size, x position)
+ yxpc cccc ---- ---- (flipy, flipx, priority?, colour)
+ -nnn nnnn nnnn nnnn (tile lookup)
+
+ */
+
+ int x,y;
+
+ UINT16 *source = &taotaido_spriteram_older[spriteno*4];
+ const gfx_element *gfx = machine->gfx[0];
+
+
+ int yzoom = (source[0] & 0xf000) >> 12;
+ int xzoom = (source[1] & 0xf000) >> 12;
+
+ int ysize = (source[0] & 0x0e00) >> 9;
+ int xsize = (source[1] & 0x0e00) >> 9;
+
+ int ypos = source[0] & 0x01ff;
+ int xpos = source[1] & 0x01ff;
+
+ int yflip = source[2] & 0x8000;
+ int xflip = source[2] & 0x4000;
+ int color = (source[2] & 0x1f00) >> 8;
+
+ int tile = source[3] & 0xffff;
+
+ xpos += (xsize*xzoom+2)/4;
+ ypos += (ysize*yzoom+2)/4;
+
+ xzoom = 32 - xzoom;
+ yzoom = 32 - yzoom;
+
+
+ for (y = 0;y <= ysize;y++)
+ {
+ int sx,sy;
+
+ if (yflip) sy = ((ypos + yzoom * (ysize - y)/2 + 16) & 0x1ff) - 16;
+ else sy = ((ypos + yzoom * y / 2 + 16) & 0x1ff) - 16;
+
+ for (x = 0;x <= xsize;x++)
+ {
+
+ /* this indirection is a bit different to the other video system games */
+ int realtile;
+
+ realtile = taotaido_spriteram2_older[tile&0x7fff];
+
+ if (realtile > 0x3fff)
+ {
+ int block;
+
+ block = (realtile & 0x3800)>>11;
+
+ realtile &= 0x07ff;
+ realtile |= taotaido_sprite_character_bank_select[block] * 0x800;
+ }
+
+ if (xflip) sx = ((xpos + xzoom * (xsize - x) / 2 + 16) & 0x1ff) - 16;
+ else sx = ((xpos + xzoom * x / 2 + 16) & 0x1ff) - 16;
+
+
+ drawgfxzoom(bitmap,gfx,
+ realtile,
+ color,
+ xflip,yflip,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,15,
+ xzoom << 11, yzoom << 11);
+
+ tile++;
+
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ /* first part of sprite ram is the list of sprites to draw, terminated with 0x4000 */
+ UINT16 *source = taotaido_spriteram_older;
+ UINT16 *finish = taotaido_spriteram_older + 0x2000/2;
+
+ while( source<finish )
+ {
+ if (source[0] == 0x4000) break;
+
+ draw_sprite(machine, source[0]&0x3ff, bitmap, cliprect);
+
+ source++;
+ }
+}
+
+
+/* the tilemap */
+
+WRITE16_HANDLER( taotaido_tileregs_w )
+{
+ switch (offset)
+ {
+ case 0: // would normally be x scroll?
+ case 1: // would normally be y scroll?
+ case 2:
+ case 3:
+ logerror ("unhanded tilemap register write offset %02x data %04x \n",offset,data);
+ break;
+
+ /* tile banks */
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ if(ACCESSING_MSB)
+ taotaido_video_bank_select[(offset-4)*2] = data >> 8;
+ if(ACCESSING_LSB)
+ taotaido_video_bank_select[(offset-4)*2+1] = data &0xff;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ break;
+ }
+}
+
+WRITE16_HANDLER( taotaido_bgvideoram_w )
+{
+ COMBINE_DATA(&taotaido_bgram[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+static TILE_GET_INFO( taotaido_bg_tile_info )
+{
+ int code = taotaido_bgram[tile_index]&0x01ff;
+ int bank = (taotaido_bgram[tile_index]&0x0e00)>>9;
+ int col = (taotaido_bgram[tile_index]&0xf000)>>12;
+
+ code |= taotaido_video_bank_select[bank]*0x200;
+
+ SET_TILE_INFO(
+ 1,
+ code,
+ col,
+ 0);
+}
+
+static TILEMAP_MAPPER( taotaido_tilemap_scan_rows )
+{
+ /* logical (col,row) -> memory offset */
+ return row*0x40 + (col&0x3f) + ((col&0x40)<<6);
+}
+
+VIDEO_START(taotaido)
+{
+ bg_tilemap = tilemap_create(taotaido_bg_tile_info,taotaido_tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,128,64);
+
+ taotaido_spriteram_old = auto_malloc(0x2000);
+ taotaido_spriteram_older = auto_malloc(0x2000);
+
+ taotaido_spriteram2_old = auto_malloc(0x10000);
+ taotaido_spriteram2_older = auto_malloc(0x10000);
+}
+
+
+VIDEO_UPDATE(taotaido)
+{
+// tilemap_set_scrollx(bg_tilemap,0,(taotaido_scrollram[0x380/2]>>4)); // the values put here end up being wrong every other frame
+// tilemap_set_scrolly(bg_tilemap,0,(taotaido_scrollram[0x382/2]>>4)); // the values put here end up being wrong every other frame
+
+ /* not amazingly efficient however it should be functional for row select and linescroll */
+ int line;
+ rectangle clip;
+
+ clip.min_x = machine->screen[0].visarea.min_x;
+ clip.max_x = machine->screen[0].visarea.max_x;
+ clip.min_y = machine->screen[0].visarea.min_y;
+ clip.max_y = machine->screen[0].visarea.max_y;
+
+ for (line = 0; line < 224;line++)
+ {
+ clip.min_y = clip.max_y = line;
+
+ tilemap_set_scrollx(bg_tilemap,0,((taotaido_scrollram[(0x00+4*line)/2])>>4)+30);
+ tilemap_set_scrolly(bg_tilemap,0,((taotaido_scrollram[(0x02+4*line)/2])>>4)-line);
+
+ tilemap_draw(bitmap,&clip,bg_tilemap,0,0);
+ }
+
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_EOF( taotaido )
+{
+ /* sprites need to be delayed by 2 frames? */
+
+ memcpy(taotaido_spriteram2_older,taotaido_spriteram2_old,0x10000);
+ memcpy(taotaido_spriteram2_old,taotaido_spriteram2,0x10000);
+
+ memcpy(taotaido_spriteram_older,taotaido_spriteram_old,0x2000);
+ memcpy(taotaido_spriteram_old,taotaido_spriteram,0x2000);
+}
diff --git a/src/mame/video/targeth.c b/src/mame/video/targeth.c
new file mode 100644
index 00000000000..e4796f14094
--- /dev/null
+++ b/src/mame/video/targeth.c
@@ -0,0 +1,150 @@
+/***************************************************************************
+
+ Target Hits Video Hardware
+
+ Functions to emulate the video hardware of the machine
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *targeth_spriteram;
+UINT16 *targeth_vregs;
+UINT16 *targeth_videoram;
+
+static tilemap *pant[2];
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/*
+ Tile format
+ -----------
+
+ Screen 0 & 1: (64*32, 16x16 tiles)
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | --xxxxxx xxxxxxxx | code
+ 0 | xx------ -------- | not used?
+ 1 | -------- ---xxxxx | color (uses 1st half of the palette)
+ 1 | -------- --x----- | flip y
+ 1 | -------- -x------ | flip x
+ 1 | xxxxxxxx x------- | not used?
+*/
+
+static TILE_GET_INFO( get_tile_info_targeth_screen0 )
+{
+ int data = targeth_videoram[tile_index << 1];
+ int data2 = targeth_videoram[(tile_index << 1) + 1];
+ int code = data & 0x3fff;
+
+ SET_TILE_INFO(0, code, data2 & 0x1f, TILE_FLIPXY((data2 >> 5) & 0x03));
+}
+
+static TILE_GET_INFO( get_tile_info_targeth_screen1 )
+{
+ int data = targeth_videoram[(0x2000/2) + (tile_index << 1)];
+ int data2 = targeth_videoram[(0x2000/2) + (tile_index << 1) + 1];
+ int code = data & 0x3fff;
+
+ SET_TILE_INFO(0, code, data2 & 0x1f, TILE_FLIPXY((data2 >> 5) & 0x03));
+}
+
+/***************************************************************************
+
+ Memory Handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( targeth_vram_w )
+{
+ targeth_videoram[offset] = data;
+ tilemap_mark_tile_dirty(pant[(offset & 0x1fff) >> 12], ((offset << 1) & 0x1fff) >> 2);
+}
+
+
+/***************************************************************************
+
+ Start/Stop the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( targeth )
+{
+ pant[0] = tilemap_create(get_tile_info_targeth_screen0,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pant[1] = tilemap_create(get_tile_info_targeth_screen1,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+
+ tilemap_set_transparent_pen(pant[0],0);
+}
+
+
+/***************************************************************************
+
+ Sprites
+
+***************************************************************************/
+
+/*
+ Sprite Format
+ -------------
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- xxxxxxxx | y position
+ 0 | --xxxxxx -------- | not used?
+ 0 | -x------ -------- | flipx
+ 0 | x------- -------- | flipy
+ 1 | xxxxxxxx xxxxxxxx | not used?
+ 2 | ------xx xxxxxxxx | x position
+ 2 | -xxxxx-- -------- | sprite color (uses 2nd half of the palette)
+ 3 | --xxxxxx xxxxxxxx | sprite code
+ 3 | xx------ -------- | not used?
+*/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int i;
+ const gfx_element *gfx = machine->gfx[0];
+
+ for (i = 3; i < (0x1000 - 6)/2; i += 4){
+ int sx = targeth_spriteram[i+2] & 0x03ff;
+ int sy = (240 - (targeth_spriteram[i] & 0x00ff)) & 0x00ff;
+ int number = targeth_spriteram[i+3] & 0x3fff;
+ int color = (targeth_spriteram[i+2] & 0x7c00) >> 10;
+ int attr = (targeth_spriteram[i] & 0xfe00) >> 9;
+
+ int xflip = attr & 0x20;
+ int yflip = attr & 0x40;
+
+ drawgfx(bitmap,gfx,number,
+ 0x20 + color,xflip,yflip,
+ sx - 0x0f,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( targeth )
+{
+ /* set scroll registers */
+ tilemap_set_scrolly(pant[0], 0, targeth_vregs[0]);
+ tilemap_set_scrollx(pant[0], 0, targeth_vregs[1] + 0x04);
+ tilemap_set_scrolly(pant[1], 0, targeth_vregs[2]);
+ tilemap_set_scrollx(pant[1], 0, targeth_vregs[3]);
+
+ tilemap_draw(bitmap,cliprect,pant[1],0,0);
+ tilemap_draw(bitmap,cliprect,pant[0],0,0);
+ draw_sprites(machine, bitmap,cliprect);
+
+ return 0;
+}
diff --git a/src/mame/video/tatsumi.c b/src/mame/video/tatsumi.c
new file mode 100644
index 00000000000..1cd870343ed
--- /dev/null
+++ b/src/mame/video/tatsumi.c
@@ -0,0 +1,997 @@
+#include "driver.h"
+#include "tatsumi.h"
+#include <math.h>
+
+static tilemap *bg_layer,*tx_layer;
+static mame_bitmap *temp_bitmap;
+
+UINT16 *roundup_r_ram, *roundup_p_ram, *roundup_l_ram;
+UINT16 *cyclwarr_videoram, *cyclwarr_videoram2;
+UINT16* tatsumi_sprite_control_ram;
+static UINT16* roundup5_vram;
+
+/******************************************************************************/
+
+WRITE16_HANDLER(tatsumi_sprite_control_w)
+{
+ COMBINE_DATA(&tatsumi_sprite_control_ram[offset]);
+
+ /* 0xe0 is bank switch, others unknown */
+// if ((offset==0xe0 && data&0xefff) || offset!=0xe0)
+// logerror("%08x: Tatsumi TZB215 sprite control %04x %08x\n", activecpu_get_pc(), offset, data);
+}
+
+/******************************************************************************/
+
+READ16_HANDLER(roundup5_vram_r)
+{
+ offset+=((tatsumi_control_word&0x0c00)>>10) * 0xc000;
+ return roundup5_vram[offset];
+}
+
+WRITE16_HANDLER(roundup5_vram_w)
+{
+ offset+=((tatsumi_control_word&0x0c00)>>10) * 0xc000;
+
+// if (offset>=0x30000)
+// logerror("effective write to vram %06x %02x (control %04x)\n",offset,data,tatsumi_control_word);
+
+ COMBINE_DATA(&roundup5_vram[offset]);
+
+ offset=offset%0xc000;
+
+ decodechar(Machine->gfx[1],offset/0x10,(UINT8 *)roundup5_vram,
+ Machine->drv->gfxdecodeinfo[1].gfxlayout);
+}
+
+
+WRITE16_HANDLER(roundup5_palette_w)
+{
+// static int hack=0;
+ int word;
+
+ COMBINE_DATA(&paletteram16[offset]);
+
+// if (offset==0xbfe)
+// hack++;
+
+// if (hack>1)
+// return;
+
+/*
+apache 3 schematics state
+
+bit 4: 250
+bit 3: 500
+bit 2: 1k
+bit 1: 2k
+bit 0: 3.9kOhm resistor
+
+*/
+
+// logerror("PAL: %04x %02x\n",offset,data);
+
+ offset&=~1;
+ word = ((paletteram16[offset] & 0xff)<<8) | (paletteram16[offset+1] & 0xff);
+ palette_set_color_rgb(Machine,offset/2,pal5bit(word >> 10),pal5bit(word >> 5),pal5bit(word >> 0));
+}
+
+
+WRITE16_HANDLER(apache3_palette_w)
+{
+// static int hack=0;
+
+ COMBINE_DATA(&paletteram16[offset]);
+
+// if (offset==0xbfe)
+// hack++;
+
+// if (hack>1)
+// return;
+
+/*
+apache 3 schematics state
+
+bit 4: 250
+bit 3: 500
+bit 2: 1k
+bit 1: 2k
+bit 0: 3.9kOhm resistor
+
+*/
+
+// logerror("PAL: %04x %02x\n",offset,data);
+
+ data = paletteram16[offset];
+ palette_set_color_rgb(Machine,offset,pal5bit(data >> 10),pal5bit(data >> 5),pal5bit(data >> 0));
+}
+
+
+WRITE16_HANDLER( roundup5_text_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty( tx_layer,offset);
+}
+
+READ16_HANDLER( cyclwarr_videoram_r )
+{
+ return cyclwarr_videoram[offset];
+}
+
+READ16_HANDLER( cyclwarr_videoram2_r )
+{
+ return cyclwarr_videoram2[offset];
+}
+
+WRITE16_HANDLER( cyclwarr_videoram_w )
+{
+ COMBINE_DATA(&cyclwarr_videoram[offset]);
+ if (offset>=0x400 && offset<0x1400)
+ tilemap_mark_tile_dirty( tx_layer,offset - 0x400);
+ if (offset>=0x1400 && offset<0x3400)
+ tilemap_mark_tile_dirty( bg_layer,offset - 0x1400);
+}
+
+WRITE16_HANDLER( cyclwarr_videoram2_w )
+{
+ COMBINE_DATA(&cyclwarr_videoram2[offset]);
+ if (offset>=0x400 && offset<0x1400)
+ tilemap_mark_tile_dirty( tx_layer,offset - 0x400);
+ if (offset>=0x1400 && offset<0x3400)
+ tilemap_mark_tile_dirty( bg_layer,offset - 0x1400);
+}
+
+static UINT8 roundupt_crt_selected_reg;
+static UINT8 roundupt_crt_reg[64];
+extern UINT16 debugA,debugB,debugC,debugD;
+
+static UINT8* shadow_pen_array;
+
+WRITE16_HANDLER( roundup5_crt_w )
+{
+ if (offset==0 && ACCESSING_LSB)
+ roundupt_crt_selected_reg=data&0x3f;
+ if (offset==1 && ACCESSING_LSB) {
+ roundupt_crt_reg[roundupt_crt_selected_reg]=data;
+// if (roundupt_crt_selected_reg!=0xa && roundupt_crt_selected_reg!=0xb && roundupt_crt_selected_reg!=29)
+// logerror("%08x: Crt write %02x %02x\n",activecpu_get_pc(),roundupt_crt_selected_reg,data);
+ }
+}
+
+/********************************************************************/
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ int tile = videoram16[tile_index];
+ SET_TILE_INFO(
+ 1,
+ tile & 0xfff,
+ tile >> 12,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info_cyclwarr )
+{
+ int tile=cyclwarr_videoram2[tile_index+0x1400];
+ int color=tile >> 14;
+
+ tile=(tile&0x3fff) | 0x000;
+
+ SET_TILE_INFO(
+ 1,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_text_tile_info_cyclwarr )
+{
+ int tile=cyclwarr_videoram[tile_index+0x400];
+ int color=tile >> 12;
+
+ tile=tile&0xfff;
+
+ SET_TILE_INFO(
+ 1,
+ tile,
+ color,
+ 0);
+}
+
+/********************************************************************/
+
+VIDEO_START( apache3 )
+{
+ tx_layer = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ shadow_pen_array = auto_malloc(8192);
+ temp_bitmap = auto_bitmap_alloc(512, 512, BITMAP_FORMAT_RGB32);
+
+ memset(shadow_pen_array, 0, 8192);
+ tilemap_set_transparent_pen(tx_layer,0);
+}
+
+VIDEO_START( roundup5 )
+{
+ tx_layer = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,128,64);
+ shadow_pen_array = auto_malloc(8192);
+ roundup5_vram = auto_malloc(0x48000 * 4);
+
+ memset(shadow_pen_array, 0, 8192);
+ tilemap_set_transparent_pen(tx_layer,0);
+}
+
+VIDEO_START( cyclwarr )
+{
+ bg_layer = tilemap_create(get_bg_tile_info_cyclwarr,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,256,256);
+ tx_layer = tilemap_create(get_text_tile_info_cyclwarr,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ shadow_pen_array = auto_malloc(8192);
+
+ memset(shadow_pen_array, 0, 8192);
+ tilemap_set_transparent_pen(bg_layer,0);
+ tilemap_set_transparent_pen(tx_layer,0);
+}
+
+/********************************************************************/
+
+INLINE void roundupt_drawgfxzoomrotate( mame_bitmap *dest_bmp,const gfx_element *gfx,
+ UINT32 code,UINT32 color,int flipx,int flipy,UINT32 ssx,UINT32 ssy,
+ const rectangle *clip, int scalex, int scaley, int rotate, int write_priority_only )
+{
+ rectangle myclip;
+
+ if (!scalex || !scaley) return;
+
+ /*
+ scalex and scaley are 16.16 fixed point numbers
+ 1<<15 : shrink to 50%
+ 1<<16 : uniform scale
+ 1<<17 : double to 200%
+ */
+
+ /* KW 991012 -- Added code to force clip to bitmap boundary */
+ if(clip)
+ {
+ myclip.min_x = clip->min_x;
+ myclip.max_x = clip->max_x;
+ myclip.min_y = clip->min_y;
+ myclip.max_y = clip->max_y;
+
+ if (myclip.min_x < 0) myclip.min_x = 0;
+ if (myclip.max_x >= dest_bmp->width) myclip.max_x = dest_bmp->width-1;
+ if (myclip.min_y < 0) myclip.min_y = 0;
+ if (myclip.max_y >= dest_bmp->height) myclip.max_y = dest_bmp->height-1;
+
+ clip=&myclip;
+ }
+
+ {
+ if( gfx )
+ {
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+ const UINT8 *shadow_pens = shadow_pen_array + (gfx->color_granularity * (color % gfx->total_colors));
+ int source_base = (code % gfx->total_elements) * gfx->height;
+
+ int block_size = 8 * scalex;
+ int sprite_screen_height = ((ssy&0xffff)+block_size)>>16;
+ int sprite_screen_width = ((ssx&0xffff)+block_size)>>16;
+
+ if (sprite_screen_width && sprite_screen_height)
+ {
+ /* compute sprite increment per screen pixel */
+ int dx = (gfx->width<<16)/sprite_screen_width;
+ int dy = (gfx->height<<16)/sprite_screen_height;
+
+ int sx;//=ssx>>16;
+ int sy;//=ssy>>16;
+
+
+// int ex = sx+sprite_screen_width;
+// int ey = sy+sprite_screen_height;
+
+ int x_index_base;
+ int y_index;
+ int ex,ey;
+
+ int incxx=0x10000;//(int)((float)dx * cos(theta));
+// int incxy=0x0;//(int)((float)dy * -sin(theta));
+ int incyx=0x0;//(int)((float)dx * sin(theta));
+// int incyy=0x10000;//(int)((float)dy * cos(theta));
+
+ if (flipx)
+ {
+
+ }
+
+
+ if (ssx&0x80000000) sx=0-(0x10000 - (ssx>>16)); else sx=ssx>>16;
+ if (ssy&0x80000000) sy=0-(0x10000 - (ssy>>16)); else sy=ssy>>16;
+ ex = sx+sprite_screen_width;
+ ey = sy+sprite_screen_height;
+ if( flipx )
+ {
+ x_index_base = (sprite_screen_width-1)*dx;
+ dx = -dx;
+ incxx=-incxx;
+ incyx=-incyx;
+ }
+ else
+ {
+ x_index_base = 0;
+ }
+
+ if( flipy )
+ {
+ y_index = (sprite_screen_height-1)*dy;
+ dy = -dy;
+ }
+ else
+ {
+ y_index = 0;
+ }
+
+ if( clip )
+ {
+ if( sx < clip->min_x)
+ { /* clip left */
+ int pixels = clip->min_x-sx;
+ sx += pixels;
+ x_index_base += pixels*dx;
+ }
+ if( sy < clip->min_y )
+ { /* clip top */
+ int pixels = clip->min_y-sy;
+ sy += pixels;
+ y_index += pixels*dy;
+ }
+ /* NS 980211 - fixed incorrect clipping */
+ if( ex > clip->max_x+1 )
+ { /* clip right */
+ int pixels = ex-clip->max_x-1;
+ ex -= pixels;
+ }
+ if( ey > clip->max_y+1 )
+ { /* clip bottom */
+ int pixels = ey-clip->max_y-1;
+ ey -= pixels;
+ }
+ }
+
+ if( ex>sx )
+ { /* skip if inner loop doesn't draw anything */
+ int y;
+#if 0
+ /* case 1: TRANSPARENCY_PEN */
+ if (transparency == TRANSPARENCY_PEN)
+ {
+ {
+ int startx=0;
+ int starty=0;
+
+// int incxx=0x10000;
+// int incxy=0;
+// int incyx=0;
+// int incyy=0x10000;
+ double theta=rotate * ((2.0 * M_PI)/512.0);
+ double c=cos(theta);
+ double s=sin(theta);
+
+
+ // if (ey-sy > 0)
+ // dy=dy / (ey-sy);
+ {
+ float angleAsRadians=(float)rotate * (7.28f / 512.0f);
+ //float ccx = cosf(angleAsRadians);
+ //float ccy = sinf(angleAsRadians);
+ float a=0;
+
+ }
+
+ for( y=sy; y<ey; y++ )
+ {
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+ int cx = startx;
+ int cy = starty;
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ UINT8 *source = gfx->gfxdata + (source_base+((cy>>16))) * gfx->line_modulo;
+ int c = source[(cx >> 16)];
+ if( c != transparent_color )
+ {
+ if (write_priority_only)
+ dest[x]=shadow_pens[c];
+ else
+ dest[x]=pal[c];
+ }
+ cx += incxx;
+ cy += incxy;
+ }
+ startx += incyx;
+ starty += incyy;
+ }
+ }
+ }
+#endif
+#if 1 // old
+ //if (transparency == TRANSPARENCY_PEN)
+ {
+ {
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = gfx->gfxdata + (source_base+(y_index>>16)) * gfx->line_modulo;
+ UINT32 *dest = BITMAP_ADDR32(dest_bmp, y, 0);
+ UINT8 *priority_dest = BITMAP_ADDR8(dest_bmp, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if( c )
+ {
+ // Only draw shadow pens if writing priority buffer
+ if (write_priority_only)
+ priority_dest[x]=shadow_pens[c];
+ else if (!shadow_pens[c])
+ dest[x]=pal[c];
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+#endif
+ }
+ }
+ }
+ }
+}
+
+static void mycopyrozbitmap_core(mame_bitmap *bitmap,mame_bitmap *srcbitmap,
+ int dstx,int dsty, int srcwidth, int srcheight,int incxx,int incxy,int incyx,int incyy,
+ const rectangle *clip,int transparency,int transparent_color)
+{
+ UINT32 cx;
+ UINT32 cy;
+ int x;
+ int sx;
+ int sy;
+ int ex;
+ int ey;
+// const int xmask = srcbitmap->width-1;
+// const int ymask = srcbitmap->height-1;
+ const int widthshifted = srcwidth << 16;
+ const int heightshifted = srcheight << 16;
+ UINT32 *dest;
+
+ UINT32 startx=0;
+ UINT32 starty=0;
+
+ sx = dstx;
+ sy = dsty;
+ ex = dstx + srcwidth;
+ ey = dsty + srcheight;
+
+ if (sx<clip->min_x) sx=clip->min_x;
+ if (ex>clip->max_x) ex=clip->max_x;
+ if (sy<clip->min_y) sy=clip->min_y;
+ if (ey>clip->max_y) ey=clip->max_y;
+
+ if (sx <= ex)
+ {
+
+ while (sy <= ey)
+ {
+ x = sx;
+ cx = startx;
+ cy = starty;
+ dest = BITMAP_ADDR32(bitmap, sy, sx);
+
+ while (x <= ex)
+ {
+ if (cx < widthshifted && cy < heightshifted)
+ {
+ int c = *BITMAP_ADDR32(srcbitmap, cy >> 16, cx >> 16);
+
+ if (c != transparent_color)
+ *dest = c;
+ }
+
+ cx += incxx;
+ cy += incxy;
+ x++;
+ dest++;
+ }
+ startx += incyx;
+ starty += incyy;
+ sy++;
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int write_priority_only, int rambank)
+{
+ int offs,fx,x,y,color;
+ int w,h,index,lines,scale,rotate;
+ UINT8 *src1, *src2;
+
+ int y_offset;
+
+ int render_x, render_y;
+ int extent_x, extent_y;
+
+ // Sprite data is double buffered
+ for (offs = rambank;offs < rambank + 0x800;offs += 6)
+ {
+ /*
+ Sprite RAM itself uses an index into two ROM tables to actually draw the object.
+
+ Sprite RAM format:
+
+ Word 0: 0xf000 - ?
+ 0x0fff - Index into ROM sprite table
+ Word 1: 0x8000 - X Flip
+ 0x7ff8 - Colour (TODO: Check top bit on Apache 3/Round up)
+ 0x0007 - ?
+ Word 2: 0xffff - X position
+ Word 3: 0xffff - Y position
+ Word 4: 0x01ff - Rotation
+
+ Sprite ROM table format, alternate lines come from each bank, with the
+ very first line indicating control information:
+
+ First bank:
+ Byte 0: Y destination offset (in scanlines, unaffected by scale).
+ Byte 1: Always 0?
+ Byte 2: Number of source scanlines to render from (so unaffected by destination scale).
+ Byte 3: Usually 0, sometimes 0x80??
+
+ Other banks:
+ Byte 0: Width of line in tiles (-1)
+ Byte 1: X offset to start drawing line at (multipled by scale * 8)
+ Bytes 2/3: Tile index to start fetching tiles from (increments per tile).
+
+ */
+ y = spriteram16[offs+3];
+ x = spriteram16[offs+2];
+ scale = spriteram16[offs+4]&0xff;
+ color = (spriteram16[offs+1]>>3)&0x1ff;
+ fx = spriteram16[offs+1]&0x8000;
+ rotate = 0;//spriteram16[offs+5]&0x1ff; // Todo: Turned off for now
+
+ index = spriteram16[offs];
+
+// if (spriteram16[offs+1]&0x7)
+// color=rand()%0xff;
+
+ /* End of sprite list marker */
+ if (index==0xffff || spriteram16[offs+4]==0xffff) //todo
+ return;
+
+ if (index>=0x1000)
+ continue;
+
+ src1 = tatsumi_rom_sprite_lookup1 + (index*4);
+ src2 = tatsumi_rom_sprite_lookup2 + (index*4);
+
+ lines=src1[2];
+ y_offset=src1[0]&0xf8;
+ lines-=y_offset;
+
+ render_x=x<<16;
+ render_y=y<<16;
+ scale=scale<<9; /* 0x80 becomes 0x10000 */
+
+ render_y+=y_offset * scale;
+
+ if (rotate)
+ {
+ render_y=0;
+ fillbitmap(temp_bitmap, 0, 0);
+ }
+
+extent_x=extent_y=0;
+
+ src1+=4;
+ h=0;
+ while (lines>0) {
+ int base, x_offs, x_width, x_pos, draw_this_line=1;
+ int this_extent=0;
+
+ /* Odd and even lines come from different banks */
+ if (h&1) {
+ x_width=src1[0]+1;
+ x_offs=src1[1]*scale*8;
+ base=src1[2] | (src1[3]<<8);
+ }
+ else {
+ x_width=src2[0]+1;
+ x_offs=src2[1]*scale*8;
+ base=src2[2] | (src2[3]<<8);
+ }
+
+ if (draw_this_line) {
+ base*=2;
+
+ if (!rotate)
+ {
+ if (fx)
+ x_pos=render_x-x_offs;
+ else
+ x_pos=render_x+x_offs;
+ }
+ else
+ x_pos=x_offs;
+
+ for (w=0; w<x_width; w++) {
+ if (rotate)
+ roundupt_drawgfxzoomrotate(temp_bitmap,machine->gfx[0],
+ base,
+ color,fx,0,x_pos,render_y,
+ cliprect,scale,scale,0,write_priority_only);
+ else
+ roundupt_drawgfxzoomrotate(bitmap,machine->gfx[0],
+ base,
+ color,fx,0,x_pos,render_y,
+ cliprect,scale,scale,0,write_priority_only);
+ base++;
+
+ if (fx)
+ x_pos-=scale*8;
+ else
+ x_pos+=scale*8;
+
+ this_extent+=scale*8;
+ }
+ if (h&1)
+ src1+=4;
+ else
+ src2+=4;
+
+ if (this_extent > extent_x)
+ extent_x=this_extent;
+ this_extent=0;
+
+ render_y+=8 * scale;
+ extent_y+=8 * scale;
+ h++;
+ lines-=8;
+ } else {
+ h=32; //hack
+ }
+ }
+
+ if (rotate)
+ {
+ double theta=rotate * ((2.0 * M_PI)/512.0);
+
+ int incxx=(int)((float)65536.0 * cos(theta));
+ int incxy=(int)((float)65536.0 * -sin(theta));
+ int incyx=(int)((float)65536.0 * sin(theta));
+ int incyy=(int)((float)65536.0 * cos(theta));
+
+ extent_x=extent_x>>16;
+ extent_y=extent_y>>16;
+ if (extent_x>2 && extent_y>2)
+ mycopyrozbitmap_core(bitmap, temp_bitmap, x/* + (extent_x/2)*/, y /*+ (extent_y/2)*/, extent_x, extent_y, incxx, incxy, incyx, incyy, cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+ }
+}
+
+static void draw_sky(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect, int palette_base, int start_offset)
+{
+ // all todo
+ int x,y;
+
+ if (start_offset&0x8000)
+ start_offset=-(0x10000 - start_offset);
+
+ start_offset=-start_offset;
+
+start_offset-=48;
+ for (y=0; y<256; y++) {
+ for (x=0; x<320; x++) {
+ int col=palette_base + y + start_offset;
+ if (col<palette_base) col=palette_base;
+ if (col>palette_base+127) col=palette_base+127;
+
+ *BITMAP_ADDR32(bitmap, y, x) = machine->pens[col];
+ }
+ }
+}
+
+static void draw_road(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,mame_bitmap *shadow_bitmap)
+{
+/*
+0xf980 0x0008 0x8c80 0x4a00 - road right to below, width unknown (32 pixels guess)
+0xfa80 0x0008 0x8c80 0x4a00 - road right to below, width unknown (32 pixels guess)
+
+0xfb80 0x0008 0x8c80 0x4a00 - road in middle of screen, width unknown (32 pixels guess)
+
+0xfc80 0x0008 0x8c80 0x4a00 - road width above to left, same width as above (ie, xpos - 32)
+0xfd80 0x0008 0x8c80 0x4a00 - road width above to left, same width as above (ie, xpos - 32)
+0xfe80 0x0008 0x8c80 0x4a00 - road width above to left, same width as above (ie, xpos - 32)
+0xff80 0x0008 0x8c80 0x4a00 - road width above to left, same width as above (ie, xpos - 32)
+0x0001 - road half/width above to left, (ie, xpos - 16)
+0x0081 - road width to left as usual (xpos-16 from above, or 32 from above2)
+
+0xfb0b 0x210b 0x8cf5 0x0dea - blue & left & right, with blue|----|----|----|----|blue
+in this mode changing columns 2 & 3 have no apparent effect
+0xfb0b 0x7b09 0x8cf5 0x0dea - as above, but scaled up - perhaps 18 pixels shifted (twice that overall size)
+0xfb0b 0x6c07 0x8cf5 0x0dea - as above, but scaled up - perhaps 40 pixels shifted from above
+0xfb0b 0xaa06 0x8cf5 0x0dea - as above, but scaled up - perhaps 16 pixels shifted from above
+0xfb0b 0xb005 0x8cf5 0x0dea - as above, but scaled up - perhaps 38 pixels shifted from above
+
+b21 diff is 1a6
+97b 20f
+76c c2
+6aa fa
+5b0
+
+
+0x0000 0x0008 0xxxxx 0xxxx - line starting at 0 for 128 pixels - 1 to 1 with road pixel data
+0xff00 0x0008 0xxxxx 0xxxx - line starting at 32 for 128 pixels - 1 to 1 with road pixel data
+0xfe00 0x0008 0xxxxx 0xxxx - line starting at 64 for 128 pixels - 1 to 1 with road pixel data
+
+
+
+at standard zoom (0x800)
+shift of 0x100 moves 32 pixels
+so shift of 8 is assumed to move 1 pixel
+
+at double zoom (0x1000)
+assume shift of 0x100 only moves 16 pixels
+so
+
+0x100 * 0x400 => 0x40
+0x100 * step 0x800 = must come out at 0x20
+0x100 * step 0x1000 = must come out at 0x10
+0x100 * step 0x2000 = 0x5
+
+pos is 11.5 fixed point
+
+-0x580 = middle
+-0x180
+-0x080
+0
+0x80
+
+*/
+ int y,x;
+ int visible_line=0;
+ const UINT16* data=roundup_r_ram;
+
+ // Road layer enable (?)
+ if ((roundup5_unknown0[0x1]&0x1)==0)
+ return;
+
+ // Road data bank select (double buffered)
+ if (roundup5_e0000_ram[0]&0x10)
+ data+=0x400;
+
+ // ?? Todo: This is wrong - don't know how to clip the road properly
+ y=256 - (roundup5_unknown0[0xb/2] >> 8);
+ data+=y*4;
+
+ visible_line=0;
+
+ for (/*y=0*/; y<256; y++) {
+
+ int shift=data[0];
+ int shift2=data[2];
+ int pal=4; //(data[3]>>8)&0xf;
+ int step=((data[1]&0xff)<<8)|((data[1]&0xff00)>>8);
+ int samplePos=0;
+ const UINT16* linedata=roundup_p_ram;// + (0x100 * pal);
+ int startPos=0, endPos=0;
+
+ int palette_byte;//=roundup_l_ram[visible_line/8];
+
+ /*
+ Each road line consists of up to two sets of 128 pixel data that can be positioned
+ on the x-axis and stretched/compressed on the x-axis. Any screen pixels to the left
+ of the first set are drawn with pen 0 of the road pixel data. Any screen pixels to the
+ right of the second set line are drawn with pen 127 of the road pixel data.
+
+ The road control data is laid out as follows (4 words per screen line, with 2 banks):
+
+ Word 0: Line shift for 1st set - 13.3 signed fixed point value.
+ Word 1: Line scale - 5.11 fixed point value. So 0x800 is 1:1, 0x400 is 1:2, etc
+ Word 2: Line shift for 2nd set - 13.3 signed fixed point value.
+ Word 3: ?
+
+ The scale is shared between both pixel sets. The 2nd set is only used when the road
+ forks into two between stages. The 2nd line shift is an offset from the last pixel
+ of the 1st set. The 2nd line shift uses a different palette bank.
+
+2nd road uses upper palette - confirmed by water stage.
+offset is from last pixel of first road segment?
+//last pixel of first road is really colour from 2nd road line?
+
+ */
+
+ palette_byte=roundup_l_ram[visible_line/8];
+ pal=4 + ((palette_byte>>(visible_line%8))&1);
+
+ visible_line++;
+
+ if (shift&0x8000)
+ shift=-(0x10000 - shift);
+ shift=-shift;
+
+ if (step)
+ startPos=((shift<<8) + 0x80 )/ step;
+
+ /* Fill in left of road segment */
+ for (x=0; x<startPos && x<320; x++) {
+ int col = linedata[0]&0xf;
+ UINT8 shadow=*BITMAP_ADDR8(shadow_bitmap, y, x);
+ if (shadow)
+ *BITMAP_ADDR32(bitmap, y, x) = machine->pens[768 + pal*16 + col];
+ else
+ *BITMAP_ADDR32(bitmap, y, x) = machine->pens[256 + pal*16 + col];
+ }
+
+ /* If startpos is negative, clip it and adjust the sampling position accordingly */
+ if (startPos<0) {
+ samplePos=step*(0-startPos);
+ startPos=0;
+ } else {
+ samplePos=0;
+ }
+
+ /* Fill in main part of road, then right-hand side edge */
+ for (x=startPos; x<320 && (samplePos>>11)<0x80; x++) {
+ // look up colour
+ int col = linedata[(samplePos>>11)&0x7f]&0xf;
+ UINT8 shadow=*BITMAP_ADDR8(shadow_bitmap, y, x);
+
+ /* Clamp if we have reached the end of the pixel data */
+ //if ((samplePos>>11) > 0x7f)
+ // col=linedata[0x7f]&0xf;
+
+ if (shadow)
+ *BITMAP_ADDR32(bitmap, y, x) = machine->pens[768 + pal*16 + col];
+ else
+ *BITMAP_ADDR32(bitmap, y, x) = machine->pens[256 + pal*16 + col];
+
+ samplePos+=step;
+ }
+
+ /* Now work out how many pixels until start of 2nd segment */
+ startPos=x;
+
+ if (shift2&0x8000)
+ shift2=-(0x10000 - shift2);
+ shift2=-shift2;
+
+ if (step)
+ endPos=((shift2<<8) + 0x80) / step;
+ else
+ endPos=0;
+ endPos-=128;
+ endPos=startPos+endPos;
+
+ /* Fill pixels */
+ for (x=startPos; x<320 && x<endPos; x++) {
+ int col = linedata[0x80]&0xf;
+ UINT8 shadow=*BITMAP_ADDR8(shadow_bitmap, y, x);
+
+ /* Clamp if we have reached the end of the pixel data */
+ //if ((samplePos>>11) > 0x7f)
+ // col=linedata[0x7f]&0xf;
+
+ if (shadow)
+ *BITMAP_ADDR32(bitmap, y, x) = machine->pens[768 + pal*16 + col + 32];
+ else
+ *BITMAP_ADDR32(bitmap, y, x) = machine->pens[256 + pal*16 + col + 32];
+ }
+
+ if (endPos<0) {
+ samplePos=step*(0-startPos);
+ }
+ else if (endPos<x) {
+ samplePos=step*(x-endPos);
+ } else {
+ samplePos=0; // todo
+ }
+
+ for (/*x=endPos*/; x<320; x++) {
+ // look up colour
+ int col = linedata[((samplePos>>11)&0x7f) + 0x200]&0xf;
+ UINT8 shadow=*BITMAP_ADDR8(shadow_bitmap, y, x);
+
+ /* Clamp if we have reached the end of the pixel data */
+ if ((samplePos>>11) > 0x7f)
+ col=linedata[0x7f + 0x200]&0xf;
+
+ if (shadow)
+ *BITMAP_ADDR32(bitmap, y, x) = machine->pens[768 + pal*16 + col + 32];
+ else
+ *BITMAP_ADDR32(bitmap, y, x) = machine->pens[256 + pal*16 + col + 32];
+
+ samplePos+=step;
+ }
+ data+=4;
+ }
+}
+
+static void update_cluts(running_machine *machine, int fake_palette_offset, int object_base, int length)
+{
+ /* Object palettes are build from a series of cluts stored in the object roms.
+
+ We update 'Mame palettes' from the clut here in order to simplify the
+ draw routines. We also note down any uses of the 'shadow' pen (index 255).
+ */
+ int i;
+ const UINT8* bank1=tatsumi_rom_clut0;
+ const UINT8* bank2=tatsumi_rom_clut1;
+ for (i=0; i<length; i+=8) {
+ palette_set_color(machine,fake_palette_offset+i+0,palette_get_color(machine,bank1[1]+object_base));
+ shadow_pen_array[i+0]=(bank1[1]==255);
+ palette_set_color(machine,fake_palette_offset+i+1,palette_get_color(machine,bank1[0]+object_base));
+ shadow_pen_array[i+1]=(bank1[0]==255);
+ palette_set_color(machine,fake_palette_offset+i+2,palette_get_color(machine,bank1[3]+object_base));
+ shadow_pen_array[i+2]=(bank1[3]==255);
+ palette_set_color(machine,fake_palette_offset+i+3,palette_get_color(machine,bank1[2]+object_base));
+ shadow_pen_array[i+3]=(bank1[2]==255);
+
+ palette_set_color(machine,fake_palette_offset+i+4,palette_get_color(machine,bank2[1]+object_base));
+ shadow_pen_array[i+4]=(bank2[1]==255);
+ palette_set_color(machine,fake_palette_offset+i+5,palette_get_color(machine,bank2[0]+object_base));
+ shadow_pen_array[i+5]=(bank2[0]==255);
+ palette_set_color(machine,fake_palette_offset+i+6,palette_get_color(machine,bank2[3]+object_base));
+ shadow_pen_array[i+6]=(bank2[3]==255);
+ palette_set_color(machine,fake_palette_offset+i+7,palette_get_color(machine,bank2[2]+object_base));
+ shadow_pen_array[i+7]=(bank2[2]==255);
+
+ bank1+=4;
+ bank2+=4;
+ }
+}
+
+/**********************************************************************/
+
+VIDEO_UPDATE( apache3 )
+{
+ update_cluts(machine, 1024, 0, 2048);
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ draw_sky(machine, bitmap, cliprect, 256, apache3_a0000[1]);
+ draw_sprites(machine, bitmap,cliprect,0, (tatsumi_sprite_control_ram[0x20]&0x1000) ? 0x1000 : 0);
+ tilemap_draw(bitmap,cliprect,tx_layer,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( roundup5 )
+{
+// UINT16 bg_x_scroll=roundup5_unknown1[0];
+// UINT16 bg_y_scroll=roundup5_unknown2[0];
+
+ update_cluts(machine, 1024, 512, 4096);
+
+ tilemap_set_scrollx(tx_layer,0,24);
+ tilemap_set_scrolly(tx_layer,0,0); //(((roundupt_crt_reg[0xe]<<8)|roundupt_crt_reg[0xf])>>5) + 96);
+
+ fillbitmap(bitmap,machine->pens[384],cliprect); // todo
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ draw_sprites(machine, priority_bitmap,cliprect,1,(tatsumi_sprite_control_ram[0xe0]&0x1000) ? 0x1000 : 0); // Alpha pass only
+ draw_road(machine, bitmap,cliprect,priority_bitmap);
+ draw_sprites(machine, bitmap,cliprect,0,(tatsumi_sprite_control_ram[0xe0]&0x1000) ? 0x1000 : 0); // Full pass
+ tilemap_draw(bitmap,cliprect,tx_layer,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( cyclwarr )
+{
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+// tilemap_draw(bitmap,cliprect,bg_layer,0,0);
+ update_cluts(machine, 8192, 4096, 8192);
+ draw_sprites(machine, bitmap,cliprect,0,(tatsumi_sprite_control_ram[0xe0]&0x1000) ? 0x1000 : 0);
+ tilemap_draw(bitmap,cliprect,tx_layer,0,0);
+ return 0;
+}
diff --git a/src/mame/video/taxidrvr.c b/src/mame/video/taxidrvr.c
new file mode 100644
index 00000000000..ec99771eaf6
--- /dev/null
+++ b/src/mame/video/taxidrvr.c
@@ -0,0 +1,157 @@
+#include "driver.h"
+#include "taxidrvr.h"
+
+
+UINT8 *taxidrvr_vram0,*taxidrvr_vram1,*taxidrvr_vram2,*taxidrvr_vram3;
+UINT8 *taxidrvr_vram4,*taxidrvr_vram5,*taxidrvr_vram6,*taxidrvr_vram7;
+UINT8 *taxidrvr_scroll;
+int taxidrvr_bghide;
+static int spritectrl[9];
+
+
+WRITE8_HANDLER( taxidrvr_spritectrl_w )
+{
+ spritectrl[offset] = data;
+}
+
+
+
+VIDEO_UPDATE( taxidrvr )
+{
+ int offs;
+ int sx,sy;
+
+
+ if (taxidrvr_bghide)
+ {
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+
+ /* kludge to fix scroll after death */
+ taxidrvr_scroll[0] = taxidrvr_scroll[1] = taxidrvr_scroll[2] = taxidrvr_scroll[3] = 0;
+ spritectrl[2] = spritectrl[5] = spritectrl[8] = 0;
+ }
+ else
+ {
+ for (offs = 0;offs < 0x400;offs++)
+ {
+ sx = offs % 32;
+ sy = offs / 32;
+
+ drawgfx(bitmap,machine->gfx[3],
+ taxidrvr_vram3[offs],
+ 0,
+ 0,0,
+ (sx*8-taxidrvr_scroll[0])&0xff,(sy*8-taxidrvr_scroll[1])&0xff,
+ cliprect,TRANSPARENCY_NONE,0);
+ }
+
+ for (offs = 0;offs < 0x400;offs++)
+ {
+ sx = offs % 32;
+ sy = offs / 32;
+
+ drawgfx(bitmap,machine->gfx[2],
+ taxidrvr_vram2[offs]+256*taxidrvr_vram2[offs+0x400],
+ 0,
+ 0,0,
+ (sx*8-taxidrvr_scroll[2])&0xff,(sy*8-taxidrvr_scroll[3])&0xff,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ if (spritectrl[2] & 4)
+ {
+ for (offs = 0;offs < 0x1000;offs++)
+ {
+ int color;
+
+ sx = ((offs/2) % 64-spritectrl[0]-256*(spritectrl[2]&1))&0x1ff;
+ sy = ((offs/2) / 64-spritectrl[1]-128*(spritectrl[2]&2))&0x1ff;
+
+ color = (taxidrvr_vram5[offs/4]>>(2*(offs&3)))&0x03;
+ if (color)
+ {
+ if (sx > 0 && sx < 256 && sy > 0 && sy < 256)
+ *BITMAP_ADDR16(bitmap, sy, sx) = color;
+ }
+ }
+ }
+
+ if (spritectrl[5] & 4)
+ {
+ for (offs = 0;offs < 0x1000;offs++)
+ {
+ int color;
+
+ sx = ((offs/2) % 64-spritectrl[3]-256*(spritectrl[5]&1))&0x1ff;
+ sy = ((offs/2) / 64-spritectrl[4]-128*(spritectrl[5]&2))&0x1ff;
+
+ color = (taxidrvr_vram6[offs/4]>>(2*(offs&3)))&0x03;
+ if (color)
+ {
+ if (sx > 0 && sx < 256 && sy > 0 && sy < 256)
+ *BITMAP_ADDR16(bitmap, sy, sx) = color;
+ }
+ }
+ }
+
+ if (spritectrl[8] & 4)
+ {
+ for (offs = 0;offs < 0x1000;offs++)
+ {
+ int color;
+
+ sx = ((offs/2) % 64-spritectrl[6]-256*(spritectrl[8]&1))&0x1ff;
+ sy = ((offs/2) / 64-spritectrl[7]-128*(spritectrl[8]&2))&0x1ff;
+
+ color = (taxidrvr_vram7[offs/4]>>(2*(offs&3)))&0x03;
+ if (color)
+ {
+ if (sx > 0 && sx < 256 && sy > 0 && sy < 256)
+ *BITMAP_ADDR16(bitmap, sy, sx) = color;
+ }
+ }
+ }
+
+ for (offs = 0;offs < 0x400;offs++)
+ {
+ sx = offs % 32;
+ sy = offs / 32;
+
+ drawgfx(bitmap,machine->gfx[1],
+ taxidrvr_vram1[offs],
+ 0,
+ 0,0,
+ sx*8,sy*8,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+
+ for (offs = 0;offs < 0x2000;offs++)
+ {
+ int color;
+
+ sx = (offs/2) % 64;
+ sy = (offs/2) / 64;
+
+ color = (taxidrvr_vram4[offs/4]>>(2*(offs&3)))&0x03;
+ if (color)
+ {
+ *BITMAP_ADDR16(bitmap, sy, sx) = 2 * color;
+ }
+ }
+ }
+
+ for (offs = 0;offs < 0x400;offs++)
+ {
+ sx = offs % 32;
+ sy = offs / 32;
+
+ drawgfx(bitmap,machine->gfx[0],
+ taxidrvr_vram0[offs],
+ 0,
+ 0,0,
+ sx*8,sy*8,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/tbowl.c b/src/mame/video/tbowl.c
new file mode 100644
index 00000000000..a05f648adcb
--- /dev/null
+++ b/src/mame/video/tbowl.c
@@ -0,0 +1,250 @@
+/* video/tbowl.c */
+
+/* see drivers/tbowl.c for more info */
+
+#include "driver.h"
+
+static tilemap *tx_tilemap, *bg_tilemap, *bg2_tilemap;
+UINT8 *tbowl_txvideoram, *tbowl_bgvideoram, *tbowl_bg2videoram;
+UINT8 *tbowl_spriteram;
+
+/*** Tilemap Stuff
+
+***/
+
+static UINT16 tbowl_xscroll;
+static UINT16 tbowl_yscroll;
+
+static UINT16 tbowl_bg2xscroll;
+static UINT16 tbowl_bg2yscroll;
+
+/* Foreground Layer (tx) Tilemap */
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int tileno;
+ int col;
+
+ tileno = tbowl_txvideoram[tile_index] | ((tbowl_txvideoram[tile_index+0x800] & 0x07) << 8);
+ col = (tbowl_txvideoram[tile_index+0x800] & 0xf0) >> 4;
+
+ SET_TILE_INFO(0,tileno,col,0);
+}
+
+WRITE8_HANDLER( tbowl_txvideoram_w )
+{
+ tbowl_txvideoram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset & 0x7ff);
+}
+
+/* Bottom BG Layer (bg) Tilemap */
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int tileno;
+ int col;
+
+ tileno = tbowl_bgvideoram[tile_index] | ((tbowl_bgvideoram[tile_index+0x1000] & 0x0f) << 8);
+ col = (tbowl_bgvideoram[tile_index+0x1000] & 0xf0) >> 4;
+
+ SET_TILE_INFO(1,tileno,col,0);
+}
+
+WRITE8_HANDLER( tbowl_bg2videoram_w )
+{
+ tbowl_bg2videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg2_tilemap,offset & 0xfff);
+}
+
+WRITE8_HANDLER (tbowl_bgxscroll_lo)
+{
+ tbowl_xscroll = (tbowl_xscroll & 0xff00) | data;
+}
+
+WRITE8_HANDLER (tbowl_bgxscroll_hi)
+{
+ tbowl_xscroll = (tbowl_xscroll & 0x00ff) | (data << 8);
+}
+
+WRITE8_HANDLER (tbowl_bgyscroll_lo)
+{
+ tbowl_yscroll = (tbowl_yscroll & 0xff00) | data;
+}
+
+WRITE8_HANDLER (tbowl_bgyscroll_hi)
+{
+ tbowl_yscroll = (tbowl_yscroll & 0x00ff) | (data << 8);
+}
+
+/* Middle BG Layer (bg2) Tilemaps */
+
+static TILE_GET_INFO( get_bg2_tile_info )
+{
+ int tileno;
+ int col;
+
+ tileno = tbowl_bg2videoram[tile_index] | ((tbowl_bg2videoram[tile_index+0x1000] & 0x0f) << 8);
+ tileno ^= 0x400;
+ col = (tbowl_bg2videoram[tile_index+0x1000] & 0xf0) >> 4;
+
+ SET_TILE_INFO(2,tileno,col,0);
+}
+
+WRITE8_HANDLER( tbowl_bgvideoram_w )
+{
+ tbowl_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0xfff);
+}
+
+WRITE8_HANDLER (tbowl_bg2xscroll_lo)
+{
+ tbowl_bg2xscroll = (tbowl_bg2xscroll & 0xff00) | data;
+}
+
+WRITE8_HANDLER (tbowl_bg2xscroll_hi)
+{
+ tbowl_bg2xscroll = (tbowl_bg2xscroll & 0x00ff) | (data << 8);
+}
+
+WRITE8_HANDLER (tbowl_bg2yscroll_lo)
+{
+ tbowl_bg2yscroll = (tbowl_bg2yscroll & 0xff00) | data;
+}
+
+WRITE8_HANDLER (tbowl_bg2yscroll_hi)
+{
+ tbowl_bg2yscroll = (tbowl_bg2yscroll & 0x00ff) | (data << 8);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect, int xscroll)
+{
+ int offs;
+ static const UINT8 layout[8][8] =
+ {
+ {0,1,4,5,16,17,20,21},
+ {2,3,6,7,18,19,22,23},
+ {8,9,12,13,24,25,28,29},
+ {10,11,14,15,26,27,30,31},
+ {32,33,36,37,48,49,52,53},
+ {34,35,38,39,50,51,54,55},
+ {40,41,44,45,56,57,60,61},
+ {42,43,46,47,58,59,62,63}
+ };
+
+ for (offs = 0;offs < 0x800;offs += 8)
+ {
+ if (tbowl_spriteram[offs+0] & 0x80) /* enable */
+ {
+ int code,color,sizex,sizey,flipx,flipy,xpos,ypos;
+ int x,y;//,priority,priority_mask;
+
+ code = (tbowl_spriteram[offs+2])+(tbowl_spriteram[offs+1]<<8);
+ color = (tbowl_spriteram[offs+3])&0x1f;
+ sizex = 1 << ((tbowl_spriteram[offs+0] & 0x03) >> 0);
+ sizey = 1 << ((tbowl_spriteram[offs+0] & 0x0c) >> 2);
+
+ flipx = (tbowl_spriteram[offs+0])&0x20;
+ flipy = 0;
+ xpos = (tbowl_spriteram[offs+6])+((tbowl_spriteram[offs+4]&0x03)<<8);
+ ypos = (tbowl_spriteram[offs+5])+((tbowl_spriteram[offs+4]&0x10)<<4);
+
+ /* bg: 1; fg:2; text: 4 */
+
+ for (y = 0;y < sizey;y++)
+ {
+ for (x = 0;x < sizex;x++)
+ {
+ int sx = xpos + 8*(flipx?(sizex-1-x):x);
+ int sy = ypos + 8*(flipy?(sizey-1-y):y);
+
+ sx -= xscroll;
+
+ drawgfx(bitmap,machine->gfx[3],
+ code + layout[y][x],
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0 );
+
+ /* wraparound */
+ drawgfx(bitmap,machine->gfx[3],
+ code + layout[y][x],
+ color,
+ flipx,flipy,
+ sx,sy-0x200,
+ cliprect,TRANSPARENCY_PEN,0 );
+
+ /* wraparound */
+ drawgfx(bitmap,machine->gfx[3],
+ code + layout[y][x],
+ color,
+ flipx,flipy,
+ sx-0x400,sy,
+ cliprect,TRANSPARENCY_PEN,0 );
+
+ /* wraparound */
+ drawgfx(bitmap,machine->gfx[3],
+ code + layout[y][x],
+ color,
+ flipx,flipy,
+ sx-0x400,sy-0x200,
+ cliprect,TRANSPARENCY_PEN,0 );
+
+
+
+ }
+ }
+ }
+ }
+
+}
+
+
+/*** Video Start / Update ***/
+
+VIDEO_START( tbowl )
+{
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,128,32);
+ bg2_tilemap = tilemap_create(get_bg2_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,128,32);
+
+ tilemap_set_transparent_pen(tx_tilemap,0);
+ tilemap_set_transparent_pen(bg_tilemap,0);
+ tilemap_set_transparent_pen(bg2_tilemap,0);
+}
+
+
+VIDEO_UPDATE( tbowl )
+{
+ if (screen == 0)
+ {
+ tilemap_set_scrollx(bg_tilemap, 0, tbowl_xscroll );
+ tilemap_set_scrolly(bg_tilemap, 0, tbowl_yscroll );
+ tilemap_set_scrollx(bg2_tilemap, 0, tbowl_bg2xscroll );
+ tilemap_set_scrolly(bg2_tilemap, 0, tbowl_bg2yscroll );
+ tilemap_set_scrollx(tx_tilemap, 0, 0 );
+ tilemap_set_scrolly(tx_tilemap, 0, 0 );
+
+ fillbitmap(bitmap,0x100,cliprect); /* is there a register controling the colour? looks odd when screen is blank */
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect, 0);
+ tilemap_draw(bitmap,cliprect,bg2_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ }
+ else if (screen ==1)
+ {
+ tilemap_set_scrollx(bg_tilemap, 0, tbowl_xscroll+32*8 );
+ tilemap_set_scrolly(bg_tilemap, 0, tbowl_yscroll );
+ tilemap_set_scrollx(bg2_tilemap, 0, tbowl_bg2xscroll+32*8 );
+ tilemap_set_scrolly(bg2_tilemap, 0, tbowl_bg2yscroll );
+ tilemap_set_scrollx(tx_tilemap, 0, 32*8 );
+ tilemap_set_scrolly(tx_tilemap, 0, 0 );
+
+ fillbitmap(bitmap,0x100,cliprect); /* is there a register controling the colour? looks odd when screen is blank */
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect, 32*8);
+ tilemap_draw(bitmap,cliprect,bg2_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/tceptor.c b/src/mame/video/tceptor.c
new file mode 100644
index 00000000000..944a19340cf
--- /dev/null
+++ b/src/mame/video/tceptor.c
@@ -0,0 +1,597 @@
+/*
+ * Thunder Ceptor board
+ * emulate video hardware
+ */
+
+#include "driver.h"
+#include "namcoic.h"
+
+#define TX_TILE_OFFSET_CENTER (32 * 2)
+#define TX_TILE_OFFSET_RIGHT (32 * 0 + 2)
+#define TX_TILE_OFFSET_LEFT (32 * 31 + 2)
+
+#define SPR_TRANS_COLOR (0xff + 768)
+#define SPR_MASK_COLOR (0xfe + 768)
+
+
+UINT8 *tceptor_tile_ram;
+UINT8 *tceptor_tile_attr;
+UINT8 *tceptor_bg_ram;
+UINT16 *tceptor_sprite_ram;
+
+static int sprite16;
+static int sprite32;
+static int bg;
+
+static tilemap *tx_tilemap;
+
+static tilemap *bg1_tilemap;
+static tilemap *bg2_tilemap;
+
+static INT32 bg1_scroll_x, bg1_scroll_y;
+static INT32 bg2_scroll_x, bg2_scroll_y;
+
+static mame_bitmap *temp_bitmap;
+
+static int is_mask_spr[1024/16];
+
+/*******************************************************************/
+
+PALETTE_INIT( tceptor )
+{
+ int totcolors, totlookup;
+ int i;
+
+ totcolors = machine->drv->total_colors;
+ totlookup = machine->drv->color_table_len;
+
+ for (i = 0; i < totcolors; i++)
+ {
+ int bit0, bit1, bit2, bit3, r, g, b;
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[totcolors] >> 0) & 0x01;
+ bit1 = (color_prom[totcolors] >> 1) & 0x01;
+ bit2 = (color_prom[totcolors] >> 2) & 0x01;
+ bit3 = (color_prom[totcolors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[2*totcolors] >> 0) & 0x01;
+ bit1 = (color_prom[2*totcolors] >> 1) & 0x01;
+ bit2 = (color_prom[2*totcolors] >> 2) & 0x01;
+ bit3 = (color_prom[2*totcolors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ color_prom++;
+ }
+
+ color_prom += 2 * totcolors;
+ /* color_prom now points to the beginning of the lookup table */
+
+ /*
+ color lookup table:
+ 0- +1024 ( 4 * 256) colors: text (use 0- 256 colors)
+ 1024- +1024 (16 * 64) colors: sprite (use 768- 256 colors)
+ 2048- +512 ( 8 * 64) colors: bg (use 0- 512 colors)
+ 3840- +256 ( 4 * 64) colors: road (use 512- 256 colors)
+ */
+
+ /* tiles lookup table (1024 colors) */
+ for (i = 0; i < 1024;i++)
+ colortable[i] = *color_prom++;
+
+ /* road lookup table (256 colors) */
+ for (i = 0; i < 256; i++)
+ colortable[i + 0xf00] = *(color_prom++) + 512;
+
+ /* sprites lookup table (1024 colors) */
+ for (i = 0;i < 1024; i++)
+ colortable[i + 1024] = *(color_prom++) + 768;
+
+ /* background: lookup prom is not presented, use prom directly (512 colors) */
+ for (i = 0;i < 512; i++)
+ colortable[i + 2048] = i;
+
+ /* setup sprite mask color map */
+ /* tceptor2: only 0x23 */
+ memset(is_mask_spr, 0, sizeof is_mask_spr);
+ for (i = 0; i < 1024; i++)
+ if (colortable[i + 1024] == SPR_MASK_COLOR)
+ is_mask_spr[i / 16] = 1;
+}
+
+
+/*******************************************************************/
+
+INLINE int get_tile_addr(int tile_index)
+{
+ int x = tile_index / 28;
+ int y = tile_index % 28;
+
+ switch (x)
+ {
+ case 0:
+ return TX_TILE_OFFSET_LEFT + y;
+ case 33:
+ return TX_TILE_OFFSET_RIGHT + y;
+ }
+
+ return TX_TILE_OFFSET_CENTER + (x - 1) + y * 32;
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int offset = get_tile_addr(tile_index);
+ int code = tceptor_tile_ram[offset];
+ int color = tceptor_tile_attr[offset];
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static void tile_mark_dirty(int offset)
+{
+ int x = -1;
+ int y = -1;
+
+ if (offset >= TX_TILE_OFFSET_LEFT && offset < TX_TILE_OFFSET_LEFT + 28)
+ {
+ x = 0;
+ y = offset - TX_TILE_OFFSET_LEFT;
+ }
+ else if (offset >= TX_TILE_OFFSET_RIGHT && offset < TX_TILE_OFFSET_RIGHT + 28)
+ {
+ x = 33;
+ y = offset - TX_TILE_OFFSET_RIGHT;
+ }
+ else if (offset >= TX_TILE_OFFSET_CENTER && offset < TX_TILE_OFFSET_CENTER + 32 * 28)
+ {
+ offset -= TX_TILE_OFFSET_CENTER;
+ x = (offset % 32) + 1;
+ y = offset / 32;
+ }
+
+ if (x >= 0)
+ tilemap_mark_tile_dirty(tx_tilemap, x * 28 + y);
+}
+
+
+READ8_HANDLER( tceptor_tile_ram_r )
+{
+ return tceptor_tile_ram[offset];
+}
+
+WRITE8_HANDLER( tceptor_tile_ram_w )
+{
+ if (tceptor_tile_ram[offset] != data)
+ {
+ tceptor_tile_ram[offset] = data;
+ tile_mark_dirty(offset);
+ }
+}
+
+READ8_HANDLER( tceptor_tile_attr_r )
+{
+ return tceptor_tile_attr[offset];
+}
+
+WRITE8_HANDLER( tceptor_tile_attr_w )
+{
+ if (tceptor_tile_attr[offset] != data)
+ {
+ tceptor_tile_attr[offset] = data;
+ tile_mark_dirty(offset);
+ }
+}
+
+
+/*******************************************************************/
+
+static TILE_GET_INFO( get_bg1_tile_info )
+{
+ UINT16 data = tceptor_bg_ram[tile_index * 2] | (tceptor_bg_ram[tile_index * 2 + 1] << 8);
+ int code = (data & 0x3ff) | 0x000;
+ int color = (data & 0xfc00) >> 10;
+
+ SET_TILE_INFO(bg, code, color, 0);
+}
+
+static TILE_GET_INFO( get_bg2_tile_info )
+{
+ UINT16 data = tceptor_bg_ram[tile_index * 2 + 0x1000] | (tceptor_bg_ram[tile_index * 2 + 1 + 0x1000] << 8);
+ int code = (data & 0x3ff) | 0x400;
+ int color = (data & 0xfc00) >> 10;
+
+ SET_TILE_INFO(bg, code, color, 0);
+}
+
+READ8_HANDLER( tceptor_bg_ram_r )
+{
+ return tceptor_bg_ram[offset];
+}
+
+WRITE8_HANDLER( tceptor_bg_ram_w )
+{
+ tceptor_bg_ram[offset] = data;
+
+ offset /= 2;
+ if (offset < 0x800)
+ tilemap_mark_tile_dirty(bg1_tilemap, offset);
+ else
+ tilemap_mark_tile_dirty(bg2_tilemap, offset - 0x800);
+}
+
+WRITE8_HANDLER( tceptor_bg_scroll_w )
+{
+ switch (offset)
+ {
+ case 0:
+ bg1_scroll_x &= 0xff;
+ bg1_scroll_x |= data << 8;
+ break;
+ case 1:
+ bg1_scroll_x &= 0xff00;
+ bg1_scroll_x |= data;
+ break;
+ case 2:
+ bg1_scroll_y = data;
+ break;
+
+ case 4:
+ bg2_scroll_x &= 0xff;
+ bg2_scroll_x |= data << 8;
+ break;
+ case 5:
+ bg2_scroll_x &= 0xff00;
+ bg2_scroll_x |= data;
+ break;
+ case 6:
+ bg2_scroll_y = data;
+ break;
+ }
+}
+
+
+/*******************************************************************/
+
+static void decode_bg(running_machine *machine, int region)
+{
+ static const gfx_layout bg_layout =
+ {
+ 8, 8,
+ 2048,
+ 3,
+ { 0x40000+4, 0, 4 },
+ { 0, 1, 2, 3, 8, 9, 10, 11 },
+ { 0, 16, 32, 48, 64, 80, 96, 112 },
+ 128
+ };
+
+ int gfx_index = bg;
+ UINT8 *src = memory_region(region) + 0x8000;
+ UINT8 *buffer;
+ int len = 0x8000;
+ int i;
+
+ buffer = malloc_or_die(len);
+
+ /* expand rom tc2-19.10d */
+ for (i = 0; i < len / 2; i++)
+ {
+ buffer[i*2+1] = src[i] & 0x0f;
+ buffer[i*2] = (src[i] & 0xf0) >> 4;
+ }
+
+ memcpy(src, buffer, len);
+ free(buffer);
+
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(&bg_layout);
+ decodegfx(machine->gfx[gfx_index], memory_region(region), 0, machine->gfx[gfx_index]->total_elements);
+
+ /* set the color information */
+ machine->gfx[gfx_index]->color_base = 2048;
+ machine->gfx[gfx_index]->total_colors = 64;
+}
+
+static void decode_sprite(running_machine *machine, int gfx_index, const gfx_layout *layout, const void *data)
+{
+ /* decode the graphics */
+ machine->gfx[gfx_index] = allocgfx(layout);
+ decodegfx(machine->gfx[gfx_index], data, 0, machine->gfx[gfx_index]->total_elements);
+
+ /* set the color information */
+ machine->gfx[gfx_index]->color_base = 1024;
+ machine->gfx[gfx_index]->total_colors = 64;
+}
+
+// fix sprite order
+static void decode_sprite16(running_machine *machine, int region)
+{
+ static const gfx_layout spr16_layout =
+ {
+ 16, 16,
+ 512,
+ 4,
+ { 0x00000, 0x00004, 0x40000, 0x40004 },
+ {
+ 0*8, 0*8+1, 0*8+2, 0*8+3, 1*8, 1*8+1, 1*8+2, 1*8+3,
+ 2*8, 2*8+1, 2*8+2, 2*8+3, 3*8, 3*8+1, 3*8+2, 3*8+3
+ },
+ {
+ 0*2*16, 1*2*16, 2*2*16, 3*2*16, 4*2*16, 5*2*16, 6*2*16, 7*2*16,
+ 8*2*16, 9*2*16, 10*2*16, 11*2*16, 12*2*16, 13*2*16, 14*2*16, 15*2*16
+ },
+ 2*16*16
+ };
+
+ UINT8 *src = memory_region(region);
+ int len = memory_region_length(region);
+ UINT8 *dst;
+ int i, y;
+
+ dst = malloc_or_die(len);
+
+ for (i = 0; i < len / (4*4*16); i++)
+ for (y = 0; y < 16; y++)
+ {
+ memcpy(&dst[(i*4 + 0) * (2*16*16/8) + y * (2*16/8)],
+ &src[i * (2*32*32/8) + y * (2*32/8)],
+ 4);
+ memcpy(&dst[(i*4 + 1) * (2*16*16/8) + y * (2*16/8)],
+ &src[i * (2*32*32/8) + y * (2*32/8) + (4*8/8)],
+ 4);
+ memcpy(&dst[(i*4 + 2) * (2*16*16/8) + y * (2*16/8)],
+ &src[i * (2*32*32/8) + y * (2*32/8) + (16*2*32/8)],
+ 4);
+ memcpy(&dst[(i*4 + 3) * (2*16*16/8) + y * (2*16/8)],
+ &src[i * (2*32*32/8) + y * (2*32/8) + (4*8/8) + (16*2*32/8)],
+ 4);
+ }
+
+ decode_sprite(machine, sprite16, &spr16_layout, dst);
+
+ free(dst);
+}
+
+// fix sprite order
+static void decode_sprite32(running_machine *machine, int region)
+{
+ static const gfx_layout spr32_layout =
+ {
+ 32, 32,
+ 1024,
+ 4,
+ { 0x000000, 0x000004, 0x200000, 0x200004 },
+ {
+ 0*8, 0*8+1, 0*8+2, 0*8+3, 1*8, 1*8+1, 1*8+2, 1*8+3,
+ 2*8, 2*8+1, 2*8+2, 2*8+3, 3*8, 3*8+1, 3*8+2, 3*8+3,
+ 4*8, 4*8+1, 4*8+2, 4*8+3, 5*8, 5*8+1, 5*8+2, 5*8+3,
+ 6*8, 6*8+1, 6*8+2, 6*8+3, 7*8, 7*8+1, 7*8+2, 7*8+3
+ },
+ {
+ 0*2*32, 1*2*32, 2*2*32, 3*2*32, 4*2*32, 5*2*32, 6*2*32, 7*2*32,
+ 8*2*32, 9*2*32, 10*2*32, 11*2*32, 12*2*32, 13*2*32, 14*2*32, 15*2*32,
+ 16*2*32, 17*2*32, 18*2*32, 19*2*32, 20*2*32, 21*2*32, 22*2*32, 23*2*32,
+ 24*2*32, 25*2*32, 26*2*32, 27*2*32, 28*2*32, 29*2*32, 30*2*32, 31*2*32
+ },
+ 2*32*32
+ };
+
+ UINT8 *src = memory_region(region);
+ int len = memory_region_length(region);
+ int total = spr32_layout.total;
+ int size = spr32_layout.charincrement / 8;
+ UINT8 *dst;
+ int i;
+
+ dst = malloc_or_die(len);
+
+ memset(dst, 0, len);
+
+ for (i = 0; i < total; i++)
+ {
+ int code;
+
+ code = (i & 0x07f) | ((i & 0x180) << 1) | 0x80;
+ code &= ~((i & 0x200) >> 2);
+
+ memcpy(&dst[size * (i + 0)], &src[size * (code + 0)], size);
+ memcpy(&dst[size * (i + total)], &src[size * (code + total)], size);
+ }
+
+ decode_sprite(machine, sprite32, &spr32_layout, dst);
+
+ free(dst);
+}
+
+static void mark_all_tiles_dirty(void)
+{
+ tilemap_mark_all_tiles_dirty(tx_tilemap);
+ tilemap_mark_all_tiles_dirty(bg1_tilemap);
+ tilemap_mark_all_tiles_dirty(bg2_tilemap);
+}
+
+VIDEO_START( tceptor )
+{
+ int gfx_index;
+
+ /* find first empty slot to decode gfx */
+ for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
+ if (machine->gfx[gfx_index] == 0)
+ break;
+ assert(gfx_index + 4 <= MAX_GFX_ELEMENTS);
+
+ bg = gfx_index++;
+ decode_bg(machine, REGION_GFX2);
+
+ sprite16 = gfx_index++;
+ decode_sprite16(machine, REGION_GFX3);
+
+ sprite32 = gfx_index++;
+ decode_sprite32(machine, REGION_GFX4);
+
+ /* allocate temp bitmaps */
+ temp_bitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ namco_road_init(machine, gfx_index);
+
+ namco_road_set_transparent_color(machine->remapped_colortable[0xfff]);
+
+ tx_tilemap = tilemap_create(get_tx_tile_info, tilemap_scan_cols, TILEMAP_TYPE_COLORTABLE, 8, 8, 34, 28);
+
+ tilemap_set_scrollx(tx_tilemap, 0, -2*8);
+ tilemap_set_scrolly(tx_tilemap, 0, 0);
+ tilemap_set_transparent_pen(tx_tilemap, 7);
+
+ bg1_tilemap = tilemap_create(get_bg1_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+ bg2_tilemap = tilemap_create(get_bg2_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ state_save_register_global(bg1_scroll_x);
+ state_save_register_global(bg1_scroll_y);
+ state_save_register_global(bg2_scroll_x);
+ state_save_register_global(bg2_scroll_y);
+
+ state_save_register_func_postload(mark_all_tiles_dirty);
+}
+
+
+/*******************************************************************/
+
+/*
+ Sprite data format
+
+ 000: zzzzzzBB BTTTTTTT
+ 002: ZZZZZZPP PPCCCCCC
+ 100: fFL---YY YYYYYYYY
+ 102: ------XX XXXXXXXX
+
+ B: bank
+ T: number
+ P: priority
+ C: color
+ X: x
+ Y: y
+ L: large sprite
+ F: flip x
+ f: flip y
+ Z: zoom x
+ z: zoom y
+*/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int sprite_priority)
+{
+ UINT16 *mem1 = &tceptor_sprite_ram[0x000/2];
+ UINT16 *mem2 = &tceptor_sprite_ram[0x100/2];
+ int need_mask = 0;
+ int i;
+
+ for (i = 0; i < 0x100; i += 2)
+ {
+ int scalex = (mem1[1 + i] & 0xfc00) << 1;
+ int scaley = (mem1[0 + i] & 0xfc00) << 1;
+ int pri = 7 - ((mem1[1 + i] & 0x3c0) >> 6);
+
+ if (pri == sprite_priority && scalex && scaley)
+ {
+ int x = mem2[1 + i] & 0x3ff;
+ int y = 512 - (mem2[0 + i] & 0x3ff);
+ int flipx = mem2[0 + i] & 0x4000;
+ int flipy = mem2[0 + i] & 0x8000;
+ int color = mem1[1 + i] & 0x3f;
+ int gfx;
+ int code;
+
+ if (mem2[0 + i] & 0x2000)
+ {
+ gfx = sprite32;
+ code = mem1[0 + i] & 0x3ff;
+
+ }
+ else
+ {
+ gfx = sprite16;
+ code = mem1[0 + i] & 0x1ff;
+ scaley *= 2;
+ }
+
+ if (is_mask_spr[color])
+ {
+ if (!need_mask)
+ {
+ // backup previous bitmap
+ copybitmap(temp_bitmap, bitmap, 0, 0, 0, 0, cliprect, TRANSPARENCY_NONE, 0);
+ }
+
+ need_mask = 1;
+ }
+
+ // round off
+ scalex += 0x800;
+ scaley += 0x800;
+
+ x -= 64;
+ y -= 78;
+
+ drawgfxzoom(bitmap,
+ machine->gfx[gfx],
+ code,
+ color,
+ flipx, flipy,
+ x, y,
+ cliprect,
+ TRANSPARENCY_COLOR, SPR_TRANS_COLOR,
+ scalex,
+ scaley);
+ }
+ }
+
+ /* if SPR_MASK_COLOR pen is used, restore pixels from previous bitmap */
+ if (need_mask)
+ {
+ int x, y;
+
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ if (*BITMAP_ADDR16(bitmap, y, x) == SPR_MASK_COLOR)
+ {
+ // restore pixel
+ *BITMAP_ADDR16(bitmap, y, x) = *BITMAP_ADDR16(temp_bitmap, y, x);
+ }
+ }
+}
+
+
+VIDEO_UPDATE( tceptor )
+{
+ rectangle rect;
+ int pri;
+ int bg_center = 144 - ((((bg1_scroll_x + bg2_scroll_x ) & 0x1ff) - 288) / 2);
+
+ // left background
+ rect = *cliprect;
+ rect.max_x = bg_center;
+ tilemap_set_scrollx(bg1_tilemap, 0, bg1_scroll_x + 12);
+ tilemap_set_scrolly(bg1_tilemap, 0, bg1_scroll_y + 20); //32?
+ tilemap_draw(bitmap, &rect, bg1_tilemap, 0, 0);
+
+ // right background
+ rect.min_x = bg_center;
+ rect.max_x = cliprect->max_x;
+ tilemap_set_scrollx(bg2_tilemap, 0, bg2_scroll_x + 20);
+ tilemap_set_scrolly(bg2_tilemap, 0, bg2_scroll_y + 20); // 32?
+ tilemap_draw(bitmap, &rect, bg2_tilemap, 0, 0);
+
+ for (pri = 0; pri < 8; pri++)
+ {
+ namco_road_draw(machine, bitmap, cliprect, pri * 2);
+ namco_road_draw(machine, bitmap, cliprect, pri * 2 + 1);
+ draw_sprites(machine, bitmap, cliprect, pri);
+ }
+
+ tilemap_draw(bitmap, cliprect, tx_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/tecmo.c b/src/mame/video/tecmo.c
new file mode 100644
index 00000000000..0e52a2ed0f0
--- /dev/null
+++ b/src/mame/video/tecmo.c
@@ -0,0 +1,252 @@
+/***************************************************************************
+
+ video hardware for Tecmo games
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *tecmo_txvideoram,*tecmo_fgvideoram,*tecmo_bgvideoram;
+
+int tecmo_video_type = 0;
+/*
+ video_type is used to distinguish Rygar, Silkworm and Gemini Wing.
+ This is needed because there is a difference in the tile and sprite indexing.
+*/
+
+static tilemap *tx_tilemap,*fg_tilemap,*bg_tilemap;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 attr = tecmo_bgvideoram[tile_index+0x200];
+ SET_TILE_INFO(
+ 3,
+ tecmo_bgvideoram[tile_index] + ((attr & 0x07) << 8),
+ attr >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 attr = tecmo_fgvideoram[tile_index+0x200];
+ SET_TILE_INFO(
+ 2,
+ tecmo_fgvideoram[tile_index] + ((attr & 0x07) << 8),
+ attr >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( gemini_get_bg_tile_info )
+{
+ UINT8 attr = tecmo_bgvideoram[tile_index+0x200];
+ SET_TILE_INFO(
+ 3,
+ tecmo_bgvideoram[tile_index] + ((attr & 0x70) << 4),
+ attr & 0x0f,
+ 0);
+}
+
+static TILE_GET_INFO( gemini_get_fg_tile_info )
+{
+ UINT8 attr = tecmo_fgvideoram[tile_index+0x200];
+ SET_TILE_INFO(
+ 2,
+ tecmo_fgvideoram[tile_index] + ((attr & 0x70) << 4),
+ attr & 0x0f,
+ 0);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ UINT8 attr = tecmo_txvideoram[tile_index+0x400];
+ SET_TILE_INFO(
+ 0,
+ tecmo_txvideoram[tile_index] + ((attr & 0x03) << 8),
+ attr >> 4,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( tecmo )
+{
+ if (tecmo_video_type == 2) /* gemini */
+ {
+ bg_tilemap = tilemap_create(gemini_get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,16);
+ fg_tilemap = tilemap_create(gemini_get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,16);
+ }
+ else /* rygar, silkworm */
+ {
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,16);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,16);
+ }
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+
+ tilemap_set_transparent_pen(bg_tilemap,0);
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_transparent_pen(tx_tilemap,0);
+
+ tilemap_set_scrolldx(bg_tilemap,-48,256+48);
+ tilemap_set_scrolldx(fg_tilemap,-48,256+48);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( tecmo_txvideoram_w )
+{
+ tecmo_txvideoram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( tecmo_fgvideoram_w )
+{
+ tecmo_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x1ff);
+}
+
+WRITE8_HANDLER( tecmo_bgvideoram_w )
+{
+ tecmo_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x1ff);
+}
+
+WRITE8_HANDLER( tecmo_fgscroll_w )
+{
+ static UINT8 scroll[3];
+
+ scroll[offset] = data;
+
+ tilemap_set_scrollx(fg_tilemap,0,scroll[0] + 256 * scroll[1]);
+ tilemap_set_scrolly(fg_tilemap,0,scroll[2]);
+}
+
+WRITE8_HANDLER( tecmo_bgscroll_w )
+{
+ static UINT8 scroll[3];
+
+ scroll[offset] = data;
+
+ tilemap_set_scrollx(bg_tilemap,0,scroll[0] + 256 * scroll[1]);
+ tilemap_set_scrolly(bg_tilemap,0,scroll[2]);
+}
+
+WRITE8_HANDLER( tecmo_flipscreen_w )
+{
+ flip_screen_set(data & 1);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+ static const UINT8 layout[8][8] =
+ {
+ {0,1,4,5,16,17,20,21},
+ {2,3,6,7,18,19,22,23},
+ {8,9,12,13,24,25,28,29},
+ {10,11,14,15,26,27,30,31},
+ {32,33,36,37,48,49,52,53},
+ {34,35,38,39,50,51,54,55},
+ {40,41,44,45,56,57,60,61},
+ {42,43,46,47,58,59,62,63}
+ };
+
+ for (offs = spriteram_size-8;offs >= 0;offs -= 8)
+ {
+ int flags = spriteram[offs+3];
+ int priority = flags>>6;
+ int bank = spriteram[offs+0];
+ if (bank & 4)
+ { /* visible */
+ int which = spriteram[offs+1];
+ int code,xpos,ypos,flipx,flipy,priority_mask,x,y;
+ int size = spriteram[offs + 2] & 3;
+
+ if (tecmo_video_type != 0) /* gemini, silkworm */
+ code = which + ((bank & 0xf8) << 5);
+ else /* rygar */
+ code = which + ((bank & 0xf0) << 4);
+
+ code &= ~((1 << (size*2)) - 1);
+ size = 1 << size;
+
+ xpos = spriteram[offs + 5] - ((flags & 0x10) << 4);
+ ypos = spriteram[offs + 4] - ((flags & 0x20) << 3);
+ flipx = bank & 1;
+ flipy = bank & 2;
+
+ if (flip_screen)
+ {
+ xpos = 256 - (8 * size) - xpos;
+ ypos = 256 - (8 * size) - ypos;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ /* bg: 1; fg:2; text: 4 */
+ switch (priority)
+ {
+ default:
+ case 0x0: priority_mask = 0; break;
+ case 0x1: priority_mask = 0xf0; break; /* obscured by text layer */
+ case 0x2: priority_mask = 0xf0|0xcc; break; /* obscured by foreground */
+ case 0x3: priority_mask = 0xf0|0xcc|0xaa; break; /* obscured by bg and fg */
+ }
+
+ for (y = 0;y < size;y++)
+ {
+ for (x = 0;x < size;x++)
+ {
+ int sx = xpos + 8*(flipx?(size-1-x):x);
+ int sy = ypos + 8*(flipy?(size-1-y):y);
+ pdrawgfx(bitmap,machine->gfx[1],
+ code + layout[y][x],
+ flags & 0xf,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0,
+ priority_mask);
+ }
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( tecmo )
+{
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0x100],cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,1);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,2);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,4);
+
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/tecmo16.c b/src/mame/video/tecmo16.c
new file mode 100644
index 00000000000..44deac1e0b0
--- /dev/null
+++ b/src/mame/video/tecmo16.c
@@ -0,0 +1,507 @@
+/******************************************************************************
+
+ Ganbare Ginkun (Japan) (c)1995 TECMO
+ Final StarForce (US) (c)1992 TECMO
+ Riot (Japan) (c)1992 NMK
+
+ Based on sprite drivers from video/wc90.c by Ernesto Corvi (ernesto@imagina.com)
+
+******************************************************************************/
+
+#include "driver.h"
+
+UINT16 *tecmo16_videoram;
+UINT16 *tecmo16_colorram;
+UINT16 *tecmo16_videoram2;
+UINT16 *tecmo16_colorram2;
+UINT16 *tecmo16_charram;
+
+static tilemap *fg_tilemap,*bg_tilemap,*tx_tilemap;
+static mame_bitmap *sprite_bitmap, *tile_bitmap_bg, *tile_bitmap_fg;
+
+static int flipscreen, game_is_riot;
+
+/******************************************************************************/
+
+static TILE_GET_INFO( fg_get_tile_info )
+{
+ int tile = tecmo16_videoram[tile_index] & 0x1fff;
+ int color = tecmo16_colorram[tile_index] & 0x0f;
+
+ /* bit 4 controls blending */
+ tileinfo->category = (tecmo16_colorram[tile_index] & 0x10) >> 4;
+
+ SET_TILE_INFO(
+ 1,
+ tile,
+ color | (tileinfo->category ? 0x70 : 0x00),
+ 0);
+}
+
+static TILE_GET_INFO( bg_get_tile_info )
+{
+ int tile = tecmo16_videoram2[tile_index] & 0x1fff;
+ int color = (tecmo16_colorram2[tile_index] & 0x0f)+0x10;
+
+ SET_TILE_INFO(
+ 1,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( tx_get_tile_info )
+{
+ int tile = tecmo16_charram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ tile & 0x0fff,
+ tile >> 12,
+ 0);
+}
+
+/******************************************************************************/
+
+VIDEO_START( fstarfrc )
+{
+ /* set up tile layers */
+ tile_bitmap_bg = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+ tile_bitmap_fg = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+
+ /* set up sprites */
+ sprite_bitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+
+ fg_tilemap = tilemap_create(fg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ bg_tilemap = tilemap_create(bg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ tx_tilemap = tilemap_create(tx_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_transparent_pen(bg_tilemap,0);
+ tilemap_set_transparent_pen(tx_tilemap,0);
+
+ tilemap_set_scrolly(tx_tilemap,0,-16);
+ flipscreen = 0;
+ game_is_riot = 0;
+}
+
+VIDEO_START( ginkun )
+{
+ /* set up tile layers */
+ tile_bitmap_bg = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+ tile_bitmap_fg = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+
+ /* set up sprites */
+ sprite_bitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+
+ fg_tilemap = tilemap_create(fg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ bg_tilemap = tilemap_create(bg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ tx_tilemap = tilemap_create(tx_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_transparent_pen(bg_tilemap,0);
+ tilemap_set_transparent_pen(tx_tilemap,0);
+ flipscreen = 0;
+ game_is_riot = 0;
+}
+
+VIDEO_START( riot )
+{
+ /* set up tile layers */
+ tile_bitmap_bg = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+ tile_bitmap_fg = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+
+ /* set up sprites */
+ sprite_bitmap = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, BITMAP_FORMAT_INDEXED16);
+
+ fg_tilemap = tilemap_create(fg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ bg_tilemap = tilemap_create(bg_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ tx_tilemap = tilemap_create(tx_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_transparent_pen(bg_tilemap,0);
+ tilemap_set_transparent_pen(tx_tilemap,0);
+ tilemap_set_scrolldy(tx_tilemap,-16,-16);
+ flipscreen = 0;
+ game_is_riot = 1;
+}
+
+/******************************************************************************/
+
+WRITE16_HANDLER( tecmo16_videoram_w )
+{
+ COMBINE_DATA(&tecmo16_videoram[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE16_HANDLER( tecmo16_colorram_w )
+{
+ COMBINE_DATA(&tecmo16_colorram[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE16_HANDLER( tecmo16_videoram2_w )
+{
+ COMBINE_DATA(&tecmo16_videoram2[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE16_HANDLER( tecmo16_colorram2_w )
+{
+ COMBINE_DATA(&tecmo16_colorram2[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+
+WRITE16_HANDLER( tecmo16_charram_w )
+{
+ COMBINE_DATA(&tecmo16_charram[offset]);
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+WRITE16_HANDLER( tecmo16_flipscreen_w )
+{
+ flipscreen = data & 0x01;
+ flip_screen_set(flipscreen);
+}
+
+/******************************************************************************/
+
+WRITE16_HANDLER( tecmo16_scroll_x_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrollx(fg_tilemap,0,scroll);
+}
+
+WRITE16_HANDLER( tecmo16_scroll_y_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrolly(fg_tilemap,0,scroll);
+}
+
+WRITE16_HANDLER( tecmo16_scroll2_x_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrollx(bg_tilemap,0,scroll);
+}
+
+WRITE16_HANDLER( tecmo16_scroll2_y_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrolly(bg_tilemap,0,scroll);
+}
+
+WRITE16_HANDLER( tecmo16_scroll_char_x_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrollx(tx_tilemap,0,scroll);
+}
+
+WRITE16_HANDLER( tecmo16_scroll_char_y_w )
+{
+ static UINT16 scroll;
+ COMBINE_DATA(&scroll);
+ tilemap_set_scrolly(tx_tilemap,0,scroll-16);
+}
+
+/******************************************************************************/
+
+/* mix & blend the paletted 16-bit tile and sprite bitmaps into an RGB 32-bit bitmap */
+static void blendbitmaps(running_machine *machine,
+ mame_bitmap *dest,mame_bitmap *src1,mame_bitmap *src2,mame_bitmap *src3,
+ int sx,int sy,const rectangle *clip)
+{
+ int ox;
+ int oy;
+ int ex;
+ int ey;
+
+ /* check bounds */
+ ox = sx;
+ oy = sy;
+
+ ex = sx + src1->width - 1;
+ if (sx < 0) sx = 0;
+ if (sx < clip->min_x) sx = clip->min_x;
+ if (ex >= dest->width) ex = dest->width - 1;
+ if (ex > clip->max_x) ex = clip->max_x;
+ if (sx > ex) return;
+
+ ey = sy + src1->height - 1;
+ if (sy < 0) sy = 0;
+ if (sy < clip->min_y) sy = clip->min_y;
+ if (ey >= dest->height) ey = dest->height - 1;
+ if (ey > clip->max_y) ey = clip->max_y;
+ if (sy > ey) return;
+
+ {
+ const pen_t *paldata = machine->pens;
+ UINT32 *end;
+
+ UINT16 *sd1 = src1->base; /* source data */
+ UINT16 *sd2 = src2->base;
+ UINT16 *sd3 = src3->base;
+
+ int sw = ex-sx+1; /* source width */
+ int sh = ey-sy+1; /* source height */
+ int sm = src1->rowpixels; /* source modulo */
+
+ UINT32 *dd = BITMAP_ADDR32(dest, sy, sx); /* dest data */
+ int dm = dest->rowpixels; /* dest modulo */
+
+ sd1 += (sx-ox);
+ sd1 += sm * (sy-oy);
+ sd2 += (sx-ox);
+ sd2 += sm * (sy-oy);
+ sd3 += (sx-ox);
+ sd3 += sm * (sy-oy);
+
+ sm -= sw;
+ dm -= sw;
+
+ while (sh)
+ {
+
+#define BLENDPIXEL(x) if (sd3[x]) { \
+ if (sd2[x]) { \
+ dd[x] = paldata[sd2[x] | 0x0400] + paldata[sd3[x]]; \
+ } else { \
+ dd[x] = paldata[sd1[x] | 0x0400] + paldata[sd3[x]]; \
+ } \
+ } else { \
+ if (sd2[x]) { \
+ if (sd2[x] & 0x0800) { \
+ dd[x] = paldata[sd1[x] | 0x0400] + paldata[sd2[x]]; \
+ } else { \
+ dd[x] = paldata[sd2[x]]; \
+ } \
+ } else { \
+ dd[x] = paldata[sd1[x]]; \
+ } \
+ }
+
+ end = dd + sw;
+ while (dd <= end - 8)
+ {
+ BLENDPIXEL(0);
+ BLENDPIXEL(1);
+ BLENDPIXEL(2);
+ BLENDPIXEL(3);
+ BLENDPIXEL(4);
+ BLENDPIXEL(5);
+ BLENDPIXEL(6);
+ BLENDPIXEL(7);
+ dd += 8;
+ sd1 += 8;
+ sd2 += 8;
+ sd3 += 8;
+ }
+ while (dd < end)
+ {
+ BLENDPIXEL(0);
+ dd++;
+ sd1++;
+ sd2++;
+ sd3++;
+ }
+ dd += dm;
+ sd1 += sm;
+ sd2 += sm;
+ sd3 += sm;
+ sh--;
+
+#undef BLENDPIXEL
+
+ }
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap_bg, mame_bitmap *bitmap_fg, mame_bitmap *bitmap_sp, const rectangle *cliprect)
+{
+ int offs;
+ static const UINT8 layout[8][8] =
+ {
+ { 0, 1, 4, 5,16,17,20,21},
+ { 2, 3, 6, 7,18,19,22,23},
+ { 8, 9,12,13,24,25,28,29},
+ {10,11,14,15,26,27,30,31},
+ {32,33,36,37,48,49,52,53},
+ {34,35,38,39,50,51,54,55},
+ {40,41,44,45,56,57,60,61},
+ {42,43,46,47,58,59,62,63}
+ };
+
+ mame_bitmap *bitmap = bitmap_bg;
+
+ for (offs = spriteram_size/2 - 8;offs >= 0;offs -= 8)
+ {
+ if (spriteram16[offs] & 0x04) /* enable */
+ {
+ int code,color,sizex,sizey,flipx,flipy,xpos,ypos;
+ int x,y,priority,priority_mask;
+
+ code = spriteram16[offs+1];
+ color = (spriteram16[offs+2] & 0xf0) >> 4;
+ sizex = 1 << ((spriteram16[offs+2] & 0x03) >> 0);
+
+ if(game_is_riot)
+ sizey = sizex;
+ else
+ sizey = 1 << ((spriteram16[offs+2] & 0x0c) >> 2);
+
+ if (sizex >= 2) code &= ~0x01;
+ if (sizey >= 2) code &= ~0x02;
+ if (sizex >= 4) code &= ~0x04;
+ if (sizey >= 4) code &= ~0x08;
+ if (sizex >= 8) code &= ~0x10;
+ if (sizey >= 8) code &= ~0x20;
+ flipx = spriteram16[offs] & 0x01;
+ flipy = spriteram16[offs] & 0x02;
+ xpos = spriteram16[offs+4];
+ if (xpos >= 0x8000) xpos -= 0x10000;
+ ypos = spriteram16[offs+3];
+ if (ypos >= 0x8000) ypos -= 0x10000;
+ priority = (spriteram16[offs] & 0xc0) >> 6;
+
+ /* bg: 1; fg:2; text: 4 */
+ switch (priority)
+ {
+ default:
+ case 0x0: priority_mask = 0; break;
+ case 0x1: priority_mask = 0xf0; break; /* obscured by text layer */
+ case 0x2: priority_mask = 0xf0|0xcc; break; /* obscured by foreground */
+ case 0x3: priority_mask = 0xf0|0xcc|0xaa; break; /* obscured by bg and fg */
+ }
+
+ if (flipscreen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ /* blending */
+ if (spriteram16[offs] & 0x20)
+ {
+ color |= 0x80;
+
+ for (y = 0;y < sizey;y++)
+ {
+ for (x = 0;x < sizex;x++)
+ {
+ int sx,sy;
+
+ if (!flipscreen)
+ {
+ sx = xpos + 8*(flipx?(sizex-1-x):x);
+ sy = ypos + 8*(flipy?(sizey-1-y):y);
+ } else {
+ sx = 256 - (xpos + 8*(!flipx?(sizex-1-x):x) + 8);
+ sy = 256 - (ypos + 8*(!flipy?(sizey-1-y):y) + 8);
+ }
+ pdrawgfx(bitmap,machine->gfx[2],
+ code + layout[y][x],
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0,
+ priority_mask);
+
+ /* wrap around x */
+ pdrawgfx(bitmap,machine->gfx[2],
+ code + layout[y][x],
+ color,
+ flipx,flipy,
+ sx-512,sy,
+ cliprect,TRANSPARENCY_PEN,0,
+ priority_mask);
+
+ /* wrap around x */
+ pdrawgfx(bitmap,machine->gfx[2],
+ code + layout[y][x],
+ color,
+ flipx,flipy,
+ sx+512,sy,
+ cliprect,TRANSPARENCY_PEN,0,
+ priority_mask);
+ }
+ }
+ }
+ else
+ {
+ bitmap = (priority >= 2) ? bitmap_bg : bitmap_fg;
+
+ for (y = 0;y < sizey;y++)
+ {
+ for (x = 0;x < sizex;x++)
+ {
+ int sx,sy;
+
+ if (!flipscreen)
+ {
+ sx = xpos + 8*(flipx?(sizex-1-x):x);
+ sy = ypos + 8*(flipy?(sizey-1-y):y);
+ } else {
+ sx = 256 - (xpos + 8*(!flipx?(sizex-1-x):x) + 8);
+ sy = 256 - (ypos + 8*(!flipy?(sizey-1-y):y) + 8);
+ }
+ pdrawgfx(bitmap,machine->gfx[2],
+ code + layout[y][x],
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0,
+ priority_mask);
+
+ /* wrap around x */
+ pdrawgfx(bitmap,machine->gfx[2],
+ code + layout[y][x],
+ color,
+ flipx,flipy,
+ sx-512,sy,
+ cliprect,TRANSPARENCY_PEN,0,
+ priority_mask);
+
+ /* wrap around x */
+ pdrawgfx(bitmap,machine->gfx[2],
+ code + layout[y][x],
+ color,
+ flipx,flipy,
+ sx+512,sy,
+ cliprect,TRANSPARENCY_PEN,0,
+ priority_mask);
+ }
+ }
+ }
+ }
+ }
+}
+
+/******************************************************************************/
+
+VIDEO_UPDATE( tecmo16 )
+{
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ fillbitmap(tile_bitmap_bg, 0x300, cliprect);
+ fillbitmap(tile_bitmap_fg, 0, cliprect);
+ fillbitmap(sprite_bitmap, 0, cliprect);
+
+ /* draw tilemaps into a 16-bit bitmap */
+ tilemap_draw(tile_bitmap_bg, cliprect,bg_tilemap, 0, 1);
+ tilemap_draw(tile_bitmap_fg, cliprect,fg_tilemap, 0, 2);
+ /* draw the blended tiles at a lower priority
+ so sprites covered by them will still be drawn */
+ tilemap_draw(tile_bitmap_fg, cliprect,fg_tilemap, 1, 0);
+ tilemap_draw(tile_bitmap_fg, cliprect,tx_tilemap, 0, 4);
+
+ /* draw sprites into a 16-bit bitmap */
+ draw_sprites(machine, tile_bitmap_bg, tile_bitmap_fg, sprite_bitmap, cliprect);
+
+ /* mix & blend the tilemaps and sprites into a 32-bit bitmap */
+ blendbitmaps(machine, bitmap, tile_bitmap_bg, tile_bitmap_fg, sprite_bitmap, 0, 0, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/tehkanwc.c b/src/mame/video/tehkanwc.c
new file mode 100644
index 00000000000..5eb98d4de14
--- /dev/null
+++ b/src/mame/video/tehkanwc.c
@@ -0,0 +1,200 @@
+/***************************************************************************
+
+Tehkan World Cup - (c) Tehkan 1985
+
+
+Ernesto Corvi
+ernesto@imagina.com
+
+Roberto Juan Fresca
+robbiex@rocketmail.com
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *tehkanwc_videoram2;
+static UINT8 scroll_x[2];
+static UINT8 led0,led1;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+WRITE8_HANDLER( tehkanwc_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( tehkanwc_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( tehkanwc_videoram2_w )
+{
+ tehkanwc_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+WRITE8_HANDLER( tehkanwc_scroll_x_w )
+{
+ scroll_x[offset] = data;
+}
+
+WRITE8_HANDLER( tehkanwc_scroll_y_w )
+{
+ tilemap_set_scrolly(bg_tilemap, 0, data);
+}
+
+WRITE8_HANDLER( tehkanwc_flipscreen_x_w )
+{
+ flip_screen_x_set(data & 0x40);
+}
+
+WRITE8_HANDLER( tehkanwc_flipscreen_y_w )
+{
+ flip_screen_y_set(data & 0x40);
+}
+
+WRITE8_HANDLER( gridiron_led0_w )
+{
+ led0 = data;
+}
+WRITE8_HANDLER( gridiron_led1_w )
+{
+ led1 = data;
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int offs = tile_index * 2;
+ int attr = tehkanwc_videoram2[offs + 1];
+ int code = tehkanwc_videoram2[offs] + ((attr & 0x30) << 4);
+ int color = attr & 0x0f;
+ int flags = ((attr & 0x40) ? TILE_FLIPX : 0) | ((attr & 0x80) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(2, code, color, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + ((attr & 0x10) << 4);
+ int color = attr & 0x0f;
+ int flags = ((attr & 0x40) ? TILE_FLIPX : 0) | ((attr & 0x80) ? TILE_FLIPY : 0);
+
+ tileinfo->category = (attr & 0x20) ? 0 : 1;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( tehkanwc )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16, 8, 32, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+/*
+ Gridiron Fight has a LED display on the control panel, to let each player
+ choose the formation without letting the other know.
+ We emulate it by showing a character on the corner of the screen; the
+ association between the bits of the port and the led segments is:
+
+ ---0---
+ | |
+ 5 1
+ | |
+ ---6---
+ | |
+ 4 2
+ | |
+ ---3---
+
+ bit 7 = enable (0 = display off)
+ */
+
+static void gridiron_draw_led(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8 led,int player)
+{
+ int i;
+
+
+ static UINT8 ledvalues[] =
+ { 0x86, 0xdb, 0xcf, 0xe6, 0xed, 0xfd, 0x87, 0xff, 0xf3, 0xf1 };
+
+
+ if ((led & 0x80) == 0) return;
+
+ for (i = 0;i < 10;i++)
+ {
+ if (led == ledvalues[i] ) break;
+ }
+
+ if (i < 10)
+ {
+ if (player == 0)
+ drawgfx(bitmap,machine->gfx[0],
+ 0xc0 + i,
+ 0x0a,
+ 0,0,
+ 0,232,
+ cliprect,TRANSPARENCY_NONE,0);
+ else
+ drawgfx(bitmap,machine->gfx[0],
+ 0xc0 + i,
+ 0x03,
+ 1,1,
+ 0,16,
+ cliprect,TRANSPARENCY_NONE,0);
+ }
+else logerror("unknown LED %02x for player %d\n",led,player);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int attr = spriteram[offs + 1];
+ int code = spriteram[offs] + ((attr & 0x08) << 5);
+ int color = attr & 0x07;
+ int flipx = attr & 0x40;
+ int flipy = attr & 0x80;
+ int sx = spriteram[offs + 2] + ((attr & 0x20) << 3) - 128;
+ int sy = spriteram[offs + 3];
+
+ if (flip_screen_x)
+ {
+ sx = 240 - sx;
+ flipx = !flipx;
+ }
+
+ if (flip_screen_y)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1],
+ code, color, flipx, flipy, sx, sy,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( tehkanwc )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, scroll_x[0] + 256 * scroll_x[1]);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 1, 0);
+ gridiron_draw_led(machine, bitmap, cliprect, led0, 0);
+ gridiron_draw_led(machine, bitmap, cliprect, led1, 1);
+ return 0;
+}
diff --git a/src/mame/video/terracre.c b/src/mame/video/terracre.c
new file mode 100644
index 00000000000..582c22f5b15
--- /dev/null
+++ b/src/mame/video/terracre.c
@@ -0,0 +1,224 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static UINT16 xscroll;
+static UINT16 yscroll;
+static tilemap *background, *foreground;
+static const UINT8 *spritepalettebank;
+
+UINT16 *amazon_videoram;
+
+static
+TILE_GET_INFO( get_bg_tile_info )
+{
+ /* xxxx.----.----.----
+ * ----.xx--.----.----
+ * ----.--xx.xxxx.xxxx */
+ unsigned data = amazon_videoram[tile_index];
+ unsigned color = data>>11;
+ SET_TILE_INFO( 1,data&0x3ff,color,0 );
+}
+
+static
+TILE_GET_INFO( get_fg_tile_info )
+{
+ int data = videoram16[tile_index];
+ SET_TILE_INFO( 0,data&0xff,0,0 );
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ const gfx_element *pGfx = machine->gfx[2];
+ const UINT16 *pSource = spriteram16;
+ int i;
+ int transparent_pen;
+
+ if( pGfx->total_elements > 0x200 )
+ { /* HORE HORE Kid */
+ transparent_pen = 0xf;
+ }
+ else
+ {
+ transparent_pen = 0x0;
+ }
+ for( i=0; i<0x200; i+=8 )
+ {
+ int tile = pSource[1]&0xff;
+ int attrs = pSource[2];
+ int flipx = attrs&0x04;
+ int flipy = attrs&0x08;
+ int color = (attrs&0xf0)>>4;
+ int sx = (pSource[3] & 0xff) - 0x80 + 256 * (attrs & 1);
+ int sy = 240 - (pSource[0] & 0xff);
+
+ if( transparent_pen )
+ {
+ int bank;
+
+ if( attrs&0x02 ) tile |= 0x200;
+ if( attrs&0x10 ) tile |= 0x100;
+
+ bank = (tile&0xfc)>>1;
+ if( tile&0x200 ) bank |= 0x80;
+ if( tile&0x100 ) bank |= 0x01;
+
+ color &= 0xe;
+ color += 16*(spritepalettebank[bank]&0xf);
+ }
+ else
+ {
+ if( attrs&0x02 ) tile|= 0x100;
+ color += 16 * (spritepalettebank[(tile>>1)&0xff] & 0x0f);
+ }
+
+ if (flip_screen)
+ {
+ sx=240-sx;
+ sy=240-sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(
+ bitmap,pGfx,tile, color,flipx,flipy,sx,sy,cliprect,TRANSPARENCY_PEN,transparent_pen );
+
+ pSource += 4;
+ }
+}
+
+PALETTE_INIT( amazon )
+{
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+ int i;
+ for( i = 0; i<machine->drv->total_colors; i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the lookup table */
+
+
+ /* characters use colors 0-15 */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = i;
+
+ /* background tiles use colors 192-255 in four banks */
+ /* the bottom two bits of the color code select the palette bank for */
+ /* pens 0-7; the top two bits for pens 8-15. */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ {
+ if (i & 8) COLOR(1,i) = 192 + (i & 0x0f) + ((i & 0xc0) >> 2);
+ else COLOR(1,i) = 192 + (i & 0x0f) + ((i & 0x30) >> 0);
+ }
+
+ /* sprites use colors 128-191 in four banks */
+ /* The lookup table tells which colors to pick from the selected bank */
+ /* the bank is selected by another PROM and depends on the top 8 bits of */
+ /* the sprite code. The PROM selects the bank *separately* for pens 0-7 and */
+ /* 8-15 (like for tiles). */
+ for (i = 0;i < TOTAL_COLORS(2)/16;i++)
+ {
+ int j;
+
+ for (j = 0;j < 16;j++)
+ {
+ if (i & 8)
+ COLOR(2,i + j * (TOTAL_COLORS(2)/16)) = 128 + ((j & 0x0c) << 2) + (*color_prom & 0x0f);
+ else
+ COLOR(2,i + j * (TOTAL_COLORS(2)/16)) = 128 + ((j & 0x03) << 4) + (*color_prom & 0x0f);
+ }
+
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the sprite palette bank table */
+ spritepalettebank = color_prom; /* we'll need it at run time */
+}
+
+WRITE16_HANDLER( amazon_background_w )
+{
+ COMBINE_DATA( &amazon_videoram[offset] );
+ tilemap_mark_tile_dirty( background, offset );
+}
+
+WRITE16_HANDLER( amazon_foreground_w )
+{
+ COMBINE_DATA( &videoram16[offset] );
+ tilemap_mark_tile_dirty( foreground, offset );
+}
+
+WRITE16_HANDLER( amazon_flipscreen_w )
+{
+ if( ACCESSING_LSB )
+ {
+ coin_counter_w( 0, data&0x01 );
+ coin_counter_w( 1, (data&0x02)>>1 );
+ flip_screen_set(data&0x04);
+ }
+}
+
+WRITE16_HANDLER( amazon_scrolly_w )
+{
+ COMBINE_DATA(&yscroll);
+ tilemap_set_scrolly(background,0,yscroll);
+}
+
+WRITE16_HANDLER( amazon_scrollx_w )
+{
+ COMBINE_DATA(&xscroll);
+ tilemap_set_scrollx(background,0,xscroll);
+}
+
+VIDEO_START( amazon )
+{
+ background = tilemap_create(get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,64,32);
+ foreground = tilemap_create(get_fg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,8,8,64,32);
+ tilemap_set_transparent_pen(foreground,0xf);
+
+ /* register for saving */
+ state_save_register_global(xscroll);
+ state_save_register_global(yscroll);
+}
+
+VIDEO_UPDATE( amazon )
+{
+ if( xscroll&0x2000 )
+ {
+ fillbitmap( bitmap,get_black_pen(machine),cliprect );
+ }
+ else
+ {
+ tilemap_draw( bitmap,cliprect, background, 0, 0 );
+ }
+ draw_sprites( machine, bitmap,cliprect );
+ tilemap_draw( bitmap,cliprect, foreground, 0, 0 );
+ return 0;
+}
diff --git a/src/mame/video/tetrisp2.c b/src/mame/video/tetrisp2.c
new file mode 100644
index 00000000000..a52265e25a4
--- /dev/null
+++ b/src/mame/video/tetrisp2.c
@@ -0,0 +1,797 @@
+/***************************************************************************
+
+ -= Tetris Plus 2 =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z with:
+
+ Q shows the background
+ W shows the foreground
+ A shows the sprites
+
+ Keys can be used together!
+
+
+ [ 2 Scrolling Layers ]
+
+ The Background is a 64 x 64 Tilemap with 16 x 16 x 8 tiles (1024 x 1024).
+ The Foreground is a 64 x 64 Tilemap with 8 x 8 x 8 tiles (512 x 512).
+ Each tile needs 4 bytes.
+
+ [ 1024? Sprites ]
+
+ Sprites are "nearly" tile based: if the data in the ROMs is decoded
+ as 8x8 tiles, and each 32 consecutive tiles are drawn like a column
+ of 256 pixels, it turns out that every 32 x 32 tiles form a picture
+ of 256 x 256 pixels (a "page").
+
+ Sprites are portions of any size from those page's graphics rendered
+ to screen.
+
+To Do:
+
+- There is a 3rd unimplemented layer capable of rotation (not used by
+ the game, can be tested in service mode).
+- Priority RAM is not taken into account.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+extern UINT16 tetrisp2_systemregs[0x10];
+
+/* Variables needed by driver: */
+
+UINT16 *tetrisp2_vram_bg, *tetrisp2_scroll_bg;
+UINT16 *tetrisp2_vram_fg, *tetrisp2_scroll_fg;
+UINT16 *tetrisp2_vram_rot, *tetrisp2_rotregs;
+
+UINT16 *tetrisp2_priority;
+
+UINT16 *rocknms_sub_vram_bg, *rocknms_sub_scroll_bg;
+UINT16 *rocknms_sub_vram_fg, *rocknms_sub_scroll_fg;
+UINT16 *rocknms_sub_vram_rot, *rocknms_sub_rotregs;
+
+UINT16 *rocknms_sub_priority;
+
+
+/***************************************************************************
+
+
+ Palette
+
+
+***************************************************************************/
+
+/* BBBBBGGGGGRRRRRx xxxxxxxxxxxxxxxx */
+WRITE16_HANDLER( tetrisp2_palette_w )
+{
+ data = COMBINE_DATA(&paletteram16[offset]);
+ if ((offset & 1) == 0)
+ palette_set_color_rgb(Machine,offset/2,pal5bit(data >> 1),pal5bit(data >> 6),pal5bit(data >> 11));
+}
+
+WRITE16_HANDLER( rocknms_sub_palette_w )
+{
+ data = COMBINE_DATA(&paletteram16_2[offset]);
+ if ((offset & 1) == 0)
+ palette_set_color_rgb(Machine,(0x8000 + (offset/2)),pal5bit(data >> 1),pal5bit(data >> 6),pal5bit(data >> 11));
+}
+
+
+
+/***************************************************************************
+
+
+ Priority
+
+
+***************************************************************************/
+
+READ16_HANDLER( tetrisp2_priority_r )
+{
+ return tetrisp2_priority[offset];
+}
+
+READ16_HANDLER( rocknms_sub_priority_r )
+{
+ return rocknms_sub_priority[offset];
+}
+
+
+WRITE16_HANDLER( tetrisp2_priority_w )
+{
+ if (ACCESSING_MSB)
+ {
+ data |= ((data & 0xff00) >> 8);
+ tetrisp2_priority[offset] = data;
+ }
+}
+
+
+WRITE16_HANDLER( rockn_priority_w )
+{
+ if (ACCESSING_MSB)
+ {
+ tetrisp2_priority[offset] = data;
+ }
+}
+
+WRITE16_HANDLER( rocknms_sub_priority_w )
+{
+ if (ACCESSING_MSB)
+ {
+ rocknms_sub_priority[offset] = data;
+ }
+}
+
+
+
+/***************************************************************************
+
+
+ Tilemaps
+
+
+ Offset: Bits: Value:
+
+ 0.w Code
+ 2.w fedc ba98 7654 ----
+ ---- ---- ---- 3210 Color
+
+
+***************************************************************************/
+
+static tilemap *tilemap_bg, *tilemap_fg, *tilemap_rot;
+static tilemap *tilemap_sub_bg, *tilemap_sub_fg, *tilemap_sub_rot;
+
+#define NX_0 (0x40)
+#define NY_0 (0x40)
+
+static TILE_GET_INFO( get_tile_info_bg )
+{
+ UINT16 code_hi = tetrisp2_vram_bg[ 2 * tile_index + 0];
+ UINT16 code_lo = tetrisp2_vram_bg[ 2 * tile_index + 1];
+ SET_TILE_INFO(
+ 1,
+ code_hi,
+ code_lo & 0xf,
+ 0);
+}
+
+WRITE16_HANDLER( tetrisp2_vram_bg_w )
+{
+ COMBINE_DATA(&tetrisp2_vram_bg[offset]);
+ tilemap_mark_tile_dirty(tilemap_bg,offset/2);
+}
+
+
+
+#define NX_1 (0x40)
+#define NY_1 (0x40)
+
+static TILE_GET_INFO( get_tile_info_fg )
+{
+ UINT16 code_hi = tetrisp2_vram_fg[ 2 * tile_index + 0];
+ UINT16 code_lo = tetrisp2_vram_fg[ 2 * tile_index + 1];
+ SET_TILE_INFO(
+ 3,
+ code_hi,
+ code_lo & 0xf,
+ 0);
+}
+
+WRITE16_HANDLER( tetrisp2_vram_fg_w )
+{
+ COMBINE_DATA(&tetrisp2_vram_fg[offset]);
+ tilemap_mark_tile_dirty(tilemap_fg,offset/2);
+}
+
+
+static TILE_GET_INFO( get_tile_info_rot )
+{
+ UINT16 code_hi = tetrisp2_vram_rot[ 2 * tile_index + 0];
+ UINT16 code_lo = tetrisp2_vram_rot[ 2 * tile_index + 1];
+ SET_TILE_INFO(
+ 2,
+ code_hi,
+ code_lo & 0xf,
+ 0);
+}
+
+WRITE16_HANDLER( tetrisp2_vram_rot_w )
+{
+ COMBINE_DATA(&tetrisp2_vram_rot[offset]);
+ tilemap_mark_tile_dirty(tilemap_rot,offset/2);
+}
+
+static TILE_GET_INFO( get_tile_info_rocknms_sub_bg )
+{
+ UINT16 code_hi = rocknms_sub_vram_bg[ 2 * tile_index + 0];
+ UINT16 code_lo = rocknms_sub_vram_bg[ 2 * tile_index + 1];
+ SET_TILE_INFO(
+ 5,
+ code_hi,
+ code_lo & 0xf,
+ 0);
+}
+
+WRITE16_HANDLER( rocknms_sub_vram_bg_w )
+{
+ COMBINE_DATA(&rocknms_sub_vram_bg[offset]);
+ tilemap_mark_tile_dirty(tilemap_sub_bg,offset/2);
+}
+
+
+static TILE_GET_INFO( get_tile_info_rocknms_sub_fg )
+{
+ UINT16 code_hi = rocknms_sub_vram_fg[ 2 * tile_index + 0];
+ UINT16 code_lo = rocknms_sub_vram_fg[ 2 * tile_index + 1];
+ SET_TILE_INFO(
+ 7,
+ code_hi,
+ code_lo & 0xf,
+ 0);
+}
+
+WRITE16_HANDLER( rocknms_sub_vram_fg_w )
+{
+ COMBINE_DATA(&rocknms_sub_vram_fg[offset]);
+ tilemap_mark_tile_dirty(tilemap_sub_fg,offset/2);
+}
+
+
+static TILE_GET_INFO( get_tile_info_rocknms_sub_rot )
+{
+ UINT16 code_hi = rocknms_sub_vram_rot[ 2 * tile_index + 0];
+ UINT16 code_lo = rocknms_sub_vram_rot[ 2 * tile_index + 1];
+ SET_TILE_INFO(
+ 6,
+ code_hi,
+ code_lo & 0xf,
+ 0);
+}
+
+WRITE16_HANDLER( rocknms_sub_vram_rot_w )
+{
+ COMBINE_DATA(&rocknms_sub_vram_rot[offset]);
+ tilemap_mark_tile_dirty(tilemap_sub_rot,offset/2);
+}
+
+
+
+
+VIDEO_START( tetrisp2 )
+{
+ tilemap_bg = tilemap_create( get_tile_info_bg,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16,16,NX_0,NY_0);
+
+ tilemap_fg = tilemap_create( get_tile_info_fg,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 8,8,NX_1,NY_1);
+
+ tilemap_rot = tilemap_create( get_tile_info_rot,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16,16,NX_0*2,NY_0*2);
+
+ tilemap_set_transparent_pen(tilemap_bg,0);
+ tilemap_set_transparent_pen(tilemap_fg,0);
+ tilemap_set_transparent_pen(tilemap_rot,0);
+}
+
+VIDEO_START( rockntread )
+{
+ tilemap_bg = tilemap_create( get_tile_info_bg,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16, 16, 256, 16); // rockn ms(main),1,2,3,4
+
+ tilemap_fg = tilemap_create( get_tile_info_fg,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 8, 8, 64, 64);
+
+ tilemap_rot = tilemap_create( get_tile_info_rot,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16, 16, 128, 128);
+
+ tilemap_set_transparent_pen(tilemap_bg, 0);
+ tilemap_set_transparent_pen(tilemap_fg, 0);
+ tilemap_set_transparent_pen(tilemap_rot, 0);
+}
+
+
+VIDEO_START( rocknms )
+{
+ tilemap_bg = tilemap_create(get_tile_info_bg,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16, 16, 256, 16); // rockn ms(main),1,2,3,4
+
+ tilemap_fg = tilemap_create(get_tile_info_fg,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 8, 8, 64, 64);
+
+ tilemap_rot = tilemap_create(get_tile_info_rot,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16, 16, 128, 128);
+
+ tilemap_sub_bg = tilemap_create(get_tile_info_rocknms_sub_bg,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16, 16, 32, 256); // rockn ms(sub)
+
+ tilemap_sub_fg = tilemap_create(get_tile_info_rocknms_sub_fg,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 8, 8, 64, 64);
+
+ tilemap_sub_rot = tilemap_create( get_tile_info_rocknms_sub_rot,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 16, 16, 128, 128);
+
+ tilemap_set_transparent_pen(tilemap_bg, 0);
+ tilemap_set_transparent_pen(tilemap_fg, 0);
+ tilemap_set_transparent_pen(tilemap_rot, 0);
+
+ tilemap_set_transparent_pen(tilemap_sub_bg, 0);
+ tilemap_set_transparent_pen(tilemap_sub_fg, 0);
+ tilemap_set_transparent_pen(tilemap_sub_rot, 0);
+}
+
+
+/***************************************************************************
+
+
+ Sprites Drawing
+
+ Offset: Bits: Meaning:
+
+ 0.w fedc ba98 ---- ----
+ ---- ---- 7654 ---- Priority
+ ---- ---- ---- 3---
+ ---- ---- ---- -2-- Draw this sprite
+ ---- ---- ---- --1- Flip Y
+ ---- ---- ---- ---0 Flip X
+
+ 2.w fedc ba98 ---- ---- Tile's Y position in the tile page (*)
+ ---- ---- 7654 3210 Tile's X position in the tile page (*)
+
+ 4.w fedc ---- ---- ---- Color
+ ---- ba98 7--- ----
+ ---- ---- -654 3210 Tile Page (32x32 tiles = 256x256 pixels each)
+
+ 6.w fedc ba98 ---- ----
+ ---- ---- 7654 ---- Y Size - 1 (*)
+ ---- ---- ---- 3210 X Size - 1 (*)
+
+ 8.w fedc ba-- ---- ----
+ ---- --98 7654 3210 Y (Signed)
+
+ A.w fedc b--- ---- ----
+ ---- -a98 7654 3210 X (Signed)
+
+ C.w fedc ba98 7654 3210 ZOOM X (unused)
+
+ E.w fedc ba98 7654 3210 ZOOM Y (unused)
+
+(*) 1 pixel granularity
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT16 *sprram_top, size_t sprram_size, int gfxnum)
+{
+ int x, y, tx, ty, sx, sy, flipx, flipy;
+ int xsize, ysize, xnum, ynum;
+ int xstart, ystart, xend, yend, xinc, yinc;
+ int code, attr, color, size;
+ int flipscreen;
+ UINT32 primask;
+ UINT16 *priority_ram;
+
+ int min_x = cliprect->min_x;
+ int max_x = cliprect->max_x;
+ int min_y = cliprect->min_y;
+ int max_y = cliprect->max_y;
+
+ UINT16 *source = sprram_top;
+ const UINT16 *finish = sprram_top + (sprram_size - 0x10) / 2;
+
+ priority_ram = tetrisp2_priority;
+
+ flipscreen = (tetrisp2_systemregs[0x00] & 0x02);
+
+ for (; source <= finish; source += 0x10/2 )
+ {
+ rectangle clip;
+
+ attr = source[ 0 ];
+
+ if ((attr & 0x0004) == 0) continue;
+
+ flipx = attr & 1;
+ flipy = attr & 2;
+
+ code = source[ 1 ];
+ color = source[ 2 ];
+
+ tx = (code >> 0) & 0xff;
+ ty = (code >> 8) & 0xff;
+
+ code = (tx / 8) +
+ (ty / 8) * (0x100/8) +
+ (color & 0x7f) * (0x100/8) * (0x100/8);
+
+ color = (color >> 12) & 0xf;
+
+ size = source[ 3 ];
+
+ xsize = ((size >> 0) & 0xff) + 1;
+ ysize = ((size >> 8) & 0xff) + 1;
+
+ xnum = ( ((tx + xsize) & ~7) + (((tx + xsize) & 7) ? 8 : 0) - (tx & ~7) ) / 8;
+ ynum = ( ((ty + ysize) & ~7) + (((ty + ysize) & 7) ? 8 : 0) - (ty & ~7) ) / 8;
+
+ sy = source[ 4 ];
+ sx = source[ 5 ];
+
+ sx = (sx & 0x3ff) - (sx & 0x400);
+ sy = (sy & 0x1ff) - (sy & 0x200);
+
+ /* Flip Screen */
+ if (flipscreen)
+ {
+ sx = max_x + 1 - sx - xsize; flipx = !flipx;
+ sy = max_y + 1 - sy - ysize; flipy = !flipy;
+ }
+
+ /* Clip the sprite if its width or height is not an integer
+ multiple of 8 pixels (1 tile) */
+
+ clip.min_x = sx;
+ clip.max_x = sx + xsize - 1;
+ clip.min_y = sy;
+ clip.max_y = sy + ysize - 1;
+
+ if (clip.min_x > max_x) continue;
+ if (clip.max_x < min_x) continue;
+
+ if (clip.min_y > max_y) continue;
+ if (clip.max_y < min_y) continue;
+
+ if (clip.min_x < min_x) clip.min_x = min_x;
+ if (clip.max_x > max_x) clip.max_x = max_x;
+
+ if (clip.min_y < min_y) clip.min_y = min_y;
+ if (clip.max_y > max_y) clip.max_y = max_y;
+
+ if (flipx) { xstart = xnum-1; xend = -1; xinc = -1; sx -= xnum*8 - xsize - (tx & 7); }
+ else { xstart = 0; xend = xnum; xinc = +1; sx -= tx & 7; }
+
+ if (flipy) { ystart = ynum-1; yend = -1; yinc = -1; sy -= ynum*8 - ysize - (ty & 7); }
+ else { ystart = 0; yend = ynum; yinc = +1; sy -= ty & 7; }
+
+ primask = 0;
+ if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x1500) / 2] & 0x38) primask |= 1 << 0;
+ if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x1400) / 2] & 0x38) primask |= 1 << 1;
+ if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x1100) / 2] & 0x38) primask |= 1 << 2;
+ if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x1000) / 2] & 0x38) primask |= 1 << 3;
+ if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x0500) / 2] & 0x38) primask |= 1 << 4;
+ if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x0400) / 2] & 0x38) primask |= 1 << 5;
+ if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x0100) / 2] & 0x38) primask |= 1 << 6;
+ if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x0000) / 2] & 0x38) primask |= 1 << 7;
+
+ for (y = ystart; y != yend; y += yinc)
+ {
+ for (x = xstart; x != xend; x += xinc)
+ {
+ pdrawgfx(bitmap, machine->gfx[gfxnum],
+ code++,
+ color,
+ flipx, flipy,
+ sx + x * 8, sy + y * 8,
+ &clip,
+ TRANSPARENCY_PEN, 0, primask);
+ }
+ code += (0x100/8) - xnum;
+ }
+ } /* end sprite loop */
+}
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+VIDEO_UPDATE( tetrisp2 )
+{
+ static int flipscreen_old = -1;
+ int flipscreen;
+ int asc_pri;
+ int scr_pri;
+ int rot_pri;
+ int rot_ofsx, rot_ofsy;
+
+ flipscreen = (tetrisp2_systemregs[0x00] & 0x02);
+
+ /* Black background color */
+ fillbitmap(bitmap, machine->pens[0x0000], cliprect);
+ fillbitmap(priority_bitmap, 0, NULL);
+
+ /* Flip Screen */
+ if (flipscreen != flipscreen_old)
+ {
+ flipscreen_old = flipscreen;
+ tilemap_set_flip(ALL_TILEMAPS, flipscreen ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
+ }
+
+ /* Flip Screen */
+ if (flipscreen)
+ {
+ rot_ofsx = 0x053f;
+ rot_ofsy = 0x04df;
+ }
+ else
+ {
+ rot_ofsx = 0x400;
+ rot_ofsy = 0x400;
+ }
+
+ tilemap_set_scrollx(tilemap_bg, 0, (((tetrisp2_scroll_bg[ 0 ] + 0x0014) + tetrisp2_scroll_bg[ 2 ] ) & 0xffff));
+ tilemap_set_scrolly(tilemap_bg, 0, (((tetrisp2_scroll_bg[ 3 ] + 0x0000) + tetrisp2_scroll_bg[ 5 ] ) & 0xffff));
+
+ tilemap_set_scrollx(tilemap_fg, 0, tetrisp2_scroll_fg[ 2 ]);
+ tilemap_set_scrolly(tilemap_fg, 0, tetrisp2_scroll_fg[ 5 ]);
+
+ tilemap_set_scrollx(tilemap_rot, 0, (tetrisp2_rotregs[ 0 ] - rot_ofsx));
+ tilemap_set_scrolly(tilemap_rot, 0, (tetrisp2_rotregs[ 2 ] - rot_ofsy));
+
+ asc_pri = scr_pri = rot_pri = 0;
+
+ if((tetrisp2_priority[0x2b00 / 2] & 0x00ff) == 0x0034)
+ asc_pri++;
+ else
+ rot_pri++;
+
+ if((tetrisp2_priority[0x2e00 / 2] & 0x00ff) == 0x0034)
+ asc_pri++;
+ else
+ scr_pri++;
+
+ if((tetrisp2_priority[0x3a00 / 2] & 0x00ff) == 0x000c)
+ scr_pri++;
+ else
+ rot_pri++;
+
+ if (rot_pri == 0)
+ tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
+ else if (scr_pri == 0)
+ tilemap_draw(bitmap,cliprect, tilemap_bg, 0, 1 << 0);
+ else if (asc_pri == 0)
+ tilemap_draw(bitmap,cliprect, tilemap_fg, 0, 1 << 2);
+
+ if (rot_pri == 1)
+ tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
+ else if (scr_pri == 1)
+ tilemap_draw(bitmap,cliprect, tilemap_bg, 0, 1 << 0);
+ else if (asc_pri == 1)
+ tilemap_draw(bitmap,cliprect, tilemap_fg, 0, 1 << 2);
+
+ if (rot_pri == 2)
+ tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
+ else if (scr_pri == 2)
+ tilemap_draw(bitmap,cliprect, tilemap_bg, 0, 1 << 0);
+ else if (asc_pri == 2)
+ tilemap_draw(bitmap,cliprect, tilemap_fg, 0, 1 << 2);
+
+ draw_sprites(machine, bitmap,cliprect, spriteram16, spriteram_size, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( rockntread )
+{
+ static int flipscreen_old = -1;
+ int flipscreen;
+ int asc_pri;
+ int scr_pri;
+ int rot_pri;
+ int rot_ofsx, rot_ofsy;
+
+ flipscreen = (tetrisp2_systemregs[0x00] & 0x02);
+
+ /* Black background color */
+ fillbitmap(bitmap, machine->pens[0x0000], cliprect);
+ fillbitmap(priority_bitmap, 0, NULL);
+
+ /* Flip Screen */
+ if (flipscreen != flipscreen_old)
+ {
+ flipscreen_old = flipscreen;
+ tilemap_set_flip(ALL_TILEMAPS, flipscreen ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
+ }
+
+ /* Flip Screen */
+ if (flipscreen)
+ {
+ rot_ofsx = 0x053f;
+ rot_ofsy = 0x04df;
+ }
+ else
+ {
+ rot_ofsx = 0x400;
+ rot_ofsy = 0x400;
+ }
+
+ tilemap_set_scrollx(tilemap_bg, 0, (((tetrisp2_scroll_bg[ 0 ] + 0x0014) + tetrisp2_scroll_bg[ 2 ] ) & 0xffff));
+ tilemap_set_scrolly(tilemap_bg, 0, (((tetrisp2_scroll_bg[ 3 ] + 0x0000) + tetrisp2_scroll_bg[ 5 ] ) & 0xffff));
+
+ tilemap_set_scrollx(tilemap_fg, 0, tetrisp2_scroll_fg[ 2 ]);
+ tilemap_set_scrolly(tilemap_fg, 0, tetrisp2_scroll_fg[ 5 ]);
+
+ tilemap_set_scrollx(tilemap_rot, 0, (tetrisp2_rotregs[ 0 ] - rot_ofsx));
+ tilemap_set_scrolly(tilemap_rot, 0, (tetrisp2_rotregs[ 2 ] - rot_ofsy));
+
+ asc_pri = scr_pri = rot_pri = 0;
+
+ if((tetrisp2_priority[0x2b00 / 2] & 0x00ff) == 0x0034)
+ asc_pri++;
+ else
+ rot_pri++;
+
+ if((tetrisp2_priority[0x2e00 / 2] & 0x00ff) == 0x0034)
+ asc_pri++;
+ else
+ scr_pri++;
+
+ if((tetrisp2_priority[0x3a00 / 2] & 0x00ff) == 0x000c)
+ scr_pri++;
+ else
+ rot_pri++;
+
+ if (rot_pri == 0)
+ tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
+ else if (scr_pri == 0)
+ tilemap_draw(bitmap,cliprect, tilemap_bg, 0, 1 << 0);
+ else if (asc_pri == 0)
+ tilemap_draw(bitmap,cliprect, tilemap_fg, 0, 1 << 2);
+
+ if (rot_pri == 1)
+ tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
+ else if (scr_pri == 1)
+ tilemap_draw(bitmap,cliprect, tilemap_bg, 0, 1 << 0);
+ else if (asc_pri == 1)
+ tilemap_draw(bitmap,cliprect, tilemap_fg, 0, 1 << 2);
+
+ if (rot_pri == 2)
+ tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
+ else if (scr_pri == 2)
+ tilemap_draw(bitmap,cliprect, tilemap_bg, 0, 1 << 0);
+ else if (asc_pri == 2)
+ tilemap_draw(bitmap,cliprect, tilemap_fg, 0, 1 << 2);
+
+ draw_sprites(machine, bitmap,cliprect, spriteram16, spriteram_size, 0);
+ return 0;
+}
+
+
+
+
+VIDEO_UPDATE( rocknms )
+{
+ int asc_pri;
+ int scr_pri;
+ int rot_pri;
+
+
+ /* Black background color */
+ if (screen==0)
+ {
+ tilemap_set_scrollx(tilemap_sub_bg, 0, rocknms_sub_scroll_bg[ 2 ] + 0x000);
+ tilemap_set_scrolly(tilemap_sub_bg, 0, rocknms_sub_scroll_bg[ 5 ] + 0x000);
+ tilemap_set_scrollx(tilemap_sub_fg, 0, rocknms_sub_scroll_fg[ 2 ] + 0x000);
+ tilemap_set_scrolly(tilemap_sub_fg, 0, rocknms_sub_scroll_fg[ 5 ] + 0x000);
+ tilemap_set_scrollx(tilemap_sub_rot, 0, rocknms_sub_rotregs[ 0 ] + 0x400);
+ tilemap_set_scrolly(tilemap_sub_rot, 0, rocknms_sub_rotregs[ 2 ] + 0x400);
+
+ fillbitmap(bitmap, machine->pens[0x0000], cliprect);
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ asc_pri = scr_pri = rot_pri = 0;
+
+ if((rocknms_sub_priority[0x2b00 / 2] & 0x00ff) == 0x0034)
+ asc_pri++;
+ else
+ rot_pri++;
+
+ if((rocknms_sub_priority[0x2e00 / 2] & 0x00ff) == 0x0034)
+ asc_pri++;
+ else
+ scr_pri++;
+
+ if((rocknms_sub_priority[0x3a00 / 2] & 0x00ff) == 0x000c)
+ scr_pri++;
+ else
+ rot_pri++;
+
+ if (rot_pri == 0)
+ tilemap_draw(bitmap,cliprect, tilemap_sub_rot, 0, 1 << 1);
+ else if (scr_pri == 0)
+ tilemap_draw(bitmap,cliprect, tilemap_sub_bg, 0, 1 << 0);
+ else if (asc_pri == 0)
+ tilemap_draw(bitmap,cliprect, tilemap_sub_fg, 0, 1 << 2);
+
+ if (rot_pri == 1)
+ tilemap_draw(bitmap,cliprect, tilemap_sub_rot, 0, 1 << 1);
+ else if (scr_pri == 1)
+ tilemap_draw(bitmap,cliprect, tilemap_sub_bg, 0, 1 << 0);
+ else if (asc_pri == 1)
+ tilemap_draw(bitmap,cliprect, tilemap_sub_fg, 0, 1 << 2);
+
+ if (rot_pri == 2)
+ tilemap_draw(bitmap,cliprect, tilemap_sub_rot, 0, 1 << 1);
+ else if (scr_pri == 2)
+ tilemap_draw(bitmap,cliprect, tilemap_sub_bg, 0, 1 << 0);
+ else if (asc_pri == 2)
+ tilemap_draw(bitmap,cliprect, tilemap_sub_fg, 0, 1 << 2);
+
+ draw_sprites(machine, bitmap,cliprect, spriteram16_2, spriteram_2_size, 4);
+ }
+ else if (screen==1) /* game screen */
+ {
+ tilemap_set_scrollx(tilemap_bg, 0, tetrisp2_scroll_bg[ 2 ] + 0x000);
+ tilemap_set_scrolly(tilemap_bg, 0, tetrisp2_scroll_bg[ 5 ] + 0x000);
+ tilemap_set_scrollx(tilemap_fg, 0, tetrisp2_scroll_fg[ 2 ] + 0x000);
+ tilemap_set_scrolly(tilemap_fg, 0, tetrisp2_scroll_fg[ 5 ] + 0x000);
+ tilemap_set_scrollx(tilemap_rot, 0, tetrisp2_rotregs[ 0 ] + 0x400);
+ tilemap_set_scrolly(tilemap_rot, 0, tetrisp2_rotregs[ 2 ] + 0x400);
+
+ /* Black background color */
+ fillbitmap(bitmap, machine->pens[0x0000], cliprect);
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ asc_pri = scr_pri = rot_pri = 0;
+
+ if((tetrisp2_priority[0x2b00 / 2] & 0x00ff) == 0x0034)
+ asc_pri++;
+ else
+ rot_pri++;
+
+ if((tetrisp2_priority[0x2e00 / 2] & 0x00ff) == 0x0034)
+ asc_pri++;
+ else
+ scr_pri++;
+
+ if((tetrisp2_priority[0x3a00 / 2] & 0x00ff) == 0x000c)
+ scr_pri++;
+ else
+ rot_pri++;
+
+ if (rot_pri == 0)
+ tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
+ else if (scr_pri == 0)
+ tilemap_draw(bitmap,cliprect, tilemap_bg, 0, 1 << 0);
+ else if (asc_pri == 0)
+ tilemap_draw(bitmap,cliprect, tilemap_fg, 0, 1 << 2);
+
+ if (rot_pri == 1)
+ tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
+ else if (scr_pri == 1)
+ tilemap_draw(bitmap,cliprect, tilemap_bg, 0, 1 << 0);
+ else if (asc_pri == 1)
+ tilemap_draw(bitmap,cliprect, tilemap_fg, 0, 1 << 2);
+
+ if (rot_pri == 2)
+ tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
+ else if (scr_pri == 2)
+ tilemap_draw(bitmap,cliprect, tilemap_bg, 0, 1 << 0);
+ else if (asc_pri == 2)
+ tilemap_draw(bitmap,cliprect, tilemap_fg, 0, 1 << 2);
+
+ draw_sprites(machine, bitmap,cliprect, spriteram16, spriteram_size, 0);
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/thedeep.c b/src/mame/video/thedeep.c
new file mode 100644
index 00000000000..f0999f4bd54
--- /dev/null
+++ b/src/mame/video/thedeep.c
@@ -0,0 +1,236 @@
+/***************************************************************************
+
+ -= Run Deep / The Deep =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+ [ 1 Horizontally Scrolling Layer ]
+
+ Size : 512 x 512
+ Tiles: 16 x 16 x 4.
+
+ In addition to a global x & y scroll register each tile-wide column
+ has its own y scroll register.
+
+ [ 1 Fixed Layer ]
+
+ Size : 256 x 256
+ Tiles: 8 x 8 x 2.
+
+ [ 128? sprites ]
+
+ Sprites tiles are 16 x 16 x 4. Each sprite has a height and width
+ specified (1,2,4, or 8 tiles).
+
+ A sprite of width N uses N consecutive sprites: the first one specifies
+ all the data (position,flip), the following ones only the tile code and
+ color for that column (tile codes in each column are consecutive).
+
+***************************************************************************/
+
+#include "driver.h"
+#include "thedeep.h"
+
+/* Variables only used here: */
+
+static tilemap *tilemap_0,*tilemap_1;
+
+/* Variables & functions needed by drivers: */
+
+UINT8 *thedeep_vram_0, *thedeep_vram_1;
+UINT8 *thedeep_scroll, *thedeep_scroll2;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( tilemap_scan_rows_back )
+{
+ return (col & 0x0f) + ((col & 0x10) << 5) + (row << 4);
+}
+
+static TILE_GET_INFO( get_tile_info_0 )
+{
+ UINT8 code = thedeep_vram_0[ tile_index * 2 + 0 ];
+ UINT8 color = thedeep_vram_0[ tile_index * 2 + 1 ];
+ SET_TILE_INFO(
+ 1,
+ code + (color << 8),
+ (color & 0xf0) >> 4,
+ TILE_FLIPX ); // why?
+}
+
+static TILE_GET_INFO( get_tile_info_1 )
+{
+ UINT8 code = thedeep_vram_1[ tile_index * 2 + 0 ];
+ UINT8 color = thedeep_vram_1[ tile_index * 2 + 1 ];
+ SET_TILE_INFO(
+ 2,
+ code + (color << 8),
+ (color & 0xf0) >> 4,
+ 0);
+}
+
+WRITE8_HANDLER( thedeep_vram_0_w )
+{
+ thedeep_vram_0[offset] = data;
+ tilemap_mark_tile_dirty(tilemap_0, offset / 2);
+}
+
+WRITE8_HANDLER( thedeep_vram_1_w )
+{
+ thedeep_vram_1[offset] = data;
+ tilemap_mark_tile_dirty(tilemap_1, offset / 2);
+}
+
+
+/***************************************************************************
+
+ Palette Init
+
+***************************************************************************/
+
+PALETTE_INIT( thedeep )
+{
+ int i;
+ for (i = 0;i < 512;i++)
+ palette_set_color_rgb(machine,i,pal4bit(color_prom[0x400 + i] >> 0),pal4bit(color_prom[0x400 + i] >> 4),pal4bit(color_prom[0x200 + i] >> 0));
+}
+
+/***************************************************************************
+
+ Video Init
+
+***************************************************************************/
+
+VIDEO_START( thedeep )
+{
+ tilemap_0 = tilemap_create(get_tile_info_0,tilemap_scan_rows_back,TILEMAP_TYPE_PEN,16,16,0x20,0x20);
+ tilemap_1 = tilemap_create(get_tile_info_1,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,0x20,0x20);
+
+ tilemap_set_transparent_pen( tilemap_0, 0 );
+ tilemap_set_transparent_pen( tilemap_1, 0 );
+
+ tilemap_set_scroll_cols(tilemap_0, 0x20); // column scroll for the background
+}
+
+/***************************************************************************
+
+ Sprites Drawing
+
+Offset: Bits: Value:
+
+ 0 Y (low bits, 0 is bottom)
+
+ 1 7------- Enable
+ -6------ Flip Y
+ --5----- Flip X ? (unused)
+ ---43--- Height: 1,2,4 or 8 tiles
+ -----21- Width: 1,2,4 or 8 tiles*
+ -------0 Y (High bit)
+
+ 2 Code (low bits)
+
+ 3 Code (high bits)
+
+ 4 X (low bits, 0 is right)
+
+ 5 7654---- Color
+ ----321-
+ -------0 X (High bit)
+
+ 6 Unused
+
+ 7 Unused
+
+* a sprite of width N uses N consecutive sprites. The first one specifies
+ all the data, the following ones only the tile code and color.
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ UINT8 *s = spriteram, *end = s + spriteram_size;
+
+ while (s < end)
+ {
+ int code,color,sx,sy,flipx,flipy,nx,ny,x,y,attr;
+
+ attr = s[1];
+ if (!(attr & 0x80)) { s+=8; continue; }
+
+ sx = s[4];
+ sy = s[0];
+
+ color = s[5];
+
+ flipx = attr & 0x00; // ?
+ flipy = attr & 0x40;
+
+ nx = 1 << ((attr & 0x06) >> 1);
+ ny = 1 << ((attr & 0x18) >> 3);
+
+ if (color & 1) sx -= 256;
+ if (attr & 1) sy -= 256;
+
+ if (flip_screen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+ sy = sy - 8;
+ }
+ else
+ {
+ sx = 240 - sx;
+ sy = 240 - sy - ny * 16 + 16;
+ }
+
+ for (x = 0; (x < nx) && (s < end); x++,s+=8)
+ {
+ code = s[2] + (s[3] << 8);
+ color = s[5] >> 4;
+
+ for (y = 0; y < ny; y++)
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ code + (flipy ? (ny - y - 1) : y),
+ color,
+ flipx,flipy,
+ sx + x * (flipx ? 16 : -16), sy + y * 16,
+ cliprect,TRANSPARENCY_PEN,0 );
+ }
+ }
+ }
+}
+
+
+/***************************************************************************
+
+ Screen Drawing
+
+***************************************************************************/
+
+VIDEO_UPDATE( thedeep )
+{
+ int scrollx = thedeep_scroll[0] + (thedeep_scroll[1]<<8);
+ int scrolly = thedeep_scroll[2] + (thedeep_scroll[3]<<8);
+ int x;
+
+ tilemap_set_scrollx(tilemap_0, 0, scrollx);
+
+ for (x = 0; x < 0x20; x++)
+ {
+ int y = thedeep_scroll2[x*2+0] + (thedeep_scroll2[x*2+1]<<8);
+ tilemap_set_scrolly(tilemap_0, x, y + scrolly);
+ }
+
+ fillbitmap(bitmap,get_black_pen(machine),cliprect);
+
+ tilemap_draw(bitmap,cliprect,tilemap_0,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,tilemap_1,0,0);
+ return 0;
+}
diff --git a/src/mame/video/thepit.c b/src/mame/video/thepit.c
new file mode 100644
index 00000000000..f8272318afc
--- /dev/null
+++ b/src/mame/video/thepit.c
@@ -0,0 +1,312 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *thepit_videoram;
+UINT8 *thepit_colorram;
+UINT8 *thepit_attributesram;
+UINT8 *thepit_spriteram;
+size_t thepit_spriteram_size;
+
+static UINT8 graphics_bank;
+static UINT8 thepit_flip_screen_x;
+static UINT8 thepit_flip_screen_y;
+static tilemap *thepit_solid_tilemap;
+static tilemap *thepit_tilemap;
+static UINT8 *dummy_tile;
+
+
+static rectangle spritevisiblearea =
+{
+ 2*8+1, 32*8-1,
+ 2*8, 30*8-1
+};
+
+static rectangle spritevisibleareaflipx =
+{
+ 0*8, 30*8-2,
+ 2*8, 30*8-1
+};
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+
+***************************************************************************/
+
+PALETTE_INIT( thepit )
+{
+ int i;
+
+ for (i = 0; i < 32; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ }
+
+ /* allocate primary colors for the background and foreground
+ this is wrong, but I don't know where to pick the colors from */
+ for (i = 0; i < 8; i++)
+ palette_set_color_rgb(machine, i + 32, pal1bit(i >> 2), pal1bit(i >> 1), pal1bit(i >> 0));
+}
+
+
+/***************************************************************************
+
+ Super Mouse has 5 bits per gun (maybe 6 for green), exact weights are
+ unknown.
+
+***************************************************************************/
+
+PALETTE_INIT( suprmous )
+{
+ int i;
+
+ for (i = 0; i < 32; i++)
+ {
+ UINT8 r = ((color_prom[i + 0x20] >> 6) | (color_prom[i + 0x00] << 2)) & 0x1f;
+ UINT8 g = BITSWAP8(color_prom[i + 0x20], 7, 6, 0, 1, 2, 3, 4, 5) & 0x1f;
+ UINT8 b = BITSWAP8(color_prom[i + 0x00], 0, 1, 2, 3, 4, 5, 6, 7) & 0x1f;
+
+ palette_set_color_rgb(machine, i + 8, pal5bit(r), pal5bit(g), pal5bit(b));
+ }
+
+ /* allocate primary colors for the background and foreground
+ this is wrong, but I don't know where to pick the colors from */
+ for (i = 0; i < 8; i++)
+ palette_set_color_rgb(machine, i + 32, pal1bit(i >> 2), pal1bit(i >> 1), pal1bit(i >> 0));
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( solid_get_tile_info )
+{
+ UINT8 back_color = (thepit_colorram[tile_index] & 0x70) >> 4;
+ int priority = (back_color != 0) && ((thepit_colorram[tile_index] & 0x80) == 0);
+ tileinfo->pen_data = dummy_tile;
+ tileinfo->palette_base = back_color + 32;
+ tileinfo->category = priority;
+}
+
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 fore_color = thepit_colorram[tile_index] % machine->gfx[0]->total_colors;
+ UINT8 code = thepit_videoram[tile_index];
+ SET_TILE_INFO(2 * graphics_bank, code, fore_color, 0);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( thepit )
+{
+ thepit_solid_tilemap = tilemap_create(solid_get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ thepit_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ tilemap_set_transparent_pen(thepit_tilemap, 0);
+
+ tilemap_set_scroll_cols(thepit_solid_tilemap, 32);
+ tilemap_set_scroll_cols(thepit_tilemap, 32);
+
+ dummy_tile = auto_malloc(8*8);
+ memset(dummy_tile, 0, 8*8);
+
+ graphics_bank = 0; /* only used in intrepid */
+}
+
+
+
+/*************************************
+ *
+ * Memory handlers
+ *
+ *************************************/
+
+WRITE8_HANDLER( thepit_videoram_w )
+{
+ thepit_videoram[offset] = data;
+ tilemap_mark_tile_dirty(thepit_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( thepit_colorram_w )
+{
+ thepit_colorram[offset] = data;
+ tilemap_mark_tile_dirty(thepit_tilemap, offset);
+ tilemap_mark_tile_dirty(thepit_solid_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( thepit_flip_screen_x_w )
+{
+ thepit_flip_screen_x = data & 0x01;
+
+ tilemap_set_flip(thepit_tilemap, thepit_flip_screen_x ? TILEMAP_FLIPX : 0);
+ tilemap_set_flip(thepit_solid_tilemap, thepit_flip_screen_x ? TILEMAP_FLIPX : 0);
+}
+
+
+WRITE8_HANDLER( thepit_flip_screen_y_w )
+{
+ thepit_flip_screen_y = data & 0x01;
+
+ tilemap_set_flip(thepit_tilemap, thepit_flip_screen_y ? TILEMAP_FLIPY : 0);
+ tilemap_set_flip(thepit_solid_tilemap, thepit_flip_screen_y ? TILEMAP_FLIPY : 0);
+}
+
+
+WRITE8_HANDLER( intrepid_graphics_bank_w )
+{
+ if (graphics_bank != (data & 0x01))
+ {
+ graphics_bank = data & 0x01;
+
+ tilemap_mark_all_tiles_dirty(thepit_tilemap);
+ }
+}
+
+
+READ8_HANDLER( thepit_input_port_0_r )
+{
+ /* Read either the real or the fake input ports depending on the
+ horizontal flip switch. (This is how the real PCB does it) */
+ if (thepit_flip_screen_x)
+ {
+ return input_port_3_r(offset);
+ }
+ else
+ {
+ return input_port_0_r(offset);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+static void draw_sprites(running_machine *machine,
+ mame_bitmap *bitmap,
+ const rectangle *cliprect,
+ int priority_to_draw)
+{
+ int offs;
+
+ for (offs = thepit_spriteram_size - 4; offs >= 0; offs -= 4)
+ {
+ if (((thepit_spriteram[offs + 2] & 0x08) >> 3) == priority_to_draw)
+ {
+ UINT8 y, x, flipx, flipy;
+
+ if ((thepit_spriteram[offs + 0] == 0) || (thepit_spriteram[offs + 3] == 0))
+ {
+ continue;
+ }
+
+ y = 240 - thepit_spriteram[offs];
+ x = thepit_spriteram[offs + 3] + 1;
+
+ flipx = thepit_spriteram[offs + 1] & 0x40;
+ flipy = thepit_spriteram[offs + 1] & 0x80;
+
+ if (thepit_flip_screen_y)
+ {
+ y = 240 - y;
+ flipy = !flipy;
+ }
+
+ if (thepit_flip_screen_x)
+ {
+ x = 242 - x;
+ flipx = !flipx;
+ }
+
+ /* sprites 0-3 are drawn one pixel down */
+ if (offs < 16) y++;
+
+ drawgfx(bitmap, machine->gfx[2 * graphics_bank + 1],
+ thepit_spriteram[offs + 1] & 0x3f,
+ thepit_spriteram[offs + 2],
+ flipx, flipy, x, y,
+ thepit_flip_screen_x ? &spritevisibleareaflipx : &spritevisiblearea,
+ TRANSPARENCY_PEN, 0);
+ }
+ }
+}
+
+
+VIDEO_UPDATE( thepit )
+{
+ offs_t offs;
+
+ for (offs = 0; offs < 32; offs++)
+ {
+ tilemap_set_scrolly(thepit_tilemap, offs, thepit_attributesram[offs << 1]);
+ tilemap_set_scrolly(thepit_solid_tilemap, offs, thepit_attributesram[offs << 1]);
+ }
+
+ /* low priority tiles */
+ tilemap_draw(bitmap, cliprect, thepit_solid_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, thepit_tilemap, 0, 0);
+
+ /* low priority sprites */
+ draw_sprites(machine, bitmap, cliprect, 0);
+
+ /* high priority tiles */
+ tilemap_draw(bitmap, cliprect, thepit_solid_tilemap, 1, 1);
+
+ /* high priority sprites */
+ draw_sprites(machine, bitmap, cliprect, 1);
+
+ return 0;
+}
diff --git a/src/mame/video/thief.c b/src/mame/video/thief.c
new file mode 100644
index 00000000000..248204f13bf
--- /dev/null
+++ b/src/mame/video/thief.c
@@ -0,0 +1,314 @@
+/* video hardware for Pacific Novelty games:
+** Thief/Nato Defense
+*/
+
+#include "driver.h"
+
+static mame_bitmap *thief_page0;
+static mame_bitmap *thief_page1;
+
+static UINT8 thief_read_mask, thief_write_mask;
+static UINT8 thief_video_control;
+
+static struct {
+ UINT8 *context_ram;
+ UINT8 bank;
+ UINT8 *image_ram;
+ UINT8 param[0x9];
+} thief_coprocessor;
+
+enum {
+ IMAGE_ADDR_LO, //0xe000
+ IMAGE_ADDR_HI, //0xe001
+ SCREEN_XPOS, //0xe002
+ SCREEN_YPOS, //0xe003
+ BLIT_WIDTH, //0xe004
+ BLIT_HEIGHT, //0xe005
+ GFX_PORT, //0xe006
+ BARL_PORT, //0xe007
+ BLIT_ATTRIBUTES //0xe008
+};
+
+/***************************************************************************/
+
+READ8_HANDLER( thief_context_ram_r ){
+ return thief_coprocessor.context_ram[0x40*thief_coprocessor.bank+offset];
+}
+
+WRITE8_HANDLER( thief_context_ram_w ){
+ thief_coprocessor.context_ram[0x40*thief_coprocessor.bank+offset] = data;
+}
+
+WRITE8_HANDLER( thief_context_bank_w ){
+ thief_coprocessor.bank = data&0xf;
+}
+
+/***************************************************************************/
+
+WRITE8_HANDLER( thief_video_control_w ){
+ if( (data^thief_video_control)&1 ){
+ /* screen flipped */
+ memset( dirtybuffer, 0x00, 0x2000*2 );
+ }
+
+ thief_video_control = data;
+/*
+ bit 0: screen flip
+ bit 1: working page
+ bit 2: visible page
+ bit 3: mirrors bit 1
+ bit 4: mirrors bit 2
+*/
+}
+
+WRITE8_HANDLER( thief_vtcsel_w ){
+ /* TMS9927 VTAC registers */
+}
+
+WRITE8_HANDLER( thief_color_map_w ){
+/*
+ --xx---- blue
+ ----xx-- green
+ ------xx red
+*/
+ static const UINT8 intensity[4] = {0x00,0x55,0xAA,0xFF};
+ int r = intensity[(data & 0x03) >> 0];
+ int g = intensity[(data & 0x0C) >> 2];
+ int b = intensity[(data & 0x30) >> 4];
+ palette_set_color( Machine,offset,MAKE_RGB(r,g,b) );
+}
+
+/***************************************************************************/
+
+WRITE8_HANDLER( thief_color_plane_w ){
+/*
+ --xx---- selects bitplane to read from (0..3)
+ ----xxxx selects bitplane(s) to write to (0x0 = none, 0xf = all)
+*/
+ thief_write_mask = data&0xf;
+ thief_read_mask = (data>>4)&3;
+}
+
+READ8_HANDLER( thief_videoram_r ){
+ UINT8 *source = &videoram[offset];
+ if( thief_video_control&0x02 ) source+=0x2000*4; /* foreground/background */
+ return source[thief_read_mask*0x2000];
+}
+
+WRITE8_HANDLER( thief_videoram_w ){
+ UINT8 *dest = &videoram[offset];
+ if( thief_video_control&0x02 ){
+ dest+=0x2000*4; /* foreground/background */
+ dirtybuffer[offset+0x2000] = 1;
+ }
+ else {
+ dirtybuffer[offset] = 1;
+ }
+ if( thief_write_mask&0x1 ) dest[0x2000*0] = data;
+ if( thief_write_mask&0x2 ) dest[0x2000*1] = data;
+ if( thief_write_mask&0x4 ) dest[0x2000*2] = data;
+ if( thief_write_mask&0x8 ) dest[0x2000*3] = data;
+}
+
+/***************************************************************************/
+
+VIDEO_START( thief ){
+ memset( &thief_coprocessor, 0x00, sizeof(thief_coprocessor) );
+
+ thief_page0 = auto_bitmap_alloc( 256,256,machine->screen[0].format );
+ thief_page1 = auto_bitmap_alloc( 256,256,machine->screen[0].format );
+
+ videoram = auto_malloc( 0x2000*4*2 );
+ memset( videoram, 0, 0x2000*4*2 );
+
+ dirtybuffer = auto_malloc( 0x2000*2 );
+ memset( dirtybuffer, 1, 0x2000*2 );
+
+ thief_coprocessor.image_ram = auto_malloc( 0x2000 );
+ thief_coprocessor.context_ram = auto_malloc( 0x400 );
+}
+
+VIDEO_UPDATE( thief ){
+ UINT32 offs;
+ int flipscreen = thief_video_control&1;
+ const pen_t *pal_data = machine->pens;
+ UINT8 *dirty = dirtybuffer;
+ const UINT8 *source = videoram;
+ mame_bitmap *page;
+
+ if( thief_video_control&4 ){ /* visible page */
+ dirty += 0x2000;
+ source += 0x2000*4;
+ page = thief_page1;
+ }
+ else {
+ page = thief_page0;
+ }
+
+ for( offs=0; offs<0x2000; offs++ ){
+ if( dirty[offs] ){
+ int ypos = offs/32;
+ int xpos = (offs%32)*8;
+ int plane0 = source[0x2000*0+offs];
+ int plane1 = source[0x2000*1+offs];
+ int plane2 = source[0x2000*2+offs];
+ int plane3 = source[0x2000*3+offs];
+ int bit;
+ if( flipscreen ){
+ for( bit=0; bit<8; bit++ ){
+ *BITMAP_ADDR16(page, 0xff - ypos, 0xff - (xpos+bit)) =
+ pal_data[
+ (((plane0<<bit)&0x80)>>7) |
+ (((plane1<<bit)&0x80)>>6) |
+ (((plane2<<bit)&0x80)>>5) |
+ (((plane3<<bit)&0x80)>>4)];
+ }
+ }
+ else {
+ for( bit=0; bit<8; bit++ ){
+ *BITMAP_ADDR16(page, ypos, xpos+bit) =
+ pal_data[
+ (((plane0<<bit)&0x80)>>7) |
+ (((plane1<<bit)&0x80)>>6) |
+ (((plane2<<bit)&0x80)>>5) |
+ (((plane3<<bit)&0x80)>>4)];
+ }
+ }
+ dirty[offs] = 0;
+ }
+ }
+ copybitmap(bitmap,page,0,0,0,0,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ return 0;
+}
+
+/***************************************************************************/
+
+static UINT16 fetch_image_addr( void ){
+ int addr = thief_coprocessor.param[IMAGE_ADDR_LO]+256*thief_coprocessor.param[IMAGE_ADDR_HI];
+ /* auto-increment */
+ thief_coprocessor.param[IMAGE_ADDR_LO]++;
+ if( thief_coprocessor.param[IMAGE_ADDR_LO]==0x00 ){
+ thief_coprocessor.param[IMAGE_ADDR_HI]++;
+ }
+ return addr;
+}
+
+WRITE8_HANDLER( thief_blit_w ){
+ int i, offs, xoffset, dy;
+ UINT8 *gfx_rom = memory_region( REGION_GFX1 );
+ UINT8 x = thief_coprocessor.param[SCREEN_XPOS];
+ UINT8 y = thief_coprocessor.param[SCREEN_YPOS];
+ UINT8 width = thief_coprocessor.param[BLIT_WIDTH];
+ UINT8 height = thief_coprocessor.param[BLIT_HEIGHT];
+ UINT8 attributes = thief_coprocessor.param[BLIT_ATTRIBUTES];
+
+ UINT8 old_data;
+ int xor_blit = data;
+ /* making the xor behavior selectable fixes score display,
+ but causes minor glitches on the playfield */
+
+ x -= width*8;
+ xoffset = x&7;
+
+ if( attributes&0x10 ){
+ y += 7-height;
+ dy = 1;
+ }
+ else {
+ dy = -1;
+ }
+ height++;
+ while( height-- ){
+ for( i=0; i<=width; i++ ){
+ int addr = fetch_image_addr();
+ if( addr<0x2000 ){
+ data = thief_coprocessor.image_ram[addr];
+ }
+ else {
+ addr -= 0x2000;
+ if( addr<0x2000*3 ) data = gfx_rom[addr];
+ }
+ offs = (y*32+x/8+i)&0x1fff;
+ old_data = thief_videoram_r( offs );
+ if( xor_blit ){
+ thief_videoram_w( offs, old_data^(data>>xoffset) );
+ }
+ else {
+ thief_videoram_w( offs,
+ (old_data&(0xff00>>xoffset)) | (data>>xoffset)
+ );
+ }
+ offs = (offs+1)&0x1fff;
+ old_data = thief_videoram_r( offs );
+ if( xor_blit ){
+ thief_videoram_w( offs, old_data^((data<<(8-xoffset))&0xff) );
+ }
+ else {
+ thief_videoram_w( offs,
+ (old_data&(0xff>>xoffset)) | ((data<<(8-xoffset))&0xff)
+ );
+ }
+ }
+ y+=dy;
+ }
+}
+
+READ8_HANDLER( thief_coprocessor_r ){
+ switch( offset ){
+ case SCREEN_XPOS: /* xpos */
+ case SCREEN_YPOS: /* ypos */
+ {
+ /* XLAT: given (x,y) coordinate, return byte address in videoram */
+ int addr = thief_coprocessor.param[SCREEN_XPOS]+256*thief_coprocessor.param[SCREEN_YPOS];
+ int result = 0xc000 | (addr>>3);
+ return (offset==0x03)?(result>>8):(result&0xff);
+ }
+ break;
+
+ case GFX_PORT:
+ {
+ int addr = fetch_image_addr();
+ if( addr<0x2000 ){
+ return thief_coprocessor.image_ram[addr];
+ }
+ else {
+ UINT8 *gfx_rom = memory_region( REGION_GFX1 );
+ addr -= 0x2000;
+ if( addr<0x6000 ) return gfx_rom[addr];
+ }
+ }
+ break;
+
+ case BARL_PORT:
+ {
+ /* return bitmask for addressed pixel */
+ int dx = thief_coprocessor.param[SCREEN_XPOS]&0x7;
+ if( thief_coprocessor.param[BLIT_ATTRIBUTES]&0x01 ){
+ return 0x01<<dx; // flipx
+ }
+ else {
+ return 0x80>>dx; // no flip
+ }
+ }
+ break;
+ }
+
+ return thief_coprocessor.param[offset];
+}
+
+WRITE8_HANDLER( thief_coprocessor_w ){
+ switch( offset ){
+ case GFX_PORT:
+ {
+ int addr = fetch_image_addr();
+ if( addr<0x2000 ){
+ thief_coprocessor.image_ram[addr] = data;
+ }
+ }
+ break;
+
+ default:
+ thief_coprocessor.param[offset] = data;
+ break;
+ }
+}
diff --git a/src/mame/video/thoop2.c b/src/mame/video/thoop2.c
new file mode 100644
index 00000000000..379a07d38f8
--- /dev/null
+++ b/src/mame/video/thoop2.c
@@ -0,0 +1,242 @@
+/***************************************************************************
+
+ Gaelco Type 1 Video Hardware Rev B
+
+ The video hardware it's nearly identical to the previous
+ revision but it can handle more tiles and more sprites
+
+ Functions to emulate the video hardware of the machine
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *thoop2_vregs;
+UINT16 *thoop2_videoram;
+UINT16 *thoop2_spriteram;
+
+static int sprite_count[5];
+static int *sprite_table[5];
+static tilemap *pant[2];
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/*
+ Tile format
+ -----------
+
+ Screen 0 & 1: (32*32, 16x16 tiles)
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- ------xx | code (high bits)
+ 0 | xxxxxxxx xxxxxx-- | code (low bits)
+ 1 | -------- --xxxxxx | color
+ 1 | -------- xx------ | priority
+ 1 | --xxxxxx -------- | not used
+ 1 | -x------ -------- | flip x
+ 1 | x------- -------- | flip y
+*/
+
+static TILE_GET_INFO( get_tile_info_thoop2_screen0 )
+{
+ int data = thoop2_videoram[tile_index << 1];
+ int data2 = thoop2_videoram[(tile_index << 1) + 1];
+ int code = ((data & 0xfffc) >> 2) | ((data & 0x0003) << 14);
+
+ tileinfo->category = (data2 >> 6) & 0x03;
+
+ SET_TILE_INFO(1, code, data2 & 0x3f, TILE_FLIPYX((data2 >> 14) & 0x03));
+}
+
+
+static TILE_GET_INFO( get_tile_info_thoop2_screen1 )
+{
+ int data = thoop2_videoram[(0x1000/2) + (tile_index << 1)];
+ int data2 = thoop2_videoram[(0x1000/2) + (tile_index << 1) + 1];
+ int code = ((data & 0xfffc) >> 2) | ((data & 0x0003) << 14);
+
+ tileinfo->category = (data2 >> 6) & 0x03;
+
+ SET_TILE_INFO(1, code, data2 & 0x3f, TILE_FLIPYX((data2 >> 14) & 0x03));
+}
+
+/***************************************************************************
+
+ Memory Handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( thoop2_vram_w )
+{
+ COMBINE_DATA(&thoop2_videoram[offset]);
+ tilemap_mark_tile_dirty(pant[offset >> 11],((offset << 1) & 0x0fff) >> 2);
+}
+
+/***************************************************************************
+
+ Start/Stop the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( thoop2 )
+{
+ int i;
+
+ pant[0] = tilemap_create(get_tile_info_thoop2_screen0,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ pant[1] = tilemap_create(get_tile_info_thoop2_screen1,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ tilemap_set_transmask(pant[0],0,0xff01,0x00ff); /* pens 1-7 opaque, pens 0, 8-15 transparent */
+ tilemap_set_transmask(pant[1],0,0xff01,0x00ff); /* pens 1-7 opaque, pens 0, 8-15 transparent */
+
+ for (i = 0; i < 5; i++){
+ sprite_table[i] = auto_malloc(512*sizeof(int));
+ }
+}
+
+/***************************************************************************
+
+ Sprites
+
+***************************************************************************/
+
+static void thoop2_sort_sprites(void)
+{
+ int i;
+
+ sprite_count[0] = 0;
+ sprite_count[1] = 0;
+ sprite_count[2] = 0;
+ sprite_count[3] = 0;
+ sprite_count[4] = 0;
+
+ for (i = 3; i < (0x1000 - 6)/2; i += 4){
+ int color = (thoop2_spriteram[i+2] & 0x7e00) >> 9;
+ int priority = (thoop2_spriteram[i] & 0x3000) >> 12;
+
+ /* palettes 0x38-0x3f are used for high priority sprites in Big Karnak */
+ if (color >= 0x38){
+ sprite_table[4][sprite_count[4]] = i;
+ sprite_count[4]++;
+ }
+
+ /* save sprite number in the proper array for later */
+ sprite_table[priority][sprite_count[priority]] = i;
+ sprite_count[priority]++;
+ }
+}
+
+/*
+ Sprite Format
+ -------------
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- xxxxxxxx | y position
+ 0 | -----xxx -------- | not used
+ 0 | ----x--- -------- | sprite size
+ 0 | --xx---- -------- | sprite priority
+ 0 | -x------ -------- | flipx
+ 0 | x------- -------- | flipy
+ 1 | xxxxxxxx xxxxxxxx | not used
+ 2 | -------x xxxxxxxx | x position
+ 2 | -xxxxxx- -------- | sprite color
+ 3 | -------- ------xx | sprite code (high bits)
+ 3 | xxxxxxxx xxxxxx-- | sprite code (low bits)
+*/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri)
+{
+ int j, x, y, ex, ey;
+ const gfx_element *gfx = machine->gfx[0];
+
+ static int x_offset[2] = {0x0,0x2};
+ static int y_offset[2] = {0x0,0x1};
+
+ for (j = 0; j < sprite_count[pri]; j++){
+ int i = sprite_table[pri][j];
+ int sx = thoop2_spriteram[i+2] & 0x01ff;
+ int sy = (240 - (thoop2_spriteram[i] & 0x00ff)) & 0x00ff;
+ int number = thoop2_spriteram[i+3];
+ int color = (thoop2_spriteram[i+2] & 0x7e00) >> 9;
+ int attr = (thoop2_spriteram[i] & 0xfe00) >> 9;
+
+ int xflip = attr & 0x20;
+ int yflip = attr & 0x40;
+ int spr_size;
+
+ number |= ((number & 0x03) << 16);
+
+ if (attr & 0x04){
+ spr_size = 1;
+ }
+ else{
+ spr_size = 2;
+ number &= (~3);
+ }
+
+ for (y = 0; y < spr_size; y++){
+ for (x = 0; x < spr_size; x++){
+
+ ex = xflip ? (spr_size-1-x) : x;
+ ey = yflip ? (spr_size-1-y) : y;
+
+ drawgfx(bitmap,gfx,number + x_offset[ex] + y_offset[ey],
+ color,xflip,yflip,
+ sx-0x0f+x*8,sy+y*8,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+}
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( thoop2 )
+{
+ /* set scroll registers */
+ tilemap_set_scrolly(pant[0], 0, thoop2_vregs[0]);
+ tilemap_set_scrollx(pant[0], 0, thoop2_vregs[1]+4);
+ tilemap_set_scrolly(pant[1], 0, thoop2_vregs[2]);
+ tilemap_set_scrollx(pant[1], 0, thoop2_vregs[3]);
+
+ thoop2_sort_sprites();
+
+ fillbitmap( bitmap, machine->pens[0], cliprect );
+
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER1 | 3,0);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER1 | 3,0);
+ draw_sprites(machine, bitmap,cliprect,3);
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER0 | 3,0);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER0 | 3,0);
+
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER1 | 2,0);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER1 | 2,0);
+ draw_sprites(machine, bitmap,cliprect,2);
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER0 | 2,0);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER0 | 2,0);
+
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER1 | 1,0);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER1 | 1,0);
+ draw_sprites(machine, bitmap,cliprect,1);
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER0 | 1,0);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER0 | 1,0);
+
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER1 | 0,0);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER1 | 0,0);
+ draw_sprites(machine, bitmap,cliprect,0);
+ tilemap_draw(bitmap,cliprect,pant[1],TILEMAP_DRAW_LAYER0 | 0,0);
+ tilemap_draw(bitmap,cliprect,pant[0],TILEMAP_DRAW_LAYER0 | 0,0);
+
+ draw_sprites(machine, bitmap,cliprect,4);
+ return 0;
+}
diff --git a/src/mame/video/thunderj.c b/src/mame/video/thunderj.c
new file mode 100644
index 00000000000..baf3d46875c
--- /dev/null
+++ b/src/mame/video/thunderj.c
@@ -0,0 +1,296 @@
+/***************************************************************************
+
+ Atari ThunderJaws hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "includes/thunderj.h"
+
+
+
+/*************************************
+ *
+ * Globals
+ *
+ *************************************/
+
+UINT8 thunderj_alpha_tile_bank;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha[tile_index];
+ int code = ((data & 0x200) ? (thunderj_alpha_tile_bank * 0x200) : 0) + (data & 0x1ff);
+ int color = ((data >> 10) & 0x0f) | ((data >> 9) & 0x20);
+ int opaque = data & 0x8000;
+ SET_TILE_INFO(2, code, color, opaque ? TILE_FORCE_LAYER0 : 0);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data1 = atarigen_playfield[tile_index];
+ UINT16 data2 = atarigen_playfield_upper[tile_index] & 0xff;
+ int code = data1 & 0x7fff;
+ int color = 0x10 + (data2 & 0x0f);
+ SET_TILE_INFO(0, code, color, (data1 >> 15) & 1);
+ tileinfo->category = (data2 >> 4) & 3;
+}
+
+
+static TILE_GET_INFO( get_playfield2_tile_info )
+{
+ UINT16 data1 = atarigen_playfield2[tile_index];
+ UINT16 data2 = atarigen_playfield_upper[tile_index] >> 8;
+ int code = data1 & 0x7fff;
+ int color = data2 & 0x0f;
+ SET_TILE_INFO(0, code, color, (data1 >> 15) & 1);
+ tileinfo->category = (data2 >> 4) & 3;
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( thunderj )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 1, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 1, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 8, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x100, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0x03ff,0,0,0 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0,0x7fff,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0x000f,0 }}, /* mask for the color */
+ {{ 0,0,0xff80,0 }}, /* mask for the X position */
+ {{ 0,0,0,0xff80 }}, /* mask for the Y position */
+ {{ 0,0,0,0x0070 }}, /* mask for the width, in tiles*/
+ {{ 0,0,0,0x0007 }}, /* mask for the height, in tiles */
+ {{ 0,0x8000,0,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0,0,0x0070,0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ NULL /* callback routine for special entries */
+ };
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8,8, 64,64);
+
+ /* initialize the second playfield */
+ atarigen_playfield2_tilemap = tilemap_create(get_playfield2_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8,8, 64,64);
+ tilemap_set_transparent_pen(atarigen_playfield2_tilemap, 0);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ tilemap_set_transparent_pen(atarigen_alpha_tilemap, 0);
+}
+
+
+
+/*************************************
+ *
+ * Mark high palette bits starting
+ * at the given X,Y and continuing
+ * until a stop or the end of line
+ *
+ *************************************/
+
+void thunderj_mark_high_palette(mame_bitmap *bitmap, UINT16 *pf, UINT16 *mo, int x, int y)
+{
+ #define START_MARKER ((4 << ATARIMO_PRIORITY_SHIFT) | 2)
+ #define END_MARKER ((4 << ATARIMO_PRIORITY_SHIFT) | 4)
+ int offnext = 0;
+
+ for ( ; x < bitmap->width; x++)
+ {
+ pf[x] |= 0x400;
+ if (offnext && (mo[x] & START_MARKER) != START_MARKER)
+ break;
+ offnext = ((mo[x] & END_MARKER) == END_MARKER);
+ }
+ }
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( thunderj )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ fillbitmap(priority_bitmap, 0, cliprect);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0x00);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 1, 0x01);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 2, 0x02);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 3, 0x03);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield2_tilemap, 0, 0x80);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield2_tilemap, 1, 0x84);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield2_tilemap, 2, 0x88);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield2_tilemap, 3, 0x8c);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ UINT8 *pri = (UINT8 *)priority_bitmap->base + priority_bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* verified from the GALs on the real PCB; equations follow
+ *
+ * --- PF/M is 1 if playfield has priority, or 0 if MOs have priority
+ * PF/M=MPX0*!MPX1*!MPX2*!MPX3*!MPX4*!MPX5*!MPX6*!MPX7
+ * +PFX3*PFX8*PFX9*!MPR0
+ * +PFX3*PFX8*!MPR0*!MPR1
+ * +PFX3*PFX9*!MPR1
+ *
+ * --- CS1 is 1 if the playfield should be displayed
+ * CS1=PF/M*!ALBG*!APIX0*!APIX1
+ * +!MPX0*!MPX1*!MPX2*!MPX3*!ALBG*!APIX0*!APIX1
+ *
+ * --- CS0 is 1 if the MOs should be displayed
+ * CS0=!PF/M*MPX0*!ALBG*!APIX0*!APIX1
+ * +!PF/M*MPX1*!ALBG*!APIX0*!APIX1
+ * +!PF/M*MPX2*!ALBG*!APIX0*!APIX1
+ * +!PF/M*MPX3*!ALBG*!APIX0*!APIX1
+ *
+ * --- CRA10 is the 0x200 bit of the color RAM index; set if pf is displayed
+ * CRA10:=CS1
+ *
+ * --- CRA9 is the 0x100 bit of the color RAM index; set if mo is displayed
+ * or if the playfield selected is playfield #2
+ * CRA9:=PFXS*CS1
+ * +!CS1*CS0
+ *
+ * --- CRA8-1 are the low 8 bits of the color RAM index; set as expected
+ * CRA8:=CS1*PFX7
+ * +!CS1*MPX7*CS0
+ * +!CS1*!CS0*ALC4
+ *
+ * CRA7:=CS1*PFX6
+ * +!CS1*MPX6*CS0
+ *
+ * CRA6:=CS1*PFX5
+ * +MPX5*!CS1*CS0
+ * +!CS1*!CS0*ALC3
+ *
+ * CRA5:=CS1*PFX4
+ * +MPX4*!CS1*CS0
+ * +!CS1*ALC2*!CS0
+ *
+ * CRA4:=CS1*PFX3
+ * +!CS1*MPX3*CS0
+ * +!CS1*!CS0*ALC1
+ *
+ * CRA3:=CS1*PFX2
+ * +MPX2*!CS1*CS0
+ * +!CS1*!CS0*ALC0
+ *
+ * CRA2:=CS1*PFX1
+ * +MPX1*!CS1*CS0
+ * +!CS1*!CS0*APIX1
+ *
+ * CRA1:=CS1*PFX0
+ * +MPX0*!CS1*CS0
+ * +!CS1*!CS0*APIX0
+ */
+ int mopriority = mo[x] >> ATARIMO_PRIORITY_SHIFT;
+ int pfm = 0;
+
+ /* upper bit of MO priority signals special rendering and doesn't draw anything */
+ if (mopriority & 4)
+ continue;
+
+ /* determine pf/m signal */
+ if ((mo[x] & 0xff) == 1)
+ pfm = 1;
+ else if (pf[x] & 8)
+ {
+ int pfpriority = (pri[x] & 0x80) ? ((pri[x] >> 2) & 3) : (pri[x] & 3);
+ if (((pfpriority == 3) && !(mopriority & 1)) ||
+ ((pfpriority & 1) && (mopriority == 0)) ||
+ ((pfpriority & 2) && !(mopriority & 2)))
+ pfm = 1;
+ }
+
+ /* if pfm is low, we display the mo */
+ if (!pfm)
+ pf[x] = mo[x] & ATARIMO_DATA_MASK;
+
+ /* don't erase yet -- we need to make another pass later */
+ }
+ }
+
+ /* add the alpha on top */
+ tilemap_draw(bitmap, cliprect, atarigen_alpha_tilemap, 0, 0);
+
+ /* now go back and process the upper bit of MO priority */
+ rectlist.rect -= rectlist.numrects;
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ int mopriority = mo[x] >> ATARIMO_PRIORITY_SHIFT;
+
+ /* upper bit of MO priority might mean palette kludges */
+ if (mopriority & 4)
+ {
+ /* if bit 2 is set, start setting high palette bits */
+ if (mo[x] & 2)
+ thunderj_mark_high_palette(bitmap, pf, mo, x, y);
+ }
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/thunderx.c b/src/mame/video/thunderx.c
new file mode 100644
index 00000000000..b8697146c43
--- /dev/null
+++ b/src/mame/video/thunderx.c
@@ -0,0 +1,91 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+int scontra_priority;
+static int layer_colorbase[3],sprite_colorbase;
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ *code |= ((*color & 0x1f) << 8) | (bank << 13);
+ *color = layer_colorbase[layer] + ((*color & 0xe0) >> 5);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051960
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority_mask,int *shadow)
+{
+ /* Sprite priority 1 means appear behind background, used only to mask sprites */
+ /* in the foreground */
+ /* Sprite priority 3 means don't draw (not used) */
+ switch (*color & 0x30)
+ {
+ case 0x00: *priority_mask = 0xf0; break;
+ case 0x10: *priority_mask = 0xf0|0xcc|0xaa; break;
+ case 0x20: *priority_mask = 0xf0|0xcc; break;
+ case 0x30: *priority_mask = 0xffff; break;
+ }
+
+ *color = sprite_colorbase + (*color & 0x0f);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( scontra )
+{
+ layer_colorbase[0] = 48;
+ layer_colorbase[1] = 0;
+ layer_colorbase[2] = 16;
+ sprite_colorbase = 32;
+
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,NORMAL_PLANE_ORDER,sprite_callback);
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( scontra )
+{
+ K052109_tilemap_update();
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ /* The background color is always from layer 1 - but it's always black anyway */
+// fillbitmap(bitmap,machine->pens[16 * layer_colorbase[1]],cliprect);
+ if (scontra_priority)
+ {
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],TILEMAP_DRAW_OPAQUE,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],0,2);
+ }
+ else
+ {
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],TILEMAP_DRAW_OPAQUE,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],0,2);
+ }
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],0,4);
+
+ K051960_sprites_draw(bitmap,cliprect,-1,-1);
+ return 0;
+}
diff --git a/src/mame/video/tia.c b/src/mame/video/tia.c
new file mode 100644
index 00000000000..e48f4aea805
--- /dev/null
+++ b/src/mame/video/tia.c
@@ -0,0 +1,2004 @@
+/***************************************************************************
+
+ Atari TIA video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "tia.h"
+#include "sound/tiaintf.h"
+#include <math.h>
+
+#define HMOVE_INACTIVE -200
+#define PLAYER_GFX_SLOTS 4
+
+// Per player graphic
+// - pixel number to start drawing from (0-7, from GRPx) / number of pixels drawn from GRPx
+// - display position to start drawing
+// - size to use
+struct player_gfx {
+ int start_pixel[PLAYER_GFX_SLOTS];
+ int start_drawing[PLAYER_GFX_SLOTS];
+ int size[PLAYER_GFX_SLOTS];
+ int skipclip[PLAYER_GFX_SLOTS];
+};
+
+static struct player_gfx p0gfx;
+static struct player_gfx p1gfx;
+
+static UINT32 frame_cycles;
+static UINT32 paddle_cycles;
+
+static int horzP0;
+static int horzP1;
+static int horzM0;
+static int horzM1;
+static int horzBL;
+static int motclkP0;
+static int motclkP1;
+static int motclkM0;
+static int motclkM1;
+static int motclkBL;
+static int startP0;
+static int startP1;
+static int startM0;
+static int startM1;
+static int skipclipP0;
+static int skipclipP1;
+static int skipM0delay;
+static int skipM1delay;
+
+static int current_bitmap;
+
+static int prev_x;
+static int prev_y;
+
+static UINT8 VSYNC;
+static UINT8 VBLANK;
+static UINT8 COLUP0;
+static UINT8 COLUP1;
+static UINT8 COLUBK;
+static UINT8 COLUPF;
+static UINT8 CTRLPF;
+static UINT8 GRP0;
+static UINT8 GRP1;
+static UINT8 REFP0;
+static UINT8 REFP1;
+static UINT8 HMP0;
+static UINT8 HMP1;
+static UINT8 HMM0;
+static UINT8 HMM1;
+static UINT8 HMBL;
+static UINT8 VDELP0;
+static UINT8 VDELP1;
+static UINT8 VDELBL;
+static UINT8 NUSIZ0;
+static UINT8 NUSIZ1;
+static UINT8 ENAM0;
+static UINT8 ENAM1;
+static UINT8 ENABL;
+static UINT8 CXM0P;
+static UINT8 CXM1P;
+static UINT8 CXP0FB;
+static UINT8 CXP1FB;
+static UINT8 CXM0FB;
+static UINT8 CXM1FB;
+static UINT8 CXBLPF;
+static UINT8 CXPPMM;
+static UINT8 RESMP0;
+static UINT8 RESMP1;
+static UINT8 PF0;
+static UINT8 PF1;
+static UINT8 PF2;
+static UINT8 INPT4;
+static UINT8 INPT5;
+
+static UINT8 prevGRP0;
+static UINT8 prevGRP1;
+static UINT8 prevENABL;
+
+static int HMOVE_started;
+static int HMOVE_started_previous;
+static UINT8 HMP0_latch;
+static UINT8 HMP1_latch;
+static UINT8 HMM0_latch;
+static UINT8 HMM1_latch;
+static UINT8 HMBL_latch;
+static UINT8 REFLECT; /* Should playfield be reflected or not */
+static UINT8 NUSIZx_changed;
+
+static mame_bitmap *helper[3];
+
+static UINT16 screen_height;
+
+static const int nusiz[8][3] =
+{
+ { 1, 1, 0 },
+ { 2, 1, 1 },
+ { 2, 1, 3 },
+ { 3, 1, 1 },
+ { 2, 1, 7 },
+ { 1, 2, 0 },
+ { 3, 1, 3 },
+ { 1, 4, 0 }
+};
+
+static read16_handler tia_read_input_port;
+static read8_handler tia_get_databus;
+static write16_handler tia_vsync_callback;
+
+static void extend_palette(running_machine *machine) {
+ int i,j;
+
+ for( i = 0; i < 128; i ++ )
+ {
+ rgb_t new_rgb = palette_get_color( machine, i );
+ UINT8 new_r = RGB_RED( new_rgb );
+ UINT8 new_g = RGB_GREEN( new_rgb );
+ UINT8 new_b = RGB_BLUE( new_rgb );
+
+ for ( j = 0; j < 128; j++ )
+ {
+ rgb_t old_rgb = palette_get_color( machine, j );
+ UINT8 old_r = RGB_RED( old_rgb );
+ UINT8 old_g = RGB_GREEN( old_rgb );
+ UINT8 old_b = RGB_BLUE( old_rgb );
+
+ palette_set_color_rgb(machine, ( ( i + 1 ) << 7 ) | j,
+ ( new_r + old_r ) / 2,
+ ( new_g + old_g ) / 2,
+ ( new_b + old_b ) / 2 );
+ }
+ }
+}
+
+PALETTE_INIT( tia_NTSC )
+{
+ int i, j;
+
+ static const double color[16][2] =
+ {
+ { 0.000, 0.000 },
+ { 0.144, -0.189 },
+ { 0.231, -0.081 },
+ { 0.243, 0.032 },
+ { 0.217, 0.121 },
+ { 0.117, 0.216 },
+ { 0.021, 0.233 },
+ { -0.066, 0.196 },
+ { -0.139, 0.134 },
+ { -0.182, 0.062 },
+ { -0.175, -0.022 },
+ { -0.136, -0.100 },
+ { -0.069, -0.150 },
+ { 0.005, -0.159 },
+ { 0.071, -0.125 },
+ { 0.124, -0.089 }
+ };
+
+ for (i = 0; i < 16; i++)
+ {
+ double I = color[i][0];
+ double Q = color[i][1];
+
+ for (j = 0; j < 8; j++)
+ {
+ double Y = j / 7.0;
+
+ double R = Y + 0.956 * I + 0.621 * Q;
+ double G = Y - 0.272 * I - 0.647 * Q;
+ double B = Y - 1.106 * I + 1.703 * Q;
+
+ R = pow(R, 0.9) / pow(1, 0.9);
+ G = pow(G, 0.9) / pow(1, 0.9);
+ B = pow(B, 0.9) / pow(1, 0.9);
+
+ if (R < 0) R = 0;
+ if (G < 0) G = 0;
+ if (B < 0) B = 0;
+
+ if (R > 1) R = 1;
+ if (G > 1) G = 1;
+ if (B > 1) B = 1;
+
+ palette_set_color_rgb(machine,8 * i + j,
+ (UINT8) (255 * R + 0.5),
+ (UINT8) (255 * G + 0.5),
+ (UINT8) (255 * B + 0.5));
+ }
+ }
+ extend_palette( machine );
+}
+
+
+PALETTE_INIT( tia_PAL )
+{
+ int i, j;
+
+ static const double color[16][2] =
+ {
+ { 0.000, 0.000 },
+ { 0.000, 0.000 },
+ { -0.222, 0.032 },
+ { -0.199, -0.027 },
+ { -0.173, 0.117 },
+ { -0.156, -0.197 },
+ { -0.094, 0.200 },
+ { -0.071, -0.229 },
+ { 0.070, 0.222 },
+ { 0.069, -0.204 },
+ { 0.177, 0.134 },
+ { 0.163, -0.130 },
+ { 0.219, 0.053 },
+ { 0.259, -0.042 },
+ { 0.000, 0.000 },
+ { 0.000, 0.000 }
+ };
+
+ for (i = 0; i < 16; i++)
+ {
+ double U = color[i][0];
+ double V = color[i][1];
+
+ for (j = 0; j < 8; j++)
+ {
+ double Y = j / 7.0;
+
+ double R = Y + 1.403 * V;
+ double G = Y - 0.344 * U - 0.714 * V;
+ double B = Y + 1.770 * U;
+
+ R = pow(R, 1.2) / pow(1, 1.2);
+ G = pow(G, 1.2) / pow(1, 1.2);
+ B = pow(B, 1.2) / pow(1, 1.2);
+
+ if (R < 0) R = 0;
+ if (G < 0) G = 0;
+ if (B < 0) B = 0;
+
+ if (R > 1) R = 1;
+ if (G > 1) G = 1;
+ if (B > 1) B = 1;
+
+ palette_set_color_rgb(machine,8 * i + j,
+ (UINT8) (255 * R + 0.5),
+ (UINT8) (255 * G + 0.5),
+ (UINT8) (255 * B + 0.5));
+ }
+ }
+ extend_palette( machine );
+}
+
+
+VIDEO_START( tia )
+{
+ int cx = machine->screen[0].width;
+
+ screen_height = machine->screen[0].height;
+ helper[0] = auto_bitmap_alloc(cx, TIA_MAX_SCREEN_HEIGHT, machine->screen[0].format);
+ helper[1] = auto_bitmap_alloc(cx, TIA_MAX_SCREEN_HEIGHT, machine->screen[0].format);
+ helper[2] = auto_bitmap_alloc(cx, TIA_MAX_SCREEN_HEIGHT, machine->screen[0].format);
+}
+
+
+VIDEO_UPDATE( tia )
+{
+ screen_height = machine->screen[0].height;
+ copybitmap(bitmap, helper[2], 0, 0, 0, 0,
+ cliprect, TRANSPARENCY_NONE, 0);
+ return 0;
+}
+
+
+static void draw_sprite_helper(UINT8* p, UINT8 *col, struct player_gfx *gfx,
+ UINT8 GRP, UINT8 COLUP, UINT8 REFP)
+{
+ int i;
+ int j;
+ int k;
+
+ if (REFP & 8)
+ {
+ GRP = BITSWAP8(GRP, 0, 1, 2, 3, 4, 5, 6, 7);
+ }
+
+ for (i = 0; i < PLAYER_GFX_SLOTS; i++)
+ {
+ int start_pos = gfx->start_drawing[i];
+ for (j = gfx->start_pixel[i]; j < 8; j++)
+ {
+ for (k = 0; k < gfx->size[i]; k++)
+ {
+ if (GRP & (0x80 >> j))
+ {
+ if ( start_pos < 160 || ! gfx->skipclip[i] ) {
+ p[start_pos % 160] = COLUP >> 1;
+ col[start_pos % 160] = COLUP >> 1;
+ }
+ }
+ start_pos++;
+ }
+ }
+ }
+}
+
+
+static void draw_missile_helper(UINT8* p, UINT8* col, int horz, int skipdelay, int latch, int start,
+ UINT8 RESMP, UINT8 ENAM, UINT8 NUSIZ, UINT8 COLUM)
+{
+ int num = nusiz[NUSIZ & 7][0];
+ int skp = nusiz[NUSIZ & 7][2];
+
+ int width = 1 << ((NUSIZ >> 4) & 3);
+
+ int i;
+ int j;
+
+ for (i = 0; i < num; i++)
+ {
+ if ( i == 0 )
+ horz -= skipdelay;
+ if ( i == 1 )
+ horz += skipdelay;
+ if ( i > 0 || start ) {
+ for (j = 0; j < width; j++)
+ {
+ if ((ENAM & 2) && !(RESMP & 2))
+ {
+ if ( latch ) {
+ switch ( horz % 4 ) {
+ case 1:
+ if ( horz >= 0 )
+ {
+ if ( horz < 156 ) {
+ p[(horz + 1) % 160] = COLUM >> 1;
+ col[(horz + 1) % 160] = COLUM >> 1;
+ }
+ p[horz % 160] = COLUM >> 1;
+ col[horz % 160] = COLUM >> 1;
+ }
+ break;
+ case 2:
+ case 3:
+ if ( horz >= 0 )
+ {
+ p[horz % 160] = COLUM >> 1;
+ col[horz % 160] = COLUM >> 1;
+ }
+ break;
+ }
+ } else {
+ if ( horz >= 0 )
+ {
+ p[horz % 160] = COLUM >> 1;
+ col[horz % 160] = COLUM >> 1;
+ }
+ }
+ }
+
+ horz++;
+ }
+ } else {
+ horz+= width;
+ }
+
+ horz += 8 * (skp + 1) - width;
+ }
+}
+
+
+static void draw_playfield_helper(UINT8* p, UINT8* col, int horz,
+ UINT8 COLU, UINT8 REFPF)
+{
+ UINT32 PF =
+ (BITSWAP8(PF0, 0, 1, 2, 3, 4, 5, 6, 7) << 0x10) |
+ (BITSWAP8(PF1, 7, 6, 5, 4, 3, 2, 1, 0) << 0x08) |
+ (BITSWAP8(PF2, 0, 1, 2, 3, 4, 5, 6, 7) << 0x00);
+
+ int i;
+ int j;
+
+ if (REFPF)
+ {
+ UINT32 swap = 0;
+
+ for (i = 0; i < 20; i++)
+ {
+ swap <<= 1;
+
+ if (PF & 1)
+ {
+ swap |= 1;
+ }
+
+ PF >>= 1;
+ }
+
+ PF = swap;
+ }
+
+ for (i = 0; i < 20; i++)
+ {
+ for (j = 0; j < 4; j++)
+ {
+ if (PF & (0x80000 >> i))
+ {
+ p[horz] = COLU >> 1;
+ col[horz] = COLU >> 1;
+ }
+
+ horz++;
+ }
+ }
+}
+
+
+static void draw_ball_helper(UINT8* p, UINT8* col, int horz, UINT8 ENAB)
+{
+ int width = 1 << ((CTRLPF >> 4) & 3);
+
+ int i;
+
+ for (i = 0; i < width; i++)
+ {
+ if (ENAB & 2)
+ {
+ p[horz % 160] = COLUPF >> 1;
+ col[horz % 160] = COLUPF >> 1;
+ }
+
+ horz++;
+ }
+}
+
+
+static void drawS0(UINT8* p, UINT8* col)
+{
+ draw_sprite_helper(p, col, &p0gfx, (VDELP0 & 1) ? prevGRP0 : GRP0, COLUP0, REFP0);
+}
+
+
+static void drawS1(UINT8* p, UINT8* col)
+{
+ draw_sprite_helper(p, col, &p1gfx, (VDELP1 & 1) ? prevGRP1 : GRP1, COLUP1, REFP1);
+}
+
+
+static void drawM0(UINT8* p, UINT8* col)
+{
+ draw_missile_helper(p, col, horzM0, skipM0delay, HMM0_latch, startM0, RESMP0, ENAM0, NUSIZ0, COLUP0);
+}
+
+
+static void drawM1(UINT8* p, UINT8* col)
+{
+ draw_missile_helper(p, col, horzM1, skipM1delay, HMM1_latch, startM1, RESMP1, ENAM1, NUSIZ1, COLUP1);
+}
+
+
+static void drawBL(UINT8* p, UINT8* col)
+{
+ draw_ball_helper(p, col, horzBL, (VDELBL & 1) ? prevENABL : ENABL);
+}
+
+
+static void drawPF(UINT8* p, UINT8 *col)
+{
+ draw_playfield_helper(p, col, 0,
+ ((CTRLPF & 6) == 2) ? COLUP0 : COLUPF, 0);
+
+ draw_playfield_helper(p, col, 80,
+ ((CTRLPF & 6) == 2) ? COLUP1 : COLUPF, REFLECT);
+}
+
+
+static int collision_check(UINT8* p1, UINT8* p2, int x1, int x2)
+{
+ int i;
+
+ for (i = x1; i < x2; i++)
+ {
+ if (p1[i] != 0xFF && p2[i] != 0xFF)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+INLINE int current_x(void)
+{
+ return 3 * ((activecpu_gettotalcycles() - frame_cycles) % 76) - 68;
+}
+
+
+INLINE int current_y(void)
+{
+ return (activecpu_gettotalcycles() - frame_cycles) / 76;
+}
+
+
+static void setup_pXgfx(void)
+{
+ int i;
+ for ( i = 0; i < PLAYER_GFX_SLOTS; i++ )
+ {
+ if ( i < nusiz[NUSIZ0 & 7][0] && i >= ( startP0 ? 0 : 1 ) )
+ {
+ p0gfx.size[i] = nusiz[NUSIZ0 & 7][1];
+ if ( i )
+ {
+ p0gfx.start_drawing[i] = ( horzP0 + (p0gfx.size[i] > 1 ? 1 : 0)
+ + i * 8 * ( nusiz[NUSIZ0 & 7][2] + p0gfx.size[i] ) ) % 160;
+ p0gfx.skipclip[i] = 0;
+ }
+ else
+ {
+ p0gfx.start_drawing[i] = horzP0 + (p0gfx.size[i] > 1 ? 1 : 0 );
+ p0gfx.skipclip[i] = skipclipP0;
+ }
+ p0gfx.start_pixel[i] = 0;
+ }
+ else
+ {
+ p0gfx.start_pixel[i] = 8;
+ }
+ if ( i < nusiz[NUSIZ1 & 7][0] && i >= ( startP1 ? 0 : 1 ) )
+ {
+ p1gfx.size[i] = nusiz[NUSIZ1 & 7][1];
+ if ( i )
+ {
+ p1gfx.start_drawing[i] = ( horzP1 + (p1gfx.size[i] > 1 ? 1 : 0)
+ + i * 8 * ( nusiz[NUSIZ1 & 7][2] + p1gfx.size[i] ) ) % 160;
+ p1gfx.skipclip[i] = 0;
+ }
+ else
+ {
+ p1gfx.start_drawing[i] = horzP1 + (p1gfx.size[i] > 1 ? 1 : 0);
+ p1gfx.skipclip[i] = skipclipP1;
+ }
+ p1gfx.start_pixel[i] = 0;
+ }
+ else
+ {
+ p1gfx.start_pixel[i] = 8;
+ }
+ }
+}
+
+static void update_bitmap(int next_x, int next_y)
+{
+ int x;
+ int y;
+
+ UINT8 linePF[160];
+ UINT8 lineP0[160];
+ UINT8 lineP1[160];
+ UINT8 lineM0[160];
+ UINT8 lineM1[160];
+ UINT8 lineBL[160];
+
+ UINT8 temp[160];
+
+ if (prev_y >= next_y && prev_x >= next_x)
+ {
+ return;
+ }
+
+ memset(linePF, 0xFF, sizeof linePF);
+ memset(lineP0, 0xFF, sizeof lineP0);
+ memset(lineP1, 0xFF, sizeof lineP1);
+ memset(lineM0, 0xFF, sizeof lineM0);
+ memset(lineM1, 0xFF, sizeof lineM1);
+ memset(lineBL, 0xFF, sizeof lineBL);
+
+ if (VBLANK & 2)
+ {
+ memset(temp, 0, 160);
+ }
+ else
+ {
+ memset(temp, COLUBK >> 1, 160);
+
+ if (CTRLPF & 4)
+ {
+ drawS1(temp, lineP1);
+ drawM1(temp, lineM1);
+ drawS0(temp, lineP0);
+ drawM0(temp, lineM0);
+ drawPF(temp, linePF);
+ drawBL(temp, lineBL);
+ }
+ else
+ {
+ drawPF(temp, linePF);
+ drawBL(temp, lineBL);
+ drawS1(temp, lineP1);
+ drawM1(temp, lineM1);
+ drawS0(temp, lineP0);
+ drawM0(temp, lineM0);
+ }
+ }
+
+ for (y = prev_y; y <= next_y; y++)
+ {
+ UINT16* p;
+
+ int x1 = prev_x;
+ int x2 = next_x;
+ int colx1;
+
+ /* Check if we have crossed a line boundary */
+ if ( y != prev_y ) {
+ int redraw_line = 0;
+
+ HMOVE_started_previous = HMOVE_INACTIVE;
+
+ if ( HMOVE_started != HMOVE_INACTIVE ) {
+ /* Apply pending motion clocks from a HMOVE initiated during the scanline */
+ if ( HMOVE_started >= 97 && HMOVE_started < 157 ) {
+ horzP0 -= motclkP0;
+ horzP1 -= motclkP1;
+ horzM0 -= motclkM0;
+ horzM1 -= motclkM1;
+ horzBL -= motclkBL;
+ if (horzP0 < 0)
+ horzP0 += 160;
+ if (horzP1 < 0)
+ horzP1 += 160;
+ if (horzM0 < 0)
+ horzM0 += 160;
+ if (horzM1 < 0)
+ horzM1 += 160;
+ if (horzBL < 0)
+ horzBL += 160;
+ HMOVE_started_previous = HMOVE_started;
+ }
+ HMOVE_started = HMOVE_INACTIVE;
+ redraw_line = 1;
+ }
+
+ /* Redraw line if the playfield reflect bit was changed after the center of the screen */
+ if ( REFLECT != ( CTRLPF & 0x01 ) ) {
+ REFLECT = CTRLPF & 0x01;
+ redraw_line = 1;
+ }
+
+ /* Redraw line if a RESPx or NUSIZx occured during the last line */
+ if ( ! startP0 || ! startP1 || ! startM0 || ! startM1) {
+ startP0 = 1;
+ startP1 = 1;
+ startM0 = 1;
+ startM1 = 1;
+
+ redraw_line = 1;
+ }
+
+ if ( skipclipP0 ) {
+ skipclipP0--;
+ redraw_line = 1;
+ }
+
+ if ( skipclipP1 ) {
+ skipclipP1--;
+ redraw_line = 1;
+ }
+
+ /* Redraw line if HMP0 latch is still set */
+ if ( HMP0_latch ) {
+ horzP0 -= 17;
+ if ( horzP0 < 0 )
+ horzP0 += 160;
+ redraw_line = 1;
+ }
+
+ /* Redraw line if HMP1 latch is still set */
+ if ( HMP1_latch ) {
+ horzP1 -= 17;
+ if ( horzP1 < 0 )
+ horzP1 += 160;
+ redraw_line = 1;
+ }
+
+ /* Redraw line if HMM0 latch is still set */
+ if ( HMM0_latch ) {
+ horzM0 -= 17;
+ if ( horzM0 < 0 )
+ horzM0 += 160;
+ redraw_line = 1;
+ }
+
+ /* Redraw line if HMM1 latch is still set */
+ if ( HMM1_latch ) {
+ horzM1 -= 17;
+ if ( horzM1 < 0 )
+ horzM1 += 160;
+ redraw_line = 1;
+ }
+
+ /* Redraw line if HMBL latch is still set */
+ if ( HMBL_latch ) {
+ horzBL -= 17;
+ if ( horzBL < 0 )
+ horzBL += 160;
+ redraw_line = 1;
+ }
+
+ /* Redraw line if NUSIZx data was changed */
+ if ( NUSIZx_changed ) {
+ NUSIZx_changed = 0;
+ redraw_line = 1;
+ }
+
+ if ( skipM0delay || skipM1delay ) {
+ skipM0delay = 0;
+ skipM1delay = 0;
+ redraw_line = 1;
+ }
+
+ if ( redraw_line ) {
+ if (VBLANK & 2)
+ {
+ setup_pXgfx();
+ memset(temp, 0, 160);
+ }
+ else
+ {
+ memset(linePF, 0xFF, sizeof linePF);
+ memset(lineP0, 0xFF, sizeof lineP0);
+ memset(lineP1, 0xFF, sizeof lineP1);
+ memset(lineM0, 0xFF, sizeof lineM0);
+ memset(lineM1, 0xFF, sizeof lineM1);
+ memset(lineBL, 0xFF, sizeof lineBL);
+
+ memset(temp, COLUBK >> 1, 160);
+
+ setup_pXgfx();
+
+ if (CTRLPF & 4)
+ {
+ drawS1(temp, lineP1);
+ drawM1(temp, lineM1);
+ drawS0(temp, lineP0);
+ drawM0(temp, lineM0);
+ drawPF(temp, linePF);
+ drawBL(temp, lineBL);
+ }
+ else
+ {
+ drawPF(temp, linePF);
+ drawBL(temp, lineBL);
+ drawS1(temp, lineP1);
+ drawM1(temp, lineM1);
+ drawS0(temp, lineP0);
+ drawM0(temp, lineM0);
+ }
+ }
+ }
+ }
+ if (y != prev_y || x1 < 0)
+ {
+ x1 = 0;
+ }
+ if (y != next_y || x2 > 160)
+ {
+ x2 = 160;
+ }
+
+ /* Collision detection also takes place under the extended hblank area */
+ colx1 = ( x1 == 8 && HMOVE_started != HMOVE_INACTIVE ) ? 0 : x1;
+
+ if (collision_check(lineM0, lineP1, colx1, x2))
+ CXM0P |= 0x80;
+ if (collision_check(lineM0, lineP0, colx1, x2))
+ CXM0P |= 0x40;
+ if (collision_check(lineM1, lineP0, colx1, x2))
+ CXM1P |= 0x80;
+ if (collision_check(lineM1, lineP1, colx1, x2))
+ CXM1P |= 0x40;
+ if (collision_check(lineP0, linePF, colx1, x2))
+ CXP0FB |= 0x80;
+ if (collision_check(lineP0, lineBL, colx1, x2))
+ CXP0FB |= 0x40;
+ if (collision_check(lineP1, linePF, colx1, x2))
+ CXP1FB |= 0x80;
+ if (collision_check(lineP1, lineBL, colx1, x2))
+ CXP1FB |= 0x40;
+ if (collision_check(lineM0, linePF, colx1, x2))
+ CXM0FB |= 0x80;
+ if (collision_check(lineM0, lineBL, colx1, x2))
+ CXM0FB |= 0x40;
+ if (collision_check(lineM1, linePF, colx1, x2))
+ CXM1FB |= 0x80;
+ if (collision_check(lineM1, lineBL, colx1, x2))
+ CXM1FB |= 0x40;
+ if (collision_check(lineBL, linePF, colx1, x2))
+ CXBLPF |= 0x80;
+ if (collision_check(lineP0, lineP1, colx1, x2))
+ CXPPMM |= 0x80;
+ if (collision_check(lineM0, lineM1, colx1, x2))
+ CXPPMM |= 0x40;
+
+ p = BITMAP_ADDR16(helper[current_bitmap], y % screen_height, 34);
+
+ for (x = x1; x < x2; x++)
+ {
+ p[x] = temp[x];
+ }
+
+ if ( x2 == 160 && y % screen_height == (screen_height - 1) ) {
+ int t_y;
+ for ( t_y = 0; t_y < helper[2]->height; t_y++ ) {
+ UINT16* l0 = BITMAP_ADDR16( helper[current_bitmap], t_y, 0 );
+ UINT16* l1 = BITMAP_ADDR16( helper[1 - current_bitmap], t_y, 0 );
+ UINT16* l2 = BITMAP_ADDR16( helper[2], t_y, 0 );
+ int t_x;
+ for( t_x = 0; t_x < helper[2]->width; t_x++ ) {
+ if ( l0[t_x] != l1[t_x] ) {
+ /* Combine both entries */
+ l2[t_x] = ( ( l0[t_x] + 1 ) << 7 ) | l1[t_x];
+ } else {
+ l2[t_x] = l0[t_x];
+ }
+ }
+ }
+ current_bitmap ^= 1;
+ }
+ }
+
+ prev_x = next_x;
+ prev_y = next_y;
+}
+
+
+static WRITE8_HANDLER( WSYNC_w )
+{
+ int cycles = activecpu_gettotalcycles() - frame_cycles;
+
+ if (cycles % 76)
+ {
+ activecpu_adjust_icount(cycles % 76 - 76);
+ }
+}
+
+
+static WRITE8_HANDLER( VSYNC_w )
+{
+ if (data & 2)
+ {
+ if (!(VSYNC & 2))
+ {
+ int curr_y = current_y();
+
+ if ( curr_y > 5 )
+ update_bitmap(
+ Machine->screen[0].width,
+ Machine->screen[0].height);
+
+ if ( tia_vsync_callback ) {
+ tia_vsync_callback( 0, curr_y, 0xFFFF );
+ }
+
+ prev_y = 0;
+ prev_x = 0;
+
+ frame_cycles += 76 * current_y();
+ }
+ }
+
+ VSYNC = data;
+}
+
+
+static WRITE8_HANDLER( VBLANK_w )
+{
+ if (data & 0x80)
+ {
+ paddle_cycles = activecpu_gettotalcycles();
+ }
+ if ( ! ( VBLANK & 0x40 ) ) {
+ INPT4 = 0x80;
+ INPT5 = 0x80;
+ }
+ VBLANK = data;
+}
+
+
+static WRITE8_HANDLER( CTRLPF_w )
+{
+ int curr_x = current_x();
+
+ CTRLPF = data;
+ if ( curr_x < 80 ) {
+ REFLECT = CTRLPF & 1;
+ }
+}
+
+static WRITE8_HANDLER( HMP0_w )
+{
+ int curr_x = current_x();
+
+ data &= 0xF0;
+
+ if ( data == HMP0 )
+ return;
+
+ /* Check if HMOVE cycles are still being applied */
+ if ( HMOVE_started != HMOVE_INACTIVE && curr_x < MIN( HMOVE_started + 6 + motclkP0 * 4, 7 ) ) {
+ int new_motclkP0 = ( data ^ 0x80 ) >> 4;
+
+ /* Check if new horizontal move can still be applied normally */
+ if ( new_motclkP0 > motclkP0 || curr_x <= MIN( HMOVE_started + 6 + new_motclkP0 * 4, 7 ) ) {
+ horzP0 -= ( new_motclkP0 - motclkP0 );
+ motclkP0 = new_motclkP0;
+ } else {
+ horzP0 -= ( 15 - motclkP0 );
+ motclkP0 = 15;
+ if ( data != 0x70 && data != 0x80 ) {
+ HMP0_latch = 1;
+ }
+ }
+ if ( horzP0 < 0 )
+ horzP0 += 160;
+ horzP0 %= 160;
+ setup_pXgfx();
+ }
+ HMP0 = data;
+}
+
+static WRITE8_HANDLER( HMP1_w )
+{
+ int curr_x = current_x();
+
+ data &= 0xF0;
+
+ if ( data == HMP1 )
+ return;
+
+ /* Check if HMOVE cycles are still being applied */
+ if ( HMOVE_started != HMOVE_INACTIVE && curr_x < MIN( HMOVE_started + 6 + motclkP1 * 4, 7 ) ) {
+ int new_motclkP1 = ( data ^ 0x80 ) >> 4;
+
+ /* Check if new horizontal move can still be applied normally */
+ if ( new_motclkP1 > motclkP1 || curr_x <= MIN( HMOVE_started + 6 + new_motclkP1 * 4, 7 ) ) {
+ horzP1 -= ( new_motclkP1 - motclkP1 );
+ motclkP1 = new_motclkP1;
+ } else {
+ horzP1 -= ( 15 - motclkP1 );
+ motclkP1 = 15;
+ if ( data != 0x70 && data != 0x80 ) {
+ HMP1_latch = 1;
+ }
+ }
+ if ( horzP1 < 0 )
+ horzP1 += 160;
+ horzP1 %= 160;
+ setup_pXgfx();
+ }
+ HMP1 = data;
+}
+
+static WRITE8_HANDLER( HMM0_w )
+{
+ int curr_x = current_x();
+
+ data &= 0xF0;
+
+ if ( data == HMM0 )
+ return;
+
+ /* Check if HMOVE cycles are still being applied */
+ if ( HMOVE_started != HMOVE_INACTIVE && curr_x < MIN( HMOVE_started + 6 + motclkM0 * 4, 7 ) ) {
+ int new_motclkM0 = ( data ^ 0x80 ) >> 4;
+
+ /* Check if new horizontal move can still be applied normally */
+ if ( new_motclkM0 > motclkM0 || curr_x <= MIN( HMOVE_started + 6 + new_motclkM0 * 4, 7 ) ) {
+ horzM0 -= ( new_motclkM0 - motclkM0 );
+ motclkM0 = new_motclkM0;
+ } else {
+ horzM0 -= ( 15 - motclkM0 );
+ motclkM0 = 15;
+ if ( data != 0x70 && data != 0x80 ) {
+ HMM0_latch = 1;
+ }
+ }
+ if ( horzM0 < 0 )
+ horzM0 += 160;
+ horzM0 %= 160;
+ }
+ HMM0 = data;
+}
+
+static WRITE8_HANDLER( HMM1_w )
+{
+ int curr_x = current_x();
+
+ data &= 0xF0;
+
+ if ( data == HMM1 )
+ return;
+
+ /* Check if HMOVE cycles are still being applied */
+ if ( HMOVE_started != HMOVE_INACTIVE && curr_x < MIN( HMOVE_started + 6 + motclkM1 * 4, 7 ) ) {
+ int new_motclkM1 = ( data ^ 0x80 ) >> 4;
+
+ /* Check if new horizontal move can still be applied normally */
+ if ( new_motclkM1 > motclkM1 || curr_x <= MIN( HMOVE_started + 6 + new_motclkM1 * 4, 7 ) ) {
+ horzM1 -= ( new_motclkM1 - motclkM1 );
+ motclkM1 = new_motclkM1;
+ } else {
+ horzM1 -= ( 15 - motclkM1 );
+ motclkM1 = 15;
+ if ( data != 0x70 && data != 0x80 ) {
+ HMM1_latch = 1;
+ }
+ }
+ if ( horzM1 < 0 )
+ horzM1 += 160;
+ horzM1 %= 160;
+ }
+ HMM1 = data;
+}
+
+static WRITE8_HANDLER( HMBL_w )
+{
+ int curr_x = current_x();
+
+ data &= 0xF0;
+
+ if ( data == HMBL )
+ return;
+
+ /* Check if HMOVE cycles are still being applied */
+ if ( HMOVE_started != HMOVE_INACTIVE && curr_x < MIN( HMOVE_started + 6 + motclkBL * 4, 7 ) ) {
+ int new_motclkBL = ( data ^ 0x80 ) >> 4;
+
+ /* Check if new horizontal move can still be applied normally */
+ if ( new_motclkBL > motclkBL || curr_x <= MIN( HMOVE_started + 6 + new_motclkBL * 4, 7 ) ) {
+ horzBL -= ( new_motclkBL - motclkBL );
+ motclkBL = new_motclkBL;
+ } else {
+ horzBL -= ( 15 - motclkBL );
+ motclkBL = 15;
+ if ( data != 0x70 && data != 0x80 ) {
+ HMBL_latch = 1;
+ }
+ }
+ if ( horzBL < 0 )
+ horzBL += 160;
+ horzBL %= 160;
+ }
+ HMBL = data;
+}
+
+static WRITE8_HANDLER( HMOVE_w )
+{
+ int curr_x = current_x();
+ int curr_y = current_y();
+
+ HMOVE_started = curr_x;
+
+ /* Check if we have to undo some of the already applied cycles from an active graphics latch */
+ if ( curr_x + 68 < 17 * 4 ) {
+ int cycle_fix = 17 - ( ( curr_x + 68 + 7 ) / 4 );
+ if ( HMP0_latch )
+ horzP0 = ( horzP0 + cycle_fix ) % 160;
+ if ( HMP1_latch )
+ horzP1 = ( horzP1 + cycle_fix ) % 160;
+ if ( HMM0_latch )
+ horzM0 = ( horzM0 + cycle_fix ) % 160;
+ if ( HMM1_latch )
+ horzM1 = ( horzM1 + cycle_fix ) % 160;
+ if ( HMBL_latch )
+ horzBL = ( horzBL + cycle_fix ) % 160;
+ }
+
+ HMP0_latch = 0;
+ HMP1_latch = 0;
+ HMM0_latch = 0;
+ HMM1_latch = 0;
+ HMBL_latch = 0;
+
+ /* Check if HMOVE activities can be ignored */
+ if ( curr_x >= -5 && curr_x < 97 ) {
+ motclkP0 = 0;
+ motclkP1 = 0;
+ motclkM0 = 0;
+ motclkM1 = 0;
+ motclkBL = 0;
+ HMOVE_started = HMOVE_INACTIVE;
+ return;
+ }
+
+ motclkP0 = ( HMP0 ^ 0x80 ) >> 4;
+ motclkP1 = ( HMP1 ^ 0x80 ) >> 4;
+ motclkM0 = ( HMM0 ^ 0x80 ) >> 4;
+ motclkM1 = ( HMM1 ^ 0x80 ) >> 4;
+ motclkBL = ( HMBL ^ 0x80 ) >> 4;
+
+ /* Adjust number of graphics motion clocks for active display */
+ if ( curr_x >= 97 && curr_x < 151 ) {
+ int skip_motclks = ( 160 - HMOVE_started - 6 ) / 4;
+ motclkP0 -= skip_motclks;
+ motclkP1 -= skip_motclks;
+ motclkM0 -= skip_motclks;
+ motclkM1 -= skip_motclks;
+ motclkBL -= skip_motclks;
+ if ( motclkP0 < 0 )
+ motclkP0 = 0;
+ if ( motclkP1 < 0 )
+ motclkP1 = 0;
+ if ( motclkM0 < 0 )
+ motclkM0 = 0;
+ if ( motclkM1 < 0 )
+ motclkM1 = 0;
+ if ( motclkBL < 0 )
+ motclkBL = 0;
+ }
+
+ if ( curr_x >= -56 && curr_x < -5 ) {
+ int max_motclks = ( 7 - ( HMOVE_started + 5 ) ) / 4;
+ if ( motclkP0 > max_motclks )
+ motclkP0 = max_motclks;
+ if ( motclkP1 > max_motclks )
+ motclkP1 = max_motclks;
+ if ( motclkM0 > max_motclks )
+ motclkM0 = max_motclks;
+ if ( motclkM1 > max_motclks )
+ motclkM1 = max_motclks;
+ if ( motclkBL > max_motclks )
+ motclkBL = max_motclks;
+ }
+
+ /* Apply horizontal motion */
+ if ( curr_x < -5 || curr_x >= 157 ) {
+ horzP0 += 8 - motclkP0;
+ horzP1 += 8 - motclkP1;
+ horzM0 += 8 - motclkM0;
+ horzM1 += 8 - motclkM1;
+ horzBL += 8 - motclkBL;
+
+ if (horzP0 < 0)
+ horzP0 += 160;
+ if (horzP1 < 0)
+ horzP1 += 160;
+ if (horzM0 < 0)
+ horzM0 += 160;
+ if (horzM1 < 0)
+ horzM1 += 160;
+ if (horzBL < 0)
+ horzBL += 160;
+
+ horzP0 %= 160;
+ horzP1 %= 160;
+ horzM0 %= 160;
+ horzM1 %= 160;
+ horzBL %= 160;
+
+ /* When HMOVE is triggered on CPU cycle 75, the HBlank period on the
+ next line is also extended. */
+ if (curr_x >= 157)
+ {
+ curr_y += 1;
+ update_bitmap( -8, curr_y );
+ }
+ else
+ {
+ setup_pXgfx();
+ }
+ if (curr_y < screen_height)
+ {
+ memset(BITMAP_ADDR16(helper[current_bitmap], curr_y, 34), 0, 16);
+ }
+
+ prev_x = 8;
+ }
+}
+
+
+static WRITE8_HANDLER( RSYNC_w )
+{
+ /* this address is used in chip testing */
+}
+
+
+static WRITE8_HANDLER( NUSIZ0_w )
+{
+ int curr_x = current_x();
+
+ /* Check if relevant bits have changed */
+ if ( ( data & 7 ) != ( NUSIZ0 & 7 ) ) {
+ int i;
+ /* Check if we are (about to start) drawing a copy of the player 0 graphics */
+ for ( i = 0; i < PLAYER_GFX_SLOTS; i++ ) {
+ if ( p0gfx.start_pixel[i] < 8 ) {
+ int min_x = p0gfx.start_drawing[i];
+ int size = ( 8 - p0gfx.start_pixel[i] ) * p0gfx.size[i];
+ if ( curr_x >= ( min_x - 5 ) % 160 && curr_x < ( min_x + size ) % 160 ) {
+ if ( curr_x >= min_x % 160 || p0gfx.start_pixel[i] != 0 ) {
+ /* This copy has started drawing */
+ if ( p0gfx.size[i] == 1 && nusiz[data & 7][1] > 1 ) {
+ int delay = 1 + ( ( p0gfx.start_pixel[i] + ( curr_x - p0gfx.start_drawing[i] ) ) & 1 );
+ update_bitmap( curr_x + delay, current_y() );
+ p0gfx.start_pixel[i] += ( curr_x + delay - p0gfx.start_drawing[i] );
+ if ( p0gfx.start_pixel[i] > 8 )
+ p0gfx.start_pixel[i] = 8;
+ p0gfx.start_drawing[i] = curr_x + delay;
+ } else if ( p0gfx.size[1] > 1 && nusiz[data & 7][1] == 1 ) {
+ int delay = ( curr_x - p0gfx.start_drawing[i] ) & ( p0gfx.size[i] - 1 );
+ if ( delay ) {
+ delay = p0gfx.size[i] - delay;
+ }
+ update_bitmap( curr_x + delay, current_y() );
+ p0gfx.start_pixel[i] += ( curr_x - p0gfx.start_drawing[i] ) / p0gfx.size[i];
+ p0gfx.start_drawing[i] = curr_x + delay;
+ } else {
+ p0gfx.start_pixel[i] += ( curr_x - p0gfx.start_drawing[i] ) / p0gfx.size[i];
+ p0gfx.start_drawing[i] = curr_x;
+ }
+ p0gfx.size[i] = nusiz[data & 7][1];
+ } else {
+ /* This copy was just about to start drawing (meltdown) */
+ /* Adjust for 1 clock delay between zoomed and non-zoomed sprites */
+ if ( p0gfx.size[i] == 1 && nusiz[data & 7][1] > 1 ) {
+ /* Check for hardware oddity */
+ if ( p0gfx.start_drawing[i] - curr_x == 2 ) {
+ p0gfx.start_drawing[i]--;
+ } else {
+ p0gfx.start_drawing[i]++;
+ }
+ } else if ( p0gfx.size[i] > 1 && nusiz[data & 7][1] == 1 ) {
+ p0gfx.start_drawing[i]--;
+ }
+ p0gfx.size[i] = nusiz[data & 7][1];
+ }
+ } else {
+ /* We are passed the copy or the copy still needs to be done. Mark
+ it as done/invalid, the data will be reset in the next loop. */
+ p0gfx.start_pixel[i] = 8;
+ }
+ }
+ }
+ /* Apply NUSIZ updates to not yet drawn copies */
+ for ( i = ( startP0 ? 0 : 1 ); i < nusiz[data & 7][0]; i++ ) {
+ int j;
+ /* Find an unused p0gfx entry */
+ for ( j = 0; j < PLAYER_GFX_SLOTS; j++ ) {
+ if ( p0gfx.start_pixel[j] == 8 )
+ break;
+ }
+ p0gfx.size[j] = nusiz[data & 7][1];
+ p0gfx.start_drawing[j] = ( horzP0 + (p0gfx.size[j] > 1 ? 1 : 0)
+ + i * 8 * ( nusiz[data & 7][2] + p0gfx.size[j] ) ) % 160;
+ if ( curr_x < p0gfx.start_drawing[j] % 160 ) {
+ p0gfx.start_pixel[j] = 0;
+ }
+ }
+ NUSIZx_changed = 1;
+ }
+ NUSIZ0 = data;
+}
+
+
+static WRITE8_HANDLER( NUSIZ1_w )
+{
+ int curr_x = current_x();
+
+ /* Check if relevant bits have changed */
+ if ( ( data & 7 ) != ( NUSIZ1 & 7 ) ) {
+ int i;
+ /* Check if we are (about to start) drawing a copy of the player 1 graphics */
+ for ( i = 0; i < PLAYER_GFX_SLOTS; i++ ) {
+ if ( p1gfx.start_pixel[i] < 8 ) {
+ int min_x = p1gfx.start_drawing[i];
+ int size = ( 8 - p1gfx.start_pixel[i] ) * p1gfx.size[i];
+ if ( curr_x >= ( min_x - 5 ) % 160 && curr_x < ( min_x + size ) % 160 ) {
+ if ( curr_x >= min_x % 160 || p1gfx.start_pixel[i] != 0 ) {
+ /* This copy has started drawing */
+ if ( p1gfx.size[i] == 1 && nusiz[data & 7][1] > 1 ) {
+ int delay = 1 + ( ( p0gfx.start_pixel[i] + ( curr_x - p0gfx.start_drawing[i] ) ) & 1 );
+ update_bitmap( curr_x + delay, current_y() );
+ p1gfx.start_pixel[i] += ( curr_x + delay - p1gfx.start_drawing[i] );
+ if ( p1gfx.start_pixel[i] > 8 )
+ p1gfx.start_pixel[i] = 8;
+ p1gfx.start_drawing[i] = curr_x + delay;
+ } else if ( p1gfx.size[1] > 1 && nusiz[data & 7][1] == 1 ) {
+ int delay = ( curr_x - p1gfx.start_drawing[i] ) & ( p1gfx.size[i] - 1 );
+ if ( delay ) {
+ delay = p1gfx.size[i] - delay;
+ }
+ update_bitmap( curr_x + delay, current_y() );
+ p1gfx.start_pixel[i] += ( curr_x - p1gfx.start_drawing[i] ) / p1gfx.size[i];
+ p1gfx.start_drawing[i] = curr_x + delay;
+ } else {
+ p1gfx.start_pixel[i] += ( curr_x - p1gfx.start_drawing[i] ) / p1gfx.size[i];
+ p1gfx.start_drawing[i] = curr_x;
+ }
+ p1gfx.size[i] = nusiz[data & 7][1];
+ } else {
+ /* This copy was just about to start drawing (meltdown) */
+ /* Adjust for 1 clock delay between zoomed and non-zoomed sprites */
+ if ( p1gfx.size[i] == 1 && nusiz[data & 7][1] > 1 ) {
+ /* Check for hardware oddity */
+ if ( p1gfx.start_drawing[i] - curr_x == 2 ) {
+ p1gfx.start_drawing[i]--;
+ } else {
+ p1gfx.start_drawing[i]++;
+ }
+ } else if ( p1gfx.size[i] > 1 && nusiz[data & 7][1] == 1 ) {
+ p1gfx.start_drawing[i]--;
+ }
+ p1gfx.size[i] = nusiz[data & 7][1];
+ }
+ } else {
+ /* We are passed the copy or the copy still needs to be done. Mark
+ it as done/invalid, the data will be reset in the next loop. */
+ p1gfx.start_pixel[i] = 8;
+ }
+ }
+ }
+ /* Apply NUSIZ updates to not yet drawn copies */
+ for ( i = ( startP1 ? 0 : 1 ); i < nusiz[data & 7][0]; i++ ) {
+ int j;
+ /* Find an unused p1gfx entry */
+ for ( j = 0; j < PLAYER_GFX_SLOTS; j++ ) {
+ if ( p1gfx.start_pixel[j] == 8 )
+ break;
+ }
+ p1gfx.size[j] = nusiz[data & 7][1];
+ p1gfx.start_drawing[j] = ( horzP1 + (p1gfx.size[j] > 1 ? 1 : 0)
+ + i * 8 * ( nusiz[data & 7][2] + p1gfx.size[j] ) ) % 160;
+ if ( curr_x < p1gfx.start_drawing[j] % 160 ) {
+ p1gfx.start_pixel[j] = 0;
+ }
+ }
+ NUSIZx_changed = 1;
+ }
+ NUSIZ1 = data;
+}
+
+
+static WRITE8_HANDLER( HMCLR_w )
+{
+ HMP0_w( offset, 0 );
+ HMP1_w( offset, 0 );
+ HMM0_w( offset, 0 );
+ HMM1_w( offset, 0 );
+ HMBL_w( offset, 0 );
+}
+
+
+static WRITE8_HANDLER( CXCLR_w )
+{
+ CXM0P = 0;
+ CXM1P = 0;
+ CXP0FB = 0;
+ CXP1FB = 0;
+ CXM0FB = 0;
+ CXM1FB = 0;
+ CXBLPF = 0;
+ CXPPMM = 0;
+}
+
+
+#define RESXX_APPLY_ACTIVE_HMOVE(HORZ,MOTION,MOTCLK) \
+ if ( curr_x < MIN( HMOVE_started + 6 + 16 * 4, 7 ) ) { \
+ int decrements_passed = ( curr_x - ( HMOVE_started + 4 ) ) / 4; \
+ HORZ += 8; \
+ if ( ( MOTCLK - decrements_passed ) > 0 ) { \
+ HORZ -= ( MOTCLK - decrements_passed ); \
+ if ( HORZ < 0 ) \
+ HORZ += 160; \
+ } \
+ }
+
+#define RESXX_APPLY_PREVIOUS_HMOVE(HORZ,MOTION) \
+ if ( HMOVE_started_previous != HMOVE_INACTIVE ) \
+ { \
+ UINT8 motclk = ( MOTION ^ 0x80 ) >> 4; \
+ if ( curr_x <= HMOVE_started_previous - 228 + 5 + motclk * 4 ) \
+ { \
+ UINT8 motclk_passed = ( curr_x - ( HMOVE_started_previous - 228 + 6 ) ) / 4; \
+ HORZ -= ( motclk - motclk_passed ); \
+ } \
+ }
+
+static WRITE8_HANDLER( RESP0_w )
+{
+ int curr_x = current_x();
+ int new_horzP0;
+
+ /* Check if HMOVE is activated during this line */
+ if ( HMOVE_started != HMOVE_INACTIVE ) {
+ new_horzP0 = ( curr_x < 7 ) ? 3 : ( curr_x + 5 );
+ /* If HMOVE is active, adjust for remaining horizontal move clocks if any */
+ RESXX_APPLY_ACTIVE_HMOVE( new_horzP0, HMP0, motclkP0 );
+ } else {
+ new_horzP0 = ( curr_x < -2 ) ? 3 : ( curr_x + 5 );
+ RESXX_APPLY_PREVIOUS_HMOVE( new_horzP0, HMP0 );
+ }
+
+ if ( new_horzP0 != horzP0 ) {
+ int i;
+ horzP0 = new_horzP0;
+ startP0 = 0;
+ skipclipP0 = 2;
+ /* Check if we are (about to start) drawing a copy of the player 0 graphics */
+ for ( i = 0; i < PLAYER_GFX_SLOTS; i++ ) {
+ if ( p0gfx.start_pixel[i] < 8 ) {
+ int min_x = p0gfx.start_drawing[i];
+ int size = ( 8 - p0gfx.start_pixel[i] ) * p0gfx.size[i];
+ if ( curr_x >= ( min_x - 5 ) % 160 && curr_x < ( min_x + size ) % 160 ) {
+ if ( curr_x >= min_x ) {
+ /* This copy has started drawing */
+ p0gfx.start_pixel[i] += ( curr_x - p0gfx.start_drawing[i] ) / p0gfx.size[i];
+ p0gfx.start_drawing[i] = curr_x;
+ } else {
+ /* This copy is waiting to start drawing */
+ p0gfx.start_drawing[i] = horzP0;
+ }
+ } else {
+ /* We are passed the copy or the copy still needs to be done. Mark
+ it as done/invalid, the data will be reset in the next loop. */
+ p0gfx.start_pixel[i] = 8;
+ }
+ }
+ }
+ /* Apply NUSIZ and position updates to not yet drawn copies */
+ for ( i = 1; i < nusiz[NUSIZ0 & 7][0]; i++ ) {
+ int j;
+ /* Find an unused p0gfx entry */
+ for ( j = 0; j < PLAYER_GFX_SLOTS; j++ ) {
+ if ( p0gfx.start_pixel[j] == 8 )
+ break;
+ }
+ p0gfx.size[j] = nusiz[NUSIZ0 & 7][1];
+ p0gfx.start_drawing[j] = ( horzP0 + (p0gfx.size[j] > 1 ? 1 : 0)
+ + i * 8 * ( nusiz[NUSIZ0 & 7][2] + p0gfx.size[j] ) ) % 160;
+ if ( curr_x < p0gfx.start_drawing[j] % 160 ) {
+ p0gfx.start_pixel[j] = 0;
+ }
+ }
+ }
+}
+
+
+static WRITE8_HANDLER( RESP1_w )
+{
+ int curr_x = current_x();
+ int new_horzP1;
+
+ /* Check if HMOVE is activated during this line */
+ if ( HMOVE_started != HMOVE_INACTIVE ) {
+ new_horzP1 = ( curr_x < 7 ) ? 3 : ( curr_x + 5 );
+ /* If HMOVE is active, adjust for remaining horizontal move clocks if any */
+ RESXX_APPLY_ACTIVE_HMOVE( new_horzP1, HMP1, motclkP1 );
+ } else {
+ new_horzP1 = ( curr_x < -2 ) ? 3 : ( curr_x + 5 );
+ RESXX_APPLY_PREVIOUS_HMOVE( new_horzP1, HMP1 );
+ }
+
+ if ( new_horzP1 != horzP1 ) {
+ int i;
+ horzP1 = new_horzP1;
+ startP1 = 0;
+ skipclipP1 = 2;
+ /* Check if we are (about to start) drawing a copy of the player 1 graphics */
+ for ( i = 0; i < PLAYER_GFX_SLOTS; i++ ) {
+ if ( p1gfx.start_pixel[i] < 8 ) {
+ int min_x = p1gfx.start_drawing[i];
+ int size = ( 8 - p1gfx.start_pixel[i] ) * p1gfx.size[i];
+ if ( curr_x >= ( min_x - 5 ) % 160 && curr_x < ( min_x + size ) % 160 ) {
+ if ( curr_x >= min_x ) {
+ /* This copy has started drawing */
+ p1gfx.start_pixel[i] += ( curr_x - p1gfx.start_drawing[i] ) / p1gfx.size[i];
+ p1gfx.start_drawing[i] = curr_x;
+ } else {
+ /* This copy is waiting to start drawing */
+ p1gfx.start_drawing[i] = horzP1;
+ }
+ } else {
+ /* We are passed the copy or the copy still needs to be done. Mark
+ it as done/invalid, the data will be reset in the next loop. */
+ p1gfx.start_pixel[i] = 8;
+ }
+ }
+ }
+ /* Apply NUSIZ and position updates to not yet drawn copies */
+ for ( i = 1; i < nusiz[NUSIZ1 & 7][0]; i++ ) {
+ int j;
+ /* Find an unused p1gfx entry */
+ for ( j = 0; j < PLAYER_GFX_SLOTS; j++ ) {
+ if ( p1gfx.start_pixel[j] == 8 )
+ break;
+ }
+ p1gfx.size[j] = nusiz[NUSIZ1 & 7][1];
+ p1gfx.start_drawing[j] = ( horzP1 + (p1gfx.size[j] > 1 ? 1 : 0)
+ + i * 8 * ( nusiz[NUSIZ1 & 7][2] + p1gfx.size[j] ) ) % 160;
+ if ( curr_x < p1gfx.start_drawing[j] % 160 ) {
+ p1gfx.start_pixel[j] = 0;
+ }
+ }
+ }
+}
+
+
+static WRITE8_HANDLER( RESM0_w )
+{
+ int curr_x = current_x();
+ int new_horzM0;
+
+ /* Check if HMOVE is activated during this line */
+ if ( HMOVE_started != HMOVE_INACTIVE ) {
+ new_horzM0 = ( curr_x < 7 ) ? 2 : ( ( curr_x + 4 ) % 160 );
+ /* If HMOVE is active, adjust for remaining horizontal move clocks if any */
+ RESXX_APPLY_ACTIVE_HMOVE( new_horzM0, HMM0, motclkM0 );
+ } else {
+ new_horzM0 = ( curr_x < -1 ) ? 2 : ( ( curr_x + 4 ) % 160 );
+ skipM0delay = ( curr_x < -1 && horzM0 % 160 >= 0 && horzM0 % 160 < 1 ) ? 4 : 0;
+ RESXX_APPLY_PREVIOUS_HMOVE( new_horzM0, HMM0 );
+ }
+ if ( new_horzM0 != horzM0 ) {
+ startM0 = skipM0delay ? 1 : 0;
+ horzM0 = new_horzM0;
+ }
+}
+
+
+static WRITE8_HANDLER( RESM1_w )
+{
+ int curr_x = current_x();
+ int new_horzM1;
+
+ /* Check if HMOVE is activated during this line */
+ if ( HMOVE_started != HMOVE_INACTIVE ) {
+ new_horzM1 = ( curr_x < 7 ) ? 2 : ( ( curr_x + 4 ) % 160 );
+ /* If HMOVE is active, adjust for remaining horizontal move clocks if any */
+ RESXX_APPLY_ACTIVE_HMOVE( new_horzM1, HMM1, motclkM1 );
+ } else {
+ new_horzM1 = ( curr_x < -1 ) ? 2 : ( ( curr_x + 4 ) % 160 );
+ skipM1delay = ( curr_x < -1 && horzM1 % 160 >= 0 && horzM1 % 160 < 1 ) ? 4 : 0;
+ RESXX_APPLY_PREVIOUS_HMOVE( new_horzM1, HMM1 );
+ }
+ if ( new_horzM1 != horzM1 ){
+ startM1 = skipM1delay ? 1 : 0;
+ horzM1 = new_horzM1;
+ }
+}
+
+
+static WRITE8_HANDLER( RESBL_w )
+{
+ int curr_x = current_x();
+
+ /* Check if HMOVE is activated during this line */
+ if ( HMOVE_started != HMOVE_INACTIVE ) {
+ horzBL = ( curr_x < 7 ) ? 2 : ( ( curr_x + 4 ) % 160 );
+ /* If HMOVE is active, adjust for remaining horizontal move clocks if any */
+ RESXX_APPLY_ACTIVE_HMOVE( horzBL, HMBL, motclkBL );
+ } else {
+ horzBL = ( curr_x < 0 ) ? 2 : ( ( curr_x + 4 ) % 160 );
+ RESXX_APPLY_PREVIOUS_HMOVE( horzBL, HMBL );
+ }
+}
+
+
+static WRITE8_HANDLER( RESMP0_w )
+{
+ if (RESMP0 & 2)
+ {
+ if ( nusiz[NUSIZ0 & 7][1] > 1 ) {
+ horzM0 = horzP0 + 3 * nusiz[NUSIZ0 & 7][1] - 1;
+ } else {
+ horzM0 = horzP0 + 4 * nusiz[NUSIZ0 & 7][1];
+ }
+ if ( HMOVE_started != HMOVE_INACTIVE ) {
+ horzM0 -= ( 8 - motclkP0 );
+ horzM0 += 8 - motclkM0;
+ if ( horzM0 < 0 )
+ horzM0 += 160;
+ }
+ horzM0 %= 160;
+ }
+
+ RESMP0 = data;
+}
+
+
+static WRITE8_HANDLER( RESMP1_w )
+{
+ if (RESMP1 & 2)
+ {
+ if ( nusiz[NUSIZ1 & 7][1] > 1 ) {
+ horzM1 = horzP1 + 3 * nusiz[NUSIZ1 & 7][1] - 1;
+ } else {
+ horzM1 = horzP1 + 4 * nusiz[NUSIZ1 & 7][1];
+ }
+ if ( HMOVE_started != HMOVE_INACTIVE ) {
+ horzM1 -= ( 8 - motclkP1 );
+ horzM1 += 8 - motclkM1;
+ if ( horzM1 < 0 )
+ horzM1 += 160;
+ }
+ horzM1 %= 160;
+ }
+
+ RESMP1 = data;
+}
+
+
+static WRITE8_HANDLER( GRP0_w )
+{
+ prevGRP1 = GRP1;
+
+ GRP0 = data;
+}
+
+
+static WRITE8_HANDLER( GRP1_w )
+{
+ prevGRP0 = GRP0;
+
+ GRP1 = data;
+
+ prevENABL = ENABL;
+}
+
+
+static READ8_HANDLER( INPT_r )
+{
+ UINT32 elapsed = activecpu_gettotalcycles() - paddle_cycles;
+ int input = TIA_INPUT_PORT_ALWAYS_ON;
+
+ if ( tia_read_input_port )
+ {
+ input = tia_read_input_port(offset & 3, 0xFFFF);
+ }
+
+ if ( input == TIA_INPUT_PORT_ALWAYS_ON )
+ return 0x80;
+ if ( input == TIA_INPUT_PORT_ALWAYS_OFF )
+ return 0x00;
+
+ return elapsed > 76 * input ? 0x80 : 0x00;
+}
+
+
+READ8_HANDLER( tia_r )
+{
+ /* lower bits 0 - 5 seem to depend on the last byte on the
+ data bus. If the driver supplied a routine to retrieve
+ that we will call that, otherwise we will use the lower
+ bit of the offset.
+ */
+ UINT8 data = offset & 0x3f;
+
+ if ( tia_get_databus )
+ {
+ data = tia_get_databus(offset) & 0x3f;
+ }
+
+ if (!(offset & 0x8))
+ {
+ update_bitmap(current_x(), current_y());
+ }
+
+ switch (offset & 0xF)
+ {
+ case 0x0:
+ return data | CXM0P;
+ case 0x1:
+ return data | CXM1P;
+ case 0x2:
+ return data | CXP0FB;
+ case 0x3:
+ return data | CXP1FB;
+ case 0x4:
+ return data | CXM0FB;
+ case 0x5:
+ return data | CXM1FB;
+ case 0x6:
+ return data | CXBLPF;
+ case 0x7:
+ return data | CXPPMM;
+ case 0x8:
+ return data | INPT_r(0);
+ case 0x9:
+ return data | INPT_r(1);
+ case 0xA:
+ return data | INPT_r(2);
+ case 0xB:
+ return data | INPT_r(3);
+ case 0xC:
+ {
+ int button = tia_read_input_port ? ( tia_read_input_port(4,0xFFFF) & 0x80 ) : 0x80;
+ INPT4 = ( VBLANK & 0x40) ? ( INPT4 & button ) : button;
+ }
+ return data | INPT4;
+ case 0xD:
+ {
+ int button = tia_read_input_port ? ( tia_read_input_port(5,0xFFFF) & 0x80 ) : 0x80;
+ INPT5 = ( VBLANK & 0x40) ? ( INPT5 & button ) : button;
+ }
+ return data | INPT5;
+ }
+
+ return data;
+}
+
+
+WRITE8_HANDLER( tia_w )
+{
+ static const int delay[0x40] =
+ {
+ 0, // VSYNC
+ 0, // VBLANK
+ 0, // WSYNC
+ 0, // RSYNC
+ 0, // NUSIZ0
+ 0, // NUSIZ1
+ 0, // COLUP0
+ 0, // COLUP1
+ 0, // COLUPF
+ 0, // COLUBK
+ 0, // CTRLPF
+ 1, // REFP0
+ 1, // REFP1
+ 4, // PF0
+ 4, // PF1
+ 4, // PF2
+ 0, // RESP0
+ 0, // RESP1
+ 0, // RESM0
+ 0, // RESM1
+ 0, // RESBL
+ -1, // AUDC0
+ -1, // AUDC1
+ -1, // AUDF0
+ -1, // AUDF1
+ -1, // AUDV0
+ -1, // AUDV1
+ 1, // GRP0
+ 1, // GRP1
+ 1, // ENAM0
+ 1, // ENAM1
+ 1, // ENABL
+ 0, // HMP0
+ 0, // HMP1
+ 0, // HMM0
+ 0, // HMM1
+ 0, // HMBL
+ 0, // VDELP0
+ 0, // VDELP1
+ 0, // VDELBL
+ 0, // RESMP0
+ 0, // RESMP1
+ 3, // HMOVE
+ 0, // HMCLR
+ 0, // CXCLR
+ };
+
+ int curr_x = current_x();
+ int curr_y = current_y();
+
+ offset &= 0x3F;
+
+ if (offset >= 0x0D && offset <= 0x0F)
+ {
+ curr_x = ( curr_x + 1 ) & ~3;
+ }
+
+ if (delay[offset] >= 0)
+ {
+ update_bitmap(curr_x + delay[offset], curr_y);
+ }
+
+ switch (offset)
+ {
+ case 0x00:
+ VSYNC_w(offset, data);
+ break;
+ case 0x01:
+ VBLANK_w(offset, data);
+ break;
+ case 0x02:
+ WSYNC_w(offset, data);
+ break;
+ case 0x03:
+ RSYNC_w(offset, data);
+ break;
+ case 0x04:
+ NUSIZ0_w(offset, data);
+ break;
+ case 0x05:
+ NUSIZ1_w(offset, data);
+ break;
+ case 0x06:
+ COLUP0 = data;
+ break;
+ case 0x07:
+ COLUP1 = data;
+ break;
+ case 0x08:
+ COLUPF = data;
+ break;
+ case 0x09:
+ COLUBK = data;
+ break;
+ case 0x0A:
+ CTRLPF_w(offset, data);
+ break;
+ case 0x0B:
+ REFP0 = data;
+ break;
+ case 0x0C:
+ REFP1 = data;
+ break;
+ case 0x0D:
+ PF0 = data;
+ break;
+ case 0x0E:
+ PF1 = data;
+ break;
+ case 0x0F:
+ PF2 = data;
+ break;
+ case 0x10:
+ RESP0_w(offset, data);
+ break;
+ case 0x11:
+ RESP1_w(offset, data);
+ break;
+ case 0x12:
+ RESM0_w(offset, data);
+ break;
+ case 0x13:
+ RESM1_w(offset, data);
+ break;
+ case 0x14:
+ RESBL_w(offset, data);
+ break;
+
+ case 0x15: /* AUDC0 */
+ case 0x16: /* AUDC1 */
+ case 0x17: /* AUDF0 */
+ case 0x18: /* AUDF1 */
+ case 0x19: /* AUDV0 */
+ case 0x1A: /* AUDV1 */
+ tia_sound_w(offset, data);
+ break;
+
+ case 0x1B:
+ GRP0_w(offset, data);
+ break;
+ case 0x1C:
+ GRP1_w(offset, data);
+ break;
+ case 0x1D:
+ ENAM0 = data;
+ break;
+ case 0x1E:
+ ENAM1 = data;
+ break;
+ case 0x1F:
+ ENABL = data;
+ break;
+ case 0x20:
+ HMP0_w(offset, data);
+ break;
+ case 0x21:
+ HMP1_w(offset, data);
+ break;
+ case 0x22:
+ HMM0_w(offset, data);
+ break;
+ case 0x23:
+ HMM1_w(offset, data);
+ break;
+ case 0x24:
+ HMBL_w(offset, data);
+ break;
+ case 0x25:
+ VDELP0 = data;
+ break;
+ case 0x26:
+ VDELP1 = data;
+ break;
+ case 0x27:
+ VDELBL = data;
+ break;
+ case 0x28:
+ RESMP0_w(offset, data);
+ break;
+ case 0x29:
+ RESMP1_w(offset, data);
+ break;
+ case 0x2A:
+ HMOVE_w(offset, data);
+ break;
+ case 0x2B:
+ HMCLR_w(offset, data);
+ break;
+ case 0x2C:
+ CXCLR_w(offset, 0);
+ break;
+ }
+}
+
+
+static void tia_reset(running_machine *machine)
+{
+ int i;
+
+ frame_cycles = 0;
+
+ INPT4 = 0x80;
+ INPT5 = 0x80;
+
+ HMP0 = 0;
+ HMP1 = 0;
+ HMM0 = 0;
+ HMM1 = 0;
+ HMBL = 0;
+
+ startP0 = 1;
+ startP1 = 1;
+
+ HMP0_latch = 0;
+ HMP1_latch = 0;
+ HMM0_latch = 0;
+ HMM1_latch = 0;
+ HMBL_latch = 0;
+
+ startM0 = 1;
+ startM1 = 1;
+ skipM0delay = 0;
+ skipM1delay = 0;
+
+ REFLECT = 0;
+
+ prev_x = 0;
+ prev_y = 0;
+
+ HMOVE_started = HMOVE_INACTIVE;
+
+ motclkP0 = 0;
+ motclkP1 = 0;
+ motclkM0 = 0;
+ motclkM1 = 0;
+ motclkBL = 0;
+
+ for( i = 0; i < PLAYER_GFX_SLOTS; i++ )
+ {
+ p0gfx.start_pixel[i] = 8;
+ p0gfx.size[i] = 1;
+ p1gfx.start_pixel[i] = 8;
+ p1gfx.size[i] = 1;
+ }
+
+ NUSIZx_changed = 0;
+}
+
+
+
+void tia_init(const struct tia_interface* ti)
+{
+ assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "Can only call tia_init at init time!");
+
+ if ( ti ) {
+ tia_read_input_port = ti->read_input_port;
+ tia_get_databus = ti->databus_contents;
+ tia_vsync_callback = ti->vsync_callback;
+ } else {
+ tia_read_input_port = NULL;
+ tia_get_databus = NULL;
+ tia_vsync_callback = NULL;
+ }
+
+ tia_reset( Machine );
+
+ add_reset_callback(Machine, tia_reset);
+}
+
diff --git a/src/mame/video/tia.h b/src/mame/video/tia.h
new file mode 100644
index 00000000000..9408bf987ca
--- /dev/null
+++ b/src/mame/video/tia.h
@@ -0,0 +1,26 @@
+#ifndef _VIDEO_TIA_H_
+#define _VIDEO_TIA_H_
+
+#define TIA_PALETTE_LENGTH 128 + 128 * 128
+#define TIA_INPUT_PORT_ALWAYS_ON 0
+#define TIA_INPUT_PORT_ALWAYS_OFF 0xffff
+#define TIA_MAX_SCREEN_HEIGHT 342
+
+struct tia_interface {
+ read16_handler read_input_port;
+ read8_handler databus_contents;
+ write16_handler vsync_callback;
+};
+
+PALETTE_INIT( tia_NTSC );
+PALETTE_INIT( tia_PAL );
+
+VIDEO_START( tia );
+VIDEO_UPDATE( tia );
+
+READ8_HANDLER( tia_r );
+WRITE8_HANDLER( tia_w );
+
+void tia_init(const struct tia_interface* ti);
+
+#endif /* _VIDEO_TIA_H_ */
diff --git a/src/mame/video/tiamc1.c b/src/mame/video/tiamc1.c
new file mode 100644
index 00000000000..1acf462fd15
--- /dev/null
+++ b/src/mame/video/tiamc1.c
@@ -0,0 +1,210 @@
+/***************************************************************************
+
+ TIA-MC1 video hardware
+
+ driver by Eugene Sandulenko
+ special thanks to Shiru for his standalone emulator and documentation
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+UINT8 *tiamc1_tileram;
+UINT8 *tiamc1_charram;
+UINT8 *tiamc1_spriteram_x;
+UINT8 *tiamc1_spriteram_y;
+UINT8 *tiamc1_spriteram_a;
+UINT8 *tiamc1_spriteram_n;
+static UINT8 tiamc1_layers_ctrl;
+static UINT8 tiamc1_bg_vshift;
+static UINT8 tiamc1_bg_hshift;
+
+static tilemap *bg_tilemap1, *bg_tilemap2;
+static rgb_t *palette;
+
+WRITE8_HANDLER( tiamc1_videoram_w )
+{
+ if(!(tiamc1_layers_ctrl & 2))
+ tiamc1_charram[offset + 0x0000] = data;
+ if(!(tiamc1_layers_ctrl & 4))
+ tiamc1_charram[offset + 0x0800] = data;
+ if(!(tiamc1_layers_ctrl & 8))
+ tiamc1_charram[offset + 0x1000] = data;
+ if(!(tiamc1_layers_ctrl & 16))
+ tiamc1_charram[offset + 0x1800] = data;
+
+ if((tiamc1_layers_ctrl & 30) ^ 0xff)
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+
+ if(!(tiamc1_layers_ctrl & 1)) {
+ tiamc1_tileram[offset] = data;
+ if (offset >= 1024)
+ tilemap_mark_tile_dirty(bg_tilemap1, offset);
+ else
+ tilemap_mark_tile_dirty(bg_tilemap2, offset);
+ }
+}
+
+WRITE8_HANDLER( tiamc1_bankswitch_w )
+{
+ if ((data & 128) != (tiamc1_layers_ctrl & 128))
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+
+ tiamc1_layers_ctrl = data;
+}
+
+WRITE8_HANDLER( tiamc1_sprite_x_w )
+{
+ tiamc1_spriteram_x[offset] = data;
+}
+
+WRITE8_HANDLER( tiamc1_sprite_y_w )
+{
+ tiamc1_spriteram_y[offset] = data;
+}
+
+WRITE8_HANDLER( tiamc1_sprite_a_w )
+{
+ tiamc1_spriteram_a[offset] = data;
+}
+
+WRITE8_HANDLER( tiamc1_sprite_n_w )
+{
+ tiamc1_spriteram_n[offset] = data;
+}
+
+WRITE8_HANDLER( tiamc1_bg_vshift_w ) {
+ tiamc1_bg_vshift = data;
+}
+WRITE8_HANDLER( tiamc1_bg_hshift_w ) {
+ tiamc1_bg_hshift = data;
+}
+
+WRITE8_HANDLER( tiamc1_palette_w )
+{
+ palette_set_color(Machine, offset, palette[data]);
+}
+
+PALETTE_INIT( tiamc1 )
+{
+ // Voltage computed by Proteus
+ //const float g_v[8]={1.05f,0.87f,0.81f,0.62f,0.44f,0.25f,0.19f,0.00f};
+ //const float r_v[8]={1.37f,1.13f,1.00f,0.75f,0.63f,0.38f,0.25f,0.00f};
+ //const float b_v[4]={1.16f,0.75f,0.42f,0.00f};
+
+ // Voltage adjusted by Shiru
+ const float g_v[8] = { 1.2071f,0.9971f,0.9259f,0.7159f,0.4912f,0.2812f,0.2100f,0.0000f};
+ const float r_v[8] = { 1.5937f,1.3125f,1.1562f,0.8750f,0.7187f,0.4375f,0.2812f,0.0000f};
+ const float b_v[4] = { 1.3523f,0.8750f,0.4773f,0.0000f};
+
+ int col;
+ int r, g, b, ir, ig, ib;
+ float tcol;
+
+ palette = auto_malloc(256 * sizeof(*palette));
+
+ for (col = 0; col < 256; col++) {
+ ir = (col >> 3) & 7;
+ ig = col & 7;
+ ib = (col >> 6) & 3;
+ tcol = 255.0f * r_v[ir] / r_v[0];
+ r = 255 - (((int)tcol) & 255);
+ tcol = 255.0f * g_v[ig] / g_v[0];
+ g = 255 - (((int)tcol) & 255);
+ tcol = 255.0f * b_v[ib] / b_v[0];
+ b = 255 - (((int)tcol) & 255);
+
+ palette[col] = MAKE_RGB(r,g,b);
+ }
+}
+
+static TILE_GET_INFO( get_bg1_tile_info )
+{
+ int code = tiamc1_tileram[tile_index];
+
+ decodechar(machine->gfx[0], code, tiamc1_charram,
+ machine->drv->gfxdecodeinfo[0].gfxlayout);
+
+ SET_TILE_INFO(0, code, 0, 0);
+}
+
+static TILE_GET_INFO( get_bg2_tile_info )
+{
+ int code = tiamc1_tileram[tile_index + 1024];
+
+ decodechar(machine->gfx[0], code, tiamc1_charram,
+ machine->drv->gfxdecodeinfo[0].gfxlayout);
+
+ SET_TILE_INFO(0, code, 0, 0);
+}
+
+VIDEO_START( tiamc1 )
+{
+ bg_tilemap1 = tilemap_create(get_bg1_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ bg_tilemap2 = tilemap_create(get_bg2_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tiamc1_bg_vshift = 0;
+ tiamc1_bg_hshift = 0;
+
+ state_save_register_global(tiamc1_layers_ctrl);
+ state_save_register_global(tiamc1_bg_vshift);
+ state_save_register_global(tiamc1_bg_hshift);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0; offs < 16; offs++)
+ {
+ int flipx, flipy, sx, sy, spritecode;
+
+ sx = tiamc1_spriteram_x[offs] ^ 0xff;
+ sy = tiamc1_spriteram_y[offs] ^ 0xff;
+ flipx = !(tiamc1_spriteram_a[offs] & 0x08);
+ flipy = !(tiamc1_spriteram_a[offs] & 0x02);
+ spritecode = tiamc1_spriteram_n[offs] ^ 0xff;
+
+ if (!(tiamc1_spriteram_a[offs] & 0x01))
+ drawgfx(bitmap, machine->gfx[1],
+ spritecode,
+ 0,
+ flipx, flipy,
+ sx, sy,
+ cliprect, TRANSPARENCY_PEN, 15);
+ }
+}
+
+VIDEO_UPDATE( tiamc1 )
+{
+#if 0
+ int i;
+
+ for (i = 0; i < 32; i++)
+ {
+ tilemap_set_scrolly(bg_tilemap1, i, tiamc1_bg_vshift ^ 0xff);
+ tilemap_set_scrolly(bg_tilemap2, i, tiamc1_bg_vshift ^ 0xff);
+ }
+
+ for (i = 0; i < 32; i++)
+ {
+ tilemap_set_scrollx(bg_tilemap1, i, tiamc1_bg_hshift ^ 0xff);
+ tilemap_set_scrollx(bg_tilemap2, i, tiamc1_bg_hshift ^ 0xff);
+ }
+#endif
+
+ if (tiamc1_layers_ctrl & 0x80)
+ tilemap_draw(bitmap, cliprect, bg_tilemap2, 0, 0);
+ else
+ tilemap_draw(bitmap, cliprect, bg_tilemap1, 0, 0);
+
+
+ draw_sprites(machine, bitmap, cliprect);
+
+ return 0;
+}
+
diff --git a/src/mame/video/tickee.c b/src/mame/video/tickee.c
new file mode 100644
index 00000000000..f1a043db29c
--- /dev/null
+++ b/src/mame/video/tickee.c
@@ -0,0 +1,121 @@
+/***************************************************************************
+
+ Raster Elite Tickee Tickats hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "cpu/tms34010/tms34010.h"
+#include "tickee.h"
+
+
+UINT16 *tickee_vram;
+
+
+/* local variables */
+static emu_timer *setup_gun_timer;
+
+
+
+/*************************************
+ *
+ * Compute X/Y coordinates
+ *
+ *************************************/
+
+INLINE void get_crosshair_xy(int player, int *x, int *y)
+{
+ *x = (((readinputport(4 + player * 2) & 0xff) * (Machine->screen[0].visarea.max_x - Machine->screen[0].visarea.min_x)) >> 8) + Machine->screen[0].visarea.min_x;
+ *y = (((readinputport(5 + player * 2) & 0xff) * (Machine->screen[0].visarea.max_y - Machine->screen[0].visarea.min_y)) >> 8) + Machine->screen[0].visarea.min_y;
+}
+
+
+
+/*************************************
+ *
+ * Light gun interrupts
+ *
+ *************************************/
+
+static TIMER_CALLBACK( trigger_gun_interrupt )
+{
+ /* fire the IRQ at the correct moment */
+ cpunum_set_input_line(0, param, ASSERT_LINE);
+}
+
+
+static TIMER_CALLBACK( clear_gun_interrupt )
+{
+ /* clear the IRQ on the next scanline? */
+ cpunum_set_input_line(0, param, CLEAR_LINE);
+}
+
+
+static TIMER_CALLBACK( setup_gun_interrupts )
+{
+ int beamx, beamy;
+
+ /* set a timer to do this again next frame */
+ timer_adjust(setup_gun_timer, video_screen_get_time_until_pos(0, 0, 0), 0, attotime_zero);
+
+ /* only do work if the palette is flashed */
+ if (!tickee_control[2])
+ return;
+
+ /* generate interrupts for player 1's gun */
+ get_crosshair_xy(0, &beamx, &beamy);
+ timer_set(video_screen_get_time_until_pos(0, beamy, beamx + 50), 0, trigger_gun_interrupt);
+ timer_set(video_screen_get_time_until_pos(0, beamy + 1, beamx + 50), 0, clear_gun_interrupt);
+
+ /* generate interrupts for player 2's gun */
+ get_crosshair_xy(1, &beamx, &beamy);
+ timer_set(video_screen_get_time_until_pos(0, beamy, beamx + 50), 1, trigger_gun_interrupt);
+ timer_set(video_screen_get_time_until_pos(0, beamy + 1, beamx + 50), 1, clear_gun_interrupt);
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+VIDEO_START( tickee )
+{
+ /* start a timer going on the first scanline of every frame */
+ setup_gun_timer = timer_alloc(setup_gun_interrupts);
+ timer_adjust(setup_gun_timer, video_screen_get_time_until_pos(0, 0, 0), 0, attotime_zero);
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+void tickee_scanline_update(running_machine *machine, int screen, mame_bitmap *bitmap, int scanline, const tms34010_display_params *params)
+{
+ UINT16 *src = &tickee_vram[(params->rowaddr << 8) & 0x3ff00];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0);
+ int coladdr = params->coladdr << 1;
+ int x;
+
+ /* blank palette: fill with pen 255 */
+ if (tickee_control[2])
+ {
+ for (x = params->heblnk; x < params->hsblnk; x++)
+ dest[x] = 0xff;
+ return;
+ }
+
+ /* copy the non-blanked portions of this scanline */
+ for (x = params->heblnk; x < params->hsblnk; x += 2)
+ {
+ UINT16 pixels = src[coladdr++ & 0xff];
+ dest[x + 0] = pixels & 0xff;
+ dest[x + 1] = pixels >> 8;
+ }
+}
diff --git a/src/mame/video/tigeroad.c b/src/mame/video/tigeroad.c
new file mode 100644
index 00000000000..4dde2f86d12
--- /dev/null
+++ b/src/mame/video/tigeroad.c
@@ -0,0 +1,170 @@
+#include "driver.h"
+
+static int bgcharbank;
+static tilemap *bg_tilemap, *fg_tilemap;
+
+WRITE16_HANDLER( tigeroad_videoram_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE16_HANDLER( tigeroad_videoctrl_w )
+{
+ int bank;
+
+ if (ACCESSING_MSB)
+ {
+ data = (data >> 8) & 0xff;
+
+ /* bit 1 flips screen */
+
+ if (flip_screen != (data & 0x02))
+ {
+ flip_screen_set(data & 0x02);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ /* bit 2 selects bg char bank */
+
+ bank = (data & 0x04) >> 2;
+
+ if (bgcharbank != bank)
+ {
+ bgcharbank = bank;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ /* bits 4-5 are coin lockouts */
+
+ coin_lockout_w(0, !(data & 0x10));
+ coin_lockout_w(1, !(data & 0x20));
+
+ /* bits 6-7 are coin counters */
+
+ coin_counter_w(0, data & 0x40);
+ coin_counter_w(1, data & 0x80);
+ }
+}
+
+WRITE16_HANDLER( tigeroad_scroll_w )
+{
+ int scroll = 0;
+
+ COMBINE_DATA(&scroll);
+
+ switch (offset)
+ {
+ case 0:
+ tilemap_set_scrollx(bg_tilemap, 0, scroll);
+ break;
+ case 1:
+ tilemap_set_scrolly(bg_tilemap, 0, -scroll - 32 * 8);
+ break;
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority )
+{
+ UINT16 *source = &buffered_spriteram16[spriteram_size/2] - 4;
+ UINT16 *finish = buffered_spriteram16;
+
+ // TODO: The Track Map should probably be drawn on top of the background tilemap...
+ // Also convert the below into a for loop!
+
+ while (source >= finish)
+ {
+ int tile_number = source[0];
+
+ if (tile_number != 0xfff) {
+ int attr = source[1];
+ int sy = source[2] & 0x1ff;
+ int sx = source[3] & 0x1ff;
+
+ int flipx = attr & 0x02;
+ int flipy = attr & 0x01;
+ int color = (attr >> 2) & 0x0f;
+
+ if (sx > 0x100) sx -= 0x200;
+ if (sy > 0x100) sy -= 0x200;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[2],
+ tile_number,
+ color,
+ flipx, flipy,
+ sx, 240 - sy,
+ cliprect,
+ TRANSPARENCY_PEN, 15);
+ }
+
+ source -= 4;
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 *tilerom = memory_region(REGION_GFX4);
+
+ int data = tilerom[tile_index];
+ int attr = tilerom[tile_index + 1];
+ int code = data + ((attr & 0xc0) << 2) + (bgcharbank << 10);
+ int color = attr & 0x0f;
+ int flags = (attr & 0x20) ? TILE_FLIPX : 0;
+
+ SET_TILE_INFO(1, code, color, flags);
+ tileinfo->group = (attr & 0x10) ? 1 : 0;
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int data = videoram16[tile_index];
+ int attr = data >> 8;
+ int code = (data & 0xff) + ((attr & 0xc0) << 2) + ((attr & 0x20) << 5);
+ int color = attr & 0x0f;
+ int flags = (attr & 0x10) ? TILE_FLIPY : 0;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+static TILEMAP_MAPPER( tigeroad_tilemap_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return 2 * (col % 8) + 16 * ((127 - row) % 8) + 128 * (col / 8) + 2048 * ((127 - row) / 8);
+}
+
+VIDEO_START( tigeroad )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tigeroad_tilemap_scan,
+ TILEMAP_TYPE_PEN, 32, 32, 128, 128);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transmask(bg_tilemap, 0, 0xffff, 0);
+ tilemap_set_transmask(bg_tilemap, 1, 0x1ff, 0xfe00);
+
+ tilemap_set_transparent_pen(fg_tilemap, 3);
+}
+
+VIDEO_UPDATE( tigeroad )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_LAYER1, 0);
+ draw_sprites(machine, bitmap, cliprect, 0);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, TILEMAP_DRAW_LAYER0, 1);
+ //draw_sprites(machine, bitmap, cliprect, 1); draw priority sprites?
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 2);
+ return 0;
+}
+
+VIDEO_EOF( tigeroad )
+{
+ buffer_spriteram16_w(0,0,0);
+}
diff --git a/src/mame/video/timelimt.c b/src/mame/video/timelimt.c
new file mode 100644
index 00000000000..7fd0036985f
--- /dev/null
+++ b/src/mame/video/timelimt.c
@@ -0,0 +1,152 @@
+#include "driver.h"
+
+/* globals */
+UINT8 *timelimt_bg_videoram;
+size_t timelimt_bg_videoram_size;
+
+/* locals */
+static int scrollx, scrolly;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Time Limit has two 32 bytes palette PROM, connected to the RGB output this
+ way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+
+PALETTE_INIT( timelimt ) {
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (*color_prom >> 6) & 0x01;
+ bit1 = (*color_prom >> 7) & 0x01;
+ b = 0x4f * bit0 + 0xa8 * bit1;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ SET_TILE_INFO(1, timelimt_bg_videoram[tile_index], 0, 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ SET_TILE_INFO(0, videoram[tile_index], 0, 0);
+}
+
+VIDEO_START( timelimt )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+/***************************************************************************/
+
+WRITE8_HANDLER( timelimt_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( timelimt_bg_videoram_w )
+{
+ timelimt_bg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( timelimt_scroll_x_lsb_w )
+{
+ scrollx &= 0x100;
+ scrollx |= data & 0xff;
+}
+
+WRITE8_HANDLER( timelimt_scroll_x_msb_w )
+{
+ scrollx &= 0xff;
+ scrollx |= ( data & 1 ) << 8;
+}
+
+WRITE8_HANDLER( timelimt_scroll_y_w )
+{
+ scrolly = data;
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for( offs = spriteram_size; offs >= 0; offs -= 4 )
+ {
+ int sy = 240 - spriteram[offs];
+ int sx = spriteram[offs+3];
+ int code = spriteram[offs+1] & 0x3f;
+ int attr = spriteram[offs+2];
+ int flipy = spriteram[offs+1] & 0x80;
+ int flipx = spriteram[offs+1] & 0x40;
+
+ code += ( attr & 0x80 ) ? 0x40 : 0x00;
+ code += ( attr & 0x40 ) ? 0x80 : 0x00;
+
+ drawgfx( bitmap, machine->gfx[2],
+ code,
+ attr & 7,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+VIDEO_UPDATE( timelimt )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, scrollx);
+ tilemap_set_scrolly(bg_tilemap, 0, scrolly);
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ draw_sprites(machine, bitmap, cliprect);
+
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/timeplt.c b/src/mame/video/timeplt.c
new file mode 100644
index 00000000000..aa0fd21ce8c
--- /dev/null
+++ b/src/mame/video/timeplt.c
@@ -0,0 +1,224 @@
+#include "driver.h"
+
+UINT8 *timeplt_videoram,*timeplt_colorram;
+static tilemap *bg_tilemap;
+
+/*
+sprites are multiplexed, so we have to buffer the spriteram
+scanline by scanline.
+*/
+static UINT8 *sprite_mux_buffer,*sprite_mux_buffer_2;
+static int scanline;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Time Pilot has two 32x8 palette PROMs and two 256x4 lookup table PROMs
+ (one for characters, one for sprites).
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 7 -- 390 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 560 ohm resistor -- BLUE
+ -- 820 ohm resistor -- BLUE
+ -- 1.2kohm resistor -- BLUE
+ -- 390 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ bit 0 -- 560 ohm resistor -- GREEN
+
+ bit 7 -- 820 ohm resistor -- GREEN
+ -- 1.2kohm resistor -- GREEN
+ -- 390 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ -- 560 ohm resistor -- RED
+ -- 820 ohm resistor -- RED
+ -- 1.2kohm resistor -- RED
+ bit 0 -- not connected
+
+***************************************************************************/
+PALETTE_INIT( timeplt )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,bit4,r,g,b;
+
+
+ bit0 = (color_prom[i + machine->drv->total_colors] >> 1) & 0x01;
+ bit1 = (color_prom[i + machine->drv->total_colors] >> 2) & 0x01;
+ bit2 = (color_prom[i + machine->drv->total_colors] >> 3) & 0x01;
+ bit3 = (color_prom[i + machine->drv->total_colors] >> 4) & 0x01;
+ bit4 = (color_prom[i + machine->drv->total_colors] >> 5) & 0x01;
+ r = 0x19 * bit0 + 0x24 * bit1 + 0x35 * bit2 + 0x40 * bit3 + 0x4d * bit4;
+ bit0 = (color_prom[i + machine->drv->total_colors] >> 6) & 0x01;
+ bit1 = (color_prom[i + machine->drv->total_colors] >> 7) & 0x01;
+ bit2 = (color_prom[i] >> 0) & 0x01;
+ bit3 = (color_prom[i] >> 1) & 0x01;
+ bit4 = (color_prom[i] >> 2) & 0x01;
+ g = 0x19 * bit0 + 0x24 * bit1 + 0x35 * bit2 + 0x40 * bit3 + 0x4d * bit4;
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ bit3 = (color_prom[i] >> 6) & 0x01;
+ bit4 = (color_prom[i] >> 7) & 0x01;
+ b = 0x19 * bit0 + 0x24 * bit1 + 0x35 * bit2 + 0x40 * bit3 + 0x4d * bit4;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the lookup table */
+
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = *(color_prom++) & 0x0f;
+
+ /* characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = (*(color_prom++) & 0x0f) + 0x10;
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 attr = timeplt_colorram[tile_index];
+ tileinfo->category = (attr & 0x10) >> 4;
+ SET_TILE_INFO(
+ 0,
+ timeplt_videoram[tile_index] + ((attr & 0x20) << 3),
+ attr & 0x1f,
+ TILE_FLIPYX((attr & 0xc0) >> 6));
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( timeplt )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ sprite_mux_buffer = auto_malloc(256 * spriteram_size);
+ sprite_mux_buffer_2 = auto_malloc(256 * spriteram_size);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( timeplt_videoram_w )
+{
+ timeplt_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( timeplt_colorram_w )
+{
+ timeplt_colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( timeplt_flipscreen_w )
+{
+ flip_screen_set(~data & 1);
+}
+
+/* Return the current video scan line */
+READ8_HANDLER( timeplt_scanline_r )
+{
+ return scanline;
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ const gfx_element *gfx = machine->gfx[1];
+ rectangle clip = *cliprect;
+ int offs;
+ int line;
+
+
+ for (line = 0;line < 256;line++)
+ {
+ if (line >= cliprect->min_y && line <= cliprect->max_y)
+ {
+ UINT8 *sr,*sr2;
+
+ sr = sprite_mux_buffer + line * spriteram_size;
+ sr2 = sprite_mux_buffer_2 + line * spriteram_size;
+ clip.min_y = clip.max_y = line;
+
+ for (offs = spriteram_size - 2;offs >= 0;offs -= 2)
+ {
+ int code,color,sx,sy,flipx,flipy;
+
+ sx = sr[offs];
+ sy = 241 - sr2[offs + 1];
+
+ if (sy > line-16 && sy <= line)
+ {
+ code = sr[offs + 1];
+ color = sr2[offs] & 0x3f;
+ flipx = ~sr2[offs] & 0x40;
+ flipy = sr2[offs] & 0x80;
+
+ drawgfx(bitmap,gfx,
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ &clip,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( timeplt )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,1,0);
+ return 0;
+}
+
+
+INTERRUPT_GEN( timeplt_interrupt )
+{
+ scanline = 255 - cpu_getiloops();
+
+ memcpy(sprite_mux_buffer + scanline * spriteram_size,spriteram,spriteram_size);
+ memcpy(sprite_mux_buffer_2 + scanline * spriteram_size,spriteram_2,spriteram_size);
+
+ if (scanline == 255)
+ nmi_line_pulse();
+}
diff --git a/src/mame/video/tmnt.c b/src/mame/video/tmnt.c
new file mode 100644
index 00000000000..cfe0f908caa
--- /dev/null
+++ b/src/mame/video/tmnt.c
@@ -0,0 +1,815 @@
+#include "driver.h"
+#include "machine/eeprom.h"
+#include "video/konamiic.h"
+
+
+static int layer_colorbase[3],sprite_colorbase,bg_colorbase;
+static int priorityflag;
+static int layerpri[3];
+static int prmrsocr_sprite_bank;
+static int sorted_layer[3];
+static int dim_c,dim_v; /* ssriders, tmnt2 */
+static int lastdim,lasten;
+
+static tilemap *roz_tilemap;
+
+
+static int glfgreat_roz_rom_bank,glfgreat_roz_char_bank,glfgreat_roz_rom_mode;
+
+static TILE_GET_INFO( glfgreat_get_roz_tile_info )
+{
+ UINT8 *rom = memory_region(REGION_USER1);
+ int code;
+
+ tile_index += 0x40000 * glfgreat_roz_rom_bank;
+
+ code = rom[tile_index+0x80000] + 256*rom[tile_index] + 256*256*((rom[tile_index/4+0x100000]>>(2*(tile_index&3)))&3);
+
+ SET_TILE_INFO(0,code & 0x3fff,code >> 14,0);
+}
+
+static TILE_GET_INFO( prmrsocr_get_roz_tile_info )
+{
+ UINT8 *rom = memory_region(REGION_USER1);
+ int code = rom[tile_index+0x20000] + 256*rom[tile_index];
+
+ SET_TILE_INFO(0,code & 0x1fff,code >> 13,0);
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+/* Missing in Action */
+
+static void mia_tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ *flags = (*color & 0x04) ? TILE_FLIPX : 0;
+ if (layer == 0)
+ {
+ *code |= ((*color & 0x01) << 8);
+ *color = layer_colorbase[layer] + ((*color & 0x80) >> 5) + ((*color & 0x10) >> 1);
+ }
+ else
+ {
+ *code |= ((*color & 0x01) << 8) | ((*color & 0x18) << 6) | (bank << 11);
+ *color = layer_colorbase[layer] + ((*color & 0xe0) >> 5);
+ }
+}
+
+static void cuebrckj_tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ if (layer == 0)
+ {
+ *code |= ((*color & 0x01) << 8);
+ *color = layer_colorbase[layer] + ((*color & 0x80) >> 5) + ((*color & 0x10) >> 1);
+ }
+ else
+ {
+ *code |= ((*color & 0xf) << 8);
+ *color = layer_colorbase[layer] + ((*color & 0xe0) >> 5);
+ }
+}
+
+static void tmnt_tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ *code |= ((*color & 0x03) << 8) | ((*color & 0x10) << 6) | ((*color & 0x0c) << 9)
+ | (bank << 13);
+ *color = layer_colorbase[layer] + ((*color & 0xe0) >> 5);
+}
+
+static void ssbl_tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ if (layer == 0)
+ {
+ *code |= ((*color & 0x03) << 8) | ((*color & 0x10) << 6) | ((*color & 0x0c) << 9)
+ | (bank << 13);
+ }
+ else
+ {
+ *code |= ((*color & 0x03) << 8) | ((*color & 0x10) << 6) | ((*color & 0x0c) << 9)
+ | (bank << 13);
+// mame_printf_debug("L%d: bank %d code %x color %x\n", layer, bank, *code, *color);
+ }
+
+ *color = layer_colorbase[layer] + ((*color & 0xe0) >> 5);
+}
+
+static int detatwin_rombank;
+
+static void detatwin_tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ /* (color & 0x02) is flip y handled internally by the 052109 */
+ *code |= ((*color & 0x01) << 8) | ((*color & 0x10) << 5) | ((*color & 0x0c) << 8)
+ | (bank << 12) | detatwin_rombank << 14;
+ *color = layer_colorbase[layer] + ((*color & 0xe0) >> 5);
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the K051960
+
+***************************************************************************/
+
+static void mia_sprite_callback(int *code,int *color,int *priority,int *shadow)
+{
+ *color = sprite_colorbase + (*color & 0x0f);
+}
+
+static void tmnt_sprite_callback(int *code,int *color,int *priority,int *shadow)
+{
+ *code |= (*color & 0x10) << 9;
+ *color = sprite_colorbase + (*color & 0x0f);
+}
+
+static void punkshot_sprite_callback(int *code,int *color,int *priority_mask,int *shadow)
+{
+ int pri = 0x20 | ((*color & 0x60) >> 2);
+ if (pri <= layerpri[2]) *priority_mask = 0;
+ else if (pri > layerpri[2] && pri <= layerpri[1]) *priority_mask = 0xf0;
+ else if (pri > layerpri[1] && pri <= layerpri[0]) *priority_mask = 0xf0|0xcc;
+ else *priority_mask = 0xf0|0xcc|0xaa;
+
+ *code |= (*color & 0x10) << 9;
+ *color = sprite_colorbase + (*color & 0x0f);
+}
+
+static void thndrx2_sprite_callback(int *code,int *color,int *priority_mask,int *shadow)
+{
+ int pri = 0x20 | ((*color & 0x60) >> 2);
+ if (pri <= layerpri[2]) *priority_mask = 0;
+ else if (pri > layerpri[2] && pri <= layerpri[1]) *priority_mask = 0xf0;
+ else if (pri > layerpri[1] && pri <= layerpri[0]) *priority_mask = 0xf0|0xcc;
+ else *priority_mask = 0xf0|0xcc|0xaa;
+
+ *color = sprite_colorbase + (*color & 0x0f);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K053245
+
+***************************************************************************/
+
+static void lgtnfght_sprite_callback(int *code,int *color,int *priority_mask)
+{
+ int pri = 0x20 | ((*color & 0x60) >> 2);
+ if (pri <= layerpri[2]) *priority_mask = 0;
+ else if (pri > layerpri[2] && pri <= layerpri[1]) *priority_mask = 0xf0;
+ else if (pri > layerpri[1] && pri <= layerpri[0]) *priority_mask = 0xf0|0xcc;
+ else *priority_mask = 0xf0|0xcc|0xaa;
+
+ *color = sprite_colorbase + (*color & 0x1f);
+}
+
+static void detatwin_sprite_callback(int *code,int *color,int *priority_mask)
+{
+#if 0
+if (input_code_pressed(KEYCODE_Q) && (*color & 0x20)) *color = rand();
+if (input_code_pressed(KEYCODE_W) && (*color & 0x40)) *color = rand();
+if (input_code_pressed(KEYCODE_E) && (*color & 0x80)) *color = rand();
+#endif
+ int pri = 0x20 | ((*color & 0x60) >> 2);
+ if (pri <= layerpri[2]) *priority_mask = 0;
+ else if (pri > layerpri[2] && pri <= layerpri[1]) *priority_mask = 0xf0;
+ else if (pri > layerpri[1] && pri <= layerpri[0]) *priority_mask = 0xf0|0xcc;
+ else *priority_mask = 0xf0|0xcc|0xaa;
+
+ *color = sprite_colorbase + (*color & 0x1f);
+}
+
+static void prmrsocr_sprite_callback(int *code,int *color,int *priority_mask)
+{
+ int pri = 0x20 | ((*color & 0x60) >> 2);
+ if (pri <= layerpri[2]) *priority_mask = 0;
+ else if (pri > layerpri[2] && pri <= layerpri[1]) *priority_mask = 0xf0;
+ else if (pri > layerpri[1] && pri <= layerpri[0]) *priority_mask = 0xf0|0xcc;
+ else *priority_mask = 0xf0|0xcc|0xaa;
+
+ *code |= prmrsocr_sprite_bank << 14;
+
+ *color = sprite_colorbase + (*color & 0x1f);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( mia )
+{
+ layer_colorbase[0] = 0;
+ layer_colorbase[1] = 32;
+ layer_colorbase[2] = 40;
+ sprite_colorbase = 16;
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,mia_tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,REVERSE_PLANE_ORDER,mia_sprite_callback);
+}
+
+VIDEO_START( cuebrckj )
+{
+ layer_colorbase[0] = 0;
+ layer_colorbase[1] = 32;
+ layer_colorbase[2] = 40;
+ sprite_colorbase = 16;
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,cuebrckj_tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,REVERSE_PLANE_ORDER,mia_sprite_callback);
+}
+
+VIDEO_START( tmnt )
+{
+ layer_colorbase[0] = 0;
+ layer_colorbase[1] = 32;
+ layer_colorbase[2] = 40;
+ sprite_colorbase = 16;
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tmnt_tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,REVERSE_PLANE_ORDER,tmnt_sprite_callback);
+}
+
+VIDEO_START( punkshot )
+{
+ K053251_vh_start();
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tmnt_tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,NORMAL_PLANE_ORDER,punkshot_sprite_callback);
+}
+
+VIDEO_START( lgtnfght ) /* also tmnt2, ssriders */
+{
+ K053251_vh_start();
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tmnt_tile_callback);
+ K053245_vh_start(machine,0, REGION_GFX2,NORMAL_PLANE_ORDER,lgtnfght_sprite_callback);
+
+ K05324x_set_z_rejection(0);
+
+ dim_c = dim_v = lastdim = lasten = 0;
+
+ state_save_register_global(dim_c);
+ state_save_register_global(dim_v);
+ state_save_register_global(lastdim);
+ state_save_register_global(lasten);
+}
+
+VIDEO_START( sunsetbl )
+{
+ K053251_vh_start();
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,ssbl_tile_callback);
+ K053245_vh_start(machine,0, REGION_GFX2,NORMAL_PLANE_ORDER,lgtnfght_sprite_callback);
+}
+
+VIDEO_START( detatwin )
+{
+ K053251_vh_start();
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,detatwin_tile_callback);
+ K053245_vh_start(machine,0, REGION_GFX2,NORMAL_PLANE_ORDER,detatwin_sprite_callback);
+}
+
+VIDEO_START( glfgreat )
+{
+ K053251_vh_start();
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tmnt_tile_callback);
+ K053245_vh_start(machine,0, REGION_GFX2,NORMAL_PLANE_ORDER,lgtnfght_sprite_callback);
+
+ roz_tilemap = tilemap_create(glfgreat_get_roz_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,512,512);
+
+ tilemap_set_transparent_pen(roz_tilemap,0);
+
+ K053936_wraparound_enable(0, 1);
+ K053936_set_offset(0, 85, 0);
+}
+
+VIDEO_START( thndrx2 )
+{
+ K053251_vh_start();
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tmnt_tile_callback);
+ K051960_vh_start(machine,REGION_GFX2,NORMAL_PLANE_ORDER,thndrx2_sprite_callback);
+}
+
+VIDEO_START( prmrsocr )
+{
+ K053251_vh_start();
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,tmnt_tile_callback);
+ K053245_vh_start(machine,0, REGION_GFX2,NORMAL_PLANE_ORDER,prmrsocr_sprite_callback);
+
+ roz_tilemap = tilemap_create(prmrsocr_get_roz_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,512,256);
+
+ tilemap_set_transparent_pen(roz_tilemap,0);
+
+ K053936_wraparound_enable(0, 0);
+ K053936_set_offset(0, 85, 1);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( tmnt_paletteram_word_w )
+{
+ COMBINE_DATA(paletteram16 + offset);
+ offset &= ~1;
+
+ data = (paletteram16[offset] << 8) | paletteram16[offset+1];
+ palette_set_color_rgb(Machine,offset / 2,pal5bit(data >> 0),pal5bit(data >> 5),pal5bit(data >> 10));
+}
+
+
+
+WRITE16_HANDLER( tmnt_0a0000_w )
+{
+ if (ACCESSING_LSB)
+ {
+ static int last;
+
+ /* bit 0/1 = coin counters */
+ coin_counter_w(0,data & 0x01);
+ coin_counter_w(1,data & 0x02); /* 2 players version */
+
+ /* bit 3 high then low triggers irq on sound CPU */
+ if (last == 0x08 && (data & 0x08) == 0)
+ cpunum_set_input_line_and_vector(1,0,HOLD_LINE,0xff);
+
+ last = data & 0x08;
+
+ /* bit 5 = irq enable */
+ interrupt_enable_w(0,data & 0x20);
+
+ /* bit 7 = enable char ROM reading through the video RAM */
+ K052109_set_RMRD_line((data & 0x80) ? ASSERT_LINE : CLEAR_LINE);
+
+ /* other bits unused */
+ }
+}
+
+WRITE16_HANDLER( punkshot_0a0020_w )
+{
+ if (ACCESSING_LSB)
+ {
+ static int last;
+
+
+ /* bit 0 = coin counter */
+ coin_counter_w(0,data & 0x01);
+
+ /* bit 2 = trigger irq on sound CPU */
+ if (last == 0x04 && (data & 0x04) == 0)
+ cpunum_set_input_line_and_vector(1,0,HOLD_LINE,0xff);
+
+ last = data & 0x04;
+
+ /* bit 3 = enable char ROM reading through the video RAM */
+ K052109_set_RMRD_line((data & 0x08) ? ASSERT_LINE : CLEAR_LINE);
+ }
+}
+
+WRITE16_HANDLER( lgtnfght_0a0018_w )
+{
+ if (ACCESSING_LSB)
+ {
+ static int last;
+
+
+ /* bit 0,1 = coin counter */
+ coin_counter_w(0,data & 0x01);
+ coin_counter_w(1,data & 0x02);
+
+ /* bit 2 = trigger irq on sound CPU */
+ if (last == 0x00 && (data & 0x04) == 0x04)
+ cpunum_set_input_line_and_vector(1,0,HOLD_LINE,0xff);
+
+ last = data & 0x04;
+
+ /* bit 3 = enable char ROM reading through the video RAM */
+ K052109_set_RMRD_line((data & 0x08) ? ASSERT_LINE : CLEAR_LINE);
+ }
+}
+
+WRITE16_HANDLER( detatwin_700300_w )
+{
+ if (ACCESSING_LSB)
+ {
+ /* bit 0,1 = coin counter */
+ coin_counter_w(0,data & 0x01);
+ coin_counter_w(1,data & 0x02);
+
+ /* bit 3 = enable char ROM reading through the video RAM */
+ K052109_set_RMRD_line((data & 0x08) ? ASSERT_LINE : CLEAR_LINE);
+
+ /* bit 7 = select char ROM bank */
+ if (detatwin_rombank != ((data & 0x80) >> 7))
+ {
+ detatwin_rombank = (data & 0x80) >> 7;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ /* other bits unknown */
+ }
+}
+
+
+READ16_HANDLER( glfgreat_rom_r )
+{
+ if (glfgreat_roz_rom_mode)
+ return memory_region(REGION_GFX3)[glfgreat_roz_char_bank * 0x80000 + offset];
+ else if (offset < 0x40000)
+ return memory_region(REGION_USER1)[offset + 0x80000 + glfgreat_roz_rom_bank * 0x40000] +
+ 256 * memory_region(REGION_USER1)[offset + glfgreat_roz_rom_bank * 0x40000];
+ else
+ return memory_region(REGION_USER1)[((offset & 0x3ffff) >> 2) + 0x100000 + glfgreat_roz_rom_bank * 0x10000];
+}
+
+WRITE16_HANDLER( glfgreat_122000_w )
+{
+ if (ACCESSING_LSB)
+ {
+ /* bit 0,1 = coin counter */
+ coin_counter_w(0,data & 0x01);
+ coin_counter_w(1,data & 0x02);
+
+ /* bit 4 = enable char ROM reading through the video RAM */
+ K052109_set_RMRD_line((data & 0x10) ? ASSERT_LINE : CLEAR_LINE);
+
+ /* bit 5 = 53596 tile rom bank selection */
+ if (glfgreat_roz_rom_bank != (data & 0x20) >> 5)
+ {
+ glfgreat_roz_rom_bank = (data & 0x20) >> 5;
+ tilemap_mark_all_tiles_dirty(roz_tilemap);
+ }
+
+ /* bit 6,7 = 53596 char bank selection for ROM test */
+ glfgreat_roz_char_bank = (data & 0xc0) >> 6;
+
+ /* other bits unknown */
+ }
+ if (ACCESSING_MSB)
+ {
+ /* bit 8 = 53596 char/rom selection for ROM test */
+ glfgreat_roz_rom_mode = data & 0x100;
+ }
+}
+
+
+WRITE16_HANDLER( ssriders_eeprom_w )
+{
+ if (ACCESSING_LSB)
+ {
+ /* bit 0 is data */
+ /* bit 1 is cs (active low) */
+ /* bit 2 is clock (active high) */
+ EEPROM_write_bit(data & 0x01);
+ EEPROM_set_cs_line((data & 0x02) ? CLEAR_LINE : ASSERT_LINE);
+ EEPROM_set_clock_line((data & 0x04) ? ASSERT_LINE : CLEAR_LINE);
+
+ /* bits 3-4 control palette dimming */
+ /* 4 = DIMPOL = when set, negate SHAD */
+ /* 3 = DIMMOD = when set, or BRIT with [negated] SHAD */
+ dim_c = data & 0x18;
+
+ /* bit 5 selects sprite ROM for testing in TMNT2 (bits 5-7, actually, according to the schematics) */
+ K053244_bankselect(0, ((data & 0x20) >> 5) << 2);
+ }
+}
+
+WRITE16_HANDLER( ssriders_1c0300_w )
+{
+ if (ACCESSING_LSB)
+ {
+ /* bit 0,1 = coin counter */
+ coin_counter_w(0,data & 0x01);
+ coin_counter_w(1,data & 0x02);
+
+ /* bit 3 = enable char ROM reading through the video RAM */
+ K052109_set_RMRD_line((data & 0x08) ? ASSERT_LINE : CLEAR_LINE);
+
+ /* bits 4-6 control palette dimming (DIM0-DIM2) */
+ dim_v = (data & 0x70) >> 4;
+ }
+}
+
+WRITE16_HANDLER( prmrsocr_122000_w )
+{
+ if (ACCESSING_LSB)
+ {
+ /* bit 0,1 = coin counter */
+ coin_counter_w(0,data & 0x01);
+ coin_counter_w(1,data & 0x02);
+
+ /* bit 4 = enable char ROM reading through the video RAM */
+ K052109_set_RMRD_line((data & 0x10) ? ASSERT_LINE : CLEAR_LINE);
+
+ /* bit 6 = sprite ROM bank */
+ prmrsocr_sprite_bank = (data & 0x40) >> 6;
+ K053244_bankselect(0, prmrsocr_sprite_bank << 2);
+
+ /* bit 7 = 53596 region selector for ROM test */
+ glfgreat_roz_char_bank = (data & 0x80) >> 7;
+
+ /* other bits unknown (unused?) */
+ }
+}
+
+READ16_HANDLER( prmrsocr_rom_r )
+{
+ if(glfgreat_roz_char_bank)
+ return memory_region(REGION_GFX3)[offset];
+ else
+ return 256 * memory_region(REGION_USER1)[offset] + memory_region(REGION_USER1)[offset + 0x020000];
+}
+
+WRITE16_HANDLER( tmnt_priority_w )
+{
+ if (ACCESSING_LSB)
+ {
+ /* bit 2/3 = priority; other bits unused */
+ /* bit2 = PRI bit3 = PRI2
+ sprite/playfield priority is controlled by these two bits, by bit 3
+ of the background tile color code, and by the SHADOW sprite
+ attribute bit.
+ Priorities are encoded in a PROM (G19 for TMNT). However, in TMNT,
+ the PROM only takes into account the PRI and SHADOW bits.
+ PRI Priority
+ 0 bg fg spr text
+ 1 bg spr fg text
+ The SHADOW bit, when set, torns a sprite into a shadow which makes
+ color below it darker (this is done by turning off three resistors
+ in parallel with the RGB output).
+
+ Note: the background color (color used when all of the four layers
+ are 0) is taken from the *foreground* palette, not the background
+ one as would be more intuitive.
+ */
+ priorityflag = (data & 0x0c) >> 2;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+/* useful function to sort the three tile layers by priority order */
+static void sortlayers(int *layer,int *pri)
+{
+#define SWAP(a,b) \
+ if (pri[a] < pri[b]) \
+ { \
+ int t; \
+ t = pri[a]; pri[a] = pri[b]; pri[b] = t; \
+ t = layer[a]; layer[a] = layer[b]; layer[b] = t; \
+ }
+
+ SWAP(0,1)
+ SWAP(0,2)
+ SWAP(1,2)
+}
+
+VIDEO_UPDATE( mia )
+{
+ K052109_tilemap_update();
+
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],TILEMAP_DRAW_OPAQUE,0);
+ if ((priorityflag & 1) == 1) K051960_sprites_draw(bitmap,cliprect,0,0);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],0,0);
+ if ((priorityflag & 1) == 0) K051960_sprites_draw(bitmap,cliprect,0,0);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( tmnt )
+{
+ K052109_tilemap_update();
+
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[2],TILEMAP_DRAW_OPAQUE,0);
+ if ((priorityflag & 1) == 1) K051960_sprites_draw(bitmap,cliprect,0,0);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[1],0,0);
+ if ((priorityflag & 1) == 0) K051960_sprites_draw(bitmap,cliprect,0,0);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[0],0,0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( punkshot )
+{
+ bg_colorbase = K053251_get_palette_index(K053251_CI0);
+ sprite_colorbase = K053251_get_palette_index(K053251_CI1);
+ layer_colorbase[0] = K053251_get_palette_index(K053251_CI2);
+ layer_colorbase[1] = K053251_get_palette_index(K053251_CI4);
+ layer_colorbase[2] = K053251_get_palette_index(K053251_CI3);
+
+ K052109_tilemap_update();
+
+ sorted_layer[0] = 0;
+ layerpri[0] = K053251_get_priority(K053251_CI2);
+ sorted_layer[1] = 1;
+ layerpri[1] = K053251_get_priority(K053251_CI4);
+ sorted_layer[2] = 2;
+ layerpri[2] = K053251_get_priority(K053251_CI3);
+
+ sortlayers(sorted_layer,layerpri);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[sorted_layer[0]],TILEMAP_DRAW_OPAQUE,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[sorted_layer[1]],0,2);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[sorted_layer[2]],0,4);
+
+ K051960_sprites_draw(bitmap,cliprect,-1,-1);
+ return 0;
+}
+
+
+VIDEO_UPDATE( lgtnfght )
+{
+ bg_colorbase = K053251_get_palette_index(K053251_CI0);
+ sprite_colorbase = K053251_get_palette_index(K053251_CI1);
+ layer_colorbase[0] = K053251_get_palette_index(K053251_CI2);
+ layer_colorbase[1] = K053251_get_palette_index(K053251_CI4);
+ layer_colorbase[2] = K053251_get_palette_index(K053251_CI3);
+
+ K052109_tilemap_update();
+
+ sorted_layer[0] = 0;
+ layerpri[0] = K053251_get_priority(K053251_CI2);
+ sorted_layer[1] = 1;
+ layerpri[1] = K053251_get_priority(K053251_CI4);
+ sorted_layer[2] = 2;
+ layerpri[2] = K053251_get_priority(K053251_CI3);
+
+ sortlayers(sorted_layer,layerpri);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[16 * bg_colorbase],cliprect);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[sorted_layer[0]],0,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[sorted_layer[1]],0,2);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[sorted_layer[2]],0,4);
+
+ K053245_sprites_draw(0, bitmap,cliprect);
+ return 0;
+}
+
+static int glfgreat_pixel;
+
+READ16_HANDLER( glfgreat_ball_r )
+{
+#ifdef MAME_DEBUG
+popmessage("%04x",glfgreat_pixel);
+#endif
+ /* if out of the ROZ layer palette range, it's in the water - return 0 */
+ if (glfgreat_pixel < 0x400 || glfgreat_pixel >= 0x500) return 0;
+ else return glfgreat_pixel & 0xff;
+}
+
+VIDEO_UPDATE( glfgreat )
+{
+ K053251_set_tilemaps(NULL,NULL,K052109_tilemap[0],K052109_tilemap[1],K052109_tilemap[2]);
+
+ bg_colorbase = K053251_get_palette_index(K053251_CI0);
+ sprite_colorbase = K053251_get_palette_index(K053251_CI1);
+ layer_colorbase[0] = K053251_get_palette_index(K053251_CI2);
+ layer_colorbase[1] = K053251_get_palette_index(K053251_CI3) + 8; /* weird... */
+ layer_colorbase[2] = K053251_get_palette_index(K053251_CI4);
+
+ K052109_tilemap_update();
+
+ sorted_layer[0] = 0;
+ layerpri[0] = K053251_get_priority(K053251_CI2);
+ sorted_layer[1] = 1;
+ layerpri[1] = K053251_get_priority(K053251_CI3);
+ sorted_layer[2] = 2;
+ layerpri[2] = K053251_get_priority(K053251_CI4);
+
+ sortlayers(sorted_layer,layerpri);
+
+ /* not sure about the 053936 priority, but it seems to work */
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[16 * bg_colorbase],cliprect);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[sorted_layer[0]],0,1);
+ if (layerpri[0] >= 0x30 && layerpri[1] < 0x30)
+ {
+ K053936_0_zoom_draw(bitmap,cliprect,roz_tilemap,0,1);
+ glfgreat_pixel = *BITMAP_ADDR16(bitmap,0x80,0x105);
+ }
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[sorted_layer[1]],0,2);
+ if (layerpri[1] >= 0x30 && layerpri[2] < 0x30)
+ {
+ K053936_0_zoom_draw(bitmap,cliprect,roz_tilemap,0,1);
+ glfgreat_pixel = *BITMAP_ADDR16(bitmap,0x80,0x105);
+ }
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[sorted_layer[2]],0,4);
+ if (layerpri[2] >= 0x30)
+ {
+ K053936_0_zoom_draw(bitmap,cliprect,roz_tilemap,0,1);
+ glfgreat_pixel = *BITMAP_ADDR16(bitmap,0x80,0x105);
+ }
+
+ K053245_sprites_draw(0, bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( tmnt2 )
+{
+ double brt;
+ int i, newdim, newen, cb, ce;
+
+ newdim = dim_v | ((~dim_c & 0x10) >> 1);
+ newen = (K053251_get_priority(5) && K053251_get_priority(5) != 0x3e);
+
+ if (newdim != lastdim || newen != lasten)
+ {
+ brt = 1.0;
+ if (newen) brt -= (1.0-PALETTE_DEFAULT_SHADOW_FACTOR)*newdim/8;
+ lastdim = newdim;
+ lasten = newen;
+
+ /*
+ Only affect the background and sprites, not text layer.
+ Instead of dimming each layer we dim the entire palette
+ except text colors because palette bases may change
+ anytime and there's no guarantee a dimmed color will be
+ reset properly.
+ */
+
+ // find the text layer's palette range
+ cb = layer_colorbase[sorted_layer[2]] << 4;
+ ce = cb + 128;
+
+ // dim all colors before it
+ for (i=0; i<cb; i++)
+ palette_set_brightness(machine,i,brt);
+
+ // reset all colors in range
+ for (i=cb; i<ce; i++)
+ palette_set_brightness(machine,i,1.0);
+
+ // dim all colors after it
+ for (i=ce; i<2048; i++)
+ palette_set_brightness(machine,i,brt);
+
+ // toggle shadow/highlight
+ if (~dim_c & 0x10)
+ palette_set_shadow_mode(machine, 1);
+ else
+ palette_set_shadow_mode(machine, 0);
+ }
+
+ video_update_lgtnfght(machine,screen,bitmap,cliprect);
+ return 0;
+}
+
+
+VIDEO_UPDATE( thndrx2 )
+{
+ bg_colorbase = K053251_get_palette_index(K053251_CI0);
+ sprite_colorbase = K053251_get_palette_index(K053251_CI1);
+ layer_colorbase[0] = K053251_get_palette_index(K053251_CI2);
+ layer_colorbase[1] = K053251_get_palette_index(K053251_CI4);
+ layer_colorbase[2] = K053251_get_palette_index(K053251_CI3);
+
+ K052109_tilemap_update();
+
+ sorted_layer[0] = 0;
+ layerpri[0] = K053251_get_priority(K053251_CI2);
+ sorted_layer[1] = 1;
+ layerpri[1] = K053251_get_priority(K053251_CI4);
+ sorted_layer[2] = 2;
+ layerpri[2] = K053251_get_priority(K053251_CI3);
+
+ sortlayers(sorted_layer,layerpri);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[16 * bg_colorbase],cliprect);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[sorted_layer[0]],0,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[sorted_layer[1]],0,2);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[sorted_layer[2]],0,4);
+
+ K051960_sprites_draw(bitmap,cliprect,-1,-1);
+ return 0;
+}
+
+
+
+/***************************************************************************
+
+ Housekeeping
+
+***************************************************************************/
+
+VIDEO_EOF( detatwin )
+{
+ K053245_clear_buffer(0);
+}
diff --git a/src/mame/video/tnzs.c b/src/mame/video/tnzs.c
new file mode 100644
index 00000000000..d942cce0169
--- /dev/null
+++ b/src/mame/video/tnzs.c
@@ -0,0 +1,236 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+#include "driver.h"
+#include "includes/tnzs.h"
+#include <ctype.h>
+
+
+
+static int tnzs_screenflip;
+
+/***************************************************************************
+
+ The New Zealand Story doesn't have a color PROM. It uses 1024 bytes of RAM
+ to dynamically create the palette. Each couple of bytes defines one
+ color (15 bits per pixel; the top bit of the second byte is unused).
+ Since the graphics use 4 bitplanes, hence 16 colors, this makes for 32
+ different color codes.
+
+***************************************************************************/
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Arkanoid has a two 512x8 palette PROMs. The two bytes joined together
+ form 512 xRRRRRGGGGGBBBBB color values.
+
+***************************************************************************/
+PALETTE_INIT( arknoid2 )
+{
+ int i,col;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ col = (color_prom[i]<<8)+color_prom[i+512];
+ palette_set_color_rgb(machine,i,pal5bit(col >> 10),pal5bit(col >> 5),pal5bit(col >> 0));
+ }
+}
+
+
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT8 *m)
+{
+ int x,y,column,tot,flag;
+ int scrollx, scrolly;
+ UINT32 upperbits;
+ int ctrl2 = tnzs_objctrl[1];
+
+
+ if ((ctrl2 ^ (~ctrl2<<1)) & 0x40)
+ {
+ m += 0x800;
+ }
+
+ if(tnzs_bg_flag[0] & 0x80)
+ flag = TRANSPARENCY_NONE;
+ else
+ flag = TRANSPARENCY_PEN;
+
+
+ /* The byte at f200 is the y-scroll value for the first column.
+ The byte at f204 is the LSB of x-scroll value for the first column.
+
+ The other columns follow at 16-byte intervals.
+
+ The 9th bit of each x-scroll value is combined into 2 bytes
+ at f302-f303 */
+
+ /* f301 controls how many columns are drawn. */
+ tot = tnzs_objctrl[1] & 0x1f;
+ if (tot == 1) tot = 16;
+
+ upperbits = tnzs_objctrl[2] + tnzs_objctrl[3] * 256;
+
+ for (column = 0;column < tot;column++)
+ {
+ scrollx = tnzs_scrollram[column*16+4] - ((upperbits & 0x01) * 256);
+ if (tnzs_screenflip)
+ scrolly = tnzs_scrollram[column*16] + 1 - 256;
+ else
+ scrolly = -tnzs_scrollram[column*16] + 1;
+
+ for (y=0;y<16;y++)
+ {
+ for (x=0;x<2;x++)
+ {
+ int code,color,flipx,flipy,sx,sy;
+ int i = 32*(column^8) + 2*y + x;
+
+
+ code = m[i] + ((m[i + 0x1000] & 0x3f) << 8);
+ color = (m[i + 0x1200] & 0xf8) >> 3; /* colours at d600-d7ff */
+ sx = x*16;
+ sy = y*16;
+ flipx = m[i + 0x1000] & 0x80;
+ flipy = m[i + 0x1000] & 0x40;
+ if (tnzs_screenflip)
+ {
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ sx + scrollx,(sy + scrolly) & 0xff,
+ cliprect,flag,0);
+
+ /* wrap around x */
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ sx + 512 + scrollx,(sy + scrolly) & 0xff,
+ cliprect,flag,0);
+ }
+ }
+
+
+ upperbits >>= 1;
+ }
+}
+
+
+static void draw_foreground(running_machine *machine,
+ mame_bitmap *bitmap,
+ const rectangle *cliprect,
+ UINT8 *char_pointer,
+ UINT8 *x_pointer,
+ UINT8 *y_pointer,
+ UINT8 *ctrl_pointer,
+ UINT8 *color_pointer)
+{
+ int i;
+ int ctrl2 = tnzs_objctrl[1];
+
+
+ if ((ctrl2 ^ (~ctrl2<<1)) & 0x40)
+ {
+ char_pointer += 0x800;
+ x_pointer += 0x800;
+ ctrl_pointer += 0x800;
+ color_pointer += 0x800;
+ }
+
+
+ /* Draw all 512 sprites */
+ for (i=0x1ff;i >= 0;i--)
+ {
+ int code,color,sx,sy,flipx,flipy;
+
+ code = char_pointer[i] + ((ctrl_pointer[i] & 0x3f) << 8);
+ color = (color_pointer[i] & 0xf8) >> 3;
+ sx = x_pointer[i] - ((color_pointer[i] & 1) << 8);
+ sy = 240 - y_pointer[i];
+ flipx = ctrl_pointer[i] & 0x80;
+ flipy = ctrl_pointer[i] & 0x40;
+ if (tnzs_screenflip)
+ {
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ /* hack to hide Chuka Taisens grey line, top left corner */
+ if ((sy == 0) && (code == 0)) sy += 240;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy+2,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ /* wrap around x */
+ drawgfx(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ sx + 512,sy+2,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+VIDEO_UPDATE( tnzs )
+{
+ /* If the byte at f300 has bit 6 set, flip the screen
+ (I'm not 100% sure about this) */
+ tnzs_screenflip = (tnzs_objctrl[0] & 0x40) >> 6;
+
+
+ /* Fill the background */
+ fillbitmap(bitmap, machine->pens[0x1f0], cliprect);
+
+ /* Redraw the background tiles (c400-c5ff) */
+ draw_background(machine, bitmap, cliprect, tnzs_objram + 0x400);
+
+ /* Draw the sprites on top */
+ draw_foreground(machine, bitmap, cliprect,
+ tnzs_objram + 0x0000, /* chars : c000 */
+ tnzs_objram + 0x0200, /* x : c200 */
+ tnzs_vdcram + 0x0000, /* y : f000 */
+ tnzs_objram + 0x1000, /* ctrl : d000 */
+ tnzs_objram + 0x1200); /* color : d200 */
+ return 0;
+}
+
+VIDEO_EOF( tnzs )
+{
+ int ctrl2 = tnzs_objctrl[1];
+ if (~ctrl2 & 0x20)
+ {
+ // note I copy sprites only. seta.c also copies the "floating tilemap"
+ if (ctrl2 & 0x40)
+ {
+ memcpy(&tnzs_objram[0x0000],&tnzs_objram[0x0800],0x0400);
+ memcpy(&tnzs_objram[0x1000],&tnzs_objram[0x1800],0x0400);
+ }
+ else
+ {
+ memcpy(&tnzs_objram[0x0800],&tnzs_objram[0x0000],0x0400);
+ memcpy(&tnzs_objram[0x1800],&tnzs_objram[0x1000],0x0400);
+ }
+
+ // and I copy the "floating tilemap" BACKWARDS - this fixes kabukiz
+ memcpy(&tnzs_objram[0x0400],&tnzs_objram[0x0c00],0x0400);
+ memcpy(&tnzs_objram[0x1400],&tnzs_objram[0x1c00],0x0400);
+ }
+}
diff --git a/src/mame/video/toaplan1.c b/src/mame/video/toaplan1.c
new file mode 100644
index 00000000000..8de69a24f43
--- /dev/null
+++ b/src/mame/video/toaplan1.c
@@ -0,0 +1,1246 @@
+/***************************************************************************
+
+ Functions to emulate the video hardware of some Toaplan games,
+ which use the BCU-2 tile controller, and the FCU-2 Sprite controller -
+ and SCU Sprite controller (Only Rally Bike uses the SCU controller).
+
+
+ There are 4 scrolling layers of graphics, stored in planes of 64x64 tiles.
+ Each tile in each plane is assigned a priority between 1 and 15, higher
+ numbers have greater priority.
+
+ BCU controller. Each tile takes up 32 bits - the format is:
+
+ 0 1 2 3
+ ---- ---- ---- ---- -ttt tttt tttt tttt = Tile number (0 - $7fff)
+ ---- ---- ---- ---- h--- ---- ---- ---- = Hidden
+ ---- ---- --cc cccc ---- ---- ---- ---- = Color (0 - $3f)
+ pppp ---- ---- ---- ---- ---- ---- ---- = Priority (0-$f)
+ ---- ???? ??-- ---- ---- ---- ---- ---- = Unknown / Unused
+
+ Scroll Reg
+
+ 0 1 2 3
+ xxxx xxxx x--- ---- ---- ---- ---- ---- = X position
+ ---- ---- ---- ---- yyyy yyyy y--- ---- = Y position
+ ---- ---- -??? ???? ---- ---- -??? ???? = Unknown / Unused
+
+
+
+ FCU controller. Sprite RAM format (except Rally Bike)
+
+ 0 1 2 3
+ -sss ssss ssss ssss ---- ---- ---- ---- = Sprite number (0 - $7fff)
+ h--- ---- ---- ---- ---- ---- ---- ---- = Hidden
+ ---- ---- ---- ---- ---- ---- --cc cccc = Color (0 - $3f)
+ ---- ---- ---- ---- ---- dddd dd-- ---- = Dimension (pointer to Size RAM)
+ ---- ---- ---- ---- pppp ---- ---- ---- = Priority (0-$f)
+
+ 4 5 6 7
+ ---- ---- ---- ---- xxxx xxxx x--- ---- = X position
+ yyyy yyyy y--- ---- ---- ---- ---- ---- = Y position
+ ---- ---- -??? ???? ---- ---- -??? ???? = Unknown
+
+
+
+ SCU controller. Sprite RAM format (Rally Bike)
+
+ 0 1 2 3
+ ---- -sss ssss ssss ---- ---- ---- ---- = Sprite number (0 - $7FF)
+ ---- ---- ---- ---- ---- ---- --cc cccc = Color (0 - $3F)
+ ---- ---- ---- ---- ---- ---x ---- ---- = Flip X
+ ---- ---- ---- ---- ---- --y- ---- ---- = Flip Y
+ ---- ---- ---- ---- ---- pp-- ---- ---- = Priority (0h,4h,8h,Ch (shifted < 2 places))
+ ???? ?--- ---- ---- ???? ---- ??-- ---- = Unknown / Unused
+
+ 4 5 6 7
+ xxxx xxxx x--- ---- ---- ---- ---- ---- = X position
+ ---- ---- ---- ---- yyyy yyyy y--- ---- = Y position
+ ---- ---- -??? ???? ---- ---- -??? ???? = Unknown
+
+
+
+ The tiles use a palette of 1024 colors, the sprites use a different palette
+ of 1024 colors.
+
+
+ BCU Controller writes Tile Offsets
+ Game reg0 reg1 reg2 reg3 X Y flip-X flip-Y
+RallyBik 41e0 2e1e 148c 0f09 01e6 00fc <- same --
+Truxton 41e0 2717 0e86 0c06 01b7 00f2 0188 01fd
+HellFire 41e0 2717 0e86 0c06 01b7 0102 0188 000d
+ZeroWing 41e0 2717 0e86 0c06 01b7 0102 0188 000d
+DemonWld 41e0 2e1e 148c 0f09 01a9 00fc 0196 0013
+FireShrk 41e0 2717 0e86 0c06 01b7 00f2 0188 01fd
+Out-Zone 41e0 2e1e 148c 0f09 01a9 00ec 0196 0003
+Vimana 41e0 2717 0e86 0c06 01b7 00f2 0188 01fd
+
+
+Sprites are of varying sizes between 8x8 and 128x128 with any variation
+in between, in multiples of 8 either way.
+Here we draw the first 8x8 part of the sprite, then by using the sprite
+dimensions, we draw the rest of the 8x8 parts to produce the complete
+sprite.
+
+
+Abnormalities:
+ The equations for flipscreen, don't suite the horizontal games. So a minor
+ hack is implemented for them, though it still isn't 100% right - see below.
+
+ How/when do priority 0 Tile layers really get displayed ?
+
+ What are the video PROMs for ? Priority maybe ?
+
+
+ ***** Notes on the horizontal game scroll Y probs (Eg, Zero Wing) *****
+
+ Scrolls PF1-X PF1-Y PF2-X PF2-Y PF3-X PF3-Y PF4-X PF4-Y
+ ------> #4180 #f880 #1240 #f880 #4380 #f880 #e380 #f880
+ -flip-> #1500 #7f00 #e8c0 #7f00 #1300 #7f00 #bb00 #7f00
+
+ ------> #4100 #f880 #1200 #7880 #4300 #f880 #e380 #f880
+ -flip-> #1500 #7f00 #e8c0 #8580?? #1300 #7f00 #bb00 #7f00
+ |
+ |
+ f880 = 1111 1000 1000 = 1f1 scroll
+ 7f00 - 0111 1111 0000 = 0fe scroll
+ 7880 = 0111 1000 1000 = 0f1 scroll
+ 8580 = 1000 0101 1000 = 10b scroll
+
+ So a snapshot of the scroll equations become (from the functions below):
+ 1f1 - (102 - 10f) == 1fe star background
+ 0Fe - (00d - 10f) == 200 star background (flipscreen)
+ 0f1 - (102 - 10f) == 0fe red background
+ 10B - (00d - 10f) == 20d red background (flipscreen) wrong!
+ 10B - (00d - 002) == 100 red background (flipscreen) should equate to this (100)
+
+
+***************************************************************************/
+
+
+#include "driver.h"
+#include "toaplan1.h"
+#include "cpu/m68000/m68000.h"
+
+
+#define TOAPLAN1_TILEVRAM_SIZE 0x4000 /* 4 tile layers each this RAM size */
+#define TOAPLAN1_SPRITERAM_SIZE 0x800 /* sprite ram */
+#define TOAPLAN1_SPRITESIZERAM_SIZE 0x80 /* sprite size ram */
+
+static UINT16 *pf4_tilevram16; /* || Drawn in this order */
+static UINT16 *pf3_tilevram16; /* || */
+static UINT16 *pf2_tilevram16; /* \||/ */
+static UINT16 *pf1_tilevram16; /* \/ */
+
+static UINT16 *toaplan1_spritesizeram16;
+static UINT16 *toaplan1_buffered_spritesizeram16;
+
+size_t toaplan1_colorram1_size;
+size_t toaplan1_colorram2_size;
+UINT16 *toaplan1_colorram1;
+UINT16 *toaplan1_colorram2;
+
+static INT32 bcu_flipscreen; /* Tile controller flip flag */
+static INT32 fcu_flipscreen; /* Sprite controller flip flag */
+
+static INT32 pf_voffs;
+static INT32 spriteram_offs;
+
+static INT32 pf1_scrollx;
+static INT32 pf1_scrolly;
+static INT32 pf2_scrollx;
+static INT32 pf2_scrolly;
+static INT32 pf3_scrollx;
+static INT32 pf3_scrolly;
+static INT32 pf4_scrollx;
+static INT32 pf4_scrolly;
+static INT32 scrollx_offs1;
+static INT32 scrollx_offs2;
+static INT32 scrollx_offs3;
+static INT32 scrollx_offs4;
+static INT32 scrolly_offs;
+
+
+#ifdef MAME_DEBUG
+static int display_pf1 = 1;
+static int display_pf2 = 1;
+static int display_pf3 = 1;
+static int display_pf4 = 1;
+static int displog = 0;
+#endif
+
+static INT32 tiles_offsetx;
+static INT32 tiles_offsety;
+
+static int toaplan1_reset; /* Hack! See toaplan1_bcu_control below */
+
+static tilemap *pf1_tilemap, *pf2_tilemap, *pf3_tilemap, *pf4_tilemap;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_pf1_tile_info )
+{
+ int color, tile_number, attrib;
+
+ tile_number = pf1_tilevram16[2*tile_index+1] & 0x7fff;
+ attrib = pf1_tilevram16[2*tile_index];
+ color = attrib & 0x3f;
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ color,
+ 0);
+ if (pf1_tilevram16[2*tile_index+1] & 0x8000) tileinfo->category = 0;
+ else tileinfo->category = (attrib & 0xf000) >> 12;
+}
+
+static TILE_GET_INFO( get_pf2_tile_info )
+{
+ int color, tile_number, attrib;
+
+ tile_number = pf2_tilevram16[2*tile_index+1] & 0x7fff;
+ attrib = pf2_tilevram16[2*tile_index];
+ color = attrib & 0x3f;
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ color,
+ 0);
+ if (pf2_tilevram16[2*tile_index+1] & 0x8000) tileinfo->category = 0;
+ else tileinfo->category = (attrib & 0xf000) >> 12;
+}
+
+static TILE_GET_INFO( get_pf3_tile_info )
+{
+ int color, tile_number, attrib;
+
+ tile_number = pf3_tilevram16[2*tile_index+1] & 0x7fff;
+ attrib = pf3_tilevram16[2*tile_index];
+ color = attrib & 0x3f;
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ color,
+ 0);
+ if (pf3_tilevram16[2*tile_index+1] & 0x8000) tileinfo->category = 0;
+ else tileinfo->category = (attrib & 0xf000) >> 12;
+}
+
+static TILE_GET_INFO( get_pf4_tile_info )
+{
+ int color, tile_number, attrib;
+
+ tile_number = pf4_tilevram16[2*tile_index+1] & 0x7fff;
+ attrib = pf4_tilevram16[2*tile_index];
+ color = attrib & 0x3f;
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ color,
+ 0);
+ if (pf4_tilevram16[2*tile_index+1] & 0x8000) tileinfo->category = 0;
+ else tileinfo->category = (attrib & 0xf000) >> 12;
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+static void toaplan1_create_tilemaps(void)
+{
+ pf1_tilemap = tilemap_create(get_pf1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ pf2_tilemap = tilemap_create(get_pf2_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ pf3_tilemap = tilemap_create(get_pf3_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ pf4_tilemap = tilemap_create(get_pf4_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+
+ tilemap_set_transparent_pen(pf1_tilemap,0);
+ tilemap_set_transparent_pen(pf2_tilemap,0);
+ tilemap_set_transparent_pen(pf3_tilemap,0);
+ tilemap_set_transparent_pen(pf4_tilemap,0);
+}
+
+
+static void toaplan1_paletteram_alloc(void)
+{
+ paletteram16 = auto_malloc(toaplan1_colorram1_size + toaplan1_colorram2_size);
+}
+
+static void toaplan1_vram_alloc(void)
+{
+ pf1_tilevram16 = auto_malloc(TOAPLAN1_TILEVRAM_SIZE);
+ memset(pf1_tilevram16,0,TOAPLAN1_TILEVRAM_SIZE);
+
+ pf2_tilevram16 = auto_malloc(TOAPLAN1_TILEVRAM_SIZE);
+ memset(pf2_tilevram16,0,TOAPLAN1_TILEVRAM_SIZE);
+
+ pf3_tilevram16 = auto_malloc(TOAPLAN1_TILEVRAM_SIZE);
+ memset(pf3_tilevram16,0,TOAPLAN1_TILEVRAM_SIZE);
+
+ pf4_tilevram16 = auto_malloc(TOAPLAN1_TILEVRAM_SIZE);
+ memset(pf4_tilevram16,0,TOAPLAN1_TILEVRAM_SIZE);
+}
+
+static void toaplan1_spritevram_alloc(void)
+{
+ spriteram16 = auto_malloc(TOAPLAN1_SPRITERAM_SIZE);
+ memset(spriteram16,0,TOAPLAN1_SPRITERAM_SIZE);
+
+ buffered_spriteram16 = auto_malloc(TOAPLAN1_SPRITERAM_SIZE);
+ memset(buffered_spriteram16,0,TOAPLAN1_SPRITERAM_SIZE);
+
+ toaplan1_spritesizeram16 = auto_malloc(TOAPLAN1_SPRITESIZERAM_SIZE);
+ memset(toaplan1_spritesizeram16,0,TOAPLAN1_SPRITESIZERAM_SIZE);
+
+ toaplan1_buffered_spritesizeram16 = auto_malloc(TOAPLAN1_SPRITESIZERAM_SIZE);
+ memset(toaplan1_buffered_spritesizeram16,0,TOAPLAN1_SPRITESIZERAM_SIZE);
+
+ spriteram_size = TOAPLAN1_SPRITERAM_SIZE;
+}
+
+static void toaplan1_set_scrolls(void)
+{
+ tilemap_set_scrollx(pf1_tilemap,0,(pf1_scrollx >> 7) - (tiles_offsetx - scrollx_offs1));
+ tilemap_set_scrollx(pf2_tilemap,0,(pf2_scrollx >> 7) - (tiles_offsetx - scrollx_offs2));
+ tilemap_set_scrollx(pf3_tilemap,0,(pf3_scrollx >> 7) - (tiles_offsetx - scrollx_offs3));
+ tilemap_set_scrollx(pf4_tilemap,0,(pf4_scrollx >> 7) - (tiles_offsetx - scrollx_offs4));
+ tilemap_set_scrolly(pf1_tilemap,0,(pf1_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ tilemap_set_scrolly(pf2_tilemap,0,(pf2_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ tilemap_set_scrolly(pf3_tilemap,0,(pf3_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ tilemap_set_scrolly(pf4_tilemap,0,(pf4_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+}
+
+static void rallybik_flipscreen(void)
+{
+ rallybik_bcu_flipscreen_w(0, bcu_flipscreen, 0);
+}
+
+static void toaplan1_flipscreen(void)
+{
+ toaplan1_bcu_flipscreen_w(0, bcu_flipscreen, 0);
+}
+
+
+VIDEO_START( rallybik )
+{
+ toaplan1_create_tilemaps();
+ toaplan1_paletteram_alloc();
+ toaplan1_vram_alloc();
+
+ scrollx_offs1 = 0x0d + 6;
+ scrollx_offs2 = 0x0d + 4;
+ scrollx_offs3 = 0x0d + 2;
+ scrollx_offs4 = 0x0d + 0;
+ scrolly_offs = 0x111;
+
+ bcu_flipscreen = -1;
+ toaplan1_reset = 0;
+
+ state_save_register_global_pointer(paletteram16, (toaplan1_colorram1_size + toaplan1_colorram2_size)/2);
+ state_save_register_global_pointer(pf1_tilevram16, TOAPLAN1_TILEVRAM_SIZE/2);
+ state_save_register_global_pointer(pf2_tilevram16, TOAPLAN1_TILEVRAM_SIZE/2);
+ state_save_register_global_pointer(pf3_tilevram16, TOAPLAN1_TILEVRAM_SIZE/2);
+ state_save_register_global_pointer(pf4_tilevram16, TOAPLAN1_TILEVRAM_SIZE/2);
+
+ state_save_register_global(scrollx_offs1);
+ state_save_register_global(scrollx_offs2);
+ state_save_register_global(scrollx_offs3);
+ state_save_register_global(scrollx_offs4);
+ state_save_register_global(scrolly_offs);
+ state_save_register_global(bcu_flipscreen);
+ state_save_register_global(pf1_scrollx);
+ state_save_register_global(pf1_scrolly);
+ state_save_register_global(pf2_scrollx);
+ state_save_register_global(pf2_scrolly);
+ state_save_register_global(pf3_scrollx);
+ state_save_register_global(pf3_scrolly);
+ state_save_register_global(pf4_scrollx);
+ state_save_register_global(pf4_scrolly);
+ state_save_register_global(tiles_offsetx);
+ state_save_register_global(tiles_offsety);
+ state_save_register_global(pf_voffs);
+ state_save_register_global(spriteram_offs);
+
+ state_save_register_func_postload(rallybik_flipscreen);
+}
+
+VIDEO_START( toaplan1 )
+{
+ toaplan1_create_tilemaps();
+ toaplan1_paletteram_alloc();
+ toaplan1_vram_alloc();
+ toaplan1_spritevram_alloc();
+
+ scrollx_offs1 = 0x1ef + 6;
+ scrollx_offs2 = 0x1ef + 4;
+ scrollx_offs3 = 0x1ef + 2;
+ scrollx_offs4 = 0x1ef + 0;
+ scrolly_offs = 0x101;
+
+ bcu_flipscreen = -1;
+ fcu_flipscreen = 0;
+ toaplan1_reset = 1;
+
+ state_save_register_global_pointer(paletteram16, (toaplan1_colorram1_size + toaplan1_colorram2_size)/2);
+ state_save_register_global_pointer(pf1_tilevram16, TOAPLAN1_TILEVRAM_SIZE/2);
+ state_save_register_global_pointer(pf2_tilevram16, TOAPLAN1_TILEVRAM_SIZE/2);
+ state_save_register_global_pointer(pf3_tilevram16, TOAPLAN1_TILEVRAM_SIZE/2);
+ state_save_register_global_pointer(pf4_tilevram16, TOAPLAN1_TILEVRAM_SIZE/2);
+ state_save_register_global_pointer(spriteram16, TOAPLAN1_SPRITERAM_SIZE/2);
+ state_save_register_global_pointer(buffered_spriteram16, TOAPLAN1_SPRITERAM_SIZE/2);
+ state_save_register_global_pointer(toaplan1_spritesizeram16, TOAPLAN1_SPRITESIZERAM_SIZE/2);
+ state_save_register_global_pointer(toaplan1_buffered_spritesizeram16, TOAPLAN1_SPRITESIZERAM_SIZE/2);
+
+ state_save_register_global(scrollx_offs1);
+ state_save_register_global(scrollx_offs2);
+ state_save_register_global(scrollx_offs3);
+ state_save_register_global(scrollx_offs4);
+ state_save_register_global(scrolly_offs);
+ state_save_register_global(bcu_flipscreen);
+ state_save_register_global(fcu_flipscreen);
+ state_save_register_global(pf1_scrollx);
+ state_save_register_global(pf1_scrolly);
+ state_save_register_global(pf2_scrolly);
+ state_save_register_global(pf2_scrollx);
+ state_save_register_global(pf3_scrollx);
+ state_save_register_global(pf3_scrolly);
+ state_save_register_global(pf4_scrollx);
+ state_save_register_global(pf4_scrolly);
+ state_save_register_global(tiles_offsetx);
+ state_save_register_global(tiles_offsety);
+ state_save_register_global(pf_voffs);
+ state_save_register_global(spriteram_offs);
+
+ state_save_register_func_postload(toaplan1_flipscreen);
+}
+
+
+/***************************************************************************
+
+ Video I/O port hardware.
+
+***************************************************************************/
+
+READ16_HANDLER( toaplan1_frame_done_r )
+{
+ return video_screen_get_vblank(0);
+}
+
+WRITE16_HANDLER( toaplan1_tile_offsets_w )
+{
+ if ( offset == 0 )
+ {
+ COMBINE_DATA(&tiles_offsetx);
+ logerror("Tiles_offsetx now = %08x\n",tiles_offsetx);
+ }
+ else
+ {
+ COMBINE_DATA(&tiles_offsety);
+ logerror("Tiles_offsety now = %08x\n",tiles_offsety);
+ }
+ toaplan1_reset = 1;
+ toaplan1_set_scrolls();
+}
+
+WRITE16_HANDLER( rallybik_bcu_flipscreen_w )
+{
+ if (ACCESSING_LSB && (data != bcu_flipscreen))
+ {
+ logerror("Setting BCU controller flipscreen port to %04x\n",data);
+ bcu_flipscreen = data & 0x01; /* 0x0001 = flip, 0x0000 = no flip */
+ tilemap_set_flip(ALL_TILEMAPS, (data ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0));
+ if (bcu_flipscreen)
+ {
+ scrollx_offs1 = 0x080 - 6;
+ scrollx_offs2 = 0x080 - 4;
+ scrollx_offs3 = 0x080 - 2;
+ scrollx_offs4 = 0x080 - 0;
+ scrolly_offs = 0x1f8;
+ }
+ else
+ {
+ scrollx_offs1 = 0x0d + 6;
+ scrollx_offs2 = 0x0d + 4;
+ scrollx_offs3 = 0x0d + 2;
+ scrollx_offs4 = 0x0d + 0;
+ scrolly_offs = 0x111;
+ }
+ toaplan1_set_scrolls();
+ }
+}
+
+WRITE16_HANDLER( toaplan1_bcu_flipscreen_w )
+{
+ if (ACCESSING_LSB && (data != bcu_flipscreen))
+ {
+ logerror("Setting BCU controller flipscreen port to %04x\n",data);
+ bcu_flipscreen = data & 0x01; /* 0x0001 = flip, 0x0000 = no flip */
+ tilemap_set_flip(ALL_TILEMAPS, (data ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0));
+ if (bcu_flipscreen)
+ {
+ scrollx_offs1 = 0x011 - 6;
+ scrollx_offs2 = 0x011 - 4;
+ scrollx_offs3 = 0x011 - 2;
+ scrollx_offs4 = 0x011 - 0;
+ scrolly_offs = 0x10f;
+ }
+ else
+ {
+ scrollx_offs1 = 0x1ef + 6;
+ scrollx_offs2 = 0x1ef + 4;
+ scrollx_offs3 = 0x1ef + 2;
+ scrollx_offs4 = 0x1ef + 0;
+ scrolly_offs = 0x101;
+ }
+ toaplan1_set_scrolls();
+ }
+}
+
+WRITE16_HANDLER( toaplan1_fcu_flipscreen_w )
+{
+ if (ACCESSING_MSB)
+ {
+ logerror("Setting FCU controller flipscreen port to %04x\n",data);
+ fcu_flipscreen = data & 0x8000; /* 0x8000 = flip, 0x0000 = no flip */
+ }
+}
+
+READ16_HANDLER( toaplan1_spriteram_offs_r ) /// this aint really needed ?
+{
+ return spriteram_offs;
+}
+
+WRITE16_HANDLER( toaplan1_spriteram_offs_w )
+{
+ COMBINE_DATA(&spriteram_offs);
+}
+
+
+/* tile palette */
+READ16_HANDLER( toaplan1_colorram1_r )
+{
+ return toaplan1_colorram1[offset];
+}
+
+WRITE16_HANDLER( toaplan1_colorram1_w )
+{
+ COMBINE_DATA(&toaplan1_colorram1[offset]);
+ paletteram16_xBBBBBGGGGGRRRRR_word_w(offset, data, mem_mask);
+}
+
+/* sprite palette */
+READ16_HANDLER( toaplan1_colorram2_r )
+{
+ return toaplan1_colorram2[offset];
+}
+
+WRITE16_HANDLER( toaplan1_colorram2_w )
+{
+ COMBINE_DATA(&toaplan1_colorram2[offset]);
+ paletteram16_xBBBBBGGGGGRRRRR_word_w(offset+(toaplan1_colorram1_size/2), data, mem_mask);
+}
+
+READ16_HANDLER( toaplan1_spriteram16_r )
+{
+ return spriteram16[spriteram_offs & ((TOAPLAN1_SPRITERAM_SIZE/2)-1)];
+}
+
+WRITE16_HANDLER( toaplan1_spriteram16_w )
+{
+ COMBINE_DATA(&spriteram16[spriteram_offs & ((TOAPLAN1_SPRITERAM_SIZE/2)-1)]);
+
+#ifdef MAME_DEBUG
+ if (spriteram_offs >= (TOAPLAN1_SPRITERAM_SIZE/2))
+ {
+ logerror("Sprite_RAM_word_w, %08x out of range !\n", spriteram_offs);
+ return;
+ }
+#endif
+
+ spriteram_offs++;
+}
+
+READ16_HANDLER( toaplan1_spritesizeram16_r )
+{
+ return toaplan1_spritesizeram16[spriteram_offs & ((TOAPLAN1_SPRITESIZERAM_SIZE/2)-1)];
+}
+
+WRITE16_HANDLER( toaplan1_spritesizeram16_w )
+{
+ COMBINE_DATA(&toaplan1_spritesizeram16[spriteram_offs & ((TOAPLAN1_SPRITESIZERAM_SIZE/2)-1)]);
+
+#ifdef MAME_DEBUG
+ if (spriteram_offs >= (TOAPLAN1_SPRITESIZERAM_SIZE/2))
+ {
+ logerror("Sprite_Size_RAM_word_w, %08x out of range !\n", spriteram_offs);
+ return;
+ }
+#endif
+
+ spriteram_offs++; /// really ? shouldn't happen on the sizeram
+}
+
+
+
+WRITE16_HANDLER( toaplan1_bcu_control_w )
+{
+ logerror("BCU tile controller register:%02x now = %04x\n",offset,data);
+
+ /*** Hack for Zero Wing and OutZone, to reset the sound system on */
+ /*** soft resets. These two games don't have a sound reset port, */
+ /*** unlike the other games */
+
+ if (toaplan1_unk_reset_port && toaplan1_reset)
+ {
+ toaplan1_reset = 0;
+ toaplan1_reset_sound(0,0,0);
+ }
+}
+
+READ16_HANDLER( toaplan1_tileram_offs_r )
+{
+ return pf_voffs;
+}
+
+WRITE16_HANDLER( toaplan1_tileram_offs_w )
+{
+ if (data >= 0x4000)
+ logerror("Hmmm, unknown video layer being selected (%08x)\n",data);
+ COMBINE_DATA(&pf_voffs);
+}
+
+
+READ16_HANDLER( toaplan1_tileram16_r )
+{
+ offs_t vram_offset;
+ UINT16 video_data = 0;
+
+ switch (pf_voffs & 0xf000) /* Locate Layer (PlayField) */
+ {
+ case 0x0000:
+ vram_offset = ((pf_voffs * 2) + offset) & ((TOAPLAN1_TILEVRAM_SIZE/2)-1);
+ video_data = pf1_tilevram16[vram_offset];
+ break;
+ case 0x1000:
+ vram_offset = ((pf_voffs * 2) + offset) & ((TOAPLAN1_TILEVRAM_SIZE/2)-1);
+ video_data = pf2_tilevram16[vram_offset];
+ break;
+ case 0x2000:
+ vram_offset = ((pf_voffs * 2) + offset) & ((TOAPLAN1_TILEVRAM_SIZE/2)-1);
+ video_data = pf3_tilevram16[vram_offset];
+ break;
+ case 0x3000:
+ vram_offset = ((pf_voffs * 2) + offset) & ((TOAPLAN1_TILEVRAM_SIZE/2)-1);
+ video_data = pf4_tilevram16[vram_offset];
+ break;
+ default:
+ logerror("Hmmm, reading %04x from unknown playfield layer address %06x Offset:%01x !!!\n",video_data,pf_voffs,offset);
+ break;
+ }
+
+ return video_data;
+}
+
+READ16_HANDLER( rallybik_tileram16_r )
+{
+ UINT16 data = toaplan1_tileram16_r(offset, mem_mask);
+
+ if (offset == 0) /* some bit lines may be stuck to others */
+ {
+ data |= ((data & 0xf000) >> 4);
+ data |= ((data & 0x0030) << 2);
+ }
+ return data;
+}
+
+WRITE16_HANDLER( toaplan1_tileram16_w )
+{
+ offs_t vram_offset;
+
+ switch (pf_voffs & 0xf000) /* Locate Layer (PlayField) */
+ {
+ case 0x0000:
+ vram_offset = ((pf_voffs * 2) + offset) & ((TOAPLAN1_TILEVRAM_SIZE/2)-1);
+ COMBINE_DATA(&pf1_tilevram16[vram_offset]);
+ tilemap_mark_tile_dirty(pf1_tilemap,vram_offset/2);
+ break;
+ case 0x1000:
+ vram_offset = ((pf_voffs * 2) + offset) & ((TOAPLAN1_TILEVRAM_SIZE/2)-1);
+ COMBINE_DATA(&pf2_tilevram16[vram_offset]);
+ tilemap_mark_tile_dirty(pf2_tilemap,vram_offset/2);
+ break;
+ case 0x2000:
+ vram_offset = ((pf_voffs * 2) + offset) & ((TOAPLAN1_TILEVRAM_SIZE/2)-1);
+ COMBINE_DATA(&pf3_tilevram16[vram_offset]);
+ tilemap_mark_tile_dirty(pf3_tilemap,vram_offset/2);
+ break;
+ case 0x3000:
+ vram_offset = ((pf_voffs * 2) + offset) & ((TOAPLAN1_TILEVRAM_SIZE/2)-1);
+ COMBINE_DATA(&pf4_tilevram16[vram_offset]);
+ tilemap_mark_tile_dirty(pf4_tilemap,vram_offset/2);
+ break;
+ default:
+ logerror("Hmmm, writing %04x to unknown playfield layer address %06x Offset:%01x\n",data,pf_voffs,offset);
+ break;
+ }
+}
+
+
+
+READ16_HANDLER( toaplan1_scroll_regs_r )
+{
+ UINT16 scroll = 0;
+
+ switch(offset)
+ {
+ case 00: scroll = pf1_scrollx; break;
+ case 01: scroll = pf1_scrolly; break;
+ case 02: scroll = pf2_scrollx; break;
+ case 03: scroll = pf2_scrolly; break;
+ case 04: scroll = pf3_scrollx; break;
+ case 05: scroll = pf3_scrolly; break;
+ case 06: scroll = pf4_scrollx; break;
+ case 07: scroll = pf4_scrolly; break;
+ default: logerror("Hmmm, reading unknown video scroll register (%08x) !!!\n",offset);
+ break;
+ }
+ return scroll;
+}
+
+
+WRITE16_HANDLER( toaplan1_scroll_regs_w )
+{
+ switch(offset)
+ {
+ case 00: COMBINE_DATA(&pf1_scrollx); /* 1D3h */
+ tilemap_set_scrollx(pf1_tilemap,0,(pf1_scrollx >> 7) - (tiles_offsetx - scrollx_offs1));
+ break;
+ case 01: COMBINE_DATA(&pf1_scrolly); /* 1EBh */
+ tilemap_set_scrolly(pf1_tilemap,0,(pf1_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ break;
+ case 02: COMBINE_DATA(&pf2_scrollx); /* 1D5h */
+ tilemap_set_scrollx(pf2_tilemap,0,(pf2_scrollx >> 7) - (tiles_offsetx - scrollx_offs2));
+ break;
+ case 03: COMBINE_DATA(&pf2_scrolly); /* 1EBh */
+ tilemap_set_scrolly(pf2_tilemap,0,(pf2_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ break;
+ case 04: COMBINE_DATA(&pf3_scrollx); /* 1D7h */
+ tilemap_set_scrollx(pf3_tilemap,0,(pf3_scrollx >> 7) - (tiles_offsetx - scrollx_offs3));
+ break;
+ case 05: COMBINE_DATA(&pf3_scrolly); /* 1EBh */
+ tilemap_set_scrolly(pf3_tilemap,0,(pf3_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ break;
+ case 06: COMBINE_DATA(&pf4_scrollx); /* 1D9h */
+ tilemap_set_scrollx(pf4_tilemap,0,(pf4_scrollx >> 7) - (tiles_offsetx - scrollx_offs4));
+ break;
+ case 07: COMBINE_DATA(&pf4_scrolly); /* 1EBh */
+ tilemap_set_scrolly(pf4_tilemap,0,(pf4_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ break;
+ default: logerror("Hmmm, writing %08x to unknown video scroll register (%08x) !!!\n",data ,offset);
+ break;
+ }
+}
+
+
+
+
+#ifdef MAME_DEBUG
+void toaplan1_log_vram(void)
+{
+ if ( input_code_pressed(KEYCODE_M) )
+ {
+ offs_t sprite_voffs;
+ while (input_code_pressed(KEYCODE_M)) ;
+ if (toaplan1_spritesizeram16) /* FCU controller */
+ {
+ int schar,sattr,sxpos,sypos,bschar,bsattr,bsxpos,bsypos;
+ UINT16 *size = (UINT16 *)(toaplan1_spritesizeram16);
+ UINT16 *bsize = (UINT16 *)(toaplan1_buffered_spritesizeram16);
+ logerror("Scrolls PF1-X PF1-Y PF2-X PF2-Y PF3-X PF3-Y PF4-X PF4-Y\n");
+ logerror("------> #%04x #%04x #%04x #%04x #%04x #%04x #%04x #%04x\n",pf1_scrollx,pf1_scrolly,pf2_scrollx,pf2_scrolly,pf3_scrollx,pf3_scrolly,pf4_scrollx,pf4_scrolly);
+ for ( sprite_voffs = 0; sprite_voffs < (spriteram_size/2); sprite_voffs += 4 )
+ {
+ bschar = buffered_spriteram16[sprite_voffs];
+ bsattr = buffered_spriteram16[sprite_voffs + 1];
+ bsxpos = buffered_spriteram16[sprite_voffs + 2];
+ bsypos = buffered_spriteram16[sprite_voffs + 3];
+ schar = spriteram16[sprite_voffs];
+ sattr = spriteram16[sprite_voffs + 1];
+ sxpos = spriteram16[sprite_voffs + 2];
+ sypos = spriteram16[sprite_voffs + 3];
+ logerror("$(%04x) Tile-Attr-Xpos-Ypos Now:%04x %04x %04x.%01x %04x.%01x nxt:%04x %04x %04x.%01x %04x.%01x\n", sprite_voffs,
+ schar, sattr, sxpos, size[( sattr>>6)&0x3f]&0xf, sypos,( size[( sattr>>6)&0x3f]>>4)&0xf,
+ bschar,bsattr,bsxpos,bsize[(bsattr>>6)&0x3f]&0xf,bsypos,(bsize[(bsattr>>6)&0x3f]>>4)&0xf);
+ }
+ }
+ else /* SCU controller */
+ {
+ int schar,sattr,sxpos,sypos,bschar,bsattr,bsxpos,bsypos;
+ logerror("Scrolls PF1-X PF1-Y PF2-X PF2-Y PF3-X PF3-Y PF4-X PF4-Y\n");
+ logerror("------> #%04x #%04x #%04x #%04x #%04x #%04x #%04x #%04x\n",pf1_scrollx,pf1_scrolly,pf2_scrollx,pf2_scrolly,pf3_scrollx,pf3_scrolly,pf4_scrollx,pf4_scrolly);
+ for ( sprite_voffs = 0; sprite_voffs < (spriteram_size/2); sprite_voffs += 4 )
+ {
+ bschar = buffered_spriteram16[sprite_voffs];
+ bsattr = buffered_spriteram16[sprite_voffs + 1];
+ bsypos = buffered_spriteram16[sprite_voffs + 2];
+ bsxpos = buffered_spriteram16[sprite_voffs + 3];
+ schar = spriteram16[sprite_voffs];
+ sattr = spriteram16[sprite_voffs + 1];
+ sypos = spriteram16[sprite_voffs + 2];
+ sxpos = spriteram16[sprite_voffs + 3];
+ logerror("$(%04x) Tile-Attr-Xpos-Ypos Now:%04x %04x %04x %04x nxt:%04x %04x %04x %04x\n", sprite_voffs,
+ schar, sattr, sxpos, sypos,
+ bschar,bsattr,bsxpos, bsypos);
+ }
+ }
+ }
+
+ if ( input_code_pressed(KEYCODE_SLASH) )
+ {
+ UINT16 *size = (UINT16 *)(toaplan1_spritesizeram16);
+ UINT16 *bsize = (UINT16 *)(toaplan1_buffered_spritesizeram16);
+ offs_t offs;
+ while (input_code_pressed(KEYCODE_SLASH)) ;
+ if (toaplan1_spritesizeram16) /* FCU controller */
+ {
+ logerror("Scrolls PF1-X PF1-Y PF2-X PF2-Y PF3-X PF3-Y PF4-X PF4-Y\n");
+ logerror("------> #%04x #%04x #%04x #%04x #%04x #%04x #%04x #%04x\n",pf1_scrollx,pf1_scrolly,pf2_scrollx,pf2_scrolly,pf3_scrollx,pf3_scrolly,pf4_scrollx,pf4_scrolly);
+ for ( offs = 0; offs < (TOAPLAN1_SPRITESIZERAM_SIZE/2); offs +=4 )
+ {
+ logerror("SizeOffs:%04x now:%04x %04x %04x %04x next: %04x %04x %04x %04x\n", offs,
+ bsize[offs+0], bsize[offs+1],
+ bsize[offs+2], bsize[offs+3],
+ size[offs+0], size[offs+1],
+ size[offs+2], size[offs+3]);
+ }
+ }
+ }
+
+ if ( input_code_pressed(KEYCODE_N) )
+ {
+ offs_t tile_voffs;
+ int tchar[5], tattr[5];
+ while (input_code_pressed(KEYCODE_N)) ; /* BCU controller */
+ logerror("Scrolls PF1-X PF1-Y PF2-X PF2-Y PF3-X PF3-Y PF4-X PF4-Y\n");
+ logerror("------> #%04x #%04x #%04x #%04x #%04x #%04x #%04x #%04x\n",pf1_scrollx,pf1_scrolly,pf2_scrollx,pf2_scrolly,pf3_scrollx,pf3_scrolly,pf4_scrollx,pf4_scrolly);
+ for ( tile_voffs = 0; tile_voffs < (TOAPLAN1_TILEVRAM_SIZE/2); tile_voffs += 2 )
+ {
+ tchar[1] = pf1_tilevram16[tile_voffs + 1];
+ tattr[1] = pf1_tilevram16[tile_voffs];
+ tchar[2] = pf2_tilevram16[tile_voffs + 1];
+ tattr[2] = pf2_tilevram16[tile_voffs];
+ tchar[3] = pf3_tilevram16[tile_voffs + 1];
+ tattr[3] = pf3_tilevram16[tile_voffs];
+ tchar[4] = pf4_tilevram16[tile_voffs + 1];
+ tattr[4] = pf4_tilevram16[tile_voffs];
+// logerror("PF3 offs:%04x Tile:%04x Attr:%04x\n", tile_voffs, tchar, tattr);
+ logerror("$(%04x) Attr-Tile PF1:%04x-%04x PF2:%04x-%04x PF3:%04x-%04x PF4:%04x-%04x\n", tile_voffs,
+ tattr[1], tchar[1], tattr[2], tchar[2],
+ tattr[3], tchar[3], tattr[4], tchar[4]);
+ }
+ }
+
+ if ( input_code_pressed(KEYCODE_W) )
+ {
+ while (input_code_pressed(KEYCODE_W)) ;
+ logerror("Mark here\n");
+ }
+ if ( input_code_pressed(KEYCODE_E) )
+ {
+ while (input_code_pressed(KEYCODE_E)) ;
+ displog += 1;
+ displog &= 1;
+ }
+ if (displog)
+ {
+ logerror("Scrolls PF1-X PF1-Y PF2-X PF2-Y PF3-X PF3-Y PF4-X PF4-Y\n");
+ logerror("------> #%04x #%04x #%04x #%04x #%04x #%04x #%04x #%04x\n",pf1_scrollx,pf1_scrolly,pf2_scrollx,pf2_scrolly,pf3_scrollx,pf3_scrolly,pf4_scrollx,pf4_scrolly);
+ }
+ if ( input_code_pressed(KEYCODE_B) )
+ {
+// while (input_code_pressed(KEYCODE_B)) ;
+ scrollx_offs1 += 0x1; scrollx_offs2 += 0x1; scrollx_offs3 += 0x1; scrollx_offs4 += 0x1;
+ logerror("Scrollx_offs now = %08x\n",scrollx_offs4);
+ tilemap_set_scrollx(pf1_tilemap,0,(pf1_scrollx >> 7) - (tiles_offsetx - scrollx_offs1));
+ tilemap_set_scrollx(pf2_tilemap,0,(pf2_scrollx >> 7) - (tiles_offsetx - scrollx_offs2));
+ tilemap_set_scrollx(pf3_tilemap,0,(pf3_scrollx >> 7) - (tiles_offsetx - scrollx_offs3));
+ tilemap_set_scrollx(pf4_tilemap,0,(pf4_scrollx >> 7) - (tiles_offsetx - scrollx_offs4));
+ }
+ if ( input_code_pressed(KEYCODE_V) )
+ {
+// while (input_code_pressed(KEYCODE_V)) ;
+ scrollx_offs1 -= 0x1; scrollx_offs2 -= 0x1; scrollx_offs3 -= 0x1; scrollx_offs4 -= 0x1;
+ logerror("Scrollx_offs now = %08x\n",scrollx_offs4);
+ tilemap_set_scrollx(pf1_tilemap,0,(pf1_scrollx >> 7) - (tiles_offsetx - scrollx_offs1));
+ tilemap_set_scrollx(pf2_tilemap,0,(pf2_scrollx >> 7) - (tiles_offsetx - scrollx_offs2));
+ tilemap_set_scrollx(pf3_tilemap,0,(pf3_scrollx >> 7) - (tiles_offsetx - scrollx_offs3));
+ tilemap_set_scrollx(pf4_tilemap,0,(pf4_scrollx >> 7) - (tiles_offsetx - scrollx_offs4));
+ }
+ if ( input_code_pressed(KEYCODE_C) )
+ {
+// while (input_code_pressed(KEYCODE_C)) ;
+ scrolly_offs += 0x1;
+ logerror("Scrolly_offs now = %08x\n",scrolly_offs);
+ tilemap_set_scrolly(pf1_tilemap,0,(pf1_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ tilemap_set_scrolly(pf2_tilemap,0,(pf2_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ tilemap_set_scrolly(pf3_tilemap,0,(pf3_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ tilemap_set_scrolly(pf4_tilemap,0,(pf4_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ }
+ if ( input_code_pressed(KEYCODE_X) )
+ {
+// while (input_code_pressed(KEYCODE_X)) ;
+ scrolly_offs -= 0x1;
+ logerror("Scrolly_offs now = %08x\n",scrolly_offs);
+ tilemap_set_scrolly(pf1_tilemap,0,(pf1_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ tilemap_set_scrolly(pf2_tilemap,0,(pf2_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ tilemap_set_scrolly(pf3_tilemap,0,(pf3_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ tilemap_set_scrolly(pf4_tilemap,0,(pf4_scrolly >> 7) - (tiles_offsety - scrolly_offs));
+ }
+
+ if ( input_code_pressed(KEYCODE_L) ) /* Turn Playfield 4 on/off */
+ {
+ while (input_code_pressed(KEYCODE_L)) ;
+ display_pf4 += 1;
+ display_pf4 &= 1;
+ tilemap_set_enable(pf4_tilemap, display_pf4);
+ }
+ if ( input_code_pressed(KEYCODE_K) ) /* Turn Playfield 3 on/off */
+ {
+ while (input_code_pressed(KEYCODE_K)) ;
+ display_pf3 += 1;
+ display_pf3 &= 1;
+ tilemap_set_enable(pf3_tilemap, display_pf3);
+ }
+ if ( input_code_pressed(KEYCODE_J) ) /* Turn Playfield 2 on/off */
+ {
+ while (input_code_pressed(KEYCODE_J)) ;
+ display_pf2 += 1;
+ display_pf2 &= 1;
+ tilemap_set_enable(pf2_tilemap, display_pf2);
+ }
+ if ( input_code_pressed(KEYCODE_H) ) /* Turn Playfield 1 on/off */
+ {
+ while (input_code_pressed(KEYCODE_H)) ;
+ display_pf1 += 1;
+ display_pf1 &= 1;
+ tilemap_set_enable(pf1_tilemap, display_pf1);
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ Sprite Handlers
+***************************************************************************/
+
+// custom function to draw a single sprite. needed to keep correct sprites - sprites and sprites - tilemaps priorities
+static void toaplan1_draw_sprite_custom(mame_bitmap *dest_bmp,const gfx_element *gfx,
+ UINT32 code,UINT32 color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int priority)
+{
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+ UINT8 *source_base = gfx->gfxdata + (code % gfx->total_elements) * gfx->char_modulo;
+
+ int sprite_screen_height = ((1<<16)*gfx->height+0x8000)>>16;
+ int sprite_screen_width = ((1<<16)*gfx->width+0x8000)>>16;
+
+ if (sprite_screen_width && sprite_screen_height)
+ {
+ /* compute sprite increment per screen pixel */
+ int dx = (gfx->width<<16)/sprite_screen_width;
+ int dy = (gfx->height<<16)/sprite_screen_height;
+
+ int ex = sx+sprite_screen_width;
+ int ey = sy+sprite_screen_height;
+
+ int x_index_base;
+ int y_index;
+
+ if( flipx )
+ {
+ x_index_base = (sprite_screen_width-1)*dx;
+ dx = -dx;
+ }
+ else
+ {
+ x_index_base = 0;
+ }
+
+ if( flipy )
+ {
+ y_index = (sprite_screen_height-1)*dy;
+ dy = -dy;
+ }
+ else
+ {
+ y_index = 0;
+ }
+
+ if( clip )
+ {
+ if( sx < clip->min_x)
+ { /* clip left */
+ int pixels = clip->min_x-sx;
+ sx += pixels;
+ x_index_base += pixels*dx;
+ }
+ if( sy < clip->min_y )
+ { /* clip top */
+ int pixels = clip->min_y-sy;
+ sy += pixels;
+ y_index += pixels*dy;
+ }
+ /* NS 980211 - fixed incorrect clipping */
+ if( ex > clip->max_x+1 )
+ { /* clip right */
+ int pixels = ex-clip->max_x-1;
+ ex -= pixels;
+ }
+ if( ey > clip->max_y+1 )
+ { /* clip bottom */
+ int pixels = ey-clip->max_y-1;
+ ey -= pixels;
+ }
+ }
+
+ if( ex>sx )
+ { /* skip if inner loop doesn't draw anything */
+ int y;
+
+ for( y=sy; y<ey; y++ )
+ {
+ UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
+ UINT16 *dest = BITMAP_ADDR16(dest_bmp, y, 0);
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+
+ int x, x_index = x_index_base;
+ for( x=sx; x<ex; x++ )
+ {
+ int c = source[x_index>>16];
+ if( c != 0 )
+ {
+ if (pri[x] < priority)
+ dest[x] = pal[c];
+ pri[x] = 0xff; // mark it "already drawn"
+ }
+ x_index += dx;
+ }
+
+ y_index += dy;
+ }
+ }
+ }
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ UINT16 *source = (UINT16 *)(buffered_spriteram16);
+ UINT16 *size = (UINT16 *)(toaplan1_buffered_spritesizeram16);
+
+ int offs;
+
+ for (offs = spriteram_size/2 - 4; offs >= 0; offs -= 4)
+ {
+ if (!(source[offs] & 0x8000))
+ {
+ int attrib, sprite, color, priority, sx, sy;
+ int sprite_sizex, sprite_sizey, dim_x, dim_y, sx_base, sy_base;
+ int sizeram_ptr;
+
+ attrib = source[offs+1];
+ priority = (attrib & 0xf000) >> 12;
+
+ sprite = source[offs] & 0x7fff;
+ color = attrib & 0x3f;
+
+ /****** find sprite dimension ******/
+ sizeram_ptr = (attrib >> 6) & 0x3f;
+ sprite_sizex = ( size[sizeram_ptr] & 0x0f) * 8;
+ sprite_sizey = ((size[sizeram_ptr] >> 4) & 0x0f) * 8;
+
+ /****** find position to display sprite ******/
+ sx_base = (source[offs + 2] >> 7) & 0x1ff;
+ sy_base = (source[offs + 3] >> 7) & 0x1ff;
+
+ if (sx_base >= 0x180) sx_base -= 0x200;
+ if (sy_base >= 0x180) sy_base -= 0x200;
+
+ /****** flip the sprite layer ******/
+ if (fcu_flipscreen)
+ {
+ sx_base += 8;
+ sy_base -= 24;
+ sx_base = 320 - sx_base;
+ sy_base = 240 - sy_base;
+ }
+
+ for (dim_y = 0; dim_y < sprite_sizey; dim_y += 8)
+ {
+ if (fcu_flipscreen) sy = sy_base - dim_y;
+ else sy = sy_base + dim_y;
+
+ for (dim_x = 0; dim_x < sprite_sizex; dim_x += 8)
+ {
+ if (fcu_flipscreen) sx = sx_base - dim_x;
+ else sx = sx_base + dim_x;
+
+ toaplan1_draw_sprite_custom(bitmap,machine->gfx[1],
+ sprite,color,
+ fcu_flipscreen,fcu_flipscreen,
+ sx,sy,
+ cliprect,priority);
+
+ sprite++ ;
+ }
+ }
+ }
+ }
+}
+
+
+static void rallybik_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority )
+{
+ int offs;
+
+ for (offs = 0; offs < (spriteram_size/2); offs += 4)
+ {
+ int attrib, sx, sy, flipx, flipy;
+ int sprite, color;
+
+ attrib = buffered_spriteram16[offs + 1];
+ if ((attrib & 0x0c00) == priority)
+ {
+ sy = (buffered_spriteram16[offs + 3] >> 7) & 0x1ff;
+ if (sy != 0x0100) /* sx = 0x01a0 or 0x0040*/
+ {
+ sprite = buffered_spriteram16[offs] & 0x7ff;
+ color = attrib & 0x3f;
+ sx = (buffered_spriteram16[offs + 2] >> 7) & 0x1ff;
+ flipx = attrib & 0x100;
+ if (flipx) sx -= 15;
+ flipy = attrib & 0x200;
+ drawgfx(bitmap,machine->gfx[1],
+ sprite,
+ color,
+ flipx,flipy,
+ sx-31,sy-16,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+}
+
+
+/***************************************************************************
+ Draw the game screen in the given mame_bitmap.
+***************************************************************************/
+
+VIDEO_UPDATE( rallybik )
+{
+ int priority;
+
+#ifdef MAME_DEBUG
+ toaplan1_log_vram();
+#endif
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,TILEMAP_DRAW_OPAQUE | 0,0);
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,TILEMAP_DRAW_OPAQUE | 1,0);
+
+ for (priority = 1; priority < 16; priority++)
+ {
+ tilemap_draw(bitmap,cliprect,pf4_tilemap,priority,0);
+ tilemap_draw(bitmap,cliprect,pf3_tilemap,priority,0);
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,priority,0);
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,priority,0);
+ rallybik_draw_sprites(machine, bitmap,cliprect,priority << 8);
+ }
+ return 0;
+}
+
+VIDEO_UPDATE( toaplan1 )
+{
+ int priority;
+
+#ifdef MAME_DEBUG
+ toaplan1_log_vram();
+#endif
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0x120],cliprect);
+
+ tilemap_draw(bitmap,cliprect,pf4_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ for (priority = 8; priority < 16; priority++)
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,TILEMAP_DRAW_OPAQUE | priority,0);
+
+ for (priority = 1; priority < 16; priority++)
+ {
+ tilemap_draw_primask(bitmap,cliprect,pf4_tilemap,priority,priority,0);
+ tilemap_draw_primask(bitmap,cliprect,pf3_tilemap,priority,priority,0);
+ tilemap_draw_primask(bitmap,cliprect,pf2_tilemap,priority,priority,0);
+ tilemap_draw_primask(bitmap,cliprect,pf1_tilemap,priority,priority,0);
+ }
+
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( demonwld )
+{
+ int priority;
+
+#ifdef MAME_DEBUG
+ toaplan1_log_vram();
+#endif
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0x120],cliprect);
+
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,TILEMAP_DRAW_OPAQUE | 0,0);
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,TILEMAP_DRAW_OPAQUE | 1,0);
+
+ for (priority = 1; priority < 16; priority++)
+ {
+ tilemap_draw_primask(bitmap,cliprect,pf4_tilemap,priority,priority,0);
+ tilemap_draw_primask(bitmap,cliprect,pf3_tilemap,priority,priority,0);
+ tilemap_draw_primask(bitmap,cliprect,pf2_tilemap,priority,priority,0);
+ tilemap_draw_primask(bitmap,cliprect,pf1_tilemap,priority,priority,0);
+ }
+
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
+
+
+/****************************************************************************
+ Spriteram is always 1 frame ahead, suggesting spriteram buffering.
+ There are no CPU output registers that control this so we
+ assume it happens automatically every frame, at the end of vblank
+****************************************************************************/
+
+VIDEO_EOF( rallybik )
+{
+ buffer_spriteram16_w(0, 0, 0);
+}
+
+VIDEO_EOF( toaplan1 )
+{
+ buffer_spriteram16_w(0, 0, 0);
+ memcpy(toaplan1_buffered_spritesizeram16, toaplan1_spritesizeram16, TOAPLAN1_SPRITESIZERAM_SIZE);
+}
+
+VIDEO_EOF( samesame )
+{
+ buffer_spriteram16_w(0, 0, 0);
+ memcpy(toaplan1_buffered_spritesizeram16, toaplan1_spritesizeram16, TOAPLAN1_SPRITESIZERAM_SIZE);
+ cpunum_set_input_line(0, MC68000_IRQ_2, HOLD_LINE); /* Frame done */
+}
diff --git a/src/mame/video/toaplan2.c b/src/mame/video/toaplan2.c
new file mode 100644
index 00000000000..8c66ee2e45b
--- /dev/null
+++ b/src/mame/video/toaplan2.c
@@ -0,0 +1,1619 @@
+/***************************************************************************
+
+ Functions to emulate the video hardware of some Toaplan games,
+ which use one or more Toaplan L7A0498 GP9001 graphic controllers.
+
+ The simpler hardware of these games use one GP9001 controller.
+ Next we have games that use two GP9001 controllers, whose priority
+ schemes between the two controllers is unknown at this time, and
+ may be game dependant.
+ Finally we have games using one GP9001 controller and an additional
+ text tile layer, which has highest priority. This text tile layer
+ appears to have line-scroll support. Some of these games copy the
+ text tile gfx data to RAM from the main CPU ROM, which easily allows
+ for effects to be added to the tiles, by manipulating the text tile
+ gfx data. The tiles are then dynamically decoded from RAM before
+ displaying them.
+
+
+ To Do / Unknowns
+ - Hack is needed to reset sound CPU and sound chip when machine
+ is 'tilted' in Pipi & Bibis. Otherwise sound CPU interferes
+ with the main CPU test of shared RAM. You get a 'Sub CPU RAM Error'
+ - What do Scroll registers 0Eh and 0Fh really do ????
+ - Snow Bros 2 sets bit 6 of the sprite X info word during weather
+ world map, and bits 4, 5 and 6 of the sprite X info word during
+ the Rabbit boss screen - reasons are unknown.
+ - Fourth set of scroll registers have been used for Sprite scroll
+ though it may not be correct. For most parts this looks right
+ except for Snow Bros 2 when in the rabbit boss screen (all sprites
+ jump when big green nasty (which is the foreground layer) comes
+ in from the left)
+ - Teki Paki tests video RAM from address 0 past SpriteRAM to $37ff.
+ This seems to be a bug in Teki Paki's vram test routine !
+ - Batsugun, relationship between the two video controllers (priority
+ wise) is wrong and unknown.
+
+
+ GP9001 Video RAM address layout:
+
+ Bank data size of video layer
+ -----------------------------------------
+ $0000-07FF 800h words for background layer
+ $0800-0FFF 800h words for foreground layer
+ $1000-17FF 800h words for top (text) layer
+ $1800-1BFF 400h words for sprites (100 possible sprites)
+
+
+
+ GP9001 Tile RAM format (each tile takes up 32 bits)
+
+ 0 1 2 3
+ ---- ---- ---- ---- xxxx xxxx xxxx xxxx = Tile number (0 - FFFFh)
+ ---- ---- -xxx xxxx ---- ---- ---- ---- = Color (0 - 7Fh)
+ ---- ---- ?--- ---- ---- ---- ---- ---- = unknown / unused
+ ---- xxxx ---- ---- ---- ---- ---- ---- = Priority (0 - Fh)
+ ???? ---- ---- ---- ---- ---- ---- ---- = unknown / unused / possible flips
+
+Sprites are of varying sizes between 8x8 and 128x128 with any variation
+in between, in multiples of 8 either way.
+
+Here we draw the first 8x8 part of the sprite, then by using the sprite
+dimensions, we draw the rest of the 8x8 parts to produce the complete
+sprite.
+
+There seems to be sprite buffering - double buffering actually.
+
+ GP9001 Sprite RAM format (data for each sprite takes up 4 words)
+
+ 0
+ ---- ---- ---- --xx = top 2 bits of Sprite number
+ ---- ---- xxxx xx-- = Color (0 - 3Fh)
+ ---- xxxx ---- ---- = Priority (0 - Fh)
+ ---x ---- ---- ---- = Flip X
+ --x- ---- ---- ---- = Flip Y
+ -?-- ---- ---- ---- = unknown / unused
+ x--- ---- ---- ---- = Show sprite ?
+
+ 1
+ xxxx xxxx xxxx xxxx = Sprite number (top two bits in word 0)
+
+ 2
+ ---- ---- ---- xxxx = Sprite X size (add 1, then multiply by 8)
+ ---- ---- -??? ---- = unknown - used in Snow Bros. 2
+ xxxx xxxx x--- ---- = X position
+
+ 3
+ ---- ---- ---- xxxx = Sprite Y size (add 1, then multiply by 8)
+ ---- ---- -??? ---- = unknown / unused
+ xxxx xxxx x--- ---- = Y position
+
+
+ Extra-text RAM format
+
+ Truxton 2, Fixeight and Raizing games have an extra-text layer.
+
+ Text RAM format $0000-1FFF (actually its probably $0000-0FFF)
+ ---- --xx xxxx xxxx = Tile number
+ xxxx xx-- ---- ---- = Color (0 - 3Fh) + 40h
+
+ Text flip / ??? $0000-01EF (some games go to $01FF (excess?))
+ ---x xxxx xxxx xxxx = ??? line something (line to draw ?) ???
+ x--- ---- ---- ---- = flip for the Text tile
+
+ Text X line-scroll ? $0000-01EF (some games go to $01FF (excess?))
+ ---- ---x xxxx xxxx = X-Scroll for each line
+
+
+
+ GP9001 Scroll Registers (hex) :
+
+ 00 Background scroll X (X flip off)
+ 01 Background scroll Y (Y flip off)
+ 02 Foreground scroll X (X flip off)
+ 03 Foreground scroll Y (Y flip off)
+ 04 Top (text) scroll X (X flip off)
+ 05 Top (text) scroll Y (Y flip off)
+ 06 Sprites scroll X (X flip off) ???
+ 07 Sprites scroll Y (Y flip off) ???
+ 0E ??? Initialise Video controller at startup ???
+ 0F Scroll update complete ??? (Not used in Ghox and V-Five)
+
+ 80 Background scroll X (X flip on)
+ 81 Background scroll Y (Y flip on)
+ 82 Foreground scroll X (X flip on)
+ 83 Foreground scroll Y (Y flip on)
+ 84 Top (text) scroll X (X flip on)
+ 85 Top (text) scroll Y (Y flip on)
+ 86 Sprites scroll X (X flip on) ???
+ 87 Sprites scroll Y (Y flip on) ???
+ 8F Same as 0Fh except flip bit is active
+
+
+Scroll Register 0E writes (Video controller inits ?) from different games:
+
+Teki-Paki | Ghox | Knuckle Bash | Truxton 2 |
+0003, 0002, 4000 | ????, ????, ???? | 0202, 0203, 4200 | 0003, 0002, 4000 |
+
+Dogyuun | Batsugun |
+0202, 0203, 4200 | 0202, 0203, 4200 |
+1202, 1203, 5200 | 1202, 1203, 5200 | <--- Second video controller
+
+Pipi & Bibis | Fix Eight | V-Five | Snow Bros. 2 |
+0003, 0002, 4000 | 0202, 0203, 4200 | 0202, 0203, 4200 | 0202, 0203, 4200 |
+
+***************************************************************************/
+
+#include "driver.h"
+#include "cpu/m68000/m68000.h"
+
+
+
+#define TOAPLAN2_BG_VRAM_SIZE 0x1000 /* Background RAM size */
+#define TOAPLAN2_FG_VRAM_SIZE 0x1000 /* Foreground RAM size */
+#define TOAPLAN2_TOP_VRAM_SIZE 0x1000 /* Top Layer RAM size */
+#define TOAPLAN2_SPRITERAM_SIZE 0x800 /* Sprite RAM size */
+#define RAIZING_TX_GFXRAM_SIZE 0x8000 /* GFX data decode RAM size */
+extern size_t toaplan2_tx_vram_size; /* 0x2000 Text layer RAM size */
+extern size_t toaplan2_tx_offs_vram_size; /* 0x200 Text layer tile flip and positon ? */
+extern size_t toaplan2_tx_scroll_vram_size; /* 0x200 Text layer scroll ? */
+extern size_t batrider_paletteram16_size;
+
+
+
+#define TOAPLAN2_SPRITE_FLIPX 0x1000 /* Sprite flip flags */
+#define TOAPLAN2_SPRITE_FLIPY 0x2000
+
+#define CPU_2_NONE 0x00
+#define CPU_2_Z80 0x5a
+#define CPU_2_HD647180 0xa5
+#define CPU_2_V25 0xff
+
+
+static UINT16 *bgvideoram16[2];
+static UINT16 *fgvideoram16[2];
+static UINT16 *topvideoram16[2];
+static UINT16 *spriteram16_now[2]; /* Sprites to draw this frame */
+static UINT16 *spriteram16_new[2]; /* Sprites to add to next frame */
+static UINT16 *spriteram16_n[2];
+UINT16 *toaplan2_txvideoram16; /* Video ram for extra text layer */
+UINT16 *toaplan2_txvideoram16_offs; /* Text layer tile flip and positon ? */
+UINT16 *toaplan2_txscrollram16; /* Text layer scroll ? */
+UINT16 *toaplan2_tx_gfxram16; /* Text Layer RAM based tiles */
+static UINT16 *raizing_tx_gfxram16; /* Text Layer RAM based tiles (Batrider) */
+static int toaplan2_overflow_vram; /* Teki Paki VRAM test is bugged. It goes out of range */
+
+static int toaplan2_scroll_reg[2];
+static int toaplan2_voffs[2];
+static int bg_scrollx[2];
+static int bg_scrolly[2];
+static int fg_scrollx[2];
+static int fg_scrolly[2];
+static int top_scrollx[2];
+static int top_scrolly[2];
+static int sprite_scrollx[2];
+static int sprite_scrolly[2];
+static int objectbank_dirty = 0; /* dirty flag of object bank (for Batrider) */
+static int batrider_object_bank[8]; /* Batrider object bank */
+
+#ifdef MAME_DEBUG
+static int display_bg[2] = { 1, 1 };
+static int display_fg[2] = { 1, 1 };
+static int display_top[2] = { 1, 1 };
+static int displog = 0;
+static int display_tx = 1;
+#endif
+static int display_sp[2] = { 1, 1 };
+
+static int sprite_priority[2][16];
+static int bg_flip[2] = { 0, 0 };
+static int fg_flip[2] = { 0, 0 };
+static int top_flip[2] = { 0, 0 };
+static int sprite_flip[2] = { 0, 0 };
+static int tx_flip = 0;
+
+extern int toaplan2_sub_cpu;
+
+static UINT8 top_tile_priority[2][16];
+static UINT8 fg_tile_priority[2][16];
+static UINT8 bg_tile_priority[2][16];
+
+
+static tilemap *top_tilemap[2], *fg_tilemap[2], *bg_tilemap[2];
+static tilemap *tx_tilemap; /* Tilemap for extra-text-layer */
+
+static int xoffset[4];
+static int yoffset[4];
+
+static void defaultOffsets(void)
+{
+ xoffset[0]=0;
+ xoffset[1]=0;
+ xoffset[2]=0;
+ xoffset[3]=0;
+
+ yoffset[0]=0;
+ yoffset[1]=0;
+ yoffset[2]=0;
+ yoffset[3]=0;
+}
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_top0_tile_info )
+{
+ int color, tile_number, attrib;
+
+ attrib = topvideoram16[0][2*tile_index];
+ tile_number = topvideoram16[0][2*tile_index+1];
+ color = attrib & 0x7f;
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ color,
+ 0);
+ tileinfo->category = (attrib & 0x0f00) >> 8;
+}
+
+static TILE_GET_INFO( get_fg0_tile_info )
+{
+ int color, tile_number, attrib;
+
+ attrib = fgvideoram16[0][2*tile_index];
+ tile_number = fgvideoram16[0][2*tile_index+1];
+ color = attrib & 0x7f;
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ color,
+ 0);
+ tileinfo->category = (attrib & 0x0f00) >> 8;
+}
+
+static TILE_GET_INFO( get_bg0_tile_info )
+{
+ int color, tile_number, attrib;
+
+ attrib = bgvideoram16[0][2*tile_index];
+ tile_number = bgvideoram16[0][2*tile_index+1];
+ color = attrib & 0x7f;
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ color,
+ 0);
+ tileinfo->category = (attrib & 0x0f00) >> 8;
+/// if ((attrib & 0x0f00) == 0) tileinfo->flags |= TILE_FORCE_LAYER0;
+}
+
+static TILE_GET_INFO( get_top1_tile_info )
+{
+ int color, tile_number, attrib;
+
+ attrib = topvideoram16[1][2*tile_index];
+ tile_number = topvideoram16[1][2*tile_index+1];
+ color = attrib & 0x7f;
+ SET_TILE_INFO(
+ 2,
+ tile_number,
+ color,
+ 0);
+ tileinfo->category = (attrib & 0x0f00) >> 8;
+}
+
+static TILE_GET_INFO( get_fg1_tile_info )
+{
+ int color, tile_number, attrib;
+
+ attrib = fgvideoram16[1][2*tile_index];
+ tile_number = fgvideoram16[1][2*tile_index+1];
+ color = attrib & 0x7f;
+ SET_TILE_INFO(
+ 2,
+ tile_number,
+ color,
+ 0);
+ tileinfo->category = (attrib & 0x0f00) >> 8;
+}
+
+static TILE_GET_INFO( get_bg1_tile_info )
+{
+ int color, tile_number, attrib;
+
+ attrib = bgvideoram16[1][2*tile_index];
+ tile_number = bgvideoram16[1][2*tile_index+1];
+ color = attrib & 0x7f;
+ SET_TILE_INFO(
+ 2,
+ tile_number,
+ color,
+ 0);
+ tileinfo->category = (attrib & 0x0f00) >> 8;
+}
+
+static TILE_GET_INFO( batrider_get_top0_tile_info )
+{
+ int color, tile_number, attrib, tile;
+
+ attrib = topvideoram16[0][2*tile_index];
+ tile = topvideoram16[0][2*tile_index+1];
+ tile_number = ( batrider_object_bank[(tile >> 13) & 7] << 13 ) | ( tile & 0x1fff );
+ color = attrib & 0x7f;
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ color,
+ 0);
+ tileinfo->category = (attrib & 0x0f00) >> 8;
+}
+
+static TILE_GET_INFO( batrider_get_fg0_tile_info )
+{
+ int color, tile_number, attrib, tile;
+
+ attrib = fgvideoram16[0][2*tile_index];
+ tile = fgvideoram16[0][2*tile_index+1];
+ tile_number = ( batrider_object_bank[(tile >> 13) & 7] << 13 ) | ( tile & 0x1fff );
+ color = attrib & 0x7f;
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ color,
+ 0);
+ tileinfo->category = (attrib & 0x0f00) >> 8;
+}
+
+static TILE_GET_INFO( batrider_get_bg0_tile_info )
+{
+ int color, tile_number, attrib, tile;
+
+ attrib = bgvideoram16[0][2*tile_index];
+ tile = bgvideoram16[0][2*tile_index+1];
+ tile_number = ( batrider_object_bank[(tile >> 13) & 7] << 13 ) | ( tile & 0x1fff );
+ color = attrib & 0x7f;
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ color,
+ 0);
+ tileinfo->category = (attrib & 0x0f00) >> 8;
+}
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ int color, tile_number, attrib;
+
+ attrib = toaplan2_txvideoram16[tile_index];
+ tile_number = attrib & 0x3ff;
+ color = ((attrib >> 10) | 0x40) & 0x7f;
+ SET_TILE_INFO(
+ 2,
+ tile_number,
+ color,
+ 0);
+ tileinfo->category = 0;
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+static void create_tilemaps_0(void)
+{
+ top_tilemap[0] = tilemap_create(get_top0_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ fg_tilemap[0] = tilemap_create(get_fg0_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ bg_tilemap[0] = tilemap_create(get_bg0_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ tilemap_set_transparent_pen(top_tilemap[0],0);
+ tilemap_set_transparent_pen(fg_tilemap[0],0);
+ tilemap_set_transparent_pen(bg_tilemap[0],0);
+}
+
+static void create_tilemaps_1(void)
+{
+ top_tilemap[1] = tilemap_create(get_top1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ fg_tilemap[1] = tilemap_create(get_fg1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ bg_tilemap[1] = tilemap_create(get_bg1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ tilemap_set_transparent_pen(top_tilemap[1],0);
+ tilemap_set_transparent_pen(fg_tilemap[1],0);
+ tilemap_set_transparent_pen(bg_tilemap[1],0);
+}
+
+static void truxton2_create_tilemaps_0(void)
+{
+ tx_tilemap = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ top_tilemap[0] = tilemap_create(get_top0_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ fg_tilemap[0] = tilemap_create(get_fg0_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ bg_tilemap[0] = tilemap_create(get_bg0_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ tilemap_set_scroll_rows(tx_tilemap,8*32); /* line scrolling */
+ tilemap_set_scroll_cols(tx_tilemap,1);
+
+ tilemap_set_transparent_pen(tx_tilemap,0);
+ tilemap_set_transparent_pen(top_tilemap[0],0);
+ tilemap_set_transparent_pen(fg_tilemap[0],0);
+ tilemap_set_transparent_pen(bg_tilemap[0],0);
+}
+
+static void batrider_create_tilemaps_0(void)
+{
+ tx_tilemap = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+ top_tilemap[0] = tilemap_create(batrider_get_top0_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ fg_tilemap[0] = tilemap_create(batrider_get_fg0_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ bg_tilemap[0] = tilemap_create(batrider_get_bg0_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ tilemap_set_scroll_rows(tx_tilemap,8*32); /* line scrolling */
+ tilemap_set_scroll_cols(tx_tilemap,1);
+
+ tilemap_set_transparent_pen(tx_tilemap,0);
+ tilemap_set_transparent_pen(top_tilemap[0],0);
+ tilemap_set_transparent_pen(fg_tilemap[0],0);
+ tilemap_set_transparent_pen(bg_tilemap[0],0);
+}
+
+
+static void toaplan2_vram_alloc(int controller)
+{
+ spriteram16_new[controller] = auto_malloc(TOAPLAN2_SPRITERAM_SIZE);
+ memset(spriteram16_new[controller],0,TOAPLAN2_SPRITERAM_SIZE);
+
+ spriteram16_now[controller] = auto_malloc(TOAPLAN2_SPRITERAM_SIZE);
+ memset(spriteram16_now[controller],0,TOAPLAN2_SPRITERAM_SIZE);
+
+ topvideoram16[controller] = auto_malloc(TOAPLAN2_TOP_VRAM_SIZE);
+ memset(topvideoram16[controller],0,TOAPLAN2_TOP_VRAM_SIZE);
+
+ fgvideoram16[controller] = auto_malloc(TOAPLAN2_FG_VRAM_SIZE);
+ memset(fgvideoram16[controller],0,TOAPLAN2_FG_VRAM_SIZE);
+
+ bgvideoram16[controller] = auto_malloc(TOAPLAN2_BG_VRAM_SIZE);
+ memset(bgvideoram16[controller],0,TOAPLAN2_BG_VRAM_SIZE);
+
+ spriteram16_n[controller] = spriteram16_now[controller];
+}
+
+static void toaplan2_vh_start(int controller)
+{
+ toaplan2_vram_alloc(controller);
+
+ if (controller == 0)
+ {
+ create_tilemaps_0();
+ }
+ if (controller == 1)
+ {
+ create_tilemaps_1();
+ }
+}
+
+VIDEO_START( toaplan2_0 )
+{
+ defaultOffsets();
+ toaplan2_vh_start(0);
+}
+
+VIDEO_START( toaplan2_1 )
+{
+ toaplan2_vh_start(0);
+ toaplan2_vh_start(1);
+ defaultOffsets();
+}
+
+VIDEO_START( truxton2_0 )
+{
+ toaplan2_vram_alloc(0);
+ truxton2_create_tilemaps_0();
+
+ if(!strcmp(machine->gamedrv->name,"fixeighb"))
+ {
+ xoffset[0]=-26;
+ xoffset[1]=-22;
+ xoffset[2]=-18;
+ xoffset[3]=8;
+
+ yoffset[0]=-15;
+ yoffset[1]=-15;
+ yoffset[2]=-15;
+ yoffset[3]=8;
+ tilemap_set_scrolldx(tx_tilemap, 0, 0);
+ }
+ else
+ {
+ defaultOffsets();
+ tilemap_set_scrolldx(tx_tilemap, 0x1d4 +1, 0x2a);
+ }
+}
+
+VIDEO_START( bgaregga_0 )
+{
+ toaplan2_vram_alloc(0);
+ truxton2_create_tilemaps_0();
+ tilemap_set_scrolldx(tx_tilemap, 0x1d4, 0x2a);
+ defaultOffsets();
+}
+
+VIDEO_START( batrider_0 )
+{
+ raizing_tx_gfxram16 = auto_malloc(RAIZING_TX_GFXRAM_SIZE);
+ memset(raizing_tx_gfxram16,0,RAIZING_TX_GFXRAM_SIZE);
+
+ toaplan2_vram_alloc(0);
+ spriteram16_n[0] = spriteram16_new[0];
+
+ batrider_create_tilemaps_0();
+
+ tilemap_set_scrolldx(tx_tilemap, 0x1d4, 0x2a);
+ defaultOffsets();
+}
+
+
+/***************************************************************************
+
+ Video I/O port hardware.
+
+***************************************************************************/
+
+static void toaplan2_voffs_w(offs_t offset, UINT16 data, UINT32 mem_mask, int controller)
+{
+ if (data >= 0x1c00)
+ logerror("Hmmm, unknown video controller %01x layer being selected (%08x)\n",controller,data);
+ COMBINE_DATA(&toaplan2_voffs[controller]);
+}
+
+WRITE16_HANDLER( toaplan2_0_voffs_w )
+{
+ toaplan2_voffs_w(offset, data, mem_mask, 0);
+}
+
+WRITE16_HANDLER( toaplan2_1_voffs_w )
+{
+ toaplan2_voffs_w(offset, data, mem_mask, 1);
+}
+
+READ16_HANDLER( toaplan2_txvideoram16_r )
+{
+ return toaplan2_txvideoram16[offset];
+}
+
+WRITE16_HANDLER( toaplan2_txvideoram16_w )
+{
+ COMBINE_DATA(&toaplan2_txvideoram16[offset]);
+ if (offset < (toaplan2_tx_vram_size/4))
+ tilemap_mark_tile_dirty(tx_tilemap,offset);
+}
+
+READ16_HANDLER( toaplan2_txvideoram16_offs_r )
+{
+ return toaplan2_txvideoram16_offs[offset];
+}
+WRITE16_HANDLER( toaplan2_txvideoram16_offs_w )
+{
+ /* Besides containing flip, function of this RAM is still unknown */
+ /* This is however line related as per line-scroll RAM below */
+ /* Maybe specifies which line to draw text info (line number data is */
+ /* opposite when flip bits are on) */
+
+ UINT16 oldword = toaplan2_txvideoram16_offs[offset];
+
+ if (oldword != data)
+ {
+ if (offset == 0) /* Wrong ! */
+ {
+ if (data & 0x8000) /* Flip off */
+ {
+ tx_flip = 0;
+ tilemap_set_flip(tx_tilemap, tx_flip);
+ tilemap_set_scrolly(tx_tilemap, 0, 0);
+ }
+ else /* Flip on */
+ {
+ tx_flip = (TILEMAP_FLIPY | TILEMAP_FLIPX);
+ tilemap_set_flip(tx_tilemap, tx_flip);
+ tilemap_set_scrolly(tx_tilemap, 0, -16);
+ }
+ }
+ COMBINE_DATA(&toaplan2_txvideoram16_offs[offset]);
+ }
+// logerror("Writing %04x to text offs RAM offset %04x\n",data,offset);
+}
+
+READ16_HANDLER( toaplan2_txscrollram16_r )
+{
+ return toaplan2_txscrollram16[offset];
+}
+WRITE16_HANDLER( toaplan2_txscrollram16_w )
+{
+ /*** Line-Scroll RAM for Text Layer ***/
+
+ int data_tx = data;
+
+ tilemap_set_scrollx(tx_tilemap, offset, data_tx);
+
+// logerror("Writing %04x to text scroll RAM offset %04x\n",data,offset);
+ COMBINE_DATA(&toaplan2_txscrollram16[offset]);
+}
+
+READ16_HANDLER( toaplan2_tx_gfxram16_r )
+{
+ return toaplan2_tx_gfxram16[offset];
+}
+
+WRITE16_HANDLER( toaplan2_tx_gfxram16_w )
+{
+ /*** Dynamic GFX decoding for Truxton 2 / FixEight ***/
+
+ UINT16 oldword = toaplan2_tx_gfxram16[offset];
+ UINT8 *toaplan2_tx_gfxram = (UINT8 *)(toaplan2_tx_gfxram16);
+
+ if (oldword != data)
+ {
+ int code = offset/32;
+ COMBINE_DATA(&toaplan2_tx_gfxram16[offset]);
+ decodechar(Machine->gfx[2], code, toaplan2_tx_gfxram,
+ Machine->drv->gfxdecodeinfo[2].gfxlayout);
+
+ tilemap_mark_all_tiles_dirty(tx_tilemap);
+ }
+}
+
+READ16_HANDLER( raizing_tx_gfxram16_r )
+{
+ offset += 0x3400/2;
+ return raizing_tx_gfxram16[offset];
+}
+WRITE16_HANDLER( raizing_tx_gfxram16_w )
+{
+ /*** Dynamic Text GFX decoding for Batrider ***/
+
+ UINT16 oldword = raizing_tx_gfxram16[offset + (0x3400 / 2)];
+
+ if (oldword != data)
+ {
+ offset += 0x3400/2;
+ COMBINE_DATA(&raizing_tx_gfxram16[offset]);
+ }
+}
+
+WRITE16_HANDLER( batrider_textdata_decode )
+{
+ /*** Dynamic Text GFX decoding for Batrider ***/
+ /*** Only done once during start-up ***/
+
+ int code;
+ UINT8 *raizing_tx_gfxram = (UINT8 *)raizing_tx_gfxram16;
+ UINT16 *dest = (UINT16 *)raizing_tx_gfxram16;
+
+ memcpy(dest, toaplan2_txvideoram16, toaplan2_tx_vram_size);
+ dest += (toaplan2_tx_vram_size/2);
+ memcpy(dest, paletteram16, batrider_paletteram16_size);
+ dest += (batrider_paletteram16_size/2);
+ memcpy(dest, toaplan2_txvideoram16_offs, toaplan2_tx_offs_vram_size);
+ dest += (toaplan2_tx_offs_vram_size/2);
+ memcpy(dest, toaplan2_txscrollram16, toaplan2_tx_scroll_vram_size);
+
+ /* Decode text characters */
+ for (code = 0; code < 1024; code++)
+ decodechar (Machine->gfx[2], code, raizing_tx_gfxram, Machine->drv->gfxdecodeinfo[2].gfxlayout);
+ tilemap_mark_all_tiles_dirty(tx_tilemap);
+}
+
+WRITE16_HANDLER( batrider_objectbank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ data &= 0xf;
+ if (batrider_object_bank[offset] != data)
+ {
+ batrider_object_bank[offset] = data;
+ objectbank_dirty = 1;
+ }
+ }
+}
+
+
+
+static int toaplan2_videoram16_r(offs_t offset, int controller)
+{
+ static UINT16 video_data = 0;
+ static offs_t vram_offset;
+
+
+ switch (toaplan2_voffs[controller] & 0xfc00)
+ {
+ case 0x0400:
+ case 0x0000:
+ vram_offset = toaplan2_voffs[controller] & ((TOAPLAN2_BG_VRAM_SIZE/2)-1);
+ video_data = bgvideoram16[controller][vram_offset];
+ break;
+ case 0x0c00:
+ case 0x0800:
+ vram_offset = toaplan2_voffs[controller] & ((TOAPLAN2_FG_VRAM_SIZE/2)-1);
+ video_data = fgvideoram16[controller][vram_offset];
+ break;
+ case 0x1400:
+ case 0x1000:
+ vram_offset = toaplan2_voffs[controller] & ((TOAPLAN2_TOP_VRAM_SIZE/2)-1);
+ video_data = topvideoram16[controller][vram_offset];
+ break;
+ case 0x1800:
+ vram_offset = toaplan2_voffs[controller] & ((TOAPLAN2_SPRITERAM_SIZE/2)-1);
+ video_data = spriteram16_new[controller][vram_offset];
+ break;
+ default:
+ video_data = toaplan2_overflow_vram;
+ logerror("Hmmm, reading %04x from unknown VC:%01x layer address %06x Offset:%01x !!!\n",video_data,controller,toaplan2_voffs[controller],offset);
+ break;
+ }
+ toaplan2_voffs[controller]++;
+ return video_data;
+}
+
+READ16_HANDLER( toaplan2_0_videoram16_r )
+{
+ return toaplan2_videoram16_r(offset, 0);
+}
+
+READ16_HANDLER( toaplan2_1_videoram16_r )
+{
+ return toaplan2_videoram16_r(offset, 1);
+}
+
+static void toaplan2_videoram16_w(offs_t offset, UINT16 data, UINT32 mem_mask, int controller)
+{
+ offs_t vram_offset;
+
+ switch (toaplan2_voffs[controller] & 0xfc00)
+ {
+ case 0x0400:
+ case 0x0000:
+ vram_offset = toaplan2_voffs[controller] & ((TOAPLAN2_BG_VRAM_SIZE/2)-1);
+ COMBINE_DATA(&bgvideoram16[controller][vram_offset]);
+ tilemap_mark_tile_dirty(bg_tilemap[controller],vram_offset/2);
+ break;
+ case 0x0c00:
+ case 0x0800:
+ vram_offset = toaplan2_voffs[controller] & ((TOAPLAN2_FG_VRAM_SIZE/2)-1);
+ COMBINE_DATA(&fgvideoram16[controller][vram_offset]);
+ tilemap_mark_tile_dirty(fg_tilemap[controller],vram_offset/2);
+ break;
+ case 0x1400:
+ case 0x1000:
+ vram_offset = toaplan2_voffs[controller] & ((TOAPLAN2_TOP_VRAM_SIZE/2)-1);
+ COMBINE_DATA(&topvideoram16[controller][vram_offset]);
+ tilemap_mark_tile_dirty(top_tilemap[controller],vram_offset/2);
+ break;
+ case 0x1800:
+ vram_offset = toaplan2_voffs[controller] & ((TOAPLAN2_SPRITERAM_SIZE/2)-1);
+ COMBINE_DATA(&spriteram16_new[controller][vram_offset]);
+ break;
+ default:
+ toaplan2_overflow_vram = data;
+ logerror("Hmmm, writing %04x to unknown VC:%01x layer address %06x Offset:%01x\n",data,controller,toaplan2_voffs[controller],offset);
+ break;
+ }
+ toaplan2_voffs[controller]++;
+}
+
+WRITE16_HANDLER( toaplan2_0_videoram16_w )
+{
+ toaplan2_videoram16_w(offset, data, mem_mask, 0);
+}
+
+WRITE16_HANDLER( toaplan2_1_videoram16_w )
+{
+ toaplan2_videoram16_w(offset, data, mem_mask, 1);
+}
+
+
+static void toaplan2_scroll_reg_select_w(offs_t offset, UINT16 data, UINT32 mem_mask, int controller)
+{
+ if (ACCESSING_LSB)
+ {
+ toaplan2_scroll_reg[controller] = data & 0x8f;
+ if (data & 0x70)
+ logerror("Hmmm, selecting unknown LSB video control register (%04x) Video controller %01x \n",toaplan2_scroll_reg[controller],controller);
+ }
+ else
+ {
+ logerror("Hmmm, selecting unknown MSB video control register (%04x) Video controller %01x \n",toaplan2_scroll_reg[controller],controller);
+ }
+}
+
+WRITE16_HANDLER( toaplan2_0_scroll_reg_select_w )
+{
+ toaplan2_scroll_reg_select_w(offset, data, mem_mask, 0);
+}
+
+WRITE16_HANDLER( toaplan2_1_scroll_reg_select_w )
+{
+ toaplan2_scroll_reg_select_w(offset, data, mem_mask, 1);
+}
+
+
+static void toaplan2_scroll_reg_data_w(offs_t offset, UINT16 data, UINT32 mem_mask, int controller)
+{
+ /************************************************************************/
+ /***** layer X and Y flips can be set independantly, so emulate it ******/
+ /************************************************************************/
+
+#ifdef MAME_DEBUG
+ int vid_controllers = 1;
+#endif
+
+ switch(toaplan2_scroll_reg[controller])
+ {
+ case 0x00: data -= 0x1d6; /* 1D6h */
+ COMBINE_DATA(&bg_scrollx[controller]);
+ bg_flip[controller] &= (~TILEMAP_FLIPX);
+ tilemap_set_flip(bg_tilemap[controller],bg_flip[controller]);
+ tilemap_set_scrollx(bg_tilemap[controller],0,bg_scrollx[controller]+xoffset[0]);
+ break;
+ case 0x01: data -= 0x1ef; /* 1EFh */
+ COMBINE_DATA(&bg_scrolly[controller]);
+ bg_flip[controller] &= (~TILEMAP_FLIPY);
+ tilemap_set_flip(bg_tilemap[controller],bg_flip[controller]);
+ tilemap_set_scrolly(bg_tilemap[controller],0,bg_scrolly[controller]+yoffset[0]);
+ break;
+ case 0x02: data -= 0x1d8; /* 1D0h */
+ COMBINE_DATA(&fg_scrollx[controller]);
+ fg_flip[controller] &= (~TILEMAP_FLIPX);
+ tilemap_set_flip(fg_tilemap[controller],fg_flip[controller]);
+ tilemap_set_scrollx(fg_tilemap[controller],0,fg_scrollx[controller]+xoffset[1]);
+ break;
+ case 0x03: data -= 0x1ef; /* 1EFh */
+ COMBINE_DATA(&fg_scrolly[controller]);
+ fg_flip[controller] &= (~TILEMAP_FLIPY);
+ tilemap_set_flip(fg_tilemap[controller],fg_flip[controller]);
+ tilemap_set_scrolly(fg_tilemap[controller],0,fg_scrolly[controller]+yoffset[1]);
+ break;
+ case 0x04: data -= 0x1da; /* 1DAh */
+ COMBINE_DATA(&top_scrollx[controller]);
+ top_flip[controller] &= (~TILEMAP_FLIPX);
+ tilemap_set_flip(top_tilemap[controller],top_flip[controller]);
+ tilemap_set_scrollx(top_tilemap[controller],0,top_scrollx[controller]+xoffset[2]);
+ break;
+ case 0x05: data -= 0x1ef; /* 1EFh */
+ COMBINE_DATA(&top_scrolly[controller]);
+ top_flip[controller] &= (~TILEMAP_FLIPY);
+ tilemap_set_flip(top_tilemap[controller],top_flip[controller]);
+ tilemap_set_scrolly(top_tilemap[controller],0,top_scrolly[controller]+yoffset[2]);
+ break;
+ case 0x06: data -= 0x1cc; /* 1D4h */
+ COMBINE_DATA(&sprite_scrollx[controller]);
+ if (sprite_scrollx[controller] & 0x8000) sprite_scrollx[controller] |= 0xfffffe00;
+ else sprite_scrollx[controller] &= 0x1ff;
+ sprite_flip[controller] &= (~TOAPLAN2_SPRITE_FLIPX);
+ break;
+ case 0x07: data -= 0x1ef; /* 1F7h */
+ COMBINE_DATA(&sprite_scrolly[controller]);
+ if (sprite_scrolly[controller] & 0x8000) sprite_scrolly[controller] |= 0xfffffe00;
+ else sprite_scrolly[controller] &= 0x1ff;
+ sprite_flip[controller] &= (~TOAPLAN2_SPRITE_FLIPY);
+ break;
+ case 0x0f: break;
+ case 0x80: data -= 0x229; /* 169h */
+ COMBINE_DATA(&bg_scrollx[controller]);
+ bg_flip[controller] |= TILEMAP_FLIPX;
+ tilemap_set_flip(bg_tilemap[controller],bg_flip[controller]);
+ tilemap_set_scrollx(bg_tilemap[controller],0,bg_scrollx[controller]+xoffset[0]);
+ break;
+ case 0x81: data -= 0x210; /* 100h */
+ COMBINE_DATA(&bg_scrolly[controller]);
+ bg_flip[controller] |= TILEMAP_FLIPY;
+ tilemap_set_flip(bg_tilemap[controller],bg_flip[controller]);
+ tilemap_set_scrolly(bg_tilemap[controller],0,bg_scrolly[controller]+yoffset[0]);
+ break;
+ case 0x82: data -= 0x227; /* 15Fh */
+ COMBINE_DATA(&fg_scrollx[controller]);
+ fg_flip[controller] |= TILEMAP_FLIPX;
+ tilemap_set_flip(fg_tilemap[controller],fg_flip[controller]);
+ tilemap_set_scrollx(fg_tilemap[controller],0,fg_scrollx[controller]+xoffset[1]);
+ break;
+ case 0x83: data -= 0x210; /* 100h */
+ COMBINE_DATA(&fg_scrolly[controller]);
+ fg_flip[controller] |= TILEMAP_FLIPY;
+ tilemap_set_flip(fg_tilemap[controller],fg_flip[controller]);
+ tilemap_set_scrolly(fg_tilemap[controller],0,fg_scrolly[controller]+yoffset[1]);
+ break;
+ case 0x84: data -= 0x225; /* 165h */
+ COMBINE_DATA(&top_scrollx[controller]);
+ top_flip[controller] |= TILEMAP_FLIPX;
+ tilemap_set_flip(top_tilemap[controller],top_flip[controller]);
+ tilemap_set_scrollx(top_tilemap[controller],0,top_scrollx[controller]+xoffset[2]);
+ break;
+ case 0x85: data -= 0x210; /* 100h */
+ COMBINE_DATA(&top_scrolly[controller]);
+ top_flip[controller] |= TILEMAP_FLIPY;
+ tilemap_set_flip(top_tilemap[controller],top_flip[controller]);
+ tilemap_set_scrolly(top_tilemap[controller],0,top_scrolly[controller]+yoffset[2]);
+ break;
+ case 0x86: data -= 0x17b; /* 17Bh */
+ COMBINE_DATA(&sprite_scrollx[controller]);
+ if (sprite_scrollx[controller] & 0x8000) sprite_scrollx[controller] |= 0xfffffe00;
+ else sprite_scrollx[controller] &= 0x1ff;
+ sprite_flip[controller] |= TOAPLAN2_SPRITE_FLIPX;
+ break;
+ case 0x87: data -= 0x108; /* 108h */
+ COMBINE_DATA(&sprite_scrolly[controller]);
+ if (sprite_scrolly[controller] & 0x8000) sprite_scrolly[controller] |= 0xfffffe00;
+ else sprite_scrolly[controller] &= 0x1ff;
+ sprite_flip[controller] |= TOAPLAN2_SPRITE_FLIPY;
+ break;
+ case 0x8f: break;
+
+ case 0x0e: /******* Initialise video controller register ? *******/
+ if ((toaplan2_sub_cpu == CPU_2_Z80) && (data == 3))
+ {
+ /* HACK! When tilted, sound CPU needs to be reset. */
+ if (Machine->drv->sound[0].type == SOUND_YM3812)
+ {
+ cpunum_set_input_line(1, INPUT_LINE_RESET, PULSE_LINE);
+ sndti_reset(SOUND_YM3812, 0);
+ }
+ }
+
+ default: logerror("Hmmm, writing %08x to unknown video control register (%08x) Video controller %01x !!!\n",data ,toaplan2_scroll_reg[controller],controller);
+ break;
+ }
+
+#ifdef MAME_DEBUG
+
+ if (spriteram16_now[1] && spriteram16_new[1]
+ && top_tilemap[1] && fg_tilemap[1] && bg_tilemap[1])
+ {
+ vid_controllers = 2;
+ }
+
+ if ( input_code_pressed_once(KEYCODE_W) )
+ {
+ display_tx += 1;
+ display_tx &= 1;
+ if (toaplan2_txvideoram16 != 0)
+ tilemap_set_enable(tx_tilemap, display_tx);
+ }
+ if ( input_code_pressed_once(KEYCODE_L) )
+ {
+ display_sp[0] += 1;
+ display_sp[0] &= 1;
+ }
+ if ( input_code_pressed_once(KEYCODE_K) )
+ {
+ display_top[0] += 1;
+ display_top[0] &= 1;
+ tilemap_set_enable(top_tilemap[0], display_top[0]);
+ }
+ if ( input_code_pressed_once(KEYCODE_J) )
+ {
+ display_fg[0] += 1;
+ display_fg[0] &= 1;
+ tilemap_set_enable(fg_tilemap[0], display_fg[0]);
+ }
+ if ( input_code_pressed_once(KEYCODE_H) )
+ {
+ display_bg[0] += 1;
+ display_bg[0] &= 1;
+ tilemap_set_enable(bg_tilemap[0], display_bg[0]);
+ }
+ if (vid_controllers == 2)
+ {
+ if ( input_code_pressed_once(KEYCODE_O) )
+ {
+ display_sp[1] += 1;
+ display_sp[1] &= 1;
+ }
+ if ( input_code_pressed_once(KEYCODE_I) )
+ {
+ display_top[1] += 1;
+ display_top[1] &= 1;
+ tilemap_set_enable(top_tilemap[1], display_top[1]);
+ }
+ if ( input_code_pressed_once(KEYCODE_U) )
+ {
+ display_fg[1] += 1;
+ display_fg[1] &= 1;
+ tilemap_set_enable(fg_tilemap[1], display_fg[1]);
+ }
+ if ( input_code_pressed_once(KEYCODE_Y) )
+ {
+ display_bg[1] += 1;
+ display_bg[1] &= 1;
+ tilemap_set_enable(bg_tilemap[1], display_bg[1]);
+ }
+ }
+#endif
+}
+
+WRITE16_HANDLER( toaplan2_0_scroll_reg_data_w )
+{
+ toaplan2_scroll_reg_data_w(offset, data, mem_mask, 0);
+}
+
+WRITE16_HANDLER( toaplan2_1_scroll_reg_data_w )
+{
+ toaplan2_scroll_reg_data_w(offset, data, mem_mask, 1);
+}
+
+
+/***************************************************************************/
+/**************** PIPIBIBI interface into this video driver ****************/
+
+WRITE16_HANDLER( pipibibi_scroll_w )
+{
+ if (ACCESSING_MSB && ACCESSING_LSB)
+ {
+ switch(offset)
+ {
+ case 0x00: data -= 0x01f; break;
+ case 0x01: data += 0x1ef; break;
+ case 0x02: data -= 0x01d; break;
+ case 0x03: data += 0x1ef; break;
+ case 0x04: data -= 0x01b; break;
+ case 0x05: data += 0x1ef; break;
+ case 0x06: data += 0x1d4; break;
+ case 0x07: data += 0x1f7; break;
+ default: logerror("PIPIBIBI writing %04x to unknown scroll register %04x",data, offset);
+ }
+
+ toaplan2_scroll_reg[0] = offset;
+ toaplan2_scroll_reg_data_w(offset, data, mem_mask, 0);
+ }
+}
+
+READ16_HANDLER( pipibibi_videoram16_r )
+{
+ toaplan2_voffs_w(0, offset, 0, 0);
+ return toaplan2_videoram16_r(0, 0);
+}
+
+WRITE16_HANDLER( pipibibi_videoram16_w)
+{
+ toaplan2_voffs_w(0, offset, 0, 0);
+ toaplan2_videoram16_w(0, data, mem_mask, 0);
+}
+
+READ16_HANDLER( pipibibi_spriteram16_r )
+{
+ toaplan2_voffs_w(0, (0x1800 + offset), 0, 0);
+ return toaplan2_videoram16_r(0, 0);
+}
+
+WRITE16_HANDLER( pipibibi_spriteram16_w )
+{
+ toaplan2_voffs_w(0, (0x1800 + offset), mem_mask, 0);
+ toaplan2_videoram16_w(0, data, mem_mask, 0);
+}
+
+
+
+#ifdef MAME_DEBUG
+void toaplan2_log_vram(void)
+{
+ offs_t sprite_voffs, tile_voffs;
+ int vid_controllers = 1;
+
+ if (spriteram16_now[1] && spriteram16_new[1]
+ && top_tilemap[1] && fg_tilemap[1] && bg_tilemap[1])
+ {
+ vid_controllers = 2;
+ }
+
+ if ( input_code_pressed_once(KEYCODE_M) )
+ {
+ UINT16 *source_now0 = (UINT16 *)(spriteram16_now[0]);
+ UINT16 *source_new0 = (UINT16 *)(spriteram16_new[0]);
+ UINT16 *source_now1 = (UINT16 *)(spriteram16_now[0]);
+ UINT16 *source_new1 = (UINT16 *)(spriteram16_new[0]);
+
+ int schar[2],sattr[2],sxpos[2],sypos[2];
+
+ if (vid_controllers == 2)
+ {
+ source_now1 = (UINT16 *)(spriteram16_now[1]);
+ source_new1 = (UINT16 *)(spriteram16_new[1]);
+ }
+
+ logerror("Scrolls BG-X BG-Y FG-X FG-Y TOP-X TOP-Y Sprite-X Sprite-Y\n");
+ logerror("---0--> %04x %04x %04x %04x %04x %04x %04x %04x\n", bg_scrollx[0],bg_scrolly[0],fg_scrollx[0],fg_scrolly[0],top_scrollx[0],top_scrolly[0],sprite_scrollx[0], sprite_scrolly[0]);
+ if (vid_controllers == 2)
+ {
+ logerror("---1--> %04x %04x %04x %04x %04x %04x %04x %04x\n", bg_scrollx[1],bg_scrolly[1],fg_scrollx[1],fg_scrolly[1],top_scrollx[1],top_scrolly[1],sprite_scrollx[1], sprite_scrolly[1]);
+ }
+ for ( sprite_voffs = 0; sprite_voffs < (TOAPLAN2_SPRITERAM_SIZE/2); sprite_voffs += 4 )
+ {
+ sattr[0] = source_now0[sprite_voffs];
+ schar[0] = source_now0[sprite_voffs + 1];
+ sxpos[0] = source_now0[sprite_voffs + 2];
+ sypos[0] = source_now0[sprite_voffs + 3];
+ sattr[1] = source_new0[sprite_voffs];
+ schar[1] = source_new0[sprite_voffs + 1];
+ sxpos[1] = source_new0[sprite_voffs + 2];
+ sypos[1] = source_new0[sprite_voffs + 3];
+ logerror("SPoffs Sprt Attr Xpos Ypos Sprt Attr Xpos Ypos\n");
+ logerror("0:%03x now:%04x %04x %04x %04x new:%04x %04x %04x %04x\n",sprite_voffs,
+ schar[0], sattr[0],sxpos[0], sypos[0],
+ schar[1], sattr[1],sxpos[1], sypos[1]);
+ if (vid_controllers == 2)
+ {
+ sattr[0] = source_now1[sprite_voffs];
+ schar[0] = source_now1[sprite_voffs + 1];
+ sxpos[0] = source_now1[sprite_voffs + 2];
+ sypos[0] = source_now1[sprite_voffs + 3];
+ sattr[1] = source_new1[sprite_voffs];
+ schar[1] = source_new1[sprite_voffs + 1];
+ sxpos[1] = source_new1[sprite_voffs + 2];
+ sypos[1] = source_new1[sprite_voffs + 3];
+ logerror("1:%03x now:%04x %04x %04x %04x new:%04x %04x %04x %04x\n",sprite_voffs,
+ schar[0], sattr[0],sxpos[0], sypos[0],
+ schar[1], sattr[1],sxpos[1], sypos[1]);
+ }
+ }
+ }
+ if ( input_code_pressed_once(KEYCODE_N) )
+ {
+ int tchar[2], tattr[2];
+ logerror("Scrolls BG-X BG-Y FG-X FG-Y TOP-X TOP-Y Sprite-X Sprite-Y\n");
+ logerror("---0--> %04x %04x %04x %04x %04x %04x %04x %04x\n", bg_scrollx[0],bg_scrolly[0],fg_scrollx[0],fg_scrolly[0],top_scrollx[0],top_scrolly[0],sprite_scrollx[0], sprite_scrolly[0]);
+ if (vid_controllers == 2)
+ {
+ logerror("---1--> %04x %04x %04x %04x %04x %04x %04x %04x\n", bg_scrollx[1],bg_scrolly[1],fg_scrollx[1],fg_scrolly[1],top_scrollx[1],top_scrolly[1],sprite_scrollx[1], sprite_scrolly[1]);
+ }
+ for ( tile_voffs = 0; tile_voffs < (TOAPLAN2_TOP_VRAM_SIZE/2); tile_voffs += 2 )
+ {
+ tchar[0] = topvideoram16[0][tile_voffs + 1];
+ tattr[0] = topvideoram16[0][tile_voffs];
+ if (vid_controllers == 2)
+ {
+ tchar[1] = topvideoram16[1][tile_voffs + 1];
+ tattr[1] = topvideoram16[1][tile_voffs];
+ logerror("TOPoffs:%04x Tile0:%04x Attr0:%04x Tile1:%04x Attr1:%04x\n", tile_voffs, tchar[0], tattr[0], tchar[1], tattr[1]);
+ }
+ else
+ {
+ logerror("TOPoffs:%04x Tile0:%04x Attr0:%04x\n", tile_voffs, tchar[0], tattr[0]);
+ }
+ }
+ }
+ if ( input_code_pressed_once(KEYCODE_B) )
+ {
+ int tchar[2], tattr[2];
+ logerror("Scrolls BG-X BG-Y FG-X FG-Y TOP-X TOP-Y Sprite-X Sprite-Y\n");
+ logerror("---0--> %04x %04x %04x %04x %04x %04x %04x %04x\n", bg_scrollx[0],bg_scrolly[0],fg_scrollx[0],fg_scrolly[0],top_scrollx[0],top_scrolly[0],sprite_scrollx[0], sprite_scrolly[0]);
+ if (vid_controllers == 2)
+ {
+ logerror("---1--> %04x %04x %04x %04x %04x %04x %04x %04x\n", bg_scrollx[1],bg_scrolly[1],fg_scrollx[1],fg_scrolly[1],top_scrollx[1],top_scrolly[1],sprite_scrollx[1], sprite_scrolly[1]);
+ }
+ for ( tile_voffs = 0; tile_voffs < (TOAPLAN2_FG_VRAM_SIZE/2); tile_voffs += 2 )
+ {
+ tchar[0] = fgvideoram16[0][tile_voffs + 1];
+ tattr[0] = fgvideoram16[0][tile_voffs];
+ if (vid_controllers == 2)
+ {
+ tchar[1] = fgvideoram16[1][tile_voffs + 1];
+ tattr[1] = fgvideoram16[1][tile_voffs];
+ logerror("FGoffs:%04x Tile0:%04x Attr0:%04x Tile1:%04x Attr1:%04x\n", tile_voffs, tchar[0], tattr[0], tchar[1], tattr[1]);
+ }
+ else
+ {
+ logerror("FGoffs:%04x Tile0:%04x Attr0:%04x\n", tile_voffs, tchar[0], tattr[0]);
+ }
+ }
+ }
+ if ( input_code_pressed_once(KEYCODE_V) )
+ {
+ int tchar[2], tattr[2];
+ logerror("Scrolls BG-X BG-Y FG-X FG-Y TOP-X TOP-Y Sprite-X Sprite-Y\n");
+ logerror("---0--> %04x %04x %04x %04x %04x %04x %04x %04x\n", bg_scrollx[0],bg_scrolly[0],fg_scrollx[0],fg_scrolly[0],top_scrollx[0],top_scrolly[0],sprite_scrollx[0], sprite_scrolly[0]);
+ if (vid_controllers == 2)
+ {
+ logerror("---1--> %04x %04x %04x %04x %04x %04x %04x %04x\n", bg_scrollx[1],bg_scrolly[1],fg_scrollx[1],fg_scrolly[1],top_scrollx[1],top_scrolly[1],sprite_scrollx[1], sprite_scrolly[1]);
+ }
+ for ( tile_voffs = 0; tile_voffs < (TOAPLAN2_BG_VRAM_SIZE/2); tile_voffs += 2 )
+ {
+ tchar[0] = bgvideoram16[0][tile_voffs + 1];
+ tattr[0] = bgvideoram16[0][tile_voffs];
+ if (vid_controllers == 2)
+ {
+ tchar[1] = bgvideoram16[1][tile_voffs + 1];
+ tattr[1] = bgvideoram16[1][tile_voffs];
+ logerror("BGoffs:%04x Tile0:%04x Attr0:%04x Tile1:%04x Attr1:%04x\n", tile_voffs, tchar[0], tattr[0], tchar[1], tattr[1]);
+ }
+ else
+ {
+ logerror("BGoffs:%04x Tile0:%04x Attr0:%04x\n", tile_voffs, tchar[0], tattr[0]);
+ }
+ }
+ }
+
+ if ( input_code_pressed_once(KEYCODE_C) )
+ logerror("Mark here\n");
+
+ if ( input_code_pressed_once(KEYCODE_E) )
+ {
+ displog += 1;
+ displog &= 1;
+ }
+ if (displog)
+ {
+ logerror("Scrolls BG-X BG-Y FG-X FG-Y TOP-X TOP-Y Sprite-X Sprite-Y\n");
+ logerror("---0--> %04x %04x %04x %04x %04x %04x %04x %04x\n", bg_scrollx[0],bg_scrolly[0],fg_scrollx[0],fg_scrolly[0],top_scrollx[0],top_scrolly[0],sprite_scrollx[0], sprite_scrolly[0]);
+ if (vid_controllers == 2)
+ {
+ logerror("---1--> %04x %04x %04x %04x %04x %04x %04x %04x\n", bg_scrollx[1],bg_scrolly[1],fg_scrollx[1],fg_scrolly[1],top_scrollx[1],top_scrolly[1],sprite_scrollx[1], sprite_scrolly[1]);
+ }
+ }
+}
+#endif
+
+
+
+/***************************************************************************
+ Sprite Handlers
+***************************************************************************/
+
+static void draw_sprites( mame_bitmap *bitmap, const rectangle *cliprect, int controller, int priority_to_display, int bank_sel )
+{
+ const gfx_element *gfx = Machine->gfx[ ((controller*2)+1) ];
+
+ int offs;
+
+ UINT16 *source = (UINT16 *)(spriteram16_n[controller]);
+
+
+ priority_to_display <<= 8;
+
+ for (offs = 0; offs < (TOAPLAN2_SPRITERAM_SIZE/2); offs += 4)
+ {
+ int attrib, sprite, color, priority, flipx, flipy, sx, sy;
+ int sprite_sizex, sprite_sizey, dim_x, dim_y, sx_base, sy_base;
+ int bank, sprite_num;
+
+ attrib = source[offs];
+ priority = (attrib & 0x0f00);
+
+ if ((priority == priority_to_display) && (attrib & 0x8000))
+ {
+ if (!bank_sel) /* No Sprite select bank switching needed */
+ {
+ sprite = ((attrib & 3) << 16) | source[offs + 1]; /* 18 bit */
+ }
+ else /* Batrider Sprite select bank switching required */
+ {
+ sprite_num = source[offs + 1] & 0x7fff;
+ bank = ((attrib & 3) << 1) | (source[offs + 1] >> 15);
+ sprite = (batrider_object_bank[bank] << 15 ) | sprite_num;
+ }
+ color = (attrib >> 2) & 0x3f;
+
+ /***** find out sprite size *****/
+ sprite_sizex = ((source[offs + 2] & 0x0f) + 1) * 8;
+ sprite_sizey = ((source[offs + 3] & 0x0f) + 1) * 8;
+
+ /***** find position to display sprite *****/
+ sx_base = ((source[offs + 2] >> 7) - (sprite_scrollx[controller]+xoffset[3])) & 0x1ff;
+ sy_base = ((source[offs + 3] >> 7) - (sprite_scrolly[controller]+yoffset[3])) & 0x1ff;
+
+ flipx = attrib & TOAPLAN2_SPRITE_FLIPX;
+ flipy = attrib & TOAPLAN2_SPRITE_FLIPY;
+
+ if (flipx)
+ {
+ /***** Wrap sprite position around *****/
+ sx_base -= 7;
+ if (sx_base >= 0x1c0) sx_base -= 0x200;
+ }
+ else
+ {
+ if (sx_base >= 0x180) sx_base -= 0x200;
+ }
+
+ if (flipy)
+ {
+ sy_base -= 7;
+ if (sy_base >= 0x1c0) sy_base -= 0x200;
+ }
+ else
+ {
+ if (sy_base >= 0x180) sy_base -= 0x200;
+ }
+
+ /***** Flip the sprite layer in any active X or Y flip *****/
+ if (sprite_flip[controller])
+ {
+ if (sprite_flip[controller] & TOAPLAN2_SPRITE_FLIPX)
+ sx_base = 320 - sx_base;
+ if (sprite_flip[controller] & TOAPLAN2_SPRITE_FLIPY)
+ sy_base = 240 - sy_base;
+ }
+
+ /***** Cancel flip, if it, and sprite layer flip are active *****/
+ flipx = (flipx ^ (sprite_flip[controller] & TOAPLAN2_SPRITE_FLIPX));
+ flipy = (flipy ^ (sprite_flip[controller] & TOAPLAN2_SPRITE_FLIPY));
+
+ /***** Draw the complete sprites using the dimension info *****/
+ for (dim_y = 0; dim_y < sprite_sizey; dim_y += 8)
+ {
+ if (flipy) sy = sy_base - dim_y;
+ else sy = sy_base + dim_y;
+ for (dim_x = 0; dim_x < sprite_sizex; dim_x += 8)
+ {
+ if (flipx) sx = sx_base - dim_x;
+ else sx = sx_base + dim_x;
+
+ drawgfx(bitmap,gfx,sprite,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ sprite++ ;
+ }
+ }
+ }
+ }
+}
+
+
+/***************************************************************************
+ Mark the sprite priority used list.
+***************************************************************************/
+static void mark_sprite_priority(int controller)
+{
+ int priority, offs;
+
+ UINT16 *source = (UINT16 *)(spriteram16_n[controller]);
+
+
+ for (priority = 0; priority < 16; priority++)
+ sprite_priority[controller][priority] = 0; /* Clear priorities used list */
+
+ for (offs = 0; offs < (TOAPLAN2_SPRITERAM_SIZE/2); offs += 4)
+ {
+ priority = (source[offs] & 0x0f00) >> 8;
+ sprite_priority[controller][priority] = display_sp[controller];
+ }
+}
+
+/***************************************************************************
+ Mark the tile priority used list.
+***************************************************************************/
+static void mark_tile_priority(int controller)
+{
+ int priority, offs;
+
+ for (priority = 0; priority < 16; priority++)
+ {
+ top_tile_priority[controller][priority] = 0;
+ fg_tile_priority[controller][priority] = 0;
+ bg_tile_priority[controller][priority] = 0;
+ }
+
+ for (offs = 0; offs < (TOAPLAN2_BG_VRAM_SIZE/2); offs += 2)
+ {
+ top_tile_priority[controller][(topvideoram16[controller][offs] & 0x0f00) >> 8] = 1;
+ fg_tile_priority[controller][(fgvideoram16[controller][offs] & 0x0f00) >> 8] = 1;
+ bg_tile_priority[controller][(bgvideoram16[controller][offs] & 0x0f00) >> 8] = 1;
+ }
+
+#if 0
+ {
+ static int bg[2]={0,0},fg[2]={0,0},top[2]={0,0};
+ bg[controller]=0;fg[controller]=0;top[controller]=0;
+ for (priority = 0; priority < 16; priority++)
+ {
+ if (bg_tile_priority[controller][priority]) bg[controller]++;
+ if (fg_tile_priority[controller][priority]) fg[controller]++;
+ if (top_tile_priority[controller][priority]) top[controller]++;
+ }
+ popmessage("b=%2d:%2d f=%2d:%2d t=%2d:%2d",bg[0],bg[1],fg[0],fg[1],top[0],top[1]);
+ }
+#endif
+}
+
+/***************************************************************************
+ Draw the game screen in the given mame_bitmap.
+***************************************************************************/
+
+VIDEO_UPDATE( toaplan2_0 )
+{
+ int priority;
+
+
+#ifdef MAME_DEBUG
+ toaplan2_log_vram();
+#endif
+
+ mark_sprite_priority(0);
+ mark_tile_priority(0);
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ for (priority = 0; priority < 16; priority++)
+ {
+ if (bg_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,bg_tilemap[0],priority,0);
+ if (fg_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,fg_tilemap[0],priority,0);
+ if (top_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,top_tilemap[0],priority,0);
+ if (sprite_priority[0][priority])
+ draw_sprites(bitmap,cliprect,0,priority,0);
+ }
+ return 0;
+}
+
+VIDEO_UPDATE( dogyuun_1 )
+{
+ int priority;
+
+
+#ifdef MAME_DEBUG
+ toaplan2_log_vram();
+#endif
+
+ mark_sprite_priority(0);
+ mark_sprite_priority(1);
+ mark_tile_priority(0);
+ mark_tile_priority(1);
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ for (priority = 0; priority < 16; priority++)
+ {
+ if (bg_tile_priority[1][priority]) tilemap_draw(bitmap,cliprect,bg_tilemap[1],priority,0);
+ if (fg_tile_priority[1][priority]) tilemap_draw(bitmap,cliprect,fg_tilemap[1],priority,0);
+ if (top_tile_priority[1][priority]) tilemap_draw(bitmap,cliprect,top_tilemap[1],priority,0);
+ if (sprite_priority[1][priority])
+ draw_sprites(bitmap,cliprect,1,priority,0);
+ }
+ for (priority = 0; priority < 16; priority++)
+ {
+ if (bg_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,bg_tilemap[0],priority,0);
+ if (fg_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,fg_tilemap[0],priority,0);
+ if (top_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,top_tilemap[0],priority,0);
+ if (sprite_priority[0][priority])
+ draw_sprites(bitmap,cliprect,0,priority,0);
+ }
+ return 0;
+}
+
+VIDEO_UPDATE( batsugun_1 )
+{
+ int priority;
+
+
+#ifdef MAME_DEBUG
+ toaplan2_log_vram();
+#endif
+
+ mark_sprite_priority(0);
+ mark_sprite_priority(1);
+ mark_tile_priority(0);
+ mark_tile_priority(1);
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ for (priority = 0; priority < 16; priority++)
+ {
+ if (bg_tile_priority[1][priority]) tilemap_draw(bitmap,cliprect,bg_tilemap[1],priority,0);/* 2 */
+ if (bg_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,bg_tilemap[0],priority,0);
+ if (fg_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,fg_tilemap[0],priority,0);
+ if (fg_tile_priority[1][priority]) tilemap_draw(bitmap,cliprect,fg_tilemap[1],priority,0);
+ if (top_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,top_tilemap[0],priority,0);
+ if (sprite_priority[0][priority])
+ draw_sprites(bitmap,cliprect,0,priority,0);
+ }
+
+ for (priority = 0; priority < 16; priority++)
+ {
+ if (top_tile_priority[1][priority]) tilemap_draw(bitmap,cliprect,top_tilemap[1],priority,0);
+ if (sprite_priority[1][priority])
+ draw_sprites(bitmap,cliprect,1,priority,0);
+ }
+
+ return 0;
+}
+
+VIDEO_UPDATE( truxton2_0 )
+{
+ video_update_toaplan2_0(machine,screen,bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( batrider_0 )
+{
+ int priority;
+
+ int line;
+ rectangle clip;
+
+#ifdef MAME_DEBUG
+ toaplan2_log_vram();
+#endif
+
+ mark_sprite_priority(0);
+ mark_tile_priority(0);
+
+ /* If object bank is changed, all tile must be redrawn to blow off glitches. */
+ /* This causes serious slow down. Is there better algorithm ? */
+ if (objectbank_dirty)
+ {
+ tilemap_mark_all_tiles_dirty(bg_tilemap[0]);
+ tilemap_mark_all_tiles_dirty(fg_tilemap[0]);
+ objectbank_dirty = 0;
+ }
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ for (priority = 0; priority < 16; priority++)
+ {
+ if (bg_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,bg_tilemap[0],priority,0);
+ if (fg_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,fg_tilemap[0],priority,0);
+ if (top_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,top_tilemap[0],priority,0);
+ if (sprite_priority[0][priority])
+ draw_sprites(bitmap,cliprect,0,priority,1); /* consider bank select */
+ }
+
+ clip.min_x = machine->screen[0].visarea.min_x;
+ clip.max_x = machine->screen[0].visarea.max_x;
+ clip.min_y = machine->screen[0].visarea.min_y;
+ clip.max_y = machine->screen[0].visarea.max_y;
+
+ /* used for 'for use in' and '8ing' screen on bbakraid, raizing on batrider */
+ for (line = 0; line < 256;line++)
+ {
+ clip.min_y = clip.max_y = line;
+ tilemap_set_scrolly(tx_tilemap,0,toaplan2_txvideoram16_offs[line&0xff]-line);
+ tilemap_draw(bitmap,&clip,tx_tilemap,0,0);
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( mahoudai_0 )
+{
+ int priority;
+
+
+#ifdef MAME_DEBUG
+ toaplan2_log_vram();
+#endif
+
+ mark_sprite_priority(0);
+ mark_tile_priority(0);
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ if (bg_tile_priority[0][0]) tilemap_draw(bitmap,cliprect,bg_tilemap[0],0,0);
+ if (fg_tile_priority[0][0]) tilemap_draw(bitmap,cliprect,fg_tilemap[0],0,0);
+ if (top_tile_priority[0][0]) tilemap_draw(bitmap,cliprect,top_tilemap[0],0,0);
+ for (priority = 1; priority < 16; priority++)
+ {
+ if (bg_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,bg_tilemap[0],priority,0);
+ if (fg_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,fg_tilemap[0],priority,0);
+ if (top_tile_priority[0][priority]) tilemap_draw(bitmap,cliprect,top_tilemap[0],priority,0);
+ if (sprite_priority[0][priority-1])
+ draw_sprites(bitmap,cliprect,0,priority-1,0);
+ }
+ if (sprite_priority[0][15])
+ draw_sprites(bitmap,cliprect,0,15,0);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ return 0;
+}
+
+
+VIDEO_EOF( toaplan2_0 )
+{
+ /** Shift sprite RAM buffers *** Used to fix sprite lag **/
+ memcpy(spriteram16_now[0],spriteram16_new[0],TOAPLAN2_SPRITERAM_SIZE);
+}
+
+VIDEO_EOF( toaplan2_1 )
+{
+ /** Shift sprite RAM buffers *** Used to fix sprite lag **/
+ memcpy(spriteram16_now[0],spriteram16_new[0],TOAPLAN2_SPRITERAM_SIZE);
+ memcpy(spriteram16_now[1],spriteram16_new[1],TOAPLAN2_SPRITERAM_SIZE);
+}
diff --git a/src/mame/video/toki.c b/src/mame/video/toki.c
new file mode 100644
index 00000000000..74e7eadade8
--- /dev/null
+++ b/src/mame/video/toki.c
@@ -0,0 +1,321 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *background_layer,*foreground_layer,*text_layer;
+
+UINT16 *toki_background1_videoram16;
+UINT16 *toki_background2_videoram16;
+UINT16 *toki_scrollram16;
+
+/*************************************************************************
+ RASTER EFFECTS
+
+Xscroll can be altered per scanline to create rowscroll effect.
+
+(The driver does not implement rowscroll on the bootleg. It seems unlikely
+the bootleggers would have been able to do this on their chipset. They
+remapped the scroll registers, so obviously they were using a different
+chip.
+
+Why then would the old ghost of one of the remapped registers
+still cause rowscroll? Probably the bootleggers simply didn't bother to
+remove all the code writing the $a0000 area.)
+
+*************************************************************************/
+
+WRITE16_HANDLER( toki_control_w )
+{
+ COMBINE_DATA(&toki_scrollram16[offset]);
+
+ video_screen_update_partial(0, video_screen_get_vpos(0) - 1);
+}
+
+VIDEO_EOF( toki )
+{
+ buffer_spriteram16_w(0,0,0);
+}
+
+VIDEO_EOF( tokib )
+{
+ buffer_spriteram16_w(0,0,0);
+}
+
+static TILE_GET_INFO( get_text_tile_info )
+{
+ int tile = videoram16[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile&=0xfff;
+
+ SET_TILE_INFO(
+ 0,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_back_tile_info )
+{
+ int tile = toki_background1_videoram16[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile&=0xfff;
+
+ SET_TILE_INFO(
+ 2,
+ tile,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_fore_tile_info )
+{
+ int tile = toki_background2_videoram16[tile_index];
+ int color=(tile>>12)&0xf;
+
+ tile&=0xfff;
+
+ SET_TILE_INFO(
+ 3,
+ tile,
+ color,
+ 0);
+}
+
+
+/*************************************
+ *
+ * Start/Stop
+ *
+ *************************************/
+
+VIDEO_START( toki )
+{
+ text_layer = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,32,32);
+ background_layer = tilemap_create(get_back_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+ foreground_layer = tilemap_create(get_fore_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ tilemap_set_transparent_pen(text_layer,15);
+ tilemap_set_transparent_pen(background_layer,15);
+ tilemap_set_transparent_pen(foreground_layer,15);
+}
+
+/*************************************/
+
+WRITE16_HANDLER( toki_foreground_videoram16_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty(text_layer,offset);
+}
+
+WRITE16_HANDLER( toki_background1_videoram16_w )
+{
+ COMBINE_DATA(&toki_background1_videoram16[offset]);
+ tilemap_mark_tile_dirty(background_layer,offset);
+}
+
+WRITE16_HANDLER( toki_background2_videoram16_w )
+{
+ COMBINE_DATA(&toki_background2_videoram16[offset]);
+ tilemap_mark_tile_dirty(foreground_layer,offset);
+}
+
+/***************************************************************************
+ SPRITES
+
+ Original Spriteram
+ ------------------
+
+ It's not clear what purpose is served by marking tiles as being part of
+ big sprites. (Big sprites in the attract abduction scene have all tiles
+ marked as "first" unlike big sprites in-game.)
+
+ We just ignore this top nibble (although perhaps in theory the bits
+ enable X/Y offsets in the low byte).
+
+ +0 x....... ........ sprite disable ??
+ +0 .xx..... ........ tile is part of big sprite (4=first, 6=middle, 2=last)
+ +0 .....x.. ........ ??? always set? (could be priority - see Bloodbro)
+ +0 .......x ........ Flip x
+ +0 ........ xxxx.... X offset: add (this * 16) to X coord
+ +0 ........ ....xxxx Y offset: add (this * 16) to Y coord
+
+ +1 xxxx.... ........ Color bank
+ +1 ....xxxx xxxxxxxx Tile number (lo bits)
+ +2 x....... ........ Tile number (hi bit)
+ +2 .???.... ........ (set in not yet used entries)
+ +2 .......x xxxxxxxx X coordinate
+ +3 .......x xxxxxxxx Y coordinate
+
+ f000 0000 f000 0000 entry not yet used: unless this is honored there
+ will be junk sprites in top left corner
+ ffff ???? ???? ???? sprite marked as dead: unless this is honored
+ there will be junk sprites after floating monkey machine
+
+
+ Bootleg Spriteram
+ -----------------
+
+ +0 .......x xxxxxxxx Sprite Y coordinate
+ +1 ...xxxxx xxxxxxxx Sprite tile number
+ +1 .x...... ........ Sprite flip x
+ +2 xxxx.... ........ Sprite color bank
+ +3 .......x xxxxxxxx Sprite X coordinate
+
+ f100 ???? ???? ???? dead / unused sprite ??
+ ???? ???? 0000 ???? dead / unused sprite ??
+
+
+***************************************************************************/
+
+
+static void toki_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int x,y,xoffs,yoffs,tile,flipx,flipy,color,offs;
+ UINT16 *sprite_word;
+
+ for (offs = (spriteram_size/2)-4;offs >= 0;offs -= 4)
+ {
+ sprite_word = &buffered_spriteram16[offs];
+
+ if ((sprite_word[2] != 0xf000) && (sprite_word[0] != 0xffff))
+ {
+ xoffs = (sprite_word[0] &0xf0);
+ x = (sprite_word[2] + xoffs) & 0x1ff;
+ if (x > 256)
+ x -= 512;
+
+ yoffs = (sprite_word[0] &0xf) << 4;
+ y = (sprite_word[3] + yoffs) & 0x1ff;
+ if (y > 256)
+ y -= 512;
+
+ color = sprite_word[1] >> 12;
+ flipx = sprite_word[0] & 0x100;
+ flipy = 0;
+ tile = (sprite_word[1] & 0xfff) + ((sprite_word[2] & 0x8000) >> 3);
+
+ if (flip_screen) {
+ x=240-x;
+ y=240-y;
+ if (flipx) flipx=0; else flipx=1;
+ flipy=1;
+ }
+
+ drawgfx (bitmap,machine->gfx[1],
+ tile,
+ color,
+ flipx,flipy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+}
+
+
+static void tokib_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int x,y,tile,flipx,color,offs;
+ UINT16 *sprite_word;
+
+ for (offs = 0;offs < spriteram_size / 2;offs += 4)
+ {
+ sprite_word = &buffered_spriteram16[offs];
+
+ if (sprite_word[0] == 0xf100)
+ break;
+ if (sprite_word[2])
+ {
+
+ x = sprite_word[3] & 0x1ff;
+ if (x > 256)
+ x -= 512;
+
+ y = sprite_word[0] & 0x1ff;
+ if (y > 256)
+ y = (512-y)+240;
+ else
+ y = 240-y;
+
+ flipx = sprite_word[1] & 0x4000;
+ tile = sprite_word[1] & 0x1fff;
+ color = sprite_word[2] >> 12;
+
+ drawgfx (bitmap,machine->gfx[1],
+ tile,
+ color,
+ flipx,0,
+ x,y-1,
+ cliprect,TRANSPARENCY_PEN,15);
+ }
+ }
+}
+
+/*************************************
+ *
+ * Master update function
+ *
+ *************************************/
+
+VIDEO_UPDATE( toki )
+{
+ int background_y_scroll,foreground_y_scroll,background_x_scroll,foreground_x_scroll;
+
+ background_x_scroll=((toki_scrollram16[0x06] &0x7f) << 1)
+ |((toki_scrollram16[0x06] &0x80) >> 7)
+ |((toki_scrollram16[0x05] &0x10) << 4);
+ background_y_scroll=((toki_scrollram16[0x0d]&0x10)<<4)+((toki_scrollram16[0x0e]&0x7f)<<1)+((toki_scrollram16[0x0e]&0x80)>>7);
+
+ tilemap_set_scrollx( background_layer, 0, background_x_scroll );
+ tilemap_set_scrolly( background_layer, 0, background_y_scroll );
+
+ foreground_x_scroll= ((toki_scrollram16[0x16] &0x7f) << 1)
+ |((toki_scrollram16[0x16] &0x80) >> 7)
+ |((toki_scrollram16[0x15] &0x10) << 4);
+ foreground_y_scroll=((toki_scrollram16[0x1d]&0x10)<<4)+((toki_scrollram16[0x1e]&0x7f)<<1)+((toki_scrollram16[0x1e]&0x80)>>7);
+
+ tilemap_set_scrollx( foreground_layer, 0, foreground_x_scroll );
+ tilemap_set_scrolly( foreground_layer, 0, foreground_y_scroll );
+
+ flip_screen_set((toki_scrollram16[0x28]&0x8000)==0);
+
+ if (toki_scrollram16[0x28]&0x100) {
+ tilemap_draw(bitmap,cliprect,background_layer,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,foreground_layer,0,0);
+ } else {
+ tilemap_draw(bitmap,cliprect,foreground_layer,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,background_layer,0,0);
+ }
+ toki_draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,text_layer,0,0);
+ return 0;
+}
+
+VIDEO_UPDATE( tokib )
+{
+ tilemap_set_scroll_rows(foreground_layer,1);
+ tilemap_set_scroll_rows(background_layer,1);
+ tilemap_set_scrolly( background_layer, 0, toki_scrollram16[0]+1 );
+ tilemap_set_scrollx( background_layer, 0, toki_scrollram16[1]-0x103 );
+ tilemap_set_scrolly( foreground_layer, 0, toki_scrollram16[2]+1 );
+ tilemap_set_scrollx( foreground_layer, 0, toki_scrollram16[3]-0x101 );
+
+ if (toki_scrollram16[3]&0x2000) {
+ tilemap_draw(bitmap,cliprect,background_layer,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,foreground_layer,0,0);
+ } else {
+ tilemap_draw(bitmap,cliprect,foreground_layer,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,background_layer,0,0);
+ }
+
+ tokib_draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,text_layer,0,0);
+ return 0;
+}
diff --git a/src/mame/video/toobin.c b/src/mame/video/toobin.c
new file mode 100644
index 00000000000..78a16f4646c
--- /dev/null
+++ b/src/mame/video/toobin.c
@@ -0,0 +1,270 @@
+/***************************************************************************
+
+ Atari Toobin' hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "toobin.h"
+
+
+
+/*************************************
+ *
+ * Globals we own
+ *
+ *************************************/
+
+static double brightness;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha[tile_index];
+ int code = data & 0x3ff;
+ int color = (data >> 12) & 0x0f;
+ SET_TILE_INFO(2, code, color, (data >> 10) & 1);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data1 = atarigen_playfield[tile_index * 2];
+ UINT16 data2 = atarigen_playfield[tile_index * 2 + 1];
+ int code = data2 & 0x3fff;
+ int color = data1 & 0x0f;
+ SET_TILE_INFO(0, code, color, TILE_FLIPYX(data2 >> 14));
+ tileinfo->category = (data1 >> 4) & 3;
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( toobin )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 1, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 1, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 1024, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x100, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0,0,0x00ff,0 }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0,0x3fff,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0,0x000f }}, /* mask for the color */
+ {{ 0,0,0,0xffc0 }}, /* mask for the X position */
+ {{ 0x7fc0,0,0,0 }}, /* mask for the Y position */
+ {{ 0x0007,0,0,0 }}, /* mask for the width, in tiles*/
+ {{ 0x0038,0,0,0 }}, /* mask for the height, in tiles */
+ {{ 0,0x4000,0,0 }}, /* mask for the horizontal flip */
+ {{ 0,0x8000,0,0 }}, /* mask for the vertical flip */
+ {{ 0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0x8000,0,0,0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ 0 /* callback routine for special entries */
+ };
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 128,64);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,48);
+ tilemap_set_transparent_pen(atarigen_alpha_tilemap, 0);
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM write handler
+ *
+ *************************************/
+
+WRITE16_HANDLER( toobin_paletteram_w )
+{
+ int newword;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ newword = paletteram16[offset];
+
+ {
+ int red = (((newword >> 10) & 31) * 224) >> 5;
+ int green = (((newword >> 5) & 31) * 224) >> 5;
+ int blue = (((newword ) & 31) * 224) >> 5;
+
+ if (red) red += 38;
+ if (green) green += 38;
+ if (blue) blue += 38;
+
+ palette_set_color(Machine, offset & 0x3ff, MAKE_RGB(red, green, blue));
+ if (!(newword & 0x8000))
+ palette_set_brightness(Machine, offset & 0x3ff, brightness);
+ else
+ palette_set_brightness(Machine, offset & 0x3ff, 1.0);
+ }
+}
+
+
+WRITE16_HANDLER( toobin_intensity_w )
+{
+ int i;
+
+ if (ACCESSING_LSB)
+ {
+ brightness = (double)(~data & 0x1f) / 31.0;
+
+ for (i = 0; i < 0x400; i++)
+ if (!(paletteram16[i] & 0x8000))
+ palette_set_brightness(Machine, i, brightness);
+ }
+}
+
+
+
+/*************************************
+ *
+ * X/Y scroll handlers
+ *
+ *************************************/
+
+WRITE16_HANDLER( toobin_xscroll_w )
+{
+ UINT16 oldscroll = *atarigen_xscroll;
+ UINT16 newscroll = oldscroll;
+ COMBINE_DATA(&newscroll);
+
+ /* if anything has changed, force a partial update */
+ if (newscroll != oldscroll)
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ /* update the playfield scrolling - hscroll is clocked on the following scanline */
+ tilemap_set_scrollx(atarigen_playfield_tilemap, 0, newscroll >> 6);
+ atarimo_set_xscroll(0, newscroll >> 6);
+
+ /* update the data */
+ *atarigen_xscroll = newscroll;
+}
+
+
+WRITE16_HANDLER( toobin_yscroll_w )
+{
+ UINT16 oldscroll = *atarigen_yscroll;
+ UINT16 newscroll = oldscroll;
+ COMBINE_DATA(&newscroll);
+
+ /* if anything has changed, force a partial update */
+ if (newscroll != oldscroll)
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ /* if bit 4 is zero, the scroll value is clocked in right away */
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, newscroll >> 6);
+ atarimo_set_yscroll(0, (newscroll >> 6) & 0x1ff);
+
+ /* update the data */
+ *atarigen_yscroll = newscroll;
+}
+
+
+
+/*************************************
+ *
+ * X/Y scroll handlers
+ *
+ *************************************/
+
+WRITE16_HANDLER( toobin_slip_w )
+{
+ int oldslip = atarimo_0_slipram[offset];
+ int newslip = oldslip;
+ COMBINE_DATA(&newslip);
+
+ /* if the SLIP is changing, force a partial update first */
+ if (oldslip != newslip)
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ /* update the data */
+ atarimo_0_slipram_w(offset, data, mem_mask);
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( toobin )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ fillbitmap(priority_bitmap, 0, cliprect);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 1, 1);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 2, 2);
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 3, 3);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ UINT8 *pri = (UINT8 *)priority_bitmap->base + priority_bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* not verified: logic is all controlled in a PAL
+
+ factors: LBPRI1-0, LBPIX3, ANPIX1-0, PFPIX3, PFPRI1-0,
+ (~LBPIX3 & ~LBPIX2 & ~LBPIX1 & ~LBPIX0)
+ */
+
+ /* only draw if not high priority PF */
+ if (!pri[x] || !(pf[x] & 8))
+ pf[x] = mo[x];
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+
+ /* add the alpha on top */
+ tilemap_draw(bitmap, cliprect, atarigen_alpha_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/topspeed.c b/src/mame/video/topspeed.c
new file mode 100644
index 00000000000..c1b07637114
--- /dev/null
+++ b/src/mame/video/topspeed.c
@@ -0,0 +1,199 @@
+#include "driver.h"
+#include "video/taitoic.h"
+
+UINT16 *topspeed_spritemap;
+UINT16 *topspeed_raster_ctrl;
+
+/****************************************************************************/
+
+VIDEO_START( topspeed )
+{
+ /* (chips, gfxnum, x_offs, y_offs, y_invert, opaque, dblwidth) */
+ PC080SN_vh_start(2,1,0,8,0,0,0);
+}
+
+
+/********************************************************************************
+ SPRITES
+
+ Layout 8 bytes per sprite
+ -------------------------
+
+ +0x00 xxxxxxx. ........ Zoom Y
+ .......x xxxxxxxx Y
+
+ +0x02 x....... ........ Flip Y
+ ........ .xxxxxxx Zoom X
+
+ +0x04 x....... ........ Priority
+ .x...... ........ Flip X
+ ..x..... ........ Unknown
+ .......x xxxxxxxx X
+
+ +0x06 xxxxxxxx ........ Color
+ ........ xxxxxxxx Tile number
+
+********************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs,map_offset,x,y,curx,cury,sprite_chunk;
+ UINT16 *spritemap = topspeed_spritemap;
+ UINT16 data,tilenum,code,color;
+ UINT8 flipx,flipy,priority,bad_chunks;
+ UINT8 j,k,px,py,zx,zy,zoomx,zoomy;
+ static const int primasks[2] = {0xff00,0xfffc}; /* Sprites are over bottom layer or under top layer */
+
+ /* Most of spriteram is not used by the 68000: rest is scratch space for the h/w perhaps ? */
+
+ for (offs = 0;offs <(0x2c0/2);offs += 4)
+ {
+ data = spriteram16[offs+2];
+
+ tilenum = spriteram16[offs+3] & 0xff;
+ color = (spriteram16[offs+3] & 0xff00) >> 8;
+ flipx = (data & 0x4000) >> 14;
+ flipy = (spriteram16[offs+1] & 0x8000) >> 15;
+ x = data & 0x1ff;
+ y = spriteram16[offs] & 0x1ff;
+ zoomx = (spriteram16[offs+1]& 0x7f);
+ zoomy = (spriteram16[offs] & 0xfe00) >> 9;
+ priority = (data & 0x8000) >> 15;
+// unknown = (data & 0x2000) >> 13;
+
+ if (y == 0x180) continue; /* dead sprite */
+
+ map_offset = tilenum << 7;
+
+ zoomx += 1;
+ zoomy += 1;
+
+ y += 3 + (128-zoomy);
+
+ /* treat coords as signed */
+ if (x > 0x140) x -= 0x200;
+ if (y > 0x140) y -= 0x200;
+
+ bad_chunks = 0;
+
+ for (sprite_chunk = 0;sprite_chunk < 128;sprite_chunk++)
+ {
+ k = sprite_chunk % 8; /* 8 sprite chunks per row */
+ j = sprite_chunk / 8; /* 16 rows */
+
+ /* pick tiles back to front for x and y flips */
+ px = (flipx) ? (7-k) : (k);
+ py = (flipy) ? (15-j) : (j);
+
+ code = spritemap[map_offset + (py<<3) + px];
+
+ if (code & 0x8000)
+ {
+ bad_chunks += 1;
+ continue;
+ }
+
+ curx = x + ((k*zoomx)/8);
+ cury = y + ((j*zoomy)/16);
+
+ zx = x + (((k+1)*zoomx)/8) - curx;
+ zy = y + (((j+1)*zoomy)/16) - cury;
+
+ pdrawgfxzoom(bitmap,machine->gfx[0],
+ code,
+ color,
+ flipx,flipy,
+ curx,cury,
+ cliprect,TRANSPARENCY_PEN,0,
+ zx<<12,zy<<13,
+ primasks[priority]);
+ }
+
+ if (bad_chunks)
+logerror("Sprite number %04x had %02x invalid chunks\n",tilenum,bad_chunks);
+ }
+}
+
+
+/***************************************************************************/
+
+VIDEO_UPDATE( topspeed )
+{
+ UINT8 layer[4];
+
+#ifdef MAME_DEBUG
+ static UINT8 dislayer[5];
+#endif
+
+#ifdef MAME_DEBUG
+ if (input_code_pressed_once (KEYCODE_V))
+ {
+ dislayer[0] ^= 1;
+ popmessage("bg: %01x",dislayer[0]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_B))
+ {
+ dislayer[1] ^= 1;
+ popmessage("fg: %01x",dislayer[1]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_N))
+ {
+ dislayer[2] ^= 1;
+ popmessage("bg2: %01x",dislayer[2]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_M))
+ {
+ dislayer[3] ^= 1;
+ popmessage("fg2: %01x",dislayer[3]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_C))
+ {
+ dislayer[4] ^= 1;
+ popmessage("sprites: %01x",dislayer[4]);
+ }
+#endif
+
+ PC080SN_tilemap_update();
+
+ /* Tilemap layer priority seems hardwired (the order is odd, too) */
+ layer[0] = 1;
+ layer[1] = 0;
+ layer[2] = 1;
+ layer[3] = 0;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+#ifdef MAME_DEBUG
+ if (dislayer[3]==0)
+#endif
+ PC080SN_tilemap_draw(bitmap,cliprect,1,layer[0],TILEMAP_DRAW_OPAQUE,1);
+
+#ifdef MAME_DEBUG
+ if (dislayer[2]==0)
+#endif
+ PC080SN_tilemap_draw_special(bitmap,cliprect,1,layer[1],0,2,topspeed_raster_ctrl);
+
+#ifdef MAME_DEBUG
+ if (dislayer[1]==0)
+#endif
+ PC080SN_tilemap_draw_special(bitmap,cliprect,0,layer[2],0,4,topspeed_raster_ctrl + 0x100);
+
+#ifdef MAME_DEBUG
+ if (dislayer[0]==0)
+#endif
+ PC080SN_tilemap_draw(bitmap,cliprect,0,layer[3],0,8);
+
+#ifdef MAME_DEBUG
+ if (dislayer[4]==0)
+#endif
+
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
+
+
diff --git a/src/mame/video/toypop.c b/src/mame/video/toypop.c
new file mode 100644
index 00000000000..4eeb6b96f97
--- /dev/null
+++ b/src/mame/video/toypop.c
@@ -0,0 +1,236 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *toypop_videoram;
+
+extern UINT8 *m68000_sharedram;
+
+static tilemap *bg_tilemap;
+UINT16 *toypop_bg_image;
+static int bitmapflip,palettebank;
+
+static colortable *toypop_colortable;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ toypop has three 256x4 palette PROM and two 256x8 color lookup table PROMs
+ (one for characters, one for sprites).
+
+***************************************************************************/
+
+PALETTE_INIT( toypop )
+{
+ int i;
+
+ /* allocate the colortable */
+ toypop_colortable = colortable_alloc(machine, 256);
+
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ // red component
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ bit3 = (color_prom[i] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ // green component
+ bit0 = (color_prom[i+0x100] >> 0) & 0x01;
+ bit1 = (color_prom[i+0x100] >> 1) & 0x01;
+ bit2 = (color_prom[i+0x100] >> 2) & 0x01;
+ bit3 = (color_prom[i+0x100] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ // blue component
+ bit0 = (color_prom[i+0x200] >> 0) & 0x01;
+ bit1 = (color_prom[i+0x200] >> 1) & 0x01;
+ bit2 = (color_prom[i+0x200] >> 2) & 0x01;
+ bit3 = (color_prom[i+0x200] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ colortable_palette_set_color(toypop_colortable, i, MAKE_RGB(r,g,b));
+ }
+
+ for (i = 0;i < 256;i++)
+ {
+ UINT8 entry;
+
+ // characters
+ colortable_entry_set_value(toypop_colortable, i + 0*256, (color_prom[i + 0x300] & 0x0f) | 0x70);
+ colortable_entry_set_value(toypop_colortable, i + 1*256, (color_prom[i + 0x300] & 0x0f) | 0xf0);
+ // sprites
+ entry = color_prom[i + 0x500];
+ colortable_entry_set_value(toypop_colortable, i + 2*256, entry);
+ }
+ for (i = 0;i < 16;i++)
+ {
+ // background
+ colortable_entry_set_value(toypop_colortable, i + 3*256 + 0*16, 0x60 + i);
+ colortable_entry_set_value(toypop_colortable, i + 3*256 + 1*16, 0xe0 + i);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/* convert from 32x32 to 36x28 */
+static TILEMAP_MAPPER( tilemap_scan )
+{
+ int offs;
+
+ row += 2;
+ col -= 2;
+ if (col & 0x20)
+ offs = row + ((col & 0x1f) << 5);
+ else
+ offs = col + (row << 5);
+
+ return offs;
+}
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 attr = toypop_videoram[tile_index + 0x400];
+ SET_TILE_INFO(
+ 0,
+ toypop_videoram[tile_index],
+ (attr & 0x3f) + 0x40 * palettebank,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( toypop )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan,TILEMAP_TYPE_PEN,8,8,36,28);
+
+ tilemap_set_transparent_pen(bg_tilemap, 0);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( toypop_videoram_w )
+{
+ toypop_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( toypop_palettebank_w )
+{
+ if (palettebank != (offset & 1))
+ {
+ palettebank = offset & 1;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE16_HANDLER( toypop_flipscreen_w )
+{
+ bitmapflip = offset & 1;
+}
+
+READ16_HANDLER( toypop_merged_background_r )
+{
+ int data1, data2;
+
+ // 0x0a0b0c0d is read as 0xabcd
+ data1 = toypop_bg_image[2*offset];
+ data2 = toypop_bg_image[2*offset + 1];
+ return ((data1 & 0xf00) << 4) | ((data1 & 0xf) << 8) | ((data2 & 0xf00) >> 4) | (data2 & 0xf);
+}
+
+WRITE16_HANDLER( toypop_merged_background_w )
+{
+ // 0xabcd is written as 0x0a0b0c0d in the background image
+ if (ACCESSING_MSB)
+ toypop_bg_image[2*offset] = ((data & 0xf00) >> 8) | ((data & 0xf000) >> 4);
+
+ if (ACCESSING_LSB)
+ toypop_bg_image[2*offset+1] = (data & 0xf) | ((data & 0xf0) << 4);
+}
+
+static void draw_background(mame_bitmap *bitmap)
+{
+ register int offs, x, y;
+ UINT8 scanline[288];
+
+ // copy the background image from RAM (0x190200-0x19FDFF) to bitmap
+ if (bitmapflip)
+ {
+ offs = 0xFDFE/2;
+ for (y = 0; y < 224; y++)
+ {
+ for (x = 0; x < 288; x+=2)
+ {
+ UINT16 data = toypop_bg_image[offs];
+ scanline[x] = data;
+ scanline[x+1] = data >> 8;
+ offs--;
+ }
+ draw_scanline8(bitmap, 0, y, 288, scanline, &Machine->pens[0x300 + 0x10*palettebank], -1);
+ }
+ }
+ else
+ {
+ offs = 0x200/2;
+ for (y = 0; y < 224; y++)
+ {
+ for (x = 0; x < 288; x+=2)
+ {
+ UINT16 data = toypop_bg_image[offs];
+ scanline[x] = data >> 8;
+ scanline[x+1] = data;
+ offs++;
+ }
+ draw_scanline8(bitmap, 0, y, 288, scanline, &Machine->pens[0x300 + 0x10*palettebank], -1);
+ }
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+/* from mappy.c */
+void mappy_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int xoffs, int yoffs, colortable *ctable, int transcolor);
+
+
+VIDEO_UPDATE( toypop )
+{
+ draw_background(bitmap);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ mappy_draw_sprites(machine, bitmap, cliprect, -31, -8, toypop_colortable, 0xff);
+ return 0;
+}
diff --git a/src/mame/video/tp84.c b/src/mame/video/tp84.c
new file mode 100644
index 00000000000..5e543c96634
--- /dev/null
+++ b/src/mame/video/tp84.c
@@ -0,0 +1,289 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *tp84_videoram2, *tp84_colorram2;
+
+static int col0;
+
+/*
+sprites are multiplexed, so we have to buffer the spriteram
+scanline by scanline.
+*/
+static UINT8 *sprite_mux_buffer;
+static int scanline;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+/*
+-The colortable is divided in 2 part:
+ -The characters colors
+ -The sprites colors
+
+-The characters colors are indexed like this:
+ -2 bits from the characters
+ -4 bits from the attribute in colorram
+ -2 bits from col0 (d3-d4)
+ -3 bits from col0 (d0-d1-d2)
+-So, there is 2048 bytes for the characters
+
+-The sprites colors are indexed like this:
+ -4 bits from the sprites (16 colors)
+ -4 bits from the attribute of the sprites
+ -3 bits from col0 (d0-d1-d2)
+-So, there is 2048 bytes for the sprites
+
+*/
+/*
+ The RGB signals are generated by 3 proms 256X4 (prom 2C, 2D and 1E)
+ The resistors values are:
+ 1K ohm
+ 470 ohm
+ 220 ohm
+ 100 ohm
+*/
+PALETTE_INIT( tp84 )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x42 * bit2 + 0x90 * bit3;
+ /* green component */
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x42 * bit2 + 0x90 * bit3;
+ /* blue component */
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x42 * bit2 + 0x90 * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+
+ color_prom += 2*machine->drv->total_colors;
+ /* color_prom now points to the beginning of the lookup table */
+
+
+ /* characters use colors 128-255 */
+ for (i = 0;i < TOTAL_COLORS(0)/8;i++)
+ {
+ int j;
+
+
+ for (j = 0;j < 8;j++)
+ COLOR(0,i+256*j) = *color_prom + 128 + 16*j;
+
+ color_prom++;
+ }
+
+ /* sprites use colors 0-127 */
+ for (i = 0;i < TOTAL_COLORS(1)/8;i++)
+ {
+ int j;
+
+
+ for (j = 0;j < 8;j++)
+ {
+ if (*color_prom) COLOR(1,i+256*j) = *color_prom + 16*j;
+ else COLOR(1,i+256*j) = 0; /* preserve transparency */
+ }
+
+ color_prom++;
+ }
+}
+
+
+WRITE8_HANDLER( tp84_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( tp84_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( tp84_videoram2_w )
+{
+ tp84_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( tp84_colorram2_w )
+{
+ tp84_colorram2[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( tp84_scroll_x_w )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, data);
+}
+
+WRITE8_HANDLER( tp84_scroll_y_w )
+{
+ tilemap_set_scrolly(bg_tilemap, 0, data);
+}
+
+WRITE8_HANDLER( tp84_flipscreen_x_w )
+{
+ flip_screen_x_set(data & 0x01);
+}
+
+WRITE8_HANDLER( tp84_flipscreen_y_w )
+{
+ flip_screen_y_set(data & 0x01);
+}
+
+/*****
+ col0 is a register to index the color Proms
+*****/
+WRITE8_HANDLER( tp84_col0_w )
+{
+ if (col0 != data)
+ {
+ col0 = data;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+/* Return the current video scan line */
+READ8_HANDLER( tp84_scanline_r )
+{
+ return scanline;
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int coloffs = ((col0 & 0x18) << 1) + ((col0 & 0x07) << 6);
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + ((attr & 0x30) << 4);
+ int color = (attr & 0x0f) + coloffs;
+ int flags = ((attr & 0x40) ? TILE_FLIPX : 0) | ((attr & 0x80) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int coloffs = ((col0 & 0x18) << 1) + ((col0 & 0x07) << 6);
+ int attr = tp84_colorram2[tile_index];
+ int code = tp84_videoram2[tile_index]+ ((attr & 0x30) << 4);
+ int color = (attr & 0x0f) + coloffs;
+ int flags = ((attr & 0x40) ? TILE_FLIPX : 0) | ((attr & 0x80) ? TILE_FLIPY : 0) | TILE_FORCE_LAYER0;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( tp84 )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+
+ sprite_mux_buffer = auto_malloc(256 * spriteram_size);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const gfx_element *gfx = machine->gfx[1];
+ int offs;
+ int line;
+ int coloffset = ((col0&0x07) << 4);
+
+ for (line = cliprect->min_y; line <= cliprect->max_y; line++)
+ {
+ UINT8 *sr;
+ rectangle clip = *cliprect;
+
+ sr = sprite_mux_buffer + line * spriteram_size;
+ clip.min_y = clip.max_y = line;
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int code,color,sx,sy,flipx,flipy;
+
+ sx = sr[offs];
+ sy = 240 - sr[offs + 3];
+
+ if (sy > line-16 && sy <= line)
+ {
+ code = sr[offs + 1];
+ color = (sr[offs + 2] & 0x0f) + coloffset;
+ flipx = ~sr[offs + 2] & 0x40;
+ flipy = sr[offs + 2] & 0x80;
+
+ drawgfx(bitmap,gfx,
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ &clip,TRANSPARENCY_COLOR,0);
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( tp84 )
+{
+ rectangle clip;
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+
+ /* draw top fg_tilemap status layer part */
+ clip.min_x = machine->screen[0].visarea.min_x;
+ clip.max_x = machine->screen[0].visarea.min_x+15;
+ clip.min_y = machine->screen[0].visarea.min_y;
+ clip.max_y = machine->screen[0].visarea.max_y;
+ tilemap_draw(bitmap, &clip, fg_tilemap, 0, 0);
+
+ /* the middle part of fg_tilemap seems to be used as normal ram and is skipped */
+
+ /* draw bottom fg_tilemap status layer part */
+ clip.min_x = machine->screen[0].visarea.max_x-15;
+ clip.max_x = machine->screen[0].visarea.max_x;
+ clip.min_y = machine->screen[0].visarea.min_y;
+ clip.max_y = machine->screen[0].visarea.max_y;
+ tilemap_draw(bitmap, &clip, fg_tilemap, 0, 0);
+ return 0;
+}
+
+INTERRUPT_GEN( tp84_6809_interrupt )
+{
+ scanline = 255 - cpu_getiloops();
+
+ memcpy(sprite_mux_buffer + scanline * spriteram_size,spriteram,spriteram_size);
+
+ if (scanline == 255)
+ irq0_line_hold();
+}
diff --git a/src/mame/video/trackfld.c b/src/mame/video/trackfld.c
new file mode 100644
index 00000000000..6f04a03784a
--- /dev/null
+++ b/src/mame/video/trackfld.c
@@ -0,0 +1,230 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *trackfld_scroll;
+UINT8 *trackfld_scroll2;
+
+static tilemap *bg_tilemap;
+static int bg_bank = 0, sprite_bank1 = 0, sprite_bank2 = 0;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Track 'n Field has one 32x8 palette PROM and two 256x4 lookup table PROMs
+ (one for characters, one for sprites).
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( trackfld )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = *(color_prom++) & 0x0f;
+
+ /* characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i) = (*(color_prom++) & 0x0f) + 0x10;
+}
+
+WRITE8_HANDLER( trackfld_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( trackfld_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( trackfld_flipscreen_w )
+{
+ if (flip_screen != data)
+ {
+ flip_screen_set(data);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+WRITE8_HANDLER( atlantol_gfxbank_w )
+{
+ static int old = 0;
+
+ if( data & 1 )
+ {
+ /* male / female sprites switch */
+ if( (old == 1 && (data & 1) == 1) ||
+ (old == 0 && (data & 1) == 1) )
+ sprite_bank2 = 0x200;
+ else
+ sprite_bank2 = 0;
+
+ sprite_bank1 = 0;
+
+ old = data & 1;
+ }
+ else
+ {
+ /* male / female sprites switch */
+ if( (old == 0 && (data & 1) == 0) ||
+ (old == 1 && (data & 1) == 0) )
+ sprite_bank2 = 0;
+ else
+ sprite_bank2 = 0x200;
+
+ sprite_bank1 = 0;
+
+ old = data & 1;
+ }
+
+ if( (data & 3) == 3 )
+ {
+ if( sprite_bank2 )
+ sprite_bank1 = 0x500;
+ else
+ sprite_bank1 = 0x300;
+ }
+ else if( (data & 3) == 2 )
+ {
+ if( sprite_bank2 )
+ sprite_bank1 = 0x300;
+ else
+ sprite_bank1 = 0x100;
+ }
+
+ if( bg_bank != (data & 0x8) )
+ {
+ bg_bank = data & 0x8;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = colorram[tile_index];
+ int code = videoram[tile_index] + 4 * (attr & 0xc0);
+ int color = attr & 0x0f;
+ int flags = ((attr & 0x10) ? TILE_FLIPX : 0) | ((attr & 0x20) ? TILE_FLIPY : 0);
+
+ if( bg_bank )
+ code |= 0x400;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( trackfld )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ tilemap_set_scroll_rows(bg_tilemap, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 2; offs >= 0; offs -= 2)
+ {
+ int attr = spriteram_2[offs];
+ int code = spriteram[offs + 1];
+ int color = attr & 0x0f;
+ int flipx = ~attr & 0x40;
+ int flipy = attr & 0x80;
+ int sx = spriteram[offs] - 1;
+ int sy = 240 - spriteram_2[offs + 1];
+
+ if (flip_screen)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ /* Note that this adjustement must be done AFTER handling flip screen, thus */
+ /* proving that this is a hardware related "feature" */
+ sy += 1;
+
+ drawgfx(bitmap, machine->gfx[1],
+ code + sprite_bank1 + sprite_bank2, color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_COLOR, 0);
+
+ /* redraw with wraparound */
+ drawgfx(bitmap,machine->gfx[1],
+ code + sprite_bank1 + sprite_bank2, color,
+ flipx, flipy,
+ sx - 256, sy,
+ cliprect,
+ TRANSPARENCY_COLOR, 0);
+ }
+}
+
+VIDEO_UPDATE( trackfld )
+{
+ int row, scrollx;
+
+ for (row = 0; row < 32; row++)
+ {
+ scrollx = trackfld_scroll[row] + 256 * (trackfld_scroll2[row] & 0x01);
+ if (flip_screen) scrollx = -scrollx;
+ tilemap_set_scrollx(bg_tilemap, row, scrollx);
+ }
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/travrusa.c b/src/mame/video/travrusa.c
new file mode 100644
index 00000000000..5b0cb934a7b
--- /dev/null
+++ b/src/mame/video/travrusa.c
@@ -0,0 +1,332 @@
+/***************************************************************************
+
+ video.c
+
+ Traverse USA
+
+L Taylor
+J Clegg
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *travrusa_videoram;
+
+static tilemap *bg_tilemap;
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Traverse USA has one 256x8 character palette PROM (some versions have two
+ 256x4), one 32x8 sprite palette PROM, and one 256x4 sprite color lookup
+ table PROM.
+
+ I don't know for sure how the palette PROMs are connected to the RGB
+ output, but it's probably something like this; note that RED and BLUE
+ are swapped wrt the usual configuration.
+
+ bit 7 -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ bit 0 -- 1 kohm resistor -- BLUE
+
+***************************************************************************/
+
+PALETTE_INIT( travrusa )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ /* character palette */
+ for (i = 0;i < 128;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ color_prom += 256;
+
+ /* sprite palette */
+ for (i = 0;i < 16;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i+128,MAKE_RGB(r,g,b));
+ }
+
+ color_prom += 32;
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* sprite lookup table */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = (color_prom[i] & 0x0f) + 128;
+}
+
+PALETTE_INIT( shtrider )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ /* character palette */
+ for (i = 0;i < 128;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 2) & 0x01;
+ bit2 = (color_prom[i] >> 3) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i+256] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 0) & 0x01;
+ bit2 = (color_prom[i] >> 1) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (color_prom[i+256] >> 0) & 0x01;
+ bit1 = (color_prom[i+256] >> 1) & 0x01;
+ bit2 = (color_prom[i+256] >> 2) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ color_prom += 512;
+
+ /* color_prom now points to the beginning of the sprite palette */
+
+ /* sprite palette */
+ for (i = 0;i < 16;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i+128,MAKE_RGB(r,g,b));
+ }
+
+ color_prom += 32;
+ /* color_prom now points to the beginning of the sprite lookup table */
+
+ /* sprite lookup table */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = (color_prom[i] & 0x0f) + 128;
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 attr = travrusa_videoram[2*tile_index+1];
+ int flags = TILE_FLIPXY((attr & 0x30) >> 4);
+
+ tileinfo->group = ((attr & 0x0f) == 0x0f) ? 1 : 0; /* tunnels */
+
+ SET_TILE_INFO(
+ 0,
+ travrusa_videoram[2*tile_index] + ((attr & 0xc0) << 2),
+ attr & 0x0f,
+ flags);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( travrusa )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_transmask(bg_tilemap,0,0xff,0x00); /* split type 0 is totally transparent in front half */
+ tilemap_set_transmask(bg_tilemap,1,0x3f,0xc0); /* split type 1 has pens 6 and 7 opaque - tunnels */
+
+ tilemap_set_scroll_rows(bg_tilemap,4);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( travrusa_videoram_w )
+{
+ travrusa_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset/2);
+}
+
+
+static int scrollx[2];
+
+static void set_scroll(void)
+{
+ int i;
+
+ for (i = 0;i <= 2;i++)
+ tilemap_set_scrollx(bg_tilemap,i,scrollx[0] + 256 * scrollx[1]);
+ tilemap_set_scrollx(bg_tilemap,3,0);
+}
+
+WRITE8_HANDLER( travrusa_scroll_x_low_w )
+{
+ scrollx[0] = data;
+ set_scroll();
+}
+
+WRITE8_HANDLER( travrusa_scroll_x_high_w )
+{
+ scrollx[1] = data;
+ set_scroll();
+}
+
+
+WRITE8_HANDLER( travrusa_flipscreen_w )
+{
+ /* screen flip is handled both by software and hardware */
+ data ^= ~readinputport(4) & 1;
+
+ flip_screen_set(data & 1);
+
+ coin_counter_w(0,data & 0x02);
+ coin_counter_w(1,data & 0x20);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+ static rectangle spritevisiblearea =
+ {
+ 1*8, 31*8-1,
+ 0*8, 24*8-1
+ };
+ static rectangle spritevisibleareaflip =
+ {
+ 1*8, 31*8-1,
+ 8*8, 32*8-1
+ };
+ rectangle clip = *cliprect;
+ if (flip_screen)
+ sect_rect(&clip, &spritevisibleareaflip);
+ else
+ sect_rect(&clip, &spritevisiblearea);
+
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int sx = ((spriteram[offs + 3] + 8) & 0xff) - 8;
+ int sy = 240 - spriteram[offs];
+ int code = spriteram[offs + 2];
+ int attr = spriteram[offs + 1];
+ int flipx = attr & 0x40;
+ int flipy = attr & 0x80;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ attr & 0x0f,
+ flipx,flipy,
+ sx,sy,
+ &clip,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+VIDEO_UPDATE( travrusa )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER1,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_LAYER0,0);
+ return 0;
+}
diff --git a/src/mame/video/triplhnt.c b/src/mame/video/triplhnt.c
new file mode 100644
index 00000000000..50df61f7d7b
--- /dev/null
+++ b/src/mame/video/triplhnt.c
@@ -0,0 +1,148 @@
+/***************************************************************************
+
+Atari Triple Hunt video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "triplhnt.h"
+
+
+UINT8* triplhnt_playfield_ram;
+UINT8* triplhnt_hpos_ram;
+UINT8* triplhnt_vpos_ram;
+UINT8* triplhnt_code_ram;
+UINT8* triplhnt_orga_ram;
+
+int triplhnt_sprite_zoom;
+int triplhnt_sprite_bank;
+
+static mame_bitmap* helper;
+static tilemap* bg_tilemap;
+
+
+static TILE_GET_INFO( get_tile_info )
+{
+ int code = triplhnt_playfield_ram[tile_index] & 0x3f;
+
+ SET_TILE_INFO(2, code, code == 0x3f ? 1 : 0, 0);
+}
+
+
+VIDEO_START( triplhnt )
+{
+ helper = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ bg_tilemap = tilemap_create(get_tile_info, tilemap_scan_rows, 0, 16, 16, 16, 16);
+}
+
+
+static TIMER_CALLBACK( triplhnt_hit_callback )
+{
+ triplhnt_set_collision(param);
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ int i;
+
+ int hit_line = 999;
+ int hit_code = 999;
+
+ for (i = 0; i < 16; i++)
+ {
+ rectangle rect;
+
+ int j = (triplhnt_orga_ram[i] & 15) ^ 15;
+
+ /* software sorts sprites by x and stores order in orga RAM */
+
+ int hpos = triplhnt_hpos_ram[j] ^ 255;
+ int vpos = triplhnt_vpos_ram[j] ^ 255;
+ int code = triplhnt_code_ram[j] ^ 255;
+
+ if (hpos == 255)
+ {
+ continue;
+ }
+
+ /* sprite placement might be wrong */
+
+ if (triplhnt_sprite_zoom)
+ {
+ rect.min_x = hpos - 16;
+ rect.min_y = 196 - vpos;
+ rect.max_x = rect.min_x + 63;
+ rect.max_y = rect.min_y + 63;
+ }
+ else
+ {
+ rect.min_x = hpos - 16;
+ rect.min_y = 224 - vpos;
+ rect.max_x = rect.min_x + 31;
+ rect.max_y = rect.min_y + 31;
+ }
+
+ /* render sprite to auxiliary bitmap */
+
+ drawgfx(helper, machine->gfx[triplhnt_sprite_zoom],
+ 2 * code + triplhnt_sprite_bank, 0, code & 8, 0,
+ rect.min_x, rect.min_y, cliprect, TRANSPARENCY_NONE, 0);
+
+ if (rect.min_x < cliprect->min_x)
+ rect.min_x = cliprect->min_x;
+ if (rect.min_y < cliprect->min_y)
+ rect.min_y = cliprect->min_y;
+ if (rect.max_x > cliprect->max_x)
+ rect.max_x = cliprect->max_x;
+ if (rect.max_y > cliprect->max_y)
+ rect.max_y = cliprect->max_y;
+
+ /* check for collisions and copy sprite */
+
+ {
+ int x;
+ int y;
+
+ for (x = rect.min_x; x <= rect.max_x; x++)
+ {
+ for (y = rect.min_y; y <= rect.max_y; y++)
+ {
+ pen_t a = *BITMAP_ADDR16(helper, y, x);
+ pen_t b = *BITMAP_ADDR16(bitmap, y, x);
+
+ if (a == 2 && b == 7)
+ {
+ hit_code = j;
+ hit_line = y;
+ }
+
+ if (a != 1)
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = a;
+ }
+ }
+ }
+ }
+ }
+
+ if (hit_line != 999 && hit_code != 999)
+ {
+ timer_set(video_screen_get_time_until_pos(0, hit_line, 0), hit_code, triplhnt_hit_callback);
+ }
+}
+
+
+VIDEO_UPDATE( triplhnt )
+{
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ draw_sprites(machine, bitmap, cliprect);
+
+ discrete_sound_w(TRIPLHNT_BEAR_ROAR_DATA, triplhnt_playfield_ram[0xfa] & 15);
+ discrete_sound_w(TRIPLHNT_SHOT_DATA, triplhnt_playfield_ram[0xfc] & 15);
+ return 0;
+}
diff --git a/src/mame/video/troangel.c b/src/mame/video/troangel.c
new file mode 100644
index 00000000000..b47d2a1350d
--- /dev/null
+++ b/src/mame/video/troangel.c
@@ -0,0 +1,239 @@
+#include "driver.h"
+
+
+UINT8 *troangel_scroll;
+
+static int flipscreen;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Tropical Angel has two 256x4 character palette PROMs, one 32x8 sprite
+ palette PROM, and one 256x4 sprite color lookup table PROM.
+
+ I don't know for sure how the palette PROMs are connected to the RGB
+ output, but it's probably something like this; note that RED and BLUE
+ are swapped wrt the usual configuration.
+
+ bit 7 -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ bit 0 -- 1 kohm resistor -- BLUE
+
+***************************************************************************/
+PALETTE_INIT( troangel )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+
+ /* character palette */
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = 0;
+ bit1 = (color_prom[256] >> 2) & 0x01;
+ bit2 = (color_prom[256] >> 3) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[0] >> 3) & 0x01;
+ bit1 = (color_prom[256] >> 0) & 0x01;
+ bit2 = (color_prom[256] >> 1) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ COLOR(0,i) = i;
+ color_prom++;
+ }
+
+ color_prom += 256;
+ /* color_prom now points to the beginning of the sprite palette */
+
+
+ /* sprite palette */
+ for (i = 0;i < 16;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i+256,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 16;
+ /* color_prom now points to the beginning of the sprite lookup table */
+
+
+ /* sprite lookup table */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ {
+ COLOR(1,i) = 256 + (~*color_prom & 0x0f);
+ color_prom++;
+ }
+}
+
+
+
+WRITE8_HANDLER( troangel_flipscreen_w )
+{
+ /* screen flip is handled both by software and hardware */
+ data ^= ~readinputport(4) & 1;
+
+ if (flipscreen != (data & 1))
+ {
+ flipscreen = data & 1;
+ memset(dirtybuffer,1,videoram_size);
+ }
+
+ coin_counter_w(0,data & 0x02);
+ coin_counter_w(1,data & 0x20);
+}
+
+
+
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+ const gfx_element *gfx = machine->gfx[0];
+
+ for (offs = videoram_size - 2;offs >= 0;offs -= 2)
+ {
+ if (dirtybuffer[offs] || dirtybuffer[offs+1])
+ {
+ int sx,sy,code,attr,flipx,flipy;
+
+
+ dirtybuffer[offs] = dirtybuffer[offs+1] = 0;
+
+ sx = (offs/2) % 32;
+ sy = (offs/2) / 32;
+
+ attr = videoram[offs+0];
+ code = videoram[offs+1] | ((attr & 0xc0) << 2);
+ flipx = attr & 0x20;
+ flipy = (attr & 0x10) >> 4;
+
+ if (flipscreen)
+ {
+ sx = 31 - sx;
+ sy = 31 - sy;
+ flipx = !flipx;
+ }
+
+ drawgfx(tmpbitmap,gfx,
+ code,
+ attr & 0x0f,
+ flipx,flipy ^ flipscreen,
+ 8*sx,8*sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ {
+ int xscroll[256];
+
+ if (flipscreen)
+ {
+ /* fixed */
+ for (offs = 0;offs < 64;offs++) xscroll[255-offs] = 0;
+
+ /* scroll (wraps around) */
+ for (offs = 64;offs < 128;offs++) xscroll[255-offs] = troangel_scroll[64];
+
+ /* linescroll (no wrap) */
+ for (offs = 128;offs < 256;offs++) xscroll[255-offs] = troangel_scroll[offs];
+ }
+ else
+ {
+ /* fixed */
+ for (offs = 0;offs < 64;offs++) xscroll[offs] = 0;
+
+ /* scroll (wraps around) */
+ for (offs = 64;offs < 128;offs++) xscroll[offs] = -troangel_scroll[64];
+
+ /* linescroll (no wrap) */
+ for (offs = 128;offs < 256;offs++) xscroll[offs] = -troangel_scroll[offs];
+ }
+
+ copyscrollbitmap(bitmap,tmpbitmap,256,xscroll,0,0,cliprect,TRANSPARENCY_NONE,0);
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+
+ for (offs = spriteram_size-4;offs >= 0;offs -= 4)
+ {
+ UINT8 attributes = spriteram[offs+1];
+ int sx = spriteram[offs+3];
+ int sy = ((224-spriteram[offs+0]-32)&0xff)+32;
+ int code = spriteram[offs+2];
+ int color = attributes&0x1f;
+ int flipy = attributes&0x80;
+ int flipx = attributes&0x40;
+
+ int tile_number = code & 0x3f;
+
+ int bank = 0;
+ if( code&0x80 ) bank += 1;
+ if( attributes&0x20 ) bank += 2;
+
+ if (flipscreen)
+ {
+ sx = 240 - sx;
+ sy = 224 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1+bank],
+ tile_number,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+
+VIDEO_UPDATE( troangel )
+{
+ draw_background(machine, bitmap, cliprect);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/truco.c b/src/mame/video/truco.c
new file mode 100644
index 00000000000..4436f3ad111
--- /dev/null
+++ b/src/mame/video/truco.c
@@ -0,0 +1,54 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+PALETTE_INIT( truco )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int r = ( i & 0x8 ) ? 0xff : 0x00;
+ int g = ( i & 0x4 ) ? 0xff : 0x00;
+ int b = ( i & 0x2 ) ? 0xff : 0x00;
+
+ int dim = ( i & 0x1 );
+
+ if ( dim ) {
+ r >>= 1;
+ g >>= 1;
+ b >>= 1;
+ }
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+VIDEO_UPDATE( truco )
+{
+ UINT8 *vid = videoram;
+ int x, y;
+
+ for( y = 0; y < 192; y++ ) {
+ for( x = 0; x < 256; x++ ) {
+ int pixel;
+
+ if ( x & 1 ) {
+ pixel = vid[x>>1] & 0x0f;
+ } else {
+ pixel = ( vid[x>>1] >> 4 ) & 0x0f;
+ }
+
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[pixel];
+ }
+
+ vid += 0x80;
+ }
+ return 0;
+}
diff --git a/src/mame/video/trucocl.c b/src/mame/video/trucocl.c
new file mode 100644
index 00000000000..6a89a90e1ce
--- /dev/null
+++ b/src/mame/video/trucocl.c
@@ -0,0 +1,82 @@
+/***************************************************************************
+
+Truco Clemente (c) 1991 Miky SRL
+
+driver by Ernesto Corvi
+
+Notes:
+- Audio is almost there.
+- After one game you can't play anymore.
+- I think this runs on a heavily modified PacMan type of board.
+
+----------------------------------
+Additional Notes (Roberto Fresca):
+----------------------------------
+Mainboard: Pacman bootleg jamma board.
+Daughterboard: Custom made, plugged in the 2 roms and Z80 mainboard sockets.
+
+ - 01 x Z80
+ - 03 x 27c010
+ - 02 x am27s19
+ - 03 x GAL 16v8b (All of them have the same contents... Maybe read protected.)
+ - 01 x PAL CE 20v8h (The fuse map is suspect too)
+ - 01 x lm324n
+
+ To not overload the driver, I put the rest of technical info in
+ http://www.mameworld.net/robbie/trucocl.htm
+
+- Added 2 "hidden" color proms (am27s19)
+- One GAL is connected to the color proms inputs.
+- The name of the company is "Miky SRL" instead of "Caloi Miky SRL".
+ Caloi (Carlos Loiseau), is the Clemente's creator.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+PALETTE_INIT( trucocl )
+{
+ int i;
+
+ for (i = 0;i < 32;i++)
+ palette_set_color_rgb(machine,i,pal4bit(color_prom[i] >> 0),pal4bit(color_prom[i+32] >> 0),pal4bit(color_prom[i+32] >> 4));
+}
+
+WRITE8_HANDLER( trucocl_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( trucocl_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int gfxsel = colorram[tile_index] & 1;
+ int bank = ( ( colorram[tile_index] >> 2 ) & 0x07 );
+ int code = videoram[tile_index];
+ int colour = (colorram[tile_index] & 2) >> 1;
+
+ code |= ( bank & 1 ) << 10;
+ code |= ( bank & 2 ) << 8;
+ code += ( bank & 4 ) << 6;
+
+ SET_TILE_INFO(gfxsel,code,colour,0);
+}
+
+VIDEO_START( trucocl )
+{
+ bg_tilemap = tilemap_create( get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32 );
+}
+
+VIDEO_UPDATE( trucocl )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/tryout.c b/src/mame/video/tryout.c
new file mode 100644
index 00000000000..315d5447079
--- /dev/null
+++ b/src/mame/video/tryout.c
@@ -0,0 +1,263 @@
+/***************************************************************
+
+ Pro Yakyuu Nyuudan Test Tryout (JPN Ver.)
+ video hardware emulation
+
+****************************************************************/
+
+#include "driver.h"
+
+static tilemap *fg_tilemap, *bg_tilemap;
+static UINT8 vram_bank;
+static UINT8 *tryout_vram, *tryout_vram_gfx;
+UINT8 *tryout_gfx_control;
+
+PALETTE_INIT( tryout )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code, attr;
+
+ code = videoram[tile_index];
+ attr = videoram[tile_index + 0x400];
+
+ code |= ((attr & 0x03) << 8);
+
+ SET_TILE_INFO(0, code, 6, 0);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ SET_TILE_INFO(2, tryout_vram[tile_index] & 0x7f, 0, 0);
+}
+
+READ8_HANDLER( tryout_vram_r )
+{
+ return tryout_vram[offset]; // debug only
+}
+
+WRITE8_HANDLER( tryout_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset & 0x3ff);
+}
+
+WRITE8_HANDLER( tryout_vram_w )
+{
+ /* There are eight banks of vram - in bank 0 the first 0x400 bytes
+ is reserved for the tilemap. In banks 2, 4 and 6 the game never
+ writes to the first 0x400 bytes - I suspect it's either
+ unused, or it actually mirrors the tilemap ram from the first bank.
+
+ The rest of the vram is tile data which has the bitplanes arranged
+ in a very strange format. For Mame's sake we reformat this on
+ the fly for easier gfx decode.
+
+ Bit 0 of the bank register seems special - it's kept low when uploading
+ gfx data and then set high from that point onwards.
+
+ */
+ const UINT8 bank=(vram_bank>>1)&0x7;
+
+
+ if ((bank==0 || bank==2 || bank==4 || bank==6) && (offset&0x7ff)<0x400) {
+ int newoff=offset&0x3ff;
+
+ switch (newoff&0x300){
+ case 0x000: newoff=(newoff&0xff) | 0x100; break;
+ case 0x100: newoff=(newoff&0xff) | 0x200; break;
+ case 0x200: newoff=(newoff&0xff) | 0x000; break;
+ case 0x300: newoff=(newoff&0xff) | 0x300; break;
+ }
+
+ tryout_vram[newoff]=data;
+ tilemap_mark_tile_dirty(bg_tilemap,newoff);
+ return;
+ }
+
+ /*
+ Bit planes for tiles are arranged as follows within vram (split into high/low nibbles):
+ 0x0400 (0) + 0x0400 (4) + 0x0800(0) - tiles 0x00 to 0x0f
+ 0x0800 (4) + 0x0c00 (0) + 0x0c00(4) - tiles 0x10 to 0x1f
+ 0x1400 (0) + 0x1400 (4) + 0x1800(0) - tiles 0x20 to 0x2f
+ 0x1800 (4) + 0x1c00 (0) + 0x1c00(4) - tiles 0x30 to 0x3f
+ etc.
+ */
+
+ offset=(offset&0x7ff) | (bank<<11);
+ tryout_vram[offset]=data;
+
+ switch (offset&0x1c00) {
+ case 0x0400:
+ tryout_vram_gfx[(offset&0x3ff) + 0x0000 + ((offset&0x2000)>>1)]=(data&0xf);
+ tryout_vram_gfx[(offset&0x3ff) + 0x2000 + ((offset&0x2000)>>1)]=(data&0xf0)>>4;
+ break;
+ case 0x0800:
+ tryout_vram_gfx[(offset&0x3ff) + 0x4000 + ((offset&0x2000)>>1)]=(data&0xf);
+ tryout_vram_gfx[(offset&0x3ff) + 0x4400 + ((offset&0x2000)>>1)]=(data&0xf0)>>4;
+ break;
+ case 0x0c00:
+ tryout_vram_gfx[(offset&0x3ff) + 0x0400 + ((offset&0x2000)>>1)]=(data&0xf);
+ tryout_vram_gfx[(offset&0x3ff) + 0x2400 + ((offset&0x2000)>>1)]=(data&0xf0)>>4;
+ break;
+ case 0x1400:
+ tryout_vram_gfx[(offset&0x3ff) + 0x0800 + ((offset&0x2000)>>1)]=(data&0xf);
+ tryout_vram_gfx[(offset&0x3ff) + 0x2800 + ((offset&0x2000)>>1)]=(data&0xf0)>>4;
+ break;
+ case 0x1800:
+ tryout_vram_gfx[(offset&0x3ff) + 0x4800 + ((offset&0x2000)>>1)]=(data&0xf);
+ tryout_vram_gfx[(offset&0x3ff) + 0x4c00 + ((offset&0x2000)>>1)]=(data&0xf0)>>4;
+ break;
+ case 0x1c00:
+ tryout_vram_gfx[(offset&0x3ff) + 0x0c00 + ((offset&0x2000)>>1)]=(data&0xf);
+ tryout_vram_gfx[(offset&0x3ff) + 0x2c00 + ((offset&0x2000)>>1)]=(data&0xf0)>>4;
+ break;
+ }
+
+ decodechar(Machine->gfx[2],(offset-0x400/64)&0x7f,tryout_vram_gfx,Machine->drv->gfxdecodeinfo[2].gfxlayout);
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+}
+
+WRITE8_HANDLER( tryout_vram_bankswitch_w )
+{
+ vram_bank = data;
+}
+
+WRITE8_HANDLER( tryout_flipscreen_w )
+{
+ flip_screen_set(data & 1);
+}
+
+static TILEMAP_MAPPER( get_fg_memory_offset )
+{
+ return (row ^ 0x1f) + (col << 5);
+}
+
+static TILEMAP_MAPPER( get_bg_memory_offset )
+{
+ int a;
+// if (col&0x20)
+// a= (7 - (row & 7)) + ((0x8 - (row & 0x8)) << 4) + ((col & 0xf) << 3) + (( ( 0x10 - (col & 0x10) ) ) << 4) + ((( (col & 0x20))) << 4);
+// else
+ a= (7 - (row & 7)) + ((0x8 - (row & 0x8)) << 4) + ((col & 0xf) << 3) + (( ( (col & 0x10) ) ) << 4) + ((( (col & 0x20))) << 4);
+
+// mame_printf_debug("%d %d -> %d\n",col,row, a);
+ return a;
+}
+
+VIDEO_START( tryout )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info,get_fg_memory_offset,TILEMAP_TYPE_PEN,8,8,32,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,get_bg_memory_offset,TILEMAP_TYPE_PEN,16,16,64,16);
+
+ tryout_vram=auto_malloc(8 * 0x800);
+ tryout_vram_gfx=auto_malloc(0x6000);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs,fx,fy,x,y,color,sprite,inc;
+
+ for (offs = 0;offs < 0x7f;offs += 4)
+ {
+ if (!(spriteram[offs]&1))
+ continue;
+
+ sprite = spriteram[offs+1] + ((spriteram_2[offs]&7)<<8);
+ x = spriteram[offs+3]-3;
+ y = spriteram[offs+2];
+ color = (spriteram[offs] & 8)>>3;
+ fx = 0;
+ fy = 0;
+ inc = 16;
+
+ if (flip_screen)
+ {
+ x = 240 - x;
+ fx = !fx;
+
+ y = 240 - y;
+ fy = !fy;
+
+ inc = -inc;
+ }
+
+ /* Double Height */
+ if(spriteram[offs] & 0x10)
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ sprite,
+ color,fx,fy,x,y + inc,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ drawgfx(bitmap,machine->gfx[1],
+ sprite+1,
+ color,fx,fy,x,y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ drawgfx(bitmap,machine->gfx[1],
+ sprite,
+ color,fx,fy,x,y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( tryout )
+{
+// UINT8* mem=memory_region(REGION_CPU1);
+
+ int scrollx;
+
+ if (!flip_screen)
+ tilemap_set_scrollx(fg_tilemap, 0, 16); /* Assumed hard-wired */
+ else
+ tilemap_set_scrollx(fg_tilemap, 0, -8); /* Assumed hard-wired */
+
+ if(tryout_gfx_control[0] == 0xc)
+ scrollx = tryout_gfx_control[1];
+ if(tryout_gfx_control[0] == 0x8 && !tryout_gfx_control[1])
+ scrollx = 0x100;
+ else
+ scrollx = tryout_gfx_control[1] | ((tryout_gfx_control[0]&1)<<8) | ((tryout_gfx_control[0]&4)<<7);
+
+ tilemap_set_scrollx(bg_tilemap, 0, scrollx);
+ tilemap_set_scrolly(bg_tilemap, 0, -tryout_gfx_control[2]);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+
+// popmessage("%02x %02x %02x - %04x",mem[0xe402],mem[0xe403],mem[0xe404], ((tryout_gfx_control[0]&1)<<8) | ((tryout_gfx_control[0]&4)<<7));
+ return 0;
+}
diff --git a/src/mame/video/tsamurai.c b/src/mame/video/tsamurai.c
new file mode 100644
index 00000000000..ed33ed09da7
--- /dev/null
+++ b/src/mame/video/tsamurai.c
@@ -0,0 +1,277 @@
+/*
+** Video Driver for Taito Samurai (1985)
+*/
+
+#include "driver.h"
+
+
+/*
+** variables
+*/
+UINT8 *tsamurai_videoram;
+static int bgcolor;
+static int textbank1, textbank2;
+
+static tilemap *background, *foreground;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 attributes = tsamurai_videoram[2*tile_index+1];
+ int tile_number = tsamurai_videoram[2*tile_index];
+ tile_number += (( attributes & 0xc0 ) >> 6 ) * 256; /* legacy */
+ tile_number += (( attributes & 0x20 ) >> 5 ) * 1024; /* Mission 660 add-on*/
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ attributes & 0x1f,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int tile_number = videoram[tile_index];
+ if (textbank1 & 0x01) tile_number += 256; /* legacy */
+ if (textbank2 & 0x01) tile_number += 512; /* Mission 660 add-on */
+ SET_TILE_INFO(
+ 1,
+ tile_number,
+ colorram[((tile_index&0x1f)*2)+1] & 0x1f,
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( tsamurai )
+{
+ background = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ foreground = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(background,0);
+ tilemap_set_transparent_pen(foreground,0);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( tsamurai_scrolly_w )
+{
+ tilemap_set_scrolly( background, 0, data );
+}
+
+WRITE8_HANDLER( tsamurai_scrollx_w )
+{
+ tilemap_set_scrollx( background, 0, data );
+}
+
+WRITE8_HANDLER( tsamurai_bgcolor_w )
+{
+ bgcolor = data;
+}
+
+WRITE8_HANDLER( tsamurai_textbank1_w )
+{
+ if( textbank1!=data )
+ {
+ textbank1 = data;
+ tilemap_mark_all_tiles_dirty( foreground );
+ }
+}
+
+WRITE8_HANDLER( tsamurai_textbank2_w )
+{
+ if( textbank2!=data )
+ {
+ textbank2 = data;
+ tilemap_mark_all_tiles_dirty( foreground );
+ }
+}
+
+WRITE8_HANDLER( tsamurai_bg_videoram_w )
+{
+ tsamurai_videoram[offset]=data;
+ offset = offset/2;
+ tilemap_mark_tile_dirty(background,offset);
+}
+WRITE8_HANDLER( tsamurai_fg_videoram_w )
+{
+ videoram[offset]=data;
+ tilemap_mark_tile_dirty(foreground,offset);
+}
+WRITE8_HANDLER( tsamurai_fg_colorram_w )
+{
+ if( colorram[offset]!=data )
+ {
+ colorram[offset]=data;
+ if (offset & 1)
+ {
+ int col = offset/2;
+ int row;
+ for (row = 0;row < 32;row++)
+ tilemap_mark_tile_dirty(foreground,32*row+col);
+ }
+ }
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ gfx_element *gfx = machine->gfx[2];
+ const UINT8 *source = spriteram+32*4-4;
+ const UINT8 *finish = spriteram; /* ? */
+ static int flicker;
+ flicker = 1-flicker;
+
+ while( source>=finish )
+ {
+ int attributes = source[2]; /* bit 0x10 is usually, but not always set */
+
+ int sx = source[3] - 16;
+ int sy = 240-source[0];
+ int sprite_number = source[1];
+ int color = attributes&0x1f;
+
+#if 0
+ /* VS Gong Fight */
+ if (attributes == 0xe)
+ attributes = 4;
+ if (attributes > 7 || attributes < 4 || attributes == 5 )
+ attributes = 6;
+ color = attributes&0x1f;
+#endif
+
+#if 0
+ /* Nunchakun */
+ color = 0x2d - (attributes&0x1f);
+#endif
+
+ if( sy<-16 ) sy += 256;
+
+ /* 240-source[0] seems nice,but some dangling sprites appear on the left */
+ /* side in Mission 660.Setting it to 242 fixes it,but will break other games. */
+ /* So I'm using this specific check. -kal 11 jul 2002 */
+// if(sprite_type == 1) sy=sy+2;
+
+ if( flip_screen )
+ {
+ drawgfx( bitmap,gfx,
+ sprite_number&0x7f,
+ color,
+ 1,(sprite_number&0x80)?0:1,
+ 256-32-sx,256-32-sy,
+ cliprect,TRANSPARENCY_PEN,0 );
+ }
+ else
+ {
+ drawgfx( bitmap,gfx,
+ sprite_number&0x7f,
+ color,
+ 0,sprite_number&0x80,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0 );
+ }
+
+ source -= 4;
+ }
+}
+
+VIDEO_UPDATE( tsamurai )
+{
+ int i;
+
+/* Do the column scroll used for the "660" logo on the title screen */
+ tilemap_set_scroll_cols(foreground, 32);
+ for (i = 0 ; i < 32 ; i++)
+ {
+ tilemap_set_scrolly(foreground, i, colorram[i*2]);
+ }
+/* end of column scroll code */
+
+ /*
+ This following isn't particularly efficient. We'd be better off to
+ dynamically change every 8th palette to the background color, so we
+ could draw the background as an opaque tilemap.
+
+ Note that the background color register isn't well understood
+ (screenshots would be helpful)
+ */
+ fillbitmap(bitmap,machine->pens[bgcolor],cliprect);
+ tilemap_draw(bitmap,cliprect,background,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,foreground,0,0);
+ return 0;
+}
+
+/***************************************************************************
+
+VS Gong Fight runs on older hardware
+
+***************************************************************************/
+
+static int vsgongf_color;
+
+WRITE8_HANDLER( vsgongf_color_w )
+{
+ if( vsgongf_color != data )
+ {
+ vsgongf_color = data;
+ tilemap_mark_all_tiles_dirty( foreground );
+ }
+}
+
+
+static TILE_GET_INFO( get_vsgongf_tile_info )
+{
+ int tile_number = videoram[tile_index];
+ int color = vsgongf_color&0x1f;
+ if( textbank1 ) tile_number += 0x100;
+ SET_TILE_INFO(
+ 1,
+ tile_number,
+ color,
+ 0);
+}
+
+VIDEO_START( vsgongf )
+{
+ foreground = tilemap_create(get_vsgongf_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+}
+
+VIDEO_UPDATE( vsgongf )
+{
+ #ifdef MAME_DEBUG
+ static int k;
+ if( input_code_pressed( KEYCODE_Q ) ){
+ while( input_code_pressed( KEYCODE_Q ) ){
+ k++;
+ vsgongf_color = k;
+ tilemap_mark_all_tiles_dirty( foreground );
+ }
+ }
+ #endif
+
+ tilemap_draw(bitmap,cliprect,foreground,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/tubep.c b/src/mame/video/tubep.c
new file mode 100644
index 00000000000..7b47510de66
--- /dev/null
+++ b/src/mame/video/tubep.c
@@ -0,0 +1,926 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/tubep.h"
+#include "video/resnet.h"
+
+
+UINT8 *tubep_textram;
+UINT8 *rjammer_backgroundram;
+UINT8 *tubep_backgroundram;
+UINT8 *tubep_sprite_colorsharedram;
+
+static UINT8 *spritemap;
+static UINT8 prom2[32];
+
+/* Globals */
+/*static UINT8 graph_ctrl[10];*/
+static UINT32 romD_addr =0;
+static UINT32 romEF_addr =0;
+static UINT32 E16_add_b = 0;
+static UINT32 HINV = 0;
+static UINT32 VINV = 0;
+static UINT32 XSize = 0;
+static UINT32 YSize = 0;
+static UINT32 mark_1 = 0;
+static UINT32 mark_2 = 0;
+static UINT32 colorram_addr_hi = 0;
+static UINT32 ls273_g6 = 0;
+static UINT32 ls273_j6 = 0;
+static UINT32 romHI_addr_mid = 0;
+static UINT32 romHI_addr_msb = 0;
+static UINT8 DISP = 0;
+static UINT8 background_romsel = 0;
+static UINT8 color_A4 = 0;
+static UINT8 ls175_b7 = 0x0f | 0xf0;
+static UINT8 ls175_e8 = 0x0f;
+static UINT8 ls377_data = 0;
+static UINT32 page = 0;
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+
+ Tube Panic has two 32 bytes palette control PROMs.
+
+ First one is connected to the RGB output this way:
+
+ bit 7 -- 220 ohm resistor -- \
+ -- 470 ohm resistor -- | -- 470 ohm pulldown resistor -- BLUE
+
+ -- 220 ohm resistor -- \
+ -- 470 ohm resistor -- | -- 470 ohm pulldown resistor -- GREEN
+ -- 1 kohm resistor -- /
+
+ -- 220 ohm resistor -- \
+ -- 470 ohm resistor -- | -- 470 ohm pulldown resistor -- RED
+ bit 0 -- 1 kohm resistor -- /
+
+
+
+ The second PROM is used to control eight 74LS368s in following way:
+ (see the schematics for more comprehensible picture)
+
+ BLUE CONTROL:
+
+ PROM bit 7 -- /enable on LS368 @E16
+ PROM bit 6 -- /enable on LS368 @E15
+
+ 6 outputs (Q1 to Q6) from E16 go to BLUE output (the same line as
+ the first PROM) via 6 resistors:
+ Q1 -- 8200 -- BLUE
+ Q2 -- 4700 -- BLUE
+ Q3 -- 2200 -- BLUE
+ Q4 -- 1000 -- BLUE
+ Q5 -- 470 -- BLUE
+ Q6 -- 220 -- BLUE
+
+ 6 outputs (Q1 to Q6) from E15 go to BLUE output (the same line as
+ the first PROM) via 6 resistors:
+ Q1 --15000 -- BLUE
+ Q2 -- 8200 -- BLUE
+ Q3 -- 4700 -- BLUE
+ Q4 -- 2200 -- BLUE
+ Q5 -- 1000 -- BLUE
+ Q6 -- 470 -- BLUE
+
+
+ GREEN CONTROL:
+
+ PROM bit 5 -- /enable on LS368 @E14
+ PROM bit 4 -- /enable on LS368 @E13
+ PROM bit 3 -- /enable on LS368 @E12
+
+ 6 outputs (Q1 to Q6) from E14 go to GREEN output (the same line as
+ the first PROM) via 6 resistors:
+ Q1 -- 8200 -- GREEN
+ Q2 -- 4700 -- GREEN
+ Q3 -- 2200 -- GREEN
+ Q4 -- 1000 -- GREEN
+ Q5 -- 470 -- GREEN
+ Q6 -- 220 -- GREEN
+
+ 6 outputs (Q1 to Q6) from E13 go to GREEN output (the same line as
+ the first PROM) via 6 resistors:
+ Q1 --15000 -- GREEN
+ Q2 -- 8200 -- GREEN
+ Q3 -- 4700 -- GREEN
+ Q4 -- 2200 -- GREEN
+ Q5 -- 1000 -- GREEN
+ Q6 -- 470 -- GREEN
+
+ 6 outputs (Q1 to Q6) from E12 go to GREEN output (the same line as
+ the first PROM) via 6 resistors:
+ Q1 --33000 -- GREEN
+ Q2 --15000 -- GREEN
+ Q3 -- 8200 -- GREEN
+ Q4 -- 4700 -- GREEN
+ Q5 -- 2200 -- GREEN
+ Q6 -- 1000 -- GREEN
+
+
+ RED CONTROL:
+
+ PROM bit 2 -- /enable on LS368 @E11
+ PROM bit 1 -- /enable on LS368 @E10
+ PROM bit 0 -- /enable on LS368 @E9
+
+ 6 outputs (Q1 to Q6) from E11 go to RED output (the same line as
+ the first PROM) via 6 resistors:
+ Q1 -- 8200 -- RED
+ Q2 -- 4700 -- RED
+ Q3 -- 2200 -- RED
+ Q4 -- 1000 -- RED
+ Q5 -- 470 -- RED
+ Q6 -- 220 -- RED
+
+ 6 outputs (Q1 to Q6) from E10 go to RED output (the same line as
+ the first PROM) via 6 resistors:
+ Q1 --15000 -- RED
+ Q2 -- 8200 -- RED
+ Q3 -- 4700 -- RED
+ Q4 -- 2200 -- RED
+ Q5 -- 1000 -- RED
+ Q6 -- 470 -- RED
+
+ 6 outputs (Q1 to Q6) from E9 go to RED output (the same line as
+ the first PROM) via 6 resistors:
+ Q1 --33000 -- RED
+ Q2 --15000 -- RED
+ Q3 -- 8200 -- RED
+ Q4 -- 4700 -- RED
+ Q5 -- 2200 -- RED
+ Q6 -- 1000 -- RED
+
+
+***************************************************************************/
+
+
+PALETTE_INIT( tubep )
+{
+ int i,r,g,b;
+
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ /* background/sprites palette variables */
+
+ static const int resistors_0[6] = { 33000, 15000, 8200, 4700, 2200, 1000 };
+ static const int resistors_1[6] = { 15000, 8200, 4700, 2200, 1000, 470 };
+ static const int resistors_2[6] = { 8200, 4700, 2200, 1000, 470, 220 };
+
+ int active_resistors_r[3*6];
+ int active_resistors_g[3*6];
+ int active_resistors_b[2*6];
+
+ double weights_r[3*6];
+ double weights_g[3*6];
+ double weights_b[2*6];
+
+ double output_scaler;
+
+ /* text palette variables */
+
+ static const int resistors_txt_rg[3] = { 1000, 470, 220 };
+ static const int resistors_txt_b [2] = { 470, 220 };
+ double weights_txt_rg[3];
+ double weights_txt_b[2];
+
+ compute_resistor_weights(0, 255, -1.0,
+ 3, resistors_txt_rg, weights_txt_rg, 470, 0,
+ 2, resistors_txt_b, weights_txt_b, 470, 0,
+ 0, 0, 0, 0, 0 );
+
+ /* create text palette */
+
+ for (i = 0; i < 32; i++)
+ {
+ int bit0,bit1,bit2;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = combine_3_weights(weights_txt_rg, bit0, bit1, bit2);
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = combine_3_weights(weights_txt_rg, bit0, bit1, bit2);
+ /* blue component */
+ bit0 = (*color_prom >> 6) & 0x01;
+ bit1 = (*color_prom >> 7) & 0x01;
+ b = combine_2_weights(weights_txt_b, bit0, bit1);
+
+ palette_set_color(machine,i, MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+
+ /* text lookup */
+ for (i = 0; i < TOTAL_COLORS(0)/2; i++)
+ {
+ COLOR(0, 2*i+0 ) = 0; /* transparent "black" */
+ COLOR(0, 2*i+1 ) = i;
+ }
+
+ /* sprites use the second PROM to control 8 x LS368. We copy content of this PROM over here */
+ for (i = 0; i < 32; i++)
+ {
+ prom2[i] = *color_prom;
+ color_prom++;
+ }
+
+
+
+ /* create background/sprites palette */
+
+ /* find the output scaler
+ in order to do this we need to calculate the output with everything enabled.
+ */
+
+ /* red component */
+ for (i=0; i<6; i++) active_resistors_r[ 0+i] = resistors_0[i];
+ for (i=0; i<6; i++) active_resistors_r[ 6+i] = resistors_1[i];
+ for (i=0; i<6; i++) active_resistors_r[12+i] = resistors_2[i];
+ /* green component */
+ for (i=0; i<6; i++) active_resistors_g[ 0+i] = resistors_0[i];
+ for (i=0; i<6; i++) active_resistors_g[ 6+i] = resistors_1[i];
+ for (i=0; i<6; i++) active_resistors_g[12+i] = resistors_2[i];
+ /* blue component */
+ for (i=0; i<6; i++) active_resistors_b[ 0+i] = resistors_1[i];
+ for (i=0; i<6; i++) active_resistors_b[ 6+i] = resistors_2[i];
+
+ /* calculate and store the scaler */
+ output_scaler = compute_resistor_weights(0, 255, -1.0,
+ 3*6, active_resistors_r, weights_r, 470, 0,
+ 3*6, active_resistors_g, weights_g, 470, 0,
+ 2*6, active_resistors_b, weights_b, 470, 0);
+
+/* compute_resistor_weights(0, 255, output_scaler,
+ 3*6, active_resistors_r, weights_r, 470, 0,
+ 3*6, active_resistors_g, weights_g, 470, 0,
+ 2*6, active_resistors_b, weights_b, 470, 0);
+*/
+ /* now calculate all possible outputs from the circuit */
+
+ for (i=0; i<256; i++)
+ {
+ int sh;
+
+ for (sh=0; sh<0x40; sh++)
+ {
+ int j = i; /* active low */
+ int shade = sh^0x3f; /* negated outputs */
+
+ int bits_r[3*6];
+ int bits_g[3*6];
+ int bits_b[2*6];
+ double out;
+ int c;
+
+ int active_r = 3*6;
+ int active_g = 3*6;
+ int active_b = 2*6;
+
+ for (c=0; c<6; c++)
+ {
+ bits_r[0 + c] = (shade>>c) & 1;
+ bits_r[6 + c] = (shade>>c) & 1;
+ bits_r[12+ c] = (shade>>c) & 1;
+
+ bits_g[0 + c] = (shade>>c) & 1;
+ bits_g[6 + c] = (shade>>c) & 1;
+ bits_g[12+ c] = (shade>>c) & 1;
+
+ bits_b[0 + c] = (shade>>c) & 1;
+ bits_b[6 + c] = (shade>>c) & 1;
+ }
+
+ //j &= 0x7; /* only red; debug */
+
+ /* red component */
+ if ((j >> 0) & 0x01) /* if LS368 @E9 is disabled */
+ {
+ for (c=0; c<6; c++) bits_r[0 +c] = 0;
+ active_r-=6;
+ }
+ if ((j >> 1) & 0x01) /* if LS368 @E10 is disabled */
+ {
+ for (c=0; c<6; c++) bits_r[6 +c] = 0;
+ active_r-=6;
+ }
+ if ((j >> 2) & 0x01) /* if LS368 @E11 is disabled */
+ {
+ for (c=0; c<6; c++) bits_r[12 +c] = 0;
+ active_r-=6;
+ }
+
+ /* green component */
+ if ((j >> 3) & 0x01) /* if LS368 @E12 is disabled */
+ {
+ for (c=0; c<6; c++) bits_g[0 +c] = 0;
+ active_g-=6;
+ }
+ if ((j >> 4) & 0x01) /* if LS368 @E13 is disabled */
+ {
+ for (c=0; c<6; c++) bits_g[6 +c] = 0;
+ active_g-=6;
+ }
+ if ((j >> 5) & 0x01) /* if LS368 @E14 is disabled */
+ {
+ for (c=0; c<6; c++) bits_g[12+c] = 0;
+ active_g-=6;
+ }
+
+ /* blue component */
+ if ((j >> 6) & 0x01) /* if LS368 @E15 is disabled */
+ {
+ for (c=0; c<6; c++) bits_b[0 +c] = 0;
+ active_b-=6;
+ }
+ if ((j >> 7) & 0x01) /* if LS368 @E16 is disabled */
+ {
+ for (c=0; c<6; c++) bits_b[6 +c] = 0;
+ active_b-=6;
+ }
+
+ out = 0.0;
+ for (c=0; c<3*6; c++) out += weights_r[c] * bits_r[c];
+ r = (int)(out + 0.5);
+
+ out = 0.0;
+ for (c=0; c<3*6; c++) out += weights_g[c] * bits_g[c];
+ g = (int)(out + 0.5);
+
+ out = 0.0;
+ for (c=0; c<2*6; c++) out += weights_b[c] * bits_b[c];
+ b = (int)(out + 0.5);
+
+ /*logerror("Calculate [%x:%x] (active resistors:r=%i g=%i b=%i) = ", i, shade, active_r, active_g, active_b);*/
+ /*logerror("r:%3i g:%3i b:%3i\n",r,g,b );*/
+
+ palette_set_color(machine,32+i*0x40+sh, MAKE_RGB(r,g,b));
+ }
+ }
+}
+
+
+VIDEO_START( tubep )
+{
+ spritemap = auto_malloc(256*256*2);
+ memset(spritemap,0,256*256*2);
+
+ /* Set up save state */
+ state_save_register_global(romD_addr);
+ state_save_register_global(romEF_addr);
+ state_save_register_global(E16_add_b);
+ state_save_register_global(HINV);
+ state_save_register_global(VINV);
+ state_save_register_global(XSize);
+ state_save_register_global(YSize);
+ state_save_register_global(mark_1);
+ state_save_register_global(mark_2);
+ state_save_register_global(colorram_addr_hi);
+ state_save_register_global(ls273_g6);
+ state_save_register_global(ls273_j6);
+ state_save_register_global(romHI_addr_mid);
+ state_save_register_global(romHI_addr_msb);
+ state_save_register_global(DISP);
+ state_save_register_global(background_romsel);
+ state_save_register_global(color_A4);
+ state_save_register_global(ls175_b7);
+ state_save_register_global(ls175_e8);
+ state_save_register_global(ls377_data);
+ state_save_register_global(page);
+}
+
+
+WRITE8_HANDLER( tubep_textram_w )
+{
+ tubep_textram[offset] = data;
+}
+
+
+WRITE8_HANDLER( tubep_background_romselect_w )
+{
+ background_romsel = data & 1;
+}
+
+
+WRITE8_HANDLER( tubep_colorproms_A4_line_w )
+{
+ color_A4 = (data & 1)<<4;
+}
+
+
+WRITE8_HANDLER( tubep_background_a000_w )
+{
+ ls175_b7 = ((data&0x0f)^0x0f) | 0xf0;
+}
+
+
+WRITE8_HANDLER( tubep_background_c000_w )
+{
+ ls175_e8 = ((data&0x0f)^0x0f);
+}
+
+
+static TIMER_CALLBACK( sprite_timer_callback )
+{
+ cpunum_set_input_line(3,0,ASSERT_LINE);
+}
+
+
+static void draw_sprite(void)
+{
+ UINT32 XDOT;
+ UINT32 YDOT;
+ UINT8 * romCxx = memory_region(REGION_USER2)+0x00000;
+ UINT8 * romD10 = memory_region(REGION_USER2)+0x10000;
+ UINT8 * romEF13 = memory_region(REGION_USER2)+0x12000;
+ UINT8 * romHI2 = memory_region(REGION_USER2)+0x14000;
+
+
+ for (YDOT=0; (YDOT^YSize) != 0x00; YDOT++)
+ {
+ /* upper part of the schematic */
+ UINT32 ls273_e12 = romD10[ romD_addr | YDOT ] & 0x7f;
+ UINT32 romEF_addr_now = romEF_addr | ls273_e12;
+ UINT32 E16_add_a = romEF13[ romEF_addr_now ] |
+ ((romEF13[0x1000 + romEF_addr_now ]&0x0f)<<8);
+ UINT32 F16_add_b = E16_add_a + E16_add_b;
+
+ /* lower part of the schematic */
+ UINT32 romHI_addr = (YDOT) | (romHI_addr_mid) | (((romHI_addr_msb + 0x800) )&0x1800);
+ UINT32 ls273_g4 = romHI2[ romHI_addr ];
+ UINT32 ls273_j4 = romHI2[0x2000+ romHI_addr ];
+ UINT32 ls86_gh5 = ls273_g4 ^ VINV;
+ UINT32 ls86_ij5 = ls273_j4 ^ VINV;
+
+ UINT32 ls157_gh7= ls273_g6 | (mark_2);
+ UINT32 ls157_ij7= ls273_j6 | (mark_1);
+ UINT32 ls283_gh8= (VINV & 1) + ls86_gh5 + ((ls86_gh5 & 0x80)<<1) + ls157_gh7;
+ UINT32 ls283_ij8= (VINV & 1) + ls86_ij5 + ((ls86_ij5 & 0x80)<<1) + ls157_ij7;
+
+ UINT32 ls273_g9 = ls283_gh8;
+ UINT32 ls273_j9 = ls283_ij8;
+
+ for (XDOT=0; (XDOT^XSize) != 0x00; XDOT++)
+ {
+ /* upper part of the schematic */
+ UINT32 romD10_out = romD10[ romD_addr | XDOT ];
+ UINT32 F16_add_a = (romD10_out & 0x7e) >>1;
+ UINT32 romCxx_addr = (F16_add_a + F16_add_b ) & 0xffff;
+ UINT32 romCxx_out = romCxx[ romCxx_addr ];
+
+ UINT32 colorram_addr_lo = (romD10_out&1) ? (romCxx_out>>4)&0x0f: (romCxx_out>>0)&0x0f;
+
+ UINT8 sp_data = tubep_sprite_colorsharedram[ colorram_addr_hi | colorram_addr_lo ] & 0x0f; /* 2114 4-bit RAM */
+
+ /* lower part of the schematic */
+ romHI_addr = (XDOT) | (romHI_addr_mid) | (romHI_addr_msb);
+ ls273_g4 = romHI2[ romHI_addr ];
+ ls273_j4 = romHI2[0x2000+ romHI_addr ];
+ ls86_gh5 = ls273_g4 ^ HINV;
+ ls86_ij5 = ls273_j4 ^ HINV;
+
+ ls157_gh7= ls273_g9;
+ ls157_ij7= ls273_j9;
+ ls283_gh8= (HINV & 1) + ls86_gh5 + ((ls86_gh5 & 0x80)<<1) + ls157_gh7;
+ ls283_ij8= (HINV & 1) + ls86_ij5 + ((ls86_ij5 & 0x80)<<1) + ls157_ij7;
+
+
+ if ( !((ls283_gh8&256) | (ls283_ij8&256)) ) /* skip wrapped sprite area - PAL12L6 (PLA019 in Roller Jammer schematics)*/
+ {
+ if ( spritemap[ (ls283_gh8&255) + (ls283_ij8&255)*256 + DISP*256*256 ] == 0x0f )
+ spritemap[ (ls283_gh8&255) + (ls283_ij8&255)*256 + DISP*256*256 ] = sp_data;
+ }
+ }
+ }
+}
+
+
+WRITE8_HANDLER( tubep_sprite_control_w )
+{
+ if (offset < 10)
+ {
+ /*graph_ctrl[offset] = data;*/
+ switch(offset)
+ {
+ case 0: /*a*/
+ romEF_addr = (0x010 | (data & 0x0f))<<7; /*roms @F13, @E13 have A11 lines connected to +5V directly */
+ HINV = (data & 0x10) ? 0xff: 0x00;
+ VINV = (data & 0x20) ? 0xff: 0x00;
+ break;
+
+ case 1: /*b: XSize-1 */
+ XSize = data & 0x7f;
+ mark_2 = (data&0x80)<<1;
+ break;
+
+ case 2: /*c: YSize-1 */
+ YSize = data & 0x7f;
+ mark_1 = (data&0x80)<<1;
+ break;
+
+ case 3: /*d*/
+ ls273_g6 = (data & 0xff);
+ break;
+
+ case 4: /*e*/
+ ls273_j6 = (data & 0xff);
+ break;
+
+ case 5: /*f*/
+ romHI_addr_mid = (data & 0x0f)<<7;
+ romHI_addr_msb = (data & 0x30)<<7;
+ break;
+
+ case 6: /*g*/
+ romD_addr = (data & 0x3f)<<7;
+ break;
+
+ case 7: /*h: adder input LSB*/
+ E16_add_b = ((data & 0xff) << 0) | (E16_add_b & 0xff00);
+ break;
+
+ case 8: /*J: adder input MSB*/
+ E16_add_b = ((data & 0xff) << 8) | (E16_add_b & 0x00ff);
+ break;
+
+ case 9: /*K*/
+ /*write to: LS174 @J3 to set color bank (hi address lines to 2114 colorram @J1 ) */
+ colorram_addr_hi = (data & 0x3f) << 4;
+
+ /*write to: LS74 @D13 to clear the interrupt line /SINT
+ /SINT line will be reasserted in XSize * YSize cycles (RH0 signal cycles)
+ */
+ /* 1.clear the /SINT interrupt line */
+ cpunum_set_input_line(3,0,CLEAR_LINE);
+
+ /* 2.assert /SINT again after this time */
+ timer_set( attotime_mul(ATTOTIME_IN_HZ(19968000/8), (XSize+1)*(YSize+1)), 0, sprite_timer_callback);
+
+ /* 3.clear of /SINT starts sprite drawing circuit */
+ draw_sprite();
+ break;
+ }
+ }
+}
+
+void tubep_vblank_end(void)
+{
+ DISP = DISP ^ 1;
+ /* logerror("EOF: DISP after this is=%i, and clearing it now.\n", DISP); */
+ /* clear the new frame (the one that was (just) displayed)*/
+ memset(spritemap+DISP*256*256, 0x0f, 256*256);
+}
+
+
+VIDEO_UPDATE( tubep )
+{
+ int offs;
+ int DISP_ = DISP^1;
+
+ /* draw background ram */
+ {
+ const pen_t *pens = &machine->pens[ 32 ]; //change it later
+
+ UINT32 h,v;
+ UINT8 * romBxx = memory_region(REGION_USER1) + 0x2000*background_romsel;
+
+ /* logerror(" update: from DISP=%i y_min=%3i y_max=%3i\n", DISP_, cliprect->min_y, cliprect->max_y+1); */
+
+ for (v = cliprect->min_y; v <= cliprect->max_y; v++) /* only for current scanline */
+ {
+ UINT32 sp_data0=0,sp_data1=0,sp_data2=0;
+ for (h = 0*8; h < 32*8; h++)
+ {
+ UINT32 bg_data;
+ UINT32 sp_data;
+ UINT32 sel0,sel1,sel2;
+
+ UINT32 romB_addr = (((h>>1)&0x3f)^((h&0x80)?0x00:0x3f)) | (((v&0x7f)^((v&0x80)?0x00:0x7f))<<6);
+
+ UINT8 rom_select = (h&0x01) ^ (((h&0x80)>>7)^1);
+
+ /* read from ROMs: B3/4 or B5/6 */
+ UINT8 romB_data_h = romBxx[ 0x4000 + 0x4000*rom_select + romB_addr ];
+ /* romB_data_h = output of LS374 @B3 or @B4 */
+
+ UINT32 VR_addr = ((romB_data_h + ls175_b7) & 0xfe) << 2;
+ /* VR_addr = output of LS157s @B1 and @B6 */
+
+ UINT8 xor_logic = (((h^v)&0x80)>>7) ^ (background_romsel & (((v&0x80)>>7)^1));
+
+ /* read from ROMs: B1/2 */
+ UINT8 romB_data_l = romBxx[ romB_addr ] ^ (xor_logic?0xff:0x00);
+ /* romB_data_l = output of LS273 @B10 */
+
+ UINT8 ls157_b11 = (romB_data_l >> ((rom_select==0)?4:0))&0x0f;
+
+ UINT8 ls283_b12 = (ls157_b11 + ls175_e8) & 0x0f;
+
+ VR_addr |= (ls283_b12>>1);
+
+ bg_data = tubep_backgroundram[ VR_addr ];
+
+ romB_data_h>>=2;
+
+ sp_data2 = sp_data1;
+ sp_data1 = sp_data0;
+ sp_data0 = spritemap[ h + v*256 +(DISP_*256*256) ];
+ sel0 = 0;
+ if (sp_data0 != 0x0f)
+ sel0 = 1;
+
+ sel1 = 1;
+ if (sp_data1 != 0x0f)
+ sel1 = 0;
+
+ sel2 = 0;
+ if (sp_data2 != 0x0f)
+ sel2 = 1;
+
+ if (sel0&sel1&sel2)
+ sp_data = sp_data2;
+ else
+ sp_data = sp_data1;
+
+ if (sp_data!=0x0f)
+ bg_data = prom2[sp_data | color_A4];
+
+ *BITMAP_ADDR16(bitmap, v, h) = pens[ bg_data*64 + romB_data_h ];
+ }
+ }
+ }
+
+ /* draw the character mapped graphics */
+ for (offs = 0;offs < 0x800; offs+=2)
+ {
+ int sx,sy;
+
+ sx = (offs/2) % 32;
+ //if (flipscreen[0]) sx = 31 - sx;
+ sy = (offs/2) / 32;
+ //if (flipscreen[1]) sy = 31 - sy;
+
+ if ((cliprect->min_y&(~0x07)) == 8*sy)
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ tubep_textram[offs],
+ ((tubep_textram[offs+1]) & 0x0f) | color_A4,
+ 0,0, /*flipscreen[0],flipscreen[1],*/
+ 8*sx,8*sy,
+ cliprect, TRANSPARENCY_PEN, machine->pens[0]);
+ }
+ }
+
+
+ return 0;
+}
+
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Roller Jammer has two 32 bytes palette PROMs, connected to the RGB
+ output this way:
+
+ bit 7 -- 220 ohm resistor -- \
+ -- 470 ohm resistor -- | -- 470 ohm pulldown resistor -- BLUE
+
+ -- 220 ohm resistor -- \
+ -- 470 ohm resistor -- | -- 470 ohm pulldown resistor -- GREEN
+ -- 1 kohm resistor -- /
+
+ -- 220 ohm resistor -- \
+ -- 470 ohm resistor -- | -- 470 ohm pulldown resistor -- RED
+ bit 0 -- 1 kohm resistor -- /
+
+***************************************************************************/
+
+PALETTE_INIT( rjammer )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ static const int resistors_rg[3] = { 1000, 470, 220 };
+ static const int resistors_b [2] = { 470, 220 };
+ double weights_rg[3];
+ double weights_b[2];
+
+ compute_resistor_weights(0, 255, -1.0,
+ 3, resistors_rg, weights_rg, 470, 0,
+ 2, resistors_b, weights_b, 470, 0,
+ 0, 0, 0, 0, 0 );
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = combine_3_weights(weights_rg, bit0, bit1, bit2);
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = combine_3_weights(weights_rg, bit0, bit1, bit2);
+ /* blue component */
+ bit0 = (*color_prom >> 6) & 0x01;
+ bit1 = (*color_prom >> 7) & 0x01;
+ b = combine_2_weights(weights_b, bit0, bit1);
+
+ palette_set_color(machine,i, MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+
+
+ /* text: colors 0, 17-31 from PROM @16B */
+ for (i = 0; i < TOTAL_COLORS(0)/2; i++)
+ {
+ COLOR(0, 2*i + 0) = 0; /* transparent "black" */
+ COLOR(0, 2*i + 1) = i+16; /* /SOFF is on the A4 line */
+ }
+}
+
+
+WRITE8_HANDLER( rjammer_background_LS377_w )
+{
+ ls377_data = data & 0xff;
+}
+
+
+WRITE8_HANDLER( rjammer_background_page_w )
+{
+ page = (data & 1) * 0x200;
+}
+
+
+VIDEO_UPDATE( rjammer )
+{
+ int offs;
+ int DISP_ = DISP^1;
+
+ /* draw background ram */
+ {
+ const pen_t *pens = &machine->pens[ 0x00 ];
+
+ UINT32 h,v;
+ UINT8 * rom13D = memory_region(REGION_USER1);
+ UINT8 * rom11BD = memory_region(REGION_USER1)+0x1000;
+ UINT8 * rom19C = memory_region(REGION_USER1)+0x5000;
+
+
+ /* this can be optimized further by extracting constants out of the loop */
+ /* especially read from ROM19C can be done once per 8 pixels*/
+ /* and the data could be bitswapped beforehand */
+
+ for (v = cliprect->min_y; v <= cliprect->max_y; v++) /* only for current scanline */
+ {
+ UINT32 sp_data0=0,sp_data1=0,sp_data2=0;
+ UINT8 pal14h4_pin19;
+ UINT8 pal14h4_pin18;
+ UINT8 pal14h4_pin13;
+
+ UINT32 addr = (v*2) | page;
+ UINT32 ram_data = rjammer_backgroundram[ addr ] + 256*(rjammer_backgroundram[ addr+1 ]&0x2f);
+
+ addr = (v>>3) | ((ls377_data&0x1f)<<5);
+ pal14h4_pin13 = (rom19C[addr] >> ((v&7)^7) ) &1;
+ pal14h4_pin19 = (ram_data>>13) & 1;
+
+ for (h = 0*8; h < 32*8; h++)
+ {
+ UINT32 sp_data;
+ UINT32 sel0,sel1,sel2;
+
+ sp_data2 = sp_data1;
+ sp_data1 = sp_data0;
+ sp_data0 = spritemap[ h + v*256 +(DISP_*256*256) ];
+ sel0 = 0;
+ if (sp_data0 != 0x0f)
+ sel0 = 1;
+
+ sel1 = 1;
+ if (sp_data1 != 0x0f)
+ sel1 = 0;
+
+ sel2 = 0;
+ if (sp_data2 != 0x0f)
+ sel2 = 1;
+
+ if (sel0&sel1&sel2)
+ sp_data = sp_data2;
+ else
+ sp_data = sp_data1;
+
+ if (sp_data!=0x0f)
+ {
+ *BITMAP_ADDR16(bitmap, v, h) = pens[0x00+ sp_data ];
+ }
+ else
+ {
+ UINT32 bg_data;
+ UINT8 color_bank;
+
+ UINT32 ls283 = (ram_data & 0xfff) + h;
+ UINT32 rom13D_addr = ((ls283>>4)&0x00f) | (v&0x0f0) | (ls283&0xf00);
+
+ /* note: there is a jumper between bit 7 and bit 6 lines (bit 7 line is unused by default) */
+ /* default: bit 6 is rom select signal 0=rom @11B, 1=rom @11D */
+
+ UINT32 rom13D_data = rom13D[ rom13D_addr ] & 0x7f;
+ /* rom13d_data is actually a content of LS377 @14C */
+
+
+ UINT32 rom11BD_addr = (rom13D_data<<7) | ((v&0x0f)<<3) | ((ls283>>1)&0x07);
+ UINT32 rom11_data = rom11BD[ rom11BD_addr];
+
+ if ((ls283&1)==0)
+ bg_data = rom11_data & 0x0f;
+ else
+ bg_data = (rom11_data>>4) & 0x0f;
+
+ addr = (h>>3) | (ls377_data<<5);
+ pal14h4_pin18 = (rom19C[addr] >> ((h&7)^7) ) &1;
+
+/*
+ PAL14H4 @15A functions:
+
+ PIN6 = disable color on offscreen area
+
+ PIN19,PIN18,PIN13 = arguments for PIN17 function
+
+ PIN17 = background color bank (goes to A4 line on PROM @16A)
+ formula for PIN17 is:
+
+ PIN17 = ( PIN13 & PIN8 & PIN9 & !PIN11 & PIN12 )
+ | ( PIN18 & PIN8 & PIN9 & PIN11 & !PIN12 )
+ | ( PIN19 )
+
+ where:
+ PIN 8 = bit 3 of bg_data
+ PIN 9 = bit 2 of bg_data
+ PIN 11= bit 1 of bg_data
+ PIN 12= bit 0 of bg_data
+
+
+ not used by now, but for the record:
+
+ PIN15 = select prom @16B (active low)
+ PIN16 = select prom @16A (active low)
+ PINs: 1,2,3,4,5 and 7,14 are used for priority system
+
+*/
+ color_bank = (pal14h4_pin13 & ((bg_data&0x08)>>3) & ((bg_data&0x04)>>2) & (((bg_data&0x02)>>1)^1) & (bg_data&0x01) )
+ | (pal14h4_pin18 & ((bg_data&0x08)>>3) & ((bg_data&0x04)>>2) & ((bg_data&0x02)>>1) & ((bg_data&0x01)^1) )
+ | (pal14h4_pin19);
+ *BITMAP_ADDR16(bitmap, v, h) = pens[0x20+ color_bank*0x10 + bg_data ];
+ }
+ }
+ }
+ }
+
+ /* draw the character mapped graphics */
+ for (offs = 0;offs < 0x800; offs+=2)
+ {
+ int sx,sy;
+
+ sx = (offs/2) % 32;
+ //if (flipscreen[0]) sx = 31 - sx;
+ sy = (offs/2) / 32;
+ //if (flipscreen[1]) sy = 31 - sy;
+
+ if ((cliprect->min_y&(~0x07)) == 8*sy)
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ tubep_textram[offs],
+ (tubep_textram[offs+1]) & 0x0f,
+ 0,0, /*flipscreen[0],flipscreen[1],*/
+ 8*sx,8*sy,
+ cliprect, TRANSPARENCY_PEN, machine->pens[0]);
+ }
+ }
+
+ return 0;
+}
+
diff --git a/src/mame/video/tumbleb.c b/src/mame/video/tumbleb.c
new file mode 100644
index 00000000000..d8cd0128b0d
--- /dev/null
+++ b/src/mame/video/tumbleb.c
@@ -0,0 +1,840 @@
+/***************************************************************************
+
+ Tumblepop (bootlegs) and similar hardware
+ Video emulation - Bryan McPhail, mish@tendril.co.uk
+
+*********************************************************************
+
+The original uses Data East custom chip 55 for backgrounds,
+custom chip 52 for sprites. The bootlegs use generic chips to perform similar
+functions
+
+Tumblepop is one of few games to take advantage of the playfields ability
+to switch between 8*8 tiles and 16*16 tiles.
+
+***************************************************************************/
+
+#include "driver.h"
+
+static UINT16 tumblepb_control_0[8];
+UINT16 *tumblepb_pf1_data,*tumblepb_pf2_data;
+static tilemap *pf1_tilemap,*pf1_alt_tilemap,*pf2_tilemap,*pf2_alt_tilemap;
+static int flipscreen;
+extern UINT16* jumppop_control;
+static UINT16 bcstory_tilebank;
+extern UINT16* suprtrio_control;
+static int sprite_xoffset;
+static int sprite_yoffset;
+
+
+/******************************************************************************/
+
+static void tumblepb_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ sprite = spriteram16[offs+1] & 0x3fff;
+ if (!sprite) continue;
+
+ y = spriteram16[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ x = spriteram16[offs+2];
+ colour = (x >>9) & 0xf;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+ y = 240 - y;
+ x = 304 - x;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flipscreen)
+ {
+ y=240-y;
+ x=304-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ sprite_xoffset + x,sprite_yoffset + y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ multi--;
+ }
+ }
+}
+
+static void jumpkids_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size/2;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ sprite = spriteram16[offs+1] & 0x7fff;
+ if (!sprite) continue;
+
+ y = spriteram16[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ x = spriteram16[offs+2];
+ colour = (x >>9) & 0xf;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+ y = 240 - y;
+ x = 304 - x;
+
+ // sprite &= ~multi; /* Todo: I bet TumblePop bootleg doesn't do this either */
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flipscreen)
+ {
+ y=240-y;
+ x=304-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ sprite_xoffset+x,sprite_yoffset + y + mult * multi, // x-1 for bcstory .. realign other layers?
+ cliprect,TRANSPARENCY_PEN,0);
+
+ multi--;
+ }
+ }
+}
+
+static void fncywld_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ sprite = spriteram16[offs+1] & 0x3fff;
+ if (!sprite) continue;
+
+ y = spriteram16[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ x = spriteram16[offs+2];
+ colour = (x >>9) & 0x3f;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+ y = 240 - y;
+ x = 304 - x;
+
+ // sprite &= ~multi; /* Todo: I bet TumblePop bootleg doesn't do this either */
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flipscreen)
+ {
+ y=240-y;
+ x=304-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ sprite_xoffset+x,sprite_yoffset+ y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,15);
+
+ multi--;
+ }
+ }
+}
+
+/******************************************************************************/
+
+WRITE16_HANDLER( bcstory_tilebank_w )
+{
+ bcstory_tilebank = data;
+ tilemap_mark_all_tiles_dirty(pf1_tilemap);
+ tilemap_mark_all_tiles_dirty(pf1_alt_tilemap);
+ tilemap_mark_all_tiles_dirty(pf2_tilemap);
+}
+
+WRITE16_HANDLER( chokchok_tilebank_w )
+{
+ bcstory_tilebank = data<<1;
+ tilemap_mark_all_tiles_dirty(pf1_tilemap);
+ tilemap_mark_all_tiles_dirty(pf1_alt_tilemap);
+ tilemap_mark_all_tiles_dirty(pf2_tilemap);
+}
+
+WRITE16_HANDLER( wlstar_tilebank_w )
+{
+ /* it just writes 0000 or ffff */
+ bcstory_tilebank = data&0x4000;
+ tilemap_mark_all_tiles_dirty(pf1_tilemap);
+ tilemap_mark_all_tiles_dirty(pf1_alt_tilemap);
+ tilemap_mark_all_tiles_dirty(pf2_tilemap);
+}
+
+
+WRITE16_HANDLER( suprtrio_tilebank_w )
+{
+ bcstory_tilebank = data<<14; // shift it here, makes using bcstory_tilebank easier
+ tilemap_mark_all_tiles_dirty(pf1_tilemap);
+ tilemap_mark_all_tiles_dirty(pf1_alt_tilemap);
+ tilemap_mark_all_tiles_dirty(pf2_tilemap);
+}
+
+
+
+
+
+WRITE16_HANDLER( tumblepb_pf1_data_w )
+{
+ COMBINE_DATA(&tumblepb_pf1_data[offset]);
+ tilemap_mark_tile_dirty(pf1_tilemap,offset);
+ tilemap_mark_tile_dirty(pf1_alt_tilemap,offset);
+}
+
+WRITE16_HANDLER( tumblepb_pf2_data_w )
+{
+ COMBINE_DATA(&tumblepb_pf2_data[offset]);
+ tilemap_mark_tile_dirty(pf2_tilemap,offset);
+
+ if (pf2_alt_tilemap)
+ tilemap_mark_tile_dirty(pf2_alt_tilemap,offset);
+}
+
+WRITE16_HANDLER( fncywld_pf1_data_w )
+{
+ COMBINE_DATA(&tumblepb_pf1_data[offset]);
+ tilemap_mark_tile_dirty(pf1_tilemap,offset/2);
+ tilemap_mark_tile_dirty(pf1_alt_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( fncywld_pf2_data_w )
+{
+ COMBINE_DATA(&tumblepb_pf2_data[offset]);
+ tilemap_mark_tile_dirty(pf2_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( tumblepb_control_0_w )
+{
+ COMBINE_DATA(&tumblepb_control_0[offset]);
+}
+
+/******************************************************************************/
+
+static TILEMAP_MAPPER( tumblep_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x60) << 5);
+}
+
+INLINE void get_bg_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int gfx_bank,UINT16 *gfx_base)
+{
+ int data = gfx_base[tile_index];
+
+ SET_TILE_INFO(
+ gfx_bank,
+ (data & 0x0fff)|(bcstory_tilebank>>2),
+ data >> 12,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg1_tile_info ) { get_bg_tile_info(machine,tileinfo,tile_index,2,tumblepb_pf1_data); }
+static TILE_GET_INFO( get_bg2_tile_info ) { get_bg_tile_info(machine,tileinfo,tile_index,1,tumblepb_pf2_data); }
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int data = tumblepb_pf1_data[tile_index];
+
+ SET_TILE_INFO(
+ 0,
+ (data & 0x0fff)|bcstory_tilebank,
+ data >> 12,
+ 0);
+}
+
+INLINE void get_fncywld_bg_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int gfx_bank,UINT16 *gfx_base)
+{
+ int data = gfx_base[tile_index*2];
+ int attr = gfx_base[tile_index*2+1];
+
+ SET_TILE_INFO(
+ gfx_bank,
+ data & 0x1fff,
+ attr & 0x1f,
+ 0);
+}
+
+static TILE_GET_INFO( get_fncywld_bg1_tile_info ) { get_fncywld_bg_tile_info(machine,tileinfo,tile_index,2,tumblepb_pf1_data); }
+static TILE_GET_INFO( get_fncywld_bg2_tile_info ) { get_fncywld_bg_tile_info(machine,tileinfo,tile_index,1,tumblepb_pf2_data); }
+
+static TILE_GET_INFO( get_fncywld_fg_tile_info )
+{
+ int data = tumblepb_pf1_data[tile_index*2];
+ int attr = tumblepb_pf1_data[tile_index*2+1];
+
+ SET_TILE_INFO(
+ 0,
+ data & 0x1fff,
+ attr & 0x1f,
+ 0);
+}
+
+
+/* jump pop */
+static TILE_GET_INFO( get_jumppop_bg1_tile_info )
+{
+ int data = tumblepb_pf1_data[tile_index];
+
+ SET_TILE_INFO(
+ 2,
+ data & 0x3fff,
+ 0,
+ 0);
+}
+
+static TILE_GET_INFO( get_jumppop_bg2_tile_info )
+{
+ int data = tumblepb_pf2_data[tile_index];
+
+ SET_TILE_INFO(
+ 1,
+ data & 0x1fff,
+ 1,
+ 0);
+}
+
+static TILE_GET_INFO( get_jumppop_bg2_alt_tile_info )
+{
+ int data = tumblepb_pf2_data[tile_index];
+
+ SET_TILE_INFO(
+ 0,
+ data & 0x7fff,
+ 1,
+ 0);
+}
+
+
+static TILE_GET_INFO( get_jumppop_fg_tile_info )
+{
+ int data = tumblepb_pf1_data[tile_index];
+
+ SET_TILE_INFO(
+ 0,
+ data & 0x7fff,
+ 0,
+ 0);
+}
+
+
+WRITE16_HANDLER( pangpang_pf1_data_w )
+{
+ COMBINE_DATA(&tumblepb_pf1_data[offset]);
+ tilemap_mark_tile_dirty(pf1_tilemap,offset/2);
+ tilemap_mark_tile_dirty(pf1_alt_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( pangpang_pf2_data_w )
+{
+ COMBINE_DATA(&tumblepb_pf2_data[offset]);
+ tilemap_mark_tile_dirty(pf2_tilemap,offset/2);
+
+ if (pf2_alt_tilemap)
+ tilemap_mark_tile_dirty(pf2_alt_tilemap,offset/2);
+}
+
+
+
+INLINE void pangpang_get_bg_tile_info(running_machine *machine, tile_data *tileinfo, int tile_index,int gfx_bank,UINT16 *gfx_base)
+{
+ int data = gfx_base[tile_index*2+1];
+ int attr = gfx_base[tile_index*2];
+
+ SET_TILE_INFO(
+ gfx_bank,
+ data & 0x1fff,
+ (attr >>12) & 0xf,
+ 0);
+}
+
+INLINE void pangpang_get_bg2x_tile_info(running_machine *machine, tile_data *tileinfo, int tile_index,int gfx_bank,UINT16 *gfx_base)
+{
+ int data = gfx_base[tile_index*2+1];
+ int attr = gfx_base[tile_index*2];
+
+ SET_TILE_INFO(
+ gfx_bank,
+ (data & 0xfff)+0x1000,
+ (attr >>12) & 0xf,
+ 0);
+}
+
+
+static TILE_GET_INFO( pangpang_get_bg1_tile_info ) { pangpang_get_bg_tile_info(machine,tileinfo,tile_index,2,tumblepb_pf1_data); }
+static TILE_GET_INFO( pangpang_get_bg2_tile_info ) { pangpang_get_bg2x_tile_info(machine,tileinfo,tile_index,1,tumblepb_pf2_data); }
+
+static TILE_GET_INFO( pangpang_get_fg_tile_info )
+{
+ int data = tumblepb_pf1_data[tile_index*2+1];
+ int attr = tumblepb_pf1_data[tile_index*2];
+
+ SET_TILE_INFO(
+ 0,
+ data & 0x1fff,
+ (attr >> 12)& 0x1f,
+ 0);
+}
+
+
+VIDEO_START( pangpang )
+{
+ pf1_tilemap = tilemap_create(pangpang_get_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ pf1_alt_tilemap = tilemap_create(pangpang_get_bg1_tile_info,tumblep_scan,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf2_tilemap = tilemap_create(pangpang_get_bg2_tile_info,tumblep_scan,TILEMAP_TYPE_PEN, 16,16,64,32);
+
+ tilemap_set_transparent_pen(pf1_tilemap,0);
+ tilemap_set_transparent_pen(pf1_alt_tilemap,0);
+ bcstory_tilebank = 0;
+
+ sprite_xoffset = -1;
+ sprite_yoffset = 0;
+}
+
+
+VIDEO_START( tumblepb )
+{
+ pf1_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ pf1_alt_tilemap = tilemap_create(get_bg1_tile_info,tumblep_scan,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf2_tilemap = tilemap_create(get_bg2_tile_info,tumblep_scan,TILEMAP_TYPE_PEN, 16,16,64,32);
+
+ tilemap_set_transparent_pen(pf1_tilemap,0);
+ tilemap_set_transparent_pen(pf1_alt_tilemap,0);
+ bcstory_tilebank = 0;
+
+ sprite_xoffset = -1;
+ sprite_yoffset = 0;
+}
+
+VIDEO_START( sdfight )
+{
+ pf1_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,64); // 64*64 to prevent bad tilemap wrapping? - check real behavior
+ pf1_alt_tilemap = tilemap_create(get_bg1_tile_info,tumblep_scan,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf2_tilemap = tilemap_create(get_bg2_tile_info,tumblep_scan,TILEMAP_TYPE_PEN, 16,16,64,32);
+
+ tilemap_set_transparent_pen(pf1_tilemap,0);
+ tilemap_set_transparent_pen(pf1_alt_tilemap,0);
+ bcstory_tilebank = 0;
+
+ /* aligned to monitor test */
+ sprite_xoffset = 0;
+ sprite_yoffset = 1;
+}
+
+VIDEO_START( fncywld )
+{
+ pf1_tilemap = tilemap_create(get_fncywld_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ pf1_alt_tilemap = tilemap_create(get_fncywld_bg1_tile_info,tumblep_scan,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf2_tilemap = tilemap_create(get_fncywld_bg2_tile_info,tumblep_scan,TILEMAP_TYPE_PEN, 16,16,64,32);
+
+ tilemap_set_transparent_pen(pf1_tilemap,15);
+ tilemap_set_transparent_pen(pf1_alt_tilemap,15);
+ bcstory_tilebank = 0;
+
+ sprite_xoffset = -1;
+ sprite_yoffset = 0;
+}
+
+VIDEO_START( jumppop )
+{
+ pf1_tilemap = tilemap_create(get_jumppop_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,128,64);
+ pf1_alt_tilemap = tilemap_create(get_jumppop_bg1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ pf2_tilemap = tilemap_create(get_jumppop_bg2_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,64,64);
+ pf2_alt_tilemap = tilemap_create(get_jumppop_bg2_alt_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,128,64);
+
+ tilemap_set_transparent_pen(pf1_tilemap,0);
+ tilemap_set_transparent_pen(pf1_alt_tilemap,0);
+
+ tilemap_set_flip(pf1_tilemap, TILEMAP_FLIPX);
+ tilemap_set_flip(pf1_alt_tilemap, TILEMAP_FLIPX);
+ tilemap_set_flip(pf2_tilemap, TILEMAP_FLIPX);
+ tilemap_set_flip(pf2_alt_tilemap, TILEMAP_FLIPX);
+ bcstory_tilebank = 0;
+
+ sprite_xoffset = -1;
+ sprite_yoffset = 0;
+}
+
+
+/******************************************************************************/
+
+
+VIDEO_UPDATE( tumblepb )
+{
+ int offs,offs2;
+
+ flipscreen=tumblepb_control_0[0]&0x80;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ if (flipscreen) offs=1; else offs=-1;
+ if (flipscreen) offs2=-3; else offs2=-5;
+
+ tilemap_set_scrollx( pf1_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf1_alt_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_alt_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf2_tilemap,0, tumblepb_control_0[3]+offs );
+ tilemap_set_scrolly( pf2_tilemap,0, tumblepb_control_0[4] );
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ if (tumblepb_control_0[6]&0x80)
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1_alt_tilemap,0,0);
+ tumblepb_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( jumpkids )
+{
+ int offs,offs2;
+
+ flipscreen=tumblepb_control_0[0]&0x80;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ if (flipscreen) offs=1; else offs=-1;
+ if (flipscreen) offs2=-3; else offs2=-5;
+
+ tilemap_set_scrollx( pf1_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf1_alt_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_alt_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf2_tilemap,0, tumblepb_control_0[3]+offs );
+ tilemap_set_scrolly( pf2_tilemap,0, tumblepb_control_0[4] );
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ if (tumblepb_control_0[6]&0x80)
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1_alt_tilemap,0,0);
+ jumpkids_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( semicom )
+{
+ int offs,offs2;
+
+ flipscreen=tumblepb_control_0[0]&0x80;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ if (flipscreen) offs=1; else offs=-1; /* fixed */
+ if (flipscreen) offs2=-3; else offs2=-5; /* fixed */
+
+ tilemap_set_scrollx( pf1_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf1_alt_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_alt_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf2_tilemap,0, tumblepb_control_0[3]+offs );
+ tilemap_set_scrolly( pf2_tilemap,0, tumblepb_control_0[4] );
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ if (tumblepb_control_0[6]&0x80)
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1_alt_tilemap,0,0);
+ jumpkids_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( semicom_altoffsets )
+{
+ int offsx,offsy,offsx2;
+
+ flipscreen=tumblepb_control_0[0]&0x80;
+
+ offsx = -1;
+ offsy = 2;
+ offsx2 = -5;
+
+ tilemap_set_scrollx( pf1_tilemap,0, tumblepb_control_0[1]+offsx2 );
+ tilemap_set_scrolly( pf1_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf1_alt_tilemap,0, tumblepb_control_0[1]+offsx2 );
+ tilemap_set_scrolly( pf1_alt_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf2_tilemap,0, tumblepb_control_0[3]+offsx );
+ tilemap_set_scrolly( pf2_tilemap,0, tumblepb_control_0[4]+offsy );
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ if (tumblepb_control_0[6]&0x80)
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1_alt_tilemap,0,0);
+ jumpkids_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( bcstory )
+{
+ int offs,offs2;
+
+ flipscreen=tumblepb_control_0[0]&0x80;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ if (flipscreen) offs=1; else offs=8; /* not sure of this */
+ if (flipscreen) offs2=-3; else offs2=8; /* not sure of this */
+
+ tilemap_set_scrollx( pf1_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf1_alt_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_alt_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf2_tilemap,0, tumblepb_control_0[3]+offs );
+ tilemap_set_scrolly( pf2_tilemap,0, tumblepb_control_0[4] );
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ if (tumblepb_control_0[6]&0x80)
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1_alt_tilemap,0,0);
+ jumpkids_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( semibase )
+{
+ int offs,offs2;
+
+ flipscreen=tumblepb_control_0[0]&0x80;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ offs=-1;
+ offs2=-2;
+
+ /* sprites need an offset too */
+
+ tilemap_set_scrollx( pf1_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf1_alt_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_alt_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf2_tilemap,0, tumblepb_control_0[3]+offs );
+ tilemap_set_scrolly( pf2_tilemap,0, tumblepb_control_0[4] );
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ if (tumblepb_control_0[6]&0x80)
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1_alt_tilemap,0,0);
+ jumpkids_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_UPDATE( sdfight )
+{
+ int offs,offs2;
+
+ flipscreen=tumblepb_control_0[0]&0x80;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ offs=-1;
+ offs2=-5; // foreground scroll..
+
+ /* sprites need an offset too */
+
+ tilemap_set_scrollx( pf1_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_tilemap,0, tumblepb_control_0[2]-16 ); // needed for the ground ...
+ tilemap_set_scrollx( pf1_alt_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_alt_tilemap,0, tumblepb_control_0[2]-16 );
+ tilemap_set_scrollx( pf2_tilemap,0, tumblepb_control_0[3]+offs );
+ tilemap_set_scrolly( pf2_tilemap,0, tumblepb_control_0[4] );
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ if (tumblepb_control_0[6]&0x80)
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1_alt_tilemap,0,0);
+ jumpkids_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+
+
+VIDEO_UPDATE( fncywld )
+{
+ int offs,offs2;
+
+ flipscreen=tumblepb_control_0[0]&0x80;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ if (flipscreen) offs=1; else offs=-1;
+ if (flipscreen) offs2=-3; else offs2=-5;
+
+ tilemap_set_scrollx( pf1_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf1_alt_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_alt_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf2_tilemap,0, tumblepb_control_0[3]+offs );
+ tilemap_set_scrolly( pf2_tilemap,0, tumblepb_control_0[4] );
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ if (tumblepb_control_0[6]&0x80)
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1_alt_tilemap,0,0);
+ fncywld_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+
+VIDEO_UPDATE( jumppop )
+{
+// fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ tilemap_set_scrollx( pf1_tilemap,0, jumppop_control[2]-0x3a0 );
+ tilemap_set_scrolly( pf1_tilemap,0, jumppop_control[3] );
+ tilemap_set_scrollx( pf1_alt_tilemap,0, jumppop_control[2]-0x3a0 );
+ tilemap_set_scrolly( pf1_alt_tilemap,0, jumppop_control[3] );
+ tilemap_set_scrollx( pf2_tilemap,0, jumppop_control[0]-0x3a2 );
+ tilemap_set_scrolly( pf2_tilemap,0, jumppop_control[1] );
+ tilemap_set_scrollx( pf2_alt_tilemap,0, jumppop_control[0]-0x3a2 );
+ tilemap_set_scrolly( pf2_alt_tilemap,0, jumppop_control[1] );
+
+ if (jumppop_control[7]&1)
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf2_alt_tilemap,0,0);
+
+ if (jumppop_control[7]&2)
+ tilemap_draw(bitmap,cliprect,pf1_alt_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+
+//popmessage("%04x %04x %04x %04x %04x %04x %04x %04x", jumppop_control[0],jumppop_control[1],jumppop_control[2],jumppop_control[3],jumppop_control[4],jumppop_control[5],jumppop_control[6],jumppop_control[7]);
+
+ jumpkids_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+
+VIDEO_UPDATE( suprtrio )
+{
+ tilemap_set_scrollx( pf1_alt_tilemap,0, -suprtrio_control[1]-6 );
+ tilemap_set_scrolly( pf1_alt_tilemap,0, -suprtrio_control[2] );
+ tilemap_set_scrollx( pf2_tilemap,0, -suprtrio_control[3]-2 );
+ tilemap_set_scrolly( pf2_tilemap,0, -suprtrio_control[4] );
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,pf1_alt_tilemap,0,0);
+
+ jumpkids_draw_sprites(machine,bitmap,cliprect);
+#if 0
+popmessage("%04x %04x %04x %04x %04x %04x %04x %04x",
+ suprtrio_control[0],
+ suprtrio_control[1],
+ suprtrio_control[2],
+ suprtrio_control[3],
+ suprtrio_control[4],
+ suprtrio_control[5],
+ suprtrio_control[6],
+ suprtrio_control[7]);
+#endif
+
+ return 0;
+}
+
+VIDEO_UPDATE( pangpang )
+{
+ int offs,offs2;
+
+ flipscreen=tumblepb_control_0[0]&0x80;
+ tilemap_set_flip(ALL_TILEMAPS,flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
+ if (flipscreen) offs=1; else offs=-1;
+ if (flipscreen) offs2=-3; else offs2=-5;
+
+ tilemap_set_scrollx( pf1_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf1_alt_tilemap,0, tumblepb_control_0[1]+offs2 );
+ tilemap_set_scrolly( pf1_alt_tilemap,0, tumblepb_control_0[2] );
+ tilemap_set_scrollx( pf2_tilemap,0, tumblepb_control_0[3]+offs );
+ tilemap_set_scrolly( pf2_tilemap,0, tumblepb_control_0[4] );
+
+ tilemap_draw(bitmap,cliprect,pf2_tilemap,0,0);
+ if (tumblepb_control_0[6]&0x80)
+ tilemap_draw(bitmap,cliprect,pf1_tilemap,0,0);
+ else
+ tilemap_draw(bitmap,cliprect,pf1_alt_tilemap,0,0);
+ jumpkids_draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+VIDEO_START( suprtrio )
+{
+ pf1_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ pf1_alt_tilemap = tilemap_create(get_bg1_tile_info,tumblep_scan,TILEMAP_TYPE_PEN,16,16,64,32);
+ pf2_tilemap = tilemap_create(get_bg2_tile_info,tumblep_scan,TILEMAP_TYPE_PEN, 16,16,64,32);
+
+ tilemap_set_transparent_pen(pf1_alt_tilemap,0);
+ bcstory_tilebank = 0;
+}
+
+
diff --git a/src/mame/video/tumblep.c b/src/mame/video/tumblep.c
new file mode 100644
index 00000000000..a037698b944
--- /dev/null
+++ b/src/mame/video/tumblep.c
@@ -0,0 +1,100 @@
+/***************************************************************************
+
+ Tumblepop Video emulation - Bryan McPhail, mish@tendril.co.uk
+
+*********************************************************************
+
+Uses Data East custom chip 55 for backgrounds, custom chip 52 for sprites.
+
+See Dark Seal & Caveman Ninja drivers for info on these chips.
+
+Tumblepop is one of few games to take advantage of the playfields ability
+to switch between 8*8 tiles and 16*16 tiles.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "deco16ic.h"
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ sprite = spriteram16[offs+1];
+ if (!sprite) continue;
+
+ y = spriteram16[offs];
+ flash=y&0x1000;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ x = spriteram16[offs+2];
+ colour = (x >>9) & 0x1f;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x0600) >> 9)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 320) x -= 512;
+ if (y >= 256) y -= 512;
+ y = 240 - y;
+ x = 304 - x;
+
+ if (x>320) continue;
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen)
+ {
+ y=240-y;
+ x=304-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ multi--;
+ }
+ }
+}
+
+VIDEO_START(tumblep)
+{
+ deco16_1_video_init();
+}
+
+VIDEO_UPDATE(tumblep)
+{
+ flip_screen_set( deco16_pf12_control[0]&0x80 );
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+
+ fillbitmap(bitmap,machine->pens[256],cliprect); /* not verified */
+
+ deco16_tilemap_2_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/tunhunt.c b/src/mame/video/tunhunt.c
new file mode 100644
index 00000000000..934451be5d1
--- /dev/null
+++ b/src/mame/video/tunhunt.c
@@ -0,0 +1,412 @@
+/*************************************************************************
+
+ Atari Tunnel Hunt hardware
+
+*************************************************************************/
+
+#include "driver.h"
+
+extern UINT8 tunhunt_control;
+extern UINT8 *tunhunt_ram;
+
+/****************************************************************************************/
+
+/* Video Hardware Addresses */
+
+/* Square Generator (13 bytes each) */
+#define LINEV 0x1403 // LINES VERTICAL START
+#define LINEVS 0x1483 // LINES VERT STOP
+#define LINEH 0x1083 // LINES HORIZ START
+#define LINEC 0x1283 // LINE COLOR, 4 BITS D0-D3
+#define LINESH 0x1203 // LINES SLOPE 4 BITS D0-D3 (signed)
+/* LINESH was used for rotation effects in an older version of the game */
+
+/* Shell Object0 */
+#define SHEL0H 0x1800 // SHELL H POSITON (NORMAL SCREEN)
+#define SHL0V 0x1400 // SHELL V START(NORMAL SCREEN)
+#define SHL0VS 0x1480 // SHELL V STOP (NORMAL SCREEN)
+#define SHL0ST 0x1200 // SHELL VSTRETCH (LIKE MST OBJ STRECTH)
+#define SHL0PC 0x1280 // SHELL PICTURE CODE (D3-D0)
+
+/* Shell Object1 (see above) */
+#define SHEL1H 0x1A00
+#define SHL1V 0x1401
+#define SHL1VS 0x1481
+#define SHL1ST 0x1201
+#define SHL1PC 0x1281
+
+/* Motion Object RAM */
+#define MOBJV 0x1C00 // V POSITION (SCREEN ON SIDE)
+#define MOBVS 0x1482 // V STOP OF MOTION OBJECT (NORMAL SCREEN)
+#define MOBJH 0x1402 // H POSITON (SCREEN ON SIDE) (VSTART - NORMAL SCREEN)
+#define MOBST 0x1082 // STARTING LINE FOR RAM SCAN ON MOBJ
+#define VSTRLO 0x1202 // VERT (SCREEN ON SIDE) STRETCH MOJ OBJ
+#define MOTT 0x2C00 // MOTION OBJECT RAM (00-0F NOT USED, BYT CLEARED)
+#define MOBSC0 0x1080 // SCAN ROM START FOR MOBJ (unused?)
+#define MOBSC1 0x1081 // (unused?)
+
+static tilemap *fg_tilemap;
+
+/****************************************************************************************/
+
+WRITE8_HANDLER( tunhunt_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( tunhunt_mott_w )
+{
+ if( spriteram[offset]!=data )
+ {
+ spriteram[offset] = data;
+ dirtybuffer[offset>>4] = 1;
+ }
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = videoram[tile_index];
+ int code = attr & 0x3f;
+ int color = attr >> 6;
+ int flags = color ? TILE_FORCE_LAYER0 : 0;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+VIDEO_START( tunhunt )
+{
+ /*
+ Motion Object RAM contains 64 lines of run-length encoded data.
+ We keep track of dirty lines and cache the expanded bitmap.
+ With max RLE expansion, bitmap size is 256x64.
+ */
+ dirtybuffer = auto_malloc(64);
+
+ memset( dirtybuffer, 1, 64 );
+ tmpbitmap = auto_bitmap_alloc( 256, 64, machine->screen[0].format );
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+ tilemap_set_scrollx(fg_tilemap, 0, 64);
+}
+
+PALETTE_INIT( tunhunt )
+{
+ /* Tunnel Hunt uses a combination of color proms and palette RAM to specify a 16 color
+ * palette. Here, we manage only the mappings for alphanumeric characters and SHELL
+ * graphics, which are unpacked ahead of time and drawn using MAME's drawgfx primitives.
+ */
+
+ /* AlphaNumerics (1bpp)
+ * 2 bits of hilite select from 4 different background colors
+ * Foreground color is always pen#4
+ * Background color is mapped as follows:
+ */
+
+ /* alpha hilite#0 */
+ colortable[0] = 0x0; /* background color#0 (transparent) */
+ colortable[1] = 0x4; /* foreground color */
+
+ /* alpha hilite#1 */
+ colortable[2] = 0x5; /* background color#1 */
+ colortable[3] = 0x4; /* foreground color */
+
+ /* alpha hilite#2 */
+ colortable[4] = 0x6; /* background color#2 */
+ colortable[5] = 0x4; /* foreground color */
+
+ /* alpha hilite#3 */
+ colortable[6] = 0xf; /* background color#3 */
+ colortable[7] = 0x4; /* foreground color */
+
+ /* shell graphics; these are either 1bpp (2 banks) or 2bpp. It isn't clear which.
+ * In any event, the following pens are associated with the shell graphics:
+ */
+ colortable[0x8] = 0;
+ colortable[0x9] = 4;//1;
+ colortable[0xa] = 2;
+ colortable[0xb] = 4;
+}
+
+/*
+Color Array Ram Assignments:
+ Location
+ 0 Blanking, border
+ 1 Mot Obj (10) (D), Shell (01)
+ 2 Mot Obj (01) (G), Shell (10)
+ 3 Mot Obj (00) (W)
+ 4 Alpha & Shell (11) - shields
+ 5 Hilight 1
+ 6 Hilight 2
+ 8-E Lines (as normal) background
+ F Hilight 3
+*/
+static void update_palette(running_machine *machine)
+{
+// const UINT8 *color_prom = memory_region( REGION_PROMS );
+/*
+ The actual contents of the color proms (unused by this driver)
+ are as follows:
+
+ D11 "blue/green"
+ 0000: 00 00 8b 0b fb 0f ff 0b
+ 00 00 0f 0f fb f0 f0 ff
+
+ C11 "red"
+ 0020: 00 f0 f0 f0 b0 b0 00 f0
+ 00 f0 f0 00 b0 00 f0 f0
+*/
+ int color;
+ int shade;
+ int i;
+ int red,green,blue;
+
+ for( i=0; i<16; i++ )
+ {
+ color = paletteram[i];
+ shade = 0xf^(color>>4);
+
+ color &= 0xf; /* hue select */
+ switch( color )
+ {
+ default:
+ case 0x0: red = 0xff; green = 0xff; blue = 0xff; break; /* white */
+ case 0x1: red = 0xff; green = 0x00; blue = 0xff; break; /* purple */
+ case 0x2: red = 0x00; green = 0x00; blue = 0xff; break; /* blue */
+ case 0x3: red = 0x00; green = 0xff; blue = 0xff; break; /* cyan */
+ case 0x4: red = 0x00; green = 0xff; blue = 0x00; break; /* green */
+ case 0x5: red = 0xff; green = 0xff; blue = 0x00; break; /* yellow */
+ case 0x6: red = 0xff; green = 0x00; blue = 0x00; break; /* red */
+ case 0x7: red = 0x00; green = 0x00; blue = 0x00; break; /* black? */
+
+ case 0x8: red = 0xff; green = 0x7f; blue = 0x00; break; /* orange */
+ case 0x9: red = 0x7f; green = 0xff; blue = 0x00; break; /* ? */
+ case 0xa: red = 0x00; green = 0xff; blue = 0x7f; break; /* ? */
+ case 0xb: red = 0x00; green = 0x7f; blue = 0xff; break; /* ? */
+ case 0xc: red = 0xff; green = 0x00; blue = 0x7f; break; /* ? */
+ case 0xd: red = 0x7f; green = 0x00; blue = 0xff; break; /* ? */
+ case 0xe: red = 0xff; green = 0xaa; blue = 0xaa; break; /* ? */
+ case 0xf: red = 0xaa; green = 0xaa; blue = 0xff; break; /* ? */
+ }
+
+ /* combine color components with shade value (0..0xf) */
+ #define APPLY_SHADE( C,S ) ((C*S)/0xf)
+ red = APPLY_SHADE(red,shade);
+ green = APPLY_SHADE(green,shade);
+ blue = APPLY_SHADE(blue,shade);
+
+ palette_set_color( machine,i,MAKE_RGB(red,green,blue) );
+ }
+}
+
+static void draw_motion_object(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+/*
+ * VSTRLO 0x1202
+ * normally 0x02 (gameplay, attract1)
+ * in attract2 (with "Tunnel Hunt" graphic), decrements from 0x2f down to 0x01
+ * goes to 0x01 for some enemy shots
+ *
+ * MOBSC0 0x1080
+ * MOBSC1 0x1081
+ * always 0x00?
+ */
+// int skip = tunhunt_ram[MOBST];
+ int x0 = 255-tunhunt_ram[MOBJV];
+ int y0 = 255-tunhunt_ram[MOBJH];
+ int scalex,scaley;
+ int line,span;
+ int x,span_data;
+ int color;
+ int count;
+ const UINT8 *source;
+
+ for( line=0; line<64; line++ )
+ {
+ if( dirtybuffer[line] )
+ {
+ dirtybuffer[line] = 0;
+ x = 0;
+ source = &spriteram[line*0x10];
+ for( span=0; span<0x10; span++ )
+ {
+ span_data = source[span];
+ if( span_data == 0xff ) break;
+ color = ((span_data>>6)&0x3)^0x3;
+ count = (span_data&0x1f)+1;
+ while( count-- && x < 256 )
+ {
+ *BITMAP_ADDR16(tmpbitmap, line, x++) = machine->pens[color];
+ }
+ }
+ while( x<256 )
+ {
+ *BITMAP_ADDR16(tmpbitmap, line, x++) = machine->pens[0];
+ }
+ } /* dirty line */
+ } /* next line */
+
+ switch( tunhunt_ram[VSTRLO] )
+ {
+ case 0x01:
+ scaley = (1<<16)*0.33; /* seems correct */
+ break;
+
+ case 0x02:
+ scaley = (1<<16)*0.50; /* seems correct */
+ break;
+
+ default:
+ scaley = (1<<16)*tunhunt_ram[VSTRLO]/4; /* ??? */
+ break;
+ }
+ scalex = (1<<16);
+
+ copyrozbitmap(
+ bitmap,tmpbitmap,
+ -x0*scalex,/* startx */
+ -y0*scaley,/* starty */
+ scalex,/* incxx */
+ 0,0,/* incxy,incyx */
+ scaley,/* incyy */
+ 0, /* no wraparound */
+ cliprect,
+ TRANSPARENCY_PEN,machine->pens[0],
+ 0 /* priority */
+ );
+}
+
+static void draw_box(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+/*
+ This is unnecessarily slow, but the box priorities aren't completely understood,
+ yet. Once understood, this function should be converted to use fillbitmap with
+ rectangular chunks instead of BITMAP_ADDR.
+
+ Tunnels:
+ 1080: 00 00 00 01 e7 18 ae 51 94 6b 88 77 83 7c 80 7f x0
+ 1480: 00 f0 17 00 22 22 5b 5b 75 75 81 81 86 86 89 89 y0
+ 1400: 00 00 97 ff f1 f1 b8 b8 9e 9e 92 92 8d 8d 8a 8a y1
+ 1280: 07 03 00 07 07 0c 0c 0d 0d 0e 0e 08 08 09 09 0a palette select
+
+ Color Bars:
+ 1080: 00 00 00 01 00 20 40 60 80 a0 c0 e0 01 2a 50 7a x0
+ 1480: 00 f0 00 00 40 40 40 40 40 40 40 40 00 00 00 00 y0
+ 1400: 00 00 00 ff ff ff ff ff ff ff ff ff 40 40 40 40 y1
+ 1280: 07 03 00 01 07 06 04 05 02 07 03 00 09 0a 0b 0c palette select
+ ->hue 06 02 ff 60 06 05 03 04 01 06 02 ff d2 00 c2 ff
+*/
+ int span,x,y;
+ int color;
+// rectangle bbox;
+ int z;
+ int x0,y0,y1;
+
+ for( y=0; y<256; y++ )
+ {
+ if (0xff-y >= cliprect->min_y && 0xff-y <= cliprect->max_y)
+ for( x=0; x<256; x++ )
+ {
+ color = 0;
+ z = 0;
+ for( span=3; span<16; span++ )
+ {
+ x0 = tunhunt_ram[span+0x1080];
+ y0 = tunhunt_ram[span+0x1480];
+ y1 = tunhunt_ram[span+0x1400];
+
+ if( y>=y0 && y<=y1 && x>=x0 && x0>=z )
+ {
+ color = tunhunt_ram[span+0x1280]&0xf;
+ z = x0; /* give priority to rightmost spans */
+ }
+ }
+ if (x >= cliprect->min_x && x <= cliprect->max_x)
+ *BITMAP_ADDR16(bitmap, 0xff-y, x) = machine->pens[color];
+ }
+ }
+}
+
+/* "shell" graphics are 16x16 pixel tiles used for player shots and targeting cursor */
+static void draw_shell(running_machine *machine,
+ mame_bitmap *bitmap,
+ const rectangle *cliprect,
+ int picture_code,
+ int hposition,
+ int vstart,
+ int vstop,
+ int vstretch,
+ int hstretch )
+{
+ if( hstretch )
+ {
+ int sx,sy;
+ for( sx=0; sx<256; sx+=16 )
+ {
+ for( sy=0; sy<256; sy+=16 )
+ {
+ drawgfx( bitmap, machine->gfx[1],
+ picture_code,
+ 0, /* color */
+ 0,0, /* flip */
+ sx,sy,
+ cliprect,
+ TRANSPARENCY_PEN,0 );
+ }
+ }
+ }
+ else
+ /*
+ vstretch is normally 0x01
+
+ targeting cursor:
+ hposition = 0x78
+ vstart = 0x90
+ vstop = 0x80
+
+ during grid test:
+ vstretch = 0xff
+ hposition = 0xff
+ vstart = 0xff
+ vstop = 0x00
+
+ */
+ drawgfx( bitmap, machine->gfx[1],
+ picture_code,
+ 0, /* color */
+ 0,0, /* flip */
+ 255-hposition-16,vstart-32,
+ cliprect,
+ TRANSPARENCY_PEN,0 );
+}
+
+VIDEO_UPDATE( tunhunt )
+{
+ update_palette(machine);
+
+ draw_box(machine, bitmap, cliprect);
+
+ draw_motion_object(machine, bitmap, cliprect);
+
+ draw_shell(machine, bitmap, cliprect,
+ tunhunt_ram[SHL0PC], /* picture code */
+ tunhunt_ram[SHEL0H], /* hposition */
+ tunhunt_ram[SHL0V], /* vstart */
+ tunhunt_ram[SHL0VS], /* vstop */
+ tunhunt_ram[SHL0ST], /* vstretch */
+ tunhunt_control&0x08 ); /* hstretch */
+
+ draw_shell(machine, bitmap, cliprect,
+ tunhunt_ram[SHL1PC], /* picture code */
+ tunhunt_ram[SHEL1H], /* hposition */
+ tunhunt_ram[SHL1V], /* vstart */
+ tunhunt_ram[SHL1VS], /* vstop */
+ tunhunt_ram[SHL1ST], /* vstretch */
+ tunhunt_control&0x10 ); /* hstretch */
+
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/turbo.c b/src/mame/video/turbo.c
new file mode 100644
index 00000000000..e4b9258af8e
--- /dev/null
+++ b/src/mame/video/turbo.c
@@ -0,0 +1,1094 @@
+/*************************************************************************
+
+ Sega Z80-3D system
+
+*************************************************************************/
+
+#include "driver.h"
+#include "turbo.h"
+#include "video/resnet.h"
+#include <math.h>
+
+
+
+typedef struct _sprite_info sprite_info;
+struct _sprite_info
+{
+ UINT16 ve; /* VE0-15 signals for this row */
+ UINT8 lst; /* LST0-7 signals for this row */
+ UINT32 latched[8]; /* latched pixel data */
+ UINT8 plb[8]; /* latched PLB state */
+ UINT32 offset[8]; /* current offset for this row */
+ UINT32 frac[8]; /* leftover fraction */
+ UINT32 step[8]; /* stepping value */
+};
+
+static const UINT32 sprite_expand[16] =
+{
+ 0x00000000, 0x00000001, 0x00000100, 0x00000101,
+ 0x00010000, 0x00010001, 0x00010100, 0x00010101,
+ 0x01000000, 0x01000001, 0x01000100, 0x01000101,
+ 0x01010000, 0x01010001, 0x01010100, 0x01010101
+};
+
+
+
+
+/*************************************
+ *
+ * Palette conversion
+ *
+ *************************************/
+
+PALETTE_INIT( turbo )
+{
+ static const int resistances[3] = { 1000, 470, 220 };
+ double rweights[3], gweights[3], bweights[2];
+ int i;
+
+ /* compute the color output resistor weights */
+ compute_resistor_weights(0, 255, -1.0,
+ 3, &resistances[0], rweights, 470, 0,
+ 3, &resistances[0], gweights, 470, 0,
+ 2, &resistances[1], bweights, 470, 0);
+
+ /* initialize the palette with these colors */
+ for (i = 0; i < 256; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ /* red component */
+ bit0 = (i >> 0) & 1;
+ bit1 = (i >> 1) & 1;
+ bit2 = (i >> 2) & 1;
+ r = combine_3_weights(rweights, bit0, bit1, bit2);
+
+ /* green component */
+ bit0 = (i >> 3) & 1;
+ bit1 = (i >> 4) & 1;
+ bit2 = (i >> 5) & 1;
+ g = combine_3_weights(gweights, bit0, bit1, bit2);
+
+ /* blue component */
+ bit0 = (i >> 6) & 1;
+ bit1 = (i >> 7) & 1;
+ b = combine_2_weights(bweights, bit0, bit1);
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ }
+}
+
+
+PALETTE_INIT( subroc3d )
+{
+ static const int resistances[3] = { 1000, 470, 220 };
+ double rweights[3], gweights[3], bweights[2];
+ int i;
+
+ /* compute the color output resistor weights */
+ compute_resistor_weights(0, 255, -1.0,
+ 3, &resistances[0], rweights, 470, 0,
+ 3, &resistances[0], gweights, 470, 0,
+ 2, &resistances[1], bweights, 470, 0);
+
+ /* initialize the palette with these colors */
+ for (i = 0; i < 256; i++)
+ {
+ int bit0, bit1, bit2, r, g, b;
+
+ /* red component */
+ bit0 = (i >> 0) & 1;
+ bit1 = (i >> 1) & 1;
+ bit2 = (i >> 2) & 1;
+ r = combine_3_weights(rweights, bit0, bit1, bit2);
+
+ /* green component */
+ bit0 = (i >> 3) & 1;
+ bit1 = (i >> 4) & 1;
+ bit2 = (i >> 5) & 1;
+ g = combine_3_weights(gweights, bit0, bit1, bit2);
+
+ /* blue component */
+ bit0 = (i >> 6) & 1;
+ bit1 = (i >> 7) & 1;
+ b = combine_2_weights(bweights, bit0, bit1);
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ }
+}
+
+
+PALETTE_INIT( buckrog )
+{
+ static const int resistances[4] = { 2200, 1000, 500, 250 };
+ double rweights[3], gweights[3], bweights[4];
+ int i;
+
+ /* compute the color output resistor weights */
+ compute_resistor_weights(0, 255, -1.0,
+ 3, &resistances[1], rweights, 1000, 0,
+ 3, &resistances[1], gweights, 1000, 0,
+ 4, &resistances[0], bweights, 1000, 0);
+
+ /* initialize the palette with these colors */
+ for (i = 0; i < 1024; i++)
+ {
+ int bit0, bit1, bit2, bit3, r, g, b;
+
+ /* red component */
+ bit0 = (i >> 0) & 1;
+ bit1 = (i >> 1) & 1;
+ bit2 = (i >> 2) & 1;
+ r = combine_3_weights(rweights, bit0, bit1, bit2);
+
+ /* green component */
+ bit0 = (i >> 3) & 1;
+ bit1 = (i >> 4) & 1;
+ bit2 = (i >> 5) & 1;
+ g = combine_3_weights(gweights, bit0, bit1, bit2);
+
+ /* blue component - note the shuffled bits */
+ bit0 = (i >> 8) & 1;
+ bit1 = (i >> 9) & 1;
+ bit2 = (i >> 6) & 1;
+ bit3 = (i >> 7) & 1;
+ b = combine_4_weights(bweights, bit0, bit1, bit2, bit3);
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ turbo_state *state = machine->driver_data;
+ int code = state->videoram[tile_index];
+ SET_TILE_INFO(0, code, code >> 2, 0);
+}
+
+
+VIDEO_START( turbo )
+{
+ turbo_state *state = machine->driver_data;
+
+ /* initialize the foreground tilemap */
+ state->fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+}
+
+
+VIDEO_START( buckrog )
+{
+ turbo_state *state = machine->driver_data;
+
+ /* initialize the foreground tilemap */
+ state->fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+
+ /* allocate the bitmap RAM */
+ state->buckrog_bitmap_ram = auto_malloc(0xe000);
+ state_save_register_global_pointer(state->buckrog_bitmap_ram, 0xe000);
+}
+
+
+
+/*************************************
+ *
+ * Videoram access
+ *
+ *************************************/
+
+WRITE8_HANDLER( turbo_videoram_w )
+{
+ turbo_state *state = Machine->driver_data;
+ state->videoram[offset] = data;
+ if (offset < 0x400)
+ {
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ tilemap_mark_tile_dirty(state->fg_tilemap, offset);
+ }
+}
+
+
+WRITE8_HANDLER( buckrog_bitmap_w )
+{
+ turbo_state *state = Machine->driver_data;
+ state->buckrog_bitmap_ram[offset] = data & 1;
+}
+
+
+
+/*************************************
+ *
+ * Sprite X scaling
+ *
+ *************************************/
+
+INLINE UINT32 sprite_xscale(UINT8 dacinput, double vr1, double vr2, double cext)
+{
+ /* compute the effective pixel clock for this sprite */
+ /* thanks to Frank Palazzolo for figuring out this logic */
+
+ /* compute the control voltage to the VCO */
+ /* VR1 and VR2 are variable resistors on Turbo, fixed on other boards */
+ double iref = 5.0 / (1.5e3 + vr2);
+ double iout = iref * ((float)dacinput / 256.0);
+ double vref = 5.0 * 1e3 / (3.8e3 + 1e3 + vr1);
+ double vco_cv = (2.2e3 * iout) + vref;
+
+ /* based on the control voltage, compute the frequency assuming a 50pF */
+ /* external capacitor; this is the graph in the datasheet. Some attempt */
+ /* to simulate the non-linearity at the edges has been made, but it is */
+ /* admittedly cheesy. */
+ double vco_freq;
+ if (vco_cv > 5.0)
+ vco_cv = 5.0;
+ if (vco_cv < 0.0)
+ vco_cv = 0.0;
+ if (vco_cv < 1.33)
+ vco_freq = (0.68129 + pow(vco_cv + 0.6, 1.285)) * 1e6;
+ else if (vco_cv < 4.3)
+ vco_freq = (3 + (8 - 3) * ((vco_cv - 1.33) / (4.3 - 1.33))) * 1e6;
+ else
+ vco_freq = (-1.560279 + pow(vco_cv - 4.3 + 6, 1.26)) * 1e6;
+
+ /* now scale based on the actual external capacitor; the frequency goes */
+ /* up by a factor of 10 for every factor of 10 the capacitance is reduced */
+ /* approximately */
+ vco_freq *= 50e-12 / cext;
+
+ /* finally, convert to a fraction (8.24) of 5MHz, which is the pixel clock */
+ return (UINT32)((vco_freq / (5e6 * TURBO_X_SCALE)) * 16777216.0);
+}
+
+
+
+/*************************************
+ *
+ * Turbo sprite handling
+ *
+ *************************************/
+
+static void turbo_prepare_sprites(turbo_state *state, UINT8 y, sprite_info *info)
+{
+ const UINT8 *pr1119 = memory_region(REGION_PROMS) + 0x200;
+ int sprnum;
+
+ /* initialize the line enable signals to 0 */
+ info->ve = 0;
+ info->lst = 0;
+
+ /* compute the sprite information, which was done on the previous scanline during HBLANK */
+ for (sprnum = 0; sprnum < 16; sprnum++)
+ {
+ UINT8 *rambase = &state->spriteram[sprnum * 0x10];
+ int level = sprnum & 7;
+ UINT8 clo, chi;
+ UINT32 sum;
+
+ /* perform the first ALU to see if we are within the scanline */
+ sum = y + (rambase[0] ^ 0xff);
+ clo = (sum >> 8) & 1;
+ sum += (y << 8) + ((rambase[1] ^ 0xff) << 8);
+ chi = (sum >> 16) & 1;
+
+ /* the AND of the low carry and the inverse of the high carry clocks an enable bit */
+ /* for this sprite; note that the logic in the Turbo schematics is reversed here */
+ if (clo & (chi ^ 1))
+ {
+ int xscale = rambase[2] ^ 0xff;
+ int yscale = rambase[3];// ^ 0xff;
+ UINT16 offset = rambase[6] + (rambase[7] << 8);
+ int offs;
+
+ /* mark this entry enabled */
+ info->ve |= 1 << sprnum;
+
+ /* look up the low byte of the sum plus the yscale value in */
+ /* IC50/PR1119 to determine if we write back the sum of the */
+ /* offset and the rowbytes this scanline (p. 138) */
+ offs = (sum & 0xff) | /* A0-A7 = AL0-AL7 */
+ ((yscale & 0x08) << 5); /* A8-A9 = /RO11-/RO12 */
+
+ /* one of the bits is selected based on the low 7 bits of yscale */
+ if (!((pr1119[offs] >> (yscale & 0x07)) & 1))
+ {
+ offset += rambase[4] + (rambase[5] << 8);
+ rambase[6] = offset;
+ rambase[7] = offset >> 8;
+ }
+
+ /* the output of the ALU here goes to the individual level counter */
+ info->latched[level] = 0;
+ info->plb[level] = 0;
+ info->offset[level] = offset;
+ info->frac[level] = 0;
+
+ /*
+ actual pots read from one board:
+ VR1 = 310 Ohm
+ VR2 = 910 Ohm
+ */
+ info->step[level] = sprite_xscale(xscale, 1.0e3 * readinputportbytag("VR1") / 100.0, 1.0e3 * readinputportbytag("VR2") / 100.0, 100e-12);
+ }
+ }
+}
+
+
+static UINT32 turbo_get_sprite_bits(UINT8 road, sprite_info *sprinfo)
+{
+ const UINT8 *sprite_gfxdata = memory_region(REGION_GFX1);
+ UINT8 sprlive = sprinfo->lst;
+ UINT32 sprdata = 0;
+ int level;
+
+ /* if we haven't left the road yet, sprites 3-7 are disabled */
+ if (!road)
+ sprlive &= 0x07;
+
+ /* loop over all live levels */
+ for (level = 0; level < 8; level++)
+ if (sprlive & (1 << level))
+ {
+ /* latch the data and advance the offset */
+ sprdata |= sprinfo->latched[level];
+ sprinfo->frac[level] += sprinfo->step[level];
+
+ /* if we're live and we've clocked more data, advance */
+ while (sprinfo->frac[level] >= 0x1000000)
+ {
+ UINT16 offs = sprinfo->offset[level];
+ UINT8 pixdata;
+
+ /* bit 0 controls which half of the byte to use */
+ /* bits 1-13 go to address lines */
+ /* bit 14 selects which of the two ROMs to read from */
+ pixdata = sprite_gfxdata[(level << 14) | ((offs >> 1) & 0x3fff)] >> ((~offs & 1) * 4);
+ sprinfo->latched[level] = sprite_expand[pixdata & 0x0f] << level;
+
+ /* if bit 3 is 0 and bit 2 is 1, the enable flip/flip is reset */
+ if ((pixdata & 0x0c) == 0x04)
+ {
+ sprinfo->lst &= ~(1 << level);
+ sprlive &= ~(1 << level);
+ }
+
+ /* if bit 15 is set, we decrement instead of increment */
+ sprinfo->offset[level] += (offs & 0x8000) ? -1 : 1;
+ sprinfo->frac[level] -= 0x1000000;
+ }
+ }
+
+ return sprdata;
+}
+
+
+
+/*************************************
+ *
+ * Turbo video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( turbo )
+{
+ turbo_state *state = machine->driver_data;
+ mame_bitmap *fgpixmap = tilemap_get_pixmap(state->fg_tilemap);
+ const UINT8 *road_gfxdata = memory_region(REGION_GFX3);
+ const UINT8 *prom_base = memory_region(REGION_PROMS);
+ const UINT8 *pr1114 = prom_base + 0x000;
+ const UINT8 *pr1115 = prom_base + 0x020;
+ const UINT8 *pr1116 = prom_base + 0x040;
+ const UINT8 *pr1117 = prom_base + 0x060;
+ const UINT8 *pr1118 = prom_base + 0x100;
+ const UINT8 *pr1121 = prom_base + 0x600;
+ const UINT8 *pr1122 = prom_base + 0x800;
+ const UINT8 *pr1123 = prom_base + 0xc00;
+ int x, y;
+
+ /* loop over rows */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ const UINT16 *fore = (UINT16 *)fgpixmap->base + y * fgpixmap->rowpixels;
+ UINT16 *dest = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+ int sel, coch, babit, slipar_acciar, area, offs, areatmp, road = 0;
+ sprite_info sprinfo;
+
+ /* compute the Y sum between opa and the current scanline (p. 141) */
+ int va = (y + state->turbo_opa) & 0xff;
+
+ /* the upper bit of OPC inverts the road (p. 141) */
+ if (!(state->turbo_opc & 0x80))
+ va ^= 0xff;
+
+ /* compute the sprite information; we use y-1 since this info was computed during HBLANK */
+ /* on the previous scanline */
+ turbo_prepare_sprites(state, y, &sprinfo);
+
+ /* loop over columns */
+ for (x = 0; x <= cliprect->max_x; x += TURBO_X_SCALE)
+ {
+ int bacol, red, grn, blu, priority, foreraw, forebits, mx, ix;
+ int xx = x / TURBO_X_SCALE;
+ UINT8 carry;
+ UINT32 sprbits;
+ UINT16 he;
+
+ /* load the bitmask from the sprite position for both halves of the sprites (p. 139) */
+ he = state->sprite_position[xx] | (state->sprite_position[xx + 0x100] << 8);
+
+ /* the AND of the line enable and horizontal enable is clocked and held in LST0-7 (p. 143) */
+ he &= sprinfo.ve;
+ sprinfo.lst |= he | (he >> 8);
+
+ /* compute the X sum between opb and the current column; only the carry matters (p. 141) */
+ carry = (xx + state->turbo_opb) >> 8;
+
+ /* the carry selects which inputs to use (p. 141) */
+ if (carry)
+ {
+ sel = state->turbo_ipb;
+ coch = state->turbo_ipc >> 4;
+ }
+ else
+ {
+ sel = state->turbo_ipa;
+ coch = state->turbo_ipc & 15;
+ }
+
+ /* look up AREA1 and AREA2 (p. 142) */
+ offs = va | /* A0- A7 = VA0-VA7 */
+ ((sel & 0x0f) << 8); /* A8-A11 = SEL0-3 */
+
+ areatmp = road_gfxdata[0x0000 | offs];
+ areatmp = ((areatmp + xx) >> 8) & 0x01;
+ area = areatmp << 0;
+
+ areatmp = road_gfxdata[0x1000 | offs];
+ areatmp = ((areatmp + xx) >> 8) & 0x01;
+ area |= areatmp << 1;
+
+ /* look up AREA3 and AREA4 (p. 142) */
+ offs = va | /* A0- A7 = VA0-VA7 */
+ ((sel & 0xf0) << 4); /* A8-A11 = SEL4-7 */
+
+ areatmp = road_gfxdata[0x2000 | offs];
+ areatmp = ((areatmp + xx) >> 8) & 0x01;
+ area |= areatmp << 2;
+
+ areatmp = road_gfxdata[0x3000 | offs];
+ areatmp = ((areatmp + xx) >> 8) & 0x01;
+ area |= areatmp << 3;
+
+ /* look up AREA5 (p. 141) */
+ offs = (xx >> 3) | /* A0- A4 = H3-H7 */
+ ((state->turbo_opc & 0x3f) << 5); /* A5-A10 = OPC0-5 */
+
+ areatmp = road_gfxdata[0x4000 | offs];
+ areatmp = (areatmp << (xx & 7)) & 0x80;
+ area |= areatmp >> 3;
+
+ /* compute the final area value and look it up in IC18/PR1115 (p. 144) */
+ /* note: SLIPAR is 0 on the road surface only */
+ /* ACCIAR is 0 on the road surface and the striped edges only */
+ babit = pr1115[area];
+ slipar_acciar = babit & 0x30;
+ if (!road && (slipar_acciar & 0x20))
+ road = 1;
+
+ /* also use the coch value to look up color info in IC13/PR1114 and IC21/PR1117 (p. 144) */
+ offs = (coch & 0x0f) | /* A0-A3: CONT0-3 = COCH0-3 */
+ ((state->turbo_fbcol & 0x01) << 4); /* A4: COL0 */
+ bacol = pr1114[offs] | (pr1117[offs] << 8);
+
+ /* at this point, do the character lookup; due to the shift register loading in */
+ /* the sync PROM, we latch character 0 during pixel 6 and start clocking in pixel */
+ /* 8, effectively shifting the display by 8; at pixel 0x108, the color latch is */
+ /* forced clear and isn't touched until the next shift register load */
+ foreraw = (xx < 8 || xx >= 0x108) ? 0 : fore[xx - 8];
+
+ /* perform the foreground color table lookup in IC99/PR1118 (p. 137) */
+ forebits = pr1118[foreraw];
+
+ /* now that we have done all the per-5MHz pixel work, mix the sprites at the scale factor */
+ for (ix = 0; ix < TURBO_X_SCALE; ix++)
+ {
+ /* iterate over live sprites and update them */
+ /* the final 32-bit value is: */
+ /* CDB0-7 = D0 -D7 */
+ /* CDG0-7 = D8 -D15 */
+ /* CDR0-7 = D16-D23 */
+ /* PLB0-7 = D24-D31 */
+ sprbits = turbo_get_sprite_bits(road, &sprinfo);
+
+ /* perform collision detection here via lookup in IC20/PR1116 (p. 144) */
+ state->turbo_collision |= pr1116[((sprbits >> 24) & 7) | (slipar_acciar >> 1)];
+
+ /* look up the sprite priority in IC11/PR1122 (p. 144) */
+ priority = ((sprbits & 0xfe000000) >> 25) | /* A0-A6: PLB1-7 */
+ ((state->turbo_fbpla & 0x07) << 7); /* A7-A9: PLA0-2 */
+ priority = pr1122[priority];
+
+ /* use that to look up the overall priority in IC12/PR1123 (p. 144) */
+ mx = (priority & 7) | /* A0-A2: PR-1122 output, bits 0-2 */
+ ((sprbits & 0x01000000) >> 21) | /* A3: PLB0 */
+ ((foreraw & 0x80) >> 3) | /* A4: PLBE */
+ ((forebits & 0x08) << 2) | /* A5: PLBF */
+ ((babit & 0x07) << 6) | /* A6-A8: BABIT1-3 */
+ ((state->turbo_fbpla & 0x08) << 6); /* A9: PLA3 */
+ mx = pr1123[mx];
+
+ /* the MX output selects one of 16 inputs; build up a 16-bit pattern to match */
+ /* these in red, green, and blue (p. 144) */
+ red = ((sprbits & 0x0000ff) >> 0) | /* D0- D7: CDR0-CDR7 */
+ ((forebits & 0x01) << 8) | /* D8: CDRF */
+ ((bacol & 0x001f) << 9) | /* D9-D13: BAR0-BAR4 */
+ (1 << 14) | /* D14: 1 */
+ (0 << 15); /* D15: 0 */
+
+ grn = ((sprbits & 0x00ff00) >> 8) | /* D0- D7: CDG0-CDG7 */
+ ((forebits & 0x02) << 7) | /* D8: CDGF */
+ ((bacol & 0x03e0) << 4) | /* D9-D13: BAG0-BAG4 */
+ (1 << 14) | /* D14: 1 */
+ (0 << 15); /* D15: 0 */
+
+ blu = ((sprbits & 0xff0000) >> 16) | /* D0- D7: CDB0-CDB7 */
+ ((forebits & 0x04) << 6) | /* D8: CDBF */
+ ((bacol & 0x7c00) >> 1) | /* D9-D13: BAB0-BAB4 */
+ (1 << 14) | /* D14: 1 */
+ (0 << 15); /* D15: 0 */
+
+ /* we then go through a muxer to select one of the 16 outputs computed above (p. 144) */
+ offs = mx | /* A0-A3: MX0-MX3 */
+ (((~red >> mx) & 1) << 4) | /* A4: CDR */
+ (((~grn >> mx) & 1) << 5) | /* A5: CDG */
+ (((~blu >> mx) & 1) << 6) | /* A6: CDB */
+ ((state->turbo_fbcol & 6) << 6); /* A7-A8: COL1-2 */
+ dest[x + ix] = pr1121[offs];
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Subroc 3D sprite handling
+ *
+ *************************************/
+
+/*
+ Sprite state machine:
+
+ 1LINE = 0 (V & 0x108 == 0x108)
+ ---------
+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 20 21 21 20 20 21 21 20 20 05 25 2c 07 e7 37 22
+ _____ _____ _____ ________
+ RAD0 = ___| |_____| |_____| |__| |___
+ ___________
+ RAD7 = ____________________________________| |
+ _________________
+ YCULL= ___________________________| |___
+ __
+ AX = _________________________________| |____________
+ __
+ D/A = __________________________________________| |___
+ ___________________________ _____ _________
+ /CLK1= |__| |__|
+ __
+ WRPL = _______________________________________| |______
+ __
+ /CLK2= _______________________________________| |______
+
+
+
+ 1LINE = 1 (V & 0x108 != 0x108)
+ ---------
+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 2c 2c 2c 2f 2f 2f 2f 20 2d 2d 2d 2d 0f 6f 2f 20
+ ___________ ____________________
+ RAD0 = _________| |__| |___
+ ___________ ________
+ RAD7 = _________| |______________| |___
+ _____________________ ____________________
+ YCULL= |__| |___
+ _____________________ ____________________
+ AX = |__| |___
+
+ D/A = _________________________________________________
+ ____________________________________ _________
+ /CLK1= |__|
+ __
+ WRPL = _______________________________________| |______
+
+ /CLK2= _________________________________________________
+
+*/
+
+static void subroc3d_prepare_sprites(turbo_state *state, UINT8 y, sprite_info *info)
+{
+ const UINT8 *pr1449 = memory_region(REGION_PROMS) + 0x300;
+ int sprnum;
+
+ /* initialize the line enable signals to 0 */
+ info->ve = 0;
+ info->lst = 0;
+
+ /* compute the sprite information, which was done on the previous scanline during HBLANK */
+ for (sprnum = 0; sprnum < 16; sprnum++)
+ {
+ UINT8 *rambase = &state->spriteram[sprnum * 8];
+ int level = sprnum & 7;
+ UINT8 clo, chi;
+ UINT32 sum;
+
+ /* perform the first ALU to see if we are within the scanline */
+ sum = y + (rambase[0]/* ^ 0xff*/);
+ clo = (sum >> 8) & 1;
+ sum += (y << 8) + ((rambase[1]/* ^ 0xff*/) << 8);
+ chi = (sum >> 16) & 1;
+
+ /* the AND of the low carry and the inverse of the high carry clocks an enable bit */
+ /* for this sprite; note that the logic in the Turbo schematics is reversed here */
+ if (clo & (chi ^ 1))
+ {
+ int xscale = rambase[2] ^ 0xff;
+ int yscale = rambase[3];// ^ 0xff;
+ UINT16 offset = rambase[6] + (rambase[7] << 8);
+ int offs;
+
+ /* mark this entry enabled */
+ info->ve |= 1 << sprnum;
+
+ /* look up the low byte of the sum plus the yscale value in */
+ /* IC50/PR1119 to determine if we write back the sum of the */
+ /* offset and the rowbytes this scanline (p. 138) */
+ offs = (sum & 0xff) | /* A0-A7 = AL0-AL7 */
+ ((yscale & 0x08) << 5); /* A8-A9 = /RO11-/RO12 */
+
+ /* one of the bits is selected based on the low 7 bits of yscale */
+ if (!((pr1449[offs] >> (yscale & 0x07)) & 1))
+ {
+ offset += rambase[4] + (rambase[5] << 8);
+ rambase[6] = offset;
+ rambase[7] = offset >> 8;
+ }
+
+ /* the output of the ALU here goes to the individual level counter */
+ info->latched[level] = 0;
+ info->plb[level] = 0;
+ info->offset[level] = offset << 1;
+ info->frac[level] = 0;
+ info->step[level] = sprite_xscale(xscale, 1.2e3, 1.2e3, 220e-12);
+ }
+ }
+}
+
+
+static UINT32 subroc3d_get_sprite_bits(sprite_info *sprinfo, UINT8 *plb)
+{
+ /* see logic on each sprite:
+ END = (CDA == 1 && (CDA ^ CDB) == 0 && (CDC ^ CDD) == 0)
+ PLB = END ^ (CDA == 1 && (CDC ^ CDD) == 0)
+ end is in bit 1, plb in bit 0
+ */
+ static const UINT8 plb_end[16] = { 0,1,1,2, 1,1,1,1, 1,1,1,1, 0,1,1,2 };
+ const UINT8 *sprite_gfxdata = memory_region(REGION_GFX1);
+ UINT32 sprdata = 0;
+ int level;
+
+ *plb = 0;
+
+ /* loop over all live levels */
+ for (level = 0; level < 8; level++)
+ if (sprinfo->lst & (1 << level))
+ {
+ /* latch the data and advance the offset */
+ sprdata |= sprinfo->latched[level];
+ *plb |= sprinfo->plb[level];
+ sprinfo->frac[level] += sprinfo->step[level];
+
+ /* if we're live and we've clocked more data, advance */
+ while (sprinfo->frac[level] >= 0x800000)
+ {
+ UINT32 offs = sprinfo->offset[level];
+ UINT8 pixdata;
+
+ /* bit 0 controls which half of the byte to use */
+ /* bits 1-13 go to address lines */
+ /* bit 14 selects which of the two ROMs to read from */
+ pixdata = sprite_gfxdata[(level << 15) | ((offs >> 1) & 0x7fff)] >> ((~offs & 1) * 4);
+ sprinfo->latched[level] = sprite_expand[pixdata & 0x0f] << level;
+ sprinfo->plb[level] = (plb_end[pixdata & 0x0f] & 1) << level;
+
+ /* if bit 3 is 0 and bit 2 is 1, the enable flip/flip is reset */
+ if (plb_end[pixdata & 0x0f] & 2)
+ sprinfo->lst &= ~(1 << level);
+
+ /* if bit 15 is set, we decrement instead of increment */
+ sprinfo->offset[level] += (offs & 0x10000) ? -1 : 1;
+ sprinfo->frac[level] -= 0x800000;
+ }
+ }
+
+ return sprdata;
+}
+
+
+
+/*************************************
+ *
+ * Subroc 3D video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( subroc3d )
+{
+ turbo_state *state = machine->driver_data;
+ mame_bitmap *fgpixmap = tilemap_get_pixmap(state->fg_tilemap);
+ const UINT8 *prom_base = memory_region(REGION_PROMS);
+ const UINT8 *pr1419 = prom_base + 0x000;
+ const UINT8 *pr1620 = prom_base + 0x200;
+ const UINT8 *pr1450 = prom_base + 0x500;
+ const UINT8 *pr1454 = prom_base + 0x920;
+ int x, y;
+
+ /* loop over rows */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ const UINT16 *fore = (UINT16 *)fgpixmap->base + y * fgpixmap->rowpixels;
+ UINT16 *dest = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+ sprite_info sprinfo;
+
+ /* compute the sprite information; we use y-1 since this info was computed during HBLANK */
+ /* on the previous scanline */
+ subroc3d_prepare_sprites(state, y, &sprinfo);
+
+ /* loop over columns */
+ for (x = 0; x <= cliprect->max_x; x += TURBO_X_SCALE)
+ {
+ int offs, finalbits, ix;
+ UINT8 xx = x / TURBO_X_SCALE;
+ UINT8 foreraw, forebits, mux, cd, plb, mplb;
+ UINT16 he;
+ UINT32 sprbits;
+
+ /* load the bitmask from the sprite position for both halves of the sprites (p. 143) */
+ he = state->sprite_position[xx * 2] | (state->sprite_position[xx * 2 + 1] << 8);
+
+ /* the AND of the line enable and horizontal enable is clocked and held in LST0-7 (p. 143) */
+ he &= sprinfo.ve;
+ sprinfo.lst |= he | (he >> 8);
+
+ /* at this point, do the character lookup */
+ if (!state->subroc3d_flip)
+ foreraw = fore[xx];
+ else
+ foreraw = fore[(pr1454[(xx >> 3) & 0x1f] << 3) | (xx & 0x07)];
+
+ /* perform the foreground color table lookup in IC62/PR1620 (p. 141) */
+ forebits = pr1620[foreraw];
+
+ /* MPLB is set based on the high bit of the raw foreground data, as an OR over the output */
+ /* of the foreground color PROM */
+ mplb = (foreraw & 0x80) || ((forebits & 0x0f) == 0);
+
+ /* now that we have done all the per-5MHz pixel work, mix the sprites at the scale factor */
+ for (ix = 0; ix < TURBO_X_SCALE; ix++)
+ {
+ /* iterate over live sprites and update them */
+ /* the final 32-bit value is: */
+ /* CDA0-7 = D0 -D7 */
+ /* CDB0-7 = D8 -D15 */
+ /* CDC0-7 = D16-D23 */
+ /* CDD0-7 = D24-D31 */
+ sprbits = subroc3d_get_sprite_bits(&sprinfo, &plb);
+
+ /* MUX0-3 is selected by PLY0-3 and the sprite enable bits, and is the output */
+ /* of IC21/PR1450 (p. 141), unless MPLB = 0, in which case the values are grounded (p. 141) */
+ if (mplb)
+ {
+ offs = (plb ^ 0xff) | /* A0-A7: /PLB0-7 */
+ ((state->subroc3d_ply & 0x02) << 7); /* A8: PLY1 */
+ mux = pr1450[offs] >> ((state->subroc3d_ply & 0x01) * 4);
+ }
+ else
+ mux = 0;
+
+ /* CD0-3 are selected from the sprite bits and MUX0-2 (p. 141) */
+ sprbits = (sprbits >> (mux & 0x07)) & 0x01010101;
+ cd = (sprbits >> (24-3)) | (sprbits >> (16-2)) | (sprbits >> (8-1)) | sprbits;
+
+ /* MUX3 selects either CD0-3 or the foreground output (p. 141) */
+ if (mux & 0x08)
+ finalbits = cd;
+ else
+ finalbits = forebits;
+
+ /* we then go through a muxer to select one of the 16 outputs computed above (p. 141) */
+ offs = (finalbits & 0x0f) | /* A0-A3: CD0-CD3 */
+ ((mux & 0x08) << 1) | /* A4: MUX3 */
+ (state->subroc3d_col << 5); /* A5-A8: COL0-COL3 */
+ dest[x + ix] = pr1419[offs];
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Buck Rogers sprite handling
+ *
+ *************************************/
+
+static void buckrog_prepare_sprites(turbo_state *state, UINT8 y, sprite_info *info)
+{
+ const UINT8 *pr5196 = memory_region(REGION_PROMS) + 0x100;
+ int sprnum;
+
+ /* initialize the line enable signals to 0 */
+ info->ve = 0;
+ info->lst = 0;
+
+ /* compute the sprite information, which was done on the previous scanline during HBLANK */
+ for (sprnum = 0; sprnum < 16; sprnum++)
+ {
+ UINT8 *rambase = &state->spriteram[sprnum * 8];
+ int level = sprnum & 7;
+ UINT8 clo, chi;
+ UINT32 sum;
+
+ /* perform the first ALU to see if we are within the scanline */
+ sum = y + (rambase[0]/* ^ 0xff*/);
+ clo = (sum >> 8) & 1;
+ sum += (y << 8) + ((rambase[1]/* ^ 0xff*/) << 8);
+ chi = (sum >> 16) & 1;
+
+ /* the AND of the low carry and the inverse of the high carry clocks an enable bit */
+ /* for this sprite; note that the logic in the Turbo schematics is reversed here */
+ if (clo & (chi ^ 1))
+ {
+ int xscale = rambase[2] ^ 0xff;
+ int yscale = rambase[3];// ^ 0xff;
+ UINT16 offset = rambase[6] + (rambase[7] << 8);
+ int offs;
+
+ /* mark this entry enabled */
+ info->ve |= 1 << sprnum;
+
+ /* look up the low byte of the sum plus the yscale value in */
+ /* IC50/PR1119 to determine if we write back the sum of the */
+ /* offset and the rowbytes this scanline (p. 138) */
+ offs = (sum & 0xff) | /* A0-A7 = AL0-AL7 */
+ ((yscale & 0x08) << 5); /* A8-A9 = /RO11-/RO12 */
+
+ /* one of the bits is selected based on the low 7 bits of yscale */
+ if (!((pr5196[offs] >> (yscale & 0x07)) & 1))
+ {
+ offset += rambase[4] + (rambase[5] << 8);
+ rambase[6] = offset;
+ rambase[7] = offset >> 8;
+ }
+
+ /* the output of the ALU here goes to the individual level counter */
+ info->latched[level] = 0;
+ info->plb[level] = 0;
+ info->offset[level] = offset << 1;
+ info->frac[level] = 0;
+ info->step[level] = sprite_xscale(xscale, 1.2e3, 500/*820*/, 220e-12);
+ }
+ }
+}
+
+
+static UINT32 buckrog_get_sprite_bits(sprite_info *sprinfo, UINT8 *plb)
+{
+ /* see logic on each sprite:
+ END = (CDA == 1 && (CDA ^ CDB) == 0 && (CDC ^ CDD) == 0)
+ PLB = END ^ (CDA == 1 && (CDC ^ CDD) == 0)
+ end is in bit 1, plb in bit 0
+ */
+ static const UINT8 plb_end[16] = { 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,2 };
+ const UINT8 *sprite_gfxdata = memory_region(REGION_GFX1);
+ UINT32 sprdata = 0;
+ int level;
+
+ *plb = 0;
+
+ /* loop over all live levels */
+ for (level = 0; level < 8; level++)
+ if (sprinfo->lst & (1 << level))
+ {
+ /* latch the data and advance the offset */
+ sprdata |= sprinfo->latched[level];
+ *plb |= sprinfo->plb[level];
+ sprinfo->frac[level] += sprinfo->step[level];
+
+ /* if we're live and we've clocked more data, advance */
+ while (sprinfo->frac[level] >= 0x800000)
+ {
+ UINT32 offs = sprinfo->offset[level];
+ UINT8 pixdata;
+
+ /* bit 0 controls which half of the byte to use */
+ /* bits 1-13 go to address lines */
+ /* bit 14 selects which of the two ROMs to read from */
+ pixdata = sprite_gfxdata[(level << 15) | ((offs >> 1) & 0x7fff)] >> ((~offs & 1) * 4);
+ sprinfo->latched[level] = sprite_expand[pixdata & 0x0f] << level;
+ sprinfo->plb[level] = (plb_end[pixdata & 0x0f] & 1) << level;
+
+ /* if bit 3 is 0 and bit 2 is 1, the enable flip/flip is reset */
+ if (plb_end[pixdata & 0x0f] & 2)
+ sprinfo->lst &= ~(1 << level);
+
+ /* if bit 15 is set, we decrement instead of increment */
+ sprinfo->offset[level] += (offs & 0x10000) ? -1 : 1;
+ sprinfo->frac[level] -= 0x800000;
+ }
+ }
+
+ return sprdata;
+}
+
+
+
+/*************************************
+ *
+ * Buck Rogers video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( buckrog )
+{
+ turbo_state *state = machine->driver_data;
+ mame_bitmap *fgpixmap = tilemap_get_pixmap(state->fg_tilemap);
+ const UINT8 *bgcolor = memory_region(REGION_GFX3);
+ const UINT8 *prom_base = memory_region(REGION_PROMS);
+ const UINT8 *pr5194 = prom_base + 0x000;
+ const UINT8 *pr5198 = prom_base + 0x500;
+ const UINT8 *pr5199 = prom_base + 0x700;
+ int x, y;
+
+ /* loop over rows */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ const UINT16 *fore = (UINT16 *)fgpixmap->base + y * fgpixmap->rowpixels;
+ UINT16 *dest = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+ sprite_info sprinfo;
+
+ /* compute the sprite information; we use y-1 since this info was computed during HBLANK */
+ /* on the previous scanline */
+ buckrog_prepare_sprites(state, y, &sprinfo);
+
+ /* loop over columns */
+ for (x = 0; x <= cliprect->max_x; x += TURBO_X_SCALE)
+ {
+ UINT8 foreraw, forebits, cd, plb, star, mux;
+ UINT8 xx = x / TURBO_X_SCALE;
+ UINT16 he;
+ UINT32 sprbits;
+ int palbits, offs, ix;
+
+ /* load the bitmask from the sprite position for both halves of the sprites (p. 143) */
+ he = state->sprite_position[xx * 2] | (state->sprite_position[xx * 2 + 1] << 8);
+
+ /* the AND of the line enable and horizontal enable is clocked and held in LST0-7 (p. 143) */
+ he &= sprinfo.ve;
+ sprinfo.lst |= he | (he >> 8);
+
+ /* at this point, do the character lookup and the foreground color table lookup in IC93/PR1598 (SH 5/5)*/
+ foreraw = fore[(pr5194[((xx >> 3) - 1) & 0x1f] << 3) | (xx & 0x07)];
+ offs = ((foreraw & 0x03) << 0) | /* A0-A1: BIT0-1 */
+ ((foreraw & 0xf8) >> 1) | /* A2-A6: BANK3-7 */
+ ((state->buckrog_fchg & 0x03) << 7); /* A7-A9: FCHG0-2 */
+ forebits = pr5198[offs];
+
+ /* fetch the STAR bit */
+ star = state->buckrog_bitmap_ram[y * 256 + xx];
+
+ /* now that we have done all the per-5MHz pixel work, mix the sprites at the scale factor */
+ for (ix = 0; ix < TURBO_X_SCALE; ix++)
+ {
+ /* iterate over live sprites and update them */
+ /* the final 32-bit value is: */
+ /* CDA0-7 = D0 -D7 */
+ /* CDB0-7 = D8 -D15 */
+ /* CDC0-7 = D16-D23 */
+ /* CDD0-7 = D24-D31 */
+ sprbits = buckrog_get_sprite_bits(&sprinfo, &plb);
+
+ /* the PLB bits go into an LS148 8-to-1 decoder and become MUX0-3 (PROM board SH 2/10) */
+ if (plb == 0)
+ mux = 8;
+ else
+ {
+ mux = 7;
+ while (!(plb & 0x80))
+ {
+ mux--;
+ plb <<= 1;
+ }
+ }
+
+ /* MUX then selects one of the sprites and selects CD0-3 */
+ sprbits = (sprbits >> (mux & 0x07)) & 0x01010101;
+ cd = (sprbits >> (24-3)) | (sprbits >> (16-2)) | (sprbits >> (8-1)) | sprbits;
+
+ /* this info goes into an LS148 8-to-3 decoder to determine the priorities (SH 5/5) */
+
+ /* priority 7 is if bit 0x80 of the foreground color is 0; CHNG = 0 */
+ if (!(forebits & 0x80))
+ {
+ palbits = ((forebits & 0x3c) << 2) |
+ ((forebits & 0x06) << 1) |
+ ((forebits & 0x01) << 0);
+ }
+
+ /* priority 6 is if MUX3 is 0; CHNG = 1 */
+ else if (!(mux & 0x08))
+ {
+ offs = (cd & 0x0f) | /* A0-A3: CD0-3 */
+ ((mux & 0x07) << 4) | /* A4-A6: MUX0-2 */
+ ((state->buckrog_obch & 0x07) << 7); /* A7-A9: OBCH0-2 */
+ palbits = pr5199[offs];
+ }
+
+ /* priority 3 is if bit 0x40 of the foreground color is 0; CHNG = 0 */
+ else if (!(forebits & 0x40))
+ {
+ palbits = ((forebits & 0x3c) << 2) |
+ ((forebits & 0x06) << 1) |
+ ((forebits & 0x01) << 0);
+ }
+
+ /* priority 1 is if the star is set; CHNG = 2 */
+ else if (star)
+ {
+ palbits = 0xff;
+ }
+
+ /* otherwise, CHNG = 3 */
+ else
+ {
+ palbits = bgcolor[y | ((state->buckrog_mov & 0x1f) << 8)];
+ palbits = (palbits & 0xc0) | ((palbits & 0x30) << 4) | ((palbits & 0x0f) << 2);
+ }
+
+ /* store the final bits for this pixel */
+ dest[x + ix] = palbits;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/tutankhm.c b/src/mame/video/tutankhm.c
new file mode 100644
index 00000000000..6a955568ece
--- /dev/null
+++ b/src/mame/video/tutankhm.c
@@ -0,0 +1,164 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+
+#include "driver.h"
+
+
+#define NUM_PENS (0x10)
+
+
+UINT8 *tutankhm_videoram;
+size_t tutankhm_videoram_size;
+UINT8 *tutankhm_paletteram;
+UINT8 *tutankhm_scroll;
+
+static UINT8 junofrst_blitterdata[4];
+static UINT8 tutankhm_flip_screen_x;
+static UINT8 tutankhm_flip_screen_y;
+
+
+
+WRITE8_HANDLER( tutankhm_flip_screen_x_w )
+{
+ tutankhm_flip_screen_x = data & 0x01;
+}
+
+
+WRITE8_HANDLER( tutankhm_flip_screen_y_w )
+{
+ tutankhm_flip_screen_y = data & 0x01;
+}
+
+
+static void get_pens(pen_t *pens)
+{
+ offs_t i;
+
+ for (i = 0; i < NUM_PENS; i++)
+ {
+ UINT8 data = tutankhm_paletteram[i];
+
+ pens[i] = MAKE_RGB(pal3bit(data >> 0), pal3bit(data >> 3), pal2bit(data >> 6));
+ }
+}
+
+
+VIDEO_UPDATE( tutankhm )
+{
+ pen_t pens[NUM_PENS];
+ offs_t offs;
+
+ get_pens(pens);
+
+ for (offs = 0; offs < tutankhm_videoram_size; offs++)
+ {
+ int i;
+
+ UINT8 data = tutankhm_videoram[offs];
+
+ UINT8 y = offs >> 7;
+ UINT8 x = offs << 1;
+
+ for (i = 0; i < 2; i++)
+ {
+ UINT8 sy = y;
+ UINT8 sx = x;
+
+ pen_t pen = pens[data & 0x0f];
+
+ /* adjust for scrolling */
+ if (x < 192)
+ {
+ sy = sy - *tutankhm_scroll;
+ }
+
+ if (tutankhm_flip_screen_y) sy = 255 - sy;
+ if (tutankhm_flip_screen_x) sx = 255 - sx;
+
+ *BITMAP_ADDR32(bitmap, sy, sx) = pen;
+
+ x = x + 1;
+ data = data >> 4;
+ }
+ }
+
+ return 0;
+}
+
+
+
+/* Juno First Blitter Hardware emulation
+
+ Juno First can blit a 16x16 graphics which comes from un-memory mapped graphics roms
+
+ $8070->$8071 specifies the destination NIBBLE address
+ $8072->$8073 specifies the source NIBBLE address
+
+ Depending on bit 0 of the source address either the source pixels will be copied to
+ the destination address, or a zero will be written.
+
+ Only source pixels which aren't 0 are copied or cleared.
+
+ This allows the game to quickly clear the sprites from the screen
+
+ TODO: Does bit 1 of the source address mean something?
+ We have to mask it off otherwise the "Juno First" logo on the title screen is wrong.
+*/
+
+WRITE8_HANDLER( junofrst_blitter_w )
+{
+ junofrst_blitterdata[offset] = data;
+
+ /* blitter is triggered by $8073 */
+ if (offset == 3)
+ {
+ int i;
+ UINT8 *gfx_rom = memory_region(REGION_GFX1);
+
+ offs_t src = ((junofrst_blitterdata[2] << 8) | junofrst_blitterdata[3]) & 0xfffc;
+ offs_t dest = (junofrst_blitterdata[0] << 8) | junofrst_blitterdata[1];
+
+ int copy = junofrst_blitterdata[3] & 0x01;
+
+ /* 16x16 graphics */
+ for (i = 0; i < 16; i++)
+ {
+ int j;
+
+ for (j = 0; j < 16; j++)
+ {
+ UINT8 data;
+
+ if (src & 1)
+ data = gfx_rom[src >> 1] & 0x0f;
+ else
+ data = gfx_rom[src >> 1] >> 4;
+
+ src = src + 1;
+
+ /* if there is a source pixel either copy the pixel or clear the pixel depending on the copy flag */
+
+ if (data)
+ {
+ if (copy==0)
+ data = 0;
+
+ if (dest & 1)
+ tutankhm_videoram[dest >> 1] = (tutankhm_videoram[dest >> 1] & 0x0f) | (data << 4);
+ else
+ tutankhm_videoram[dest >> 1] = (tutankhm_videoram[dest >> 1] & 0xf0) | data;
+ }
+
+ dest = dest + 1;
+ }
+
+ dest = dest + 240;
+ }
+ }
+}
diff --git a/src/mame/video/twin16.c b/src/mame/video/twin16.c
new file mode 100644
index 00000000000..76a69254b6f
--- /dev/null
+++ b/src/mame/video/twin16.c
@@ -0,0 +1,463 @@
+/*
+
+ Konami Twin16 Hardware - Video
+
+ TODO:
+
+ - convert background to tilemap
+ - clean up sprite drawing
+ - sprite-background priorities
+ - sprite lag in devilw
+ - sprite Y axis lag in vulcan
+ - add shadow sprites (alpha blending) to sprites in at least devilw
+
+*/
+
+#include "driver.h"
+
+extern UINT16 twin16_custom_video;
+extern UINT16 *twin16_gfx_rom;
+extern UINT16 *twin16_videoram2;
+extern UINT16 *twin16_sprite_gfx_ram;
+extern UINT16 *twin16_tile_gfx_ram;
+extern int twin16_spriteram_process_enable( void );
+
+static int need_process_spriteram;
+static UINT16 gfx_bank;
+static UINT16 scrollx[3], scrolly[3];
+static UINT16 video_register;
+
+enum {
+ TWIN16_SCREEN_FLIPY = 0x01, /* ? breaks devils world text layer */
+ TWIN16_SCREEN_FLIPX = 0x02, /* confirmed: Hard Puncher Intro */
+ TWIN16_UNKNOWN1 = 0x04, /* ?Hard Puncher uses this */
+ TWIN16_PLANE_ORDER = 0x08, /* confirmed: Devil Worlds */
+ TWIN16_TILE_FLIPY = 0x20 /* confirmed? Vulcan Venture */
+};
+
+static tilemap *fg_tilemap;
+
+WRITE16_HANDLER( twin16_videoram2_w )
+{
+ COMBINE_DATA(&twin16_videoram2[offset]);
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE16_HANDLER( twin16_paletteram_word_w )
+{ // identical to tmnt_paletteram_w
+ COMBINE_DATA(paletteram16 + offset);
+ offset &= ~1;
+
+ data = ((paletteram16[offset] & 0xff) << 8) | (paletteram16[offset + 1] & 0xff);
+ palette_set_color_rgb(Machine, offset / 2, pal5bit(data >> 0), pal5bit(data >> 5), pal5bit(data >> 10));
+}
+
+WRITE16_HANDLER( fround_gfx_bank_w )
+{
+ COMBINE_DATA(&gfx_bank);
+}
+
+WRITE16_HANDLER( twin16_video_register_w )
+{
+ switch (offset) {
+ case 0:
+ COMBINE_DATA( &video_register );
+
+ flip_screen_x_set(video_register & TWIN16_SCREEN_FLIPX);
+
+ if (twin16_custom_video)
+ flip_screen_y_set(video_register & TWIN16_SCREEN_FLIPY);
+ else
+ flip_screen_y_set(~video_register & TWIN16_SCREEN_FLIPY);
+
+ break;
+
+ case 1: COMBINE_DATA( &scrollx[0] ); break;
+ case 2: COMBINE_DATA( &scrolly[0] ); break;
+ case 3: COMBINE_DATA( &scrollx[1] ); break;
+ case 4: COMBINE_DATA( &scrolly[1] ); break;
+ case 5: COMBINE_DATA( &scrollx[2] ); break;
+ case 6: COMBINE_DATA( &scrolly[2] ); break;
+
+ default:
+ logerror("unknown video_register write:%d", data );
+ break;
+ }
+}
+
+static void draw_sprite( /* slow slow slow, but it's ok for now */
+ mame_bitmap *bitmap,
+ const UINT16 *pen_data,
+ const pen_t *pal_data,
+ int xpos, int ypos,
+ int width, int height,
+ int flipx, int flipy, int pri )
+{
+
+ int x,y,pval;
+ if( xpos>=320 ) xpos -= 65536;
+ if( ypos>=256 ) ypos -= 65536;
+
+ if (pri) pval=2; else pval=8;
+
+ {
+ {
+ for( y=0; y<height; y++ )
+ {
+ int sy = (flipy)?(ypos+height-1-y):(ypos+y);
+ if( sy>=16 && sy<256-16 )
+ {
+ UINT16 *dest = BITMAP_ADDR16(bitmap, sy, 0);
+ UINT8 *pdest = BITMAP_ADDR8(priority_bitmap, sy, 0);
+
+ for( x=0; x<width; x++ )
+ {
+ int sx = (flipx)?(xpos+width-1-x):(xpos+x);
+ if( sx>=0 && sx<320 )
+ {
+ UINT16 pen = pen_data[x/4];
+ switch( x%4 )
+ {
+ case 0: pen = pen>>12; break;
+ case 1: pen = (pen>>8)&0xf; break;
+ case 2: pen = (pen>>4)&0xf; break;
+ case 3: pen = pen&0xf; break;
+ }
+
+ if( pen )
+ {
+ if(pdest[sx]<pval) { dest[sx] = pal_data[pen]; }
+
+ pdest[sx]|=0x10;
+ }
+ }
+ }
+ }
+ pen_data += width/4;
+ }
+ }
+ }
+}
+
+void twin16_spriteram_process( void )
+{
+ UINT16 dx = scrollx[0];
+ UINT16 dy = scrolly[0];
+
+ const UINT16 *source = &spriteram16[0x0000];
+ const UINT16 *finish = &spriteram16[0x1800];
+
+ memset( &spriteram16[0x1800], 0, 0x800 );
+ while( source<finish ){
+ UINT16 priority = source[0];
+ if( priority & 0x8000 ){
+ UINT16 *dest = &spriteram16[0x1800 + 4*(priority&0xff)];
+
+ INT32 xpos = (0x10000*source[4])|source[5];
+ INT32 ypos = (0x10000*source[6])|source[7];
+
+ UINT16 attributes = source[2]&0x03ff; /* scale,size,color */
+ if( priority & 0x0200 ) attributes |= 0x4000;
+ /* Todo: priority & 0x0100 is also used */
+ attributes |= 0x8000;
+
+ dest[0] = source[3]; /* gfx data */
+ dest[1] = ((xpos>>8) - dx)&0xffff;
+ dest[2] = ((ypos>>8) - dy)&0xffff;
+ dest[3] = attributes;
+ }
+ source += 0x50/2;
+ }
+ need_process_spriteram = 0;
+}
+
+/*
+ * Sprite Format
+ * ----------------------------------
+ *
+ * Word | Bit(s) | Use
+ * -----+-fedcba9876543210-+----------------
+ * 0 | --xxxxxxxxxxxxxx | code
+ * -----+------------------+
+ * 1 | -------xxxxxxxxx | ypos
+ * -----+------------------+
+ * 2 | -------xxxxxxxxx | xpos
+ * -----+------------------+
+ * 3 | x--------------- | enble
+ * 3 | -x-------------- | priority?
+ * 3 | ------x--------- | yflip?
+ * 3 | -------x-------- | xflip
+ * 3 | --------xx------ | height
+ * 3 | ----------xx---- | width
+ * 3 | ------------xxxx | color
+
+shadow bit?
+
+ */
+
+static void draw_sprites( mame_bitmap *bitmap )
+{
+ int count = 0;
+
+ const UINT16 *source = 0x1800+buffered_spriteram16 + 0x800 - 4;
+ const UINT16 *finish = 0x1800+buffered_spriteram16;
+
+ for (; source >= finish; source -= 4) {
+ UINT16 attributes = source[3];
+ UINT16 code = source[0];
+
+ if((code!=0xffff) && (attributes&0x8000)) {
+ int xpos = source[1];
+ int ypos = source[2];
+
+ const pen_t *pal_data = Machine->pens+((attributes&0xf)+0x10)*16;
+ int height = 16<<((attributes>>6)&0x3);
+ int width = 16<<((attributes>>4)&0x3);
+ const UINT16 *pen_data = 0;
+ int flipy = attributes&0x0200;
+ int flipx = attributes&0x0100;
+
+ if( twin16_custom_video == 1 ) {
+ pen_data = twin16_gfx_rom + 0x80000;
+ }
+ else {
+ switch( (code>>12)&0x3 ){ /* bank select */
+ case 0:
+ pen_data = twin16_gfx_rom;
+ break;
+
+ case 1:
+ pen_data = twin16_gfx_rom + 0x40000;
+ break;
+
+ case 2:
+ pen_data = twin16_gfx_rom + 0x80000;
+ if( code&0x4000 ) pen_data += 0x40000;
+ break;
+
+ case 3:
+ pen_data = twin16_sprite_gfx_ram;
+ break;
+ }
+ code &= 0xfff;
+ }
+
+ /* some code masking */
+ if(height == 64 && width == 64)
+ {
+ code &= ~8; // fixes bad sprites in vulcan ending sequence
+ }
+ else if(height == 32 && width == 32)
+ {
+ code &= ~3; // fixes bad sprites in devilw
+ }
+ else if(height == 32 && width == 16)
+ {
+ code &= ~1; // fixes bad sprites in devilw
+ }
+ else if(height == 16 && width == 32)
+ {
+ code &= ~1; // fixes bad sprites in devilw
+ }
+
+ pen_data += code*0x40;
+
+ if( video_register&TWIN16_SCREEN_FLIPY ){
+ if (ypos>65000) ypos=ypos-65536; /* Bit hacky */
+ ypos = 256-ypos-height;
+ flipy = !flipy;
+ }
+ if( video_register&TWIN16_SCREEN_FLIPX ){
+ if (xpos>65000) xpos=xpos-65536; /* Bit hacky */
+ xpos = 320-xpos-width;
+ flipx = !flipx;
+ }
+
+ //if( sprite_which==count || !input_code_pressed( KEYCODE_B ) )
+ draw_sprite( bitmap, pen_data, pal_data, xpos, ypos, width, height, flipx, flipy, (attributes&0x4000) );
+ }
+
+ count++;
+ }
+}
+
+static void draw_layer( mame_bitmap *bitmap, int opaque ){
+ const UINT16 *gfx_base;
+ const UINT16 *source = videoram16;
+ int i, xxor, yxor;
+ int bank_table[4];
+ int dx, dy, palette;
+ int tile_flipx = 0; // video_register&TWIN16_TILE_FLIPX;
+ int tile_flipy = video_register&TWIN16_TILE_FLIPY;
+
+ if( ((video_register&TWIN16_PLANE_ORDER)?1:0) != opaque ){
+ source += 0x1000;
+ dx = scrollx[2];
+ dy = scrolly[2];
+ palette = 1;
+ }
+ else {
+ source += 0x0000;
+ dx = scrollx[1];
+ dy = scrolly[1];
+ palette = 0;
+ }
+
+ if( twin16_custom_video == 1 ){
+ gfx_base = twin16_gfx_rom;
+ bank_table[3] = (gfx_bank>>(4*3))&0xf;
+ bank_table[2] = (gfx_bank>>(4*2))&0xf;
+ bank_table[1] = (gfx_bank>>(4*1))&0xf;
+ bank_table[0] = (gfx_bank>>(4*0))&0xf;
+ }
+ else {
+ gfx_base = twin16_tile_gfx_ram;
+ bank_table[0] = 0;
+ bank_table[1] = 1;
+ bank_table[2] = 2;
+ bank_table[3] = 3;
+ }
+
+ if( video_register&TWIN16_SCREEN_FLIPX ){
+ dx = 256-dx-64;
+ tile_flipx = !tile_flipx;
+ }
+
+ if( video_register&TWIN16_SCREEN_FLIPY ){
+ dy = 256-dy;
+ tile_flipy = !tile_flipy;
+ }
+
+ xxor = tile_flipx ? 7 : 0;
+ yxor = tile_flipy ? 7 : 0;
+
+ for( i=0; i<64*64; i++ )
+ {
+ int y1, y2, x1, x2;
+ int sx = (i%64)*8;
+ int sy = (i/64)*8;
+ int xpos,ypos;
+
+ if( video_register&TWIN16_SCREEN_FLIPX ) sx = 63*8 - sx;
+ if( video_register&TWIN16_SCREEN_FLIPY ) sy = 63*8 - sy;
+
+ xpos = (sx-dx)&0x1ff;
+ ypos = (sy-dy)&0x1ff;
+ if( xpos>=320 ) xpos -= 512;
+ if( ypos>=256 ) ypos -= 512;
+
+ x1 = MAX(xpos, 0);
+ x2 = MIN(xpos+7, bitmap->width-1);
+ y1 = MAX(ypos, 0);
+ y2 = MIN(ypos+7, bitmap->height-1);
+
+ if (x1 <= x2 && y1 <= y2)
+ {
+ int code = source[i];
+ /*
+ xxx------------- color
+ ---xx----------- tile bank
+ -----xxxxxxxxxxx tile number
+ */
+ const UINT16 *gfx_data = gfx_base + (code&0x7ff)*16 + bank_table[(code>>11)&0x3]*0x8000;
+ int color = (code>>13);
+ const pen_t *pal_data = Machine->pens + 16*(0x20+color+8*palette);
+ int x, y;
+
+ if( opaque )
+ {
+ for (y = y1; y <= y2; y++)
+ {
+ const UINT16 *gfxptr = gfx_data + ((y - ypos) ^ yxor) * 2;
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ UINT8 *pdest = BITMAP_ADDR8(priority_bitmap, y, 0);
+
+ for (x = x1; x <= x2; x++)
+ {
+ int effx = (x - xpos) ^ xxor;
+ UINT16 data = gfxptr[effx / 4];
+ dest[x] = pal_data[(data >> 4*(~effx & 3)) & 0x0f];
+ pdest[x] |= 1;
+ }
+ }
+ }
+ else
+ {
+ for (y = y1; y <= y2; y++)
+ {
+ const UINT16 *gfxptr = gfx_data + ((y - ypos) ^ yxor) * 2;
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+ UINT8 *pdest = BITMAP_ADDR8(priority_bitmap, y, 0);
+
+ for (x = x1; x <= x2; x++)
+ {
+ int effx = (x - xpos) ^ xxor;
+ UINT16 data = gfxptr[effx / 4];
+ UINT8 pen = (data >> 4*(~effx & 3)) & 0x0f;
+ if (pen)
+ {
+ dest[x] = pal_data[pen];
+ pdest[x] |= 4;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ const UINT16 *source = twin16_videoram2;
+ int attr = source[tile_index];
+ int code = attr & 0x1ff;
+ int color = (attr >> 9) & 0x0f;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+VIDEO_START( twin16 )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows_flip_y,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+VIDEO_START( fround )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+}
+
+VIDEO_EOF( twin16 )
+{
+ if( twin16_spriteram_process_enable() && need_process_spriteram )
+ twin16_spriteram_process();
+
+ need_process_spriteram = 1;
+
+ buffer_spriteram16_w(0,0,0);
+}
+
+VIDEO_UPDATE( twin16 )
+{
+ fillbitmap(priority_bitmap,0,cliprect);
+ draw_layer( bitmap,1 );
+ draw_layer( bitmap,0 );
+ draw_sprites( bitmap );
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
+
+VIDEO_UPDATE( vulcan )
+{
+ fillbitmap(priority_bitmap,0,cliprect);
+ draw_layer( bitmap,1 );
+ draw_sprites( bitmap );
+ draw_layer( bitmap,0 );
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/twincobr.c b/src/mame/video/twincobr.c
new file mode 100644
index 00000000000..d60e7cdc19a
--- /dev/null
+++ b/src/mame/video/twincobr.c
@@ -0,0 +1,521 @@
+/***************************************************************************
+ video.c
+
+ Functions to emulate the video hardware of these machines.
+ Video is 30x40 tiles. (200x320 for Twin Cobra/Flying shark)
+ Video is 40x30 tiles. (320x200 for Wardner)
+
+ Video has 3 scrolling tile layers (Background, Foreground and Text) and
+ Sprites that have 4 priorities. Lowest priority is "Off".
+ Wardner has an unusual sprite priority in the shop scenes, whereby a
+ middle level priority Sprite appears over a high priority Sprite ?
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/crtc6845.h"
+#include "twincobr.h"
+
+
+void twincobr_flipscreen(int flip);
+void twincobr_display(int enable);
+static void twincobr_restore_screen(void);
+
+INT32 twincobr_fg_rom_bank;
+INT32 twincobr_bg_ram_bank;
+INT32 wardner_sprite_hack; /* Required for weird sprite priority in wardner */
+ /* when hero is in shop. Hero should cover shop owner */
+
+static UINT16 *twincobr_bgvideoram16;
+static UINT16 *twincobr_fgvideoram16;
+static UINT16 *twincobr_txvideoram16;
+
+static size_t twincobr_bgvideoram_size;
+static size_t twincobr_fgvideoram_size;
+static size_t twincobr_txvideoram_size;
+
+static INT32 txscrollx;
+static INT32 txscrolly;
+static INT32 fgscrollx;
+static INT32 fgscrolly;
+static INT32 bgscrollx;
+static INT32 bgscrolly;
+static INT32 txoffs;
+static INT32 fgoffs;
+static INT32 bgoffs;
+static INT32 scroll_x;
+static INT32 scroll_y;
+static INT32 twincobr_display_on;
+static INT32 twincobr_flip_screen;
+
+static tilemap *bg_tilemap, *fg_tilemap, *tx_tilemap;
+
+
+/***************************************************************************
+ Callbacks for the TileMap code
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code, tile_number, color;
+
+ code = twincobr_bgvideoram16[tile_index+twincobr_bg_ram_bank];
+ tile_number = code & 0x0fff;
+ color = (code & 0xf000) >> 12;
+ SET_TILE_INFO(
+ 2,
+ tile_number,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code, tile_number, color;
+
+ code = twincobr_fgvideoram16[tile_index];
+ tile_number = (code & 0x0fff) | twincobr_fg_rom_bank;
+ color = (code & 0xf000) >> 12;
+ SET_TILE_INFO(
+ 1,
+ tile_number,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ int code, tile_number, color;
+
+ code = twincobr_txvideoram16[tile_index];
+ tile_number = code & 0x07ff;
+ color = (code & 0xf800) >> 11;
+ SET_TILE_INFO(
+ 0,
+ tile_number,
+ color,
+ 0);
+}
+
+/***************************************************************************
+ Start the video hardware emulation.
+***************************************************************************/
+
+static void twincobr_create_tilemaps(void)
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64);
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_transparent_pen(tx_tilemap,0);
+}
+
+VIDEO_START( toaplan0 )
+{
+ /* the video RAM is accessed via ports, it's not memory mapped */
+ twincobr_txvideoram_size = 0x0800;
+ twincobr_bgvideoram_size = 0x2000; /* banked two times 0x1000 */
+ twincobr_fgvideoram_size = 0x1000;
+
+ twincobr_create_tilemaps();
+
+ twincobr_txvideoram16 = auto_malloc(twincobr_txvideoram_size*2);
+ memset(twincobr_txvideoram16,0,twincobr_txvideoram_size*2);
+
+ twincobr_fgvideoram16 = auto_malloc(twincobr_fgvideoram_size*2);
+ memset(twincobr_fgvideoram16,0,twincobr_fgvideoram_size*2);
+
+ twincobr_bgvideoram16 = auto_malloc(twincobr_bgvideoram_size*2);
+ memset(twincobr_bgvideoram16,0,twincobr_bgvideoram_size*2);
+
+ twincobr_display_on = 0;
+ twincobr_display(twincobr_display_on);
+
+ state_save_register_global_pointer(twincobr_txvideoram16, twincobr_txvideoram_size);
+ state_save_register_global_pointer(twincobr_fgvideoram16, twincobr_fgvideoram_size);
+ state_save_register_global_pointer(twincobr_bgvideoram16, twincobr_bgvideoram_size);
+ state_save_register_global(txoffs);
+ state_save_register_global(fgoffs);
+ state_save_register_global(bgoffs);
+ state_save_register_global(scroll_x);
+ state_save_register_global(scroll_y);
+ state_save_register_global(txscrollx);
+ state_save_register_global(fgscrollx);
+ state_save_register_global(bgscrollx);
+ state_save_register_global(txscrolly);
+ state_save_register_global(fgscrolly);
+ state_save_register_global(bgscrolly);
+ state_save_register_global(twincobr_display_on);
+ state_save_register_global(twincobr_fg_rom_bank);
+ state_save_register_global(twincobr_bg_ram_bank);
+ state_save_register_global(twincobr_flip_screen);
+ state_save_register_global(wardner_sprite_hack);
+ state_save_register_func_postload(twincobr_restore_screen);
+}
+
+static void twincobr_restore_screen(void)
+{
+ twincobr_display(twincobr_display_on);
+ twincobr_flipscreen(twincobr_flip_screen);
+}
+
+
+/***************************************************************************
+ Video I/O interface
+***************************************************************************/
+
+void twincobr_display(int enable)
+{
+ twincobr_display_on = enable;
+ tilemap_set_enable(bg_tilemap, enable);
+ tilemap_set_enable(fg_tilemap, enable);
+ tilemap_set_enable(tx_tilemap, enable);
+}
+
+void twincobr_flipscreen(int flip)
+{
+ tilemap_set_flip(ALL_TILEMAPS, (flip ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0));
+ twincobr_flip_screen = flip;
+ if (flip) {
+ scroll_x = -58;
+ scroll_y = -29;
+ if (toaplan_main_cpu == 1) scroll_y += 256; /* Wardner */
+ }
+ else {
+ scroll_x = 55;
+ scroll_y = 30;
+ }
+}
+
+WRITE16_HANDLER( twincobr_crtc_reg_sel_w )
+{
+ crtc6845_address_w(offset, data);
+}
+
+WRITE16_HANDLER( twincobr_crtc_data_w )
+{
+ crtc6845_register_w(offset, data);
+}
+
+WRITE16_HANDLER( twincobr_txoffs_w )
+{
+ COMBINE_DATA(&txoffs);
+ txoffs %= twincobr_txvideoram_size;
+}
+READ16_HANDLER( twincobr_txram_r )
+{
+ return twincobr_txvideoram16[txoffs];
+}
+WRITE16_HANDLER( twincobr_txram_w )
+{
+ COMBINE_DATA(&twincobr_txvideoram16[txoffs]);
+ tilemap_mark_tile_dirty(tx_tilemap,txoffs);
+}
+
+WRITE16_HANDLER( twincobr_bgoffs_w )
+{
+ COMBINE_DATA(&bgoffs);
+ bgoffs %= (twincobr_bgvideoram_size >> 1);
+}
+READ16_HANDLER( twincobr_bgram_r )
+{
+ return twincobr_bgvideoram16[bgoffs+twincobr_bg_ram_bank];
+}
+WRITE16_HANDLER( twincobr_bgram_w )
+{
+ COMBINE_DATA(&twincobr_bgvideoram16[bgoffs+twincobr_bg_ram_bank]);
+ tilemap_mark_tile_dirty(bg_tilemap,(bgoffs+twincobr_bg_ram_bank));
+}
+
+WRITE16_HANDLER( twincobr_fgoffs_w )
+{
+ COMBINE_DATA(&fgoffs);
+ fgoffs %= twincobr_fgvideoram_size;
+}
+READ16_HANDLER( twincobr_fgram_r )
+{
+ return twincobr_fgvideoram16[fgoffs];
+}
+WRITE16_HANDLER( twincobr_fgram_w )
+{
+ COMBINE_DATA(&twincobr_fgvideoram16[fgoffs]);
+ tilemap_mark_tile_dirty(fg_tilemap,fgoffs);
+}
+
+
+WRITE16_HANDLER( twincobr_txscroll_w )
+{
+ if (offset == 0) {
+ COMBINE_DATA(&txscrollx);
+ tilemap_set_scrollx(tx_tilemap,0,(txscrollx+scroll_x) & 0x1ff);
+ }
+ else {
+ COMBINE_DATA(&txscrolly);
+ tilemap_set_scrolly(tx_tilemap,0,(txscrolly+scroll_y) & 0x1ff);
+ }
+}
+
+WRITE16_HANDLER( twincobr_bgscroll_w )
+{
+ if (offset == 0) {
+ COMBINE_DATA(&bgscrollx);
+ tilemap_set_scrollx(bg_tilemap,0,(bgscrollx+scroll_x) & 0x1ff);
+ }
+ else {
+ COMBINE_DATA(&bgscrolly);
+ tilemap_set_scrolly(bg_tilemap,0,(bgscrolly+scroll_y) & 0x1ff);
+ }
+}
+
+WRITE16_HANDLER( twincobr_fgscroll_w )
+{
+ if (offset == 0) {
+ COMBINE_DATA(&fgscrollx);
+ tilemap_set_scrollx(fg_tilemap,0,(fgscrollx+scroll_x) & 0x1ff);
+ }
+ else {
+ COMBINE_DATA(&fgscrolly);
+ tilemap_set_scrolly(fg_tilemap,0,(fgscrolly+scroll_y) & 0x1ff);
+ }
+}
+
+WRITE16_HANDLER( twincobr_exscroll_w ) /* Extra unused video layer */
+{
+ if (offset == 0) logerror("PC - write %04x to unknown video scroll Y register\n",data);
+ else logerror("PC - write %04x to unknown video scroll X register\n",data);
+}
+
+/******************** Wardner interface to this hardware ********************/
+WRITE8_HANDLER( wardner_txlayer_w )
+{
+ int shift = 8 * (offset & 1);
+ twincobr_txoffs_w(offset / 2, data << shift, 0xff00 >> shift);
+}
+
+WRITE8_HANDLER( wardner_bglayer_w )
+{
+ int shift = 8 * (offset & 1);
+ twincobr_bgoffs_w(offset / 2, data << shift, 0xff00 >> shift);
+}
+
+WRITE8_HANDLER( wardner_fglayer_w )
+{
+ int shift = 8 * (offset & 1);
+ twincobr_fgoffs_w(offset / 2, data << shift, 0xff00 >> shift);
+}
+
+WRITE8_HANDLER( wardner_txscroll_w )
+{
+ int shift = 8 * (offset & 1);
+ twincobr_txscroll_w(offset / 2, data << shift, 0xff00 >> shift);
+}
+
+WRITE8_HANDLER( wardner_bgscroll_w )
+{
+ int shift = 8 * (offset & 1);
+ twincobr_bgscroll_w(offset / 2, data << shift, 0xff00 >> shift);
+}
+
+WRITE8_HANDLER( wardner_fgscroll_w )
+{
+ int shift = 8 * (offset & 1);
+ twincobr_fgscroll_w(offset / 2, data << shift, 0xff00 >> shift);
+}
+
+WRITE8_HANDLER( wardner_exscroll_w ) /* Extra unused video layer */
+{
+ switch (offset)
+ {
+ case 01: data <<= 8;
+ case 00: logerror("PC - write %04x to unknown video scroll X register\n",data); break;
+ case 03: data <<= 8;
+ case 02: logerror("PC - write %04x to unknown video scroll Y register\n",data); break;
+ }
+}
+
+READ8_HANDLER( wardner_videoram_r )
+{
+ int shift = 8 * (offset & 1);
+ switch (offset/2) {
+ case 0: return twincobr_txram_r(0,0) >> shift; break;
+ case 1: return twincobr_bgram_r(0,0) >> shift; break;
+ case 2: return twincobr_fgram_r(0,0) >> shift; break;
+ }
+ return 0;
+}
+
+WRITE8_HANDLER( wardner_videoram_w )
+{
+ int shift = 8 * (offset & 1);
+ switch (offset/2) {
+ case 0: twincobr_txram_w(0,data << shift, 0xff00 >> shift); break;
+ case 1: twincobr_bgram_w(0,data << shift, 0xff00 >> shift); break;
+ case 2: twincobr_fgram_w(0,data << shift, 0xff00 >> shift); break;
+ }
+}
+
+READ8_HANDLER( wardner_sprite_r )
+{
+ int shift = (offset & 1) * 8;
+ return spriteram16[offset/2] >> shift;
+}
+
+WRITE8_HANDLER( wardner_sprite_w )
+{
+ if (offset & 1)
+ spriteram16[offset/2] = (spriteram16[offset/2] & 0x00ff) | (data << 8);
+ else
+ spriteram16[offset/2] = (spriteram16[offset/2] & 0xff00) | data;
+}
+
+WRITE8_HANDLER( wardner_CRTC_reg_sel_w )
+{
+ crtc6845_address_w(offset, data);
+}
+
+WRITE8_HANDLER( wardner_CRTC_data_w )
+{
+ crtc6845_register_w(0, data);
+}
+
+
+/***************************************************************************
+ Ugly sprite hack for Wardner when hero is in shop
+***************************************************************************/
+
+static void wardner_sprite_priority_hack(void)
+{
+ if (fgscrollx != bgscrollx) {
+ if ((fgscrollx==0x1c9) || (twincobr_flip_screen && (fgscrollx==0x17a))) { /* in the shop ? */
+ int wardner_hack = buffered_spriteram16[0x0b04/2];
+ /* sprite position 0x6300 to 0x8700 -- hero on shop keeper (normal) */
+ /* sprite position 0x3900 to 0x5e00 -- hero on shop keeper (flip) */
+ if ((wardner_hack > 0x3900) && (wardner_hack < 0x8700)) { /* hero at shop keeper ? */
+ wardner_hack = buffered_spriteram16[0x0b02/2];
+ wardner_hack |= 0x0400; /* make hero top priority */
+ buffered_spriteram16[0x0b02/2] = wardner_hack;
+ wardner_hack = buffered_spriteram16[0x0b0a/2];
+ wardner_hack |= 0x0400;
+ buffered_spriteram16[0x0b0a/2] = wardner_hack;
+ wardner_hack = buffered_spriteram16[0x0b12/2];
+ wardner_hack |= 0x0400;
+ buffered_spriteram16[0x0b12/2] = wardner_hack;
+ wardner_hack = buffered_spriteram16[0x0b1a/2];
+ wardner_hack |= 0x0400;
+ buffered_spriteram16[0x0b1a/2] = wardner_hack;
+ }
+ }
+ }
+}
+
+
+
+#ifdef MAME_DEBUG
+void twincobr_log_vram(void)
+{
+ if ( input_code_pressed(KEYCODE_M) )
+ {
+ offs_t tile_voffs;
+ int tcode[3];
+ while (input_code_pressed(KEYCODE_M)) ;
+ logerror("Scrolls BG-X BG-Y FG-X FG-Y TX-X TX-Y\n");
+ logerror("------> %04x %04x %04x %04x %04x %04x\n",bgscrollx,bgscrolly,fgscrollx,fgscrolly,txscrollx,txscrolly);
+ for ( tile_voffs = 0; tile_voffs < (twincobr_txvideoram_size/2); tile_voffs++ )
+ {
+ tcode[1] = twincobr_bgvideoram16[tile_voffs];
+ tcode[2] = twincobr_fgvideoram16[tile_voffs];
+ tcode[3] = twincobr_txvideoram16[tile_voffs];
+ logerror("$(%04x) (Col-Tile) BG1:%01x-%03x FG1:%01x-%03x TX1:%02x-%03x\n", tile_voffs,
+ tcode[1] & 0xf000 >> 12, tcode[1] & 0x0fff,
+ tcode[2] & 0xf000 >> 12, tcode[2] & 0x0fff,
+ tcode[3] & 0xf800 >> 11, tcode[3] & 0x07ff);
+ }
+ for ( tile_voffs = (twincobr_txvideoram_size/2); tile_voffs < (twincobr_fgvideoram_size/2); tile_voffs++ )
+ {
+ tcode[1] = twincobr_bgvideoram16[tile_voffs];
+ tcode[2] = twincobr_fgvideoram16[tile_voffs];
+ logerror("$(%04x) (Col-Tile) BG1:%01x-%03x FG1:%01x-%03x\n", tile_voffs,
+ tcode[1] & 0xf000 >> 12, tcode[1] & 0x0fff,
+ tcode[2] & 0xf000 >> 12, tcode[2] & 0x0fff);
+ }
+ for ( tile_voffs = (twincobr_fgvideoram_size/2); tile_voffs < (twincobr_bgvideoram_size/2); tile_voffs++ )
+ {
+ tcode[1] = twincobr_bgvideoram16[tile_voffs];
+ logerror("$(%04x) (Col-Tile) BG1:%01x-%03x\n", tile_voffs,
+ tcode[1] & 0xf000 >> 12, tcode[1] & 0x0fff);
+ }
+ }
+}
+#endif
+
+
+/***************************************************************************
+ Sprite Handlers
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority )
+{
+ int offs;
+
+ if (twincobr_display_on)
+ {
+ for (offs = 0;offs < spriteram_size/2;offs += 4)
+ {
+ int attribute,sx,sy,flipx,flipy;
+ int sprite, color;
+
+ attribute = buffered_spriteram16[offs + 1];
+ if ((attribute & 0x0c00) == priority) { /* low priority */
+ sy = buffered_spriteram16[offs + 3] >> 7;
+ if (sy != 0x0100) { /* sx = 0x01a0 or 0x0040*/
+ sprite = buffered_spriteram16[offs] & 0x7ff;
+ color = attribute & 0x3f;
+ sx = buffered_spriteram16[offs + 2] >> 7;
+ flipx = attribute & 0x100;
+ if (flipx) sx -= 14; /* should really be 15 */
+ flipy = attribute & 0x200;
+ drawgfx(bitmap,machine->gfx[3],
+ sprite,
+ color,
+ flipx,flipy,
+ sx-32,sy-16,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+ }
+}
+
+
+/***************************************************************************
+ Draw the game screen in the given mame_bitmap.
+***************************************************************************/
+
+VIDEO_UPDATE( toaplan0 )
+{
+#ifdef MAME_DEBUG
+ twincobr_log_vram();
+#endif
+
+ if (wardner_sprite_hack) wardner_sprite_priority_hack();
+
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ draw_sprites(machine, bitmap,cliprect,0x0400);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect,0x0800);
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect,0x0c00);
+ return 0;
+}
+
+
+VIDEO_EOF( toaplan0 )
+{
+ /* Spriteram is always 1 frame ahead, suggesting spriteram buffering.
+ There are no CPU output registers that control this so we
+ assume it happens automatically every frame, at the end of vblank */
+ buffer_spriteram16_w(0,0,0);
+}
diff --git a/src/mame/video/tx1.c b/src/mame/video/tx1.c
new file mode 100644
index 00000000000..60892a2c532
--- /dev/null
+++ b/src/mame/video/tx1.c
@@ -0,0 +1,406 @@
+/*====================================================================*/
+/* TX-1/Buggy Boy (Tatsumi) Hardware */
+/* Philip J Bennett 2005 */
+/* */
+/* Video Emulation */
+/*====================================================================*/
+
+#include "driver.h"
+
+extern UINT16 *buggyb1_vram;
+extern UINT16 *buggyboy_vram;
+extern UINT16 *bb_objram;
+extern UINT16 *bb_sky;
+
+extern tilemap *buggyb1_tilemap;
+extern tilemap *buggyboy_tilemap;
+extern size_t bb_objectram_size;
+
+
+extern UINT16 *tx1_vram;
+extern UINT16 *tx1_object_ram;
+
+extern tilemap *tx1_tilemap;
+extern size_t tx1_objectram_size;
+
+/*********/
+/* TX-1 */
+/********/
+
+WRITE16_HANDLER( tx1_vram_w )
+{
+ COMBINE_DATA(&tx1_vram[offset]);
+ tilemap_mark_tile_dirty(tx1_tilemap,offset);
+}
+
+static TILE_GET_INFO( get_tx1_tile_info )
+{
+ int tileno = (tx1_vram[tile_index]&0x03ff) | ((tx1_vram[tile_index] & 0x8000) >> 5);
+
+ SET_TILE_INFO(0,tileno,0,0);
+}
+
+VIDEO_START( tx1 )
+{
+ tx1_tilemap = tilemap_create(get_tx1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,128,64);
+ tilemap_set_transparent_pen(tx1_tilemap,0xff);
+}
+
+VIDEO_UPDATE( tx1 )
+{
+ /* the video hardware seems to use one large tilemap, scroll it to the right position for each screen */
+ int xscrollamount = screen*256;
+ tilemap_set_scrollx(tx1_tilemap,0,xscrollamount);
+
+
+ tilemap_draw(bitmap,cliprect,tx1_tilemap,0,0);
+ return 0;
+}
+
+/*************/
+/* Buggy Boy */
+/*************/
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ IC39, BB12 = Blue
+ IC40, BB11 = Green
+ IC41, BB10 = Red
+
+ IC42, BB13 = Brightness
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1.0kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+ bit 0 -- 4.7kohm resistor -- BLUE
+ bit 1 -- 4.7kohm resistor -- GREEN
+ bit 2 -- 4.7kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( buggyboy )
+{
+ int i;
+
+ for (i = 0; i < 256;i++)
+ {
+ int bit0,bit1,bit2,bit3,bit4,r,g,b;
+
+ bit0 = color_prom[i] & 1;
+ bit1 = (color_prom[i] >> 1) & 1;
+ bit2 = (color_prom[i] >> 2) & 1;
+ bit3 = (color_prom[i] >> 3) & 1;
+ bit4 = (color_prom[i+0x300] >> 2) & 1;
+ r = 0x06 * bit4 + 0x0d * bit0 + 0x1e * bit1 + 0x41 * bit2 + 0x8a * bit3;
+
+ bit0 = color_prom[i+0x100] & 1;
+ bit1 = (color_prom[i+0x100] >> 1) & 1;
+ bit2 = (color_prom[i+0x100] >> 2) & 1;
+ bit3 = (color_prom[i+0x100] >> 3) & 1;
+ bit4 = (color_prom[i+0x300] >> 1) & 1;
+ g = 0x06 * bit4 + 0x0d * bit0 + 0x1e * bit1 + 0x41 * bit2 + 0x8a * bit3;
+
+ bit0 = color_prom[i+0x200] & 1;
+ bit1 = (color_prom[i+0x200] >> 1) & 1;
+ bit2 = (color_prom[i+0x200] >> 2) & 1;
+ bit3 = (color_prom[i+0x200] >> 3) & 1;
+ bit4 = (color_prom[i+0x300]) & 1;
+ b = 0x06 * bit4 + 0x0d * bit0 + 0x1e * bit1 + 0x41 * bit2 + 0x8a * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+
+ /** Set up the colour lookups **/
+
+ /* Objects use colours 0-63 */
+ /* There are 2048 palette, however, this is expanded to 8192 */
+
+ for (i = 0; i < 2048; i++)
+ colortable[256+i] = ((0xf-color_prom[i + 0x500]) & 0xf) + 48;
+
+ for (i = 0; i < 2048; i++)
+ colortable[256+2048+i] = ((0xf-color_prom[i + 0x500]) & 0xf) + 32;
+
+ for (i = 0; i < 2048; i++)
+ colortable[256+2048+2048+i] = ((0xf-color_prom[i + 0x500]) & 0xf) + 16;
+
+ /* Only this is used? */
+ for (i = 0; i < 2048; i++)
+ colortable[256+2048+2048+2048+i] = ((0xf-color_prom[i + 0x500]) & 0xf);
+
+ /* Road uses 64-127 */
+ /* Colour PROM only constitutes bits 0-3 - so expand 4-6*/
+ for (i = 0; i < 256; i++)
+ colortable[256+8192+i] = (color_prom[i + 0x1500] & 0xf) + 64;
+
+ for (i = 0; i < 256; i++)
+ colortable[256+8192+256+i] = (color_prom[i + 0x1500] & 0xf) + 64 + 16;
+
+ for (i = 0; i < 256; i++)
+ colortable[256+8192+256*2+i] = (color_prom[i + 0x1500] & 0xf) + 64 + 32;
+
+ for (i = 0; i < 256; i++)
+ colortable[256+8192+256*3+i] = (color_prom[i + 0x1500] & 0xf) + 64 + 48;
+
+ /* Sky uses colours 128-191 directly - no lookup */
+
+ /* Characters use colours 192-255 */
+ for (i = 0; i < 256; i++)
+ colortable[i] = (color_prom[i + 0x400] & 0xf) + 192;
+
+}
+
+
+WRITE16_HANDLER( buggyb1_vram_w )
+{
+ COMBINE_DATA(&buggyb1_vram[offset]);
+ tilemap_mark_tile_dirty(buggyb1_tilemap,offset);
+}
+
+WRITE16_HANDLER( buggyboy_vram_w )
+{
+ COMBINE_DATA(&buggyboy_vram[offset]);
+ tilemap_mark_tile_dirty(buggyboy_tilemap,offset);
+}
+
+
+static TILE_GET_INFO( get_buggyb1_tile_info )
+{
+ int color, tileno;
+
+ color = ((buggyb1_vram[tile_index] >>10) & 0x3f);
+ tileno = (buggyb1_vram[tile_index]&0x03ff) | ((buggyb1_vram[tile_index] & 0x8000) >> 5);
+
+ SET_TILE_INFO(0,tileno,color,0);
+}
+
+static TILE_GET_INFO( get_buggyboy_tile_info )
+{
+ int color, tileno;
+
+ color = ((buggyboy_vram[tile_index] >>10) & 0x3f);
+ tileno = (buggyboy_vram[tile_index]&0x03ff) | ((buggyboy_vram[tile_index] & 0x8000) >> 5);
+
+ SET_TILE_INFO(0,tileno,color,0);
+}
+
+
+/*
+
+ Applies to both versions of Buggy Boy
+
+ Each object entry occupies 16 bytes:
+
+ Byte 0: Sprite code
+ Byte 1: Y-Position (bit 15 has some significance)
+
+ Byte 2: Scale
+ Byte 3: Scale
+
+ Byte 4: Scale 0=Tiny 0x7f=Normal 0xff=Huge ?
+ Byte 5: Bit 7 = X-Flip, Bit 4 = chunk bank, Bit 5-6 = palette select, Bit 0-1 = palette related (PC_TMP)
+
+ Byte 6: Scale
+ Byte 7: Scale
+
+ Byte 8: X position bits 0-7
+ Byte 9: X position bits 8-9
+
+ Remaining bytes are unusued.
+
+*/
+
+/* Rewrite once scale parameters etc. are discovered */
+static void draw_objects(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int xdrawoffset)
+{
+ int offs;
+
+ UINT8 PROM_lookup;
+ UINT16 ROM_lookup;
+
+ UINT8 *rom_lut = (UINT8 *)memory_region(REGION_USER3); /* Object index ROM */
+ UINT8 *prom_lut = (UINT8 *)memory_region(REGION_PROMS)+0x1600; /* Object index PROM */
+
+ UINT8 *ROM_LUTA = (UINT8 *)memory_region(REGION_USER2); /* Object LUT (lower byte) */
+ UINT8 *ROM_LUTB = (UINT8 *)memory_region(REGION_USER2)+0x8000; /* Object LUT (lower byte) */
+ UINT8 *ROM_CLUT = (UINT8 *)memory_region(REGION_USER3)+0x2000; /* Object palette LUT */
+
+ for (offs = 0x0; offs <= (bb_objectram_size)/2; offs += 8)
+ {
+ int inc,last;
+ int bit_12, PSA0_12, PSA, object_flip_x;
+ int index_y,index_x,index=0;
+
+
+ if((bb_objram[offs+0] >> 8) == 0xff) /* End of object list marker? */
+ return;
+
+ /* The object code is fed into ROM and PROM to generate a lookup into a pair of ROMs */
+ PROM_lookup = bb_objram[offs] & 0xff;
+ ROM_lookup = ((bb_objram[offs] & 0xff) << 4) | ((bb_objram[offs+1]>>11) & 0xf);
+
+ if(rom_lut[ROM_lookup] == 0xff) /* Do not draw object */
+ continue;
+
+
+ /* Calculate 13-bit index into object lookup ROMs that holds 8x8 chunk sequence */
+ bit_12 = (((bb_objram[offs]>>7)&0x1) | ((bb_objram[offs]>>6)&0x1)) <<12;
+ PSA0_12 = ( ( (prom_lut[PROM_lookup]&0xf)<<8) | rom_lut[ROM_lookup] | bit_12) & 0x1fff;
+
+ PSA = (PSA0_12 << 2);
+
+ object_flip_x = (bb_objram[offs+2]>>15)&0x1;
+
+ for (index_y=0; index_y<16; index_y++)
+ {
+ if (object_flip_x)
+ {
+ index_x=16;
+ inc=-1;
+ last=0;
+ }
+ else
+ {
+ index_x=0;
+ inc=1;
+ last=16;
+ }
+
+ while(index_x!=last)
+ {
+ /* Bit 14 of chunk_number = data_end, related to end of line */
+ int chunk_number = (ROM_LUTB[PSA+index]<<8) | ROM_LUTA[PSA+index]; // PSBB0-15
+
+ int sx = (bb_objram[offs+4])+(index_x*8);
+ int sy = (bb_objram[offs+0] >> 8)+(index_y*7);
+
+ /* Calculate the 14-bit CLUT ROM address */
+ int bit13 = (bb_objram[offs+2] & 0x1000) << 1;
+ int bit12 = (chunk_number & 0x2000) >> 1;
+
+ /* Tile Number bit 12 -> 1 = Bits 6-7 of BUG16s or bits 8-9 of PC_TMP */
+ int bits6_and_7 = (chunk_number & 0x1000 ? chunk_number : bb_objram[offs+2] >> 2) & 0xc0;
+ int CLUT_ROM_ADDR = (chunk_number & 0xf3f) + bits6_and_7 + bit12 + bit13;
+
+ /* Now form the 12 bit OPCD */
+ int bits10_and_11 = 0xc00 - (bb_objram[offs+2] & 0xc00);
+ int OPCS = (bb_objram[offs+2] & 0x6000) >> 5; // bits 8 and 9
+ int OPCD = (ROM_CLUT[CLUT_ROM_ADDR] + OPCS + bits10_and_11) & 0xfff;
+
+ int tmp = (OPCD&0x7f); // bits 0-6
+ int tmp2= (OPCD&0x300)>>1; // bits 9,8 (bit 7 is not there)
+ int tmp3 = bits10_and_11 >> 1;
+
+ int color = (tmp + tmp2 + tmp3);
+ int trans;
+
+ /* 8x8 chunk ROM bank (0-2) */
+ int bank = (((bb_objram[offs+2]>>11)&0x2) | ((chunk_number>>13)&0x1))+1;
+ int zoomx = 0xffff; //object_ram[offs+6]<<8;
+ int zoomy = 0xffff; //object_ram[offs+4]<<8;
+ int flipx = ((chunk_number>>15) & 0x1) ^ object_flip_x;
+ int flipy = 0;
+
+ const gfx_element *gfx = machine->gfx[bank];
+
+ if(!(OPCD & 0x80)) /* Seems to work! */
+ trans = TRANSPARENCY_PEN;
+ else
+ trans = TRANSPARENCY_NONE;
+
+ index_x+=inc;
+ index++;
+
+ drawgfxzoom(bitmap, gfx,
+ chunk_number,
+ color,
+ flipx,flipy,
+ sx-xdrawoffset,sy,
+ cliprect,trans,0,
+ zoomx,zoomy);
+ }
+ }
+ }
+}
+
+
+VIDEO_START( buggyb1 )
+{
+ buggyb1_tilemap = tilemap_create(get_buggyb1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,64);
+ tilemap_set_transparent_pen(buggyb1_tilemap, 0);
+}
+
+
+VIDEO_START( buggyboy )
+{
+ buggyboy_tilemap = tilemap_create(get_buggyboy_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,128,64);
+ tilemap_set_transparent_pen(buggyboy_tilemap, 0);
+}
+
+
+
+/* Gradient sky - 'scrolls' up and down */
+static void draw_sky(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int x,y,colour;
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ colour = (((*bb_sky & 0x7f) + y)>>2)&0x3f;
+ *BITMAP_ADDR16(bitmap, y, x) = machine->pens[0x80 + colour];
+ }
+ }
+}
+
+
+/*
+The current layer mixing implementation is incorrect.
+
+On the actual PCB, the GAME OVER sign chains should be behind the text but the
+objects are often in front of the characters.
+
+See schematic page 11 for mixing logic.
+
+*/
+
+
+VIDEO_UPDATE( buggyb1 )
+{
+ if(*bb_sky & 0x80)
+ {
+ draw_sky(machine, bitmap, cliprect);
+ tilemap_draw(bitmap,cliprect,buggyb1_tilemap,0,0);
+ draw_objects(machine, bitmap,cliprect,0);
+ }
+ else
+ {
+ tilemap_draw(bitmap,cliprect,buggyb1_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ draw_objects(machine, bitmap,cliprect,0);
+ }
+ return 0;
+}
+
+VIDEO_UPDATE( buggyboy )
+{
+ /* the video hardware seems to use one large tilemap, scroll it to the right position for each screen */
+ int xscrollamount = screen*256;
+ tilemap_set_scrollx(buggyboy_tilemap,0,xscrollamount);
+
+ if(*bb_sky & 0x80)
+ {
+ draw_sky(machine, bitmap, cliprect);
+ tilemap_draw(bitmap,cliprect,buggyboy_tilemap,0,0);
+ draw_objects(machine, bitmap,cliprect,xscrollamount);
+ }
+ else
+ {
+ tilemap_draw(bitmap,cliprect,buggyboy_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ draw_objects(machine, bitmap,cliprect,xscrollamount);
+ }
+ return 0;
+}
diff --git a/src/mame/video/ultraman.c b/src/mame/video/ultraman.c
new file mode 100644
index 00000000000..7262146a21b
--- /dev/null
+++ b/src/mame/video/ultraman.c
@@ -0,0 +1,135 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+#define SPRITEROM_MEM_REGION REGION_GFX1
+#define ZOOMROM0_MEM_REGION REGION_GFX2
+#define ZOOMROM1_MEM_REGION REGION_GFX3
+#define ZOOMROM2_MEM_REGION REGION_GFX4
+
+static int sprite_colorbase, zoom_colorbase[3];
+static int bank0,bank1,bank2;
+
+
+/***************************************************************************
+
+ Callbacks for the K051960
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority,int *shadow)
+{
+ *priority = (*color & 0x80) >> 7;
+ *color = sprite_colorbase + ((*color & 0x7e) >> 1);
+ *shadow = 0;
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K051316
+
+***************************************************************************/
+
+static void zoom_callback_0(int *code,int *color,int *flags)
+{
+ *code |= ((*color & 0x07) << 8) | (bank0 << 11);
+ *color = zoom_colorbase[0] + ((*color & 0xf8) >> 3);
+}
+
+static void zoom_callback_1(int *code,int *color,int *flags)
+{
+ *code |= ((*color & 0x07) << 8) | (bank1 << 11);
+ *color = zoom_colorbase[1] + ((*color & 0xf8) >> 3);
+}
+
+static void zoom_callback_2(int *code,int *color,int *flags)
+{
+ *code |= ((*color & 0x07) << 8) | (bank2 << 11);
+ *color = zoom_colorbase[2] + ((*color & 0xf8) >> 3);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( ultraman )
+{
+ sprite_colorbase = 192;
+ zoom_colorbase[0] = 0;
+ zoom_colorbase[1] = 64;
+ zoom_colorbase[2] = 128;
+
+ K051960_vh_start(machine,SPRITEROM_MEM_REGION,NORMAL_PLANE_ORDER,sprite_callback);
+ K051316_vh_start_0(machine,ZOOMROM0_MEM_REGION,4,FALSE,0,zoom_callback_0);
+ K051316_vh_start_1(machine,ZOOMROM1_MEM_REGION,4,FALSE,0,zoom_callback_1);
+ K051316_vh_start_2(machine,ZOOMROM2_MEM_REGION,4,TRUE,0,zoom_callback_2);
+
+ K051316_set_offset(0, 8, 0);
+ K051316_set_offset(1, 8, 0);
+ K051316_set_offset(2, 8, 0);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( ultraman_gfxctrl_w )
+{
+ if (ACCESSING_LSB)
+ {
+ /* bit 0: enable wraparound for scr #1
+ bit 1: msb of code for scr #1
+ bit 2: enable wraparound for scr #2
+ bit 3: msb of code for scr #2
+ bit 4: enable wraparound for scr #3
+ bit 5: msb of code for scr #3
+ bit 6: coin counter 1
+ bit 7: coin counter 2 */
+ K051316_wraparound_enable(0,data & 0x01);
+ if (bank0 != ((data & 0x02) >> 1))
+ {
+ bank0 = (data & 0x02) >> 1;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS); /* should mark only zoom0 */
+ }
+ K051316_wraparound_enable(1,data & 0x04);
+ if (bank1 != ((data & 0x08) >> 3))
+ {
+ bank1 = (data & 0x08) >> 3;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS); /* should mark only zoom1 */
+ }
+ K051316_wraparound_enable(2,data & 0x10);
+ if (bank2 != ((data & 0x20) >> 5))
+ {
+ bank2 = (data & 0x20) >> 5;
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS); /* should mark only zoom2 */
+ }
+ coin_counter_w(0, data & 0x40);
+ coin_counter_w(1, data & 0x80);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( ultraman )
+{
+ K051316_zoom_draw_2(bitmap,cliprect,0,0);
+ K051316_zoom_draw_1(bitmap,cliprect,0,0);
+ K051960_sprites_draw(bitmap,cliprect,0,0);
+ K051316_zoom_draw_0(bitmap,cliprect,0,0);
+ K051960_sprites_draw(bitmap,cliprect,1,1);
+ return 0;
+}
diff --git a/src/mame/video/ultratnk.c b/src/mame/video/ultratnk.c
new file mode 100644
index 00000000000..214794fc1ea
--- /dev/null
+++ b/src/mame/video/ultratnk.c
@@ -0,0 +1,164 @@
+/***************************************************************************
+
+Atari Ultra Tank video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+#include "ultratnk.h"
+#include "audio/sprint4.h"
+
+static tilemap* playfield;
+
+static mame_bitmap* helper;
+
+int ultratnk_collision[4];
+
+
+PALETTE_INIT( ultratnk )
+{
+ palette_set_color(machine, 0, MAKE_RGB(0x00, 0x00, 0x00));
+ palette_set_color(machine, 1, MAKE_RGB(0xa4, 0xa4, 0xa4));
+ palette_set_color(machine, 2, MAKE_RGB(0x5b, 0x5b, 0x5b));
+ palette_set_color(machine, 3, MAKE_RGB(0xff, 0xff, 0xff));
+
+ colortable[0] = color_prom[0x00] & 3;
+ colortable[2] = color_prom[0x00] & 3;
+ colortable[4] = color_prom[0x00] & 3;
+ colortable[6] = color_prom[0x00] & 3;
+ colortable[8] = color_prom[0x00] & 3;
+
+ colortable[1] = color_prom[0x01] & 3;
+ colortable[3] = color_prom[0x02] & 3;
+ colortable[5] = color_prom[0x04] & 3;
+ colortable[7] = color_prom[0x08] & 3;
+ colortable[9] = color_prom[0x10] & 3;
+}
+
+
+static TILE_GET_INFO( ultratnk_tile_info )
+{
+ UINT8 code = videoram[tile_index];
+
+ if (code & 0x20)
+ {
+ SET_TILE_INFO(0, code, code >> 6, 0);
+ }
+ else
+ {
+ SET_TILE_INFO(0, code, 4, 0);
+ }
+}
+
+
+VIDEO_START( ultratnk )
+{
+ helper = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ playfield = tilemap_create(ultratnk_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+
+VIDEO_UPDATE( ultratnk )
+{
+ int i;
+
+ tilemap_draw(bitmap, cliprect, playfield, 0, 0);
+
+ for (i = 0; i < 4; i++)
+ {
+ int bank = 0;
+
+ UINT8 horz = videoram[0x390 + 2 * i + 0];
+ UINT8 attr = videoram[0x390 + 2 * i + 1];
+ UINT8 vert = videoram[0x398 + 2 * i + 0];
+ UINT8 code = videoram[0x398 + 2 * i + 1];
+
+ if (code & 4)
+ {
+ bank = 32;
+ }
+
+ if (!(attr & 0x80))
+ {
+ drawgfx(bitmap, machine->gfx[1],
+ (code >> 3) | bank,
+ i,
+ 0, 0,
+ horz - 15,
+ vert - 15,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+ }
+
+ return 0;
+}
+
+
+VIDEO_EOF( ultratnk )
+{
+ UINT16 BG = machine->remapped_colortable[machine->gfx[0]->color_base];
+
+ int i;
+
+ /* check for sprite-playfield collisions */
+
+ for (i = 0; i < 4; i++)
+ {
+ rectangle rect;
+
+ int x;
+ int y;
+
+ int bank = 0;
+
+ UINT8 horz = videoram[0x390 + 2 * i + 0];
+ UINT8 vert = videoram[0x398 + 2 * i + 0];
+ UINT8 code = videoram[0x398 + 2 * i + 1];
+
+ rect.min_x = horz - 15;
+ rect.min_y = vert - 15;
+ rect.max_x = horz - 15 + machine->gfx[1]->width - 1;
+ rect.max_y = vert - 15 + machine->gfx[1]->height - 1;
+
+ sect_rect(&rect, &machine->screen[0].visarea);
+
+ tilemap_draw(helper, &rect, playfield, 0, 0);
+
+ if (code & 4)
+ {
+ bank = 32;
+ }
+
+ drawgfx(helper, machine->gfx[1],
+ (code >> 3) | bank,
+ 4,
+ 0, 0,
+ horz - 15,
+ vert - 15,
+ &rect, TRANSPARENCY_PEN, 1);
+
+ for (y = rect.min_y; y <= rect.max_y; y++)
+ {
+ for (x = rect.min_x; x <= rect.max_x; x++)
+ {
+ if (*BITMAP_ADDR16(helper, y, x) != BG)
+ {
+ ultratnk_collision[i] = 1;
+ }
+ }
+ }
+ }
+
+ /* update sound status */
+
+ discrete_sound_w(ULTRATNK_MOTOR_DATA_1, videoram[0x391] & 15);
+ discrete_sound_w(ULTRATNK_MOTOR_DATA_2, videoram[0x393] & 15);
+}
+
+
+WRITE8_HANDLER( ultratnk_video_ram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(playfield, offset);
+}
diff --git a/src/mame/video/undrfire.c b/src/mame/video/undrfire.c
new file mode 100644
index 00000000000..80bba563bd0
--- /dev/null
+++ b/src/mame/video/undrfire.c
@@ -0,0 +1,371 @@
+#include "driver.h"
+#include "video/taitoic.h"
+
+#define TC0100SCN_GFX_NUM 2
+#define TC0480SCP_GFX_NUM 1
+
+UINT16 undrfire_rotate_ctrl[8];
+
+struct tempsprite
+{
+ int gfx;
+ int code,color;
+ int flipx,flipy;
+ int x,y;
+ int zoomx,zoomy;
+ int primask;
+};
+static struct tempsprite *spritelist;
+
+
+/******************************************************************/
+
+VIDEO_START( undrfire )
+{
+ int i;
+
+ spritelist = auto_malloc(0x4000 * sizeof(*spritelist));
+
+ TC0100SCN_vh_start(machine,1,TC0100SCN_GFX_NUM,50,8,0,0,0,0,0);
+ TC0480SCP_vh_start(machine,TC0480SCP_GFX_NUM,0,0x24,0,-1,0,0,0,0);
+
+ for (i=0; i<16384; i++) /* Fix later - some weird colours in places */
+ palette_set_color(machine,i,MAKE_RGB(0,0,0));
+}
+
+/***************************************************************
+ SPRITE DRAW ROUTINES
+
+We draw a series of small tiles ("chunks") together to
+create each big sprite. The spritemap rom provides the lookup
+table for this. The game hardware looks up 16x16 sprite chunks
+from the spritemap rom, creating a 64x64 sprite like this:
+
+ 0 1 2 3
+ 4 5 6 7
+ 8 9 10 11
+ 12 13 14 15
+
+(where the number is the word offset into the spritemap rom).
+It can also create 32x32 sprites.
+
+NB: unused portions of the spritemap rom contain hex FF's.
+It is a useful coding check to warn in the log if these
+are being accessed. [They can be inadvertently while
+spriteram is being tested, take no notice of that.]
+
+Heavy use is made of sprite zooming.
+
+ ***
+
+ Sprite table layout (4 long words per entry)
+
+ ------------------------------------------
+ 0 | ........ x....... ........ ........ | Flip X
+ 0 | ........ .xxxxxxx ........ ........ | ZoomX
+ 0 | ........ ........ .xxxxxxx xxxxxxxx | Sprite Tile
+ | |
+ 2 | ........ ....xx.. ........ ........ | Sprite/tile priority [*]
+ 2 | ........ ......xx xxxxxx.. ........ | Palette bank
+ 2 | ........ ........ ......xx xxxxxxxx | X position
+ | |
+ 3 | ........ .....x.. ........ ........ | Sprite size (0=32x32, 1=64x64)
+ 3 | ........ ......x. ........ ........ | Flip Y
+ 3 | ........ .......x xxxxxx.. ........ | ZoomY
+ 3 | ........ ........ ......xx xxxxxxxx | Y position
+ ------------------------------------------
+
+ [* 00=over BG0, 01=BG1, 10=BG2, 11=BG3 ]
+ [or 00=over BG1, 01=BG2, 10=BG3, 11=BG3 ]
+
+***************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,const int *primasks,int x_offs,int y_offs)
+{
+ UINT16 *spritemap = (UINT16 *)memory_region(REGION_USER1);
+ int offs, data, tilenum, color, flipx, flipy;
+ int x, y, priority, dblsize, curx, cury;
+ int sprites_flipscreen = 0;
+ int zoomx, zoomy, zx, zy;
+ int sprite_chunk,map_offset,code,j,k,px,py;
+ int dimension,total_chunks,bad_chunks;
+
+ /* pdrawgfx() needs us to draw sprites front to back, so we have to build a list
+ while processing sprite ram and then draw them all at the end */
+ struct tempsprite *sprite_ptr = spritelist;
+
+ for (offs = (spriteram_size/4-4);offs >= 0;offs -= 4)
+ {
+ data = spriteram32[offs+0];
+ flipx = (data & 0x00800000) >> 23;
+ zoomx = (data & 0x007f0000) >> 16;
+ tilenum = (data & 0x00007fff);
+
+ data = spriteram32[offs+2];
+ priority = (data & 0x000c0000) >> 18;
+ color = (data & 0x0003fc00) >> 10;
+ x = (data & 0x000003ff);
+
+ data = spriteram32[offs+3];
+ dblsize = (data & 0x00040000) >> 18;
+ flipy = (data & 0x00020000) >> 17;
+ zoomy = (data & 0x0001fc00) >> 10;
+ y = (data & 0x000003ff);
+
+ color |= (0x100 + (priority << 6)); /* priority bits select color bank */
+ color /= 2; /* as sprites are 5bpp */
+ flipy = !flipy;
+ y = (-y &0x3ff);
+
+ if (!tilenum) continue;
+
+ flipy = !flipy;
+ zoomx += 1;
+ zoomy += 1;
+
+ y += y_offs;
+
+ /* treat coords as signed */
+ if (x>0x340) x -= 0x400;
+ if (y>0x340) y -= 0x400;
+
+ x -= x_offs;
+
+ bad_chunks = 0;
+ dimension = ((dblsize*2) + 2); // 2 or 4
+ total_chunks = ((dblsize*3) + 1) << 2; // 4 or 16
+ map_offset = tilenum << 2;
+
+ {
+ for (sprite_chunk=0;sprite_chunk<total_chunks;sprite_chunk++)
+ {
+ j = sprite_chunk / dimension; /* rows */
+ k = sprite_chunk % dimension; /* chunks per row */
+
+ px = k;
+ py = j;
+ /* pick tiles back to front for x and y flips */
+ if (flipx) px = dimension-1-k;
+ if (flipy) py = dimension-1-j;
+
+ code = spritemap[map_offset + px + (py<<(dblsize+1))];
+
+ if (code==0xffff)
+ {
+ bad_chunks += 1;
+ continue;
+ }
+
+ curx = x + ((k*zoomx)/dimension);
+ cury = y + ((j*zoomy)/dimension);
+
+ zx= x + (((k+1)*zoomx)/dimension) - curx;
+ zy= y + (((j+1)*zoomy)/dimension) - cury;
+
+ if (sprites_flipscreen)
+ {
+ /* -zx/y is there to fix zoomed sprite coords in screenflip.
+ drawgfxzoom does not know to draw from flip-side of sprites when
+ screen is flipped; so we must correct the coords ourselves. */
+
+ curx = 320 - curx - zx;
+ cury = 256 - cury - zy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ sprite_ptr->gfx = 0;
+ sprite_ptr->code = code;
+ sprite_ptr->color = color;
+ sprite_ptr->flipx = !flipx;
+ sprite_ptr->flipy = flipy;
+ sprite_ptr->x = curx;
+ sprite_ptr->y = cury;
+ sprite_ptr->zoomx = zx << 12;
+ sprite_ptr->zoomy = zy << 12;
+
+ if (primasks)
+ {
+ sprite_ptr->primask = primasks[priority];
+
+ sprite_ptr++;
+ }
+ else
+ {
+ drawgfxzoom(bitmap,machine->gfx[sprite_ptr->gfx],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,TRANSPARENCY_PEN,0,
+ sprite_ptr->zoomx,sprite_ptr->zoomy);
+ }
+ }
+ }
+
+ if (bad_chunks)
+logerror("Sprite number %04x had %02x invalid chunks\n",tilenum,bad_chunks);
+ }
+
+ /* this happens only if primsks != NULL */
+ while (sprite_ptr != spritelist)
+ {
+ sprite_ptr--;
+
+ pdrawgfxzoom(bitmap,machine->gfx[sprite_ptr->gfx],
+ sprite_ptr->code,
+ sprite_ptr->color,
+ sprite_ptr->flipx,sprite_ptr->flipy,
+ sprite_ptr->x,sprite_ptr->y,
+ cliprect,TRANSPARENCY_PEN,0,
+ sprite_ptr->zoomx,sprite_ptr->zoomy,
+ sprite_ptr->primask);
+ }
+}
+
+/**************************************************************
+ SCREEN REFRESH
+**************************************************************/
+
+VIDEO_UPDATE( undrfire )
+{
+ UINT8 layer[5];
+ UINT8 pivlayer[3];
+ UINT16 priority;
+
+#ifdef MAME_DEBUG
+ static UINT8 dislayer[6]; /* Layer toggles to help get layers correct */
+#endif
+
+#ifdef MAME_DEBUG
+ if (input_code_pressed_once (KEYCODE_X))
+ {
+ dislayer[5] ^= 1;
+ popmessage("piv text: %01x",dislayer[5]);
+ }
+ if (input_code_pressed_once (KEYCODE_C))
+ {
+ dislayer[0] ^= 1;
+ popmessage("bg0: %01x",dislayer[0]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_V))
+ {
+ dislayer[1] ^= 1;
+ popmessage("bg1: %01x",dislayer[1]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_B))
+ {
+ dislayer[2] ^= 1;
+ popmessage("bg2: %01x",dislayer[2]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_N))
+ {
+ dislayer[3] ^= 1;
+ popmessage("bg3: %01x",dislayer[3]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_M))
+ {
+ dislayer[4] ^= 1;
+ popmessage("sprites: %01x",dislayer[4]);
+ }
+#endif
+
+ TC0100SCN_tilemap_update(machine);
+ TC0480SCP_tilemap_update(machine);
+
+ priority = TC0480SCP_get_bg_priority();
+
+ layer[0] = (priority &0xf000) >> 12; /* tells us which bg layer is bottom */
+ layer[1] = (priority &0x0f00) >> 8;
+ layer[2] = (priority &0x00f0) >> 4;
+ layer[3] = (priority &0x000f) >> 0; /* tells us which is top */
+ layer[4] = 4; /* text layer always over bg layers */
+
+ pivlayer[0] = TC0100SCN_bottomlayer(0);
+ pivlayer[1] = pivlayer[0]^1;
+ pivlayer[2] = 2;
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ fillbitmap(bitmap,machine->pens[0],cliprect); /* wrong color? */
+
+
+/* The "PIV" chip seems to be a renamed TC0100SCN. It has a
+ bottom layer usually full of bright garish colors that
+ vaguely mimic the structure of the layers on top. Seems
+ pointless - it's always hidden by other layers. Does it
+ serve some blending pupose ? */
+
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,pivlayer[0],0,0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,pivlayer[1],0,0);
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[0]]==0)
+#endif
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[0],0,1);
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[1]]==0)
+#endif
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[1],0,2);
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[2]]==0)
+#endif
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[2],0,4);
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[3]]==0)
+#endif
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[3],0,8);
+
+#ifdef MAME_DEBUG
+ if (dislayer[4]==0)
+#endif
+ /* Sprites have variable priority (we kludge this on road levels) */
+ {
+ if ((TC0480SCP_pri_reg &0x3) == 3) /* on road levels kludge sprites up 1 priority */
+ {
+ static const int primasks[4] = {0xfff0, 0xff00, 0x0, 0x0};
+ draw_sprites(machine, bitmap,cliprect,primasks,44,-574);
+ }
+ else
+ {
+ static const int primasks[4] = {0xfffc, 0xfff0, 0xff00, 0x0};
+ draw_sprites(machine, bitmap,cliprect,primasks,44,-574);
+ }
+ }
+
+#ifdef MAME_DEBUG
+ if (dislayer[5]==0)
+#endif
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,pivlayer[2],0,0); /* piv text layer */
+
+ TC0480SCP_tilemap_draw(bitmap,cliprect,layer[4],0,0); /* TC0480SCP text layer */
+
+ /* See if we should draw artificial gun targets */
+ /* (not yet implemented...) */
+
+ if (input_port_7_word_r(0,0) & 0x1) /* Fake DSW */
+ {
+ popmessage("Gunsights on");
+ }
+
+/* Enable this to see rotation (?) control words */
+#if 0
+ {
+ char buf[80];
+ int i;
+
+ for (i = 0; i < 8; i += 1)
+ {
+ sprintf (buf, "%02x: %04x", i, undrfire_rotate_ctrl[i]);
+ ui_draw_text (buf, 0, i*8);
+ }
+ }
+#endif
+ return 0;
+}
diff --git a/src/mame/video/unico.c b/src/mame/video/unico.c
new file mode 100644
index 00000000000..1db9b9f3b69
--- /dev/null
+++ b/src/mame/video/unico.c
@@ -0,0 +1,412 @@
+/***************************************************************************
+
+ -= Unico Games =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z with:
+
+ Q / W / E Shows Layer 0 / 1 / 2
+ A Shows Sprites
+
+ Keys can be used together!
+
+
+ [ 3 Scrolling Layers ]
+
+ Tile Size: 16 x 16 x 8
+ Layer Size (tiles): 64 x 64
+
+ [ 512 Sprites ]
+
+ Sprites are made of 16 x 16 x 8 tiles. Size can vary from 1 to
+ 16 tiles horizontally, while their height is always 1 tile.
+ There seems to be 4 levels of priority (wrt layers) for each
+ sprite, following this simple scheme:
+
+ [if we denote the three layers with 0-3 (0 being the backmost)
+ and the sprite with S]
+
+ Sprite Priority Order (back -> front)
+ 0 S 0 1 2
+ 1 0 S 1 2
+ 2 0 1 S 2
+ 3 0 1 2 S
+
+***************************************************************************/
+
+#include "driver.h"
+#include "unico.h"
+
+/* Variables needed by drivers: */
+
+UINT16 *unico_vram_0, *unico_scrollx_0, *unico_scrolly_0;
+UINT16 *unico_vram_1, *unico_scrollx_1, *unico_scrolly_1;
+UINT16 *unico_vram_2, *unico_scrollx_2, *unico_scrolly_2;
+UINT32 *unico_vram32_0, *unico_vram32_1, *unico_vram32_2, *unico_scroll32;
+
+
+/***************************************************************************
+
+ Palette
+
+ Byte: 0 1 2 3
+ Gun: R G B 0
+
+ 6 Bits x Gun
+
+***************************************************************************/
+
+WRITE16_HANDLER( unico_palette_w )
+{
+ UINT16 data1, data2;
+ COMBINE_DATA(&paletteram16[offset]);
+ data1 = paletteram16[offset & ~1];
+ data2 = paletteram16[offset | 1];
+ palette_set_color_rgb( Machine,offset/2,
+ (data1 >> 8) & 0xFC,
+ (data1 >> 0) & 0xFC,
+ (data2 >> 8) & 0xFC );
+}
+
+WRITE32_HANDLER( unico_palette32_w )
+{
+ UINT32 rgb0 = COMBINE_DATA(&paletteram32[offset]);
+ palette_set_color_rgb( Machine,offset,
+ (rgb0 >> 24) & 0xFC,
+ (rgb0 >> 16) & 0xFC,
+ (rgb0 >> 8) & 0xFC );
+}
+
+
+/***************************************************************************
+
+ Tilemaps
+
+ Offset: Bits: Value:
+
+ 0.w Code
+ 2.w fedc ba98 7--- ----
+ ---- ---- -6-- ---- Flip Y
+ ---- ---- --5- ---- Flip X
+ ---- ---- ---4 3210 Color
+
+***************************************************************************/
+
+#define LAYER( _N_ ) \
+static tilemap *tilemap_##_N_; \
+\
+static TILE_GET_INFO( get_tile_info_##_N_ ) \
+{ \
+ UINT16 code = unico_vram_##_N_[ 2 * tile_index + 0 ]; \
+ UINT16 attr = unico_vram_##_N_[ 2 * tile_index + 1 ]; \
+ SET_TILE_INFO(1, code, attr & 0x1f, TILE_FLIPYX( attr >> 5 )); \
+} \
+\
+static TILE_GET_INFO( get_tile_info32_##_N_ ) \
+{ \
+ UINT32 code = unico_vram32_##_N_[tile_index]; \
+ SET_TILE_INFO(1, code >> 16, code & 0x1f, TILE_FLIPYX( code >> 5 )); \
+} \
+\
+WRITE16_HANDLER( unico_vram_##_N_##_w ) \
+{ \
+ COMBINE_DATA(&unico_vram_##_N_[offset]); \
+ tilemap_mark_tile_dirty(tilemap_##_N_,offset/2); \
+} \
+\
+WRITE32_HANDLER( unico_vram32_##_N_##_w ) \
+{ \
+ COMBINE_DATA(&unico_vram32_##_N_[offset]); \
+ tilemap_mark_tile_dirty(tilemap_##_N_,offset); \
+}
+
+LAYER( 0 )
+LAYER( 1 )
+LAYER( 2 )
+
+
+
+/***************************************************************************
+
+
+ Video Hardware Init
+
+
+***************************************************************************/
+
+static int sprites_scrolldx, sprites_scrolldy;
+
+VIDEO_START( unico )
+{
+ tilemap_0 = tilemap_create( get_tile_info_0,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 0x40, 0x40);
+
+ tilemap_1 = tilemap_create( get_tile_info_1,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 0x40, 0x40);
+
+ tilemap_2 = tilemap_create( get_tile_info_2,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 0x40, 0x40);
+
+ sprites_scrolldx = -0x3f;
+ sprites_scrolldy = -0x0e;
+
+ tilemap_set_scrolldx(tilemap_0,-0x32,0);
+ tilemap_set_scrolldx(tilemap_1,-0x30,0);
+ tilemap_set_scrolldx(tilemap_2,-0x2e,0);
+
+ tilemap_set_scrolldy(tilemap_0,-0x0f,0);
+ tilemap_set_scrolldy(tilemap_1,-0x0f,0);
+ tilemap_set_scrolldy(tilemap_2,-0x0f,0);
+
+ tilemap_set_transparent_pen(tilemap_0,0x00);
+ tilemap_set_transparent_pen(tilemap_1,0x00);
+ tilemap_set_transparent_pen(tilemap_2,0x00);
+}
+
+VIDEO_START( zeropnt2 )
+{
+ tilemap_0 = tilemap_create( get_tile_info32_0,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 0x40, 0x40);
+
+ tilemap_1 = tilemap_create( get_tile_info32_1,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 0x40, 0x40);
+
+ tilemap_2 = tilemap_create( get_tile_info32_2,tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 16,16, 0x40, 0x40);
+
+ sprites_scrolldx = -0x3f;
+ sprites_scrolldy = -0x0e;
+
+ tilemap_set_scrolldx(tilemap_0,-0x32,0);
+ tilemap_set_scrolldx(tilemap_1,-0x30,0);
+ tilemap_set_scrolldx(tilemap_2,-0x2e,0);
+
+ tilemap_set_scrolldy(tilemap_0,-0x0f,0);
+ tilemap_set_scrolldy(tilemap_1,-0x0f,0);
+ tilemap_set_scrolldy(tilemap_2,-0x0f,0);
+
+ tilemap_set_transparent_pen(tilemap_0,0x00);
+ tilemap_set_transparent_pen(tilemap_1,0x00);
+ tilemap_set_transparent_pen(tilemap_2,0x00);
+}
+
+
+
+/***************************************************************************
+
+ Sprites Drawing
+
+
+ 0.w X
+
+ 2.w Y
+
+ 4.w Code
+
+ 6.w fe-- ---- ---- ----
+ --dc ---- ---- ---- Priority
+ ---- ba98 ---- ---- Number of tiles along X, minus 1
+ ---- ---- 7--- ----
+ ---- ---- -6-- ---- Flip Y?
+ ---- ---- --5- ---- Flip X
+ ---- ---- ---4 3210 Color
+
+
+***************************************************************************/
+
+static void unico_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ /* Draw them backwards, for pdrawgfx */
+ for ( offs = (spriteram_size-8)/2; offs >= 0 ; offs -= 8/2 )
+ {
+ int x, startx, endx, incx;
+
+ int sx = spriteram16[ offs + 0 ];
+ int sy = spriteram16[ offs + 1 ];
+ int code = spriteram16[ offs + 2 ];
+ int attr = spriteram16[ offs + 3 ];
+
+ int flipx = attr & 0x020;
+ int flipy = attr & 0x040; // not sure
+
+ int dimx = ((attr >> 8) & 0xf) + 1;
+
+ int priority = ((attr >> 12) & 0x3);
+ int pri_mask;
+
+ switch( priority )
+ {
+ case 0: pri_mask = 0xfe; break; // below all
+ case 1: pri_mask = 0xf0; break; // above layer 0
+ case 2: pri_mask = 0xfc; break; // above layer 1
+ default:
+ case 3: pri_mask = 0x00; // above all
+ }
+
+ sx += sprites_scrolldx;
+ sy += sprites_scrolldy;
+
+ sx = (sx & 0x1ff) - (sx & 0x200);
+ sy = (sy & 0x1ff) - (sy & 0x200);
+
+ if (flipx) { startx = sx+(dimx-1)*16; endx = sx-16; incx = -16; }
+ else { startx = sx; endx = sx+dimx*16; incx = +16; }
+
+ for (x = startx ; x != endx ; x += incx)
+ {
+ pdrawgfx( bitmap, machine->gfx[0],
+ code++,
+ attr & 0x1f,
+ flipx, flipy,
+ x, sy,
+ cliprect, TRANSPARENCY_PEN,0x00,
+ pri_mask );
+ }
+ }
+}
+
+static void zeropnt2_draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ /* Draw them backwards, for pdrawgfx */
+ for ( offs = (spriteram_size-8)/4; offs >= 0 ; offs -= 8/4 )
+ {
+ int x, startx, endx, incx;
+
+ int sx = spriteram32[ offs + 0 ] >> 16;
+ int sy = spriteram32[ offs + 0 ] & 0xffff;
+ int code = spriteram32[ offs + 1 ] >> 16;
+ int attr = spriteram32[ offs + 1 ] & 0xffff;
+
+ int flipx = attr & 0x020;
+ int flipy = attr & 0x040; // not sure
+
+ int dimx = ((attr >> 8) & 0xf) + 1;
+
+ int priority = ((attr >> 12) & 0x3);
+ int pri_mask;
+
+ switch( priority )
+ {
+ case 0: pri_mask = 0xfe; break; // below all
+ case 1: pri_mask = 0xf0; break; // above layer 0
+ case 2: pri_mask = 0xfc; break; // above layer 1
+ default:
+ case 3: pri_mask = 0x00; // above all
+ }
+
+ sx += sprites_scrolldx;
+ sy += sprites_scrolldy;
+
+ sx = (sx & 0x1ff) - (sx & 0x200);
+ sy = (sy & 0x1ff) - (sy & 0x200);
+
+ if (flipx) { startx = sx+(dimx-1)*16; endx = sx-16; incx = -16; }
+ else { startx = sx; endx = sx+dimx*16; incx = +16; }
+
+ for (x = startx ; x != endx ; x += incx)
+ {
+ pdrawgfx( bitmap, machine->gfx[0],
+ code++,
+ attr & 0x1f,
+ flipx, flipy,
+ x, sy,
+ cliprect, TRANSPARENCY_PEN,0x00,
+ pri_mask );
+ }
+ }
+}
+
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+VIDEO_UPDATE( unico )
+{
+ int layers_ctrl = -1;
+
+ tilemap_set_scrollx(tilemap_0, 0, *unico_scrollx_0);
+ tilemap_set_scrolly(tilemap_0, 0, *unico_scrolly_0);
+
+ tilemap_set_scrollx(tilemap_1, 0, *unico_scrollx_1);
+ tilemap_set_scrolly(tilemap_1, 0, *unico_scrolly_1);
+
+ tilemap_set_scrolly(tilemap_2, 0, *unico_scrolly_2);
+ tilemap_set_scrollx(tilemap_2, 0, *unico_scrollx_2);
+
+#ifdef MAME_DEBUG
+if ( input_code_pressed(KEYCODE_Z) || input_code_pressed(KEYCODE_X) )
+{
+ int msk = 0;
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+ if (input_code_pressed(KEYCODE_E)) msk |= 4;
+ if (input_code_pressed(KEYCODE_A)) msk |= 8;
+ if (msk != 0) layers_ctrl &= msk;
+}
+#endif
+
+ /* The background color is the first of the last palette */
+ fillbitmap(bitmap,machine->pens[0x1f00],cliprect);
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ if (layers_ctrl & 1) tilemap_draw(bitmap,cliprect,tilemap_0,0,1);
+ if (layers_ctrl & 2) tilemap_draw(bitmap,cliprect,tilemap_1,0,2);
+ if (layers_ctrl & 4) tilemap_draw(bitmap,cliprect,tilemap_2,0,4);
+
+ /* Sprites are drawn last, using pdrawgfx */
+ if (layers_ctrl & 8) unico_draw_sprites(machine, bitmap,cliprect);
+
+ return 0;
+}
+
+VIDEO_UPDATE( zeropnt2 )
+{
+ int layers_ctrl = -1;
+
+ tilemap_set_scrollx(tilemap_0, 0, unico_scroll32[0] >> 16);
+ tilemap_set_scrolly(tilemap_0, 0, unico_scroll32[0] & 0xffff);
+
+ tilemap_set_scrollx(tilemap_1, 0, unico_scroll32[2] & 0xffff);
+ tilemap_set_scrolly(tilemap_1, 0, unico_scroll32[5] >> 16);
+
+ tilemap_set_scrollx(tilemap_2, 0, unico_scroll32[2] >> 16);
+ tilemap_set_scrolly(tilemap_2, 0, unico_scroll32[1] >> 16);
+
+#ifdef MAME_DEBUG
+if ( input_code_pressed(KEYCODE_Z) || input_code_pressed(KEYCODE_X) )
+{
+ int msk = 0;
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+ if (input_code_pressed(KEYCODE_E)) msk |= 4;
+ if (input_code_pressed(KEYCODE_A)) msk |= 8;
+ if (msk != 0) layers_ctrl &= msk;
+}
+#endif
+
+ /* The background color is the first of the last palette */
+ fillbitmap(bitmap,machine->pens[0x1f00],cliprect);
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ if (layers_ctrl & 1) tilemap_draw(bitmap,cliprect,tilemap_0,0,1);
+ if (layers_ctrl & 2) tilemap_draw(bitmap,cliprect,tilemap_1,0,2);
+ if (layers_ctrl & 4) tilemap_draw(bitmap,cliprect,tilemap_2,0,4);
+
+ /* Sprites are drawn last, using pdrawgfx */
+ if (layers_ctrl & 8) zeropnt2_draw_sprites(machine, bitmap,cliprect);
+
+ return 0;
+}
+
diff --git a/src/mame/video/usgames.c b/src/mame/video/usgames.c
new file mode 100644
index 00000000000..5cb13ffa71c
--- /dev/null
+++ b/src/mame/video/usgames.c
@@ -0,0 +1,74 @@
+#include "driver.h"
+
+UINT8 *usg_videoram,*usg_charram;
+
+
+static tilemap *usg_tilemap;
+
+
+
+PALETTE_INIT(usg)
+{
+ int j;
+
+ for (j = 0;j < 16;j++)
+ {
+ int r = (j & 1) >> 0;
+ int g = (j & 2) >> 1;
+ int b = (j & 4) >> 2;
+ int i = (j & 8) >> 3;
+
+ r = 0xff * r;
+ g = 0x7f * g * (i + 1);
+ b = 0x7f * b * (i + 1);
+
+ palette_set_color(machine,j,MAKE_RGB(r,g,b));
+ }
+
+ for (j = 0;j < 256;j++)
+ {
+ colortable[2*j] = j & 0x0f;
+ colortable[2*j+1] = j >> 4;
+ }
+}
+
+
+
+static TILE_GET_INFO( get_usg_tile_info )
+{
+ int tileno, colour;
+
+ tileno = usg_videoram[tile_index*2];
+ colour = usg_videoram[tile_index*2+1];
+
+ SET_TILE_INFO(0,tileno,colour,0);
+}
+
+VIDEO_START(usg)
+{
+ usg_tilemap = tilemap_create(get_usg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+}
+
+
+WRITE8_HANDLER( usg_videoram_w )
+{
+ usg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(usg_tilemap,offset/2);
+}
+
+WRITE8_HANDLER( usg_charram_w )
+{
+ usg_charram[offset] = data;
+
+ decodechar(Machine->gfx[0], offset/8, usg_charram, Machine->drv->gfxdecodeinfo[0].gfxlayout);
+
+ tilemap_mark_all_tiles_dirty(usg_tilemap);
+}
+
+
+
+VIDEO_UPDATE(usg)
+{
+ tilemap_draw(bitmap,cliprect,usg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/vaportra.c b/src/mame/video/vaportra.c
new file mode 100644
index 00000000000..a144b458460
--- /dev/null
+++ b/src/mame/video/vaportra.c
@@ -0,0 +1,187 @@
+/***************************************************************************
+
+ Vapour Trail Video emulation - Bryan McPhail, mish@tendril.co.uk
+
+****************************************************************************
+
+ 2 Data East 55 chips for playfields (same as Dark Seal, etc)
+ 1 Data East MXC-06 chip for sprites (same as Bad Dudes, etc)
+
+***************************************************************************/
+
+#include "driver.h"
+#include "deco16ic.h"
+
+static UINT16 vaportra_priority[2];
+
+/******************************************************************************/
+
+static int vaportra_bank_callback(const int bank)
+{
+ return ((bank>>4)&0x7) * 0x1000;
+}
+
+
+VIDEO_START( vaportra )
+{
+ deco16_2_video_init(0);
+
+ deco16_pf1_rowscroll = 0;
+ deco16_pf2_rowscroll = 0;
+ deco16_pf3_rowscroll = 0;
+ deco16_pf4_rowscroll = 0;
+
+ deco16_set_tilemap_bank_callback(0, vaportra_bank_callback);
+ deco16_set_tilemap_bank_callback(1, vaportra_bank_callback);
+ deco16_set_tilemap_bank_callback(2, vaportra_bank_callback);
+ deco16_set_tilemap_bank_callback(3, vaportra_bank_callback);
+
+ deco16_pf1_colour_bank=0x00;
+ deco16_pf2_colour_bank=0x20;
+ deco16_pf4_colour_bank=0x40;
+ deco16_pf3_colour_bank=0x30;
+}
+
+/******************************************************************************/
+
+
+WRITE16_HANDLER( vaportra_priority_w )
+{
+ COMBINE_DATA(&vaportra_priority[offset]);
+}
+
+/******************************************************************************/
+
+static void update_24bitcol(int offset)
+{
+ UINT8 r,g,b;
+
+ r = (paletteram16[offset] >> 0) & 0xff;
+ g = (paletteram16[offset] >> 8) & 0xff;
+ b = (paletteram16_2[offset] >> 0) & 0xff;
+
+ palette_set_color(Machine,offset,MAKE_RGB(r,g,b));
+}
+
+WRITE16_HANDLER( vaportra_palette_24bit_rg_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ update_24bitcol(offset);
+}
+
+WRITE16_HANDLER( vaportra_palette_24bit_b_w )
+{
+ COMBINE_DATA(&paletteram16_2[offset]);
+ update_24bitcol(offset);
+}
+
+/******************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri)
+{
+ int offs,priority_value;
+
+ priority_value=vaportra_priority[1];
+
+ for (offs = 0;offs < 0x400;offs += 4)
+ {
+ int x,y,sprite,colour,multi,fx,fy,inc,flash,mult;
+
+ y = buffered_spriteram16[offs];
+ if ((y&0x8000) == 0) continue;
+
+ sprite = buffered_spriteram16[offs+1] & 0x1fff;
+ x = buffered_spriteram16[offs+2];
+ colour = (x >> 12) &0xf;
+ if (pri && (colour>=priority_value)) continue;
+ if (!pri && !(colour>=priority_value)) continue;
+
+ flash=x&0x800;
+ if (flash && (cpu_getcurrentframe() & 1)) continue;
+
+ fx = y & 0x2000;
+ fy = y & 0x4000;
+ multi = (1 << ((y & 0x1800) >> 11)) - 1; /* 1x, 2x, 4x, 8x height */
+
+ x = x & 0x01ff;
+ y = y & 0x01ff;
+ if (x >= 256) x -= 512;
+ if (y >= 256) y -= 512;
+ x = 240 - x;
+ y = 240 - y;
+
+ if (x>256) continue; /* Speedup */
+
+ sprite &= ~multi;
+ if (fy)
+ inc = -1;
+ else
+ {
+ sprite += multi;
+ inc = 1;
+ }
+
+ if (flip_screen)
+ {
+ y=240-y;
+ x=240-x;
+ if (fx) fx=0; else fx=1;
+ if (fy) fy=0; else fy=1;
+ mult=16;
+ }
+ else mult=-16;
+
+ while (multi >= 0)
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ sprite - multi * inc,
+ colour,
+ fx,fy,
+ x,y + mult * multi,
+ cliprect,TRANSPARENCY_PEN,0);
+
+ multi--;
+ }
+ }
+}
+
+
+VIDEO_UPDATE( vaportra )
+{
+ int pri=vaportra_priority[0] & 0x03;
+
+ flip_screen_set( !(deco16_pf12_control[0]&0x80) );
+
+ deco16_pf12_update(deco16_pf1_rowscroll,deco16_pf2_rowscroll);
+ deco16_pf34_update(deco16_pf3_rowscroll,deco16_pf4_rowscroll);
+
+ /* Draw playfields */
+ if (pri==0) {
+ deco16_tilemap_4_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ deco16_tilemap_3_draw(bitmap,cliprect,0,0);
+ draw_sprites(machine, bitmap,cliprect,0);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,0);
+ }
+ else if (pri==1) {
+ deco16_tilemap_3_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ deco16_tilemap_4_draw(bitmap,cliprect,0,0);
+ draw_sprites(machine, bitmap,cliprect,0);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,0);
+ }
+ else if (pri==2) {
+ deco16_tilemap_4_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,0);
+ draw_sprites(machine, bitmap,cliprect,0);
+ deco16_tilemap_3_draw(bitmap,cliprect,0,0);
+ }
+ else {
+ deco16_tilemap_3_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE,0);
+ deco16_tilemap_2_draw(bitmap,cliprect,0,0);
+ draw_sprites(machine, bitmap,cliprect,0);
+ deco16_tilemap_4_draw(bitmap,cliprect,0,0);
+ }
+
+ draw_sprites(machine,bitmap,cliprect,1);
+ deco16_tilemap_1_draw(bitmap,cliprect,0,0);
+ return 0;
+}
diff --git a/src/mame/video/vastar.c b/src/mame/video/vastar.c
new file mode 100644
index 00000000000..dd6827b9a48
--- /dev/null
+++ b/src/mame/video/vastar.c
@@ -0,0 +1,229 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+UINT8 *vastar_bg1videoram,*vastar_bg2videoram,*vastar_fgvideoram;
+UINT8 *vastar_bg1_scroll,*vastar_bg2_scroll;
+UINT8 *vastar_sprite_priority;
+
+static tilemap *fg_tilemap, *bg1_tilemap, *bg2_tilemap;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code, color;
+
+ code = vastar_fgvideoram[tile_index + 0x800] | (vastar_fgvideoram[tile_index + 0x400] << 8);
+ color = vastar_fgvideoram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ code,
+ color & 0x3f,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg1_tile_info )
+{
+ int code, color;
+
+ code = vastar_bg1videoram[tile_index + 0x800] | (vastar_bg1videoram[tile_index] << 8);
+ color = vastar_bg1videoram[tile_index + 0xc00];
+ SET_TILE_INFO(
+ 4,
+ code,
+ color & 0x3f,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg2_tile_info )
+{
+ int code, color;
+
+ code = vastar_bg2videoram[tile_index + 0x800] | (vastar_bg2videoram[tile_index] << 8);
+ color = vastar_bg2videoram[tile_index + 0xc00];
+ SET_TILE_INFO(
+ 3,
+ code,
+ color & 0x3f,
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( vastar )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ bg1_tilemap = tilemap_create(get_bg1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+ bg2_tilemap = tilemap_create(get_bg2_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_transparent_pen(bg1_tilemap,0);
+ tilemap_set_transparent_pen(bg2_tilemap,0);
+
+ tilemap_set_scroll_cols(bg1_tilemap, 32);
+ tilemap_set_scroll_cols(bg2_tilemap, 32);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( vastar_fgvideoram_w )
+{
+ vastar_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( vastar_bg1videoram_w )
+{
+ vastar_bg1videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg1_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( vastar_bg2videoram_w )
+{
+ vastar_bg2videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg2_tilemap,offset & 0x3ff);
+}
+
+
+READ8_HANDLER( vastar_bg1videoram_r )
+{
+ return vastar_bg1videoram[offset];
+}
+
+READ8_HANDLER( vastar_bg2videoram_r )
+{
+ return vastar_bg2videoram[offset];
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+
+ for (offs = 0; offs < spriteram_size; offs += 2)
+ {
+ int code, sx, sy, color, flipx, flipy;
+
+
+ code = ((spriteram_3[offs] & 0xfc) >> 2) + ((spriteram_2[offs] & 0x01) << 6)
+ + ((offs & 0x20) << 2);
+
+ sx = spriteram_3[offs + 1];
+ sy = spriteram[offs];
+ color = spriteram[offs + 1] & 0x3f;
+ flipx = spriteram_3[offs] & 0x02;
+ flipy = spriteram_3[offs] & 0x01;
+
+ if (flip_screen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ if (spriteram_2[offs] & 0x08) /* double width */
+ {
+ if (!flip_screen)
+ sy = 224 - sy;
+
+ drawgfx(bitmap,machine->gfx[2],
+ code/2,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ /* redraw with wraparound */
+ drawgfx(bitmap,machine->gfx[2],
+ code/2,
+ color,
+ flipx,flipy,
+ sx,sy+256,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ if (!flip_screen)
+ sy = 240 - sy;
+
+ drawgfx(bitmap,machine->gfx[1],
+ code,
+ color,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( vastar )
+{
+ int i;
+
+
+ for (i = 0;i < 32;i++)
+ {
+ tilemap_set_scrolly(bg1_tilemap,i,vastar_bg1_scroll[i]);
+ tilemap_set_scrolly(bg2_tilemap,i,vastar_bg2_scroll[i]);
+ }
+
+ switch (*vastar_sprite_priority)
+ {
+ case 0:
+ tilemap_draw(bitmap,cliprect, bg1_tilemap, TILEMAP_DRAW_OPAQUE,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect, bg2_tilemap, 0,0);
+ tilemap_draw(bitmap,cliprect, fg_tilemap, 0,0);
+ break;
+
+ case 2:
+ tilemap_draw(bitmap,cliprect, bg1_tilemap, TILEMAP_DRAW_OPAQUE,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect, bg1_tilemap, 0,0);
+ tilemap_draw(bitmap,cliprect, bg2_tilemap, 0,0);
+ tilemap_draw(bitmap,cliprect, fg_tilemap, 0,0);
+ break;
+
+ case 3:
+ tilemap_draw(bitmap,cliprect, bg1_tilemap, TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect, bg2_tilemap, 0,0);
+ tilemap_draw(bitmap,cliprect, fg_tilemap, 0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ break;
+
+ default:
+ logerror("Unimplemented priority %X\n", *vastar_sprite_priority);
+ break;
+ }
+ return 0;
+}
diff --git a/src/mame/video/vball.c b/src/mame/video/vball.c
new file mode 100644
index 00000000000..831b62ea387
--- /dev/null
+++ b/src/mame/video/vball.c
@@ -0,0 +1,191 @@
+/***************************************************************************
+
+ Video Hardware for Championship V'ball by Paul Hampson
+ Generally copied from China Gate by Paul Hampson
+ "Mainly copied from video of Double Dragon (bootleg) & Double Dragon II"
+
+***************************************************************************/
+
+#include "driver.h"
+#include "cpu/m6502/m6502.h"
+
+int vb_scrollx_hi=0;
+int vb_scrollx_lo=0;
+int vb_scrolly_hi=0;
+
+UINT8 *vb_scrolly_lo;
+UINT8 *vb_videoram;
+UINT8 *vb_attribram;
+int vball_gfxset=0;
+int vb_bgprombank=0xff;
+int vb_spprombank=0xff;
+
+static tilemap *bg_tilemap;
+static int scrollx[32];
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( background_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x20) << 5) + ((row & 0x20) <<6);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 code = vb_videoram[tile_index];
+ UINT8 attr = vb_attribram[tile_index];
+ SET_TILE_INFO(
+ 0,
+ code + ((attr & 0x1f) << 8) + (vball_gfxset<<8),
+ (attr >> 5) & 0x7,
+ 0);
+}
+
+
+VIDEO_START( vb )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,background_scan,TILEMAP_TYPE_PEN, 8, 8,64,64);
+
+ tilemap_set_scroll_rows(bg_tilemap,32);
+}
+
+WRITE8_HANDLER( vb_videoram_w )
+{
+ vb_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+#ifdef UNUSED_FUNCTION
+READ8_HANDLER( vb_attrib_r )
+{
+ return vb_attribram[offset];
+}
+#endif
+
+WRITE8_HANDLER( vb_attrib_w )
+{
+ vb_attribram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+void vb_bgprombank_w( int bank )
+{
+ int i;
+ UINT8* color_prom;
+
+ if (bank==vb_bgprombank) return;
+
+ color_prom = memory_region(REGION_PROMS) + bank*0x80;
+ for (i=0;i<128;i++, color_prom++) {
+ palette_set_color_rgb(Machine,i,pal4bit(color_prom[0] >> 0),pal4bit(color_prom[0] >> 4),
+ pal4bit(color_prom[0x800] >> 0));
+ }
+ vb_bgprombank=bank;
+}
+
+void vb_spprombank_w( int bank )
+{
+
+ int i;
+ UINT8* color_prom;
+
+ if (bank==vb_spprombank) return;
+
+ color_prom = memory_region(REGION_PROMS)+0x400 + bank*0x80;
+ for (i=128;i<256;i++,color_prom++) {
+ palette_set_color_rgb(Machine,i,pal4bit(color_prom[0] >> 0),pal4bit(color_prom[0] >> 4),
+ pal4bit(color_prom[0x800] >> 0));
+ }
+ vb_spprombank=bank;
+}
+
+void vb_mark_all_dirty( void )
+{
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+}
+
+#define DRAW_SPRITE( order, sx, sy ) drawgfx( bitmap, gfx, \
+ (which+order),color,flipx,flipy,sx,sy, \
+ cliprect,TRANSPARENCY_PEN,0);
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ const gfx_element *gfx = machine->gfx[1];
+ UINT8 *src = spriteram;
+ int i;
+
+/* 240-Y S|X|CLR|WCH WHICH 240-X
+ xxxxxxxx x|x|xxx|xxx xxxxxxxx xxxxxxxx
+*/
+ for (i = 0;i < spriteram_size;i += 4)
+ {
+ int attr = src[i+1];
+ int which = src[i+2]+((attr & 0x07)<<8);
+ int sx = ((src[i+3] + 8) & 0xff) - 7;
+ int sy = 240 - src[i];
+ int size = (attr & 0x80) >> 7;
+ int color = (attr & 0x38) >> 3;
+ int flipx = ~attr & 0x40;
+ int flipy = 0;
+ int dy = -16;
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ dy = -dy;
+ }
+
+ switch (size)
+ {
+ case 0: /* normal */
+ DRAW_SPRITE(0,sx,sy);
+ break;
+
+ case 1: /* double y */
+ DRAW_SPRITE(0,sx,sy + dy);
+ DRAW_SPRITE(1,sx,sy);
+ break;
+ }
+ }
+}
+
+#undef DRAW_SPRITE
+
+VIDEO_UPDATE( vb )
+{
+ int i;
+
+ tilemap_set_scrolly(bg_tilemap,0,vb_scrolly_hi + *vb_scrolly_lo);
+
+ /*To get linescrolling to work properly, we must ignore the 1st two scroll values, no idea why! -SJE */
+ for (i = 2;i < 32;i++) {
+ tilemap_set_scrollx(bg_tilemap,i,scrollx[i-2]);
+ //logerror("scrollx[%d] = %d\n",i,scrollx[i]);
+ }
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
+
+
+/*I don't really understand what the proper timing of this should be,
+ but after TONS of testing, the tilemap individual line scrolling works as long as flip screen is not set -SJE
+*/
+INTERRUPT_GEN( vball_interrupt )
+{
+ int line = 31 - cpu_getiloops();
+ if (line < 13)
+ cpunum_set_input_line(0, M6502_IRQ_LINE, HOLD_LINE);
+ else if (line == 13)
+ cpunum_set_input_line(0, INPUT_LINE_NMI, PULSE_LINE);
+ //save the scroll x register value
+ if(line<32) scrollx[31-line] = (vb_scrollx_hi + vb_scrollx_lo+4);
+}
diff --git a/src/mame/video/vendetta.c b/src/mame/video/vendetta.c
new file mode 100644
index 00000000000..3941a678eac
--- /dev/null
+++ b/src/mame/video/vendetta.c
@@ -0,0 +1,124 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+static int layer_colorbase[3],bg_colorbase,sprite_colorbase;
+static int layerpri[3];
+
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void vendetta_tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ *code |= ((*color & 0x03) << 8) | ((*color & 0x30) << 6) |
+ ((*color & 0x0c) << 10) | (bank << 14);
+ *color = layer_colorbase[layer] + ((*color & 0xc0) >> 6);
+}
+
+static void esckids_tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ *code |= ((*color & 0x03) << 8) | ((*color & 0x10) << 6) |
+ ((*color & 0x0c) << 9) | (bank << 13);
+ *color = layer_colorbase[layer] + ((*color & 0xe0) >> 5);
+}
+
+
+/***************************************************************************
+
+ Callbacks for the K053247
+
+***************************************************************************/
+
+static void sprite_callback(int *code,int *color,int *priority_mask)
+{
+ int pri = (*color & 0x03e0) >> 4; /* ??????? */
+ if (pri <= layerpri[2]) *priority_mask = 0;
+ else if (pri > layerpri[2] && pri <= layerpri[1]) *priority_mask = 0xf0;
+ else if (pri > layerpri[1] && pri <= layerpri[0]) *priority_mask = 0xf0|0xcc;
+ else *priority_mask = 0xf0|0xcc|0xaa;
+
+ *color = sprite_colorbase + (*color & 0x001f);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( vendetta )
+{
+ K053251_vh_start();
+
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,vendetta_tile_callback);
+ K053247_vh_start(machine,REGION_GFX2,53,6,NORMAL_PLANE_ORDER,sprite_callback);
+}
+
+VIDEO_START( esckids )
+{
+ K053251_vh_start();
+
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,esckids_tile_callback);
+ K053247_vh_start(machine,REGION_GFX2,101,6,NORMAL_PLANE_ORDER,sprite_callback);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+/* useful function to sort the three tile layers by priority order */
+static void sortlayers(int *layer,int *pri)
+{
+#define SWAP(a,b) \
+ if (pri[a] < pri[b]) \
+ { \
+ int t; \
+ t = pri[a]; pri[a] = pri[b]; pri[b] = t; \
+ t = layer[a]; layer[a] = layer[b]; layer[b] = t; \
+ }
+
+ SWAP(0,1)
+ SWAP(0,2)
+ SWAP(1,2)
+}
+
+VIDEO_UPDATE( vendetta )
+{
+ int layer[3];
+
+
+ bg_colorbase = K053251_get_palette_index(K053251_CI0);
+ sprite_colorbase = K053251_get_palette_index(K053251_CI1);
+ layer_colorbase[0] = K053251_get_palette_index(K053251_CI2);
+ layer_colorbase[1] = K053251_get_palette_index(K053251_CI3);
+ layer_colorbase[2] = K053251_get_palette_index(K053251_CI4);
+
+ K052109_tilemap_update();
+
+ layer[0] = 0;
+ layerpri[0] = K053251_get_priority(K053251_CI2);
+ layer[1] = 1;
+ layerpri[1] = K053251_get_priority(K053251_CI3);
+ layer[2] = 2;
+ layerpri[2] = K053251_get_priority(K053251_CI4);
+
+ sortlayers(layer,layerpri);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[0]],TILEMAP_DRAW_OPAQUE,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[1]],0,2);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[2]],0,4);
+
+ K053247_sprites_draw(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/vertigo.c b/src/mame/video/vertigo.c
new file mode 100644
index 00000000000..b1df3ca4a54
--- /dev/null
+++ b/src/mame/video/vertigo.c
@@ -0,0 +1,656 @@
+/*************************************************************************
+
+ Exidy Vertigo hardware
+
+ The Vertigo vector CPU consists of four AMD 2901 bit slice
+ processors, logic to control microcode program flow and a digital
+ vector generator. The microcode for the bit slice CPUs is stored in 13
+ bipolar proms for a total of 512 52bit wide micro instructions. The
+ microcode not only crontrols the 2901s but also loading and storing
+ of operands and results, program flow control and vector generation.
+
+ +----+----+----+----+----+----+-------+-----+-----+------+-----+----+---+
+ |VUC |VUC |VUC |VUC |VUC |VUC | VUC | VUC | VUC | VUC | VUC |VUC |VUC| labels
+ | 10 | 13 | 9 | 8 | 7 | 6 | 5 | 12 | 11 | 2 | 1 | 4 | 3 |
+ +----+----+----+----+----+----+-------+-----+-----+------+-----+----+---+
+ | | | | | | | | | | | |PR5/|R5/| schematics
+ |J5/4|G5/1|K5/5|L5/6|M5/7|N5/8| P5/9 |H5/2 |HJ5/3|S5/12 |T5/13| 10 |11 |
+ +----+----+----+----+----+----+-------+-----+-----+------+-----+----+---+
+ 55 44|4444|4444|3333|3333|3322|2 2 2 2|2 222|11 11|1 1 11|110 0|0000|0000
+ 21 98|7654|3210|9876|5432|1098|7 6 5 4|3 210|98 76|5 4 32|109 8|7654|3210
+
+ xx|xxxx|aaaa|bbbb|iiii|iiii|i c m r|r ooo|ii oo| j jj|jjj m|mmmm|mmmm
+ 54|3210|3210|3210|8765|4321|0 n r s|w fff|ff aa| p 43|210 a|aaaa|aaaa
+ e e|r 210|10 10| o | 8|7654|3210
+ q l i s
+ t
+ e
+ x: address for 64 words of 16 bit wide SRAM
+ a: A register index
+ b: B register index
+ i: 2901 instruction
+ cn: carry bit
+ mreq, rsel, rwrite: signals for memory access
+ of: vector generator
+ if: vector RAM/ROM data select
+ oa: vector RAM/ROM address select
+ jpos: jump condition inverted
+ j: jump condition and type
+ m: jump address
+
+ Variables, enums and defines are named as in the schematics (pp. 6, 7)
+ where possible.
+
+*************************************************************************/
+
+#include "driver.h"
+#include "profiler.h"
+#include "video/vector.h"
+#include "vertigo.h"
+
+
+/*************************************
+ *
+ * Macros and enums
+ *
+ *************************************/
+
+#define MC_LENGTH 512
+
+#define V_ADDPOINT(h,v,c,i) \
+ vector_add_point (((h) & 0x7ff) << 14, (0x6ff - ((v) & 0x7ff)) << 14, VECTOR_COLOR444(c), (i))
+
+#define ADD(r,s,c) (((r) + (s) + (c)) & 0xffff)
+#define SUBR(r,s,c) ((~(r) + (s) + (c)) & 0xffff)
+#define SUBS(r,s,c) (((r) + ~(s) + (c)) & 0xffff)
+#define OR(r,s) ((r) | (s))
+#define AND(r,s) ((r) & (s))
+#define NOTRS(r,s) (~(r) & (s))
+#define EXOR(r,s) ((r) ^ (s))
+#define EXNOR(r,s) (~((r) ^ (s)))
+
+/* values for MC_DST */
+enum {
+ QREG = 0,
+ NOP,
+ RAMA,
+ RAMF,
+ RAMQD,
+ RAMD,
+ RAMQU,
+ RAMU
+};
+
+/* values for MC_IF */
+enum {
+ S_ROMDE = 0,
+ S_RAMDE
+};
+
+/* values for MC_OA */
+enum {
+ S_SREG = 0,
+ S_ROMA,
+ S_RAMD
+};
+
+/* values for MC_JMP */
+enum {
+ S_JBK = 0,
+ S_CALL,
+ S_OPT,
+ S_RETURN
+};
+
+/* values for MC_JCON */
+enum {
+ S_ALWAYS = 0,
+ S_MSB,
+ S_FEQ0,
+ S_Y10,
+ S_VFIN,
+ S_FPOS,
+ S_INTL4
+};
+
+
+/*************************************
+ *
+ * Global variables
+ *
+ *************************************/
+
+UINT16 *vertigo_vectorram;
+
+
+/*************************************
+ *
+ * Typedefs
+ *
+ *************************************/
+
+typedef struct _am2901
+{
+ UINT32 ram[16]; /* internal ram */
+ UINT32 d; /* direct data D input */
+ UINT32 q; /* Q register */
+ UINT32 f; /* F ALU result */
+ UINT32 y; /* Y output */
+} am2901;
+
+typedef struct _vector_generator
+{
+ UINT32 sreg; /* shift register */
+ UINT32 l1; /* latch 1 adder operand only */
+ UINT32 l2; /* latch 2 adder operand only */
+ UINT32 c_v; /* vertical position counter */
+ UINT32 c_h; /* horizontal position counter */
+ UINT32 c_l; /* length counter */
+ UINT32 adder_s; /* slope generator result and B input */
+ UINT32 adder_a; /* slope generator A input */
+ UINT32 color; /* color */
+ UINT32 intensity; /* intensity */
+ UINT32 brez; /* h/v-counters enable */
+ UINT32 vfin; /* drawing yes/no */
+ UINT32 hud1; /* h-counter up or down (stored in L1) */
+ UINT32 hud2; /* h-counter up or down (stored in L2) */
+ UINT32 vud1; /* v-counter up or down (stored in L1) */
+ UINT32 vud2; /* v-counter up or down (stored in L2) */
+ UINT32 hc1; /* use h- or v-counter in L1 mode */
+ UINT32 ven; /* vector intensity enable */
+} vector_generator;
+
+typedef struct _microcode
+{
+ UINT32 x;
+ UINT32 a;
+ UINT32 b;
+ UINT32 inst;
+ UINT32 dest;
+ UINT32 cn;
+ UINT32 mreq;
+ UINT32 rsel;
+ UINT32 rwrite;
+ UINT32 of;
+ UINT32 iif;
+ UINT32 oa;
+ UINT32 jpos;
+ UINT32 jmp;
+ UINT32 jcon;
+ UINT32 ma;
+} microcode;
+
+typedef struct _vproc
+{
+ UINT16 sram[64]; /* external sram */
+ UINT16 ramlatch; /* latch between 2901 and sram */
+ UINT16 rom_adr; /* vector ROM/RAM address latch */
+ UINT32 pc; /* program counter */
+ UINT32 ret; /* return address */
+
+} vproc;
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static vproc vs;
+static am2901 bsp;
+static vector_generator vgen;
+static UINT16 *vertigo_vectorrom;
+static microcode mc[MC_LENGTH];
+
+
+/*************************************
+ *
+ * Vector processor initialization
+ *
+ *************************************/
+
+void vertigo_vproc_init(void)
+{
+ int i;
+ UINT64 *mcode;
+
+ vertigo_vectorrom = (UINT16 *)memory_region(REGION_USER1);
+ mcode = (UINT64 *)memory_region(REGION_PROMS);
+
+ /* Decode microcode */
+ for (i = 0; i < MC_LENGTH; i++)
+ {
+ mc[i].x = (mcode[i] >> 44) & 0x3f;
+ mc[i].a = (mcode[i] >> 40) & 0xf;
+ mc[i].b = (mcode[i] >> 36) & 0xf;
+ mc[i].inst = (mcode[i] >> 27) & 077;
+ mc[i].dest = (mcode[i] >> 33) & 07;
+ mc[i].cn = (mcode[i] >> 26) & 0x1;
+ mc[i].mreq = (mcode[i] >> 25) & 0x1;
+ mc[i].rwrite = (mcode[i] >> 23) & 0x1;
+ mc[i].rsel = mc[i].rwrite & ((mcode[i] >> 24) & 0x1);
+ mc[i].of = (mcode[i] >> 20) & 0x7;
+ mc[i].iif = (mcode[i] >> 18) & 0x3;
+ mc[i].oa = (mcode[i] >> 16) & 0x3;
+ mc[i].jpos = (mcode[i] >> 14) & 0x1;
+ mc[i].jmp = (mcode[i] >> 12) & 0x3;
+ mc[i].jcon = (mcode[i] >> 9) & 0x7;
+ mc[i].ma = mcode[i] & 0x1ff;
+ }
+
+ memset(&vs, 0, sizeof(vs));
+ memset(&bsp, 0, sizeof(bsp));
+ memset(&vgen, 0, sizeof(vgen));
+
+ state_save_register_item_array("vector_proc", 0, vs.sram);
+ state_save_register_item("vector_proc", 0, vs.ramlatch);
+ state_save_register_item("vector_proc", 0, vs.rom_adr);
+ state_save_register_item("vector_proc", 0, vs.pc);
+ state_save_register_item("vector_proc", 0, vs.ret);
+
+ state_save_register_item_array("vector_proc", 0, bsp.ram);
+ state_save_register_item("vector_proc", 0, bsp.d);
+ state_save_register_item("vector_proc", 0, bsp.q);
+ state_save_register_item("vector_proc", 0, bsp.f);
+ state_save_register_item("vector_proc", 0, bsp.y);
+
+ state_save_register_item("vector_proc", 0, vgen.sreg);
+ state_save_register_item("vector_proc", 0, vgen.l1);
+ state_save_register_item("vector_proc", 0, vgen.l2);
+ state_save_register_item("vector_proc", 0, vgen.c_v);
+ state_save_register_item("vector_proc", 0, vgen.c_h);
+ state_save_register_item("vector_proc", 0, vgen.c_l);
+ state_save_register_item("vector_proc", 0, vgen.adder_s);
+ state_save_register_item("vector_proc", 0, vgen.adder_a);
+ state_save_register_item("vector_proc", 0, vgen.color);
+ state_save_register_item("vector_proc", 0, vgen.intensity);
+ state_save_register_item("vector_proc", 0, vgen.brez);
+ state_save_register_item("vector_proc", 0, vgen.vfin);
+ state_save_register_item("vector_proc", 0, vgen.hud1);
+ state_save_register_item("vector_proc", 0, vgen.hud2);
+ state_save_register_item("vector_proc", 0, vgen.vud1);
+ state_save_register_item("vector_proc", 0, vgen.vud2);
+ state_save_register_item("vector_proc", 0, vgen.hc1);
+ state_save_register_item("vector_proc", 0, vgen.ven);
+}
+
+
+/********************************************
+ *
+ * 4 x AM2901 bit slice processors
+ * Q3 and IN3 are hardwired
+ *
+ ********************************************/
+
+static void am2901x4 (am2901 *bsp, microcode *mc)
+{
+ switch (mc->inst)
+ {
+ case 000: bsp->f = ADD(bsp->ram[mc->a], bsp->q, mc->cn); break;
+ case 001: bsp->f = ADD(bsp->ram[mc->a], bsp->ram[mc->b], mc->cn); break;
+ case 002: bsp->f = ADD(0, bsp->q, mc->cn); break;
+ case 003: bsp->f = ADD(0, bsp->ram[mc->b], mc->cn); break;
+ case 004: bsp->f = ADD(0, bsp->ram[mc->a], mc->cn); break;
+ case 005: bsp->f = ADD(bsp->d, bsp->ram[mc->a], mc->cn); break;
+ case 006: bsp->f = ADD(bsp->d, bsp->q, mc->cn); break;
+ case 007: bsp->f = ADD(bsp->d, 0, mc->cn); break;
+
+ case 010: bsp->f = SUBR(bsp->ram[mc->a], bsp->q, mc->cn); break;
+ case 011: bsp->f = SUBR(bsp->ram[mc->a], bsp->ram[mc->b], mc->cn); break;
+ case 012: bsp->f = SUBR(0, bsp->q, mc->cn); break;
+ case 013: bsp->f = SUBR(0, bsp->ram[mc->b], mc->cn); break;
+ case 014: bsp->f = SUBR(0, bsp->ram[mc->a], mc->cn); break;
+ case 015: bsp->f = SUBR(bsp->d, bsp->ram[mc->a], mc->cn); break;
+ case 016: bsp->f = SUBR(bsp->d, bsp->q, mc->cn); break;
+ case 017: bsp->f = SUBR(bsp->d, 0, mc->cn); break;
+
+ case 020: bsp->f = SUBS(bsp->ram[mc->a], bsp->q, mc->cn); break;
+ case 021: bsp->f = SUBS(bsp->ram[mc->a], bsp->ram[mc->b], mc->cn); break;
+ case 022: bsp->f = SUBS(0, bsp->q, mc->cn); break;
+ case 023: bsp->f = SUBS(0, bsp->ram[mc->b], mc->cn); break;
+ case 024: bsp->f = SUBS(0, bsp->ram[mc->a], mc->cn); break;
+ case 025: bsp->f = SUBS(bsp->d, bsp->ram[mc->a], mc->cn); break;
+ case 026: bsp->f = SUBS(bsp->d, bsp->q, mc->cn); break;
+ case 027: bsp->f = SUBS(bsp->d, 0, mc->cn); break;
+
+ case 030: bsp->f = OR(bsp->ram[mc->a], bsp->q); break;
+ case 031: bsp->f = OR(bsp->ram[mc->a], bsp->ram[mc->b]); break;
+ case 032: bsp->f = OR(0, bsp->q); break;
+ case 033: bsp->f = OR(0, bsp->ram[mc->b]); break;
+ case 034: bsp->f = OR(0, bsp->ram[mc->a]); break;
+ case 035: bsp->f = OR(bsp->d, bsp->ram[mc->a]); break;
+ case 036: bsp->f = OR(bsp->d, bsp->q); break;
+ case 037: bsp->f = OR(bsp->d, 0); break;
+
+ case 040: bsp->f = AND(bsp->ram[mc->a], bsp->q); break;
+ case 041: bsp->f = AND(bsp->ram[mc->a], bsp->ram[mc->b]); break;
+ case 042: bsp->f = AND(0, bsp->q); break;
+ case 043: bsp->f = AND(0, bsp->ram[mc->b]); break;
+ case 044: bsp->f = AND(0, bsp->ram[mc->a]); break;
+ case 045: bsp->f = AND(bsp->d, bsp->ram[mc->a]); break;
+ case 046: bsp->f = AND(bsp->d, bsp->q); break;
+ case 047: bsp->f = AND(bsp->d, 0); break;
+
+ case 050: bsp->f = NOTRS(bsp->ram[mc->a], bsp->q); break;
+ case 051: bsp->f = NOTRS(bsp->ram[mc->a], bsp->ram[mc->b]); break;
+ case 052: bsp->f = NOTRS(0, bsp->q); break;
+ case 053: bsp->f = NOTRS(0, bsp->ram[mc->b]); break;
+ case 054: bsp->f = NOTRS(0, bsp->ram[mc->a]); break;
+ case 055: bsp->f = NOTRS(bsp->d, bsp->ram[mc->a]); break;
+ case 056: bsp->f = NOTRS(bsp->d, bsp->q); break;
+ case 057: bsp->f = NOTRS(bsp->d, 0); break;
+
+ case 060: bsp->f = EXOR(bsp->ram[mc->a], bsp->q); break;
+ case 061: bsp->f = EXOR(bsp->ram[mc->a], bsp->ram[mc->b]); break;
+ case 062: bsp->f = EXOR(0, bsp->q); break;
+ case 063: bsp->f = EXOR(0, bsp->ram[mc->b]); break;
+ case 064: bsp->f = EXOR(0, bsp->ram[mc->a]); break;
+ case 065: bsp->f = EXOR(bsp->d, bsp->ram[mc->a]); break;
+ case 066: bsp->f = EXOR(bsp->d, bsp->q); break;
+ case 067: bsp->f = EXOR(bsp->d, 0); break;
+
+ case 070: bsp->f = EXNOR(bsp->ram[mc->a], bsp->q); break;
+ case 071: bsp->f = EXNOR(bsp->ram[mc->a], bsp->ram[mc->b]); break;
+ case 072: bsp->f = EXNOR(0, bsp->q); break;
+ case 073: bsp->f = EXNOR(0, bsp->ram[mc->b]); break;
+ case 074: bsp->f = EXNOR(0, bsp->ram[mc->a]); break;
+ case 075: bsp->f = EXNOR(bsp->d, bsp->ram[mc->a]); break;
+ case 076: bsp->f = EXNOR(bsp->d, bsp->q); break;
+ case 077: bsp->f = EXNOR(bsp->d, 0); break;
+ }
+
+ switch (mc->dest)
+ {
+ case QREG:
+ bsp->q = bsp->f;
+ bsp->y = bsp->f;
+ break;
+ case NOP:
+ bsp->y = bsp->f;
+ break;
+ case RAMA:
+ bsp->y = bsp->ram[mc->a];
+ bsp->ram[mc->b] = bsp->f;
+ break;
+ case RAMF:
+ bsp->y = bsp->f;
+ bsp->ram[mc->b] = bsp->f;
+ break;
+ case RAMQD:
+ bsp->y = bsp->f;
+ bsp->q = (bsp->q >> 1) & 0x7fff; /* Q3 is low */
+ bsp->ram[mc->b] = (bsp->f >> 1) | 0x8000; /* IN3 is high! */
+ break;
+ case RAMD:
+ bsp->y = bsp->f;
+ bsp->ram[mc->b] = (bsp->f >> 1) | 0x8000; /* IN3 is high! */
+ break;
+ case RAMQU:
+ bsp->y = bsp->f;
+ bsp->ram[mc->b] = (bsp->f << 1) & 0xffff;
+ bsp->q = (bsp->q << 1) & 0xffff;
+ break;
+ case RAMU:
+ bsp->y = bsp->f;
+ bsp->ram[mc->b] = (bsp->f << 1) & 0xffff;
+ break;
+ }
+}
+
+
+/********************************************
+ *
+ * Vector Generator
+ *
+ * This part of the hardware draws vectors
+ * under control of the bit slice processors.
+ * It is just a bunch of counters, latches
+ * and DACs.
+ *
+ ********************************************/
+
+static void vertigo_vgen (vector_generator *vg)
+{
+ if (vg->c_l & 0x800)
+ {
+ vg->vfin = 1;
+ vg->c_l = (vg->c_l+1) & 0xfff;
+
+ if ((vg->c_l & 0x800) == 0)
+ {
+ vg->brez = 0;
+ vg->vfin = 0;
+ }
+
+ if (vg->brez) /* H/V counter enabled */
+ {
+ /* Depending on MSB of adder only one or both
+ counters are de-/incremented. This is all
+ defined by the shift register which is
+ latched in bits 12-15 of L1/L2.
+ */
+ if (vg->adder_s & 0x800)
+ {
+ if (vg->hc1)
+ vg->c_h += vg->hud1? -1: 1;
+ else
+ vg->c_v += vg->vud1? -1: 1;
+ vg->adder_a = vg->l1;
+ }
+ else
+ {
+ vg->c_h += vg->hud2? -1: 1;
+ vg->c_v += vg->vud2? -1: 1;
+ vg->adder_a = vg->l2;
+ }
+
+ /* H/V counters are 12 bit */
+ vg->c_v &= 0xfff;
+ vg->c_h &= 0xfff;
+ }
+
+ vg->adder_s = (vg->adder_s + vg->adder_a) & 0xfff;
+ }
+
+ if (vg->brez ^ vg->ven)
+ {
+ if (vg->brez)
+ V_ADDPOINT (vg->c_h, vg->c_v, 0, 0);
+ else
+ V_ADDPOINT (vg->c_h, vg->c_v, vg->color, vg->intensity);
+ vg->ven = vg->brez;
+ }
+}
+
+/*************************************
+ *
+ * Vector processor
+ *
+ *************************************/
+
+void vertigo_vproc(int cycles, int irq4)
+{
+ int jcond;
+ microcode *cmc;
+
+ if (irq4) vector_clear_list();
+
+ profiler_mark(PROFILER_USER1);
+
+ while (cycles--)
+ {
+ /* Microcode at current PC */
+ cmc = &mc[vs.pc];
+
+ /* Load data */
+ if (cmc->iif == S_RAMDE)
+ {
+ bsp.d = vs.ramlatch;
+ }
+ else if (cmc->iif == S_ROMDE)
+ {
+ if (vs.rom_adr < 0x2000)
+ {
+ bsp.d = vertigo_vectorram[vs.rom_adr & 0xfff];
+ }
+ else
+ {
+ bsp.d = vertigo_vectorrom[vs.rom_adr & 0x7fff];
+ }
+ }
+
+ /* SRAM selected ? */
+ if (cmc->rsel == 0)
+ {
+ if (cmc->rwrite)
+ {
+ bsp.d = vs.sram[cmc->x];
+ }
+ else
+ {
+ /* Data can be transferred between vector ROM/RAM
+ and SRAM without going through the 2901 */
+ vs.sram[cmc->x] = bsp.d;
+ }
+ }
+
+ am2901x4 (&bsp, cmc);
+
+ /* Store data */
+ switch (cmc->oa)
+ {
+ case S_RAMD:
+ vs.ramlatch = bsp.y;
+ if (cmc->iif==S_RAMDE && (cmc->rsel == 0) && (cmc->rwrite == 0))
+ vs.sram[cmc->x] = vs.ramlatch;
+ break;
+ case S_ROMA:
+ vs.rom_adr = bsp.y;
+ break;
+ case S_SREG:
+ /* FPOS is shifted into sreg */
+ vgen.sreg = (vgen.sreg >> 1) | ((bsp.f >> 9) & 4);
+ break;
+ default:
+ break;
+ }
+
+ /* Vector generator setup */
+ switch (cmc->of)
+ {
+ case 0:
+ vgen.color = bsp.y & 0xfff;
+ break;
+ case 1:
+ vgen.intensity = bsp.y & 0xff;
+ break;
+ case 2:
+ vgen.l1 = bsp.y & 0xfff;
+ vgen.adder_s = 0;
+ vgen.adder_a = vgen.l2;
+ vgen.hud1 = vgen.sreg & 1;
+ vgen.vud1 = vgen.sreg & 2;
+ vgen.hc1 = vgen.sreg & 4;
+ vgen.brez = 1;
+ break;
+ case 3:
+ vgen.l2 = bsp.y & 0xfff;
+ vgen.adder_s = (vgen.adder_s + vgen.adder_a) & 0xfff;
+ if (vgen.adder_s & 0x800)
+ vgen.adder_a = vgen.l1;
+ else
+ vgen.adder_a = vgen.l2;
+ vgen.hud2 = vgen.sreg & 1;
+ vgen.vud2 = vgen.sreg & 2;
+ break;
+ case 4:
+ vgen.c_v = bsp.y & 0xfff;
+ break;
+ case 5:
+ vgen.c_h = bsp.y & 0xfff;
+ break;
+ case 6:
+ /* Loading the c_l counter starts
+ * the vector counters if MSB is set
+ */
+ vgen.c_l = bsp.y & 0xfff;
+ break;
+ }
+
+ vertigo_vgen (&vgen);
+
+ /* Microcode program flow */
+ switch (cmc->jcon)
+ {
+ case S_MSB:
+ /* ALU most significant bit */
+ jcond = (bsp.f >> 15) & 1;
+ break;
+ case S_FEQ0:
+ /* ALU is 0 */
+ jcond = (bsp.f == 0)? 1 : 0;
+ break;
+ case S_Y10:
+ jcond = (bsp.y >> 10) & 1;
+ break;
+ case S_VFIN:
+ jcond = vgen.vfin;
+ break;
+ case S_FPOS:
+ /* FPOS is bit 11 */
+ jcond = (bsp.f >> 11) & 1;
+ break;
+ case S_INTL4:
+ jcond = irq4;
+ /* Detect idle loop. If the code takes a jump
+ on irq4 or !irq4 the destination is a idle loop
+ waiting for irq4 state change. We then take a short
+ cut and run for just 100 cycles to make sure the
+ loop is actually entered.
+ */
+ if ((cmc->jpos != irq4) && cycles > 100)
+ {
+ cycles=100;
+ }
+ break;
+ default:
+ jcond = 1;
+ break;
+ }
+
+ if (jcond ^ cmc->jpos)
+ {
+ /* Except for JBK, address bit 8 isn't changed
+ in program flow. */
+ switch (cmc->jmp)
+ {
+ case S_JBK:
+ /* JBK is the only jump where MA8 is used */
+ vs.pc = cmc->ma;
+ break;
+ case S_CALL:
+ /* call and store return address */
+ vs.ret = (vs.pc + 1) & 0xff;
+ vs.pc = (vs.pc & 0x100) | (cmc->ma & 0xff);
+ break;
+ case S_OPT:
+ /* OPT is used for microcode jump tables. The first
+ four address bits are defined by bits 12-15
+ of 2901 input (D) */
+ vs.pc = (vs.pc & 0x100) | (cmc->ma & 0xf0) | ((bsp.d >> 12) & 0xf);
+ break;
+ case S_RETURN:
+ /* return from call */
+ vs.pc = (vs.pc & 0x100) | vs.ret;
+ break;
+ }
+ }
+ else
+ {
+ vs.pc = (vs.pc & 0x100) | ((vs.pc + 1) & 0xff);
+ }
+ }
+
+ profiler_mark(PROFILER_END);
+}
diff --git a/src/mame/video/vicdual.c b/src/mame/video/vicdual.c
new file mode 100644
index 00000000000..249627700b1
--- /dev/null
+++ b/src/mame/video/vicdual.c
@@ -0,0 +1,151 @@
+/***************************************************************************
+
+ VIC Dual Game board
+
+****************************************************************************/
+
+#include "driver.h"
+#include "includes/vicdual.h"
+
+
+static UINT8 palette_bank;
+
+
+static pen_t pens_from_color_prom[] =
+{
+ RGB_BLACK,
+ MAKE_RGB(0x00, 0xff, 0x00),
+ MAKE_RGB(0x00, 0x00, 0xff),
+ MAKE_RGB(0x00, 0xff, 0xff),
+ MAKE_RGB(0xff, 0x00, 0x00),
+ MAKE_RGB(0xff, 0xff, 0x00),
+ MAKE_RGB(0xff, 0x00, 0xff),
+ RGB_WHITE
+};
+
+
+WRITE8_HANDLER( vicdual_palette_bank_w )
+{
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ palette_bank = data & 3;
+}
+
+
+VIDEO_UPDATE( vicdual_bw )
+{
+ UINT8 x = 0;
+ UINT8 y = cliprect->min_y;
+ UINT8 video_data = 0;
+
+ while (1)
+ {
+ pen_t pen;
+
+ if ((x & 0x07) == 0)
+ {
+ offs_t offs;
+ UINT8 char_code;
+
+ /* read the character code */
+ offs = (y >> 3 << 5) | (x >> 3);
+ char_code = vicdual_videoram_r(offs);
+
+ /* read the appropriate line of the character ram */
+ offs = (char_code << 3) | (y & 0x07);
+ video_data = vicdual_characterram_r(offs);
+ }
+
+ /* plot the current pixel */
+ pen = (video_data & 0x80) ? RGB_WHITE : RGB_BLACK;
+ *BITMAP_ADDR32(bitmap, y, x) = pen;
+
+ /* next pixel */
+ video_data = video_data << 1;
+ x = x + 1;
+
+ /* end of line? */
+ if (x == 0)
+ {
+ /* end of region to update? */
+ if (y == cliprect->max_y)
+ {
+ break;
+ }
+
+ /* next row */
+ y = y + 1;
+ }
+ }
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( vicdual_color )
+{
+ UINT8 *color_prom = (UINT8 *)memory_region(REGION_PROMS);
+ UINT8 x = 0;
+ UINT8 y = cliprect->min_y;
+ UINT8 video_data = 0;
+ pen_t back_pen = 0;
+ pen_t fore_pen = 0;
+
+ while (1)
+ {
+ pen_t pen;
+
+ if ((x & 0x07) == 0)
+ {
+ offs_t offs;
+ UINT8 char_code;
+
+ /* read the character code */
+ offs = (y >> 3 << 5) | (x >> 3);
+ char_code = vicdual_videoram_r(offs);
+
+ /* read the appropriate line of the character ram */
+ offs = (char_code << 3) | (y & 0x07);
+ video_data = vicdual_characterram_r(offs);
+
+ /* get the foreground and background colors from the PROM */
+ offs = (char_code >> 5) | (palette_bank << 3);
+ back_pen = pens_from_color_prom[(color_prom[offs] >> 1) & 0x07];
+ fore_pen = pens_from_color_prom[(color_prom[offs] >> 5) & 0x07];
+ }
+
+ /* plot the current pixel */
+ pen = (video_data & 0x80) ? fore_pen : back_pen;
+ *BITMAP_ADDR32(bitmap, y, x) = pen;
+
+ /* next pixel */
+ video_data = video_data << 1;
+ x = x + 1;
+
+ /* end of line? */
+ if (x == 0)
+ {
+ /* end of region to update? */
+ if (y == cliprect->max_y)
+ {
+ break;
+ }
+
+ /* next row */
+ y = y + 1;
+ }
+ }
+
+ return 0;
+}
+
+
+VIDEO_UPDATE( vicdual_bw_or_color )
+{
+ if (vicdual_is_cabinet_color())
+ video_update_vicdual_color(machine, screen, bitmap, cliprect);
+ else
+ video_update_vicdual_bw(machine, screen, bitmap, cliprect);
+
+ return 0;
+}
diff --git a/src/mame/video/victory.c b/src/mame/video/victory.c
new file mode 100644
index 00000000000..59c9724aba8
--- /dev/null
+++ b/src/mame/video/victory.c
@@ -0,0 +1,1231 @@
+/***************************************************************************
+
+ Victory video system
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+/* globally-accessible storage */
+UINT8 *victory_charram;
+
+/* local allocated storage */
+static UINT8 *bgbitmap;
+static UINT8 *fgbitmap;
+static UINT8 *bgdirty;
+static UINT8 *chardirty;
+static UINT8 *scandirty;
+static UINT8 *rram, *gram, *bram;
+
+/* interrupt, collision, and control states */
+static UINT8 vblank_irq;
+static UINT8 fgcoll, fgcollx, fgcolly;
+static UINT8 bgcoll, bgcollx, bgcolly;
+static UINT8 scrollx, scrolly;
+static UINT8 update_complete;
+static UINT8 video_control;
+
+/* microcode state */
+static struct
+{
+ UINT16 i;
+ UINT16 pc;
+ UINT8 r,g,b;
+ UINT8 x,xp,y,yp;
+ UINT8 cmd,cmdlo;
+ emu_timer * timer;
+ UINT8 timer_active;
+ attotime endtime;
+} micro;
+
+
+/* number of ticks per clock of the microcode state machine */
+/* from what I can tell, this should be divided by 32, not 8 */
+/* but the interrupt test does some precise timing, and fails */
+/* if it's not 8 */
+#define MICRO_STATE_CLOCK_PERIOD ATTOTIME_IN_HZ(11827000/8)
+
+
+/* debugging constants */
+#define LOG_MICROCODE 0
+#define LOG_COLLISION 0
+
+
+/* function prototypes */
+static int command2(void);
+static int command3(void);
+static int command4(void);
+static int command5(void);
+static int command6(void);
+static int command7(void);
+
+
+
+/*************************************
+ *
+ * Initialize the video system
+ *
+ *************************************/
+
+VIDEO_START( victory )
+{
+ /* allocate bitmapram */
+ rram = auto_malloc(0x4000);
+ gram = auto_malloc(0x4000);
+ bram = auto_malloc(0x4000);
+
+ /* allocate bitmaps */
+ bgbitmap = auto_malloc(256 * 256);
+ fgbitmap = auto_malloc(256 * 256);
+
+ /* allocate dirty maps */
+ bgdirty = auto_malloc(32 * 32);
+ chardirty = auto_malloc(256);
+ scandirty = auto_malloc(512);
+
+ /* mark everything dirty */
+ memset(bgdirty, 1, 32 * 32);
+ memset(chardirty, 1, 256);
+ memset(scandirty, 1, 512);
+
+ /* reset globals */
+ vblank_irq = 0;
+ fgcoll = fgcollx = fgcolly = 0;
+ bgcoll = bgcollx = bgcolly = 0;
+ scrollx = scrolly = 0;
+ update_complete = 0;
+ video_control = 0;
+ memset(&micro, 0, sizeof(micro));
+ micro.timer = timer_alloc(NULL);
+}
+
+
+
+/*************************************
+ *
+ * Interrupt generation
+ *
+ *************************************/
+
+static void victory_update_irq(void)
+{
+ if (vblank_irq || fgcoll || (bgcoll && (video_control & 0x20)))
+ cpunum_set_input_line(0, 0, ASSERT_LINE);
+ else
+ cpunum_set_input_line(0, 0, CLEAR_LINE);
+}
+
+
+INTERRUPT_GEN( victory_vblank_interrupt )
+{
+ vblank_irq = 1;
+ victory_update_irq();
+ logerror("------------- VBLANK ----------------\n");
+}
+
+
+
+/*************************************
+ *
+ * Video RAM write
+ *
+ *************************************/
+
+WRITE8_HANDLER( victory_videoram_w )
+{
+ if (videoram[offset] != data)
+ {
+ videoram[offset] = data;
+ bgdirty[offset] = 1;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Character RAM write
+ *
+ *************************************/
+
+WRITE8_HANDLER( victory_charram_w )
+{
+ if (victory_charram[offset] != data)
+ {
+ victory_charram[offset] = data;
+ chardirty[(offset / 8) % 256] = 1;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM write
+ *
+ *************************************/
+
+WRITE8_HANDLER( victory_paletteram_w )
+{
+ palette_set_color_rgb(Machine, offset & 0x3f, pal3bit(((offset & 0x80) >> 5) | ((data & 0xc0) >> 6)), pal3bit(data >> 0), pal3bit(data >> 3));
+}
+
+
+
+/*************************************
+ *
+ * Video control read
+ *
+ *************************************/
+
+READ8_HANDLER( victory_video_control_r )
+{
+ int result = 0;
+
+ switch (offset)
+ {
+ case 0: /* 5XFIQ */
+ result = fgcollx;
+ if (LOG_COLLISION) logerror("%04X:5XFIQ read = %02X\n", activecpu_get_previouspc(), result);
+ return result;
+
+ case 1: /* 5CLFIQ */
+ result = fgcolly;
+ if (fgcoll)
+ {
+ fgcoll = 0;
+ victory_update_irq();
+ }
+ if (LOG_COLLISION) logerror("%04X:5CLFIQ read = %02X\n", activecpu_get_previouspc(), result);
+ return result;
+
+ case 2: /* 5BACKX */
+ result = bgcollx & 0xfc;
+ if (LOG_COLLISION) logerror("%04X:5BACKX read = %02X\n", activecpu_get_previouspc(), result);
+ return result;
+
+ case 3: /* 5BACKY */
+ result = bgcolly;
+ if (bgcoll)
+ {
+ bgcoll = 0;
+ victory_update_irq();
+ }
+ if (LOG_COLLISION) logerror("%04X:5BACKY read = %02X\n", activecpu_get_previouspc(), result);
+ return result;
+
+ case 4: /* 5STAT */
+ // D7 = BUSY (9A1) -- microcode
+ // D6 = 5FCIRQ (3B1)
+ // D5 = 5VIRQ
+ // D4 = 5BCIRQ (3B1)
+ // D3 = SL256
+ if (micro.timer_active && attotime_compare(timer_timeelapsed(micro.timer), micro.endtime) < 0)
+ result |= 0x80;
+ result |= (~fgcoll & 1) << 6;
+ result |= (~vblank_irq & 1) << 5;
+ result |= (~bgcoll & 1) << 4;
+ result |= (video_screen_get_vpos(0) & 0x100) >> 5;
+ if (LOG_COLLISION) logerror("%04X:5STAT read = %02X\n", activecpu_get_previouspc(), result);
+ return result;
+
+ default:
+ logerror("%04X:victory_video_control_r(%02X)\n", activecpu_get_previouspc(), offset);
+ break;
+ }
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Video control write
+ *
+ *************************************/
+
+WRITE8_HANDLER( victory_video_control_w )
+{
+ switch (offset)
+ {
+ case 0: /* LOAD IL */
+ if (LOG_MICROCODE) logerror("%04X:IL=%02X\n", activecpu_get_previouspc(), data);
+ micro.i = (micro.i & 0xff00) | (data & 0x00ff);
+ break;
+
+ case 1: /* LOAD IH */
+ if (LOG_MICROCODE) logerror("%04X:IH=%02X\n", activecpu_get_previouspc(), data);
+ micro.i = (micro.i & 0x00ff) | ((data << 8) & 0xff00);
+ if (micro.cmdlo == 5)
+ {
+ if (LOG_MICROCODE) logerror(" Command 5 triggered by write to IH\n");
+ command5();
+ }
+ break;
+
+ case 2: /* LOAD CMD */
+ if (LOG_MICROCODE) logerror("%04X:CMD=%02X\n", activecpu_get_previouspc(), data);
+ micro.cmd = data;
+ micro.cmdlo = data & 7;
+ if (micro.cmdlo == 0)
+ logerror(" Command 0 triggered\n");
+ else if (micro.cmdlo == 1)
+ logerror(" Command 1 triggered\n");
+ else if (micro.cmdlo == 6)
+ {
+ if (LOG_MICROCODE) logerror(" Command 6 triggered\n");
+ command6();
+ }
+ break;
+
+ case 3: /* LOAD G */
+ if (LOG_MICROCODE) logerror("%04X:G=%02X\n", activecpu_get_previouspc(), data);
+ micro.g = data;
+ break;
+
+ case 4: /* LOAD X */
+ if (LOG_MICROCODE) logerror("%04X:X=%02X\n", activecpu_get_previouspc(), data);
+ micro.xp = data;
+ if (micro.cmdlo == 3)
+ {
+ if (LOG_MICROCODE) logerror(" Command 3 triggered by write to X\n");
+ command3();
+ }
+ break;
+
+ case 5: /* LOAD Y */
+ if (LOG_MICROCODE) logerror("%04X:Y=%02X\n", activecpu_get_previouspc(), data);
+ micro.yp = data;
+ if (micro.cmdlo == 4)
+ {
+ if (LOG_MICROCODE) logerror(" Command 4 triggered by write to Y\n");
+ command4();
+ }
+ break;
+
+ case 6: /* LOAD R */
+ if (LOG_MICROCODE) logerror("%04X:R=%02X\n", activecpu_get_previouspc(), data);
+ micro.r = data;
+ break;
+
+ case 7: /* LOAD B */
+ if (LOG_MICROCODE) logerror("%04X:B=%02X\n", activecpu_get_previouspc(), data);
+ micro.b = data;
+ if (micro.cmdlo == 2)
+ {
+ if (LOG_MICROCODE) logerror(" Command 2 triggered by write to B\n");
+ command2();
+ }
+ else if (micro.cmdlo == 7)
+ {
+ if (LOG_MICROCODE) logerror(" Command 7 triggered by write to B\n");
+ command7();
+ }
+ break;
+
+ case 8: /* SCROLLX */
+ if (LOG_MICROCODE) logerror("%04X:SCROLLX write = %02X\n", activecpu_get_previouspc(), data);
+ scrollx = data;
+ break;
+
+ case 9: /* SCROLLY */
+ if (LOG_MICROCODE) logerror("%04X:SCROLLY write = %02X\n", activecpu_get_previouspc(), data);
+ scrolly = data;
+ break;
+
+ case 10: /* CONTROL */
+ // D7 = HLMBK
+ // D6 = VLMBK
+ // D5 = BIRQEA
+ // D4 = SEL5060
+ // D3 = SINVERT
+ // D2 = BIR12
+ // D1 = SELOVER
+ if (LOG_MICROCODE) logerror("%04X:CONTROL write = %02X\n", activecpu_get_previouspc(), data);
+ video_control = data;
+ break;
+
+ case 11: /* CLRVIRQ */
+ if (LOG_MICROCODE) logerror("%04X:CLRVIRQ write = %02X\n", activecpu_get_previouspc(), data);
+ vblank_irq = 0;
+ victory_update_irq();
+ break;
+
+ default:
+ if (LOG_MICROCODE) logerror("%04X:victory_video_control_w(%02X) = %02X\n", activecpu_get_previouspc(), offset, data);
+ break;
+ }
+}
+
+
+/***************************************************************************************************
+
+ Victory Microcode
+ -----------------
+
+ The cool thing about this hardware is the use of microcode, which is like having a little
+ graphics coprocessor around to do the hard stuff. The operations that can be performed by
+ this bit of circuitry include pixel plotting, line drawing, sprite drawing, and data
+ transfer, all with optional collision detection. In addition, data can be uploaded into
+ the $2000-$21FF address range and then "executed" as mini subroutines.
+
+ Commands to the microcode are written to the command register at $C102, followed by
+ whatever parameters are needed. Parameters are stored in registers. There are a number
+ of registers, accessed at these addresses:
+
+ C100-C101: I (16 bits)
+ C102: CMD (8 bits)
+ C103: G (8 bits)
+ C104: X' (8 bits)
+ C105: Y' (8 bits)
+ C106: R (8 bits)
+ C107: B (8 bits)
+
+ Writing the last parameter triggers the command. There are a total of 6 commands supported:
+
+ command 2: copy data
+ when register B is written, take the bytes from R, G and B and transfer them
+ into video RAM at address I
+
+ command 3: draw sprite
+ when register X is written, draw a sprite at location (X,Y) using the data from
+ video RAM address I; the width is given by (R >> 5) * 8, and then height is
+ given by (R & 31) * 2; data is XORed with the current VRAM contents
+
+ command 4: execute program
+ when register Y is written, copy Y * 2 to the PC and begin executing the commands
+ at ($2000 + PC); each command loads 6 bytes from VRAM into registers CMD,X,Y,I and R;
+ the program stops executing after it receives a command with the high bit off
+
+ command 5: draw vector
+ when register IH is written, draw a vector of length IL starting at location (X,Y);
+ IH serves as the bresenhem increment for the minor axis; bits 4-6 of the command
+ select which octant to draw into; each VRAM write XORs the data from R,G and B
+ with the current VRAM contents
+
+ command 6: copy data
+ when the command is written, copy (R & 31) * 2 bytes of data from video RAM location
+ I to video RAM location ($2000 + PC)
+
+ command 7: plot pixel
+ when register B is written, take the bytes from R, G and B and XOR them with the
+ video RAM contents at (X,Y)
+
+ The command register is actually broken down into bitfields as follows:
+
+ D7 -> must be high for a program to continue execution; otherwise, it will stop
+ D4-D6 -> for non-vector commands, enables VRAM writes to the red, blue and green planes
+ D3 -> enable collision detection for commands 3,5,7
+ D0-D2 -> command
+
+ The microcode is actually a big state machine, driven by the 4 PROMs at 19B,19C,19D and 19E.
+ Below are some of the gory details of the state machine.
+
+***************************************************************************************************
+
+ 19E:
+ D7 -> inverter -> ZERO RAM [11C8, 13D8]
+ D6 -> select on the mux at 18F
+ D5 -> BUSY [4B6]
+ D4 -> D on flip flop at 16E
+ D3 -> D3 of alternate selection from mux at 18F
+ D2 -> D2 of alternate selection from mux at 18F
+ D1 -> D1 of alternate selection from mux at 18F
+ D0 -> D0 of alternate selection from mux at 18F
+
+ 19B:
+ D7 -> S LOAD LH [11B8]
+ D6 -> INC I (AND with WRITE EA) [8A8]
+ D5 -> S INC Y (AND with WRITE EA) [8C8]
+ D4 -> SXFERY (AND with WRITE EA) [8C8]
+ D3 -> D on flip flop at 15E, output goes to SADDX [8C8]
+ D2 -> S LOAD PC [8B8]
+ D1 -> CPU0 [11C8, 13C7]
+ D0 -> INC X (AND with WRITE EA) [8C8]
+
+ 19C:
+ D7 -> SXFERX/INC X (AND with WRITE EA) [8C8, 11B8, 12C8]
+ D6 -> see D5
+ D5 -> selects one of 4 with D6:
+ 0 -> SEA VDATA
+ 1 -> SEA BUFF
+ 2 -> SEA SR 1
+ 3 -> SEA SR 2
+ D4 -> ADD 128 [11C8, 12C8]
+ also: S ACC CLEAR (AND with WRITE EA) [10B8]
+ D3 -> S ACC CLK (AND with S SEQ CLK) [10B8]
+ D2 -> INC PC [8B8]
+ D1 -> INC L [11B8]
+ D0 -> INC H [11B8]
+
+ 19D:
+ D7 -> S W VRAM (AND with WRITE EA) [14A8]
+ D6 -> S WRITE BUSS1 (AND with WRITE EA) [7A8]
+ D5 -> S WRITE BUSS2 (AND with WRITE EA) [7A8]
+ D4 -> D2 of alternate selection from mux at 18E
+ D3 -> D1 of alternate selection from mux at 18E
+ D2 -> D0 of alternate selection from mux at 18E
+ D1 -> ASEL1 (AND with WRITE EA) [8D8]
+ D0 -> ASEL0 (AND with WRITE EA) [8D8]
+
+
+ Always on in non-zero states: BUSY, CPU0
+
+ State Next ASEL SEA Interesting bits
+ ----- ---- ---- --- --------------------------------------------
+ 00 /SETRDY ? 00 : 01 3 0 None
+ 01 CM0-2 0 0
+ 02 00 0 0 ZERORAM, INCI, SWVRAM
+ 03 1C 2 0 SLOADLH, SXFERY
+ 04 1A 2 0 SLOADPC
+ 05 0A 1 0 SXFERY, ADD128+SACCCLEAR, SACCCLK
+ 06 0C 0 0 SLOADLH, SLOADPC
+ 07 08 1 0 SXFERY, SXFERX+INCX
+ 08 09 1 2 INCX, SWVRAM
+ 09 00 1 3 SWVRAM
+ 0A VFIN ? 19 : 0B 1 0 SXFERX+INCX
+ 0B 0A 1 2 INCI, SACCCLK, SWVRAM
+ 0C 0D 0 1 INCI, SXFERX+INCX, INCL
+ 0D /LTC ? 0C : 0E 2 2 ZERORAM, INCPC, SWVRAM
+ 0E 19 2 2
+
+ 19 /CM7 ? 00 : 1A 2 0
+ 1A 1B 2 0 INCPC, SWRITEBUSS1
+ 1B 01 2 0 INCPC, SWRITEBUSS2
+ 1C HTC ? 19 : 1D 0 1
+ 1D 1E 1 2 INCX, SXFERX+INCX, INCL, SWVRAM
+ 1E /LTC ? 1C : 1F 1 3 INCI, SINCY, SWVRAM
+ 1F 1C 1 0 ZERORAM, SXFERY, SADDX, INCH
+
+Registers:
+
+ X' = 8-bit value = 2 x 4-bit counters at 11B/13B
+ SADDX -> enables clock to count
+ LF/RT -> controls direction of counting
+ SLDX -> loads data from RED VRAM or D0-D7 into X'
+ OUT -> to X
+
+ X = 8-bit value = 2 x 4-bit counters at 12D/13D
+ SINCX -> enables clock to count
+ SXFERX -> loads data from X' into X, with an XOR of 7
+ OUT -> to X1-X128
+
+ Y' = 8-bit value = 8-bit latch
+ SLDY -> loads data from BLUE VRAM or D0-D7 into Y'
+ OUT -> to Y
+
+ Y = 8-bit value = 2 x 4-bit counters at 10B/8B
+ SINCY -> enables clock to count
+ SXFERY -> loads data from Y' into Y
+ OUT -> to Y1-Y128
+
+ I = 16-bit value = 4 x 4-bit counters at 12C/11C/12B/14B
+ INCI -> enables clock to count
+ SLDIH -> loads data from BLUE VRAM or D0-D7 into upper 8 bits of I
+ SLDIL -> loads data from RED VRAM or D0-D7 into lower 8 bits of I
+ OUT -> to I1-I32000
+
+ PC = 9-bit value = 2 x 4-bit counters at 9B/7B plus JK flip-flop at 12E
+ INCPC -> toggles flip-flop and increments
+ SLOADPC-> loads data from Y' into PC
+
+ L = 5-bit value = 2 x 4-bit counters at 3H/4H
+ INCL -> enables clock to count
+ SLOADLH-> loads data from SEA
+
+ H = 3-bit value = 1 x 4-bit counter at 5H
+ INCH -> enables clock to count
+ SLOADLH-> loads data from SEA
+
+ 14-bit VRAM address comes from one of several sources, depending on ASEL
+ ASEL0 -> I & 0x3fff
+ ASEL1 -> ((Y & 0xff) << 5) | ((X & 0xff) >> 3)
+ ASEL2 -> 0x2000 | (PC & 0x1ff)
+ ASEL3 -> ((L & 0xff) << 5) | ((E & 0xff) >> 3) [video refresh]
+
+***************************************************************************************************/
+
+
+/*************************************
+ *
+ * Microcode timing
+ *
+ *************************************/
+
+INLINE void count_states(int states)
+{
+ attotime state_time = attotime_make(0, attotime_to_attoseconds(MICRO_STATE_CLOCK_PERIOD) * states);
+
+ if (!micro.timer)
+ {
+ timer_adjust(micro.timer, attotime_never, 0, attotime_zero);
+ micro.timer_active = 1;
+ micro.endtime = state_time;
+ }
+ else if (attotime_compare(timer_timeelapsed(micro.timer), micro.endtime) > 0)
+ {
+ timer_adjust(micro.timer, attotime_never, 0, attotime_zero);
+ micro.timer_active = 1;
+ micro.endtime = state_time;
+ }
+ else
+ micro.endtime = attotime_add(micro.endtime, state_time);
+}
+
+
+/*************************************
+ *
+ * Microcode command 2:
+ * Load data from R/G/B
+ *
+ *************************************/
+
+static int command2(void)
+{
+/*
+ Actual microcode:
+ 02 00 0 0 ZERORAM, INCI, SWVRAM
+
+ Basic gist of things:
+ WRITE
+ I++
+ goto state00
+*/
+ int addr = micro.i++ & 0x3fff;
+
+ if (micro.cmd & 0x10)
+ gram[addr] = micro.g;
+ if (micro.cmd & 0x20)
+ bram[addr] = micro.b;
+ if (micro.cmd & 0x40)
+ rram[addr] = micro.r;
+
+ scandirty[addr >> 5] = 1;
+ count_states(3);
+ return 0;
+}
+
+
+/*************************************
+ *
+ * Microcode command 3:
+ * Draw sprite from I to (X,Y)
+ *
+ *************************************/
+
+static int command3(void)
+{
+/*
+ Actual microcode:
+ 03 1C 2 0 SLOADLH, SXFERY
+ 1C HTC ? 19 : 1D 0 1
+ 1D 1E 1 2 INCX, SXFERX+INCX, INCL, SWVRAM
+ 1E /LTC ? 1C : 1F 1 3 INCI, SINCY, SWVRAM
+ 1F 1C 1 0 ZERORAM, SXFERY, SADDX, INCH
+
+ Basic gist of things:
+ H = R >> 5
+ L = (R & 0x1f) << 1
+ Y = Y'
+ state1C:
+ if (H & 8) goto state19
+ X = X'; L++
+ WRITE
+ I++; Y++
+ if ((L & 0x20) == 0) goto state1C
+ Y = Y'; X'++; H++
+ goto state1C
+*/
+ int ycount = 64 - (micro.r & 31) * 2;
+ int xcount = 8 - (micro.r >> 5);
+ int shift = micro.xp & 7;
+ int nshift = 8 - shift;
+ int x, y, sy;
+
+ for (x = 0; x < xcount; x++, micro.xp += 8)
+ {
+ sy = micro.yp;
+
+ for (y = 0; y < ycount; y++)
+ {
+ int srcoffs = micro.i++ & 0x3fff;
+ int dstoffs = (sy++ & 0xff) * 32 + micro.xp / 8;
+ UINT8 src;
+
+ /* non-collision-detect case */
+ if (!(micro.cmd & 0x08) || fgcoll)
+ {
+ if (micro.cmd & 0x10)
+ {
+ src = gram[srcoffs];
+ gram[dstoffs + 0] ^= src >> shift;
+ gram[dstoffs + 1] ^= src << nshift;
+ }
+ if (micro.cmd & 0x20)
+ {
+ src = bram[srcoffs];
+ bram[dstoffs + 0] ^= src >> shift;
+ bram[dstoffs + 1] ^= src << nshift;
+ }
+ if (micro.cmd & 0x40)
+ {
+ src = rram[srcoffs];
+ rram[dstoffs + 0] ^= src >> shift;
+ rram[dstoffs + 1] ^= src << nshift;
+ }
+ }
+
+ /* collision-detect case */
+ else
+ {
+ if (micro.cmd & 0x10)
+ {
+ src = gram[srcoffs];
+ if ((gram[dstoffs + 0] & (src >> shift)) | (gram[dstoffs + 1] & (src << nshift)))
+ fgcoll = 1, fgcollx = micro.xp, fgcolly = sy - 1;
+ gram[dstoffs + 0] ^= src >> shift;
+ gram[dstoffs + 1] ^= src << nshift;
+ }
+ if (micro.cmd & 0x20)
+ {
+ src = bram[srcoffs];
+ if ((bram[dstoffs + 0] & (src >> shift)) | (bram[dstoffs + 1] & (src << nshift)))
+ fgcoll = 1, fgcollx = micro.xp, fgcolly = sy - 1;
+ bram[dstoffs + 0] ^= src >> shift;
+ bram[dstoffs + 1] ^= src << nshift;
+ }
+ if (micro.cmd & 0x40)
+ {
+ src = rram[srcoffs];
+ if ((rram[dstoffs + 0] & (src >> shift)) | (rram[dstoffs + 1] & (src << nshift)))
+ fgcoll = 1, fgcollx = micro.xp, fgcolly = sy - 1;
+ rram[dstoffs + 0] ^= src >> shift;
+ rram[dstoffs + 1] ^= src << nshift;
+ }
+ if (fgcoll) victory_update_irq();
+ }
+ }
+ }
+
+ /* mark scanlines dirty */
+ sy = micro.yp;
+ for (y = 0; y < ycount; y++)
+ scandirty[sy++ & 0xff] = 1;
+
+ count_states(3 + (2 + 2 * ycount) * xcount);
+
+ return micro.cmd & 0x80;
+}
+
+
+/*************************************
+ *
+ * Microcode command 4:
+ * Execute commands at (Y * 2)
+ *
+ *************************************/
+
+static int command4(void)
+{
+/*
+ Actual microcode:
+ 04 1A 2 0 SLOADPC
+ 1A 1B 2 0 INCPC, SWRITEBUSS1
+ 1B 01 2 0 INCPC, SWRITEBUSS2
+
+ Basic gist of things:
+ PC = Y' << 1
+ CM = GREEN[PC]
+ I = (BLUE[PC] << 8) + RED[PC]
+ PC++
+ R = GREEN[PC]
+ X' = RED[PC]
+ Y' = BLUE[PC]
+ PC++
+ goto state01
+*/
+ int keep_going = 0;
+
+ if (LOG_MICROCODE) logerror("================= EXECUTE BEGIN\n");
+
+ count_states(4);
+
+ micro.pc = micro.yp << 1;
+ do
+ {
+ micro.cmd = gram[0x2000 + micro.pc];
+ micro.cmdlo = micro.cmd & 7;
+ micro.i = (bram[0x2000 + micro.pc] << 8) | rram[0x2000 + micro.pc];
+ micro.r = gram[0x2001 + micro.pc];
+ micro.xp = rram[0x2001 + micro.pc];
+ micro.yp = bram[0x2001 + micro.pc];
+ if (LOG_MICROCODE) logerror("PC=%03X CMD=%02X I=%04X R=%02X X=%02X Y=%02X\n", micro.pc, micro.cmd, micro.i, micro.r, micro.xp, micro.yp);
+ micro.pc = (micro.pc + 2) & 0x1ff;
+
+ switch (micro.cmdlo)
+ {
+ case 0: break;
+ case 1: break;
+ case 2: keep_going = command2(); break;
+ case 3: keep_going = command3(); break;
+ case 4: micro.pc = micro.yp << 1; keep_going = 1; break;
+ case 5: keep_going = command5(); break;
+ case 6: keep_going = command6(); break;
+ case 7: keep_going = command7(); break;
+ }
+ } while (keep_going);
+
+ if (LOG_MICROCODE) logerror("================= EXECUTE END\n");
+
+ return micro.cmd & 0x80;
+}
+
+
+/*************************************
+ *
+ * Microcode command 5:
+ * Draw vector from (X,Y)
+ *
+ *************************************/
+
+static int command5(void)
+{
+/*
+ Actual microcode:
+ 05 0A 1 0 SXFERY, ADD128+SACCCLEAR, SACCCLK
+ 0A VFIN ? 19 : 0B 1 0 SXFERX+INCX
+ 0B 0A 1 2 INCI, SACCCLK, SWVRAM
+
+ Basic gist of things:
+ Y = Y'; ACC = 128
+ X = X'/CLOCK SR
+ while (!(IL & 0x100))
+ {
+ IL++; ACC += IH
+ adjust X,Y based on carry
+ WRITE(X,Y) [SR1]
+ }
+
+ line draw: one of 8 cases based on VDATA
+
+ no carry carry
+ -------- -----
+ case 0: 1011 -> X++, Y 1101 -> X++, Y--
+ case 1: 0101 -> X, Y-- 1101 -> X++, Y--
+ case 2: 0101 -> X, Y-- 1100 -> X--, Y--
+ case 3: 1010 -> X--, Y 1100 -> X--, Y--
+ case 4: 1010 -> X--, Y 1110 -> X--, Y++
+ case 5: 0111 -> X, Y++ 1110 -> X--, Y++
+ case 6: 0111 -> X, Y++ 1111 -> X++, Y++
+ case 7: 1011 -> X++, Y 1111 -> X++, Y++
+
+*/
+ static const INT8 inctable[8][4] =
+ {
+ { 1, 0, 1,-1 },
+ { 0,-1, 1,-1 },
+ { 0,-1,-1,-1 },
+ { -1, 0,-1,-1 },
+ { -1, 0,-1, 1 },
+ { 0, 1,-1, 1 },
+ { 0, 1, 1, 1 },
+ { 1, 0, 1, 1 }
+ };
+
+ int xinc = inctable[(micro.cmd >> 4) & 7][0];
+ int yinc = inctable[(micro.cmd >> 4) & 7][1];
+ int xincc = inctable[(micro.cmd >> 4) & 7][2];
+ int yincc = inctable[(micro.cmd >> 4) & 7][3];
+ UINT8 x = micro.xp;
+ UINT8 y = micro.yp;
+ int acc = 0x80;
+ int i = micro.i >> 8;
+ int c;
+
+ /* non-collision-detect case */
+ if (!(micro.cmd & 0x08) || fgcoll)
+ {
+ for (c = micro.i & 0xff; c < 0x100; c++)
+ {
+ int addr = y * 32 + x / 8;
+ int shift = x & 7;
+ int nshift = 8 - shift;
+
+ gram[addr + 0] ^= micro.g >> shift;
+ gram[addr + 1] ^= micro.g << nshift;
+ bram[addr + 0] ^= micro.b >> shift;
+ bram[addr + 1] ^= micro.b << nshift;
+ rram[addr + 0] ^= micro.r >> shift;
+ rram[addr + 1] ^= micro.r << nshift;
+ scandirty[y] = 1;
+
+ acc += i;
+ if (acc & 0x100)
+ {
+ x += xincc;
+ y += yincc;
+ }
+ else
+ {
+ x += xinc;
+ y += yinc;
+ }
+ acc &= 0xff;
+ }
+ }
+
+ /* collision-detect case */
+ else
+ {
+ for (c = micro.i & 0xff; c < 0x100; c++)
+ {
+ int addr = y * 32 + x / 8;
+ int shift = x & 7;
+ int nshift = 8 - shift;
+
+ if ((gram[addr + 0] & (micro.g >> shift)) | (gram[addr + 1] & (micro.g << nshift)) |
+ (bram[addr + 0] & (micro.b >> shift)) | (bram[addr + 1] & (micro.b << nshift)) |
+ (rram[addr + 0] & (micro.r >> shift)) | (rram[addr + 1] & (micro.r << nshift)))
+ fgcoll = 1, fgcollx = x, fgcolly = y;
+
+ gram[addr + 0] ^= micro.g >> shift;
+ gram[addr + 1] ^= micro.g << nshift;
+ bram[addr + 0] ^= micro.b >> shift;
+ bram[addr + 1] ^= micro.b << nshift;
+ rram[addr + 0] ^= micro.r >> shift;
+ rram[addr + 1] ^= micro.r << nshift;
+ scandirty[y] = 1;
+
+ acc += i;
+ if (acc & 0x100)
+ {
+ x += xincc;
+ y += yincc;
+ }
+ else
+ {
+ x += xinc;
+ y += yinc;
+ }
+ acc &= 0xff;
+ }
+ if (fgcoll) victory_update_irq();
+ }
+
+ micro.xp = x;
+
+ count_states(3 + 2 * (0x100 - (micro.i & 0xff)));
+
+ return micro.cmd & 0x80;
+}
+
+
+/*************************************
+ *
+ * Microcode command 6:
+ * Copy data from I to (Y * 2)
+ *
+ *************************************/
+
+static int command6(void)
+{
+/*
+ Actual microcode:
+ 06 0C 0 0 SLOADLH, SLOADPC
+ 0C 0D 0 1 INCI, SXFERX+INCX, INCL
+ 0D /LTC ? 0C : 0E 2 2 ZERORAM, INCPC, SWVRAM
+ 0E 19 2 2
+
+ Basic gist of things:
+ H = R >> 5
+ L = (R & 0x1f) << 1
+ PC = Y'
+ state0C:
+ I++; X = X'; L++
+ WRITE(I, *PC)
+ PC++
+ if ((L & 0x20) == 0) goto state1C
+*/
+ int i;
+
+ micro.pc = micro.yp << 1;
+ for (i = (micro.r & 31) << 1; i < 64; i++)
+ {
+ int saddr = micro.i++ & 0x3fff;
+ int daddr = 0x2000 + micro.pc++;
+ micro.pc &= 0x1ff;
+
+ if (micro.cmd & 0x10)
+ gram[daddr] = gram[saddr];
+ if (micro.cmd & 0x20)
+ bram[daddr] = bram[saddr];
+ if (micro.cmd & 0x40)
+ rram[daddr] = rram[saddr];
+
+ scandirty[daddr >> 5] = 1;
+ }
+
+ count_states(3 + 2 * (64 - (micro.r & 31) * 2));
+
+ return micro.cmd & 0x80;
+}
+
+
+/*************************************
+ *
+ * Microcode command 7:
+ * Draw pixels to (X,Y)
+ *
+ *************************************/
+
+static int command7(void)
+{
+/*
+ Actual microcode:
+ 07 08 1 0 SXFERY, SXFERX+INCX
+ 08 09 1 2 INCX, SWVRAM
+ 09 00 1 3 SWVRAM
+
+ Basic gist of things:
+ Y = Y'
+ X = X'/CLOCK SR
+ WRITE SR1
+ X++
+ WRITE SR2
+*/
+ int addr = micro.yp * 32 + micro.xp / 8;
+ int shift = micro.xp & 7;
+ int nshift = 8 - shift;
+
+ /* non-collision-detect case */
+ if (!(micro.cmd & 0x08) || fgcoll)
+ {
+ if (micro.cmd & 0x10)
+ {
+ gram[addr + 0] ^= micro.g >> shift;
+ gram[addr + 1] ^= micro.g << nshift;
+ }
+ if (micro.cmd & 0x20)
+ {
+ bram[addr + 0] ^= micro.b >> shift;
+ bram[addr + 1] ^= micro.b << nshift;
+ }
+ if (micro.cmd & 0x40)
+ {
+ rram[addr + 0] ^= micro.r >> shift;
+ rram[addr + 1] ^= micro.r << nshift;
+ }
+ }
+
+ /* collision-detect case */
+ else
+ {
+ if (micro.cmd & 0x10)
+ {
+ if ((gram[addr + 0] & (micro.g >> shift)) | (gram[addr + 1] & (micro.g << nshift)))
+ fgcoll = 1, fgcollx = micro.xp + 8, fgcolly = micro.yp;
+ gram[addr + 0] ^= micro.g >> shift;
+ gram[addr + 1] ^= micro.g << nshift;
+ }
+ if (micro.cmd & 0x20)
+ {
+ if ((bram[addr + 0] & (micro.b >> shift)) | (bram[addr + 1] & (micro.b << nshift)))
+ fgcoll = 1, fgcollx = micro.xp + 8, fgcolly = micro.yp;
+ bram[addr + 0] ^= micro.b >> shift;
+ bram[addr + 1] ^= micro.b << nshift;
+ }
+ if (micro.cmd & 0x40)
+ {
+ if ((rram[addr + 0] & (micro.r >> shift)) | (rram[addr + 1] & (micro.r << nshift)))
+ fgcoll = 1, fgcollx = micro.xp + 8, fgcolly = micro.yp;
+ rram[addr + 0] ^= micro.r >> shift;
+ rram[addr + 1] ^= micro.r << nshift;
+ }
+ if (fgcoll) victory_update_irq();
+ }
+
+ count_states(4);
+
+ scandirty[micro.yp] = 1;
+ return micro.cmd & 0x80;
+}
+
+
+/*************************************
+ *
+ * Background update
+ *
+ *************************************/
+
+static void update_background(void)
+{
+ int x, y, row, offs;
+
+ /* update the background and any dirty characters in it */
+ for (y = offs = 0; y < 32; y++)
+ for (x = 0; x < 32; x++, offs++)
+ {
+ int code = videoram[offs];
+
+ /* see if the videoram or character RAM has changed, redraw it */
+ if (bgdirty[offs] || chardirty[code])
+ {
+ for (row = 0; row < 8; row++)
+ {
+ UINT8 pix2 = victory_charram[0x0000 + 8 * code + row];
+ UINT8 pix1 = victory_charram[0x0800 + 8 * code + row];
+ UINT8 pix0 = victory_charram[0x1000 + 8 * code + row];
+ UINT8 *dst = &bgbitmap[(y * 8 + row) * 256 + x * 8];
+
+ *dst++ = ((pix2 & 0x80) >> 5) | ((pix1 & 0x80) >> 6) | ((pix0 & 0x80) >> 7);
+ *dst++ = ((pix2 & 0x40) >> 4) | ((pix1 & 0x40) >> 5) | ((pix0 & 0x40) >> 6);
+ *dst++ = ((pix2 & 0x20) >> 3) | ((pix1 & 0x20) >> 4) | ((pix0 & 0x20) >> 5);
+ *dst++ = ((pix2 & 0x10) >> 2) | ((pix1 & 0x10) >> 3) | ((pix0 & 0x10) >> 4);
+ *dst++ = ((pix2 & 0x08) >> 1) | ((pix1 & 0x08) >> 2) | ((pix0 & 0x08) >> 3);
+ *dst++ = ((pix2 & 0x04) ) | ((pix1 & 0x04) >> 1) | ((pix0 & 0x04) >> 2);
+ *dst++ = ((pix2 & 0x02) << 1) | ((pix1 & 0x02) ) | ((pix0 & 0x02) >> 1);
+ *dst++ = ((pix2 & 0x01) << 2) | ((pix1 & 0x01) << 1) | ((pix0 & 0x01) );
+ }
+ bgdirty[offs] = 0;
+ }
+ }
+
+ /* reset the char dirty array */
+ memset(chardirty, 0, 256);
+}
+
+
+/*************************************
+ *
+ * Foreground update
+ *
+ *************************************/
+
+static void update_foreground(void)
+{
+ int x, y;
+
+ /* update the foreground's dirty scanlines */
+ for (y = 0; y < 256; y++)
+ if (scandirty[y])
+ {
+ UINT8 *dst = &fgbitmap[y * 256];
+
+ /* assemble the RGB bits for each 8-pixel chunk */
+ for (x = 0; x < 256; x += 8)
+ {
+ UINT8 g = gram[y * 32 + x / 8];
+ UINT8 b = bram[y * 32 + x / 8];
+ UINT8 r = rram[y * 32 + x / 8];
+
+ *dst++ = ((r & 0x80) >> 5) | ((b & 0x80) >> 6) | ((g & 0x80) >> 7);
+ *dst++ = ((r & 0x40) >> 4) | ((b & 0x40) >> 5) | ((g & 0x40) >> 6);
+ *dst++ = ((r & 0x20) >> 3) | ((b & 0x20) >> 4) | ((g & 0x20) >> 5);
+ *dst++ = ((r & 0x10) >> 2) | ((b & 0x10) >> 3) | ((g & 0x10) >> 4);
+ *dst++ = ((r & 0x08) >> 1) | ((b & 0x08) >> 2) | ((g & 0x08) >> 3);
+ *dst++ = ((r & 0x04) ) | ((b & 0x04) >> 1) | ((g & 0x04) >> 2);
+ *dst++ = ((r & 0x02) << 1) | ((b & 0x02) ) | ((g & 0x02) >> 1);
+ *dst++ = ((r & 0x01) << 2) | ((b & 0x01) << 1) | ((g & 0x01) );
+ }
+ scandirty[y] = 0;
+ }
+}
+
+
+static TIMER_CALLBACK( bgcoll_irq_callback )
+{
+ bgcollx = param & 0xff;
+ bgcolly = param >> 8;
+ bgcoll = 1;
+ victory_update_irq();
+}
+
+
+
+/*************************************
+ *
+ * End-of-frame callback
+ *
+ *************************************/
+
+VIDEO_EOF( victory )
+{
+ int bgcollmask = (video_control & 4) ? 4 : 7;
+ int count = 0;
+ int x, y;
+
+ /* if we already did it, skip it */
+ if (update_complete)
+ {
+ update_complete = 0;
+ return;
+ }
+ update_complete = 0;
+
+ /* update the foreground & background */
+ update_foreground();
+ update_background();
+
+ /* blend the bitmaps and do collision detection */
+ for (y = 0; y < 256; y++)
+ {
+ int sy = (scrolly + y) & 255;
+ UINT8 *fg = &fgbitmap[y * 256];
+ UINT8 *bg = &bgbitmap[sy * 256];
+
+ /* do the blending */
+ for (x = 0; x < 256; x++)
+ {
+ int fpix = *fg++;
+ int bpix = bg[(x + scrollx) & 255];
+ if (fpix && (bpix & bgcollmask) && count++ < 128)
+ timer_set(video_screen_get_time_until_pos(0, y, x), x | (y << 8), bgcoll_irq_callback);
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Standard screen refresh callback
+ *
+ *************************************/
+
+VIDEO_UPDATE( victory )
+{
+ int bgcollmask = (video_control & 4) ? 4 : 7;
+ int count = 0;
+ int x, y;
+
+ /* update the foreground & background */
+ update_foreground();
+ update_background();
+
+ /* blend the bitmaps and do collision detection */
+ for (y = 0; y < 256; y++)
+ {
+ int sy = (scrolly + y) & 255;
+ UINT8 *fg = &fgbitmap[y * 256];
+ UINT8 *bg = &bgbitmap[sy * 256];
+ UINT8 scanline[256];
+
+ /* do the blending */
+ for (x = 0; x < 256; x++)
+ {
+ int fpix = *fg++;
+ int bpix = bg[(x + scrollx) & 255];
+ scanline[x] = bpix | (fpix << 3);
+ if (fpix && (bpix & bgcollmask) && count++ < 128)
+ timer_set(video_screen_get_time_until_pos(0, y, x), x | (y << 8), bgcoll_irq_callback);
+ }
+
+ /* draw the scanline */
+ draw_scanline8(bitmap, 0, y, 256, scanline, machine->pens, -1);
+ }
+
+ /* indicate that we already did collision detection */
+ update_complete = 1;
+ return 0;
+}
diff --git a/src/mame/video/videopin.c b/src/mame/video/videopin.c
new file mode 100644
index 00000000000..a4992fc45c4
--- /dev/null
+++ b/src/mame/video/videopin.c
@@ -0,0 +1,116 @@
+/*************************************************************************
+
+ Atari Video Pinball video emulation
+
+*************************************************************************/
+
+#include "driver.h"
+#include "includes/videopin.h"
+
+UINT8* videopin_video_ram;
+
+static int ball_x;
+static int ball_y;
+
+static tilemap* bg_tilemap;
+
+
+static TILEMAP_MAPPER( get_memory_offset )
+{
+ return num_rows * ((col + 16) % 48) + row;
+}
+
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 code = videopin_video_ram[tile_index];
+
+ SET_TILE_INFO(0, code, 0, (code & 0x40) ? TILE_FLIPY : 0);
+}
+
+
+VIDEO_START( videopin )
+{
+ bg_tilemap = tilemap_create(get_tile_info, get_memory_offset, TILEMAP_TYPE_PEN, 8, 8, 48, 32);
+}
+
+
+VIDEO_UPDATE( videopin )
+{
+ int col;
+ int row;
+
+ tilemap_set_scrollx(bg_tilemap, 0, -8); /* account for delayed loading of shift reg C6 */
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ for (row = 0; row < 32; row++)
+ {
+ for (col = 0; col < 48; col++)
+ {
+ UINT32 offset = get_memory_offset(col, row, 48, 32);
+
+ if (videopin_video_ram[offset] & 0x80) /* ball bit found */
+ {
+ rectangle rect;
+
+ int x = 8 * col;
+ int y = 8 * row;
+
+ int i;
+ int j;
+
+ x += 4; /* account for delayed loading of flip-flop C4 */
+
+ rect.min_x = x;
+ rect.min_y = y;
+ rect.max_x = x + 15;
+ rect.max_y = y + 15;
+
+ if (rect.min_x < cliprect->min_x)
+ rect.min_x = cliprect->min_x;
+ if (rect.min_y < cliprect->min_y)
+ rect.min_y = cliprect->min_y;
+ if (rect.max_x > cliprect->max_x)
+ rect.max_x = cliprect->max_x;
+ if (rect.max_y > cliprect->max_y)
+ rect.max_y = cliprect->max_y;
+
+ x -= ball_x;
+ y -= ball_y;
+
+ /* ball placement is still 0.5 pixels off but don't tell anyone */
+
+ for (i = 0; i < 2; i++)
+ {
+ for (j = 0; j < 2; j++)
+ {
+ drawgfx(bitmap, machine->gfx[1],
+ 0, 0,
+ 0, 0,
+ x + 16 * i,
+ y + 16 * j,
+ &rect, TRANSPARENCY_PEN, 0);
+ }
+ }
+
+ return 0; /* keep things simple and ignore the rest */
+ }
+ }
+ }
+ return 0;
+}
+
+
+WRITE8_HANDLER( videopin_ball_w )
+{
+ ball_x = data & 15;
+ ball_y = data >> 4;
+}
+
+
+WRITE8_HANDLER( videopin_video_ram_w )
+{
+ videopin_video_ram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
diff --git a/src/mame/video/vigilant.c b/src/mame/video/vigilant.c
new file mode 100644
index 00000000000..9b3433906d1
--- /dev/null
+++ b/src/mame/video/vigilant.c
@@ -0,0 +1,342 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+ TODO:
+
+ - Get a dump of the PAL16L8 (IC38 - 4M). This controls transparency.
+ It takes as input 4 bits of sprite color, and 6 bits of background tile
+ color. It outputs a sprite enable line, a background enable line, and
+ a background select (which layer of background to draw).
+ - Add cocktail flipping.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+static rectangle bottomvisiblearea =
+{
+ 16*8, 48*8-1,
+ 6*8, 32*8-1
+};
+
+//UINT8 *vigilant_paletteram;
+//UINT8 *vigilant_sprite_paletteram;
+
+static int horiz_scroll_low=0;
+static int horiz_scroll_high=0;
+static int rear_horiz_scroll_low=0;
+static int rear_horiz_scroll_high=0;
+static int rear_color=0;
+static int rear_disable=1;
+
+static int rear_refresh=1;
+
+static mame_bitmap *bg_bitmap;
+
+
+VIDEO_START( vigilant )
+{
+ video_start_generic(machine);
+
+ bg_bitmap = auto_bitmap_alloc(512*4,256,machine->screen[0].format);
+}
+
+
+
+/***************************************************************************
+ update_background
+
+ There are three background ROMs, each one contains a 512x256 picture.
+ Redraw them if the palette changes.
+ **************************************************************************/
+static void update_background(running_machine *machine)
+{
+ int row,col,page;
+ int charcode;
+
+
+ charcode=0;
+
+ /* There are only three background ROMs (4 on bunccaneers!) */
+ for (page=0; page<4; page++)
+ {
+ for( row=0; row<256; row++ )
+ {
+ for( col=0; col<512; col+=32 )
+ {
+ drawgfx(bg_bitmap,
+ machine->gfx[2],
+ charcode,
+ row < 128 ? 0 : 1,
+ 0,0,
+ 512*page + col,row,
+ 0,TRANSPARENCY_NONE,0);
+ charcode++;
+ }
+ }
+ }
+}
+
+/***************************************************************************
+ vigilant_paletteram_w
+
+ There are two palette chips, each one is labelled "KNA91H014". One is
+ used for the sprites, one is used for the two background layers.
+
+ The chip has three enables (!CS, !E0, !E1), R/W pins, A0-A7 as input,
+ 'L' and 'H' inputs, and D0-D4 as input. 'L' and 'H' are used to bank
+ into Red, Green, and Blue memory. There are only 5 bits of memory for
+ each byte, and a total of 256*3 bytes memory per chip.
+
+ There are additionally two sets of D0-D7 inputs per chip labelled 'A'
+ and 'B'. There is also an 'S' pin to select between the two input sets.
+ These are used to index a color triplet of RGB. The triplet is read
+ from RAM, and output to R0-R4, G0-G4, and B0-B4.
+ **************************************************************************/
+WRITE8_HANDLER( vigilant_paletteram_w )
+{
+ int bank,r,g,b;
+
+
+ paletteram[offset] = data;
+
+ bank = offset & 0x400;
+ offset &= 0xff;
+
+ r = (paletteram[bank + offset + 0x000] << 3) & 0xFF;
+ g = (paletteram[bank + offset + 0x100] << 3) & 0xFF;
+ b = (paletteram[bank + offset + 0x200] << 3) & 0xFF;
+
+ palette_set_color(Machine, (bank >> 2) + offset,MAKE_RGB(r,g,b));
+}
+
+
+
+/***************************************************************************
+ vigilant_horiz_scroll_w
+
+ horiz_scroll_low = HSPL, an 8-bit register
+ horiz_scroll_high = HSPH, a 1-bit register
+ **************************************************************************/
+WRITE8_HANDLER( vigilant_horiz_scroll_w )
+{
+ if (offset==0)
+ horiz_scroll_low = data;
+ else
+ horiz_scroll_high = (data & 0x01) * 256;
+}
+
+/***************************************************************************
+ vigilant_rear_horiz_scroll_w
+
+ rear_horiz_scroll_low = RHSPL, an 8-bit register
+ rear_horiz_scroll_high = RHSPH, an 8-bit register but only 3 bits are saved
+***************************************************************************/
+WRITE8_HANDLER( vigilant_rear_horiz_scroll_w )
+{
+ if (offset==0)
+ rear_horiz_scroll_low = data;
+ else
+ rear_horiz_scroll_high = (data & 0x07) * 256;
+}
+
+/***************************************************************************
+ vigilant_rear_color_w
+
+ This is an 8-bit register labelled RCOD.
+ D6 is hooked to !ROME (rear_disable)
+ D3 = RCC2 (rear color bit 2)
+ D2 = RCC1 (rear color bit 1)
+ D0 = RCC0 (rear color bit 0)
+
+ I know it looks odd, but D1, D4, D5, and D7 are empty.
+
+ What makes this extremely odd is that RCC is supposed to hook up to the
+ palette. However, the top four bits of the palette inputs are labelled:
+ "RCC3", "RCC2", "V256E", "RCC0". Methinks there's a typo.
+ **************************************************************************/
+WRITE8_HANDLER( vigilant_rear_color_w )
+{
+ rear_disable = data & 0x40;
+ rear_color = (data & 0x0d);
+}
+
+/***************************************************************************
+ draw_foreground
+
+ ???
+ **************************************************************************/
+
+static void draw_foreground(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority, int opaque )
+{
+ int offs;
+ int scroll = -(horiz_scroll_low + horiz_scroll_high);
+
+
+ for (offs = 0; offs<videoram_size; offs+=2 )
+ {
+ int sy = 8 * ((offs/2) / 64);
+ int sx = 8 * ((offs/2) % 64);
+ int attributes = videoram[offs+1];
+ int color = attributes & 0x0F;
+ int tile_number = videoram[offs] | ((attributes & 0xF0) << 4);
+
+ if (priority) /* foreground */
+ {
+ if ((color & 0x0c) == 0x0c) /* mask sprites */
+ {
+ if (sy >= 48)
+ {
+ sx = (sx + scroll) & 0x1ff;
+
+ drawgfx(bitmap,machine->gfx[0],
+ tile_number,
+ color,
+ 0,0,
+ sx,sy,
+ &bottomvisiblearea,TRANSPARENCY_PENS,0x00ff);
+ }
+ }
+ }
+ else /* background */
+ {
+ if (sy >= 48)
+ sx = (sx + scroll) & 0x1ff;
+
+ drawgfx(bitmap,machine->gfx[0],
+ tile_number,
+ color,
+ 0,0,
+ sx,sy,
+ cliprect,(opaque || color >= 4) ? TRANSPARENCY_NONE : TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int scrollx = 0x17a + 16*8 - (rear_horiz_scroll_low + rear_horiz_scroll_high);
+
+
+ if (rear_refresh)
+ {
+ update_background(machine);
+ rear_refresh=0;
+ }
+
+ copyscrollbitmap(bitmap,bg_bitmap,1,&scrollx,0,0,&bottomvisiblearea,TRANSPARENCY_NONE,0);
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0;offs < spriteram_size;offs += 8)
+ {
+ int code,color,sx,sy,flipx,flipy,h,y;
+
+ code = spriteram[offs+4] | ((spriteram[offs+5] & 0x0f) << 8);
+ color = spriteram[offs+0] & 0x0f;
+ sx = (spriteram[offs+6] | ((spriteram[offs+7] & 0x01) << 8));
+ sy = 256+128 - (spriteram[offs+2] | ((spriteram[offs+3] & 0x01) << 8));
+ flipx = spriteram[offs+5] & 0x40;
+ flipy = spriteram[offs+5] & 0x80;
+ h = 1 << ((spriteram[offs+5] & 0x30) >> 4);
+ sy -= 16 * h;
+
+ code &= ~(h - 1);
+
+ for (y = 0;y < h;y++)
+ {
+ int c = code;
+
+ if (flipy) c += h-1-y;
+ else c += y;
+
+ drawgfx(bitmap,machine->gfx[1],
+ c,
+ color,
+ flipx,flipy,
+ sx,sy + 16*y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( vigilant )
+{
+ int i;
+
+ /* copy the background palette */
+ for (i = 0;i < 16;i++)
+ {
+ int r,g,b;
+
+
+ r = (paletteram[0x400 + 16 * rear_color + i] << 3) & 0xFF;
+ g = (paletteram[0x500 + 16 * rear_color + i] << 3) & 0xFF;
+ b = (paletteram[0x600 + 16 * rear_color + i] << 3) & 0xFF;
+
+ palette_set_color(machine,512 + i,MAKE_RGB(r,g,b));
+
+ r = (paletteram[0x400 + 16 * rear_color + 32 + i] << 3) & 0xFF;
+ g = (paletteram[0x500 + 16 * rear_color + 32 + i] << 3) & 0xFF;
+ b = (paletteram[0x600 + 16 * rear_color + 32 + i] << 3) & 0xFF;
+
+ palette_set_color(machine,512 + 16 + i,MAKE_RGB(r,g,b));
+ }
+
+ if (rear_disable) /* opaque foreground */
+ {
+ draw_foreground(machine,bitmap,cliprect,0,1);
+ draw_sprites(machine,bitmap,&bottomvisiblearea);
+ draw_foreground(machine,bitmap,cliprect,1,0);
+ }
+ else
+ {
+ draw_background(machine,bitmap,cliprect);
+ draw_foreground(machine,bitmap,cliprect,0,0);
+ draw_sprites(machine,bitmap,&bottomvisiblearea);
+ draw_foreground(machine,bitmap,cliprect,1,0); // priority tiles
+ }
+ return 0;
+}
+
+VIDEO_UPDATE( kikcubic )
+{
+ int offs;
+
+
+ for (offs = 0; offs<videoram_size; offs+=2 )
+ {
+ int sy = 8 * ((offs/2) / 64);
+ int sx = 8 * ((offs/2) % 64);
+ int attributes = videoram[offs+1];
+ int color = (attributes & 0xF0) >> 4;
+ int tile_number = videoram[offs] | ((attributes & 0x0F) << 8);
+
+ if (dirtybuffer[offs] || dirtybuffer[offs+1])
+ {
+ dirtybuffer[offs] = dirtybuffer[offs+1] = 0;
+
+ drawgfx(tmpbitmap,machine->gfx[0],
+ tile_number,
+ color,
+ 0,0,
+ sx,sy,
+ 0,TRANSPARENCY_NONE,0);
+ }
+ }
+
+ copybitmap(bitmap,tmpbitmap,0,0,0,0,cliprect,TRANSPARENCY_NONE,0);
+
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/vindictr.c b/src/mame/video/vindictr.c
new file mode 100644
index 00000000000..1c69805b485
--- /dev/null
+++ b/src/mame/video/vindictr.c
@@ -0,0 +1,303 @@
+/***************************************************************************
+
+ Atari Vindicators hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "vindictr.h"
+#include "thunderj.h"
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static UINT8 playfield_tile_bank;
+static UINT16 playfield_xscroll;
+static UINT16 playfield_yscroll;
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha[tile_index];
+ int code = data & 0x3ff;
+ int color = ((data >> 10) & 0x0f) | ((data >> 9) & 0x20);
+ int opaque = data & 0x8000;
+ SET_TILE_INFO(1, code, color, opaque ? TILE_FORCE_LAYER0 : 0);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data = atarigen_playfield[tile_index];
+ int code = (playfield_tile_bank * 0x1000) + (data & 0xfff);
+ int color = 0x10 + 2 * ((data >> 12) & 7);
+ SET_TILE_INFO(0, code, color, (data >> 15) & 1);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( vindictr )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 0, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 1, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 8, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x100, /* base palette entry */
+ 0x100, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0,0,0,0x03ff }}, /* mask for the link */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0x7fff,0,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0x000f,0,0 }}, /* mask for the color */
+ {{ 0,0xff80,0,0 }}, /* mask for the X position */
+ {{ 0,0,0xff80,0 }}, /* mask for the Y position */
+ {{ 0,0,0x0038,0 }}, /* mask for the width, in tiles*/
+ {{ 0,0,0x0007,0 }}, /* mask for the height, in tiles */
+ {{ 0,0,0x0040,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0,0x0070,0,0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ NULL /* callback routine for special entries */
+ };
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 8,8, 64,64);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ tilemap_set_transparent_pen(atarigen_alpha_tilemap, 0);
+}
+
+
+
+/*************************************
+ *
+ * Palette RAM control
+ *
+ *************************************/
+
+WRITE16_HANDLER( vindictr_paletteram_w )
+{
+ static const int ztable[16] =
+ { 0x0, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11 };
+ int c;
+
+ /* first blend the data */
+ COMBINE_DATA(&paletteram16[offset]);
+ data = paletteram16[offset];
+
+ /* now generate colors at all 16 intensities */
+ for (c = 0; c < 8; c++)
+ {
+ int i = ztable[((data >> 12) + (c * 2)) & 15];
+ int r = ((data >> 8) & 15) * i;
+ int g = ((data >> 4) & 15) * i;
+ int b = ((data >> 0) & 15) * i;
+
+ palette_set_color(Machine,offset + c*2048,MAKE_RGB(r,g,b));
+ }
+}
+
+
+
+/*************************************
+ *
+ * Periodic scanline updater
+ *
+ *************************************/
+
+void vindictr_scanline_update(running_machine *machine, int scrnum, int scanline)
+{
+ UINT16 *base = &atarigen_alpha[((scanline - 8) / 8) * 64 + 42];
+ int x;
+
+ /* keep in range */
+ if (base < atarigen_alpha)
+ base += 0x7c0;
+ else if (base >= &atarigen_alpha[0x7c0])
+ return;
+
+ /* update the current parameters */
+ for (x = 42; x < 64; x++)
+ {
+ UINT16 data = *base++;
+
+ switch ((data >> 9) & 7)
+ {
+ case 2: /* /PFB */
+ if (playfield_tile_bank != (data & 7))
+ {
+ video_screen_update_partial(0, scanline - 1);
+ playfield_tile_bank = data & 7;
+ tilemap_mark_all_tiles_dirty(atarigen_playfield_tilemap);
+ }
+ break;
+
+ case 3: /* /PFHSLD */
+ if (playfield_xscroll != (data & 0x1ff))
+ {
+ video_screen_update_partial(0, scanline - 1);
+ tilemap_set_scrollx(atarigen_playfield_tilemap, 0, data);
+ playfield_xscroll = data & 0x1ff;
+ }
+ break;
+
+ case 4: /* /MOHS */
+ if (atarimo_get_xscroll(0) != (data & 0x1ff))
+ {
+ video_screen_update_partial(0, scanline - 1);
+ atarimo_set_xscroll(0, data & 0x1ff);
+ }
+ break;
+
+ case 5: /* /PFSPC */
+ break;
+
+ case 6: /* /VIRQ */
+ atarigen_scanline_int_gen();
+ break;
+
+ case 7: /* /PFVS */
+ {
+ /* a new vscroll latches the offset into a counter; we must adjust for this */
+ int offset = scanline;
+ if (offset > machine->screen[0].visarea.max_y)
+ offset -= machine->screen[0].visarea.max_y + 1;
+
+ if (playfield_yscroll != ((data - offset) & 0x1ff))
+ {
+ video_screen_update_partial(0, scanline - 1);
+ tilemap_set_scrolly(atarigen_playfield_tilemap, 0, data - offset);
+ atarimo_set_yscroll(0, (data - offset) & 0x1ff);
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( vindictr )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* partially verified via schematics (there are a lot of PALs involved!):
+
+ SHADE = PAL(MPR1-0, LB7-0, PFX6-5, PFX3-2, PF/M)
+
+ if (SHADE)
+ CRA |= 0x100
+
+ MOG3-1 = ~MAT3-1 if MAT6==1 and MSD3==1
+ */
+ int mopriority = mo[x] >> ATARIMO_PRIORITY_SHIFT;
+
+ /* upper bit of MO priority signals special rendering and doesn't draw anything */
+ if (mopriority & 4)
+ continue;
+
+ /* MO pen 1 doesn't draw, but it sets the SHADE flag and bumps the palette offset */
+ if ((mo[x] & 0x0f) == 1)
+ {
+ if ((mo[x] & 0xf0) != 0)
+ pf[x] |= 0x100;
+ }
+ else
+ pf[x] = mo[x] & ATARIMO_DATA_MASK;
+
+ /* don't erase yet -- we need to make another pass later */
+ }
+ }
+
+ /* add the alpha on top */
+ tilemap_draw(bitmap, cliprect, atarigen_alpha_tilemap, 0, 0);
+
+ /* now go back and process the upper bit of MO priority */
+ rectlist.rect -= rectlist.numrects;
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ int mopriority = mo[x] >> ATARIMO_PRIORITY_SHIFT;
+
+ /* upper bit of MO priority might mean palette kludges */
+ if (mopriority & 4)
+ {
+ /* if bit 2 is set, start setting high palette bits */
+ if (mo[x] & 2)
+ thunderj_mark_high_palette(bitmap, pf, mo, x, y);
+
+ /* if the upper bit of pen data is set, we adjust the final intensity */
+ if (mo[x] & 8)
+ pf[x] |= (~mo[x] & 0xe0) << 6;
+ }
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+ return 0;
+}
diff --git a/src/mame/video/volfied.c b/src/mame/video/volfied.c
new file mode 100644
index 00000000000..b922f67d5bd
--- /dev/null
+++ b/src/mame/video/volfied.c
@@ -0,0 +1,139 @@
+#include "driver.h"
+#include "video/taitoic.h"
+
+static UINT16* video_ram = NULL;
+
+static UINT16 video_ctrl = 0;
+static UINT16 video_mask = 0;
+
+
+/******************************************************
+ INITIALISATION AND CLEAN-UP
+******************************************************/
+
+VIDEO_START( volfied )
+{
+ video_ram = auto_malloc(0x40000 * sizeof (UINT16));
+
+ state_save_register_global_pointer(video_ram, 0x40000);
+ state_save_register_global(video_ctrl);
+ state_save_register_global(video_mask);
+
+ PC090OJ_vh_start(0, 0, 0, 0);
+}
+
+
+/*******************************************************
+ READ AND WRITE HANDLERS
+*******************************************************/
+
+READ16_HANDLER( volfied_video_ram_r )
+{
+ return video_ram[offset];
+}
+
+WRITE16_HANDLER( volfied_video_ram_w )
+{
+ mem_mask |= ~video_mask;
+
+ COMBINE_DATA(&video_ram[offset]);
+}
+
+WRITE16_HANDLER( volfied_video_ctrl_w )
+{
+ COMBINE_DATA(&video_ctrl);
+}
+
+READ16_HANDLER( volfied_video_ctrl_r )
+{
+ /* Could this be some kind of hardware collision detection? If bit 6 is
+ set the game will check for collisions with the large enemy, whereas
+ bit 5 does the same for small enemies. Bit 7 is also used although
+ its purpose is unclear. This register is usually read during a VBI
+ and stored in work RAM for later use. */
+
+ return 0x60;
+}
+
+WRITE16_HANDLER( volfied_video_mask_w )
+{
+ COMBINE_DATA(&video_mask);
+}
+
+WRITE16_HANDLER( volfied_sprite_ctrl_w )
+{
+ PC090OJ_sprite_ctrl = (data & 0x3c) >> 2;
+}
+
+
+/*******************************************************
+ SCREEN REFRESH
+*******************************************************/
+
+static void refresh_pixel_layer(running_machine *machine, mame_bitmap *bitmap)
+{
+ int x, y;
+
+ /*********************************************************
+
+ VIDEO RAM has 2 screens x 256 rows x 512 columns x 16 bits
+
+ x--------------- select image
+ -x-------------- ? (used for 3-D corners)
+ --x------------- ? (used for 3-D walls)
+ ---xxxx--------- image B
+ -------xxx------ palette index bits #8 to #A
+ ----------x----- ?
+ -----------x---- ?
+ ------------xxxx image A
+
+ '3d' corners & walls are made using unknown bits for each
+ line the player draws. However, on the pcb they just
+ appear as solid black. Perhaps it was prototype code that
+ was turned off at some stage.
+
+ *********************************************************/
+
+ UINT16* p = video_ram;
+
+ if (video_ctrl & 1)
+ {
+ p += 0x20000;
+ }
+
+ for (y = 0; y < machine->screen[0].height; y++)
+ {
+ for (x = 1; x < machine->screen[0].width + 1; x++) // Hmm, 1 pixel offset is needed to align properly with sprites
+ {
+ int color = (p[x] << 2) & 0x700;
+
+ if (p[x] & 0x8000)
+ {
+ color |= 0x800 | ((p[x] >> 9) & 0xf);
+
+ if (p[x] & 0x2000)
+ {
+ color &= ~0xf; /* hack */
+ }
+ }
+ else
+ {
+ color |= p[x] & 0xf;
+ }
+
+ *BITMAP_ADDR16(bitmap, y, x - 1) = machine->pens[color];
+ }
+
+ p += 512;
+ }
+}
+
+VIDEO_UPDATE( volfied )
+{
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ refresh_pixel_layer(machine, bitmap);
+
+ PC090OJ_draw_sprites(machine, bitmap, cliprect, 0);
+ return 0;
+}
diff --git a/src/mame/video/vrender0.c b/src/mame/video/vrender0.c
new file mode 100644
index 00000000000..ddd73f4aec0
--- /dev/null
+++ b/src/mame/video/vrender0.c
@@ -0,0 +1,522 @@
+#include "driver.h"
+#include "vrender0.h"
+
+/***********************************
+ VRENDER ZERO
+ VIDEO EMULATION By ElSemi
+
+
+ The VRender0 is a very special 2D sprite renderer. The spec says it's based on 3D
+ technology.
+ The device processes "display lists" that contain pointers to the texture, tex coords
+ and the step increments on x and y (dxx,dxy,dyx,dyy) allowing ROZ effects on sprites.
+ It supports alphablend with programmable factors per channel and for source and dest
+ color.
+
+************************************/
+/*************
+Missing:
+
+
+**************/
+
+static UINT16 InternalPalette[256];
+static UINT32 LastPalUpdate=0xffffffff;
+
+/*
+Pick a rare enough color to disable transparency (that way I save a cmp per loop to check
+if I must draw transparent or not. The palette build will take this color in account so
+no color in the palette will have this value
+*/
+#define NOTRANSCOLOR 0xecda
+
+#define RGB32(r,g,b) ((r<<16)|(g<<8)|(b<<0))
+#define RGB16(r,g,b) ((r&0xf8)<<8)|((g&0xfc)<<3)|((b&0xf8)>>3)
+
+INLINE UINT16 RGB32TO16(UINT32 rgb)
+{
+ return (((rgb>>(16+3))&0x1f)<<11)|(((rgb>>(8+2))&0x3f)<<5)|(((rgb>>(3))&0x1f)<<0);
+}
+
+typedef struct
+{
+ UINT32 Tx;
+ UINT32 Ty;
+ UINT32 Txdx;
+ UINT32 Tydx;
+ UINT32 Txdy;
+ UINT32 Tydy;
+ UINT32 SrcAlphaColor;
+ UINT32 SrcBlend;
+ UINT32 DstAlphaColor;
+ UINT32 DstBlend;
+ UINT32 ShadeColor;
+ UINT32 TransColor;
+ UINT32 TileOffset;
+ UINT32 FontOffset;
+ UINT32 PalOffset;
+ UINT32 PaletteBank;
+ UINT32 TextureMode;
+ UINT32 PixelFormat;
+ UINT32 Width;
+ UINT32 Height;
+} _RenderState;
+
+static _RenderState RenderState;
+
+typedef struct
+{
+ UINT16 *Dest;
+ UINT32 Pitch; //in UINT16s
+ UINT32 w,h;
+ UINT32 Tx;
+ UINT32 Ty;
+ UINT32 Txdx;
+ UINT32 Tydx;
+ UINT32 Txdy;
+ UINT32 Tydy;
+ UINT16 TWidth;
+ UINT16 THeight;
+ union _u
+ {
+ UINT8 *Imageb;
+ UINT16 *Imagew;
+ } u;
+ UINT16 *Tile;
+ UINT16 *Pal;
+ UINT32 TransColor;
+ UINT32 Shade;
+ UINT8 Clamp;
+ UINT8 Trans;
+ UINT8 SrcAlpha;
+ UINT32 SrcColor;
+ UINT8 DstAlpha;
+ UINT32 DstColor;
+} _Quad;
+
+#define EXTRACTR8(Src) (((Src>>11)<<3)&0xff)
+#define EXTRACTG8(Src) (((Src>>5)<<2)&0xff)
+#define EXTRACTB8(Src) (((Src>>0)<<3)&0xff)
+
+INLINE UINT16 Shade(UINT16 Src,UINT32 Shade)
+{
+ UINT32 scr=(EXTRACTR8(Src)*((Shade>>16)&0xff))>>8;
+ UINT32 scg=(EXTRACTG8(Src)*((Shade>>8)&0xff))>>8;
+ UINT32 scb=(EXTRACTB8(Src)*((Shade>>0)&0xff))>>8;
+ return RGB16(scr,scg,scb);
+}
+
+static UINT16 Alpha(_Quad *Quad,UINT16 Src,UINT16 Dst)
+{
+ UINT32 scr=(EXTRACTR8(Src)*((Quad->Shade>>16)&0xff))>>8;
+ UINT32 scg=(EXTRACTG8(Src)*((Quad->Shade>>8)&0xff))>>8;
+ UINT32 scb=(EXTRACTB8(Src)*((Quad->Shade>>0)&0xff))>>8;
+ UINT32 dcr=EXTRACTR8(Dst);
+ UINT32 dcg=EXTRACTG8(Dst);
+ UINT32 dcb=EXTRACTB8(Dst);
+
+ UINT32 smulr,smulg,smulb;
+ UINT32 dmulr,dmulg,dmulb;
+
+ switch(Quad->SrcAlpha&0x1f)
+ {
+ case 0x01:
+ smulr=smulg=smulb=0;
+ break;
+ case 0x02:
+ smulr=(Quad->SrcColor>>16)&0xff;
+ smulg=(Quad->SrcColor>>8)&0xff;
+ smulb=(Quad->SrcColor>>0)&0xff;
+ break;
+ case 0x04:
+ smulr=scr;
+ smulg=scg;
+ smulb=scb;
+ break;
+ case 0x08:
+ smulr=(Quad->DstColor>>16)&0xff;
+ smulg=(Quad->DstColor>>8)&0xff;
+ smulb=(Quad->DstColor>>0)&0xff;
+ break;
+ case 0x10:
+ smulr=dcr;
+ smulg=dcg;
+ smulb=dcb;
+ break;
+ default:
+ smulr=smulg=smulb=0;
+ break;
+ }
+ if(Quad->SrcAlpha&0x20)
+ {
+ smulr=0x100-smulr;
+ smulg=0x100-smulg;
+ smulb=0x100-smulb;
+ }
+
+ switch(Quad->DstAlpha&0x1f)
+ {
+ case 0x01:
+ dmulr=dmulg=dmulb=0;
+ break;
+ case 0x02:
+ dmulr=(Quad->SrcColor>>16)&0xff;
+ dmulg=(Quad->SrcColor>>8)&0xff;
+ dmulb=(Quad->SrcColor>>0)&0xff;
+ break;
+ case 0x04:
+ dmulr=scr;
+ dmulg=scg;
+ dmulb=scb;
+ break;
+ case 0x08:
+ dmulr=(Quad->DstColor>>16)&0xff;
+ dmulg=(Quad->DstColor>>8)&0xff;
+ dmulb=(Quad->DstColor>>0)&0xff;
+ break;
+ case 0x10:
+ dmulr=dcr;
+ dmulg=dcg;
+ dmulb=dcb;
+ break;
+ default:
+ dmulr=dmulg=dmulb=0;
+ break;
+ }
+ if(Quad->DstAlpha&0x20)
+ {
+ dmulr=0x100-dmulr;
+ dmulg=0x100-dmulg;
+ dmulb=0x100-dmulb;
+ }
+
+
+ dcr=(scr*smulr+dcr*dmulr)>>8;
+ if(dcr>0xff)
+ dcr=0xff;
+ dcg=(scg*smulg+dcg*dmulg)>>8;
+ if(dcg>0xff)
+ dcg=0xff;
+ dcb=(scb*smulb+dcb*dmulb)>>8;
+ if(dcb>0xff)
+ dcb=0xff;
+ return RGB16(dcr,dcg,dcb);
+}
+
+#define TILENAME(bpp,t,a) \
+static void DrawQuad##bpp##t##a(_Quad *Quad)
+
+//TRUST ON THE COMPILER OPTIMIZATIONS
+#define TILETEMPL(bpp,t,a) \
+TILENAME(bpp,t,a)\
+{\
+ UINT32 TransColor=Quad->Trans?RGB32TO16(Quad->TransColor):NOTRANSCOLOR;\
+ UINT32 x,y;\
+ UINT16 *line=Quad->Dest;\
+ UINT32 y_tx=Quad->Tx,y_ty=Quad->Ty;\
+ UINT32 x_tx,x_ty;\
+ UINT32 Maskw=Quad->TWidth-1;\
+ UINT32 Maskh=Quad->THeight-1;\
+ UINT32 W=Quad->TWidth>>3;\
+\
+ for(y=0;y<Quad->h;++y)\
+ {\
+ UINT16 *pixel=line;\
+ x_tx=y_tx;\
+ x_ty=y_ty;\
+ for(x=0;x<Quad->w;++x)\
+ {\
+ UINT32 Offset;\
+ UINT32 tx=x_tx>>9;\
+ UINT32 ty=x_ty>>9;\
+ UINT16 Color;\
+ if(Quad->Clamp)\
+ {\
+ if(tx>Maskw)\
+ goto Clamped;\
+ if(ty>Maskh)\
+ goto Clamped;\
+ }\
+ else\
+ {\
+ tx&=Maskw;\
+ ty&=Maskh;\
+ }\
+\
+ if(t)\
+ {\
+ UINT32 Index=Quad->Tile[(ty>>3)*(W)+(tx>>3)];\
+ Offset=(Index<<6)+((ty&7)<<3)+(tx&7);\
+ }\
+ else\
+ Offset=ty*(Quad->TWidth)+tx;\
+\
+ if(bpp==4)\
+ {\
+ UINT8 Texel=Quad->u.Imageb[Offset/2];\
+ if(Offset&1)\
+ Texel&=0xf;\
+ else\
+ Texel=(Texel>>4)&0xf;\
+ Color=Quad->Pal[Texel];\
+ }\
+ else if(bpp==8)\
+ {\
+ UINT8 Texel=Quad->u.Imageb[Offset];\
+ Texel=Quad->u.Imageb[Offset];\
+ Color=Quad->Pal[Texel];\
+ }\
+ else if(bpp==16)\
+ {\
+ Color=Quad->u.Imagew[Offset];\
+ }\
+ if(Color!=TransColor)\
+ {\
+ if(a==1)\
+ *pixel=Alpha(Quad,Color,*pixel);\
+ else if(a==2)\
+ *pixel=Shade(Color,Quad->Shade);\
+ else\
+ *pixel=Color;\
+ }\
+ ++pixel;\
+Clamped:\
+ x_tx+=Quad->Txdx;\
+ x_ty+=Quad->Tydx;\
+ }\
+ line+=Quad->Pitch;\
+ y_tx+=Quad->Txdy;\
+ y_ty+=Quad->Tydy;\
+ }\
+}\
+
+TILETEMPL(16,0,0) TILETEMPL(16,0,1) TILETEMPL(16,0,2)
+TILETEMPL(16,1,0) TILETEMPL(16,1,1) TILETEMPL(16,1,2)
+
+TILETEMPL(8,0,0) TILETEMPL(8,0,1) TILETEMPL(8,0,2)
+TILETEMPL(8,1,0) TILETEMPL(8,1,1) TILETEMPL(8,1,2)
+
+TILETEMPL(4,0,0) TILETEMPL(4,0,1) TILETEMPL(4,0,2)
+TILETEMPL(4,1,0) TILETEMPL(4,1,1) TILETEMPL(4,1,2)
+
+#undef TILENAME
+#define TILENAME(bpp,t,a) \
+DrawQuad##bpp##t##a
+
+
+static void DrawQuadFill(_Quad *Quad)
+{
+ UINT32 x,y;
+ UINT16 *line=Quad->Dest;
+ UINT16 ShadeColor=RGB32TO16(Quad->Shade);
+ for(y=0;y<Quad->h;++y)
+ {
+ UINT16 *pixel=line;
+ for(x=0;x<Quad->w;++x)
+ {
+ if(Quad->SrcAlpha)
+ *pixel=Alpha(Quad,Quad->Shade,*pixel);
+ else
+ *pixel=ShadeColor;
+ ++pixel;
+ }
+ line+=Quad->Pitch;
+ }
+}
+
+typedef void (*_DrawTemplate)(_Quad *);
+
+static _DrawTemplate DrawImage[]=
+{
+ TILENAME(4,0,0),
+ TILENAME(8,0,0),
+ TILENAME(16,0,0),
+ TILENAME(16,0,0),
+
+ TILENAME(4,0,1),
+ TILENAME(8,0,1),
+ TILENAME(16,0,1),
+ TILENAME(16,0,1),
+
+ TILENAME(4,0,2),
+ TILENAME(8,0,2),
+ TILENAME(16,0,2),
+ TILENAME(16,0,2),
+};
+
+static _DrawTemplate DrawTile[]=
+{
+ TILENAME(4,1,0),
+ TILENAME(8,1,0),
+ TILENAME(16,1,0),
+ TILENAME(16,1,0),
+
+ TILENAME(4,1,1),
+ TILENAME(8,1,1),
+ TILENAME(16,1,1),
+ TILENAME(16,1,1),
+
+ TILENAME(4,1,2),
+ TILENAME(8,1,2),
+ TILENAME(16,1,2),
+ TILENAME(16,1,2),
+};
+
+#define Packet(i) program_read_word_32le(PacketPtr+2*i)
+
+//Returns TRUE if the operation was a flip (sync or async)
+int ProcessPacket(UINT32 PacketPtr,UINT16 *Dest,UINT8 *TEXTURE)
+{
+ UINT32 Dx=Packet(1)&0x3ff;
+ UINT32 Dy=Packet(2)&0x1ff;
+ UINT32 Endx=Packet(3)&0x3ff;
+ UINT32 Endy=Packet(4)&0x1ff;
+ UINT32 Mode=0;
+ UINT16 Packet0=Packet(0);
+
+ if(Packet0&0x81) //Sync or ASync flip
+ {
+ LastPalUpdate=0xffffffff; //Force update palette next frame
+ return 1;
+ }
+
+ if(Packet0&0x200)
+ {
+ RenderState.Tx=Packet(5)|((Packet(6)&0x1F)<<16);
+ RenderState.Ty=Packet(7)|((Packet(8)&0x1F)<<16);
+ }
+ else
+ {
+ RenderState.Tx=0;
+ RenderState.Ty=0;
+ }
+ if(Packet0&0x400)
+ {
+ RenderState.Txdx=Packet(9)|((Packet(10)&0x1F)<<16);
+ RenderState.Tydx=Packet(11)|((Packet(12)&0x1F)<<16);
+ RenderState.Txdy=Packet(13)|((Packet(14)&0x1F)<<16);
+ RenderState.Tydy=Packet(15)|((Packet(16)&0x1F)<<16);
+ }
+ else
+ {
+ RenderState.Txdx=1<<9;
+ RenderState.Tydx=0;
+ RenderState.Txdy=0;
+ RenderState.Tydy=1<<9;
+ }
+ if(Packet0&0x800)
+ {
+ RenderState.SrcAlphaColor=Packet(17)|((Packet(18)&0xff)<<16);
+ RenderState.SrcBlend=(Packet(18)>>8)&0x3f;
+ RenderState.DstAlphaColor=Packet(19)|((Packet(20)&0xff)<<16);
+ RenderState.DstBlend=(Packet(20)>>8)&0x3f;
+ }
+ if(Packet0&0x1000)
+ RenderState.ShadeColor=Packet(21)|((Packet(22)&0xFF)<<16);
+ if(Packet0&0x2000)
+ RenderState.TransColor=Packet(23)|((Packet(24)&0xFF)<<16);
+ if(Packet0&0x4000)
+ {
+ RenderState.TileOffset=Packet(25);
+ RenderState.FontOffset=Packet(26);
+ RenderState.PalOffset=Packet(27)>>3;
+ RenderState.PaletteBank=(Packet(28)>>8)&0xF;
+ RenderState.TextureMode=Packet(28)&0x1000;
+ RenderState.PixelFormat=(Packet(28)>>6)&3;
+ RenderState.Width =8<<((Packet(28)>>0)&0x7);
+ RenderState.Height=8<<((Packet(28)>>3)&0x7);
+ }
+
+
+ if(Packet0&0x40 && RenderState.PalOffset!=LastPalUpdate)
+ {
+ UINT32 *Pal=(UINT32*) (TEXTURE+1024*RenderState.PalOffset);
+ UINT16 Trans=RGB32TO16(RenderState.TransColor);
+ int i;
+ for(i=0;i<256;++i)
+ {
+ UINT32 p=Pal[i];
+ UINT16 v=RGB32TO16(p);
+ if((v==Trans && p!=RenderState.TransColor) || v==NOTRANSCOLOR) //Error due to conversion. caused transparent
+ {
+ if((v&0x1f)!=0x1f)
+ v++; //Make the color a bit different (blueish) so it's not
+ else
+ v--;
+ }
+ InternalPalette[i]=v; //made transparent by mistake
+ }
+ LastPalUpdate=RenderState.PalOffset;
+ }
+
+ if(Packet0&0x100)
+ {
+ _Quad Quad;
+
+ Quad.Pitch=512;
+
+// assert(Endx>=Dx && Endy>=Dy);
+
+ if(Packet0&2)
+ {
+ Quad.SrcAlpha=RenderState.SrcBlend;
+ Quad.DstAlpha=RenderState.DstBlend;
+ Quad.SrcColor=RenderState.SrcAlphaColor;
+ Quad.DstColor=RenderState.DstAlphaColor;
+ Mode=1;
+ }
+ else
+ Quad.SrcAlpha=0;
+
+ Quad.w=1+Endx-Dx;
+ Quad.h=1+Endy-Dy;
+
+ Quad.Dest=(UINT16*) Dest;
+ Quad.Dest=Quad.Dest+Dx+(Dy*Quad.Pitch);
+
+ Quad.Tx=RenderState.Tx;
+ Quad.Ty=RenderState.Ty;
+ Quad.Txdx=RenderState.Txdx;
+ Quad.Tydx=RenderState.Tydx;
+ Quad.Txdy=RenderState.Txdy;
+ Quad.Tydy=RenderState.Tydy;
+ if(Packet0&0x10)
+ {
+ Quad.Shade=RenderState.ShadeColor;
+ if(!Mode) //Alpha includes Shade
+ Mode=2;
+ /*
+ //simulate shade with alphablend (SLOW!!!)
+ if(!Quad.SrcAlpha && (Packet0&0x8))
+ {
+ Quad.SrcAlpha=0x21; //1
+ Quad.DstAlpha=0x01; //0
+ }*/
+ }
+ else
+ Quad.Shade=RGB32(255,255,255);
+ Quad.TransColor=RenderState.TransColor;
+ Quad.TWidth=RenderState.Width;
+ Quad.THeight=RenderState.Height;
+ Quad.Trans=Packet0&4;
+ //Quad.Trans=0;
+ Quad.Clamp=Packet0&0x20;
+
+ if(Packet0&0x8) //Texture Enable
+ {
+ Quad.u.Imageb=TEXTURE+128*RenderState.FontOffset;
+ Quad.Tile=(UINT16*) (TEXTURE+128*RenderState.TileOffset);
+ if(!RenderState.PixelFormat)
+ Quad.Pal=InternalPalette+(RenderState.PaletteBank*16);
+ else
+ Quad.Pal=InternalPalette;
+ if(RenderState.TextureMode) //Tiled
+ DrawTile[RenderState.PixelFormat+4*Mode](&Quad);
+ else
+ DrawImage[RenderState.PixelFormat+4*Mode](&Quad);
+ }
+ else
+ DrawQuadFill(&Quad);
+ }
+ return 0;
+}
diff --git a/src/mame/video/vrender0.h b/src/mame/video/vrender0.h
new file mode 100644
index 00000000000..01833e4bbbb
--- /dev/null
+++ b/src/mame/video/vrender0.h
@@ -0,0 +1,2 @@
+
+extern int ProcessPacket(UINT32 PacketPtr,UINT16 *Dest,UINT8 *TEXTURE);
diff --git a/src/mame/video/vsnes.c b/src/mame/video/vsnes.c
new file mode 100644
index 00000000000..8161774d01c
--- /dev/null
+++ b/src/mame/video/vsnes.c
@@ -0,0 +1,76 @@
+#include "driver.h"
+#include "video/ppu2c0x.h"
+
+/* from machine */
+extern int vsnes_gun_controller;
+
+
+PALETTE_INIT( vsnes )
+{
+ ppu2c0x_init_palette(machine, 0 );
+}
+
+PALETTE_INIT( vsdual )
+{
+ ppu2c0x_init_palette(machine, 0 );
+ ppu2c0x_init_palette(machine, 8*4*16 );
+}
+
+static void ppu_irq( int num, int *ppu_regs )
+{
+ cpunum_set_input_line(num, INPUT_LINE_NMI, PULSE_LINE );
+}
+
+/* our ppu interface */
+static const ppu2c0x_interface ppu_interface =
+{
+ PPU_2C04, /* type */
+ 1, /* num */
+ { REGION_GFX1 }, /* vrom gfx region */
+ { 0 }, /* gfxlayout num */
+ { 0 }, /* color base */
+ { PPU_MIRROR_NONE }, /* mirroring */
+ { ppu_irq } /* irq */
+};
+
+/* our ppu interface for dual games */
+static const ppu2c0x_interface ppu_dual_interface =
+{
+ PPU_2C04, /* type */
+ 2, /* num */
+ { REGION_GFX1, REGION_GFX2 }, /* vrom gfx region */
+ { 0, 1 }, /* gfxlayout num */
+ { 0, 64 }, /* color base */
+ { PPU_MIRROR_NONE, PPU_MIRROR_NONE }, /* mirroring */
+ { ppu_irq, ppu_irq } /* irq */
+};
+
+VIDEO_START( vsnes )
+{
+ ppu2c0x_init(machine, &ppu_interface );
+}
+
+VIDEO_START( vsdual )
+{
+ ppu2c0x_init(machine, &ppu_dual_interface );
+}
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+VIDEO_UPDATE( vsnes )
+{
+ /* render the ppu */
+ ppu2c0x_render( 0, bitmap, 0, 0, 0, 0 );
+ return 0;
+}
+
+
+VIDEO_UPDATE( vsdual )
+{
+ /* render the ppu's */
+ ppu2c0x_render( screen, bitmap, 0, 0, 0, 0 );
+ return 0;
+}
diff --git a/src/mame/video/vulgus.c b/src/mame/video/vulgus.c
new file mode 100644
index 00000000000..1a1cac04abb
--- /dev/null
+++ b/src/mame/video/vulgus.c
@@ -0,0 +1,229 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *vulgus_fgvideoram,*vulgus_bgvideoram;
+UINT8 *vulgus_scroll_low,*vulgus_scroll_high;
+
+static int vulgus_palette_bank;
+static tilemap *fg_tilemap, *bg_tilemap;
+static colortable *vulgus_colortable;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+***************************************************************************/
+
+PALETTE_INIT( vulgus )
+{
+ int i;
+
+ vulgus_colortable = colortable_alloc(machine, 256);
+
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[256] >> 0) & 0x01;
+ bit1 = (color_prom[256] >> 1) & 0x01;
+ bit2 = (color_prom[256] >> 2) & 0x01;
+ bit3 = (color_prom[256] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ bit0 = (color_prom[2*256] >> 0) & 0x01;
+ bit1 = (color_prom[2*256] >> 1) & 0x01;
+ bit2 = (color_prom[2*256] >> 2) & 0x01;
+ bit3 = (color_prom[2*256] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ colortable_palette_set_color(vulgus_colortable,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ color_prom += 2*256;
+ /* color_prom now points to the beginning of the lookup table */
+
+
+ /* characters use colors 32-47 (?) */
+ for (i = 0;i < machine->gfx[0]->total_colors * machine->gfx[0]->color_granularity;i++)
+ colortable_entry_set_value(vulgus_colortable, machine->gfx[0]->color_base + i, 32 + *color_prom++);
+
+ /* sprites use colors 16-31 */
+ for (i = 0;i < machine->gfx[2]->total_colors * machine->gfx[2]->color_granularity;i++)
+ colortable_entry_set_value(vulgus_colortable, machine->gfx[2]->color_base + i, 16 + *color_prom++);
+
+ /* background tiles use colors 0-15, 64-79, 128-143, 192-207 in four banks */
+ for (i = 0;i < machine->gfx[1]->total_colors * machine->gfx[1]->color_granularity / 4;i++)
+ {
+ colortable_entry_set_value(vulgus_colortable, machine->gfx[1]->color_base + 0*32*8 + i, *color_prom);
+ colortable_entry_set_value(vulgus_colortable, machine->gfx[1]->color_base + 1*32*8 + i, *color_prom + 64);
+ colortable_entry_set_value(vulgus_colortable, machine->gfx[1]->color_base + 2*32*8 + i, *color_prom + 128);
+ colortable_entry_set_value(vulgus_colortable, machine->gfx[1]->color_base + 3*32*8 + i, *color_prom + 192);
+ color_prom++;
+ }
+}
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code, color;
+
+ code = vulgus_fgvideoram[tile_index];
+ color = vulgus_fgvideoram[tile_index + 0x400];
+ SET_TILE_INFO(
+ 0,
+ code + ((color & 0x80) << 1),
+ color & 0x3f,
+ 0);
+ tileinfo->group = color & 0x3f;
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code, color;
+
+ code = vulgus_bgvideoram[tile_index];
+ color = vulgus_bgvideoram[tile_index + 0x400];
+ SET_TILE_INFO(
+ 1,
+ code + ((color & 0x80) << 1),
+ (color & 0x1f) + (0x20 * vulgus_palette_bank),
+ TILE_FLIPYX((color & 0x60) >> 5));
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( vulgus )
+{
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN,16,16,32,32);
+
+ colortable_configure_tilemap_groups(vulgus_colortable, fg_tilemap, machine->gfx[0], 47);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( vulgus_fgvideoram_w )
+{
+ vulgus_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( vulgus_bgvideoram_w )
+{
+ vulgus_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+}
+
+
+WRITE8_HANDLER( vulgus_c804_w )
+{
+ /* bits 0 and 1 are coin counters */
+ coin_counter_w(0, data & 0x01);
+ coin_counter_w(1, data & 0x02);
+
+ /* bit 7 flips screen */
+ flip_screen_set(data & 0x80);
+}
+
+
+WRITE8_HANDLER( vulgus_palette_bank_w )
+{
+ if (vulgus_palette_bank != (data & 3))
+ {
+ vulgus_palette_bank = data & 3;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int code,i,col,sx,sy,dir;
+
+
+ code = spriteram[offs];
+ col = spriteram[offs + 1] & 0x0f;
+ sx = spriteram[offs + 3];
+ sy = spriteram[offs + 2];
+ dir = 1;
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy = 240 - sy;
+ dir = -1;
+ }
+
+ i = (spriteram[offs + 1] & 0xc0) >> 6;
+ if (i == 2) i = 3;
+
+ do
+ {
+ drawgfx(bitmap,machine->gfx[2],
+ code + i,
+ col,
+ flip_screen,flip_screen,
+ sx, sy + 16 * i * dir,
+ cliprect,TRANSPARENCY_PEN,15);
+
+ /* draw again with wraparound */
+ drawgfx(bitmap,machine->gfx[2],
+ code + i,
+ col,
+ flip_screen,flip_screen,
+ sx, sy + 16 * i * dir - dir * 256,
+ cliprect,TRANSPARENCY_PEN,15);
+ i--;
+ } while (i >= 0);
+ }
+}
+
+VIDEO_UPDATE( vulgus )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, vulgus_scroll_low[1] + 256 * vulgus_scroll_high[1]);
+ tilemap_set_scrolly(bg_tilemap, 0, vulgus_scroll_low[0] + 256 * vulgus_scroll_high[0]);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/warpwarp.c b/src/mame/video/warpwarp.c
new file mode 100644
index 00000000000..1eb61d01807
--- /dev/null
+++ b/src/mame/video/warpwarp.c
@@ -0,0 +1,269 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/warpwarp.h"
+
+
+UINT8 *geebee_videoram,*warpwarp_videoram;
+int geebee_handleoverlay;
+int geebee_bgw;
+int warpwarp_ball_on;
+int warpwarp_ball_h,warpwarp_ball_v;
+int warpwarp_ball_sizex, warpwarp_ball_sizey;
+
+static tilemap *bg_tilemap;
+
+
+static const rgb_t geebee_palette[] =
+{
+ MAKE_RGB(0x00,0x00,0x00), /* black */
+ MAKE_RGB(0xff,0xff,0xff), /* white */
+ MAKE_RGB(0x7f,0x7f,0x7f) /* grey */
+};
+
+static UINT16 geebee_colortable[] =
+{
+ 0, 1,
+ 1, 0,
+ 0, 2,
+ 2, 0
+};
+
+static UINT16 navarone_colortable[] =
+{
+ 0, 2,
+ 2, 0,
+};
+
+
+/* Initialise the palette */
+PALETTE_INIT( geebee )
+{
+ int i;
+ for (i = 0; i < sizeof(geebee_palette)/sizeof(geebee_palette[0]); i++)
+ palette_set_color(machine,i,geebee_palette[i]);
+ memcpy(colortable, geebee_colortable, sizeof (geebee_colortable));
+}
+
+/* Initialise the palette */
+PALETTE_INIT( navarone )
+{
+ int i;
+ for (i = 0; i < sizeof(geebee_palette)/sizeof(geebee_palette[0]); i++)
+ palette_set_color(machine,i,geebee_palette[i]);
+ memcpy(colortable, navarone_colortable, sizeof (navarone_colortable));
+}
+
+
+/***************************************************************************
+
+ Warp Warp doesn't use PROMs - the 8-bit code is directly converted into a
+ color.
+
+ The color RAM is connected to the RGB output this way (I think - schematics
+ are fuzzy):
+
+ bit 7 -- 300 ohm resistor -- BLUE
+ -- 820 ohm resistor -- BLUE
+ -- 300 ohm resistor -- GREEN
+ -- 820 ohm resistor -- GREEN
+ -- 1.6kohm resistor -- GREEN
+ -- 300 ohm resistor -- RED
+ -- 820 ohm resistor -- RED
+ bit 0 -- 1.6kohm resistor -- RED
+
+ Moreover, the bullet is pure white, obtained with three 220 ohm resistors.
+
+***************************************************************************/
+
+PALETTE_INIT( warpwarp )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (i >> 0) & 0x01;
+ bit1 = (i >> 1) & 0x01;
+ bit2 = (i >> 2) & 0x01;
+ r = 0x1f * bit0 + 0x3c * bit1 + 0xa4 * bit2;
+ /* green component */
+ bit0 = (i >> 3) & 0x01;
+ bit1 = (i >> 4) & 0x01;
+ bit2 = (i >> 5) & 0x01;
+ g = 0x1f * bit0 + 0x3c * bit1 + 0xa4 * bit2;
+ /* blue component */
+ bit0 = 0;
+ bit1 = (i >> 6) & 0x01;
+ bit2 = (i >> 7) & 0x01;
+ b = 0x1f * bit0 + 0x3c * bit1 + 0xa4 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ for (i = 0;i < machine->drv->color_table_len;i += 2)
+ {
+ colortable[i] = 0; /* black background */
+ colortable[i + 1] = i / 2; /* colored foreground */
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/* convert from 32x32 to 34x28 */
+static UINT32 tilemap_scan(UINT32 col,UINT32 row,UINT32 num_cols,UINT32 num_rows)
+{
+ int offs;
+
+ row += 2;
+ col--;
+ if (col & 0x20)
+ offs = row + ((col & 1) << 5);
+ else
+ offs = col + (row << 5);
+
+ return offs;
+}
+
+static TILE_GET_INFO( geebee_get_tile_info )
+{
+ int code = geebee_videoram[tile_index];
+ int color = (geebee_bgw & 1) | ((code & 0x80) >> 6);
+ SET_TILE_INFO(
+ 0,
+ code,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( navarone_get_tile_info )
+{
+ int code = geebee_videoram[tile_index];
+ int color = geebee_bgw & 1;
+ SET_TILE_INFO(
+ 0,
+ code,
+ color,
+ 0);
+}
+
+static TILE_GET_INFO( warpwarp_get_tile_info )
+{
+ SET_TILE_INFO(
+ 0,
+ warpwarp_videoram[tile_index],
+ warpwarp_videoram[tile_index + 0x400],
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( geebee )
+{
+ bg_tilemap = tilemap_create(geebee_get_tile_info,tilemap_scan,TILEMAP_TYPE_PEN,8,8,34,28);
+}
+
+VIDEO_START( navarone )
+{
+ bg_tilemap = tilemap_create(navarone_get_tile_info,tilemap_scan,TILEMAP_TYPE_PEN,8,8,34,28);
+}
+
+VIDEO_START( warpwarp )
+{
+ bg_tilemap = tilemap_create(warpwarp_get_tile_info,tilemap_scan,TILEMAP_TYPE_PEN,8,8,34,28);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( geebee_videoram_w )
+{
+ geebee_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( warpwarp_videoram_w )
+{
+ warpwarp_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+INLINE void geebee_plot(mame_bitmap *bitmap, const rectangle *cliprect, int x, int y, int pen)
+{
+ if (x >= cliprect->min_x && x <= cliprect->max_x && y >= cliprect->min_y && y <= cliprect->max_y)
+ *BITMAP_ADDR16(bitmap, y, x) = pen;
+}
+
+static void draw_ball(mame_bitmap *bitmap, const rectangle *cliprect,int color)
+{
+ if (warpwarp_ball_on)
+ {
+ int x = 256+8 - warpwarp_ball_h;
+ int y = 240 - warpwarp_ball_v;
+ int i,j;
+
+ for (i = warpwarp_ball_sizey;i > 0;i--)
+ {
+ for (j = warpwarp_ball_sizex;j > 0;j--)
+ {
+ geebee_plot(bitmap, cliprect, x-j, y-i, color);
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( geebee )
+{
+ /* use an overlay only in upright mode */
+ if (geebee_handleoverlay)
+ output_set_value("overlay", (readinputport(2) & 0x01) == 0);
+
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ draw_ball(bitmap,cliprect,1);
+ return 0;
+}
+
+
+
+VIDEO_UPDATE( warpwarp )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ draw_ball(bitmap,cliprect,0xf6);
+ return 0;
+}
diff --git a/src/mame/video/warriorb.c b/src/mame/video/warriorb.c
new file mode 100644
index 00000000000..f82b06fb8b8
--- /dev/null
+++ b/src/mame/video/warriorb.c
@@ -0,0 +1,138 @@
+#include "driver.h"
+#include "video/taitoic.h"
+
+#define TC0100SCN_GFX_NUM 1
+
+/**********************************************************/
+
+static void warriorb_core_vh_start(running_machine *machine, int x_offs,int multiscrn_xoffs)
+{
+ int chips;
+
+ chips = number_of_TC0100SCN();
+
+ assert_always(chips > 0, "erroneous TC0100SCN configuration");
+
+ TC0100SCN_vh_start(machine,chips,TC0100SCN_GFX_NUM,x_offs,0,0,0,0,0,multiscrn_xoffs);
+
+ if (has_TC0110PCR())
+ TC0110PCR_vh_start();
+
+ if (has_second_TC0110PCR())
+ TC0110PCR_1_vh_start();
+
+ /* Ensure palette from correct TC0110PCR used for each screen */
+ TC0100SCN_set_chip_colbanks(0,0x100,0x0);
+}
+
+VIDEO_START( darius2d )
+{
+ warriorb_core_vh_start(machine, 4,0);
+}
+
+VIDEO_START( warriorb )
+{
+ warriorb_core_vh_start(machine, 4,1);
+}
+
+
+/************************************************************
+ SPRITE DRAW ROUTINE
+************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int x_offs,int y_offs)
+{
+ int offs, data, data2, tilenum, color, flipx, flipy;
+ int x, y, priority, pri_mask;
+
+#ifdef MAME_DEBUG
+ int unknown=0;
+#endif
+
+ /* pdrawgfx() needs us to draw sprites front to back */
+ for (offs = 0;offs < spriteram_size/2;offs += 4)
+ {
+ data = spriteram16[offs+1];
+ tilenum = data & 0x7fff;
+
+ data = spriteram16[offs+0];
+ y = (-(data &0x1ff) - 24) & 0x1ff; /* (inverted y adjusted for vis area) */
+ flipy = (data & 0x200) >> 9;
+
+ data2 = spriteram16[offs+2];
+ /* 8,4 also seen in msbyte */
+ priority = (data2 & 0x0100) >> 8; // 1 = low
+
+ if(priority)
+ pri_mask = 0xfffe;
+ else
+ pri_mask = 0;
+
+ color = (data2 & 0x7f);
+
+ data = spriteram16[offs+3];
+ x = (data & 0x3ff);
+ flipx = (data & 0x400) >> 10;
+
+
+#ifdef MAME_DEBUG
+ if (data2 & 0xf280) unknown |= (data2 &0xf280);
+#endif
+
+ x -= x_offs;
+ y += y_offs;
+
+ /* sprite wrap: coords become negative at high values */
+ if (x>0x3c0) x -= 0x400;
+ if (y>0x180) y -= 0x200;
+
+ pdrawgfx(bitmap,machine->gfx[0],
+ tilenum,
+ color,
+ flipx,flipy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,0,pri_mask);
+ }
+
+#ifdef MAME_DEBUG
+ if (unknown)
+ popmessage("unknown sprite bits: %04x",unknown);
+#endif
+}
+
+
+/**************************************************************
+ SCREEN REFRESH
+**************************************************************/
+
+VIDEO_UPDATE( warriorb )
+{
+ int xoffs = 40*8*screen;
+ UINT8 layer[3], nodraw;
+
+ TC0100SCN_tilemap_update(machine);
+
+ layer[0] = TC0100SCN_bottomlayer(0);
+ layer[1] = layer[0]^1;
+ layer[2] = 2;
+
+ /* Clear priority bitmap */
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ /* chip 0 does tilemaps on the left, chip 1 does the ones on the right */
+ // draw bottom layer
+ nodraw = TC0100SCN_tilemap_draw(machine,bitmap,cliprect,screen,layer[0],TILEMAP_DRAW_OPAQUE,0); /* left */
+
+ /* Ensure screen blanked even when bottom layers not drawn due to disable bit */
+ if(nodraw) fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ // draw middle layer
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,screen,layer[1],0,1);
+
+ /* Sprites can be under/over the layer below text layer */
+ draw_sprites(machine, bitmap,cliprect,xoffs,8); // draw sprites
+
+ // draw top(text) layer
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,screen,layer[2],0,0);
+ return 0;
+}
diff --git a/src/mame/video/wc90.c b/src/mame/video/wc90.c
new file mode 100644
index 00000000000..c46c13a822e
--- /dev/null
+++ b/src/mame/video/wc90.c
@@ -0,0 +1,386 @@
+#include "driver.h"
+
+
+UINT8 *wc90_fgvideoram,*wc90_bgvideoram,*wc90_txvideoram;
+
+
+UINT8 *wc90_scroll0xlo, *wc90_scroll0xhi;
+UINT8 *wc90_scroll1xlo, *wc90_scroll1xhi;
+UINT8 *wc90_scroll2xlo, *wc90_scroll2xhi;
+
+UINT8 *wc90_scroll0ylo, *wc90_scroll0yhi;
+UINT8 *wc90_scroll1ylo, *wc90_scroll1yhi;
+UINT8 *wc90_scroll2ylo, *wc90_scroll2yhi;
+
+
+static tilemap *tx_tilemap,*fg_tilemap,*bg_tilemap;
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = wc90_bgvideoram[tile_index];
+ int tile = wc90_bgvideoram[tile_index + 0x800] +
+ 256 * ((attr & 3) + ((attr >> 1) & 4));
+ SET_TILE_INFO(
+ 2,
+ tile,
+ attr >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = wc90_fgvideoram[tile_index];
+ int tile = wc90_fgvideoram[tile_index + 0x800] +
+ 256 * ((attr & 3) + ((attr >> 1) & 4));
+ SET_TILE_INFO(
+ 1,
+ tile,
+ attr >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ SET_TILE_INFO(
+ 0,
+ wc90_txvideoram[tile_index + 0x800] + ((wc90_txvideoram[tile_index] & 0x07) << 8),
+ wc90_txvideoram[tile_index] >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( track_get_bg_tile_info )
+{
+ int attr = wc90_bgvideoram[tile_index];
+ int tile = wc90_bgvideoram[tile_index + 0x800] +
+ 256 * (attr & 7);
+ SET_TILE_INFO(
+ 2,
+ tile,
+ attr >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( track_get_fg_tile_info )
+{
+ int attr = wc90_fgvideoram[tile_index];
+ int tile = wc90_fgvideoram[tile_index + 0x800] +
+ 256 * (attr & 7);
+ SET_TILE_INFO(
+ 1,
+ tile,
+ attr >> 4,
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( wc90 )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,64,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_transparent_pen(tx_tilemap,0);
+}
+
+VIDEO_START( wc90t )
+{
+ bg_tilemap = tilemap_create(track_get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,64,32);
+ fg_tilemap = tilemap_create(track_get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,0);
+ tilemap_set_transparent_pen(tx_tilemap,0);
+}
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( wc90_bgvideoram_w )
+{
+ wc90_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x7ff);
+}
+
+WRITE8_HANDLER( wc90_fgvideoram_w )
+{
+ wc90_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x7ff);
+}
+
+WRITE8_HANDLER( wc90_txvideoram_w )
+{
+ wc90_txvideoram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset & 0x7ff);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+#define WC90_DRAW_SPRITE( code, sx, sy ) \
+ drawgfx( bitmap, machine->gfx[3], code, flags >> 4, \
+ bank&1, bank&2, sx, sy, cliprect, TRANSPARENCY_PEN, 0 )
+
+static char pos32x32[] = { 0, 1, 2, 3 };
+static char pos32x32x[] = { 1, 0, 3, 2 };
+static char pos32x32y[] = { 2, 3, 0, 1 };
+static char pos32x32xy[] = { 3, 2, 1, 0 };
+
+static char pos32x64[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+static char pos32x64x[] = { 5, 4, 7, 6, 1, 0, 3, 2 };
+static char pos32x64y[] = { 2, 3, 0, 1, 6, 7, 4, 5 };
+static char pos32x64xy[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
+
+static char pos64x32[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+static char pos64x32x[] = { 1, 0, 3, 2, 5, 4, 7, 6 };
+static char pos64x32y[] = { 6, 7, 4, 5, 2, 3, 0, 1 };
+static char pos64x32xy[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
+
+static char pos64x64[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+static char pos64x64x[] = { 5, 4, 7, 6, 1, 0, 3, 2, 13, 12, 15, 14, 9, 8, 11, 10 };
+static char pos64x64y[] = { 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5 };
+static char pos64x64xy[] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
+
+static char* p32x32[4] = {
+ pos32x32,
+ pos32x32x,
+ pos32x32y,
+ pos32x32xy
+};
+
+static char* p32x64[4] = {
+ pos32x64,
+ pos32x64x,
+ pos32x64y,
+ pos32x64xy
+};
+
+static char* p64x32[4] = {
+ pos64x32,
+ pos64x32x,
+ pos64x32y,
+ pos64x32xy
+};
+
+static char* p64x64[4] = {
+ pos64x64,
+ pos64x64x,
+ pos64x64y,
+ pos64x64xy
+};
+
+static void draw_sprite_16x16(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int code,
+ int sx, int sy, int bank, int flags ) {
+ WC90_DRAW_SPRITE( code, sx, sy );
+}
+
+static void draw_sprite_16x32(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int code,
+ int sx, int sy, int bank, int flags ) {
+ if ( bank & 2 ) {
+ WC90_DRAW_SPRITE( code+1, sx, sy+16 );
+ WC90_DRAW_SPRITE( code, sx, sy );
+ } else {
+ WC90_DRAW_SPRITE( code, sx, sy );
+ WC90_DRAW_SPRITE( code+1, sx, sy+16 );
+ }
+}
+
+static void draw_sprite_16x64(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int code,
+ int sx, int sy, int bank, int flags ) {
+ if ( bank & 2 ) {
+ WC90_DRAW_SPRITE( code+3, sx, sy+48 );
+ WC90_DRAW_SPRITE( code+2, sx, sy+32 );
+ WC90_DRAW_SPRITE( code+1, sx, sy+16 );
+ WC90_DRAW_SPRITE( code, sx, sy );
+ } else {
+ WC90_DRAW_SPRITE( code, sx, sy );
+ WC90_DRAW_SPRITE( code+1, sx, sy+16 );
+ WC90_DRAW_SPRITE( code+2, sx, sy+32 );
+ WC90_DRAW_SPRITE( code+3, sx, sy+48 );
+ }
+}
+
+static void draw_sprite_32x16(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int code,
+ int sx, int sy, int bank, int flags ) {
+ if ( bank & 1 ) {
+ WC90_DRAW_SPRITE( code+1, sx+16, sy );
+ WC90_DRAW_SPRITE( code, sx, sy );
+ } else {
+ WC90_DRAW_SPRITE( code, sx, sy );
+ WC90_DRAW_SPRITE( code+1, sx+16, sy );
+ }
+}
+
+static void draw_sprite_32x32(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int code,
+ int sx, int sy, int bank, int flags ) {
+
+ char *p = p32x32[ bank&3 ];
+
+ WC90_DRAW_SPRITE( code+p[0], sx, sy );
+ WC90_DRAW_SPRITE( code+p[1], sx+16, sy );
+ WC90_DRAW_SPRITE( code+p[2], sx, sy+16 );
+ WC90_DRAW_SPRITE( code+p[3], sx+16, sy+16 );
+}
+
+static void draw_sprite_32x64(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int code,
+ int sx, int sy, int bank, int flags ) {
+
+ char *p = p32x64[ bank&3 ];
+
+ WC90_DRAW_SPRITE( code+p[0], sx, sy );
+ WC90_DRAW_SPRITE( code+p[1], sx+16, sy );
+ WC90_DRAW_SPRITE( code+p[2], sx, sy+16 );
+ WC90_DRAW_SPRITE( code+p[3], sx+16, sy+16 );
+ WC90_DRAW_SPRITE( code+p[4], sx, sy+32 );
+ WC90_DRAW_SPRITE( code+p[5], sx+16, sy+32 );
+ WC90_DRAW_SPRITE( code+p[6], sx, sy+48 );
+ WC90_DRAW_SPRITE( code+p[7], sx+16, sy+48 );
+}
+
+static void draw_sprite_64x16(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int code,
+ int sx, int sy, int bank, int flags ) {
+ if ( bank & 1 ) {
+ WC90_DRAW_SPRITE( code+3, sx+48, sy );
+ WC90_DRAW_SPRITE( code+2, sx+32, sy );
+ WC90_DRAW_SPRITE( code+1, sx+16, sy );
+ WC90_DRAW_SPRITE( code, sx, sy );
+ } else {
+ WC90_DRAW_SPRITE( code, sx, sy );
+ WC90_DRAW_SPRITE( code+1, sx+16, sy );
+ WC90_DRAW_SPRITE( code+2, sx+32, sy );
+ WC90_DRAW_SPRITE( code+3, sx+48, sy );
+ }
+}
+
+static void draw_sprite_64x32(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int code,
+ int sx, int sy, int bank, int flags ) {
+
+ char *p = p64x32[ bank&3 ];
+
+ WC90_DRAW_SPRITE( code+p[0], sx, sy );
+ WC90_DRAW_SPRITE( code+p[1], sx+16, sy );
+ WC90_DRAW_SPRITE( code+p[2], sx, sy+16 );
+ WC90_DRAW_SPRITE( code+p[3], sx+16, sy+16 );
+ WC90_DRAW_SPRITE( code+p[4], sx+32, sy );
+ WC90_DRAW_SPRITE( code+p[5], sx+48, sy );
+ WC90_DRAW_SPRITE( code+p[6], sx+32, sy+16 );
+ WC90_DRAW_SPRITE( code+p[7], sx+48, sy+16 );
+}
+
+static void draw_sprite_64x64(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int code,
+ int sx, int sy, int bank, int flags ) {
+
+ char *p = p64x64[ bank&3 ];
+
+ WC90_DRAW_SPRITE( code+p[0], sx, sy );
+ WC90_DRAW_SPRITE( code+p[1], sx+16, sy );
+ WC90_DRAW_SPRITE( code+p[2], sx, sy+16 );
+ WC90_DRAW_SPRITE( code+p[3], sx+16, sy+16 );
+ WC90_DRAW_SPRITE( code+p[4], sx+32, sy );
+ WC90_DRAW_SPRITE( code+p[5], sx+48, sy );
+ WC90_DRAW_SPRITE( code+p[6], sx+32, sy+16 );
+ WC90_DRAW_SPRITE( code+p[7], sx+48, sy+16 );
+
+ WC90_DRAW_SPRITE( code+p[8], sx, sy+32 );
+ WC90_DRAW_SPRITE( code+p[9], sx+16, sy+32 );
+ WC90_DRAW_SPRITE( code+p[10], sx, sy+48 );
+ WC90_DRAW_SPRITE( code+p[11], sx+16, sy+48 );
+ WC90_DRAW_SPRITE( code+p[12], sx+32, sy+32 );
+ WC90_DRAW_SPRITE( code+p[13], sx+48, sy+32 );
+ WC90_DRAW_SPRITE( code+p[14], sx+32, sy+48 );
+ WC90_DRAW_SPRITE( code+p[15], sx+48, sy+48 );
+}
+
+static void draw_sprite_invalid(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int code,
+ int sx, int sy, int bank, int flags ) {
+ logerror("8 pixel sprite size not supported\n" );
+}
+
+typedef void (*draw_sprites_procdef)(running_machine *, mame_bitmap *, const rectangle *, int, int, int, int, int );
+
+static draw_sprites_procdef draw_sprites_proc[16] = {
+ draw_sprite_invalid, /* 0000 = 08x08 */
+ draw_sprite_invalid, /* 0001 = 16x08 */
+ draw_sprite_invalid, /* 0010 = 32x08 */
+ draw_sprite_invalid, /* 0011 = 64x08 */
+ draw_sprite_invalid, /* 0100 = 08x16 */
+ draw_sprite_16x16, /* 0101 = 16x16 */
+ draw_sprite_32x16, /* 0110 = 32x16 */
+ draw_sprite_64x16, /* 0111 = 64x16 */
+ draw_sprite_invalid, /* 1000 = 08x32 */
+ draw_sprite_16x32, /* 1001 = 16x32 */
+ draw_sprite_32x32, /* 1010 = 32x32 */
+ draw_sprite_64x32, /* 1011 = 64x32 */
+ draw_sprite_invalid, /* 1100 = 08x64 */
+ draw_sprite_16x64, /* 1101 = 16x64 */
+ draw_sprite_32x64, /* 1110 = 32x64 */
+ draw_sprite_64x64 /* 1111 = 64x64 */
+};
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority )
+{
+ int offs, sx,sy, flags, which;
+
+ /* draw all visible sprites of specified priority */
+ for (offs = 0;offs < spriteram_size;offs += 16){
+ int bank = spriteram[offs+0];
+
+ if ( ( bank >> 4 ) == priority ) {
+
+ if ( bank & 4 ) { /* visible */
+ which = ( spriteram[offs+2] >> 2 ) + ( spriteram[offs+3] << 6 );
+
+ sx = spriteram[offs + 8] + ( (spriteram[offs + 9] & 1 ) << 8 );
+ sy = spriteram[offs + 6] + ( (spriteram[offs + 7] & 1 ) << 8 );
+
+ flags = spriteram[offs+4];
+ ( *( draw_sprites_proc[ flags & 0x0f ] ) )(machine, bitmap,cliprect, which, sx, sy, bank, flags );
+ }
+ }
+ }
+}
+
+#undef WC90_DRAW_SPRITE
+
+
+VIDEO_UPDATE( wc90 )
+{
+ tilemap_set_scrollx(bg_tilemap,0,wc90_scroll2xlo[0] + 256 * wc90_scroll2xhi[0]);
+ tilemap_set_scrolly(bg_tilemap,0,wc90_scroll2ylo[0] + 256 * wc90_scroll2yhi[0]);
+ tilemap_set_scrollx(fg_tilemap,0,wc90_scroll1xlo[0] + 256 * wc90_scroll1xhi[0]);
+ tilemap_set_scrolly(fg_tilemap,0,wc90_scroll1ylo[0] + 256 * wc90_scroll1yhi[0]);
+ tilemap_set_scrollx(tx_tilemap,0,wc90_scroll0xlo[0] + 256 * wc90_scroll0xhi[0]);
+ tilemap_set_scrolly(tx_tilemap,0,wc90_scroll0ylo[0] + 256 * wc90_scroll0yhi[0]);
+
+// draw_sprites(machine, bitmap,cliprect, 3 );
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect, 2 );
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect, 1 );
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect, 0 );
+ return 0;
+}
diff --git a/src/mame/video/wc90b.c b/src/mame/video/wc90b.c
new file mode 100644
index 00000000000..e00092377c6
--- /dev/null
+++ b/src/mame/video/wc90b.c
@@ -0,0 +1,151 @@
+#include "driver.h"
+
+
+UINT8 *wc90b_fgvideoram,*wc90b_bgvideoram,*wc90b_txvideoram;
+
+UINT8 *wc90b_scroll1x;
+UINT8 *wc90b_scroll2x;
+
+UINT8 *wc90b_scroll1y;
+UINT8 *wc90b_scroll2y;
+
+
+static tilemap *tx_tilemap,*fg_tilemap,*bg_tilemap;
+
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int attr = wc90b_bgvideoram[tile_index];
+ int tile = wc90b_bgvideoram[tile_index + 0x800];
+ SET_TILE_INFO(
+ 9 + ((attr & 3) + ((attr >> 1) & 4)),
+ tile,
+ attr >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int attr = wc90b_fgvideoram[tile_index];
+ int tile = wc90b_fgvideoram[tile_index + 0x800];
+ SET_TILE_INFO(
+ 1 + ((attr & 3) + ((attr >> 1) & 4)),
+ tile,
+ attr >> 4,
+ 0);
+}
+
+static TILE_GET_INFO( get_tx_tile_info )
+{
+ SET_TILE_INFO(
+ 0,
+ wc90b_txvideoram[tile_index + 0x800] + ((wc90b_txvideoram[tile_index] & 0x07) << 8),
+ wc90b_txvideoram[tile_index] >> 4,
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( wc90b )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16,16,64,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+
+ tilemap_set_transparent_pen(fg_tilemap,15);
+ tilemap_set_transparent_pen(tx_tilemap,15);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( wc90b_bgvideoram_w )
+{
+ wc90b_bgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x7ff);
+}
+
+WRITE8_HANDLER( wc90b_fgvideoram_w )
+{
+ wc90b_fgvideoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset & 0x7ff);
+}
+
+WRITE8_HANDLER( wc90b_txvideoram_w )
+{
+ wc90b_txvideoram[offset] = data;
+ tilemap_mark_tile_dirty(tx_tilemap,offset & 0x7ff);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority ){
+ int offs;
+
+ /* draw all visible sprites of specified priority */
+ for ( offs = spriteram_size - 8;offs >= 0;offs -= 8 ){
+
+ if ( ( ~( spriteram[offs+3] >> 6 ) & 3 ) == priority ) {
+
+ if ( spriteram[offs+1] > 16 ) { /* visible */
+ int code = ( spriteram[offs+3] & 0x3f ) << 4;
+ int bank = spriteram[offs+0];
+ int flags = spriteram[offs+4];
+
+ code += ( bank & 0xf0 ) >> 4;
+ code <<= 2;
+ code += ( bank & 0x0f ) >> 2;
+
+ drawgfx( bitmap,machine->gfx[ 17 ], code,
+ flags >> 4, /* color */
+ bank&1, /* flipx */
+ bank&2, /* flipy */
+ spriteram[offs + 2], /* sx */
+ 240 - spriteram[offs + 1], /* sy */
+ cliprect,TRANSPARENCY_PEN,15 );
+ }
+ }
+ }
+}
+
+VIDEO_UPDATE( wc90b )
+{
+ tilemap_set_scrollx(bg_tilemap,0,8 * wc90b_scroll2x[0] + 256);
+ tilemap_set_scrolly(bg_tilemap,0,wc90b_scroll2y[0] + ((wc90b_scroll2y[0] < 0x10 || wc90b_scroll2y[0] == 0xff) ? 256 : 0));
+ tilemap_set_scrollx(fg_tilemap,0,8 * wc90b_scroll1x[0] + 256);
+ tilemap_set_scrolly(fg_tilemap,0,wc90b_scroll1y[0] + ((wc90b_scroll1y[0] < 0x10 || wc90b_scroll1y[0] == 0xff) ? 256 : 0));
+
+// draw_sprites(machine, bitmap,cliprect, 3 );
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect, 2 );
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect, 1 );
+ tilemap_draw(bitmap,cliprect,tx_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect, 0 );
+ return 0;
+}
diff --git a/src/mame/video/wecleman.c b/src/mame/video/wecleman.c
new file mode 100644
index 00000000000..99a8bbdeeaa
--- /dev/null
+++ b/src/mame/video/wecleman.c
@@ -0,0 +1,1132 @@
+/***************************************************************************
+ WEC Le Mans 24 & Hot Chase
+
+ (C) 1986 & 1988 Konami
+
+ driver by Luca Elia (l.elia@tin.it)
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/konamiic.h"
+
+#define BMP_PAD 8
+#define BLEND_STEPS 16
+#define BLEND_MIN 0
+#define BLEND_MAX (BLEND_STEPS*0x20-1)
+#define BLEND_INC 1
+#define BLEND_DEC -8
+
+#define SPRITE_FLIPX 0x01
+#define SPRITE_FLIPY 0x02
+#define NUM_SPRITES 256
+
+struct sprite
+{
+ UINT8 *pen_data; /* points to top left corner of tile data */
+ int line_offset;
+
+ const pen_t *pal_data;
+
+ int x_offset, y_offset;
+ int tile_width, tile_height;
+ int total_width, total_height; /* in screen coordinates */
+ int x, y;
+ int shadow_mode, flags;
+};
+
+/* Variables defined in driver: */
+extern int wecleman_selected_ip, wecleman_irqctrl;
+
+/* Variables that driver has acces to: */
+UINT16 *wecleman_videostatus;
+UINT16 *wecleman_pageram, *wecleman_txtram, *wecleman_roadram;
+size_t wecleman_roadram_size;
+static int wecleman_bgpage[4], wecleman_fgpage[4], *wecleman_gfx_bank;
+
+/* Variables only used here: */
+static tilemap *bg_tilemap, *fg_tilemap, *txt_tilemap;
+
+static struct sprite *sprite_list;
+static struct sprite **spr_ptr_list;
+static int *spr_idx_list, *spr_pri_list, *t32x32pm;
+static int gameid, spr_offsx, spr_offsy, spr_count;
+static UINT16 *rgb_half;
+
+static int cloud_blend, cloud_ds, cloud_visible;
+
+
+/***************************************************************************
+
+ Sprite Description and Routines
+ -------------------------------
+
+ Sprites: 256 entries, 16 bytes each, first ten bytes used (and tested)
+
+ Offset Bits Meaning
+
+ 00.w fedc ba98 ---- ---- Screen Y stop
+ ---- ---- 7654 3210 Screen Y start
+
+ 02.w fedc ba-- ---- ---- High bits of sprite "address"
+ ---- --9- ---- ---- Flip Y ?
+ ---- ---8 7654 3210 Screen X start
+
+ 04.w fedc ba98 ---- ---- Color
+ ---- ---- 7654 3210 Source Width / 8
+
+ 06.w f--- ---- ---- ---- Flip X
+ -edc ba98 7654 3210 Low bits of sprite "address"
+
+ 08.w --dc ba98 ---- ---- Y? Shrink Factor
+ ---- ---- --54 3210 X? Shrink Factor
+
+ Sprite "address" is the index of the pixel the hardware has to start
+ fetching data from, divided by 8. Only the on-screen height and source data
+ width are provided, along with two shrinking factors. So on screen width
+ and source height are calculated by the hardware using the shrink factors.
+ The factors are in the range 0 (no shrinking) - 3F (half size).
+
+ Hot Chase: shadow of trees is pen 0x0a
+
+***************************************************************************/
+
+static struct sprite *sprite_list_create(int num_sprites)
+{
+ struct sprite *spr_list;
+
+ spr_list = auto_malloc(num_sprites * sizeof(struct sprite));
+
+ memset(spr_list, 0, num_sprites * sizeof(struct sprite));
+
+ return spr_list;
+}
+
+static void get_sprite_info(running_machine *machine)
+{
+ const pen_t *base_pal = machine->remapped_colortable;
+ UINT8 *base_gfx = memory_region(REGION_GFX1);
+ int gfx_max = memory_region_length(REGION_GFX1);
+
+ UINT16 *source = spriteram16;
+
+ struct sprite *sprite = sprite_list;
+ struct sprite *finish = sprite_list + NUM_SPRITES;
+
+ int bank, code, gfx, zoom;
+
+ for (spr_count=0; sprite<finish; source+=0x10/2, sprite++)
+ {
+ if (source[0x00/2] == 0xffff) break;
+
+ sprite->y = source[0x00/2] & 0xff;
+ sprite->total_height = (source[0x00/2] >> 8) - sprite->y;
+ if (sprite->total_height < 1) continue;
+
+ sprite->x = source[0x02/2] & 0x1ff;
+ bank = source[0x02/2] >> 10;
+ if (bank == 0x3f) continue;
+
+ sprite->tile_width = source[0x04/2] & 0xff;
+ if (sprite->tile_width < 1) continue;
+
+ sprite->shadow_mode = source[0x04/2] & 0x4000;
+
+ code = source[0x06/2];
+ zoom = source[0x08/2];
+
+ sprite->pal_data = base_pal + ((source[0x0e/2] & 0xff) << 4);
+
+ gfx = (wecleman_gfx_bank[bank] << 15) + (code & 0x7fff);
+
+ sprite->flags = 0;
+ if (code & 0x8000) { sprite->flags |= SPRITE_FLIPX; gfx += 1-sprite->tile_width; }
+ if (source[0x02/2] & 0x0200) sprite->flags |= SPRITE_FLIPY;
+
+ gfx <<= 3;
+ sprite->tile_width <<= 3;
+ sprite->tile_height = (sprite->total_height * 0x80) / (0x80 - (zoom >> 8)); // needs work
+
+ if ((gfx + sprite->tile_width * sprite->tile_height - 1) >= gfx_max) continue;
+
+ sprite->pen_data = base_gfx + gfx;
+ sprite->line_offset = sprite->tile_width;
+ sprite->total_width = sprite->tile_width - (sprite->tile_width * (zoom & 0xff)) / 0x80;
+ sprite->total_height += 1;
+ sprite->x += spr_offsx;
+ sprite->y += spr_offsy;
+
+ if (gameid == 0)
+ {
+ spr_idx_list[spr_count] = spr_count;
+ spr_pri_list[spr_count] = source[0x0e/2] >> 8;
+ }
+
+ spr_ptr_list[spr_count] = sprite;
+ spr_count++;
+ }
+}
+
+// priority sorting, silly but good for smaller arrays
+static void sortsprite(int *idx_array, int *key_array, int size)
+{
+ int i, j, tgt_val, low_val, low_pos, src_idx, tgt_idx, hi_idx;
+
+ idx_array += size;
+
+ for (j=-size; j<-1; j++)
+ {
+ src_idx = idx_array[j];
+ low_pos = j;
+ low_val = key_array[src_idx];
+ hi_idx = src_idx;
+ for (i=j+1; i; i++)
+ {
+ tgt_idx = idx_array[i];
+ tgt_val = key_array[tgt_idx];
+ if (low_val > tgt_val)
+ { low_val = tgt_val; low_pos = i; }
+ else if ((low_val == tgt_val) && (hi_idx <= tgt_idx))
+ { hi_idx = tgt_idx; low_pos = i; }
+ }
+ low_val = idx_array[low_pos];
+ idx_array[low_pos] = src_idx;
+ idx_array[j] = low_val;
+ }
+}
+
+// draws a 8bpp palette sprites on a 16bpp direct RGB target (sub-par implementation)
+static void do_blit_zoom16(mame_bitmap *bitmap, const rectangle *cliprect, struct sprite *sprite)
+{
+#define PRECISION_X 20
+#define PRECISION_Y 20
+#define FPY_HALF (1<<(PRECISION_Y-1))
+
+ const pen_t *pal_base;
+ int src_f0y, src_fdy, src_f0x, src_fdx, src_fpx;
+ int x1, x2, y1, y2, dx, dy, sx, sy;
+ int xcount0=0, ycount0=0;
+
+ if (sprite->flags & SPRITE_FLIPX)
+ {
+ x2 = sprite->x;
+ x1 = x2 + sprite->total_width;
+ dx = -1;
+ if (x2 < cliprect->min_x) x2 = cliprect->min_x;
+ if (x1 > cliprect->max_x )
+ {
+ xcount0 = x1 - cliprect->max_x;
+ x1 = cliprect->max_x;
+ }
+ if (x2 >= x1) return;
+ x1--; x2--;
+ }
+ else
+ {
+ x1 = sprite->x;
+ x2 = x1 + sprite->total_width;
+ dx = 1;
+ if (x1 < cliprect->min_x )
+ {
+ xcount0 = cliprect->min_x - x1;
+ x1 = cliprect->min_x;
+ }
+ if (x2 > cliprect->max_x ) x2 = cliprect->max_x;
+ if (x1 >= x2) return;
+ }
+
+ if (sprite->flags & SPRITE_FLIPY)
+ {
+ y2 = sprite->y;
+ y1 = y2 + sprite->total_height;
+ dy = -1;
+ if (y2 < cliprect->min_y ) y2 = cliprect->min_y;
+ if (y1 > cliprect->max_y )
+ {
+ ycount0 = cliprect->max_y;
+ y1 = cliprect->max_y;
+ }
+ if (y2 >= y1) return;
+ y1--; y2--;
+ }
+ else
+ {
+ y1 = sprite->y;
+ y2 = y1 + sprite->total_height;
+ dy = 1;
+ if (y1 < cliprect->min_y )
+ {
+ ycount0 = cliprect->min_y - y1;
+ y1 = cliprect->min_y;
+ }
+ if (y2 > cliprect->max_y) y2 = cliprect->max_y;
+ if (y1 >= y2) return;
+ }
+
+ // calculate entry point decimals
+ src_fdy = (sprite->tile_height<<PRECISION_Y) / sprite->total_height;
+ src_f0y = src_fdy * ycount0 + FPY_HALF;
+
+ src_fdx = (sprite->tile_width<<PRECISION_X) / sprite->total_width;
+ src_f0x = src_fdx * xcount0;
+
+ // pre-loop assignments and adjustments
+ pal_base = sprite->pal_data;
+
+ x1 -= dx;
+ x2 -= dx;
+
+ for (sy = y1; sy != y2; sy += dy)
+ {
+ UINT8 *row_base = sprite->pen_data + (src_f0y>>PRECISION_Y) * sprite->line_offset;
+ UINT16 *dst_ptr = BITMAP_ADDR16(bitmap, sy, 0);
+ src_fpx = src_f0x;
+
+ if (!sprite->shadow_mode)
+ {
+ for (sx = x1; sx != x2; sx += dx)
+ {
+ int pix = row_base[src_fpx >> PRECISION_X];
+ if (pix & 0x80) break;
+ if (pix)
+ dst_ptr[sx] = pal_base[pix];
+ src_fpx += src_fdx;
+ }
+ }
+ else if (gameid == 0) // Wec Le Mans
+ {
+ for (sx = x1; sx != x2; sx += dx)
+ {
+ int pix = row_base[src_fpx >> PRECISION_X];
+ if (pix & 0x80) break;
+ if (pix)
+ {
+ if (pix != 0xa)
+ dst_ptr[sx] = pal_base[pix];
+ else
+ dst_ptr[sx] = rgb_half[dst_ptr[sx]];
+ }
+ src_fpx += src_fdx;
+ }
+ }
+ else // Hot Chase
+ {
+ for (sx = x1; sx != x2; sx += dx)
+ {
+ int pix = row_base[src_fpx >> PRECISION_X];
+ if (pix & 0x80) break;
+ if (pix)
+ {
+ if (pix != 0xa)
+ dst_ptr[sx] = pal_base[pix];
+ else
+ dst_ptr[sx] |= 0x800;
+ }
+ src_fpx += src_fdx;
+ }
+ }
+
+ src_f0y += src_fdy;
+ }
+}
+
+static void sprite_draw(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int i;
+
+ if (gameid == 0) // Wec Le Mans
+ {
+ sortsprite(spr_idx_list, spr_pri_list, spr_count);
+
+ for (i=0; i<spr_count; i++) do_blit_zoom16(bitmap, cliprect, spr_ptr_list[spr_idx_list[i]]);
+ }
+ else // Hot Chase
+ {
+ for (i=0; i<spr_count; i++) do_blit_zoom16(bitmap, cliprect, spr_ptr_list[i]);
+ }
+}
+
+
+/***************************************************************************
+
+ Background Description and Routines
+ -----------------------------------
+
+ [WEC Le Mans 24]
+
+[ 2 Scrolling Layers ]
+ [Background]
+ [Foreground]
+ Tile Size: 8x8
+
+ Tile Format: see wecleman_get_bg_tile_info()
+
+ Layer Size: 4 Pages - Page0 Page1 Page2 Page3
+ each page is 512 x 256 (64 x 32 tiles)
+
+ Page Selection Reg.: 108efe [Bg]
+ 108efc [Fg]
+ 4 pages to choose from
+
+ Scrolling Columns: 1
+ Scrolling Columns Reg.: 108f26 [Bg]
+ 108f24 [Fg]
+
+ Scrolling Rows: 224 / 8 (Screen-wise scrolling)
+ Scrolling Rows Reg.: 108f82/4/6.. [Bg]
+ 108f80/2/4.. [Fg]
+
+[ 1 Text Layer ]
+ Tile Size: 8x8
+
+ Tile Format: see wecleman_get_txt_tile_info()
+
+ Layer Size: 1 Page: 512 x 256 (64 x 32 tiles)
+
+ Scrolling: -
+
+[ 1 Road Layer ]
+
+[ 256 Sprites ]
+ Zooming Sprites, see below
+
+
+ [Hot Chase]
+
+[ 3 Zooming Layers ]
+ [Background]
+ [Foreground (text)]
+ [Road]
+
+[ 256 Sprites ]
+ Zooming Sprites, see below
+
+***************************************************************************/
+
+/***************************************************************************
+ WEC Le Mans 24
+***************************************************************************/
+
+#define PAGE_GFX (0)
+#define PAGE_NX (0x40)
+#define PAGE_NY (0x20)
+#define TILEMAP_DIMY (PAGE_NY * 2 * 8)
+
+/*------------------------------------------------------------------------
+ [ Frontmost (text) layer + video registers ]
+------------------------------------------------------------------------*/
+
+static TILE_GET_INFO( wecleman_get_txt_tile_info )
+{
+ int code = wecleman_txtram[tile_index];
+ SET_TILE_INFO(PAGE_GFX, code&0xfff, (code>>5&0x78)+(code>>12), 0);
+}
+
+WRITE16_HANDLER( wecleman_txtram_w )
+{
+ UINT16 old_data = wecleman_txtram[offset];
+ UINT16 new_data = COMBINE_DATA(&wecleman_txtram[offset]);
+
+ if ( old_data != new_data )
+ {
+ if (offset >= 0xE00/2 ) /* Video registers */
+ {
+ /* pages selector for the background */
+ if (offset == 0xEFE/2)
+ {
+ wecleman_bgpage[0] = (new_data >> 0x4) & 3;
+ wecleman_bgpage[1] = (new_data >> 0x0) & 3;
+ wecleman_bgpage[2] = (new_data >> 0xc) & 3;
+ wecleman_bgpage[3] = (new_data >> 0x8) & 3;
+ tilemap_mark_all_tiles_dirty(bg_tilemap);
+ }
+
+ /* pages selector for the foreground */
+ if (offset == 0xEFC/2)
+ {
+ wecleman_fgpage[0] = (new_data >> 0x4) & 3;
+ wecleman_fgpage[1] = (new_data >> 0x0) & 3;
+ wecleman_fgpage[2] = (new_data >> 0xc) & 3;
+ wecleman_fgpage[3] = (new_data >> 0x8) & 3;
+ tilemap_mark_all_tiles_dirty(fg_tilemap);
+ }
+
+ /* Parallactic horizontal scroll registers follow */
+ }
+ else
+ tilemap_mark_tile_dirty(txt_tilemap, offset);
+ }
+}
+
+/*------------------------------------------------------------------------
+ [ Background ]
+------------------------------------------------------------------------*/
+
+static TILE_GET_INFO( wecleman_get_bg_tile_info )
+{
+ int page = wecleman_bgpage[((tile_index&0x7f)>>6) + ((tile_index>>12)<<1)];
+ int code = wecleman_pageram[(tile_index&0x3f) + ((tile_index>>7&0x1f)<<6) + (page<<11)];
+
+ SET_TILE_INFO(PAGE_GFX, code&0xfff, (code>>5&0x78)+(code>>12), 0);
+}
+
+/*------------------------------------------------------------------------
+ [ Foreground ]
+------------------------------------------------------------------------*/
+
+static TILE_GET_INFO( wecleman_get_fg_tile_info )
+{
+ int page = wecleman_fgpage[((tile_index&0x7f)>>6) + ((tile_index>>12)<<1)];
+ int code = wecleman_pageram[(tile_index&0x3f) + ((tile_index>>7&0x1f)<<6) + (page<<11)];
+
+ if (!code || code==0xffff) code = 0x20;
+ SET_TILE_INFO(PAGE_GFX, code&0xfff, (code>>5&0x78)+(code>>12), 0);
+}
+
+/*------------------------------------------------------------------------
+ [ Pages (Background & Foreground) ]
+------------------------------------------------------------------------*/
+
+/* Pages that compose both the background and the foreground */
+WRITE16_HANDLER( wecleman_pageram_w )
+{
+ COMBINE_DATA(&wecleman_pageram[offset]);
+
+ {
+ int page,col,row;
+
+ page = ( offset ) / (PAGE_NX * PAGE_NY);
+ col = ( offset ) % PAGE_NX;
+ row = ( offset / PAGE_NX ) % PAGE_NY;
+
+ /* background */
+ if (wecleman_bgpage[0] == page) tilemap_mark_tile_dirty(bg_tilemap, (col+PAGE_NX*0) + (row+PAGE_NY*0)*PAGE_NX*2 );
+ if (wecleman_bgpage[1] == page) tilemap_mark_tile_dirty(bg_tilemap, (col+PAGE_NX*1) + (row+PAGE_NY*0)*PAGE_NX*2 );
+ if (wecleman_bgpage[2] == page) tilemap_mark_tile_dirty(bg_tilemap, (col+PAGE_NX*0) + (row+PAGE_NY*1)*PAGE_NX*2 );
+ if (wecleman_bgpage[3] == page) tilemap_mark_tile_dirty(bg_tilemap, (col+PAGE_NX*1) + (row+PAGE_NY*1)*PAGE_NX*2 );
+
+ /* foreground */
+ if (wecleman_fgpage[0] == page) tilemap_mark_tile_dirty(fg_tilemap, (col+PAGE_NX*0) + (row+PAGE_NY*0)*PAGE_NX*2 );
+ if (wecleman_fgpage[1] == page) tilemap_mark_tile_dirty(fg_tilemap, (col+PAGE_NX*1) + (row+PAGE_NY*0)*PAGE_NX*2 );
+ if (wecleman_fgpage[2] == page) tilemap_mark_tile_dirty(fg_tilemap, (col+PAGE_NX*0) + (row+PAGE_NY*1)*PAGE_NX*2 );
+ if (wecleman_fgpage[3] == page) tilemap_mark_tile_dirty(fg_tilemap, (col+PAGE_NX*1) + (row+PAGE_NY*1)*PAGE_NX*2 );
+ }
+}
+
+/*------------------------------------------------------------------------
+ Road Drawing
+
+ This layer is composed of horizontal lines gfx elements
+ There are 256 lines in ROM, each is 512 pixels wide
+
+ Offset: Elements: Data:
+ 0000-01ff 100 Words Code
+
+ fedcba98-------- Priority?
+ --------76543210 Line Number
+
+ 0200-03ff 100 Words Horizontal Scroll
+ 0400-05ff 100 Words Color
+ 0600-07ff 100 Words ??
+
+ We draw each line using a bunch of 64x1 tiles
+
+------------------------------------------------------------------------*/
+
+static void wecleman_draw_road(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority)
+{
+// must be powers of 2
+#define XSIZE 512
+#define YSIZE 256
+
+#define YMASK (YSIZE-1)
+
+#define DST_WIDTH 320
+#define DST_HEIGHT 224
+
+#define MIDCURB_DY 5
+#define TOPCURB_DY 7
+
+ static const pen_t road_color[48] =
+ {
+ 0x3f1,0x3f3,0x3f5,0x3fd,0x3fd,0x3fb,0x3fd,0x7ff, // road color 0
+ 0x3f0,0x3f2,0x3f4,0x3fc,0x3fc,0x3fb,0x3fc,0x7fe, // road color 1
+ 0, 0, 0,0x3f9,0x3f9, 0, 0, 0, // midcurb color 0
+ 0, 0, 0,0x3f8,0x3f8, 0, 0, 0, // midcurb color 1
+ 0, 0, 0,0x3f7, 0, 0, 0, 0, // topcurb color 0
+ 0, 0, 0,0x3f6, 0, 0, 0, 0 // topcutb color 1
+ };
+
+
+ UINT8 *src_ptr;
+ const pen_t *pal_ptr, *rgb_ptr;
+
+ int scrollx, sy, sx;
+ int mdy, tdy, i;
+
+ rgb_ptr = machine->remapped_colortable;
+
+ if (priority == 0x02)
+ {
+ // draw sky; each scanline is assumed to be dword aligned
+ for (sy=cliprect->min_y-BMP_PAD; sy<DST_HEIGHT; sy++)
+ {
+ UINT16 *dst = BITMAP_ADDR16(bitmap, sy+BMP_PAD, BMP_PAD);
+ UINT16 pix, road;
+
+ road = wecleman_roadram[sy];
+ if ((road>>8) != 0x02) continue;
+
+ pix = rgb_ptr[(wecleman_roadram[sy+(YSIZE*2)] & 0xf) + 0x7f0];
+
+ for (sx = 0; sx < DST_WIDTH; sx++)
+ dst[sx] = pix;
+ }
+ }
+ else if (priority == 0x04)
+ {
+ // draw road
+ UINT8 *src_base = machine->gfx[1]->gfxdata;
+ pen_t road_rgb[48];
+
+ for (i=0; i<48; i++)
+ {
+ int color = road_color[i];
+ road_rgb[i] = color ? rgb_ptr[color] : 0xffffffff;
+ }
+
+ for (sy=cliprect->min_y-BMP_PAD; sy<DST_HEIGHT; sy++)
+ {
+ UINT16 *dst = BITMAP_ADDR16(bitmap, sy+BMP_PAD, BMP_PAD);
+ UINT16 pix, road;
+
+ road = wecleman_roadram[sy];
+ if ((road>>8) != 0x04) continue;
+ road &= YMASK;
+
+ src_ptr = src_base + (road << 9);
+ mdy = ((road * MIDCURB_DY) >> 8) * bitmap->rowpixels;
+ tdy = ((road * TOPCURB_DY) >> 8) * bitmap->rowpixels;
+
+ scrollx = wecleman_roadram[sy+YSIZE] + (0x18 - 0xe00);
+
+ pal_ptr = road_rgb + ((wecleman_roadram[sy+(YSIZE*2)]<<3) & 8);
+
+ for (sx = 0; sx < DST_WIDTH; sx++, scrollx++)
+ {
+ if (scrollx >= 0 && scrollx < XSIZE)
+ {
+ pen_t temp;
+
+ pix = src_ptr[scrollx];
+ dst[sx] = pal_ptr[pix];
+
+ temp = pal_ptr[pix + 16];
+ if (temp != 0xffffffff) dst[sx - mdy] = temp;
+
+ temp = pal_ptr[pix + 32];
+ if (temp != 0xffffffff) dst[sx - tdy] = temp;
+ }
+ else
+ dst[sx] = pal_ptr[7];
+ }
+ }
+ }
+
+#undef YSIZE
+#undef XSIZE
+}
+
+/*------------------------------------------------------------------------
+ Sky Drawing
+------------------------------------------------------------------------*/
+
+// blends two 8x8x16bpp direct RGB tilemaps
+static void draw_cloud(running_machine *machine, mame_bitmap *bitmap,
+ gfx_element *gfx,
+ UINT16 *tm_base,
+ int x0, int y0, // target coordinate
+ int xcount, int ycount, // number of tiles to draw in x and y
+ int scrollx, int scrolly, // tilemap scroll position
+ int tmw_l2, int tmh_l2, // tilemap width and height in log(2)
+ int alpha, int pal_offset ) // alpha(0-3f), # of color codes to shift
+{
+ UINT8 *src_base, *src_ptr;
+ UINT16 *tmap_ptr, *dst_base, *dst_ptr;
+ const pen_t *pal_base, *pal_ptr;
+
+ int tilew, tileh;
+ int tmskipx, tmskipy, tmscanx, tmmaskx, tmmasky;
+ int dx, dy, dst_pitch;
+ int i, j, tx, ty;
+
+ if (alpha > 0x1f) return;
+
+ tilew = gfx->width;
+ tileh = gfx->height;
+
+ tmmaskx = (1<<tmw_l2) - 1;
+ tmmasky = (1<<tmh_l2) - 1;
+
+ scrollx &= ((tilew<<tmw_l2) - 1);
+ scrolly &= ((tileh<<tmh_l2) - 1);
+
+ tmskipx = scrollx / tilew;
+ dx = -(scrollx & (tilew-1));
+ tmskipy = scrolly / tileh;
+ dy = -(scrolly & (tileh-1));
+
+ src_base = gfx->gfxdata;
+
+ dst_pitch = bitmap->rowpixels;
+ dst_base = (UINT16 *)bitmap->base + (y0+dy)*dst_pitch + (x0+dx);
+
+ pal_base = machine->remapped_colortable + pal_offset * gfx->color_granularity;
+
+ alpha <<= 6;
+
+ dst_base += 8;
+ for (i = 0; i < ycount; i++)
+ {
+ tmap_ptr = tm_base + ((tmskipy++ & tmmasky)<<tmw_l2);
+ tmscanx = tmskipx;
+
+ for (j = 0; j < xcount; j++)
+ {
+ UINT16 tiledata = tmap_ptr[tmscanx++ & tmmaskx];
+
+ // Wec Le Mans specific: decodes tile index in EBX
+ UINT16 tile_index = tiledata & 0xfff;
+
+ // Wec Le Mans specific: decodes tile color in EAX
+ UINT16 tile_color = ((tiledata >> 5) & 0x78) + (tiledata >> 12);
+
+ src_ptr = src_base + tile_index * gfx->char_modulo;
+ pal_ptr = pal_base + tile_color * gfx->color_granularity;
+ dst_ptr = dst_base + j * tilew;
+
+ /* alpha case */
+ if (alpha > 0)
+ {
+ for (ty = 0; ty < tileh; ty++)
+ {
+ for (tx = 0; tx < tilew; tx++)
+ {
+ UINT8 srcpix = *src_ptr++;
+ pen_t srcrgb = pal_ptr[srcpix];
+ UINT16 dstrgb = dst_ptr[tx];
+ int sr, sg, sb, dr, dg, db;
+
+ sr = (srcrgb >> 0) & 0x1f;
+ sg = (srcrgb >> 5) & 0x1f;
+ sb = (srcrgb >> 10) & 0x1f;
+
+ dr = (dstrgb >> 0) & 0x1f;
+ dg = (dstrgb >> 5) & 0x1f;
+ db = (dstrgb >> 10) & 0x1f;
+
+ dr = (t32x32pm[dr - sr + alpha] >> 5) + dr;
+ dg = (t32x32pm[dg - sg + alpha] >> 5) + dg;
+ db = (t32x32pm[db - sb + alpha] >> 5) + db;
+
+ dst_ptr[tx] = dr | (dg << 5) | (db << 10);
+ }
+ dst_ptr += dst_pitch;
+ }
+ }
+
+ /* non-alpha case */
+ else
+ {
+ for (ty = 0; ty < tileh; ty++)
+ {
+ for (tx = 0; tx < tilew; tx++)
+ dst_ptr[tx] = pal_ptr[*src_ptr++];
+ dst_ptr += dst_pitch;
+ }
+ }
+ }
+
+ dst_base += dst_pitch * tileh;
+ }
+}
+
+/***************************************************************************
+ Hot Chase
+***************************************************************************/
+
+/*------------------------------------------------------------------------
+ Road Drawing
+
+ This layer is composed of horizontal lines gfx elements
+ There are 512 lines in ROM, each is 512 pixels wide
+
+ Offset: Elements: Data:
+ 0000-03ff 00-FF Code (4 bytes)
+
+ Code:
+ 00.w
+ fedc ba98 ---- ---- Unused?
+ ---- ---- 7654 ---- color
+ ---- ---- ---- 3210 scroll x
+ 02.w
+ fedc ba-- ---- ---- scroll x
+ ---- --9- ---- ---- ?
+ ---- ---8 7654 3210 code
+
+ We draw each line using a bunch of 64x1 tiles
+
+------------------------------------------------------------------------*/
+
+static void hotchase_draw_road(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+/* Referred to what's in the ROMs */
+#define XSIZE 512
+#define YSIZE 512
+
+ int sx, sy;
+
+ /* Let's draw from the top to the bottom of the visible screen */
+ for (sy = machine->screen[0].visarea.min_y;sy <= machine->screen[0].visarea.max_y;sy++)
+ {
+ int code = wecleman_roadram[sy*4/2+2/2] + (wecleman_roadram[sy*4/2+0/2] << 16);
+ int color = ((code & 0x00f00000) >> 20) + 0x70;
+ int scrollx = ((code & 0x0007fc00) >> 10) * 2;
+
+ /* convert line number in gfx element number: */
+ /* code is the tile code of the start of this line */
+ code &= 0x1ff;
+ code *= XSIZE / 32;
+
+ for (sx=0; sx<2*XSIZE; sx+=64)
+ {
+ drawgfx(bitmap,machine->gfx[0],
+ code++,
+ color,
+ 0,0,
+ ((sx-scrollx)&0x3ff)-(384-32),sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+
+#undef XSIZE
+#undef YSIZE
+}
+
+
+/***************************************************************************
+ Palette Routines
+***************************************************************************/
+
+// new video and palette code
+WRITE16_HANDLER( wecleman_videostatus_w )
+{
+ COMBINE_DATA(wecleman_videostatus);
+
+ // bit0-6: background transition, 0=off, 1=on
+ // bit7: palette being changed, 0=no, 1=yes
+ if (ACCESSING_LSB)
+ {
+ if ((data & 0x7f) == 0 && !cloud_ds)
+ cloud_ds = BLEND_INC;
+ else
+ if ((data & 0x7f) == 1 && !cloud_visible)
+ {
+ data ^= 1;
+ cloud_ds = BLEND_DEC;
+ cloud_visible = 1;
+ }
+ }
+}
+
+WRITE16_HANDLER( hotchase_paletteram16_SBGRBBBBGGGGRRRR_word_w )
+{
+ int newword, r, g, b;
+
+ newword = COMBINE_DATA(&paletteram16[offset]);
+
+ r = ((newword << 1) & 0x1E ) | ((newword >> 12) & 0x01);
+ g = ((newword >> 3) & 0x1E ) | ((newword >> 13) & 0x01);
+ b = ((newword >> 7) & 0x1E ) | ((newword >> 14) & 0x01);
+
+ palette_set_color_rgb(Machine, offset, pal5bit(r), pal5bit(g), pal5bit(b));
+ r>>=1; g>>=1; b>>=1;
+ palette_set_color_rgb(Machine, offset+0x800, pal5bit(r)/2, pal5bit(g)/2, pal5bit(b)/2);
+}
+
+WRITE16_HANDLER( wecleman_paletteram16_SSSSBBBBGGGGRRRR_word_w )
+{
+ int newword = COMBINE_DATA(&paletteram16[offset]);
+
+ // the highest nibble has some unknown functions
+// if (newword & 0xf000) logerror("MSN set on color %03x: %1x\n", offset, newword>>12);
+ palette_set_color_rgb(Machine, offset, pal4bit(newword >> 0), pal4bit(newword >> 4), pal4bit(newword >> 8));
+}
+
+
+/***************************************************************************
+ Initializations
+***************************************************************************/
+
+VIDEO_START( wecleman )
+{
+ /*
+ Sprite banking - each bank is 0x20000 bytes (we support 0x40 bank codes)
+ This game has ROMs for 16 banks
+ */
+ static int bank[0x40] =
+ {
+ 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,
+ 8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,
+ 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,
+ 8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15
+ };
+
+ UINT8 *buffer;
+ int i, j;
+
+ assert(machine->screen[0].format == BITMAP_FORMAT_RGB15);
+ buffer = auto_malloc(0x12c00); // working buffer for sprite operations
+
+ gameid = 0;
+ wecleman_gfx_bank = bank;
+ spr_offsx = -0xbc + BMP_PAD;
+ spr_offsy = 1 + BMP_PAD;
+ cloud_blend = BLEND_MAX;
+ cloud_ds = 0;
+ cloud_visible = 0;
+
+ rgb_half = (UINT16*)(buffer + 0x00000);
+ t32x32pm = (int*)(buffer + 0x10020);
+ spr_ptr_list = (struct sprite **)(buffer + 0x12000);
+ spr_idx_list = (int *)(buffer + 0x12400);
+ spr_pri_list = (int *)(buffer + 0x12800);
+
+ for (i=0; i<0x8000; i++)
+ {
+ j = i>>1;
+ rgb_half[i] = (j&0xf) | (j&0x1e0) | (j&0x3c00);
+ }
+
+ for (j=0; j<0x20; j++)
+ {
+ for (i=-0x1f; i<0x20; i++)
+ {
+ *(t32x32pm + (j<<6) + i) = i * j;
+ }
+ }
+
+ sprite_list = sprite_list_create(NUM_SPRITES);
+
+ bg_tilemap = tilemap_create(wecleman_get_bg_tile_info,
+ tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, /* We draw part of the road below */
+ 8,8,
+ PAGE_NX * 2, PAGE_NY * 2 );
+
+ fg_tilemap = tilemap_create(wecleman_get_fg_tile_info,
+ tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 8,8,
+ PAGE_NX * 2, PAGE_NY * 2);
+
+ txt_tilemap = tilemap_create(wecleman_get_txt_tile_info,
+ tilemap_scan_rows,
+ TILEMAP_TYPE_PEN,
+ 8,8,
+ PAGE_NX * 1, PAGE_NY * 1);
+
+ tilemap_set_scroll_rows(bg_tilemap, TILEMAP_DIMY); /* Screen-wise scrolling */
+ tilemap_set_scroll_cols(bg_tilemap, 1);
+ tilemap_set_transparent_pen(bg_tilemap,0);
+
+ tilemap_set_scroll_rows(fg_tilemap, TILEMAP_DIMY); /* Screen-wise scrolling */
+ tilemap_set_scroll_cols(fg_tilemap, 1);
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ tilemap_set_scroll_rows(txt_tilemap, 1);
+ tilemap_set_scroll_cols(txt_tilemap, 1);
+ tilemap_set_transparent_pen(txt_tilemap,0);
+
+ tilemap_set_scrollx(txt_tilemap, 0, 512-320-16 -BMP_PAD);
+ tilemap_set_scrolly(txt_tilemap, 0, -BMP_PAD );
+
+ // patches out a mysterious pixel floating in the sky (tile decoding bug?)
+ *(machine->gfx[0]->gfxdata + (machine->gfx[0]->char_modulo*0xaca+7)) = 0;
+}
+
+// Callbacks for the K051316
+#define ZOOMROM0_MEM_REGION REGION_GFX2
+#define ZOOMROM1_MEM_REGION REGION_GFX3
+
+static void zoom_callback_0(int *code,int *color,int *flags)
+{
+ *code |= (*color & 0x03) << 8;
+ *color = (*color & 0xfc) >> 2;
+}
+
+static void zoom_callback_1(int *code,int *color,int *flags)
+{
+ *code |= (*color & 0x01) << 8;
+ *color = ((*color & 0x3f) << 1) | ((*code & 0x80) >> 7);
+}
+
+VIDEO_START( hotchase )
+{
+ /*
+ Sprite banking - each bank is 0x20000 bytes (we support 0x40 bank codes)
+ This game has ROMs for 0x30 banks
+ */
+ static int bank[0x40] =
+ {
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
+ 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+ };
+
+ UINT8 *buffer;
+
+ buffer = auto_malloc(0x400); // reserve 1k for sprite list
+
+ gameid = 1;
+ wecleman_gfx_bank = bank;
+ spr_offsx = -0xc0;
+ spr_offsy = 0;
+
+ spr_ptr_list = (struct sprite **)buffer;
+
+ sprite_list = sprite_list_create(NUM_SPRITES);
+
+ K051316_vh_start_0(machine,ZOOMROM0_MEM_REGION,4,FALSE,0,zoom_callback_0);
+ K051316_vh_start_1(machine,ZOOMROM1_MEM_REGION,4,FALSE,0,zoom_callback_1);
+
+ K051316_wraparound_enable(0,1);
+// K051316_wraparound_enable(1,1);
+ K051316_set_offset(0, -0xB0/2, -16);
+ K051316_set_offset(1, -0xB0/2, -16);
+}
+
+
+/***************************************************************************
+ Video Updates
+***************************************************************************/
+
+VIDEO_UPDATE ( wecleman )
+{
+ const pen_t *mrct;
+ int video_on;
+ int fg_x, bg_x, fg_y, bg_y;
+ int cloud_sx, cloud_sy;
+ int i, j, k;
+
+ mrct = machine->remapped_colortable;
+
+ video_on = wecleman_irqctrl & 0x40;
+
+ set_led_status(0, wecleman_selected_ip & 0x04); // Start lamp
+
+ fg_y = (wecleman_txtram[0x0f24>>1] & (TILEMAP_DIMY - 1));
+ bg_y = (wecleman_txtram[0x0f26>>1] & (TILEMAP_DIMY - 1));
+
+ cloud_sx = wecleman_txtram[0xfee>>1] + 0xb0;
+ cloud_sy = bg_y;
+
+ tilemap_set_scrolly(bg_tilemap, 0, bg_y -BMP_PAD);
+ tilemap_set_scrolly(fg_tilemap, 0, fg_y -BMP_PAD);
+
+ for (i=0; i<(28<<2); i+=4)
+ {
+ fg_x = wecleman_txtram[(i+0xf80)>>1] + (0xb0 -BMP_PAD);
+ bg_x = wecleman_txtram[(i+0xf82)>>1] + (0xb0 -BMP_PAD);
+
+ k = i<<1;
+ for (j=0; j<8; j++)
+ {
+ tilemap_set_scrollx(fg_tilemap, (fg_y + k + j) & (TILEMAP_DIMY - 1), fg_x);
+ tilemap_set_scrollx(bg_tilemap, (bg_y + k + j) & (TILEMAP_DIMY - 1), bg_x);
+ }
+ }
+
+ // temporary fix for ranking screen tile masking
+ /* palette hacks! */
+ ((pen_t *)mrct)[0x27] = mrct[0x24];
+
+ get_sprite_info(machine);
+
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ /* Draw the road (lines which have priority 0x02) */
+ if (video_on) wecleman_draw_road(machine, bitmap, cliprect, 0x02);
+
+ /* Draw the background */
+ if (video_on) tilemap_draw(bitmap,cliprect, bg_tilemap, 0, 0);
+
+ // draws the cloud layer; needs work
+ if (cloud_visible)
+ {
+ /* palette hacks! */
+ ((pen_t *)mrct)[0] = ((pen_t *)mrct)[0x40] = ((pen_t *)mrct)[0x200] = ((pen_t *)mrct)[0x205];
+
+ if (video_on)
+ draw_cloud(machine,
+ bitmap,
+ machine->gfx[0],
+ wecleman_pageram+0x1800,
+ BMP_PAD, BMP_PAD,
+ 41, 20,
+ cloud_sx, cloud_sy,
+ 6, 5,
+ cloud_blend/BLEND_STEPS, 0);
+
+ cloud_blend += cloud_ds;
+
+ if (cloud_blend < BLEND_MIN)
+ { cloud_blend = BLEND_MIN; cloud_ds = 0; *wecleman_videostatus |= 1; }
+ else if (cloud_blend > BLEND_MAX)
+ { cloud_blend = BLEND_MAX; cloud_ds = 0; cloud_visible = 0; }
+ }
+
+ /* Draw the foreground */
+ if (video_on) tilemap_draw(bitmap,cliprect, fg_tilemap, 0, 0);
+
+ /* Draw the road (lines which have priority 0x04) */
+ if (video_on) wecleman_draw_road(machine, bitmap,cliprect, 0x04);
+
+ /* Draw the sprites */
+ if (video_on) sprite_draw(bitmap,cliprect);
+
+ /* Draw the text layer */
+ if (video_on) tilemap_draw(bitmap,cliprect, txt_tilemap, 0, 0);
+ return 0;
+}
+
+/***************************************************************************
+ Hot Chase
+***************************************************************************/
+
+VIDEO_UPDATE( hotchase )
+{
+ int video_on;
+
+ video_on = wecleman_irqctrl & 0x40;
+
+ set_led_status(0, wecleman_selected_ip & 0x04); // Start lamp
+
+ get_sprite_info(machine);
+
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+
+ /* Draw the background */
+ if (video_on) K051316_zoom_draw_0(bitmap,cliprect, 0, 0);
+
+ /* Draw the road */
+ if (video_on) hotchase_draw_road(machine, bitmap, cliprect);
+
+ /* Draw the sprites */
+ if (video_on) sprite_draw(bitmap,cliprect);
+
+ /* Draw the foreground (text) */
+ if (video_on) K051316_zoom_draw_1(bitmap,cliprect, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/welltris.c b/src/mame/video/welltris.c
new file mode 100644
index 00000000000..61baa070c2f
--- /dev/null
+++ b/src/mame/video/welltris.c
@@ -0,0 +1,250 @@
+#include "driver.h"
+
+
+
+extern UINT16 *welltris_spriteram;
+extern size_t welltris_spriteram_size;
+extern UINT16 *welltris_pixelram;
+extern UINT16 *welltris_charvideoram;
+
+static tilemap *char_tilemap;
+static UINT8 gfxbank[8];
+static UINT16 charpalettebank;
+static UINT16 spritepalettebank;
+static UINT16 pixelpalettebank;
+static int welltris_scrollx, welltris_scrolly;
+
+
+
+#ifdef UNUSED_FUNCTION
+READ16_HANDLER( welltris_spriteram_r )
+{
+ return welltris_spriteram[offset];
+}
+#endif
+
+WRITE16_HANDLER( welltris_spriteram_w )
+{
+ int offs;
+
+ COMBINE_DATA(&welltris_spriteram[offset]);
+
+ /* hack... sprite doesn't work otherwise (quiz18kn) */
+ if ((offset == 0x1fe) &&
+ (welltris_spriteram[0x01fc] == 0x0000) &&
+ (welltris_spriteram[0x01fd] == 0x0000) &&
+ (welltris_spriteram[0x01ff] == 0x0000)) {
+ for (offs = 0; offs < 0x1fc; offs++) welltris_spriteram[offs] = 0x0000;
+ }
+}
+
+
+/* Sprite Drawing is pretty much the same as fromance.c */
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ static const UINT8 zoomtable[16] = { 0,7,14,20,25,30,34,38,42,46,49,52,54,57,59,61 };
+ int offs;
+
+ /* draw the sprites */
+ for (offs = 0; offs < 0x200 - 4; offs += 4) {
+ int data0 = welltris_spriteram[offs + 0];
+ int data1 = welltris_spriteram[offs + 1];
+ int data2 = welltris_spriteram[offs + 2];
+ int data3 = welltris_spriteram[offs + 3];
+ int code = data3 & 0x1fff;
+ int color = (data2 & 0x0f) + (0x10 * spritepalettebank);
+ int y = (data0 & 0x1ff) + 1;
+ int x = (data1 & 0x1ff) + 6;
+ int yzoom = (data0 >> 12) & 15;
+ int xzoom = (data1 >> 12) & 15;
+ int zoomed = (xzoom | yzoom);
+ int ytiles = ((data2 >> 12) & 7) + 1;
+ int xtiles = ((data2 >> 8) & 7) + 1;
+ int yflip = (data2 >> 15) & 1;
+ int xflip = (data2 >> 11) & 1;
+ int xt, yt;
+
+ if (!(welltris_spriteram[offs + 2] & 0x0080)) continue;
+
+ /* compute the zoom factor -- stolen from aerofgt.c */
+ xzoom = 16 - zoomtable[xzoom] / 8;
+ yzoom = 16 - zoomtable[yzoom] / 8;
+
+ /* wrap around */
+ if (x > machine->screen[0].visarea.max_x) x -= 0x200;
+ if (y > machine->screen[0].visarea.max_y) y -= 0x200;
+
+ /* normal case */
+ if (!xflip && !yflip) {
+ for (yt = 0; yt < ytiles; yt++) {
+ for (xt = 0; xt < xtiles; xt++, code++) {
+ if (!zoomed)
+ drawgfx(bitmap, machine->gfx[1], code, color, 0, 0,
+ x + xt * 16, y + yt * 16, cliprect, TRANSPARENCY_PEN, 15);
+ else
+ drawgfxzoom(bitmap, machine->gfx[1], code, color, 0, 0,
+ x + xt * xzoom, y + yt * yzoom, cliprect, TRANSPARENCY_PEN, 15,
+ 0x1000 * xzoom, 0x1000 * yzoom);
+ }
+ if (xtiles == 3) code += 1;
+ if (xtiles == 5) code += 3;
+ if (xtiles == 6) code += 2;
+ if (xtiles == 7) code += 1;
+ }
+ }
+
+ /* xflipped case */
+ else if (xflip && !yflip) {
+ for (yt = 0; yt < ytiles; yt++) {
+ for (xt = 0; xt < xtiles; xt++, code++) {
+ if (!zoomed)
+ drawgfx(bitmap, machine->gfx[1], code, color, 1, 0,
+ x + (xtiles - 1 - xt) * 16, y + yt * 16, cliprect, TRANSPARENCY_PEN, 15);
+ else
+ drawgfxzoom(bitmap, machine->gfx[1], code, color, 1, 0,
+ x + (xtiles - 1 - xt) * xzoom, y + yt * yzoom, cliprect, TRANSPARENCY_PEN, 15,
+ 0x1000 * xzoom, 0x1000 * yzoom);
+ }
+ if (xtiles == 3) code += 1;
+ if (xtiles == 5) code += 3;
+ if (xtiles == 6) code += 2;
+ if (xtiles == 7) code += 1;
+ }
+ }
+
+ /* yflipped case */
+ else if (!xflip && yflip) {
+ for (yt = 0; yt < ytiles; yt++) {
+ for (xt = 0; xt < xtiles; xt++, code++) {
+ if (!zoomed)
+ drawgfx(bitmap, machine->gfx[1], code, color, 0, 1,
+ x + xt * 16, y + (ytiles - 1 - yt) * 16, cliprect, TRANSPARENCY_PEN, 15);
+ else
+ drawgfxzoom(bitmap, machine->gfx[1], code, color, 0, 1,
+ x + xt * xzoom, y + (ytiles - 1 - yt) * yzoom, cliprect, TRANSPARENCY_PEN, 15,
+ 0x1000 * xzoom, 0x1000 * yzoom);
+ }
+ if (xtiles == 3) code += 1;
+ if (xtiles == 5) code += 3;
+ if (xtiles == 6) code += 2;
+ if (xtiles == 7) code += 1;
+ }
+ }
+
+ /* x & yflipped case */
+ else {
+ for (yt = 0; yt < ytiles; yt++) {
+ for (xt = 0; xt < xtiles; xt++, code++) {
+ if (!zoomed)
+ drawgfx(bitmap, machine->gfx[1], code, color, 1, 1,
+ x + (xtiles - 1 - xt) * 16, y + (ytiles - 1 - yt) * 16, cliprect, TRANSPARENCY_PEN, 15);
+ else
+ drawgfxzoom(bitmap, machine->gfx[1], code, color, 1, 1,
+ x + (xtiles - 1 - xt) * xzoom, y + (ytiles - 1 - yt) * yzoom, cliprect, TRANSPARENCY_PEN, 15,
+ 0x1000 * xzoom, 0x1000 * yzoom);
+ }
+ if (xtiles == 3) code += 1;
+ if (xtiles == 5) code += 3;
+ if (xtiles == 6) code += 2;
+ if (xtiles == 7) code += 1;
+ }
+ }
+ }
+}
+
+static void setbank(tilemap *tmap, int num, int bank)
+{
+ if (gfxbank[num] != bank)
+ {
+ gfxbank[num] = bank;
+ tilemap_mark_all_tiles_dirty(tmap);
+ }
+}
+
+
+/* Not really enough evidence here */
+
+WRITE16_HANDLER( welltris_palette_bank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ if (charpalettebank != (data & 0x03))
+ {
+ charpalettebank = (data & 0x03);
+ tilemap_mark_all_tiles_dirty(char_tilemap);
+ }
+
+ flip_screen_set(data & 0x80);
+
+ spritepalettebank = (data & 0x20) >> 5;
+ pixelpalettebank = (data & 0x08) >> 3;
+ }
+}
+
+WRITE16_HANDLER( welltris_gfxbank_w )
+{
+ if (ACCESSING_LSB)
+ {
+ setbank(char_tilemap, 0, (data & 0xf0) >> 4);
+ setbank(char_tilemap, 1, data & 0x0f);
+ }
+}
+
+WRITE16_HANDLER( welltris_scrollreg_w )
+{
+ switch (offset) {
+ case 0: welltris_scrollx = data - 14; break;
+ case 1: welltris_scrolly = data + 0; break;
+ }
+}
+
+static TILE_GET_INFO( get_welltris_tile_info )
+{
+ UINT16 code = welltris_charvideoram[tile_index];
+ int bank = (code & 0x1000) >> 12;
+
+ SET_TILE_INFO(
+ 0,
+ (code & 0x0fff) + (gfxbank[bank] << 12),
+ ((code & 0xe000) >> 13) + (8 * charpalettebank),
+ 0);
+}
+
+WRITE16_HANDLER( welltris_charvideoram_w )
+{
+ COMBINE_DATA(&welltris_charvideoram[offset]);
+ tilemap_mark_tile_dirty(char_tilemap, offset);
+}
+
+VIDEO_START( welltris )
+{
+ char_tilemap = tilemap_create(get_welltris_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ tilemap_set_transparent_pen(char_tilemap, 15);
+}
+
+static void draw_background(mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int x, y;
+ int pixdata;
+
+ for (y = 0; y < 256; y++) {
+ for (x = 0; x < 512 / 2; x++) {
+ pixdata = welltris_pixelram[(x & 0xff) + (y & 0xff) * 256];
+
+ *BITMAP_ADDR16(bitmap, y, (x * 2) + 0) = (pixdata >> 8) + (0x100 * pixelpalettebank) + 0x400;
+ *BITMAP_ADDR16(bitmap, y, (x * 2) + 1) = (pixdata & 0xff) + (0x100 * pixelpalettebank) + 0x400;
+ }
+ }
+}
+
+VIDEO_UPDATE( welltris )
+{
+ tilemap_set_scrollx(char_tilemap, 0, welltris_scrollx);
+ tilemap_set_scrolly(char_tilemap, 0, welltris_scrolly);
+
+ draw_background(bitmap, cliprect);
+ tilemap_draw(bitmap, cliprect, char_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/wgp.c b/src/mame/video/wgp.c
new file mode 100644
index 00000000000..b33a3506464
--- /dev/null
+++ b/src/mame/video/wgp.c
@@ -0,0 +1,774 @@
+#include "driver.h"
+#include "video/taitoic.h"
+
+#define TC0100SCN_GFX_NUM 1
+
+static tilemap *wgp_piv_tilemap[3];
+
+UINT16 *wgp_spritemap;
+size_t wgp_spritemap_size;
+UINT16 *wgp_pivram;
+UINT16 *wgp_piv_ctrlram;
+
+static UINT16 wgp_piv_ctrl_reg;
+static UINT16 wgp_piv_zoom[3],wgp_piv_scrollx[3],wgp_piv_scrolly[3];
+UINT16 wgp_rotate_ctrl[8];
+static int wgp_piv_xoffs,wgp_piv_yoffs;
+
+
+
+/*******************************************************************/
+
+INLINE void common_get_piv_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int num)
+{
+ UINT16 tilenum = wgp_pivram[tile_index + num*0x1000]; /* 3 blocks of $2000 */
+ UINT16 attr = wgp_pivram[tile_index + num*0x1000 + 0x8000]; /* 3 blocks of $2000 */
+
+ SET_TILE_INFO(
+ 2,
+ tilenum & 0x3fff,
+ (attr & 0x3f), /* attr &0x1 ?? */
+ TILE_FLIPYX( (attr & 0xc0) >> 6));
+}
+
+static TILE_GET_INFO( get_piv0_tile_info )
+{
+ common_get_piv_tile_info(machine,tileinfo,tile_index,0);
+}
+
+static TILE_GET_INFO( get_piv1_tile_info )
+{
+ common_get_piv_tile_info(machine,tileinfo,tile_index,1);
+}
+
+static TILE_GET_INFO( get_piv2_tile_info )
+{
+ common_get_piv_tile_info(machine,tileinfo,tile_index,2);
+}
+
+static void dirty_piv_tilemaps(void)
+{
+ tilemap_mark_all_tiles_dirty(wgp_piv_tilemap[0]);
+ tilemap_mark_all_tiles_dirty(wgp_piv_tilemap[1]);
+ tilemap_mark_all_tiles_dirty(wgp_piv_tilemap[2]);
+}
+
+
+static void wgp_core_vh_start(running_machine *machine, int x_offs,int y_offs,int piv_xoffs,int piv_yoffs)
+{
+ wgp_piv_tilemap[0] = tilemap_create(get_piv0_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ wgp_piv_tilemap[1] = tilemap_create(get_piv1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+ wgp_piv_tilemap[2] = tilemap_create(get_piv2_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,64);
+
+ TC0100SCN_vh_start(machine,1,TC0100SCN_GFX_NUM,x_offs,y_offs,0,0,0,0,0);
+
+ if (has_TC0110PCR())
+ TC0110PCR_vh_start();
+
+ wgp_piv_xoffs = piv_xoffs;
+ wgp_piv_yoffs = piv_yoffs;
+
+ tilemap_set_transparent_pen( wgp_piv_tilemap[0],0 );
+ tilemap_set_transparent_pen( wgp_piv_tilemap[1],0 );
+ tilemap_set_transparent_pen( wgp_piv_tilemap[2],0 );
+
+ /* flipscreen n/a */
+ tilemap_set_scrolldx( wgp_piv_tilemap[0],-piv_xoffs,0 );
+ tilemap_set_scrolldx( wgp_piv_tilemap[1],-piv_xoffs,0 );
+ tilemap_set_scrolldx( wgp_piv_tilemap[2],-piv_xoffs,0 );
+ tilemap_set_scrolldy( wgp_piv_tilemap[0],-piv_yoffs,0 );
+ tilemap_set_scrolldy( wgp_piv_tilemap[1],-piv_yoffs,0 );
+ tilemap_set_scrolldy( wgp_piv_tilemap[2],-piv_yoffs,0 );
+
+ /* We don't need tilemap_set_scroll_rows, as the custom draw routine
+ applies rowscroll manually */
+
+ TC0100SCN_set_colbanks(0x80,0xc0,0x40);
+
+ /* colors from saved states are often screwy (and this doesn't help...) */
+ state_save_register_func_postload(dirty_piv_tilemaps);
+}
+
+VIDEO_START( wgp )
+{
+ wgp_core_vh_start(machine, 0,0,32,16);
+}
+
+VIDEO_START( wgp2 )
+{
+ wgp_core_vh_start(machine, 4,2,32,16);
+}
+
+
+/******************************************************************
+ PIV TILEMAP READ AND WRITE HANDLERS
+
+Piv Tilemaps
+------------
+
+(The unused gaps look as though Taito considered making their
+custom chip capable of four rather than three tilemaps.)
+
+500000 - 501fff : unknown/unused
+502000 - 507fff : piv tilemaps 0-2 [tile numbers only]
+
+508000 - 50ffff : this area relates to pixel rows in each piv tilemap.
+ Includes rowscroll for the piv tilemaps, 1-2 of which act as a
+ simple road. To curve, it has rowscroll applied to each row.
+
+508000 - 5087ff unknown/unused
+
+508800 piv0 row color bank (low byte = row horizontal zoom)
+509000 piv1 row color bank (low byte = row horizontal zoom)
+509800 piv2 row color bank (low byte = row horizontal zoom)
+
+ Usual low byte is 0x7f, the default row horizontal zoom.
+
+ The high byte is the color offset per pixel row. Controlling
+ color bank per scanline is rare in Taito games. Top Speed may
+ have a similar system to make its road 'move'.
+
+ In-game the high bytes are set to various values (seen 0 - 0x2b).
+
+50a000 piv0 rowscroll [sky] (not used, but the code supports this)
+50c000 piv1 rowscroll [road] (values 0xfd00 - 0x400)
+50e000 piv2 rowscroll [road or scenery] (values 0xfd00 - 0x403)
+
+ [It seems strange that unnecessarily large space allocations were
+ made for rowscroll. Perhaps the raster color/zoom effects were an
+ afterthought, and 508000-9fff was originally slated as rowscroll
+ for 'missing' 4th piv layer. Certainly the layout is illogical.]
+
+510000 - 511fff : unknown/unused
+512000 - 517fff : piv tilemaps 0-2 [just tile colors ??]
+
+*******************************************************************/
+
+READ16_HANDLER( wgp_pivram_word_r )
+{
+ return wgp_pivram[offset];
+}
+
+WRITE16_HANDLER( wgp_pivram_word_w )
+{
+ COMBINE_DATA(&wgp_pivram[offset]);
+
+ if (offset<0x3000)
+ {
+ tilemap_mark_tile_dirty(wgp_piv_tilemap[(offset / 0x1000)], (offset % 0x1000) );
+ }
+ else if ((offset >=0x3400) && (offset<0x4000))
+ {
+ /* do nothing, custom draw routine takes care of raster effects */
+ }
+ else if ((offset >=0x8000) && (offset<0xb000))
+ {
+ tilemap_mark_tile_dirty(wgp_piv_tilemap[((offset - 0x8000)/ 0x1000)], (offset % 0x1000) );
+ }
+}
+
+READ16_HANDLER( wgp_piv_ctrl_word_r )
+{
+ return wgp_piv_ctrlram[offset];
+}
+
+WRITE16_HANDLER( wgp_piv_ctrl_word_w )
+{
+ UINT16 a,b;
+
+ COMBINE_DATA(&wgp_piv_ctrlram[offset]);
+ data = wgp_piv_ctrlram[offset];
+
+ switch (offset)
+ {
+ case 0x00:
+ a = -data;
+ b = (a &0xffe0) >> 1; /* kill bit 4 */
+ wgp_piv_scrollx[0] = (a &0xf) | b;
+ break;
+
+ case 0x01:
+ a = -data;
+ b = (a &0xffe0) >> 1;
+ wgp_piv_scrollx[1] = (a &0xf) | b;
+ break;
+
+ case 0x02:
+ a = -data;
+ b = (a &0xffe0) >> 1;
+ wgp_piv_scrollx[2] = (a &0xf) | b;
+ break;
+
+ case 0x03:
+ wgp_piv_scrolly[0] = data;
+ break;
+
+ case 0x04:
+ wgp_piv_scrolly[1] = data;
+ break;
+
+ case 0x05:
+ wgp_piv_scrolly[2] = data;
+ break;
+
+ case 0x06:
+ /* Overall control reg (?)
+ 0x39 %00111001 normal
+ 0x2d %00101101 piv2 layer goes under piv1
+ seen on Wgp stages 4,5,7 in which piv 2 used
+ for cloud or scenery wandering up screen */
+
+ wgp_piv_ctrl_reg = data;
+ break;
+
+ case 0x08:
+ /* piv 0 y zoom (0x7f = normal, not seen others) */
+ wgp_piv_zoom[0] = data;
+ break;
+
+ case 0x09:
+ /* piv 1 y zoom (0x7f = normal, values 0 &
+ 0xff7f-ffbc in Wgp2) */
+ wgp_piv_zoom[1] = data;
+ break;
+
+ case 0x0a:
+ /* piv 2 y zoom (0x7f = normal, values 0 &
+ 0xff7f-ffbc in Wgp2, 0-0x98 in Wgp round 4/5) */
+ wgp_piv_zoom[2] = data;
+ break;
+ }
+}
+
+
+
+
+/****************************************************************
+ SPRITE DRAW ROUTINES
+
+TODO
+====
+
+Implement rotation/zoom properly.
+
+Sprite/piv priority: sprites always over?
+
+Wgp round 1 had some junky brown mud bank sprites in-game.
+They are indexed 0xe720-e790. 0x2720*4 => +0x9c80-9e80 in
+the spritemap area. They should be 2x2 not 4x4 tiles. We
+kludge this. Round 2 +0x9d40-9f40 contains the 2x2 sprites.
+What REALLY controls number of tiles in a sprite?
+
+Sprite colors: dust after crash in Wgp2 is odd; some
+black/grey barrels on late Wgp circuit also look strange -
+possibly the same wrong color.
+
+
+Memory Map
+----------
+
+400000 - 40bfff : Sprite tile mapping area
+
+ Tile numbers (0-0x3fff) alternate with word containing tile
+ color/unknown bits. I'm _not_ 100% sure that only Wgp2 uses
+ the unknown bits.
+
+ xxxxxxxx x....... unused ??
+ ........ .x...... unknown (Wgp2 only: Taito tyre bridge on default course)
+ ........ ..x..... unknown (Wgp2 only)
+ ........ ...x.... unknown (Wgp2 only: Direction signs just before hill # 1)
+ ........ ....cccc color (0-15)
+
+ Tile map for each standard big sprite is 64 bytes (16 tiles).
+ (standard big sprite comprises 4x4 16x16 tiles)
+
+ Tile map for each small sprite only uses 16 of the 64 bytes.
+ The remaining 48 bytes are garbage and should be ignored.
+ (small sprite comprises 2x2 16x16 tiles)
+
+40c000 - 40dbff : Sprite Table
+
+ Every 16 bytes contains one sprite entry. First entry is
+ ignored [as 0 in active sprites list means no sprite].
+
+ (0x1c0 [no.of entries] * 0x40 [bytes for big sprite] = 0x6fff
+ of sprite tile mapping area can be addressed at any one time.)
+
+ Sprite entry (preliminary)
+ ------------
+
+ +0x00 x pos (signed)
+ +0x02 y pos (signed)
+ +0x04 index to tile mapping area [2 msbs always set]
+
+ (400000 + (index &0x3fff) << 2) points to relevant part of
+ sprite tile mapping area. Index >0x2fff would be invalid.
+
+ +0x06 zoom size (pixels) [typical range 0x1-5f, 0x3f = standard]
+ Looked up from a logarithm table in the data rom indexed
+ by the z coordinate. Max size prog allows before it blanks
+ the sprite is 0x140.
+
+ +0x08 incxx ?? (usually stuck at 0xf800)
+ +0x0a incyy ?? (usually stuck at 0xf800)
+
+ +0x0c z coordinate i.e. how far away the sprite is from you
+ going into the screen. Max distance prog allows before it
+ blanks the sprite is 0x3fff. 0x1400 is about the farthest
+ away that the code creates sprites. 0x400 = standard
+ distance corresponding to 0x3f zoom. <0x400 = close to
+
+ +0x0e non-zero only during rotation.
+
+ NB: +0x0c and +0x0e are paired. Equivalent of incyx and incxy ??
+
+ (No longer used entries typically have 0xfff6 in +0x06 and +0x08.)
+
+ Only 2 rotation examples (i) at 0x40c000 when Taito
+ logo displayed (Wgp only). (ii) stage 5 (rain).
+ Other in-game sprites are simply using +0x06 and +0x0c,
+
+ So the sprite rotation in Wgp screenshots must be a *blanket*
+ rotate effect, identical to the one applied to piv layers.
+ This explains why sprite/piv positions are basically okay
+ despite failure to implement rotation.
+
+40dc00 - 40dfff: Active Sprites list
+
+ Each word is a sprite number, 0x0 thru 0x1bf. If !=0
+ a word makes active the 0x10 bytes of sprite data at
+ (40c000 + sprite_num * 0x10). (Wgp2 fills this in reverse).
+
+40fff0: Unknown (sprite control word?)
+
+ Wgp alternates 0x8000 and 0. Wgp2 only pokes 0.
+ Could this be some frame buffer control that would help to
+ reduce the sprite timing glitches in Wgp?
+
+****************************************************************/
+
+/* Sprite tilemapping area doesn't have a straightforward
+ structure for each big sprite: the hardware is probably
+ constructing each 4x4 sprite from 4 2x2 sprites... */
+
+static UINT8 xlookup[16] =
+ { 0, 1, 0, 1,
+ 2, 3, 2, 3,
+ 0, 1, 0, 1,
+ 2, 3, 2, 3 };
+
+static UINT8 ylookup[16] =
+ { 0, 0, 1, 1,
+ 0, 0, 1, 1,
+ 2, 2, 3, 3,
+ 2, 2, 3, 3 };
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int y_offs)
+{
+ int offs,i,j,k;
+ int x,y,curx,cury;
+ int zx,zy,zoomx,zoomy,priority=0;
+ UINT8 small_sprite,col,flipx,flipy;
+ UINT16 code,bigsprite,map_index;
+ UINT16 rotate=0;
+ UINT16 tile_mask = (machine->gfx[0]->total_elements) - 1;
+ static const int primasks[2] = {0x0, 0xfffc}; /* fff0 => under rhs of road only */
+
+ for (offs = 0x1ff;offs >= 0;offs--)
+ {
+ code = (spriteram16[0xe00+offs]);
+
+ if (code) /* do we have an active sprite ? */
+ {
+ i = (code << 3) &0xfff; /* yes, so we look up its sprite entry */
+
+ x = spriteram16[i];
+ y = spriteram16[i + 1];
+ bigsprite = spriteram16[i + 2] &0x3fff;
+
+ /* The last five words [i + 3 thru 7] must be zoom/rotation
+ control: for time being we kludge zoom using 1 word.
+ Timing problems are causing many glitches. */
+
+if ((spriteram16[i + 4]==0xfff6) && (spriteram16[i + 5]==0))
+ continue;
+
+if (((spriteram16[i + 4]!=0xf800) && (spriteram16[i + 4]!=0xfff6))
+ || ((spriteram16[i + 5]!=0xf800) && (spriteram16[i + 5]!=0))
+ || spriteram16[i + 7]!=0)
+
+ rotate = i << 1;
+
+ /***** Begin zoom kludge ******/
+
+ zoomx = (spriteram16[i + 3] &0x1ff) + 1;
+ zoomy = (spriteram16[i + 3] &0x1ff) + 1;
+
+ y -=4;
+ // distant sprites were some 16 pixels too far down //
+ y -=((0x40-zoomy)/4);
+
+ /****** end zoom kludge *******/
+
+ /* Treat coords as signed */
+ if (x & 0x8000) x -= 0x10000;
+ if (y & 0x8000) y -= 0x10000;
+
+ map_index = bigsprite << 1; /* now we access sprite tilemap */
+
+ /* don't know what selects 2x2 sprites: we use a nasty kludge
+ which seems to work */
+
+ i = wgp_spritemap[map_index + 0xa];
+ j = wgp_spritemap[map_index + 0xc];
+ small_sprite = ((i > 0) & (i <=8) & (j > 0) & (j <=8));
+
+ if (small_sprite)
+ {
+ for (i=0;i<4;i++)
+ {
+ code = wgp_spritemap[(map_index + (i << 1))] &tile_mask;
+ col = wgp_spritemap[(map_index + (i << 1) + 1)] &0xf;
+
+ /* not known what controls priority */
+ priority = (wgp_spritemap[(map_index + (i << 1) + 1)] &0x70) >> 4;
+
+ flipx=0; // no flip xy?
+ flipy=0;
+
+ k = xlookup[i]; // assumes no xflip
+ j = ylookup[i]; // assumes no yflip
+
+ curx = x + ((k*zoomx)/2);
+ cury = y + ((j*zoomy)/2);
+
+ zx = x + (((k+1)*zoomx)/2) - curx;
+ zy = y + (((j+1)*zoomy)/2) - cury;
+
+ pdrawgfxzoom(bitmap, machine->gfx[0],
+ code,
+ col,
+ flipx, flipy,
+ curx,cury,
+ cliprect,TRANSPARENCY_PEN,0,
+ zx << 12, zy << 12,
+ primasks[((priority >> 1) &1)]); /* maybe >> 2 or 0...? */
+ }
+ }
+ else
+ {
+ for (i=0;i<16;i++)
+ {
+ code = wgp_spritemap[(map_index + (i << 1))] &tile_mask;
+ col = wgp_spritemap[(map_index + (i << 1) + 1)] &0xf;
+
+ /* not known what controls priority */
+ priority = (wgp_spritemap[(map_index + (i << 1) + 1)] &0x70) >> 4;
+
+ flipx=0; // no flip xy?
+ flipy=0;
+
+ k = xlookup[i]; // assumes no xflip
+ j = ylookup[i]; // assumes no yflip
+
+ curx = x + ((k*zoomx)/4);
+ cury = y + ((j*zoomy)/4);
+
+ zx = x + (((k+1)*zoomx)/4) - curx;
+ zy = y + (((j+1)*zoomy)/4) - cury;
+
+ pdrawgfxzoom(bitmap, machine->gfx[0],
+ code,
+ col,
+ flipx, flipy,
+ curx,cury,
+ cliprect,TRANSPARENCY_PEN,0,
+ zx << 12, zy << 12,
+ primasks[((priority >> 1) &1)]); /* maybe >> 2 or 0...? */
+ }
+ }
+ }
+
+ }
+#if 0
+ if (rotate)
+ {
+ char buf[80];
+ sprintf(buf,"sprite rotate offs %04x ?",rotate);
+ popmessage(buf);
+ }
+#endif
+}
+
+
+/*********************************************************
+ CUSTOM DRAW
+*********************************************************/
+
+INLINE void bryan2_drawscanline(
+ mame_bitmap *bitmap,int x,int y,int length,
+ const UINT16 *src,int transparent,UINT32 orient,int pri)
+{
+ UINT16 *dsti = BITMAP_ADDR16(bitmap, y, x);
+ UINT8 *dstp = BITMAP_ADDR8(priority_bitmap, y, x);
+
+ if (transparent) {
+ while (length--) {
+ UINT32 spixel = *src++;
+ if (spixel<0x7fff) {
+ *dsti = spixel;
+ *dstp = pri;
+ }
+ dsti++;
+ dstp++;
+ }
+ } else { /* Not transparent case */
+ while (length--) {
+ *dsti++ = *src++;
+ *dstp++ = pri;
+ }
+ }
+}
+
+
+
+static void wgp_piv_layer_draw(mame_bitmap *bitmap,const rectangle *cliprect,int layer,int flags,UINT32 priority)
+{
+ mame_bitmap *srcbitmap = tilemap_get_pixmap(wgp_piv_tilemap[layer]);
+ mame_bitmap *flagsbitmap = tilemap_get_flagsmap(wgp_piv_tilemap[layer]);
+
+ UINT16 *dst16,*src16;
+ UINT8 *tsrc;
+ int i,y,y_index,src_y_index,row_index,row_zoom;
+
+ /* I have a fairly strong feeling these should be UINT32's, x_index is
+ falling through from max +ve to max -ve quite a lot in this routine */
+ int sx,x_index,x_step,x_max;
+
+ UINT32 zoomx,zoomy;
+ UINT16 scanline[512];
+ UINT16 row_colbank,row_scroll;
+ int flipscreen = 0; /* n/a */
+ int machine_flip = 0; /* for ROT 180 ? */
+
+ UINT16 screen_width = cliprect->max_x -
+ cliprect->min_x + 1;
+ UINT16 min_y = cliprect->min_y;
+ UINT16 max_y = cliprect->max_y;
+
+ int width_mask=0x3ff;
+
+ zoomx = 0x10000; /* No overall X zoom, unlike TC0480SCP */
+
+ /* Y-axis zoom offers expansion/compression: 0x7f = no zoom, 0xff = max ???
+ In WGP see: stage 4 (big spectator stand)
+ stage 5 (cloud layer)
+ stage 7 (two bits of background scenery)
+ stage 8 (unknown - surely something should be appearing here...)
+ In WGP2 see: road at big hill (default course) */
+
+ /* This calculation may be wrong, the y_index one too */
+ zoomy = 0x10000 - (((wgp_piv_ctrlram[0x08 + layer] &0xff) - 0x7f) * 512);
+
+ if (!flipscreen)
+ {
+ sx = ((wgp_piv_scrollx[layer]) << 16);
+ sx += (wgp_piv_xoffs) * zoomx; /* may be imperfect */
+
+ y_index = (wgp_piv_scrolly[layer] << 16);
+ y_index += (wgp_piv_yoffs + min_y) * zoomy; /* may be imperfect */
+ }
+ else /* piv tiles flipscreen n/a */
+ {
+ sx = 0;
+ y_index = 0;
+ }
+
+ if (!machine_flip) y=min_y; else y=max_y;
+
+ do
+ {
+ int a;
+
+ src_y_index = (y_index>>16) &0x3ff;
+ row_index = src_y_index;
+
+ row_zoom = wgp_pivram[row_index + layer*0x400 + 0x3400] &0xff;
+
+ row_colbank = wgp_pivram[row_index + layer*0x400 + 0x3400] >> 8;
+ a = (row_colbank &0xe0); /* kill bit 4 */
+ row_colbank = (((row_colbank &0xf) << 1) | a) << 4;
+
+ row_scroll = wgp_pivram[row_index + layer*0x1000 + 0x4000];
+ a = (row_scroll &0xffe0) >> 1; /* kill bit 4 */
+ row_scroll = ((row_scroll &0xf) | a) &width_mask;
+
+ x_index = sx - (row_scroll << 16);
+
+ x_step = zoomx;
+ if (row_zoom > 0x7f) /* zoom in: reduce x_step */
+ {
+ x_step -= (((row_zoom - 0x7f) << 8) &0xffff);
+ }
+ else if (row_zoom < 0x7f) /* zoom out: increase x_step */
+ {
+ x_step += (((0x7f - row_zoom) << 8) &0xffff);
+ }
+
+ x_max = x_index + screen_width * x_step;
+ src16 = BITMAP_ADDR16(srcbitmap, src_y_index, 0);
+ tsrc = BITMAP_ADDR8(flagsbitmap, src_y_index, 0);
+ dst16 = scanline;
+
+ if (flags & TILEMAP_DRAW_OPAQUE)
+ {
+ for (i=0; i<screen_width; i++)
+ {
+ *dst16++ = src16[(x_index >> 16) &width_mask] + row_colbank;
+ x_index += x_step;
+ }
+ }
+ else
+ {
+ for (i=0; i<screen_width; i++)
+ {
+ if (tsrc[(x_index >> 16) &width_mask])
+ *dst16++ = src16[(x_index >> 16) &width_mask] + row_colbank;
+ else
+ *dst16++ = 0x8000;
+ x_index += x_step;
+ }
+ }
+
+ if (flags & TILEMAP_DRAW_OPAQUE)
+ bryan2_drawscanline(bitmap,0,y,screen_width,scanline,0,ROT0,priority);
+ else
+ bryan2_drawscanline(bitmap,0,y,screen_width,scanline,1,ROT0,priority);
+
+ y_index += zoomy;
+ if (!machine_flip) y++; else y--;
+ }
+ while ( (!machine_flip && y<=max_y) || (machine_flip && y>=min_y) );
+
+}
+
+
+
+/**************************************************************
+ SCREEN REFRESH
+**************************************************************/
+
+VIDEO_UPDATE( wgp )
+{
+ int i;
+ UINT8 layer[3];
+
+#ifdef MAME_DEBUG
+ static UINT8 dislayer[4];
+#endif
+
+#ifdef MAME_DEBUG
+ if (input_code_pressed_once (KEYCODE_V))
+ {
+ dislayer[0] ^= 1;
+ popmessage("piv0: %01x",dislayer[0]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_B))
+ {
+ dislayer[1] ^= 1;
+ popmessage("piv1: %01x",dislayer[1]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_N))
+ {
+ dislayer[2] ^= 1;
+ popmessage("piv2: %01x",dislayer[2]);
+ }
+
+ if (input_code_pressed_once (KEYCODE_M))
+ {
+ dislayer[3] ^= 1;
+ popmessage("TC0100SCN top bg layer: %01x",dislayer[3]);
+ }
+#endif
+
+ for (i=0;i<3;i++)
+ {
+ tilemap_set_scrollx(wgp_piv_tilemap[i], 0, wgp_piv_scrollx[i]);
+ tilemap_set_scrolly(wgp_piv_tilemap[i], 0, wgp_piv_scrolly[i]);
+ }
+
+ TC0100SCN_tilemap_update(machine);
+
+ fillbitmap(bitmap, machine->pens[0], cliprect);
+
+ layer[0] = 0;
+ layer[1] = 1;
+ layer[2] = 2;
+
+ if (wgp_piv_ctrl_reg == 0x2d)
+ {
+ layer[1] = 2;
+ layer[2] = 1;
+ }
+
+/* We should draw the following on a 1024x1024 bitmap... */
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[0]]==0)
+#endif
+ wgp_piv_layer_draw(bitmap,cliprect,layer[0],TILEMAP_DRAW_OPAQUE,1);
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[1]]==0)
+#endif
+ wgp_piv_layer_draw(bitmap,cliprect,layer[1],0,2);
+
+#ifdef MAME_DEBUG
+ if (dislayer[layer[2]]==0)
+#endif
+ wgp_piv_layer_draw(bitmap,cliprect,layer[2],0,4);
+
+ draw_sprites(machine, bitmap,cliprect,16);
+
+/* ... then here we should apply rotation from wgp_sate_ctrl[] to
+ the bitmap before we draw the TC0100SCN layers on it */
+
+ layer[0] = TC0100SCN_bottomlayer(0);
+ layer[1] = layer[0]^1;
+ layer[2] = 2;
+
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[0],0,0);
+
+#ifdef MAME_DEBUG
+ if (dislayer[3]==0)
+#endif
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[1],0,0);
+ TC0100SCN_tilemap_draw(machine,bitmap,cliprect,0,layer[2],0,0);
+
+#if 0
+ {
+ char buf[80];
+ sprintf(buf,"wgp_piv_ctrl_reg: %04x y zoom: %04x %04x %04x",wgp_piv_ctrl_reg,
+ wgp_piv_zoom[0],wgp_piv_zoom[1],wgp_piv_zoom[2]);
+ popmessage(buf);
+ }
+#endif
+
+/* Enable this to watch the rotation control words */
+#if 0
+ {
+ char buf[80];
+ int i;
+
+ for (i = 0; i < 8; i += 1)
+ {
+ sprintf (buf, "%02x: %04x", i, wgp_rotate_ctrl[i]);
+ ui_draw_text (buf, 0, i*8);
+ }
+ }
+#endif
+ return 0;
+}
+
diff --git a/src/mame/video/williams.c b/src/mame/video/williams.c
new file mode 100644
index 00000000000..d9f71a77a55
--- /dev/null
+++ b/src/mame/video/williams.c
@@ -0,0 +1,777 @@
+/***************************************************************************
+
+ Williams 6809 system
+
+****************************************************************************
+
+ The basic video system involves a 4-bit-per-pixel bitmap, oriented
+ in inverted X/Y order. That is, pixels (0,0) and (1,0) come from the
+ byte at offset 0. Pixels (2,0) and (3,0) come from the byte at offset
+ 256. Pixels (4,0) and (5,0) come from the byte at offset 512. Etc.
+
+ Defender and Stargate simply draw graphics to the framebuffer directly
+ with no extra intervention.
+
+ Later games added a pair of "special chips" (SC-01) to the board which
+ are special purpose blitters. During their operation they HALT the
+ main CPU so that they can control the busses. The operation of the
+ chips is described in detail below.
+
+ The original SC-01 had a bug that forced an XOR of the width and height
+ values with 4. This was fixed in the SC-02, which was used on several
+ later games.
+
+ Beginning with Sinistar, additional video tweaks were added.
+
+ In Sinistar, a clipping window can be specified and enabled in order
+ to prevent the blitter chip from drawing beyond a certain address.
+ This clipping window can be switched on and off at will.
+
+ In Blaster, a number of features were added. First, a fixed window can
+ be enabled which cuts off blitter drawing at 0x9700. Second, on a
+ per-scanline basis, an "erase behind" feature can be turned on which
+ clears the video RAM to 0 after it is refreshed to the screen. Third,
+ on a per-scanline basis, an alternate color can be latched as the new
+ background color.
+
+ For Mystic Marathon and the 3 other "2nd generation" Williams games,
+ a tilemap background layer was added. This layer consisted of 24x16
+ tiles and only scrolled in the X direction. In addition, the palette
+ was expanded to 1024 entries, some of which were used for the tilemap.
+ The traditional foreground bitmap could be configured to use any bank
+ of 16 colors from the full palette.
+
+****************************************************************************
+
+ Blitter description from Sean Riddle's page:
+
+ This page contains information about the Williams Special Chips, which
+ were 'bit blitters'- block transfer chips that could move data around on
+ the screen and in memory faster than the CPU. In fact, I've timed the
+ special chips at 16 megs in 18.1 seconds. That's 910K/sec, not bad for
+ the early 80s.
+
+ The blitters were not used in Defender and Stargate, but
+ were added to the ROM boards of the later games. Splat!, Blaster, Mystic
+ Marathon and Joust 2 used Special Chip 2s. The only difference that I've
+ seen is that SC1s have a small bug. When you tell the SC1 the size of
+ the data to move, you have to exclusive-or the width and height with 2.
+ The SC2s eliminate this bug.
+
+ The blitters were accessed at memory location $CA00-CA06.
+
+ CA01 is the mask, usually $FF to move all bits.
+ CA02-3 is the source data location.
+ CA04-5 is the destination data location.
+
+ Writing to CA00 starts the blit, and the byte written determines how the
+ data is blitted.
+
+ Bit 0 indicates that the source data is either laid out linear, one
+ pixel after the last, or in screen format, where there are 256 bytes from
+ one pair of pixels to the next.
+
+ Bit 1 indicates the same, but for the destination data.
+
+ I'm not sure what bit 2 does. Looking at the image, I can't tell, but
+ perhaps it has to do with the mask. My test files only used a mask of $FF.
+
+ Bit 3 tells the blitter only to blit the foreground- that is, everything
+ that is not color 0. Also known as transparency mode.
+
+ Bit 4 is 'solid' mode. Only the color indicated by the mask is blitted.
+ Note that this just creates a rectangle unless bit 3 is also set, in which
+ case it blits the image, but in a solid color.
+
+ Bit 5 shifts the image one pixel to the right. Any data on the far right
+ jumps to the far left.
+
+ Bits 6 and 7 only blit every other pixel of the image. Bit 6 says even only,
+ while bit 7 says odd only.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/resnet.h"
+#include "williams.h"
+
+
+
+/*************************************
+ *
+ * Global variables
+ *
+ *************************************/
+
+/* RAM globals */
+UINT8 *williams_videoram;
+UINT8 *williams2_tileram;
+UINT8 *blaster_palette_0;
+UINT8 *blaster_scanline_control;
+
+/* blitter globals */
+UINT8 williams_blitter_config;
+UINT16 williams_blitter_clip_address;
+UINT8 williams_blitter_window_enable;
+
+/* tilemap globals */
+UINT8 williams2_tilemap_config;
+
+/* rendering globals */
+UINT8 williams_cocktail;
+
+
+
+/*************************************
+ *
+ * Static global variables
+ *
+ *************************************/
+
+/* RAM variable */
+static UINT8 *williams2_paletteram;
+
+/* palette variables */
+static rgb_t *palette_lookup;
+
+/* blitter variables */
+static UINT8 blitterram[8];
+static UINT8 blitter_xor;
+static UINT8 blitter_remap_index;
+static const UINT8 *blitter_remap;
+static UINT8 *blitter_remap_lookup;
+
+/* Blaster-specific variables */
+static UINT8 blaster_color0;
+static UINT8 blaster_video_control;
+
+/* tilemap variables */
+static tilemap *bg_tilemap;
+static UINT16 tilemap_xscroll;
+static UINT8 williams2_fg_color;
+
+
+
+/*************************************
+ *
+ * Prototypes
+ *
+ *************************************/
+
+static void blitter_init(int blitter_config, const UINT8 *remap_prom);
+static void create_palette_lookup(void);
+static TILE_GET_INFO( get_tile_info );
+static int blitter_core(int sstart, int dstart, int w, int h, int data);
+
+
+
+/*************************************
+ *
+ * Williams video startup
+ *
+ *************************************/
+
+static void state_save_register(void)
+{
+ state_save_register_global(williams_blitter_window_enable);
+ state_save_register_global(williams_cocktail);
+ state_save_register_global_array(blitterram);
+ state_save_register_global(blitter_remap_index);
+ state_save_register_global(blaster_color0);
+ state_save_register_global(blaster_video_control);
+ state_save_register_global(tilemap_xscroll);
+ state_save_register_global(williams2_fg_color);
+}
+
+
+VIDEO_START( williams )
+{
+ blitter_init(williams_blitter_config, NULL);
+ create_palette_lookup();
+ state_save_register();
+}
+
+
+VIDEO_START( blaster )
+{
+ blitter_init(williams_blitter_config, memory_region(REGION_PROMS));
+ create_palette_lookup();
+ state_save_register();
+}
+
+
+VIDEO_START( williams2 )
+{
+ blitter_init(williams_blitter_config, NULL);
+
+ /* allocate paletteram */
+ williams2_paletteram = auto_malloc(0x400 * 2);
+ state_save_register_global_pointer(williams2_paletteram, 0x400 * 2);
+
+ /* create the tilemap */
+ bg_tilemap = tilemap_create(get_tile_info, tilemap_scan_cols, TILEMAP_TYPE_PEN, 24,16, 128,16);
+ tilemap_set_scrolldx(bg_tilemap, 2, 0);
+
+ state_save_register();
+}
+
+
+
+/*************************************
+ *
+ * Williams video update
+ *
+ *************************************/
+
+VIDEO_UPDATE( williams )
+{
+ int x, y;
+
+ /* loop over rows */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT8 *source = &williams_videoram[y];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+
+ /* loop over columns */
+ for (x = cliprect->min_x & ~1; x <= cliprect->max_x; x += 2)
+ {
+ int pix = source[(x/2) * 256];
+ dest[x+0] = pix >> 4;
+ dest[x+1] = pix & 0x0f;
+ }
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( blaster )
+{
+ int x, y;
+
+ /* if we're blitting from the top, start with a 0 for color 0 */
+ if (cliprect->min_y == machine->screen[0].visarea.min_y || !(blaster_video_control & 1))
+ blaster_color0 = 0;
+
+ /* loop over rows */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ int erase_behind = blaster_video_control & blaster_scanline_control[y] & 2;
+ UINT8 *source = &williams_videoram[y];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+
+ /* latch a new color0 pen? */
+ if (blaster_video_control & blaster_scanline_control[y] & 1)
+ blaster_color0 = 16 + y;
+
+ /* loop over columns */
+ for (x = cliprect->min_x & ~1; x <= cliprect->max_x; x += 2)
+ {
+ int pix = source[(x/2) * 256];
+
+ /* clear behind us if requested */
+ if (erase_behind)
+ source[(x/2) * 256] = 0;
+
+ /* now draw */
+ dest[x+0] = (pix & 0xf0) ? (pix >> 4) : blaster_color0;
+ dest[x+1] = (pix & 0x0f) ? (pix & 0x0f) : blaster_color0;
+ }
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( williams2 )
+{
+ int x, y, basecolor;
+
+ /* draw the background */
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+
+ /* copy the bitmap data on top of that */
+ basecolor = williams2_fg_color * 16;
+
+ /* loop over rows */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT8 *source = &williams_videoram[y];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+
+ /* loop over columns */
+ for (x = cliprect->min_x & ~1; x <= cliprect->max_x; x += 2)
+ {
+ int pix = source[(x/2) * 256];
+
+ if (pix & 0xf0)
+ dest[x+0] = basecolor + (pix >> 4);
+ if (pix & 0x0f)
+ dest[x+1] = basecolor + (pix & 0x0f);
+ }
+ }
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Williams palette I/O
+ *
+ *************************************/
+
+static void create_palette_lookup(void)
+{
+ static const int resistances_rg[3] = { 1200, 560, 330 };
+ static const int resistances_b[2] = { 560, 330 };
+ double weights_r[3], weights_g[3], weights_b[2];
+ int i;
+
+ /* compute palette information */
+ /* note that there really are pullup/pulldown resistors, but this situation is complicated */
+ /* by the use of transistors, so we ignore that and just use the realtive resistor weights */
+ compute_resistor_weights(0, 255, -1.0,
+ 3, resistances_rg, weights_r, 0, 0,
+ 3, resistances_rg, weights_g, 0, 0,
+ 2, resistances_b, weights_b, 0, 0);
+
+ /* build a palette lookup */
+ palette_lookup = auto_malloc(256 * sizeof(*palette_lookup));
+ for (i = 0; i < 256; i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (i >> 0) & 0x01;
+ bit1 = (i >> 1) & 0x01;
+ bit2 = (i >> 2) & 0x01;
+ r = combine_3_weights(weights_r, bit0, bit1, bit2);
+
+ /* green component */
+ bit0 = (i >> 3) & 0x01;
+ bit1 = (i >> 4) & 0x01;
+ bit2 = (i >> 5) & 0x01;
+ g = combine_3_weights(weights_g, bit0, bit1, bit2);
+
+ /* blue component */
+ bit0 = (i >> 6) & 0x01;
+ bit1 = (i >> 7) & 0x01;
+ b = combine_2_weights(weights_b, bit0, bit1);
+
+ palette_lookup[i] = MAKE_RGB(r, g, b);
+ }
+}
+
+
+WRITE8_HANDLER( williams_paletteram_w )
+{
+ paletteram[offset] = data;
+ palette_set_color(Machine, offset, palette_lookup[data]);
+}
+
+
+READ8_HANDLER( williams2_paletteram_r )
+{
+ return williams2_paletteram[offset];
+}
+
+
+WRITE8_HANDLER( williams2_paletteram_w )
+{
+ static const UINT8 ztable[16] =
+ {
+ 0x0, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
+ 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11
+ };
+ UINT8 entry_lo, entry_hi, i, r, g, b;
+
+ /* set the new value */
+ williams2_paletteram[offset] = data;
+
+ /* pull the associated low/high bytes */
+ entry_lo = williams2_paletteram[offset & ~1];
+ entry_hi = williams2_paletteram[offset | 1];
+
+ /* update the palette entry */
+ i = ztable[(entry_hi >> 4) & 15];
+ b = ((entry_hi >> 0) & 15) * i;
+ g = ((entry_lo >> 4) & 15) * i;
+ r = ((entry_lo >> 0) & 15) * i;
+ palette_set_color(Machine, offset / 2, MAKE_RGB(r, g, b));
+}
+
+
+WRITE8_HANDLER( williams2_fg_select_w )
+{
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ williams2_fg_color = data & 0x3f;
+}
+
+
+
+/*************************************
+ *
+ * Video position readout
+ *
+ *************************************/
+
+READ8_HANDLER( williams_video_counter_r )
+{
+ return video_screen_get_vpos(0) & 0xfc;
+}
+
+
+READ8_HANDLER( williams2_video_counter_r )
+{
+ return video_screen_get_vpos(0);
+}
+
+
+
+/*************************************
+ *
+ * Tilemap handling
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ int mask = machine->gfx[0]->total_elements - 1;
+ int data = williams2_tileram[tile_index];
+ int y = (tile_index >> 1) & 7;
+ int color = 0;
+
+ switch (williams2_tilemap_config)
+ {
+ case WILLIAMS_TILEMAP_MYSTICM:
+ {
+ /* IC79 is a 74LS85 comparator that controls the low bit */
+ int a = 1 | ((color & 1) << 2) | ((color & 1) << 3);
+ int b = ((y & 6) >> 1);
+ int casc = (y & 1);
+ color = (a > b) || ((a == b) && !casc);
+ break;
+ }
+
+ case WILLIAMS_TILEMAP_TSHOOT:
+ /* IC79 is a 74LS157 selector jumpered to be enabled */
+ color = y;
+ break;
+
+ case WILLIAMS_TILEMAP_JOUST2:
+ /* IC79 is a 74LS157 selector jumpered to be disabled */
+ color = 0;
+ break;
+ }
+
+ SET_TILE_INFO(0, data & mask, color, (data & ~mask) ? TILE_FLIPX : 0);
+}
+
+
+WRITE8_HANDLER( williams2_bg_select_w )
+{
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+
+ /* based on the tilemap config, only certain bits are used */
+ /* the rest are determined by other factors */
+ switch (williams2_tilemap_config)
+ {
+ case WILLIAMS_TILEMAP_MYSTICM:
+ /* IC79 is a 74LS85 comparator that controls the low bit */
+ data &= 0x3e;
+ break;
+
+ case WILLIAMS_TILEMAP_TSHOOT:
+ /* IC79 is a 74LS157 selector jumpered to be enabled */
+ data &= 0x38;
+ break;
+
+ case WILLIAMS_TILEMAP_JOUST2:
+ /* IC79 is a 74LS157 selector jumpered to be disabled */
+ data &= 0x3f;
+ break;
+ }
+ tilemap_set_palette_offset(bg_tilemap, data * 16);
+}
+
+
+WRITE8_HANDLER( williams2_tileram_w )
+{
+ williams2_tileram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( williams2_xscroll_low_w )
+{
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ tilemap_xscroll = (tilemap_xscroll & ~0x00f) | ((data & 0x80) >> 4) | (data & 0x07);
+ tilemap_set_scrollx(bg_tilemap, 0, (tilemap_xscroll & 7) + ((tilemap_xscroll >> 3) * 6));
+}
+
+
+WRITE8_HANDLER( williams2_xscroll_high_w )
+{
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ tilemap_xscroll = (tilemap_xscroll & 0x00f) | (data << 4);
+ tilemap_set_scrollx(bg_tilemap, 0, (tilemap_xscroll & 7) + ((tilemap_xscroll >> 3) * 6));
+}
+
+
+
+/*************************************
+ *
+ * Blaster-specific enhancements
+ *
+ *************************************/
+
+WRITE8_HANDLER( blaster_remap_select_w )
+{
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ blitter_remap_index = data;
+ blitter_remap = blitter_remap_lookup + data * 256;
+}
+
+
+WRITE8_HANDLER( blaster_video_control_w )
+{
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ blaster_video_control = data;
+}
+
+
+WRITE8_HANDLER( blaster_scanline_control_w )
+{
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ blaster_scanline_control[offset] = data;
+}
+
+
+WRITE8_HANDLER( blaster_palette_0_w )
+{
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ blaster_palette_0[offset] = data;
+ palette_set_color(Machine, 16 + offset, palette_lookup[data ^ 0xff]);
+}
+
+
+
+/*************************************
+ *
+ * Blitter setup and control
+ *
+ *************************************/
+
+static void blitter_init(int blitter_config, const UINT8 *remap_prom)
+{
+ static const UINT8 dummy_table[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
+ int i,j;
+
+ /* by default, there is no clipping window - this will be touched only by games that have one */
+ williams_blitter_window_enable = 0;
+
+ /* switch off the video config */
+ blitter_xor = (blitter_config == WILLIAMS_BLITTER_SC01) ? 4 : 0;
+
+ /* create the remap table; if no PROM, make an identity remap table */
+ blitter_remap_lookup = auto_malloc(256 * 256);
+ blitter_remap_index = 0;
+ blitter_remap = blitter_remap_lookup;
+ for (i = 0; i < 256; i++)
+ {
+ const UINT8 *table = remap_prom ? (remap_prom + (i & 0x7f) * 16) : dummy_table;
+ for (j = 0; j < 256; j++)
+ blitter_remap_lookup[i * 256 + j] = (table[j >> 4] << 4) | table[j & 0x0f];
+ }
+}
+
+
+WRITE8_HANDLER( williams_blitter_w )
+{
+ int sstart, dstart, w, h, accesses;
+ int estimated_clocks_at_4MHz;
+
+ /* store the data */
+ blitterram[offset] = data;
+
+ /* only writes to location 0 trigger the blit */
+ if (offset != 0)
+ return;
+
+ /* compute the starting locations */
+ sstart = (blitterram[2] << 8) + blitterram[3];
+ dstart = (blitterram[4] << 8) + blitterram[5];
+
+ /* compute the width and height */
+ w = blitterram[6] ^ blitter_xor;
+ h = blitterram[7] ^ blitter_xor;
+
+ /* adjust the width and height */
+ if (w == 0) w = 1;
+ if (h == 0) h = 1;
+ if (w == 255) w = 256;
+ if (h == 255) h = 256;
+
+ /* do the actual blit */
+ accesses = blitter_core(sstart, dstart, w, h, data);
+
+ /* based on the number of memory accesses needed to do the blit, compute how long the blit will take */
+ /* this is just a guess */
+ estimated_clocks_at_4MHz = 20 + 2 * accesses;
+ activecpu_adjust_icount(-((estimated_clocks_at_4MHz + 3) / 4));
+
+ /* Log blits */
+ logerror("%04X:Blit @ %3d : %02X%02X -> %02X%02X, %3dx%3d, mask=%02X, flags=%02X, icount=%d, win=%d\n",
+ activecpu_get_pc(), video_screen_get_vpos(0),
+ blitterram[2], blitterram[3],
+ blitterram[4], blitterram[5],
+ blitterram[6], blitterram[7],
+ blitterram[1], blitterram[0],
+ ((estimated_clocks_at_4MHz + 3) / 4), williams_blitter_window_enable);
+}
+
+
+WRITE8_HANDLER( williams2_blit_window_enable_w )
+{
+ williams_blitter_window_enable = data & 0x01;
+}
+
+
+
+/*************************************
+ *
+ * Blitter core
+ *
+ *************************************/
+
+INLINE void blit_pixel(int offset, int srcdata, int data, int mask, int solid)
+{
+ /* always read from video RAM regardless of the bank setting */
+ int pix = (offset < 0xc000) ? williams_videoram[offset] : program_read_byte(offset);
+
+ /* handle transparency */
+ if (data & 0x08)
+ {
+ if (!(srcdata & 0xf0)) mask |= 0xf0;
+ if (!(srcdata & 0x0f)) mask |= 0x0f;
+ }
+
+ /* handle solid versus source data */
+ pix &= mask;
+ if (data & 0x10)
+ pix |= solid & ~mask;
+ else
+ pix |= srcdata & ~mask;
+
+ /* if the window is enabled, only blit to videoram below the clipping address */
+ /* note that we have to allow blits to non-video RAM (e.g. tileram) because those */
+ /* are not blocked by the window enable */
+ if (!williams_blitter_window_enable || offset < williams_blitter_clip_address || offset >= 0xc000)
+ program_write_byte(offset, pix);
+}
+
+
+static int blitter_core(int sstart, int dstart, int w, int h, int data)
+{
+ int source, sxadv, syadv;
+ int dest, dxadv, dyadv;
+ int i, j, solid;
+ int accesses = 0;
+ int keepmask;
+
+ /* compute how much to advance in the x and y loops */
+ sxadv = (data & 0x01) ? 0x100 : 1;
+ syadv = (data & 0x01) ? 1 : w;
+ dxadv = (data & 0x02) ? 0x100 : 1;
+ dyadv = (data & 0x02) ? 1 : w;
+
+ /* determine the common mask */
+ keepmask = 0x00;
+ if (data & 0x80) keepmask |= 0xf0;
+ if (data & 0x40) keepmask |= 0x0f;
+ if (keepmask == 0xff)
+ return accesses;
+
+ /* set the solid pixel value to the mask value */
+ solid = blitterram[1];
+
+ /* first case: no shifting */
+ if (!(data & 0x20))
+ {
+ /* loop over the height */
+ for (i = 0; i < h; i++)
+ {
+ source = sstart & 0xffff;
+ dest = dstart & 0xffff;
+
+ /* loop over the width */
+ for (j = w; j > 0; j--)
+ {
+ blit_pixel(dest, blitter_remap[program_read_byte(source)], data, keepmask, solid);
+ accesses += 2;
+
+ /* advance */
+ source = (source + sxadv) & 0xffff;
+ dest = (dest + dxadv) & 0xffff;
+ }
+
+ sstart += syadv;
+
+ /* note that PlayBall! indicates the X coordinate doesn't wrap */
+ if (data & 0x02)
+ dstart = (dstart & 0xff00) | ((dstart + dyadv) & 0xff);
+ else
+ dstart += dyadv;
+ }
+ }
+
+ /* second case: shifted one pixel */
+ else
+ {
+ /* swap halves of the keep mask and the solid color */
+ keepmask = ((keepmask & 0xf0) >> 4) | ((keepmask & 0x0f) << 4);
+ solid = ((solid & 0xf0) >> 4) | ((solid & 0x0f) << 4);
+
+ /* loop over the height */
+ for (i = 0; i < h; i++)
+ {
+ int pixdata;
+
+ source = sstart & 0xffff;
+ dest = dstart & 0xffff;
+
+ /* left edge case */
+ pixdata = blitter_remap[program_read_byte(source)];
+ blit_pixel(dest, (pixdata >> 4) & 0x0f, data, keepmask | 0xf0, solid);
+ accesses += 2;
+
+ source = (source + sxadv) & 0xffff;
+ dest = (dest + dxadv) & 0xffff;
+
+ /* loop over the width */
+ for (j = w - 1; j > 0; j--)
+ {
+ pixdata = (pixdata << 8) | blitter_remap[program_read_byte(source)];
+ blit_pixel(dest, (pixdata >> 4) & 0xff, data, keepmask, solid);
+ accesses += 2;
+
+ source = (source + sxadv) & 0xffff;
+ dest = (dest + dxadv) & 0xffff;
+ }
+
+ /* right edge case */
+ blit_pixel(dest, (pixdata << 4) & 0xf0, data, keepmask | 0x0f, solid);
+ accesses++;
+
+ sstart += syadv;
+
+ /* note that PlayBall! indicates the X coordinate doesn't wrap */
+ if (data & 0x02)
+ dstart = (dstart & 0xff00) | ((dstart + dyadv) & 0xff);
+ else
+ dstart += dyadv;
+ }
+ }
+
+ return accesses;
+}
diff --git a/src/mame/video/wiping.c b/src/mame/video/wiping.c
new file mode 100644
index 00000000000..125b1f8e697
--- /dev/null
+++ b/src/mame/video/wiping.c
@@ -0,0 +1,219 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+static int flipscreen;
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+***************************************************************************/
+
+PALETTE_INIT( wiping )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + (offs)])
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (*color_prom >> 6) & 0x01;
+ bit1 = (*color_prom >> 7) & 0x01;
+ b = 0x4f * bit0 + 0xa8 * bit1;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* chars use colors 0-15 */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ COLOR(0,i ^ 3) = *(color_prom++) & 0x0f;
+
+ /* sprites use colors 16-31 */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i ^ 3) = (*(color_prom++) & 0x0f) + 0x10;
+}
+
+
+
+WRITE8_HANDLER( wiping_flipscreen_w )
+{
+ if (flipscreen != (data & 1))
+ {
+ flipscreen = (data & 1);
+ memset(dirtybuffer,1,videoram_size);
+ }
+}
+
+
+VIDEO_UPDATE( wiping )
+{
+ int offs;
+
+ for (offs = videoram_size - 1; offs > 0; offs--)
+ {
+ if (dirtybuffer[offs])
+ {
+ int mx,my,sx,sy;
+
+ dirtybuffer[offs] = 0;
+
+ mx = offs % 32;
+ my = offs / 32;
+
+ if (my < 2)
+ {
+ sx = my + 34;
+ sy = mx - 2;
+ }
+ else if (my >= 30)
+ {
+ sx = my - 30;
+ sy = mx - 2;
+ }
+ else
+ {
+ sx = mx + 2;
+ sy = my - 2;
+ }
+
+ if (flipscreen)
+ {
+ sx = 35 - sx;
+ sy = 27 - sy;
+ }
+
+ drawgfx(tmpbitmap,machine->gfx[0],
+ videoram[offs],
+ colorram[offs] & 0x3f,
+ flipscreen,flipscreen,
+ sx*8,sy*8,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ }
+ }
+ copybitmap(bitmap,tmpbitmap,0,0,0,0,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+
+ /* Note, we're counting up on purpose ! */
+ /* This way the vacuum cleaner is always on top */
+ for (offs = 0x0; offs < 128; offs += 2) {
+ int sx,sy,flipx,flipy,otherbank;
+
+ sx = spriteram[offs+0x100+1] + ((spriteram[offs+0x81] & 0x01) << 8) - 40;
+ sy = 224 - spriteram[offs+0x100];
+
+ otherbank = spriteram[offs+0x80] & 0x01;
+
+ flipy = spriteram[offs] & 0x40;
+ flipx = spriteram[offs] & 0x80;
+
+ if (flipscreen)
+ {
+ sy = 208 - sy;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs] & 0x3f) + 64 * otherbank,
+ spriteram[offs+1] & 0x3f,
+ flipx,flipy,
+ sx,sy,
+ &machine->screen[0].visarea,TRANSPARENCY_COLOR,0x1f);
+ }
+
+ /* redraw high priority chars */
+ for (offs = videoram_size - 1; offs > 0; offs--)
+ {
+ if (colorram[offs] & 0x80)
+ {
+ int mx,my,sx,sy;
+
+ mx = offs % 32;
+ my = offs / 32;
+
+ if (my < 2)
+ {
+ sx = my + 34;
+ sy = mx - 2;
+ }
+ else if (my >= 30)
+ {
+ sx = my - 30;
+ sy = mx - 2;
+ }
+ else
+ {
+ sx = mx + 2;
+ sy = my - 2;
+ }
+
+ if (flipscreen)
+ {
+ sx = 35 - sx;
+ sy = 27 - sy;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ videoram[offs],
+ colorram[offs] & 0x3f,
+ flipscreen,flipscreen,
+ sx*8,sy*8,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ }
+ }
+
+
+#if 0
+{
+ int i,j;
+ extern UINT8 *wiping_soundregs;
+
+ for (i = 0;i < 8;i++)
+ {
+ for (j = 0;j < 8;j++)
+ {
+ char buf[40];
+ sprintf(buf,"%01x",wiping_soundregs[i*8+j]&0xf);
+ ui_draw_text(buf,j*10,i*8);
+ }
+ }
+
+ for (i = 0;i < 8;i++)
+ {
+ for (j = 0;j < 8;j++)
+ {
+ char buf[40];
+ sprintf(buf,"%01x",wiping_soundregs[0x2000+i*8+j]>>4);
+ ui_draw_text(buf,j*10,80+i*8);
+ }
+ }
+}
+#endif
+ return 0;
+}
diff --git a/src/mame/video/wiz.c b/src/mame/video/wiz.c
new file mode 100644
index 00000000000..ebfe421cda4
--- /dev/null
+++ b/src/mame/video/wiz.c
@@ -0,0 +1,301 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+static rectangle spritevisiblearea =
+{
+ 2*8, 32*8-1,
+ 2*8, 30*8-1
+};
+
+static rectangle spritevisibleareaflipx =
+{
+ 0*8, 30*8-1,
+ 2*8, 30*8-1
+};
+
+UINT8 *wiz_videoram2;
+UINT8 *wiz_colorram2;
+UINT8 *wiz_attributesram;
+UINT8 *wiz_attributesram2;
+
+static INT32 flipx, flipy;
+static INT32 bgpen;
+
+UINT8 *wiz_sprite_bank;
+static UINT8 char_bank[2];
+static UINT8 palbank[2];
+static int palette_bank;
+
+
+VIDEO_START( wiz )
+{
+ video_start_generic(machine);
+
+ state_save_register_global_array(char_bank);
+ state_save_register_global_array(palbank);
+ state_save_register_global(flipx);
+ state_save_register_global(flipy);
+ state_save_register_global(bgpen);
+}
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Stinger has three 256x4 palette PROMs (one per gun).
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 100 ohm resistor -- RED/GREEN/BLUE
+ -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 1 kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+PALETTE_INIT( wiz )
+{
+ int i;
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x42 * bit2 + 0x90 * bit3;
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x42 * bit2 + 0x90 * bit3;
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x42 * bit2 + 0x90 * bit3;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( wiz_attributes_w )
+{
+ if ((offset & 1) && wiz_attributesram[offset] != data)
+ {
+ int i;
+
+
+ for (i = offset / 2;i < videoram_size;i += 32)
+ {
+ dirtybuffer[i] = 1;
+ }
+ }
+
+ wiz_attributesram[offset] = data;
+}
+
+WRITE8_HANDLER( wiz_palettebank_w )
+{
+ if (palbank[offset] != (data & 1))
+ {
+ palbank[offset] = data & 1;
+ palette_bank = palbank[0] + 2 * palbank[1];
+
+ memset(dirtybuffer,1,videoram_size);
+ }
+}
+
+WRITE8_HANDLER( wiz_bgcolor_w )
+{
+ bgpen = data;
+}
+
+WRITE8_HANDLER( wiz_char_bank_select_w )
+{
+ if (char_bank[offset] != (data & 1))
+ {
+ char_bank[offset] = data & 1;
+ memset(dirtybuffer,1,videoram_size);
+ }
+}
+
+WRITE8_HANDLER( wiz_flipx_w )
+{
+ if (flipx != data)
+ {
+ flipx = data;
+
+ memset(dirtybuffer, 1, videoram_size);
+ }
+}
+
+
+WRITE8_HANDLER( wiz_flipy_w )
+{
+ if (flipy != data)
+ {
+ flipy = data;
+
+ memset(dirtybuffer, 1, videoram_size);
+ }
+}
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int bank, int colortype)
+{
+ int offs;
+
+ /* for every character in the Video RAM, check if it has been modified */
+ /* since last time and update it accordingly. */
+
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int scroll,sx,sy,col;
+
+ sx = offs % 32;
+ sy = offs / 32;
+
+ if (colortype)
+ {
+ col = (wiz_attributesram[2 * sx + 1] & 0x07);
+ }
+ else
+ {
+ col = (wiz_attributesram[2 * (offs % 32) + 1] & 0x04) + (videoram[offs] & 3);
+ }
+
+ scroll = (8*sy + 256 - wiz_attributesram[2 * sx]) % 256;
+ if (flipy)
+ {
+ scroll = (248 - scroll) % 256;
+ }
+ if (flipx) sx = 31 - sx;
+
+
+ drawgfx(bitmap,machine->gfx[bank],
+ videoram[offs],
+ col + 8 * palette_bank,
+ flipx,flipy,
+ 8*sx,scroll,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+static void draw_foreground(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int colortype)
+{
+ int offs;
+
+ /* draw the frontmost playfield. They are characters, but draw them as sprites. */
+ for (offs = videoram_size - 1;offs >= 0;offs--)
+ {
+ int scroll,sx,sy,col;
+
+
+ sx = offs % 32;
+ sy = offs / 32;
+
+ if (colortype)
+ {
+ col = (wiz_attributesram2[2 * sx + 1] & 0x07);
+ }
+ else
+ {
+ col = (wiz_colorram2[offs] & 0x07);
+ }
+
+ scroll = (8*sy + 256 - wiz_attributesram2[2 * sx]) % 256;
+ if (flipy)
+ {
+ scroll = (248 - scroll) % 256;
+ }
+ if (flipx) sx = 31 - sx;
+
+
+ drawgfx(bitmap,machine->gfx[char_bank[1]],
+ wiz_videoram2[offs],
+ col + 8 * palette_bank,
+ flipx,flipy,
+ 8*sx,scroll,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,
+ const rectangle *cliprect, UINT8* sprite_ram,
+ int bank)
+{
+ int offs;
+
+ for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
+ {
+ int sx,sy;
+
+
+ sx = sprite_ram[offs + 3];
+ sy = sprite_ram[offs];
+
+ if (!sx || !sy) continue;
+
+ if ( flipx) sx = 240 - sx;
+ if (!flipy) sy = 240 - sy;
+
+ drawgfx(bitmap,machine->gfx[bank],
+ sprite_ram[offs + 1],
+ (sprite_ram[offs + 2] & 0x07) + 8 * palette_bank,
+ flipx,flipy,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+VIDEO_UPDATE( kungfut )
+{
+ fillbitmap(bitmap,machine->pens[bgpen],cliprect);
+ draw_background(machine, bitmap, cliprect, 2 + char_bank[0] , 0);
+ draw_foreground(machine, bitmap, cliprect, 0);
+ draw_sprites(machine, bitmap, cliprect, spriteram_2, 4);
+ draw_sprites(machine, bitmap, cliprect, spriteram , 5);
+ return 0;
+}
+
+VIDEO_UPDATE( wiz )
+{
+ int bank;
+ const rectangle* visible_area;
+
+ fillbitmap(bitmap,machine->pens[bgpen],cliprect);
+ draw_background(machine, bitmap, cliprect, 2 + ((char_bank[0] << 1) | char_bank[1]), 0);
+ draw_foreground(machine, bitmap, cliprect, 0);
+
+ visible_area = flipx ? &spritevisibleareaflipx : &spritevisiblearea;
+
+ bank = 7 + *wiz_sprite_bank;
+
+ draw_sprites(machine, bitmap, visible_area, spriteram_2, 6);
+ draw_sprites(machine, bitmap, visible_area, spriteram , bank);
+ return 0;
+}
+
+
+VIDEO_UPDATE( stinger )
+{
+ fillbitmap(bitmap,machine->pens[bgpen],cliprect);
+ draw_background(machine, bitmap, cliprect, 2 + char_bank[0], 1);
+ draw_foreground(machine, bitmap, cliprect, 1);
+ draw_sprites(machine, bitmap, cliprect, spriteram_2, 4);
+ draw_sprites(machine, bitmap, cliprect, spriteram , 5);
+ return 0;
+}
diff --git a/src/mame/video/wolfpack.c b/src/mame/video/wolfpack.c
new file mode 100644
index 00000000000..c0ad9a7a42d
--- /dev/null
+++ b/src/mame/video/wolfpack.c
@@ -0,0 +1,327 @@
+/***************************************************************************
+
+Atari Wolf Pack (prototype) video emulation
+
+***************************************************************************/
+
+#include "driver.h"
+
+int wolfpack_collision;
+
+UINT8* wolfpack_alpha_num_ram;
+
+static unsigned current_index;
+
+static UINT8 wolfpack_video_invert;
+static UINT8 wolfpack_ship_reflect;
+static UINT8 wolfpack_pt_pos_select;
+static UINT8 wolfpack_pt_horz;
+static UINT8 wolfpack_pt_pic;
+static UINT8 wolfpack_ship_h;
+static UINT8 wolfpack_torpedo_pic;
+static UINT8 wolfpack_ship_size;
+static UINT8 wolfpack_ship_h_precess;
+static UINT8 wolfpack_ship_pic;
+static UINT8 wolfpack_torpedo_h;
+static UINT8 wolfpack_torpedo_v;
+
+static UINT8* LFSR;
+
+static mame_bitmap* helper;
+
+
+WRITE8_HANDLER( wolfpack_ship_size_w )
+{
+ UINT8 color;
+
+ color = 0x48;
+
+ if (data & 0x10) color += 0x13;
+ if (data & 0x20) color += 0x22;
+ if (data & 0x40) color += 0x3A;
+ if (data & 0x80) color += 0x48;
+
+ palette_set_color(Machine,3,MAKE_RGB(color,color,color));
+
+ palette_set_color_rgb(Machine,7,
+ color < 0xb8 ? color + 0x48 : 0xff,
+ color < 0xb8 ? color + 0x48 : 0xff,
+ color < 0xb8 ? color + 0x48 : 0xff);
+
+ wolfpack_ship_size = data >> 2;
+}
+
+
+WRITE8_HANDLER( wolfpack_video_invert_w )
+{
+ wolfpack_video_invert = data & 1;
+}
+WRITE8_HANDLER( wolfpack_ship_reflect_w )
+{
+ wolfpack_ship_reflect = data & 1;
+}
+WRITE8_HANDLER( wolfpack_pt_pos_select_w )
+{
+ wolfpack_pt_pos_select = data & 1;
+}
+WRITE8_HANDLER( wolfpack_pt_horz_w )
+{
+ wolfpack_pt_horz = data;
+}
+WRITE8_HANDLER( wolfpack_pt_pic_w )
+{
+ wolfpack_pt_pic = data & 0x3f;
+}
+WRITE8_HANDLER( wolfpack_ship_h_w )
+{
+ wolfpack_ship_h = data;
+}
+WRITE8_HANDLER( wolfpack_torpedo_pic_w )
+{
+ wolfpack_torpedo_pic = data;
+}
+WRITE8_HANDLER( wolfpack_ship_h_precess_w )
+{
+ wolfpack_ship_h_precess = data & 0x3f;
+}
+WRITE8_HANDLER( wolfpack_ship_pic_w )
+{
+ wolfpack_ship_pic = data & 0x0f;
+}
+WRITE8_HANDLER( wolfpack_torpedo_h_w )
+{
+ wolfpack_torpedo_h = data;
+}
+WRITE8_HANDLER( wolfpack_torpedo_v_w )
+{
+ wolfpack_torpedo_v = data;
+}
+
+
+VIDEO_START( wolfpack )
+{
+ UINT16 val = 0;
+
+ int i;
+
+ LFSR = auto_malloc(0x8000);
+
+ helper = auto_bitmap_alloc(machine->screen[0].width, machine->screen[0].height, machine->screen[0].format);
+
+ for (i = 0; i < 0x8000; i++)
+ {
+ int bit =
+ (val >> 0x0) ^
+ (val >> 0xE) ^ 1;
+
+ val = (val << 1) | (bit & 1);
+
+ LFSR[i] = (val & 0xc00) == 0xc00;
+ }
+
+ current_index = 0x80;
+}
+
+
+static void draw_ship(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ static const UINT32 scaler[] =
+ {
+ 0x00000, 0x00500, 0x00A00, 0x01000,
+ 0x01000, 0x01200, 0x01500, 0x01800,
+ 0x01800, 0x01D00, 0x02200, 0x02800,
+ 0x02800, 0x02800, 0x02800, 0x02800,
+ 0x02800, 0x03000, 0x03800, 0x04000,
+ 0x04000, 0x04500, 0x04A00, 0x05000,
+ 0x05000, 0x05500, 0x05A00, 0x06000,
+ 0x06000, 0x06A00, 0x07500, 0x08000,
+ 0x08000, 0x08A00, 0x09500, 0x0A000,
+ 0x0A000, 0x0B000, 0x0C000, 0x0D000,
+ 0x0D000, 0x0E000, 0x0F000, 0x10000,
+ 0x10000, 0x11A00, 0x13500, 0x15000,
+ 0x15000, 0x17500, 0x19A00, 0x1C000,
+ 0x1C000, 0x1EA00, 0x21500, 0x24000,
+ 0x24000, 0x26A00, 0x29500, 0x2C000,
+ 0x2C000, 0x2FA00, 0x33500, 0x37000
+ };
+
+ int chop = (scaler[wolfpack_ship_size] * wolfpack_ship_h_precess) >> 16;
+
+ drawgfxzoom(bitmap, machine->gfx[1],
+ wolfpack_ship_pic,
+ 0,
+ wolfpack_ship_reflect, 0,
+ 2 * (wolfpack_ship_h - chop),
+ 128,
+ cliprect,
+ TRANSPARENCY_PEN, 0,
+ 2 * scaler[wolfpack_ship_size], scaler[wolfpack_ship_size]);
+}
+
+
+static void draw_torpedo(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ int count = 0;
+
+ int x;
+ int y;
+
+ drawgfx(bitmap, machine->gfx[3],
+ wolfpack_torpedo_pic,
+ 0,
+ 0, 0,
+ 2 * (244 - wolfpack_torpedo_h),
+ 224 - wolfpack_torpedo_v,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+
+ for (y = 16; y < 224 - wolfpack_torpedo_v; y++)
+ {
+ int x1;
+ int x2;
+
+ if (y % 16 == 1)
+ {
+ count = (count - 1) & 7;
+ }
+
+ x1 = 248 - wolfpack_torpedo_h - count;
+ x2 = 248 - wolfpack_torpedo_h + count;
+
+ for (x = 2 * x1; x < 2 * x2; x++)
+ {
+ if (LFSR[(current_index + 0x300 * y + x) % 0x8000])
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = 1;
+ }
+ }
+ }
+}
+
+
+static void draw_pt(running_machine *machine, mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ rectangle rect = *cliprect;
+
+ if (!(wolfpack_pt_pic & 0x20))
+ {
+ rect.min_x = 256;
+ }
+ if (!(wolfpack_pt_pic & 0x10))
+ {
+ rect.max_x = 255;
+ }
+
+ drawgfx(bitmap, machine->gfx[2],
+ wolfpack_pt_pic,
+ 0,
+ 0, 0,
+ 2 * wolfpack_pt_horz,
+ wolfpack_pt_pos_select ? 0x70 : 0xA0,
+ &rect,
+ TRANSPARENCY_PEN, 0);
+
+ drawgfx(bitmap, machine->gfx[2],
+ wolfpack_pt_pic,
+ 0,
+ 0, 0,
+ 2 * wolfpack_pt_horz - 512,
+ wolfpack_pt_pos_select ? 0x70 : 0xA0,
+ &rect,
+ TRANSPARENCY_PEN, 0);
+}
+
+
+static void draw_water(mame_bitmap* bitmap, const rectangle* cliprect)
+{
+ rectangle rect = *cliprect;
+
+ int x;
+ int y;
+
+ if (rect.max_y > 127)
+ {
+ rect.max_y = 127;
+ }
+
+ for (y = rect.min_y; y <= rect.max_y; y++)
+ {
+ UINT16* p = BITMAP_ADDR16(bitmap, y, 0);
+
+ for (x = rect.min_x; x <= rect.max_x; x++)
+ {
+ p[x] |= 4;
+ }
+ }
+}
+
+
+VIDEO_UPDATE( wolfpack )
+{
+ int i;
+ int j;
+
+ fillbitmap(bitmap, wolfpack_video_invert, cliprect);
+
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 32; j++)
+ {
+ int code = wolfpack_alpha_num_ram[32 * i + j];
+
+ drawgfx(bitmap, machine->gfx[0],
+ code,
+ wolfpack_video_invert,
+ 0, 0,
+ 16 * j,
+ 192 + 8 * i,
+ cliprect,
+ TRANSPARENCY_NONE, 0);
+ }
+ }
+
+ draw_pt(machine, bitmap, cliprect);
+ draw_ship(machine, bitmap, cliprect);
+ draw_torpedo(machine, bitmap, cliprect);
+ draw_water(bitmap, cliprect);
+ return 0;
+}
+
+
+VIDEO_EOF( wolfpack )
+{
+ rectangle rect;
+
+ int x;
+ int y;
+
+ rect.min_x = 0;
+ rect.min_y = 0;
+ rect.max_x = helper->width - 1;
+ rect.max_y = helper->height - 1;
+
+ fillbitmap(helper, 0, &rect);
+
+ draw_ship(machine, helper, &rect);
+
+ for (y = 128; y < 224 - wolfpack_torpedo_v; y++)
+ {
+ int x1 = 248 - wolfpack_torpedo_h - 1;
+ int x2 = 248 - wolfpack_torpedo_h + 1;
+
+ for (x = 2 * x1; x < 2 * x2; x++)
+ {
+ if (x < 0 || x >= helper->width)
+ continue;
+ if (y < 0 || y >= helper->height)
+ continue;
+
+ if (*BITMAP_ADDR16(helper, y, x))
+ {
+ wolfpack_collision = 1;
+ }
+ }
+ }
+
+ current_index += 0x300 * 262;
+}
diff --git a/src/mame/video/wrally.c b/src/mame/video/wrally.c
new file mode 100644
index 00000000000..9996176b709
--- /dev/null
+++ b/src/mame/video/wrally.c
@@ -0,0 +1,172 @@
+/***************************************************************************
+
+ World Rally Video Hardware
+
+ Functions to emulate the video hardware of the machine
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *wrally_spriteram;
+UINT16 *wrally_vregs;
+UINT16 *wrally_videoram;
+
+static tilemap *pant[2];
+
+/* from machine/wrally.c */
+extern UINT16 *wrally_encr_table[2];
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+/*
+ Tile format
+ -----------
+
+ Screen 0 & 1: (64*32, 16x16 tiles)
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | --xxxxxx xxxxxxxx | code
+ 0 | xx------ -------- | not used?
+ 1 | xxxxxxxx xxxxxxxx | unknown
+
+ preliminary
+*/
+
+
+static TILE_GET_INFO( get_tile_info_wrally_screen0 )
+{
+ int data = wrally_videoram[tile_index << 1];
+ int data2 = wrally_videoram[(tile_index << 1) + 1];
+ int code = data & 0x3fff;
+
+ SET_TILE_INFO(0, code, data2 & 0x1f, TILE_FLIPXY((data2 >> 5) & 0x00));
+}
+
+static TILE_GET_INFO( get_tile_info_wrally_screen1 )
+{
+ int data = wrally_videoram[(0x2000/2) + (tile_index << 1)];
+ int data2 = wrally_videoram[(0x2000/2) + (tile_index << 1) + 1];
+ int code = data & 0x3fff;
+
+ SET_TILE_INFO(0, code, data2 & 0x1f, TILE_FLIPXY((data2 >> 5) & 0x00));
+}
+
+/***************************************************************************
+
+ Memory Handlers
+
+***************************************************************************/
+
+WRITE16_HANDLER( wrally_vram_w )
+{
+ wrally_videoram[offset] = wrally_encr_table[offset & 0x01][data];
+
+ tilemap_mark_tile_dirty(pant[(offset & 0x1fff) >> 12], ((offset << 1) & 0x1fff) >> 2);
+}
+
+
+/***************************************************************************
+
+ Start/Stop the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( wrally )
+{
+ pant[0] = tilemap_create(get_tile_info_wrally_screen0,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+ pant[1] = tilemap_create(get_tile_info_wrally_screen1,tilemap_scan_rows,TILEMAP_TYPE_PEN,16,16,64,32);
+
+ tilemap_set_transparent_pen(pant[0],0);
+ tilemap_set_transparent_pen(pant[1],0);
+}
+
+
+/***************************************************************************
+
+ Sprites
+
+***************************************************************************/
+
+/*
+ Sprite Format
+ -------------
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- xxxxxxxx | y position
+ 0 | --xxxxxx -------- | not used?
+ 0 | -x------ -------- | flipx
+ 0 | x------- -------- | flipy
+ 1 | xxxxxxxx xxxxxxxx | unknown
+ 2 | ------xx xxxxxxxx | x position
+ 2 | --xxxx-- -------- | sprite color (low 4 bits)
+ 2 | xx------ -------- | unknown
+ 3 | --xxxxxx xxxxxxxx | sprite code
+ 3 | xx------ -------- | not used?
+
+ preliminary
+*/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int i, x, y, ex, ey;
+ const gfx_element *gfx = machine->gfx[0];
+
+ static int x_offset[2] = {0x0,0x2};
+ static int y_offset[2] = {0x0,0x1};
+
+ for (i = 3; i < (0x1000 - 6)/2; i += 4){
+ int sx = wrally_spriteram[i+2] & 0x03ff;
+ int sy = (240 - (wrally_spriteram[i] & 0x00ff)) & 0x00ff;
+ int number = wrally_spriteram[i+3] & 0x3fff;
+ int color = ((wrally_spriteram[i+2] & 0xfc00) >> 10);
+ int attr = (wrally_spriteram[i] & 0xfe00) >> 9;
+
+ int xflip = attr & 0x20;
+ int yflip = attr & 0x40;
+ int spr_size = 1;
+
+ color = (color & 0x0f);
+
+ for (y = 0; y < spr_size; y++){
+ for (x = 0; x < spr_size; x++){
+
+ ex = xflip ? (spr_size-1-x) : x;
+ ey = yflip ? (spr_size-1-y) : y;
+
+ drawgfx(bitmap,gfx,number + x_offset[ex] + y_offset[ey],
+ 0x20 + color,xflip,yflip,
+ sx-0x0f+x*16,sy+y*16,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+}
+
+/***************************************************************************
+
+ Display Refresh
+
+***************************************************************************/
+
+VIDEO_UPDATE( wrally )
+{
+ /* set scroll registers */
+ tilemap_set_scrolly(pant[0], 0, wrally_vregs[0]);
+ tilemap_set_scrollx(pant[0], 0, wrally_vregs[1]);
+ tilemap_set_scrolly(pant[1], 0, wrally_vregs[2]);
+ tilemap_set_scrollx(pant[1], 0, wrally_vregs[3]);
+
+ fillbitmap( bitmap, machine->pens[0], cliprect );
+
+ tilemap_draw(bitmap,cliprect,pant[1],0,0);
+ tilemap_draw(bitmap,cliprect,pant[0],0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/wwfsstar.c b/src/mame/video/wwfsstar.c
new file mode 100644
index 00000000000..4eb8fec8d11
--- /dev/null
+++ b/src/mame/video/wwfsstar.c
@@ -0,0 +1,225 @@
+/*******************************************************************************
+ WWF Superstars (C) 1989 Technos Japan (video/wwfsstar.c)
+********************************************************************************
+ driver by David Haywood
+
+ see (drivers/wwfsstar.c) for more notes
+*******************************************************************************/
+
+#include "driver.h"
+
+UINT16 *wwfsstar_fg0_videoram, *wwfsstar_bg0_videoram;
+extern int wwfsstar_scrollx, wwfsstar_scrolly;
+static tilemap *fg0_tilemap, *bg0_tilemap;
+
+/*******************************************************************************
+ Write Handlers
+********************************************************************************
+ for writes to Video Ram
+*******************************************************************************/
+
+WRITE16_HANDLER( wwfsstar_fg0_videoram_w )
+{
+ COMBINE_DATA(&wwfsstar_fg0_videoram[offset]);
+ tilemap_mark_tile_dirty(fg0_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( wwfsstar_bg0_videoram_w )
+{
+ COMBINE_DATA(&wwfsstar_bg0_videoram[offset]);
+ tilemap_mark_tile_dirty(bg0_tilemap,offset/2);
+}
+
+/*******************************************************************************
+ Tilemap Related Functions
+*******************************************************************************/
+
+static TILE_GET_INFO( get_fg0_tile_info )
+{
+ /*- FG0 RAM Format -**
+
+ 0x1000 sized region (4096 bytes)
+
+ 32x32 tilemap, 4 bytes per tile
+
+ ---- ---- CCCC TTTT ---- ---- TTTT TTTT
+
+ C = Colour Bank (0-15)
+ T = Tile Number (0 - 4095)
+
+ other bits unknown / unused
+
+ **- End of Comments -*/
+
+ UINT16 *tilebase;
+ int tileno;
+ int colbank;
+ tilebase = &wwfsstar_fg0_videoram[tile_index*2];
+ tileno = (tilebase[1] & 0x00ff) | ((tilebase[0] & 0x000f) << 8);
+ colbank = (tilebase[0] & 0x00f0) >> 4;
+ SET_TILE_INFO(
+ 0,
+ tileno,
+ colbank,
+ 0);
+}
+
+static TILEMAP_MAPPER( bg0_scan )
+{
+ return (col & 0x0f) + ((row & 0x0f) << 4) + ((col & 0x10) << 4) + ((row & 0x10) << 5);
+}
+
+static TILE_GET_INFO( get_bg0_tile_info )
+{
+ /*- BG0 RAM Format -**
+
+ 0x1000 sized region (4096 bytes)
+
+ 32x32 tilemap, 4 bytes per tile
+
+ ---- ---- FCCC TTTT ---- ---- TTTT TTTT
+
+ C = Colour Bank (0-7)
+ T = Tile Number (0 - 4095)
+ F = FlipX
+
+ other bits unknown / unused
+
+ **- End of Comments -*/
+
+ UINT16 *tilebase;
+ int tileno, colbank, flipx;
+ tilebase = &wwfsstar_bg0_videoram[tile_index*2];
+ tileno = (tilebase[1] & 0x00ff) | ((tilebase[0] & 0x000f) << 8);
+ colbank = (tilebase[0] & 0x0070) >> 4;
+ flipx = (tilebase[0] & 0x0080) >> 7;
+ SET_TILE_INFO(
+ 2,
+ tileno,
+ colbank,
+ flipx ? TILE_FLIPX : 0);
+}
+
+/*******************************************************************************
+ Sprite Related Functions
+********************************************************************************
+ sprite colour marking could probably be improved..
+*******************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ /*- SPR RAM Format -**
+
+ 0x3FF sized region (1024 bytes)
+
+ 10 bytes per sprite
+
+ ---- ---- yyyy yyyy ---- ---- CCCC XYLE ---- ---- fFNN NNNN ---- ---- nnnn nnnn ---- ---- xxxx xxxx
+
+ Yy = sprite Y Position
+ Xx = sprite X Position
+ C = colour bank
+ f = flip Y
+ F = flip X
+ L = chain sprite (32x16)
+ E = sprite enable
+ Nn = Sprite Number
+
+ other bits unused
+
+ **- End of Comments -*/
+
+ const gfx_element *gfx = machine->gfx[1];
+ UINT16 *source = spriteram16;
+ UINT16 *finish = source + 0x3ff/2;
+
+ while (source < finish)
+ {
+ int xpos, ypos, colourbank, flipx, flipy, chain, enable, number, count;
+
+ enable = (source [1] & 0x0001);
+
+ if (enable)
+ {
+ ypos = ((source [0] & 0x00ff) | ((source [1] & 0x0004) << 6) );
+ ypos = (((256 - ypos) & 0x1ff) - 16) ;
+ xpos = ((source [4] & 0x00ff) | ((source [1] & 0x0008) << 5) );
+ xpos = (((256 - xpos) & 0x1ff) - 16);
+ flipx = (source [2] & 0x0080 ) >> 7;
+ flipy = (source [2] & 0x0040 ) >> 6;
+ chain = (source [1] & 0x0002 ) >> 1;
+ chain += 1;
+ number = (source [3] & 0x00ff) | ((source [2] & 0x003f) << 8);
+ colourbank = (source [1] & 0x00f0) >> 4;
+
+ number &= ~(chain - 1);
+
+ if (flip_screen)
+ {
+ flipy = !flipy;
+ flipx = !flipx;
+ ypos=240-ypos;
+ xpos=240-xpos;
+ }
+
+ for (count=0;count<chain;count++)
+ {
+ if (flip_screen)
+ {
+ if (!flipy)
+ {
+ drawgfx(bitmap,gfx,number+count,colourbank,flipx,flipy,xpos,ypos+16*count,cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ drawgfx(bitmap,gfx,number+count,colourbank,flipx,flipy,xpos,ypos+(16*(chain-1))-(16*count),cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ else
+ {
+ if (!flipy)
+ {
+ drawgfx(bitmap,gfx,number+count,colourbank,flipx,flipy,xpos,ypos-(16*(chain-1))+(16*count),cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ drawgfx(bitmap,gfx,number+count,colourbank,flipx,flipy,xpos,ypos-16*count,cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+ }
+
+ source+=5;
+ }
+}
+
+/*******************************************************************************
+ Video Start and Refresh Functions
+********************************************************************************
+ Drawing Order is simple
+ BG0 - Back
+ SPR - Middle
+ FG0 - Front
+*******************************************************************************/
+
+
+VIDEO_START( wwfsstar )
+{
+ fg0_tilemap = tilemap_create(get_fg0_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+ tilemap_set_transparent_pen(fg0_tilemap,0);
+
+ bg0_tilemap = tilemap_create(get_bg0_tile_info,bg0_scan,TILEMAP_TYPE_PEN, 16, 16,32,32);
+ tilemap_set_transparent_pen(fg0_tilemap,0);
+}
+
+VIDEO_UPDATE( wwfsstar )
+{
+ tilemap_set_scrolly( bg0_tilemap, 0, wwfsstar_scrolly );
+ tilemap_set_scrollx( bg0_tilemap, 0, wwfsstar_scrollx );
+
+ tilemap_draw(bitmap,cliprect,bg0_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect );
+ tilemap_draw(bitmap,cliprect,fg0_tilemap,0,0);
+
+ return 0;
+}
diff --git a/src/mame/video/wwfwfest.c b/src/mame/video/wwfwfest.c
new file mode 100644
index 00000000000..a1aee8297f5
--- /dev/null
+++ b/src/mame/video/wwfwfest.c
@@ -0,0 +1,284 @@
+/*******************************************************************************
+ WWF Wrestlefest (C) 1991 Technos Japan (video/wwfwfest.c)
+********************************************************************************
+ driver by David Haywood
+
+ see (drivers/wwfwfest.c) for more notes
+*******************************************************************************/
+
+#include "driver.h"
+#include "includes/wwfwfest.h"
+
+static tilemap *fg0_tilemap, *bg0_tilemap, *bg1_tilemap;
+int wwfwfest_pri;
+int wwfwfest_bg0_scrollx, wwfwfest_bg0_scrolly, wwfwfest_bg1_scrollx, wwfwfest_bg1_scrolly;
+UINT16 *wwfwfest_fg0_videoram, *wwfwfest_bg0_videoram, *wwfwfest_bg1_videoram;
+static int sprite_xoff, bg0_dx, bg1_dx[2];
+
+/*******************************************************************************
+ Write Handlers
+********************************************************************************
+ for writes to Video Ram
+*******************************************************************************/
+
+WRITE16_HANDLER( wwfwfest_fg0_videoram_w )
+{
+ /* Videoram is 8 bit, upper & lower byte writes end up in the same place */
+ if (ACCESSING_MSB && ACCESSING_LSB) {
+ COMBINE_DATA(&wwfwfest_fg0_videoram[offset]);
+ } else if (ACCESSING_MSB) {
+ wwfwfest_fg0_videoram[offset]=(data>>8)&0xff;
+ } else {
+ wwfwfest_fg0_videoram[offset]=data&0xff;
+ }
+
+ tilemap_mark_tile_dirty(fg0_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( wwfwfest_bg0_videoram_w )
+{
+ COMBINE_DATA(&wwfwfest_bg0_videoram[offset]);
+ tilemap_mark_tile_dirty(bg0_tilemap,offset/2);
+}
+
+WRITE16_HANDLER( wwfwfest_bg1_videoram_w )
+{
+ COMBINE_DATA(&wwfwfest_bg1_videoram[offset]);
+ tilemap_mark_tile_dirty(bg1_tilemap,offset);
+}
+
+/*******************************************************************************
+ Tilemap Related Functions
+*******************************************************************************/
+static TILE_GET_INFO( get_fg0_tile_info )
+{
+ /*- FG0 RAM Format -**
+
+ 4 bytes per tile
+
+ ---- ---- tttt tttt ---- ---- ???? TTTT
+
+ C = Colour Bank (0-15)
+ T = Tile Number (0 - 4095)
+
+ other bits unknown / unused
+
+ basically the same as WWF Superstar's FG0 Ram but
+ more of it and the used bytes the other way around
+
+ **- End of Comments -*/
+
+ UINT16 *tilebase;
+ int tileno;
+ int colbank;
+ tilebase = &wwfwfest_fg0_videoram[tile_index*2];
+ tileno = (tilebase[0] & 0x00ff) | ((tilebase[1] & 0x000f) << 8);
+ colbank = (tilebase[1] & 0x00f0) >> 4;
+ SET_TILE_INFO(
+ 0,
+ tileno,
+ colbank,
+ 0);
+}
+
+static TILE_GET_INFO( get_bg0_tile_info )
+{
+ /*- BG0 RAM Format -**
+
+ 4 bytes per tile
+
+ ---- ---- fF-- CCCC ---- TTTT tttt tttt
+
+ C = Colour Bank (0-15)
+ T = Tile Number (0 - 4095)
+ f = Flip Y
+ F = Flip X
+
+ other bits unknown / unused
+
+ **- End of Comments -*/
+
+ UINT16 *tilebase;
+ int tileno,colbank;
+
+ tilebase = &wwfwfest_bg0_videoram[tile_index*2];
+ tileno = (tilebase[1] & 0x0fff);
+ colbank = (tilebase[0] & 0x000f);
+ SET_TILE_INFO(
+ 2,
+ tileno,
+ colbank,
+ TILE_FLIPYX((tilebase[0] & 0x00c0) >> 6));
+}
+
+static TILE_GET_INFO( get_bg1_tile_info )
+{
+ /*- BG1 RAM Format -**
+
+ 2 bytes per tile
+
+ CCCC TTTT tttt tttt
+
+ C = Colour Bank (0-15)
+ T = Tile Number (0 - 4095)
+
+ **- End of Comments -*/
+
+ UINT16 *tilebase;
+ int tileno;
+ int colbank;
+ tilebase = &wwfwfest_bg1_videoram[tile_index];
+ tileno = (tilebase[0] & 0x0fff);
+ colbank = (tilebase[0] & 0xf000) >> 12;
+ SET_TILE_INFO(
+ 3,
+ tileno,
+ colbank,
+ 0);
+}
+
+/*******************************************************************************
+ Sprite Related Functions
+********************************************************************************
+ sprite drawing could probably be improved a bit
+*******************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ /*- SPR RAM Format -**
+
+ 16 bytes per sprite
+
+ ---- ---- yyyy yyyy ---- ---- lllF fXYE ---- ---- nnnn nnnn ---- ---- NNNN NNNN
+ ---- ---- ---- CCCC ---- ---- xxxx xxxx ---- ---- ---- ---- ---- ---- ---- ----
+
+ Yy = sprite Y Position
+ Xx = sprite X Position
+ C = colour bank
+ f = flip Y
+ F = flip X
+ l = chain sprite
+ E = sprite enable
+ Nn = Sprite Number
+
+ other bits unused
+
+ **- End of Comments -*/
+
+ const gfx_element *gfx = machine->gfx[1];
+ UINT16 *source = buffered_spriteram16;
+ UINT16 *finish = source + 0x2000/2;
+
+ while( source<finish )
+ {
+ int xpos, ypos, colourbank, flipx, flipy, chain, enable, number, count;
+
+ enable = (source[1] & 0x0001);
+
+ if (enable) {
+ xpos = +(source[5] & 0x00ff) | (source[1] & 0x0004) << 6;
+ if (xpos>512-16) xpos -=512;
+ xpos += sprite_xoff;
+ ypos = (source[0] & 0x00ff) | (source[1] & 0x0002) << 7;
+ ypos = (256 - ypos) & 0x1ff;
+ ypos -= 16 ;
+ flipx = (source[1] & 0x0010) >> 4;
+ flipy = (source[1] & 0x0008) >> 3;
+ chain = (source[1] & 0x00e0) >> 5;
+ chain += 1;
+ number = (source[2] & 0x00ff) | (source[3] & 0x00ff) << 8;
+ colourbank = (source[4] & 0x000f);
+
+ if (flip_screen) {
+ if (flipy) flipy=0; else flipy=1;
+ if (flipx) flipx=0; else flipx=1;
+ ypos=240-ypos-sprite_xoff;
+ xpos=304-xpos;
+ }
+
+ for (count=0;count<chain;count++) {
+ if (flip_screen) {
+ if (!flipy) {
+ drawgfx(bitmap,gfx,number+count,colourbank,flipx,flipy,xpos,ypos+(16*(chain-1))-(16*count),cliprect,TRANSPARENCY_PEN,0);
+ } else {
+ drawgfx(bitmap,gfx,number+count,colourbank,flipx,flipy,xpos,ypos+16*count,cliprect,TRANSPARENCY_PEN,0);
+ }
+ } else {
+ if (flipy) {
+ drawgfx(bitmap,gfx,number+count,colourbank,flipx,flipy,xpos,ypos-(16*(chain-1))+(16*count),cliprect,TRANSPARENCY_PEN,0);
+ } else {
+ drawgfx(bitmap,gfx,number+count,colourbank,flipx,flipy,xpos,ypos-16*count,cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+ }
+ }
+ source+=8;
+ }
+}
+
+/*******************************************************************************
+ Video Start and Refresh Functions
+********************************************************************************
+ Draw Order / Priority seems to affect where the scroll values are used also.
+*******************************************************************************/
+
+VIDEO_START( wwfwfest )
+{
+ fg0_tilemap = tilemap_create(get_fg0_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,64,32);
+ bg1_tilemap = tilemap_create(get_bg1_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+ bg0_tilemap = tilemap_create(get_bg0_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 16, 16,32,32);
+
+ tilemap_set_transparent_pen(fg0_tilemap,0);
+ tilemap_set_transparent_pen(bg1_tilemap,0);
+ tilemap_set_transparent_pen(bg0_tilemap,0);
+
+ sprite_xoff = bg0_dx = bg1_dx[0] = bg1_dx[1] = 0;
+}
+
+VIDEO_START( wwfwfstb )
+{
+ video_start_wwfwfest(machine);
+
+ sprite_xoff = 2;
+ bg0_dx = bg1_dx[0] = -4;
+ bg1_dx[1] = -2;
+}
+
+VIDEO_UPDATE( wwfwfest )
+{
+ if (wwfwfest_pri == 0x0078) {
+ tilemap_set_scrolly( bg0_tilemap, 0, wwfwfest_bg0_scrolly );
+ tilemap_set_scrollx( bg0_tilemap, 0, wwfwfest_bg0_scrollx + bg0_dx);
+ tilemap_set_scrolly( bg1_tilemap, 0, wwfwfest_bg1_scrolly );
+ tilemap_set_scrollx( bg1_tilemap, 0, wwfwfest_bg1_scrollx + bg1_dx[0]);
+ } else {
+ tilemap_set_scrolly( bg1_tilemap, 0, wwfwfest_bg0_scrolly );
+ tilemap_set_scrollx( bg1_tilemap, 0, wwfwfest_bg0_scrollx + bg1_dx[1]);
+ tilemap_set_scrolly( bg0_tilemap, 0, wwfwfest_bg1_scrolly );
+ tilemap_set_scrollx( bg0_tilemap, 0, wwfwfest_bg1_scrollx + bg0_dx);
+ }
+
+ /* todo : which bits of pri are significant to the order */
+
+ if (wwfwfest_pri == 0x007b) {
+ tilemap_draw(bitmap,cliprect,bg0_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,fg0_tilemap,0,0);
+ }
+
+ if (wwfwfest_pri == 0x007c) {
+ tilemap_draw(bitmap,cliprect,bg0_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,fg0_tilemap,0,0);
+ }
+
+ if (wwfwfest_pri == 0x0078) {
+ tilemap_draw(bitmap,cliprect,bg1_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,bg0_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,fg0_tilemap,0,0);
+ }
+ return 0;
+}
diff --git a/src/mame/video/xain.c b/src/mame/video/xain.c
new file mode 100644
index 00000000000..52561bbc77d
--- /dev/null
+++ b/src/mame/video/xain.c
@@ -0,0 +1,275 @@
+/***************************************************************************
+
+ xain.c
+
+ The priority prom has 7 inputs:
+
+ A0: Text layer (MAP)
+ A1: Sprite layer (OBJ)
+ A2: BG1
+ A3: BG2
+ A4-A6: From CPU priority register
+
+ The 2 bit data output from the prom selects:
+
+ 0 - Text layer
+ 1 - Sprite layer
+ 2 - BG1
+ 3 - BG2
+
+ Decoding the prom manually gives the following rules:
+
+ PRI mode 0 - text (top) -> sprite -> bg1 -> bg2 (bottom)
+ PRI mode 1 - text (top) -> sprite -> bg2 -> bg1 (bottom)
+ PRI mode 2 - bg1 (top) -> sprite -> bg2 -> text (bottom)
+ PRI mode 3 - bg2 (top) -> sprite -> bg1 -> text (bottom)
+ PRI mode 4 - bg1 (top) -> sprite -> text -> bg2 (bottom)
+ PRI mode 5 - bg2 (top) -> sprite -> text -> bg1 (bottom)
+ PRI mode 6 - text (top) -> bg1 -> sprite -> bg2 (bottom)
+ PRI mode 7 - text (top) -> bg2 -> sprite -> bg1 (bottom)
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *xain_charram, *xain_bgram0, *xain_bgram1, xain_pri;
+
+static tilemap *char_tilemap, *bgram0_tilemap, *bgram1_tilemap;
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILEMAP_MAPPER( back_scan )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x0f) + ((row & 0x0f) << 4) + ((col & 0x10) << 4) + ((row & 0x10) << 5);
+}
+
+static TILE_GET_INFO( get_bgram0_tile_info )
+{
+ int attr = xain_bgram0[tile_index | 0x400];
+ SET_TILE_INFO(
+ 2,
+ xain_bgram0[tile_index] | ((attr & 7) << 8),
+ (attr & 0x70) >> 4,
+ (attr & 0x80) ? TILE_FLIPX : 0);
+}
+
+static TILE_GET_INFO( get_bgram1_tile_info )
+{
+ int attr = xain_bgram1[tile_index | 0x400];
+ SET_TILE_INFO(
+ 1,
+ xain_bgram1[tile_index] | ((attr & 7) << 8),
+ (attr & 0x70) >> 4,
+ (attr & 0x80) ? TILE_FLIPX : 0);
+}
+
+static TILE_GET_INFO( get_char_tile_info )
+{
+ int attr = xain_charram[tile_index | 0x400];
+ SET_TILE_INFO(
+ 0,
+ xain_charram[tile_index] | ((attr & 3) << 8),
+ (attr & 0xe0) >> 5,
+ 0);
+}
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( xain )
+{
+ bgram0_tilemap = tilemap_create(get_bgram0_tile_info,back_scan, TILEMAP_TYPE_PEN,16,16,32,32);
+ bgram1_tilemap = tilemap_create(get_bgram1_tile_info,back_scan, TILEMAP_TYPE_PEN,16,16,32,32);
+ char_tilemap = tilemap_create(get_char_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8, 8,32,32);
+
+ tilemap_set_transparent_pen(bgram0_tilemap,0);
+ tilemap_set_transparent_pen(bgram1_tilemap,0);
+ tilemap_set_transparent_pen(char_tilemap,0);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( xain_bgram0_w )
+{
+ xain_bgram0[offset] = data;
+ tilemap_mark_tile_dirty(bgram0_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( xain_bgram1_w )
+{
+ xain_bgram1[offset] = data;
+ tilemap_mark_tile_dirty(bgram1_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( xain_charram_w )
+{
+ xain_charram[offset] = data;
+ tilemap_mark_tile_dirty(char_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( xain_scrollxP0_w )
+{
+ static UINT8 xain_scrollxP0[2];
+
+ xain_scrollxP0[offset] = data;
+ tilemap_set_scrollx(bgram0_tilemap, 0, xain_scrollxP0[0]|(xain_scrollxP0[1]<<8));
+}
+
+WRITE8_HANDLER( xain_scrollyP0_w )
+{
+ static UINT8 xain_scrollyP0[2];
+
+ xain_scrollyP0[offset] = data;
+ tilemap_set_scrolly(bgram0_tilemap, 0, xain_scrollyP0[0]|(xain_scrollyP0[1]<<8));
+}
+
+WRITE8_HANDLER( xain_scrollxP1_w )
+{
+ static UINT8 xain_scrollxP1[2];
+
+ xain_scrollxP1[offset] = data;
+ tilemap_set_scrollx(bgram1_tilemap, 0, xain_scrollxP1[0]|(xain_scrollxP1[1]<<8));
+}
+
+WRITE8_HANDLER( xain_scrollyP1_w )
+{
+ static UINT8 xain_scrollyP1[2];
+
+ xain_scrollyP1[offset] = data;
+ tilemap_set_scrolly(bgram1_tilemap, 0, xain_scrollyP1[0]|(xain_scrollyP1[1]<<8));
+}
+
+
+WRITE8_HANDLER( xain_flipscreen_w )
+{
+ flip_screen_set(data & 1);
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0; offs < spriteram_size;offs += 4)
+ {
+ int sx,sy,flipx;
+ int attr = spriteram[offs+1];
+ int numtile = spriteram[offs+2] | ((attr & 7) << 8);
+ int color = (attr & 0x38) >> 3;
+
+ sx = 239 - spriteram[offs+3];
+ if (sx <= -7) sx += 256;
+ sy = 240 - spriteram[offs];
+ if (sy <= -7) sy += 256;
+ flipx = attr & 0x40;
+ if (flip_screen)
+ {
+ sx = 239 - sx;
+ sy = 240 - sy;
+ flipx = !flipx;
+ }
+
+ if (attr & 0x80) /* double height */
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ numtile,
+ color,
+ flipx,flip_screen,
+ sx-1,flip_screen?sy+16:sy-16,
+ cliprect,TRANSPARENCY_PEN,0);
+ drawgfx(bitmap,machine->gfx[3],
+ numtile+1,
+ color,
+ flipx,flip_screen,
+ sx-1,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ else
+ {
+ drawgfx(bitmap,machine->gfx[3],
+ numtile,
+ color,
+ flipx,flip_screen,
+ sx,sy,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+ }
+}
+
+VIDEO_UPDATE( xain )
+{
+ switch (xain_pri&0x7)
+ {
+ case 0:
+ tilemap_draw(bitmap,cliprect,bgram0_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,bgram1_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,char_tilemap,0,0);
+ break;
+ case 1:
+ tilemap_draw(bitmap,cliprect,bgram1_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,bgram0_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,char_tilemap,0,0);
+ break;
+ case 2:
+ tilemap_draw(bitmap,cliprect,char_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,bgram0_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bgram1_tilemap,0,0);
+ break;
+ case 3:
+ tilemap_draw(bitmap,cliprect,char_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,bgram1_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bgram0_tilemap,0,0);
+ break;
+ case 4:
+ tilemap_draw(bitmap,cliprect,bgram0_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,char_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bgram1_tilemap,0,0);
+ break;
+ case 5:
+ tilemap_draw(bitmap,cliprect,bgram1_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ tilemap_draw(bitmap,cliprect,char_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bgram0_tilemap,0,0);
+ break;
+ case 6:
+ tilemap_draw(bitmap,cliprect,bgram0_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bgram1_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,char_tilemap,0,0);
+ break;
+ case 7:
+ tilemap_draw(bitmap,cliprect,bgram1_tilemap,TILEMAP_DRAW_OPAQUE,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,bgram0_tilemap,0,0);
+ tilemap_draw(bitmap,cliprect,char_tilemap,0,0);
+ break;
+ }
+ return 0;
+}
diff --git a/src/mame/video/xevious.c b/src/mame/video/xevious.c
new file mode 100644
index 00000000000..45bbd4ae1b0
--- /dev/null
+++ b/src/mame/video/xevious.c
@@ -0,0 +1,518 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/galaga.h"
+
+
+UINT8 *xevious_fg_videoram,*xevious_fg_colorram;
+UINT8 *xevious_bg_videoram,*xevious_bg_colorram;
+UINT8 *xevious_sr1,*xevious_sr2,*xevious_sr3;
+
+static tilemap *fg_tilemap,*bg_tilemap;
+static INT32 xevious_bs[2];
+
+static colortable *xevious_colortable;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Xevious has three 256x4 palette PROMs (one per gun) and four 512x4 lookup
+ table PROMs (two for sprites, two for background tiles; foreground
+ characters map directly to a palette color without using a PROM).
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+PALETTE_INIT( xevious )
+{
+ int i;
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+
+ xevious_colortable = colortable_alloc(machine, 128+1);
+
+ for (i = 0;i < 128;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* green component */
+ bit0 = (color_prom[256] >> 0) & 0x01;
+ bit1 = (color_prom[256] >> 1) & 0x01;
+ bit2 = (color_prom[256] >> 2) & 0x01;
+ bit3 = (color_prom[256] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* blue component */
+ bit0 = (color_prom[2*256] >> 0) & 0x01;
+ bit1 = (color_prom[2*256] >> 1) & 0x01;
+ bit2 = (color_prom[2*256] >> 2) & 0x01;
+ bit3 = (color_prom[2*256] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ colortable_palette_set_color(xevious_colortable,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color 0x80 is used by sprites to mark transparency */
+ colortable_palette_set_color(xevious_colortable,0x80,MAKE_RGB(0,0,0));
+
+ color_prom += 128; /* the bottom part of the PROM is unused */
+ color_prom += 2*256;
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* background tiles */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ {
+ colortable_entry_set_value(xevious_colortable, machine->gfx[1]->color_base + i,
+ (color_prom[0] & 0x0f) | ((color_prom[TOTAL_COLORS(1)] & 0x0f) << 4));
+
+ color_prom++;
+ }
+ color_prom += TOTAL_COLORS(1);
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(2);i++)
+ {
+ int c = (color_prom[0] & 0x0f) | ((color_prom[TOTAL_COLORS(2)] & 0x0f) << 4);
+
+ colortable_entry_set_value(xevious_colortable, machine->gfx[2]->color_base + i,
+ (c & 0x80) ? (c & 0x7f) : 0x80);
+
+ color_prom++;
+ }
+ color_prom += TOTAL_COLORS(2);
+
+ /* foreground characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ {
+ colortable_entry_set_value(xevious_colortable, machine->gfx[0]->color_base + i,
+ (i % 2 != 0) ? (i / 2) : 0x80);
+ }
+}
+
+
+
+PALETTE_INIT( battles )
+{
+ int i;
+
+ xevious_colortable = colortable_alloc(machine, 128+1);
+
+ for (i = 0;i < 128;i++)
+ {
+ int bit0,bit1,bit2,bit3,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* green component */
+ bit0 = (color_prom[256] >> 0) & 0x01;
+ bit1 = (color_prom[256] >> 1) & 0x01;
+ bit2 = (color_prom[256] >> 2) & 0x01;
+ bit3 = (color_prom[256] >> 3) & 0x01;
+ g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+ /* blue component */
+ bit0 = (color_prom[2*256] >> 0) & 0x01;
+ bit1 = (color_prom[2*256] >> 1) & 0x01;
+ bit2 = (color_prom[2*256] >> 2) & 0x01;
+ bit3 = (color_prom[2*256] >> 3) & 0x01;
+ b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ colortable_palette_set_color(xevious_colortable,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+
+ /* color 0x80 is used by sprites to mark transparency */
+ colortable_palette_set_color(xevious_colortable,0x80,MAKE_RGB(0,0,0));
+
+ color_prom += 128; /* the bottom part of the PROM is unused */
+ color_prom += 2*256;
+ /* color_prom now points to the beginning of the lookup table */
+
+ /* background tiles */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ {
+ colortable_entry_set_value(xevious_colortable, machine->gfx[1]->color_base + i,
+ (color_prom[0] & 0x0f) | ((color_prom[0x400] & 0x0f) << 4));
+
+ color_prom++;
+ }
+ color_prom += 0x600;
+
+ /* sprites */
+ for (i = 0;i < TOTAL_COLORS(2);i++)
+ {
+ int c = (color_prom[0] & 0x0f) | ((color_prom[0x400] & 0x0f) << 4);
+
+ colortable_entry_set_value(xevious_colortable, machine->gfx[2]->color_base + i,
+ (c & 0x80) ? (c & 0x7f) : 0x80);
+
+ color_prom++;
+ }
+
+ /* foreground characters */
+ for (i = 0;i < TOTAL_COLORS(0);i++)
+ {
+ colortable_entry_set_value(xevious_colortable, machine->gfx[0]->color_base + i,
+ (i % 2 != 0) ? (i / 2) : 0x80);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ UINT8 attr = xevious_fg_colorram[tile_index];
+
+ /* the hardware has two character sets, one normal and one x-flipped. When
+ screen is flipped, character y flip is done by the hardware inverting the
+ timing signals, while x flip is done by selecting the 2nd character set.
+ We reproduce this here, but since the tilemap system automatically flips
+ characters when screen is flipped, we have to flip them back. */
+ UINT8 color = ((attr & 0x03) << 4) | ((attr & 0x3c) >> 2);
+ SET_TILE_INFO(
+ 0,
+ xevious_fg_videoram[tile_index] | (flip_screen ? 0x100 : 0),
+ color,
+ TILE_FLIPYX((attr & 0xc0) >> 6) ^ (flip_screen ? TILE_FLIPX : 0));
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ UINT8 code = xevious_bg_videoram[tile_index];
+ UINT8 attr = xevious_bg_colorram[tile_index];
+ UINT8 color = ((attr & 0x3c) >> 2) | ((code & 0x80) >> 3) | ((attr & 0x03) << 5);
+ SET_TILE_INFO(
+ 1,
+ code + ((attr & 0x01) << 8),
+ color,
+ TILE_FLIPYX((attr & 0xc0) >> 6));
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( xevious )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 8,8,64,32);
+ fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ tilemap_set_scrolldx(bg_tilemap,-20,288+27);
+ tilemap_set_scrolldy(bg_tilemap,-16,-16);
+ tilemap_set_scrolldx(fg_tilemap,-32,288+32);
+ tilemap_set_scrolldy(fg_tilemap,-18,-10);
+ tilemap_set_transparent_pen(fg_tilemap,0);
+
+ spriteram_2 = xevious_sr1 + 0x780;
+ spriteram_3 = xevious_sr2 + 0x780;
+ spriteram = xevious_sr3 + 0x780;
+
+ state_save_register_global_array(xevious_bs);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+READ8_HANDLER( xevious_fg_videoram_r )
+{
+ return xevious_fg_videoram[offset];
+}
+
+READ8_HANDLER( xevious_fg_colorram_r )
+{
+ return xevious_fg_colorram[offset];
+}
+
+READ8_HANDLER( xevious_bg_videoram_r )
+{
+ return xevious_bg_videoram[offset];
+}
+
+READ8_HANDLER( xevious_bg_colorram_r )
+{
+ return xevious_bg_colorram[offset];
+}
+
+WRITE8_HANDLER( xevious_fg_videoram_w )
+{
+ xevious_fg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE8_HANDLER( xevious_fg_colorram_w )
+{
+ xevious_fg_colorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap,offset);
+}
+
+WRITE8_HANDLER( xevious_bg_videoram_w )
+{
+ xevious_bg_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( xevious_bg_colorram_w )
+{
+ xevious_bg_colorram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset);
+}
+
+WRITE8_HANDLER( xevious_vh_latch_w )
+{
+ int reg;
+ int scroll = data + ((offset&0x01)<<8); /* A0 -> D8 */
+
+ reg = (offset&0xf0)>>4;
+
+ switch (reg)
+ {
+ case 0:
+ tilemap_set_scrollx(bg_tilemap,0,scroll);
+ break;
+ case 1:
+ tilemap_set_scrollx(fg_tilemap,0,scroll);
+ break;
+ case 2:
+ tilemap_set_scrolly(bg_tilemap,0,scroll);
+ break;
+ case 3:
+ tilemap_set_scrolly(fg_tilemap,0,scroll);
+ break;
+ case 7:
+ flip_screen_set(scroll & 1);
+ break;
+ default:
+ logerror("CRTC WRITE REG: %x Data: %03x\n",reg, scroll);
+ break;
+ }
+}
+
+
+/* emulation for schematic 9B */
+WRITE8_HANDLER( xevious_bs_w )
+{
+ xevious_bs[offset & 1] = data;
+}
+
+READ8_HANDLER( xevious_bb_r )
+{
+ UINT8 *rom2a = memory_region(REGION_GFX4);
+ UINT8 *rom2b = memory_region(REGION_GFX4)+0x1000;
+ UINT8 *rom2c = memory_region(REGION_GFX4)+0x3000;
+ int adr_2b,adr_2c;
+ int dat1,dat2;
+
+ /* get BS to 12 bit data from 2A,2B */
+ adr_2b = ((xevious_bs[1] & 0x7e) << 6) | ((xevious_bs[0] & 0xfe) >> 1);
+
+ if (adr_2b & 1)
+ {
+ /* high bits select */
+ dat1 = ((rom2a[adr_2b >> 1] & 0xf0) << 4) | rom2b[adr_2b];
+ }
+ else
+ {
+ /* low bits select */
+ dat1 = ((rom2a[adr_2b >> 1] & 0x0f) << 8) | rom2b[adr_2b];
+ }
+
+ adr_2c = ((dat1 & 0x1ff) << 2) | ((xevious_bs[1] & 1) << 1) | (xevious_bs[0] & 1);
+ if (dat1 & 0x400) adr_2c ^= 1;
+ if (dat1 & 0x200) adr_2c ^= 2;
+
+ if (offset & 1)
+ {
+ /* return BB1 */
+ dat2 = rom2c[adr_2c | 0x800];
+ }
+ else
+ {
+ /* return BB0 */
+ dat2 = rom2c[adr_2c];
+ /* swap bit 6 & 7 */
+ dat2 = BITSWAP8(dat2, 6,7,5,4,3,2,1,0);
+ /* flip x & y */
+ if (dat1 & 0x400) dat2 ^= 0x40;
+ if (dat1 & 0x200) dat2 ^= 0x80;
+ }
+ return dat2;
+}
+
+
+/*
+background pattern data
+
+colorram mapping
+b000-bfff background attribute
+ bit 0-1 COL:palette set select
+ bit 2-5 AN :color select
+ bit 6 AFF:Y flip
+ bit 7 PFF:X flip
+c000-cfff background pattern name
+ bit 0-7 PP0-7
+
+seet 8A
+ 2 +-------+
+COL0,1 -------------------------------------->|backg. |
+ 1 |color |
+PP7------------------------------------------>|replace|
+ 4 | ROM | 6
+AN0-3 --------------------------------------->| 4H |-----> color code 6 bit
+ 1 +-----------+ +--------+ | 4F |
+COL0 ---->|B8 ROM 3C| 16 |custom | 2 | |
+ 8 | |----->|shifter |----->| |
+PP0-7 ---->|B0-7 ROM 3D| |16->2*8 | | |
+ +-----------+ +--------+ +-------+
+
+font rom controller
+ 1 +-----+ +--------+
+ANF --->| ROM | 8 |shift | 1
+ 8 | 3B |---->|reg |-----> font data
+PP0-7 --->| | |8->1*8 |
+ +-----+ +--------+
+
+font color ( not use color map )
+ 2 |
+COL0-1 --->| color code 6 bit
+ 4 |
+AN0-3 --->|
+
+sprite
+
+ROM 3M,3L color replace table for sprite
+
+*/
+
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs,sx,sy;
+
+
+ for (offs = 0;offs < 0x80;offs += 2)
+ {
+ if ((spriteram[offs + 1] & 0x40) == 0) /* I'm not sure about this one */
+ {
+ int bank,code,color,flipx,flipy;
+ UINT32 transmask;
+
+ if (spriteram_3[offs] & 0x80)
+ {
+ bank = 2;
+ code = (spriteram[offs] & 0x3f) + 0x100;
+ }
+ else
+ {
+ bank = 2;
+ code = spriteram[offs];
+ }
+
+ color = spriteram[offs + 1] & 0x7f;
+ flipx = spriteram_3[offs] & 4;
+ flipy = spriteram_3[offs] & 8;
+ if (flip_screen)
+ {
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+ sx = spriteram_2[offs + 1] - 40 + 0x100*(spriteram_3[offs + 1] & 1);
+ sy = 28*8-spriteram_2[offs]-1;
+
+ transmask = colortable_get_transpen_mask(xevious_colortable, machine->gfx[bank], color, 0x80);
+
+ if (spriteram_3[offs] & 2) /* double height (?) */
+ {
+ if (spriteram_3[offs] & 1) /* double width, double height */
+ {
+ code &= ~3;
+ drawgfx(bitmap,machine->gfx[bank],
+ code+3,color,flipx,flipy,
+ flipx ? sx : sx+16,flipy ? sy-16 : sy,
+ cliprect,TRANSPARENCY_PENS,transmask);
+ drawgfx(bitmap,machine->gfx[bank],
+ code+1,color,flipx,flipy,
+ flipx ? sx : sx+16,flipy ? sy : sy-16,
+ cliprect,TRANSPARENCY_PENS,transmask);
+ }
+ code &= ~2;
+ drawgfx(bitmap,machine->gfx[bank],
+ code+2,color,flipx,flipy,
+ flipx ? sx+16 : sx,flipy ? sy-16 : sy,
+ cliprect,TRANSPARENCY_PENS,transmask);
+ drawgfx(bitmap,machine->gfx[bank],
+ code,color,flipx,flipy,
+ flipx ? sx+16 : sx,flipy ? sy : sy-16,
+ cliprect,TRANSPARENCY_PENS,transmask);
+ }
+ else if (spriteram_3[offs] & 1) /* double width */
+ {
+ code &= ~1;
+ drawgfx(bitmap,machine->gfx[bank],
+ code,color,flipx,flipy,
+ flipx ? sx+16 : sx,flipy ? sy-16 : sy,
+ cliprect,TRANSPARENCY_PENS,transmask);
+ drawgfx(bitmap,machine->gfx[bank],
+ code+1,color,flipx,flipy,
+ flipx ? sx : sx+16,flipy ? sy-16 : sy,
+ cliprect,TRANSPARENCY_PENS,transmask);
+ }
+ else /* normal */
+ {
+ drawgfx(bitmap,machine->gfx[bank],
+ code,color,flipx,flipy,sx,sy,
+ cliprect,TRANSPARENCY_PENS,transmask);
+ }
+ }
+ }
+}
+
+
+VIDEO_UPDATE( xevious )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+ draw_sprites(machine, bitmap,cliprect);
+ tilemap_draw(bitmap,cliprect,fg_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/xexex.c b/src/mame/video/xexex.c
new file mode 100644
index 00000000000..7c4a807168a
--- /dev/null
+++ b/src/mame/video/xexex.c
@@ -0,0 +1,143 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+static int sprite_colorbase;
+static int layer_colorbase[4], layerpri[4];
+static int cur_alpha;
+
+void xexex_set_alpha(int on)
+{
+ cur_alpha = on;
+}
+
+static void xexex_sprite_callback(int *code, int *color, int *priority_mask)
+{
+ int pri, c = *color;
+
+ // Xexex doesn't seem to use bit8 and 9 as effect selectors so this should be safe.
+ // (pdrawgfx() still needs change to fix Elaine's end-game graphics)
+ pri = (c & 0x3e0) >> 4;
+
+ if (pri <= layerpri[3]) *priority_mask = 0; else
+ if (pri > layerpri[3] && pri <= layerpri[2]) *priority_mask = 0xff00; else
+ if (pri > layerpri[2] && pri <= layerpri[1]) *priority_mask = 0xff00|0xf0f0; else
+ if (pri > layerpri[1] && pri <= layerpri[0]) *priority_mask = 0xff00|0xf0f0|0xcccc; else
+ *priority_mask = 0xff00|0xf0f0|0xcccc|0xaaaa;
+
+ *color = sprite_colorbase | (c & 0x001f);
+}
+
+static void xexex_tile_callback(int layer, int *code, int *color, int *flags)
+{
+ *color = layer_colorbase[layer] | (*color>>2 & 0x0f);
+}
+
+VIDEO_START( xexex )
+{
+ int region = REGION_GFX3;
+
+ assert(machine->screen[0].format == BITMAP_FORMAT_RGB32);
+
+ cur_alpha = 0;
+
+ K053251_vh_start();
+ K054338_vh_start();
+ K053250_vh_start(1, &region);
+
+ K056832_vh_start(machine,REGION_GFX1, K056832_BPP_4, 1, NULL, xexex_tile_callback, 0);
+ K053247_vh_start(machine,REGION_GFX2, -48, 32, NORMAL_PLANE_ORDER, xexex_sprite_callback);
+
+ // Xexex has relative plane offsets of -2,2,4,6 vs. -2,0,2,3 in MW and GX.
+ K056832_set_LayerOffset(0, -2, 16);
+ K056832_set_LayerOffset(1, 2, 16);
+ K056832_set_LayerOffset(2, 4, 16);
+ K056832_set_LayerOffset(3, 6, 16);
+
+ K053250_set_LayerOffset(0, -5,-16);
+
+ K054338_invert_alpha(0);
+}
+
+/* useful function to sort the four tile layers by priority order */
+/* suboptimal, but for such a size who cares ? */
+static void sortlayers(int *layer, int *pri)
+{
+#define SWAP(a,b) \
+ if (pri[a] < pri[b]) \
+ { \
+ int t; \
+ t = pri[a]; pri[a] = pri[b]; pri[b] = t; \
+ t = layer[a]; layer[a] = layer[b]; layer[b] = t; \
+ }
+
+ SWAP(0, 1)
+ SWAP(0, 2)
+ SWAP(0, 3)
+ SWAP(1, 2)
+ SWAP(1, 3)
+ SWAP(2, 3)
+}
+
+VIDEO_UPDATE( xexex )
+{
+ static const int K053251_CI[4] = { K053251_CI1, K053251_CI2, K053251_CI3, K053251_CI4 };
+ int layer[4];
+ int bg_colorbase, new_colorbase, plane, alpha;
+
+ sprite_colorbase = K053251_get_palette_index(K053251_CI0);
+ bg_colorbase = K053251_get_palette_index(K053251_CI1);
+ layer_colorbase[0] = 0x70;
+
+ for (plane=1; plane<4; plane++)
+ {
+ new_colorbase = K053251_get_palette_index(K053251_CI[plane]);
+ if (layer_colorbase[plane] != new_colorbase)
+ {
+ layer_colorbase[plane] = new_colorbase;
+ K056832_mark_plane_dirty(plane);
+ }
+ }
+
+ layer[0] = 1;
+ layerpri[0] = K053251_get_priority(K053251_CI2);
+ layer[1] = 2;
+ layerpri[1] = K053251_get_priority(K053251_CI3);
+ layer[2] = 3;
+ layerpri[2] = K053251_get_priority(K053251_CI4);
+ layer[3] = -1;
+ layerpri[3] = K053251_get_priority(K053251_CI1);
+
+ sortlayers(layer, layerpri);
+
+ K054338_update_all_shadows(machine);
+ K054338_fill_backcolor(machine, bitmap, 0);
+
+ fillbitmap(priority_bitmap, 0, cliprect);
+
+ for (plane=0; plane<4; plane++)
+ {
+ if (layer[plane] < 0)
+ {
+ K053250_draw(machine, bitmap, cliprect, 0, bg_colorbase, 0, 1<<plane);
+ }
+ else if (!cur_alpha || layer[plane] != 1)
+ {
+ K056832_tilemap_draw(machine, bitmap, cliprect, layer[plane], 0, 1<<plane);
+ }
+ }
+
+ K053247_sprites_draw(machine, bitmap, cliprect);
+
+ if (cur_alpha)
+ {
+ alpha = K054338_set_alpha_level(1);
+
+ if (alpha > 0)
+ {
+ K056832_tilemap_draw(machine, bitmap, cliprect, 1, (alpha >= 255) ? 0 : TILEMAP_DRAW_ALPHA, 0);
+ }
+ }
+
+ K056832_tilemap_draw(machine, bitmap, cliprect, 0, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/xmen.c b/src/mame/video/xmen.c
new file mode 100644
index 00000000000..f7e8e9cb488
--- /dev/null
+++ b/src/mame/video/xmen.c
@@ -0,0 +1,258 @@
+#include "driver.h"
+#include "video/konamiic.h"
+
+
+static int layer_colorbase[3],sprite_colorbase,bg_colorbase;
+static int layerpri[3];
+
+
+/***************************************************************************
+
+ Callbacks for the K052109
+
+***************************************************************************/
+
+static void xmen_tile_callback(int layer,int bank,int *code,int *color,int *flags,int *priority)
+{
+ /* (color & 0x02) is flip y handled internally by the 052109 */
+ if (layer == 0)
+ *color = layer_colorbase[layer] + ((*color & 0xf0) >> 4);
+ else
+ *color = layer_colorbase[layer] + ((*color & 0x7c) >> 2);
+}
+
+/***************************************************************************
+
+ Callbacks for the K053247
+
+***************************************************************************/
+
+static void xmen_sprite_callback(int *code,int *color,int *priority_mask)
+{
+ int pri = (*color & 0x00e0) >> 4; /* ??????? */
+ if (pri <= layerpri[2]) *priority_mask = 0;
+ else if (pri > layerpri[2] && pri <= layerpri[1]) *priority_mask = 0xf0;
+ else if (pri > layerpri[1] && pri <= layerpri[0]) *priority_mask = 0xf0|0xcc;
+ else *priority_mask = 0xf0|0xcc|0xaa;
+
+ *color = sprite_colorbase + (*color & 0x001f);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( xmen )
+{
+ K053251_vh_start();
+
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,xmen_tile_callback);
+ K053247_vh_start(machine,REGION_GFX2,53,-2,NORMAL_PLANE_ORDER,xmen_sprite_callback);
+}
+
+static mame_bitmap * screen_right;
+static mame_bitmap * screen_left;
+static UINT16 *K053247_ram;
+
+VIDEO_START( xmen6p )
+{
+ K053251_vh_start();
+
+ K052109_vh_start(machine,REGION_GFX1,NORMAL_PLANE_ORDER,xmen_tile_callback);
+ K053247_vh_start(machine,REGION_GFX2,53,-2,NORMAL_PLANE_ORDER,xmen_sprite_callback);
+ K053247_export_config(&K053247_ram, NULL, NULL, NULL, NULL);
+
+ screen_left = auto_bitmap_alloc(64*8, 32*8, BITMAP_FORMAT_INDEXED16);
+ screen_right = auto_bitmap_alloc(64*8, 32*8, BITMAP_FORMAT_INDEXED16);
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+/* useful function to sort the three tile layers by priority order */
+static void sortlayers(int *layer,int *pri)
+{
+#define SWAP(a,b) \
+ if (pri[a] < pri[b]) \
+ { \
+ int t; \
+ t = pri[a]; pri[a] = pri[b]; pri[b] = t; \
+ t = layer[a]; layer[a] = layer[b]; layer[b] = t; \
+ }
+
+ SWAP(0,1)
+ SWAP(0,2)
+ SWAP(1,2)
+}
+
+
+VIDEO_UPDATE( xmen )
+{
+ int layer[3];
+
+
+ bg_colorbase = K053251_get_palette_index(K053251_CI4);
+ sprite_colorbase = K053251_get_palette_index(K053251_CI1);
+ layer_colorbase[0] = K053251_get_palette_index(K053251_CI3);
+ layer_colorbase[1] = K053251_get_palette_index(K053251_CI0);
+ layer_colorbase[2] = K053251_get_palette_index(K053251_CI2);
+
+ K052109_tilemap_update();
+
+ layer[0] = 0;
+ layerpri[0] = K053251_get_priority(K053251_CI3);
+ layer[1] = 1;
+ layerpri[1] = K053251_get_priority(K053251_CI0);
+ layer[2] = 2;
+ layerpri[2] = K053251_get_priority(K053251_CI2);
+
+ sortlayers(layer,layerpri);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+ /* note the '+1' in the background color!!! */
+ fillbitmap(bitmap,machine->pens[16 * bg_colorbase+1],cliprect);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[0]],0,1);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[1]],0,2);
+ tilemap_draw(bitmap,cliprect,K052109_tilemap[layer[2]],0,4);
+
+ pdrawgfx_shadow_lowpri = 1; /* fix shadows of boulders in front of feet */
+ K053247_sprites_draw(machine, bitmap,cliprect);
+ return 0;
+}
+
+extern UINT16 xmen_current_frame;
+extern UINT16*xmen6p_spriteramleft;
+extern UINT16*xmen6p_spriteramright;
+extern UINT16*xmen6p_tilemapleft;
+extern UINT16*xmen6p_tilemapright;
+extern WRITE8_HANDLER( K052109_w );
+
+
+
+VIDEO_UPDATE( xmen6p )
+{
+ int x,y;
+ /* update every other frame ...help prevent screens lagging (although it still does..)..
+ but maybe the hw has its own buffering hence the extra ram */
+// if (xmen_current_frame&0x8000) /* actually don't bother */
+ {
+
+ for(y=0;y<32*8;y++)
+ {
+ UINT16* line_dest = BITMAP_ADDR16(bitmap, y, 0);
+ UINT16* line_src;
+
+ if (screen==0) line_src = BITMAP_ADDR16(screen_left, y, 0);
+ else line_src = BITMAP_ADDR16(screen_right, y, 0);
+
+ for (x=12*8;x<52*8;x++)
+ {
+ line_dest[x] = line_src[x];
+ }
+ }
+ }
+ return 0;
+}
+
+/* my lefts and rights are mixed up in several places.. */
+VIDEO_EOF( xmen6p )
+{
+ int layer[3];
+ mame_bitmap * renderbitmap;
+ rectangle cliprect;
+ int offset;
+
+ xmen_current_frame ^=0x8000;
+
+// cliprect.min_x = machine->screen[0].visarea.min_x;
+// cliprect.max_x = machine->screen[0].visarea.max_x;
+// cliprect.min_y = machine->screen[0].visarea.min_y;
+// cliprect.max_y = machine->screen[0].visarea.max_y;
+
+ cliprect.min_x = 0;
+ cliprect.max_x = 64*8-1;
+ cliprect.min_y = 2*8;
+ cliprect.max_y = 30*8-1;
+
+
+
+
+ if (xmen_current_frame&0x8000)
+ {
+
+ /* copy the desired spritelist to the chip */
+ memcpy(K053247_ram,xmen6p_spriteramright,0x1000);
+ /* we write the entire content of the tileram to the chip to ensure
+ everything gets marked as dirty and the desired tilemap is rendered
+
+ this is not very efficient!
+ */
+ for (offset=0;offset<(0xc000/2);offset++)
+ {
+// K052109_lsb_w
+ K052109_w(offset,xmen6p_tilemapright[offset]&0x00ff);
+ }
+
+
+ renderbitmap = screen_right;
+ }
+ else
+ {
+ /* copy the desired spritelist to the chip */
+ memcpy(K053247_ram,xmen6p_spriteramleft,0x1000);
+
+ /* we write the entire content of the tileram to the chip to ensure
+ everything gets marked as dirty and the desired tilemap is rendered
+
+ this is not very efficient!
+ */
+ for (offset=0;offset<(0xc000/2);offset++)
+ {
+// K052109_lsb_w
+ K052109_w(offset,xmen6p_tilemapleft[offset]&0x00ff);
+ }
+
+
+
+
+ renderbitmap = screen_left;
+ }
+
+
+ bg_colorbase = K053251_get_palette_index(K053251_CI4);
+ sprite_colorbase = K053251_get_palette_index(K053251_CI1);
+ layer_colorbase[0] = K053251_get_palette_index(K053251_CI3);
+ layer_colorbase[1] = K053251_get_palette_index(K053251_CI0);
+ layer_colorbase[2] = K053251_get_palette_index(K053251_CI2);
+
+ K052109_tilemap_update();
+
+ layer[0] = 0;
+ layerpri[0] = K053251_get_priority(K053251_CI3);
+ layer[1] = 1;
+ layerpri[1] = K053251_get_priority(K053251_CI0);
+ layer[2] = 2;
+ layerpri[2] = K053251_get_priority(K053251_CI2);
+
+ sortlayers(layer,layerpri);
+
+ fillbitmap(priority_bitmap,0,&cliprect);
+ /* note the '+1' in the background color!!! */
+ fillbitmap(renderbitmap,machine->pens[16 * bg_colorbase+1],&cliprect);
+ tilemap_draw(renderbitmap,&cliprect,K052109_tilemap[layer[0]],0,1);
+ tilemap_draw(renderbitmap,&cliprect,K052109_tilemap[layer[1]],0,2);
+ tilemap_draw(renderbitmap,&cliprect,K052109_tilemap[layer[2]],0,4);
+
+ pdrawgfx_shadow_lowpri = 1; /* fix shadows of boulders in front of feet */
+ K053247_sprites_draw(machine, renderbitmap,&cliprect);
+
+}
+
diff --git a/src/mame/video/xorworld.c b/src/mame/video/xorworld.c
new file mode 100644
index 00000000000..aa24f61bc72
--- /dev/null
+++ b/src/mame/video/xorworld.c
@@ -0,0 +1,115 @@
+#include "driver.h"
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Xor World has three 256x4 palette PROMs (one per gun).
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 460 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+
+PALETTE_INIT( xorworld )
+{
+ int i;
+
+ for (i = 0;i < machine->drv->total_colors;i++){
+ int bit0,bit1,bit2,bit3;
+ int r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ bit3 = (color_prom[0] >> 3) & 0x01;
+ r = 0x0e*bit0 + 0x1e*bit1 + 0x44*bit2 + 0x8f*bit3;
+ /* green component */
+ bit0 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ g = 0x0e*bit0 + 0x1e*bit1 + 0x44*bit2 + 0x8f*bit3;
+ /* blue component */
+ bit0 = (color_prom[2*machine->drv->total_colors] >> 0) & 0x01;
+ bit1 = (color_prom[2*machine->drv->total_colors] >> 1) & 0x01;
+ bit2 = (color_prom[2*machine->drv->total_colors] >> 2) & 0x01;
+ bit3 = (color_prom[2*machine->drv->total_colors] >> 3) & 0x01;
+ b = 0x0e*bit0 + 0x1e * bit1 + 0x44*bit2 + 0x8f*bit3;
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+}
+
+WRITE16_HANDLER( xorworld_videoram16_w )
+{
+ COMBINE_DATA(&videoram16[offset]);
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+/*
+ Tile format
+ -----------
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | ----xxxx xxxxxxxx | code
+ 0 | xxxx---- -------- | color
+*/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int data = videoram16[tile_index];
+ int code = data & 0x0fff;
+
+ SET_TILE_INFO(0, code, data >> 12, 0);
+}
+
+VIDEO_START( xorworld )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+/*
+ Sprite Format
+ -------------
+
+ Word | Bit(s) | Description
+ -----+-FEDCBA98-76543210-+--------------------------
+ 0 | -------- xxxxxxxx | x position
+ 0 | xxxxxxxx -------- | y position
+ 1 | -------- ------xx | flipxy? (not used)
+ 1 | ----xxxx xxxxxx-- | sprite number
+ 1 | xxxx---- -------- | sprite color
+*/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int i;
+
+ for (i = 0; i < 0x40; i += 2)
+ {
+ int sx = spriteram16[i] & 0x00ff;
+ int sy = 240 - (((spriteram16[i] & 0xff00) >> 8) & 0xff);
+ int code = (spriteram16[i+1] & 0x0ffc) >> 2;
+ int color = (spriteram16[i+1] & 0xf000) >> 12;
+
+ drawgfx(bitmap, machine->gfx[1], code, color, 0, 0, sx, sy,
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( xorworld )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/xxmissio.c b/src/mame/video/xxmissio.c
new file mode 100644
index 00000000000..3ded80d1310
--- /dev/null
+++ b/src/mame/video/xxmissio.c
@@ -0,0 +1,201 @@
+/*******************************************************************************
+
+XX Mission (c) 1986 UPL
+
+Video hardware driver by Uki
+
+ 31/Mar/2001 -
+
+*******************************************************************************/
+
+#include "driver.h"
+
+UINT8 *xxmissio_fgram;
+
+static UINT8 xxmissio_xscroll,xxmissio_yscroll;
+static UINT8 flipscreen;
+static UINT8 xxmissio_bg_redraw;
+
+
+WRITE8_HANDLER( xxmissio_scroll_x_w )
+{
+ xxmissio_xscroll = data;
+}
+WRITE8_HANDLER( xxmissio_scroll_y_w )
+{
+ xxmissio_yscroll = data;
+}
+
+WRITE8_HANDLER( xxmissio_flipscreen_w )
+{
+ if ((data & 0x01) != flipscreen)
+ {
+ flipscreen = data & 0x01;
+ xxmissio_bg_redraw = 1;
+ }
+}
+
+WRITE8_HANDLER( xxmissio_videoram_w )
+{
+ int offs = offset & 0x7e0;
+ int x = (offset + (xxmissio_xscroll >> 3) ) & 0x1f;
+ offs |= x;
+
+ videoram[offs] = data;
+ dirtybuffer[offs & 0x3ff] = 1;
+}
+READ8_HANDLER( xxmissio_videoram_r )
+{
+ int offs = offset & 0x7e0;
+ int x = (offset + (xxmissio_xscroll >> 3) ) & 0x1f;
+ offs |= x;
+
+ return videoram[offs];
+}
+
+WRITE8_HANDLER( xxmissio_paletteram_w )
+{
+ paletteram_BBGGRRII_w(offset,data);
+
+ if (offset >= 0x200)
+ xxmissio_bg_redraw = 1;
+}
+
+/****************************************************************************/
+
+VIDEO_UPDATE( xxmissio )
+{
+ int offs;
+ int chr,col;
+ int x,y,px,py,fx,fy,sx,sy;
+
+ int size = videoram_size/2;
+
+ if (xxmissio_bg_redraw==1)
+ memset(dirtybuffer,1,size);
+
+/* draw BG layer */
+
+ for (y=0; y<32; y++)
+ {
+ for (x=0; x<32; x++)
+ {
+ offs = y*0x20 + x;
+
+ if (flipscreen!=0)
+ offs = (size-1)-offs;
+
+ if (dirtybuffer[offs] != 0)
+ {
+ dirtybuffer[offs]=0;
+
+ px = x*16;
+ py = y*8;
+
+ chr = videoram[ offs ] ;
+ col = videoram[ offs + size];
+ chr = chr + ((col & 0xc0) << 2 );
+ col = col & 0x0f;
+
+ drawgfx(tmpbitmap,machine->gfx[2],
+ chr,
+ col,
+ flipscreen,flipscreen,
+ px,py,
+ &machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ }
+ }
+ }
+
+ if (flipscreen == 0)
+ {
+ sx = -xxmissio_xscroll*2+12;
+ sy = -xxmissio_yscroll;
+ }
+ else
+ {
+ sx = xxmissio_xscroll*2+2;
+ sy = xxmissio_yscroll;
+ }
+
+ copyscrollbitmap(bitmap,tmpbitmap,1,&sx,1,&sy,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+ xxmissio_bg_redraw = 0;
+
+/* draw sprites */
+
+ for (offs=0; offs<spriteram_size; offs +=32)
+ {
+ chr = spriteram[offs];
+ col = spriteram[offs+3];
+
+ fx = ((col & 0x10) >> 4) ^ flipscreen;
+ fy = ((col & 0x20) >> 5) ^ flipscreen;
+
+ x = spriteram[offs+1]*2;
+ y = spriteram[offs+2];
+
+ chr = chr + ((col & 0x40) << 2);
+ col = col & 0x07;
+
+ if (flipscreen==0)
+ {
+ px = x-8;
+ py = y;
+ }
+ else
+ {
+ px = 480-x-8;
+ py = 240-y;
+ }
+
+ px &= 0x1ff;
+
+ drawgfx(bitmap,machine->gfx[1],
+ chr,
+ col,
+ fx,fy,
+ px,py,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ if (px>0x1e0)
+ drawgfx(bitmap,machine->gfx[1],
+ chr,
+ col,
+ fx,fy,
+ px-0x200,py,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+
+ }
+
+
+/* draw FG layer */
+
+ for (y=4; y<28; y++)
+ {
+ for (x=0; x<32; x++)
+ {
+ offs = y*32+x;
+ chr = xxmissio_fgram[offs];
+ col = xxmissio_fgram[offs + 0x400] & 0x07;
+
+ if (flipscreen==0)
+ {
+ px = 16*x;
+ py = 8*y;
+ }
+ else
+ {
+ px = 496-16*x;
+ py = 248-8*y;
+ }
+
+ drawgfx(bitmap,machine->gfx[0],
+ chr,
+ col,
+ flipscreen,flipscreen,
+ px,py,
+ &machine->screen[0].visarea,TRANSPARENCY_PEN,0);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/mame/video/xybots.c b/src/mame/video/xybots.c
new file mode 100644
index 00000000000..f965f06a03c
--- /dev/null
+++ b/src/mame/video/xybots.c
@@ -0,0 +1,166 @@
+/***************************************************************************
+
+ Atari Xybots hardware
+
+****************************************************************************/
+
+#include "driver.h"
+#include "machine/atarigen.h"
+#include "includes/xybots.h"
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_alpha_tile_info )
+{
+ UINT16 data = atarigen_alpha[tile_index];
+ int code = data & 0x3ff;
+ int color = (data >> 12) & 7;
+ int opaque = data & 0x8000;
+ SET_TILE_INFO(2, code, color, opaque ? TILE_FORCE_LAYER0 : 0);
+}
+
+
+static TILE_GET_INFO( get_playfield_tile_info )
+{
+ UINT16 data = atarigen_playfield[tile_index];
+ int code = data & 0x1fff;
+ int color = (data >> 11) & 0x0f;
+ SET_TILE_INFO(0, code, color, (data >> 15) & 1);
+}
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( xybots )
+{
+ static const struct atarimo_desc modesc =
+ {
+ 1, /* index to which gfx system */
+ 1, /* number of motion object banks */
+ 0, /* are the entries linked? */
+ 0, /* are the entries split? */
+ 0, /* render in reverse order? */
+ 0, /* render in swapped X/Y order? */
+ 0, /* does the neighbor bit affect the next object? */
+ 0, /* pixels per SLIP entry (0 for no-slip) */
+ 0, /* pixel offset for SLIPs */
+ 0, /* maximum number of links to visit/scanline (0=all) */
+
+ 0x100, /* base palette entry */
+ 0x300, /* maximum number of colors */
+ 0, /* transparent pen index */
+
+ {{ 0x3f }}, /* mask for the link (dummy) */
+ {{ 0 }}, /* mask for the graphics bank */
+ {{ 0x3fff,0,0,0 }}, /* mask for the code index */
+ {{ 0 }}, /* mask for the upper code index */
+ {{ 0,0,0,0x000f }}, /* mask for the color */
+ {{ 0,0,0,0xff80 }}, /* mask for the X position */
+ {{ 0,0,0xff80,0 }}, /* mask for the Y position */
+ {{ 0 }}, /* mask for the width, in tiles*/
+ {{ 0,0,0x0007,0 }}, /* mask for the height, in tiles */
+ {{ 0x8000,0,0,0 }}, /* mask for the horizontal flip */
+ {{ 0 }}, /* mask for the vertical flip */
+ {{ 0,0x000f,0,0 }}, /* mask for the priority */
+ {{ 0 }}, /* mask for the neighbor */
+ {{ 0 }}, /* mask for absolute coordinates */
+
+ {{ 0 }}, /* mask for the special value */
+ 0, /* resulting value to indicate "special" */
+ NULL /* callback routine for special entries */
+ };
+
+ /* initialize the playfield */
+ atarigen_playfield_tilemap = tilemap_create(get_playfield_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+
+ /* initialize the motion objects */
+ atarimo_init(machine, 0, &modesc);
+
+ /* initialize the alphanumerics */
+ atarigen_alpha_tilemap = tilemap_create(get_alpha_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ tilemap_set_transparent_pen(atarigen_alpha_tilemap, 0);
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( xybots )
+{
+ struct atarimo_rect_list rectlist;
+ mame_bitmap *mobitmap;
+ int x, y, r;
+
+ /* draw the playfield */
+ tilemap_draw(bitmap, cliprect, atarigen_playfield_tilemap, 0, 0);
+
+ /* draw and merge the MO */
+ mobitmap = atarimo_render(machine, 0, cliprect, &rectlist);
+ for (r = 0; r < rectlist.numrects; r++, rectlist.rect++)
+ for (y = rectlist.rect->min_y; y <= rectlist.rect->max_y; y++)
+ {
+ UINT16 *mo = (UINT16 *)mobitmap->base + mobitmap->rowpixels * y;
+ UINT16 *pf = (UINT16 *)bitmap->base + bitmap->rowpixels * y;
+ for (x = rectlist.rect->min_x; x <= rectlist.rect->max_x; x++)
+ if (mo[x])
+ {
+ /* verified via schematics:
+
+ PRIEN = ~(~MOPIX3 & ~MOPIX2 & ~MOPIX1) = (MOPIX3-0 > 1)
+
+ if (PRIEN)
+ PF/MO = (~MOPRI3-0 > PFCOL3-0)
+ else
+ PF/MO = (~MOPRI3-0 >= PFCOL3-0)
+
+ if (PF/MO | ~(PRIEN & MOCOL3))
+ GPC(P3-0) = PFPIX3-0
+ else
+ GPC(P3-0) = ~MOCOL3-0
+ */
+ int mopriority = (mo[x] >> ATARIMO_PRIORITY_SHIFT) ^ 15;
+ int pfcolor = (pf[x] >> 4) & 0x0f;
+ int prien = ((mo[x] & 0x0f) > 1);
+
+ if (prien)
+ {
+ if (mopriority <= pfcolor)
+ {
+ /* this first case doesn't make sense from the schematics, but it has */
+ /* the correct effect */
+ if (mo[x] & 0x80)
+ pf[x] = (mo[x] ^ 0x2f0) & ATARIMO_DATA_MASK;
+ else
+ pf[x] = mo[x] & ATARIMO_DATA_MASK;
+ }
+ }
+ else
+ {
+ if (mopriority < pfcolor)
+ pf[x] = mo[x] & ATARIMO_DATA_MASK;
+ }
+
+ /* erase behind ourselves */
+ mo[x] = 0;
+ }
+ }
+
+ /* add the alpha on top */
+ tilemap_draw(bitmap, cliprect, atarigen_alpha_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/xyonix.c b/src/mame/video/xyonix.c
new file mode 100644
index 00000000000..f7f8b6ee77d
--- /dev/null
+++ b/src/mame/video/xyonix.c
@@ -0,0 +1,63 @@
+
+#include "driver.h"
+
+extern UINT8 *xyonix_vidram;
+
+static tilemap *xyonix_tilemap;
+
+
+PALETTE_INIT( xyonix )
+{
+ int i;
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[i] >> 5) & 0x01;
+ bit1 = (color_prom[i] >> 6) & 0x01;
+ bit2 = (color_prom[i] >> 7) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ b = 0x4f * bit0 + 0xa8 * bit1;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+}
+
+
+static TILE_GET_INFO( get_xyonix_tile_info )
+{
+ int tileno;
+ int attr = xyonix_vidram[tile_index+0x1000+1];
+
+ tileno = (xyonix_vidram[tile_index+1] << 0) | ((attr & 0x0f) << 8);
+
+ SET_TILE_INFO(0,tileno,attr >> 4,0);
+}
+
+WRITE8_HANDLER( xyonix_vidram_w )
+{
+ xyonix_vidram[offset] = data;
+ tilemap_mark_tile_dirty(xyonix_tilemap,(offset-1)&0x0fff);
+}
+
+VIDEO_START(xyonix)
+{
+ xyonix_tilemap = tilemap_create(get_xyonix_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN, 4, 8,80,32);
+}
+
+VIDEO_UPDATE(xyonix)
+{
+ tilemap_draw(bitmap,cliprect,xyonix_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/yard.c b/src/mame/video/yard.c
new file mode 100644
index 00000000000..5aafaa79b7d
--- /dev/null
+++ b/src/mame/video/yard.c
@@ -0,0 +1,281 @@
+/***************************************************************************
+
+ video.c
+
+ 10 Yard Fight
+
+L Taylor
+J Clegg
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT8 *yard_scroll_x_low;
+UINT8 *yard_scroll_x_high;
+UINT8 *yard_scroll_y_low;
+UINT8 *yard_score_panel_disabled;
+static mame_bitmap *scroll_panel_bitmap;
+
+static tilemap *bg_tilemap;
+
+#define SCROLL_PANEL_WIDTH (14*4)
+#define RADAR_PALETTE_BASE (256+16)
+#define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+#define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+static rectangle clippanel =
+{
+ 26*8, 32*8-1,
+ 1*8, 31*8-1
+};
+
+static rectangle clippanelflip =
+{
+ 0*8, 6*8-1,
+ 1*8, 31*8-1
+};
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ 10 Yard Fight has two 256x4 character palette PROMs, one 32x8 sprite
+ palette PROM, one 256x4 sprite color lookup table PROM, and two 256x4
+ radar palette PROMs.
+
+ I don't know for sure how the palette PROMs are connected to the RGB
+ output, but it's probably something like this; note that RED and BLUE
+ are swapped wrt the usual configuration.
+
+ bit 7 -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ bit 0 -- 1 kohm resistor -- BLUE
+
+***************************************************************************/
+PALETTE_INIT( yard )
+{
+ int i;
+
+ /* character palette */
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = 0;
+ bit1 = (color_prom[256] >> 2) & 0x01;
+ bit2 = (color_prom[256] >> 3) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[0] >> 3) & 0x01;
+ bit1 = (color_prom[256] >> 0) & 0x01;
+ bit2 = (color_prom[256] >> 1) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+
+ color_prom += 256;
+ /* color_prom now points to the beginning of the sprite palette */
+
+ /* sprite palette */
+ for (i = 0;i < 16;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i+256,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+
+ color_prom += 16;
+ /* color_prom now points to the beginning of the sprite lookup table */
+
+ /* sprite lookup table */
+ for (i = 0;i < TOTAL_COLORS(1);i++)
+ COLOR(1,i) = 256 + (*(color_prom++) & 0x0f);
+
+ /* color_prom now points to the beginning of the radar palette */
+
+ /* radar palette */
+ for (i = 0;i < 256;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = 0;
+ bit1 = (color_prom[256] >> 2) & 0x01;
+ bit2 = (color_prom[256] >> 3) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* green component */
+ bit0 = (color_prom[0] >> 3) & 0x01;
+ bit1 = (color_prom[256] >> 0) & 0x01;
+ bit2 = (color_prom[256] >> 1) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+ /* blue component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[0] >> 1) & 0x01;
+ bit2 = (color_prom[0] >> 2) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i+256+16,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( yard_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+WRITE8_HANDLER( yard_scroll_panel_w )
+{
+ int sx,sy,i;
+
+ sx = ( offset % 16 );
+ sy = ( offset / 16 );
+
+ if (sx < 1 || sx > 14) return;
+
+ sx = 4 * (sx - 1);
+
+ for (i = 0;i < 4;i++)
+ {
+ int col;
+
+ col = (data >> i) & 0x11;
+ col = ((col >> 3) | col) & 3;
+
+ *BITMAP_ADDR16(scroll_panel_bitmap, sy, sx + i) = Machine->pens[RADAR_PALETTE_BASE + (sy & 0xfc) + col];
+ }
+}
+
+static TILE_GET_INFO( yard_get_bg_tile_info )
+{
+ int offs = tile_index * 2;
+ int attr = videoram[offs + 1];
+ int code = videoram[offs] + ((attr & 0xc0) << 2);
+ int color = attr & 0x1f;
+ int flags = (attr & 0x20) ? TILE_FLIPX : 0;
+
+ SET_TILE_INFO(0, code, color, flags);
+}
+
+static UINT32 yard_tilemap_scan_rows( UINT32 col, UINT32 row, UINT32 num_cols, UINT32 num_rows )
+{
+ /* logical (col,row) -> memory offset */
+ if (col >= 32)
+ return (row+32)*32 + col-32;
+ else
+ return row*32 + col;
+}
+
+VIDEO_START( yard )
+{
+ bg_tilemap = tilemap_create(yard_get_bg_tile_info, yard_tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 64, 32);
+
+ scroll_panel_bitmap = auto_bitmap_alloc(SCROLL_PANEL_WIDTH, machine->screen[0].height, machine->screen[0].format);
+}
+
+#define DRAW_SPRITE(code, sy) drawgfx(bitmap, machine->gfx[1], code, color, flipx, flipy, sx, sy, cliprect, TRANSPARENCY_COLOR, 256);
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ int offs;
+
+ for (offs = spriteram_size - 4; offs >= 0; offs -= 4)
+ {
+ int attr = spriteram[offs + 1];
+ int bank = (attr & 0x20) >> 5;
+ int code1 = spriteram[offs + 2] & 0xbf;
+ int code2 = 0;
+ int color = attr & 0x1f;
+ int flipx = attr & 0x40;
+ int flipy = attr & 0x80;
+ int sx = spriteram[offs + 3];
+ int sy1 = 241 - spriteram[offs];
+ int sy2 = 0;
+
+ if (flipy)
+ {
+ code2 = code1;
+ code1 += 0x40;
+ }
+ else
+ {
+ code2 = code1 + 0x40;
+ }
+
+ if (flip_screen)
+ {
+ sx = 240 - sx;
+ sy2 = 224 - sy1;
+ sy1 = sy2 + 0x10;
+ flipx = !flipx;
+ flipy = !flipy;
+ }
+ else
+ {
+ sy2 = sy1 + 0x10;
+ }
+
+ DRAW_SPRITE(code1 + 256 * bank, sy1)
+ DRAW_SPRITE(code2 + 256 * bank, sy2)
+ }
+}
+
+static void draw_panel( mame_bitmap *bitmap, const rectangle *cliprect )
+{
+ if (! *yard_score_panel_disabled)
+ {
+ int sx = flip_screen ? cliprect->min_x - 8 : cliprect->max_x + 1 - SCROLL_PANEL_WIDTH;
+
+ copybitmap(bitmap, scroll_panel_bitmap, flip_screen, flip_screen, sx, 0,
+ flip_screen ? &clippanelflip : &clippanel, TRANSPARENCY_NONE, 0);
+ }
+}
+
+VIDEO_UPDATE( yard )
+{
+ tilemap_set_scrollx(bg_tilemap, 0, (*yard_scroll_x_high * 0x100) + *yard_scroll_x_low);
+ tilemap_set_scrolly(bg_tilemap, 0, *yard_scroll_y_low);
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ draw_panel(bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/ygv608.c b/src/mame/video/ygv608.c
new file mode 100644
index 00000000000..ec17121c800
--- /dev/null
+++ b/src/mame/video/ygv608.c
@@ -0,0 +1,1801 @@
+
+/*
+ * Yamaha YGV608 - PVDC2 Pattern mode Video Display Controller 2
+ * - Mark McDougall
+ *
+ * Notes:
+ * ======
+ *
+ * This implementation is far from complete.
+ * There's enough here to emulate Namco ND-1 games.
+ * Some functionality is missing, some is incomplete.
+ * Also missing for ND-1 is rotation and scaling (cosmetic only).
+ *
+ * It could also do with some optimisation for speed!
+ *
+ * (Still lots of debugging info/options in here!)
+ *
+ * TODO: soon
+ * create tilemaps at vh_start time and switch between at runtime
+ * mark tiles dirty when VRAM is written to instead of dirtying entire
+ * screen each frame
+ *
+ * T.B.D. (not critical to ND-1)
+ * ======
+ *
+ * Rotation
+ * Scaling
+ * Split-screen scrolling by row (by column supported) (see test mode)
+ * Everything else! :)
+ */
+
+#include <ctype.h>
+#include "driver.h"
+#include "namcond1.h" // only while debugging
+#include "video/ygv608.h"
+
+#define _ENABLE_SPRITES
+#define _ENABLE_SCROLLX
+#define _ENABLE_SCROLLY
+//#define _ENABLE_SCREEN_RESIZE
+//#define _ENABLE_ROTATE_ZOOM
+//#define _SHOW_VIDEO_DEBUG
+
+static YGV608 ygv608;
+
+static tilemap *tilemap_A_cache_8[3];
+static tilemap *tilemap_A_cache_16[3];
+static tilemap *tilemap_B_cache_8[3];
+static tilemap *tilemap_B_cache_16[3];
+static tilemap *tilemap_A = NULL;
+static tilemap *tilemap_B = NULL;
+static mame_bitmap *work_bitmap = NULL;
+
+static void HandleYGV608Reset( void );
+static void HandleRomTransfers( void );
+static void SetPreShortcuts( int reg, int data );
+static void SetPostShortcuts( int reg );
+
+#ifdef MAME_DEBUG
+static void ShowYGV608Registers( void );
+#endif
+
+/* interrupt generated every 1ms second */
+INTERRUPT_GEN( ygv608_timed_interrupt )
+{
+/*
+ this is not quite generic, because we trigger a 68k interrupt
+ - if this chip is ever used by another driver, we should make
+ this more generic - or move it into the machine driver
+*/
+
+ static int timer = 0;
+
+ if( ++timer == 1000 )
+ timer = 0;
+
+ /* once every 60Hz, set the vertical border interval start flag */
+ if( ( timer % (1000/60) ) == 0 )
+ {
+ ygv608.ports.s.p6 |= p6_fv;
+ if (ygv608.regs.s.r14 & r14_iev)
+ irq2_line_hold();
+ }
+
+ /* once every 60Hz, set the position detection flag (somewhere) */
+ else if( ( timer % (1000/60) ) == 7 )
+ {
+ ygv608.ports.s.p6 |= p6_fp;
+ if (ygv608.regs.s.r14 & r14_iep)
+ irq2_line_hold();
+ }
+}
+
+
+static TILEMAP_MAPPER( get_tile_offset )
+{
+ // this optimisation is not much good to us,
+ // since we really need row,col in the get_tile_info() routines
+ // - so just pack them into a UINT32
+
+ return( ( col << 6 ) | row );
+}
+
+#define layout_total(x) \
+(machine->drv->gfxdecodeinfo[x].gfxlayout->total)
+
+static TILE_GET_INFO( get_tile_info_A_8 )
+{
+ // extract row,col packed into tile_index
+ int col = tile_index >> 6;
+ int row = tile_index & 0x3f;
+
+ UINT8 attr = 0;
+ int pattern_name_base = 0;
+ int set = ((ygv608.regs.s.r7 & r7_md) == MD_1PLANE_256COLOUR
+ ? GFX_8X8_8BIT : GFX_8X8_4BIT );
+ int base = row >> ygv608.base_y_shift;
+
+ if( col >= ygv608.page_x )
+ {
+ SET_TILE_INFO( set, 0, 0, 0 );
+ }
+ else if( row >= ygv608.page_y )
+ {
+ SET_TILE_INFO( set, 0, 0, 0 );
+ }
+ else
+ {
+ int sx, sy, page;
+ int i = pattern_name_base + (((row << ygv608.pny_shift) + col) << ygv608.bits16);
+ int j = ygv608.pattern_name_table[i];
+ int f = 0;
+
+ if( ygv608.bits16 )
+ {
+ j += ((int)(ygv608.pattern_name_table[i+1] & ygv608.na8_mask )) << 8;
+ // attribute only valid in 16 color mode
+ if (set == GFX_8X8_4BIT)
+ attr = ygv608.pattern_name_table[i+1] >> 4;
+
+ if (ygv608.regs.s.r7 & r7_flip)
+ {
+ if (ygv608.pattern_name_table[i+1] & (1<<3)) f |= TILE_FLIPX;
+ if (ygv608.pattern_name_table[i+1] & (1<<2)) f |= TILE_FLIPY;
+ }
+ }
+
+ /* calculate page according to scroll data */
+ /* - assuming full-screen scroll only for now... */
+ sy = (int)ygv608.scroll_data_table[0][0x00] +
+ (((int)ygv608.scroll_data_table[0][0x01] & 0x0f ) << 8);
+ sx = (int)ygv608.scroll_data_table[0][0x80] +
+ (((int)ygv608.scroll_data_table[0][0x81] & 0x0f ) << 8);
+
+ if ((ygv608.regs.s.r7 & r7_md) == MD_2PLANE_16BIT)
+ {
+ page = ( ( sx + col * 8 ) % 1024 ) / 256;
+ page += ( ( ( sy + row * 8 ) % 2048 ) / 256 ) * 4;
+ }
+ else if (ygv608.regs.s.r8 & r8_pgs)
+ {
+ page = ( ( sx + col * 8 ) % 2048 ) / 512;
+ page += ( ( ( sy + row * 8 ) % 2048 ) / 256 ) * 4;
+ }
+ else
+ {
+ page = ( ( sx + col * 8 ) % 2048 ) / 256;
+ page += ( ( ( sy + row * 8 ) % 2048 ) / 512 ) * 8;
+ }
+
+ /* add page, base address to pattern name */
+ j += ( (int)ygv608.scroll_data_table[0][0xc0+page] << 10 );
+ j += ( ygv608.base_addr[0][base] << 8 );
+
+ if( j >= layout_total(set) )
+ {
+ logerror( "A_8X8: tilemap=%d\n", j );
+ j = 0;
+ }
+ if ((ygv608.regs.s.r12 & r12_apf) != 0)
+ {
+ // attribute only valid in 16 color mode
+ if( set == GFX_8X8_4BIT )
+ attr = ( j >> ( ((ygv608.regs.s.r12 & r12_apf) - 1 ) * 2 ) ) & 0x0f;
+ }
+ // banking
+ if (set == GFX_8X8_4BIT)
+ {
+ j += namcond1_gfxbank * 0x10000;
+ }
+ else // 8x8x8
+ {
+ j += namcond1_gfxbank * 0x8000;
+ }
+
+ SET_TILE_INFO( set, j, attr & 0x0F, f );
+ }
+}
+
+static TILE_GET_INFO( get_tile_info_B_8 )
+{
+ // extract row,col packed into tile_index
+ int col = tile_index >> 6;
+ int row = tile_index & 0x3f;
+
+ UINT8 attr = 0;
+ int pattern_name_base = ( ( ygv608.page_y << ygv608.pny_shift )
+ << ygv608.bits16 );
+ int set = GFX_8X8_4BIT;
+ int base = row >> ygv608.base_y_shift;
+
+ if ((ygv608.regs.s.r7 & r7_md) & MD_1PLANE )
+ {
+ SET_TILE_INFO( set, 0, 0, 0 );
+ }
+ else if (col >= ygv608.page_x)
+ {
+ SET_TILE_INFO( set, 0, 0, 0 );
+ }
+ else if (row >= ygv608.page_y)
+ {
+ SET_TILE_INFO( set, 0, 0, 0 );
+ }
+ else
+ {
+ int sx, sy, page;
+ int i = pattern_name_base + (((row << ygv608.pny_shift) + col) << ygv608.bits16);
+ int j = ygv608.pattern_name_table[i];
+ int f = 0;
+
+ if (ygv608.bits16)
+ {
+ j += ((int)(ygv608.pattern_name_table[i+1] & ygv608.na8_mask )) << 8;
+ attr = ygv608.pattern_name_table[i+1] >> 4; /*& 0x00; 0xf0;*/
+
+ if (ygv608.regs.s.r7 & r7_flip)
+ {
+ if (ygv608.pattern_name_table[i+1] & (1<<3)) f |= TILE_FLIPX;
+ if (ygv608.pattern_name_table[i+1] & (1<<2)) f |= TILE_FLIPY;
+ }
+ }
+
+ /* calculate page according to scroll data */
+ /* - assuming full-screen scroll only for now... */
+ sy = (int)ygv608.scroll_data_table[1][0x00] +
+ (((int)ygv608.scroll_data_table[1][0x01] & 0x0f ) << 8);
+ sx = (int)ygv608.scroll_data_table[1][0x80] +
+ (((int)ygv608.scroll_data_table[1][0x81] & 0x0f ) << 8);
+
+ if ((ygv608.regs.s.r7 & r7_md) == MD_2PLANE_16BIT )
+ {
+ page = ( ( sx + col * 8 ) % 1024 ) / 256;
+ page += ( ( ( sy + row * 8 ) % 2048 ) / 256 ) * 4;
+ }
+ else if (ygv608.regs.s.r8 & r8_pgs)
+ {
+ page = ( ( sx + col * 8 ) % 2048 ) / 512;
+ page += ( ( ( sy + row * 8 ) % 2048 ) / 256 ) * 4;
+ }
+ else
+ {
+ page = ( ( sx + col * 8 ) % 2048 ) / 256;
+ page += ( ( ( sy + row * 8 ) % 2048 ) / 512 ) * 8;
+ }
+
+ /* add page, base address to pattern name */
+ j += ( (int)ygv608.scroll_data_table[1][0xc0+page] << 10 );
+ j += ( ygv608.base_addr[1][base] << 8 );
+
+ if( j >= layout_total(set) )
+ {
+ logerror( "B_8X8: tilemap=%d\n", j );
+ j = 0;
+ }
+ if ((ygv608.regs.s.r12 & r12_bpf) != 0)
+ {
+ UINT8 color = (ygv608.regs.s.r12 & r12_bpf) >> 3;
+
+ /* assume 16 colour mode for now... */
+ attr = ( j >> ( (color - 1 ) * 2 ) ) & 0x0f;
+ }
+
+ // banking
+ if (set == GFX_8X8_4BIT)
+ {
+ j += namcond1_gfxbank * 0x10000;
+ }
+ else // 8x8x8
+ {
+ j += namcond1_gfxbank * 0x8000;
+ }
+
+ SET_TILE_INFO( set, j, attr, f );
+ }
+}
+
+static TILE_GET_INFO( get_tile_info_A_16 )
+{
+ // extract row,col packed into tile_index
+ int col = tile_index >> 6;
+ int row = tile_index & 0x3f;
+
+ UINT8 attr = 0;
+ int pattern_name_base = 0;
+ int set = ((ygv608.regs.s.r7 & r7_md) == MD_1PLANE_256COLOUR
+ ? GFX_16X16_8BIT : GFX_16X16_4BIT );
+ int base = row >> ygv608.base_y_shift;
+
+ if( col >= ygv608.page_x ) {
+ SET_TILE_INFO( set, 0, 0, 0 );
+ }
+ else if( row >= ygv608.page_y ) {
+ SET_TILE_INFO( set, 0, 0, 0 );
+ }
+ else {
+ int sx, sy, page;
+ int j;
+ int i = ( ( ( row << ygv608.pny_shift ) + col ) << ygv608.bits16 );
+ int f = 0;
+ i += pattern_name_base;
+
+ j = ygv608.pattern_name_table[i];
+ if( ygv608.bits16 ) {
+ j += ((int)(ygv608.pattern_name_table[i+1] & ygv608.na8_mask )) << 8;
+ // attribute only valid in 16 color mode
+ if( set == GFX_16X16_4BIT )
+ attr = ygv608.pattern_name_table[i+1] >> 4;
+
+ if (ygv608.regs.s.r7 & r7_flip)
+ {
+ if (ygv608.pattern_name_table[i+1] & (1<<3)) f |= TILE_FLIPX;
+ if (ygv608.pattern_name_table[i+1] & (1<<2)) f |= TILE_FLIPY;
+ }
+ }
+
+ /* calculate page according to scroll data */
+ /* - assuming full-screen scroll only for now... */
+ sy = (int)ygv608.scroll_data_table[0][0x00] +
+ (((int)ygv608.scroll_data_table[0][0x01] & 0x0f ) << 8);
+ sx = (int)ygv608.scroll_data_table[0][0x80] +
+ (((int)ygv608.scroll_data_table[0][0x81] & 0x0f ) << 8);
+ if((ygv608.regs.s.r7 & r7_md) == MD_2PLANE_16BIT ) {
+ page = ( ( sx + col * 16 ) % 2048 ) / 512;
+ page += ( ( sy + row * 16 ) / 512 ) * 4;
+ }
+ else if (ygv608.regs.s.r8 & r8_pgs) {
+ page = ( sx + col * 16 ) / 512;
+ page += ( ( sy + row * 16 ) / 1024 ) * 8;
+ }
+ else {
+ page = ( sx + col * 16 ) / 1024;
+ page += ( ( sy + row * 16 ) / 512 ) * 4;
+ }
+
+ /* add page, base address to pattern name */
+ j += ( (int)ygv608.scroll_data_table[0][0xc0+page] << 8 );
+ j += ( ygv608.base_addr[0][base] << 8 );
+
+ if( j >= layout_total(set) ) {
+ logerror( "A_16X16: tilemap=%d\n", j );
+ j = 0;
+ }
+
+ if ((ygv608.regs.s.r12 & r12_apf) != 0)
+ {
+ // attribute only valid in 16 color mode
+ if( set == GFX_16X16_4BIT )
+ attr = ( j >> ( ((ygv608.regs.s.r12 & r12_apf)) * 2 ) ) & 0x0f;
+ }
+
+ // banking
+ if (set == GFX_16X16_4BIT)
+ {
+ j += namcond1_gfxbank * 0x4000;
+ }
+ else // 8x8x8
+ {
+ j += namcond1_gfxbank * 0x2000;
+ }
+
+
+ SET_TILE_INFO( set, j, attr, f );
+ }
+}
+
+static TILE_GET_INFO( get_tile_info_B_16 )
+{
+ // extract row,col packed into tile_index
+ int col = tile_index >> 6;
+ int row = tile_index & 0x3f;
+
+ UINT8 attr = 0;
+ int pattern_name_base = ( ( ygv608.page_y << ygv608.pny_shift )
+ << ygv608.bits16 );
+ int set = GFX_16X16_4BIT;
+ int base = row >> ygv608.base_y_shift;
+
+ if((ygv608.regs.s.r7 & r7_md) & MD_1PLANE ) {
+ SET_TILE_INFO( set, 0, 0, 0 );
+ }
+ if( col >= ygv608.page_x ) {
+ SET_TILE_INFO( set, 0, 0, 0 );
+ }
+ else if( row >= ygv608.page_y ) {
+ SET_TILE_INFO( set, 0, 0, 0 );
+ }
+ else {
+ int sx, sy, page;
+ int j;
+ int i = ( ( ( row << ygv608.pny_shift ) + col ) << ygv608.bits16 );
+ int f = 0;
+ i += pattern_name_base;
+
+ j = ygv608.pattern_name_table[i];
+ if( ygv608.bits16 ) {
+ j += ((int)(ygv608.pattern_name_table[i+1] & ygv608.na8_mask )) << 8;
+ attr = ygv608.pattern_name_table[i+1] >> 4; /*& 0x00; 0xf0;*/
+
+ if (ygv608.regs.s.r7 & r7_flip)
+ {
+ if (ygv608.pattern_name_table[i+1] & (1<<3)) f |= TILE_FLIPX;
+ if (ygv608.pattern_name_table[i+1] & (1<<2)) f |= TILE_FLIPY;
+ }
+ }
+
+ /* calculate page according to scroll data */
+ /* - assuming full-screen scroll only for now... */
+ sy = (int)ygv608.scroll_data_table[1][0x00] +
+ (((int)ygv608.scroll_data_table[1][0x01] & 0x0f ) << 8);
+ sx = (int)ygv608.scroll_data_table[1][0x80] +
+ (((int)ygv608.scroll_data_table[1][0x81] & 0x0f ) << 8);
+ if((ygv608.regs.s.r7 & r7_md) == MD_2PLANE_16BIT ) {
+ page = ( ( sx + col * 16 ) % 2048 ) / 512;
+ page += ( ( sy + row * 16 ) / 512 ) * 4;
+ }
+ else if (ygv608.regs.s.r8 & r8_pgs) {
+ page = ( sx + col * 16 ) / 512;
+ page += ( ( sy + row * 16 ) / 1024 ) * 8;
+ }
+ else {
+ page = ( sx + col * 16 ) / 1024;
+ page += ( ( sy + row * 16 ) / 512 ) * 4;
+ }
+
+ /* add page, base address to pattern name */
+ j += ( (int)ygv608.scroll_data_table[1][0xc0+page] << 8 );
+ j += ( ygv608.base_addr[1][base] << 8 );
+
+ if( j >= layout_total(set) ) {
+ logerror( "B_16X16: tilemap=%d\n", j );
+ j = 0;
+ }
+
+ if ((ygv608.regs.s.r12 & r12_bpf) != 0)
+ {
+ UINT8 color = (ygv608.regs.s.r12 & r12_bpf) >> 3;
+
+ /* assume 16 colour mode for now... */
+ attr = ( j >> (color * 2)) & 0x0f;
+ }
+
+ // banking
+ if (set == GFX_16X16_4BIT)
+ {
+ j += namcond1_gfxbank * 0x4000;
+ }
+ else // 8x8x8
+ {
+ j += namcond1_gfxbank * 0x2000;
+ }
+
+
+ SET_TILE_INFO( set, j, attr, f );
+ }
+}
+
+static void ygv608_postload(void)
+{
+ int i;
+
+ ygv608.screen_resize = 1;
+ ygv608.tilemap_resize = 1;
+
+ for(i = 0; i < 50; i++)
+ SetPostShortcuts(i);
+}
+
+static void ygv608_register_state_save(void)
+{
+ state_save_register_item_array("ygv608", 0, ygv608.ports.b);
+ state_save_register_item_array("ygv608", 0, ygv608.regs.b);
+ state_save_register_item_array("ygv608", 0, ygv608.pattern_name_table);
+ state_save_register_item_array("ygv608", 0, ygv608.sprite_attribute_table.b);
+ state_save_register_item_2d_array("ygv608", 0, ygv608.scroll_data_table);
+ state_save_register_item_2d_array("ygv608", 0, ygv608.colour_palette);
+
+ state_save_register_func_postload(ygv608_postload);
+}
+
+VIDEO_START( ygv608 )
+{
+ memset( &ygv608, 0, sizeof(ygv608) );
+
+ // flag rebuild of the tilemaps
+ ygv608.screen_resize = 1;
+ ygv608.tilemap_resize = 1;
+ namcond1_gfxbank = 0;
+
+ /* create tilemaps of all sizes and combinations */
+ tilemap_A_cache_8[0] = tilemap_create(get_tile_info_A_8, get_tile_offset, TILEMAP_TYPE_PEN, 8,8, 32,32);
+ tilemap_A_cache_8[1] = tilemap_create(get_tile_info_A_8, get_tile_offset, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ tilemap_A_cache_8[2] = tilemap_create(get_tile_info_A_8, get_tile_offset, TILEMAP_TYPE_PEN, 8,8, 32,64);
+
+ tilemap_A_cache_16[0] = tilemap_create(get_tile_info_A_16, get_tile_offset, TILEMAP_TYPE_PEN, 16,16, 32,32);
+ tilemap_A_cache_16[1] = tilemap_create(get_tile_info_A_16, get_tile_offset, TILEMAP_TYPE_PEN, 16,16, 64,32);
+ tilemap_A_cache_16[2] = tilemap_create(get_tile_info_A_16, get_tile_offset, TILEMAP_TYPE_PEN, 16,16, 32,64);
+
+ tilemap_B_cache_8[0] = tilemap_create(get_tile_info_B_8, get_tile_offset, TILEMAP_TYPE_PEN, 8,8, 32,32);
+ tilemap_B_cache_8[1] = tilemap_create(get_tile_info_B_8, get_tile_offset, TILEMAP_TYPE_PEN, 8,8, 64,32);
+ tilemap_B_cache_8[2] = tilemap_create(get_tile_info_B_8, get_tile_offset, TILEMAP_TYPE_PEN, 8,8, 32,64);
+
+ tilemap_B_cache_16[0] = tilemap_create(get_tile_info_B_16, get_tile_offset, TILEMAP_TYPE_PEN, 16,16, 32,32);
+ tilemap_B_cache_16[1] = tilemap_create(get_tile_info_B_16, get_tile_offset, TILEMAP_TYPE_PEN, 16,16, 64,32);
+ tilemap_B_cache_16[2] = tilemap_create(get_tile_info_B_16, get_tile_offset, TILEMAP_TYPE_PEN, 16,16, 32,64);
+
+ tilemap_A = NULL;
+ tilemap_B = NULL;
+
+ ygv608_register_state_save();
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect )
+{
+#ifdef _ENABLE_SPRITES
+
+ // sprites are always clipped to 512x512
+ // - regardless of the visible display dimensions
+ static rectangle spriteClip = { 0, 512, 0, 512 };
+
+ PSPRITE_ATTR sa;
+ int flipx = 0, flipy = 0;
+ int i;
+
+ /* ensure that sprites are enabled */
+ if( ((ygv608.regs.s.r7 & r7_dspe) == 0 ) || (ygv608.regs.s.r10 & r10_sprd))
+ return;
+
+ /* draw sprites */
+ sect_rect(&spriteClip, cliprect);
+ sa = &ygv608.sprite_attribute_table.s[YGV608_MAX_SPRITES-1];
+ for( i=0; i<YGV608_MAX_SPRITES; i++, sa-- )
+ {
+ int code, color, sx, sy, size, attr, g_attr, spf;
+
+ color = (sa->attr >> 4) & 0x0f;
+ sx = ( (int)(sa->attr & 0x02) << 7 ) | (int)sa->sx;
+ sy = ( ( ( (int)(sa->attr & 0x01) << 8 ) | (int)sa->sy ) + 1 ) & 0x1ff;
+ attr = (sa->attr & 0x0c) >> 2;
+ g_attr = (ygv608.regs.s.r10 & r10_spa) >> 6;
+ spf = (ygv608.regs.s.r12 & r12_spf) >> 6;
+
+ if ((ygv608.regs.s.r10 & r10_spas) == SPAS_SPRITESIZE )
+ {
+ size = g_attr;
+ flipx = (attr & SZ_HORIZREVERSE) != 0;
+ flipy = (attr & SZ_VERTREVERSE) != 0;
+ }
+ else
+ {
+ size = attr;
+ flipx = (g_attr & SZ_HORIZREVERSE) != 0;
+ flipy = (g_attr & SZ_VERTREVERSE) != 0;
+ }
+
+ switch( size ) {
+
+ case SZ_8X8 :
+ code = ( (int)ygv608.regs.s.sba << 8 ) | (int)sa->sn;
+ if (spf != 0)
+ color = ( code >> ( (spf - 1) * 2 ) ) & 0x0f;
+ if( code >= layout_total(GFX_8X8_4BIT) ) {
+ logerror( "SZ_8X8: sprite=%d\n", code );
+ code = 0;
+ }
+ drawgfx( bitmap, machine->gfx[GFX_8X8_4BIT],
+ code+namcond1_gfxbank*0x10000,
+ color,
+ flipx,flipy,
+ sx,sy,
+ &spriteClip,TRANSPARENCY_PEN,0x00);
+ // redraw with wrap-around
+ if( sx > 512-8 )
+ drawgfx( bitmap, machine->gfx[GFX_8X8_4BIT],
+ code+namcond1_gfxbank*0x10000,
+ color,
+ flipx,flipy,
+ sx-512,sy,
+ &spriteClip,TRANSPARENCY_PEN,0x00);
+ if( sy > 512-8 )
+ drawgfx( bitmap, machine->gfx[GFX_8X8_4BIT],
+ code+namcond1_gfxbank*0x10000,
+ color,
+ flipx,flipy,
+ sx,sy-512,
+ &spriteClip,TRANSPARENCY_PEN,0x00);
+ // really should draw again for both wrapped!
+ // - ignore until someone thinks it's required
+ break;
+
+ case SZ_16X16 :
+ code = ( ( (int)ygv608.regs.s.sba & 0xfc ) << 6 ) | (int)sa->sn;
+ if (spf != 0)
+ color = ( code >> (spf * 2) ) & 0x0f;
+ if( code >= layout_total(GFX_16X16_4BIT) ) {
+ logerror( "SZ_8X8: sprite=%d\n", code );
+ code = 0;
+ }
+ drawgfx( bitmap, machine->gfx[GFX_16X16_4BIT],
+ code+namcond1_gfxbank*0x4000,
+ color,
+ flipx,flipy,
+ sx,sy,
+ &spriteClip,TRANSPARENCY_PEN,0x00);
+ // redraw with wrap-around
+ if( sx > 512-16 )
+ drawgfx( bitmap, machine->gfx[GFX_16X16_4BIT],
+ code+namcond1_gfxbank*0x4000,
+ color,
+ flipx,flipy,
+ sx-512,sy,
+ &spriteClip,TRANSPARENCY_PEN,0x00);
+ if( sy > 512-16 )
+ drawgfx( bitmap, machine->gfx[GFX_16X16_4BIT],
+ code+namcond1_gfxbank*0x4000,
+ color,
+ flipx,flipy,
+ sx,sy-512,
+ &spriteClip,TRANSPARENCY_PEN,0x00);
+ // really should draw again for both wrapped!
+ // - ignore until someone thinks it's required
+ break;
+
+ case SZ_32X32 :
+ code = ( ( (int)ygv608.regs.s.sba & 0xf0 ) << 4 ) | (int)sa->sn;
+ if (spf != 0)
+ color = ( code >> ( (spf + 1) * 2 ) ) & 0x0f;
+ if( code >= layout_total(GFX_32X32_4BIT) ) {
+ logerror( "SZ_32X32: sprite=%d\n", code );
+ code = 0;
+ }
+ drawgfx( bitmap, machine->gfx[GFX_32X32_4BIT],
+ code+namcond1_gfxbank*0x1000,
+ color,
+ flipx,flipy,
+ sx,sy,
+ &spriteClip,TRANSPARENCY_PEN,0x00);
+ // redraw with wrap-around
+ if( sx > 512-32 )
+ drawgfx( bitmap, machine->gfx[GFX_32X32_4BIT],
+ code+namcond1_gfxbank*0x1000,
+ color,
+ flipx,flipy,
+ sx-512,sy,
+ &spriteClip,TRANSPARENCY_PEN,0x00);
+ if( sy > 512-32 )
+ drawgfx( bitmap, machine->gfx[GFX_32X32_4BIT],
+ code+namcond1_gfxbank*0x1000,
+ color,
+ flipx,flipy,
+ sx,sy-512,
+ &spriteClip,TRANSPARENCY_PEN,0x00);
+ // really should draw again for both wrapped!
+ // - ignore until someone thinks it's required
+ break;
+
+ case SZ_64X64 :
+ code = ( ( (int)ygv608.regs.s.sba & 0xc0 ) << 2 ) | (int)sa->sn;
+ if (spf != 0)
+ color = ( code >> ( (spf + 1) * 2 ) ) & 0x0f;
+ if( code >= layout_total(GFX_64X64_4BIT) ) {
+ logerror( "SZ_64X64: sprite=%d\n", code );
+ code = 0;
+ }
+ drawgfx( bitmap, machine->gfx[GFX_64X64_4BIT],
+ code+namcond1_gfxbank*0x400,
+ color,
+ flipx,flipy,
+ sx,sy,
+ &spriteClip,TRANSPARENCY_PEN,0x00);
+ // redraw with wrap-around
+ if( sx > 512-64 )
+ drawgfx( bitmap, machine->gfx[GFX_64X64_4BIT],
+ code+namcond1_gfxbank*0x400,
+ color,
+ flipx,flipy,
+ sx-512,sy,
+ &spriteClip,TRANSPARENCY_PEN,0x00);
+ if( sy > 512-64 )
+ drawgfx( bitmap, machine->gfx[GFX_64X64_4BIT],
+ code+namcond1_gfxbank*0x400,
+ color,
+ flipx,flipy,
+ sx,sy-512,
+ &spriteClip,TRANSPARENCY_PEN,0x00);
+ // really should draw again for both wrapped!
+ // - ignore until someone thinks it's required
+ break;
+
+ default :
+ break;
+ }
+ }
+
+#endif
+}
+
+#ifdef _SHOW_VIDEO_DEBUG
+static char *mode[] = { "2PLANE_8BIT",
+ "2PLANE_16BIT",
+ "1PLANE_16COLORS",
+ "1PLANE_256COLORS" };
+
+static char *psize[] = { "8x8", "16x16", "32x32", "64x64" };
+#endif
+
+VIDEO_UPDATE( ygv608 )
+{
+#ifdef _SHOW_VIDEO_DEBUG
+ char buffer[64];
+#endif
+ int col;
+#ifdef _ENABLE_ROTATE_ZOOM
+ int xc, yc;
+ double r, alpha, sin_theta, cos_theta;
+#endif
+ rectangle finalclip;
+
+ // clip to the current bitmap
+ finalclip.min_x = 0;
+ finalclip.max_x = machine->screen[0].width - 1;
+ finalclip.min_y = 0;
+ finalclip.max_y = machine->screen[0].height - 1;
+ sect_rect(&finalclip, cliprect);
+ cliprect = &finalclip;
+
+ // punt if not initialized
+ if (ygv608.page_x == 0 || ygv608.page_y == 0)
+ {
+ fillbitmap(bitmap, 0, cliprect);
+ return 0;
+ }
+
+ if( ygv608.screen_resize )
+ {
+#ifdef _ENABLE_SCREEN_RESIZE
+ // hdw should be scaled by 16, not 8
+ // - is it something to do with double dot-clocks???
+ video_screen_set_visarea(0, 0, ((int)(ygv608.regs.s.hdw)<<3/*4*/)-1,
+ 0, ((int)(ygv608.regs.s.vdw)<<3)-1 );
+#endif
+
+ if( work_bitmap )
+ bitmap_free( work_bitmap );
+ work_bitmap = bitmap_alloc( machine->screen[0].width,
+ machine->screen[0].height, machine->screen[0].format );
+
+ // reset resize flag
+ ygv608.screen_resize = 0;
+ }
+
+ if( ygv608.tilemap_resize )
+ {
+ int index;
+
+ /* based on the page sizes, pick an index */
+ if (ygv608.page_x == 64)
+ index = 1;
+ else if (ygv608.page_y == 64)
+ index = 2;
+ else
+ index = 0;
+
+ if ((ygv608.regs.s.r9 & r9_pts) == PTS_8X8 )
+ tilemap_A = tilemap_A_cache_8[index];
+ else
+ tilemap_A = tilemap_A_cache_16[index];
+ tilemap_mark_all_tiles_dirty(tilemap_A);
+
+ tilemap_set_transparent_pen( tilemap_A, 0 );
+ // for NCV1 it's sufficient to scroll only columns
+ tilemap_set_scroll_cols( tilemap_A, ygv608.page_x );
+
+ if ((ygv608.regs.s.r9 & r9_pts) == PTS_8X8 )
+ tilemap_B = tilemap_B_cache_8[index];
+ else
+ tilemap_B = tilemap_B_cache_16[index];
+ tilemap_mark_all_tiles_dirty(tilemap_B);
+
+ // for NCV1 it's sufficient to scroll only columns
+ tilemap_set_scroll_cols( tilemap_B, ygv608.page_x );
+
+ // now clear the screen in case we change to 1-plane mode
+ fillbitmap( work_bitmap, machine->pens[0], cliprect );
+
+ // reset resize flag
+ ygv608.tilemap_resize = 0;
+ }
+
+#ifdef _ENABLE_SCROLLY
+
+ for( col=0; col<ygv608.page_x; col++ )
+ {
+ tilemap_set_scrolly( tilemap_B, col,
+ ( (int)ygv608.scroll_data_table[1][(col>>ygv608.col_shift)<<1] +
+ ( (int)ygv608.scroll_data_table[1][((col>>ygv608.col_shift)<<1)+1] << 8 ) ) );
+
+ tilemap_set_scrolly( tilemap_A, col,
+ ( (int)ygv608.scroll_data_table[0][(col>>ygv608.col_shift)<<1] +
+ ( (int)ygv608.scroll_data_table[0][((col>>ygv608.col_shift)<<1)+1] << 8 ) ) );
+ }
+
+#endif
+
+#ifdef _ENABLE_SCROLLX
+
+ tilemap_set_scrollx( tilemap_B, 0,
+ ( (int)ygv608.scroll_data_table[1][0x80] +
+ ( (int)ygv608.scroll_data_table[1][0x81] << 8 ) ) );
+
+ tilemap_set_scrollx( tilemap_A, 0,
+ ( (int)ygv608.scroll_data_table[0][0x80] +
+ ( (int)ygv608.scroll_data_table[0][0x81] << 8 ) ) );
+
+#endif
+
+ tilemap_set_enable( tilemap_A, ygv608.regs.s.r7 & r7_dspe);
+ if((ygv608.regs.s.r7 & r7_md) & MD_1PLANE )
+ tilemap_set_enable( tilemap_B, 0 );
+ else
+ tilemap_set_enable( tilemap_B, ygv608.regs.s.r7 & r7_dspe);
+
+ tilemap_mark_all_tiles_dirty( tilemap_A );
+ tilemap_mark_all_tiles_dirty( tilemap_B );
+
+
+ /*
+ * now we can render the screen
+ */
+
+#if 1
+ // LBO - need to implement proper pen marking for sprites as well as set aside a non-transparent
+ // pen to be used for background fills when plane B is disabled.
+ if ((ygv608.regs.s.r7 & r7_md) & MD_1PLANE)
+ {
+ // If the background tilemap is disabled, we need to clear the bitmap to black
+ fillbitmap (work_bitmap,machine->pens[0],cliprect);
+// fillbitmap (work_bitmap,1,&machine->screen[0].visarea);
+ }
+ else
+#endif
+ tilemap_draw( work_bitmap,cliprect, tilemap_B, 0, 0 );
+
+#ifdef _ENABLE_ROTATE_ZOOM
+
+ /*
+ * fudge - translate ax,ay to startx, starty each time
+ */
+
+ xc = ygv608.ax >> 16;
+ yc = ygv608.ay >> 16;
+ r = sqrt( (double)( xc * xc + yc * yc ) );
+ alpha = atan( (double)xc / (double)yc );
+ sin_theta = (double)ygv608.dyx / (double)0x10000;
+ cos_theta = (double)ygv608.dx / (double)0x10000;
+
+ if( ygv608.regs.s.zron )
+ copyrozbitmap( bitmap, work_bitmap,
+ ( machine->screen[0].visarea.min_x << 16 ) +
+ ygv608.ax + 0x10000 * r *
+ ( -sin( alpha ) * cos_theta + cos( alpha ) * sin_theta ),
+ ( machine->screen[0].visarea.min_y << 16 ) +
+ ygv608.ay + 0x10000 * r *
+ ( cos( alpha ) * cos_theta + sin( alpha ) * sin_theta ),
+ ygv608.dx, ygv608.dxy, ygv608.dyx, ygv608.dy, 0,
+ cliprect,
+ TRANSPARENCY_NONE, 0, 0 );
+ else
+#endif
+ copybitmap( bitmap, work_bitmap, 0, 0, 0, 0,
+ cliprect,
+ TRANSPARENCY_NONE, 0 );
+
+ // for some reason we can't use an opaque tilemap_A
+ // so use a transparent but clear the work bitmap first
+ // - look at why this is the case?!?
+ fillbitmap( work_bitmap,
+ machine->pens[0],
+ &machine->screen[0].visarea );
+
+ if ((ygv608.regs.s.r11 & r11_prm) == PRM_ASBDEX ||
+ (ygv608.regs.s.r11 & r11_prm) == PRM_ASEBDX )
+ draw_sprites(machine, bitmap,cliprect );
+
+ tilemap_draw( work_bitmap,cliprect, tilemap_A, 0, 0 );
+
+#ifdef _ENABLE_ROTATE_ZOOM
+ if( ygv608.regs.s.zron )
+ copyrozbitmap( bitmap, work_bitmap,
+ ygv608.ax, // + ( machine->screen[0].visarea.min_x << 16 ),
+ ygv608.ay, // + ( machine->screen[0].visarea.min_y << 16 ),
+ ygv608.dx, ygv608.dxy, ygv608.dyx, ygv608.dy, 0,
+ cliprect,
+ TRANSPARENCY_PEN, machine->pens[0], 0 );
+ else
+#endif
+ copybitmap( bitmap, work_bitmap, 0, 0, 0, 0,
+ cliprect,
+ TRANSPARENCY_PEN, machine->pens[0] );
+
+ if ((ygv608.regs.s.r11 & r11_prm) == PRM_SABDEX ||
+ (ygv608.regs.s.r11 & r11_prm) == PRM_SEABDX)
+ draw_sprites(machine, bitmap,cliprect );
+
+
+#ifdef _SHOW_VIDEO_DEBUG
+ /* show screen control information */
+ ui_draw_text( mode[(ygv608.regs.s.r7 & r7_md) >> 1], 0, 0 );
+ sprintf( buffer, "%02ux%02u", ygv608.page_x, ygv608.page_y );
+ ui_draw_text( buffer, 0, 16 );
+ ui_draw_text( psize[(ygv608.regs.s.r9 & r9_pts) >> 6], 0, 32 );
+ sprintf( buffer, "A: SX:%d SY:%d",
+ (int)ygv608.scroll_data_table[0][0x80] +
+ ( ( (int)ygv608.scroll_data_table[0][0x81] & 0x0f ) << 8 ),
+ (int)ygv608.scroll_data_table[0][0x00] +
+ ( ( (int)ygv608.scroll_data_table[0][0x01] & 0x0f ) << 8 ) );
+ ui_draw_text( buffer, 0, 48 );
+ sprintf( buffer, "B: SX:%d SY:%d",
+ (int)ygv608.scroll_data_table[1][0x80] +
+ ( ( (int)ygv608.scroll_data_table[1][0x81] & 0x0f ) << 8 ),
+ (int)ygv608.scroll_data_table[1][0x00] +
+ ( ( (int)ygv608.scroll_data_table[1][0x01] & 0x0f ) << 8 ) );
+ ui_draw_text( buffer, 0, 64 );
+#endif
+ return 0;
+}
+
+READ16_HANDLER( ygv608_r )
+{
+ static int p0_state = 0;
+ static int p3_state = 0;
+ static int pattern_name_base = 0; /* pattern name table base address */
+ int pn=0;
+ UINT16 data = 0;
+
+ switch (offset)
+ {
+ case 0x00: /* P#0 - pattern name table data port */
+ {
+ UINT8 xTile = ygv608.regs.s.r1 & r1_pnx;
+ UINT8 yTile = ygv608.regs.s.r0 & r0_pny;
+
+ switch (p0_state)
+ {
+ case 0:
+ /* Are we reading from plane B? */
+ if (!((ygv608.regs.s.r7 & r7_md) & MD_1PLANE) && (ygv608.regs.s.r0 & r0_b_a))
+ pattern_name_base = ((ygv608.page_y << ygv608.pny_shift) << ygv608.bits16);
+
+ /* read character from ram */
+ pn = pattern_name_base + (((yTile << ygv608.pny_shift) + xTile) << ygv608.bits16);
+ break;
+
+ case 1:
+ /* read character from ram */
+ pn = pattern_name_base + (((yTile << ygv608.pny_shift) + xTile) << ygv608.bits16) + 1;
+ break;
+ }
+
+ if (pn > 4095)
+ {
+ logerror( "attempt (%d) to read pattern name %d\n"
+ "mode = %d, pgs = %d (%dx%d)\n"
+ "pattern_name_base = %d\n"
+ "pnx = %d, pny = %d, pny_shift = %d, bits16 = %d\n",
+ p0_state,
+ pn, ygv608.regs.s.r7 & r7_md, ygv608.regs.s.r8 & r8_pgs,
+ ygv608.page_x, ygv608.page_y,
+ pattern_name_base,
+ xTile, yTile, ygv608.pny_shift,
+ ygv608.bits16 );
+ pn = 0;
+ }
+ data = ygv608.pattern_name_table[pn];
+
+ p0_state++;
+ if ((ygv608.regs.s.r7 & r7_md) == MD_2PLANE_8BIT )
+ p0_state++;
+
+ if (p0_state == 2)
+ {
+ if (ygv608.regs.s.r0 & r0_pnya)
+ {
+ if (yTile++ == (ygv608.page_y - 1))
+ {
+ yTile = 0;
+ if (xTile++ == (ygv608.page_x - 1))
+ {
+ xTile = 0;
+ // we're now off this tile plane, toggle planes
+ ygv608.regs.s.r0 ^= r0_b_a;
+ }
+ }
+ ygv608.regs.s.r0 &= ~r0_pny;
+ ygv608.regs.s.r0 |= yTile;
+ ygv608.regs.s.r1 &= ~r1_pnx;
+ ygv608.regs.s.r1 |= xTile;
+ }
+ else if (ygv608.regs.s.r1 & r1_pnxa)
+ {
+ if (xTile++ == (ygv608.page_x - 1))
+ {
+ xTile = 0;
+ if (yTile++ == (ygv608.page_y - 1))
+ {
+ yTile = 0;
+ // we're now off this tile plane, toggle planes
+ ygv608.regs.s.r0 ^= r0_b_a;
+ }
+ }
+ ygv608.regs.s.r0 &= ~r0_pny;
+ ygv608.regs.s.r0 |= yTile;
+ ygv608.regs.s.r1 &= ~r1_pnx;
+ ygv608.regs.s.r1 |= xTile;
+ }
+ p0_state = 0;
+ pattern_name_base = 0;
+ }
+ return (data << 8);
+ }
+ break;
+
+ case 0x01: /* P#1 - sprite data port */
+ data = ygv608.sprite_attribute_table.b[ygv608.regs.s.saa];
+ if (ygv608.regs.s.r2 & r2_saar)
+ ygv608.regs.s.saa++;
+ return (data << 8);
+ break;
+
+ case 0x02: /* P#2 - scroll data port */
+ data = ygv608.scroll_data_table[(ygv608.regs.s.r2 & r2_b_a) >> 4][ygv608.regs.s.sca];
+ if (ygv608.regs.s.r2 & r2_scar)
+ {
+ ygv608.regs.s.sca++;
+ /* handle wrap to next plane */
+ if (ygv608.regs.s.sca == 0)
+ ygv608.regs.s.r2 ^= r2_b_a;
+ }
+ return( data << 8 );
+ break;
+
+ case 0x03: /* P#3 - color palette data port */
+ data = ygv608.colour_palette[ygv608.regs.s.cc][p3_state];
+ if( ++p3_state == 3 )
+ {
+ p3_state = 0;
+ if( ygv608.regs.s.r2 & r2_cpar)
+ ygv608.regs.s.cc++;
+ }
+ return( data << 8 );
+ break;
+
+ case 0x04: /* P#4 - register data port */
+ {
+ UINT8 regNum = (ygv608.ports.s.p5) & p5_rn;
+ data = ygv608.regs.b[regNum];
+ if (ygv608.ports.s.p5 & p5_rrai)
+ {
+ regNum ++;
+ if (regNum == 50)
+ {
+ regNum = 0;
+ logerror( "warning: rn=50 after read increment\n" );
+ }
+ ygv608.ports.s.p5 &= ~p5_rn;
+ ygv608.ports.s.p5 |= regNum;
+ }
+ return (data << 8);
+ }
+ break;
+
+ case 0x05:
+ break;
+
+ case 0x06:
+ case 0x07:
+ return( (UINT16)(ygv608.ports.b[offset]) << 8 );
+
+ default :
+ logerror( "unknown ygv608 register (%d)\n", offset );
+ break;
+ }
+
+ return( 0 );
+}
+
+WRITE16_HANDLER( ygv608_w )
+{
+ static int p0_state = 0;
+ static int p3_state = 0;
+ static int pattern_name_base = 0; /* pattern name table base address */
+ int pn=0;
+
+ data = ( data >> 8 ) & 0xff;
+
+ switch (offset)
+ {
+ case 0x00: /* P#0 - pattern name table data port */
+ {
+ UINT8 xTile = ygv608.regs.s.r1 & r1_pnx;
+ UINT8 yTile = ygv608.regs.s.r0 & r0_pny;
+
+ switch (p0_state)
+ {
+ case 0:
+ /* Are we reading from plane B? */
+ if (!((ygv608.regs.s.r7 & r7_md) & MD_1PLANE) && (ygv608.regs.s.r0 & r0_b_a))
+ pattern_name_base = ((ygv608.page_y << ygv608.pny_shift) << ygv608.bits16);
+
+ /* read character from ram */
+ pn = pattern_name_base + (((yTile << ygv608.pny_shift) + xTile) << ygv608.bits16);
+ break;
+
+ case 1:
+ /* read character from ram */
+ pn = pattern_name_base + (((yTile << ygv608.pny_shift) + xTile) << ygv608.bits16) + 1;
+ break;
+ }
+
+ if (pn > 4095)
+ {
+ logerror( "attempt (%d) to read pattern name %d\n"
+ "mode = %d, pgs = %d (%dx%d)\n"
+ "pattern_name_base = %d\n"
+ "pnx = %d, pny = %d, pny_shift = %d, bits16 = %d\n",
+ p0_state,
+ pn, ygv608.regs.s.r7 & r7_md, ygv608.regs.s.r8 & r8_pgs,
+ ygv608.page_x, ygv608.page_y,
+ pattern_name_base,
+ xTile, yTile, ygv608.pny_shift,
+ ygv608.bits16 );
+ pn = 0;
+ }
+ ygv608.pattern_name_table[pn] = data;
+
+ p0_state++;
+ if ((ygv608.regs.s.r7 & r7_md) == MD_2PLANE_8BIT )
+ p0_state++;
+
+ if (p0_state == 2)
+ {
+ if (ygv608.regs.s.r0 & r0_pnya)
+ {
+ if (yTile++ == (ygv608.page_y - 1))
+ {
+ yTile = 0;
+ if (xTile++ == (ygv608.page_x - 1))
+ {
+ xTile = 0;
+ ygv608.regs.s.r0 ^= r0_b_a;
+ }
+ }
+ ygv608.regs.s.r0 &= ~r0_pny;
+ ygv608.regs.s.r0 |= yTile;
+ ygv608.regs.s.r1 &= ~r1_pnx;
+ ygv608.regs.s.r1 |= xTile;
+ }
+ else if (ygv608.regs.s.r1 & r1_pnxa)
+ {
+ if (xTile++ == (ygv608.page_x - 1))
+ {
+ xTile = 0;
+ if (yTile++ == (ygv608.page_y - 1))
+ {
+ yTile = 0;
+ ygv608.regs.s.r0 ^= r0_b_a;
+ }
+ }
+ ygv608.regs.s.r0 &= ~r0_pny;
+ ygv608.regs.s.r0 |= yTile;
+ ygv608.regs.s.r1 &= ~r1_pnx;
+ ygv608.regs.s.r1 |= xTile;
+ }
+ p0_state = 0;
+ pattern_name_base = 0;
+ }
+ }
+ break;
+
+ case 0x01: /* P#1 - sprite data port */
+ ygv608.sprite_attribute_table.b[ygv608.regs.s.saa] = data;
+ if( ygv608.regs.s.r2 & r2_saaw)
+ ygv608.regs.s.saa++;
+ break;
+
+ case 0x02: /* P#2 - scroll data port */
+ ygv608.scroll_data_table[(ygv608.regs.s.r2 & r2_b_a) >> 4][ygv608.regs.s.sca] = data;
+ if (ygv608.regs.s.r2 & r2_scaw)
+ {
+ ygv608.regs.s.sca++;
+ /* handle wrap to next plane */
+ if (ygv608.regs.s.sca == 0)
+ ygv608.regs.s.r2 ^= r2_b_a;
+ }
+ break;
+
+ case 0x03: /* P#3 - colour palette data port */
+ ygv608.colour_palette[ygv608.regs.s.cc][p3_state] = data;
+ if (++p3_state == 3)
+ {
+ p3_state = 0;
+ palette_set_color_rgb(Machine,ygv608.regs.s.cc,
+ pal6bit(ygv608.colour_palette[ygv608.regs.s.cc][0]),
+ pal6bit(ygv608.colour_palette[ygv608.regs.s.cc][1]),
+ pal6bit(ygv608.colour_palette[ygv608.regs.s.cc][2]) );
+ if (ygv608.regs.s.r2 & r2_cpaw)
+ ygv608.regs.s.cc++;
+ }
+ break;
+
+ case 0x04: /* P#4 - register data port */
+ {
+ UINT8 regNum = (ygv608.ports.s.p5) & p5_rn;
+#if 0
+ logerror( "R#%d = $%02X\n", regNum, data );
+#endif
+ SetPreShortcuts (regNum, data);
+ ygv608.regs.b[regNum] = data;
+ SetPostShortcuts (regNum);
+ if (ygv608.ports.s.p5 & p5_rwai)
+ {
+ regNum ++;
+ if (regNum == 50)
+ {
+ regNum = 0;
+ logerror( "warning: rn=50 after write increment\n" );
+ }
+ ygv608.ports.s.p5 &= ~p5_rn;
+ ygv608.ports.s.p5 |= regNum;
+ }
+ }
+ break;
+
+ case 0x05: /* P#5 - register select port */
+ ygv608.ports.b[5] = data;
+ break;
+
+ case 0x06: /* P#6 - status port */
+ /* writing a '1' resets that bit */
+ ygv608.ports.b[6] &= ~data;
+ break;
+
+ case 0x07: /* P#7 - system control port */
+ ygv608.ports.b[7] = data;
+ if (ygv608.ports.b[7] & 0x3e)
+ HandleRomTransfers();
+ if (ygv608.ports.b[7] & 0x01)
+ HandleYGV608Reset();
+ break;
+
+ default:
+ logerror( "unknown ygv608 register (%d)\n", offset );
+ break;
+ }
+}
+
+static void HandleYGV608Reset( void )
+{
+ int i;
+
+ /* Clear ports #0-7 */
+ memset( &ygv608.ports.b[0], 0, 8 );
+
+ /* Clear registers #0-38, #47-49 */
+ memset( &ygv608.regs.b[0], 0, 39 );
+ memset( &ygv608.regs.b[47], 0, 3 );
+
+ /* Clear internal ram */
+ memset( ygv608.pattern_name_table, 0, 4096 );
+ memset( ygv608.sprite_attribute_table.b, 0,
+ YGV608_SPRITE_ATTR_TABLE_SIZE );
+ memset( ygv608.scroll_data_table, 0, 2*256 );
+ memset( ygv608.colour_palette, 0, 256*3 );
+
+ /* should set shortcuts here too */
+ for( i=0; i<50; i++ ) {
+ //SetPreShortcuts( i );
+ SetPostShortcuts( i );
+ }
+}
+
+/*
+ The YGV608 has a function to block-move data from the rom into
+ internal tables. This function is not used in NCV1, but I used
+ it for testing trojan ROM software.
+ - So leave it in!
+ */
+
+static void HandleRomTransfers(void)
+{
+#if 0
+ static UINT8 *sdt = (UINT8 *)ygv608.scroll_data_table;
+ static UINT8 *sat = (UINT8 *)ygv608.sprite_attribute_table.b;
+
+ /* fudge copy from sprite data for now... */
+ UINT8 *RAM = Machine->memory_region[0];
+ int i;
+
+ int src = ( ( (int)ygv608.regs.s.tb13 << 8 ) +
+ (int)ygv608.regs.s.tb5 ) << 5;
+ int bytes = (int)ygv608.regs.s.tn4 << 4;
+
+ logerror( "Transferring data from rom...\n" );
+
+ /* pattern name table */
+ if( ygv608.ports.s.tn ) {
+ }
+
+ /* scroll table */
+ if( ygv608.ports.s.tl ) {
+
+ int dest = (int)ygv608.regs.s.sca;
+ if( ygv608.regs.s.p2_b_a )
+ dest += 0x100;
+
+ /* fudge a transfer for now... */
+ for( i=0; i<bytes; i++ ) {
+ sdt[(dest+i)%512] = RAM[src+(i^0x01)];
+
+ }
+
+ /* flag as finished */
+ ygv608.ports.s.tl = 0;
+ }
+
+ /* sprite attribute table */
+ if( ygv608.ports.s.ts ) {
+
+ int dest = (int)ygv608.regs.s.saa;
+
+ /* fudge a transfer for now... */
+ for( i=0; i<bytes; i++ ) {
+ sat[(dest+i)%256] = RAM[src+(i^0x01)];
+
+ }
+
+ /* flag as finished */
+ ygv608.ports.s.ts = 0;
+ }
+#endif
+}
+
+#if 0
+void nvsram( offs_t offset, UINT16 data )
+{
+ static int i = 0;
+
+ data = ( data >> 8 ) & 0xff;
+
+ if( 1 ) {
+ static char ascii[16];
+ if( i%16 == 0 )
+ logerror( "%04X: ", offset );
+ logerror( "%02X ", data );
+ ascii[i%16] = ( isprint( data ) ? data : '.' );
+ if( i%16 == 15 )
+ logerror( "| %-16.16s\n", ascii );
+ }
+
+ i++;
+}
+#endif
+
+// Set any "short-cut" variables before we update the YGV608 registers
+// - these are used only in optimisation of the emulation
+
+static void SetPreShortcuts( int reg, int data )
+{
+ switch( reg ) {
+
+ case 7 :
+ if( ( ( data >> MD_SHIFT ) & MD_MASK ) != (ygv608.regs.s.r7 & r7_md))
+ ygv608.tilemap_resize = 1;
+ break;
+
+ case 8 :
+ if( ( ( data >> PGS_SHIFT ) & PGS_MASK ) != (ygv608.regs.s.r8 & r8_pgs))
+ ygv608.tilemap_resize = 1;
+ break;
+
+ case 9 :
+ if( ( ( data >> PTS_SHIFT ) & PTS_MASK ) != (ygv608.regs.s.r9 & r9_pts))
+ ygv608.tilemap_resize= 1;
+ break;
+
+ case 40 :
+ if( ( ( data >> HDW_SHIFT ) & HDW_MASK ) != (ygv608.regs.s.r40 & r40_hdw))
+ ygv608.screen_resize = 1;
+ break;
+
+ case 44 :
+ if( ( ( data >> VDW_SHIFT ) & VDW_MASK ) != (ygv608.regs.s.r44 & r44_vdw))
+ ygv608.screen_resize = 1;
+ break;
+ }
+}
+
+// Set any "short-cut" variables after we have updated the YGV608 registers
+// - these are used only in optimisation of the emulation
+
+static void SetPostShortcuts( int reg )
+{
+ int plane, addr;
+
+ switch (reg)
+ {
+ case 0:
+ {
+ UINT8 yTile = ygv608.regs.s.r0 & r0_pny;
+
+ if (yTile >= ygv608.page_y)
+ logerror ("setting pny(%d) >= page_y(%d) @ $%X\n",
+ yTile, ygv608.page_y, activecpu_get_pc() );
+ yTile &= (ygv608.page_y - 1);
+ ygv608.regs.s.r0 &= ~r0_pny;
+ ygv608.regs.s.r0 |= yTile;
+ }
+ break;
+
+ case 1:
+ {
+ UINT8 xTile = ygv608.regs.s.r1 & r1_pnx;
+
+ if (xTile >= ygv608.page_x)
+ logerror ("setting pnx(%d) >= page_x(%d) @ $%X\n",
+ xTile, ygv608.page_x, activecpu_get_pc() );
+ xTile &= (ygv608.page_x - 1);
+ ygv608.regs.s.r1 &= ~r1_pnx;
+ ygv608.regs.s.r1 |= xTile;
+ }
+ break;
+
+ case 6:
+#if 0
+ logerror( "SBA = $%08X\n", (int)ygv608.regs.s.sba << 13 );
+#endif
+ break;
+
+ case 7:
+ ygv608.na8_mask = ((ygv608.regs.s.r7 & r7_flip) ? 0x03 : 0x0f );
+ /* fall thru */
+
+ case 8 :
+ ygv608.bits16 = ((ygv608.regs.s.r7 & r7_md) == MD_2PLANE_8BIT ? 0 : 1 );
+ if((ygv608.regs.s.r7 & r7_md) == MD_2PLANE_16BIT )
+ ygv608.page_x = ygv608.page_y = 32;
+ else {
+ if ((ygv608.regs.s.r8 & r8_pgs) == 0 ) {
+ ygv608.page_x = 64;
+ ygv608.page_y = 32;
+ }
+ else {
+ ygv608.page_x = 32;
+ ygv608.page_y = 64;
+ }
+ }
+ ygv608.pny_shift = ( ygv608.page_x == 32 ? 5 : 6 );
+
+ /* bits to shift pattern y coordinate to extract base */
+ ygv608.base_y_shift = ( ygv608.page_y == 32 ? 2 : 3 );
+
+ break;
+
+ case 9 :
+ switch (ygv608.regs.s.r9 & r9_slv)
+ {
+ case SLV_SCREEN :
+ // always use scoll table entry #1
+ ygv608.col_shift = 8;
+ break;
+ default :
+ if ((ygv608.regs.s.r9 & r9_pts) == PTS_8X8 )
+ ygv608.col_shift = (ygv608.regs.s.r9 & r9_slv) - 4;
+ else
+ ygv608.col_shift = (ygv608.regs.s.r9 & r9_slv) - 5;
+ if( ygv608.col_shift < 0 )
+ {
+ // we can't handle certain conditions
+ logerror( "Unhandled slv condition (pts=$%X,slv=$%X)\n",
+ ygv608.regs.s.r9 & r9_pts, ygv608.regs.s.r9 & r9_slv);
+ ygv608.col_shift = 8;
+ }
+ break;
+ }
+
+ //if( ygv608.regs.s.slh != SLH_SCREEN )
+ // logerror( "SLH = %1X\n", ygv608.regs.s.slh );
+ break;
+
+ case 11 :
+ //ShowYGV608Registers();
+ break;
+
+ case 17 : case 18 : case 19 : case 20 :
+ case 21 : case 22 : case 23 : case 24 :
+ plane = (reg-17) >> 2;
+ addr = ( (reg-17) << 1 ) & 0x07;
+ ygv608.base_addr[plane][addr] = ygv608.regs.b[reg] & 0x0f;
+ ygv608.base_addr[plane][addr+1] = ygv608.regs.b[reg] >> 4;
+ break;
+
+ case 25 : case 26 : case 27 :
+ ygv608.ax = (int)(ygv608.regs.s.ax16 & 0x1f) << 16 |
+ (int)ygv608.regs.s.ax8 << 8 |
+ (int)ygv608.regs.s.ax0;
+ ygv608.ax <<= 7;
+ if( ygv608.ax & 0x08000000 ) ygv608.ax |= 0xf8000000; // 2s complement
+ //logerror( "ygv608.ax = $%X\n", ygv608.ax );
+ break;
+
+ case 28 : case 29 :
+ ygv608.dx = (int)(ygv608.regs.s.dx8 & 0x1f) << 8 | (int)ygv608.regs.s.dx0;
+ ygv608.dx <<= 7;
+ if( ygv608.dx & 0x00080000 ) ygv608.dx |= 0xfff80000; // 2s complement
+ break;
+
+ case 30 : case 31 :
+ ygv608.dxy = (int)(ygv608.regs.s.dxy8 & 0x1f) << 8 | (int)ygv608.regs.s.dxy0;
+ ygv608.dxy <<= 7;
+ if( ygv608.dxy & 0x00080000 ) ygv608.dxy |= 0xfff80000; // 2s complement
+ break;
+
+ case 32 : case 33 : case 34 :
+ ygv608.ay = (int)(ygv608.regs.s.ay16 & 0x1f) << 16 |
+ (int)ygv608.regs.s.ay8 << 8 |
+ (int)ygv608.regs.s.ay0;
+ ygv608.ay <<= 7;
+ if( ygv608.ay & 0x08000000 ) ygv608.ay |= 0xf8000000; // 2s complement
+ //logerror( "ygv608.ay = $%X\n", ygv608.ay );
+ break;
+
+ case 35 : case 36 :
+ ygv608.dy = (int)(ygv608.regs.s.dy8 & 0x1f) << 8 | (int)ygv608.regs.s.dy0;
+ ygv608.dy <<= 7;
+ if( ygv608.dy & 0x00080000 ) ygv608.dy |= 0xfff80000; // 2s complement
+ break;
+
+ case 37 : case 38 :
+ ygv608.dyx = (int)(ygv608.regs.s.dyx8 & 0x1f) << 8 | (int)ygv608.regs.s.dyx0;
+ ygv608.dyx <<= 7;
+ if( ygv608.dyx & 0x00080000 ) ygv608.dyx |= 0xfff80000; // 2s complement
+ break;
+
+ case 40 : case 41 : case 42 :
+ //ShowYGV608Registers();
+ break;
+
+ }
+
+}
+
+/*
+ * The rest of this stuff is for debugging only!
+ */
+
+#ifdef MAME_DEBUG
+
+#define nSHOW_SOURCE_MODE
+
+#if 0
+void dump_block( char *name, UINT8 *block, int len )
+{
+ int i;
+
+ logerror( "UINT8 %s[] = {\n", name );
+ for( i=0; i<len; i++ ) {
+ if( i%8 == 0 )
+ logerror( " " );
+ logerror( "0x%02X, ", block[i] );
+ if( i%8 == 7 )
+ logerror( "\n" );
+ }
+ logerror( "};\n" );
+}
+#endif
+READ16_HANDLER( ygv608_debug_trigger )
+{
+ static int oneshot = 0;
+
+ int i;
+ char ascii[16];
+
+ if( oneshot )
+ return( 0 );
+ oneshot = 1;
+
+ ShowYGV608Registers();
+
+#ifdef SHOW_SOURCE_MODE
+#if 0
+ dump_block( "ygv608_regs",
+ (UINT8 *)ygv608.regs.b,
+ 64 );
+ dump_block( "ygv608_pnt",
+ (UINT8 *)ygv608.pattern_name_table,
+ 4096 );
+ dump_block( "ygv608_sat",
+ (UINT8 *)ygv608.sprite_attribute_table.b,
+ 256 );
+ dump_block( "ygv608_sdt",
+ (UINT8 *)ygv608.scroll_data_table,
+ 512 );
+ dump_block( "ygv608_cp",
+ (UINT8 *)ygv608.colour_palette,
+ 768 );
+#endif
+
+#else
+
+ /*
+ * Dump pattern name table ram
+ */
+#if 1
+ logerror( "Pattern Name Table\n" );
+ for( i=0; i<4096; i++ ) {
+ if( i % 16 == 0 )
+ logerror( "$%04X : ", i );
+ logerror( "%02X ", ygv608.pattern_name_table[i] );
+ if( isprint( ygv608.pattern_name_table[i] ) )
+ ascii[i%16] = ygv608.pattern_name_table[i];
+ else
+ ascii[i%16] = '.';
+ if( i % 16 == 15 )
+ logerror( " | %-16.16s\n", ascii );
+ }
+ logerror( "\n" );
+#endif
+
+ /*
+ * Dump scroll table ram
+ */
+
+ logerror( "Scroll Table\n" );
+ for( i=0; i<512; i++ ) {
+ if( i % 16 == 0 )
+ logerror( "$%04X : ", i );
+ logerror( "%02X ", ygv608.scroll_data_table[0][i] );
+ if( isprint( ygv608.scroll_data_table[0][i] ) )
+ ascii[i%16] = ygv608.scroll_data_table[0][i];
+ else
+ ascii[i%16] = '.';
+ if( i % 16 == 15 )
+ logerror( " | %-16.16s\n", ascii );
+ }
+ logerror( "\n" );
+
+#endif
+
+ return( 0 );
+}
+
+void ShowYGV608Registers( void )
+{
+ int p, b;
+
+ logerror( "YGV608 Registers\n" );
+ logerror(
+ "\tR#00: $%02X : PNYA(%d),B/A(%c),PNY(%d)\n",
+ ygv608.regs.b[0],
+ ygv608.regs.s.r0 & r0_pnya,
+ ((ygv608.regs.s.r0 & r0_b_a) ? 'B' : 'A' ),
+ ygv608.regs.s.r0 & r0_pny);
+
+ logerror(
+ "\tR#01: $%02X : PNXA(%d),PNX(%d)\n",
+ ygv608.regs.b[1],
+ ygv608.regs.s.r1 & r1_pnxa,
+ ygv608.regs.s.r1 & r1_pnx);
+
+ logerror(
+ "\tR#02: $%02X : CPAW(%d),CPAR(%d),B/A(%d),SCAW(%d),SCAR(%d),SAAW(%d),SAAR(%d)\n",
+ ygv608.regs.b[2],
+ ygv608.regs.s.r2 & r2_cpaw,
+ ygv608.regs.s.r2 & r2_cpar,
+ ygv608.regs.s.r2 & r2_b_a,
+ ygv608.regs.s.r2 & r2_scaw,
+ ygv608.regs.s.r2 & r2_scar,
+ ygv608.regs.s.r2 & r2_saaw,
+ ygv608.regs.s.r2 & r2_saar);
+
+ logerror(
+ "\tR#03: $%02X : SAA($%02X)\n",
+ ygv608.regs.b[3],
+ ygv608.regs.s.saa );
+
+ logerror(
+ "\tR#04: $%02X : SCA($%02X)\n",
+ ygv608.regs.b[4],
+ ygv608.regs.s.sca );
+
+ logerror(
+ "\tR#05: $%02X : CC($%02X)\n",
+ ygv608.regs.b[5],
+ ygv608.regs.s.cc );
+
+ logerror(
+ "\tR#06: $%02X : SBA($%02X)\n",
+ ygv608.regs.b[6],
+ ygv608.regs.s.sba );
+
+ logerror(
+ "\tR#07: $%02X : DSPE(%d),MD(%d),ZRON(%d),FLIP(%d),DCKM(%d)\n",
+ ygv608.regs.b[7],
+ ygv608.regs.s.r7 & r7_dspe,
+ ygv608.regs.s.r7 & r7_md,
+ ygv608.regs.s.r7 & r7_zron,
+ ygv608.regs.s.r7 & r7_flip,
+ ygv608.regs.s.r7 & r7_dckm);
+
+ logerror(
+ "\tR#08: $%02X : HDS(%d),VDS(%d),RLRT(%d),RLSC(%d),PGS(%d)\n",
+ ygv608.regs.b[8],
+ ygv608.regs.s.r8 & r8_hds,
+ ygv608.regs.s.r8 & r8_vds,
+ ygv608.regs.s.r8 & r8_rlrt,
+ ygv608.regs.s.r8 & r8_rlsc,
+ ygv608.regs.s.r8 & r8_pgs);
+
+ logerror(
+ "\tR#11: $%02X : CTPA(%d),CTPB(%d),PRM(%d),CBDR(%d),YSE(%d),SCM(%d)\n",
+ ygv608.regs.b[11],
+ ygv608.regs.s.r11 & r11_ctpa,
+ ygv608.regs.s.r11 & r11_ctpb,
+ ygv608.regs.s.r11 & r11_prm,
+ ygv608.regs.s.r11 & r11_cbdr,
+ ygv608.regs.s.r11 & r11_yse,
+ ygv608.regs.s.r11 & r11_scm);
+
+ logerror(
+ "\tR#40: $%02X : HTL9:8($%02X)=$%06X,HDW(%d)\n",
+ ygv608.regs.b[40],
+ ygv608.regs.s.r40 & r40_htl89, (int)(ygv608.regs.s.r40 & r40_htl89) << 8,
+ ygv608.regs.s.r40 & r40_hdw);
+
+ logerror(
+ "\tR#41: $%02X : HDSP($%02X)\n",
+ ygv608.regs.b[41],
+ ygv608.regs.s.hdsp );
+
+ logerror(
+ "\tR#42: $%02X : HTL7:0($%02X)\n",
+ ygv608.regs.b[42],
+ ygv608.regs.s.htl );
+
+ logerror(
+ "\t HTL=$%03X\n",
+ ( (int)(ygv608.regs.s.r40 & r40_htl89) << 8 ) |
+ ( (int)ygv608.regs.s.htl ) );
+
+ logerror(
+ "\tR#47: $%02X : TB12:5($%02X) = $%06X\n",
+ ygv608.regs.b[47],
+ ygv608.regs.s.tb5, (int)ygv608.regs.s.tb5 << 5 );
+
+ logerror(
+ "\tR#48: $%02X : TB20:13($%02X) = $%06X\n",
+ ygv608.regs.b[48],
+ ygv608.regs.s.tb13, (int)ygv608.regs.s.tb13 << 13 );
+
+ logerror(
+ "\t TB=$%06X\n",
+ ( (int)ygv608.regs.s.tb13 << 13 ) |
+ ( (int)ygv608.regs.s.tb5 << 5 ) );
+
+ logerror(
+ "\tR#49: $%02X : TN11:4($%02X) = $%04X\n",
+ ygv608.regs.b[49],
+ ygv608.regs.s.tn4, (int)ygv608.regs.s.tn4 << 4 );
+
+ logerror(
+ "ShortCuts:\n" );
+
+ for( p=0; p<2; p++ ) {
+ logerror( "\t" );
+ for( b=0; b<8; b++ ) {
+ logerror( "%02X ", ygv608.base_addr[p][b] );
+ }
+ logerror( "\n" );
+ }
+}
+
+#endif // MAME_DEBUG
diff --git a/src/mame/video/ygv608.h b/src/mame/video/ygv608.h
new file mode 100644
index 00000000000..66f5ff80d0e
--- /dev/null
+++ b/src/mame/video/ygv608.h
@@ -0,0 +1,342 @@
+#ifndef __YGV608_H__
+#define __YGV608_H__
+
+/*
+ * Yamaha YGV608 - PVDC2 Pattern mode Video Display Controller 2
+ * - Mark McDougall
+ */
+
+// Fundamental constants
+#define YGV608_SPRITE_ATTR_TABLE_SIZE 256
+
+enum {
+ p5_rwai = 0x80, // increment register select on reads
+ p5_rrai = 0x40, // increment register select on writes
+ p5_rn = 0x3f, // register select
+
+// p6_res6 = 0xe0,
+ p6_fp = 0x10, // position detection flag
+ p6_fv = 0x08, // vertical border interval flag
+ p6_fc = 0x04,
+ p6_hb = 0x02, // horizontal blanking flag?
+ p6_vb = 0x01, // vertical blanking flag?
+
+// p7_res7 = 0xc0,
+ p7_tr = 0x20,
+ p7_tc = 0x10,
+ p7_tl = 0x08,
+ p7_ts = 0x04,
+ p7_tn = 0x02,
+ p7_sr = 0x01,
+
+ r0_pnya = 0x80, // if set, increment name table address after reads
+ r0_b_a = 0x40, // if set, we're reading from the second plane of tile data
+ r0_pny = 0x3f, // y-coordinate of current name table address
+
+ r1_pnxa = 0x80, // if set, increment name table address after read
+ r1_res1 = 0x40,
+ r1_pnx = 0x3f, // x-coordinate of current name table address
+
+ r2_cpaw = 0x80, // if set, increment color palette address after writes
+ r2_cpar = 0x40, // if set, increment color palette address after reads
+// r2_res2 = 0x20,
+ r2_b_a = 0x10,
+ r2_scaw = 0x08, // if set, increment scroll address after writes
+ r2_scar = 0x04, // if set, increment scroll address after reads
+ r2_saaw = 0x02, // if set, increment sprite address after writes
+ r2_saar = 0x01, // if set, increment sprite address after reads
+
+ r7_dckm = 0x80,
+ r7_flip = 0x40,
+// r7_res7 = 0x30,
+ r7_zron = 0x08, // if set, roz plane is active
+ r7_md = 0x06, // determines 1 of 4 possible video modes
+ r7_dspe = 0x01, // if set, display is enabled
+
+ r8_hds = 0xc0,
+ r8_vds = 0x30,
+ r8_rlrt = 0x08,
+ r8_rlsc = 0x04,
+// r8_res8 = 0x02,
+ r8_pgs = 0x01,
+
+ r9_pts = 0xc0,
+ r9_slh = 0x38,
+ r9_slv = 0x07,
+
+ r10_spa = 0xc0, // misc global sprite attributes (x/y flip or sprite size)
+ r10_spas = 0x20, // if set, spa controls sprite flip, if clear, controls sprite size
+ r10_sprd = 0x10, // if set, sprites are disabled
+ r10_mcb = 0x0c,
+ r10_mca = 0x03,
+
+ r11_scm = 0xc0,
+ r11_yse = 0x20,
+ r11_cbdr = 0x10,
+ r11_prm = 0x0c, // determines one of 4 priority settings
+ r11_ctpb = 0x02,
+ r11_ctpa = 0x01,
+
+ r12_spf = 0xc0,
+ r12_bpf = 0x38,
+ r12_apf = 0x07,
+
+// r14_res14 = 0xfc,
+ r14_iep = 0x02, // if set, generate IRQ on position detection (?)
+ r14_iev = 0x01, // if set, generate IRQ on vertical border interval draw
+
+ // these 4 are currently unimplemented by us
+ r16_fpm = 0x80,
+ r16_il8 = 0x40,
+ r16_res16 = 0x20,
+ r16_ih = 0x1f,
+
+ r17_ba1 = 0x70,
+ r17_ba0 = 0x07,
+ r18_ba3 = 0x70,
+ r18_ba2 = 0x07,
+ r19_ba5 = 0x70,
+ r19_ba4 = 0x07,
+ r20_ba7 = 0x70,
+ r20_ba6 = 0x07,
+ r21_bb1 = 0x70,
+ r21_bb0 = 0x07,
+ r22_bb3 = 0x70,
+ r22_bb2 = 0x07,
+ r23_bb5 = 0x70,
+ r23_bb4 = 0x07,
+ r24_bb7 = 0x70,
+ r24_bb6 = 0x07,
+
+ r39_hsw = 0xe0,
+ r39_hbw = 0x1f,
+
+ r40_htl89 = 0xc0,
+ r40_hdw = 0x3f,
+
+ r43_vsw = 0xe0,
+ r43_vbw = 0x1f,
+
+ r44_vsls = 0x40,
+ r44_vdw = 0x1f,
+
+ r45_vtl8 = 0x80,
+ r45_tres = 0x40,
+ r45_vdp = 0x1f
+};
+
+
+typedef struct _ygv_ports {
+ UINT8 na; // P#0 - pattern name table data port (read/write)
+ UINT8 p1; // P#1 - sprite data port (read/write)
+ UINT8 p2; // P#2 - scroll data port (read/write)
+ UINT8 p3; // P#3 - colour palette data port (read/write)
+ UINT8 p4; // P#4 - register data port (read/write)
+ UINT8 p5; // P#5 - register select port (write only)
+ UINT8 p6; // P#6 - status port (read/write)
+ UINT8 p7; // P#7 - system control port (read/write)
+} YGV_PORTS, *pYGV_PORTS;
+
+typedef struct _ygv_regs {
+ UINT8 r0; // R#0 - pattern name table access ptr (r/w)
+ UINT8 r1; // R#1 - pattern name table access ptr (r/w)
+ UINT8 r2; // R#2 - built in ram access control
+ UINT8 saa; // R#3 - sprite attribute table access ptr (r/w)
+ UINT8 sca; // R#4 - scroll table access ptr (r/w)
+ UINT8 cc; // R#5 - color palette access ptr (r/w)
+ UINT8 sba; // R#6 - sprite generator base address (r/w)
+
+ // R#7 - R#11 - screen control (r/w)
+ UINT8 r7; // misc screen control (r/w)
+ UINT8 r8; // misc screen control (r/w)
+ UINT8 r9; // misc screen control (r/w)
+ UINT8 r10; // misc screen control (r/w)
+ UINT8 r11; // misc screen control (r/w)
+
+ UINT8 r12; // R#12 - color palette selection (r/w)
+ UINT8 bdc; // R#13 - border colour (wo)
+
+ // R#14 - R#16 - interrupt control
+ UINT8 r14;
+ UINT8 il;
+ UINT8 r16;
+
+ // R#17 - R#24 - base address (wo)
+ UINT8 r17;
+ UINT8 r18;
+ UINT8 r19;
+ UINT8 r20;
+ UINT8 r21;
+ UINT8 r22;
+ UINT8 r23;
+ UINT8 r24;
+
+ // R#25 - R#38 - enlargement, contraction and rotation parameters (wo)
+ UINT8 ax0;
+ UINT8 ax8;
+ UINT8 ax16;
+
+ UINT8 dx0;
+ UINT8 dx8;
+ UINT8 dxy0;
+ UINT8 dxy8;
+
+ UINT8 ay0;
+ UINT8 ay8;
+ UINT8 ay16;
+
+ UINT8 dy0;
+ UINT8 dy8;
+ UINT8 dyx0;
+ UINT8 dyx8;
+
+ // R#39 - R#46 - display scan control (wo)
+ UINT8 r39;
+ UINT8 r40;
+ UINT8 hdsp;
+ UINT8 htl;
+ UINT8 r43;
+ UINT8 r44;
+ UINT8 r45;
+ UINT8 vtl;
+
+ // R#47 - R#49 - rom transfer control (wo)
+ UINT8 tb5;
+ UINT8 tb13;
+ UINT8 tn4;
+
+} YGV_REGS, *pYGV_REGS;
+
+#define YGV608_MAX_SPRITES (YGV608_SPRITE_ATTR_TABLE_SIZE>>2)
+
+// R#7(md)
+#define MD_2PLANE_8BIT 0x00
+#define MD_2PLANE_16BIT 0x02
+#define MD_1PLANE_16COLOUR 0x04
+#define MD_1PLANE_256COLOUR 0x06
+#define MD_1PLANE (MD_1PLANE_16COLOUR & MD_1PLANE_256COLOUR)
+#define MD_SHIFT 0
+#define MD_MASK 0x06
+
+// R#8
+#define PGS_64X32 0x0
+#define PGS_32X64 0x1
+#define PGS_SHIFT 0
+#define PGS_MASK 0x01
+
+// R#9
+#define SLV_SCREEN 0x00
+#define SLV_8 0x04
+#define SLV_16 0x05
+#define SLV_32 0x06
+#define SLV_64 0x07
+#define SLH_SCREEN 0x00
+#define SLH_8 0x04
+#define SLH_16 0x05
+#define SLH_32 0x06
+#define SLH_64 0x07
+#define PTS_8X8 0x00
+#define PTS_16X16 0x40
+#define PTS_32X32 0x80
+#define PTS_64X64 0xc0
+#define PTS_SHIFT 0
+#define PTS_MASK 0xc0
+
+// R#10
+#define SPAS_SPRITESIZE 0
+#define SPAS_SPRITEREVERSE 1
+
+// R#10(spas)=1
+#define SZ_8X8 0x00
+#define SZ_16X16 0x01
+#define SZ_32X32 0x02
+#define SZ_64X64 0x03
+
+// R#10(spas)=0
+#define SZ_NOREVERSE 0x00
+#define SZ_VERTREVERSE 0x01
+#define SZ_HORIZREVERSE 0x02
+#define SZ_BOTHREVERSE 0x03
+
+// R#11(prm)
+#define PRM_SABDEX 0x00
+#define PRM_ASBDEX 0x04
+#define PRM_SEABDX 0x08
+#define PRM_ASEBDX 0x0c
+
+// R#40
+#define HDW_SHIFT 0
+#define HDW_MASK 0x3f
+
+// R#44
+#define VDW_SHIFT 0
+#define VDW_MASK 0x3f
+
+typedef struct {
+ UINT8 sy; // y dot position 7:0
+ UINT8 sx; // x dot position 7:0
+ UINT8 attr; // 0xf0 = color, 0x0c = size, reverse, 0x02 = x hi bit, 0x01 = y hi bit
+ UINT8 sn; // pattern name (0-255)
+} SPRITE_ATTR, *PSPRITE_ATTR;
+
+
+typedef struct _ygv608 {
+
+ union {
+ UINT8 b[8];
+ YGV_PORTS s;
+ } ports;
+
+ union {
+ UINT8 b[50];
+ YGV_REGS s;
+ } regs;
+
+ /*
+ * Built in ram
+ */
+
+ UINT8 pattern_name_table[4096];
+
+ union {
+ UINT8 b[YGV608_SPRITE_ATTR_TABLE_SIZE];
+ SPRITE_ATTR s[YGV608_MAX_SPRITES];
+ } sprite_attribute_table;
+
+ UINT8 scroll_data_table[2][256];
+ UINT8 colour_palette[256][3];
+
+ /*
+ * Shortcut variables
+ */
+
+ UINT32 bits16; // bits per pattern (8/16)
+ UINT32 page_x, page_y; // pattern page size
+ UINT32 pny_shift; // y coord multiplier
+ UINT8 na8_mask; // mask on/off na11/9:8
+ int col_shift; // shift in scroll table column index
+
+ // rotation, zoom shortcuts
+ UINT32 ax, dx, dxy, ay, dy, dyx;
+
+ // base address shortcuts
+ UINT32 base_addr[2][8];
+ UINT32 base_y_shift; // for extracting pattern y coord 'base'
+
+ UINT8 screen_resize; // screen requires resize
+ UINT8 tilemap_resize; // tilemap requires resize
+
+} YGV608, *pYGV608;
+
+
+INTERRUPT_GEN( ygv608_timed_interrupt );
+VIDEO_START( ygv608 );
+VIDEO_UPDATE( ygv608 );
+
+READ16_HANDLER( ygv608_r );
+WRITE16_HANDLER( ygv608_w );
+
+// to be removed
+extern READ16_HANDLER( ygv608_debug_trigger );
+
+#endif
diff --git a/src/mame/video/yiear.c b/src/mame/video/yiear.c
new file mode 100644
index 00000000000..ea24a644aac
--- /dev/null
+++ b/src/mame/video/yiear.c
@@ -0,0 +1,150 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+int yiear_nmi_enable;
+
+static tilemap *bg_tilemap;
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+ Yie Ar Kung-Fu has one 32x8 palette PROM, connected to the RGB output this
+ way:
+
+ bit 7 -- 220 ohm resistor -- BLUE
+ -- 470 ohm resistor -- BLUE
+ -- 220 ohm resistor -- GREEN
+ -- 470 ohm resistor -- GREEN
+ -- 1 kohm resistor -- GREEN
+ -- 220 ohm resistor -- RED
+ -- 470 ohm resistor -- RED
+ bit 0 -- 1 kohm resistor -- RED
+
+***************************************************************************/
+PALETTE_INIT( yiear )
+{
+ int i;
+
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* green component */
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* blue component */
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ color_prom++;
+ }
+}
+
+WRITE8_HANDLER( yiear_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
+}
+
+WRITE8_HANDLER( yiear_control_w )
+{
+ /* bit 0 flips screen */
+
+ if (flip_screen != (data & 0x01))
+ {
+ flip_screen_set(data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+
+ /* bit 1 is NMI enable */
+
+ yiear_nmi_enable = data & 0x02;
+
+ /* bit 2 is IRQ enable */
+
+ interrupt_enable_w(0, data & 0x04);
+
+ /* bits 3 and 4 are coin counters */
+
+ coin_counter_w(0, data & 0x08);
+ coin_counter_w(1, data & 0x10);
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int offs = tile_index * 2;
+ int attr = videoram[offs];
+ int code = videoram[offs + 1] | ((attr & 0x10) << 4);
+// int color = (attr & 0xf0) >> 4;
+ int flags = ((attr & 0x80) ? TILE_FLIPX : 0) | ((attr & 0x40) ? TILE_FLIPY : 0);
+
+ SET_TILE_INFO(0, code, 0, flags);
+}
+
+VIDEO_START( yiear )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 2;offs >= 0;offs -= 2)
+ {
+ int attr = spriteram[offs];
+ int code = spriteram_2[offs + 1] + 256 * (attr & 0x01);
+ int color = 0;
+ int flipx = ~attr & 0x40;
+ int flipy = attr & 0x80;
+ int sy = 240 - spriteram[offs + 1];
+ int sx = spriteram_2[offs];
+
+ if (flip_screen)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ if (offs < 0x26)
+ {
+ sy++; /* fix title screen & garbage at the bottom of the screen */
+ }
+
+ drawgfx(bitmap, machine->gfx[1],
+ code, color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( yiear )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mame/video/yunsun16.c b/src/mame/video/yunsun16.c
new file mode 100644
index 00000000000..f74bbd97ce8
--- /dev/null
+++ b/src/mame/video/yunsun16.c
@@ -0,0 +1,237 @@
+/***************************************************************************
+
+ -= Yun Sung 16 Bit Games =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+ [ 2 Scrolling Layers ]
+
+ Tiles are 16 x 16 x 8. The layout of the tilemap is a bit weird:
+ 16 consecutive tile codes define a vertical column.
+ 16 columns form a page (256 x 256).
+ The tilemap is made of 4 x 4 pages (1024 x 1024)
+
+ [ 512? Sprites ]
+
+ Sprites are 16 x 16 x 4 in size. There's RAM for 512, but
+ the game just copies 384 entries.
+
+
+***************************************************************************/
+
+#include "driver.h"
+
+/* Variables that driver has access to: */
+
+UINT16 *yunsun16_vram_0, *yunsun16_vram_1;
+UINT16 *yunsun16_scroll_0, *yunsun16_scroll_1;
+UINT16 *yunsun16_priority;
+
+
+/***************************************************************************
+
+
+ Tilemaps
+
+
+***************************************************************************/
+
+static tilemap *tilemap_0, *tilemap_1;
+
+#define TMAP_GFX (0)
+#define TILES_PER_PAGE_X (0x10)
+#define TILES_PER_PAGE_Y (0x10)
+#define PAGES_PER_TMAP_X (0x4)
+#define PAGES_PER_TMAP_Y (0x4)
+
+static TILEMAP_MAPPER( yunsun16_tilemap_scan_pages )
+{
+ return (row / TILES_PER_PAGE_Y) * TILES_PER_PAGE_X * TILES_PER_PAGE_Y * PAGES_PER_TMAP_X +
+ (row % TILES_PER_PAGE_Y) +
+
+ (col / TILES_PER_PAGE_X) * TILES_PER_PAGE_X * TILES_PER_PAGE_Y +
+ (col % TILES_PER_PAGE_X) * TILES_PER_PAGE_Y;
+}
+
+static TILE_GET_INFO( get_tile_info_0 )
+{
+ UINT16 code = yunsun16_vram_0[ 2 * tile_index + 0 ];
+ UINT16 attr = yunsun16_vram_0[ 2 * tile_index + 1 ];
+ SET_TILE_INFO(
+ TMAP_GFX,
+ code,
+ attr & 0xf,
+ (attr & 0x20) ? TILE_FLIPX : 0);
+}
+
+static TILE_GET_INFO( get_tile_info_1 )
+{
+ UINT16 code = yunsun16_vram_1[ 2 * tile_index + 0 ];
+ UINT16 attr = yunsun16_vram_1[ 2 * tile_index + 1 ];
+ SET_TILE_INFO(
+ TMAP_GFX,
+ code,
+ attr & 0xf,
+ (attr & 0x20) ? TILE_FLIPX : 0);
+}
+
+WRITE16_HANDLER( yunsun16_vram_0_w )
+{
+ COMBINE_DATA(&yunsun16_vram_0[offset]);
+ tilemap_mark_tile_dirty(tilemap_0,offset/2);
+}
+
+WRITE16_HANDLER( yunsun16_vram_1_w )
+{
+ COMBINE_DATA(&yunsun16_vram_1[offset]);
+ tilemap_mark_tile_dirty(tilemap_1,offset/2);
+}
+
+
+/***************************************************************************
+
+
+ Video Hardware Init
+
+
+***************************************************************************/
+
+static int sprites_scrolldx, sprites_scrolldy;
+
+VIDEO_START( yunsun16 )
+{
+ tilemap_0 = tilemap_create( get_tile_info_0,yunsun16_tilemap_scan_pages,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ TILES_PER_PAGE_X*PAGES_PER_TMAP_X,TILES_PER_PAGE_Y*PAGES_PER_TMAP_Y);
+
+ tilemap_1 = tilemap_create( get_tile_info_1,yunsun16_tilemap_scan_pages,
+ TILEMAP_TYPE_PEN,
+ 16,16,
+ TILES_PER_PAGE_X*PAGES_PER_TMAP_X,TILES_PER_PAGE_Y*PAGES_PER_TMAP_Y);
+
+ sprites_scrolldx = -0x40;
+ sprites_scrolldy = -0x0f;
+ tilemap_set_scrolldx(tilemap_0,-0x34,0);
+ tilemap_set_scrolldx(tilemap_1,-0x38,0);
+
+ tilemap_set_scrolldy(tilemap_0,-0x10,0);
+ tilemap_set_scrolldy(tilemap_1,-0x10,0);
+
+ tilemap_set_transparent_pen(tilemap_0,0xff);
+ tilemap_set_transparent_pen(tilemap_1,0xff);
+}
+
+
+/***************************************************************************
+
+
+ Sprites Drawing
+
+
+ 0.w X
+
+ 2.w Y
+
+ 4.w Code
+
+ 6.w fedc ba98 7--- ----
+ ---- ---- -6-- ---- Flip Y
+ ---- ---- --5- ---- Flip X
+ ---- ---- ---4 3210 Color
+
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+
+ int max_x = machine->screen[0].visarea.max_x+1;
+ int max_y = machine->screen[0].visarea.max_y+1;
+
+ int pri = *yunsun16_priority & 3;
+ int pri_mask;
+
+ switch( pri )
+ {
+ case 1: pri_mask = (1<<1)|(1<<2)|(1<<3); break;
+ case 2: pri_mask = (1<<2)|(1<<3); break;
+ case 3:
+ default: pri_mask = 0;
+ }
+
+ for ( offs = (spriteram_size-8)/2 ; offs >= 0; offs -= 8/2 )
+ {
+ int x = spriteram16[offs + 0];
+ int y = spriteram16[offs + 1];
+ int code = spriteram16[offs + 2];
+ int attr = spriteram16[offs + 3];
+ int flipx = attr & 0x20;
+ int flipy = attr & 0x40;
+
+
+ x += sprites_scrolldx;
+ y += sprites_scrolldy;
+
+ if (flip_screen) // not used?
+ {
+ flipx = !flipx; x = max_x - x - 16;
+ flipy = !flipy; y = max_y - y - 16;
+ }
+
+ pdrawgfx( bitmap,machine->gfx[1],
+ code,
+ attr & 0x1f,
+ flipx, flipy,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,15,
+ pri_mask );
+ }
+}
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+
+VIDEO_UPDATE( yunsun16 )
+{
+ tilemap_set_scrollx(tilemap_0, 0, yunsun16_scroll_0[ 0 ]);
+ tilemap_set_scrolly(tilemap_0, 0, yunsun16_scroll_0[ 1 ]);
+
+ tilemap_set_scrollx(tilemap_1, 0, yunsun16_scroll_1[ 0 ]);
+ tilemap_set_scrolly(tilemap_1, 0, yunsun16_scroll_1[ 1 ]);
+
+// popmessage("%04X", *yunsun16_priority);
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ if((*yunsun16_priority & 0x0c) == 4)
+ {
+ /* The color of the this layer's transparent pen goes below everything */
+ tilemap_draw(bitmap,cliprect,tilemap_0, TILEMAP_DRAW_OPAQUE, 0);
+
+ tilemap_draw(bitmap,cliprect,tilemap_0, 0, 1);
+
+ tilemap_draw(bitmap,cliprect,tilemap_1, 0, 2);
+ }
+ else if((*yunsun16_priority & 0x0c) == 8)
+ {
+ /* The color of the this layer's transparent pen goes below everything */
+ tilemap_draw(bitmap,cliprect,tilemap_1, TILEMAP_DRAW_OPAQUE, 0);
+
+ tilemap_draw(bitmap,cliprect,tilemap_1, 0, 1);
+
+ tilemap_draw(bitmap,cliprect,tilemap_0, 0, 2);
+ }
+
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/yunsung8.c b/src/mame/video/yunsung8.c
new file mode 100644
index 00000000000..f5e80d04132
--- /dev/null
+++ b/src/mame/video/yunsung8.c
@@ -0,0 +1,206 @@
+/***************************************************************************
+
+ -= Yun Sung 8 Bit Games =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+Note: if MAME_DEBUG is defined, pressing Z with:
+
+ Q shows the background layer
+ W shows the foreground layer
+
+ [ 2 Fixed Layers ]
+
+ [ Background ]
+
+ Layer Size: 512 x 256
+ Tiles: 8 x 8 x 8
+
+ [ Foreground ]
+
+ Layer Size: 512 x 256
+ Tiles: 8 x 8 x 4
+
+
+ There are no sprites.
+
+***************************************************************************/
+
+#include "driver.h"
+
+/* Variables that driver has access to: */
+
+UINT8 *yunsung8_videoram_0, *yunsung8_videoram_1;
+int yunsung8_layers_ctrl;
+
+/* Variables only used here: */
+
+static tilemap *tilemap_0, *tilemap_1;
+static int yunsung8_videobank;
+
+
+/***************************************************************************
+
+ Memory Handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( yunsung8_videobank_w )
+{
+ yunsung8_videobank = data;
+}
+
+
+READ8_HANDLER( yunsung8_videoram_r )
+{
+ int bank;
+
+ /* Bit 1 of the bankswitching register contols the c000-c7ff
+ area (Palette). Bit 0 controls the c800-dfff area (Tiles) */
+
+ if (offset < 0x0800) bank = yunsung8_videobank & 2;
+ else bank = yunsung8_videobank & 1;
+
+ if (bank) return yunsung8_videoram_0[offset];
+ else return yunsung8_videoram_1[offset];
+}
+
+
+WRITE8_HANDLER( yunsung8_videoram_w )
+{
+ if (offset < 0x0800) // c000-c7ff Banked Palette RAM
+ {
+ int bank = yunsung8_videobank & 2;
+ UINT8 *RAM;
+ int color;
+
+ if (bank) RAM = yunsung8_videoram_0;
+ else RAM = yunsung8_videoram_1;
+
+ RAM[offset] = data;
+ color = RAM[offset & ~1] | (RAM[offset | 1] << 8);
+
+ /* BBBBBGGGGGRRRRRx */
+ palette_set_color_rgb(Machine, offset/2 + (bank ? 0x400:0), pal5bit(color >> 0), pal5bit(color >> 5), pal5bit(color >> 10));
+ }
+ else
+ {
+ int tile;
+ int bank = yunsung8_videobank & 1;
+
+ if (offset < 0x1000) tile = (offset-0x0800); // c800-cfff: Banked Color RAM
+ else tile = (offset-0x1000)/2; // d000-dfff: Banked Tiles RAM
+
+ if (bank) { yunsung8_videoram_0[offset] = data;
+ tilemap_mark_tile_dirty(tilemap_0, tile); }
+ else { yunsung8_videoram_1[offset] = data;
+ tilemap_mark_tile_dirty(tilemap_1, tile); }
+ }
+}
+
+
+WRITE8_HANDLER( yunsung8_flipscreen_w )
+{
+ tilemap_set_flip(ALL_TILEMAPS, (data & 1) ? (TILEMAP_FLIPX|TILEMAP_FLIPY) : 0);
+}
+
+
+/***************************************************************************
+
+ [ Tiles Format ]
+
+ Offset:
+
+ Video RAM + 0000.b Code (Low Bits)
+ Video RAM + 0001.b Code (High Bits)
+
+ Color RAM + 0000.b Color
+
+
+***************************************************************************/
+
+/* Background */
+
+#define DIM_NX_0 (0x40)
+#define DIM_NY_0 (0x20)
+
+static TILE_GET_INFO( get_tile_info_0 )
+{
+ int code = yunsung8_videoram_0[0x1000+tile_index * 2 + 0] + yunsung8_videoram_0[0x1000+tile_index * 2 + 1] * 256;
+ int color = yunsung8_videoram_0[0x0800+ tile_index] & 0x07;
+ SET_TILE_INFO(
+ 0,
+ code,
+ color,
+ 0);
+}
+
+/* Text Plane */
+
+#define DIM_NX_1 (0x40)
+#define DIM_NY_1 (0x20)
+
+static TILE_GET_INFO( get_tile_info_1 )
+{
+ int code = yunsung8_videoram_1[0x1000+ tile_index * 2 + 0] + yunsung8_videoram_1[0x1000+tile_index * 2 + 1] * 256;
+ int color = yunsung8_videoram_1[0x0800+ tile_index] & 0x3f;
+ SET_TILE_INFO(
+ 1,
+ code,
+ color,
+ 0);
+}
+
+
+
+
+/***************************************************************************
+
+
+ Vide Hardware Init
+
+
+***************************************************************************/
+
+VIDEO_START( yunsung8 )
+{
+ tilemap_0 = tilemap_create( get_tile_info_0, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, DIM_NX_0, DIM_NY_0 );
+
+ tilemap_1 = tilemap_create( get_tile_info_1, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8,8, DIM_NX_1, DIM_NY_1 );
+
+ tilemap_set_transparent_pen(tilemap_1,0);
+}
+
+
+
+/***************************************************************************
+
+
+ Screen Drawing
+
+
+***************************************************************************/
+
+VIDEO_UPDATE( yunsung8 )
+{
+ int layers_ctrl = (~yunsung8_layers_ctrl) >> 4;
+
+#ifdef MAME_DEBUG
+if (input_code_pressed(KEYCODE_Z))
+{
+ int msk = 0;
+ if (input_code_pressed(KEYCODE_Q)) msk |= 1;
+ if (input_code_pressed(KEYCODE_W)) msk |= 2;
+ if (msk != 0) layers_ctrl &= msk;
+}
+#endif
+
+ if (layers_ctrl&1) tilemap_draw(bitmap,cliprect, tilemap_0, 0,0);
+ else fillbitmap(bitmap,machine->pens[0],cliprect);
+
+ if (layers_ctrl&2) tilemap_draw(bitmap,cliprect, tilemap_1, 0,0);
+ return 0;
+}
diff --git a/src/mame/video/zac2650.c b/src/mame/video/zac2650.c
new file mode 100644
index 00000000000..7b18ccedc35
--- /dev/null
+++ b/src/mame/video/zac2650.c
@@ -0,0 +1,242 @@
+/*************************************************************/
+/* */
+/* Zaccaria/Zelco S2650 based games video */
+/* */
+/*************************************************************/
+
+#include "driver.h"
+
+UINT8 *s2636ram;
+static mame_bitmap *spritebitmap;
+
+static UINT8 dirtychar[256>>3];
+static int CollisionBackground;
+static int CollisionSprite;
+
+static tilemap *bg_tilemap;
+
+
+/**************************************************************/
+/* The S2636 is a standard sprite chip used by several boards */
+/* Emulation of this chip may be moved into a seperate unit */
+/* once it's workings are fully understood. */
+/**************************************************************/
+
+WRITE8_HANDLER( tinvader_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( zac_s2636_w )
+{
+ if (s2636ram[offset] != data)
+ {
+ s2636ram[offset] = data;
+ dirtychar[offset>>3] = 1;
+ }
+}
+
+READ8_HANDLER( zac_s2636_r )
+{
+ if(offset!=0xCB) return s2636ram[offset];
+ else return CollisionSprite;
+}
+
+READ8_HANDLER( tinvader_port_0_r )
+{
+ return input_port_0_r(0) - CollisionBackground;
+}
+
+/*****************************************/
+/* Check for Collision between 2 sprites */
+/*****************************************/
+
+static int SpriteCollision(running_machine *machine, int first,int second)
+{
+ int Checksum=0;
+ int x,y;
+
+ if((s2636ram[first * 0x10 + 10] < 0xf0) && (s2636ram[second * 0x10 + 10] < 0xf0))
+ {
+ int fx = (s2636ram[first * 0x10 + 10] * 4)-22;
+ int fy = (s2636ram[first * 0x10 + 12] * 3)+3;
+ int expand = (first==1) ? 2 : 1;
+
+ /* Draw first sprite */
+
+ drawgfx(spritebitmap,machine->gfx[expand],
+ first * 2,
+ 0,
+ 0,0,
+ fx,fy,
+ 0, TRANSPARENCY_NONE, 0);
+
+ /* Get fingerprint */
+
+ for (x = fx; x < fx + machine->gfx[expand]->width; x++)
+ {
+ for (y = fy; y < fy + machine->gfx[expand]->height; y++)
+ {
+ if ((x < machine->screen[0].visarea.min_x) ||
+ (x > machine->screen[0].visarea.max_x) ||
+ (y < machine->screen[0].visarea.min_y) ||
+ (y > machine->screen[0].visarea.max_y))
+ {
+ continue;
+ }
+
+ Checksum += *BITMAP_ADDR16(spritebitmap, y, x);
+ }
+ }
+
+ /* Blackout second sprite */
+
+ drawgfx(spritebitmap,machine->gfx[1],
+ second * 2,
+ 1,
+ 0,0,
+ (s2636ram[second * 0x10 + 10] * 4)-22,(s2636ram[second * 0x10 + 12] * 3) + 3,
+ 0, TRANSPARENCY_PEN, 0);
+
+ /* Remove fingerprint */
+
+ for (x = fx; x < fx + machine->gfx[expand]->width; x++)
+ {
+ for (y = fy; y < fy + machine->gfx[expand]->height; y++)
+ {
+ if ((x < machine->screen[0].visarea.min_x) ||
+ (x > machine->screen[0].visarea.max_x) ||
+ (y < machine->screen[0].visarea.min_y) ||
+ (y > machine->screen[0].visarea.max_y))
+ {
+ continue;
+ }
+
+ Checksum -= *BITMAP_ADDR16(spritebitmap, y, x);
+ }
+ }
+
+ /* Zero bitmap */
+
+ drawgfx(spritebitmap,machine->gfx[expand],
+ first * 2,
+ 1,
+ 0,0,
+ fx,fy,
+ 0, TRANSPARENCY_NONE, 0);
+ }
+
+ return Checksum;
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = videoram[tile_index];
+
+ SET_TILE_INFO(0, code, 0, 0);
+}
+
+VIDEO_START( tinvader )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 24, 24, 32, 32);
+
+ spritebitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+ tmpbitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap)
+{
+ int offs;
+
+ /* -------------------------------------------------------------- */
+ /* There seems to be a strange setup with this board, in that it */
+ /* appears that the S2636 runs from a different clock than the */
+ /* background generator, When the program maps sprite position to */
+ /* character position it only has 6 pixels of sprite for 8 pixels */
+ /* of character. */
+ /* -------------------------------------------------------------- */
+ /* n.b. The original has several graphic glitches as well, so it */
+ /* does not seem to be a fault of the emulation! */
+ /* -------------------------------------------------------------- */
+
+ CollisionBackground = 0; /* Read from 0x1e80 bit 7 */
+
+ // for collision detection checking
+ copybitmap(tmpbitmap,bitmap,0,0,0,0,&machine->screen[0].visarea,TRANSPARENCY_NONE,0);
+
+ for(offs=0;offs<0x50;offs+=0x10)
+ {
+ if((s2636ram[offs+10]<0xF0) && (offs!=0x30))
+ {
+ int spriteno = (offs / 8);
+ int expand = ((s2636ram[0xc0] & (spriteno*2))!=0) ? 2 : 1;
+ int bx = (s2636ram[offs+10] * 4) - 22;
+ int by = (s2636ram[offs+12] * 3) + 3;
+ int x,y;
+
+ if(dirtychar[spriteno])
+ {
+ /* 16x8 version */
+ decodechar(machine->gfx[1],spriteno,s2636ram,machine->drv->gfxdecodeinfo[1].gfxlayout);
+
+ /* 16x16 version */
+ decodechar(machine->gfx[2],spriteno,s2636ram,machine->drv->gfxdecodeinfo[2].gfxlayout);
+
+ dirtychar[spriteno] = 0;
+ }
+
+ /* Sprite->Background collision detection */
+ drawgfx(bitmap,machine->gfx[expand],
+ spriteno,
+ 1,
+ 0,0,
+ bx,by,
+ 0, TRANSPARENCY_PEN, 0);
+
+ for (x = bx; x < bx + machine->gfx[expand]->width; x++)
+ {
+ for (y = by; y < by + machine->gfx[expand]->height; y++)
+ {
+ if ((x < machine->screen[0].visarea.min_x) ||
+ (x > machine->screen[0].visarea.max_x) ||
+ (y < machine->screen[0].visarea.min_y) ||
+ (y > machine->screen[0].visarea.max_y))
+ {
+ continue;
+ }
+
+ if (*BITMAP_ADDR16(bitmap, y, x) != *BITMAP_ADDR16(tmpbitmap, y, x))
+ {
+ CollisionBackground = 0x80;
+ break;
+ }
+ }
+ }
+
+ drawgfx(bitmap,machine->gfx[expand],
+ spriteno,
+ 0,
+ 0,0,
+ bx,by,
+ 0, TRANSPARENCY_PEN, 0);
+ }
+ }
+
+ /* Sprite->Sprite collision detection */
+ CollisionSprite = 0;
+// if(SpriteCollision(machine, 0,1)) CollisionSprite |= 0x20; /* Not Used */
+ if(SpriteCollision(machine, 0,2)) CollisionSprite |= 0x10;
+ if(SpriteCollision(machine, 0,4)) CollisionSprite |= 0x08;
+ if(SpriteCollision(machine, 1,2)) CollisionSprite |= 0x04;
+ if(SpriteCollision(machine, 1,4)) CollisionSprite |= 0x02;
+// if(SpriteCollision(machine, 2,4)) CollisionSprite |= 0x01; /* Not Used */
+}
+
+VIDEO_UPDATE( tinvader )
+{
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ draw_sprites(machine, bitmap);
+ return 0;
+}
diff --git a/src/mame/video/zaccaria.c b/src/mame/video/zaccaria.c
new file mode 100644
index 00000000000..46342c1995c
--- /dev/null
+++ b/src/mame/video/zaccaria.c
@@ -0,0 +1,291 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+
+
+
+UINT8 *zaccaria_videoram,*zaccaria_attributesram;
+
+static tilemap *bg_tilemap;
+
+static rectangle spritevisiblearea =
+{
+ 2*8+1, 29*8-1,
+ 2*8, 30*8-1
+};
+static rectangle spritevisiblearea_flipx =
+{
+ 3*8+1, 30*8-1,
+ 2*8, 30*8-1
+};
+
+
+
+/***************************************************************************
+
+ Convert the color PROMs into a more useable format.
+
+
+Here's the hookup from the proms (82s131) to the r-g-b-outputs
+
+ Prom 9F 74LS374
+ ----------- ____________
+ 12 | 3 2 |---680 ohm----| blue out
+ 11 | 4 5 |---1k ohm-----| (+ 470 ohm pulldown)
+ 10 | 7 6 |---820 ohm-------|
+ 9 | 8 9 |---1k ohm--------| green out
+ Prom 9G | | | (+ 390 ohm pulldown)
+ 12 | 13 12 |---1.2k ohm------|
+ 11 | 14 15 |---820 ohm----------|
+ 10 | 17 16 |---1k ohm-----------| red out
+ 9 | 18 19 |---1.2k ohm---------| (+ 390 ohm pulldown)
+ |__________|
+
+
+***************************************************************************/
+PALETTE_INIT( zaccaria )
+{
+ int i,j,k;
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ for (i = 0;i < machine->drv->total_colors;i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+
+ /*
+ TODO: I'm not sure, but I think that pen 0 must always be black, otherwise
+ there's some junk brown background in Jack Rabbit.
+ From the schematics it seems that the background color can be changed, but
+ I'm not sure where it would be taken from; I think the high bits of
+ attributesram, but they are always 0 in these games so they would turn out
+ black anyway.
+ */
+ if (((i % 64) / 8) == 0)
+ {
+ palette_set_color(machine,i,MAKE_RGB(0,0,0));
+ }
+ else
+ {
+ /* red component */
+ bit0 = (color_prom[0] >> 3) & 0x01;
+ bit1 = (color_prom[0] >> 2) & 0x01;
+ bit2 = (color_prom[0] >> 1) & 0x01;
+ r = 0x46 * bit0 + 0x53 * bit1 + 0x66 * bit2;
+ /* green component */
+ bit0 = (color_prom[0] >> 0) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 3) & 0x01;
+ bit2 = (color_prom[machine->drv->total_colors] >> 2) & 0x01;
+ g = 0x46 * bit0 + 0x53 * bit1 + 0x66 * bit2;
+ /* blue component */
+ bit0 = (color_prom[machine->drv->total_colors] >> 1) & 0x01;
+ bit1 = (color_prom[machine->drv->total_colors] >> 0) & 0x01;
+ b = 0x66 * bit0 + 0x96 * bit1;
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+ }
+
+ color_prom++;
+ }
+
+ /* There are 512 unique colors, which seem to be organized in 8 blocks */
+ /* of 64. In each block, colors are not in the usual sequential order */
+ /* but in interleaved order, like Phoenix. Additionally, colors for */
+ /* background and sprites are interleaved. */
+ for (i = 0;i < 8;i++)
+ {
+ for (j = 0;j < 4;j++)
+ {
+ for (k = 0;k < 8;k++)
+ {
+ /* swap j and k to make the colors sequential */
+ COLOR(0,32 * i + 8 * j + k) = 64 * i + 8 * k + 2*j;
+ }
+ }
+ }
+ for (i = 0;i < 8;i++)
+ {
+ for (j = 0;j < 4;j++)
+ {
+ for (k = 0;k < 8;k++)
+ {
+ /* swap j and k to make the colors sequential */
+ COLOR(1,32 * i + 8 * j + k) = 64 * i + 8 * k + 2*j+1;
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+static TILE_GET_INFO( get_tile_info )
+{
+ UINT8 attr = zaccaria_videoram[tile_index + 0x400];
+ SET_TILE_INFO(
+ 0,
+ zaccaria_videoram[tile_index] + ((attr & 0x03) << 8),
+ ((attr & 0x0c) >> 2) + ((zaccaria_attributesram[2 * (tile_index % 32) + 1] & 0x07) << 2),
+ 0);
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( zaccaria )
+{
+ bg_tilemap = tilemap_create(get_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,32,32);
+
+ tilemap_set_scroll_cols(bg_tilemap,32);
+}
+
+
+
+/***************************************************************************
+
+ Memory handlers
+
+***************************************************************************/
+
+WRITE8_HANDLER( zaccaria_videoram_w )
+{
+ zaccaria_videoram[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap,offset & 0x3ff);
+}
+
+WRITE8_HANDLER( zaccaria_attributes_w )
+{
+ if (offset & 1)
+ {
+ if (zaccaria_attributesram[offset] != data)
+ {
+ int i;
+
+ for (i = offset / 2;i < 0x400;i += 32)
+ tilemap_mark_tile_dirty(bg_tilemap,i);
+ }
+ }
+ else
+ tilemap_set_scrolly(bg_tilemap,offset / 2,data);
+
+ zaccaria_attributesram[offset] = data;
+}
+
+WRITE8_HANDLER( zaccaria_flip_screen_x_w )
+{
+ flip_screen_x_set(data & 1);
+}
+
+WRITE8_HANDLER( zaccaria_flip_screen_y_w )
+{
+ flip_screen_y_set(data & 1);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int offs;
+ rectangle clip = *cliprect;
+
+ if (flip_screen_x)
+ sect_rect(&clip, &spritevisiblearea_flipx);
+ else
+ sect_rect(&clip, &spritevisiblearea);
+
+ /*
+ TODO: sprites have 32 color codes, but we are using only 8. In Jack
+ Rabbit the extra codes are all duplicates, but there is a quadruple
+ of codes in Money Money which contains two different combinations. That
+ color code seems to be used only by crocodiles, so the one we are picking
+ seems the correct one (otherwise they would be red).
+ */
+
+ /*
+ TODO: sprite placement is not perfect, I made the Jack Rabbit mouth
+ animation correct but this moves one pixel to the left the sprite
+ which masks the holes when you fall in them. The hardware is probably
+ similar to Amidar, but the code in the Amidar driver is not good either.
+ */
+ for (offs = 0;offs < spriteram_2_size;offs += 4)
+ {
+ int sx = spriteram_2[offs + 3] + 1;
+ int sy = 242 - spriteram_2[offs];
+ int flipx = spriteram_2[offs + 2] & 0x40;
+ int flipy = spriteram_2[offs + 2] & 0x80;
+
+ if (flip_screen_x)
+ {
+ sx = 240 - sx;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram_2[offs + 2] & 0x3f) + (spriteram_2[offs + 1] & 0xc0),
+ 4 * (spriteram_2[offs + 1] & 0x07),
+ flipx,flipy,
+ sx,sy,
+ &clip,TRANSPARENCY_PEN,0);
+ }
+
+ for (offs = 0;offs < spriteram_size;offs += 4)
+ {
+ int sx = spriteram[offs + 3] + 1;
+ int sy = 242 - spriteram[offs];
+ int flipx = spriteram[offs + 1] & 0x40;
+ int flipy = spriteram[offs + 1] & 0x80;
+
+ if (flip_screen_x)
+ {
+ sx = 240 - sx;
+ flipx = !flipx;
+ }
+ if (flip_screen_y)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap,machine->gfx[1],
+ (spriteram[offs + 1] & 0x3f) + (spriteram[offs + 2] & 0xc0),
+ 4 * (spriteram[offs + 2] & 0x07),
+ flipx,flipy,
+ sx,sy,
+ &clip,TRANSPARENCY_PEN,0);
+ }
+}
+
+
+VIDEO_UPDATE( zaccaria )
+{
+ tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
+
+ draw_sprites(machine, bitmap,cliprect);
+ return 0;
+}
diff --git a/src/mame/video/zaxxon.c b/src/mame/video/zaxxon.c
new file mode 100644
index 00000000000..afb6464d7f3
--- /dev/null
+++ b/src/mame/video/zaxxon.c
@@ -0,0 +1,487 @@
+/***************************************************************************
+
+ Sega Zaxxon hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "zaxxon.h"
+#include "video/resnet.h"
+
+static const UINT8 *color_codes;
+
+static UINT8 bg_enable;
+static UINT8 bg_color;
+static UINT16 bg_position;
+static UINT8 fg_color;
+
+static UINT8 congo_fg_bank;
+static UINT8 congo_color_bank;
+static UINT8 congo_custom[4];
+
+static tilemap *fg_tilemap;
+static tilemap *bg_tilemap;
+
+
+
+/*************************************
+ *
+ * Palette conversion
+ *
+ *************************************/
+
+PALETTE_INIT( zaxxon )
+{
+ static const int resistances[3] = { 1000, 470, 220 };
+ double rweights[3], gweights[3], bweights[2];
+ int i;
+
+ /* compute the color output resistor weights */
+ compute_resistor_weights(0, 255, -1.0,
+ 3, &resistances[0], rweights, 470, 0,
+ 3, &resistances[0], gweights, 470, 0,
+ 2, &resistances[1], bweights, 470, 0);
+
+ /* initialize the palette with these colors */
+ for (i = 0; i < machine->drv->total_colors; i++)
+ {
+ int bit0, bit1, bit2;
+ int r, g, b;
+
+ /* red component */
+ bit0 = (color_prom[i] >> 0) & 0x01;
+ bit1 = (color_prom[i] >> 1) & 0x01;
+ bit2 = (color_prom[i] >> 2) & 0x01;
+ r = combine_3_weights(rweights, bit0, bit1, bit2);
+
+ /* green component */
+ bit0 = (color_prom[i] >> 3) & 0x01;
+ bit1 = (color_prom[i] >> 4) & 0x01;
+ bit2 = (color_prom[i] >> 5) & 0x01;
+ g = combine_3_weights(gweights, bit0, bit1, bit2);
+
+ /* blue component */
+ bit0 = (color_prom[i] >> 6) & 0x01;
+ bit1 = (color_prom[i] >> 7) & 0x01;
+ b = combine_2_weights(bweights, bit0, bit1);
+
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ }
+
+ /* color_prom now points to the beginning of the character color codes */
+ color_codes = &color_prom[256];
+}
+
+
+
+/*************************************
+ *
+ * Tilemap callbacks
+ *
+ *************************************/
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ const UINT8 *source = memory_region(REGION_GFX4);
+ int size = memory_region_length(REGION_GFX4) / 2;
+ int eff_index = tile_index & (size - 1);
+ int code = source[eff_index] + 256 * (source[eff_index + size] & 3);
+ int color = source[eff_index + size] >> 4;
+ SET_TILE_INFO(1, code, color, 0);
+}
+
+
+static TILE_GET_INFO( zaxxon_get_fg_tile_info )
+{
+ int sx = tile_index % 32;
+ int sy = tile_index / 32;
+ int code = videoram[tile_index];
+ int color = color_codes[sx + 32 * (sy / 4)] & 0x0f;
+ SET_TILE_INFO(0, code, color * 2, 0);
+}
+
+
+static TILE_GET_INFO( razmataz_get_fg_tile_info )
+{
+ int code = videoram[tile_index];
+ int color = color_codes[code] & 0x0f;
+ SET_TILE_INFO(0, code, color * 2, 0);
+}
+
+
+static TILE_GET_INFO( congo_get_fg_tile_info )
+{
+ int code = videoram[tile_index] + (congo_fg_bank << 8);
+ int color = colorram[tile_index] & 0x1f;
+ SET_TILE_INFO(0, code, color * 2, 0);
+}
+
+
+
+/*************************************
+ *
+ * Video startup
+ *
+ *************************************/
+
+static void video_start_common(running_machine *machine, tile_get_info_callback fg_tile_info)
+{
+ /* reset globals */
+ bg_enable = 0;
+ bg_color = 0;
+ bg_position = 0;
+ fg_color = 0;
+ congo_fg_bank = 0;
+ congo_color_bank = 0;
+ memset(congo_custom, 0, sizeof(congo_custom));
+
+ /* create a background and foreground tilemap */
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,512);
+ fg_tilemap = tilemap_create(fg_tile_info, tilemap_scan_rows, TILEMAP_TYPE_PEN, 8,8, 32,32);
+
+ /* configure the foreground tilemap */
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+ tilemap_set_scrolldx(fg_tilemap, 0, machine->screen[0].width - 256);
+ tilemap_set_scrolldy(fg_tilemap, 0, machine->screen[0].height - 256);
+
+ /* register for save states */
+ state_save_register_global(bg_enable);
+ state_save_register_global(bg_color);
+ state_save_register_global(bg_position);
+ state_save_register_global(fg_color);
+}
+
+
+VIDEO_START( zaxxon )
+{
+ video_start_common(machine, zaxxon_get_fg_tile_info);
+}
+
+
+VIDEO_START( razmataz )
+{
+ video_start_common(machine, razmataz_get_fg_tile_info);
+}
+
+
+VIDEO_START( congo )
+{
+ /* allocate our own spriteram since it is not accessible by the main CPU */
+ spriteram = auto_malloc(0x100);
+
+ /* register for save states */
+ state_save_register_global(congo_fg_bank);
+ state_save_register_global(congo_color_bank);
+ state_save_register_global_array(congo_custom);
+ state_save_register_global_pointer(spriteram, 0x100);
+
+ video_start_common(machine, congo_get_fg_tile_info);
+}
+
+
+
+/*************************************
+ *
+ * Video latches and controls
+ *
+ *************************************/
+
+WRITE8_HANDLER( zaxxon_flipscreen_w )
+{
+ /* low bit controls flip; background and sprite flip are handled at render time */
+ flip_screen = ~data & 1;
+ tilemap_set_flip(fg_tilemap, flip_screen ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
+}
+
+
+WRITE8_HANDLER( zaxxon_fg_color_w )
+{
+ /* low bit selects high color palette index */
+ fg_color = (data & 1) * 0x80;
+ tilemap_set_palette_offset(fg_tilemap, fg_color + (congo_color_bank << 8));
+}
+
+
+WRITE8_HANDLER( zaxxon_bg_position_w )
+{
+ /* 11 bits of scroll position are stored */
+ if (offset == 0)
+ bg_position = (bg_position & 0x700) | ((data << 0) & 0x0ff);
+ else
+ bg_position = (bg_position & 0x0ff) | ((data << 8) & 0x700);
+}
+
+
+WRITE8_HANDLER( zaxxon_bg_color_w )
+{
+ /* low bit selects high color palette index */
+ bg_color = (data & 1) * 0x80;
+}
+
+
+WRITE8_HANDLER( zaxxon_bg_enable_w )
+{
+ /* low bit enables/disables the background layer */
+ bg_enable = data & 1;
+}
+
+
+WRITE8_HANDLER( congo_fg_bank_w )
+{
+ /* low bit controls the topmost character bit */
+ congo_fg_bank = data & 1;
+ tilemap_mark_all_tiles_dirty(fg_tilemap);
+}
+
+
+WRITE8_HANDLER( congo_color_bank_w )
+{
+ /* low bit controls the topmost bit into the color PROM */
+ congo_color_bank = data & 1;
+ tilemap_set_palette_offset(fg_tilemap, fg_color + (congo_color_bank << 8));
+}
+
+
+
+/*************************************
+ *
+ * Foreground tilemap access
+ *
+ *************************************/
+
+WRITE8_HANDLER( zaxxon_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+
+WRITE8_HANDLER( congo_colorram_w )
+{
+ colorram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+
+
+/*************************************
+ *
+ * Congo Bongo custom sprite DMA
+ *
+ *************************************/
+
+WRITE8_HANDLER( congo_sprite_custom_w )
+{
+ congo_custom[offset] = data;
+
+ /* seems to trigger on a write of 1 to the 4th byte */
+ if (offset == 3 && data == 0x01)
+ {
+ UINT16 saddr = congo_custom[0] | (congo_custom[1] << 8);
+ int count = congo_custom[2];
+
+ /* count cycles (just a guess) */
+ activecpu_adjust_icount(-count * 5);
+
+ /* this is just a guess; the chip is hardwired to the spriteram */
+ while (count-- >= 0)
+ {
+ UINT8 daddr = program_read_byte(saddr + 0) * 4;
+ spriteram[(daddr + 0) & 0xff] = program_read_byte(saddr + 1);
+ spriteram[(daddr + 1) & 0xff] = program_read_byte(saddr + 2);
+ spriteram[(daddr + 2) & 0xff] = program_read_byte(saddr + 3);
+ spriteram[(daddr + 3) & 0xff] = program_read_byte(saddr + 4);
+ saddr += 0x20;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Background pixmap drawing
+ *
+ *************************************/
+
+static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int skew)
+{
+ /* only draw if enabled */
+ if (bg_enable)
+ {
+ mame_bitmap *pixmap = tilemap_get_pixmap(bg_tilemap);
+ int colorbase = bg_color + (congo_color_bank << 8);
+ int xmask = pixmap->width - 1;
+ int ymask = pixmap->height - 1;
+ int flipmask = flip_screen ? 0xff : 0x00;
+ int flipoffs = flip_screen ? 0x38 : 0x40;
+ int x, y;
+
+ /* the starting X value is offset by 1 pixel (normal) or 7 pixels */
+ /* (flipped) due to a delay in the loading */
+ if (!flip_screen)
+ flipoffs -= 1;
+ else
+ flipoffs += 7;
+
+ /* loop over visible rows */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT16 *dst = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+ int srcx, srcy, vf;
+ UINT16 *src;
+
+ /* VF = flipped V signals */
+ vf = y ^ flipmask;
+
+ /* base of the source row comes from VF plus the scroll value */
+ /* this is done by the 3 4-bit adders at U56, U74, U75 */
+ srcy = vf + ((bg_position << 1) ^ 0xfff) + 1;
+ src = (UINT16 *)pixmap->base + (srcy & ymask) * pixmap->rowpixels;
+
+ /* loop over visible colums */
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ /* start with HF = flipped H signals */
+ srcx = x ^ flipmask;
+ if (skew)
+ {
+ /* position within source row is a two-stage addition */
+ /* first stage is HF plus half the VF, done by the 2 4-bit */
+ /* adders at U53, U54 */
+ srcx += ((vf >> 1) ^ 0xff) + 1;
+
+ /* second stage is first stage plus a constant based on the flip */
+ /* value is 0x40 for non-flipped, or 0x38 for flipped */
+ srcx += flipoffs;
+ }
+
+ /* store the pixel, offset by the color offset */
+ dst[x] = src[srcx & xmask] + colorbase;
+ }
+ }
+ }
+
+ /* if not enabled, fill the background with black */
+ else
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+}
+
+
+
+/*************************************
+ *
+ * Sprite drawing
+ *
+ *************************************/
+
+INLINE int find_minimum_y(UINT8 value)
+{
+ int flipmask = flip_screen ? 0xff : 0x00;
+ int flipconst = flip_screen ? 0xef : 0xf1;
+ int y;
+
+ /* the sum of the Y position plus a constant based on the flip state */
+ /* is added to the current flipped VF; if the top 3 bits are 1, we hit */
+
+ /* first find a 16-pixel bucket where we hit */
+ for (y = 0; y < 256; y += 16)
+ {
+ int sum = (value + flipconst + 1) + (y ^ flipmask);
+ if ((sum & 0xe0) == 0xe0)
+ break;
+ }
+
+ /* then scan backwards until we no longer match */
+ while (1)
+ {
+ int sum = (value + flipconst + 1) + ((y - 1) ^ flipmask);
+ if ((sum & 0xe0) != 0xe0)
+ break;
+ y--;
+ }
+
+ /* add one line since we draw sprites on the previous line */
+ return (y + 1) & 0xff;
+}
+
+
+INLINE int find_minimum_x(UINT8 value)
+{
+ int flipmask = flip_screen ? 0xff : 0x00;
+ int x;
+
+ /* the sum of the X position plus a constant specifies the address within */
+ /* the line bufer; if we're flipped, we will write backwards */
+ x = (value + 0xef + 1) ^ flipmask;
+ if (flipmask)
+ x -= 31;
+ return x & 0xff;
+}
+
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, UINT16 flipxmask, UINT16 flipymask)
+{
+ int flipmask = flip_screen ? 0xff : 0x00;
+ int offs;
+
+ /* only the lower half of sprite RAM is read during rendering */
+ for (offs = 0x7c; offs >= 0; offs -= 4)
+ {
+ int sy = find_minimum_y(spriteram[offs]);
+ int flipy = (spriteram[offs + (flipymask >> 8)] ^ flipmask) & flipymask;
+ int flipx = (spriteram[offs + (flipxmask >> 8)] ^ flipmask) & flipxmask;
+ int code = spriteram[offs + 1];
+ int color = (spriteram[offs + 2] & 0x1f) + (congo_color_bank << 5);
+ int sx = find_minimum_x(spriteram[offs + 3]);
+
+ /* draw with 256 pixel offsets to ensure we wrap properly */
+ drawgfx(bitmap, machine->gfx[2], code, color, flipx, flipy, sx, sy, cliprect, TRANSPARENCY_PEN, 0);
+ drawgfx(bitmap, machine->gfx[2], code, color, flipx, flipy, sx, sy - 0x100, cliprect, TRANSPARENCY_PEN, 0);
+ drawgfx(bitmap, machine->gfx[2], code, color, flipx, flipy, sx - 0x100, sy, cliprect, TRANSPARENCY_PEN, 0);
+ drawgfx(bitmap, machine->gfx[2], code, color, flipx, flipy, sx - 0x100, sy - 0x100, cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+
+
+/*************************************
+ *
+ * Core video updates
+ *
+ *************************************/
+
+VIDEO_UPDATE( zaxxon )
+{
+ draw_background(machine, bitmap, cliprect, TRUE);
+ draw_sprites(machine, bitmap, cliprect, 0x140, 0x180);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( futspy )
+{
+ draw_background(machine, bitmap, cliprect, TRUE);
+ draw_sprites(machine, bitmap, cliprect, 0x180, 0x180);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( razmataz )
+{
+ draw_background(machine, bitmap, cliprect, FALSE);
+ draw_sprites(machine, bitmap, cliprect, 0x140, 0x180);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
+
+
+VIDEO_UPDATE( congo )
+{
+ draw_background(machine, bitmap, cliprect, TRUE);
+ draw_sprites(machine, bitmap, cliprect, 0x280, 0x180);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ return 0;
+}
diff --git a/src/mame/video/zerozone.c b/src/mame/video/zerozone.c
new file mode 100644
index 00000000000..850eaaa4442
--- /dev/null
+++ b/src/mame/video/zerozone.c
@@ -0,0 +1,50 @@
+/***************************************************************************
+
+ video/zerozone.c
+
+***************************************************************************/
+
+#include "driver.h"
+
+UINT16 *zerozone_videoram;
+static UINT16 zerozone_tilebank;
+
+static tilemap *zerozone_tilemap;
+
+WRITE16_HANDLER( zerozone_tilemap_w )
+{
+ COMBINE_DATA(&zerozone_videoram[offset]);
+ tilemap_mark_tile_dirty(zerozone_tilemap,offset);
+}
+
+
+WRITE16_HANDLER(zerozone_tilebank_w)
+{
+// popmessage ("Data %04x",data);
+ zerozone_tilebank = data & 0x7;
+ tilemap_mark_all_tiles_dirty(zerozone_tilemap);
+}
+
+static TILE_GET_INFO( get_zerozone_tile_info )
+{
+ int tileno,colour;
+ tileno = zerozone_videoram[tile_index] & 0x07ff;
+ colour = zerozone_videoram[tile_index] & 0xf000;
+
+ if (zerozone_videoram[tile_index] & 0x0800) tileno += zerozone_tilebank * 0x800;
+
+ SET_TILE_INFO(0,tileno,colour>>12,0);
+}
+
+VIDEO_START( zerozone )
+{
+ // i'm not 100% sure it should be opaque, pink title screen looks strange in las vegas girls
+ // but if its transparent other things look incorrect
+ zerozone_tilemap = tilemap_create(get_zerozone_tile_info,tilemap_scan_cols,TILEMAP_TYPE_PEN, 8, 8, 64,32);
+}
+
+VIDEO_UPDATE( zerozone )
+{
+ tilemap_draw(bitmap,cliprect,zerozone_tilemap,0,0);
+ return 0;
+}
diff --git a/src/mame/video/zodiack.c b/src/mame/video/zodiack.c
new file mode 100644
index 00000000000..f14bc6b0f9a
--- /dev/null
+++ b/src/mame/video/zodiack.c
@@ -0,0 +1,219 @@
+/***************************************************************************
+
+ video.c
+
+ Functions to emulate the video hardware of the machine.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "includes/espial.h"
+
+UINT8 *zodiack_videoram2;
+UINT8 *zodiack_attributesram;
+UINT8 *zodiack_bulletsram;
+size_t zodiack_bulletsram_size;
+
+static tilemap *bg_tilemap, *fg_tilemap;
+
+WRITE8_HANDLER( zodiack_videoram_w )
+{
+ videoram[offset] = data;
+ tilemap_mark_tile_dirty(fg_tilemap, offset);
+}
+
+WRITE8_HANDLER( zodiack_videoram2_w )
+{
+ zodiack_videoram2[offset] = data;
+ tilemap_mark_tile_dirty(bg_tilemap, offset);
+}
+
+WRITE8_HANDLER( zodiack_attributes_w )
+{
+ if ((offset & 1) && zodiack_attributesram[offset] != data)
+ {
+ int i;
+
+ for (i = offset / 2;i < videoram_size; i += 32)
+ {
+ tilemap_mark_tile_dirty(bg_tilemap, i);
+ tilemap_mark_tile_dirty(fg_tilemap, i);
+ }
+ }
+
+ zodiack_attributesram[offset] = data;
+}
+
+WRITE8_HANDLER( zodiack_flipscreen_w )
+{
+ if (flip_screen != (~data & 0x01))
+ {
+ flip_screen_set(~data & 0x01);
+ tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
+ }
+}
+
+PALETTE_INIT( zodiack )
+{
+ int i;
+
+ #define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)
+ #define COLOR(gfxn,offs) (colortable[machine->drv->gfxdecodeinfo[gfxn].color_codes_start + offs])
+
+ /* first, the character/sprite palette */
+ for (i = 0;i < machine->drv->total_colors-1; i++)
+ {
+ int bit0,bit1,bit2,r,g,b;
+
+ /* red component */
+
+ bit0 = (*color_prom >> 0) & 0x01;
+ bit1 = (*color_prom >> 1) & 0x01;
+ bit2 = (*color_prom >> 2) & 0x01;
+
+ r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* green component */
+
+ bit0 = (*color_prom >> 3) & 0x01;
+ bit1 = (*color_prom >> 4) & 0x01;
+ bit2 = (*color_prom >> 5) & 0x01;
+
+ g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ /* blue component */
+
+ bit0 = 0;
+ bit1 = (*color_prom >> 6) & 0x01;
+ bit2 = (*color_prom >> 7) & 0x01;
+
+ b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
+
+ palette_set_color(machine,i,MAKE_RGB(r,g,b));
+
+ color_prom++;
+ }
+
+ /* white for bullets */
+
+ palette_set_color(machine,machine->drv->total_colors-1,MAKE_RGB(0xff,0xff,0xff));
+
+ for (i = 0;i < TOTAL_COLORS(0);i+=2)
+ {
+ COLOR(0,i ) = (32 + (i / 2));
+ COLOR(0,i+1) = (40 + (i / 2));
+ }
+
+ for (i = 0;i < TOTAL_COLORS(3);i++)
+ {
+ if ((i & 3) == 0) COLOR(3,i) = 0;
+ }
+
+ /* bullet */
+ COLOR(2, 0) = 0;
+ COLOR(2, 1) = 48;
+}
+
+static TILE_GET_INFO( get_bg_tile_info )
+{
+ int code = zodiack_videoram2[tile_index];
+ int color = (zodiack_attributesram[2 * (tile_index % 32) + 1] >> 4) & 0x07;
+
+ SET_TILE_INFO(0, code, color, 0);
+}
+
+static TILE_GET_INFO( get_fg_tile_info )
+{
+ int code = videoram[tile_index];
+ int color = zodiack_attributesram[2 * (tile_index % 32) + 1] & 0x07;
+
+ SET_TILE_INFO(3, code, color, 0);
+}
+
+VIDEO_START( zodiack )
+{
+ bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows,
+ TILEMAP_TYPE_PEN, 8, 8, 32, 32);
+
+ tilemap_set_transparent_pen(fg_tilemap, 0);
+ tilemap_set_scroll_cols(fg_tilemap, 32);
+
+ flip_screen = 0;
+}
+
+static void draw_bullets(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = 0; offs < zodiack_bulletsram_size; offs += 4)
+ {
+ int x, y;
+
+ x = zodiack_bulletsram[offs + 3] + 7;
+ y = 255 - zodiack_bulletsram[offs + 1];
+
+ if (flip_screen && percuss_hardware)
+ {
+ y = 255 - y;
+ }
+
+ drawgfx(
+ bitmap,
+ machine->gfx[2],
+ 0, /* this is just a dot, generated by the hardware */
+ 0,
+ 0,0,
+ x,y,
+ cliprect,TRANSPARENCY_PEN,0);
+ }
+}
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
+{
+ int offs;
+
+ for (offs = spriteram_size - 4; offs >= 0; offs -= 4)
+ {
+ int flipx, flipy, sx, sy, spritecode;
+
+ sx = 240 - spriteram[offs + 3];
+ sy = 240 - spriteram[offs];
+ flipx = !(spriteram[offs + 1] & 0x40);
+ flipy = spriteram[offs + 1] & 0x80;
+ spritecode = spriteram[offs + 1] & 0x3f;
+
+ if (flip_screen && percuss_hardware)
+ {
+ sy = 240 - sy;
+ flipy = !flipy;
+ }
+
+ drawgfx(bitmap, machine->gfx[1],
+ spritecode,
+ spriteram[offs + 2] & 0x07,
+ flipx, flipy,
+ sx, sy,
+ //flip_screen[0] ? &spritevisibleareaflipx : &spritevisiblearea,TRANSPARENCY_PEN,0);
+ //&spritevisiblearea,TRANSPARENCY_PEN,0);
+ cliprect, TRANSPARENCY_PEN, 0);
+ }
+}
+
+VIDEO_UPDATE( zodiack )
+{
+ int i;
+
+ for (i = 0; i < 32; i++)
+ {
+ tilemap_set_scrolly(fg_tilemap, i, zodiack_attributesram[i * 2]);
+ }
+
+ tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
+ tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
+ draw_bullets(machine, bitmap, cliprect);
+ draw_sprites(machine, bitmap, cliprect);
+ return 0;
+}